Imported Upstream version 0.9.7 94/259094/2 upstream upstream/0.9.7
authorMinje Ahn <minje.ahn@samsung.com>
Tue, 1 Jun 2021 05:37:55 +0000 (14:37 +0900)
committerMinje Ahn <minje.ahn@samsung.com>
Tue, 1 Jun 2021 06:52:48 +0000 (15:52 +0900)
Change-Id: Iffb927fb1fbbfd203a48f7cfe75caecf602c8491

443 files changed:
.editorconfig [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
CODINGSTYLE.txt [new file with mode: 0644]
CONTRIBUTIONS.txt [new file with mode: 0644]
COPYING [new file with mode: 0644]
COPYING.LIB [new file with mode: 0644]
COPYING.exception [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
Doxyfile [new file with mode: 0644]
FAQ.html [new file with mode: 0644]
INSTALL [new file with mode: 0644]
NEWS [new file with mode: 0644]
README.html [new file with mode: 0644]
TODO [new file with mode: 0644]
cmake/modules/FindBoost.cmake [new file with mode: 0644]
cmake/modules/FindCppUnit.cmake [new file with mode: 0644]
cmake/modules/FindFONTCONFIG.cmake [new file with mode: 0644]
cmake/modules/FindFREETYPE.cmake [new file with mode: 0644]
cmake/modules/FindLIBCRYPTO.cmake [new file with mode: 0644]
cmake/modules/FindLIBIDN.cmake [new file with mode: 0644]
cmake/modules/FindLIBJPEG.cmake [new file with mode: 0644]
cmake/modules/FindLIBSTLPORT.cmake [new file with mode: 0644]
cmake/modules/FindLUA.cmake [new file with mode: 0644]
cmake/modules/FindLua51.cmake [new file with mode: 0644]
cmake/modules/FindOpenSSL.cmake [new file with mode: 0644]
cmake/modules/FindTIFF.cmake [new file with mode: 0644]
cmake/modules/FindUNISTRING.cmake [new file with mode: 0644]
cmake/modules/FindZLIB.cmake [new file with mode: 0644]
cmake/modules/LibraryDebugAndRelease.cmake [new file with mode: 0644]
cmake/modules/MacroEnsureVersion.cmake [new file with mode: 0644]
cmake_uninstall.cmake.in [new file with mode: 0644]
doc/podofo_architecture.png [new file with mode: 0644]
examples/CMakeLists.txt [new file with mode: 0644]
examples/helloworld-base14/CMakeLists.txt [new file with mode: 0644]
examples/helloworld-base14/helloworld-base14.cpp [new file with mode: 0644]
examples/helloworld/CMakeLists.txt [new file with mode: 0644]
examples/helloworld/helloworld.cpp [new file with mode: 0644]
examples/pdfcontentsgraph/CMakeLists.txt [new file with mode: 0644]
examples/pdfcontentsgraph/PdfContentsGraph.cpp [new file with mode: 0644]
examples/pdfcontentsgraph/PdfContentsGraph.h [new file with mode: 0644]
examples/pdfcontentsgraph/README.txt [new file with mode: 0644]
examples/pdfcontentsgraph/main.cpp [new file with mode: 0644]
man/CMakeLists.txt [new file with mode: 0644]
man/podofobox.1 [new file with mode: 0644]
man/podofocolor.1 [new file with mode: 0644]
man/podofocountpages.1 [new file with mode: 0644]
man/podofocrop.1 [new file with mode: 0644]
man/podofoencrypt.1 [new file with mode: 0644]
man/podofogc.1 [new file with mode: 0644]
man/podofoimg2pdf.1 [new file with mode: 0644]
man/podofoimgextract.1 [new file with mode: 0644]
man/podofoimpose.1 [new file with mode: 0644]
man/podofoincrementalupdates.1 [new file with mode: 0644]
man/podofomerge.1 [new file with mode: 0644]
man/podofopages.1 [new file with mode: 0644]
man/podofopdfinfo.1 [new file with mode: 0644]
man/podofotxt2pdf.1 [new file with mode: 0644]
man/podofotxtextract.1 [new file with mode: 0644]
man/podofouncompress.1 [new file with mode: 0644]
man/podofoxmp.1 [new file with mode: 0644]
podofo_config.h.in [new file with mode: 0644]
src/podofo/CMakeLists.txt [new file with mode: 0644]
src/podofo/base/Pdf3rdPtyForwardDecl.h [new file with mode: 0644]
src/podofo/base/PdfArray.cpp [new file with mode: 0644]
src/podofo/base/PdfArray.h [new file with mode: 0644]
src/podofo/base/PdfCanvas.cpp [new file with mode: 0644]
src/podofo/base/PdfCanvas.h [new file with mode: 0644]
src/podofo/base/PdfColor.cpp [new file with mode: 0644]
src/podofo/base/PdfColor.h [new file with mode: 0644]
src/podofo/base/PdfCompilerCompat.h [new file with mode: 0644]
src/podofo/base/PdfCompilerCompatPrivate.h [new file with mode: 0644]
src/podofo/base/PdfContentsTokenizer.cpp [new file with mode: 0644]
src/podofo/base/PdfContentsTokenizer.h [new file with mode: 0644]
src/podofo/base/PdfData.cpp [new file with mode: 0644]
src/podofo/base/PdfData.h [new file with mode: 0644]
src/podofo/base/PdfDataType.cpp [new file with mode: 0644]
src/podofo/base/PdfDataType.h [new file with mode: 0644]
src/podofo/base/PdfDate.cpp [new file with mode: 0644]
src/podofo/base/PdfDate.h [new file with mode: 0644]
src/podofo/base/PdfDefines.h [new file with mode: 0644]
src/podofo/base/PdfDefinesPrivate.h [new file with mode: 0644]
src/podofo/base/PdfDictionary.cpp [new file with mode: 0644]
src/podofo/base/PdfDictionary.h [new file with mode: 0644]
src/podofo/base/PdfEncoding.cpp [new file with mode: 0644]
src/podofo/base/PdfEncoding.h [new file with mode: 0644]
src/podofo/base/PdfEncodingFactory.cpp [new file with mode: 0644]
src/podofo/base/PdfEncodingFactory.h [new file with mode: 0644]
src/podofo/base/PdfEncrypt.cpp [new file with mode: 0644]
src/podofo/base/PdfEncrypt.h [new file with mode: 0644]
src/podofo/base/PdfError.cpp [new file with mode: 0644]
src/podofo/base/PdfError.h [new file with mode: 0644]
src/podofo/base/PdfExtension.h [new file with mode: 0644]
src/podofo/base/PdfFileStream.cpp [new file with mode: 0644]
src/podofo/base/PdfFileStream.h [new file with mode: 0644]
src/podofo/base/PdfFilter.cpp [new file with mode: 0644]
src/podofo/base/PdfFilter.h [new file with mode: 0644]
src/podofo/base/PdfFiltersPrivate.cpp [new file with mode: 0644]
src/podofo/base/PdfFiltersPrivate.h [new file with mode: 0644]
src/podofo/base/PdfImmediateWriter.cpp [new file with mode: 0644]
src/podofo/base/PdfImmediateWriter.h [new file with mode: 0644]
src/podofo/base/PdfInputDevice.cpp [new file with mode: 0644]
src/podofo/base/PdfInputDevice.h [new file with mode: 0644]
src/podofo/base/PdfInputStream.cpp [new file with mode: 0644]
src/podofo/base/PdfInputStream.h [new file with mode: 0644]
src/podofo/base/PdfLocale.cpp [new file with mode: 0644]
src/podofo/base/PdfLocale.h [new file with mode: 0644]
src/podofo/base/PdfMemStream.cpp [new file with mode: 0644]
src/podofo/base/PdfMemStream.h [new file with mode: 0644]
src/podofo/base/PdfMemoryManagement.cpp [new file with mode: 0644]
src/podofo/base/PdfMemoryManagement.h [new file with mode: 0644]
src/podofo/base/PdfName.cpp [new file with mode: 0644]
src/podofo/base/PdfName.h [new file with mode: 0644]
src/podofo/base/PdfObject.cpp [new file with mode: 0644]
src/podofo/base/PdfObject.h [new file with mode: 0644]
src/podofo/base/PdfObjectStreamParserObject.cpp [new file with mode: 0644]
src/podofo/base/PdfObjectStreamParserObject.h [new file with mode: 0644]
src/podofo/base/PdfOutputDevice.cpp [new file with mode: 0644]
src/podofo/base/PdfOutputDevice.h [new file with mode: 0644]
src/podofo/base/PdfOutputStream.cpp [new file with mode: 0644]
src/podofo/base/PdfOutputStream.h [new file with mode: 0644]
src/podofo/base/PdfOwnedDataType.cpp [new file with mode: 0644]
src/podofo/base/PdfOwnedDataType.h [new file with mode: 0644]
src/podofo/base/PdfParser.cpp [new file with mode: 0644]
src/podofo/base/PdfParser.h [new file with mode: 0644]
src/podofo/base/PdfParserObject.cpp [new file with mode: 0644]
src/podofo/base/PdfParserObject.h [new file with mode: 0644]
src/podofo/base/PdfRect.cpp [new file with mode: 0644]
src/podofo/base/PdfRect.h [new file with mode: 0644]
src/podofo/base/PdfRefCountedBuffer.cpp [new file with mode: 0644]
src/podofo/base/PdfRefCountedBuffer.h [new file with mode: 0644]
src/podofo/base/PdfRefCountedInputDevice.cpp [new file with mode: 0644]
src/podofo/base/PdfRefCountedInputDevice.h [new file with mode: 0644]
src/podofo/base/PdfReference.cpp [new file with mode: 0644]
src/podofo/base/PdfReference.h [new file with mode: 0644]
src/podofo/base/PdfStream.cpp [new file with mode: 0644]
src/podofo/base/PdfStream.h [new file with mode: 0644]
src/podofo/base/PdfString.cpp [new file with mode: 0644]
src/podofo/base/PdfString.h [new file with mode: 0644]
src/podofo/base/PdfTokenizer.cpp [new file with mode: 0644]
src/podofo/base/PdfTokenizer.h [new file with mode: 0644]
src/podofo/base/PdfVariant.cpp [new file with mode: 0644]
src/podofo/base/PdfVariant.h [new file with mode: 0644]
src/podofo/base/PdfVecObjects.cpp [new file with mode: 0644]
src/podofo/base/PdfVecObjects.h [new file with mode: 0644]
src/podofo/base/PdfVersion.h [new file with mode: 0644]
src/podofo/base/PdfWriter.cpp [new file with mode: 0644]
src/podofo/base/PdfWriter.h [new file with mode: 0644]
src/podofo/base/PdfXRef.cpp [new file with mode: 0644]
src/podofo/base/PdfXRef.h [new file with mode: 0644]
src/podofo/base/PdfXRefStream.cpp [new file with mode: 0644]
src/podofo/base/PdfXRefStream.h [new file with mode: 0644]
src/podofo/base/PdfXRefStreamParserObject.cpp [new file with mode: 0644]
src/podofo/base/PdfXRefStreamParserObject.h [new file with mode: 0644]
src/podofo/base/podofoapi.h [new file with mode: 0644]
src/podofo/base/util/PdfMutex.h [new file with mode: 0644]
src/podofo/base/util/PdfMutexImpl_noop.h [new file with mode: 0644]
src/podofo/base/util/PdfMutexImpl_pthread.h [new file with mode: 0644]
src/podofo/base/util/PdfMutexImpl_win32.h [new file with mode: 0644]
src/podofo/base/util/PdfMutexWrapper.h [new file with mode: 0644]
src/podofo/doc/PdfAcroForm.cpp [new file with mode: 0644]
src/podofo/doc/PdfAcroForm.h [new file with mode: 0644]
src/podofo/doc/PdfAction.cpp [new file with mode: 0644]
src/podofo/doc/PdfAction.h [new file with mode: 0644]
src/podofo/doc/PdfAnnotation.cpp [new file with mode: 0644]
src/podofo/doc/PdfAnnotation.h [new file with mode: 0644]
src/podofo/doc/PdfCMapEncoding.cpp [new file with mode: 0644]
src/podofo/doc/PdfCMapEncoding.h [new file with mode: 0644]
src/podofo/doc/PdfContents.cpp [new file with mode: 0644]
src/podofo/doc/PdfContents.h [new file with mode: 0644]
src/podofo/doc/PdfDestination.cpp [new file with mode: 0644]
src/podofo/doc/PdfDestination.h [new file with mode: 0644]
src/podofo/doc/PdfDifferenceEncoding.cpp [new file with mode: 0644]
src/podofo/doc/PdfDifferenceEncoding.h [new file with mode: 0644]
src/podofo/doc/PdfDocument.cpp [new file with mode: 0644]
src/podofo/doc/PdfDocument.h [new file with mode: 0644]
src/podofo/doc/PdfElement.cpp [new file with mode: 0644]
src/podofo/doc/PdfElement.h [new file with mode: 0644]
src/podofo/doc/PdfEncodingObjectFactory.cpp [new file with mode: 0644]
src/podofo/doc/PdfEncodingObjectFactory.h [new file with mode: 0644]
src/podofo/doc/PdfExtGState.cpp [new file with mode: 0644]
src/podofo/doc/PdfExtGState.h [new file with mode: 0644]
src/podofo/doc/PdfField.cpp [new file with mode: 0644]
src/podofo/doc/PdfField.h [new file with mode: 0644]
src/podofo/doc/PdfFileSpec.cpp [new file with mode: 0644]
src/podofo/doc/PdfFileSpec.h [new file with mode: 0644]
src/podofo/doc/PdfFont.cpp [new file with mode: 0644]
src/podofo/doc/PdfFont.h [new file with mode: 0644]
src/podofo/doc/PdfFontCID.cpp [new file with mode: 0644]
src/podofo/doc/PdfFontCID.h [new file with mode: 0644]
src/podofo/doc/PdfFontCache.cpp [new file with mode: 0644]
src/podofo/doc/PdfFontCache.h [new file with mode: 0644]
src/podofo/doc/PdfFontConfigWrapper.cpp [new file with mode: 0644]
src/podofo/doc/PdfFontConfigWrapper.h [new file with mode: 0644]
src/podofo/doc/PdfFontFactory.cpp [new file with mode: 0644]
src/podofo/doc/PdfFontFactory.h [new file with mode: 0644]
src/podofo/doc/PdfFontFactoryBase14Data.h [new file with mode: 0644]
src/podofo/doc/PdfFontMetrics.cpp [new file with mode: 0644]
src/podofo/doc/PdfFontMetrics.h [new file with mode: 0644]
src/podofo/doc/PdfFontMetricsBase14.cpp [new file with mode: 0644]
src/podofo/doc/PdfFontMetricsBase14.h [new file with mode: 0644]
src/podofo/doc/PdfFontMetricsFreetype.cpp [new file with mode: 0644]
src/podofo/doc/PdfFontMetricsFreetype.h [new file with mode: 0644]
src/podofo/doc/PdfFontMetricsObject.cpp [new file with mode: 0644]
src/podofo/doc/PdfFontMetricsObject.h [new file with mode: 0644]
src/podofo/doc/PdfFontSimple.cpp [new file with mode: 0644]
src/podofo/doc/PdfFontSimple.h [new file with mode: 0644]
src/podofo/doc/PdfFontTTFSubset.cpp [new file with mode: 0644]
src/podofo/doc/PdfFontTTFSubset.h [new file with mode: 0644]
src/podofo/doc/PdfFontTrueType.cpp [new file with mode: 0644]
src/podofo/doc/PdfFontTrueType.h [new file with mode: 0644]
src/podofo/doc/PdfFontType1.cpp [new file with mode: 0644]
src/podofo/doc/PdfFontType1.h [new file with mode: 0644]
src/podofo/doc/PdfFontType1Base14.cpp [new file with mode: 0644]
src/podofo/doc/PdfFontType1Base14.h [new file with mode: 0644]
src/podofo/doc/PdfFontType3.cpp [new file with mode: 0644]
src/podofo/doc/PdfFontType3.h [new file with mode: 0644]
src/podofo/doc/PdfFunction.cpp [new file with mode: 0644]
src/podofo/doc/PdfFunction.h [new file with mode: 0644]
src/podofo/doc/PdfHintStream.cpp [new file with mode: 0644]
src/podofo/doc/PdfHintStream.h [new file with mode: 0644]
src/podofo/doc/PdfIdentityEncoding.cpp [new file with mode: 0644]
src/podofo/doc/PdfIdentityEncoding.h [new file with mode: 0644]
src/podofo/doc/PdfImage.cpp [new file with mode: 0644]
src/podofo/doc/PdfImage.h [new file with mode: 0644]
src/podofo/doc/PdfInfo.cpp [new file with mode: 0644]
src/podofo/doc/PdfInfo.h [new file with mode: 0644]
src/podofo/doc/PdfMemDocument.cpp [new file with mode: 0644]
src/podofo/doc/PdfMemDocument.h [new file with mode: 0644]
src/podofo/doc/PdfNamesTree.cpp [new file with mode: 0644]
src/podofo/doc/PdfNamesTree.h [new file with mode: 0644]
src/podofo/doc/PdfOutlines.cpp [new file with mode: 0644]
src/podofo/doc/PdfOutlines.h [new file with mode: 0644]
src/podofo/doc/PdfPage.cpp [new file with mode: 0644]
src/podofo/doc/PdfPage.h [new file with mode: 0644]
src/podofo/doc/PdfPagesTree.cpp [new file with mode: 0644]
src/podofo/doc/PdfPagesTree.h [new file with mode: 0644]
src/podofo/doc/PdfPagesTreeCache.cpp [new file with mode: 0644]
src/podofo/doc/PdfPagesTreeCache.h [new file with mode: 0644]
src/podofo/doc/PdfPainter.cpp [new file with mode: 0644]
src/podofo/doc/PdfPainter.h [new file with mode: 0644]
src/podofo/doc/PdfPainterMM.cpp [new file with mode: 0644]
src/podofo/doc/PdfPainterMM.h [new file with mode: 0644]
src/podofo/doc/PdfShadingPattern.cpp [new file with mode: 0644]
src/podofo/doc/PdfShadingPattern.h [new file with mode: 0644]
src/podofo/doc/PdfSignOutputDevice.cpp [new file with mode: 0644]
src/podofo/doc/PdfSignOutputDevice.h [new file with mode: 0644]
src/podofo/doc/PdfSignatureField.cpp [new file with mode: 0644]
src/podofo/doc/PdfSignatureField.h [new file with mode: 0644]
src/podofo/doc/PdfStreamedDocument.cpp [new file with mode: 0644]
src/podofo/doc/PdfStreamedDocument.h [new file with mode: 0644]
src/podofo/doc/PdfTTFWriter.cpp [new file with mode: 0644]
src/podofo/doc/PdfTTFWriter.h [new file with mode: 0644]
src/podofo/doc/PdfTable.cpp [new file with mode: 0644]
src/podofo/doc/PdfTable.h [new file with mode: 0644]
src/podofo/doc/PdfTilingPattern.cpp [new file with mode: 0644]
src/podofo/doc/PdfTilingPattern.h [new file with mode: 0644]
src/podofo/doc/PdfXObject.cpp [new file with mode: 0644]
src/podofo/doc/PdfXObject.h [new file with mode: 0644]
src/podofo/doc/podofo-doc.rc [new file with mode: 0644]
src/podofo/libpodofo.pc.in [new file with mode: 0644]
src/podofo/podofo-base.h [new file with mode: 0644]
src/podofo/podofo.h [new file with mode: 0644]
test/CMakeLists.txt [new file with mode: 0644]
test/ContentParser/CMakeLists.txt [new file with mode: 0644]
test/ContentParser/main.cpp [new file with mode: 0644]
test/CreationTest/CMakeLists.txt [new file with mode: 0644]
test/CreationTest/CreationTest.cpp [new file with mode: 0644]
test/CreationTest/resources/Illust.pdf [new file with mode: 0644]
test/CreationTest/resources/watzmann.jpg [new file with mode: 0644]
test/FilterTest/CMakeLists.txt [new file with mode: 0644]
test/FilterTest/FilterTest.cpp [new file with mode: 0644]
test/FormTest/CMakeLists.txt [new file with mode: 0644]
test/FormTest/FormTest.cpp [new file with mode: 0644]
test/LargeTest/CMakeLists.txt [new file with mode: 0644]
test/LargeTest/LargeTest.cpp [new file with mode: 0644]
test/ObjectParserTest/CMakeLists.txt [new file with mode: 0644]
test/ObjectParserTest/ObjectParserTest.cpp [new file with mode: 0644]
test/ObjectParserTest/objects/27_0_R.exp [new file with mode: 0644]
test/ObjectParserTest/objects/27_0_R.info [new file with mode: 0644]
test/ObjectParserTest/objects/27_0_R.obj [new file with mode: 0644]
test/ObjectParserTest/objects/613_0_R.obj [new file with mode: 0644]
test/ParserTest/CMakeLists.txt [new file with mode: 0644]
test/ParserTest/ParserTest.cpp [new file with mode: 0644]
test/PdfTest.h [new file with mode: 0644]
test/SignTest/CMakeLists.txt [new file with mode: 0644]
test/SignTest/SignTest.cpp [new file with mode: 0644]
test/SignatureTest/CMakeLists.txt [new file with mode: 0644]
test/SignatureTest/NSSSignatureGenerator.cpp [new file with mode: 0644]
test/SignatureTest/NSSSignatureGenerator.h [new file with mode: 0644]
test/SignatureTest/SignTest.cpp [new file with mode: 0644]
test/SignatureTest/SignatureGenerator.h [new file with mode: 0644]
test/SignatureTest/SimpleSignatureGenerator.h [new file with mode: 0644]
test/TokenizerTest/CMakeLists.txt [new file with mode: 0644]
test/TokenizerTest/TokenizerTest.cpp [new file with mode: 0644]
test/VariantTest/CMakeLists.txt [new file with mode: 0644]
test/VariantTest/VariantTest.cpp [new file with mode: 0644]
test/WatermarkTest/CMakeLists.txt [new file with mode: 0644]
test/WatermarkTest/WatermarkTest.cpp [new file with mode: 0644]
test/WatermarkTest/WatermarkTest.vcproj [new file with mode: 0644]
test/pdfs/README.txt [new file with mode: 0644]
test/pdfs/inline-image.pdf [new file with mode: 0644]
test/pdfs/inline-image.txt [new file with mode: 0644]
test/system/podofo-system.sh [new file with mode: 0755]
test/unit/BasicTypeTest.cpp [new file with mode: 0644]
test/unit/BasicTypeTest.h [new file with mode: 0644]
test/unit/CMakeLists.txt [new file with mode: 0644]
test/unit/ColorTest.cpp [new file with mode: 0644]
test/unit/ColorTest.h [new file with mode: 0644]
test/unit/DateTest.cpp [new file with mode: 0644]
test/unit/DateTest.h [new file with mode: 0644]
test/unit/DeviceTest.cpp [new file with mode: 0644]
test/unit/DeviceTest.h [new file with mode: 0644]
test/unit/ElementTest.cpp [new file with mode: 0644]
test/unit/ElementTest.h [new file with mode: 0644]
test/unit/EncodingTest.cpp [new file with mode: 0644]
test/unit/EncodingTest.h [new file with mode: 0644]
test/unit/EncryptTest.cpp [new file with mode: 0644]
test/unit/EncryptTest.h [new file with mode: 0644]
test/unit/FilterTest.cpp [new file with mode: 0644]
test/unit/FilterTest.h [new file with mode: 0644]
test/unit/FontTest.cpp [new file with mode: 0644]
test/unit/FontTest.h [new file with mode: 0644]
test/unit/NameTest.cpp [new file with mode: 0644]
test/unit/NameTest.h [new file with mode: 0644]
test/unit/PageTest.cpp [new file with mode: 0644]
test/unit/PageTest.h [new file with mode: 0644]
test/unit/PagesTreeTest.cpp [new file with mode: 0644]
test/unit/PagesTreeTest.h [new file with mode: 0644]
test/unit/PainterTest.cpp [new file with mode: 0644]
test/unit/PainterTest.h [new file with mode: 0644]
test/unit/ParserTest.cpp [new file with mode: 0644]
test/unit/ParserTest.h [new file with mode: 0644]
test/unit/StringTest.cpp [new file with mode: 0644]
test/unit/StringTest.h [new file with mode: 0644]
test/unit/TestUtils.cpp [new file with mode: 0644]
test/unit/TestUtils.h [new file with mode: 0644]
test/unit/TokenizerTest.cpp [new file with mode: 0644]
test/unit/TokenizerTest.h [new file with mode: 0644]
test/unit/VariantTest.cpp [new file with mode: 0644]
test/unit/VariantTest.h [new file with mode: 0644]
test/unit/cppunitextensions.h [new file with mode: 0644]
test/unit/main.cpp [new file with mode: 0644]
test/valgrind.suppressions [new file with mode: 0644]
tools/CMakeLists.txt [new file with mode: 0644]
tools/podofobox/CMakeLists.txt [new file with mode: 0644]
tools/podofobox/boxsetter.cpp [new file with mode: 0644]
tools/podofobox/boxsetter.h [new file with mode: 0644]
tools/podofobox/podofobox.cpp [new file with mode: 0644]
tools/podofocolor/CMakeLists.txt [new file with mode: 0644]
tools/podofocolor/colorchanger.cpp [new file with mode: 0644]
tools/podofocolor/colorchanger.h [new file with mode: 0644]
tools/podofocolor/colorspace.cpp [new file with mode: 0644]
tools/podofocolor/colorspace.h [new file with mode: 0644]
tools/podofocolor/dummyconverter.cpp [new file with mode: 0644]
tools/podofocolor/dummyconverter.h [new file with mode: 0644]
tools/podofocolor/example.lua [new file with mode: 0644]
tools/podofocolor/graphicsstack.cpp [new file with mode: 0644]
tools/podofocolor/graphicsstack.h [new file with mode: 0644]
tools/podofocolor/grayscaleconverter.cpp [new file with mode: 0644]
tools/podofocolor/grayscaleconverter.h [new file with mode: 0644]
tools/podofocolor/iconverter.cpp [new file with mode: 0644]
tools/podofocolor/iconverter.h [new file with mode: 0644]
tools/podofocolor/lua_compat.h [new file with mode: 0644]
tools/podofocolor/luaconverter.cpp [new file with mode: 0644]
tools/podofocolor/luaconverter.h [new file with mode: 0644]
tools/podofocolor/podofocolor.cpp [new file with mode: 0644]
tools/podofocountpages/CMakeLists.txt [new file with mode: 0644]
tools/podofocountpages/countpages.cpp [new file with mode: 0644]
tools/podofocrop/CMakeLists.txt [new file with mode: 0644]
tools/podofocrop/podofocrop.cpp [new file with mode: 0644]
tools/podofoencrypt/CMakeLists.txt [new file with mode: 0644]
tools/podofoencrypt/podofoencrypt.cpp [new file with mode: 0644]
tools/podofogc/CMakeLists.txt [new file with mode: 0644]
tools/podofogc/podofogc.cpp [new file with mode: 0644]
tools/podofoimg2pdf/CMakeLists.txt [new file with mode: 0644]
tools/podofoimg2pdf/ImageConverter.cpp [new file with mode: 0644]
tools/podofoimg2pdf/ImageConverter.h [new file with mode: 0644]
tools/podofoimg2pdf/podofoimg2pdf.cpp [new file with mode: 0644]
tools/podofoimgextract/CMakeLists.txt [new file with mode: 0644]
tools/podofoimgextract/ImageExtractor.cpp [new file with mode: 0644]
tools/podofoimgextract/ImageExtractor.h [new file with mode: 0644]
tools/podofoimgextract/podofoimgextract.cpp [new file with mode: 0644]
tools/podofoimgextract/podofoimgextract.vcproj [new file with mode: 0644]
tools/podofoimpose/CMakeLists.txt [new file with mode: 0644]
tools/podofoimpose/README.html [new file with mode: 0644]
tools/podofoimpose/charpainter.cpp [new file with mode: 0644]
tools/podofoimpose/charpainter.h [new file with mode: 0644]
tools/podofoimpose/impositionplan.cpp [new file with mode: 0644]
tools/podofoimpose/impositionplan.h [new file with mode: 0644]
tools/podofoimpose/lua_compat.h [new file with mode: 0644]
tools/podofoimpose/pdftranslator.cpp [new file with mode: 0644]
tools/podofoimpose/pdftranslator.h [new file with mode: 0644]
tools/podofoimpose/planreader_legacy.cpp [new file with mode: 0644]
tools/podofoimpose/planreader_legacy.h [new file with mode: 0644]
tools/podofoimpose/planreader_lua.cpp [new file with mode: 0644]
tools/podofoimpose/planreader_lua.h [new file with mode: 0644]
tools/podofoimpose/plans/lua/Booklet-A4-duplex.plan [new file with mode: 0644]
tools/podofoimpose/plans/lua/Booklet-USlegal-duplex.plan [new file with mode: 0644]
tools/podofoimpose/plans/lua/Booklet-USletter-bottom.plan [new file with mode: 0644]
tools/podofoimpose/plans/lua/Booklet-USletter-duplex.plan [new file with mode: 0644]
tools/podofoimpose/plans/lua/Booklet-USletter-top.plan [new file with mode: 0644]
tools/podofoimpose/plans/lua/Booklet.plan [new file with mode: 0644]
tools/podofoimpose/plans/lua/Identity.plan [new file with mode: 0644]
tools/podofoimpose/plans/lua/In4.plan [new file with mode: 0644]
tools/podofoimpose/plans/lua/Test.plan [new file with mode: 0644]
tools/podofoimpose/podofoimpose.cpp [new file with mode: 0644]
tools/podofoimpose/sample.pdf [new file with mode: 0644]
tools/podofoimpose/sample.plan [new file with mode: 0644]
tools/podofoincrementalupdates/CMakeLists.txt [new file with mode: 0644]
tools/podofoincrementalupdates/incrementalupdates.cpp [new file with mode: 0644]
tools/podofomerge/CMakeLists.txt [new file with mode: 0644]
tools/podofomerge/podofomerge.cpp [new file with mode: 0644]
tools/podofomerge/podofomerge.vcproj [new file with mode: 0644]
tools/podofonooc/CMakeLists.txt [new file with mode: 0644]
tools/podofonooc/podofonooc.cpp [new file with mode: 0644]
tools/podofopages/CMakeLists.txt [new file with mode: 0644]
tools/podofopages/DeleteOperation.cpp [new file with mode: 0644]
tools/podofopages/DeleteOperation.h [new file with mode: 0644]
tools/podofopages/MoveOperation.cpp [new file with mode: 0644]
tools/podofopages/MoveOperation.h [new file with mode: 0644]
tools/podofopages/Operation.h [new file with mode: 0644]
tools/podofopages/podofopages.cpp [new file with mode: 0644]
tools/podofopdfinfo/CMakeLists.txt [new file with mode: 0644]
tools/podofopdfinfo/pdfinfo.cpp [new file with mode: 0644]
tools/podofopdfinfo/pdfinfo.h [new file with mode: 0644]
tools/podofopdfinfo/podofopdfinfo.cpp [new file with mode: 0644]
tools/podofosign/CMakeLists.txt [new file with mode: 0644]
tools/podofosign/podofosign.cpp [new file with mode: 0644]
tools/podofotxt2pdf/CMakeLists.txt [new file with mode: 0644]
tools/podofotxt2pdf/podofotxt2pdf.cpp [new file with mode: 0644]
tools/podofotxt2pdf/podofotxt2pdf.vcproj [new file with mode: 0644]
tools/podofotxtextract/CMakeLists.txt [new file with mode: 0644]
tools/podofotxtextract/TextExtractor.cpp [new file with mode: 0644]
tools/podofotxtextract/TextExtractor.h [new file with mode: 0644]
tools/podofotxtextract/podofotxtextract.cpp [new file with mode: 0644]
tools/podofouncompress/CMakeLists.txt [new file with mode: 0644]
tools/podofouncompress/Uncompress.cpp [new file with mode: 0644]
tools/podofouncompress/Uncompress.h [new file with mode: 0644]
tools/podofouncompress/podofouncompress.cpp [new file with mode: 0644]
tools/podofoxmp/CMakeLists.txt [new file with mode: 0644]
tools/podofoxmp/podofoxmp.cpp [new file with mode: 0644]
vcincludes/unistd.h [new file with mode: 0644]

diff --git a/.editorconfig b/.editorconfig
new file mode 100644 (file)
index 0000000..949c8d8
--- /dev/null
@@ -0,0 +1,11 @@
+[*.{cpp,h,hpp}]
+end_of_line = lf
+charset = utf-8
+indent_style = space
+indent_size = 4
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.txt]
+end_of_line = lf
+charset = utf-8
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..48f9150
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,8 @@
+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>
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c42b590
--- /dev/null
@@ -0,0 +1,579 @@
+CMAKE_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 "7" 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(CheckCXXSourceCompiles)
+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
+if(POLICY CMP0033)
+CMAKE_POLICY(SET CMP0033 NEW) # https://cmake.org/cmake/help/v3.0/policy/CMP0033.html
+endif()
+
+# 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}")
+
+CHECK_CXX_SOURCE_COMPILES("#include <memory>
+                       class Cls {
+                       public:
+                       Cls() {}
+                       ~Cls() {}
+                       };
+                       int main(void) { std::unique_ptr<Cls> cls; return 0; }" PODOFO_HAVE_UNIQUE_PTR)
+
+# 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 <unistd.h>
+    # 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.
+
+    # If the user hasn't specifically said whether they want
+    # -fvisibility=hidden or not, turn it on if it's said to
+    # be supported, off for other gcc versions.
+    IF(NOT DEFINED PODOFO_USE_VISIBILITY)
+        SET(PODOFO_USE_VISIBILITY ${PODOFO_HAVE_GCC_SYMBOL_VISIBILITY})
+    ENDIF(NOT DEFINED PODOFO_USE_VISIBILITY)
+
+    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+
+    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Woverloaded-virtual -Wswitch -Wcast-qual -Wwrite-strings -Wredundant-decls -Wreorder -Wno-deprecated-declarations")
+
+    #
+    # 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")
+  SET(PNG_LIBRARIES "")
+ENDIF(PNG_FOUND)
+
+FIND_PACKAGE(UNISTRING)
+
+IF(UNISTRING_FOUND)
+  MESSAGE("Found LibUnistring headers in ${UNISTRING_INCLUDE_DIR}, library at ${UNISTRING_LIBRARY}")
+  SET(PODOFO_HAVE_UNISTRING_LIB TRUE)
+  INCLUDE_DIRECTORIES(${UNISTRING_INCLUDE_DIR})
+ELSE(UNISTRING_FOUND)
+  MESSAGE("LibUnistring not found. Unistring support will be disabled")
+  SET(UNISTRING_LIBRARY "")
+ENDIF(UNISTRING_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}/src   # 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/podofo
+    ${FREETYPE_INCLUDE_DIR}
+    ${ZLIB_INCLUDE_DIR}
+    ${EXTRA_INCLUDES}
+     )
+LINK_DIRECTORIES(
+    ${PoDoFo_BINARY_DIR}/src/podofo
+    )
+
+#
+# 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}
+  ${OPENSSL_LIBRARIES}
+  ${LIBJPEG_LIBRARIES}
+  ${PLATFORM_SYSTEM_LIBRARIES}
+  ${stlport_libraries_if_use_stlport}
+  ${FREETYPE_LIBRARIES}
+  ${PNG_LIBRARIES}
+  ${TIFF_LIBRARIES}
+  ${UNISTRING_LIBRARY}
+  )
+
+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)
+
+IF(WIN32 OR PODOFO_BUILD_STATIC)
+  SET(PODOFO_LIB
+      podofo
+      ${PODOFO_LIB_DEPENDS}
+      )
+ELSE(WIN32 OR PODOFO_BUILD_STATIC)
+  SET(PODOFO_LIB podofo
+      ${stlport_libraries_if_use_stlport}
+      )
+ENDIF(WIN32 OR PODOFO_BUILD_STATIC)
+
+#
+# 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/podofo)
+IF(NOT PODOFO_BUILD_LIB_ONLY)
+ADD_SUBDIRECTORY(test)
+ADD_SUBDIRECTORY(tools)
+ADD_SUBDIRECTORY(examples)
+ADD_SUBDIRECTORY(man)
+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)
+
diff --git a/CODINGSTYLE.txt b/CODINGSTYLE.txt
new file mode 100644 (file)
index 0000000..59901f3
--- /dev/null
@@ -0,0 +1,333 @@
+This 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 <domseichter@web.de> 
+
+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. <windows.h> 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. 
diff --git a/CONTRIBUTIONS.txt b/CONTRIBUTIONS.txt
new file mode 100644 (file)
index 0000000..6266c24
--- /dev/null
@@ -0,0 +1,75 @@
+This document describes how to contribute code to PoDoFo.
+
+     2010 Dominik Seichter <domseichter@web.de>
+
+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
+<podofo-users@lists.sourceforge.net>. 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
+<podofo-svn@lists.sourceforge.net>. 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.
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..5b6e7c6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+                   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.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 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.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/COPYING.LIB b/COPYING.LIB
new file mode 100644 (file)
index 0000000..e38ffa8
--- /dev/null
@@ -0,0 +1,481 @@
+                 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.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+          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!
diff --git a/COPYING.exception b/COPYING.exception
new file mode 100644 (file)
index 0000000..d219f7f
--- /dev/null
@@ -0,0 +1,13 @@
+
+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.                       
\ No newline at end of file
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..f3e8922
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,162 @@
+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;
+       
diff --git a/Doxyfile b/Doxyfile
new file mode 100644 (file)
index 0000000..6f0a1d4
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,1642 @@
+# 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.6
+
+# 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 <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> 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 <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> 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
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+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
diff --git a/FAQ.html b/FAQ.html
new file mode 100644 (file)
index 0000000..ee0d1e9
--- /dev/null
+++ b/FAQ.html
@@ -0,0 +1,266 @@
+<!DOCTYPE html 
+     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+       <title>PoDoFo FAQ</title>
+
+       <style type="text/css">
+       h1 {
+               font-size: 140%;
+       }
+       h2 {
+               font-variant: small-caps;
+               font-size: 120%;
+               padding-left: 0.5em;
+       }
+       ul p {
+               font-variant: small-caps;
+               font-weight: bold;
+       }
+       .question {
+               font-style: italic;
+               padding-left: 1.5em;
+               font-size: 110%;
+               font-weight: bold;
+       }
+       .answer {
+               padding-left: 1.5em;
+       }
+       </style>
+</head>
+<body>
+       <h1>PoDoFo FAQ</h1>
+
+       <ul>
+               <p><a href="#s_general">General</a></p>
+               <ul>
+                       <li><a href="#q_platforms">What platforms are supported by PoDoFo?</a></li>
+                       <li><a href="#commercial">Can I use PoDoFo in my commercial application?</a></li>
+                       <li><a href="#q_language">What language is PoDoFo written in?</a></li>
+                       <li><a href="#q_stability">Does PoDoFo offer a stable API or ABI?</a></li>
+                       <li><a href="#q_mailinglists">Does PoDoFo have a mailing list?</a></li>
+                       <li><a href="#q_contact">My question isn't answered here. Where do I go next?</a></li>
+               </ul>
+               <p><a href="#s_otherlang">Other Programming Languages</a></p>
+               <ul>
+                       <li><a href="#q_c">My program is written in C. Can I use PoDoFo?</a></li>
+                       <li><a href="#q_cwrap">Is there a C wrapper for PoDoFo?</a></li>
+                       <li><a href="#q_java">I'm a Java developer. Can I use PoDoFo?</a></li>
+                       <li><a href="#q_otherlang">Are any other languages supported?</a></li>
+               </ul>
+               <p><a href="#s_troubleshooting">Troubleshooting</a></p>
+               <ul>
+                       <li><a href="#q_stdterminate">Sometimes my program crashes in a call to PoDoFo
+       and produces a traceback including a call to
+       <code>std::terminate()</code>. Why?</a></li>
+                       <li><a href="#q_sigabrt">Why does my program crash with a SIGABRT (Signal #6) in a call to PoDoFo?</a></li>
+                       <li><a href="#q_setlocale">PoDoFo creates invalid PDF files because <b>,</b> is used in floats instead of <b>.</b> Why?</a></li>
+
+               </ul>
+       </ul>
+
+       <a name="s_general"><h2>General</h2></a>
+
+       <a name="q_platforms"><p class="question">What platforms are supported by PoDoFo?</p></a>
+       <p class="answer">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.</p>
+
+       <a name="q_commercial"><p class="question">Can I use PoDoFo in my commercial application?</p></a>
+       <div class="answer">
+               <p>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.</p>
+
+               <p>The PoDoFo developers would be happy if you would credit
+               them for using PoDoFo in your application, though this is not a
+               license obligation.</p>
+       </div>
+
+       <a name="q_language"><p class="question">What language is PoDoFo written in?</p></a>
+       <p class="answer">PoDoFo is written entirely in C++. If you're interested in using it from other languages, see the
+       <a href="#s_otherlang">section on those below</a>.</p>
+
+       <a name="q_stability"><p class="question">Does PoDoFo offer a stable API or ABI?</p></a>
+       <div class="answer">
+               <p>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.</p>
+
+               <p>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 <a href="http://svnbook.red-bean.com/en/1.0/ch07s03.html">svn:externals</a> 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.</p>
+
+               <p>The README offers some more information on how to minimise the impact of
+               API changes on your application.</p>
+
+               <p>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.</p>
+       </div>
+
+       <a name="q_mailinglists"><p class="question">Does PoDoFo have a mailing list?</p></a>
+       <p class="answer">Yes. See our <a href="http://podofo.sourceforge.net/support.html">support</a> 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.</p>
+
+       <a name="q_contact"><p class="question">My question isn't answered here. Where do I go next?</p></a>
+       <p class="answer">Your best bet is to email the <a href="http://podofo.sourceforge.net/support.html">podofo-users mailing list</a>.</p>
+
+       <a name="s_otherlang"><h2>Other Programming Languages</h2></a>
+
+       <a name="q_c"><p class="question">My program is written in C. Can I use PoDoFo?</p></a>
+       <div class="answer">
+               <p>PoDoFo can not be used directly from a basic C program, but if you have access to a C++ compiler there are acceptable workarounds.</p>
+
+               <p>The cleanest approach is probably to write your PoDoFo-using
+               code as C++ and have it expose a pure C interface (using
+               <code>extern "C"</code> and the <code>nothrow()</code> 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
+               <code>free()</code>'d in your pure C code (or vice versa).</p>
+
+               <p>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.</p>
+       </div>
+
+       <a name="q_cwrap"><p class="question">Is there a C wrapper for PoDoFo?</p></a>
+       <div class="answer">
+               <p>Not as yet.</p>
+
+               <p>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:</p>
+
+               <ul>
+                       <li>provide factory functions for PoDoFo objects</li>
+                       <li>provide deletion functions for PoDoFo objects</li>
+                       <li>write wrappers for methods that take an instance as
+                       their first argument (also expanding overloaded
+                       methods) and translate thrown exceptions into error
+                       codes.</li>
+               </ul>
+
+               <p>The PoDoFo authors would be interested in hearing about any such effort, but are not working on anything along those lines themselves.</p>
+       </div>
+
+       <a name="q_java"><p class="question">I'm a Java developer. Can I use PoDoFo?</p></a>
+       <p class="answer">Not with Java, no, though we don't discriminate if
+       you've used it but want to move to another language ;-)&nbsp;. 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 <a href="http://itextpdf.com/">iText</a>.</p>
+
+       <a name="q_dotnet"><p class="question">I'm a C# or other .NET developer. Can I use PoDoFo?</p></a>
+       <p class="answer">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.</p>
+
+       <a name="q_otherlang"><p class="question">Are any other languages supported?</p></a>
+       <p class="answer">No. Python bindings would be a fun <a href="http://www.boost.org/libs/python/doc/">Boost.Python</a> project, though.</p>
+
+       <a name="s_troubleshooting"><h2>Troubleshooting</h2></a>
+
+       <a name="q_stdterminate"><p class="question">Sometimes my program crashes in a call to PoDoFo
+       and produces a traceback including a call to
+       <code>std::terminate()</code>. Why?</p></a>
+       <div class="answer">
+               <p>If you're seeing a traceback including a call to <code>std::terminate()</code>, 
+               like the (simplified) one shown below, the problem is probably that you're
+               not catching an exception being thrown by PoDoFo.</p>
+
+                       <code>
+                       raise()<br/>
+                       abort()<br/>
+                       std::set_unexpected()<br/>
+                       <b>std::terminate</b>()<br/>
+                       PoDoFo::SomePoDoFoMethod()<br/>
+                       main()<br/>
+                       </code>
+
+               <p>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.</p>
+
+               <p>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 <code>std::terminate()</code> for you. This
+               in turn will call <code>abort()</code>. On Linux, a
+               <code>SIGABRT</code> (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.</p>
+       </div>
+
+       <a name="q_sigabrt"><p class="question">Why does my program crash with a SIGABRT (Signal #6) in a call to PoDoFo?</p></a>
+       <p class="answer">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).</p>
+
+       <a name="q_unusual_terminate"><p class="question">Why does my program exit with the message "Application has requested runtime to terminate it in an unusual way" ? </p>
+       <p class="answer">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 <a href="http://sourceforge.net/project/showfiles.php?group_id=2435">this page under "GNU Source Level Debugger"</a>, then run <code>gdb --args myprogram.exe</code>. 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 <code>std::terminate</code>.</p>
+
+
+       <a name="q_setlocale"><p class="question">PoDoFo creates invalid PDF
+       files because <b>,</b> is used in floats instead of <b>.</b> Why?</p></a>
+       <p class="answer">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 <b>.</b> (point) as a separator.
+       Some languages like German use a <b>,</b> (comma) instead.<br/>
+       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.</p>
+
+       <a name="q_testsuites"><p class="question">Where can I get test PDF files?</p>
+       <p class="answer">
+               <ul>
+               <li>Misc. PDF test files
+                       <ul>
+                       <li><a href="http://www.novapdf.com/kb/pdf-example-files-created-with-novapdf-138.html">Example PDF files from novapdf.com</a>&nbsp;
+They are for encryption, font subsetting and several other PDF features.
+This link doesn't mean any recommendation.</li>
+                       </ul>
+               </li>
+               <li>Colour and ICC:
+                       <ul>
+                       <li><a href="http://www.eci.org/doku.php?id=en:downloads#altona_test_suite">Altona test suite</a></li>
+                       <li><a href="http://www.gwg.org/download/test-suites/ghent-output-suite/">Ghent Output Suite (version 4.0)</a></li>
+                       </ul>
+               </li>
+               </ul>
+       </p>
+
+</body>
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..6b87bcd
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1 @@
+Please see the file README for instruction on howto install PoDoFo on your system.
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/README.html b/README.html
new file mode 100644 (file)
index 0000000..92dccbb
--- /dev/null
@@ -0,0 +1,731 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<title>PoDoFo Readme</title>
+</head>
+<body>
+
+<h1>PoDoFo</h1>
+
+<ol>
+       <li><a href="#what_is_podofo">What is PoDoFo?</a></li>
+       <li><a href="#where_can_i_get_it">Where can I can get it?</a></li>
+       <li><a href="#requirements">Requirements</a></li>
+       <li><a href="#installation">Installation</a>
+       <ol>
+               <li><a href="#stlport_support">STLPort support</a>
+               <li><a href="#boost_support">Boost support</a>
+               <li><a href="#installation_with_cmake">Installation with CMake</a>
+               <ol>
+                       <li><a href="#cmake_builds_on_linux_unix">CMake builds on Linux/UNIX</a></li>
+                       <li><a href="#cmake_builds_on_mac_os_x">CMake builds on Mac OS X</a></li>
+                       <li><a href="#homebrew_builds_on_macos">Homebrew builds on Mac OS X</a></li>
+                       <li><a href="#cmake_builds_on_windows">CMake builds on Windows</a></li>
+               </ol>
+               </li>
+       </ol>
+       </li>
+       <li><a href="#using_podofo_in_your_application">Using PoDoFo in Your Application</a></li>
+       <li><a href="#preprocessor">Preprocessor defines used in PoDoFo</a></li>
+       <li><a href="#structure">Structure of the library</a></li>
+       <li><a href="#contact">Contact</a></li>
+       <li><a href="#licensing">Licensing</a></li>
+</ol>
+
+<h2><a name="what_is_podofo" />What is PoDoFo?</h2>
+
+<p>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 (<b>Po</b>rtable <b>Do</b>cument
+<b>Fo</b>rmat).</p>
+
+<p>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.</p>
+
+<p>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.</p>
+
+<p>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.</p>
+
+<p>See:</p>
+
+<ul>
+<li><a href="http://cairographics.org/">http://cairographics.org/</a></li>
+<li><a href="http://poppler.freedesktop.org/">http://poppler.freedesktop.org/</a></li>
+</ul>
+
+<p>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:</p>
+
+<ul>
+  <li><b>podofoencrypt</b> -
+    Encrypts any PDF and allows to set PDF permissions..</li>
+
+  <li><b>podofoimgextract</b> -
+    Extracts all images from a given PDF file.</li>
+
+  <li><b>podofoimpose</b> -
+    A powerful
+    PDF <a href="http://en.wikipedia.org/wiki/Imposition">imposition</a>
+    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.</li>
+
+  <li><b>podofomerge</b> -
+    Merges two PDF files into onw.</li>
+
+  <li><b>podofopdfinfo</b> -
+  Provides some basic info about a PDF - metadata, page details, etc.</li>
+
+  <li><b>podofotxt2pdf</b> -
+  Converts a text file to a PDF</li>
+
+  <li><b>podofotxtextract</b> -
+  A tool that extracts all text from a PDF file. Works only for simple PDFs
+  at the moment.</li>
+
+  <li><b>podofouncompress</b> -
+  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.</li>
+</ul>
+
+<p>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.</p>
+
+<p>As of version 0.7 PoDoFo is available for Unix, Mac
+OS X and Windows platforms.</p>
+
+<h2><a name="where_can_i_get_it" />Where can I can get it?</h2>
+
+<p>PoDoFo is available on the internet: <a href="http://podofo.sf.net">podofo.sf.net</a></p>
+
+<h2><a name="requirements" />Requirements</h2>
+
+<p>To build PoDoFo lib you need a working toolchain and a c++ compiler as well as
+the following libraries:</p>
+
+<ul>
+<li>zlib</li>
+<li>freetype2</li>
+<li>fontconfig (Unix & Mac OS X only)</li>
+<li>libjpeg (optional)</li>
+<li>libtiff (optional)</li>
+<li>libidn (optional)</li>
+<li>libCrypto++ (optional)</li>
+</ul>
+
+<p>See <a href="#installation_with_cmake">Installation with CMake</a> for a
+list of tested platforms and compilers. In general, any reasonably well behaved
+C++ compiler should work.</p>
+
+<p>A list of known -dev / -devel packages required for various Linux distros is maintained
+in the <a href="#required_linux_packages">required Linux packages</a> appendix.</p>
+
+<p>See also <a href="#using_podofo">Using PoDoFo</a>.</p>
+
+<h2><a name="installation">Installation</a></h2>
+
+<p>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.</p>
+
+<p>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.</p>
+
+<p>Unix users should generate Unix Makefiles with CMake, though it's also possible
+to produce a KDevelop project. See <a href="#cmake_builds_on_linux_unix">CMake builds on Linux/UNIX</a></p>
+
+<p>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 <a href="#cmake_builds_on_windows">CMake builds on Windows</a></p>
+
+<p>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 <a href="#cmake_builds_on_mac_os_x">Mac OS X
+       section</a> below, and the <a href="#installation_with_cmake">generic instructions for cmake builds</a></p>
+
+
+<h3><a name="stlport_support" />STLPort support</h3>
+
+<p>Don't know what STLPort is? Ignore it and skip this section. Packagers should
+not enable STLPort.</p>
+
+<p>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.</p>
+
+<p>It is unnecessary and unwise to build PoDoFo against STLPort on any current
+major platform unless you have a specific reason to do so.</p>
+
+<h3><a name="boost_support" />Boost support</h3>
+
+<p>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.</p>
+
+<p>Packagers should not currently build PoDoFo with boost support.</p>
+
+<h3><a name="installation_with_cmake" />Installation with CMake</h3>
+
+<P>PoDoFo has support for builds using CMake on all supported
+platforms. The CMake build has been tested on:</p>
+
+<ul>
+<li>Visual C++ 9 Express Edition [Win32] ("Visual Studio 9 2008" target)</li>
+<li>Visual C++ 8 Express Edition [Win32] ("Visual Studio 8 2005" target) (needs additional setup)</li>
+<li>Visual C++ 8 Express +NMake [Win32] ("NMake Makefiles" target) (needs additional setup)</li>
+<li>MinGW with GCC 3.4.2 [Win32] ("MinGW Makefiles" target)</li>
+<li>gcc 3.3.5 [Linux: Debian 3.1] ("Unix Makefiles" target)</li>
+<li>gcc 4.0, 4.1, 4.2 [Linux: Debian 4.0] ("Unix Makefiles" target)</li>
+<li>gcc 4.0 [Mac OS X 10.4.10] ("Unix Makefiles" target)</li>
+</ul>
+
+<p>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.</p>
+
+<p>You can use the CMake variable <code>CMAKE_BUILD_TYPE</code> to control the type of
+build. The main values supported are <code>DEBUG</code> and <code>RELEASE</code>. The default is
+DEBUG. Set the build type with the CMake argument:<br/>
+&nbsp;&nbsp;<code>-DCMAKE_BUILD_TYPE=DEBUG</code><br/>
+&nbsp;&nbsp;&nbsp;or<br/>
+&nbsp;&nbsp;<code>-DCMAKE_BUILD_TYPE=RELEASE</code><br/>
+as appropriate.</p>
+
+<p>You can control where the files are installed with `make install' with
+       <code>-DCMAKE_INSTALL_PREFIX=/path/to/install/dir</code></p>
+
+<p>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.</p>
+
+<p>On all Makefile-style builds, set the <code>VERBOSE</code> flag to 1 on the make command
+line to see all compiler commands etc, eg: <code>make VERBOSE=1</code></p>
+
+<h4><a name="cmake_builds_on_linux_unix"/>CMake builds on Linux/UNIX</h4>
+
+<p>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.</p>
+
+<p>To build and install:</p>
+
+<pre>
+mkdir ../podofo-build
+cd ../podofo-build
+cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="$HOME/podofo" ../podofo-src
+make
+make install
+</pre>
+
+<p>To see detailed compiler output, use:</p>
+
+<pre>
+make VERBOSE=1
+</pre>
+
+<p>If you're working on a 64 bit linux that has a /usr/lib64 directory, add
+<code>-DWANT_LIB64:BOOL=TRUE</code> to the CMake command line.</p>
+
+<p>If you need to specify additional paths to search for libraries, set the
+<code>CMAKE_INCLUDE_PATH</code> and <code>CMAKE_LIBRARY_PATH</code> environment variables or set them on
+the command line:</p>
+
+<pre>
+cmake -G "Unix Makefiles" ../podofo-src \
+       -DCMAKE_INCLUDE_PATH=/usr/sfw/include \
+       -DCMAKE_LIBRARY_PATH=/usr/sfw/lib
+</pre>
+
+<p>If you wish to generate only a static library or only a shared library, set the
+<code>PODOFO_BUILD_SHARED</code> and/or <code>PODOFO_BUILD_STATIC</code> flags:</p>
+
+<pre>
+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
+</pre>
+
+<p>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
+<code>-DPODOFO_BUILD_STATIC:BOOL=TRUE</code>, or upgrade to CMake 2.6.x .</p>
+
+<p>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.</p>
+
+<p>If your system has gcc 4, PoDoFo will tell gcc to make symbols hidden by
+default using the <code>-fvisibility=hidden</code> flag to gcc. Only symbols explicitly
+exported by PoDoFo will be exported. You can explicitly enable or disable this
+behaviour with the boolean flag:
+    <code>-DPODOFO_USE_VISIBILITY=1</code> (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.</p>
+
+<h4><a name="cmake_builds_on_mac_os_x"/>CMake builds on Mac OS X</h4>
+
+<p>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.</p>
+
+<p>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
+<code>CMAKE_INCLUDE_PATH</code> and <code>CMAKE_LIBRARY_PATH</code> arguments appropriately.</p>
+
+<h5>Dependencies</h5>
+
+<p>I'll assume you're installing podofo and any required libraries into $HOME/libs
+. Adjust to taste, but keep it consistent.</p>
+
+<p>The easiest way to get any required libraries is to use <a href="http://macports.org/">MacPorts</a>
+to install the libjpeg, fontconfig, and freetype libraries. Once you've installed MacPorts, just run:</p>
+
+<pre>
+/opt/local/bin/port install fontconfig freetype jpeg tiff lua
+</pre>
+
+<p>MacPorts will automatically build the libraries and their dependencies, installing them in /opt/local.</p>
+
+<p>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.</p>
+
+<h5>PoDoFo its self</h5>
+
+<p>You should be able to configure and install podofo on Mac OS X using:</p>
+<pre>
+       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
+</pre>
+
+<p>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</p>
+
+<h4><a name="homebrew_builds_on_macos" />Homebrew builds on Mac OS X</h4>
+
+<p>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.
+<pre>
+brew install fontconfig
+brew install libjpeg
+brew install libtiff
+cd ((directory of podofo))
+cmake -G "Unix Makefiles"
+make
+make install
+</pre>
+</p>
+
+<h4><a name="cmake_builds_on_windows" />CMake builds on Windows</h4>
+
+<h5><a name="windows_dependencies"/>Windows Dependencies</h5>
+
+<p>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.</p>
+
+<h6><a name="windows_dependency_zlib">zlib</h6>
+
+<p>Both MinGW and Visual Studio users should use the standard precompiled zlib dll from <a href="http://zlib.org">zlib.org</a>. There is no need to compile your own.</p>
+
+<p>Remember that you must ship <code>zlib1.dll</code> 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.</p>
+
+<h6><a name="windows_dependency_libjpeg"/>libjpeg</h6>
+
+<p>MinGW users can download the latest libjpeg installer from <a href="http://gnuwin32.sf.net">GnuWin32</a></p>.
+
+<p>For Visual Studio you will need to build libjpeg with your version of Visual Studio. Download the libjpeg sources from <a href="http://www.ijg.org/">http://www.ijg.org/</a> and unpack them into a working directory. I'll assume you've used <code>C:\Developer\jpeg</code>. Once the sources are unpacked, start a visual studio command prompt and cd into <code>c:\developer\jpeg</code> then run <code>copy jconfig.vc jconfig.h</code> then <code>nmake /f makefile.vc /a</code></p>.
+
+<p>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.</p>
+
+<h5><a name="windows_podofo"/>Building PoDoFo on Windows</h5>
+
+<p>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.</p>
+
+<p>CMake 2.6.x is required for Windows. You can download it from
+ <a href="http://www.cmake.org/HTML/Download.html">cmake.org</a></p>.
+
+<p>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.</p>
+
+<p>On Windows, if you are linking against a shared (DLL) build of PoDoFo you
+MUST define the preprocessor macro <code>USING_SHARED_PODOFO</code> 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.</p>
+
+<p>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:</p>
+
+<pre>
+       -DPODOFO_BUILD_SHARED=FALSE
+</pre>
+
+<p>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.</p>
+
+<p>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 <code>-DJPEG_COMPATIBLE_RUNTIME</code> to CMake to tell
+PoDoFo it's safe not to use its' workarounds for incompatible runtimes.</p>
+
+<h5><a name="handling_library_naming_on_win32" />Handling library naming on win32</h5>
+
+<p>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:</p>
+
+<ul>
+       <li>FREETYPE_LIBRARY_NAMES_DEBUG, FREETYPE_LIBRARY_NAMES_RELEASE and FREETYPE_LIBRARY_NAMES</li>
+       <li>TIFF_LIBRARY_NAMES_DEBUG, TIFF_LIBRARY_NAMES_RELEASE and TIFF_LIBRARY_NAMES</li>
+       <li>LIBJPEG_LIBRARY_NAMES_DEBUG, LIBJPEG_LIBRARY_NAMES_RELEASE and LIBJPEG_LIBRARY_NAMES</li>
+       <li>ZLIB_LIBRARY_NAMES_DEBUG, ZLIB_LIBRARY_NAMES_RELEASE, ZLIB_LIBRARY_NAMES</li>
+</ul>
+
+<p>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.</p>
+
+<h5><a name="cmake_builds_on_windows_with_mingw" />CMake builds on Windows with MinGW</h5>
+
+<p>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.</p>
+
+<p>Once MinGW is set up, make sure that the MinGW "bin" directory is on your PATH, and be sure to set
+<code>CMAKE_INCLUDE_PATH</code> and <code>CMAKE_LIBRARY_PATH</code> such that
+CMake can find the headers and .lib files for the libraries PoDoFo requires.
+The GnuWin32 library packages from <a
+       href="http://gnuwin32.sf.net">http://gnuwin32.sf.net/</a> are known to
+work with PoDoFo, so installing zlib, freetype, and libjpeg from there should do the trick.</p>
+
+<p>To configure and build PoDoFo with a default GnuWin32 install and with MinGW already on your PATH:</p>
+
+<pre>
+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
+</pre>
+
+<p>It is extremely strongly recommended that you build PoDoFo only as a static
+library if you are using MinGW by setting the
+<code>-DPODOFO_BUILD_SHARED:BOOL=FALSE</code> 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
+<code>std::string</code> 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.</p>
+
+<h5><a name="cmake_builds_on_windows_with_visual_studio" />CMake builds on Windows with Visual Studio</h5>
+
+<p>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.</p>
+
+<p>You'll also need CMake 2.6.</p>
+
+<p>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 <a href="http://download.savannah.gnu.org/releases/freetype/">http://download.savannah.gnu.org/releases/freetype/</a>
+- 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 <code>freetype239MT.lib</code> and
+<code>freetype239MT_D.lib</code> and are found in <code>objs\win32\vc2008</code>, so adjust if yours are different.</p>
+
+<p>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.</p>
+
+<p>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 <code>build.cmd</code> file for the CMake command since on Windows it
+tends to get rather long. Here's an example that assumes the
+<code>build.cmd</code> file is in an empty directory with
+<code>..\podofo-src</code> being the relative path to the PoDoFo sources.</p>
+
+<pre>
+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
+</pre>
+
+<p>Run the saved <code>build.cmd</code> from a cmd.exe window. If all goes well, you can open and build the generated <code>podofo.sln</code> in Visual Studio and build it.</p>
+
+<p>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.</p>
+
+<p>You can download the free Visual C++ Express Edition 9 from <a href="http://www.microsoft.com/express/">Microsoft</a>.</p>
+
+<b>PROBLEMS?</b>
+
+<p>If you have problems, try deleting your build directory then re-running
+the commands above after running:</p>
+
+<pre>
+set PATH=%SystemRoot%;%SystemRoot%\SYSTEM32
+</pre>
+
+<p>in the <code>cmd.exe</code> window you are using. If you do this you'll have
+to copy <code>jpeg62.dll</code>, <code>freetype6.dll</code>, and
+<code>zlib.dll</code> (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.</p>
+
+<h5><a name="cmake_builds_on_windows_with_nmake" />CMake builds on Windows with NMake</h5>
+
+<p>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.</p>
+
+<p>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.</p>
+
+<h2><a name="using_podofo_in_your_application" />Using PoDoFo in Your Application</a></h2>
+
+<p>A simple example that uses PoDoFo can be found in <code>examples/helloworld</code> . You
+will also find the tests and tools shipped with PoDoFo informative when
+learning to use the library. Reading the documentation on <code>PdfMemDocument</code>,
+<code>PdfStreamedDocument</code>, <code>PdfObject</code> and <code>PdfVariant</code> may also be useful.</p>
+
+<h3><a name="unstable_api" />UNSTABLE API (IMPORTANT)</a></h3>
+
+<p>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, <code>PdfDocument</code>
+changed from being a concrete class to an abstract parent of <code>PdfMemDocument</code> and
+<code>PdfStreamedDocument</code>, thus breaking code that instantiates <code>PdfDocument</code> .</p>
+
+<p>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.</p>
+
+<p>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.</p>
+
+<p>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.</p>
+
+<p>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.</p>
+
+<h3><a name="compiling_and_linking_against_podofo"/>Compiling and Linking Against PoDoFo</h3>
+
+<p>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:</p>
+
+<pre>
+    -lpodofo -lfreetype -lfontconfig -ljpeg -lz
+</pre>
+
+<p>is generally appropriate. Win32 users must also ensure that they link to
+<code>gdi32</code> and <code>ws_win32</code>.</p>
+
+<h3>Handling Exceptions</h3>
+
+<p>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&amp; 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.</p>
+
+<p>More general information about exception handling is in the <a href="FAQ.html">FAQ</a>.</p>
+
+<h2><a name="preprocessor">Preprocessor defines used in PoDoFo</h2>
+
+<p>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.</p>
+
+<table>
+  <tr>
+    <td><b>Define</b></td>
+    <td><b>Meaning</b></td>
+  </tr>
+
+  <tr>
+    <td><code>DEBUG</code></td>
+    <td>Indicates a debug build of PoDoFo.</td>
+  </tr>
+  <tr>
+    <td><code>PODOFO_EXTRA_CHECKS</code></td>
+    <td>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.
+    </td>
+  </tr>
+  <tr>
+    <td><code>PODOFO_IS_LITTLE_ENDIAN</code></td>
+    <td>This define is set on all little endian
+      system and required on these systems for PoDoFo to work properly.</td>
+  </tr>
+  <tr>
+    <td><code>PODOFO_IS_BIG_ENDIAN</code></td>
+    <td>This define is set on all big endian
+      system and required on these systems for PoDoFo to work properly.</td>
+  </tr>
+  <tr>
+    <td><code>PODOFO_MULTI_THREAD</code></td>
+    <td>Will compile PoDoFo with threading support, e.g. mutex that lock
+      global variables.</td>
+  </tr>
+  <tr>
+    <td><code>PODOFO_VERBOSE_DEBUG</code></td>
+    <td>This will cause PoDoFo to write even more debug output to the commandline.</td>
+  </tr>
+  <tr>
+    <td><code>HAVE_BOOST</code></td>
+    <td>If defined PoDoFo is compiled with Boost support.</td>
+  </tr>
+  <tr>
+    <td><code>PODOFO_HAVE_JPEG_LIB</code></td>
+    <td>If defined PoDoFo will use libJpeg to read and decode JPEG images.</td>
+  </tr>
+  <tr>
+    <td><code>PODOFO_HAVE_TIFF_LIB</code></td>
+    <td>If defined PoDoFo will use libTiff to read and decode TIFF images.</td>
+  </tr>
+  <tr>
+    <td><code>PODOFO_HAVE_LUA</code></td>
+    <td>If defined PoDoFoImpose will be built with Lua support for plan files.</td>
+  </tr>
+</table>
+
+<h2><a name="structure" />Structure of the library</h2>
+
+<p>PoDoFo is structured into two libraries <b>podofo-base</b>
+  and <b>podofo-doc</b>, where most users want to use <b>podofo-doc</b> which
+  includes all the PoDoFo features and dependends on the <b>podofo-base</b>
+  library. 
+</p>
+
+<p>
+If you only need basic PDF editing features and are not afraid of working with
+the object in a PDF file directly (see PdfObject), <b>podofo-base</b> is the
+right choice for you. It has only a few dependencies (zlib and libjpeg for
+compression). Contrary, <b>podofo-doc</b> 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.
+</p>
+<p align="center">
+<img src="doc/podofo_architecture.png" alt="Architecture" />
+</p>
+
+<h2><a name="contact" />Contact</a></h2>
+
+<p>If you have questions on PoDoFo or bug reports, feature requests you can email
+our mailinglist &lt;podofo-users@lists.sf.net&gt;. Sign up details are available
+on <a href="http://podofo.sourceforge.net/support.html#mail">the podofo support page</a>.</p>
+
+<h2><a name="licensing" />Licensing</h2>
+
+<p>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.</p>
+
+<h2>Appendices</h2>
+
+<h3><a name="required_linux_packages">Required Linux Packages</a></h3>
+
+<p>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.</p>
+
+<ul>
+<li>Ubuntu (also generally applies to recent Debian)
+    <ul>
+    <li>8.10 and most others: sudo aptitude install build-essential g++ cmake libz-dev libtiff-dev libjpeg-dev libfreetype6-dev libfontconfig-dev</li>
+    </ul>
+</li>
+</ul>
+
+</body>
+</html>
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..28249da
--- /dev/null
+++ b/TODO
@@ -0,0 +1,35 @@
+PoDoFo 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.
diff --git a/cmake/modules/FindBoost.cmake b/cmake/modules/FindBoost.cmake
new file mode 100644 (file)
index 0000000..f50a5fb
--- /dev/null
@@ -0,0 +1,156 @@
+# - 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 <Your Path>
+# points to the root directory of the include directory of Boost. e.g
+# If you have put boost in C:\development\Boost then <Your Path> 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 <Your Path>/include/boost<-version>
+# 2) Use CMAKE_INCLUDE_PATH to set a path to <Your Path>/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} "<Your Path>/include")
+# 3) Set an environment variable called ${BOOST_ROOT} that points to the root of where you have
+#    installed Boost, e.g. <Your Path>. 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)
diff --git a/cmake/modules/FindCppUnit.cmake b/cmake/modules/FindCppUnit.cmake
new file mode 100644 (file)
index 0000000..adaaeb6
--- /dev/null
@@ -0,0 +1,69 @@
+# - 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)
diff --git a/cmake/modules/FindFONTCONFIG.cmake b/cmake/modules/FindFONTCONFIG.cmake
new file mode 100644 (file)
index 0000000..66273e6
--- /dev/null
@@ -0,0 +1,45 @@
+# - 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, <montel@kde.org>
+#
+# 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)
diff --git a/cmake/modules/FindFREETYPE.cmake b/cmake/modules/FindFREETYPE.cmake
new file mode 100644 (file)
index 0000000..4111479
--- /dev/null
@@ -0,0 +1,107 @@
+#\r
+# Find the native FREETYPE includes and library\r
+#\r
+\r
+# This module defines\r
+# FREETYPE_INCLUDE_DIR, where to find ft2build.h, ftheader.h, ...\r
+# FREETYPE_LIBRARIES, the libraries to link against to use FREETYPE.\r
+# FREETYPE_FOUND, If false, do not try to use FREETYPE.\r
+\r
+# also defined, but not for general use are\r
+# FREETYPE_LIBRARY, where to find the FREETYPE library.\r
+\r
+SET(FREETYPE_FIND_QUIETLY 1)\r
+\r
+# first we try to find ft2build.h in the new location as\r
+# of freetype 2.5.1\r
+FIND_PATH(FREETYPE_INCLUDE_DIR_FT2BUILD ft2build.h\r
+  /usr/include/freetype2\r
+  /usr/local/include/freetype2\r
+  /usr/X11/include/freetype2\r
+  NO_CMAKE_SYSTEM_PATH\r
+)\r
+\r
+# in case we couldn't find it in the new location\r
+# we check the old location\r
+IF (NOT FREETYPE_INCLUDE_DIR_FT2BUILD)\r
+  FIND_PATH(FREETYPE_INCLUDE_DIR_FT2BUILD ft2build.h\r
+    /usr/include\r
+    /usr/local/include\r
+    /usr/X11/include\r
+    NO_CMAKE_SYSTEM_PATH\r
+  )\r
+ENDIF (NOT FREETYPE_INCLUDE_DIR_FT2BUILD)\r
+\r
+# now try to find ftheader.h in the new location first\r
+FIND_PATH(FREETYPE_INCLUDE_DIR_FTHEADER config/ftheader.h\r
+  /usr/include/freetype2\r
+  /usr/local/include/freetype2\r
+  /usr/X11/include/freetype2\r
+  ${FREETYPE_INCLUDE_DIR_FT2BUILD}\r
+  NO_CMAKE_SYSTEM_PATH\r
+)\r
+\r
+# in case we couldn't find it in the new location\r
+# we check the old location\r
+IF (NOT FREETYPE_INCLUDE_DIR_FTHEADER)\r
+  FIND_PATH(FREETYPE_INCLUDE_DIR_FTHEADER freetype/config/ftheader.h\r
+    /usr/include/freetype2\r
+    /usr/local/include/freetype2\r
+    /usr/X11/include/freetype2\r
+    ${FREETYPE_INCLUDE_DIR_FT2BUILD}\r
+    ${FREETYPE_INCLUDE_DIR_FT2BUILD}/freetype2\r
+    NO_CMAKE_SYSTEM_PATH\r
+  )\r
+ENDIF (NOT FREETYPE_INCLUDE_DIR_FTHEADER)\r
+\r
+IF ( FREETYPE_INCLUDE_DIR_FTHEADER AND FREETYPE_INCLUDE_DIR_FT2BUILD )\r
+       SET(FREETYPE_INCLUDE_DIR\r
+               ${FREETYPE_INCLUDE_DIR_FTHEADER}\r
+               ${FREETYPE_INCLUDE_DIR_FT2BUILD})\r
+ENDIF ( FREETYPE_INCLUDE_DIR_FTHEADER AND FREETYPE_INCLUDE_DIR_FT2BUILD )\r
+\r
+LIST(REMOVE_DUPLICATES FREETYPE_INCLUDE_DIR)\r
+\r
+IF(NOT FREETYPE_FIND_QUIETLY)\r
+  MESSAGE("FREETYPE_INCLUDE_DIR_FT2BUILD ${FREETYPE_INCLUDE_DIR_FT2BUILD}")\r
+  MESSAGE("FREETYPE_INCLUDE_DIR_FTHEADER ${FREETYPE_INCLUDE_DIR_FTHEADER}")\r
+  MESSAGE("FREETYPE_INCLUDE_DIR ${FREETYPE_INCLUDE_DIR}")\r
+ENDIF(NOT FREETYPE_FIND_QUIETLY)\r
+\r
+SET(FREETYPE_LIBRARY_NAMES_DEBUG ${FREETYPE_LIBRARY_NAMES_DEBUG} freetyped libfreetyped)\r
+SET(FREETYPE_LIBRARY_NAMES_RELEASE ${FREETYPE_LIBRARY_NAMES_RELEASE} freetype libfreetype)\r
+\r
+SET(FREETYPE_LIB_PATHS /usr/lib /usr/local/lib /usr/X11/lib)\r
+\r
+FIND_LIBRARY(FREETYPE_LIBRARY_RELEASE\r
+  ${FREETYPE_LIBRARY_NAMES_RELEASE}\r
+  ${FREETYPE_LIBRARY_NAMES}\r
+  PATHS\r
+  ${FREETYPE_LIB_PATHS}\r
+)\r
+FIND_LIBRARY(FREETYPE_LIBRARY_DEBUG\r
+  ${FREETYPE_LIBRARY_NAMES_DEBUG}\r
+  PATHS\r
+  ${FREETYPE_LIB_PATHS}\r
+)\r
+\r
+INCLUDE(LibraryDebugAndRelease)\r
+SET_LIBRARY_FROM_DEBUG_AND_RELEASE(FREETYPE)\r
+SET(FREETYPE_LIBRARIES ${FREETYPE_LIBRARY})\r
+\r
+IF(NOT FREETYPE_FIND_QUIETLY)\r
+  MESSAGE("FREETYPE_LIBRARY_DEBUG ${FREETYPE_LIBRARY_DEBUG}")\r
+  MESSAGE("FREETYPE_LIBRARY_RELEASE ${FREETYPE_LIBRARY_RELEASE}")\r
+  MESSAGE("FREETYPE_LIBRARY ${FREETYPE_LIBRARY}")\r
+ENDIF(NOT FREETYPE_FIND_QUIETLY)\r
+\r
+# MESSAGE(STATUS "ft lib ${FREETYPE_LIBRARY}")\r
+# MESSAGE(STATUS "ft2 build ${FREETYPE_INCLUDE_DIR_FT2BUILD}")\r
+# MESSAGE(STATUS "ft header ${FREETYPE_INCLUDE_DIR_FTHEADER}")\r
+\r
+INCLUDE(FindPackageHandleStandardArgs)\r
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(FREETYPE DEFAULT_MSG FREETYPE_LIBRARY FREETYPE_INCLUDE_DIR)\r
+\r
+IF (NOT FREETYPE_FIND_QUIETLY)\r
+MESSAGE(STATUS "Found Freetype2: ${FREETYPE_LIBRARY}")\r
+ENDIF (NOT FREETYPE_FIND_QUIETLY)\r
diff --git a/cmake/modules/FindLIBCRYPTO.cmake b/cmake/modules/FindLIBCRYPTO.cmake
new file mode 100644 (file)
index 0000000..7b3ffd4
--- /dev/null
@@ -0,0 +1,88 @@
+# - Find libCrypto\r
+# Find the native OpenSSL LIBCRYPTO includes and library\r
+#\r
+#  LIBCRYPTO_INCLUDE_DIR - where to find sha.h, etc.\r
+#  LIBCRYPTO_LIBRARIES   - List of libraries when using libCrypto.\r
+#  LIBCRYPTO_FOUND       - True if libCrypto found.\r
+\r
+\r
+IF (LIBCRYPTO_INCLUDE_DIR)\r
+  # Already in cache, be silent\r
+  SET(LIBCRYPTO_FIND_QUIETLY TRUE)\r
+ENDIF (LIBCRYPTO_INCLUDE_DIR)\r
+\r
+IF (NOT LIBCRYPTO_INCLUDE_DIR OR NOT LIBCRYPTO_LIBRARIES)\r
+  FIND_PACKAGE(PkgConfig)\r
+\r
+  IF (PKG_CONFIG_FOUND)\r
+    PKG_CHECK_MODULES (LIBCRYPTO libcrypto)\r
+    IF (LIBCRYPTO_FOUND)\r
+      SET (LIBCRYPTO_INCLUDE_DIR ${LIBCRYPTO_INCLUDE_DIRS})\r
+    ENDIF (LIBCRYPTO_FOUND)\r
+  ENDIF (PKG_CONFIG_FOUND)\r
+ENDIF (NOT LIBCRYPTO_INCLUDE_DIR OR NOT LIBCRYPTO_LIBRARIES)\r
+\r
+IF (NOT LIBCRYPTO_INCLUDE_DIR OR NOT LIBCRYPTO_LIBRARIES)\r
+  # Require a regular OpenSSL even on OSX/iOS\r
+  # IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")\r
+  #   # MacOSX has deprecated the use of openssl crypto functions\r
+  #   # and replaced it with API-compatible CommonCrypto\r
+  #   FIND_PATH(LIBCRYPTO_INCLUDE_DIR CommonCrypto/CommonDigest.h)\r
+  #   SET(LIBCRYPTO_LIBRARY_NAMES_RELEASE ${LIBCRYPTO_LIBRARY_NAMES_RELEASE} ${LIBCRYPTO_LIBRARY_NAMES} ssl)\r
+  #   SET(LIBCRYPTO_LIBRARY_NAMES_DEBUG ${LIBCRYPTO_LIBRARY_NAMES_DEBUG} ssld)\r
+  # ELSE(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") \r
+    FIND_PATH(LIBCRYPTO_INCLUDE_DIR openssl/sha.h)\r
+    SET(LIBCRYPTO_LIBRARY_NAMES_RELEASE ${LIBCRYPTO_LIBRARY_NAMES_RELEASE} ${LIBCRYPTO_LIBRARY_NAMES} crypto)\r
+    SET(LIBCRYPTO_LIBRARY_NAMES_DEBUG ${LIBCRYPTO_LIBRARY_NAMES_DEBUG} cryptod)\r
+  # ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") \r
+\r
+  FIND_LIBRARY(LIBCRYPTO_LIBRARY_RELEASE NAMES ${LIBCRYPTO_LIBRARY_NAMES_RELEASE} )\r
+\r
+  # Find a debug library if one exists and use that for debug builds.\r
+  # This really only does anything for win32, but does no harm on other\r
+  # platforms.\r
+  FIND_LIBRARY(LIBCRYPTO_LIBRARY_DEBUG NAMES ${LIBCRYPTO_LIBRARY_NAMES_DEBUG})\r
+\r
+  INCLUDE(LibraryDebugAndRelease)\r
+  SET_LIBRARY_FROM_DEBUG_AND_RELEASE(LIBCRYPTO)\r
+\r
+  # handle the QUIETLY and REQUIRED arguments and set LIBCRYPTO_FOUND to TRUE if \r
+  # all listed variables are TRUE\r
+  INCLUDE(FindPackageHandleStandardArgs)\r
+  FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBCRYPTO DEFAULT_MSG LIBCRYPTO_LIBRARY LIBCRYPTO_INCLUDE_DIR)\r
+\r
+  IF(LIBCRYPTO_FOUND)\r
+    SET( LIBCRYPTO_LIBRARIES ${LIBCRYPTO_LIBRARY} )\r
+  ELSE(LIBCRYPTO_FOUND)\r
+    SET( LIBCRYPTO_LIBRARIES )\r
+  ENDIF(LIBCRYPTO_FOUND)\r
+\r
+  MARK_AS_ADVANCED( LIBCRYPTO_LIBRARY LIBCRYPTO_INCLUDE_DIR )\r
+\r
+ENDIF (NOT LIBCRYPTO_INCLUDE_DIR OR NOT LIBCRYPTO_LIBRARIES)\r
+\r
+# check whether using OpenSSL 1.1 API\r
+IF (DEFINED LIBCRYPTO_INCLUDE_DIR AND DEFINED LIBCRYPTO_LIBRARIES)\r
+  INCLUDE(CheckCSourceCompiles)\r
+\r
+  SET(CMAKE_REQUIRED_INCLUDES ${LIBCRYPTO_INCLUDE_DIR})\r
+  SET(CMAKE_REQUIRED_LIBRARIES ${LIBCRYPTO_LIBRARIES})\r
+\r
+  CHECK_C_SOURCE_COMPILES("#include <openssl/opensslv.h>\r
+                       #ifndef OPENSSL_VERSION_NUMBER\r
+                       #error No OPENSSL_VERSION_NUMBER defined\r
+                       #endif\r
+                       #if OPENSSL_VERSION_NUMBER < 0x10100000L\r
+                       #error This is not OpenSSL 1.1 or higher\r
+                       #endif\r
+                       int main(void) { return 0; }" PODOFO_HAVE_OPENSSL_1_1)\r
+\r
+  CHECK_C_SOURCE_COMPILES("#include <openssl/opensslconf.h>\r
+                       #ifndef OPENSSL_NO_RC4\r
+                       #error No OPENSSL_NO_RC4 defined\r
+                       #endif\r
+                       int main(void) { return 0; }" PODOFO_HAVE_OPENSSL_NO_RC4)\r
+\r
+  UNSET(CMAKE_REQUIRED_INCLUDES)\r
+  UNSET(CMAKE_REQUIRED_LIBRARIES)\r
+ENDIF (DEFINED LIBCRYPTO_INCLUDE_DIR AND DEFINED LIBCRYPTO_LIBRARIES)\r
diff --git a/cmake/modules/FindLIBIDN.cmake b/cmake/modules/FindLIBIDN.cmake
new file mode 100644 (file)
index 0000000..e90b432
--- /dev/null
@@ -0,0 +1,40 @@
+# - Find libidn\r
+# Find the native LIBIDN includes and library\r
+#\r
+#  LIBIDN_INCLUDE_DIR - where to find stringprep.h, etc.\r
+#  LIBIDN_LIBRARIES   - List of libraries when using libidn.\r
+#  LIBIDN_FOUND       - True if libidn found.\r
+\r
+\r
+IF (LIBIDN_INCLUDE_DIR)\r
+  # Already in cache, be silent\r
+  SET(LIBIDN_FIND_QUIETLY TRUE)\r
+ENDIF (LIBIDN_INCLUDE_DIR)\r
+\r
+FIND_PATH(LIBIDN_INCLUDE_DIR stringprep.h)\r
+\r
+SET(LIBIDN_LIBRARY_NAMES_RELEASE ${LIBIDN_LIBRARY_NAMES_RELEASE} ${LIBIDN_LIBRARY_NAMES} idn)\r
+FIND_LIBRARY(LIBIDN_LIBRARY_RELEASE NAMES ${LIBIDN_LIBRARY_NAMES_RELEASE} )\r
+\r
+# Find a debug library if one exists and use that for debug builds.\r
+# This really only does anything for win32, but does no harm on other\r
+# platforms.\r
+SET(LIBIDN_LIBRARY_NAMES_DEBUG ${LIBIDN_LIBRARY_NAMES_DEBUG} idnd)\r
+FIND_LIBRARY(LIBIDN_LIBRARY_DEBUG NAMES ${LIBIDN_LIBRARY_NAMES_DEBUG})\r
+\r
+INCLUDE(LibraryDebugAndRelease)\r
+SET_LIBRARY_FROM_DEBUG_AND_RELEASE(LIBIDN)\r
+\r
+# handle the QUIETLY and REQUIRED arguments and set LIBIDN_FOUND to TRUE if \r
+# all listed variables are TRUE\r
+INCLUDE(FindPackageHandleStandardArgs)\r
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBIDN DEFAULT_MSG LIBIDN_LIBRARY LIBIDN_INCLUDE_DIR)\r
+\r
+IF(LIBIDN_FOUND)\r
+  SET( LIBIDN_LIBRARIES ${LIBIDN_LIBRARY} )\r
+ELSE(LIBIDN_FOUND)\r
+  SET( LIBIDN_LIBRARIES )\r
+ENDIF(LIBIDN_FOUND)\r
+\r
+MARK_AS_ADVANCED( LIBIDN_LIBRARY LIBIDN_INCLUDE_DIR )\r
+\r
diff --git a/cmake/modules/FindLIBJPEG.cmake b/cmake/modules/FindLIBJPEG.cmake
new file mode 100644 (file)
index 0000000..13541a4
--- /dev/null
@@ -0,0 +1,32 @@
+# - Find LIBJPEG\r
+# Find the native LIBJPEG includes and library\r
+# This module defines\r
+#  LIBJPEG_INCLUDE_DIR, where to find jpeglib.h, etc.\r
+#  LIBJPEG_LIBRARIES, the libraries needed to use LIBJPEG.\r
+#  LIBJPEG_FOUND, If false, do not try to use LIBJPEG.\r
+# also defined, but not for general use are\r
+#  LIBJPEG_LIBRARY, where to find the LIBJPEG library.\r
+\r
+FIND_PATH(LIBJPEG_INCLUDE_DIR jpeglib.h)\r
+\r
+SET(LIBJPEG_LIBRARY_NAMES_RELEASE ${LIBJPEG_LIBRARY_NAMES_RELEASE} ${LIBJPEG_LIBRARY_NAMES} jpeg libjpeg)\r
+FIND_LIBRARY(LIBJPEG_LIBRARY_RELEASE NAMES ${LIBJPEG_LIBRARY_NAMES_RELEASE} )\r
+\r
+SET(LIBJPEG_LIBRARY_NAMES_DEBUG ${LIBJPEG_LIBRARY_NAMES_DEBUG} jpegd libjpegd jpeg_d libjpeg_d)\r
+FIND_LIBRARY(LIBJPEG_LIBRARY_DEBUG NAMES ${LIBJPEG_LIBRARY_NAMES_DEBUG} )\r
+\r
+INCLUDE(LibraryDebugAndRelease)\r
+SET_LIBRARY_FROM_DEBUG_AND_RELEASE(LIBJPEG)\r
+\r
+# handle the QUIETLY and REQUIRED arguments and set LIBJPEG_FOUND to TRUE if \r
+# all listed variables are TRUE\r
+INCLUDE(FindPackageHandleStandardArgs)\r
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBJPEG DEFAULT_MSG LIBJPEG_LIBRARY LIBJPEG_INCLUDE_DIR)\r
+\r
+IF(LIBJPEG_FOUND)\r
+  SET(LIBJPEG_LIBRARIES ${LIBJPEG_LIBRARY})\r
+ELSE(LIBJPEG_FOUND)\r
+  MESSAGE("libjpeg not found: Library ${LIBJPEG_LIBRARY}, headers ${LIBJPEG_INCLUDE_DIR}")\r
+ENDIF(LIBJPEG_FOUND)\r
+\r
+MARK_AS_ADVANCED(LIBJPEG_LIBRARY LIBJPEG_INCLUDE_DIR )\r
diff --git a/cmake/modules/FindLIBSTLPORT.cmake b/cmake/modules/FindLIBSTLPORT.cmake
new file mode 100644 (file)
index 0000000..a55e951
--- /dev/null
@@ -0,0 +1,15 @@
+FIND_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})
diff --git a/cmake/modules/FindLUA.cmake b/cmake/modules/FindLUA.cmake
new file mode 100644 (file)
index 0000000..aa45eba
--- /dev/null
@@ -0,0 +1,26 @@
+# 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, <montel@kde.org>
+#
+# 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)
diff --git a/cmake/modules/FindLua51.cmake b/cmake/modules/FindLua51.cmake
new file mode 100644 (file)
index 0000000..0a82e8c
--- /dev/null
@@ -0,0 +1,74 @@
+# 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 <lua/lua.h>
+# 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)
+
diff --git a/cmake/modules/FindOpenSSL.cmake b/cmake/modules/FindOpenSSL.cmake
new file mode 100644 (file)
index 0000000..aace137
--- /dev/null
@@ -0,0 +1,76 @@
+# - Try to find the OpenSSL encryption library\r
+# Once done this will define\r
+#\r
+#  OPENSSL_FOUND - system has the OpenSSL library\r
+#  OPENSSL_INCLUDE_DIR - the OpenSSL include directory\r
+#  OPENSSL_LIBRARIES - The libraries needed to use OpenSSL\r
+\r
+# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>\r
+# Modified by Craig Ringer, 2008:\r
+#      - Handle !REQUIRED\r
+#\r
+# Redistribution and use is allowed according to the terms of the BSD license.\r
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.\r
+\r
+\r
+IF(OPENSSL_LIBRARIES)\r
+   SET(OpenSSL_FIND_QUIETLY TRUE)\r
+ENDIF(OPENSSL_LIBRARIES)\r
+\r
+IF(SSL_EAY_DEBUG AND SSL_EAY_RELEASE)\r
+   SET(LIB_FOUND 1)\r
+ENDIF(SSL_EAY_DEBUG AND SSL_EAY_RELEASE)\r
+\r
+FIND_PATH(OPENSSL_INCLUDE_DIR openssl/ssl.h )\r
+\r
+IF(WIN32 AND MSVC)\r
+   # /MD and /MDd are the standard values - if somone wants to use\r
+   # others, the libnames have to change here too\r
+   # use also ssl and ssleay32 in debug as fallback for openssl < 0.9.8b\r
+\r
+   FIND_LIBRARY(SSL_EAY_DEBUG NAMES ssleay32MDd ssl ssleay32)\r
+   FIND_LIBRARY(SSL_EAY_RELEASE NAMES ssleay32MD ssl ssleay32)\r
+\r
+   IF(MSVC_IDE)\r
+      IF(SSL_EAY_DEBUG AND SSL_EAY_RELEASE)\r
+         SET(OPENSSL_LIBRARIES optimized ${SSL_EAY_RELEASE} debug ${SSL_EAY_DEBUG})\r
+      ELSE(SSL_EAY_DEBUG AND SSL_EAY_RELEASE)\r
+         MESSAGE("OpenSSL: Could not find the debug and release version of openssl")\r
+        MESSAGE("OpenSSL: Disabling OpenSSL")\r
+        SET(OPENSSL_LIBRARIES)\r
+      ENDIF(SSL_EAY_DEBUG AND SSL_EAY_RELEASE)\r
+   ELSE(MSVC_IDE)\r
+      STRING(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_TOLOWER)\r
+      IF(CMAKE_BUILD_TYPE_TOLOWER MATCHES debug)\r
+         SET(OPENSSL_LIBRARIES ${SSL_EAY_DEBUG})\r
+      ELSE(CMAKE_BUILD_TYPE_TOLOWER MATCHES debug)\r
+         SET(OPENSSL_LIBRARIES ${SSL_EAY_RELEASE})\r
+      ENDIF(CMAKE_BUILD_TYPE_TOLOWER MATCHES debug)\r
+   ENDIF(MSVC_IDE)\r
+   MARK_AS_ADVANCED(SSL_EAY_DEBUG SSL_EAY_RELEASE)\r
+ELSE(WIN32 AND MSVC)\r
+\r
+   FIND_LIBRARY(OPENSSL_LIBRARIES NAMES ssl ssleay32 ssleay32MD )\r
+\r
+ENDIF(WIN32 AND MSVC)\r
+\r
+IF(OPENSSL_INCLUDE_DIR AND OPENSSL_LIBRARIES)\r
+   SET(OPENSSL_FOUND TRUE)\r
+ELSE(OPENSSL_INCLUDE_DIR AND OPENSSL_LIBRARIES)\r
+   SET(OPENSSL_FOUND FALSE)\r
+ENDIF (OPENSSL_INCLUDE_DIR AND OPENSSL_LIBRARIES)\r
+\r
+IF (OPENSSL_FOUND)\r
+   IF (NOT OpenSSL_FIND_QUIETLY)\r
+      MESSAGE(STATUS "Found OpenSSL: ${OPENSSL_LIBRARIES}")\r
+   ENDIF (NOT OpenSSL_FIND_QUIETLY)\r
+ELSE (OPENSSL_FOUND)\r
+   IF (OpenSSL_FIND_REQUIRED)\r
+      MESSAGE(FATAL_ERROR "Could NOT find OpenSSL")\r
+   ELSE (OpenSSL_FIND_REQUIRED)\r
+      SET (OPENSSL_LIBRARIES "")\r
+   ENDIF (OpenSSL_FIND_REQUIRED)\r
+ENDIF (OPENSSL_FOUND)\r
+\r
+MARK_AS_ADVANCED(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES)\r
+\r
diff --git a/cmake/modules/FindTIFF.cmake b/cmake/modules/FindTIFF.cmake
new file mode 100644 (file)
index 0000000..d331a01
--- /dev/null
@@ -0,0 +1,28 @@
+# - Find TIFF library\r
+# Find the native TIFF includes and library\r
+# This module defines\r
+#  TIFF_INCLUDE_DIR, where to find tiff.h, etc.\r
+#  TIFF_LIBRARIES, libraries to link against to use TIFF.\r
+#  TIFF_FOUND, If false, do not try to use TIFF.\r
+# also defined, but not for general use are\r
+#  TIFF_LIBRARY, where to find the TIFF library.\r
+\r
+FIND_PATH(TIFF_INCLUDE_DIR tiff.h)\r
+\r
+SET(TIFF_LIBRARY_NAMES_RELEASE ${TIFF_LIBRARY_NAMES_RELEASE} ${TIFF_LIBRARY_NAMES} tiff libtiff)\r
+SET(TIFF_LIBRARY_NAMES_DEBUG ${TIFF_LIBRARY_NAMES_DEBUG} tiffd libtiffd)\r
+\r
+FIND_LIBRARY(TIFF_LIBRARY_RELEASE NAMES ${TIFF_LIBRARY_NAMES_RELEASE} )\r
+FIND_LIBRARY(TIFF_LIBRARY_DEBUG NAMES ${TIFF_LIBRARY_NAMES_DEBUG} )\r
+\r
+INCLUDE(LibraryDebugAndRelease)\r
+SET_LIBRARY_FROM_DEBUG_AND_RELEASE(TIFF)\r
+\r
+# handle the QUIETLY and REQUIRED arguments and set TIFF_FOUND to TRUE if \r
+# all listed variables are TRUE\r
+INCLUDE(FindPackageHandleStandardArgs)\r
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(TIFF DEFAULT_MSG TIFF_LIBRARY TIFF_INCLUDE_DIR)\r
+\r
+IF(TIFF_FOUND)\r
+  SET( TIFF_LIBRARIES ${TIFF_LIBRARY} )\r
+ENDIF(TIFF_FOUND)\r
diff --git a/cmake/modules/FindUNISTRING.cmake b/cmake/modules/FindUNISTRING.cmake
new file mode 100644 (file)
index 0000000..642e503
--- /dev/null
@@ -0,0 +1,26 @@
+
+# - Find UNISTRING
+# Find the unistring includes and library
+#
+#  UNISTRING_INCLUDE_DIR - where to find unistr.h, etc.
+#  UNISTRING_LIBRARY     - unistring library.
+#  UNISTRING_FOUND       - True if unistring found.
+
+IF (UNISTRING_INCLUDE_DIR)
+    # Already in cache, be silent
+    SET(UNISTRING_FIND_QUIETLY TRUE)
+ENDIF (UNISTRING_INCLUDE_DIR)
+
+FIND_PATH(UNISTRING_INCLUDE_DIR unistr.h)
+
+SET(UNISTRING_NAMES unistring libunistring)
+FIND_LIBRARY(UNISTRING_LIBRARY NAMES ${UNISTRING_NAMES})
+
+# handle the QUIETLY and REQUIRED arguments and set UNISTRING_FOUND to
+# TRUE if all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(UNISTRING DEFAULT_MSG
+    UNISTRING_INCLUDE_DIR UNISTRING_LIBRARY)
+
+MARK_AS_ADVANCED(UNISTRING_LIBRARY UNISTRING_INCLUDE_DIR UNISTRING_LIBRARY)
+
diff --git a/cmake/modules/FindZLIB.cmake b/cmake/modules/FindZLIB.cmake
new file mode 100644 (file)
index 0000000..05887f8
--- /dev/null
@@ -0,0 +1,55 @@
+# - Find zlib\r
+# Find the native ZLIB includes and library\r
+#\r
+#  ZLIB_INCLUDE_DIR - where to find zlib.h, etc.\r
+#  ZLIB_LIBRARIES   - List of libraries when using zlib.\r
+#  ZLIB_FOUND       - True if zlib found.\r
+\r
+\r
+IF (ZLIB_INCLUDE_DIR)\r
+  # Already in cache, be silent\r
+  SET(ZLIB_FIND_QUIETLY TRUE)\r
+ENDIF (ZLIB_INCLUDE_DIR)\r
+\r
+FIND_PATH(ZLIB_INCLUDE_DIR zlib.h)\r
+\r
+# On win32, qt statically links to zlib and libpng, and exports their symbols.\r
+# We can just link to Qt to get zlib and libpng. We still require the user to\r
+# supply their own headers on the search path, but they can and should just\r
+# specify ${QTDIR}/src/3rdparty/zlib/include .\r
+# To use this, you must use FindQt before FindZlib.\r
+IF(QT_QTCORE_LIBRARY AND USE_QT_ZLIB_PNGLIB)\r
+\r
+  MESSAGE("Using zlib from qt")\r
+  SET(ZLIB_LIBRARY_RELEASE ${QT_QTCORE_LIBRARY_RELEASE})\r
+  SET(ZLIB_LIBRARY_DEBUG ${QT_QTCORE_LIBRARY_DEBUG})\r
+  SET(ZLIB_LIBRARY ${QT_QTCORE_LIBRARY})\r
+\r
+ELSE(QT_QTCORE_LIBRARY AND USE_QT_ZLIB_PNGLIB)\r
+\r
+  SET(ZLIB_LIBRARY_NAMES_RELEASE ${ZLIB_LIBRARY_NAMES_RELEASE} ${ZLIB_LIBRARY_NAMES} zlib1 zlib zdll z)\r
+  FIND_LIBRARY(ZLIB_LIBRARY_RELEASE NAMES ${ZLIB_LIBRARY_NAMES_RELEASE} )\r
+\r
+  # Find a debug library if one exists and use that for debug builds.\r
+  # This really only does anything for win32, but does no harm on other\r
+  # platforms.\r
+  SET(ZLIB_LIBRARY_NAMES_DEBUG ${ZLIB_LIBRARY_NAMES_DEBUG} zlib1d zlibd zdlld)\r
+  FIND_LIBRARY(ZLIB_LIBRARY_DEBUG NAMES ${ZLIB_LIBRARY_NAMES_DEBUG})\r
+\r
+  INCLUDE(LibraryDebugAndRelease)\r
+  SET_LIBRARY_FROM_DEBUG_AND_RELEASE(ZLIB)\r
+\r
+ENDIF(QT_QTCORE_LIBRARY AND USE_QT_ZLIB_PNGLIB)\r
+\r
+# handle the QUIETLY and REQUIRED arguments and set ZLIB_FOUND to TRUE if \r
+# all listed variables are TRUE\r
+INCLUDE(FindPackageHandleStandardArgs)\r
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(ZLIB DEFAULT_MSG ZLIB_LIBRARY ZLIB_INCLUDE_DIR)\r
+\r
+IF(ZLIB_FOUND)\r
+  SET( ZLIB_LIBRARIES ${ZLIB_LIBRARY} )\r
+ELSE(ZLIB_FOUND)\r
+  SET( ZLIB_LIBRARIES )\r
+ENDIF(ZLIB_FOUND)\r
+\r
+MARK_AS_ADVANCED( ZLIB_LIBRARY ZLIB_INCLUDE_DIR )\r
diff --git a/cmake/modules/LibraryDebugAndRelease.cmake b/cmake/modules/LibraryDebugAndRelease.cmake
new file mode 100644 (file)
index 0000000..b7f64f0
--- /dev/null
@@ -0,0 +1,25 @@
+#\r
+# This macro is used when we may have a debug and or release build of a library,\r
+# and we want to produce a single easy to use library string that'll do the right\r
+# thing. If both debug and release versions are available, we'll automatically use the\r
+# debug version for debug builds and the release version for release builds.\r
+#\r
+# If only one build exists, we use that one irrespective of build type.\r
+#\r
+MACRO(SET_LIBRARY_FROM_DEBUG_AND_RELEASE _NAME)\r
+\r
+  IF(NOT DEFINED "${_NAME}_LIBRARY_RELEASE" OR NOT DEFINED "${_NAME}_LIBRARY_DEBUG")\r
+    MESSAGE(FATAL_ERROR "${_NAME}_LIBRARY_DEBUG OR ${_NAME}_LIBRARY_RELEASE undefined")\r
+  ENDIF(NOT DEFINED "${_NAME}_LIBRARY_RELEASE" OR NOT DEFINED "${_NAME}_LIBRARY_DEBUG")\r
+  IF(${_NAME}_LIBRARY_RELEASE AND ${_NAME}_LIBRARY_DEBUG)\r
+    SET(${_NAME}_LIBRARY "optimized;${${_NAME}_LIBRARY_RELEASE};debug;${${_NAME}_LIBRARY_DEBUG}")\r
+  ELSE(${_NAME}_LIBRARY_RELEASE AND ${_NAME}_LIBRARY_DEBUG)\r
+    IF(${_NAME}_LIBRARY_DEBUG)\r
+      MESSAGE("WARNING: ${_NAME} debug library will be used even for release builds")\r
+      SET(${_NAME}_LIBRARY ${${_NAME}_LIBRARY_DEBUG})\r
+    ELSE(${_NAME}_LIBRARY_DEBUG)\r
+      SET(${_NAME}_LIBRARY ${${_NAME}_LIBRARY_RELEASE})\r
+    ENDIF(${_NAME}_LIBRARY_DEBUG)\r
+  ENDIF(${_NAME}_LIBRARY_RELEASE AND ${_NAME}_LIBRARY_DEBUG)\r
+\r
+ENDMACRO(SET_LIBRARY_FROM_DEBUG_AND_RELEASE)\r
diff --git a/cmake/modules/MacroEnsureVersion.cmake b/cmake/modules/MacroEnsureVersion.cmake
new file mode 100644 (file)
index 0000000..c6df537
--- /dev/null
@@ -0,0 +1,71 @@
+# 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, <faure@kde.org>
+#
+# 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, <faure@kde.org>
+# Copyright (c) 2007, Pino Toscano, <pino@kde.org>
+#
+# 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)
diff --git a/cmake_uninstall.cmake.in b/cmake_uninstall.cmake.in
new file mode 100644 (file)
index 0000000..cfc33ff
--- /dev/null
@@ -0,0 +1,18 @@
+IF(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)
\ No newline at end of file
diff --git a/doc/podofo_architecture.png b/doc/podofo_architecture.png
new file mode 100644 (file)
index 0000000..0c0407f
Binary files /dev/null and b/doc/podofo_architecture.png differ
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6eb61ed
--- /dev/null
@@ -0,0 +1,11 @@
+IF(BOOST_FOUND)
+  SET(graph pdfcontentsgraph)
+ELSE(BOOST_FOUND)
+  SET(graph)
+ENDIF(BOOST_FOUND)
+
+SUBDIRS(
+       helloworld
+       helloworld-base14
+       ${graph}
+       )
diff --git a/examples/helloworld-base14/CMakeLists.txt b/examples/helloworld-base14/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7515632
--- /dev/null
@@ -0,0 +1,17 @@
+# 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})
diff --git a/examples/helloworld-base14/helloworld-base14.cpp b/examples/helloworld-base14/helloworld-base14.cpp
new file mode 100644 (file)
index 0000000..c83ce32
--- /dev/null
@@ -0,0 +1,373 @@
+/***************************************************************************
+ *   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 <iostream>
+
+/*
+ * 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 <podofo.h>
+
+/*
+ * 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);
+           }
+       }
+
+
+}
+
diff --git a/examples/helloworld/CMakeLists.txt b/examples/helloworld/CMakeLists.txt
new file mode 100644 (file)
index 0000000..755b263
--- /dev/null
@@ -0,0 +1,17 @@
+# 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})
diff --git a/examples/helloworld/helloworld.cpp b/examples/helloworld/helloworld.cpp
new file mode 100644 (file)
index 0000000..dd102e2
--- /dev/null
@@ -0,0 +1,270 @@
+/***************************************************************************
+ *   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 <iostream>
+
+/*
+ * 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 <podofo/podofo.h>
+
+/*
+ * 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;
+}
diff --git a/examples/pdfcontentsgraph/CMakeLists.txt b/examples/pdfcontentsgraph/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7f6270b
--- /dev/null
@@ -0,0 +1,6 @@
+ADD_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})
diff --git a/examples/pdfcontentsgraph/PdfContentsGraph.cpp b/examples/pdfcontentsgraph/PdfContentsGraph.cpp
new file mode 100644 (file)
index 0000000..4426643
--- /dev/null
@@ -0,0 +1,501 @@
+#include "PdfContentsGraph.h"
+
+#if !defined(PODOFO_HAVE_BOOST)
+#error This module requires boost::graph
+#endif
+
+#include <string>
+#include <iostream>
+#include <map>
+#include <stack>
+#include <list>
+#include <sstream>
+
+#include <boost/graph/depth_first_search.hpp>
+
+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<string,const PdfContentsGraph::KWInfo*> generateKWNameMap()
+{
+    map<string,const PdfContentsGraph::KWInfo*> m;
+    const PdfContentsGraph::KWInfo* ki = &(kwInfo[0]);
+    do {
+        m.insert( pair<string,const PdfContentsGraph::KWInfo*>(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<PdfContentStreamKeyword,const PdfContentsGraph::KWInfo*> generateKWIdMap()
+{
+    map<PdfContentStreamKeyword,const PdfContentsGraph::KWInfo*> m;
+    const PdfContentsGraph::KWInfo* ki = &(kwInfo[0]);
+    do {
+        m.insert( pair<PdfContentStreamKeyword,const PdfContentsGraph::KWInfo*>(ki->kw,ki) );
+        ki ++;
+    } while ( ki->kt != PdfContentsGraph::KT_Undefined );
+    return m;
+}
+
+// Mapping table from keyword string value to KWInfo
+static const map<string,const PdfContentsGraph::KWInfo*> kwNameMap = generateKWNameMap();
+// Mapping table from keyword enum value to KWInfo
+static const map<PdfContentStreamKeyword,const PdfContentsGraph::KWInfo*> 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>
+{
+    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>
+{
+    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<typename EV, bool Arriving>
+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<PdfContentsGraph::Vertex> s,
+        ostream& os)
+{
+    vector<PdfContentsGraph::Vertex> 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<PdfContentsGraph::Vertex> & 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<PdfContentsGraph::Vertex> &,
+        const string &)
+{
+}
+#endif
+
+//
+// Format an error message reporting an open/close operator mismatch error.
+//
+std::string formatMismatchError(
+        const PdfContentsGraph::Graph & g,
+        const stack<PdfContentsGraph::Vertex> & 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<PdfContentsGraph::Vertex> & 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<PdfContentsGraph::Vertex> 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<string,const KWInfo*>::const_iterator itEnd = kwNameMap.end();
+    map<string,const KWInfo*>::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<PdfContentStreamKeyword,const KWInfo*>::const_iterator itEnd = kwIdMap.end();
+    map<PdfContentStreamKeyword,const KWInfo*>::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<Vertex> 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<PdfVariant> 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<on_discover_vertex,true>,PrintVertexVisitor<on_finish_vertex,false> > EVList;
+    dfs_visitor<EVList> vis = make_dfs_visitor(
+            EVList( PrintVertexVisitor<on_discover_vertex,true>(&outStream),
+                    PrintVertexVisitor<on_finish_vertex,false>(&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<PdfVariant>::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
diff --git a/examples/pdfcontentsgraph/PdfContentsGraph.h b/examples/pdfcontentsgraph/PdfContentsGraph.h
new file mode 100644 (file)
index 0000000..0d87323
--- /dev/null
@@ -0,0 +1,280 @@
+#ifndef _PODOFO_PDFCONTENTSGRAPH_H
+#define _PODOFO_PDFCONTENTSGRAPH_H
+
+#include "podofo/podofo.h"
+
+#if defined(PODOFO_HAVE_BOOST)
+
+#include <utility>
+#include <string>
+
+#include <boost/graph/graph_traits.hpp>
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/variant.hpp>
+
+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<PdfContentStreamKeyword,std::string> KWVariant;
+        typedef std::vector<PoDoFo::PdfVariant> 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<KWInstance,KWInstance> NodeData;
+    typedef boost::adjacency_list<boost::listS,boost::vecS,boost::directedS,NodeData> Graph;
+    typedef boost::graph_traits<Graph>::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<typename T1, typename T2>
+    std::pair<KWInstance,KWInstance> MakeNode( const T1 & kw1, const T2 & kw2 )
+    {
+        return std::pair<KWInstance,KWInstance>(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<typename T1>
+    std::pair<KWInstance,KWInstance> MakeNode( const T1 & kw )
+    {
+        return std::pair<KWInstance,KWInstance>(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
diff --git a/examples/pdfcontentsgraph/README.txt b/examples/pdfcontentsgraph/README.txt
new file mode 100644 (file)
index 0000000..905a26b
--- /dev/null
@@ -0,0 +1,18 @@
+PdfContentsGraph 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 <craig@postnewspapers.com.au>
diff --git a/examples/pdfcontentsgraph/main.cpp b/examples/pdfcontentsgraph/main.cpp
new file mode 100644 (file)
index 0000000..e073dc6
--- /dev/null
@@ -0,0 +1,96 @@
+#include "podofo.h"
+#include "PdfContentsGraph.h"
+
+#include <iostream>
+#include <stack>
+#include <algorithm>
+#include <string>
+#include <iomanip>
+#include <cstdio>
+
+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;
+}
diff --git a/man/CMakeLists.txt b/man/CMakeLists.txt
new file mode 100644 (file)
index 0000000..97e292a
--- /dev/null
@@ -0,0 +1,21 @@
+
+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
+  )
diff --git a/man/podofobox.1 b/man/podofobox.1
new file mode 100644 (file)
index 0000000..b40916d
--- /dev/null
@@ -0,0 +1,38 @@
+.TH "PODOFOBOX" "1" "2010-12-09" "PoDoFo" "podofobox"
+.PP
+.SH NAME
+podofobox \- set the media, crop, bleed, trim, and art box on pages of a PDF
+file\.
+.PP
+.SH SYNOPSIS
+\fBpodofobox\fR [inputfile] [outpufile] [box] [left] [bottom] [width] [height]
+.PP
+.SH DESCRIPTION
+.B podofobox
+is one of the command line tools from the PoDoFo library that provide several
+useful operations to work with PDF files\. It can set the media, crop, bleed,
+trim, and art box on pages of a PDF file\.
+.PP
+.SH "SEE ALSO"
+.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 <domseichter@web\.de> and others\.
+.PP
+This manual page was written by Oleksandr Moskalenko <malex@debian\.org> for
+the Debian Project (but may be used by others)\.
diff --git a/man/podofocolor.1 b/man/podofocolor.1
new file mode 100644 (file)
index 0000000..3ac1810
--- /dev/null
@@ -0,0 +1,56 @@
+.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
+\fBconvert all colors to grayscale\fR 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 <domseichter@web\.de> and others\.
+.PP
+This manual page was written by Dominik Seichter <domseichter@web\.de> for
+the PoDoFo Project (but may be used by others)\.
diff --git a/man/podofocountpages.1 b/man/podofocountpages.1
new file mode 100644 (file)
index 0000000..accf622
--- /dev/null
@@ -0,0 +1,48 @@
+.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 <domseichter@web\.de> and others\.
+.PP
+This manual page was written by Oleksandr Moskalenko <malex@debian\.org> for
+the Debian Project (but may be used by others)\.
diff --git a/man/podofocrop.1 b/man/podofocrop.1
new file mode 100644 (file)
index 0000000..8ec05ee
--- /dev/null
@@ -0,0 +1,38 @@
+.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 <domseichter@web\.de> and others\.
+.PP
+This manual page was written by Oleksandr Moskalenko <malex@debian\.org> for
+the Debian Project (but may be used by others)\.
diff --git a/man/podofoencrypt.1 b/man/podofoencrypt.1
new file mode 100644 (file)
index 0000000..880d43e
--- /dev/null
@@ -0,0 +1,127 @@
+.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 <userpassword>] \-o <ownerpassword> <inputfile> <outputfile>
+.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 <password>\fR
+.RS
+An optional user password
+.RE
+.PP
+\fB\-o <password>\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 annotations or form fields (if ePdfPermissions_Edit is set also allow the creation of 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 <domseichter@web\.de> and others\.
+.PP
+This manual page was written by Oleksandr Moskalenko <malex@debian\.org> for
+the Debian Project (but may be used by others)\.
diff --git a/man/podofogc.1 b/man/podofogc.1
new file mode 100644 (file)
index 0000000..31b7224
--- /dev/null
@@ -0,0 +1,39 @@
+.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 <domseichter@web\.de> and others\.
+.PP
+This manual page was written by Oleksandr Moskalenko <malex@debian\.org> for
+the Debian Project (but may be used by others)\.
diff --git a/man/podofoimg2pdf.1 b/man/podofoimg2pdf.1
new file mode 100644 (file)
index 0000000..93ec05c
--- /dev/null
@@ -0,0 +1,56 @@
+.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 <domseichter@web\.de> and others\.
+.PP
+This manual page was written by Oleksandr Moskalenko <malex@debian\.org> for
+the Debian Project (but may be used by others)\.
+
diff --git a/man/podofoimgextract.1 b/man/podofoimgextract.1
new file mode 100644 (file)
index 0000000..dc784c6
--- /dev/null
@@ -0,0 +1,38 @@
+.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 <domseichter@web\.de> and others\.
+.PP
+This manual page was written by Oleksandr Moskalenko <malex@debian\.org> for
+the Debian Project (but may be used by others)\.
diff --git a/man/podofoimpose.1 b/man/podofoimpose.1
new file mode 100644 (file)
index 0000000..fb5d011
--- /dev/null
@@ -0,0 +1,60 @@
+.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 [Interpreter]
+.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[Interpreter]\fR
+.RS
+Imposition interpreter\. 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 <domseichter@web\.de> and others\.
+.PP
+This manual page was written by Oleksandr Moskalenko <malex@debian\.org> for
+the Debian Project (but may be used by others)\.
diff --git a/man/podofoincrementalupdates.1 b/man/podofoincrementalupdates.1
new file mode 100644 (file)
index 0000000..cf3dabe
--- /dev/null
@@ -0,0 +1,58 @@
+.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 <domseichter@web\.de> and others\.
+.PP
+This manual page was written by Oleksandr Moskalenko <malex@debian\.org> for
+the Debian Project (but may be used by others)\.
+
diff --git a/man/podofomerge.1 b/man/podofomerge.1
new file mode 100644 (file)
index 0000000..75cca65
--- /dev/null
@@ -0,0 +1,39 @@
+.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 <domseichter@web\.de> and others\.
+.PP
+This manual page was written by Oleksandr Moskalenko <malex@debian\.org> for
+the Debian Project (but may be used by others)\.
+
+
diff --git a/man/podofopages.1 b/man/podofopages.1
new file mode 100644 (file)
index 0000000..53e1d2a
--- /dev/null
@@ -0,0 +1,55 @@
+.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 <domseichter@web\.de> and others\.
+.PP
+This manual page was written by Oleksandr Moskalenko <malex@debian\.org> for
+the Debian Project (but may be used by others)\.
diff --git a/man/podofopdfinfo.1 b/man/podofopdfinfo.1
new file mode 100644 (file)
index 0000000..e7d37a3
--- /dev/null
@@ -0,0 +1,77 @@
+.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 <domseichter@web\.de> and others\.
+.PP
+This manual page was written by Oleksandr Moskalenko <malex@debian\.org> for
+the Debian Project (but may be used by others)\.
diff --git a/man/podofotxt2pdf.1 b/man/podofotxt2pdf.1
new file mode 100644 (file)
index 0000000..33142c3
--- /dev/null
@@ -0,0 +1,65 @@
+.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 <name>] [\-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  <name>
+.RS
+.PP
+Use the font <name>\.
+.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 <domseichter@web\.de> and others\.
+.PP
+This manual page was written by Oleksandr Moskalenko <malex@debian\.org> for
+the Debian Project (but may be used by others)\.
diff --git a/man/podofotxtextract.1 b/man/podofotxtextract.1
new file mode 100644 (file)
index 0000000..1f85668
--- /dev/null
@@ -0,0 +1,46 @@
+.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 <domseichter@web\.de> and others\.
+.PP
+This manual page was written by Oleksandr Moskalenko <malex@debian\.org> for
+the Debian Project (but may be used by others)\.
diff --git a/man/podofouncompress.1 b/man/podofouncompress.1
new file mode 100644 (file)
index 0000000..1964bad
--- /dev/null
@@ -0,0 +1,53 @@
+.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 <domseichter@web\.de> and others\.
+.PP
+This manual page was written by Oleksandr Moskalenko <malex@debian\.org> for
+the Debian Project (but may be used by others)\.
diff --git a/man/podofoxmp.1 b/man/podofoxmp.1
new file mode 100644 (file)
index 0000000..739a708
--- /dev/null
@@ -0,0 +1,60 @@
+.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 conjunction
+with an [outputfile]\.
+.RE
+.PP
+\fB[outputfile]\fR
+.RS
+.PP
+Output PDF file\. It is only used in conjunction 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 <domseichter@web\.de> and others\.
+.PP
+This manual page was written by Oleksandr Moskalenko <malex@debian\.org> for
+the Debian Project (but may be used by others)\.
diff --git a/podofo_config.h.in b/podofo_config.h.in
new file mode 100644 (file)
index 0000000..9a8e7c3
--- /dev/null
@@ -0,0 +1,62 @@
+/* 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_UNIQUE_PTR 1
+#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_OPENSSL_NO_RC4
+#cmakedefine PODOFO_HAVE_LIBIDN
+#cmakedefine PODOFO_HAVE_UNISTRING_LIB
diff --git a/src/podofo/CMakeLists.txt b/src/podofo/CMakeLists.txt
new file mode 100644 (file)
index 0000000..bba6b5f
--- /dev/null
@@ -0,0 +1,346 @@
+CMAKE_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/PdfOwnedDataType.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/PdfOwnedDataType.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
+  )
+
+SET(PODOFO_HEADER_FILES
+  ${PODOFO_HEADERS}
+  ${PODOFO_BASE_HEADERS}
+  ${PODOFO_BASE_HEADERS2}
+  ${PODOFO_DOC_HEADERS}
+  )
+
+# Create a Source Group for Visual Studio
+# so that headers are listed in the folder view
+# and are easier accessible
+SOURCE_GROUP("Header Files" FILES ${PODOFO_HEADER_FILES})
+
+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} ${PODOFO_HEADER_FILES})
+    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} ${PODOFO_HEADER_FILES})
+    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.pc"
+          @ONLY)
+        INSTALL(
+          FILES "${PoDoFo_BINARY_DIR}/libpodofo.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"
+     )
diff --git a/src/podofo/base/Pdf3rdPtyForwardDecl.h b/src/podofo/base/Pdf3rdPtyForwardDecl.h
new file mode 100644 (file)
index 0000000..d3a5329
--- /dev/null
@@ -0,0 +1,44 @@
+#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
diff --git a/src/podofo/base/PdfArray.cpp b/src/podofo/base/PdfArray.cpp
new file mode 100644 (file)
index 0000000..07c6620
--- /dev/null
@@ -0,0 +1,262 @@
+/***************************************************************************
+ *   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 <limits>
+
+namespace PoDoFo {
+
+PdfArray::PdfArray()
+    : m_bDirty( false )
+{
+}
+
+PdfArray::PdfArray( const PdfObject &var )
+    : m_bDirty( false )
+{
+    this->push_back( var );
+}
+
+PdfArray::PdfArray(const PdfArray & rhs)
+    : PdfOwnedDataType( rhs ), m_bDirty( rhs.m_bDirty ), m_objects( rhs.m_objects )
+{
+}
+
+PdfArray::~PdfArray()
+{
+}
+
+PdfObject * PdfArray::findAt( size_type idx ) const
+{
+    PdfObject *obj = &const_cast<PdfArray *>( this )->m_objects[idx];
+    if ( obj->IsReference() )
+        return GetIndirectObject( obj->GetReference() );
+    else
+        return obj;
+}
+
+void PdfArray::clear()
+{
+    AssertMutable();
+    if ( m_objects.size() == 0 )
+        return;
+
+    m_objects.clear();
+    m_bDirty = true;
+}
+
+PdfArray::iterator PdfArray::insert( const iterator &pos, const PdfObject &val )
+{
+    AssertMutable();
+
+    m_bDirty = true;
+    iterator ret = m_objects.insert( pos, val );
+    PdfVecObjects *pOwner = GetObjectOwner();
+    if ( pOwner != NULL )
+        ret->SetOwner( pOwner );
+    return ret;
+}
+
+void PdfArray::erase( const iterator &pos )
+{
+    AssertMutable();
+
+    m_objects.erase( pos );
+    m_bDirty = true;
+}
+
+void PdfArray::erase( const iterator &first, const iterator &last )
+{
+    AssertMutable();
+
+    m_objects.erase( first, last );
+    m_bDirty = true;
+}
+PdfArray& PdfArray::operator=( const PdfArray &rhs )
+{
+    if (this != &rhs)
+    {
+        m_bDirty = rhs.m_bDirty;
+        m_objects = rhs.m_objects;
+        this->PdfOwnedDataType::operator=( rhs );
+    }
+    else
+    {
+        //do nothing
+    }
+    
+    return *this;
+}
+
+void PdfArray::resize( size_t count, value_type val )
+{
+    AssertMutable();
+
+    size_t currentSize = size();
+    m_objects.resize( count, val );
+    PdfVecObjects *pOwner = GetObjectOwner();
+    if ( pOwner != NULL )
+    {
+        for ( size_t i = currentSize; i < count; i++ )
+            m_objects[i].SetOwner( pOwner );
+    }
+
+    m_bDirty = currentSize != count;
+}
+
+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<size_t>::max();
+    
+    for ( size_t i=0; i<this->size(); 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;
+        }
+    }
+}
+
+void PdfArray::SetOwner( PdfObject *pOwner )
+{
+    PdfOwnedDataType::SetOwner( pOwner );
+    PdfVecObjects *pVecOwner = pOwner->GetOwner();
+    if ( pVecOwner != NULL )
+    {
+        // Set owmership for all children
+        PdfArray::iterator it = this->begin();
+        PdfArray::iterator end = this->end();
+        for ( ; it != end; it++ )
+            it->SetOwner( pVecOwner );
+    }
+}
+
+};
diff --git a/src/podofo/base/PdfArray.h b/src/podofo/base/PdfArray.h
new file mode 100644 (file)
index 0000000..6e15256
--- /dev/null
@@ -0,0 +1,541 @@
+/***************************************************************************
+ *   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 "PdfOwnedDataType.h"
+#include "PdfObject.h"
+
+namespace PoDoFo {
+
+/** 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 : public PdfOwnedDataType {
+ public:
+    typedef size_t                                          size_type;
+    typedef PdfObject                                       value_type;
+    typedef value_type &                                    reference;
+    typedef const value_type &                              const_reference;
+    typedef std::vector<value_type>::iterator               iterator;
+    typedef std::vector<value_type>::const_iterator         const_iterator;
+    typedef std::vector<value_type>::reverse_iterator       reverse_iterator;
+    typedef std::vector<value_type>::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;
+
+    /** Get the object at the given index out of the array.
+     *
+     * Lookup in the indirect objects as well, if the shallow object was a reference.
+     * The returned value is a pointer to the internal object in the dictionary
+     * so it MUST not be deleted.
+     *
+     *  \param idx
+     *  \returns pointer to the found value. NULL if the index was out of the boundaries
+     */
+    inline const PdfObject * FindAt( size_type idx ) const;
+    inline PdfObject * FindAt( size_type idx );
+
+    /** 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 );
+
+    /** Remove all elements from the array
+     */
+    void clear();
+
+    /** 
+     *  \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 count new size
+     * \param value refernce value
+     */
+    void resize( size_t count, value_type val = 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<typename _InputIterator> 
+        void insert(const iterator& __position, 
+                    const _InputIterator& __first,
+                    const _InputIterator& __last);
+#endif
+
+    iterator insert( const iterator &pos, const PdfObject &val );
+
+    void erase( const iterator& pos );
+    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 );
+
+ protected:
+     void SetOwner( PdfObject* pOwner );
+
+ private:
+    PdfObject * findAt(size_type idx) const;
+
+ private:
+    bool         m_bDirty; ///< Indicates if this object was modified after construction
+    std::vector<PdfObject> m_objects;
+};
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+inline const PdfObject * PdfArray::FindAt( size_type idx ) const
+{
+    return findAt( idx );
+}
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+inline PdfObject * PdfArray::FindAt( size_type idx )
+{
+    return findAt( idx );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+size_t PdfArray::GetSize() const
+{
+    return m_objects.size();
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+void PdfArray::push_back( const PdfObject & var )
+{
+    insert( end(), var );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+void PdfArray::Clear()
+{
+    clear();
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+size_t PdfArray::size() const
+{
+    return m_objects.size();
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+bool PdfArray::empty() const
+{
+    return m_objects.empty();
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+PdfObject& PdfArray::operator[](size_type __n)
+{
+    AssertMutable();
+
+    return m_objects[__n];
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+const PdfObject& PdfArray::operator[](size_type __n) const
+{
+    return m_objects[__n];
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+PdfArray::iterator PdfArray::begin()
+{
+    return m_objects.begin();
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+PdfArray::const_iterator PdfArray::begin() const
+{
+    return m_objects.begin();
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+PdfArray::iterator PdfArray::end()
+{
+    return m_objects.end();
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+PdfArray::const_iterator PdfArray::end() const
+{
+    return m_objects.end();
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+PdfArray::reverse_iterator PdfArray::rbegin()
+{
+    return m_objects.rbegin();
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+PdfArray::const_reverse_iterator PdfArray::rbegin() const
+{
+    return m_objects.rbegin();
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+PdfArray::reverse_iterator PdfArray::rend()
+{
+    return m_objects.rend();
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+PdfArray::const_reverse_iterator PdfArray::rend() const
+{
+    return m_objects.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<typename _InputIterator>
+void PdfArray::insert(const PdfArray::iterator& __position, 
+                      const _InputIterator& __first,
+                      const _InputIterator& __last)
+#endif
+{
+    AssertMutable();
+
+    PdfVecObjects *pOwner = GetObjectOwner();
+    iterator it1 = __first;
+    iterator it2 = __position;
+    for ( ; it1 != __last; it1++, it2++ )
+    {
+        it2 = m_objects.insert( it2, *it1 );
+        if ( pOwner != NULL )
+            it2->SetOwner( pOwner );
+    }
+
+    m_bDirty = true;
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+void PdfArray::reserve( size_type __n )
+{
+    AssertMutable();
+
+    m_objects.reserve( __n );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+PdfObject & PdfArray::front()
+{
+    return m_objects.front();
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+const PdfObject & PdfArray::front() const
+{
+    return m_objects.front();
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+PdfObject & PdfArray::back()
+{
+    return m_objects.back();
+}
+      
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+const PdfObject & PdfArray::back() const
+{
+    return m_objects.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 m_objects == rhs.m_objects;
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+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 m_objects != rhs.m_objects;
+}
+
+typedef PdfArray                 TVariantList;
+typedef PdfArray::iterator       TIVariantList;
+typedef PdfArray::const_iterator TCIVariantList;
+
+};
+
+#endif // _PDF_ARRAY_H_
diff --git a/src/podofo/base/PdfCanvas.cpp b/src/podofo/base/PdfCanvas.cpp
new file mode 100644 (file)
index 0000000..3f96262
--- /dev/null
@@ -0,0 +1,152 @@
+/***************************************************************************
+ *   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 {
+
+const PdfArray PdfCanvas::GetProcSet()
+{
+    PdfArray procset;
+    procset.push_back( PdfName( "PDF" ) );
+    procset.push_back( PdfName( "Text" ) );
+    procset.push_back( PdfName( "ImageB" ) );
+    procset.push_back( PdfName( "ImageC" ) );
+    procset.push_back( PdfName( "ImageI" ) );
+    
+    return 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->MustGetIndirectKey( "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->MustGetIndirectKey( "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 );
+    }
+}
+
+};
+
diff --git a/src/podofo/base/PdfCanvas.h b/src/podofo/base/PdfCanvas.h
new file mode 100644 (file)
index 0000000..8dc11ba
--- /dev/null
@@ -0,0 +1,108 @@
+/***************************************************************************
+ *   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 copy of procset PdfArray.
+     *  \returns a 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 );
+
+};
+
+};
+
+#endif /* _PDF_CANVAS_H_ */
diff --git a/src/podofo/base/PdfColor.cpp b/src/podofo/base/PdfColor.cpp
new file mode 100644 (file)
index 0000000..1298022
--- /dev/null
@@ -0,0 +1,1257 @@
+/***************************************************************************
+ *   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 <algorithm>
+#include <ctype.h>
+
+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<unsigned long>(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<double>(R)/255.0, 
+                             static_cast<double>(G)/255.0, 
+                             static_cast<double>(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<unsigned int>(PdfTokenizer::GetHexValue( *pszName++ ));
+                const unsigned int R_LO = static_cast<unsigned int>(PdfTokenizer::GetHexValue( *pszName++ ));
+                const unsigned int R = (R_HI << 4) | R_LO;
+                
+                const unsigned int G_HI = static_cast<unsigned int>(PdfTokenizer::GetHexValue( *pszName++ ));
+                const unsigned int G_LO = static_cast<unsigned int>(PdfTokenizer::GetHexValue( *pszName++ ));
+                const unsigned int G = (G_HI << 4) | G_LO;
+
+                const unsigned int B_HI = static_cast<unsigned int>(PdfTokenizer::GetHexValue( *pszName++ ));
+                const unsigned int B_LO = static_cast<unsigned int>(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<double>(R)/255.0, 
+                                     static_cast<double>(G)/255.0, 
+                                     static_cast<double>(B)/255.0 );
+                }
+                else
+                {
+                    PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor );
+                }
+            }
+            else if( lLen == 9 ) // CMYK
+            {
+                const unsigned int C_HI = static_cast<unsigned int>(PdfTokenizer::GetHexValue( *pszName++ ));
+                const unsigned int C_LO = static_cast<unsigned int>(PdfTokenizer::GetHexValue( *pszName++ ));
+                const unsigned int C = (C_HI << 4) | C_LO;
+                
+                const unsigned int M_HI = static_cast<unsigned int>(PdfTokenizer::GetHexValue( *pszName++ ));
+                const unsigned int M_LO = static_cast<unsigned int>(PdfTokenizer::GetHexValue( *pszName++ ));
+                const unsigned int M = (M_HI << 4) | M_LO;
+
+                const unsigned int Y_HI = static_cast<unsigned int>(PdfTokenizer::GetHexValue( *pszName++ ));
+                const unsigned int Y_LO = static_cast<unsigned int>(PdfTokenizer::GetHexValue( *pszName++ ));
+                const unsigned int Y = (Y_HI << 4) | Y_LO;
+
+                const unsigned int K_HI = static_cast<unsigned int>(PdfTokenizer::GetHexValue( *pszName++ ));
+                const unsigned int K_LO = static_cast<unsigned int>(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<double>(C)/255.0, 
+                                     static_cast<double>(M)/255.0, 
+                                     static_cast<double>(Y)/255.0,
+                                     static_cast<double>(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<const PdfNamedColor*, const PdfNamedColor*> 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<pdf_int64>(8) );
+
+            PdfArray decode;
+            decode.push_back( static_cast<pdf_int64>(0) );
+            decode.push_back( static_cast<pdf_int64>(1) );
+            decode.push_back( static_cast<pdf_int64>(0) );
+            decode.push_back( static_cast<pdf_int64>(1) );
+            decode.push_back( static_cast<pdf_int64>(0) );
+            decode.push_back( static_cast<pdf_int64>(1) );
+            decode.push_back( static_cast<pdf_int64>(0) );
+            decode.push_back( static_cast<pdf_int64>(1) );
+            csTintFunc->GetDictionary().AddKey( "Decode", decode );
+
+            PdfArray domain;
+            domain.push_back( static_cast<pdf_int64>(0) );
+            domain.push_back( static_cast<pdf_int64>(1) );
+            csTintFunc->GetDictionary().AddKey( "Domain", domain );
+
+            PdfArray encode;
+            encode.push_back( static_cast<pdf_int64>(0) );
+            encode.push_back( static_cast<pdf_int64>(1) );
+            csTintFunc->GetDictionary().AddKey( "Encode", encode );
+
+            csTintFunc->GetDictionary().AddKey( "Filter", PdfName( "FlateDecode" ) );
+            csTintFunc->GetDictionary().AddKey( "FunctionType", PdfVariant( static_cast<pdf_int64>(0L) ) );
+            //csTintFunc->GetDictionary().AddKey( "FunctionType", 
+            //                                    PdfVariant( static_cast<pdf_int64>(ePdfFunctionType_Sampled) ) );
+
+            switch ( m_eAlternateColorSpace )
+            {
+                case ePdfColorSpace_DeviceGray:
+                {
+                    char data[1*2];
+                    data[0] = 0;
+                    data[1] = static_cast<char> (m_uColor.gray);
+
+                    PdfArray range;
+                    range.push_back( static_cast<pdf_int64>(0) );
+                    range.push_back( static_cast<pdf_int64>(1) );
+                    csTintFunc->GetDictionary().AddKey( "Range", range );
+
+                    PdfArray size;
+                    size.push_back( static_cast<pdf_int64>(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<char> (m_uColor.rgb[0] * 255);
+                    data[4] = static_cast<char> (m_uColor.rgb[1] * 255);
+                    data[5] = static_cast<char> (m_uColor.rgb[2] * 255);
+
+                    PdfArray range;
+                    range.push_back( static_cast<pdf_int64>(0) );
+                    range.push_back( static_cast<pdf_int64>(1) );
+                    range.push_back( static_cast<pdf_int64>(0) );
+                    range.push_back( static_cast<pdf_int64>(1) );
+                    range.push_back( static_cast<pdf_int64>(0) );
+                    range.push_back( static_cast<pdf_int64>(1) );
+                    csTintFunc->GetDictionary().AddKey( "Range", range );
+
+                    PdfArray size;
+                    size.push_back( static_cast<pdf_int64>(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<char> (m_uColor.cmyk[0] * 255);
+                    data[5] = static_cast<char> (m_uColor.cmyk[1] * 255);
+                    data[6] = static_cast<char> (m_uColor.cmyk[2] * 255);
+                    data[7] = static_cast<char> (m_uColor.cmyk[3] * 255);
+
+                    PdfArray range;
+                    range.push_back( static_cast<pdf_int64>(0) );
+                    range.push_back( static_cast<pdf_int64>(1) );
+                    range.push_back( static_cast<pdf_int64>(0) );
+                    range.push_back( static_cast<pdf_int64>(1) );
+                    range.push_back( static_cast<pdf_int64>(0) );
+                    range.push_back( static_cast<pdf_int64>(1) );
+                    range.push_back( static_cast<pdf_int64>(0) );
+                    range.push_back( static_cast<pdf_int64>(1) );
+                    csTintFunc->GetDictionary().AddKey( "Range", range );
+
+                    PdfArray size;
+                    size.push_back( static_cast<pdf_int64>(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<char> (m_uColor.lab[0] * 255);
+                    data[4] = static_cast<char> (m_uColor.lab[1] * 255);
+                    data[5] = static_cast<char> (m_uColor.lab[2] * 255);
+
+                    PdfArray range;
+                    range.push_back( static_cast<pdf_int64>(0) );
+                    range.push_back( static_cast<pdf_int64>(1) );
+                    range.push_back( static_cast<pdf_int64>(0) );
+                    range.push_back( static_cast<pdf_int64>(1) );
+                    range.push_back( static_cast<pdf_int64>(0) );
+                    range.push_back( static_cast<pdf_int64>(1) );
+                    csTintFunc->GetDictionary().AddKey( "Range", range );
+
+                    PdfArray size;
+                    size.push_back( static_cast<pdf_int64>(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<pdf_int64>(-128) );
+            rangeArr.push_back( static_cast<pdf_int64>(127) );
+            rangeArr.push_back( static_cast<pdf_int64>(-128) );
+            rangeArr.push_back( static_cast<pdf_int64>(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();
+    }
+    
+}
+
+};
+
diff --git a/src/podofo/base/PdfColor.h b/src/podofo/base/PdfColor.h
new file mode 100644 (file)
index 0000000..fc4b72d
--- /dev/null
@@ -0,0 +1,900 @@
+/***************************************************************************
+ *   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_
diff --git a/src/podofo/base/PdfCompilerCompat.h b/src/podofo/base/PdfCompilerCompat.h
new file mode 100644 (file)
index 0000000..146731d
--- /dev/null
@@ -0,0 +1,256 @@
+/***************************************************************************
+ *   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_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 <stddef.h>
+#else
+#  include <cstddef>
+#endif
+
+#if defined(TEST_BIG)
+#  define PODOFO_IS_BIG_ENDIAN
+#else
+#  define PODOFO_IS_LITTLE_ENDIAN
+#endif
+
+#if PODOFO_HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#if PODOFO_HAVE_BASETSD_H
+#include <BaseTsd.h>
+#endif
+
+#if PODOFO_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#if PODOFO_HAVE_MEM_H
+#include <mem.h>
+#endif
+
+#if PODOFO_HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+#if PODOFO_HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+// alloca() is defined only in <cstdlib> on Mac OS X,
+// only in <malloc.h> on win32, and in both on Linux.
+#if defined(_WIN32)
+#include <malloc.h>
+#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"
+#  define PDF_SIZE_FORMAT "Iu"
+#elif defined(SZ_INT64) && defined(SZ_LONG) && SZ_INT64 == SZ_LONG
+#  define PDF_FORMAT_INT64 "ld"
+#  define PDF_FORMAT_UINT64 "lu"
+#  define PDF_SIZE_FORMAT "zu"
+#else
+#  define PDF_FORMAT_INT64 "lld"
+#  define PDF_FORMAT_UINT64 "llu"
+#  define PDF_SIZE_FORMAT "zu"
+#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)
+
+/**
+ * \page PoDoFo PdfCompilerCompat Header
+ * 
+ * <b>PdfCompilerCompat.h</b> 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
diff --git a/src/podofo/base/PdfCompilerCompatPrivate.h b/src/podofo/base/PdfCompilerCompatPrivate.h
new file mode 100644 (file)
index 0000000..5db483d
--- /dev/null
@@ -0,0 +1,276 @@
+/***************************************************************************
+ *   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_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 "<cmath>" but provides a usable "math.h"
+   // and it needs a bunch of other includes
+#  include <stdlib.h>
+#  include <stdio.h>
+#  include <string.h>
+#  include <math.h>
+#  include <time.h>
+#else
+   // We can use the ISO C++ headers with other compilers
+#  include <cstdlib>
+#  include <cstdio>
+#  include <cmath>
+#  include <cstring>
+#  include <ctime>
+#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 <winsock2.h>       // This will include windows.h, so we have to define _WIN32_WINNT
+                                    // if we want to use threads later.
+#        undef _WIN32_WINNT 
+#      else
+#        include <winsock2.h>
+#      endif // _WIN32_WINNT
+#    endif // _WIN32 || _WIN64
+#  else
+#    include <winsock2.h>
+#  endif // PODOFO_MULTI_THREAD
+#endif
+
+#if PODOFO_HAVE_ARPA_INET_H
+#  include <arpa/inet.h>
+#endif
+
+#ifdef PODOFO_MULTI_THREAD
+#  if defined(_WIN32) || defined(_WIN64)
+#    if defined(_MSC_VER) && !defined(_WINSOCK2API_)
+#      error <winsock2.h> must be included before <windows.h>, config problem?
+#    endif
+#    ifndef _WIN32_WINNT
+#      define _WIN32_WINNT 0x0400 // Make the TryEnterCriticalSection method available
+#      include <windows.h>
+#      undef _WIN32_WINNT 
+#    else
+#      include <windows.h>
+#    endif // _WIN32_WINNT
+#  else
+#    include <pthread.h>
+#  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<pdf_uint32>( 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<pdf_uint16>( 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<pdf_uint32>( 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<pdf_uint16>( 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 <typename T>
+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: <afx.h>  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 <malloc.h>
+  #include <crtdbg.h>
+  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 <xdebug>
+  // // #define new _NEW_CRT
+#endif // _DEBUG
+#endif // _MSC_VER
+
+// prefer std::unique_ptr over std::auto_ptr
+#ifdef PODOFO_HAVE_UNIQUE_PTR
+#define PODOFO_UNIQUEU_PTR std::unique_ptr
+#else
+#define PODOFO_UNIQUEU_PTR std::auto_ptr
+#endif
+
+/**
+ * \page PoDoFo PdfCompilerCompatPrivate Header
+ * 
+ * <b>PdfCompilerCompatPrivate.h</b> 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
diff --git a/src/podofo/base/PdfContentsTokenizer.cpp b/src/podofo/base/PdfContentsTokenizer.cpp
new file mode 100644 (file)
index 0000000..03e1fd5
--- /dev/null
@@ -0,0 +1,288 @@
+/***************************************************************************
+ *   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 <iostream>
+
+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( const PdfObject* pObject )
+{
+    PODOFO_RAISE_LOGIC_IF( pObject == NULL, "Content stream object == NULL!" );
+
+    const PdfStream* pStream = pObject->GetStream();
+
+    PdfRefCountedBuffer buffer(0);
+    PdfBufferOutputStream stream( &buffer );
+    if( pStream )
+        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<size_t>(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<pdf_int64>(m_buffer.GetSize())) 
+        {
+            // image is larger than buffer => resize buffer
+            m_buffer.Resize(m_buffer.GetSize()*2);
+        }
+    }
+    
+    return false;
+}
+};
diff --git a/src/podofo/base/PdfContentsTokenizer.h b/src/podofo/base/PdfContentsTokenizer.h
new file mode 100644 (file)
index 0000000..7b32218
--- /dev/null
@@ -0,0 +1,133 @@
+/***************************************************************************
+ *   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 <list>
+
+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( const PdfObject* pObject );
+    bool ReadInlineImgData(EPdfContentsType& reType, const char*& rpszKeyword, PoDoFo::PdfVariant & rVariant);
+
+ private:
+    std::list<PdfObject*>     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_
+
diff --git a/src/podofo/base/PdfData.cpp b/src/podofo/base/PdfData.cpp
new file mode 100644 (file)
index 0000000..824baba
--- /dev/null
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *   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() );
+}
+
+};
diff --git a/src/podofo/base/PdfData.h b/src/podofo/base/PdfData.h
new file mode 100644 (file)
index 0000000..3d7114d
--- /dev/null
@@ -0,0 +1,136 @@
+/***************************************************************************
+ *   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_ */
+
diff --git a/src/podofo/base/PdfDataType.cpp b/src/podofo/base/PdfDataType.cpp
new file mode 100644 (file)
index 0000000..95269d4
--- /dev/null
@@ -0,0 +1,60 @@
+/***************************************************************************
+ *   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
+}
+
+};
+
+
diff --git a/src/podofo/base/PdfDataType.h b/src/podofo/base/PdfDataType.h
new file mode 100644 (file)
index 0000000..006ef2e
--- /dev/null
@@ -0,0 +1,155 @@
+/***************************************************************************
+ *   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_ */
+
diff --git a/src/podofo/base/PdfDate.cpp b/src/podofo/base/PdfDate.cpp
new file mode 100644 (file)
index 0000000..cefa221
--- /dev/null
@@ -0,0 +1,290 @@
+/***************************************************************************
+ *   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 <string.h>
+#include <sstream>
+namespace  {
+
+/** Parse fixed length number from string
+  *  \param in string to read number from
+  *  \param length exact number characters to read
+  *  \param min minimal value of number
+  *  \param max maximal value of number
+  *  \param ret parsed number (updated only on success)
+  */
+enum EParseFixLenNumberResult {Ok, Missing, Error};
+EParseFixLenNumberResult ParseFixLenNumber(const char *&in, unsigned int length, int min, int max, int &ret_)
+{
+    if ( in == NULL || *in == '\0' || *in == '+' || *in == '-' || *in == 'Z') return Missing;
+    int ret = 0;
+    for(unsigned int i=0;i<length;i++)
+    {
+        if ( in == NULL || !isdigit(*in)) return Error;
+        ret = ret*10+ (*in-'0');
+        in++;
+    }
+    if ( ret < min || ret > max ) return Error;
+    ret_ = ret;
+    return Ok;
+}
+
+bool ParseOptionalFields(const char *&pszDate, tm& _tm)
+{
+    EParseFixLenNumberResult res = ParseFixLenNumber(pszDate,2,1,12,_tm.tm_mon);
+    if ( res == Error )
+    {
+        return false;
+    }
+    else if( res == Missing)
+    {
+        return true;
+    }
+    _tm.tm_mon--;
+
+    res = ParseFixLenNumber(pszDate,2,1,31,_tm.tm_mday);
+    if ( res == Error )
+    {
+        return false;
+    }
+    else if( res == Missing)
+    {
+        return true;
+    }
+
+    res = ParseFixLenNumber(pszDate,2,0,23,_tm.tm_hour);
+    if ( res == Error )
+    {
+        return false;
+    }
+    else if( res == Missing)
+    {
+        return true;
+    }
+
+    res = ParseFixLenNumber(pszDate,2,0,59,_tm.tm_min);
+    if ( res == Error )
+    {
+        return false;
+    }
+    else if( res == Missing)
+    {
+        return true;
+    }
+
+    res = ParseFixLenNumber(pszDate,2,0,59,_tm.tm_sec);
+    if ( res == Error )
+    {
+        return false;
+    }
+    return true;
+}
+
+
+time_t ParseZoneShift(const char *&pszDate, tm& _tm)
+{
+    int nZoneShift = 0;
+    int nZoneHour = 0;
+    int nZoneMin = 0;
+
+    if ( *pszDate != '\0' )
+    {
+        switch (*pszDate) {
+        case '+':
+            nZoneShift = -1;
+            break;
+        case '-':
+            nZoneShift = 1;
+            break;
+        case 'Z':
+            nZoneShift = 0;
+            break;
+        default:
+            return time_t(-1);
+        }
+        pszDate++;
+        if ( ParseFixLenNumber(pszDate,2,0,59,nZoneHour) != Ok)
+        {
+            return time_t(-1);
+        }
+        if (*pszDate == '\'') {
+            pszDate++;
+            if ( ParseFixLenNumber(pszDate,2,0,59,nZoneMin) != Ok)
+            {
+                return time_t(-1);
+            }
+            if (*pszDate != '\'')
+            {
+                return time_t(-1);
+            }
+            pszDate++;
+        }
+    }
+    if ( *pszDate != '\0' ) 
+    {
+        return time_t(-1);
+    }
+
+    // convert to 
+    time_t m_time = mktime(&_tm);
+    if ( m_time == -1 ) 
+    {
+        return m_time;
+    }
+
+    m_time += nZoneShift*(nZoneHour*3600 + nZoneMin*60);
+    return m_time;
+}
+
+}
+
+namespace PoDoFo {
+
+PdfDate::PdfDate()
+    : m_bValid( false )
+{
+    m_time = time( &m_time );
+    CreateStringRepresentation();
+}
+
+PdfDate::PdfDate( const time_t & t )
+    : m_time( t ), m_bValid( false )
+{
+    CreateStringRepresentation();
+}
+
+PdfDate::PdfDate( const PdfString & sDate )
+    : m_time( -1 ), m_bValid( false )
+{
+    if ( !sDate.IsValid() )
+    {
+        m_szDate[0] = 0;
+        return;
+    }
+
+    strncpy(m_szDate,sDate.GetString(),PDF_DATE_BUFFER_SIZE);
+
+    struct tm _tm{};
+    _tm.tm_mday = 1;
+
+    const char * pszDate = sDate.GetString();
+    if ( pszDate == NULL ) return;
+    if ( *pszDate == 'D' ) {
+        pszDate++;
+        if ( *pszDate++ != ':' ) return;
+    }
+
+    // year is not optional
+    if ( ParseFixLenNumber(pszDate,4,0,9999,_tm.tm_year) != Ok)
+        return;
+    _tm.tm_year -= 1900;
+
+    // all other values are optional, if not set they are 0-init (except mday)
+    if(!ParseOptionalFields(pszDate, _tm))
+    {
+        return;
+    }
+
+    // zone is optional
+    m_time = ParseZoneShift(pszDate, _tm);
+    m_bValid = ( m_time != -1);
+}
+
+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* pstm = localtime( &m_time );
+    if( !pstm )
+    {
+        std::ostringstream ss;
+        ss << "Invalid date specified with time_t value " << m_time << "\n";
+        PdfError::DebugMessage( ss.str().c_str() );
+        strcpy( m_szDate, INVALIDDATE );
+        return;
+    }
+
+    struct tm stm = *pstm;
+
+#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<int>( 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;
+}
+
+};
diff --git a/src/podofo/base/PdfDate.h b/src/podofo/base/PdfDate.h
new file mode 100644 (file)
index 0000000..a51a9f9
--- /dev/null
@@ -0,0 +1,146 @@
+/***************************************************************************
+ *   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 <ctime>
+
+// 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();
+
+ 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_
diff --git a/src/podofo/base/PdfDefines.h b/src/podofo/base/PdfDefines.h
new file mode 100644 (file)
index 0000000..770adc6
--- /dev/null
@@ -0,0 +1,552 @@
+/***************************************************************************
+ *   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 <wchar.h>
+
+// Include common STL files
+#include <map>
+#include <string>
+#include <vector>
+#include <set>
+
+// Include common BOOST settings 
+#ifdef PODOFO_HAVE_BOOST
+#include <boost/config.hpp>
+#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 <assert.h>
+#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 {
+    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 &lt;AF00BE&gt; 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 = 0xff         /**< The Datatype is unknown. The value is chosen to enable value storage in 8-bit unsigned integer. */
+};
+
+/**
+ * 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 <typename T> const T PDF_MAX ( const T a, const T b ) {
+  return (b<a)?a:b;
+}
+
+/**
+ * PDF_MIN(x,y)
+ * \returns the minimum 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 <typename T> const T PDF_MIN ( const T a, const T b ) {
+  return (a<b)?a:b;
+}
+
+#ifndef PODOFO_CONVERSION_CONSTANT
+#define PODOFO_CONVERSION_CONSTANT 0.002834645669291339
+#endif // PODOFO_CONVERSION_CONSTANT
+
+}; // end namespace PoDoFo
+
+/**
+ * \mainpage
+ *
+ * <b>PoDoFo</b> 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 <b>PoDoFo</b> 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 <b>PoDoFo</b> tools are simple tools build around the <b>PoDoFo</b> library. These tools
+ * are first of all examples on how to use the <b>PoDoFo</b> 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 <b>PoDoFoBrowser</b> which is not included in
+ * this package, but can be downloaded from the <b>PoDoFo</b> webpage. <b>PoDoFoBrowser</b> 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 <b>PoDoFo</b> is available for Unix, Mac OS X and Windows platforms. 
+ *
+ * More information can be found at: http://podofo.sourceforge.net
+ *
+ * <b>PoDoFo</b> is created by Dominik Seichter <domseichter@web.de>, 
+ * Leonard Rosenthol <leonardr@pdfsages.com> and Craig Ringer <craig@postnewspapers.com.au>
+ *
+ * \page Codingstyle (Codingstyle)
+ * \verbinclude CODINGSTYLE.txt
+ *
+ */
+
+#endif // !PODOFO_COMPILE_RC
+
+#endif // _PDF_DEFINES_H_
diff --git a/src/podofo/base/PdfDefinesPrivate.h b/src/podofo/base/PdfDefinesPrivate.h
new file mode 100644 (file)
index 0000000..48fa126
--- /dev/null
@@ -0,0 +1,22 @@
+#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 <PoDoFo PdfDefinesPrivate Header>
+ *
+ * <b>PdfDefinesPrivate.h</b> 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
diff --git a/src/podofo/base/PdfDictionary.cpp b/src/podofo/base/PdfDictionary.cpp
new file mode 100644 (file)
index 0000000..b085c60
--- /dev/null
@@ -0,0 +1,411 @@
+/***************************************************************************
+ *   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 )
+    : PdfOwnedDataType()
+{
+    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;
+    }
+
+    PdfOwnedDataType::operator=( rhs );
+    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 );
+    }
+    */
+    PdfObject *objToInsert = new PdfObject(rObject);
+    std::pair<TKeyMap::iterator, bool> inserted = m_mapKeys.insert( std::make_pair( identifier, objToInsert ) );
+    if ( !inserted.second )
+    {
+        delete inserted.first->second;
+        inserted.first->second = objToInsert;
+    }
+
+    PdfVecObjects *pOwner = GetObjectOwner();
+    if ( pOwner != NULL )
+        inserted.first->second->SetOwner( pOwner );
+    m_bDirty = true;
+}
+
+void PdfDictionary::AddKey( const PdfName & identifier, const PdfObject* pObject )
+{
+    this->AddKey( identifier, *pObject );
+}
+
+PdfObject * PdfDictionary::getKey( const PdfName & key ) const
+{
+    if( !key.GetLength() )
+        return NULL;
+
+    TCIKeyMap it;
+
+    it = m_mapKeys.find( key );
+
+    if( it == m_mapKeys.end() )
+        return NULL;
+
+    return (*it).second;
+}
+
+PdfObject * PdfDictionary::findKey( const PdfName &key ) const
+{
+    PdfObject *obj = getKey( key );
+    if ( obj != NULL )
+    {
+        if ( obj->IsReference() )
+            return GetIndirectObject( obj->GetReference() );
+        else
+            return obj;
+    }
+
+    return NULL;
+}
+
+PdfObject * PdfDictionary::findKeyParent( const PdfName & key ) const
+{
+    PdfObject *obj = findKey( key );
+    if (obj == NULL)
+    {
+        PdfObject *parent = findKey( "Parent" );
+        if ( parent == NULL )
+        {
+            return NULL;
+        }
+        else
+        {
+            if ( parent->IsDictionary() )
+                return parent->GetDictionary().findKeyParent( key );
+            else
+                return NULL;
+        }
+    }
+    else
+    {
+        return obj;
+    }
+}
+
+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 )
+{
+    TKeyMap::iterator found = m_mapKeys.find( identifier );
+    if( found != m_mapKeys.end() )
+    {
+        AssertMutable();
+        delete found->second;
+        m_mapKeys.erase( found );
+        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;
+        }
+    }
+}
+
+TCIKeyMap PdfDictionary::begin() const
+{
+    return m_mapKeys.begin();
+}
+
+TCIKeyMap PdfDictionary::end() const
+{
+    return m_mapKeys.end();
+}
+
+void PdfDictionary::SetOwner( PdfObject *pOwner )
+{
+    PdfOwnedDataType::SetOwner( pOwner );
+    PdfVecObjects *pVecOwner = pOwner->GetOwner();
+    if ( pVecOwner != NULL )
+    {
+        // Set owmership for all children
+        TCIKeyMap it = this->begin();
+        TCIKeyMap end = this->end();
+        for ( ; it != end; it++ )
+            it->second->SetOwner( pVecOwner );
+    }
+}
+
+};
diff --git a/src/podofo/base/PdfDictionary.h b/src/podofo/base/PdfDictionary.h
new file mode 100644 (file)
index 0000000..373bc79
--- /dev/null
@@ -0,0 +1,433 @@
+/***************************************************************************
+ *   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 "PdfOwnedDataType.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 <tr1/unordered_map>
+#endif // PODOFO_USE_ORDERED_MAP
+
+namespace PoDoFo {
+
+#ifdef PODOFO_USE_UNORDERED_MAP
+class PdfNameHash : public std::unary_function<PdfName, size_t>
+{
+public:
+    size_t operator()( const PdfName& v ) const
+    {
+        std::tr1::hash<std::string> hasher;
+        
+        return hasher( v.GetName() );
+    }
+};
+
+typedef std::tr1::unordered_map<PdfName,PdfObject*, PdfNameHash>      TKeyMap;
+#else
+typedef std::map<PdfName,PdfObject*>      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 PdfOwnedDataType {
+ 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 pObject pointer to 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 key's 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 named key in the dictionary
+     * 
+     *  \returns pointer to the found value, or 0 if the key was not found.
+     */
+    inline const PdfObject* GetKey( const PdfName & key ) const;
+
+    /** Get the key's 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.
+     */
+    inline PdfObject* GetKey( const PdfName & key );
+
+    /** Get the keys value out of the dictionary
+     *
+     * Lookup in the indirect objects as well, if the shallow object was a reference.
+     * 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.
+     */
+    inline const PdfObject* FindKey( const PdfName & key ) const;
+    inline PdfObject* FindKey( const PdfName & key );
+
+    /** Get the keys value out of the dictionary
+     *
+     * Lookup in the indirect objects as well, if the shallow object was a reference.
+     * Also lookup the parent objects, if /Parent key is found in 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.
+     */
+    inline const PdfObject* FindKeyParent( const PdfName & key ) const;
+    inline PdfObject* FindKeyParent( const PdfName & key );
+
+    /** Get the key's value out of the dictionary.
+     *
+     * The returned value is a reference to the internal object in the dictionary
+     * so it MUST not be deleted. If the key is not found, this throws a PdfError
+     * exception with error code ePdfError_NoObject, instead of returning.
+     * This is intended to make code more readable by sparing (especially multiple)
+     * NULL checks.
+     *
+     *  \param key look for the key named key in the dictionary
+     * 
+     *  \returns reference to the found value (never 0).
+     *  \throws PdfError(ePdfError_NoObject).
+     */
+    inline const PdfObject& MustGetKey( const PdfName & key ) const;
+
+    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 exist, 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 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;
+
+    /**
+    *  \returns the size of the internal map
+    */
+    inline size_t GetSize() 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 );
+
+ public:
+     TCIKeyMap begin() const;
+     TCIKeyMap end() const;
+
+ protected:
+     void SetOwner( PdfObject* pOwner );
+
+ private:
+     PdfObject * getKey(const PdfName & key) const;
+     PdfObject * findKey(const PdfName & key) const;
+     PdfObject * findKeyParent(const PdfName & key) const;
+
+ private: 
+    TKeyMap      m_mapKeys; 
+
+    bool         m_bDirty; ///< Indicates if this object was modified after construction
+};
+
+typedef std::vector<PdfDictionary*>      TVecDictionaries; 
+typedef        TVecDictionaries::iterator       TIVecDictionaries; 
+typedef        TVecDictionaries::const_iterator TCIVecDictionaries;
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+inline const PdfObject * PdfDictionary::GetKey( const PdfName &key ) const
+{
+    return getKey(key);
+}
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+inline PdfObject * PdfDictionary::GetKey( const PdfName &key )
+{
+    return getKey(key);
+}
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+inline const PdfObject * PdfDictionary::FindKey( const PdfName &key ) const
+{
+    return findKey(key);
+}
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+inline PdfObject * PdfDictionary::FindKey( const PdfName &key )
+{
+    return findKey(key);
+}
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+inline const PdfObject* PdfDictionary::FindKeyParent( const PdfName &key ) const
+{
+    return findKeyParent(key);
+}
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+inline PdfObject* PdfDictionary::FindKeyParent( const PdfName &key )
+{
+    return findKeyParent(key);
+}
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+size_t PdfDictionary::GetSize() const
+{
+    return m_mapKeys.size();
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+const TKeyMap & PdfDictionary::GetKeys() const 
+{ 
+    return m_mapKeys; 
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+TKeyMap & PdfDictionary::GetKeys() 
+{ 
+    return m_mapKeys; 
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+const PdfObject& PdfDictionary::MustGetKey( const PdfName & key ) const
+{
+    const PdfObject* obj = GetKey( key );
+    if (!obj)
+        PODOFO_RAISE_ERROR( ePdfError_NoObject );
+    return *obj;
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+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_
diff --git a/src/podofo/base/PdfEncoding.cpp b/src/podofo/base/PdfEncoding.cpp
new file mode 100644 (file)
index 0000000..0321f87
--- /dev/null
@@ -0,0 +1,2680 @@
+/***************************************************************************
+ *   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 <stack>
+#include <stdlib.h>
+#include <string.h>
+#include <limits>
+#include <sstream>
+#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<const pdf_utf16be*>(rEncodedString.GetString());
+        const size_t lLen = rEncodedString.GetLength()/2;
+        pdf_utf16be lCID, lUnicodeValue;
+        
+        pdf_utf16be* pszUtf16 = static_cast<pdf_utf16be*>(podofo_calloc(lLen, sizeof(pdf_utf16be)));
+        if( !pszUtf16 )
+        {
+            PODOFO_RAISE_ERROR( ePdfError_OutOfMemory );
+        }
+        
+        for(size_t i = 0 ; i<lLen ; i++)
+        {
+            
+#ifdef PODOFO_IS_LITTLE_ENDIAN
+            lCID = (pStr[i] << 8) | (pStr[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<pdf_utf16be>(pFont->GetFontMetrics()->GetGlyphId( (((*pStr & 0xff) << 8) | ((*pStr & 0xff00) >> 8)) ));
+#else
+                lCID = static_cast<pdf_utf16be>(pFont->GetFontMetrics()->GetGlyphId( *pStr ));
+#endif // PODOFO_IS_LITTLE_ENDIAN
+            }
+            
+            out << static_cast<unsigned char>((lCID & 0xff00) >> 8);
+            out << static_cast<unsigned char>(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<std::string> 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)
+            {
+                // need 2 entries - one to pop() and one for top()
+                if ( stkToken.size() < 2 )
+                {
+                    PODOFO_RAISE_ERROR_INFO(ePdfError_InvalidStream, "CMap missing object number before beginbfrange");
+                }
+                
+                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)
+            {
+                // need 2 entries - one to pop() and one for top()
+                if ( stkToken.size() < 2 )
+                {
+                    PODOFO_RAISE_ERROR_INFO(ePdfError_InvalidStream, "CMap missing object number before beginbfchar");
+                }
+                
+                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<pdf_utf16be, pdf_utf16be>::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<pdf_utf16be, pdf_utf16be>::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 );
+       // CVE-2017-7379 - previously lTableLength was 0xffff, but pdf_utf16be characters can be in range 0..0xffff so this
+       // caused out-by-one heap overflow when character 0xffff was encoded
+    const long         lTableLength     = std::numeric_limits<pdf_utf16be>::max() + 1;
+    const pdf_utf16be* cpUnicodeTable   = this->GetToUnicodeTable();
+
+    if( !m_pEncodingTable ) // double check
+    {
+        m_pEncodingTable = static_cast<char*>(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<size_t>(cpUnicodeTable[i]) ] = 
+                static_cast<unsigned char>(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<pdf_utf16be*>(podofo_calloc( (lLen + 1), sizeof(pdf_utf16be)));
+        if( !pszStringUtf16 )
+        {
+            PODOFO_RAISE_ERROR( ePdfError_OutOfMemory );
+        }
+        
+        const char* pszString = rEncodedString.GetString();
+        for( int i=0;i<lLen;i++ )
+        {
+#ifdef PODOFO_IS_BIG_ENDIAN
+            pszStringUtf16[i] = cpUnicodeTable[ static_cast<unsigned char>(*pszString) ];
+#else
+            pszStringUtf16[i] =
+            ((( cpUnicodeTable[ static_cast<unsigned char>(*pszString) ] << 8 ) & 0xff00) |
+             (( cpUnicodeTable[ static_cast<unsigned char>(*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<PdfSimpleEncoding*>(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<char*>(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<lLen;i++ )
+        {
+            pdf_utf16be val = pszUtf16[i];
+#ifdef PODOFO_IS_LITTLE_ENDIAN
+            val = ((val & 0xff00) >> 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<PdfSimpleEncoding*>(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
+    0x0000,  // CC undefined
+    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,  // <control>
+    0x0081,  // <control>
+    0x0082,  // <control>
+    0x0083,  // <control>
+    0x0084,  // <control>
+    0x0085,  // <control>
+    0x0086,  // <control>
+    0x0087,  // <control>
+    0x0088,  // <control>
+    0x0089,  // <control>
+    0x008A,  // <control>
+    0x008B,  // <control>
+    0x008C,  // <control>
+    0x008D,  // <control>
+    0x008E,  // <control>
+    0x008F,  // <control>
+    0x0090,  // <control>
+    0x0091,  // <control>
+    0x0092,  // <control>
+    0x0093,  // <control>
+    0x0094,  // <control>
+    0x0095,  // <control>
+    0x0096,  // <control>
+    0x0097,  // <control>
+    0x0098,  // <control>
+    0x0099,  // <control>
+    0x009A,  // <control>
+    0x009B,  // <control>
+    0x009C,  // <control>
+    0x009D,  // <control>
+    0x009E,  // <control>
+    0x009F,  // <control>
+    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 */
diff --git a/src/podofo/base/PdfEncoding.h b/src/podofo/base/PdfEncoding.h
new file mode 100644 (file)
index 0000000..47bcada
--- /dev/null
@@ -0,0 +1,822 @@
+/***************************************************************************
+ *   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 <iterator>
+
+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
+    const PdfObject* m_pToUnicode;    ///< Pointer to /ToUnicode object, if any
+ protected:
+    std::map<pdf_utf16be, pdf_utf16be> m_toUnicode;
+               
+    pdf_utf16be GetUnicodeValue( pdf_utf16be ) const;
+ private:
+    
+    /** Parse the /ToUnicode object
+    */
+    void ParseToUnicode();
+    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()
+    {
+        m_id = "Win1250Encoding";
+    }
+
+ protected:
+
+    virtual const PdfName & GetID() const
+    {
+        return m_id;
+    }
+
+    /** 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
+    PdfName m_id;
+};
+
+/**
+* ISO-8859-2 encoding
+*/
+class PODOFO_API PdfIso88592Encoding : public PdfWinAnsiEncoding
+{
+ public:
+   
+    /** Create a new PdfIso88592Encoding
+     */
+    PdfIso88592Encoding()
+    {
+        m_id = "Iso88592Encoding";
+    }
+
+ protected:
+
+    virtual const PdfName & GetID() const
+    {
+        return m_id;
+    }
+
+    /** 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
+    PdfName m_id;
+};
+
+}; /* namespace PoDoFo */
+
+
+#endif // _PDF_ENCODING_H_
+
diff --git a/src/podofo/base/PdfEncodingFactory.cpp b/src/podofo/base/PdfEncodingFactory.cpp
new file mode 100644 (file)
index 0000000..dc50f49
--- /dev/null
@@ -0,0 +1,266 @@
+/***************************************************************************
+ *   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++;
+}
+
+};
diff --git a/src/podofo/base/PdfEncodingFactory.h b/src/podofo/base/PdfEncodingFactory.h
new file mode 100644 (file)
index 0000000..be374b4
--- /dev/null
@@ -0,0 +1,227 @@
+/***************************************************************************
+ *   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__
+
diff --git a/src/podofo/base/PdfEncrypt.cpp b/src/podofo/base/PdfEncrypt.cpp
new file mode 100644 (file)
index 0000000..303d664
--- /dev/null
@@ -0,0 +1,2224 @@
+/*
+ **********************************************************************
+ ** 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 <stdlib.h>
+#include <string.h>
+#include <sstream>
+#include <vector>
+
+#ifdef PODOFO_HAVE_OPENSSL
+// SHA-256
+#ifdef PODOFO_HAVE_LIBIDN
+// AES-256 dependencies :
+// SASL
+#if defined(_MSC_VER)
+// Fix missing posix "ssize_t" typedef in MSVC
+#include <BaseTsd.h>
+typedef SSIZE_T ssize_t;
+#endif
+#include <stringprep.h>
+#include <openssl/sha.h>
+#endif // PODOFO_HAVE_LIBIDN
+
+#include <openssl/opensslconf.h>
+#include <openssl/md5.h>
+#include <openssl/evp.h>
+#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 PODOFO_HAVE_OPENSSL_NO_RC4
+ePdfEncryptAlgorithm_RC4V1 |
+ePdfEncryptAlgorithm_RC4V2 |
+#endif // PODOFO_HAVE_OPENSSL_NO_RC4
+ePdfEncryptAlgorithm_AESV2 |
+ePdfEncryptAlgorithm_AESV3;
+#else // PODOFO_HAVE_LIBIDN
+int PdfEncrypt::s_nEnabledEncryptionAlgorithms =
+#ifndef PODOFO_HAVE_OPENSSL_NO_RC4
+ePdfEncryptAlgorithm_RC4V1 |
+ePdfEncryptAlgorithm_RC4V2 |
+#endif // PODOFO_HAVE_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 PODOFO_HAVE_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<unsigned char>(i);
+            
+            j = 0;
+            for (i = 0; i < 256; i++)
+            {
+                t = static_cast<size_t>(m_rc4[i]);
+                j = (j + t + static_cast<size_t>(key[i % keylen])) % 256;
+                m_rc4[i] = m_rc4[j];
+                m_rc4[j] = static_cast<unsigned char>(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<unsigned char>(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<char*>(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 // PODOFO_HAVE_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;
+               int bufferOffset = 0;
+               if( bFirstRead ) {
+                       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" );
+
+                       bufferOffset = AES_IV_LENGTH;
+                       bFirstRead = false;
+               }
+
+               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.
+                       tempBuffer.resize( lLen + 16 );
+                       status = EVP_DecryptUpdate( aes, &tempBuffer[0], &lOutLen, pBuffer + bufferOffset, lLen - bufferOffset );
+                       memcpy( pBuffer, &tempBuffer[0], lOutLen );
+               }
+               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:
+       std::vector<unsigned char> tempBuffer;
+       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 PODOFO_HAVE_OPENSSL_NO_RC4
+        case ePdfEncryptAlgorithm_RC4V2:           
+        case ePdfEncryptAlgorithm_RC4V1:
+            pdfEncrypt = new PdfEncryptRC4(userPassword, ownerPassword, protection, eAlgorithm, eKeyLength);
+            break;
+#endif // PODOFO_HAVE_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 {
+        lV     = static_cast<long>(pObject->GetDictionary().MustGetKey( PdfName("V") ).GetNumber());
+        rValue = static_cast<int>( pObject->GetDictionary().MustGetKey( PdfName("R") ).GetNumber());
+        
+        pValue = static_cast<int>( pObject->GetDictionary().MustGetKey( PdfName("P") ).GetNumber());
+        
+        oValue =                   pObject->GetDictionary().MustGetKey( PdfName("O") ).GetString();        
+        uValue =                   pObject->GetDictionary().MustGetKey( 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 or missing key in encryption dictionary" );
+        throw e;
+    }
+    
+#ifndef PODOFO_HAVE_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<int>(lLength), encryptMetadata);
+    }
+    else 
+#endif // PODOFO_HAVE_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 PODOFO_HAVE_OPENSSL_NO_RC4
+    else
+        pdfEncrypt = new PdfEncryptRC4(rhs);
+#endif // PODOFO_HAVE_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<const PdfEncryptMD5Base*>(ptr)->m_rc4key, sizeof(unsigned char) * 16 );
+    memcpy( m_rc4last, static_cast<const PdfEncryptMD5Base*>(ptr)->m_rc4last, sizeof(unsigned char) * 256 );
+       m_bEncryptMetadata = static_cast<const PdfEncryptMD5Base*>(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<unsigned char>( 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<unsigned char>(static_cast<unsigned int>(digest[j] ^ (19-i)));
+                else
+                    mkey[j] = static_cast<unsigned char>(static_cast<unsigned int>(digest[j] ^ i));
+            }
+#ifndef PODOFO_HAVE_OPENSSL_NO_RC4
+            RC4(mkey, keyLength, ownerKey, 32, ownerKey, 32);
+#endif // PODOFO_HAVE_OPENSSL_NO_RC4
+        }
+    }
+#ifndef PODOFO_HAVE_OPENSSL_NO_RC4
+    else
+    {
+        RC4(digest, 5, userPad, 32, ownerKey, 32);
+    }
+#endif // PODOFO_HAVE_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<unsigned char> ( pValue        & 0xff);
+    ext[1] = static_cast<unsigned char> ((pValue >>  8) & 0xff);
+    ext[2] = static_cast<unsigned char> ((pValue >> 16) & 0xff);
+    ext[3] = static_cast<unsigned char> ((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<unsigned int>(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<unsigned char>( 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<unsigned char>(m_encryptionKey[j] ^ k);
+            }
+            
+#ifndef PODOFO_HAVE_OPENSSL_NO_RC4
+            RC4(digest, m_keyLength, userKey, 16, userKey, 16);
+#endif // PODOFO_HAVE_OPENSSL_NO_RC4
+        }
+    }
+#ifndef PODOFO_HAVE_OPENSSL_NO_RC4
+    else
+    {
+        RC4(m_encryptionKey, m_keyLength, padding, 32, userKey, 32);
+    }
+#endif // PODOFO_HAVE_OPENSSL_NO_RC4
+    if (docId != NULL)
+    {
+        delete [] docId;
+    }
+}
+
+void PdfEncryptMD5Base::CreateObjKey( unsigned char objkey[16], int* pnKeyLen ) const
+{
+    const unsigned int n = static_cast<unsigned int>(m_curReference.ObjectNumber());
+    const unsigned int g = static_cast<unsigned int>(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<size_t>(m_keyLength);
+    
+    for (size_t j = 0; j < KEY_LENGTH_SIZE_T; j++)
+    {
+        nkey[j] = m_encryptionKey[j];
+    }
+    nkey[m_keyLength+0] = static_cast<unsigned char>(0xff &  n);
+    nkey[m_keyLength+1] = static_cast<unsigned char>(0xff & (n >> 8));
+    nkey[m_keyLength+2] = static_cast<unsigned char>(0xff & (n >> 16));
+    nkey[m_keyLength+3] = static_cast<unsigned char>(0xff &  g);
+    nkey[m_keyLength+4] = static_cast<unsigned char>(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 PODOFO_HAVE_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 // PODOFO_HAVE_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<const unsigned char*>(m_documentId.c_str()), 
+                 static_cast<unsigned int>(m_documentId.length()), iv);
+}
+    
+PdfString PdfEncryptMD5Base::GetMD5String( const unsigned char* pBuffer, int nLength )
+{
+    char data[MD5_DIGEST_LENGTH];
+    
+    GetMD5Binary( pBuffer, nLength, reinterpret_cast<unsigned char*>(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 PODOFO_HAVE_OPENSSL_NO_RC4
+               if(m_eAlgorithm == ePdfEncryptAlgorithm_RC4V2)
+                       stdCf.AddKey( PdfName("CFM"), PdfName("V2") );
+               else
+#endif // PODOFO_HAVE_OPENSSL_NO_RC4
+                       stdCf.AddKey( PdfName("CFM"), PdfName("AESV2") );
+        stdCf.AddKey( PdfName("Length"), static_cast<pdf_int64>(PODOFO_LL_LITERAL(16)) );
+        
+        rDictionary.AddKey( PdfName("O"), PdfString( reinterpret_cast<const char*>(this->GetOValue()), 32, true ) );
+        rDictionary.AddKey( PdfName("U"), PdfString( reinterpret_cast<const char*>(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<pdf_int64>(PODOFO_LL_LITERAL(4)) );
+        rDictionary.AddKey( PdfName("R"), static_cast<pdf_int64>(PODOFO_LL_LITERAL(4)) );
+        rDictionary.AddKey( PdfName("Length"), static_cast<pdf_int64>(PODOFO_LL_LITERAL(128)) );
+               if(!m_bEncryptMetadata)
+                       rDictionary.AddKey( PdfName("EncryptMetadata"), PdfVariant( false ) );
+    }
+#ifndef PODOFO_HAVE_OPENSSL_NO_RC4
+    else if(m_eAlgorithm == ePdfEncryptAlgorithm_RC4V1)
+    {
+        rDictionary.AddKey( PdfName("V"), static_cast<pdf_int64>(PODOFO_LL_LITERAL(1)) );
+        // Can be 2 or 3
+        rDictionary.AddKey( PdfName("R"), static_cast<pdf_int64>(m_rValue) );
+    }
+    else if(m_eAlgorithm == ePdfEncryptAlgorithm_RC4V2)
+    {
+        rDictionary.AddKey( PdfName("V"), static_cast<pdf_int64>(PODOFO_LL_LITERAL(2)) );
+        rDictionary.AddKey( PdfName("R"), static_cast<pdf_int64>(PODOFO_LL_LITERAL(3)) );
+               rDictionary.AddKey( PdfName("Length"), PdfVariant( static_cast<pdf_int64>(m_eKeyLength) ) );
+    }
+#endif // PODOFO_HAVE_OPENSSL_NO_RC4
+    
+    rDictionary.AddKey( PdfName("O"), PdfString( reinterpret_cast<const char*>(this->GetOValue()), 32, true ) );
+    rDictionary.AddKey( PdfName("U"), PdfString( reinterpret_cast<const char*>(this->GetUValue()), 32, true ) );
+    rDictionary.AddKey( PdfName("P"), PdfVariant( static_cast<pdf_int64>(this->GetPValue()) ) );
+}
+    
+#ifndef PODOFO_HAVE_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<PdfEncryptRC4*>(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<EPdfKeyLength>(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<int>(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 // PODOFO_HAVE_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<PdfEncryptAESV2*>(this)->GenerateInitialVector(outStr);
+    
+    const_cast<PdfEncryptAESV2*>(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<PdfEncryptAESV2*>(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<const PdfEncryptSHABase*>(ptr)->m_permsValue, sizeof(unsigned char) * 16 );
+    
+    memcpy( m_ueValue, static_cast<const PdfEncryptSHABase*>(ptr)->m_ueValue, sizeof(unsigned char) * 32 );
+    memcpy( m_oeValue, static_cast<const PdfEncryptSHABase*>(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<AES_IV_LENGTH; i++)
+        iv[i] = rand()%255;
+}
+    
+void PdfEncryptSHABase::CreateEncryptionDictionary( PdfDictionary & rDictionary ) const
+{
+    rDictionary.AddKey( PdfName("Filter"), PdfName("Standard") );
+    
+    PdfDictionary cf;
+    PdfDictionary stdCf;
+    
+    rDictionary.AddKey( PdfName("V"), static_cast<pdf_int64>(PODOFO_LL_LITERAL(5)) );
+    rDictionary.AddKey( PdfName("R"), static_cast<pdf_int64>(PODOFO_LL_LITERAL(5)) );
+    rDictionary.AddKey( PdfName("Length"), static_cast<pdf_int64>(PODOFO_LL_LITERAL(256)) );
+    
+    stdCf.AddKey( PdfName("CFM"), PdfName("AESV3") );
+    stdCf.AddKey( PdfName("Length"), static_cast<pdf_int64>(PODOFO_LL_LITERAL(32)) );
+    
+    rDictionary.AddKey( PdfName("O"), PdfString( reinterpret_cast<const char*>(this->GetOValue()), 48, true ) );
+    rDictionary.AddKey( PdfName("OE"), PdfString( reinterpret_cast<const char*>(this->GetOEValue()), 32, true ) );
+    rDictionary.AddKey( PdfName("U"), PdfString( reinterpret_cast<const char*>(this->GetUValue()), 48, true ) );
+    rDictionary.AddKey( PdfName("UE"), PdfString( reinterpret_cast<const char*>(this->GetUEValue()), 32, true ) );
+    rDictionary.AddKey( PdfName("Perms"), PdfString( reinterpret_cast<const char*>(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<pdf_int64>(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<PdfEncryptAESV3*>(this)->GenerateInitialVector(outStr);
+    
+    const_cast<PdfEncryptAESV3*>(this)->BaseEncrypt(const_cast<unsigned char*>(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<PdfEncryptAESV3*>(this)->BaseDecrypt(const_cast<unsigned char*>(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 <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#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<unsigned int *>(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<unsigned int *>(ctx->in)[14] = ctx->bits[0];
+  reinterpret_cast<unsigned int *>(ctx->in)[15] = ctx->bits[1];
+
+  MD5Transform(ctx->buf, reinterpret_cast<unsigned int *>(ctx->in));
+  memcpy(digest, ctx->buf, MD5_HASHBYTES);
+  memset( reinterpret_cast<char *>(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<unsigned int>(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<unsigned char *>(ctx->in) + t;
+
+    t = 64 - t;
+    if (len < t)
+    {
+      memcpy(p, buf, len);
+      return;
+    }
+    memcpy(p, buf, t);
+    MD5Transform(ctx->buf, reinterpret_cast<unsigned int *>(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<unsigned int *>(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<<s | 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<unsigned char*>(data) );
+
+    return PdfString( data, MD5_HASHBYTES, true );
+}
+
+#endif // PODOFO_HAVE_OPENSSL
+}
diff --git a/src/podofo/base/PdfEncrypt.h b/src/podofo/base/PdfEncrypt.h
new file mode 100644 (file)
index 0000000..9b7ea94
--- /dev/null
@@ -0,0 +1,876 @@
+/***************************************************************************
+ *   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 <string.h>
+
+namespace PoDoFo {
+
+class PdfDictionary;
+class PdfInputStream;
+class PdfObject;
+class PdfOutputStream;
+class AESCryptoEngine;
+#ifndef PODOFO_HAVE_OPENSSL_NO_RC4
+class RC4CryptoEngine;
+#endif // PODOFO_HAVE_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 PODOFO_HAVE_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 // PODOFO_HAVE_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 PODOFO_HAVE_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 // PODOFO_HAVE_OPENSSL_NO_RC4
+    
+#ifdef PODOFO_HAVE_OPENSSL_NO_RC4
+class PdfEncryptMD5Base : public PdfEncrypt {
+#else
+class PdfEncryptMD5Base : public PdfEncrypt, public PdfEncryptRC4Base {
+#endif // PODOFO_HAVE_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 PODOFO_HAVE_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 // PODOFO_HAVE_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_
diff --git a/src/podofo/base/PdfError.cpp b/src/podofo/base/PdfError.cpp
new file mode 100644 (file)
index 0000000..964d1ae
--- /dev/null
@@ -0,0 +1,714 @@
+/**************************************************************************
+ *    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 <stdarg.h>
+#include <stdio.h>
+
+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, std::string sInfo )
+    : m_nLine( line ), m_sFile( pszFile ? pszFile : "" ), m_sInfo( sInfo )
+{
+
+}
+
+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, 
+                    std::string sInformation )
+{
+    this->SetError( eCode, pszFile, line, sInformation );
+}
+
+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_BrokenFile:
+            pszMsg = "ePdfError_BrokenFile";
+            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_BrokenFile:
+            pszMsg = "The file content is broken.";
+            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;
+}
+
+};
diff --git a/src/podofo/base/PdfError.h b/src/podofo/base/PdfError.h
new file mode 100644 (file)
index 0000000..df8004b
--- /dev/null
@@ -0,0 +1,572 @@
+/***************************************************************************
+ *   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 <string>
+#include <queue>
+#include <cstdarg>
+
+#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 enum values 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_BrokenFile,               /**< The file content is broken. */
+
+    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 )
+ *  
+ *  Throw an exception of type PdfError with the error code x, which should be
+ *  one of the values of the enum EPdfError. File and line info are included.
+ */
+#define PODOFO_RAISE_ERROR( x ) throw ::PoDoFo::PdfError( x, __FILE__, __LINE__ );
+
+/** \def PODOFO_RAISE_ERROR_INFO( x, y )
+ *  
+ *  Throw an exception of type PdfError with the error code x, which should be
+ *  one of the values of the enum EPdfError. File and line info are included.
+ *  Additionally extra information on the error, y is set, which will also be
+ *  output by PdfError::PrintErrorMsg().
+ *  y can be a C string, but can also be a C++ std::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' .
+ */
+#define PODOFO_RAISE_LOGIC_IF( x, y ) { if (x) throw ::PoDoFo::PdfError( ePdfError_InternalLogic, __FILE__, __LINE__, y ); };
+
+class PODOFO_API PdfErrorInfo {
+ public:
+    PdfErrorInfo();
+    PdfErrorInfo( int line, const char* pszFile, const char* pszInfo );
+    PdfErrorInfo( int line, const char* pszFile, std::string 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( std::string pszInfo ) { m_sInfo = 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<PdfErrorInfo>        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 the PoDoFo library.
+ *  If a method encounters an error,
+ *  a PdfError object is thrown as a C++ exception.
+ *  
+ *  This class does not inherit from std::exception.
+ *
+ *  This class also provides meaningful error descriptions
+ *  for the error codes which are values of the enum EPdfError,
+ *  which are all codes PoDoFo uses (except the first and last one).
+ */
+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 replace 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 ePdfError_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
+     */
+    PdfError( const EPdfError & eCode, const char* pszFile = NULL, int line = 0, 
+              const char* pszInformation = NULL );
+
+    /** 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 sInformation additional information on this error
+     */
+    explicit PdfError( const EPdfError & eCode, const char* pszFile, int line, 
+                        std::string sInformation );
+
+    /** 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 this PdfError object
+     *  with an error code
+     *  \param eCode an error code (value of the enum EPdfError)
+     *  \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 the objects have different error codes.
+     */
+    bool operator!=( const PdfError & rhs );
+
+    /** Overloaded comparison operator, compares this PdfError object
+     *  with an error code
+     *  \param eCode an error code (value of the enum EPdfError)
+     *  \returns true if this object has a 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.
+     *  \returns the callstack deque of PdfErrorInfo objects.
+     */
+    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 sInformation 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, int line,
+                        std::string sInformation );
+
+    /** 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 information.
+     *  \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 information.
+     *  \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 );
+
+       /** 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 sInformation 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, int line, std::string sInformation );
+
+    /** \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. This includes callstack
+     *  and extra info, if any of either was set.
+     */
+    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::SetError( const EPdfError & eCode, const char* pszFile, int line, std::string sInformation )
+{
+    m_error = eCode;
+    this->AddToCallstack( pszFile, line, sInformation );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+void PdfError::AddToCallstack( const char* pszFile, int line, std::string sInformation )
+{
+    m_callStack.push_front( PdfErrorInfo( line, pszFile, sInformation ) );
+}
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+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_ */
+
+
+
diff --git a/src/podofo/base/PdfExtension.h b/src/podofo/base/PdfExtension.h
new file mode 100644 (file)
index 0000000..71f2ea2
--- /dev/null
@@ -0,0 +1,63 @@
+/**************************************************************************
+ *   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_
diff --git a/src/podofo/base/PdfFileStream.cpp b/src/podofo/base/PdfFileStream.cpp
new file mode 100644 (file)
index 0000000..1980791
--- /dev/null
@@ -0,0 +1,143 @@
+/***************************************************************************
+ *   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<pdf_int64>(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<long>(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<long>(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() );
+}
+
+};
+
diff --git a/src/podofo/base/PdfFileStream.h b/src/podofo/base/PdfFileStream.h
new file mode 100644 (file)
index 0000000..559e115
--- /dev/null
@@ -0,0 +1,190 @@
+/***************************************************************************
+ *   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_
diff --git a/src/podofo/base/PdfFilter.cpp b/src/podofo/base/PdfFilter.cpp
new file mode 100644 (file)
index 0000000..693069c
--- /dev/null
@@ -0,0 +1,462 @@
+/***************************************************************************
+ *   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_pFilter( NULL )
+    {
+        m_pFilter = PdfFilterFactory::Create( eFilter );
+
+        if( !m_pFilter ) 
+        {
+            PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter );
+        }
+
+        m_pFilter->BeginEncode( pOutputStream );
+
+        if( !bOwnStream )
+            m_pOutputStream = NULL;
+    }
+
+    virtual ~PdfFilteredEncodeStream()
+    {
+        delete m_pOutputStream;
+        delete m_pFilter;
+    }
+
+    /** 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_pFilter->EncodeBlock( pBuffer, lLen );
+        
+        return 0;
+    }
+
+    virtual void Close() 
+    {
+        m_pFilter->EndEncode();
+    }
+
+private:
+    PdfOutputStream* m_pOutputStream;
+    PdfFilter*       m_pFilter;
+};
+
+/** 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 (optionally, see constructor).
+ */
+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 PdfFilteredDecodeStream if the parameter bOwnStream is true.
+     *
+     *  \param pOutputStream write all data to this output stream after decoding the data.
+     *         The PdfOutputStream is deleted along with this object if bOwnStream is true.
+     *  \param eFilter use this filter for decoding.
+     *  \param bOwnStream if true pOutputStream will be deleted along with this stream
+     *  \param pDecodeParms additional parameters for decoding
+     */
+    PdfFilteredDecodeStream( PdfOutputStream* pOutputStream, const EPdfFilter eFilter, bool bOwnStream,
+                             const PdfDictionary* pDecodeParms = NULL )
+        : m_pOutputStream( pOutputStream ), m_pFilter( NULL ), m_bFilterFailed( false )
+    {
+        m_pFilter = PdfFilterFactory::Create( eFilter );
+        if( !m_pFilter ) 
+        {
+            PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter );
+        }
+
+        m_pFilter->BeginDecode( pOutputStream, pDecodeParms );
+
+        if( !bOwnStream )
+            m_pOutputStream = NULL;
+    }
+
+    virtual ~PdfFilteredDecodeStream()
+    {
+        delete m_pOutputStream;
+        delete m_pFilter;
+    }
+
+    /** 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_pFilter->DecodeBlock( pBuffer, lLen );
+        }
+        catch( PdfError & e ) 
+        {
+            e.AddToCallstack( __FILE__, __LINE__ );
+            m_bFilterFailed = true;
+            throw e;
+        }
+
+        return 0;
+    }
+
+    virtual void Close() 
+    {
+        try {
+            if( !m_bFilterFailed ) 
+            {
+                m_pFilter->EndDecode();
+            }
+        }
+        catch( PdfError & e )
+        {
+            std::ostringstream oss;
+            oss << "PdfFilter::EndDecode() failed in filter of type "
+                << PdfFilterFactory::FilterTypeToName( m_pFilter->GetType() ) << ".\n";
+            e.AddToCallstack( __FILE__, __LINE__, oss.str() );
+            m_bFilterFailed = true;
+            throw e;
+        }
+
+    }
+
+private:
+    PdfOutputStream* m_pOutputStream;
+    PdfFilter*       m_pFilter;
+    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<PdfFilter*>(this)->BeginEncode( &stream );
+    const_cast<PdfFilter*>(this)->EncodeBlock( pInBuffer, lInLen );
+    const_cast<PdfFilter*>(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<PdfFilter*>(this)->BeginDecode( &stream, pDecodeParms );
+    const_cast<PdfFilter*>(this)->DecodeBlock( pInBuffer, lInLen );
+    const_cast<PdfFilter*>(this)->EndDecode();
+
+    *ppOutBuffer = stream.TakeBuffer();
+    *plOutLen    = stream.GetLength();
+}
+
+// -----------------------------------------------------
+// PdfFilterFactory code
+// -----------------------------------------------------
+
+PdfFilterFactory::PdfFilterFactory()
+{
+}
+
+PdfFilter* 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 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* pFilterStream = new PdfFilteredDecodeStream( pStream, *it, false, pDictionary );
+    ++it;
+
+    while( it != filters.rend() ) 
+    {
+        pFilterStream = new PdfFilteredDecodeStream( pFilterStream, *it, true, pDictionary );
+        ++it;
+    }
+
+    return pFilterStream;
+}
+
+EPdfFilter PdfFilterFactory::FilterNameToType( const PdfName & name, bool bSupportShortNames )
+{
+    int i = 0;
+
+    while( aszFilters[i] )
+    {
+        if( name == aszFilters[i] )
+            return static_cast<EPdfFilter>(i);
+        
+        ++i;
+    }
+
+    if( bSupportShortNames )
+    {
+        i = 0;
+        while( aszShortFilters[i] )
+        {
+            if( name == aszShortFilters[i] )
+                return static_cast<EPdfFilter>(i);
+            
+            ++i;
+        }        
+    }
+
+    PODOFO_RAISE_ERROR_INFO( ePdfError_UnsupportedFilter, name.GetName().c_str() );
+}
+
+const char* PdfFilterFactory::FilterTypeToName( EPdfFilter eFilter )
+{
+    return aszFilters[static_cast<int>(eFilter)];
+}
+
+TVecFilters PdfFilterFactory::CreateFilterList( const PdfObject* pObject )
+{
+    TVecFilters filters;
+
+    const PdfObject* pObj    = NULL;
+
+    if( pObject->IsDictionary() && pObject->GetDictionary().HasKey( "Filter" ) )
+        pObj = pObject->GetIndirectKey( "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;
+}
+
+};
diff --git a/src/podofo/base/PdfFilter.h b/src/podofo/base/PdfFilter.h
new file mode 100644 (file)
index 0000000..2b8a90a
--- /dev/null
@@ -0,0 +1,539 @@
+/***************************************************************************
+ *   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 <memory>
+#include <cassert>
+
+#include "PdfDefines.h"
+
+#include "PdfInputStream.h"
+#include "PdfOutputStream.h"
+
+namespace PoDoFo {
+
+class PdfDictionary;
+class PdfName;
+class PdfObject;
+class PdfOutputStream;
+
+typedef std::vector<EPdfFilter>            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 ) {
+           e.AddToCallstack( __FILE__, __LINE__ );
+               // Clean up and close stream
+               this->FailEncodeDecode();
+               throw e;
+       }
+    try { // introduced to fix issue #58
+        if( m_pOutputStream ) 
+        {
+            m_pOutputStream->Close();
+            m_pOutputStream = NULL;
+        }
+    } catch( PdfError & e ) {
+            e.AddToCallstack( __FILE__, __LINE__, "Exception caught closing filter's output stream.\n");
+            // Closing stream failed, just get rid of it
+            m_pOutputStream = NULL;
+            throw e;
+    } 
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+void PdfFilter::FailEncodeDecode()
+{
+    if ( m_pOutputStream != NULL ) // OC 19.08.2010 BugFix: Sometimes FailEncodeDecode() is called twice
+        m_pOutputStream->Close(); // mabri: issue #58 seems fixed without exception safety here ...
+    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, whom should delete non-NULL
+     *  PdfFilter instance, when no longer needed.
+     *
+     *  \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 PdfFilter* 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_ */
diff --git a/src/podofo/base/PdfFiltersPrivate.cpp b/src/podofo/base/PdfFiltersPrivate.cpp
new file mode 100644 (file)
index 0000000..d41444b
--- /dev/null
@@ -0,0 +1,1345 @@
+/***************************************************************************
+ *   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 <stdlib.h>
+#include <string.h>
+
+#ifdef PODOFO_HAVE_TIFF_LIB
+extern "C" {
+#ifdef _WIN32          // For O_RDONLY
+    // TODO: DS
+#else
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#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<int>(pDecodeParms->GetKeyAsLong( "Predictor", 1L ));
+        m_nColors      = static_cast<int>(pDecodeParms->GetKeyAsLong( "Colors", 1L ));
+        m_nBPC         = static_cast<int>(pDecodeParms->GetKeyAsLong( "BitsPerComponent", 8L ));
+        m_nColumns     = static_cast<int>(pDecodeParms->GetKeyAsLong( "Columns", 1L ));
+        m_nEarlyChange = static_cast<int>(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<char*>(podofo_calloc( m_nRows, sizeof(char) ));
+        if( !m_pPrev )
+        {
+            PODOFO_RAISE_ERROR( ePdfError_OutOfMemory );
+        }
+
+        memset( m_pPrev, 0, sizeof(char) * m_nRows );
+
+        m_pUpperLeftPixelComponents = static_cast<char*>(podofo_calloc( m_nBpp, sizeof(char) ));
+        if( !m_pUpperLeftPixelComponents )
+        {
+            PODOFO_RAISE_ERROR( ePdfError_OutOfMemory );
+        }
+
+        memset( m_pUpperLeftPixelComponents, 0, sizeof(char) * m_nBpp );
+    };
+
+    ~PdfPredictorDecoder()
+    {
+        podofo_free( m_pPrev );
+        podofo_free( m_pUpperLeftPixelComponents );
+    }
+
+    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_INFO( ePdfError_InvalidPredictor, "tiff predictors other than 8 BPC are not implemented" );
+                        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
+                    {
+                        int nLeftByteIndex = m_nCurRowIndex - m_nBpp;
+
+                        int a = nLeftByteIndex < 0 ? 0 : static_cast<unsigned char>( m_pPrev[nLeftByteIndex] );
+                        int b = static_cast<unsigned char>( m_pPrev[m_nCurRowIndex] );
+
+                        int nCurrComponentIndex = m_nCurRowIndex % m_nBpp;
+                        int c = nLeftByteIndex < 0 ? 0 : static_cast<unsigned char>( m_pUpperLeftPixelComponents[nCurrComponentIndex] );
+
+                        int p = a + b - c;
+
+                        int pa = p - a;
+                        if( pa < 0 ) pa = -pa;
+
+                        int pb = p - b;
+                        if( pb < 0 ) pb = -pb;
+
+                        int pc = p - c;
+                        if( pc < 0 ) pc = -pc;
+
+                        char closestByte;
+                        if( pa <= pb && pa <= pc )
+                            closestByte = a;
+                        else if( pb <= pc )
+                            closestByte = b;
+                        else
+                            closestByte = c;
+
+                        // Save the byte we're about to clobber for the next pixel's prediction
+                        m_pUpperLeftPixelComponents[nCurrComponentIndex] = m_pPrev[m_nCurRowIndex];
+
+                        m_pPrev[m_nCurRowIndex] = *pBuffer + closestByte;
+                        break;
+                    }
+                    case 15: // png optimum
+                        PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidPredictor, "png optimum predictor is not implemented" );
+                        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;
+
+    // The PNG Paeth predictor uses the values of the pixel above and to the left
+    // of the current pixel. But we overwrite the row above as we go, so we'll
+    // have to store the bytes of the upper-left pixel separately.
+    char* m_pUpperLeftPixelComponents;
+};
+
+
+// -------------------------------------------------------
+// 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<char>(tuple % 85);
+        tuple /= 85;
+    } 
+    while (--i > 0);
+
+    i = count;
+    do 
+    {
+        out[z++] = static_cast<unsigned char>(*--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<char>(tuple >> 24);
+            data[1] = static_cast<char>(tuple >> 16);
+            data[2] = static_cast<char>(tuple >>  8);
+            data[3] = static_cast<char>(tuple);
+            break;
+       case 3:
+            data[0] = static_cast<char>(tuple >> 24);
+            data[1] = static_cast<char>(tuple >> 16);
+            data[2] = static_cast<char>(tuple >>  8);
+            break;
+       case 2:
+            data[0] = static_cast<char>(tuple >> 24);
+            data[1] = static_cast<char>(tuple >> 16);
+            break;
+       case 1:
+            data[0] = static_cast<char>(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<long>(lLen);
+    m_stream.next_in  = reinterpret_cast<Bytef*>(const_cast<char*>(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<char*>(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<long>(lLen);
+    m_stream.next_in  = reinterpret_cast<Bytef*>(const_cast<char*>(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<char*>(m_buffer), nWrittenData, GetStream() );
+            else
+                GetStream()->Write( reinterpret_cast<char*>(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<int>(*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<unsigned char> 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<pdf_uint32>(static_cast<unsigned char>(*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<char*>(&(data[0])), data.size(), GetStream() );
+                else
+                    GetStream()->Write( reinterpret_cast<char*>(&(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<unsigned char>(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<JOCTET*>(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<j_common_ptr>( &m_cinfo ), JPOOL_IMAGE, lRowBytes, 1);
+    pOutBuffer = static_cast<char*>(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<char*>(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<my_src_ptr>(cinfo->src);
+    WARNMS(cinfo, JWRN_JPEG_EOF);
+
+    /* Create a fake EOI marker */
+    src->eoi_buffer[0] = static_cast<JOCTET>(0xFF);
+    src->eoi_buffer[1] = static_cast<JOCTET>(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<my_src_ptr>(cinfo->src);
+
+    if (num_bytes > 0) {
+        while (num_bytes > static_cast<long>(src->pub.bytes_in_buffer) ) {
+            num_bytes -= static_cast<long>(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<size_t>(num_bytes);
+        src->pub.bytes_in_buffer -= static_cast<size_t>(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<struct jpeg_source_mgr *>(
+            (*cinfo->mem->alloc_small) ( reinterpret_cast<j_common_ptr>(cinfo), JPOOL_PERMANENT,
+                                        sizeof(my_source_mgr)));
+
+    }
+
+
+    src = reinterpret_cast<my_src_ptr>(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<thandle_t>(-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);
+        }
+
+    }
+    */
+
+#else // DS_CCITT_DEVELOPMENT_CODE
+    PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter );
+#endif // DS_CCITT_DEVELOPMENT_CODE
+}
+#ifndef _MSC_VER
+#pragma GCC diagnostic pop
+#endif
+
+void PdfCCITTFilter::DecodeBlockImpl( const char*, pdf_long )
+{
+    PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter );
+}
+
+void PdfCCITTFilter::EndDecodeImpl()
+{
+    PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter );
+}
+
+#endif // PODOFO_HAVE_TIFF_LIB
+
+
+};
diff --git a/src/podofo/base/PdfFiltersPrivate.h b/src/podofo/base/PdfFiltersPrivate.h
new file mode 100644 (file)
index 0000000..2c7eda5
--- /dev/null
@@ -0,0 +1,991 @@
+/***************************************************************************
+ *   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 <zlib.h>
+
+#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<unsigned char> value;
+    };
+    
+    typedef std::vector<TLzwItem>     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_ */
diff --git a/src/podofo/base/PdfImmediateWriter.cpp b/src/podofo/base/PdfImmediateWriter.cpp
new file mode 100644 (file)
index 0000000..2753a23
--- /dev/null
@@ -0,0 +1,195 @@
+/***************************************************************************
+ *   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<PdfObject*>(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<PdfObject*>(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_uint64 lXRefOffset = static_cast<pdf_uint64>( 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%" PDF_FORMAT_UINT64 "\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<PdfStream*>(new PdfMemStream( pParent )) :
+        static_cast<PdfStream*>(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<const PdfFileStream*>(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<PdfFileStream*>(pFileStream)->SetEncrypted( m_pEncrypt );
+    }
+}
+    
+void PdfImmediateWriter::EndAppendStream( const PdfStream* pStream )
+{
+    const PdfFileStream* pFileStream = dynamic_cast<const PdfFileStream*>(pStream );
+    if( pFileStream ) 
+    {
+        // A PdfFileStream has to be opened before
+        PODOFO_ASSERT( m_bOpenStream );
+        m_bOpenStream = false;
+    }
+}
+
+};
+
diff --git a/src/podofo/base/PdfImmediateWriter.h b/src/podofo/base/PdfImmediateWriter.h
new file mode 100644 (file)
index 0000000..d233107
--- /dev/null
@@ -0,0 +1,158 @@
+/***************************************************************************
+ *   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_ */
+
diff --git a/src/podofo/base/PdfInputDevice.cpp b/src/podofo/base/PdfInputDevice.cpp
new file mode 100644 (file)
index 0000000..5e7f357
--- /dev/null
@@ -0,0 +1,285 @@
+/***************************************************************************
+ *   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 <cstdarg>
+#include <fstream>
+#include <sstream>
+#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;
+
+            if( dir == std::ios_base::beg )
+                whence = SEEK_SET;
+            else if( dir == std::ios_base::cur )
+                whence = SEEK_CUR;
+            else // if( dir == std::ios_base::end )
+                whence = SEEK_END;
+            
+            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
diff --git a/src/podofo/base/PdfInputDevice.h b/src/podofo/base/PdfInputDevice.h
new file mode 100644 (file)
index 0000000..889569d
--- /dev/null
@@ -0,0 +1,213 @@
+/***************************************************************************
+ *   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 <istream>
+#include <ios>
+#include <cstdio>
+
+#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_
diff --git a/src/podofo/base/PdfInputStream.cpp b/src/podofo/base/PdfInputStream.cpp
new file mode 100644 (file)
index 0000000..b409c1b
--- /dev/null
@@ -0,0 +1,161 @@
+/***************************************************************************
+ *   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 <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+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 );
+}
+
+};
diff --git a/src/podofo/base/PdfInputStream.h b/src/podofo/base/PdfInputStream.h
new file mode 100644 (file)
index 0000000..2f93155
--- /dev/null
@@ -0,0 +1,175 @@
+/***************************************************************************
+ *   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_
diff --git a/src/podofo/base/PdfLocale.cpp b/src/podofo/base/PdfLocale.cpp
new file mode 100644 (file)
index 0000000..9fefaac
--- /dev/null
@@ -0,0 +1,65 @@
+/***************************************************************************
+ *   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 "PdfDefines.h"
+#include "PdfLocale.h"
+#include "PdfError.h"
+#include "PdfDefinesPrivate.h"
+
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+
+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
+}
+
+};
diff --git a/src/podofo/base/PdfLocale.h b/src/podofo/base/PdfLocale.h
new file mode 100644 (file)
index 0000000..a0015b4
--- /dev/null
@@ -0,0 +1,69 @@
+/***************************************************************************
+ *   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 PODOFO_PDFLOCALE_H
+#define PODOFO_PDFLOCALE_H
+
+#include <ios>
+
+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
diff --git a/src/podofo/base/PdfMemStream.cpp b/src/podofo/base/PdfMemStream.cpp
new file mode 100644 (file)
index 0000000..9aaae04
--- /dev/null
@@ -0,0 +1,305 @@
+/***************************************************************************
+ *   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 <stdlib.h>
+
+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<PdfBufferOutputStream*>(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<pdf_int64>(m_lLength) ) );
+}
+
+void PdfMemStream::GetCopy( char** pBuffer, pdf_long* lLen ) const
+{
+    if( !pBuffer || !lLen )
+    {
+        PODOFO_RAISE_ERROR( ePdfError_InvalidHandle );
+    }
+
+    *pBuffer = static_cast<char*>(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->MustGetIndirectKey( "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;
+
+    PODOFO_UNIQUEU_PTR<PdfFilter> 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<const PdfMemStream*>(&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<pdf_int64>(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<const unsigned char*>(this->Get()), lLen,
+                          reinterpret_cast<unsigned char*>(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;
+}
+
+
+};
diff --git a/src/podofo/base/PdfMemStream.h b/src/podofo/base/PdfMemStream.h
new file mode 100644 (file)
index 0000000..f0fd175
--- /dev/null
@@ -0,0 +1,220 @@
+/***************************************************************************
+ *   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_
diff --git a/src/podofo/base/PdfMemoryManagement.cpp b/src/podofo/base/PdfMemoryManagement.cpp
new file mode 100644 (file)
index 0000000..b35698b
--- /dev/null
@@ -0,0 +1,211 @@
+/***************************************************************************
+ *   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 <limits>
+
+#define SIZE_MAX std::numeric_limits<size_t>::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 <errno.h>
+#endif
+
+namespace PoDoFo {
+
+bool podofo_is_little_endian()
+{ 
+    int _p = 1;
+    return ((reinterpret_cast<char*>(&_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: <afx.h>  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
diff --git a/src/podofo/base/PdfMemoryManagement.h b/src/podofo/base/PdfMemoryManagement.h
new file mode 100644 (file)
index 0000000..d42c9e1
--- /dev/null
@@ -0,0 +1,82 @@
+/***************************************************************************
+ *   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 <stdlib.h>
+
+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_
+
diff --git a/src/podofo/base/PdfName.cpp b/src/podofo/base/PdfName.cpp
new file mode 100644 (file)
index 0000000..79e31d4
--- /dev/null
@@ -0,0 +1,220 @@
+/***************************************************************************
+ *   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 <string.h>
+
+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<typename T>
+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<typename T>
+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<unsigned char>(*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<typename T>
+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 == '#' && incount + 1 < length)
+        {
+            unsigned char hi = static_cast<unsigned char>(*(++it)); ++incount;
+            unsigned char low = static_cast<unsigned char>(*(++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 ) );
+}
+
+};
+
diff --git a/src/podofo/base/PdfName.h b/src/podofo/base/PdfName.h
new file mode 100644 (file)
index 0000000..c7e12e2
--- /dev/null
@@ -0,0 +1,275 @@
+/***************************************************************************
+ *   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_ */
+
diff --git a/src/podofo/base/PdfObject.cpp b/src/podofo/base/PdfObject.cpp
new file mode 100644 (file)
index 0000000..60ef178
--- /dev/null
@@ -0,0 +1,433 @@
+/***************************************************************************
+ *   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 <sstream>
+#include <fstream>
+
+#include <string.h>
+
+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();
+}
+
+// NOTE: Don't copy owner. Copied objects must be always detached.
+// Ownership will be set automatically elsewhere
+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<PdfObject*>(&rhs)->DelayedStreamLoad();
+    m_bDelayedStreamLoadDone = rhs.DelayedStreamLoadDone();
+
+    // FIXME:
+    // Copying stream is currently broken:
+    // 1) PdfVecObjects::CreateStream( const PdfStream & ) is broken as it just returns NULL
+    // 2) Stream should be copyable also when m_pOwner is NULL (which is the case for copy constructor)
+    //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::SetOwner( PdfVecObjects* pVecObjects )
+{
+    PODOFO_ASSERT( pVecObjects != NULL );
+    if ( m_pOwner == pVecObjects )
+    {
+        // The inner owner for variant data objects is guaranteed to be same
+        return;
+    }
+
+    m_pOwner = pVecObjects;
+    if ( DelayedLoadDone() )
+        SetVariantOwner( GetDataType() );
+}
+
+void PdfObject::AfterDelayedLoad( EPdfDataType eDataType )
+{
+    SetVariantOwner( eDataType );
+}
+
+void PdfObject::SetVariantOwner( EPdfDataType eDataType )
+{
+    switch ( eDataType )
+    {
+        case ePdfDataType_Dictionary:
+            static_cast<PdfOwnedDataType &>( GetDictionary_NoDL() ).SetOwner( this );
+            break;
+        case ePdfDataType_Array:
+            static_cast<PdfOwnedDataType &>( GetArray_NoDL() ).SetOwner( this );
+            break;
+        default:
+            break;
+    }
+}
+
+void PdfObject::InitPdfObject()
+{
+    m_pStream                 = NULL;
+    m_pOwner                  = NULL;
+    m_bDelayedStreamLoadDone  = true;
+    SetVariantOwner( GetDataType() );
+
+#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<PdfFileStream*>(m_pStream);
+        if( !pFileStream )
+        {
+            // PdfFileStream handles encryption internally
+            pdf_long lLength = pEncrypt->CalculateStreamLength(m_pStream->GetLength());
+            PdfVariant varLength = static_cast<pdf_int64>(lLength);
+            *(const_cast<PdfObject*>(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
+{
+    if ( !this->IsDictionary() )
+        return NULL;
+
+    // DominikS: TODO Remove const on GetIndirectKey
+    return const_cast<PdfObject*>( this->GetDictionary().FindKey( key ) );
+}
+
+pdf_int64 PdfObject::GetIndirectKeyAsLong( const PdfName & key, pdf_int64 lDefault ) const
+{
+    const PdfObject* pObject = GetIndirectKey( key );
+    
+    if( pObject && pObject->GetDataType() == ePdfDataType_Number ) 
+    {
+        return pObject->GetNumber();
+    }
+
+    return lDefault;
+}
+
+double PdfObject::GetIndirectKeyAsReal( const PdfName & key, double dDefault ) const
+{
+    const PdfObject* pObject = GetIndirectKey( key );
+    
+    if( pObject && (
+        pObject->GetDataType() == ePdfDataType_Real ||
+        pObject->GetDataType() == ePdfDataType_Number))
+    {
+        return pObject->GetReal();
+    }
+
+    return dDefault;
+}
+
+bool PdfObject::GetIndirectKeyAsBool( const PdfName & key, bool bDefault ) const
+{
+    const PdfObject* pObject = GetIndirectKey( key );
+
+    if( pObject && pObject->GetDataType() == ePdfDataType_Bool ) 
+    {
+        return pObject->GetBool();
+    }
+
+    return bDefault;
+}
+
+PdfName PdfObject::GetIndirectKeyAsName( const PdfName & key ) const
+{
+    const PdfObject* pObject = GetIndirectKey( key );
+
+    if( pObject && pObject->GetDataType() == ePdfDataType_Name ) 
+    {
+        return pObject->GetName();
+    }
+    
+    return PdfName(""); // return an empty name
+}
+
+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 )
+{
+    if( &rhs == this)
+        return *this;
+
+    // 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;
+    m_pStream = NULL;
+
+    const_cast<PdfObject*>(&rhs)->DelayedStreamLoad();
+
+    // NOTE: Don't copy owner. Objects being assigned always keep current ownership
+    PdfVariant::operator=(rhs);
+    m_reference     = rhs.m_reference;
+    m_bDelayedStreamLoadDone = rhs.DelayedStreamLoadDone();
+    SetVariantOwner( GetDataType() );
+
+    // FIXME:
+    // Copying stream is currently broken:
+    // 1) PdfVecObjects::CreateStream( const PdfStream & ) is broken as it just returns NULL
+    // 2) Stream should be copyable also when m_pOwner is NULL
+    //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();
+}
+
+};
diff --git a/src/podofo/base/PdfObject.h b/src/podofo/base/PdfObject.h
new file mode 100644 (file)
index 0000000..af71138
--- /dev/null
@@ -0,0 +1,487 @@
+/***************************************************************************
+ *   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;
+class PdfDictionary;
+class PdfArray;
+class PdfDocument;
+
+/**
+ * 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;
+    friend class PdfArray;
+    friend class PdfDictionary;
+    friend class PdfDocument;
+
+ 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 this parameter is not null a key "/Type" will
+     *                 be added to the dictionary with the parameter's value.
+     */
+    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 associated objects and streams will be copied along with the PdfObject.
+     *  \param rhs PdfObject to clone
+     */
+    PdfObject( const PdfObject & rhs );
+
+    virtual ~PdfObject();
+
+    /** Get the key's 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;
+
+    pdf_int64 GetIndirectKeyAsLong( const PdfName & key, pdf_int64 lDefault = 0 ) const;
+
+    double GetIndirectKeyAsReal( const PdfName & key, double dDefault = 0.0 ) const;
+
+    bool GetIndirectKeyAsBool( const PdfName & key, bool bDefault = false ) const;
+
+    PdfName GetIndirectKeyAsName( 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 an 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 
+     *  PdfObject instances. It compares the object number. If object numbers
+     *  are equal, the generation number is compared.
+     */
+    PODOFO_NOTHROW inline bool operator<( const PdfObject & rhs ) const;
+
+    /** Comparison operator.
+     *  Compares two PDF object instances only based on their object and generation number.
+     */
+    PODOFO_NOTHROW inline bool operator==( const PdfObject & rhs ) const;
+
+    /** Get the owner of this object.
+     *  \return the owner (if it wasn't changed anywhere, creator) of this object
+     */
+    inline PdfVecObjects* GetOwner() const;
+
+    /** Creates a copy of an existing PdfObject.
+     *  All associated 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 of
+     *  \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 created in memory completely, 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();
+
+    virtual void AfterDelayedLoad( EPdfDataType eDataType );
+
+    /** Set the owner of this object variant
+     */
+    void SetVariantOwner( EPdfDataType eDataType );
+
+ private:
+     /** Set the owner of this object, i.e. the PdfVecObjects to which
+      *  this object belongs.
+      *
+      *  \param pVecObjects a vector of pdf objects
+      */
+     void SetOwner(PdfVecObjects* pVecObjects);
+
+ 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<typename T> 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 required 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 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<PdfObject*>(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_
+
+
+
diff --git a/src/podofo/base/PdfObjectStreamParserObject.cpp b/src/podofo/base/PdfObjectStreamParserObject.cpp
new file mode 100644 (file)
index 0000000..dc09dff
--- /dev/null
@@ -0,0 +1,135 @@
+/***************************************************************************
+ *   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 "PdfInputDevice.h"
+#include "PdfParserObject.h"
+#include "PdfStream.h"
+#include "PdfVecObjects.h"
+
+#include <limits>
+#include <algorithm>
+
+#if defined(PODOFO_VERBOSE_DEBUG)
+#include <iostream>
+#endif
+
+namespace PoDoFo {
+
+PdfObjectStreamParserObject::PdfObjectStreamParserObject(PdfParserObject* pParser, PdfVecObjects* pVecObjects, const PdfRefCountedBuffer & rBuffer)
+    : m_pParser( pParser ), m_vecObjects( pVecObjects ), m_buffer( rBuffer )
+{
+
+}
+
+PdfObjectStreamParserObject::~PdfObjectStreamParserObject()
+{
+
+}
+
+void PdfObjectStreamParserObject::Parse(ObjectIdList const & list)
+{
+    pdf_int64 lNum   = m_pParser->GetIndirectKeyAsLong( "N", 0 );
+    pdf_int64 lFirst = m_pParser->GetIndirectKeyAsLong( "First", 0 );
+    
+    char* pBuffer;
+    pdf_long lBufferLen;
+    m_pParser->GetStream()->GetFilteredCopy( &pBuffer, &lBufferLen );
+
+    try {
+        this->ReadObjectsFromStream( pBuffer, lBufferLen, lNum, lFirst, list );
+
+        // 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;
+    }
+
+    podofo_free( pBuffer );
+}
+
+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<pdf_int64>(i) < lNum )
+    {
+        const pdf_int64 lObj     = tokenizer.GetNextNumber();
+        const pdf_int64 lOff     = tokenizer.GetNextNumber();
+        const std::streamoff pos = device.Device()->Tell();
+
+        if( lFirst >= std::numeric_limits<pdf_int64>::max() - lOff )
+        {
+            PODOFO_RAISE_ERROR_INFO( ePdfError_BrokenFile,
+                                    "Object position out of max limit" );
+        }
+
+        // move to the position of the object in the stream
+        device.Device()->Seek( static_cast<std::streamoff>(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 );
+        variantTokenizer.GetNextVariant( var, 0 ); // Stream is already decrypted
+               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<int>(lObj), PODOFO_LL_LITERAL(0) ))) 
+            {
+                PdfError::LogMessage( eLogSeverity_Warning, "Object: %" PDF_FORMAT_INT64 " 0 R will be deleted and loaded again.\n", lObj );
+                delete m_vecObjects->RemoveObject(PdfReference( static_cast<int>(lObj), PODOFO_LL_LITERAL(0) ),false);
+            }
+            m_vecObjects->insert_sorted( new PdfObject( PdfReference( static_cast<int>(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;
+    }
+}
+
+}; 
diff --git a/src/podofo/base/PdfObjectStreamParserObject.h b/src/podofo/base/PdfObjectStreamParserObject.h
new file mode 100644 (file)
index 0000000..42af47b
--- /dev/null
@@ -0,0 +1,81 @@
+/***************************************************************************
+ *   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 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<pdf_int64> 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
+     */
+    PdfObjectStreamParserObject(PdfParserObject* pParser, PdfVecObjects* pVecObjects, const PdfRefCountedBuffer & rBuffer);
+
+    ~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;
+};
+
+};
+
+#endif // _PDF_OBJECT_STREAM_PARSER_OBJECT_H_
diff --git a/src/podofo/base/PdfOutputDevice.cpp b/src/podofo/base/PdfOutputDevice.cpp
new file mode 100644 (file)
index 0000000..d460c13
--- /dev/null
@@ -0,0 +1,425 @@
+/***************************************************************************
+ *   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 <fstream>
+#include <sstream>
+
+
+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( std::iostream* pStream )
+{
+    this->Init();
+
+    m_pStream = pStream;
+    m_pReadStream = pStream;
+    m_pStreamOwned = false;
+
+#if USE_CXX_LOCALE
+    m_pStreamSavedLocale = m_pStream->getloc();
+    PdfLocaleImbue(*m_pStream);
+#endif 
+}
+
+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<unsigned long>(m_pRefCountedBuffer->GetSize()) )
+            {
+                m_pRefCountedBuffer->Resize( m_ulPosition + lBytes );
+            }
+
+            memcpy( m_pRefCountedBuffer->GetBuffer() + m_ulPosition, data, lBytes );
+        }
+
+    }
+
+    m_ulPosition += static_cast<size_t>(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<size_t>(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<size_t>(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<size_t>(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();
+    }
+}
+
+};
diff --git a/src/podofo/base/PdfOutputDevice.h b/src/podofo/base/PdfOutputDevice.h
new file mode 100644 (file)
index 0000000..31497f5
--- /dev/null
@@ -0,0 +1,261 @@
+/***************************************************************************
+ *   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 <cstdarg>
+#include <ostream>
+#include <iostream>
+
+#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 );
+
+    /** Construct a new PdfOutputDevice that writes all data to a std::iostream
+     *  and reads from it as well.
+     *
+     *  WARNING: PoDoFo will change the stream's locale.  It will be restored when
+     *  the PdfOutputStream controlling the stream is destroyed.
+     *
+     *  \param pStream read/write from/to this std::iostream
+     */
+    PdfOutputDevice( std::iostream* pStream );
+
+    /** 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_
+
diff --git a/src/podofo/base/PdfOutputStream.cpp b/src/podofo/base/PdfOutputStream.cpp
new file mode 100644 (file)
index 0000000..02c5c71
--- /dev/null
@@ -0,0 +1,159 @@
+/***************************************************************************
+ *   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 <stdlib.h>
+#include <string.h>
+
+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<char*>(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 )
+{
+    if( !pBuffer ) 
+    {
+        PODOFO_RAISE_ERROR( ePdfError_InvalidHandle );
+    }
+
+    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( !pBuffer ) 
+    {
+        return 0;
+    }
+
+    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<char*>(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<pdf_long>(m_pBuffer->GetSize()) ) 
+        m_pBuffer->Resize( m_lLength + lLen );
+
+    memcpy( m_pBuffer->GetBuffer() + m_lLength, pBuffer, lLen );
+    m_lLength += lLen;
+    
+    return lLen;
+}
+
+};
diff --git a/src/podofo/base/PdfOutputStream.h b/src/podofo/base/PdfOutputStream.h
new file mode 100644 (file)
index 0000000..d4d4c54
--- /dev/null
@@ -0,0 +1,283 @@
+/***************************************************************************
+ *   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 <string>
+
+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_
diff --git a/src/podofo/base/PdfOwnedDataType.cpp b/src/podofo/base/PdfOwnedDataType.cpp
new file mode 100644 (file)
index 0000000..d66c033
--- /dev/null
@@ -0,0 +1,78 @@
+/***************************************************************************
+ *   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 "PdfOwnedDataType.h"
+#include "PdfObject.h"
+#include "PdfVecObjects.h"
+
+namespace PoDoFo {
+
+PdfOwnedDataType::PdfOwnedDataType()
+    : m_pOwner( NULL )
+{
+}
+
+// NOTE: Don't copy owner. Copied objects must be always detached.
+// Ownership will be set automatically elsewhere
+PdfOwnedDataType::PdfOwnedDataType( const PdfOwnedDataType &rhs )
+    : PdfDataType( rhs ), m_pOwner( NULL )
+{
+}
+
+PdfObject * PdfOwnedDataType::GetIndirectObject( const PdfReference &rReference ) const
+{
+    if ( m_pOwner == NULL )
+        PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "Object is a reference but does not have an owner!" );
+
+    return m_pOwner->GetOwner()->GetObject( rReference );
+}
+
+void PdfOwnedDataType::SetOwner( PdfObject* pOwner )
+{
+    PODOFO_ASSERT( pOwner != NULL );
+    m_pOwner = pOwner;
+}
+
+PdfOwnedDataType & PdfOwnedDataType::operator=( const PdfOwnedDataType & rhs )
+{
+    // NOTE: Don't copy owner. Objects being assigned will keep current ownership
+    PdfDataType::operator=( rhs );
+    return *this;
+}
+
+PdfVecObjects * PdfOwnedDataType::GetObjectOwner()
+{
+    return m_pOwner == NULL ? NULL : m_pOwner->GetOwner();
+}
+
+};
diff --git a/src/podofo/base/PdfOwnedDataType.h b/src/podofo/base/PdfOwnedDataType.h
new file mode 100644 (file)
index 0000000..9843914
--- /dev/null
@@ -0,0 +1,90 @@
+/***************************************************************************
+ *   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_OWNED_DATATYPE_H_
+#define _PDF_OWNED_DATATYPE_H_
+
+#include "PdfDataType.h"
+
+namespace PoDoFo {
+
+class PdfObject;
+class PdfVecObjects;
+class PdfReference;
+
+/**
+ * A PdfDataType object with PdfObject owner
+ */
+class PODOFO_API PdfOwnedDataType : public PdfDataType {
+    friend class PdfObject;
+protected:
+    /** Create a new PdfDataOwnedType.
+     *  Can only be called by subclasses
+     */
+    PdfOwnedDataType();
+
+    PdfOwnedDataType( const PdfOwnedDataType &rhs );
+
+public:
+
+    /** \returns a pointer to a PdfVecObjects that is the
+     *           owner of this data type.
+     *           Might be NULL if the data type has no owner.
+     */
+    inline const PdfObject* GetOwner() const;
+    inline PdfObject* GetOwner();
+
+    PdfOwnedDataType & operator=( const PdfOwnedDataType &rhs );
+
+protected:
+    PdfObject * GetIndirectObject( const PdfReference &rReference ) const;
+    PdfVecObjects * GetObjectOwner();
+    virtual void SetOwner( PdfObject *pOwner );
+
+private:
+    PdfObject *m_pOwner;
+};
+
+inline const PdfObject* PdfOwnedDataType::GetOwner() const
+{
+    return m_pOwner;
+}
+
+inline PdfObject* PdfOwnedDataType::GetOwner()
+{
+    return m_pOwner;
+}
+
+}; // namespace PoDoFo
+
+#endif /* _PDF_OWNED_DATATYPE_H_ */
diff --git a/src/podofo/base/PdfParser.cpp b/src/podofo/base/PdfParser.cpp
new file mode 100644 (file)
index 0000000..d9c1db8
--- /dev/null
@@ -0,0 +1,1554 @@
+/***************************************************************************
+ *   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 <cstring>
+#include <cstdlib>
+#include <sstream>
+#include <algorithm>
+#include <iostream>
+#include <limits>
+
+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
+#elif 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 {
+
+bool PdfParser::s_bIgnoreBrokenObjects = true;
+const long nMaxNumIndirectObjects = (1L << 23) - 1L;
+long PdfParser::s_nMaxObjects = nMaxNumIndirectObjects;
+  
+    
+class PdfRecursionGuard
+{
+  // RAII recursion guard ensures m_nRecursionDepth is always decremented
+  // because the destructor is always called when control leaves a method
+  // via return or an exception.
+  // see http://en.cppreference.com/w/cpp/language/raii
+
+  // It's used like this in PdfParser methods
+  // PdfRecursionGuard guard(m_nRecursionDepth);
+
+  public:
+    PdfRecursionGuard( int& nRecursionDepth ) 
+    : m_nRecursionDepth(nRecursionDepth) 
+    { 
+        // 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 maxRecursionDepth = 500;
+
+        ++m_nRecursionDepth;
+
+        if ( m_nRecursionDepth > maxRecursionDepth )
+        {
+            // avoid stack overflow on documents that have circular cross references in /Prev entries
+            // in trailer and XRef streams (possible via a chain of entries with a loop)
+            PODOFO_RAISE_ERROR( ePdfError_InvalidXRef );
+        }    
+    }
+
+    ~PdfRecursionGuard() 
+    { 
+        --m_nRecursionDepth;    
+    }
+
+  private:
+    // must be a reference so that we modify m_nRecursionDepth in parent class
+    int& m_nRecursionDepth;
+};
+
+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_nIncrementalUpdates = 0;
+    m_nRecursionDepth = 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
+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 // _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<long>(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;
+    }
+
+    if (m_nNumObjects > 0)
+    {
+      ResizeOffsets( 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<EPdfVersion>(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_t>(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<PdfParserObject*>(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<pdf_long>(lXRef-PDF_XREF_BUF) > 0 ? static_cast<pdf_long>(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<int>(m_ePdfVersion) );
+            // PODOFO_RAISE_ERROR( ePdfError_InvalidLinearization );
+        }
+
+        {
+            m_nXRefLinearizedOffset = static_cast<pdf_long>(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()
+{
+    PdfRecursionGuard guard(m_nRecursionDepth);
+
+    // 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<pdf_long>(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 {
+                pdf_long lOffset = static_cast<pdf_long>(trailer.GetDictionary().GetKeyAsLong( "Prev", 0 ));
+
+                if( m_visitedXRefOffsets.find( lOffset ) == m_visitedXRefOffsets.end() )
+                    ReadXRefContents( lOffset );
+                else
+                    PdfError::LogMessage( eLogSeverity_Warning, "XRef contents at offset %" PDF_FORMAT_INT64 " requested twice, skipping the second read\n", static_cast<pdf_int64>( lOffset ));
+            } 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 );
+    }
+}
+
+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<PdfParserObject*>(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<PdfParserObject*>(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=%" PDF_FORMAT_INT64 "\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 )
+{
+    PdfRecursionGuard guard(m_nRecursionDepth);
+
+    pdf_int64 nFirstObject = 0;
+    pdf_int64 nNumObjects  = 0;
+
+    if( m_visitedXRefOffsets.find( lOffset ) != m_visitedXRefOffsets.end() )
+    {
+        std::ostringstream oss;
+        oss << "Cycle in xref structure. Offset  "
+            << lOffset << " already visited.";
+        
+        PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidXRef, oss.str() );
+    }
+    else
+    {
+        m_visitedXRefOffsets.insert( lOffset );
+    }
+    
+    
+    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<std::streamoff>(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;
+        }
+    }
+}
+
+static bool CheckEOL( char e1, char e2 )
+{   
+    // From pdf reference, page 94:
+    // If the file's end-of-line marker is a single character (either a carriage return or a line feed),
+    // it is preceded by a single space; if the marker is 2 characters (both a carriage return and a line feed),
+    // it is not preceded by a space.            
+    return ( (e1 == '\r' && e2 == '\n') || (e1 == '\n' && e2 == '\r') || (e1 == ' ' && (e2 == '\r' || e2 == '\n')) );
+}
+
+void PdfParser::ReadXRefSubsection( pdf_int64 & nFirstObject, pdf_int64 & nNumObjects )
+{
+    pdf_int64 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 < 0 )
+        PODOFO_RAISE_ERROR_INFO( ePdfError_ValueOutOfRange, "ReadXRefSubsection: nFirstObject is negative" );
+    if ( nNumObjects < 0 )
+        PODOFO_RAISE_ERROR_INFO( ePdfError_ValueOutOfRange, "ReadXRefSubsection: nNumObjects is negative" );
+
+    const pdf_int64 maxNum
+      = static_cast<pdf_int64>(PdfParser::s_nMaxObjects);
+
+    // overflow guard, fixes CVE-2017-5853 (signed integer overflow)
+    // also fixes CVE-2017-6844 (buffer overflow) together with below size check
+    if( (maxNum >= nNumObjects) && (nFirstObject <= maxNum - nNumObjects) )
+    {
+        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,
+              static_cast<pdf_int64>( m_nNumObjects ));
+        }
+
+        if ( static_cast<pdf_uint64>( nFirstObject ) + static_cast<pdf_uint64>( nNumObjects ) > static_cast<pdf_uint64>( std::numeric_limits<size_t>::max() ) )
+        {
+            PODOFO_RAISE_ERROR_INFO( ePdfError_ValueOutOfRange,
+                "xref subsection's given entry numbers together too large" );
+        }
+        
+        if( nFirstObject + nNumObjects > m_nNumObjects )
+        {
+            try {
+             
+#ifdef _WIN32
+                m_nNumObjects = static_cast<long>(nFirstObject+nNumObjects);
+#else
+                m_nNumObjects = nFirstObject + nNumObjects;
+#endif // _WIN32
+                ResizeOffsets(nFirstObject + nNumObjects);
+
+            } catch (std::exception &) {
+                // If m_nNumObjects*sizeof(TXRefEntry) > std::numeric_limits<size_t>::max() then
+                // resize() throws std::length_error, for smaller allocations that fail it may throw
+                // std::bad_alloc (implementation-dependent). "20.5.5.12 Restrictions on exception 
+                // handling" in the C++ Standard says any function that throws an exception is allowed 
+                // to throw implementation-defined exceptions derived the base type (std::exception)
+                // so we need to catch all std::exceptions here
+                PODOFO_RAISE_ERROR( ePdfError_OutOfMemory );
+            }
+        }
+    }
+    else
+    {
+        PdfError::LogMessage( eLogSeverity_Error, "There are more objects (%" PDF_FORMAT_INT64
+            " + %" PDF_FORMAT_INT64 " seemingly) in this XRef"
+            " table than supported by standard PDF, or it's inconsistent.\n",
+            nFirstObject, nNumObjects);
+        PODOFO_RAISE_ERROR( ePdfError_InvalidXRef );
+    }
+
+    // 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<int>(nFirstObject+count);
+#else
+               const int objID = nFirstObject+count;
+#endif // _WIN32
+
+        if( static_cast<size_t>(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)
+            // eol is a 2-character end-of-line sequence
+            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 || !CheckEOL( empty1, empty2 ) )
+            {
+                // 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<pdf_long>(llOffset);
+            m_offsets[objID].lGeneration = static_cast<long>(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 )
+{
+    PdfRecursionGuard guard(m_nRecursionDepth);
+
+    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() && xrefObject.GetPreviousOffset() != lOffset) 
+    {
+        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();
+            if( i <= 0 || static_cast<size_t>( i ) >= m_offsets.size () )
+            {
+                std::ostringstream oss;
+                oss << "Encryption dictionary references a nonexistent object " << pEncrypt->GetReference().ObjectNumber() << " " 
+                    << pEncrypt->GetReference().GenerationNumber();
+                PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidEncryptionDict, oss.str().c_str() );
+            }
+
+            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<int>(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( s_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<int>(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<int>(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<int>(m_offsets[i].lGeneration), 
+                                  static_cast<int>(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)
+        {
+            const PdfParserObject* pObject = dynamic_cast<PdfParserObject*>(*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<PdfParserObject*>(m_vecObjects->GetObject( PdfReference( nObjNo, 0 ) ) );
+    if( !pStream )
+    {
+        std::ostringstream oss;
+        oss << "Loading of object " << nObjNo << " 0 R failed!" << std::endl;
+
+        if( s_bIgnoreBrokenObjects )
+        {
+            PdfError::LogMessage( eLogSeverity_Error, oss.str().c_str() );
+            return;
+        }
+        else
+        {
+            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<pdf_int64>(i));
+               }
+       }
+    
+    PdfObjectStreamParserObject pParserObject( pStream, m_vecObjects, m_buffer );
+    pParserObject.Parse( list );
+}
+
+const char* PdfParser::GetPdfVersionString() const
+{
+    return s_szPdfVersions[static_cast<int>(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<pdf_long>(nFileSize), static_cast<pdf_long>(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<pdf_long>(nFileSize), static_cast<pdf_long>(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->MustGetIndirectKey( 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<int>(m_ePdfVersion)],
+                                          s_szPdfVersionNums[i] );
+                    m_ePdfVersion = static_cast<EPdfVersion>(i);
+                    break;
+                }
+            }
+        }
+    }
+    
+}
+
+void PdfParser::ResizeOffsets( pdf_long nNewSize )
+{
+    // allow caller to specify a max object count to avoid very slow load times on large documents
+    if (nNewSize > s_nMaxObjects)
+    {
+        PODOFO_RAISE_ERROR_INFO( ePdfError_ValueOutOfRange,  "nNewSize is greater than m_nMaxObjects." );
+    }
+    
+    m_offsets.resize( nNewSize );  
+}
+
+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<int>(nEOFTokenLen), std::ios_base::end );
+    if( IsStrictParsing() )
+    {
+        // For strict mode EOF marker must be at the very end of the file
+        if( static_cast<size_t>(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<size_t>(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;
+}
+
+
+};
+
+
+
diff --git a/src/podofo/base/PdfParser.h b/src/podofo/base/PdfParser.h
new file mode 100644 (file)
index 0000000..ec0fdff
--- /dev/null
@@ -0,0 +1,723 @@
+/***************************************************************************
+ *   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<int,PdfObject*>    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<TXRefEntry>      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 static bool GetIgnoreBrokenObjects();
+
+    /**
+     * Specify if the parser should ignore broken
+     * objects, i.e. XRef entries that do not point
+     * to valid objects.
+     *
+     * Default is to ignore broken objects and
+     * to not throw an exception if one is found.
+     *
+     * \param bBroken if true broken objects will be ignored
+     */
+    inline static void SetIgnoreBrokenObjects( bool bBroken );
+
+    /**
+     * \return maximum object count to read
+     */
+    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.
+     *
+     * By default, the maximum object count is set to 8388607 
+     * which is the maximum number of indirect objects according 
+     * to the PDF specification.
+     *
+     * \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();
+
+
+    /** Resize the internal structure m_offsets in a safe manner.
+     *  The limit for the maximum number of indirect objects in a PDF file is checked by this method.
+     *  The maximum is 2^23-1 (8.388.607). 
+     *
+     *  \param nNewSize new size of the vector
+     */
+    void ResizeOffsets( pdf_long nNewSize );
+    
+ 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<int> m_setObjectStreams;
+
+    bool          m_bStrictParsing;
+
+    int           m_nIncrementalUpdates;
+    int           m_nRecursionDepth;
+
+    static bool   s_bIgnoreBrokenObjects;
+
+    static long   s_nMaxObjects;
+    
+    std::set<pdf_long> m_visitedXRefOffsets;
+};
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+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 s_bIgnoreBrokenObjects;
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+void PdfParser::SetIgnoreBrokenObjects( bool bBroken )
+{
+    s_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_
+
diff --git a/src/podofo/base/PdfParserObject.cpp b/src/podofo/base/PdfParserObject.cpp
new file mode 100644 (file)
index 0000000..5818b75
--- /dev/null
@@ -0,0 +1,438 @@
+/***************************************************************************
+ *   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 <iostream>
+#include <sstream>
+
+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<unsigned int>(obj), static_cast<pdf_uint16>(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 );
+
+    do
+    {
+        // Skip spaces between the stream keyword and the carriage return/line feed or line feed
+        // Actually, this is not required by PDF Reference, but certain PDFs have additionals whitespaces
+        c = m_device.Device()->Look();
+        if ( c == ' ' )
+            c = m_device.Device()->GetChar();
+    } while ( c == ' ' );
+
+    // 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.
+    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->IsReference() )
+            pFilterObj = m_pOwner->GetObject( pFilterObj->GetReference() );
+               if( pFilterObj && pFilterObj->IsArray() ) {
+                       PdfArray filters = pFilterObj->GetArray();
+                       for(PdfArray::iterator it = filters.begin(); it != filters.end(); it++) {
+                PdfObject *filter = &*it;
+                if( filter->IsReference() )
+                    filter = m_pOwner->GetObject( filter->GetReference() );
+                if( filter && filter->IsName() )
+                    if( filter->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<pdf_long>(lLen) );
+        delete pInput;
+    }
+    else
+        this->GetStream_NoDL()->SetRawData( &reader, static_cast<pdf_long>(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();
+    }
+}
+
+};
diff --git a/src/podofo/base/PdfParserObject.h b/src/podofo/base/PdfParserObject.h
new file mode 100644 (file)
index 0000000..c161dd6
--- /dev/null
@@ -0,0 +1,238 @@
+/***************************************************************************
+ *   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<pdf_int64>(m_lOffset);
+}
+
+};
+
+#endif // _PDF_PARSER_OBJECT_H_
diff --git a/src/podofo/base/PdfRect.cpp b/src/podofo/base/PdfRect.cpp
new file mode 100644 (file)
index 0000000..9bec96a
--- /dev/null
@@ -0,0 +1,183 @@
+/***************************************************************************
+ *   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 <iostream>
+#include <sstream>
+#include <iomanip>
+
+static void NormalizeCoordinates( double &coord1, double &coord2 );
+
+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 ) 
+    {
+        double x1 = inArray[0].GetReal();
+        double y1 = inArray[1].GetReal();
+        double x2 = inArray[2].GetReal();
+        double y2 = inArray[3].GetReal();
+
+        // See Pdf Reference 1.7, 3.8.4 Rectangles
+        NormalizeCoordinates( x1, x2 );
+        NormalizeCoordinates( y1, y2 );
+
+        m_dLeft   = x1;
+        m_dBottom = y1;
+        m_dWidth  = x2 - x1;
+        m_dHeight = y2 - y1;
+    }
+    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;
+}
+
+};
+
+void NormalizeCoordinates( double & coord1, double & coord2 )
+{
+    if ( coord1 > coord2 )
+    {
+        double temp = coord1;
+        coord1 = coord2;
+        coord2 = temp;
+    }
+}
diff --git a/src/podofo/base/PdfRect.h b/src/podofo/base/PdfRect.h
new file mode 100644 (file)
index 0000000..40dbcdb
--- /dev/null
@@ -0,0 +1,205 @@
+/***************************************************************************
+ *   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_ */
diff --git a/src/podofo/base/PdfRefCountedBuffer.cpp b/src/podofo/base/PdfRefCountedBuffer.cpp
new file mode 100644 (file)
index 0000000..6cb6c5a
--- /dev/null
@@ -0,0 +1,269 @@
+/***************************************************************************
+ *   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 <stdlib.h>
+#include <string.h>
+
+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<char*>(podofo_calloc( lSize, sizeof(char) ));
+    else
+        pBuffer->m_pHeapBuffer = 0;
+    pBuffer->m_lBufferSize     = PDF_MAX( lSize, static_cast<size_t>(+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<size_t>(m_pBuffer->m_lBufferSize) < lSize ? lSize - static_cast<size_t>(m_pBuffer->m_lBufferSize) : 0 );
+        // We might have pre-allocated enough to service the request already
+        if( static_cast<size_t>(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<char*>(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<char*>(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<char*>(podofo_calloc( lSize, sizeof(char) ));
+        }
+        else
+        {
+            m_pBuffer->m_pHeapBuffer = 0;
+        }
+
+        m_pBuffer->m_lBufferSize     = PDF_MAX( lSize, static_cast<size_t>(+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;
+    }
+}
+
+
+};
diff --git a/src/podofo/base/PdfRefCountedBuffer.h b/src/podofo/base/PdfRefCountedBuffer.h
new file mode 100644 (file)
index 0000000..c82dfa5
--- /dev/null
@@ -0,0 +1,326 @@
+/***************************************************************************
+ *   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<size_t>(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_
+
diff --git a/src/podofo/base/PdfRefCountedInputDevice.cpp b/src/podofo/base/PdfRefCountedInputDevice.cpp
new file mode 100644 (file)
index 0000000..38bbc97
--- /dev/null
@@ -0,0 +1,136 @@
+/***************************************************************************
+ *   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;
+}
+
+
+};
diff --git a/src/podofo/base/PdfRefCountedInputDevice.h b/src/podofo/base/PdfRefCountedInputDevice.h
new file mode 100644 (file)
index 0000000..afa904e
--- /dev/null
@@ -0,0 +1,139 @@
+/***************************************************************************
+ *   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_
+
+
diff --git a/src/podofo/base/PdfReference.cpp b/src/podofo/base/PdfReference.cpp
new file mode 100644 (file)
index 0000000..711876b
--- /dev/null
@@ -0,0 +1,63 @@
+/***************************************************************************
+ *   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 <sstream>
+
+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();
+}
+
+};
diff --git a/src/podofo/base/PdfReference.h b/src/podofo/base/PdfReference.h
new file mode 100644 (file)
index 0000000..a5d4b84
--- /dev/null
@@ -0,0 +1,256 @@
+/***************************************************************************
+ *   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_
+
+
diff --git a/src/podofo/base/PdfStream.cpp b/src/podofo/base/PdfStream.cpp
new file mode 100644 (file)
index 0000000..fd102fc
--- /dev/null
@@ -0,0 +1,260 @@
+/***************************************************************************
+ *   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 <iostream>
+
+#include <stdlib.h>
+
+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<char*>(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<char*>(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::uniqueu_ptr so that pDecodeStream is deleted 
+        // even in the case of an exception 
+        PODOFO_UNIQUEU_PTR<PdfOutputStream> 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<char*>(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<pdf_int64>(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 );
+}
+
+};
diff --git a/src/podofo/base/PdfStream.h b/src/podofo/base/PdfStream.h
new file mode 100644 (file)
index 0000000..70e241b
--- /dev/null
@@ -0,0 +1,367 @@
+/***************************************************************************
+ *   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 <string.h>
+
+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<char*>(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_
diff --git a/src/podofo/base/PdfString.cpp b/src/podofo/base/PdfString.cpp
new file mode 100644 (file)
index 0000000..5a68b50
--- /dev/null
@@ -0,0 +1,1261 @@
+/***************************************************************************
+ *   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 <alloca.h>
+#elif defined(__APPLE__) || defined(__linux)
+#include <cstdlib>
+#elif defined(_WIN32)
+#include <malloc.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#ifdef PODOFO_HAVE_UNISTRING_LIB
+#include <unistr.h>
+#endif /* PODOFO_HAVE_UNISTRING_LIB */
+
+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<char*>(g_StrEscMap);
+    memset( map, 0, sizeof(char) * lAllocLen );
+    map[static_cast<unsigned char>('\n')] = 'n'; // Line feed (LF)
+    map[static_cast<unsigned char>('\r')] = 'r'; // Carriage return (CR)
+    map[static_cast<unsigned char>('\t')] = 't'; // Horizontal tab (HT)
+    map[static_cast<unsigned char>('\b')] = 'b'; // Backspace (BS)
+    map[static_cast<unsigned char>('\f')] = 'f'; // Form feed (FF)
+    map[static_cast<unsigned char>(')')] = ')';  
+    map[static_cast<unsigned char>('(')] = '(';  
+    map[static_cast<unsigned char>('\\')] = '\\';
+
+    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<char>(0xFE), static_cast<char>(0xFF) };
+#else
+const char  PdfString::s_pszUnicodeMarker[]  = { static_cast<char>(0xFE), static_cast<char>(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 );
+        }
+        const bool wchar_t_is_two_bytes = sizeof(wchar_t) == 2;
+        if( wchar_t_is_two_bytes ) 
+        {
+            // 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<char*>(podofo_malloc( lDest ));
+            if (!pDest)
+            {
+                PODOFO_RAISE_ERROR(ePdfError_OutOfMemory);
+            }
+
+            size_t cnt   = wcstombs(pDest, pszString, lDest);
+            if( cnt != static_cast<size_t>(-1) )
+            {
+                // No error
+                InitFromUtf8( reinterpret_cast<pdf_utf8*>(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<const char*>(pszStringUtf8) ) );
+
+    m_sUtf8 = reinterpret_cast<const char*>(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<const char*>(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<const char*>(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<const char*>(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<size_t>(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<unsigned char*>(m_buffer.GetBuffer()),
+                           static_cast<unsigned int>(m_buffer.GetSize()-2),
+                          reinterpret_cast<unsigned char*>(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<char>(0xFE) && m_buffer.GetBuffer()[1] == static_cast<char>(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<const unsigned char*>(pInputBuffer), nInputBufferLen, reinterpret_cast<unsigned char*>(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<unsigned char>(*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<char>  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<pdf_utf16be *>(&bytes[0]); 
+#else
+    pdf_utf16be *pBuffer = reinterpret_cast<pdf_utf16be *>(bytes.data()); 
+#endif
+
+    lBufLen = PdfString::ConvertUTF8toUTF16( pszStringUtf8, lLen, pBuffer, lBufLen );
+
+    lBufLen = lBufLen > 0 ? (lBufLen-1) << 1 : 0; // 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<const char*>(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 * characterlength.
+
+        pdf_long  lBufferLen = (5*this->GetUnicodeLength())+2;
+        char* pBuffer    = static_cast<char*>(podofo_calloc( lBufferLen, sizeof(char) ));
+        if( !pBuffer )
+        {
+            PODOFO_RAISE_ERROR( ePdfError_OutOfMemory );
+        }
+
+        pdf_long lUtf8 = PdfString::ConvertUTF16toUTF8( reinterpret_cast<const pdf_utf16be*>(m_buffer.GetBuffer()), 
+                                                    this->GetUnicodeLength(), 
+                                                    reinterpret_cast<pdf_utf8*>(pBuffer), lBufferLen, ePdfStringConversion_Lenient );
+        if (lUtf8 + 1 > lBufferLen) // + 1 to account for 2 bytes termination here vs. 1 byte there
+        {
+            pBuffer = static_cast<char*>(podofo_realloc( pBuffer, lUtf8 + 1 ) );
+            if( !pBuffer )
+            {
+                PODOFO_RAISE_ERROR( ePdfError_OutOfMemory );
+            }
+            if (lUtf8 - 1 > lBufferLen)
+                lUtf8 = PdfString::ConvertUTF16toUTF8( reinterpret_cast<const pdf_utf16be*>(m_buffer.GetBuffer()),
+                                                       this->GetUnicodeLength(), reinterpret_cast<pdf_utf8*>(pBuffer), lUtf8 + 1);
+        }
+
+        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<const wchar_t*>(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
+    {
+        pdf_long                  lLen  = (m_buffer.GetSize() - 1) << 1;
+        PdfString             str;
+        PdfRefCountedBuffer   buffer( lLen + 1 );
+        PdfMemoryOutputStream stream( buffer.GetBuffer(), lLen );
+
+        PODOFO_UNIQUEU_PTR<PdfFilter> 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
+    {
+        pdf_long                  lLen = m_buffer.GetSize() >> 1;
+        PdfString             str;
+        PdfRefCountedBuffer   buffer( lLen );
+        PdfMemoryOutputStream stream( buffer.GetBuffer(), lLen );
+
+        PODOFO_UNIQUEU_PTR<PdfFilter> 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;
+    }
+}
+
+PdfRefCountedBuffer &PdfString::GetBuffer(void)
+{
+       return m_buffer;
+}
+
+#ifdef PODOFO_HAVE_UNISTRING_LIB
+
+pdf_long PdfString::ConvertUTF8toUTF16( const pdf_utf8* pszUtf8, pdf_utf16be* pszUtf16, pdf_long lLenUtf16 )
+{
+    return pszUtf8 ? 
+        PdfString::ConvertUTF8toUTF16( pszUtf8, strlen( reinterpret_cast<const char*>(pszUtf8) ), pszUtf16, lLenUtf16 ) : 0;
+}
+
+pdf_long PdfString::ConvertUTF8toUTF16( const pdf_utf8* pszUtf8, pdf_long lLenUtf8, 
+                                    pdf_utf16be* pszUtf16, pdf_long lLenUtf16,
+                                    EPdfStringConversion eConversion )
+{
+    const uint8_t* s = reinterpret_cast<const uint8_t*>(pszUtf8);
+    uint16_t* resultBuf = reinterpret_cast<uint16_t*>(pszUtf16);
+    size_t sLength = lLenUtf8;
+    size_t resultBufLength = lLenUtf16*sizeof(pdf_utf16be);
+
+    u8_to_u16 (s, sLength, resultBuf, &resultBufLength);
+
+    pdf_long lBufferLen = PODOFO_MIN( static_cast<pdf_long>(resultBufLength + 1), lLenUtf16 );
+    PdfRefCountedBuffer buffer(reinterpret_cast<char*>(pszUtf16), lBufferLen * sizeof(pdf_utf16be));
+    buffer.SetTakePossesion(false);
+    
+#ifdef PODOFO_IS_LITTLE_ENDIAN
+    SwapBytes( buffer.GetBuffer(), lBufferLen*sizeof(pdf_utf16be) );
+#endif // PODOFO_IS_LITTLE_ENDIAN
+
+    // Make sure buffer is 0 termnated
+    reinterpret_cast<pdf_utf16be*>(buffer.GetBuffer())[resultBufLength] = 0;
+    
+    return lBufferLen;
+}
+
+
+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 );
+}
+
+// returns used, or if not enough memory passed in, needed length incl. 1 byte termination
+pdf_long PdfString::ConvertUTF16toUTF8( const pdf_utf16be* pszUtf16, pdf_long lLenUtf16, 
+                                    pdf_utf8* pszUtf8, pdf_long lLenUtf8, 
+                                    EPdfStringConversion eConversion  )
+{
+    PdfRefCountedBuffer buffer(lLenUtf16 * sizeof(pdf_utf16be));
+    memcpy( buffer.GetBuffer(), pszUtf16, lLenUtf16 * sizeof(pdf_utf16be) );
+
+#ifdef PODOFO_IS_LITTLE_ENDIAN
+    SwapBytes( buffer.GetBuffer(), lLenUtf16*sizeof(pdf_utf16be) );
+#endif // PODOFO_IS_LITTLE_ENDIAN
+   
+    const uint16_t* s = reinterpret_cast<const uint16_t*>(buffer.GetBuffer());
+    uint8_t* pResultBuf = reinterpret_cast<pdf_utf8*>(pszUtf8);
+    
+    size_t sLength = lLenUtf16;
+    size_t resultBufLength = lLenUtf8;
+
+    uint8_t* pReturnBuf = u16_to_u8( s, sLength, pResultBuf, &resultBufLength );
+    if (pReturnBuf != pResultBuf)
+    {
+        free(pReturnBuf); // allocated by libunistring, so don't use podofo_free()
+        PdfError::LogMessage( eLogSeverity_Warning, "Output string size too little to hold it\n" );
+        return resultBufLength + 1;
+    }
+
+    pdf_long lBufferLen = PODOFO_MIN( static_cast<pdf_long>(resultBufLength + 1), lLenUtf8 );
+
+    // Make sure buffer is 0 terminated
+    if ( static_cast<pdf_long>(resultBufLength + 1) <= lLenUtf8 )
+        pszUtf8[resultBufLength] = 0;
+    else
+        return resultBufLength + 1; // means: check for this in the caller to detect non-termination
+    
+    return lBufferLen;
+}
+
+#else /* PODOFO_HAVE_UNISTRING_LIB */
+
+/*
+ * 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<unsigned long>(0x0000FFFD)
+#define UNI_MAX_BMP          static_cast<unsigned long>(0x0000FFFF)
+#define UNI_MAX_UTF16        static_cast<unsigned long>(0x0010FFFF)
+
+#define UNI_SUR_HIGH_START   static_cast<unsigned long>(0xD800)
+#define UNI_SUR_HIGH_END     static_cast<unsigned long>(0xDBFF)
+#define UNI_SUR_LOW_START    static_cast<unsigned long>(0xDC00)
+#define UNI_SUR_LOW_END      static_cast<unsigned long>(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;
+    // fall through
+    case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+    // fall through
+    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;
+       }
+
+    // fall through
+    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<const char*>(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 */
+            // fall through
+           case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
+            // fall through
+           case 3: ch += *source++; ch <<= 6;
+            // fall through
+           case 2: ch += *source++; ch <<= 6;
+            // fall through
+           case 1: ch += *source++; ch <<= 6;
+            // fall through
+           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<pdf_utf16be>(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<pdf_utf16be>((ch >> halfShift) + UNI_SUR_HIGH_START);
+           *target++ = static_cast<pdf_utf16be>((ch & halfMask) + UNI_SUR_LOW_START);
+       }
+    }
+
+    // swap to UTF-16be on LE systems
+#ifdef PODOFO_IS_LITTLE_ENDIAN
+    PdfString::SwapBytes( reinterpret_cast<char*>(pszUtf16), static_cast<pdf_long>(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<pdf_utf16be*>(source), pszUtf16, lLenUtf16 * sizeof(pdf_utf16be) );
+    
+    PdfString::SwapBytes( reinterpret_cast<char*>(const_cast<pdf_utf16be*>(source)), lLenUtf16 * sizeof(pdf_utf16be) );
+    pszUtf16  = source;
+    const_cast<pdf_utf16be*>(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<unsigned long>(0x80)) {            
+                bytesToWrite = 1;
+            } else if (ch < static_cast<unsigned long>(0x800)) {     
+                bytesToWrite = 2;
+            } else if (ch < static_cast<unsigned long>(0x10000)) {   
+                bytesToWrite = 3;
+            } else if (ch < static_cast<unsigned long>(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<pdf_utf8>((ch | byteMark) & byteMask); ch >>= 6;
+                // fall through
+                case 3: *--target = static_cast<pdf_utf8>((ch | byteMark) & byteMask); ch >>= 6;
+                // fall through
+                case 2: *--target = static_cast<pdf_utf8>((ch | byteMark) & byteMask); ch >>= 6;
+                // fall through
+                case 1: *--target = static_cast<pdf_utf8>(ch | firstByteMark[bytesToWrite]);
+            }
+            target += bytesToWrite;
+        }
+    }
+    catch( PdfError & e ) 
+    {
+        if( bOwnBuf )
+            delete[] const_cast<pdf_utf16be *>(pszUtf16);
+
+        throw e;
+    }
+
+    if( bOwnBuf )
+        delete[] const_cast<pdf_utf16be *>(pszUtf16);
+
+    // return bytes written
+    return target - pszUtf8;
+}
+
+/* ---------------------------------------------------------------------
+
+    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.
+
+   --------------------------------------------------------------------- */
+
+#endif /* PODOFO_HAVE_UNISTRING_LIB */
+
+
+};
diff --git a/src/podofo/base/PdfString.h b/src/podofo/base/PdfString.h
new file mode 100644 (file)
index 0000000..19d5142
--- /dev/null
@@ -0,0 +1,556 @@
+/***************************************************************************
+ *   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 and may contain '\0' bytes.
+     *
+     *  If IsUnicode() returns true, the return value
+     *  points to a UTF-16BE string buffer with GetCharacterLength()
+     *  characters (GetLength() bytes without the terminating '\0').
+     *  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 GetLength
+     */
+    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 with GetCharacterLength() characters (GetLength() bytes without
+     *  the terminating '\0' bytes).
+     *
+     *  If IsUnicode() returns false, the return value
+     *  points to a PdfDocEncoding string buffer with GetLength()
+     *  characters (so may well not be valid as UTF-16BE).
+     *  Better use GetString() 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 GetUnicodeLength
+     */
+    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
+      *          (zero size buffer, internally NULL, 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<pdf_utf16be*>(m_buffer.GetBuffer());
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+const std::string & PdfString::GetStringUtf8() const
+{
+    if( this->IsValid() && !m_sUtf8.length() && m_buffer.GetSize() - 2) 
+        const_cast<PdfString*>(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_
diff --git a/src/podofo/base/PdfTokenizer.cpp b/src/podofo/base/PdfTokenizer.cpp
new file mode 100644 (file)
index 0000000..9167f29
--- /dev/null
@@ -0,0 +1,893 @@
+/***************************************************************************
+ *   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 <limits>
+#include <sstream>
+#include <memory>
+
+#include <stdlib.h>
+#include <string.h>
+
+#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<char*>(g_DelMap);
+    memset( map, 0, sizeof(char) * g_MapAllocLen );
+    for (int i = 0; i < PoDoFo::s_nNumDelimiters; ++i)
+    {
+        map[static_cast<int>(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<char*>(g_WsMap);
+    memset( map, 0, sizeof(char) * g_MapAllocLen );
+    for (int i = 0; i < PoDoFo::s_nNumWhiteSpaces; ++i)
+    {
+        map[static_cast<int>(PoDoFo::s_cWhiteSpaces[i])] = 1;
+    }
+    return map;
+}
+
+// Generate the escape character map at runtime
+const char* genEscMap()
+{
+    char* map = static_cast<char*>(g_EscMap);
+    memset( map, 0, sizeof(char) * g_MapAllocLen );
+
+    map[static_cast<unsigned char>('n')] = '\n'; // Line feed (LF)
+    map[static_cast<unsigned char>('r')] = '\r'; // Carriage return (CR)
+    map[static_cast<unsigned char>('t')] = '\t'; // Horizontal tab (HT)
+    map[static_cast<unsigned char>('b')] = '\b'; // Backspace (BS)
+    map[static_cast<unsigned char>('f')] = '\f'; // Form feed (FF)
+    map[static_cast<unsigned char>(')')] = ')';
+    map[static_cast<unsigned char>('(')] = '(';
+    map[static_cast<unsigned char>('\\')] = '\\';
+
+    return map;
+}
+
+// Generate the hex character map at runtime
+const char* genHexMap()
+{
+    char* map = static_cast<char*>(g_hexMap);
+    memset( map, PdfTokenizer::HEX_NOT_FOUND, sizeof(char) * g_MapAllocLen );
+
+    map[static_cast<unsigned char>('0')] = 0x0;
+    map[static_cast<unsigned char>('1')] = 0x1;
+    map[static_cast<unsigned char>('2')] = 0x2;
+    map[static_cast<unsigned char>('3')] = 0x3;
+    map[static_cast<unsigned char>('4')] = 0x4;
+    map[static_cast<unsigned char>('5')] = 0x5;
+    map[static_cast<unsigned char>('6')] = 0x6;
+    map[static_cast<unsigned char>('7')] = 0x7;
+    map[static_cast<unsigned char>('8')] = 0x8;
+    map[static_cast<unsigned char>('9')] = 0x9;
+    map[static_cast<unsigned char>('a')] = 0xA;
+    map[static_cast<unsigned char>('b')] = 0xB;
+    map[static_cast<unsigned char>('c')] = 0xC;
+    map[static_cast<unsigned char>('d')] = 0xD;
+    map[static_cast<unsigned char>('e')] = 0xE;
+    map[static_cast<unsigned char>('f')] = 0xF;
+    map[static_cast<unsigned char>('A')] = 0xA;
+    map[static_cast<unsigned char>('B')] = 0xB;
+    map[static_cast<unsigned char>('C')] = 0xC;
+    map[static_cast<unsigned char>('D')] = 0xD;
+    map[static_cast<unsigned char>('E')] = 0xE;
+    map[static_cast<unsigned char>('F')] = 0xF;
+
+    return map;
+}
+
+};
+
+const unsigned int PdfTokenizer::HEX_NOT_FOUND   = std::numeric_limits<unsigned int>::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 + 1 < static_cast<pdf_int64>(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<const unsigned char>(*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<pdf_int64>(_strtoui64( pszToken, NULL, 10 )) );
+#else
+            rVariant = PdfVariant( static_cast<pdf_int64>(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<char**>(&pszToken), 10 );
+#else
+            long  l   = strtol( pszStart, const_cast<char**>(&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<unsigned int>(rVariant.GetNumber()),
+                                         static_cast<const pdf_uint16>(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;
+    PODOFO_UNIQUEU_PTR<std::vector<char> > contentsHexBuffer;
+
+    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();
+
+        // Try to get the next variant
+        gotToken = this->GetNextToken( pszToken, &eType );
+        if ( !gotToken )
+        {
+            PODOFO_RAISE_ERROR_INFO( ePdfError_UnexpectedEOF, "Expected variant." );
+        }
+
+        EPdfDataType eDataType = this->DetermineDataType( pszToken, eType, val );
+        if ( key == "Contents" && eDataType == ePdfDataType_HexString )
+        {
+            // 'Contents' key in signature dictionaries is an unencrypted Hex string:
+            // save the string buffer for later check if it needed decryption
+            contentsHexBuffer = PODOFO_UNIQUEU_PTR<std::vector<char> >( new std::vector<char>() );
+            ReadHexString( *contentsHexBuffer );
+            continue;
+        }
+
+        switch ( eDataType )
+        {
+            case ePdfDataType_Null:
+            case ePdfDataType_Bool:
+            case ePdfDataType_Number:
+            case ePdfDataType_Real:
+            case ePdfDataType_Reference:
+            {
+                // the data was already read into rVariant by the DetermineDataType function
+                break;
+            }
+            case ePdfDataType_Name:
+            case ePdfDataType_String:
+            case ePdfDataType_HexString:
+            case ePdfDataType_Array:
+            case ePdfDataType_Dictionary:
+            {
+                this->ReadDataType( eDataType, val, pEncrypt );
+                break;
+            }
+            case ePdfDataType_RawData:
+            case ePdfDataType_Unknown:
+            default:
+            {
+                PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Unexpected data type" );
+            }
+        }
+
+        dict.AddKey( key, val );
+    }
+
+    if ( contentsHexBuffer.get() != NULL )
+    {
+        PdfObject *type = dict.GetKey( "Type" );
+        // "Contents" is unencrypted in /Type/Sig and /Type/DocTimeStamp dictionaries 
+        // https://issues.apache.org/jira/browse/PDFBOX-3173
+        bool contentsUnencrypted = type != NULL && type->GetDataType() == ePdfDataType_Name &&
+            (type->GetName() == PdfName( "Sig" ) || type->GetName() == PdfName( "DocTimeStamp" ));
+
+        PdfEncrypt *encrypt = NULL;
+        if ( !contentsUnencrypted )
+            encrypt = pEncrypt;
+
+        PdfString string;
+        string.SetHexData( contentsHexBuffer->size() ? &(*contentsHexBuffer)[0] : "", contentsHexBuffer->size(), encrypt );
+
+        val = string;
+        dict.AddKey( "Contents", 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<char>(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<unsigned char*>(&(m_vecBuffer[0])),
+                              static_cast<unsigned int>(m_vecBuffer.size()),
+                              reinterpret_cast<unsigned char*>(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 )
+{
+    ReadHexString( m_vecBuffer );
+
+    PdfString string;
+    string.SetHexData( m_vecBuffer.size() ? &(m_vecBuffer[0]) : "", m_vecBuffer.size(), pEncrypt );
+
+    rVariant = string;
+}
+
+void PdfTokenizer::ReadHexString( std::vector<char>& rVecBuffer)
+{
+    rVecBuffer.clear();
+    int        c;
+
+    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'))
+            rVecBuffer.push_back( c );
+    }
+
+    // pad to an even length if necessary
+    if(rVecBuffer.size() % 2 )
+        rVecBuffer.push_back( '0' );
+}
+
+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 ) );
+}
+
+};
diff --git a/src/podofo/base/PdfTokenizer.h b/src/podofo/base/PdfTokenizer.h
new file mode 100644 (file)
index 0000000..b7032b6
--- /dev/null
@@ -0,0 +1,328 @@
+/***************************************************************************
+ *   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 <deque>
+#include <sstream>
+
+namespace PoDoFo {
+
+class PdfEncrypt;
+class PdfVariant;
+
+enum EPdfTokenType {
+    ePdfTokenType_Delimiter,
+    ePdfTokenType_Token,
+
+    ePdfTokenType_Unknown = 0xFF
+};
+
+typedef std::pair<std::string,EPdfTokenType> TTokenizerPair;
+typedef std::deque<TTokenizerPair>           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 hex string from the input device
+     *  and store it into a vector.
+     *
+     *  \param rVecBuffer store the hex string into this variable
+     */
+    void ReadHexString( std::vector<char> &rVecBuffer );
+
+    /** 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<char> 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<size_t>(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<size_t>(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<size_t>(ch)];
+}
+
+
+};
+
+#endif // _PDF_TOKENIZER_H_
diff --git a/src/podofo/base/PdfVariant.cpp b/src/podofo/base/PdfVariant.cpp
new file mode 100644 (file)
index 0000000..421a59c
--- /dev/null
@@ -0,0 +1,464 @@
+/***************************************************************************
+ *   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 <sstream>
+
+#include <string.h>
+
+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<PdfDictionary*>(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<PdfArray*>(rhs.m_Data.pData)) );
+            break;
+        }
+        case ePdfDataType_Reference:
+        {
+            if( rhs.m_Data.pData ) 
+                m_Data.pData = new PdfReference( *(static_cast<PdfReference*>(rhs.m_Data.pData)) );
+            break;
+        }
+        case ePdfDataType_Dictionary:
+        {
+            if( rhs.m_Data.pData ) 
+                m_Data.pData = new PdfDictionary( *(static_cast<PdfDictionary*>(rhs.m_Data.pData)) );
+            break;
+        }
+        case ePdfDataType_Name:
+        {
+            if( rhs.m_Data.pData ) 
+                m_Data.pData = new PdfName( *(static_cast<PdfName*>(rhs.m_Data.pData)) );
+            break;
+        }
+        case ePdfDataType_String:
+        case ePdfDataType_HexString:
+        {
+            if( rhs.m_Data.pData ) 
+                m_Data.pData = new PdfString( *(static_cast<PdfString*>(rhs.m_Data.pData)) );
+            break;
+        }
+            
+        case ePdfDataType_RawData: 
+        {
+            if( rhs.m_Data.pData ) 
+                m_Data.pData = new PdfData( *(static_cast<PdfData*>(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" );
+}
+
+};
+
+
+
diff --git a/src/podofo/base/PdfVariant.h b/src/podofo/base/PdfVariant.h
new file mode 100644 (file)
index 0000000..f360827
--- /dev/null
@@ -0,0 +1,1088 @@
+/***************************************************************************
+ *   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 <math.h>
+#else
+#include <cmath>
+#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;
+
+    /** Set the string value of this object.
+     * \param str the string value
+     *
+     * This will set the dirty flag of this object.
+     * \see IsDirty
+     */
+    inline void SetString(const PdfString & str);
+
+    /** \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();
+
+    /** Called after delayed load
+     *  \param eDataType Detected data type
+     */
+    inline virtual void AfterDelayedLoad( EPdfDataType eDataType );
+
+    /**
+     * 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<typename T> 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 may be modified
+
+
+    /** Datatype of the variant, required to access the correct member of the union UVariant.
+     *  The data type is to save RAM space because this class is used in very many instances.
+     *  No fixed-underlying-type enum is used, for pre-C++11 compatibility.
+     *  The type is unsigned because there's no negative value in the enum PdfDataType and
+     *  to cleanly enable the ePdfDataType_Unknown value to be 0xff (as sentinel value).
+     */
+    pdf_uint8 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<PdfVariant*>(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
+        const_cast<PdfVariant*>(this)->AfterDelayedLoad( ( EPdfDataType )m_eDataType );
+    }
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+bool PdfVariant::IsEmpty() const
+{
+    DelayedLoad();
+
+    return (m_eDataType == ePdfDataType_Null);
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+EPdfDataType PdfVariant::GetDataType() const
+{
+    DelayedLoad();
+
+    return static_cast<EPdfDataType>(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<double>(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<long>(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<long>(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<double>(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);
+}
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+void PdfVariant::SetString(const PdfString &str)
+{
+    DelayedLoad();
+
+    if (!IsString())
+    {
+        PODOFO_RAISE_ERROR(ePdfError_InvalidDataType);
+    }
+
+    AssertMutable();
+    *((PdfString*)m_Data.pData) = str;
+    SetDirty(true);
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+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 );
+}
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+void PdfVariant::AfterDelayedLoad( EPdfDataType eDataType )
+{
+    ( void )eDataType;
+    // Do nothing
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+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_
diff --git a/src/podofo/base/PdfVecObjects.cpp b/src/podofo/base/PdfVecObjects.cpp
new file mode 100644 (file)
index 0000000..e8ae047
--- /dev/null
@@ -0,0 +1,628 @@
+/***************************************************************************
+ *   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 <algorithm>
+
+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;
+};
+
+// This is static, IMHO (mabri) different values per-instance could cause confusion.
+// It has to be defined here because of the one-definition rule.
+size_t PdfVecObjects::m_nMaxReserveSize = static_cast<size_t>(8388607); // cf. Table C.1 in section C.2 of PDF32000_2008.pdf
+
+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<PdfVecObjects*>(this)->Sort();
+
+    PdfObject refObj( ref, NULL );
+    TCIVecObjects it = std::lower_bound( m_vector.begin(), m_vector.end(), &refObj, ObjectComparatorPredicate() );
+    if( it != m_vector.end() && (refObj.Reference() == (*it)->Reference()) )
+    {
+        return *it;
+    }
+
+    return NULL;
+}
+
+PdfObject* PdfVecObjects::MustGetObject( const PdfReference & ref ) const
+{
+    PdfObject* obj = GetObject( ref );
+    if (!obj)
+        PODOFO_RAISE_ERROR( ePdfError_NoObject );
+    return obj;
+}
+
+size_t PdfVecObjects::GetIndex( const PdfReference & ref ) const
+{
+    if( !m_bSorted )
+        const_cast<PdfVecObjects*>(this)->Sort();
+
+    PdfObject refObj( ref, NULL );
+    std::pair<TCIVecObjects,TCIVecObjects> 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<TIVecObjects,TIVecObjects> 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<unsigned int>(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<TIPdfReferenceList,TIPdfReferenceList> 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<PdfVecObjects*>(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<TCIVecObjects,TCIVecObjects> 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<PdfReference*>(&(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<TPdfReferenceList::iterator, TPdfReferenceList::iterator> 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();
+    }
+}
+
+};
+
+
diff --git a/src/podofo/base/PdfVecObjects.h b/src/podofo/base/PdfVecObjects.h
new file mode 100644 (file)
index 0000000..7e36f41
--- /dev/null
@@ -0,0 +1,689 @@
+/***************************************************************************
+ *   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 <list>
+
+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<PdfReference>                 TPdfReferenceList;
+typedef TPdfReferenceList::iterator              TIPdfReferenceList;
+typedef TPdfReferenceList::const_iterator        TCIPdfReferenceList;
+
+typedef std::set<PdfReference>                   TPdfReferenceSet;
+typedef TPdfReferenceSet::iterator               TIPdfReferenceSet;
+typedef TPdfReferenceSet::const_iterator         TCIPdfReferenceSet;
+
+typedef std::list<PdfReference*>                 TReferencePointerList;
+typedef TReferencePointerList::iterator          TIReferencePointerList;
+typedef TReferencePointerList::const_iterator    TCIReferencePointerList;
+
+typedef std::vector<TReferencePointerList  >     TVecReferencePointerList;
+typedef TVecReferencePointerList::iterator       TIVecReferencePointerList;
+typedef TVecReferencePointerList::const_iterator TCIVecReferencePointerList;
+
+/*
+typedef std::vector<PdfObject*>      TVecObjects;
+typedef TVecObjects::iterator        TIVecObjects;
+typedef TVecObjects::const_iterator  TCIVecObjects;
+*/
+
+typedef std::vector<PdfObject*>      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<Observer*>        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 a pointer to it if it is found. Throws a PdfError
+     *  exception with error code ePdfError_NoObject if no object was found
+     *  \param ref the object to be found
+     *  \returns the found object
+     *  \throws PdfError(ePdfError_NoObject)
+     */
+    PdfObject* MustGetObject( 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();
+
+    /**
+     * Set the maximum number of elements Reserve() will work for (to fix
+     * CVE-2018-5783) which is called with a value from the PDF in the parser.
+     * The default is from Table C.1 in section C.2 of PDF32000_2008.pdf
+     * (PDF 1.7 standard free version).
+     * This sets a static variable, so don't use from multiple threads
+     * (without proper locking).
+     * \param size Number of elements to allow to be reserved
+     */
+    void SetMaxReserveSize(size_t size);
+
+    /**
+     * Gets the maximum number of elements Reserve() will work for (to fix
+     * CVE-2018-5783) which is called with a value from the PDF in the parser.
+     * The default is from Table C.1 in section C.2 of PDF32000_2008.pdf
+     * (PDF 1.7 standard free version): 8388607.
+     */
+    size_t GetMaxReserveSize() const;
+
+    /** 
+     * 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
+    static size_t       m_nMaxReserveSize;
+};
+
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline size_t PdfVecObjects::GetSize() const
+{
+    return m_vector.size();
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfVecObjects::SetMaxReserveSize(size_t size)
+{
+    m_nMaxReserveSize = size;
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline size_t PdfVecObjects::GetMaxReserveSize() const
+{
+    return m_nMaxReserveSize;
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfVecObjects::Reserve( size_t size )
+{
+    if( size <= m_nMaxReserveSize ) // Fix CVE-2018-5783
+    {
+        m_vector.reserve( size );
+    } 
+    else
+    {
+        PdfError::DebugMessage( "Call to PdfVecObjects::Reserve with %"
+                           PDF_SIZE_FORMAT" is over allowed limit of %"
+                           PDF_SIZE_FORMAT".\n", size, m_nMaxReserveSize );
+    }
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+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_
diff --git a/src/podofo/base/PdfVersion.h b/src/podofo/base/PdfVersion.h
new file mode 100644 (file)
index 0000000..f74f940
--- /dev/null
@@ -0,0 +1,10 @@
+#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
diff --git a/src/podofo/base/PdfWriter.cpp b/src/podofo/base/PdfWriter.cpp
new file mode 100644 (file)
index 0000000..55dfae6
--- /dev/null
@@ -0,0 +1,772 @@
+/***************************************************************************
+ *   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 <iostream>
+#include <stdlib.h>
+
+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%" PDF_FORMAT_UINT64 "\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<char *>( 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<int>(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<const PdfParserObject *>(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<char*>(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<pdf_int64>(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<pdf_int64>(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<int>(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");
+        // The PDF spec, section 7.5.5, implies that the ID may be
+        // indirect as long as the PDF is not encrypted. Handle that
+        // case.
+        if ( idObj->IsReference() ) {
+            idObj = m_vecObjects->MustGetObject( idObj->GetReference() );
+        }
+
+        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<char*>(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<unsigned char*>(pBuffer),
+                                           static_cast<unsigned int>(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 );
+}
+
+};
+
diff --git a/src/podofo/base/PdfWriter.h b/src/podofo/base/PdfWriter.h
new file mode 100644 (file)
index 0000000..6f577bb
--- /dev/null
@@ -0,0 +1,423 @@
+/***************************************************************************
+ *   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<int>(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_
diff --git a/src/podofo/base/PdfXRef.cpp b/src/podofo/base/PdfXRef.cpp
new file mode 100644 (file)
index 0000000..8076cd6
--- /dev/null
@@ -0,0 +1,361 @@
+/***************************************************************************
+ *   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 <algorithm>
+
+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 );
+}
+
+};
diff --git a/src/podofo/base/PdfXRef.h b/src/podofo/base/PdfXRef.h
new file mode 100644 (file)
index 0000000..d6a6eb4
--- /dev/null
@@ -0,0 +1,234 @@
+/***************************************************************************
+ *   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<TXRefItem>         TVecXRefItems;
+    typedef TVecXRefItems::iterator        TIVecXRefItems;
+    typedef TVecXRefItems::const_iterator  TCIVecXRefItems;
+
+    typedef std::vector<PdfReference>      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<PdfXRefBlock>      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_ */
diff --git a/src/podofo/base/PdfXRefStream.cpp b/src/podofo/base/PdfXRefStream.cpp
new file mode 100644 (file)
index 0000000..e65ecf7
--- /dev/null
@@ -0,0 +1,122 @@
+/***************************************************************************
+ *   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 <alloca.h>
+#elif defined(__APPLE__) || defined(__linux)
+#include <cstdlib>
+#elif defined(_WIN32)
+#include <malloc.h>
+#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<pdf_int64>(first) );
+    m_indeces.push_back( static_cast<pdf_int64>(count) );
+}
+
+void PdfXRefStream::WriteXRefEntry( PdfOutputDevice*, pdf_uint64 offset, pdf_gennum generation, 
+                                    char cMode, pdf_objnum objectNumber ) 
+{
+    std::vector<char>  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<char>( cMode == 'n' ? 1 : 0 );
+    buffer[m_bufferLen-1] = static_cast<char>( cMode == 'n' ? 0 : generation );
+
+    const pdf_uint32 offset_be = ::PoDoFo::compat::podofo_htonl(static_cast<pdf_uint32>(offset));
+    memcpy( &buffer[1], reinterpret_cast<const char*>(&offset_be), sizeof(pdf_uint32) );
+
+    m_pObject->GetStream()->Append( buffer, m_bufferLen );
+}
+
+void PdfXRefStream::EndWrite( PdfOutputDevice* pDevice )
+{
+    PdfArray w;
+
+    w.push_back( static_cast<pdf_int64>(1) );
+    w.push_back( static_cast<pdf_int64>(sizeof(pdf_uint32)) );
+    w.push_back( static_cast<pdf_int64>(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<size_t>(m_offset) );
+    m_pObject->WriteObject( pDevice, m_pWriter->GetWriteMode(), NULL ); // DominikS: Requires encryption info??
+    m_indeces.Clear();
+}
+
+};
+
diff --git a/src/podofo/base/PdfXRefStream.h b/src/podofo/base/PdfXRefStream.h
new file mode 100644 (file)
index 0000000..e83c436
--- /dev/null
@@ -0,0 +1,137 @@
+/***************************************************************************
+ *   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_ */
diff --git a/src/podofo/base/PdfXRefStreamParserObject.cpp b/src/podofo/base/PdfXRefStreamParserObject.cpp
new file mode 100644 (file)
index 0000000..99cb78d
--- /dev/null
@@ -0,0 +1,292 @@
+/***************************************************************************
+ *   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 "PdfDefinesPrivate.h"
+#include "PdfDictionary.h"
+#include "PdfStream.h"
+#include "PdfVariant.h"
+
+#include <limits>
+
+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<pdf_long>(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<W_ARRAY_SIZE;i++ )
+    {
+        if( !vWArray.GetArray()[i].IsNumber() )
+        {
+            PODOFO_RAISE_ERROR( ePdfError_NoXRef );
+        }
+
+        nW[i] = static_cast<pdf_int64>(vWArray.GetArray()[i].GetNumber());
+    }
+
+    std::vector<pdf_int64> vecIndeces;
+    GetIndeces( vecIndeces, static_cast<pdf_int64>(lSize) );
+
+    ParseStream( nW, vecIndeces );
+}
+
+void PdfXRefStreamParserObject::ParseStream( const pdf_int64 nW[W_ARRAY_SIZE], const std::vector<pdf_int64> & rvecIndeces )
+{
+    char*        pBuffer;
+    pdf_long     lBufferLen;
+
+    for(pdf_int64 nLengthSum = 0, i = 0; i < W_ARRAY_SIZE; i++ )
+    {
+        if ( nW[i] < 0 )
+        {
+            PODOFO_RAISE_ERROR_INFO( ePdfError_NoXRef,
+                                    "Negative field length in XRef stream" );
+        }
+        if ( std::numeric_limits<pdf_int64>::max() - nLengthSum < nW[i] )
+        {
+            PODOFO_RAISE_ERROR_INFO( ePdfError_NoXRef,
+                                    "Invalid entry length in XRef stream" );
+        }
+        else
+        {
+            nLengthSum += nW[i];
+        }
+    }
+
+    const size_t entryLen  = static_cast<size_t>(nW[0] + nW[1] + nW[2]);
+
+    this->GetStream()->GetFilteredCopy( &pBuffer, &lBufferLen );
+
+    
+    std::vector<pdf_int64>::const_iterator it = rvecIndeces.begin();
+    #ifdef PODOFO_HAVE_UNIQUE_PTR
+    std::unique_ptr<char, decltype( &podofo_free )> pStart( pBuffer, &podofo_free );
+    #else // PODOFO_HAVE_UNIQUE_PTR
+    class StrAutoPtr {
+    private:
+        char *str;
+    public:
+        StrAutoPtr( char *in_str ) : str( in_str ) {}
+        ~StrAutoPtr() {
+            podofo_free( str );
+        }
+        char *get( void ) const { return str; }
+    };
+    StrAutoPtr pStart( pBuffer );
+    #endif // PODOFO_HAVE_UNIQUE_PTR
+
+    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<int>(nFirstObj));
+        //printf("nCount=%i\n", static_cast<int>(nCount));
+        while( nCount > 0 )
+        {
+            if( (pBuffer - pStart.get()) >= lBufferLen ) 
+            {
+                PODOFO_RAISE_ERROR_INFO( ePdfError_NoXRef, "Invalid count in XRef stream" );
+            }
+
+            //printf("nCount=%i ", static_cast<int>(nCount));
+            //printf("pBuffer=%li ", (long)(pBuffer - pStart));
+            //printf("pEnd=%li ", lBufferLen);
+            if ( nFirstObj >= 0 && nFirstObj < static_cast<pdf_int64>(m_pOffsets->size()) 
+                 && ! (*m_pOffsets)[static_cast<int>(nFirstObj)].bParsed)
+            {
+               ReadXRefStreamEntry( pBuffer, lBufferLen, nW, static_cast<int>(nFirstObj) );
+            }
+
+                       nFirstObj++ ;
+            pBuffer += entryLen;
+            --nCount;
+        }
+        //printf("Exp: nFirstObj=%i nFirstObjOrg + nCount=%i\n", nFirstObj - 1, nFirstObjOrg + nCountOrg - 1 );
+        //printf("===\n");
+    }
+}
+
+void PdfXRefStreamParserObject::GetIndeces( std::vector<pdf_int64> & 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<pdf_int64>(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_ARRAY_SIZE;i++ )
+    {
+        if( lW[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<W_MAX_BYTES;z++ )
+        {
+            nData[i] = (nData[i] << 8) + static_cast<unsigned char>(*pBuffer);
+            ++pBuffer;
+        }
+    }
+
+
+    //printf("OBJ=%i nData = [ %i %i %i ]\n", nObjNo, static_cast<int>(nData[0]), static_cast<int>(nData[1]), static_cast<int>(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 );
+}
+
+};
diff --git a/src/podofo/base/PdfXRefStreamParserObject.h b/src/podofo/base/PdfXRefStreamParserObject.h
new file mode 100644 (file)
index 0000000..eb3e07c
--- /dev/null
@@ -0,0 +1,129 @@
+/***************************************************************************
+ *   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.
+ * This is only marked PODOFO_API for the benefit of the tests,
+ * the class is for internal use only. It is deprecated, so
+ * don't ever rely on it (i.e. externally or in PoDoFo tools).
+ */
+class PODOFO_DEPRECATED PODOFO_API 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<pdf_int64> & 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<pdf_int64> & 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_
diff --git a/src/podofo/base/podofoapi.h b/src/podofo/base/podofoapi.h
new file mode 100644 (file)
index 0000000..c0589f1
--- /dev/null
@@ -0,0 +1,216 @@
+/***************************************************************************
+ *   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 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 */
+
+#ifdef __GNU__
+  #define PODOFO_HAS_GCC_ATTRIBUTE_DEPRECATED 1
+#elif defined(__has_attribute)
+  #if __has_attribute(__deprecated__)
+    #define PODOFO_HAS_GCC_ATTRIBUTE_DEPRECATED 1
+  #endif
+#endif
+
+#ifdef PODOFO_HAS_GCC_ATTRIBUTE_DEPRECATED
+    /* gcc (or compat. clang) will issue a warning if a function or variable so annotated is used */
+    #define PODOFO_DEPRECATED       __attribute__((__deprecated__))
+#else
+    #define PODOFO_DEPRECATED
+#endif
+
+#ifdef __GNU__
+    /* 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_PURE_FUNCTION
+    #ifdef _MSC_VER
+      #define PODOFO_NOTHROW        __declspec(nothrow)
+    #else
+      #define PODOFO_NOTHROW
+    #endif
+#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
diff --git a/src/podofo/base/util/PdfMutex.h b/src/podofo/base/util/PdfMutex.h
new file mode 100644 (file)
index 0000000..1b0bbef
--- /dev/null
@@ -0,0 +1,85 @@
+/***************************************************************************
+ *   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
diff --git a/src/podofo/base/util/PdfMutexImpl_noop.h b/src/podofo/base/util/PdfMutexImpl_noop.h
new file mode 100644 (file)
index 0000000..39917fd
--- /dev/null
@@ -0,0 +1,79 @@
+/***************************************************************************
+ *   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
diff --git a/src/podofo/base/util/PdfMutexImpl_pthread.h b/src/podofo/base/util/PdfMutexImpl_pthread.h
new file mode 100644 (file)
index 0000000..4f65715
--- /dev/null
@@ -0,0 +1,131 @@
+/***************************************************************************
+ *   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 <pthread.h>
+#include <errno.h>
+
+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
diff --git a/src/podofo/base/util/PdfMutexImpl_win32.h b/src/podofo/base/util/PdfMutexImpl_win32.h
new file mode 100644 (file)
index 0000000..780d65a
--- /dev/null
@@ -0,0 +1,123 @@
+/***************************************************************************
+ *   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
diff --git a/src/podofo/base/util/PdfMutexWrapper.h b/src/podofo/base/util/PdfMutexWrapper.h
new file mode 100644 (file)
index 0000000..eabe6ea
--- /dev/null
@@ -0,0 +1,105 @@
+/***************************************************************************
+ *   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_
diff --git a/src/podofo/doc/PdfAcroForm.cpp b/src/podofo/doc/PdfAcroForm.cpp
new file mode 100644 (file)
index 0000000..cbc7687
--- /dev/null
@@ -0,0 +1,129 @@
+/***************************************************************************
+ *   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 <sstream>
+
+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()->MustGetIndirectKey( PdfName("DR") );
+        
+        if( !pResource->GetDictionary().HasKey( PdfName("Font") ) )
+            pResource->GetDictionary().AddKey( PdfName("Font"), PdfDictionary() );
+        pFontDict = pResource->MustGetIndirectKey( PdfName("Font") );
+
+        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()->GetIndirectKeyAsBool( PdfName("NeedAppearances"), false );
+}
+
+};
diff --git a/src/podofo/doc/PdfAcroForm.h b/src/podofo/doc/PdfAcroForm.h
new file mode 100644 (file)
index 0000000..abac028
--- /dev/null
@@ -0,0 +1,115 @@
+/***************************************************************************
+ *   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_
diff --git a/src/podofo/doc/PdfAction.cpp b/src/podofo/doc/PdfAction.cpp
new file mode 100644 (file)
index 0000000..8da7557
--- /dev/null
@@ -0,0 +1,153 @@
+/***************************************************************************
+ *   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<EPdfAction>(TypeNameToIndex( this->GetObject()->GetIndirectKeyAsName( "S" ).GetName().c_str(), s_names, s_lNumActions, ePdfAction_Unknown ));
+}
+
+PdfAction::PdfAction( const PdfAction & rhs )
+    : PdfElement( "Action", rhs.GetNonConstObject() )
+{
+    m_eType = static_cast<EPdfAction>(TypeNameToIndex( this->GetObject()->GetIndirectKeyAsName( "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()->MustGetIndirectKey( "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()->MustGetIndirectKey( "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() );
+}
+
+
+
+};
+
diff --git a/src/podofo/doc/PdfAction.h b/src/podofo/doc/PdfAction.h
new file mode 100644 (file)
index 0000000..51dbaa8
--- /dev/null
@@ -0,0 +1,163 @@
+/***************************************************************************
+ *   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_
diff --git a/src/podofo/doc/PdfAnnotation.cpp b/src/podofo/doc/PdfAnnotation.cpp
new file mode 100644 (file)
index 0000000..19bdb56
--- /dev/null
@@ -0,0 +1,428 @@
+/***************************************************************************
+ *   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 );
+    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<EPdfAnnotation>(TypeNameToIndex( this->GetObject()->GetIndirectKeyAsName( 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()->MustGetIndirectKey( PdfName::KeyRect )->GetArray() );
+
+   return PdfRect();
+}
+
+void PdfAnnotation::SetRect(const PdfRect & rRect)
+{
+    PdfVariant rect;
+    rRect.ToVariant( rect );
+    this->GetObject()->GetDictionary().AddKey( PdfName::KeyRect, rect );
+}
+
+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<pdf_int64>(uiFlags) ) );
+}
+
+pdf_uint32 PdfAnnotation::GetFlags() const
+{
+    if( this->GetObject()->GetDictionary().HasKey( "F" ) )
+        return static_cast<pdf_uint32>(this->GetObject()->MustGetIndirectKey( "F" )->GetNumber());
+
+    return static_cast<pdf_uint32>(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()->MustGetIndirectKey( "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()->MustGetIndirectKey( "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()->MustGetIndirectKey( "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<PdfAnnotation*>(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()->MustGetIndirectKey( "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<PdfAnnotation*>(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()->MustGetIndirectKey( "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 (highlight, 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()->MustGetIndirectKey( "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 );
+}
+
+};
diff --git a/src/podofo/doc/PdfAnnotation.h b/src/podofo/doc/PdfAnnotation.h
new file mode 100644 (file)
index 0000000..f7ebaf3
--- /dev/null
@@ -0,0 +1,437 @@
+/***************************************************************************
+ *   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 rectangle of this annotation.
+     * \param rRect rectangle to set
+     */
+    void SetRect( const PdfRect & rRect );
+    /** 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_ */
diff --git a/src/podofo/doc/PdfCMapEncoding.cpp b/src/podofo/doc/PdfCMapEncoding.cpp
new file mode 100644 (file)
index 0000000..a70ae16
--- /dev/null
@@ -0,0 +1,372 @@
+/***************************************************************************
+ *   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 <iostream>
+#include <stack>
+#include <iomanip>
+#include <string>
+
+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<std::string> 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 = static_cast<const PdfObject*>(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)
+    {
+      if(!m_toUnicode.empty())
+      {
+        
+        const pdf_uint8* pStr = reinterpret_cast<const pdf_uint8*>(rEncodedString.GetString());
+        const size_t lLen = rEncodedString.GetLength();
+        
+        pdf_utf16be* pszUtf16 = static_cast<pdf_utf16be*>(podofo_calloc(lLen, sizeof(pdf_utf16be)));
+        if( !pszUtf16 )
+        {
+          PODOFO_RAISE_ERROR( ePdfError_OutOfMemory );
+        }
+        
+        size_t lDstLen = 0;
+        pdf_utf16be lCID, lUnicodeValue;
+        pdf_uint8* const pCID = reinterpret_cast<pdf_uint8*>(&lCID);
+        for(size_t iSrc = 0 ; iSrc<lLen ;)
+        {
+          lCID = 0;
+#ifdef PODOFO_IS_LITTLE_ENDIAN
+          pCID[0] = pStr[iSrc];
+#else
+          pCID[1] = pStr[iSrc];
+#endif // PODOFO_IS_LITTLE_ENDIAN
+
+          iSrc++;
+          
+          lUnicodeValue = this->GetUnicodeValue(lCID);
+
+          if (lUnicodeValue == 0)
+          {
+#ifdef PODOFO_IS_LITTLE_ENDIAN
+            pCID[1] = pStr[iSrc];
+#else
+            pCID[0] = pStr[iSrc];
+#endif // PODOFO_IS_LITTLE_ENDIAN
+          
+            iSrc++;
+            lUnicodeValue = this->GetUnicodeValue(lCID);
+          }
+          
+#ifdef PODOFO_IS_LITTLE_ENDIAN
+          pszUtf16[lDstLen] = (lUnicodeValue << 8) | (lUnicodeValue >> 8 );
+#else
+          pszUtf16[lDstLen] = lUnicodeValue;
+#endif // PODOFO_IS_LITTLE_ENDIAN
+          lDstLen++;
+        }
+        
+        PdfString ret( pszUtf16, lDstLen );
+        podofo_free( pszUtf16 );
+        
+        return ret;
+        
+      }
+      else
+        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<pdf_utf16be>(nIndex);
+#endif // PODOFO_IS_LITTLE_ENDIAN
+}
+
+
+const PdfName & PdfCMapEncoding::GetID() const
+{
+    PODOFO_RAISE_ERROR( ePdfError_NotImplemented );
+}
+
+};
diff --git a/src/podofo/doc/PdfCMapEncoding.h b/src/podofo/doc/PdfCMapEncoding.h
new file mode 100644 (file)
index 0000000..72d2f06
--- /dev/null
@@ -0,0 +1,77 @@
+/***************************************************************************
+ *   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<pdf_utf16be, pdf_utf16be> m_cMap;
+};
+
+}; /*PoDoFo namespace end*/
+
+#endif // _PDF_CMAP_ENCODING_H 
+
+
+
+
diff --git a/src/podofo/doc/PdfContents.cpp b/src/podofo/doc/PdfContents.cpp
new file mode 100644 (file)
index 0000000..a27b37d
--- /dev/null
@@ -0,0 +1,110 @@
+/***************************************************************************
+ *   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 <iostream>
+
+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()->MustGetObject( 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 );
+    }
+}
+
+};
+
diff --git a/src/podofo/doc/PdfContents.h b/src/podofo/doc/PdfContents.h
new file mode 100644 (file)
index 0000000..88af784
--- /dev/null
@@ -0,0 +1,92 @@
+/***************************************************************************
+ *   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_ */
diff --git a/src/podofo/doc/PdfDestination.cpp b/src/podofo/doc/PdfDestination.cpp
new file mode 100644 (file)
index 0000000..8d34a8d
--- /dev/null
@@ -0,0 +1,262 @@
+/***************************************************************************
+ *   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<PdfMemDocument*>(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->MustGetIndirectKey( "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 );
+}
+
+};
diff --git a/src/podofo/doc/PdfDestination.h b/src/podofo/doc/PdfDestination.h
new file mode 100644 (file)
index 0000000..f42a353
--- /dev/null
@@ -0,0 +1,411 @@
+/***************************************************************************
+ *   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_
+
diff --git a/src/podofo/doc/PdfDifferenceEncoding.cpp b/src/podofo/doc/PdfDifferenceEncoding.cpp
new file mode 100644 (file)
index 0000000..a66023b
--- /dev/null
@@ -0,0 +1,2687 @@
+/***************************************************************************
+ *   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 <cstdlib>
+#include <cstring>
+#include <sstream>
+#include <algorithm>
+
+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<TIVecDifferences,TCIVecDifferences> 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<TIVecDifferences,TIVecDifferences> it = 
+        std::equal_range( const_cast<PdfEncodingDifference*>(this)->m_vecDifferences.begin(), 
+                          const_cast<PdfEncodingDifference*>(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
+{
+       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()->MustGetIndirectKey( 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()->MustGetIndirectKey( 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<int>(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<pdf_utf16be>(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 );
+    size_t lLen = str.GetCharacterLength();
+
+    pdf_utf16be* pszUtf16 = static_cast<pdf_utf16be*>(podofo_calloc(lLen, sizeof(pdf_utf16be)));
+    if( !pszUtf16 )
+    {
+        PODOFO_RAISE_ERROR( ePdfError_OutOfMemory );
+    }
+
+    memcpy( pszUtf16, str.GetUnicode(), lLen * sizeof(pdf_utf16be) );
+    const unsigned char* pszInput = (const unsigned char*) rEncodedString.GetString();
+    for( size_t i = 0; i < lLen; i++ ) 
+    {
+        PdfName     name;
+        pdf_utf16be value;
+        //TODO: This method should take pdf_uint8 instead of int because of its
+        // domain (0 to 255) for 1st param, but PoDoFo still has known security
+        // issues so an API change is a Bad Thing (mabri: IMO at least) to do now.
+        if( m_differences.Contains( static_cast<int>(pszInput[i]), 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<pdf_utf16be*>(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<pdf_utf16be*>(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<char*>(podofo_calloc( (lLen + 1), sizeof(char) ));
+    if( !pDest ) 
+    {
+        PODOFO_RAISE_ERROR( ePdfError_OutOfMemory );
+    }
+
+    char *pCur = pDest;
+    long lNewLen = 0L;
+
+    for( int i=0;i<lLen;i++ ) 
+    {
+        pdf_utf16be val = pszUtf16[i];
+
+        if (!m_differences.ContainsUnicodeValue(val, *pCur))
+       {
+            *pCur = static_cast<const PdfSimpleEncoding *>(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 */
diff --git a/src/podofo/doc/PdfDifferenceEncoding.h b/src/podofo/doc/PdfDifferenceEncoding.h
new file mode 100644 (file)
index 0000000..6e3fc2d
--- /dev/null
@@ -0,0 +1,354 @@
+/***************************************************************************
+ *   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 <iterator>
+
+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<TDifference>                 TVecDifferences;
+    typedef std::vector<TDifference>::iterator       TIVecDifferences;
+    typedef std::vector<TDifference>::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_
+
diff --git a/src/podofo/doc/PdfDocument.cpp b/src/podofo/doc/PdfDocument.cpp
new file mode 100644 (file)
index 0000000..6bd4741
--- /dev/null
@@ -0,0 +1,941 @@
+/***************************************************************************
+ *   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 <algorithm>
+#include <deque>
+#include <iostream>
+
+
+#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<PdfRect>& 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<unsigned int>(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<unsigned int>((*it)->Reference().ObjectNumber() + difference), (*it)->Reference().GenerationNumber() ), *(*it) );
+        m_vecObjects.push_back( pObj );
+
+        if( (*it)->IsDictionary() && (*it)->HasStream() )
+            *(pObj->GetStream()) = *(static_cast<const PdfObject*>(*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;i<rDoc.GetPageCount();i++ )
+        {
+            PdfPage*      pPage = rDoc.GetPage( i );
+            if (NULL == pPage)
+            {
+                std::ostringstream oss;
+                oss << "No page " << i << " (the first is 0) found.";
+                PODOFO_RAISE_ERROR_INFO( ePdfError_PageNotFound, oss.str() );
+            }
+            PdfObject*    pObj  = m_vecObjects.MustGetObject( PdfReference( pPage->GetObject()->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<PdfMemDocument&>(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.MustGetObject( 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<unsigned int>(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<unsigned int>((*it)->Reference().ObjectNumber() + difference), (*it)->Reference().GenerationNumber() ), *(*it) );
+        m_vecObjects.push_back( pObj );
+
+        if( (*it)->IsDictionary() && (*it)->HasStream() )
+            *(pObj->GetStream()) = *(static_cast<const PdfObject*>(*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;i<rDoc.GetPageCount();i++ )
+    {
+        if (i != nPageIndex) {
+            continue;
+        }
+
+        PdfPage*      pPage = rDoc.GetPage( i );
+        PdfObject*    pObj  = m_vecObjects.MustGetObject( PdfReference( pPage->GetObject()->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<PdfMemDocument&>(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.MustGetObject( 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<unsigned int>(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.MustGetObject( 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
+        const PdfObject* pContents = pObj->MustGetIndirectKey( "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 !!
+                    const 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())
+                        {
+                            const 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();
+            const 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()->MustGetIndirectKey( 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 );
+}
+
+};
+
diff --git a/src/podofo/doc/PdfDocument.h b/src/podofo/doc/PdfDocument.h
new file mode 100644 (file)
index 0000000..b92459b
--- /dev/null
@@ -0,0 +1,785 @@
+/***************************************************************************
+ *   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<PdfRect>& 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_
diff --git a/src/podofo/doc/PdfElement.cpp b/src/podofo/doc/PdfElement.cpp
new file mode 100644 (file)
index 0000000..a36f0a3
--- /dev/null
@@ -0,0 +1,130 @@
+/***************************************************************************
+ *   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 <string.h>
+
+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->GetIndirectKeyAsName( PdfName::KeyType ) != pszType ) 
+    {
+        PdfError::LogMessage( eLogSeverity_Debug, "Expected key %s but got key %s.", 
+                              pszType, m_pObject->GetIndirectKeyAsName( 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; i<lLen; i++ )
+    {
+        if( ppTypes[i] && strcmp( pszType, ppTypes[i] ) == 0 ) 
+        {
+            return i;
+        }
+    }
+    
+    return nUnknownValue;
+}
+PdfObject* PdfElement::CreateObject( const char* pszType )
+{
+    return m_pObject->GetOwner()->CreateObject( pszType );
+}
+
+
+};
diff --git a/src/podofo/doc/PdfElement.h b/src/podofo/doc/PdfElement.h
new file mode 100644 (file)
index 0000000..d7dcaf6
--- /dev/null
@@ -0,0 +1,201 @@
+/***************************************************************************
+ *   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<PdfElement*>(this)->m_pObject;
+}
+
+};
+
+#endif // PDF_ELEMENT_H_
diff --git a/src/podofo/doc/PdfEncodingObjectFactory.cpp b/src/podofo/doc/PdfEncodingObjectFactory.cpp
new file mode 100644 (file)
index 0000000..80f3ee4
--- /dev/null
@@ -0,0 +1,100 @@
+/***************************************************************************
+ *   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 <iostream>
+using namespace std;
+
+namespace PoDoFo
+{
+
+const PdfEncoding *PdfEncodingObjectFactory::CreateEncoding (PdfObject *pObject, PdfObject *pToUnicode, bool bExplicitNames)
+{
+    if (pObject->IsReference ())
+    {
+        // resolve any references
+        pObject = pObject->GetOwner ()->MustGetObject (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 ("SymbolSetEncoding"))       // CB 21.02.2019
+            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 */
diff --git a/src/podofo/doc/PdfEncodingObjectFactory.h b/src/podofo/doc/PdfEncodingObjectFactory.h
new file mode 100644 (file)
index 0000000..37295ae
--- /dev/null
@@ -0,0 +1,69 @@
+/***************************************************************************
+ *   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_
diff --git a/src/podofo/doc/PdfExtGState.cpp b/src/podofo/doc/PdfExtGState.cpp
new file mode 100644 (file)
index 0000000..d0fb9fb
--- /dev/null
@@ -0,0 +1,140 @@
+/***************************************************************************
+ *   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 <sstream>
+
+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<double>(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<pdf_int64>(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<pdf_int64>(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
diff --git a/src/podofo/doc/PdfExtGState.h b/src/podofo/doc/PdfExtGState.h
new file mode 100644 (file)
index 0000000..cc6a814
--- /dev/null
@@ -0,0 +1,142 @@
+/***************************************************************************
+ *   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_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_
+
diff --git a/src/podofo/doc/PdfField.cpp b/src/podofo/doc/PdfField.cpp
new file mode 100644 (file)
index 0000000..c8ccc3d
--- /dev/null
@@ -0,0 +1,1010 @@
+/***************************************************************************
+ *   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 <sstream>
+
+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*)
+    : m_pObject( pWidget->GetObject() ), m_pWidget( pWidget ), m_eField( eField )
+{
+    Init( pParent );
+}
+
+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
+    if( !pParent->GetObject()->GetDictionary().HasKey( "Fields" ) )
+        pParent->GetObject()->GetDictionary().AddKey( "Fields", PdfArray() );
+    pParent->GetObject()->MustGetIndirectKey( "Fields" )->GetArray().push_back( m_pObject->Reference() );
+
+    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->GetIndirectKey(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->GetIndirectKey( 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<PdfField*>(this)->m_pObject->GetDictionary().AddKey( PdfName("MK"), dictionary );
+    }
+
+    pMK = m_pObject->GetIndirectKey( 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->MustGetIndirectKey( 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->MustGetIndirectKey( 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->MustGetIndirectKey( 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->MustGetIndirectKey( 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->MustGetIndirectKey( 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->MustGetIndirectKey( 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->MustGetIndirectKey( 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->MustGetIndirectKey( 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<int>(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->MustGetIndirectKey( 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->MustGetIndirectKey( 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->MustGetIndirectKey( PdfName("AP") )->GetDictionary().HasKey( PdfName("N") ) )
+        m_pObject->MustGetIndirectKey( PdfName("AP") )->GetDictionary().AddKey( PdfName("N"), PdfDictionary() );
+
+    m_pObject->MustGetIndirectKey( PdfName("AP") )->
+        MustGetIndirectKey( 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
+{
+    if (m_pObject->GetDictionary().HasKey(PdfName("V"))) {
+        PdfName name = m_pObject->MustGetIndirectKey( PdfName("V") )->GetName();
+        return (name == PdfName("Yes") || name == PdfName("On"));
+     } else if (m_pObject->GetDictionary().HasKey(PdfName("AS"))) {
+        PdfName name = m_pObject->MustGetIndirectKey( 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.IsUnicode() ? rsText.GetUnicodeLength() : rsText.GetLength()) > nMax )
+        m_pObject->GetDictionary().AddKey( key, rsText.IsUnicode() ? PdfString( rsText.GetUnicode(), nMax) : 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->MustGetIndirectKey( key )->GetString();
+
+    return str;
+}
+
+void PdfTextField::SetMaxLen( pdf_long nMaxLen )
+{
+    m_pObject->GetDictionary().AddKey( PdfName("MaxLen"), static_cast<pdf_int64>(nMaxLen) );
+}
+
+pdf_long  PdfTextField::GetMaxLen() const
+{
+    return static_cast<pdf_long>(m_pObject->GetDictionary().HasKey( PdfName("MaxLen") ) ? 
+                                 m_pObject->MustGetIndirectKey( 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;
+
+    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") ) )
+        m_pObject->GetDictionary().AddKey( PdfName("Opt"), PdfArray() );
+
+    PdfArray &opt = m_pObject->MustGetIndirectKey( PdfName("Opt") )->GetArray();
+
+    // TODO: Sorting
+    opt.push_back( var );
+
+    /*
+    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 )
+{
+    if( !m_pObject->GetDictionary().HasKey( PdfName("Opt") ) )
+        m_pObject->GetDictionary().AddKey( PdfName("Opt"), PdfArray() );
+
+    PdfArray &opt = m_pObject->MustGetIndirectKey( PdfName("Opt") )->GetArray();
+    
+    if( nIndex < 0 || nIndex > static_cast<int>(opt.size()) )
+    {
+        PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange );
+    }
+
+    opt.erase( opt.begin() + nIndex );
+}
+
+const PdfString PdfListField::GetItem( int nIndex ) const
+{
+    PdfArray   opt;
+    
+    if( m_pObject->GetDictionary().HasKey( PdfName("Opt") ) )
+        opt = m_pObject->MustGetIndirectKey( PdfName("Opt") )->GetArray();
+    
+    if( nIndex < 0 || nIndex > static_cast<int>(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->MustGetIndirectKey( PdfName("Opt") )->GetArray();
+    
+    if( nIndex < 0 || nIndex >= static_cast<int>(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->MustGetIndirectKey( 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->MustGetIndirectKey( PdfName("V") );
+        if( pValue->IsString() || pValue->IsHexString() )
+        {
+            PdfString value = pValue->GetString();
+            for( int i=0;i<static_cast<int>(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<int>(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<int>(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<int>(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<int>(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<int>(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<int>(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<int>(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<int>(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" );
+    }
+}
+
+};
diff --git a/src/podofo/doc/PdfField.h b/src/podofo/doc/PdfField.h
new file mode 100644 (file)
index 0000000..3c5c0cc
--- /dev/null
@@ -0,0 +1,1389 @@
+/***************************************************************************
+ *   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<int>(ePdfField_ReadOnly), bReadOnly );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline bool PdfField::IsReadOnly() const
+{
+    return this->GetFieldFlag( static_cast<int>(ePdfField_ReadOnly), false );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfField::SetRequired( bool bRequired )
+{
+    this->SetFieldFlag( static_cast<int>(ePdfField_Required), bRequired );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline bool PdfField::IsRequired() const
+{
+    return this->GetFieldFlag( static_cast<int>(ePdfField_Required), false );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfField::SetExport( bool bExport )
+{
+    this->SetFieldFlag( static_cast<int>(ePdfField_NoExport), bExport );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline bool PdfField::IsExport() const
+{
+    return this->GetFieldFlag( static_cast<int>(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<int>(ePdfButton_PushButton), false );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline bool PdfButton::IsCheckBox() const
+{
+    return (!this->GetFieldFlag( static_cast<int>(ePdfButton_Radio), false ) &&
+            !this->GetFieldFlag( static_cast<int>(ePdfButton_PushButton), false ) );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline bool PdfButton::IsRadioButton() const
+{
+    return this->GetFieldFlag( static_cast<int>(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<int>(ePdfTextField_MultiLine), bMultiLine );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline bool PdfTextField::IsMultiLine() const
+{
+    return this->GetFieldFlag( static_cast<int>(ePdfTextField_MultiLine), false );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfTextField::SetPasswordField( bool bPassword )
+{
+    this->SetFieldFlag( static_cast<int>(ePdfTextField_Password), bPassword );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline bool PdfTextField::IsPasswordField() const
+{
+    return this->GetFieldFlag( static_cast<int>(ePdfTextField_Password), false );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfTextField::SetFileField( bool bFile )
+{
+    this->SetFieldFlag( static_cast<int>(ePdfTextField_FileSelect), bFile );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline bool PdfTextField::IsFileField() const
+{
+    return this->GetFieldFlag( static_cast<int>(ePdfTextField_FileSelect), false );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfTextField::SetSpellcheckingEnabled( bool bSpellcheck )
+{
+    this->SetFieldFlag( static_cast<int>(ePdfTextField_NoSpellcheck), !bSpellcheck );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline bool PdfTextField::IsSpellcheckingEnabled() const
+{
+    return this->GetFieldFlag( static_cast<int>(ePdfTextField_NoSpellcheck), true );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfTextField::SetScrollBarsEnabled( bool bScroll )
+{
+    this->SetFieldFlag( static_cast<int>(ePdfTextField_NoScroll), !bScroll );    
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline bool PdfTextField::IsScrollBarsEnabled() const
+{
+    return this->GetFieldFlag( static_cast<int>(ePdfTextField_NoScroll), true );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfTextField::SetCombs( bool bCombs )
+{
+    this->SetFieldFlag( static_cast<int>(ePdfTextField_Comb), bCombs );        
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline bool PdfTextField::IsCombs() const
+{
+    return this->GetFieldFlag( static_cast<int>(ePdfTextField_Comb), false );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfTextField::SetRichText( bool bRichText )
+{
+    this->SetFieldFlag( static_cast<int>(ePdfTextField_RichText), bRichText);        
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline bool PdfTextField::IsRichText() const
+{
+    return this->GetFieldFlag( static_cast<int>(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<int>(ePdfListField_Combo), false );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfListField::SetSpellcheckingEnabled( bool bSpellcheck )
+{
+    this->SetFieldFlag( static_cast<int>(ePdfListField_NoSpellcheck), !bSpellcheck );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline bool PdfListField::IsSpellcheckingEnabled() const
+{
+    return this->GetFieldFlag( static_cast<int>(ePdfListField_NoSpellcheck), true );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfListField::SetSorted( bool bSorted )
+{
+    this->SetFieldFlag( static_cast<int>(ePdfListField_Sort), bSorted );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline bool PdfListField::IsSorted() const
+{
+    return this->GetFieldFlag( static_cast<int>(ePdfListField_Sort), false );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfListField::SetMultiSelect( bool bMulti )
+{
+    this->SetFieldFlag( static_cast<int>(ePdfListField_MultiSelect), bMulti );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline bool PdfListField::IsMultiSelect() const
+{
+    return this->GetFieldFlag( static_cast<int>(ePdfListField_MultiSelect), false );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfListField::SetCommitOnSelectionChange( bool bCommit )
+{
+    this->SetFieldFlag( static_cast<int>(ePdfListField_CommitOnSelChange), bCommit );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline bool PdfListField::IsCommitOnSelectionChange() const
+{
+    return this->GetFieldFlag( static_cast<int>(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<int>(ePdfListField_Edit), bEdit);        
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline bool PdfComboBox::IsEditable() const
+{
+    return this->GetFieldFlag( static_cast<int>(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_
diff --git a/src/podofo/doc/PdfFileSpec.cpp b/src/podofo/doc/PdfFileSpec.cpp
new file mode 100644 (file)
index 0000000..aefdfad
--- /dev/null
@@ -0,0 +1,350 @@
+/***************************************************************************
+ *   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 <sstream>
+
+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<nLen;i++ ) 
+    {
+        wchar_t ch = pszFilename[i];
+        if (ch == L':' || ch == L'\\')
+            ch = L'/';
+        if ((ch >= 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<pdf_int64>(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<nLen;i++ ) 
+    {
+        char ch = pszFilename[i];
+        if (ch == ':' || ch == '\\')
+            ch = '/';
+        if ((ch >= '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<pdf_int64>(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<const char*>(data),size);
+    pStream->GetStream()->Set( &memstream );
+
+    // Add additional information about the embedded file to the stream
+    PdfDictionary params;
+    params.AddKey( "Size", static_cast<pdf_int64>(size) );
+    pStream->GetDictionary().AddKey("Params", params );
+}
+
+const PdfString & PdfFileSpec::GetFilename(bool canUnicode) const
+{
+    if( canUnicode && this->GetObject()->GetDictionary().HasKey( "UF" ) )
+{
+        return this->GetObject()->MustGetIndirectKey( "UF" )->GetString();
+    }
+
+    if( this->GetObject()->GetDictionary().HasKey( "F" ) )
+    {
+        return this->GetObject()->MustGetIndirectKey( "F" )->GetString();
+    }
+
+    PODOFO_RAISE_ERROR( ePdfError_InvalidDataType );
+}
+
+
+};
diff --git a/src/podofo/doc/PdfFileSpec.h b/src/podofo/doc/PdfFileSpec.h
new file mode 100644 (file)
index 0000000..2d20f55
--- /dev/null
@@ -0,0 +1,135 @@
+/***************************************************************************
+ *   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_
+
diff --git a/src/podofo/doc/PdfFont.cpp b/src/podofo/doc/PdfFont.cpp
new file mode 100644 (file)
index 0000000..847676b
--- /dev/null
@@ -0,0 +1,198 @@
+/***************************************************************************
+ *   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 <stdlib.h>
+#include <string.h>
+#include <sstream>
+
+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;
+
+    PODOFO_UNIQUEU_PTR<PdfFilter> 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;
+}
+
+};
diff --git a/src/podofo/doc/PdfFont.h b/src/podofo/doc/PdfFont.h
new file mode 100644 (file)
index 0000000..7895243
--- /dev/null
@@ -0,0 +1,468 @@
+/***************************************************************************
+ *   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_
+
diff --git a/src/podofo/doc/PdfFontCID.cpp b/src/podofo/doc/PdfFontCID.cpp
new file mode 100644 (file)
index 0000000..a40ebe3
--- /dev/null
@@ -0,0 +1,952 @@
+/***************************************************************************
+ *   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 <ft2build.h>
+#include FT_FREETYPE_H
+
+#include <iostream>
+#include <sstream>
+
+namespace PoDoFo {
+
+struct TBFRange {
+    FT_UInt srcCode;
+    std::vector<FT_UInt> vecDest;
+};
+
+typedef std::map<long, double> GlyphWidths;
+typedef std::map<FT_UInt, FT_ULong> GidToCodePoint;
+static bool fillGidToCodePoint(GidToCodePoint& array, PdfFontMetrics* metrics);
+typedef std::map<pdf_utf16be, int> UnicodeToIndex;
+static UnicodeToIndex getUnicodeToIndexTable(const PdfEncoding* pEnconding);
+
+static GlyphWidths getGlyphWidths(PdfFontMetrics* metrics, const std::set<pdf_utf16be>& setUsed, const UnicodeToIndex& unicodeToIndex);
+static GlyphWidths getGlyphWidths(PdfFontMetrics* metrics, const std::set<pdf_utf16be>& setUsed);
+
+static void createWidths(PdfObject* pFontDict, PdfFontMetrics* metrics, const std::set<pdf_utf16be>& setUsed, const UnicodeToIndex& unicodeToIndex);
+static void createWidths(PdfObject* pFontDict, PdfFontMetrics* metrics, const std::set<pdf_utf16be>& setUsed);
+
+static GidToCodePoint getGidToCodePoint(const PdfEncoding* pEncoding, PdfFontMetrics* pMetrics, const std::set<pdf_utf16be>& setUsed, const UnicodeToIndex& unicodeToIndex);
+static GidToCodePoint getGidToCodePoint(const PdfEncoding* pEncoding, PdfFontMetrics* pMetrics, const std::set<pdf_utf16be>& setUsed);
+
+static void fillUnicodeStream( PdfStream* pStream , const GidToCodePoint& gidToCodePoint, int nFirstChar, int nLastChar, bool bSingleByteEncoding);
+
+#define SWAP_UTF16BE(x) static_cast<pdf_utf16be>(((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<pdf_int64>(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") );
+
+        if( !bSubset )
+        {
+            // Add the width keys
+            this->CreateWidth( m_pDescendantFonts );
+
+            // Create the ToUnicode CMap
+            PdfObject* pUnicode = this->GetObject()->GetOwner()->CreateObject();
+
+            this->CreateCMap( pUnicode );
+            this->GetObject()->GetDictionary().AddKey( "ToUnicode", pUnicode->Reference() );
+        }
+    }
+
+    // Setting the FontDescriptor paras:
+    array.Clear();
+    m_pMetrics->GetBoundingBox( array );
+
+    pDescriptor->GetDictionary().AddKey( "FontName", this->GetBaseFont() );
+    pDescriptor->GetDictionary().AddKey( PdfName::KeyFlags, PdfVariant( static_cast<pdf_int64>(PODOFO_LL_LITERAL(32)) ) ); // TODO: 0 ????
+    pDescriptor->GetDictionary().AddKey( "FontBBox", array );
+    pDescriptor->GetDictionary().AddKey( "ItalicAngle", PdfVariant( static_cast<pdf_int64>(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<pdf_int64>(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<unsigned char> 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<const char*>(&array[0]), array.size());
+#else
+                    PdfMemoryInputStream stream(reinterpret_cast<const char*>(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<pdf_int64>(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<char*> is dangerous if string literals may ever be passed
+        char* pBuffer = const_cast<char*>( 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<pdf_int64>(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<pdf_int64>(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<double*>(podofo_calloc( cAbsoluteMax, sizeof(double) ) );
+    if( !pdWidth )
+    {
+        PODOFO_RAISE_ERROR( ePdfError_OutOfMemory );
+    }
+
+    for( i=0;i<cAbsoluteMax;i++ )
+        pdWidth[i] = 0.0;
+
+    // Load the width of all requested glyph indeces
+    int nMin       = 0xffff;
+    int nMax       = 0;
+
+    long    lGlyph = 0;
+
+    for( i=nFirstChar;i<=nLastChar;i++ )
+    {
+        lGlyph = m_pMetrics->GetGlyphId( i );
+        if( lGlyph )
+        {
+            nMin = PDF_MIN( static_cast<long>(nMin), lGlyph );
+            nMax = PDF_MAX( static_cast<long>(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<int>(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( static_cast<pdf_int64>(dCurWidth + 0.5) );
+                }
+                else
+                {
+                    if( array.size() && array.back().IsArray() ) 
+                    {
+                        array.back().GetArray().push_back( static_cast<pdf_int64>(dCurWidth + 0.5) );
+                    }
+                    else
+                    {
+                        PdfArray tmp;
+                        tmp.push_back( static_cast<pdf_int64>(dCurWidth + 0.5) );
+                        
+                        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( static_cast<pdf_int64>(dCurWidth + 0.5) );
+        }
+        
+        pFontDict->GetDictionary().AddKey( PdfName("W"), array ); 
+    }
+
+    podofo_free( pdWidth );
+}
+
+void PdfFontCID::CreateCMap( PdfObject* pUnicode ) const
+{
+    GidToCodePoint gidToCodePoint;
+    if (fillGidToCodePoint(gidToCodePoint, m_pMetrics)) 
+    {
+        fillUnicodeStream( pUnicode->GetStream(), gidToCodePoint, m_pEncoding->GetFirstChar(), m_pEncoding->GetLastChar(), m_pEncoding->IsSingleByteEncoding() );
+    }
+}
+
+static std::vector<TBFRange>
+createUnicodeRanges(const GidToCodePoint& gidToCodePoint, int nFirstChar, int nLastChar)
+{
+    TBFRange curRange;
+    curRange.srcCode = -1;
+    std::vector<TBFRange> 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<int>(charcode) > nLastChar )
+        {
+            break;
+        }
+        if( static_cast<int>(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<TBFRange> 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> <FF>\n");
+    else
+        pStream->Append("<0000> <FFFF>\n");
+    pStream->Append("endcodespacerange\n");
+
+    int numberOfEntries = 0;
+
+    std::vector<TBFRange>::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<unsigned int>(iStart) );
+            range << "<" << buffer << "> <";
+            snprintf( buffer, BUFFER_LEN, "%02X", static_cast<unsigned int>(iEnd) );
+        }
+        else
+        {
+        snprintf( buffer, BUFFER_LEN, "%04X", static_cast<unsigned int>(iStart) );
+        range << "<" << buffer << "> <";
+        snprintf( buffer, BUFFER_LEN, "%04X", static_cast<unsigned int>(iEnd) );
+        }
+        range << buffer << "> [ ";
+
+        std::vector<FT_UInt>::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<pdf_utf16be>& setUsed, const UnicodeToIndex& unicodeToIndex)
+{
+    GidToCodePoint gidToCodePoint;
+    pdf_utf16be codePoint;
+    long lGlyph;
+    long lRepl = pMetrics->GetGlyphId( 0xFFFD );
+
+    UnicodeToIndex::const_iterator indexLookup;
+    for (std::set<pdf_utf16be>::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<pdf_utf16be>& setUsed)
+{
+    GidToCodePoint gidToCodePoint;
+    pdf_utf16be codePoint;
+    long lGlyph;
+    for (std::set<pdf_utf16be>::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<const PdfFontMetricsFreetype *>(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<pdf_int64>(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<pdf_int64>(_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<pdf_int64>(_width + 0.5));
+        emitArrayWidths();
+        return;
+    }
+    emitSameWidth();
+}
+
+void WidthExporter::emitSameWidth()
+{
+    _output.push_back(static_cast<pdf_int64>(_start));
+    _output.push_back(static_cast<pdf_int64>(_start + _count - 1));
+    _output.push_back(static_cast<pdf_int64>(_width + 0.5));
+}
+
+void WidthExporter::emitArrayWidths()
+{
+    _output.push_back(static_cast<pdf_int64>(_start));
+    _output.push_back(_widths);
+    _widths.Clear();
+}
+
+void WidthExporter::updateSBE(GlyphWidths::const_iterator& it)
+{
+    _output.push_back(static_cast<pdf_int64>(_width + 0.5));
+    while(++_start < it->first) {
+        _output.push_back(static_cast<pdf_int64>(0));
+    }
+    reset(it);
+}
+void WidthExporter::finishSBE()
+{
+    _output.push_back(static_cast<pdf_int64>(_width + 0.5));
+}
+
+static bool
+fillGidToCodePoint(GidToCodePoint& array, PdfFontMetrics* metrics)
+{
+    PdfFontMetricsFreetype* pFreetype = dynamic_cast<PdfFontMetricsFreetype*>(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<FT_UInt, FT_ULong>(gindex, charcode));
+        charcode = FT_Get_Next_Char( face, charcode, &gindex );
+    }
+    return true;
+}
+
+static GlyphWidths
+getGlyphWidths(PdfFontMetrics* pMetrics, const std::set<pdf_utf16be>& 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<pdf_utf16be>::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<pdf_utf16be>& 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<pdf_utf16be>::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<pdf_utf16be>& 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<pdf_int64>(glyphWidths.begin()->first) ) );
+        pFontDict->GetDictionary().AddKey("LastChar",  PdfVariant( static_cast<pdf_int64>(glyphWidths.rbegin()->first) ) );
+    }
+}
+
+static void
+createWidths(PdfObject* pFontDict, PdfFontMetrics* metrics, const std::set<pdf_utf16be>& 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          
+        }
+    }
+}
+
+};
+
diff --git a/src/podofo/doc/PdfFontCID.h b/src/podofo/doc/PdfFontCID.h
new file mode 100644 (file)
index 0000000..7b1ce3a
--- /dev/null
@@ -0,0 +1,133 @@
+/***************************************************************************
+ *   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 <set>
+
+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<pdf_utf16be> m_setUsed;
+
+    void MaybeUpdateBaseFontKey(void);
+
+    /* to update "BaseFont" key */
+    virtual void SetBold( bool bBold );
+    virtual void SetItalic( bool bItalic );
+};
+
+};
+
+#endif // _PDF_FONT_CID_H_
+
diff --git a/src/podofo/doc/PdfFontCache.cpp b/src/podofo/doc/PdfFontCache.cpp
new file mode 100644 (file)
index 0000000..af43a27
--- /dev/null
@@ -0,0 +1,937 @@
+/***************************************************************************
+ *   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 <algorithm>
+
+#ifdef _WIN32
+
+//#include <windows.h>
+// 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 <ft2build.h>
+#include FT_FREETYPE_H
+
+#if defined(PODOFO_HAVE_FONTCONFIG)
+#include <fontconfig/fontconfig.h>
+#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<TISortedFontList,TCISortedFontList> 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<TISortedFontList,TCISortedFontList> it;
+
+    size_t lMaxLen = wcslen(pszFontName) * 5;
+
+    if (lMaxLen == 0) 
+        PODOFO_RAISE_ERROR_INFO(ePdfError_InternalLogic, "Font name is empty");
+        
+    char* pmbFontName = static_cast<char*>(podofo_malloc(lMaxLen));
+    if (!pmbFontName)
+    {
+        PODOFO_RAISE_ERROR(ePdfError_OutOfMemory);
+    }
+    if( wcstombs(pmbFontName, pszFontName, lMaxLen) == static_cast<size_t>(-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<TISortedFontList,TCISortedFontList> 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<TISortedFontList,TCISortedFontList> 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<TISortedFontList,TCISortedFontList> 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<PdfFontType1 *>(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<TISortedFontList,TCISortedFontList> 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<wchar_t*>(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<char*>(podofo_malloc(lMaxLen));
+    if( !pmbFontName )
+    {
+        PODOFO_RAISE_ERROR( ePdfError_OutOfMemory );
+    }
+
+    if( wcstombs( pmbFontName, logFont.lfFaceName, lMaxLen ) == static_cast<size_t>(-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<char*>(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<const char*>(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<FcConfig*>(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;
+}
+
+};
diff --git a/src/podofo/doc/PdfFontCache.h b/src/podofo/doc/PdfFontCache.h
new file mode 100644 (file)
index 0000000..4cf4544
--- /dev/null
@@ -0,0 +1,466 @@
+/***************************************************************************
+ *   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 <windows.h>
+
+// 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<const pdf_utf8*>(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<TFontCacheElement>  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<int> & 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_ */
+
diff --git a/src/podofo/doc/PdfFontConfigWrapper.cpp b/src/podofo/doc/PdfFontConfigWrapper.cpp
new file mode 100644 (file)
index 0000000..6d86966
--- /dev/null
@@ -0,0 +1,123 @@
+/***************************************************************************
+ *   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 <fontconfig/fontconfig.h>
+#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<FcConfig*>(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<void*>(FcInitLoadConfigAndFonts());
+            this->m_pFontConfig->m_bInitialized = true;
+        }
+    }
+#endif
+}
+
+};
diff --git a/src/podofo/doc/PdfFontConfigWrapper.h b/src/podofo/doc/PdfFontConfigWrapper.h
new file mode 100644 (file)
index 0000000..766427b
--- /dev/null
@@ -0,0 +1,142 @@
+/***************************************************************************
+ *   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.                       *
+ ***************************************************************************/
+
+#ifndef _PDF_FONT_CONFIG_WRAPPER_H_
+#define _PDF_FONT_CONFIG_WRAPPER_H_
+
+#include "podofo/base/PdfDefines.h"
+#include "podofo/base/Pdf3rdPtyForwardDecl.h"
+#include "podofo/base/util/PdfMutex.h"
+
+namespace PoDoFo {
+
+/**
+ * This class initializes and destroys the FontConfig library.
+ * 
+ * As initializing fontconfig can take a long time, you 
+ * can create a wrapper by yourself to cache initialization of
+ * fontconfig.
+ *
+ * This class is reference counted. The last user of the fontconfig library
+ * will destroy the fontconfig handle.
+ *
+ * The fontconfig library is initialized on first used (lazy loading!)
+ */
+class PODOFO_DOC_API PdfFontConfigWrapper {
+public:
+    /**
+     * Create a new FontConfigWrapper and initialize the fontconfig library.
+     */
+    PdfFontConfigWrapper();
+
+    /**
+     * Copy an existing PdfFontConfigWrapper
+     */
+    PdfFontConfigWrapper(const PdfFontConfigWrapper & rhs);
+
+    ~PdfFontConfigWrapper();
+
+    /**
+     * Get access to the internal fontconfig handle.
+     * Accesses to this handle have to be synchronized using a mutex!
+     *
+     * \see GetFontConfigMutex
+     *
+     * \returns a FcConfig handle (you can cast to FcConfig)
+     */
+    inline void * GetFontConfig();
+
+#if defined(PODOFO_HAVE_FONTCONFIG)
+    /**
+     * Mutex which has to be used to synchronize uses of FontConfig
+     */
+    inline Util::PdfMutex & GetFontConfigMutex();
+#endif
+
+    const PdfFontConfigWrapper & operator=(const PdfFontConfigWrapper & rhs);
+
+private:
+    /**
+     * Destroy fontconfig reference if reference count is 0
+     */
+    void DerefBuffer();
+
+    /**
+     * Do the lazy initialization of fontconfig
+     */
+    void InitializeFontConfig();
+
+private:
+
+#if defined(PODOFO_HAVE_FONTCONFIG)
+    static Util::PdfMutex m_FcMutex;
+#endif
+
+    struct TRefCountedFontConfig {
+        void* m_pFcConfig;             ///< Handle to fontconfig on unix systems
+        long  m_lRefCount;
+        bool  m_bInitialized;          ///< Is fontconfig initialized yet?
+    };
+
+    TRefCountedFontConfig* m_pFontConfig;
+};
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+void* PdfFontConfigWrapper::GetFontConfig() 
+{
+    if( m_pFontConfig != NULL ) 
+    {
+        InitializeFontConfig();
+        return m_pFontConfig->m_pFcConfig;
+    } 
+    else 
+    {
+        return NULL;
+    }
+}
+
+#if defined(PODOFO_HAVE_FONTCONFIG)
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+Util::PdfMutex & PdfFontConfigWrapper::GetFontConfigMutex()
+{
+    return m_FcMutex;
+}
+#endif
+
+}; // PoDoFo
+
+#endif // _PDF_FONT_WRAPPER_H_
diff --git a/src/podofo/doc/PdfFontFactory.cpp b/src/podofo/doc/PdfFontFactory.cpp
new file mode 100644 (file)
index 0000000..9983f75
--- /dev/null
@@ -0,0 +1,413 @@
+/***************************************************************************
+ *   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() : "<unknown>"),
+                                      (pMetrics->GetFilename() ? pMetrics->GetFilename() : "<unknown>") );
+        }
+    }
+    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() : "<unknown>"),
+                                      (pMetrics->GetFilename() ? pMetrics->GetFilename() : "<unknown>") );
+        }
+    }
+
+    return pFont;
+}
+
+PdfFont* PdfFontFactory::CreateFont( FT_Library*, PdfObject* pObject )
+{
+    PdfFontMetrics* pMetrics    = NULL;
+    PdfFont*        pFont       = NULL;
+    PdfObject*      pDescriptor = NULL;
+    PdfObject*      pEncoding   = NULL;
+
+    PdfVariant* pTypeKey = pObject->GetIndirectKey( PdfName::KeyType );
+    if ( NULL == pTypeKey )
+    {
+        PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Font: No Type" );
+    }
+
+    if( pTypeKey->GetName() != PdfName("Font") )
+    {
+        PODOFO_RAISE_ERROR( ePdfError_InvalidDataType );
+    }
+
+    PdfVariant* pSubTypeKey = pObject->GetIndirectKey( PdfName::KeySubtype );
+    if ( NULL == pSubTypeKey )
+    {
+        PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Font: No SubType" );
+    }
+    const PdfName & rSubType = pSubTypeKey->GetName();
+    if( rSubType == PdfName("Type0") ) 
+    {
+        // TABLE 5.18 Entries in a Type 0 font dictionary
+
+        // The PDF reference states that DescendantFonts must be an array,
+        // some applications (e.g. MS Word) put the array into an indirect object though.
+        PdfObject* const pDescendantObj = pObject->GetIndirectKey( "DescendantFonts" );
+
+        if ( NULL == pDescendantObj )
+            PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Type0 Font: No DescendantFonts" );
+        
+        PdfArray & descendants = pDescendantObj->GetArray();
+        PdfObject* pFontObject = NULL;
+        
+        if( descendants.size() )
+        {
+            // DescendantFonts is a one-element array
+            PdfObject &descendant = descendants[0];
+
+            if( descendant.IsReference() )
+            {
+                pFontObject = pObject->GetOwner()->GetObject( descendant.GetReference() );
+                pDescriptor = pFontObject->GetIndirectKey( "FontDescriptor" );
+            }
+            else
+            {
+                pFontObject = &descendant;
+                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<</Registry(XXX)/Ordering(XXX)/Supplement 0>>)
+            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" );
+           if ( NULL == pBaseFont )
+               PODOFO_RAISE_ERROR_INFO( ePdfError_NoObject, "No BaseFont object found"
+                                       " by reference in given object" );
+           const char* pszBaseFontName = pBaseFont->GetName().GetName().c_str();
+           const 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(new PdfFontMetricsBase14(*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<pdf_int32>(pDescriptor->GetIndirectKeyAsLong( "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;
+}
+
+
+const 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(
+        new PdfFontMetricsBase14(*PODOFO_Base14FontDef_FindBuiltinData(pszFontName)), pEncoding, pParent);
+    if (pFont) {
+        pFont->SetBold( eFlags & ePdfFont_Bold ? true : false );
+        pFont->SetItalic( eFlags & ePdfFont_Italic ? true : false );
+    }
+    return pFont;
+}
+
+};
diff --git a/src/podofo/doc/PdfFontFactory.h b/src/podofo/doc/PdfFontFactory.h
new file mode 100644 (file)
index 0000000..471eb07
--- /dev/null
@@ -0,0 +1,125 @@
+/***************************************************************************
+ *   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_ */
+
+
diff --git a/src/podofo/doc/PdfFontFactoryBase14Data.h b/src/podofo/doc/PdfFontFactoryBase14Data.h
new file mode 100644 (file)
index 0000000..f848233
--- /dev/null
@@ -0,0 +1,4645 @@
+/***************************************************************************
+ *   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 const   PdfFontMetricsBase14   PODOFO_BUILTIN_FONTS[] = {
+    PdfFontMetricsBase14(
+        PODOFO_HPDF_FONT_COURIER,
+        CHAR_DATA_COURIER,
+        PODOFO_FALSE,
+        627,
+        -373,
+        426,
+        562,
+        261,
+        -224,
+        PdfRect(-23, -250, 715, 805)
+    ),
+    PdfFontMetricsBase14(
+        PODOFO_HPDF_FONT_COURIER_BOLD,
+        CHAR_DATA_COURIER_BOLD,
+        PODOFO_FALSE,
+        627,
+        -373,
+        439,
+        562,
+        261,
+        -224,
+        PdfRect(-113, -250, 749, 801)
+    ),
+    PdfFontMetricsBase14(
+        PODOFO_HPDF_FONT_COURIER_OBLIQUE,
+        CHAR_DATA_COURIER_OBLIQUE,
+        PODOFO_FALSE,
+        627,
+        -373,
+        426,
+        562,
+        261,
+        -224,
+        PdfRect(-27, -250, 849, 805)
+    ),
+    PdfFontMetricsBase14(
+        PODOFO_HPDF_FONT_COURIER_BOLD_OBLIQUE,
+        CHAR_DATA_COURIER_BOLD_OBLIQUE,
+        PODOFO_FALSE,
+        627,
+        -373,
+        439,
+        562,
+        261,
+        -224,
+        PdfRect(-57, -250, 869, 801)
+    ),
+    PdfFontMetricsBase14(
+        PODOFO_HPDF_FONT_HELVETICA,
+        CHAR_DATA_HELVETICA,
+        PODOFO_FALSE,
+        750,
+        -250,
+        523,
+        718,
+        290,
+        -100,
+        PdfRect(-166, -225, 1000, 931)
+    ),
+    PdfFontMetricsBase14(
+        PODOFO_HPDF_FONT_HELVETICA_BOLD,
+        CHAR_DATA_HELVETICA_BOLD,
+        PODOFO_FALSE,
+        750,
+        -250,
+        532,
+        718,
+        290,
+        -100,
+        PdfRect(-170, -228, 1003, 962)
+    ),
+    PdfFontMetricsBase14(
+        PODOFO_HPDF_FONT_HELVETICA_OBLIQUE,
+        CHAR_DATA_HELVETICA_OBLIQUE,
+        PODOFO_FALSE,
+        750,
+        -250,
+        532,
+        718,
+        290,
+        -100,
+        PdfRect(-170, -225, 1116, 931)
+    ),
+    PdfFontMetricsBase14(
+        PODOFO_HPDF_FONT_HELVETICA_BOLD_OBLIQUE,
+        CHAR_DATA_HELVETICA_BOLD_OBLIQUE,
+        PODOFO_FALSE,
+        750,
+        -250,
+        532,
+        718,
+        290,
+        -100,
+        PdfRect(-174, -228, 1114, 962)
+    ),
+    PdfFontMetricsBase14(
+        PODOFO_HPDF_FONT_TIMES_ROMAN,
+        CHAR_DATA_TIMES_ROMAN,
+        PODOFO_FALSE,
+        727,
+        -273,
+        450,
+        662,
+        262,
+        -100,
+        PdfRect(-168, -218, 1000, 898)
+    ),
+    PdfFontMetricsBase14(
+        PODOFO_HPDF_FONT_TIMES_BOLD,
+        CHAR_DATA_TIMES_BOLD,
+        PODOFO_FALSE,
+        727,
+        -273,
+        461,
+        676,
+        262,
+        -100,
+        PdfRect(-168, -218, 1000, 935)
+    ),
+    PdfFontMetricsBase14(
+        PODOFO_HPDF_FONT_TIMES_ITALIC,
+        CHAR_DATA_TIMES_ITALIC,
+        PODOFO_FALSE,
+        727,
+        -273,
+        441,
+        653,
+        262,
+        -100,
+        PdfRect(-169, -217, 1010, 883)
+    ),
+    PdfFontMetricsBase14(
+        PODOFO_HPDF_FONT_TIMES_BOLD_ITALIC,
+        CHAR_DATA_TIMES_BOLD_ITALIC,
+        PODOFO_FALSE,
+        727,
+        -273,
+        462,
+        669,
+        262,
+        -100,
+        PdfRect(-200, -218, 996, 921)
+    ),
+    PdfFontMetricsBase14(
+        PODOFO_HPDF_FONT_SYMBOL,
+        CHAR_DATA_SYMBOL,
+        PODOFO_TRUE,
+        683,
+        -217,
+        462,
+        669,
+        341,
+        -100,
+       PdfRect(-180, -293, 1090, 1010)
+    ),
+    PdfFontMetricsBase14(
+        PODOFO_HPDF_FONT_ZAPF_DINGBATS,
+        CHAR_DATA_ZAPF_DINGBATS,
+        PODOFO_TRUE,
+        683,
+        -217,
+        462,
+        669,
+        341,
+        -100,
+        PdfRect(-1, -143, 981, 820)
+    ),
+    PdfFontMetricsBase14(
+        NULL,
+        NULL,
+        PODOFO_FALSE,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        PdfRect(0, 0, 0, 0)
+    ),
+};
+
+};
+
+#endif // _PDF_FONT_FACTORY_BASE14_DATA_H_
diff --git a/src/podofo/doc/PdfFontMetrics.cpp b/src/podofo/doc/PdfFontMetrics.cpp
new file mode 100644 (file)
index 0000000..72e8cca
--- /dev/null
@@ -0,0 +1,1024 @@
+/***************************************************************************
+ *   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 <sstream>
+
+#include <wchar.h>
+#include <ft2build.h>
+#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 <Carbon/Carbon.h>
+#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<unsigned int>(pDescriptor->GetDictionary().GetKeyAsLong( "FontWeight", 400L ));
+    m_nItalicAngle = static_cast<int>(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<strlen( inFontName ); i++ ) {
+        if ( inFontName[i] == '-' ) {
+            if ( !foundSpace ) {
+                localFontName[j++] = ' ';
+                foundSpace = true;
+            } else {
+                // do nothing, we skip over it!
+            }
+        } else {
+            localFontName[j++] = inFontName[i];
+        }
+    }
+    localFontName[j] = 0;      // helps to zero term
+    // inLog.Debug( boost::format( "LocalFontName: %s\n" ) % localFontName );
+#else
+    strcpy( localFontName, inFontName );
+#endif
+
+    // 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 );
+
+
+    int        numFONDs = Count1Resources( 'FOND' );
+    // inLog.Debug( boost::format( "Number of 'FOND' resources = %d\n" ) % numFONDs );
+
+   for ( res_index = 1; ; ++res_index )
+    {
+      fond = Get1IndResource( 'FOND', res_index );
+      if ( ResError() ) {
+        // inLog.Debug( boost::format( "Get1IndResource ('FOND' #%d) failed - Error %d\n" ) % res_index % ResError() );
+        error = FT_Err_Cannot_Open_Resource;
+        goto Error;
+      }
+
+      short   fond_id;
+      OSType  fond_type;
+      Str255  fond_name;
+      GetResInfo( fond, &fond_id, &fond_type, fond_name );
+      if ( ResError() != noErr || fond_type != 'FOND' ) {
+          // inLog.Debug( boost::format( "GetResInfo failed - Error %d\n") % ResError() );
+          error = FT_Err_Invalid_File_Format;
+          goto Error;
+      }
+      fond_name[ fond_name[0]+1 ] = 0;
+
+      // check to make sure this is a font we want to load (TTF or OTF)
+      HLock( fond );
+      parse_fond( *fond, &have_sfnt, &sfnt_id, ps_name, lwfn_file_name, inFaceIndex );
+      HUnlock( fond );
+
+      // if either the original font name OR the modified one match - go for it!
+      // inLog.Debug( boost::format( "FOND name: '%s' - PSName: '%s'\n" ) % &fond_name[1] % ps_name );
+      if ( ft_strcmp( (char*)&fond_name[1] /*ps_name*/, localFontName ) == 0 ) {
+          inFaceIndex = res_index-1;
+          // inLog.Debug( boost::format( "Matched '%s' at res_index:%d\n" ) % &fond_name[1] % res_index );
+          break;
+      } else if ( ft_strcmp( (char*)&fond_name[1], inFontName ) == 0 ) {
+          inFaceIndex = res_index-1;
+          // inLog.Debug( boost::format( "Matched '%s' at res_index:%d\n" ) % &fond_name[1] % res_index );
+          break;
+      }
+
+    }
+
+    if ( lwfn_file_name[0] )
+    {
+        lwfn_file_name[lwfn_file_name[0]+1] = 0;       // zero term for C
+      // inLog.Debug( boost::format( "Found LWFN at '%s'\n" ) % &lwfn_file_name[1] );
+
+      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 ) ) {
+        FT_Byte*  pfb_data;
+        FT_ULong  pfb_size;
+        FT_Error  error;
+        short     res_ref;
+
+        res_ref = FSpOpenResFile( &lwfn_spec, fsRdPerm );
+        if ( res_ref < 0 ) {
+            // inLog.Debug( "FSpOpenResFile on LWFN failed\n" );
+            return FT_Err_Cannot_Open_Resource;
+        } else {
+            // inLog.Debug( "FSpOpenResFile on LWFN succeeded!\n" );
+        }
+
+        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" );
+        }
+    } else if ( have_sfnt ) {
+        Handle     sfnt = NULL;
+        FT_Byte*   sfnt_data;
+        size_t     sfnt_size;
+
+        // inLog.Debug( "Loading from SFNT...\n" );
+
+        sfnt = GetResource( 'sfnt', sfnt_id );
+        if ( ResError() ) {
+            // inLog.Debug( boost::format( "GetResource ('sfnt' #%d) failed - Error %d\n" ) % sfnt_id % ResError() );
+            return FT_Err_Invalid_Handle;
+        }
+
+        sfnt_size = (FT_ULong)GetHandleSize( sfnt );
+        sfnt_data = (FT_Byte*)ASmalloc( (FT_Long)sfnt_size );
+        if ( sfnt_data == NULL ) {
+            ReleaseResource( sfnt );
+            return error;
+        }
+
+        HLock( sfnt );
+        memcpy( sfnt_data, *sfnt, sfnt_size );
+        HUnlock( sfnt );
+        ReleaseResource( sfnt );
+
+        *outBuffer = (char*)sfnt_data;
+        outBufLen = sfnt_size;
+    } else {
+        // inLog.Debug( boost::format( "have_sfnt is false, sfnt_id is %d, and inFaceIndex is %d\n" ) % sfnt_id % inFaceIndex );
+    }
+
+Error:
+    CloseResFile( res_ref );
+    return error;
+}
+
+std::string    Std2AltFontName( const std::string& inStdName )
+{
+    std::string        altName( "" );
+
+    if ( inStdName == "Courier" )
+        altName.assign( "Courier New" );
+    else if ( inStdName == "Courier-Bold" )
+        altName.assign( "Courier New Bold" );
+    else if ( inStdName == "Courier-Oblique" )
+        altName.assign( "Courier New Italic" );
+    else if ( inStdName == "Courier-BoldOblique" )
+        altName.assign( "Courier New Bold Italic" );
+    else if ( inStdName == "Times-Roman" )
+        altName.assign( "Times New Roman" );
+    else if ( inStdName == "Times-Bold" )
+        altName.assign( "Times New Roman Bold" );
+    else if ( inStdName == "Times-Italic" )
+        altName.assign( "Times New Roman Italic" );
+    else if ( inStdName == "Times-BoldItalic" )
+        altName.assign( "Times New Roman Bold Italic" );
+    else if ( inStdName == "ZapfDingbats" )
+        altName.assign( "Zapf Dingbats" );
+
+    // if we haven't already found it, try doing common subs
+    if ( altName.empty() ) {
+        int j = 0;
+        bool   foundSpace = false;
+        for ( int i=0; i<inStdName.length(); i++ ) {
+            if ( inStdName[i] == ',' ) {
+                altName += ' ';
+            } else if ( inStdName[i] == '-' ) {
+                if ( !foundSpace ) {
+                    altName += ' ';
+                    foundSpace = true;
+                } else {
+                    // do nothing, we skip over it!
+                }
+            } else {
+                altName += inStdName[i];
+            }
+        }
+    }
+
+    return altName;
+}
+
+std::string PdfFontMetrics::GetFilenameForFont( const char* pszFontname )
+{
+    // TODO: Use FT_GetFile_From_Mac_ATS_Name
+
+    FSSpec  fSpec;
+    FT_Long fIndex = 0;
+    FT_Error    error = My_FT_GetFile_From_Mac_ATS_Name( const_cast<char*>(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<char*>(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; i<nLength; i++ )
+    {
+        dWidth += CharWidth( *localText );
+        if (*localText == 0x20)
+            dWidth += m_fWordSpace * this->GetFontScale() / 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<nLength; i++ )
+    {
+#ifdef PODOFO_IS_LITTLE_ENDIAN
+        uChar = static_cast<unsigned short>(((*localText & 0x00ff) << 8 | (*localText & 0xff00) >> 8));
+#else
+        uChar = static_cast<unsigned short>(*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<unsigned int>(wcslen( pszText ));
+
+    const wchar_t *localText = pszText;
+    for ( unsigned int i=0; i<nLength; i++ )
+    {
+        dWidth += CharWidth( static_cast<int>(*localText) );
+        if ( static_cast<int>(*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;
+}
+
+};
diff --git a/src/podofo/doc/PdfFontMetrics.h b/src/podofo/doc/PdfFontMetrics.h
new file mode 100644 (file)
index 0000000..56433e0
--- /dev/null
@@ -0,0 +1,587 @@
+/***************************************************************************
+ *   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<double> m_vecWidth;
+
+    EPdfFontType  m_eFontType;
+    std::string   m_sFontSubsetPrefix;
+};
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+unsigned long PdfFontMetrics::CharWidthMM( unsigned char c ) const
+{
+    return static_cast<unsigned long>(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<unsigned long>(this->StringWidth( pszText, nLength ) / PODOFO_CONVERSION_CONSTANT);
+}
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+unsigned long PdfFontMetrics::StringWidthMM( const pdf_utf16be* pszText, unsigned int nLength ) const
+{
+    return static_cast<unsigned long>(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<unsigned long>(this->StringWidth( pszText, nLength ) / PODOFO_CONVERSION_CONSTANT);
+}
+#endif
+#endif
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+unsigned long PdfFontMetrics::GetLineSpacingMM() const
+{
+    return static_cast<unsigned long>(this->GetLineSpacing() / PODOFO_CONVERSION_CONSTANT);
+}
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+long PdfFontMetrics::GetUnderlinePositionMM() const
+{
+    return static_cast<long>(this->GetUnderlinePosition() /  PODOFO_CONVERSION_CONSTANT);
+}
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+unsigned long PdfFontMetrics::GetStrikeOutPositionMM() const
+{
+    return static_cast<long>(this->GetStrikeOutPosition() /  PODOFO_CONVERSION_CONSTANT);
+}
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+unsigned long PdfFontMetrics::GetUnderlineThicknessMM() const
+{
+    return static_cast<unsigned long>(this->GetUnderlineThickness() / PODOFO_CONVERSION_CONSTANT);
+}
+
+// -----------------------------------------------------
+//
+// -----------------------------------------------------
+unsigned long PdfFontMetrics::GetStrikeoutThicknessMM() const
+{
+    return static_cast<unsigned long>(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_
+
diff --git a/src/podofo/doc/PdfFontMetricsBase14.cpp b/src/podofo/doc/PdfFontMetricsBase14.cpp
new file mode 100644 (file)
index 0000000..2deb0e4
--- /dev/null
@@ -0,0 +1,283 @@
+/***************************************************************************
+ *   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,
+                                           pdf_int16         mstrikeout_pos,
+                                           pdf_int16         munderline_pos,
+                                           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.05;
+    m_dStrikeOutThickness = m_dUnderlineThickness;
+    units_per_EM          = 1000;
+    m_dPdfAscent          = ascent * 1000 / units_per_EM;
+    m_dPdfDescent         = descent * 1000 / units_per_EM;
+    
+    m_dAscent             = ascent;
+    m_dDescent            = descent;
+    m_dUnderlinePosition  = static_cast<double>(munderline_pos) / units_per_EM;
+    m_dStrikeOutPosition  = static_cast<double>(mstrikeout_pos) / units_per_EM;
+
+    // calculate the line spacing now, as it changes only with the font size
+    m_dLineSpacing        = (static_cast<double>(ascent + abs(descent)) / units_per_EM);
+    m_dAscent             = static_cast<double>(ascent) /  units_per_EM;
+    m_dDescent            = static_cast<double>(descent) /  units_per_EM;
+}
+
+PdfFontMetricsBase14::~PdfFontMetricsBase14()
+{
+}
+
+double PdfFontMetricsBase14::GetGlyphWidth( int nGlyphId ) const 
+{
+    return widths_table[static_cast<unsigned int>(nGlyphId)].width; 
+}
+
+double PdfFontMetricsBase14::GetGlyphWidth( const char* ) const 
+{
+    return 0.0;
+}
+
+double PdfFontMetricsBase14::CharWidth( unsigned char c ) const 
+{
+    double dWidth = widths_table[static_cast<unsigned int>(GetGlyphId(c) )].width;
+    
+    return dWidth * static_cast<double>(this->GetFontSize() * this->GetFontScale() / 100.0) / 1000.0 +
+        static_cast<double>( 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<unsigned int>(GetGlyphIdUnicode(c) )].width;
+       
+    return dWidth * static_cast<double>(this->GetFontSize() * this->GetFontScale() / 100.0) / 1000.0 +
+        static_cast<double>( 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;
+    long lSwappedUnicode = ((lUnicode & 0xFF00) >> 8) | ((lUnicode & 0x00FF) << 8);
+
+    // 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 ||
+            widths_table[i].unicode == lSwappedUnicode )
+        {
+            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);
+
+            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;
+}
+
+};
diff --git a/src/podofo/doc/PdfFontMetricsBase14.h b/src/podofo/doc/PdfFontMetricsBase14.h
new file mode 100644 (file)
index 0000000..591da56
--- /dev/null
@@ -0,0 +1,296 @@
+/***************************************************************************
+ *   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 <string.h>
+
+/*
+  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,
+                         pdf_int16         mstrikeout_pos,
+                         pdf_int16         munderline_pos,
+                         const PdfRect &  mbbox);
+
+    ~PdfFontMetricsBase14();
+
+       friend  const 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;
+
+};
+
+
+const PdfFontMetricsBase14*
+PODOFO_Base14FontDef_FindBuiltinData  (const char  *font_name);
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline double PdfFontMetricsBase14::GetCapHeight() const 
+{
+    return cap_height;
+}
+
+};
+
+#endif // _PDF_FONT_METRICS_BASE14_H_
diff --git a/src/podofo/doc/PdfFontMetricsFreetype.cpp b/src/podofo/doc/PdfFontMetricsFreetype.cpp
new file mode 100644 (file)
index 0000000..8bb0c46
--- /dev/null
@@ -0,0 +1,549 @@
+/***************************************************************************
+ *   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 <iostream>
+#include <sstream>
+
+#include <wchar.h>
+#include <ft2build.h>
+#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 <Carbon/Carbon.h>
+#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<FT_Byte*>(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<char*>(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<FT_Byte*>(m_bufFontData.GetBuffer()), 
+    openArgs.memory_size = static_cast<FT_Long>(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; c<m_pFace->num_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<double>(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<int>(fSize*64.0), 0, 72, 72 );
+
+    // calculate the line spacing now, as it changes only with the font size
+    m_dLineSpacing        = (static_cast<double>(m_pFace->height) / m_pFace->units_per_EM);
+    m_dUnderlineThickness = (static_cast<double>(m_pFace->underline_thickness) / m_pFace->units_per_EM);
+    m_dUnderlinePosition  = (static_cast<double>(m_pFace->underline_position)  / m_pFace->units_per_EM);
+    m_dAscent  = static_cast<double>(m_pFace->ascender) / m_pFace->units_per_EM;
+    m_dDescent = static_cast<double>(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<TT_OS2*>(FT_Get_Sfnt_Table( m_pFace, ft_sfnt_os2 ));
+    if( pOs2Table ) 
+    {
+        m_dStrikeOutPosition  = static_cast<double>(pOs2Table->yStrikeoutPosition) / m_pFace->units_per_EM;
+        m_dStrikeOutThickness = static_cast<double>(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<char *>(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<unsigned int>(c)];
+
+    return dWidth * static_cast<double>(this->GetFontSize() * this->GetFontScale() / 100.0) / 1000.0 +
+        static_cast<double>( 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<int>(c) < PODOFO_WIDTH_CACHE_SIZE ) 
+    {
+        dWidth = m_vecWidth[static_cast<unsigned int>(c)];
+    }
+    else
+    {
+        ftErr = FT_Load_Char( m_pFace, static_cast<FT_UInt>(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<double>(this->GetFontSize() * this->GetFontScale() / 100.0) / 1000.0 +
+        static_cast<double>( 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;
+}
+
+};
diff --git a/src/podofo/doc/PdfFontMetricsFreetype.h b/src/podofo/doc/PdfFontMetricsFreetype.h
new file mode 100644 (file)
index 0000000..9e8c2d9
--- /dev/null
@@ -0,0 +1,325 @@
+/***************************************************************************
+ *   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<double> m_vecWidth;
+};
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+FT_Face PdfFontMetricsFreetype::GetFace() 
+{ 
+    return m_pFace; 
+} 
+
+};
+
+#endif // _PDF_FONT_METRICS_FREETYPE_H_
+
diff --git a/src/podofo/doc/PdfFontMetricsObject.cpp b/src/podofo/doc/PdfFontMetricsObject.cpp
new file mode 100644 (file)
index 0000000..6a56286
--- /dev/null
@@ -0,0 +1,372 @@
+/***************************************************************************
+ *   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->MustGetIndirectKey( 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->MustGetIndirectKey( "FontName" )->GetName();
+            if (pDescriptor->GetDictionary().HasKey( "FontBBox" ))
+                m_bbox         = pDescriptor->MustGetIndirectKey( "FontBBox" )->GetArray();
+        } else {
+            if (pFont->GetDictionary().HasKey( "Name" ))
+                m_sName        = pFont->MustGetIndirectKey( "Name" )->GetName();
+            if (pFont->GetDictionary().HasKey( "FontBBox" ))
+                m_bbox         = pFont->MustGetIndirectKey( "FontBBox" )->GetArray();
+        }
+        if (pFont->GetDictionary().HasKey( "FontMatrix" )) {
+            // Type3 fonts have a custom FontMatrix
+            m_matrix = pFont->MustGetIndirectKey( "FontMatrix" )->GetArray();
+        }
+        m_nFirst       = static_cast<int>(pFont->GetIndirectKeyAsLong( "FirstChar", 0L ));
+        m_nLast        = static_cast<int>(pFont->GetIndirectKeyAsLong( "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->GetIndirectKey( "MissingWidth" );
+            } else {
+                widths = pFont->GetIndirectKey( "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<double>(pFont->GetIndirectKeyAsLong( "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<int>(w.GetSize())) {
+                               int start = static_cast<int>(w[pos++].GetNumber());
+                               PODOFO_ASSERT (start >= 0);
+                               PdfObject * second = &w[pos];
+                               if (second->IsReference()) {
+                                       // Make sure array referenced is available:
+                                       second->DelayedStreamLoad();
+                                       // second do not have an associated owner; use the one in pw
+                                       second = pw->GetOwner()->MustGetObject(second->GetReference());
+                                       PODOFO_ASSERT (!second->IsNull());
+                               }
+                               if (second->IsArray()) {
+                                       PdfArray widths = second->GetArray();
+                                       ++pos;
+                                       int length = start + static_cast<int>(widths.GetSize());
+                                       PODOFO_ASSERT (length >= start);
+                                       if (length > static_cast<int>(m_width.GetSize())) {
+                                               m_width.resize(length, default_width);
+                                       }
+                                       for (int i = 0; i < static_cast<int>(widths.GetSize()); ++i) {
+                                               m_width[start + i] = widths[i];
+                                       }
+                               } else {
+                                       int end = static_cast<int>(w[pos++].GetNumber());
+                                       int length = end + 1;
+                                       PODOFO_ASSERT (length >= start);
+                                       if (length > static_cast<int>(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<unsigned int>(pDescriptor->GetIndirectKeyAsLong( "FontWeight", 400L ));
+        m_nItalicAngle = static_cast<int>(pDescriptor->GetIndirectKeyAsLong( "ItalicAngle", 0L ));
+        m_dPdfAscent   = pDescriptor->GetIndirectKeyAsReal( "Ascent", 0.0 );
+        m_dPdfDescent  = pDescriptor->GetIndirectKeyAsReal( "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<int>(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<int>(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;
+}
+
+};
diff --git a/src/podofo/doc/PdfFontMetricsObject.h b/src/podofo/doc/PdfFontMetricsObject.h
new file mode 100644 (file)
index 0000000..4864cbe
--- /dev/null
@@ -0,0 +1,253 @@
+/***************************************************************************
+ *   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_
+
diff --git a/src/podofo/doc/PdfFontSimple.cpp b/src/podofo/doc/PdfFontSimple.cpp
new file mode 100644 (file)
index 0000000..6582629
--- /dev/null
@@ -0,0 +1,128 @@
+/***************************************************************************
+ *   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<pdf_int64>(m_pEncoding->GetFirstChar()) ) );
+    this->GetObject()->GetDictionary().AddKey("LastChar", PdfVariant( static_cast<pdf_int64>(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<pdf_int64>(PODOFO_LL_LITERAL(32)) ) ); // TODO: 0 ????
+    pDescriptor->GetDictionary().AddKey( "FontBBox", array );
+    pDescriptor->GetDictionary().AddKey( "ItalicAngle", PdfVariant( static_cast<pdf_int64>(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<pdf_int64>(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;
+    }
+}
+
+};
diff --git a/src/podofo/doc/PdfFontSimple.h b/src/podofo/doc/PdfFontSimple.h
new file mode 100644 (file)
index 0000000..97dd33e
--- /dev/null
@@ -0,0 +1,100 @@
+/***************************************************************************
+ *   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_ */
diff --git a/src/podofo/doc/PdfFontTTFSubset.cpp b/src/podofo/doc/PdfFontTTFSubset.cpp
new file mode 100644 (file)
index 0000000..043a311
--- /dev/null
@@ -0,0 +1,878 @@
+/***************************************************************************
+ *   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 <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_TRUETYPE_TABLES_H
+#include FT_TRUETYPE_TAGS_H
+
+#include <cstring>
+#include <iostream>
+#include <algorithm>
+
+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<char>(value >> 24);
+    bufp[1] = static_cast<char>(value >> 16);
+    bufp[2] = static_cast<char>(value >>  8);
+    bufp[3] = static_cast<char>(value);
+}
+
+inline void TTFWriteUInt16(char *bufp, unsigned short value)
+{
+    bufp[0] = static_cast<char>(value >> 8);
+    bufp[1] = static_cast<char>(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<unsigned long>(bufp[offset + 0]) << 24) & 0xff000000) 
+          | ((static_cast<unsigned long>(bufp[offset + 1]) << 16) & 0x00ff0000) 
+          | ((static_cast<unsigned long>(bufp[offset + 2]) <<  8) & 0x0000ff00) 
+          | ((static_cast<unsigned long>(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<TTrueTypeTable>::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<char>(tag>>24) << static_cast<char>(tag>>16)
+        << static_cast<char>(tag>>8)  << static_cast<char>(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<unsigned short>(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<pdf_utf16be>& usedChars )
+{
+    CodePoint codePoint;
+    GID gid;
+
+    for (std::set<pdf_utf16be>::const_iterator it = usedChars.begin(); it != usedChars.end(); ++it) {
+        codePoint = *it;
+        gid = static_cast<GID>( 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<unsigned long>(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<unsigned short>(cit->first);
+        range.delta   = static_cast<short>( 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<unsigned short>(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<unsigned short>(~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<unsigned short>::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<unsigned long>(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<unsigned short>(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<unsigned short>(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<unsigned short>(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<TTrueTypeTable>::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<TTrueTypeTable>::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<pdf_utf16be>& usedChars, std::vector<unsigned char>& 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<char*>(address), sz );
+}
+
+
+#if UNUSED_CODE
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+static unsigned int GetPadding(unsigned long ul)
+{
+    ul &= 3;
+    if (ul != 0)
+    {
+        ul = 4-ul;
+    }
+    
+    return ul;
+}
+#endif
+
+
+}; /* PoDoFo */
+
diff --git a/src/podofo/doc/PdfFontTTFSubset.h b/src/podofo/doc/PdfFontTTFSubset.h
new file mode 100644 (file)
index 0000000..626eece
--- /dev/null
@@ -0,0 +1,253 @@
+/***************************************************************************
+ *   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 <string>
+#include <vector>
+
+namespace PoDoFo {
+
+class PdfInputDevice;
+class PdfOutputDevice;
+
+// This code is based heavily on code by ZhangYang 
+// (张杨.国际) <zhang_yang@founder.com>
+//
+// (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<pdf_utf16be>& usedChars, std::vector<unsigned char>& 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<GID, TGlyphData> GlyphMap;
+    typedef std::map<CodePoint, GID> 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<CMapv4Range> CMapRanges;
+
+    class CMap {
+    public:
+        CMap()
+            : segCount( 0 )
+        {
+        }
+        
+           unsigned short segCount;
+           CMapRanges ranges;
+           std::vector<unsigned short> 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<pdf_utf16be>& 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<TTrueTypeTable> 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_ */
diff --git a/src/podofo/doc/PdfFontTrueType.cpp b/src/podofo/doc/PdfFontTrueType.cpp
new file mode 100644 (file)
index 0000000..65e8665
--- /dev/null
@@ -0,0 +1,100 @@
+/***************************************************************************
+ *   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<char*> is dangerous if string literals may ever be passed
+        char* pBuffer = const_cast<char*>( 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<pdf_int64>(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<pdf_int64>(lSize) ) );
+        pContents->GetStream()->Set( &stream );
+            
+    }
+}
+
+
+
+};
+
diff --git a/src/podofo/doc/PdfFontTrueType.h b/src/podofo/doc/PdfFontTrueType.h
new file mode 100644 (file)
index 0000000..2342eb7
--- /dev/null
@@ -0,0 +1,91 @@
+/***************************************************************************
+ *   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_
+
diff --git a/src/podofo/doc/PdfFontType1.cpp b/src/podofo/doc/PdfFontType1.cpp
new file mode 100644 (file)
index 0000000..cc0bd97
--- /dev/null
@@ -0,0 +1,771 @@
+/***************************************************************************
+ *   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 <stdlib.h>
+
+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<const unsigned char *>(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<char*>(podofo_calloc( lSize, sizeof(char) ));
+        if( !pAllocated )
+        {
+            fclose( hFile );
+            PODOFO_RAISE_ERROR( ePdfError_OutOfMemory );
+        }
+
+        if( static_cast<pdf_long>( 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<unsigned const char*>(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<char>( 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<char *>( &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<char>(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<size_t>(-1) 
+                        && line.find( "-| " ) == static_cast<size_t>(-1) )
+                               {
+                                       plain = inCrypt.Decrypt( inBuff[inIndex+i] );
+                                       outBuff[outIndex++] = plain;
+                                       line += static_cast<char>(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<size_t>(-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<char>(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<size_t>(-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<const char *>(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<char*>(podofo_calloc( lSize, sizeof(char) ));
+        if( !pAllocated )
+        {
+            fclose( hFile );
+            PODOFO_RAISE_ERROR( ePdfError_OutOfMemory );
+        }
+
+        if( static_cast<pdf_long>( 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<unsigned char*>(const_cast<char*>(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<long>(&pBuffer[lSize] - reinterpret_cast<const char*>(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<int>(plain-139);
+                       }
+                       else if ( plain >= 247  &&  plain <= 250 )
+                       {
+                               unsigned char next = crypt.Decrypt( buffer[j++] );
+
+                               number = (static_cast<int>(plain)-247)*256 + next + 108;
+                       }
+                       else if ( plain >= 251  &&  plain <= 254 )
+                       {
+                               unsigned char next = crypt.Decrypt( buffer[j++] );
+
+                               number = -((static_cast<int>(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<int>(next1) << 24)
+                    + (static_cast<int>(next2) << 16)
+                    + (static_cast<int>(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;
+}
+
+};
+
diff --git a/src/podofo/doc/PdfFontType1.h b/src/podofo/doc/PdfFontType1.h
new file mode 100644 (file)
index 0000000..86ba2d4
--- /dev/null
@@ -0,0 +1,180 @@
+/***************************************************************************
+ *   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<std::string>   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_
+
diff --git a/src/podofo/doc/PdfFontType1Base14.cpp b/src/podofo/doc/PdfFontType1Base14.cpp
new file mode 100644 (file)
index 0000000..dd35efd
--- /dev/null
@@ -0,0 +1,117 @@
+/***************************************************************************
+ *   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 );
+}
+
+/*
+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<pdf_int64>(m_pEncoding->GetFirstChar()) ) );
+    this->GetObject()->GetDictionary().AddKey("LastChar", PdfVariant( static_cast<pdf_int64>(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<pdf_int64>(32LL) ) ); // TODO: 0 ????
+//             pDescriptor->GetDictionary().AddKey( "FontBBox", array );
+       
+    
+       
+               
+//                     pDescriptor->GetDictionary().AddKey( "ItalicAngle", PdfVariant( static_cast<pdf_int64>(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<pdf_int64>(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
+}
+
+
+};
diff --git a/src/podofo/doc/PdfFontType1Base14.h b/src/podofo/doc/PdfFontType1Base14.h
new file mode 100644 (file)
index 0000000..3b12fb7
--- /dev/null
@@ -0,0 +1,87 @@
+/***************************************************************************
+ *   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 );
+
+ 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_
+
diff --git a/src/podofo/doc/PdfFontType3.cpp b/src/podofo/doc/PdfFontType3.cpp
new file mode 100644 (file)
index 0000000..ecf5867
--- /dev/null
@@ -0,0 +1,64 @@
+/***************************************************************************
+ *   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 );
+}
+};
+
diff --git a/src/podofo/doc/PdfFontType3.h b/src/podofo/doc/PdfFontType3.h
new file mode 100644 (file)
index 0000000..2df3fd5
--- /dev/null
@@ -0,0 +1,90 @@
+/***************************************************************************
+ *   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_
+
diff --git a/src/podofo/doc/PdfFunction.cpp b/src/podofo/doc/PdfFunction.cpp
new file mode 100644 (file)
index 0000000..2741bff
--- /dev/null
@@ -0,0 +1,155 @@
+/***************************************************************************
+ *   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<pdf_int64>(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<pdf_int64>(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<pdf_int64>(PODOFO_LL_LITERAL(1)) ) );
+    this->GetObject()->GetDictionary().AddKey( PdfName("BitsPerSample"), PdfObject( static_cast<pdf_int64>(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 );
+}
+
+};
diff --git a/src/podofo/doc/PdfFunction.h b/src/podofo/doc/PdfFunction.h
new file mode 100644 (file)
index 0000000..e47ec22
--- /dev/null
@@ -0,0 +1,224 @@
+/***************************************************************************
+ *   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 <list>
+
+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<PdfFunction> List;
+    typedef std::list<char> 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_
diff --git a/src/podofo/doc/PdfHintStream.cpp b/src/podofo/doc/PdfHintStream.cpp
new file mode 100644 (file)
index 0000000..2a857b6
--- /dev/null
@@ -0,0 +1,374 @@
+/***************************************************************************
+ *   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<TPageEntrySharedObjectInfo>       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;i<nPageCount;i++ )
+    {
+        lstPages.clear();
+
+        this->GetObject()->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<double>(maxNumberOfObjects-header.nLeastNumberOfObjects) ) );
+    header.nBitsPageLength               = (pdf_uint16)ceil( logb( static_cast<double>(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<nPageCount;i++ )
+    {
+        vecPages[i].nObjectsPerPage -= header.nLeastNumberOfObjects;
+        vecPages[i].nPageLength     -= header.nLeastPageLength;
+        vecPages[i].Write( this );
+    }
+
+    header.Write( this );
+}
+
+void PdfHintStream::CreateSharedObjectHintTable()
+{
+    PdfVariant offset( static_cast<long>(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<char*>(&val), 2 );
+}
+
+void PdfHintStream::WriteUInt32( pdf_uint32 val )
+{
+    val = ::PoDoFo::compat::podofo_htonl(val);
+    this->GetObject()->GetStream()->Append( reinterpret_cast<char*>(&val), 4 );
+}
+
+}; // end namespace PoDoFo::NonPublic
+}; // end namespace PoDoFo
diff --git a/src/podofo/doc/PdfHintStream.h b/src/podofo/doc/PdfHintStream.h
new file mode 100644 (file)
index 0000000..28518ac
--- /dev/null
@@ -0,0 +1,82 @@
+/***************************************************************************
+ *   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_ */
diff --git a/src/podofo/doc/PdfIdentityEncoding.cpp b/src/podofo/doc/PdfIdentityEncoding.cpp
new file mode 100644 (file)
index 0000000..cd419a5
--- /dev/null
@@ -0,0 +1,135 @@
+/***************************************************************************
+ *   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 <sstream>
+#include <iostream>
+#include <stack>
+#include <iomanip>
+#include <string>
+
+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<pdf_utf16be>(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<char>(lGlyphId >> 8);
+            outp[1] = static_cast<char>(lGlyphId);
+            outp += 2;
+
+            ++pStr;
+        }
+        return buffer;
+    }
+    else
+    {
+        PODOFO_RAISE_ERROR( ePdfError_InvalidHandle );
+    }
+
+    return PdfRefCountedBuffer();
+}
+    
+}; /* namespace PoDoFo */
diff --git a/src/podofo/doc/PdfIdentityEncoding.h b/src/podofo/doc/PdfIdentityEncoding.h
new file mode 100644 (file)
index 0000000..06af7bb
--- /dev/null
@@ -0,0 +1,173 @@
+/***************************************************************************
+ *   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_
diff --git a/src/podofo/doc/PdfImage.cpp b/src/podofo/doc/PdfImage.cpp
new file mode 100644 (file)
index 0000000..b15c56e
--- /dev/null
@@ -0,0 +1,1146 @@
+/***************************************************************************
+ *   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 <stdio.h>
+#include <wchar.h>
+#include <sstream>
+
+// 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 <png.h>
+#endif /// PODOFO_HAVE_PNG_LIB
+
+// <windows.h> 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<double>(this->GetObject()->MustGetIndirectKey( "Height" )->GetNumber()) );
+    m_rRect.SetWidth ( static_cast<double>(this->GetObject()->MustGetIndirectKey( "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<pdf_int64>(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<pdf_int64>(nWidth) ) );
+    this->GetObject()->GetDictionary().AddKey( "Height", PdfVariant( static_cast<pdf_int64>(nHeight) ) );
+    this->GetObject()->GetDictionary().AddKey( "BitsPerComponent", PdfVariant( static_cast<pdf_int64>(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<pdf_int64>(nWidth) ) );
+    this->GetObject()->GetDictionary().AddKey( "Height", PdfVariant( static_cast<pdf_int64>(nHeight) ) );
+    this->GetObject()->GetDictionary().AddKey( "BitsPerComponent", PdfVariant( static_cast<pdf_int64>(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<pdf_int64>(0) ) );
+                decode.insert( decode.end(), PdfVariant( static_cast<pdf_int64>(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<pdf_int64>(1) ) );
+                decode.insert( decode.end(), PdfVariant( static_cast<pdf_int64>(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<pdf_int64>(0) ) );
+            decode.insert( decode.end(), PdfVariant( static_cast<pdf_int64>(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<pdf_int64>(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<unsigned int>(width),
+                 static_cast<unsigned int>(height),
+                 static_cast<unsigned int>(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<tsize_t>(_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<tsize_t>(pos) > _size)
+                {
+                    _pos = _size;
+                }
+                else
+                {
+                    _pos = pos;
+                }
+                break;
+            case SEEK_CUR:
+                if (static_cast<tsize_t>(pos + _pos) > _size)
+                {
+                    _pos = _size;
+                }
+                else
+                {
+                    _pos += pos;
+                }
+                break;
+            case SEEK_END:
+                if (static_cast<tsize_t>(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
+
+static void LoadFromPngContent(png_structp pPng, png_infop pInfo, PdfImage *image)
+{
+    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 */
+    /* 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
+    } else if (color_type != PNG_COLOR_TYPE_PALETTE && depth < 8) {
+        png_set_packing(pPng);
+    }
+
+    /* transform transparency to alpha */
+    if (color_type != PNG_COLOR_TYPE_PALETTE && png_get_valid (pPng, pInfo, PNG_INFO_tRNS))
+        png_set_tRNS_to_alpha (pPng);
+
+    if (depth == 16)
+        png_set_strip_16(pPng);
+
+    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 );
+    }
+
+    size_t lRowLen = png_get_rowbytes(pPng, pInfo);
+    size_t lLen = lRowLen * height;
+    char* pBuffer = static_cast<char*>(podofo_calloc(lLen, sizeof(char)));
+       if (!pBuffer)
+       {
+               PODOFO_RAISE_ERROR(ePdfError_OutOfMemory);
+       }
+
+    png_bytepp pRows = static_cast<png_bytepp>(podofo_calloc(height, sizeof(png_bytep)));
+       if (!pRows)
+       {
+               PODOFO_RAISE_ERROR(ePdfError_OutOfMemory);
+    }
+
+    for(unsigned int y=0; y<height; y++)
+    {
+        pRows[y] = reinterpret_cast<png_bytep>(pBuffer + y * lRowLen);
+    }
+
+    png_read_image(pPng, pRows);
+
+    png_bytep paletteTrans;
+    int numTransColors;
+    if (color_type & PNG_COLOR_MASK_ALPHA ||
+        (color_type == PNG_COLOR_TYPE_PALETTE && png_get_valid(pPng, pInfo, PNG_INFO_tRNS) && png_get_tRNS(pPng, pInfo, &paletteTrans, &numTransColors, NULL)))
+    {
+        // Handle alpha channel and create smask
+        char *smask = static_cast<char*>(podofo_calloc(height, width));
+        png_uint_32 smaskIndex = 0;
+        if (color_type == PNG_COLOR_TYPE_PALETTE) {
+            for (png_uint_32 r = 0; r < height; r++) {
+                png_bytep row = pRows[r];
+                for (png_uint_32 c = 0; c < width; c++) {
+                    png_byte color;
+                    if (depth == 8) {
+                        color = row[c];
+                    } else if (depth == 4) {
+                        color = c % 2 ? row[c / 2] >> 4 : row[c / 2] & 0xF;
+                    } else if (depth == 2) {
+                        color = (row[c / 4] >> c % 4 * 2) & 3;
+                    } else if (depth == 1) {
+                        color = (row[c / 4] >> c % 8) & 1;
+                    }
+                    smask[smaskIndex++] = color < numTransColors ? paletteTrans[color] : 0xFF;
+                }
+            }
+        } else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
+            for (png_uint_32 r = 0; r < height; r++) {
+                png_bytep row = pRows[r];
+                for (png_uint_32 c = 0; c < width; c++) {
+                    memmove(pBuffer + 3 * smaskIndex, row + 4 * c, 3); // 3 byte for rgb
+                    smask[smaskIndex++] = row[c * 4 + 3]; // 4th byte for alpha
+                }
+            }
+            lLen = 3 * width * height;
+        } else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
+            for (png_uint_32 r = 0; r < height; r++) {
+                png_bytep row = pRows[r];
+                for (png_uint_32 c = 0; c < width; c++) {
+                    pBuffer[smaskIndex] = row[c * 2]; // 1 byte for gray
+                    smask[smaskIndex++] = row[c * 2 + 1]; // 2nd byte for alpha
+                }
+            }
+            lLen = width * height;
+        }
+        PdfMemoryInputStream smaskstream(smask, width * height);
+        PdfImage smakeImage(image->GetObject()->GetOwner());
+        smakeImage.SetImageColorSpace(ePdfColorSpace_DeviceGray);
+        smakeImage.SetImageData(width, height, 8, &smaskstream);
+        image->SetImageSoftmask(&smakeImage);
+        podofo_free(smask);
+    }
+
+    // Set color space
+    if (color_type == PNG_COLOR_TYPE_PALETTE) {
+        png_color *pColors;
+        int numColors;
+        png_get_PLTE(pPng, pInfo, &pColors, &numColors);
+
+        char *datap = new char[numColors * 3];
+        for (int i = 0; i < numColors; i++, pColors++)
+        {
+            datap[3 * i + 0] = pColors->red;
+            datap[3 * i + 1] = pColors->green;
+            datap[3 * i + 2] = pColors->blue;
+        }
+        PdfMemoryInputStream stream(datap, numColors * 3);
+        PdfObject* pIdxObject = image->GetObject()->GetOwner()->CreateObject();
+        pIdxObject->GetStream()->Set(&stream);
+
+        PdfArray array;
+        array.push_back(PdfName("DeviceRGB"));
+        array.push_back(static_cast<pdf_int64>(numColors - 1));
+        array.push_back(pIdxObject->Reference());
+        image->SetImageColorSpace(ePdfColorSpace_Indexed, &array);
+    } else if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
+        image->SetImageColorSpace(ePdfColorSpace_DeviceGray);
+    } else {
+        image->SetImageColorSpace(ePdfColorSpace_DeviceRGB);
+    }
+
+    // Set the image data and flate compress it
+    PdfMemoryInputStream stream( pBuffer, lLen );
+    image->SetImageData( width, height, depth, &stream );
+    
+    podofo_free(pBuffer);
+    podofo_free(pRows);
+    
+    png_destroy_read_struct(&pPng, &pInfo, (png_infopp)NULL);
+}
+
+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);
+
+    LoadFromPngContent(pPng, pInfo, this);
+}
+
+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);
+    
+    LoadFromPngContent(pPng, pInfo, this);
+}
+#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));
+}
+};
diff --git a/src/podofo/doc/PdfImage.h b/src/podofo/doc/PdfImage.h
new file mode 100644 (file)
index 0000000..2fb9dc3
--- /dev/null
@@ -0,0 +1,325 @@
+/***************************************************************************
+ *   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_
diff --git a/src/podofo/doc/PdfInfo.cpp b/src/podofo/doc/PdfInfo.cpp
new file mode 100644 (file)
index 0000000..943b0f4
--- /dev/null
@@ -0,0 +1,147 @@
+/***************************************************************************
+ *   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()->GetIndirectKey( rName );
+    
+    return pObj && (pObj->IsString() || pObj->IsHexString()) ? pObj->GetString() : PdfString::StringNull;
+}
+
+const PdfName & PdfInfo::GetNameFromInfoDict(const PdfName & rName) const
+{
+    const PdfObject* pObj = this->GetObject()->GetIndirectKey( 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" ) );
+}
+
+};
+
+
+
diff --git a/src/podofo/doc/PdfInfo.h b/src/podofo/doc/PdfInfo.h
new file mode 100644 (file)
index 0000000..96be2ef
--- /dev/null
@@ -0,0 +1,267 @@
+/***************************************************************************
+ *   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_
diff --git a/src/podofo/doc/PdfMemDocument.cpp b/src/podofo/doc/PdfMemDocument.cpp
new file mode 100644 (file)
index 0000000..66b154f
--- /dev/null
@@ -0,0 +1,729 @@
+/***************************************************************************
+ *   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 <algorithm>
+#include <deque>
+#include <iostream>
+
+#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<char *>( 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() );
+    try {
+        m_pParser->ParseFile( pszFilename, true );
+        InitFromParser( m_pParser );
+    } catch (PdfError& e) {
+        if ( e.GetError() != ePdfError_InvalidPassword )
+        {
+            Clear(); // avoid m_pParser leak (issue #49)
+            e.AddToCallstack( __FILE__, __LINE__, "Handler fixes issue #49" );
+        }
+        throw;
+    }
+}
+
+#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<wchar_t *>( podofo_malloc( sizeof( wchar_t ) * ( lLen + 1 ) ) );
+        wmemcpy( 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::LoadFromBuffer( 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::LoadFromDevice( 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<PdfExtension> PdfMemDocument::GetPdfExtensions() const {
+    
+    std::vector<PdfExtension> 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<EPdfVersion>(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.
+     */
+
+    PdfOutputDevice device( pszFilename );
+
+    this->Write( &device );
+}
+
+#ifdef _WIN32
+void PdfMemDocument::Write( const wchar_t* pszFilename )
+{
+    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.
+     */
+
+     // makes sure pending subset-fonts are embedded
+    m_fontCache.EmbedSubsetFonts();
+
+    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 );
+    }
+
+    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 );
+    }
+
+    // makes sure pending subset-fonts are embedded
+    m_fontCache.EmbedSubsetFonts();
+
+    /** 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<PdfParserObject*>(pObj);
+    if( !pParserObject ) 
+    {
+        PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, 
+                                 "FreeObjectMemory works only on classes of type PdfParserObject." );
+    }
+
+    pParserObject->FreeObjectMemory( bForce );
+}
+
+};
+
diff --git a/src/podofo/doc/PdfMemDocument.h b/src/podofo/doc/PdfMemDocument.h
new file mode 100644 (file)
index 0000000..f7baa4b
--- /dev/null
@@ -0,0 +1,760 @@
+/**************************************************************************
+ *   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, LoadFromBuffer, LoadFromDevice
+     */
+    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, LoadFromBuffer, LoadFromDevice
+     */
+    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, Load, LoadFromDevice
+     */
+    void LoadFromBuffer( 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, Load, LoadFromBuffer
+     */
+    void LoadFromDevice( 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<PdfExtension> 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_
diff --git a/src/podofo/doc/PdfNamesTree.cpp b/src/podofo/doc/PdfNamesTree.cpp
new file mode 100644 (file)
index 0000000..d834369
--- /dev/null
@@ -0,0 +1,526 @@
+/***************************************************************************
+ *   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 <sstream>
+
+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()->MustGetIndirectKey("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()->MustGetIndirectKey("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()->MustGetIndirectKey( PdfName("Kids") )->IsArray() )
+        {
+            const PdfReference & rRefFirst = (*this->GetObject()->MustGetIndirectKey("Kids")->GetArray().begin()).GetReference();
+            PdfObject* pChild = this->GetObject()->GetOwner()->GetObject( rRefFirst );
+            if( pChild && pChild->GetDictionary().HasKey( PdfName("Limits") ) &&
+                pChild->MustGetIndirectKey( PdfName("Limits") )->IsArray() ) 
+                limits.push_back( *(pChild->MustGetIndirectKey("Limits")->GetArray().begin()) );
+            
+            const PdfReference & rRefLast = this->GetObject()->MustGetIndirectKey("Kids")->GetArray().back().GetReference();
+            pChild = this->GetObject()->GetOwner()->GetObject( rRefLast );
+            if( pChild && pChild->GetDictionary().HasKey( PdfName("Limits") ) &&
+                pChild->MustGetIndirectKey( PdfName("Limits") )->IsArray() ) 
+                limits.push_back( pChild->MustGetIndirectKey("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()->MustGetIndirectKey( PdfName("Names") )->IsArray() )
+        {
+            limits.push_back( (*this->GetObject()->MustGetIndirectKey("Names")->GetArray().begin()) );
+            limits.push_back( (*(this->GetObject()->MustGetIndirectKey("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()->MustGetIndirectKey("Kids")->GetArray()) :
+                                               &(this->GetObject()->MustGetIndirectKey("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()->MustGetIndirectKey("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( m_pParent != NULL ? m_pParent : this, pChild1 ).SetLimits();
+        PdfNameTreeNode( this, 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->MustGetIndirectKey("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
+    {
+        PdfArray & names      = pObj->MustGetIndirectKey("Names")->GetArray();
+        PdfArray::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;
+                if( it->IsReference() )
+                    return this->GetObject()->GetOwner()->GetObject( (*it).GetReference() );
+
+                return &(*it);
+            }
+
+            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->MustGetIndirectKey("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->MustGetIndirectKey("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->MustGetIndirectKey("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;
+            // fixes (security) issue #39 in PoDoFo's tracker (sourceforge.net)
+            if ( it == names.end() )
+            {
+                PdfError::LogMessage( eLogSeverity_Warning,
+                                "No reference in /Names array last element in "
+                                "object %lu %lu, possible\nexploit attempt!\n",
+                                pObj->Reference().ObjectNumber(),
+                                pObj->Reference().GenerationNumber() );
+                break;
+            }
+            rDict.AddKey( name, (*it) );
+            ++it;
+        }
+        
+    }
+
+}
+
+};
+
diff --git a/src/podofo/doc/PdfNamesTree.h b/src/podofo/doc/PdfNamesTree.h
new file mode 100644 (file)
index 0000000..27a1f74
--- /dev/null
@@ -0,0 +1,184 @@
+/***************************************************************************
+ *   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_
diff --git a/src/podofo/doc/PdfOutlines.cpp b/src/podofo/doc/PdfOutlines.cpp
new file mode 100644 (file)
index 0000000..2a48d89
--- /dev/null
@@ -0,0 +1,409 @@
+/***************************************************************************
+ *   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()->MustGetObject( first ), this, NULL );
+    }
+
+    if( this->GetObject()->GetDictionary().HasKey( "Next" ) )
+    {
+        next     = this->GetObject()->GetDictionary().GetKey("Next")->GetReference();
+        PdfObject* pObj = pObject->GetOwner()->MustGetObject( next );
+
+        m_pNext  = new PdfOutlineItem( pObj, pParentOutline, 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->InsertChildInternal( pItem, false );
+
+    return pItem;
+}
+
+void PdfOutlineItem::InsertChild( PdfOutlineItem* pItem )
+{
+    this->InsertChildInternal( pItem, true );
+}
+
+void PdfOutlineItem::InsertChildInternal( PdfOutlineItem* pItem, bool bCheckParent )
+{
+    PdfOutlineItem* pItemToCheckParent = pItem;
+    PdfOutlineItem* pRoot = NULL;
+    PdfOutlineItem* pRootOfThis = NULL;
+
+    if ( !pItemToCheckParent )
+        return;
+
+    if( bCheckParent )
+    {
+        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 ) // later 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()->MustGetIndirectKey( "Title" )->GetString();
+}
+
+void PdfOutlineItem::SetTextFormat( EPdfOutlineFormat eFormat )
+{
+    this->GetObject()->GetDictionary().AddKey( "F", static_cast<pdf_int64>(eFormat) );
+}
+
+EPdfOutlineFormat PdfOutlineItem::GetTextFormat() const
+{
+    if( this->GetObject()->GetDictionary().HasKey( "F" ) )
+        return static_cast<EPdfOutlineFormat>(this->GetObject()->MustGetIndirectKey( "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()->MustGetIndirectKey( "C" )->GetArray()[0].GetReal();
+
+    return 0.0;
+}
+
+double PdfOutlineItem::GetTextColorGreen() const
+{
+    if( this->GetObject()->GetDictionary().HasKey( "C" ) )
+        return this->GetObject()->MustGetIndirectKey( "C" )->GetArray()[1].GetReal();
+
+    return 0.0;
+}
+
+double PdfOutlineItem::GetTextColorBlue() const
+{
+    if( this->GetObject()->GetDictionary().HasKey( "C" ) )
+        return this->GetObject()->MustGetIndirectKey( "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() ) );
+}
+
+};
diff --git a/src/podofo/doc/PdfOutlines.h b/src/podofo/doc/PdfOutlines.h
new file mode 100644 (file)
index 0000000..3805692
--- /dev/null
@@ -0,0 +1,347 @@
+/***************************************************************************
+ *   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 );
+
+    void InsertChildInternal( PdfOutlineItem* pItem, bool bCheckParent );
+
+ 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_
diff --git a/src/podofo/doc/PdfPage.cpp b/src/podofo/doc/PdfPage.cpp
new file mode 100644 (file)
index 0000000..404412c
--- /dev/null
@@ -0,0 +1,770 @@
+/***************************************************************************
+ *   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 "base/PdfColor.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<PdfObject*> & rListOfParents )
+    : PdfElement( "Page", pObject ), PdfCanvas()
+{
+    m_pResources = this->GetObject()->GetIndirectKey( "Resources" );
+    if( !m_pResources ) 
+    {
+        // Resources might be inherited
+        std::deque<PdfObject*>::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 ait, aend = m_mapAnnotations.end();
+
+    for( ait = m_mapAnnotations.begin(); ait != aend; ait++ )
+    {
+        delete (*ait).second;
+    }
+
+    TIMapAnnotationDirect dit, dend = m_mapAnnotationsDirect.end();
+
+    for( dit = m_mapAnnotationsDirect.begin(); dit != dend; dit++ )
+    {
+        delete (*dit).second;
+    }
+
+    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<PdfPage*>(this)->CreateContents();
+    }
+
+    return m_pContents->GetContents(); 
+}
+
+PdfObject* PdfPage::GetContentsForAppending() const
+{ 
+    if( !m_pContents ) 
+    {
+        const_cast<PdfPage*>(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, int depth ) const
+{
+    const PdfObject* pObj = NULL;
+
+    // check for it in the object itself
+    if ( inObject->GetDictionary().HasKey( inKey ) ) 
+    {
+        pObj = inObject->MustGetIndirectKey( 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" ) ) 
+    {
+        // CVE-2017-5852 - prevent stack overflow if Parent chain contains a loop, or is very long
+        // e.g. pObj->GetParent() == pObj or pObj->GetParent()->GetParent() == pObj
+        // default stack sizes
+        // Windows: 1 MB
+        // Linux: 2 MB
+        // macOS: 8 MB for main thread, 0.5 MB for secondary threads
+        // 0.5 MB is enough space for 1000 512 byte stack frames and 2000 256 byte stack frames
+        const int maxRecursionDepth = 1000;
+
+        if ( depth > maxRecursionDepth )
+            PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange );
+
+        pObj = inObject->GetIndirectKey( "Parent" );
+        if( pObj == inObject )
+        {
+            std::ostringstream oss;
+            oss << "Object " << inObject->Reference().ObjectNumber() << " "
+                << inObject->Reference().GenerationNumber() << " references itself as Parent";
+            PODOFO_RAISE_ERROR_INFO( ePdfError_BrokenFile, oss.str().c_str() );
+        }
+
+        if( pObj )
+            pObj = GetInheritedKeyFromObject( inKey, pObj, depth + 1 );
+    }
+
+    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() );
+    
+    // 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<int>(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<pdf_int64>(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<PdfObject*>(this->GetObject()->GetDictionary().GetKey( "Annots" ));
+    }
+
+    return NULL;
+}
+
+int PdfPage::GetNumAnnots() const
+{
+    PdfObject* pObj = this->GetAnnotationsArray();
+
+    return pObj ? static_cast<int>(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<unsigned int>(index) >= pObj->GetArray().size() )
+    {
+        PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange );
+    }
+
+    PdfObject* pItem = &(pObj->GetArray()[index]);
+    if( pItem->IsDictionary() )
+    {
+        pAnnot = m_mapAnnotationsDirect[pItem];
+        if( !pAnnot )
+        {
+            pAnnot = new PdfAnnotation( pItem, this );
+            m_mapAnnotationsDirect[pItem] = pAnnot;
+        }
+    }
+    else
+    {
+        ref = pItem->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 )
+{
+    PdfObject* pObj = this->GetAnnotationsArray( false );
+    PdfObject* pItem;
+
+    if( !(pObj && pObj->IsArray()) )
+    {
+        PODOFO_RAISE_ERROR( ePdfError_InvalidDataType );
+    }
+
+    if( index < 0 && static_cast<unsigned int>(index) >= pObj->GetArray().size() )
+    {
+        PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange );
+    }
+
+    pItem = &(pObj->GetArray()[index]);
+
+    if( pItem->IsDictionary() )
+    {
+        PdfAnnotation* pAnnot;
+
+        pObj->GetArray().erase( pObj->GetArray().begin() + index );
+
+        // delete any cached PdfAnnotations
+        pAnnot = m_mapAnnotationsDirect[pItem];
+        if( pAnnot )
+        {
+            delete pAnnot;
+            m_mapAnnotationsDirect.erase( pItem );
+        }
+    }
+    else
+    {
+        this->DeleteAnnotation( pItem->GetReference() );
+    }
+}
+
+void PdfPage::DeleteAnnotation( const PdfReference & ref )
+{
+    PdfAnnotation*     pAnnot;
+    PdfArray::iterator it;
+    PdfObject*         pObj   = this->GetAnnotationsArray( false );
+    bool               bFound = false;
+
+    // find the array iterator pointing to the annotation, so it can be deleted later
+
+    if( !(pObj && pObj->IsArray()) )
+    {
+        PODOFO_RAISE_ERROR( ePdfError_InvalidDataType );
+    }
+
+    it = pObj->GetArray().begin();
+    while( it != pObj->GetArray().end() ) 
+    {
+        if( (*it).IsReference() && (*it).GetReference() == ref ) 
+        {
+            // Element may not be deleted from the array at this point, because doing
+            // this invalidates all PdfReferences references derived from the array.
+            // This includes the 'ref' parameter, when it is never copied by value,
+            // as it happens when this function is called via DeleteAnnotation( int )!
+            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 );
+    
+    // Delete the annotation from the annotation array.
+       // Has to be performed at last, since it will invalidate 'ref' when
+       // it was derived from the array itself and never copied by value!
+    pObj->GetArray().erase( it );
+}
+
+// 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<PdfObject*>(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<PdfObject*>(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<PdfObject*>(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<PdfObject*>(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();
+
+    // CVE-2017-5852 - prevent infinite loop if Parent chain contains a loop
+    // e.g. pParent->GetIndirectKey( "Parent" ) == pParent or pParent->GetIndirectKey( "Parent" )->GetIndirectKey( "Parent" ) == pParent
+    const int maxRecursionDepth = 1000;
+    int depth = 0;
+
+    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)
+                {
+                    std::ostringstream oss;
+                    oss << "Object " << (*it).GetReference().ToString() << " not found from Kids array "
+                        << pKids->Reference().ToString(); 
+                    PODOFO_RAISE_ERROR_INFO( ePdfError_NoObject, oss.str() );
+                }
+
+                if( pNode->GetDictionary().HasKey( PdfName::KeyType )
+                    && pNode->MustGetIndirectKey( PdfName::KeyType )->GetName() == PdfName( "Pages" ) )
+                {
+                    PdfObject* pCount = pNode->GetIndirectKey( "Count" );
+                    if( pCount != NULL ) {
+                        nPageNumber += static_cast<int>(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" );
+        ++depth;
+
+        if ( depth > maxRecursionDepth )
+        {
+            PODOFO_RAISE_ERROR_INFO( ePdfError_BrokenFile, "Loop in Parent chain" );
+        }
+    }
+
+    return ++nPageNumber;
+}
+
+int PdfPage::GetNumFields() const
+{
+    int                  nCount  = 0;
+    int                  nAnnots = this->GetNumAnnots();
+    const PdfAnnotation* pAnnot  = NULL;
+    for( int i=0;i<nAnnots;i++ )
+    {
+        pAnnot = const_cast<PdfPage*>(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;i<nAnnots;i++ )
+    {
+        pAnnot = this->GetAnnotation( 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<PdfPage*>(this)->GetField( index );
+    return field;
+}
+
+PdfObject* PdfPage::GetFromResources( const PdfName & rType, const PdfName & rKey )
+{
+    if( m_pResources == NULL ) // Fix CVE-2017-7381
+    {
+        PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "No Resources" );
+    } 
+    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 && pType->IsDictionary() && pType->GetDictionary().HasKey( rKey ) )
+        {
+            PdfObject* pObj = pType->GetDictionary().GetKey( rKey ); // CB 08.12.2017 Can be an array
+            if (pObj->IsReference())
+            {
+                const PdfReference & ref = pType->GetDictionary().GetKey( rKey )->GetReference();
+                return this->GetObject()->GetOwner()->GetObject( ref );
+            }
+            return pObj; // END
+        }
+    }
+    
+    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->IsArray() )
+         return pObj;
+    }
+    else if( bCreate ) 
+    {
+        PdfArray array;
+        this->GetNonConstObject()->GetDictionary().AddKey( "Annots", array );
+        return const_cast<PdfObject*>(this->GetObject()->GetDictionary().GetKey( "Annots" ));
+    }
+
+    return NULL;
+}
+
+void PdfPage::SetICCProfile( const char *pszCSTag, PdfInputStream *pStream, pdf_int64 nColorComponents, EPdfColorSpace eAlternateColorSpace )
+{
+    // Check nColorComponents for a valid value
+    if ( nColorComponents != 1 &&
+         nColorComponents != 3 &&
+         nColorComponents != 4 )
+    {
+        PODOFO_RAISE_ERROR_INFO( ePdfError_ValueOutOfRange, "SetICCProfile nColorComponents must be 1, 3 or 4!" );
+    }
+
+    // Create a colorspace object
+    PdfObject* iccObject = this->GetObject()->GetOwner()->CreateObject();
+    PdfName nameForCS = PdfColor::GetNameForColorSpace( eAlternateColorSpace );
+    iccObject->GetDictionary().AddKey( PdfName("Alternate"), nameForCS );
+    iccObject->GetDictionary().AddKey( PdfName("N"), nColorComponents );
+    iccObject->GetStream()->Set( pStream );
+
+    // Add the colorspace
+    PdfArray array;
+    array.push_back( PdfName("ICCBased") );
+    array.push_back( iccObject->Reference() );
+
+    PoDoFo::PdfDictionary iccBasedDictionary;
+    iccBasedDictionary.AddKey( PdfName(pszCSTag), array );
+
+    // Add the colorspace to resource
+    GetResources()->GetDictionary().AddKey( PdfName("ColorSpace"), iccBasedDictionary );
+}
+
+
+};
diff --git a/src/podofo/doc/PdfPage.h b/src/podofo/doc/PdfPage.h
new file mode 100644 (file)
index 0000000..f1f4e76
--- /dev/null
@@ -0,0 +1,352 @@
+/***************************************************************************
+ *   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;
+class PdfInputStream;
+
+typedef std::map<PdfReference,PdfAnnotation*> TMapAnnotation;
+typedef TMapAnnotation::iterator              TIMapAnnotation;
+typedef TMapAnnotation::const_iterator        TCIMapAnnotation;
+typedef std::map<PdfObject *,PdfAnnotation*>  TMapAnnotationDirect;
+typedef TMapAnnotationDirect::iterator        TIMapAnnotationDirect;
+typedef TMapAnnotationDirect::const_iterator  TCIMapAnnotationDirect;
+
+/** 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<PdfObject*> & 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);
+
+    /** Set an ICC profile for this page
+     *
+     *  \param pszCSTag a ColorSpace tag
+     *  \param pStream an input stream from which the ICC profiles data can be read
+     *  \param nColorComponents the number of colorcomponents of the ICC profile (expected is 1, 3 or 4 components)
+     *  \param eAlternateColorSpace an alternate colorspace to use if the ICC profile cannot be used
+     *
+     *  \see PdfPainter::SetDependICCProfileColor()
+     */
+    virtual void SetICCProfile( const char* pszCSTag, PdfInputStream* pStream, pdf_int64 nColorComponents,
+                                EPdfColorSpace eAlternateColorSpace = ePdfColorSpace_DeviceRGB );
+ 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, int depth = 0 ) 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;
+    TMapAnnotationDirect m_mapAnnotationsDirect;
+};
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+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_
diff --git a/src/podofo/doc/PdfPagesTree.cpp b/src/podofo/doc/PdfPagesTree.cpp
new file mode 100644 (file)
index 0000000..a1da196
--- /dev/null
@@ -0,0 +1,766 @@
+/***************************************************************************
+ *   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 <algorithm>
+
+#include "base/PdfArray.h"
+#include "base/PdfDictionary.h"
+#include "base/PdfObject.h"
+#include "base/PdfOutputDevice.h"
+#include "base/PdfVecObjects.h"
+
+#include "PdfPage.h"
+
+#include <iostream>
+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<pdf_int64>(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;i<this->GetTotalNumberOfPages();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<PdfObject*>& 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() );
+
+    int pageCount;
+    if ( atIndex < 0 )
+        atIndex = 0;
+    else if ( atIndex > ( pageCount = this->GetTotalNumberOfPages() ) )
+        atIndex = pageCount;
+
+    InsertPage( atIndex - 1, pPage );
+    m_cache.AddPageObject( atIndex, pPage );
+
+    return pPage;
+}
+
+void PdfPagesTree::CreatePages( const std::vector<PdfRect>& vecSizes )
+{
+    std::vector<PdfPage*> vecPages;
+    std::vector<PdfObject*> vecObjects;
+    for (std::vector<PdfRect>::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 numKids = GetChildCount(pParent);
+
+    // use <= since nPageNum is 0-based
+    if( static_cast<int>(numKids) <= nPageNum ) 
+    {
+        PdfError::LogMessage( eLogSeverity_Critical,
+           "Cannot retrieve page %i from a document with only %i pages.",
+                              nPageNum, static_cast<int>(numKids) );
+        return NULL;
+    }
+
+    //printf("Fetching: %i %i\n", numKids, nPageNum );
+
+    // We have to traverse the tree
+    //
+    // BEWARE: There is no valid shortcut for tree traversal.
+    // Even if eKidsArray.size()==numKids, this does not imply that
+    // eKidsArray can be accessed with the index of the page directly.
+    // The tree could have an arbitrary complex structure because
+    // internal nodes with no leaves (page objects) are not forbidden
+    // by the PDF spec.
+    while( it != rKidsArray.end() ) 
+    {
+        if(!(*it).IsReference() ) 
+        {
+            PdfError::LogMessage( eLogSeverity_Critical, "Requesting page index %i. Invalid datatype in kids array: %s\n", 
+                                  nPageNum, (*it).GetDataTypeString()); 
+            return NULL;
+        }
+
+                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 tree node
+                        // and go to the next child in rKidsArray
+                        nPageNum -= childCount;
+                    }
+                    else
+                    {
+                        // page is in the subtree of pChild
+                        // => call GetPageNode() recursively
+                        
+                        rLstParents.push_back( pParent );
+
+                        if ( std::find( rLstParents.begin(), rLstParents.end(), pChild )
+                             != rLstParents.end() ) // cycle in parent list detected, fend
+                        { // off security vulnerability similar to CVE-2017-8054 (infinite recursion)
+                            std::ostringstream oss;
+                            oss << "Cycle in page tree: child in /Kids array of object "
+                                << ( *(rLstParents.rbegin()) )->Reference().ToString()
+                                << " back-references to object " << pChild->Reference()
+                                .ToString() << " one of whose descendants the former is.";
+                            PODOFO_RAISE_ERROR_INFO( ePdfError_PageNotFound, oss.str() );
+                        }
+
+                        return this->GetPageNode( nPageNum, pChild, rLstParents );
+                    }
+                }
+                else if( this->IsTypePage(pChild) ) 
+                {
+                    if( 0 == nPageNum )
+                    {
+                        // page found
+                        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);
+                    return NULL;
+                }
+            
+            ++it;
+        }
+
+    return NULL;
+}
+
+bool PdfPagesTree::IsTypePage(const PdfObject* pObject) const 
+{
+    if( !pObject )
+        return false;
+
+    if( pObject->GetIndirectKeyAsName( PdfName( "Type" ) ) == PdfName( "Page" ) )
+        return true;
+
+    return false;
+}
+
+bool PdfPagesTree::IsTypePages(const PdfObject* pObject) const 
+{
+    if( !pObject )
+        return false;
+
+    if( pObject->GetIndirectKeyAsName( 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<int>( 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->MustGetIndirectKey( 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->MustGetIndirectKey( 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<PdfObject*>& 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->MustGetIndirectKey( 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<PdfObject*>::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<int>(oldKids.size())) ) 
+    {
+        for (std::vector<PdfObject*>::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<PdfObject*>::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->MustGetIndirectKey( 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<pdf_int64>(cnt) ) );
+    }
+
+    return cnt ;
+}
+
+bool PdfPagesTree::IsEmptyPageNode( PdfObject* pPageNode ) 
+{
+    long lCount = GetChildCount( pPageNode );
+    bool bKidsEmpty = true;
+
+    if( pPageNode->GetDictionary().HasKey( PdfName("Kids") ) )
+    {
+        bKidsEmpty = pPageNode->MustGetIndirectKey( PdfName("Kids") )->GetArray().empty();
+    }
+
+    return ( lCount == 0L || bKidsEmpty );
+}
+
+/*
+PdfObject* PdfPagesTree::GetPageNode( int nPageNum, PdfObject* pPagesObject, 
+                                      std::deque<PdfObject*> & 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<int>(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;
+}
+*/
+
+};
diff --git a/src/podofo/doc/PdfPagesTree.h b/src/podofo/doc/PdfPagesTree.h
new file mode 100644 (file)
index 0000000..129daa5
--- /dev/null
@@ -0,0 +1,315 @@
+/***************************************************************************
+ *   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<PdfObject*>& 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<PdfRect>& 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 );
+
+    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<PdfObject*>& 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<PdfObject*> & 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<PdfObject*> & 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_
+
+
diff --git a/src/podofo/doc/PdfPagesTreeCache.cpp b/src/podofo/doc/PdfPagesTreeCache.cpp
new file mode 100644 (file)
index 0000000..775ea38
--- /dev/null
@@ -0,0 +1,146 @@
+/***************************************************************************
+ *   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<int>(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<int>(m_deqPageObjs.size()) )
+    {
+        m_deqPageObjs.resize( nIndex + 1 );
+    }
+
+    m_deqPageObjs[nIndex] = pPage;
+}
+
+void PdfPagesTreeCache::AddPageObjects( int nIndex, std::vector<PdfPage*> vecPages )
+{
+    if( (nIndex + static_cast<int>(vecPages.size())) >= static_cast<int>(m_deqPageObjs.size()) )
+    {
+        m_deqPageObjs.resize( nIndex + vecPages.size() + 1 );
+    }
+    
+    for (size_t i=0; i<vecPages.size(); ++i)
+    {
+        // Delete any old pages if it is at the same position
+        PdfPage* pOldPage = GetPage( nIndex + i );
+        delete pOldPage;
+
+        // Assign the new page
+        m_deqPageObjs[nIndex + i]  = vecPages.at(i);
+    }
+}
+
+void PdfPagesTreeCache::InsertPage( int nAfterPageIndex ) 
+{
+    const int nBeforeIndex = ( nAfterPageIndex == ePdfPageInsertionPoint_InsertBeforeFirstPage ) ? 0 : nAfterPageIndex+1;
+
+    if( nBeforeIndex >= static_cast<int>(m_deqPageObjs.size()) )
+        m_deqPageObjs.resize( nBeforeIndex + 1 );
+
+    m_deqPageObjs.insert( m_deqPageObjs.begin() + nBeforeIndex, static_cast<PdfPage*>(NULL) );
+}
+
+void PdfPagesTreeCache::InsertPages( int nAfterPageIndex, int nCount ) 
+{
+    const int nBeforeIndex = ( nAfterPageIndex == ePdfPageInsertionPoint_InsertBeforeFirstPage ) ? 0 : nAfterPageIndex+1;
+
+    if( nBeforeIndex+nCount >= static_cast<int>(m_deqPageObjs.size()) )
+        m_deqPageObjs.resize( nBeforeIndex + nCount + 1 );
+
+    for (int i=0; i<nCount; ++i)
+        m_deqPageObjs.insert( m_deqPageObjs.begin() + nBeforeIndex + i, static_cast<PdfPage*>(NULL) );
+}
+
+void PdfPagesTreeCache::DeletePage( int nIndex )
+{
+    if( nIndex < 0 || nIndex >= static_cast<int>(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();
+}
+
+};
diff --git a/src/podofo/doc/PdfPagesTreeCache.h b/src/podofo/doc/PdfPagesTreeCache.h
new file mode 100644 (file)
index 0000000..e45e713
--- /dev/null
@@ -0,0 +1,131 @@
+/***************************************************************************
+ *   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<PdfPage*> 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_
+
+
diff --git a/src/podofo/doc/PdfPainter.cpp b/src/podofo/doc/PdfPainter.cpp
new file mode 100644 (file)
index 0000000..22be9aa
--- /dev/null
@@ -0,0 +1,2042 @@
+/***************************************************************************
+ *   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 <iostream>
+#include <iomanip>
+#include <vector>
+
+#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 <stdlib.h>
+
+#define BEZIER_POINTS 13
+
+/* 4/3 * (1-cos 45\e,A0\e(B)/sin 45\e,A0\e(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 iswspace( SwapCharBytesIfRequired(ch) ) != 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_isCurColorICCDepend( false ), m_CSTag()
+{
+    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!" );
+
+    #ifdef DEBUG
+    PODOFO_ASSERT( !m_pCanvas );
+    #endif
+}
+
+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_isCurColorICCDepend = false;
+
+    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<int>(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<int>(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<int>(dRoundX) || static_cast<int>(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;i<BEZIER_POINTS; i+=3 )
+    {
+        m_curPath
+                                 << dPointX[i] << " "
+              << dPointY[i] << " "
+              << dPointX[i+1] << " "
+              << dPointY[i+1] << " "
+              << dPointX[i+2] << " "
+              << dPointY[i+2]    
+              << " c" << std::endl;
+
+        m_oss << dPointX[i] << " "
+              << dPointY[i] << " "
+              << dPointX[i+1] << " "
+              << dPointY[i+1] << " "
+              << dPointX[i+2] << " "
+              << dPointY[i+2]    
+              << " c" << std::endl;
+    }
+
+    m_pCanvas->Append( 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<long>(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;
+    PODOFO_UNIQUEU_PTR<PdfFilter> 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, bool bSkipSpaces )
+{
+    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<PdfString> vecLines = GetMultiLineTextAsLines( dWidth, sString, bSkipSpaces );
+    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<PdfString>::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<PdfString> PdfPainter::GetMultiLineTextAsLines( double dWidth, const PdfString & rsText, bool bSkipSpaces )
+{
+    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<PdfString>();
+    
+    if( rsText.GetCharacterLength() == 0 ) // empty string
+        return std::vector<PdfString>(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<pdf_utf16be> stringUtf16(stringUtf8.length() + 1, 0);
+    PODOFO_ASSERT( stringUtf16.size() > 0 );
+    const pdf_long converted = PdfString::ConvertUTF8toUTF16(
+           reinterpret_cast<const pdf_utf8*>(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<PdfString> 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 ) );
+                    if (bSkipSpaces)
+                    {
+                        // Skip all spaces at the end of the line
+                        while( IsSpaceChar( *( pszCurrentCharacter + 1 ) ) )
+                            pszCurrentCharacter++;
+
+                        pszStartOfCurrentWord = pszCurrentCharacter + 1;
+                    }
+                    else
+                    {
+                        pszStartOfCurrentWord = pszCurrentCharacter;
+                    }
+                    startOfWord=true;
+                }
+                pszLineBegin = pszStartOfCurrentWord;
+
+                if (!startOfWord)
+                {
+                    dCurWidthOfLine = m_pFont->GetFontMetrics()->StringWidth( 
+                                               pszStartOfCurrentWord, pszCurrentCharacter - pszStartOfCurrentWord );
+                }
+                else
+                {
+                    dCurWidthOfLine = 0.0;
+                }
+            }
+            else if( ( dCurWidthOfLine + m_pFont->GetFontMetrics()->UnicodeCharWidth( SwapCharBytesIfRequired( *pszCurrentCharacter ) ) ) > dWidth )
+            {
+                vecLines.push_back( PdfString( pszLineBegin, pszCurrentCharacter - pszLineBegin ) );
+                if( bSkipSpaces )
+                {
+                    // Skip all spaces at the end of the line
+                    while( IsSpaceChar( *( pszCurrentCharacter + 1 ) ) )
+                        pszCurrentCharacter++;
+
+                    pszStartOfCurrentWord = pszCurrentCharacter + 1;
+                }
+                else
+                {
+                    pszStartOfCurrentWord = pszCurrentCharacter;
+                }
+                pszLineBegin = pszStartOfCurrentWord;
+                startOfWord = true;
+                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<int>(pGlyphFont->GetFontMetrics()->GetGlyphWidth( pszGlyphname ) );
+                       pEncoding = pDocument->GetObjects().CreateObject( "Encoding" );
+               
+                       code++;
+               
+                       PdfArray diffs;
+                       diffs.push_back( PdfVariant( static_cast<pdf_int64>( 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->MustGetIndirectKey( "Widths" );
+                       PdfArray & rWidthArr = pWidthObj->GetArray();
+                       for ( unsigned int i = 0; i < rWidthArr.size(); i++ )
+                       {
+                               rWidthArr[i] = PdfVariant( static_cast<pdf_int64>( 0 ) );
+                       }
+                       rWidthArr[code] = PdfVariant( static_cast<pdf_int64>( 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->MustGetIndirectKey( "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<int>(pGlyphFont->GetFontMetrics()->GetGlyphWidth( pszGlyphname ) );
+
+                       code++;
+
+                       PdfArray diffs;
+            diffs = pEncoding->MustGetIndirectKey( "Differences" )->GetArray();
+                       diffs.push_back( PdfName( pszGlyphname ) );
+
+                       pEncoding->GetDictionary().AddKey( "Differences", diffs );
+
+                       // enter width of glyph
+            PdfObject* pWidthObj = pGlyphFontObj->MustGetIndirectKey( "Widths" );
+                       PdfArray & rWidthArr = pWidthObj->GetArray();
+                       rWidthArr[code] = PdfVariant( static_cast<pdf_int64>( 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, 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<int>(ceil (fabs (th_arc / (PI * 0.5 + 0.001))));
+
+    for (i = 0; i < n_segs; i++) {
+        double nth0 = th0 + static_cast<double>(i) * th_arc / n_segs,
+               nth1 = th0 + static_cast<double>(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<double>(ang1 + ang2) / 2.0f) / 180.0f * PI;
+    double new_angle = static_cast<double>(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()
+{
+    if ( m_isCurColorICCDepend )
+    {
+        m_oss.str("");
+        m_oss << "/" << m_CSTag     << " CS ";
+        m_oss << m_curColor.GetRed()   << " "
+              << m_curColor.GetGreen() << " "
+              << m_curColor.GetBlue()
+              << " SC" << std::endl;
+        m_pCanvas->Append( m_oss.str() );
+    }
+    else
+    {
+        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() );
+}
+
+void PdfPainter::SetDependICCProfileColor( const PdfColor &rColor, const std::string &pCSTag )
+{
+    m_isCurColorICCDepend = true;
+    m_curColor = rColor;
+    m_CSTag = pCSTag;
+
+    m_oss.str("");
+    m_oss << "/" << m_CSTag << " cs ";
+    m_oss << rColor.GetRed()   << " "
+          << rColor.GetGreen() << " "
+          << rColor.GetBlue()
+          << " sc" << 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<char*>(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<m_nTabWidth; z++ )
+                pszTab[i+z] = cSpace;
+            
+            i+=m_nTabWidth;
+        }
+        else
+            pszTab[i++] = *pszText;
+        
+        ++pszText;
+    }
+    
+    pszTab[i]  = 0;
+    PdfString str( pszTab );
+    podofo_free( pszTab );
+    
+    return str;
+}
+
+PdfString PdfPainter::ExpandTabs_pdf_utf16be( const pdf_utf16be* pszText, long lStringLen, int nTabCnt, const pdf_utf16be cTab, const pdf_utf16be cSpace ) const
+{
+    long lLen    = lStringLen + nTabCnt*(m_nTabWidth-1) + sizeof(pdf_utf16be);
+    pdf_utf16be*   pszTab  = static_cast<pdf_utf16be*>(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<m_nTabWidth; z++ )
+                pszTab[i+z] = cSpace;
+            
+            i+=m_nTabWidth;
+        }
+        else
+            pszTab[i++] = *pszText;
+        
+        ++pszText;
+    }
+    
+    pszTab[i]  = 0;
+
+    PdfString str( pszTab );
+    podofo_free( pszTab );
+    
+    return str;
+}
+#else
+template<typename C>
+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<C*>(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<m_nTabWidth; z++ )
+                pszTab[i+z] = cSpace;
+            
+            i+=m_nTabWidth;
+        }
+        else
+            pszTab[i++] = *pszText;
+        
+        ++pszText;
+    }
+    
+    pszTab[i]  = 0;
+
+    PdfString str( pszTab );
+    podofo_free( pszTab );
+    
+    return str;
+}
+#endif
+
+PdfString PdfPainter::ExpandTabs( const PdfString & rsString, pdf_long lStringLen ) const
+{
+    int               nTabCnt  = 0;
+    int               i;
+    bool              bUnicode = rsString.IsUnicode();
+    const pdf_utf16be cTab     = 0x0900;
+    const pdf_utf16be cSpace   = 0x2000;
+
+    if( lStringLen == -1 )
+        lStringLen = rsString.GetCharacterLength();
+
+    if (lStringLen > rsString.GetCharacterLength())
+    {
+        PdfError::DebugMessage( "Requested to expand tabs in string of %" PDF_FORMAT_INT64 " chars, while it has only %" PDF_FORMAT_INT64 "; correcting the value\n",
+            static_cast<pdf_int64>( lStringLen ), static_cast<pdf_int64>( rsString.GetCharacterLength() ) );
+
+        lStringLen = rsString.GetCharacterLength();
+    }
+
+    // count the number of tabs in the string
+    if( bUnicode ) 
+    {
+        for( i=0;i<lStringLen;i++ )
+            if( rsString.GetUnicode()[i] == cTab ) 
+                ++nTabCnt;
+    }
+    else
+    {
+        for( i=0;i<lStringLen;i++ )
+            if( rsString.GetString()[i] == '\t' )
+                ++nTabCnt;
+    }
+
+    // if no tabs are found: bail out!
+    if( !nTabCnt )
+        return rsString;
+    
+#if defined(_MSC_VER)  &&  _MSC_VER <= 1200    // MSC 6.0 has a template-bug
+    if( rsString.IsUnicode() )
+        return ExpandTabs_pdf_utf16be( rsString.GetUnicode(), lStringLen, nTabCnt, cTab, cSpace );
+    else
+        return ExpandTabs_char( rsString.GetString(), lStringLen, nTabCnt, '\t', ' ' );
+#else
+    if( rsString.IsUnicode() )
+        return ExpandTabsPrivate<pdf_utf16be>( rsString.GetUnicode(), lStringLen, nTabCnt, cTab, cSpace );
+    else
+        return ExpandTabsPrivate<char>( rsString.GetString(), lStringLen, nTabCnt, '\t', ' ' );
+#endif
+}
+
+} /* namespace PoDoFo */
+
diff --git a/src/podofo/doc/PdfPainter.h b/src/podofo/doc/PdfPainter.h
new file mode 100644 (file)
index 0000000..f64cf14
--- /dev/null
@@ -0,0 +1,996 @@
+/***************************************************************************
+ *   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 <sstream>
+
+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
+     *  \param bSkipSpaces whether the trailing whitespaces should be skipped, so that next line doesn't start with whitespace
+     */
+    void DrawMultiLineText( double dX, double dY, double dWidth, double dHeight, 
+                            const PdfString & rsText, EPdfAlignment eAlignment = ePdfAlignment_Left,
+                            EPdfVerticalAlignment eVertical = ePdfVerticalAlignment_Top, bool bClip = true, bool bSkipSpaces = 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
+     *  \param bSkipSpaces whether the trailing whitespaces should be skipped, so that next line doesn't start with whitespace
+     */
+    inline void DrawMultiLineText( const PdfRect & rRect, const PdfString & rsText, EPdfAlignment eAlignment = ePdfAlignment_Left,
+                                   EPdfVerticalAlignment eVertical = ePdfVerticalAlignment_Top, bool bClip = true, bool bSkipSpaces = 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
+     *  \param bSkipSpaces whether the trailing whitespaces should be skipped, so that next line doesn't start with whitespace
+     */
+    std::vector<PdfString> GetMultiLineTextAsLines( double dWidth, const PdfString & rsText, bool bSkipSpaces = true);
+
+    /** 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);
+
+    /** Set rgb color that depend on color space setting, "cs" tag.
+     *
+     * \param rColor a PdfColor object
+     * \param pCSTag a CS tag used in PdfPage::SetICCProfile
+     *
+     * \see PdfPage::SetICCProfile()
+     */
+    void SetDependICCProfileColor( const PdfColor & rColor, const std::string & pCSTag );
+
+ 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<typename C>
+        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;
+
+    /** True if should use color with ICC Profile
+     */
+    bool m_isCurColorICCDepend;
+    /** ColorSpace tag
+     */
+    std::string m_CSTag;
+
+    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<unsigned short>(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, bool bSkipSpaces )
+{
+    this->DrawMultiLineText( rRect.GetLeft(), rRect.GetBottom(), rRect.GetWidth(), rRect.GetHeight(), 
+                             rsText, eAlignment, eVertical, bClip, bSkipSpaces );
+}
+
+};
+
+#endif // _PDF_PAINTER_H_
diff --git a/src/podofo/doc/PdfPainterMM.cpp b/src/podofo/doc/PdfPainterMM.cpp
new file mode 100644 (file)
index 0000000..4d425e8
--- /dev/null
@@ -0,0 +1,47 @@
+/***************************************************************************
+ *   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()
+{
+}
+
+};
diff --git a/src/podofo/doc/PdfPainterMM.h b/src/podofo/doc/PdfPainterMM.h
new file mode 100644 (file)
index 0000000..6ca0f43
--- /dev/null
@@ -0,0 +1,269 @@
+/***************************************************************************
+ *   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<double>(lWidth) * CONVERSION_CONSTANT );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfPainterMM::DrawLineMM( long lStartX, long lStartY, long lEndX, long lEndY )
+{
+    this->DrawLine( static_cast<double>(lStartX) * CONVERSION_CONSTANT,
+                    static_cast<double>(lStartY) * CONVERSION_CONSTANT,
+                    static_cast<double>(lEndX)   * CONVERSION_CONSTANT,
+                    static_cast<double>(lEndY)   * CONVERSION_CONSTANT );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfPainterMM::RectangleMM( long lX, long lY, long lWidth, long lHeight )
+{
+    this->Rectangle( static_cast<double>(lX)      * CONVERSION_CONSTANT,
+                       static_cast<double>(lY)      * CONVERSION_CONSTANT,
+                       static_cast<double>(lWidth)  * CONVERSION_CONSTANT,
+                       static_cast<double>(lHeight) * CONVERSION_CONSTANT );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfPainterMM::EllipseMM( long lX, long lY, long lWidth, long lHeight )
+{
+    this->Ellipse( static_cast<double>(lX)      * CONVERSION_CONSTANT,
+                       static_cast<double>(lY)      * CONVERSION_CONSTANT,
+                       static_cast<double>(lWidth)  * CONVERSION_CONSTANT,
+                       static_cast<double>(lHeight) * CONVERSION_CONSTANT );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfPainterMM::DrawTextMM( long lX, long lY, const PdfString & sText)
+{
+    this->DrawText( static_cast<double>(lX) * CONVERSION_CONSTANT,
+                    static_cast<double>(lY) * CONVERSION_CONSTANT,
+                    sText );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfPainterMM::DrawTextMM( long lX, long lY, const PdfString & sText, long lLen )
+{
+   this->DrawText( static_cast<double>(lX) * CONVERSION_CONSTANT,
+                   static_cast<double>(lY) * CONVERSION_CONSTANT,
+                   sText, lLen );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfPainterMM::DrawImageMM( long lX, long lY, PdfImage* pObject, double dScaleX, double dScaleY )
+{
+   this->DrawImage( static_cast<double>(lX) * CONVERSION_CONSTANT,
+                    static_cast<double>(lY) * CONVERSION_CONSTANT,
+                    pObject, dScaleX, dScaleY );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfPainterMM::DrawXObjectMM( long lX, long lY, PdfXObject* pObject, double dScaleX, double dScaleY )
+{
+   this->DrawXObject( static_cast<double>(lX) * CONVERSION_CONSTANT,
+                      static_cast<double>(lY) * CONVERSION_CONSTANT,
+                      pObject, dScaleX, dScaleY );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfPainterMM::LineToMM( long lX, long lY )
+{
+    this->LineTo( static_cast<double>(lX) * CONVERSION_CONSTANT,
+                  static_cast<double>(lY) * CONVERSION_CONSTANT );
+}
+
+// -----------------------------------------------------
+// 
+// -----------------------------------------------------
+inline void PdfPainterMM::MoveToMM( long lX, long lY )
+{
+    this->MoveTo( static_cast<double>(lX) * CONVERSION_CONSTANT,
+                  static_cast<double>(lY) * CONVERSION_CONSTANT );
+}
+
+
+};
+
+#endif // _PDF_PAINTER_MM_H_
diff --git a/src/podofo/doc/PdfShadingPattern.cpp b/src/podofo/doc/PdfShadingPattern.cpp
new file mode 100644 (file)
index 0000000..8a91f4c
--- /dev/null
@@ -0,0 +1,618 @@
+/***************************************************************************
+ *   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 <sstream>
+
+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<pdf_int64>(eShadingType) );
+
+    this->GetObject()->GetDictionary().AddKey( PdfName("PatternType"), static_cast<pdf_int64>(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());
+        }
+}
+
+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<char> ( rLL.GetRed() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rLL.GetGreen() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rLL.GetBlue() *255.0 ) );
+       
+                       samples.insert( samples.end(), static_cast<char> ( rLR.GetRed() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rLR.GetGreen() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rLR.GetBlue() *255.0 ) );
+       
+                       samples.insert( samples.end(), static_cast<char> ( rUL.GetRed() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rUL.GetGreen() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rUL.GetBlue() *255.0 ) );
+       
+                       samples.insert( samples.end(), static_cast<char> ( rUR.GetRed() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rUR.GetGreen() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( 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<char> ( rLL.GetCyan() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rLL.GetMagenta() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rLL.GetYellow() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rLL.GetBlack() *255.0 ) );
+       
+                       samples.insert( samples.end(), static_cast<char> ( rLR.GetCyan() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rLR.GetMagenta() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rLR.GetYellow() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rLR.GetBlack() *255.0 ) );
+       
+                       samples.insert( samples.end(), static_cast<char> ( rUL.GetCyan() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rUL.GetMagenta() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rUL.GetYellow() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rUL.GetBlack() *255.0 ) );
+       
+                       samples.insert( samples.end(), static_cast<char> ( rUR.GetCyan() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rUR.GetMagenta() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rUR.GetYellow() *255.0 ) );
+                       samples.insert( samples.end(), static_cast<char> ( 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<char> ( rLL.GetGrayScale() *255.0 ) );
+       
+                       samples.insert( samples.end(), static_cast<char> ( rLR.GetGrayScale() *255.0 ) );
+       
+                       samples.insert( samples.end(), static_cast<char> ( rUL.GetGrayScale() *255.0 ) );
+       
+                       samples.insert( samples.end(), static_cast<char> ( 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<char> ( rLL.GetCieL() *2.55 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rLL.GetCieA() +128 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rLL.GetCieB() +128 ) );
+
+                       samples.insert( samples.end(), static_cast<char> ( rLR.GetCieL() *2.55 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rLR.GetCieA() +128 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rLR.GetCieB() +128 ) );
+
+                       samples.insert( samples.end(), static_cast<char> ( rUL.GetCieL() *2.55 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rUL.GetCieA() +128 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rUL.GetCieB() +128 ) );
+
+                       samples.insert( samples.end(), static_cast<char> ( rUR.GetCieL() *2.55 ) );
+                       samples.insert( samples.end(), static_cast<char> ( rUR.GetCieA() +128 ) );
+                       samples.insert( samples.end(), static_cast<char> ( 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<char> ( rLL.GetDensity() *255.0 ) );
+
+                       samples.insert( samples.end(), static_cast<char> ( rLR.GetDensity() *255.0 ) );
+
+                       samples.insert( samples.end(), static_cast<char> ( rUL.GetDensity() *255.0 ) );
+
+                       samples.insert( samples.end(), static_cast<char> ( 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<pdf_int64>(0));
+       decode.push_back(static_cast<pdf_int64>(1));
+       decode.push_back(static_cast<pdf_int64>(0));
+       decode.push_back(static_cast<pdf_int64>(1));
+       decode.push_back(static_cast<pdf_int64>(0));
+       decode.push_back(static_cast<pdf_int64>(1));
+
+       PdfObject *shadingObject = this->GetObject()->GetIndirectKey(PdfName("Shading"));
+       PdfDictionary &shading = shadingObject->GetDictionary();
+
+       shading.AddKey( PdfName("ColorSpace"), PdfName("DeviceRGB") );
+       shading.AddKey( PdfName("BitsPerCoordinate"), static_cast<pdf_int64>(8));
+       shading.AddKey( PdfName("BitsPerComponent"), static_cast<pdf_int64>(8));
+       shading.AddKey( PdfName("BitsPerFlag"), static_cast<pdf_int64>(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<char>(255.0 * (dX0 - minx) / (maxx - minx));
+       buff[ 2] = static_cast<char>(255.0 * (dY0 - miny) / (maxy - miny));
+       buff[ 3] = static_cast<char>(255.0 * rgb0.GetRed());
+       buff[ 4] = static_cast<char>(255.0 * rgb0.GetGreen());
+       buff[ 5] = static_cast<char>(255.0 * rgb0.GetBlue());
+
+       buff[ 6] = 0; // flag - start new triangle
+       buff[ 7] = static_cast<char>(255.0 * (dX1 - minx) / (maxx - minx));
+       buff[ 8] = static_cast<char>(255.0 * (dY1 - miny) / (maxy - miny));
+       buff[ 9] = static_cast<char>(255.0 * rgb1.GetRed());
+       buff[10] = static_cast<char>(255.0 * rgb1.GetGreen());
+       buff[11] = static_cast<char>(255.0 * rgb1.GetBlue());
+
+       buff[12] = 0; // flag - start new triangle
+       buff[13] = static_cast<char>(255.0 * (dX2 - minx) / (maxx - minx));
+       buff[14] = static_cast<char>(255.0 * (dY2 - miny) / (maxy - miny));
+       buff[15] = static_cast<char>(255.0 * rgb2.GetRed());
+       buff[16] = static_cast<char>(255.0 * rgb2.GetGreen());
+       buff[17] = static_cast<char>(255.0 * rgb2.GetBlue());
+
+       shadingObject->GetStream()->Set(buff, len);
+}
+
+}      // end namespace
diff --git a/src/podofo/doc/PdfShadingPattern.h b/src/podofo/doc/PdfShadingPattern.h
new file mode 100644 (file)
index 0000000..d104a59
--- /dev/null
@@ -0,0 +1,302 @@
+/***************************************************************************
+ *   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_
+
diff --git a/src/podofo/doc/PdfSignOutputDevice.cpp b/src/podofo/doc/PdfSignOutputDevice.cpp
new file mode 100644 (file)
index 0000000..0a37e00
--- /dev/null
@@ -0,0 +1,245 @@
+/***************************************************************************
+ *   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 <string.h>
+
+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<char*>(podofo_malloc(lSignatureSize));
+       if (!pData)
+       {
+               PODOFO_RAISE_ERROR(ePdfError_OutOfMemory);
+    }
+    
+    for(size_t i=0; i<lSignatureSize; i++)
+    {
+        pData[i]=srcBeacon[i%lLen];
+    }
+    m_pSignatureBeacon = new PdfData(pData, lSignatureSize);
+    podofo_free(pData);
+}
+
+size_t PdfSignOutputDevice::GetSignatureSize()const
+{
+       return (m_pSignatureBeacon == NULL) ? 0 : ( m_pSignatureBeacon->data().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<pdf_int64>(0)) );
+    arr.push_back( PdfVariant(static_cast<pdf_int64>(m_sBeaconPos)) );
+    arr.push_back( PdfVariant(static_cast<pdf_int64>(m_sBeaconPos+m_pSignatureBeacon->data().size()+2) ) );
+    arr.push_back( PdfVariant(static_cast<pdf_int64>(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()<sPosSize)
+    {
+        // drop last ']'
+        sPosition.resize(sPosition.size()-1);
+        while(sPosition.size()<(sPosSize-1)) {
+            sPosition+=' ';
+        }
+        sPosition+=']';
+    }
+
+    m_pRealDevice->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(pos<m_sBeaconPos)
+       {
+               size_t readSize = PODOFO_MIN(lLen, m_sBeaconPos-pos);
+               if(readSize>0) {
+                       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);
+}
+
+}
+
diff --git a/src/podofo/doc/PdfSignOutputDevice.h b/src/podofo/doc/PdfSignOutputDevice.h
new file mode 100644 (file)
index 0000000..357b467
--- /dev/null
@@ -0,0 +1,145 @@
+/***************************************************************************
+ *   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
diff --git a/src/podofo/doc/PdfSignatureField.cpp b/src/podofo/doc/PdfSignatureField.cpp
new file mode 100644 (file)
index 0000000..c29c010
--- /dev/null
@@ -0,0 +1,262 @@
+/***************************************************************************
+ *   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 <string.h>
+
+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 = GetFieldObject()->GetIndirectKey( "V" );
+    }
+}
+
+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<char*>(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" ) );
+}
+
+}
diff --git a/src/podofo/doc/PdfSignatureField.h b/src/podofo/doc/PdfSignatureField.h
new file mode 100644 (file)
index 0000000..7616c72
--- /dev/null
@@ -0,0 +1,143 @@
+/***************************************************************************
+ *   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:
+     * <</ByteRange[ 0 1234567890 1234567890 1234567890]/Contents<signatureData>
+     * Have to be replaiced with the following structure:
+     * <</ByteRange[ 0 count pos count]/Contents<real signature ...0-padding>
+     */
+    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
diff --git a/src/podofo/doc/PdfStreamedDocument.cpp b/src/podofo/doc/PdfStreamedDocument.cpp
new file mode 100644 (file)
index 0000000..0036410
--- /dev/null
@@ -0,0 +1,86 @@
+/***************************************************************************
+ *   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();
+}
+
+
+
+};
diff --git a/src/podofo/doc/PdfStreamedDocument.h b/src/podofo/doc/PdfStreamedDocument.h
new file mode 100644 (file)
index 0000000..0e959b4
--- /dev/null
@@ -0,0 +1,341 @@
+/***************************************************************************
+ *   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_ */
diff --git a/src/podofo/doc/PdfTTFWriter.cpp b/src/podofo/doc/PdfTTFWriter.cpp
new file mode 100644 (file)
index 0000000..2108892
--- /dev/null
@@ -0,0 +1,1517 @@
+/***************************************************************************
+ *   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 <algorithm>
+#include <cmath>
+
+#include <ft2build.h>
+#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 <cmath> 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<double>(2.0f),static_cast<double>(x)); }
+#endif
+}
+
+namespace PoDoFo {
+
+extern bool podofo_is_little_endian();
+
+#define READ_TTF_USHORT( value ) { pDevice->Read( reinterpret_cast<char*>(&(value)), sizeof(pdf_ttf_ushort) ); \
+                                 if( podofo_is_little_endian() ) \
+                                     this->SwapUShort( &(value) ); }
+
+#define READ_TTF_SHORT( value )  { pDevice->Read( reinterpret_cast<char*>(&(value)), sizeof(pdf_ttf_short) ); \
+                                 if( podofo_is_little_endian() ) \
+                                     this->SwapShort( &(value) ); }
+
+#define READ_TTF_ULONG( value )  { pDevice->Read( reinterpret_cast<char*>(&(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<char*>(&(value)), sizeof(pdf_ttf_ushort) ); }
+
+#define WRITE_TTF_SHORT( value ) { { if( podofo_is_little_endian() ) \
+                                        this->SwapShort( &(value) ); } \
+                                      pDevice->Write( reinterpret_cast<char*>(&(value)), sizeof(pdf_ttf_short) ); }
+                                    
+#define WRITE_TTF_ULONG( value ) { { if( podofo_is_little_endian() ) \
+                                        this->SwapULong( &(value) ); } \
+                                      pDevice->Write( reinterpret_cast<char*>(&(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<int>('H') );
+    m_vecGlyphIndeces.push_back( static_cast<int>('a') );
+    m_vecGlyphIndeces.push_back( static_cast<int>('l') );
+    m_vecGlyphIndeces.push_back( static_cast<int>('o') );
+    m_vecGlyphIndeces.push_back( static_cast<int>(' ') );
+    m_vecGlyphIndeces.push_back( static_cast<int>('W') );
+    m_vecGlyphIndeces.push_back( static_cast<int>('r') );
+    m_vecGlyphIndeces.push_back( static_cast<int>('d') );
+    m_vecGlyphIndeces.push_back( static_cast<int>('!') );
+    // 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<int> & 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;i<m_tTableDirectory.numTables;i++ ) 
+    {
+        this->ReadTableDirectoryEntry( 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<char*>(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<char*>(&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<char*>(&m_tTableDirectory), sizeof(TTableDirectory) );
+}
+
+void PdfTTFWriter::ReadTableDirectoryEntry( PdfInputDevice* pDevice, TTableDirectoryEntry* pEntry ) 
+{
+    pDevice->Read( reinterpret_cast<char*>(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<char*>(&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<char*>(&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<char*>(&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<char*>(&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<char*>(&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<char*>(&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<char*>(&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<TCMapEntry> 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;i<nSegCount;i++ )
+        READ_TTF_USHORT( m_ranges[i].nEnd );
+
+    READ_TTF_USHORT( nReservedPad );
+
+    for( i=0;i<nSegCount;i++ )
+        READ_TTF_USHORT( m_ranges[i].nStart );
+
+    for( i=0;i<nSegCount;i++ )
+        READ_TTF_SHORT( m_ranges[i].nDelta );
+
+    for( i=0;i<nSegCount;i++ )
+    {
+        long lPos = pDevice->Tell();
+        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<pdf_ttf_short>(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;i<nSegCount;i++ ) 
+    {
+        printf("Range: %x - %x Delta: %6i Offset: %6u\n", m_ranges[i].nStart, m_ranges[i].nEnd, 
+               m_ranges[i].nDelta, m_ranges[i].nOffset );
+        
+    }
+    */
+}
+
+void PdfTTFWriter::SwapGlyfHeader( TGlyphHeader* pHeader )
+{
+    SwapShort ( &pHeader->numberOfContours );
+    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<int>::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<char*>(&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<char*>(&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<char*>(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<char*>(&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<char*>(&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;z<glyph.vecXCoordinates.size();z++ ) 
+        {
+            printf("Coordinate %i %i\n", glyph.vecXCoordinates[z], glyph.vecYCoordinates[z] );
+        }
+        */
+    }
+    else
+    {
+        // read a composite glyph
+
+        pdf_ttf_ushort flags;
+        do {
+            pdf_ttf_ushort glyphIndex;
+            
+            pDevice->Read( reinterpret_cast<char*>(&flags),      sizeof(pdf_ttf_ushort) );
+            pDevice->Read( reinterpret_cast<char*>(&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<char*>(&glyph.arg1), sizeof(pdf_ttf_short) );
+                pDevice->Read( reinterpret_cast<char*>(&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<char*>(&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<char*>(&glyph.xx), sizeof(pdf_ttf_short) );
+                pDevice->Read( reinterpret_cast<char*>(&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<char*>(&glyph.xx), sizeof(pdf_ttf_short) );
+                pDevice->Read( reinterpret_cast<char*>(&glyph.yx), sizeof(pdf_ttf_short) );
+                pDevice->Read( reinterpret_cast<char*>(&glyph.yy), sizeof(pdf_ttf_short) );
+                pDevice->Read( reinterpret_cast<char*>(&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<char*>(&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<char*>(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<static_cast<unsigned int>(lNumTables); i++ )  
+        pDevice->Write( reinterpret_cast<const char*>(&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<const pdf_ttf_ulong*>(&(*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<char*>(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<char*>(&(*it).m_tHeader), sizeof(TGlyphHeader) );
+
+        if( (*it).IsComposite() ) 
+        {
+            // TODO: Write a composite glyph
+
+        }
+        else
+        {
+            // Write a simple glyph
+            std::vector<pdf_ttf_ushort>::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<char*>(&(*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<TCMapRange> 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<pdf_ttf_ushort>(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<pdf_ttf_ushort>(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<static_cast<int>(vecRanges.size());i++ )
+    {
+        WRITE_TTF_USHORT( vecRanges[i].nEnd );
+    }
+    
+    nValue = 0;
+    WRITE_TTF_USHORT( nValue ); // reserve pad
+
+    for( i=0;i<static_cast<int>(vecRanges.size());i++ )
+    {
+        WRITE_TTF_USHORT( vecRanges[i].nStart );
+    }
+
+    for( i=0;i<static_cast<int>(vecRanges.size());i++ )
+    {
+        WRITE_TTF_SHORT( vecRanges[i].nDelta );
+    }
+
+    for( i=0;i<static_cast<int>(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<char*>(&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<const char*>(&lValue), sizeof(pdf_ttf_ulong) );
+
+    while( it != m_vecLoca.end() )
+    {
+        lValue = (*it);
+        this->SwapULong( &lValue );
+        pDevice->Write( reinterpret_cast<const char*>(&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<char*>(&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<pdf_ttf_ushort>(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<char*>(&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<char*>(&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<char*>(&m_tHead), sizeof(THead) );
+}
+
+void PdfTTFWriter::WritePostTable( PdfOutputDevice* pDevice )
+{
+    m_tPost.format = 0x00020000;
+
+    // write table header
+    pDevice->Write( reinterpret_cast<char*>(&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<char*>(&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<char*>(&nameIndex), sizeof(pdf_ttf_ushort) );
+    }
+
+    // write names
+    std::vector<int>::const_iterator it = m_vecGlyphIndeces.begin();
+    while( it != m_vecGlyphIndeces.end() )
+    {
+        const char*   pszName = "Test";
+        unsigned char cLen    = static_cast<unsigned char>(strlen(pszName));
+        pDevice->Write( reinterpret_cast<char*>(&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<pdf_ttf_ulong*>(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<unsigned char> & rvecFlags, 
+                                              std::vector<pdf_ttf_short> & rvecCoordinates, int nFlagShort, int nFlag )
+{
+    pdf_ttf_short longCoordinate;
+    unsigned char shortCoordinate;
+
+    printf("~~~~~~~~~~~\n");
+    printf("FLAGS: %i\n", rvecFlags.size() );
+    std::vector<unsigned char>::const_iterator itFlags = rvecFlags.begin();
+    while( itFlags != rvecFlags.end() )
+    {
+        if( (*itFlags & nFlagShort) == nFlagShort ) 
+        {
+            // read a 1 byte long coordinate
+            pDevice->Read( reinterpret_cast<char*>(&shortCoordinate), sizeof(char) );
+            printf("Got short: %i\n", shortCoordinate );
+            longCoordinate = static_cast<pdf_ttf_short>(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<unsigned char> & rvecFlags, 
+                                               std::vector<pdf_ttf_short> & rvecCoordinates, int nFlagShort, int nFlag )
+{
+    pdf_ttf_short longCoordinate;
+    pdf_ttf_short lastCoordinate;
+    char          shortCoordinate;
+    
+    std::vector<unsigned char>::const_iterator    itFlags       = rvecFlags.begin();
+    std::vector<pdf_ttf_short>::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<char>(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<char*>(&longCoordinate), sizeof(pdf_ttf_short) );
+       
+        }
+
+        ++itFlags;
+    }
+}
+
+
+long PdfTTFWriter::GetGlyphDataLocation( unsigned int nIndex, long* plLength, PdfInputDevice* pDevice ) const
+{
+    // find the correct cmap range
+    std::vector<TCMapRange>::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<unsigned int>( (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];
+}
+
+};
+
+};
diff --git a/src/podofo/doc/PdfTTFWriter.h b/src/podofo/doc/PdfTTFWriter.h
new file mode 100644 (file)
index 0000000..d6971c5
--- /dev/null
@@ -0,0 +1,711 @@
+/***************************************************************************
+ *   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<TTableDirectoryEntry>         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<TTable>       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<pdf_ttf_ushort> vecEndPoints;
+        std::vector<pdf_ttf_short>  vecXCoordinates;
+        std::vector<pdf_ttf_short>  vecYCoordinates;
+        std::vector<unsigned char>  vecFlags;     ///< Parsed font flags which are used to read glyf coordinates
+        std::vector<unsigned char>  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<PdfTTFGlyph>   TVecGlyphs;
+    typedef TVecGlyphs::iterator       TIVecGlyphs;
+    typedef TVecGlyphs::const_iterator TCIVecGlyphs;
+
+    typedef std::vector<pdf_ttf_ulong> 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<int> & 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<unsigned char> & rvecFlags, 
+                                    std::vector<pdf_ttf_short> & rvecCoordinates, int nFlagShort, int nFlag );
+
+    void WriteSimpleGlyfCoordinates( PdfOutputDevice* pDevice, const std::vector<unsigned char> & rvecFlags, 
+                                     std::vector<pdf_ttf_short> & 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<int>          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<TCMapRange>   m_ranges;           ///< CMap ranges
+    TCMapFormat4 format4;
+    std::vector<pdf_ttf_short> m_vecGlyphIds;
+
+    std::vector<TLongHorMetric> 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_
diff --git a/src/podofo/doc/PdfTable.cpp b/src/podofo/doc/PdfTable.cpp
new file mode 100644 (file)
index 0000000..acef620
--- /dev/null
@@ -0,0 +1,519 @@
+/***************************************************************************
+ *   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 <stdlib.h>
+
+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<PdfString**>(podofo_calloc( nRows, sizeof(PdfString*) ));
+    if( !m_ppData )
+    {
+        PODOFO_RAISE_ERROR( ePdfError_OutOfMemory );
+    }
+
+    for( int i=0;i<nRows;i++ ) 
+        m_ppData[i] = new PdfString[nCols];
+}
+
+PdfSimpleTableModel::~PdfSimpleTableModel()
+{
+    if( m_ppData ) 
+    {
+        for( int i=0;i<m_nRows;i++ ) 
+            delete [] m_ppData[i];
+
+        podofo_free( m_ppData );
+    }
+}
+
+PdfTable::PdfTable( int nCols, int nRows ) 
+    : m_pModel( NULL ),
+      m_nCols( nCols ), m_nRows( nRows ),
+      m_dColWidth( 0.0 ), m_dRowHeight( 0.0 ),
+      m_dTableWidth( 0.0 ), m_dTableHeight( 0.0 ),
+      m_pdColWidths( NULL ), m_pdRowHeights( NULL ),
+      m_bAutoPageBreak( false ), m_pCustomData( NULL ),
+      m_fpCallback( NULL )
+{
+
+}
+
+PdfTable::~PdfTable()
+{
+       delete [] m_pdColWidths;
+       delete [] m_pdRowHeights;
+}
+
+void PdfTable::Draw( double dX, double dY, PdfPainter* pPainter, const PdfRect & rClipRect,
+                     double* pdLastX, double* pdLastY )
+{
+    if( !pPainter ) 
+    {
+        PODOFO_RAISE_ERROR( ePdfError_InvalidHandle );
+    }
+
+    //RG: TODO Should dCurY variable be initialised with 0? (line 257 may fall through without initialisation!)
+    int i = 0;
+    int j = 0;
+    double  dCurX = 0.0;
+    double  dCurY = 0.0;
+
+    double  dWidth = 0.0;
+    double  dHeight = 0.0;
+    double  dVertical = 0.0;
+    double* pdColWidths  = new double[this->GetCols()];
+    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<int>(rClipRect.GetBottom()) && 
+          !static_cast<int>(rClipRect.GetLeft()) &&
+          !static_cast<int>(rClipRect.GetWidth()) && 
+          !static_cast<int>(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;j<m_nRows;j++ )
+        {
+                       if( this->CheckForNewPage( &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;i<m_nCols;i++ ) 
+            {
+                   // set a clipping rectangle
+                pPainter->Save();
+                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;i<m_nCols;i++ )
+    {
+        pPainter->SetStrokingColor( 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<double>(m_nCols);
+        }
+        
+        for(i=0;i<m_nCols;i++)
+            pdWidths[i] = dWidth;
+    }
+    
+    if( m_pdRowHeights ) 
+        memcpy( pdHeights, m_pdRowHeights, sizeof(double) * m_nRows );
+    else
+    {
+        if( dHeight <= 0.0 )
+        {
+            double dTableHeight = m_dTableHeight;
+            
+            if( dTableHeight <= 0.0 )
+            {
+                // The gap from the top is only removed once!!!
+                dTableHeight = dY;
+            }
+            
+            dHeight = dTableHeight / static_cast<double>(m_nRows);
+        }
+        
+        for(i=0;i<m_nRows;i++)
+            pdHeights[i] = dHeight;
+    }
+
+    // Sum up all widths and heights values
+    // to get the total width of the table
+    *pdWidth  = 0.0;
+    *pdHeight = 0.0;
+
+    for(i=0;i<m_nCols;i++)
+        *pdWidth += pdWidths[i];
+
+    for(i=0;i<m_nRows;i++)
+        *pdHeight += pdHeights[i];
+}
+
+bool PdfTable::CheckForNewPage( double* pdY, double* pdCurY, double dRowHeight, PdfPainter* pPainter )
+{
+    if( !m_bAutoPageBreak )
+        return false;
+
+    if( (*pdY - *pdCurY) - dRowHeight < m_curClipRect.GetBottom() )
+    {
+        pPainter->Restore();
+
+        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;i<iCols;i++ )
+                dWidth += pdColWidths[i] + 2 * dcTableBorder;
+
+        for( i=0;i<iRows;i++ )
+                dHeight += pdRowHeights[i] + 2 * dcTableBorder;
+
+        mcPainter.SetColor( 0, 0, 0 );
+        double dCurX = 0.0;
+        double dCurY = 0.0;
+        dCurX = 0.0;
+        for( i=0;i<iCols;i++ ) 
+        {
+                dCurY = 0.0;
+                for( j=0;j<iRows;j++ )
+                {
+                        // draw cell background
+                        if( bFillBackground ) 
+                        {
+                                mcPainter.Save();
+                                mcPainter.SetGray( 0.7  );
+                                double dBackW = pdColWidths[i] + 2 * dcTableBorder;
+                                double dBackH = pdRowHeights[j] + 2 * dcTableBorder;
+                                mcPainter.FillRect( dX + dCurX, dY + dCurY + dBackH, 
+                                                                        dBackW, 
+                                                                        dBackH );
+                                mcPainter.Restore();
+                        }
+
+                        // draw border 
+                        mcPainter.DrawLine( dX, dY + dCurY, dX + dWidth, dY + dCurY);
+
+                        // draw cell contents
+                        mcPainter.DrawText( dX + dCurX + dcTableBorder, dY + dCurY + dcTableBorder, apsTable[i+(iRows-j-1)*iCols]);
+                        dCurY += pdRowHeights[j] + 2 * dcTableBorder;
+                }
+                mcPainter.DrawLine( dX, dY + dCurY, dX + dWidth, dY + dCurY);
+                mcPainter.DrawLine( dX + dCurX, dY, dX + dCurX, dY + dHeight );
+                dCurX += pdColWidths[i] + 2 * dcTableBorder;
+        }
+        mcPainter.DrawLine( dX + dCurX, dY, dX + dCurX, dY + dHeight );
+        mcPainter.Restore();
+}*/
+};
diff --git a/src/podofo/doc/PdfTable.h b/src/podofo/doc/PdfTable.h
new file mode 100644 (file)
index 0000000..ddd2cc8
--- /dev/null
@@ -0,0 +1,917 @@
+/***************************************************************************
+ *   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 <string.h>
+
+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_
diff --git a/src/podofo/doc/PdfTilingPattern.cpp b/src/podofo/doc/PdfTilingPattern.cpp
new file mode 100644 (file)
index 0000000..e8bf453
--- /dev/null
@@ -0,0 +1,244 @@
+/***************************************************************************
+*   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 <iostream>
+#include <iomanip>
+#include <sstream>
+
+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<pdf_int64>(1L) ); // Tiling pattern
+       this->GetObject()->GetDictionary().AddKey( PdfName("PaintType"), static_cast<pdf_int64>(1L) ); // Colored
+       this->GetObject()->GetDictionary().AddKey( PdfName("TilingType"), static_cast<pdf_int64>(1L) ); // Constant spacing
+       this->GetObject()->GetDictionary().AddKey( PdfName("BBox"), var );
+       this->GetObject()->GetDictionary().AddKey( PdfName("XStep"), static_cast<pdf_int64>(rRect.GetWidth()) );
+       this->GetObject()->GetDictionary().AddKey( PdfName("YStep"), static_cast<pdf_int64>(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<pdf_int64>(1));
+               array.push_back (static_cast<pdf_int64>(0));
+               array.push_back (static_cast<pdf_int64>(0));
+               array.push_back (static_cast<pdf_int64>(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
diff --git a/src/podofo/doc/PdfTilingPattern.h b/src/podofo/doc/PdfTilingPattern.h
new file mode 100644 (file)
index 0000000..592e25c
--- /dev/null
@@ -0,0 +1,133 @@
+/***************************************************************************
+ *   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_
diff --git a/src/podofo/doc/PdfXObject.cpp b/src/podofo/doc/PdfXObject.cpp
new file mode 100644 (file)
index 0000000..587f105
--- /dev/null
@@ -0,0 +1,363 @@
+/***************************************************************************
+ *   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 <sstream>
+
+#define PI           3.141592654f
+
+using namespace std;
+
+namespace PoDoFo {
+
+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<const PdfDocument*>(&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_Reference  = this->GetObject()->Reference();
+
+    if( this->GetObject()->GetIndirectKey( "BBox" ) )
+        m_rRect = PdfRect( this->GetObject()->GetIndirectKey( "BBox" )->GetArray() );
+}
+
+void PdfXObject::InitXObject( const PdfRect & rRect, const char* pszPrefix )
+{
+    PdfVariant    var;
+    ostringstream out;
+    PdfLocaleImbue(out);
+
+    // Initialize static data
+    if( m_matrix.empty() )
+    {
+        // This matrix is the same for all PdfXObjects so cache it
+        m_matrix.push_back( PdfVariant( static_cast<pdf_int64>(PODOFO_LL_LITERAL(1)) ) );
+        m_matrix.push_back( PdfVariant( static_cast<pdf_int64>(PODOFO_LL_LITERAL(0)) ) );
+        m_matrix.push_back( PdfVariant( static_cast<pdf_int64>(PODOFO_LL_LITERAL(0)) ) );
+        m_matrix.push_back( PdfVariant( static_cast<pdf_int64>(PODOFO_LL_LITERAL(1)) ) );
+        m_matrix.push_back( PdfVariant( static_cast<pdf_int64>(PODOFO_LL_LITERAL(0)) ) );
+        m_matrix.push_back( PdfVariant( static_cast<pdf_int64>(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<pdf_int64>(PODOFO_LL_LITERAL(1)) ) ); // only 1 is only defined in the specification.
+    this->GetObject()->GetDictionary().AddKey( "Matrix", m_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()->GetIndirectKeyAsName( 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();
+}
+
+};
diff --git a/src/podofo/doc/PdfXObject.h b/src/podofo/doc/PdfXObject.h
new file mode 100644 (file)
index 0000000..9c65378
--- /dev/null
@@ -0,0 +1,217 @@
+/***************************************************************************
+ *   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:
+    PdfArray         m_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_ */
+
+
diff --git a/src/podofo/doc/podofo-doc.rc b/src/podofo/doc/podofo-doc.rc
new file mode 100644 (file)
index 0000000..7d22701
--- /dev/null
@@ -0,0 +1,78 @@
+#define PODOFO_COMPILE_RC\r
+\r
+#include "base/podofoapi.h"
+#include "base/PdfDefines.h"
+#include "base/PdfVersion.h"
+#include "winresrc.h"
+
+#undef PODOFO_COMPILE_RC\r
+\r
+#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
diff --git a/src/podofo/libpodofo.pc.in b/src/podofo/libpodofo.pc.in
new file mode 100644 (file)
index 0000000..214b692
--- /dev/null
@@ -0,0 +1,10 @@
+prefix=@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
+Cflags: -I${includedir}
diff --git a/src/podofo/podofo-base.h b/src/podofo/podofo-base.h
new file mode 100644 (file)
index 0000000..1c6f74b
--- /dev/null
@@ -0,0 +1,84 @@
+/***************************************************************************
+ *   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_
diff --git a/src/podofo/podofo.h b/src/podofo/podofo.h
new file mode 100644 (file)
index 0000000..f3b8523
--- /dev/null
@@ -0,0 +1,106 @@
+/***************************************************************************
+ *   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_ */
+
+
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3312482
--- /dev/null
@@ -0,0 +1,15 @@
+SUBDIRS(
+       ContentParser
+       CreationTest
+       FilterTest
+       FormTest
+       LargeTest
+       ObjectParserTest
+       ParserTest
+       SignatureTest
+       TokenizerTest
+       VariantTest
+       WatermarkTest
+       unit
+       )
+
diff --git a/test/ContentParser/CMakeLists.txt b/test/ContentParser/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1e0dd67
--- /dev/null
@@ -0,0 +1,5 @@
+
+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})
diff --git a/test/ContentParser/main.cpp b/test/ContentParser/main.cpp
new file mode 100644 (file)
index 0000000..35f615a
--- /dev/null
@@ -0,0 +1,184 @@
+#include "podofo.h"
+#include "../PdfTest.h"
+
+#include <iostream>
+#include <stack>
+#include <algorithm>
+#include <string>
+#include <iomanip>
+#include <cstdio>
+
+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<PdfVariant> 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<unsigned short>(*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;
+}
diff --git a/test/CreationTest/CMakeLists.txt b/test/CreationTest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c5341d1
--- /dev/null
@@ -0,0 +1,11 @@
+ADD_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"
+    )
diff --git a/test/CreationTest/CreationTest.cpp b/test/CreationTest/CreationTest.cpp
new file mode 100644 (file)
index 0000000..6be2f8f
--- /dev/null
@@ -0,0 +1,994 @@
+/***************************************************************************
+ *   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 <cstdlib>
+#include <cstdio>
+#include <iostream>
+
+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;
+
+    PODOFO_UNIQUEU_PTR<PdfFilter> 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<const pdf_utf8*>("「PoDoFo」は今から日本語も話せます。"));
+    PdfAnnotation* pAnnotation =
+        pPage->CreateAnnotation( ePdfAnnotation_Text, PdfRect( 400.0, 200.0, 20.0, 20.0 ) );
+
+    PdfString sGerman(reinterpret_cast<const pdf_utf8*>("Unicode Umlauts: ÄÖÜß"));
+    pAnnotation->SetTitle( sGerman );
+    pAnnotation->SetContents( sJap );
+    pAnnotation->SetOpen( true );
+}
+
+void CreateUnicodeAnnotationFreeText( PdfPage* pPage, PdfDocument* pDocument )
+{
+    PdfString sJap(reinterpret_cast<const pdf_utf8*>("「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<const pdf_utf8*>("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<const pdf_utf8*>("「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<int> vecCharacters;
+    vecCharacters.push_back( static_cast<int>('C') );
+    vecCharacters.push_back( static_cast<int>('G') );
+    vecCharacters.push_back( static_cast<int>('a') );
+    vecCharacters.push_back( static_cast<int>('c') );
+    vecCharacters.push_back( static_cast<int>('e') );
+    vecCharacters.push_back( static_cast<int>('l') );
+    vecCharacters.push_back( static_cast<int>('o') );
+    vecCharacters.push_back( static_cast<int>('p') );
+    vecCharacters.push_back( static_cast<int>('s') );
+    vecCharacters.push_back( static_cast<int>('r') );
+    vecCharacters.push_back( static_cast<int>('y') );
+    vecCharacters.push_back( static_cast<int>(' ') );
+    vecCharacters.push_back( static_cast<int>('-') );
+
+    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<double>(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<double>(i)/10.0, 0.0, static_cast<double>(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<double>(i)/10.0, 0.0, static_cast<double>(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++ )\r
+    {
+        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/watzmann.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/watzmann.jpg", true, pDocument );
+    pFileAnnotation =  pPage->CreateAnnotation( ePdfAnnotation_FileAttachement, PdfRect( 300.0, 400.0, 250.0, 50.0 ) );
+    pFileAnnotation->SetContents( "A JPEG image of the Watzmann mountain, taken by Dominik 2016-07-05." );
+    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<long>(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;i<nCols;i++)
+        for(z=0;z<nRows;z++)
+        {
+            std::ostringstream oss;
+            oss << "Cell " << i << " " << z;
+            model.SetText( i, z, PdfString( oss.str() ) );
+        }
+
+    PdfTable table1( nCols, nRows );
+    table1.SetTableWidth ( 80000 * CONVERSION_CONSTANT );
+    table1.SetTableHeight( 120000 * CONVERSION_CONSTANT );
+    table1.SetModel( &model );
+    table1.Draw( dX, dY, pPainter );
+
+
+    dY = pPage->GetPageSize().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;i<nCols2;i++)
+        for(z=0;z<nRows2;z++)
+        {
+            std::ostringstream oss;
+            oss << rand();
+            model2.SetText( i, z, PdfString( oss.str() ) );
+        }
+
+    PdfTable table2( nCols2, nRows2 );
+    table2.SetModel( &model2 );
+    table2.Draw( dX, dY, pPainter );
+}
+
+void LargeMultiLineTextTest( PdfPainter* pPainter, PdfPage* pPage, PdfDocument* pDocument )
+{
+    double     x     = 10000 * CONVERSION_CONSTANT;
+    double     y     = pPage->GetPageSize().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=%" PDF_FORMAT_UINT64 "\n", static_cast<pdf_uint64>(sizeof(PdfVariant)) );
+        printf("sizeof object=%" PDF_FORMAT_UINT64 "\n", static_cast<pdf_uint64>(sizeof(PdfObject)) );
+        printf("sizeof reference=%" PDF_FORMAT_UINT64 "\n", static_cast<pdf_uint64>(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<long>(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<const pdf_utf8*>("「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<int>(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;
+}
diff --git a/test/CreationTest/resources/Illust.pdf b/test/CreationTest/resources/Illust.pdf
new file mode 100644 (file)
index 0000000..bcff320
--- /dev/null
@@ -0,0 +1,1407 @@
+%PDF-1.4\r%âãÏÓ\r
+1 0 obj\r<</Metadata 34 0 R/Pages 2 0 R/Type/Catalog>>\rendobj\r34 0 obj\r<</Subtype/XML/Length 41342/Type/Metadata>>stream\r
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
+<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.1-c036 46.277092, Fri Feb 23 2007 14:17:08        ">
+   <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+      <rdf:Description rdf:about=""
+            xmlns:dc="http://purl.org/dc/elements/1.1/">
+         <dc:format>application/pdf</dc:format>
+         <dc:title>
+            <rdf:Alt>
+               <rdf:li xml:lang="x-default">Illust</rdf:li>
+            </rdf:Alt>
+         </dc:title>
+      </rdf:Description>
+      <rdf:Description rdf:about=""
+            xmlns:xap="http://ns.adobe.com/xap/1.0/"
+            xmlns:xapGImg="http://ns.adobe.com/xap/1.0/g/img/">
+         <xap:CreatorTool>Adobe Illustrator CS3</xap:CreatorTool>
+         <xap:CreateDate>2007-09-05T11:52:56+02:00</xap:CreateDate>
+         <xap:ModifyDate>2007-09-05T11:52:56+02:00</xap:ModifyDate>
+         <xap:MetadataDate>2007-09-05T11:52:56+02:00</xap:MetadataDate>
+         <xap:Thumbnails>
+            <rdf:Alt>
+               <rdf:li rdf:parseType="Resource">
+                  <xapGImg:width>200</xapGImg:width>
+                  <xapGImg:height>256</xapGImg:height>
+                  <xapGImg:format>JPEG</xapGImg:format>
+                  <xapGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAADIAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX&#xA;Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX&#xA;Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX&#xA;Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F&#xA;XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX&#xA;Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXkv/OT+oX9h+VstxY3&#xA;MtpP9dtl9aB2jehLVHJSDhCvj7/GfnD/AKvuof8ASVP/AM14Uu/xn5w/6vuof9JU/wDzXirv8Z+c&#xA;P+r7qH/SVP8A814q+pP+cSNW1TUvKetyajeT3kiX6qj3EjylR6KmgLk0wFD1Hzh5V1rWpbW40jXp&#xA;9EubVJUBjEskMnqsn97Cs0KPREdQT8S8uSlWAOBWPXv5befJbLSIrTz7dWl5pcTRvei3klM5ITgZ&#xA;YnuTFJxKb+ssjMCfirviqqfIX5kzPaSXn5gSytbXUV06xafHbJIqGUPEywzKSjJIgCuWWqcirE7K&#xA;ss8sabr2naWLfXNYOuah6ju199XitBwY1RBFFVQEG1aknFU2xV2KuxV2KuxV2KuxV2KuxV2KuxV2&#xA;KuxV2KuxV2KvHf8AnK3/AMlNL/zHW362whXxdhS7FXYq+sv+cOP+UP17/toL/wAmFwFBfQOBXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq82/5yC8oeYvNn5eSaR5ftPruoNdwSiD1&#xA;IovgQnkeUzRrtXxxCvmL/oWv86/+pc/6fbD/AKr4bS7/AKFr/Ov/AKlz/p9sP+q+Nq7/AKFr/Ov/&#xA;AKlz/p9sP+q+Nq+hf+cavIPm3yZ5b1az8y2H1C5urxZoI/Vhm5IIlWtYXkA3HfEoew4FdirsVdir&#xA;sVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs&#xA;VdirsVdirsVdirsVdirsVdirsVdirBLv86/IlhPFZ6pPPp+p3EssNrp0sDyTymKeS2qv1f1owryw&#xA;sF5OPemKpiv5oeRyvNtSVF4hwSjk8Wthd1IUMV/dN+1TeoG+Ksmt7iK5t4riFuUMyLJG1CKqwqDQ&#xA;0I2PfFVTFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FVO5tra6t5La5&#xA;iSe3mUpNDIodHRhRlZWqCCOoOKr0RERURQqKAFUCgAHQAYq3irsVdirsVdirsVdirsVdirsVdirs&#xA;VdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV&#xA;dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd&#xA;irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir/9k=</xapGImg:image>
+               </rdf:li>
+            </rdf:Alt>
+         </xap:Thumbnails>
+      </rdf:Description>
+      <rdf:Description rdf:about=""
+            xmlns:xapMM="http://ns.adobe.com/xap/1.0/mm/"
+            xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#"
+            xmlns:stMfs="http://ns.adobe.com/xap/1.0/sType/ManifestItem#">
+         <xapMM:DocumentID>uuid:CBF2C183945BDC1192F7ABDCFD1A3597</xapMM:DocumentID>
+         <xapMM:InstanceID>uuid:875c03d0-1825-4840-951a-7b833c396f5e</xapMM:InstanceID>
+         <xapMM:DerivedFrom rdf:parseType="Resource">
+            <stRef:instanceID>uuid:CAF2C183945BDC1192F7ABDCFD1A3597</stRef:instanceID>
+            <stRef:documentID>uuid:C8F2C183945BDC1192F7ABDCFD1A3597</stRef:documentID>
+         </xapMM:DerivedFrom>
+         <xapMM:Manifest>
+            <rdf:Seq>
+               <rdf:li rdf:parseType="Resource">
+                  <stMfs:linkForm>EmbedByReference</stMfs:linkForm>
+                  <stMfs:reference rdf:parseType="Resource">
+                     <stRef:filePath>T:\d904\d4\TEST1.PDF</stRef:filePath>
+                  </stMfs:reference>
+               </rdf:li>
+            </rdf:Seq>
+         </xapMM:Manifest>
+      </rdf:Description>
+      <rdf:Description rdf:about=""
+            xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/">
+         <illustrator:StartupProfile>Print</illustrator:StartupProfile>
+      </rdf:Description>
+      <rdf:Description rdf:about=""
+            xmlns:xapTPg="http://ns.adobe.com/xap/1.0/t/pg/"
+            xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
+            xmlns:stFnt="http://ns.adobe.com/xap/1.0/sType/Font#"
+            xmlns:xapG="http://ns.adobe.com/xap/1.0/g/">
+         <xapTPg:NPages>1</xapTPg:NPages>
+         <xapTPg:HasVisibleTransparency>False</xapTPg:HasVisibleTransparency>
+         <xapTPg:HasVisibleOverprint>False</xapTPg:HasVisibleOverprint>
+         <xapTPg:MaxPageSize rdf:parseType="Resource">
+            <stDim:w>110.000004</stDim:w>
+            <stDim:h>100.000001</stDim:h>
+            <stDim:unit>Millimeters</stDim:unit>
+         </xapTPg:MaxPageSize>
+         <xapTPg:Fonts>
+            <rdf:Bag>
+               <rdf:li rdf:parseType="Resource">
+                  <stFnt:fontName>Times-Roman</stFnt:fontName>
+                  <stFnt:fontFamily>Times</stFnt:fontFamily>
+                  <stFnt:fontFace>Roman</stFnt:fontFace>
+                  <stFnt:fontType>Type 1</stFnt:fontType>
+                  <stFnt:versionString>002.000</stFnt:versionString>
+                  <stFnt:composite>False</stFnt:composite>
+                  <stFnt:fontFileName>TIR_____.PFB; TIR_____.PFM</stFnt:fontFileName>
+               </rdf:li>
+               <rdf:li rdf:parseType="Resource">
+                  <stFnt:fontName>PBAAAA+Courier</stFnt:fontName>
+                  <stFnt:fontFamily>PBAAAA+Courier</stFnt:fontFamily>
+                  <stFnt:fontType>Unknown</stFnt:fontType>
+                  <stFnt:versionString>Version 2.007;PS 002.000;Core 1.0.38;makeotf.lib1.7.9032</stFnt:versionString>
+                  <stFnt:composite>False</stFnt:composite>
+                  <stFnt:fontFileName>MyriadPro-Regular.otf</stFnt:fontFileName>
+               </rdf:li>
+            </rdf:Bag>
+         </xapTPg:Fonts>
+         <xapTPg:PlateNames>
+            <rdf:Seq>
+               <rdf:li>Cyan</rdf:li>
+               <rdf:li>Magenta</rdf:li>
+               <rdf:li>Yellow</rdf:li>
+               <rdf:li>Black</rdf:li>
+            </rdf:Seq>
+         </xapTPg:PlateNames>
+         <xapTPg:SwatchGroups>
+            <rdf:Seq>
+               <rdf:li rdf:parseType="Resource">
+                  <xapG:groupName>Standard-Farbfeldgruppe</xapG:groupName>
+                  <xapG:groupType>0</xapG:groupType>
+                  <xapG:Colorants>
+                     <rdf:Seq>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>Weiß</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>0.000000</xapG:cyan>
+                           <xapG:magenta>0.000000</xapG:magenta>
+                           <xapG:yellow>0.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>Schwarz</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>0.000000</xapG:cyan>
+                           <xapG:magenta>0.000000</xapG:magenta>
+                           <xapG:yellow>0.000000</xapG:yellow>
+                           <xapG:black>100.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>CMYK Rot</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>0.000000</xapG:cyan>
+                           <xapG:magenta>100.000000</xapG:magenta>
+                           <xapG:yellow>100.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>CMYK Gelb</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>0.000000</xapG:cyan>
+                           <xapG:magenta>0.000000</xapG:magenta>
+                           <xapG:yellow>100.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>CMYK Grün</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>100.000000</xapG:cyan>
+                           <xapG:magenta>0.000000</xapG:magenta>
+                           <xapG:yellow>100.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>CMYK Cyan</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>100.000000</xapG:cyan>
+                           <xapG:magenta>0.000000</xapG:magenta>
+                           <xapG:yellow>0.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>CMYK Blau</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>100.000000</xapG:cyan>
+                           <xapG:magenta>100.000000</xapG:magenta>
+                           <xapG:yellow>0.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>CMYK Magenta</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>0.000000</xapG:cyan>
+                           <xapG:magenta>100.000000</xapG:magenta>
+                           <xapG:yellow>0.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=15 M=100 Y=90 K=10</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>14.999998</xapG:cyan>
+                           <xapG:magenta>100.000000</xapG:magenta>
+                           <xapG:yellow>90.000004</xapG:yellow>
+                           <xapG:black>10.000002</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=0 M=90 Y=85 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>0.000000</xapG:cyan>
+                           <xapG:magenta>90.000004</xapG:magenta>
+                           <xapG:yellow>84.999996</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=0 M=80 Y=95 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>0.000000</xapG:cyan>
+                           <xapG:magenta>80.000001</xapG:magenta>
+                           <xapG:yellow>94.999999</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=0 M=50 Y=100 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>0.000000</xapG:cyan>
+                           <xapG:magenta>50.000000</xapG:magenta>
+                           <xapG:yellow>100.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=0 M=35 Y=85 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>0.000000</xapG:cyan>
+                           <xapG:magenta>35.000002</xapG:magenta>
+                           <xapG:yellow>84.999996</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=5 M=0 Y=90 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>5.000001</xapG:cyan>
+                           <xapG:magenta>0.000000</xapG:magenta>
+                           <xapG:yellow>90.000004</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=20 M=0 Y=100 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>19.999999</xapG:cyan>
+                           <xapG:magenta>0.000000</xapG:magenta>
+                           <xapG:yellow>100.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=50 M=0 Y=100 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>50.000000</xapG:cyan>
+                           <xapG:magenta>0.000000</xapG:magenta>
+                           <xapG:yellow>100.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=75 M=0 Y=100 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>75.000000</xapG:cyan>
+                           <xapG:magenta>0.000000</xapG:magenta>
+                           <xapG:yellow>100.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=85 M=10 Y=100 K=10</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>84.999996</xapG:cyan>
+                           <xapG:magenta>10.000002</xapG:magenta>
+                           <xapG:yellow>100.000000</xapG:yellow>
+                           <xapG:black>10.000002</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=90 M=30 Y=95 K=30</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>90.000004</xapG:cyan>
+                           <xapG:magenta>30.000001</xapG:magenta>
+                           <xapG:yellow>94.999999</xapG:yellow>
+                           <xapG:black>30.000001</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=75 M=0 Y=75 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>75.000000</xapG:cyan>
+                           <xapG:magenta>0.000000</xapG:magenta>
+                           <xapG:yellow>75.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=80 M=10 Y=45 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>80.000001</xapG:cyan>
+                           <xapG:magenta>10.000002</xapG:magenta>
+                           <xapG:yellow>44.999999</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=70 M=15 Y=0 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>69.999999</xapG:cyan>
+                           <xapG:magenta>14.999998</xapG:magenta>
+                           <xapG:yellow>0.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=85 M=50 Y=0 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>84.999996</xapG:cyan>
+                           <xapG:magenta>50.000000</xapG:magenta>
+                           <xapG:yellow>0.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=100 M=95 Y=5 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>100.000000</xapG:cyan>
+                           <xapG:magenta>94.999999</xapG:magenta>
+                           <xapG:yellow>5.000001</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=100 M=100 Y=25 K=25</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>100.000000</xapG:cyan>
+                           <xapG:magenta>100.000000</xapG:magenta>
+                           <xapG:yellow>25.000000</xapG:yellow>
+                           <xapG:black>25.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=75 M=100 Y=0 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>75.000000</xapG:cyan>
+                           <xapG:magenta>100.000000</xapG:magenta>
+                           <xapG:yellow>0.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=50 M=100 Y=0 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>50.000000</xapG:cyan>
+                           <xapG:magenta>100.000000</xapG:magenta>
+                           <xapG:yellow>0.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=35 M=100 Y=35 K=10</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>35.000002</xapG:cyan>
+                           <xapG:magenta>100.000000</xapG:magenta>
+                           <xapG:yellow>35.000002</xapG:yellow>
+                           <xapG:black>10.000002</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=10 M=100 Y=50 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>10.000002</xapG:cyan>
+                           <xapG:magenta>100.000000</xapG:magenta>
+                           <xapG:yellow>50.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=0 M=95 Y=20 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>0.000000</xapG:cyan>
+                           <xapG:magenta>94.999999</xapG:magenta>
+                           <xapG:yellow>19.999999</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=25 M=25 Y=40 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>25.000000</xapG:cyan>
+                           <xapG:magenta>25.000000</xapG:magenta>
+                           <xapG:yellow>39.999998</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=40 M=45 Y=50 K=5</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>39.999998</xapG:cyan>
+                           <xapG:magenta>44.999999</xapG:magenta>
+                           <xapG:yellow>50.000000</xapG:yellow>
+                           <xapG:black>5.000001</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=50 M=50 Y=60 K=25</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>50.000000</xapG:cyan>
+                           <xapG:magenta>50.000000</xapG:magenta>
+                           <xapG:yellow>60.000002</xapG:yellow>
+                           <xapG:black>25.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=55 M=60 Y=65 K=40</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>55.000001</xapG:cyan>
+                           <xapG:magenta>60.000002</xapG:magenta>
+                           <xapG:yellow>64.999998</xapG:yellow>
+                           <xapG:black>39.999998</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=25 M=40 Y=65 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>25.000000</xapG:cyan>
+                           <xapG:magenta>39.999998</xapG:magenta>
+                           <xapG:yellow>64.999998</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=30 M=50 Y=75 K=10</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>30.000001</xapG:cyan>
+                           <xapG:magenta>50.000000</xapG:magenta>
+                           <xapG:yellow>75.000000</xapG:yellow>
+                           <xapG:black>10.000002</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=35 M=60 Y=80 K=25</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>35.000002</xapG:cyan>
+                           <xapG:magenta>60.000002</xapG:magenta>
+                           <xapG:yellow>80.000001</xapG:yellow>
+                           <xapG:black>25.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=40 M=65 Y=90 K=35</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>39.999998</xapG:cyan>
+                           <xapG:magenta>64.999998</xapG:magenta>
+                           <xapG:yellow>90.000004</xapG:yellow>
+                           <xapG:black>35.000002</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=40 M=70 Y=100 K=50</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>39.999998</xapG:cyan>
+                           <xapG:magenta>69.999999</xapG:magenta>
+                           <xapG:yellow>100.000000</xapG:yellow>
+                           <xapG:black>50.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=50 M=70 Y=80 K=70</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>50.000000</xapG:cyan>
+                           <xapG:magenta>69.999999</xapG:magenta>
+                           <xapG:yellow>80.000001</xapG:yellow>
+                           <xapG:black>69.999999</xapG:black>
+                        </rdf:li>
+                     </rdf:Seq>
+                  </xapG:Colorants>
+               </rdf:li>
+               <rdf:li rdf:parseType="Resource">
+                  <xapG:groupName>Druckfarben</xapG:groupName>
+                  <xapG:groupType>1</xapG:groupType>
+                  <xapG:Colorants>
+                     <rdf:Seq>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=0 M=30 Y=70 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>0.000000</xapG:cyan>
+                           <xapG:magenta>30.000001</xapG:magenta>
+                           <xapG:yellow>69.999999</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=5 M=70 Y=90 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>5.000001</xapG:cyan>
+                           <xapG:magenta>69.999999</xapG:magenta>
+                           <xapG:yellow>90.000004</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=5 M=90 Y=75 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>5.000001</xapG:cyan>
+                           <xapG:magenta>90.000004</xapG:magenta>
+                           <xapG:yellow>75.000000</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=30 M=0 Y=95 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>30.000001</xapG:cyan>
+                           <xapG:magenta>0.000000</xapG:magenta>
+                           <xapG:yellow>94.999999</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=60 M=5 Y=95 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>60.000002</xapG:cyan>
+                           <xapG:magenta>5.000001</xapG:magenta>
+                           <xapG:yellow>94.999999</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=30 M=0 Y=10 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>30.000001</xapG:cyan>
+                           <xapG:magenta>0.000000</xapG:magenta>
+                           <xapG:yellow>10.000002</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=60 M=10 Y=5 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>60.000002</xapG:cyan>
+                           <xapG:magenta>10.000002</xapG:magenta>
+                           <xapG:yellow>5.000001</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>C=80 M=5 Y=10 K=0</xapG:swatchName>
+                           <xapG:mode>CMYK</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:cyan>80.000001</xapG:cyan>
+                           <xapG:magenta>5.000001</xapG:magenta>
+                           <xapG:yellow>10.000002</xapG:yellow>
+                           <xapG:black>0.000000</xapG:black>
+                        </rdf:li>
+                     </rdf:Seq>
+                  </xapG:Colorants>
+               </rdf:li>
+               <rdf:li rdf:parseType="Resource">
+                  <xapG:groupName>Graustufen</xapG:groupName>
+                  <xapG:groupType>1</xapG:groupType>
+                  <xapG:Colorants>
+                     <rdf:Seq>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>K=100</xapG:swatchName>
+                           <xapG:mode>GRAY</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:gray>255</xapG:gray>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>K=90</xapG:swatchName>
+                           <xapG:mode>GRAY</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:gray>229</xapG:gray>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>K=80</xapG:swatchName>
+                           <xapG:mode>GRAY</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:gray>203</xapG:gray>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>K=70</xapG:swatchName>
+                           <xapG:mode>GRAY</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:gray>178</xapG:gray>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>K=60</xapG:swatchName>
+                           <xapG:mode>GRAY</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:gray>152</xapG:gray>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>K=50</xapG:swatchName>
+                           <xapG:mode>GRAY</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:gray>127</xapG:gray>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>K=40</xapG:swatchName>
+                           <xapG:mode>GRAY</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:gray>101</xapG:gray>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>K=30</xapG:swatchName>
+                           <xapG:mode>GRAY</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:gray>76</xapG:gray>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>K=20</xapG:swatchName>
+                           <xapG:mode>GRAY</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:gray>50</xapG:gray>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>K=10</xapG:swatchName>
+                           <xapG:mode>GRAY</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:gray>25</xapG:gray>
+                        </rdf:li>
+                        <rdf:li rdf:parseType="Resource">
+                           <xapG:swatchName>K=5</xapG:swatchName>
+                           <xapG:mode>GRAY</xapG:mode>
+                           <xapG:type>PROCESS</xapG:type>
+                           <xapG:gray>12</xapG:gray>
+                        </rdf:li>
+                     </rdf:Seq>
+                  </xapG:Colorants>
+               </rdf:li>
+            </rdf:Seq>
+         </xapTPg:SwatchGroups>
+      </rdf:Description>
+      <rdf:Description rdf:about=""
+            xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
+         <pdf:Producer>Adobe PDF library 8.00</pdf:Producer>
+      </rdf:Description>
+   </rdf:RDF>
+</x:xmpmeta>
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                                                                                                    
+                           
+<?xpacket end="w"?>\r
+endstream\rendobj\r2 0 obj\r<</Count 1/Type/Pages/Kids[5 0 R]>>\rendobj\r5 0 obj\r<</Parent 2 0 R/Contents 27 0 R/BleedBox[0.0 0.0 311.811 283.465]/PieceInfo<</Illustrator 6 0 R>>/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<</Font<</T1_0 23 0 R/T1_1 25 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0<</Color[20224 32768 65535]/Visible true/Editable true/Dimmed false/Preview true/Printed true/Title(Ebene 1)>>>>/ExtGState<</GS0 20 0 R>>>>/Type/Page/LastModified(D:20070905115214+02'00')>>\rendobj\r27 0 obj\r<</Length 221/Filter/FlateDecode>>stream\r
+H\89\ÐMKÄ@\f\ 6à{~Å{l\ f\9bNæ«3×®\8bøÑÃâ\80\a\11ÙC]ÔuŶ\82þ{g*."¹\84\90ä!i®w_Ã\88¦_+tgk\90B      ÁË)»"\8b\1eÔ\9cß(ì'\121l=$j\8e:b\15\85Å·ð\96\18\aêè=ÏêPÚ\1c\8c\b\a\11¬~\v¹ã\16\125I\1e
+\90\1e\ f¦!&²·ÆCÛÀÖF\8dôJwUª[U\rµ¸êsÆÅáð1Íãn~\eëûtI\9b\ 55-;×\9eLm\1dG\15þ\90ù\82\85\95ÿ¬Q¬C\9bËË
\8bZ¥a\9a\9f\8eû:=\17bÓç÷lé[\80\ 1\0ø\ 4\r
+endstream\rendobj\r33 0 obj\r<</Length 85/Filter[/ASCII85Decode/FlateDecode]/BitsPerComponent 8/ColorSpace 31 0 R/Width 38/Height 35>>stream\r
+8;Xp,Sc4.*)[TicNm'rog=k71E(m?92ulcQ)ic@)9*NFKPa\G.j>%(e)X;hR$jPE#
+UL4eo#64c/!.r#_l2~>\r
+endstream\rendobj\r20 0 obj\r<</OPM 1/BM/Normal/CA 1.0/OP false/SMask/None/ca 1.0/AIS false/op false/Type/ExtGState/SA true>>\rendobj\r23 0 obj\r<</Subtype/Type1/FontDescriptor 24 0 R/LastChar 120/Widths[250 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 333 0 0 0 0 0 0 0 0 0 0 611 0 0 0 0 0 0 0 0 0 0 0 0 444 0 0 0 444 0 0 0 0 0 0 278 0 0 500 0 0 333 389 278 500 0 0 500]/BaseFont/HVXUYP+Times-Roman/FirstChar 32/Encoding/WinAnsiEncoding/Type/Font>>\rendobj\r25 0 obj\r<</Subtype/Type1/FontDescriptor 26 0 R/LastChar 116/Widths[600 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 600 0 600 0 600 0 0 0 0 600 0 0 0 0 600 600]/BaseFont/HVXUYP+Courier/FirstChar 84/Encoding/WinAnsiEncoding/Type/Font>>\rendobj\r26 0 obj\r<</StemV 51/FontName/HVXUYP+Courier/FontStretch/Normal/FontFile3 30 0 R/FontWeight 400/Flags 34/Descent -250/FontBBox[-23 -250 623 805]/Ascent 805/FontFamily(Courier)/CapHeight 562/XHeight 426/Type/FontDescriptor/ItalicAngle 0>>\rendobj\r30 0 obj\r<</Subtype/Type1C/Length 851/Filter/FlateDecode>>stream\r
+H\894\91mLSg\14Ç\9fÛr{\rÖ[äZMzõÞ»`æ\e+Ö"È4¾´\8a\ 5Í\`.B·\91\89åEq-méÄ \80\ 2¦C(©¨¡\19\92e)\bq\91Ect·»K\1d2\92e\88\88\ 6\8d ñ%3J\²\ f\9e\87<M´tÙùðËÉÿ¼ä\9fs(\94¤B\14Eél\9fïÛ[ôé\1a«³Æ]épÏIi\98§ð\92$¼T»ØKÚgÕ³7èe\b]<±\0¬:(Xxyv4\15©(ªô ÕéªuW\96Wx¥\95¥«$SÎ\86\9cô8sÖ&hJp]\82æ\ 4³¥m\a\9cû\1dRa­Çë8ì\91ò¾)uº]N÷×^Ç\ 1£$m«ª\92
+æ¶y¤\ 2\87ÇáöÅÕÿ]Åc=ÊE6\94\8fö ÏÐ^4/n\1e©ÐN\14¢4\94\99:¦JSU°­2.\93©wÈØ\80Þ¡\8c\ 6\ 4y
+ä%²E\eð5<¬\8fÕk\8e\92ã\91\96.(¤Á\12+#)vøM&)¸\f,\9a.R\18é Ù:\ 5²dX®P\7fÝÂ(ªÆ}¯ô\87r­®]|\9añæÛ\16\11gjN÷\9c>\7fÁ0\9a\ f\vÉÇDGØl²\82,\ 3Ö\fºg\ fú\7f\1a\17b[ Hÿ¼ëÞÍ\7fø\99©}F\91%&\ 5\18\ 5Æår%õú\10<R¸\19\\83\13\99,]ç×p\8fF«r\am<\99·"\83hÉâ×&H¾;ôó¯WĶM\9aå»}[r\8b;\7f°\bõEtÝðË£Q\1eÖ\ e<\9d\12c:8¬\7fv\7fâï\97·7\7fdÞ¾=Ãh½óF\88ß\0¦eP\83\96\82>E\r)x³Þ\ ekÈ4±Ù±Q&;1Ë\80:  ´\9b\88\96ù¯9n
+\f(Üdx®û        \99βCµ\9cÅp×!Èü24|u\84\9fºð¥E$\9exÁ%gÃYæOÏ]\92¼5¿¢ø\v\81\9b\1ccØ:ÙëÃ+åSߦ>¿r(
+\91Aw\94\vsçp\13DõMá\96Þ°¡§½'ð½Àõ\96\ 4h·¿¹¹\81\ f\ 4\1aÅÐWÕgì¼\95$\1d4\13\16V7\8e|'rý/ü#'>1ìN?²gcæÀäI¡¸\85æ*\83Î6\97ÓPã÷5ù\ 4®?r\8aîk\v\9eïä\ 3\1d~\7f»X\1d\1dl\1cá\1f\82îÒ\f¨   \1d´µ\8b\oz óì¸áÆDø÷\89\17^K\870÷ÛW²\1d\82IáƸA0á[zn\8cð;ìwH\80ùàAùÓ\89û\17{ÿ\10\9a#tIZQc       ¿Ñ\11þW\84J\bÉ$ÄÄ\ax\86­íÆÃÝÄø#\18»\83­\90\1dÒ@Sçã`Ì\1f \1f\86\18%Y\99\8fg\16½\17`\002\83ã\r
+endstream\rendobj\r24 0 obj\r<</StemV 84/FontName/HVXUYP+Times-Roman/FontStretch/Normal/FontFile3 29 0 R/FontWeight 400/Flags 34/Descent -218/FontBBox[-168 -218 1000 898]/Ascent 898/FontFamily(Times)/CapHeight 662/XHeight 450/Type/FontDescriptor/ItalicAngle 0>>\rendobj\r29 0 obj\r<</Subtype/Type1C/Length 1325/Filter/FlateDecode>>stream\r
+H\89\1c\91kP\13w\14Åw    É2­\ 6Ë\1a\94]Ý][ñ    j±\16°Lg¨¨0U¤\80\14\9fåµ\94\15Hh^\10\12\bIyä     (ÏD\bA\10\12 U\11ÐÒ"BKE\9d©Ò±ãø\18\99ÁÚÖi­uêô¿úçC\ 3÷ÃïÃ\99\9c¹\aEüý\10\14Eñø´ô\83\87\926§r\85¬"<YV\98)]\90×ð$Ê\87øÃ\18(}­{\1d,\\8d \1eËRP\1e\bZÞò¬\12n  Z0uï\92\15iäÜçyJfCöFæÝè¨\1da\v\8c\dô\ 2£·-rû"#\99Ø\1cY\16ˤh\14J¶PÁ$H³eò"\99<SÉæla\98Ø\82\ 2&yá\9a\82If\15¬\íS\17c1\9c\82Éd\94òÌ\1c¶0S\9eÏÈr\99}\9cT¦Ô\14±áñ¬o+v/\93)ÍÙ*\933\9coY¡ÊRp9\¦\9cc\15[\10ß È&d\aò\11²\aÙ\8f$!)H*r\10IC\ e!K}\1f@\ 4\88\10Ù\89\98P\1ceQ7ú\9bßn¿\e\82`\81Þ\7f)#fÄ
+«ë\95¿\v\ 5Ø\vA{0\18s\89\8a¦{\ 4\9f\84=è>u§\96rÁ±\12ìQ\8dC\1fKÌ'aqúÒ÷Í\94\18\9c²ºøgÃh\87\ep/\0ç^\1eŧ»$\91µz×-\82o\98À\80\ 6ú¹é.Q\15øP8?-ª\82\1f
+»D\0íìq\ 1?rbÞ$\8a5)·ÕP%à2&\9e\0ªÕ ¦+èüã=\8fÀ\86\87øKp\11\ 4J
+Mú\ 2\1dUm,(W\91¹Ò¾QÚ\8e}Õü=Ø<F\81­ð¸ÄXQnP\93R«ÇC\83O±kÖçp#\85ÿ\ 5\ 3\8eÆek[d}g]\9dnº±Úé$ú.´\ fxG+vQ\89\18þ\12F~ü\1e·\9e\88\1fÏ\9d\98¼zqà<µ«~ØÒN\9eî³}7Lû¢Ü\ 6Ò~\80\9dC»o\ 3ö\85\80\ f\ 3Q\92\eÆÞ\b2aç\10Ø­§ÁM\11XQ\117\1eN~\0\97%Âýðí»Ñ@\0ÖN\81U}M4|\0Â$\8fO\ föL\92÷\9bâ\8f\9c¢Å1V'ÿ\9fãR1úlVà\ e\ 6\15NÑ'µ¥\rS\ 4ÿ\14«±§\95¦\95¥\95\87h1[K£­\95\1c<©=NÏ\7f\81¥jÊ\93j(±¡\97\8fèE=O\80ã\89\0\98ù\f   $¢!
+\ 3!ùd-\90\80°\19@ÿ\rBÃçà
+ºm>Q\ 2\97(Á¾_þ\9d\1c¿ñû\15\9fm\19|'\9eM§}\ 5;Áóg        -Æ\eAwgñ黳\92\14­)Õ@é@¥\13K·su·       ¼\15¨°þKc]\14>ÝÕ\94÷5Ùåpu\ f\14»9\96+\8e;J\9b\7f\15\85¸çpñ!Íam\80\16³76Û\1däi\97%\89\16÷\e:ëÕüþ3Æâ +×\13[\ 17s¤\15?\vn\81\9f$xS\rX-¬\10áÞ\1aSu¥±´ ã3rSFBJìdîõ<\1aï\99:!ì×t(ò\89ä£ZncÉÜU=¥\15á,ÜÖ\8aá=\8d'ëj[H[ïHÉeòæÃá¹ky½\87½4î\85ÈMang\95§\83\1e\9c¼tY\1dÚI\89c\fãü\92~tfV\0\1aø4É:\10 j°ÖWR¹i:\15\9b\13 R©ªô\84Én²[¨«pB´~¨èÊ7£\ 3#]Ty³°¼B£Ê'Ó­?öÑ`ð\1fLl\98âÔ#\ e\1eo\vúy\16ì\99ÅÛð\18^1&9`6\9f9G\80?aD)6c®Sg\13x\eÔc'*\rÆ/)UQaY!\99`¼î Á}¸®\fó\9aûÍ\a\bX\8f­¹§\18jÿ¶np\90Âu##Â(Ìn\1em»à\98p\84\88}½xÕ Ê\19Ô\ 6Ba(\9f\ 53@\ 4þ\a\98¼#©«nÑë\bµ±¦Àâ«é\98\13\15ÙØ)¸\1c¤¯Ä_>\ 2K\1aZ½Þ\11[\88\13Fè°6Ë\19\8b\9a¨¨2&n§J<YÓí\84»ÛÞN9a¶\ e\e°µX\87\12\9fµ+¡\b\1f+3\17\99Bt ÔwQmm7ÓÍ\ e÷ÉFê>\b\14\8aË\1c¯69 º      (¬"àl\98×Ù°Þ7fßäMËÁ+Éÿ\ 2\f\0\15;^'\r
+endstream\rendobj\r31 0 obj\r[/Indexed/DeviceRGB 255 32 0 R]\rendobj\r32 0 obj\r<</Length 428/Filter[/ASCII85Decode/FlateDecode]>>stream\r
+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#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\.?d>Mn
+6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1
+VNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH<
+PO7r\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O(
+l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~>\r
+endstream\rendobj\r6 0 obj\r<</Private 7 0 R/LastModified(D:20070905115214+02'00')>>\rendobj\r7 0 obj\r<</ContainerVersion 9/RoundtripVersion 13/CreatorVersion 13/AIMetaData 8 0 R/AIPDFPrivateData10 18 0 R/AIPDFPrivateData11 19 0 R/AIPDFPrivateData1 9 0 R/AIPDFPrivateData2 10 0 R/AIPDFPrivateData3 11 0 R/AIPDFPrivateData4 12 0 R/AIPDFPrivateData5 13 0 R/AIPDFPrivateData6 14 0 R/AIPDFPrivateData7 15 0 R/AIPDFPrivateData8 16 0 R/AIPDFPrivateData9 17 0 R/NumBlock 11>>\rendobj\r8 0 obj\r<</Length 986>>stream\r
+%!PS-Adobe-3.0 \r
+%%Creator: Adobe Illustrator(R) 13.0\r
+%%AI8_CreatorVersion: 13.0.0\r
+%%For: (rmi) ()\r
+%%Title: (Illust.ai)\r
+%%CreationDate: 9/5/2007 11:51 AM\r
+%%BoundingBox: -70 37 543 830\r
+%%HiResBoundingBox: -69.7129 37.5566 542.2871 829.5562\r
+%%DocumentProcessColors: Cyan Magenta Yellow Black\r
+%%DocumentFiles:T:\d904\d4\TEST1.PDF\r
+%AI5_FileFormat 9.0\r
+%AI12_BuildNumber: 409\r
+%AI3_ColorUsage: Color\r
+%AI7_ImageSettings: 0\r
+%%CMYKProcessColor: 1 1 1 1 ([Passermarken])\r
+%AI3_TemplateBox: 156.5 140.9648 156.5 140.9648\r
+%AI3_TileBox: -141.6948 -279.1377 453.3252 562.7227\r
+%AI3_DocumentPreview: None\r
+%AI5_ArtSize: 311.811 283.4646\r
+%AI5_RulerUnits: 1\r
+%AI9_ColorModel: 2\r
+%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0\r
+%AI5_TargetResolution: 800\r
+%AI5_NumLayers: 1\r
+%AI9_OpenToView: -49 283.4648 3.17 1321 917 18 0 0 44 93 0 0 1 1 1 0 1\r
+%AI5_OpenViewLayers: 7\r
+%%PageOrigin:0 0\r
+%AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9\r
+%AI9_Flatten: 1\r
+%AI12_CMSettings: 00.MS\r
+%%EndComments\r
+\r
+endstream\rendobj\r18 0 obj\r<</Length 15485/Filter[/FlateDecode]>>stream\r
+H\89\9cWÛVâÊ\16}?c\9c\7f\88\e\15l\90\9b\bÊM\12\ 2
+B{\ 1ÅÖöR$\15(IR±\92´­ß³¿a?\9d·þ±³\92\10@\84\80ûAGHV­Û\9c5W\15ý\85\99Á\88nõU$\8dv¸Ø\7fÿ³õ\98ä\12\rÝâ"     dY\8côm\v\9b \89ÉqÊ\bÖ-d\11ª¯°TTb\f){\1f\9bí/13¨I>z»ÄH]\10\18²T\91\11\1f®kø+ ?c \8dâXG}\15Ëc³È\ e\97¸Ò\89DeÜ\ 1;}°`\85d\9b\16Õ\14¢â/,z¦}\8bX\93%Éxz\7fQê®­\8c¡k:~%²5\\95¾\81\ 6\98è
+]eÇð\80\98\16[\ 5\99W U)ë#f\ 65Ùµ\84Îa\99*J\Å\8aµ¾µE\8dõ\8d\19\19\f¿à»O-@gl\9f]j¯!62ç2_Ãz\9aù\1aƳ\99¯aþ!óEà(º\15\97U\83)T·Ì \10M\80P3\18\15h\9bq\13[\8a\8a,\1d\86{ÉE¦¿\8d8\ 3\87Tµg\18\94Ú_b:ødºÄP¢:lTË¿ýF¥\ 2\r\81Ât\84\ 3|2\99\99s{:µ¨õ®\9d\85gj_\14\ÒâN+1û\85%í-P\19§\96Ô\1ab66-p\11¾\91Jqç\8eºr¼oÏ\89D\9a/\9ao\1cr"\95l\rÔ\95ë`Ë68\ 3éX\1d\9b\13;ð7gØBúÀ\ 65àΩa\e\ 2¥ªçY§\1cõU\9e#:ç\90ÄÑ]¿\9f  '#\80\f±7.Ï%¾Së\12K\94ÉX\1eë\9c\80uÛzÇðF!:\ 18\82\85\ ftDÅ®ÇïHÃ\ 1-vÊ9\17ë\8fçãî5TÕvÅ\8a²\9a\fsA\1fT\91\81úD\85gìc\95[4KÀS\92óae\1c\85Ù. \a®¸>R\91.­©Úà)íätf[\86mU©.»\ 3ª!CÇ\89B&è.©g6\v        f Ûl\15ÿæ\1c!¦º9»\83>³ÓA«\8dÍ!wé\16@Þ]Ýæ.çwUfá\ 6ôÛÙ¦:\15é«n"'tC\ 3rð}`\80ß\80»6±`$1Ìñ¶¢þùÇ´õÁýÊ®¸®ë^qðÝÅÌ\9a\ 18\9d^\ 2\8c»°êÌ\96\80¤\96´3íÑ\83:S·¡K@\ fhÂ9U\89ô¶>\ eÔ¶\9c¹Êy"bþ\e\1e@\bÀ\7f\9cÈ,«\ 3\818fèmZó'\14]Å]L\ 2/ê*\1a,\1c.~ð3E\ 1\80ê\8cj<³^)\e\1aKKW
++gëÒ¥­é\98ͬ ¬4\84e¸:\9d`§D\97§A\83©µxY\10«\96\0»\ e¹Ò3a\9dñô\89\94A¤ðÅ\8e\97\18í#«\85Þ0\v\9aCËʼ°\11èâ\8a\9a;%ãÇÞ~\ 1Ð.5Ö\bé0\7f\8bO\1aAÙ~b~°Ø|Üw\9fµ&pÓÎ)Õ§ÐAe\9fùcv\r\1e\8c¥´Ë\90n\1a\88a}Â\9e5\95éÒ;Ú¿Íjp`]\9a\ 1:âNÓuxZ\aíéáþ5Á¯+./þ\8a.#Z\eNµ=üñè¾4\ 4TàØ\a\9di? "Lï&éý\95\92Ð\85\1dÝ!ïA§F¿\95\0\82aàuT£c!]Fl\1d]\9aÛ\ 33;n\89ì{Ë\ 4çF3#\9b©ÀÝÒ±ûÎþ\84\9bÁ¥3$ÖÙ\9aÎLD\16î\ em­¯#¢®Ó~÷\f\8b\99\83V÷ÍÀk\81àÔ¿\1e\ 6\8b\86õÌÕ (1\9fsÿjªONwkãòa\12®\19KÄ&\1c\17ÎÃ>kx\16t;úH\18¢\8fÖ®bªá\81\98\83l6tÅçTäN@¦søç\90­pá\99³ú®¿)Â÷p¹Á&g\ 2Õ9\99`Îÿ\80\89\ e\a\19\ f°Îõ1Ѹ\8e\81\89\ 4\97%\9d\83\8f\80û¬?\11èI8¤\9a\1cä±+Ò\91\89\98½b\1dNâ\\a\9cC\0\13sµY×1\ e¾O¾r\9e\1fÓøó7p×¹ùÌ\ 4á\0\9d\13^\83\e0Ï`tÀ\90¦q¯°ú=Π      q®¡\ 3~dàd\8d\18d\ e,å´?ÿHCçÁõáüAV\83?ÿS-\ 2÷°q\96\90\90ùþ\8a¥\91kà¥bë}<Bºs\r3­øÚô\91\181¾DÓÙ£ÞÊ3ÅÂCA\90\ 6Î\10z\9dÓÒ\82\91¼:Ð\9e»¹±fx÷\8c¯í¸sd\rÇ+
+\\ 4ÞxNª\93\7fñ\15\88\7féå;ÕFã`_Ä\8eo÷kæèlû.Zì\95Â\ 5t\13kîm\9fí
+\15\ró\ 3}£Yß\88EÂU\82âæföê¤\96\rå+WÇåvæ(ßú\19nW\98-åêµtû`+\95É\84\92IS|\16\a±äf¥ð\10ÿV)Æ\f³b\9e¦\13\10¦Rhm0ߪi        \83\93\8b\98Á\9d*)\95%1\1e\ f\ f>ÅjÉ? `N¬oås·Ç\96ø|/dnwc¼F[&ßèXÃh9\e²ëbf³'<«á\1e\84\11\95d³¿ÐÛfîPÉ]_Üýä»Õøõò¨³vùûJqT¿¯ä͸\16\15c[v=r,+\10ÆíWý    ôUTî{9A­¨7yE\18ZÕaî6õ¡#OÛ¢\94j½T\8a\9eç\b\92\ f\83\a
+OÛ/bCnl\b»\aÏ\9b|g7¤{IÜ Ù\860\87Ï\91¨T\93ö/"Õaæ±Pä·ö¶£Â÷ØS´R\r_Õ«ØþV¾n\86\86\ 5IB#ç\89DkJkè\85N%\13(ÇÈæS\9e<4eAÝ:
+ï²èO\9bou¶_\9c\ 2v*\85æp\ fÂd\v×÷\15^\97ÂZ´Ô.$rÚÏ\12Éå\12¦²Ç3©\91\8a\8eò©\89KIl\9a×й\\18çz{I9Oª      \ 4 §Ú¥Èn\f\vjî\ójøÑÚªT\eÅP¯\16;Ü7\1dl\1awÙP9W¥\ fÑâµ|\97O÷C÷®ß²¾\ 5%\95³ßB\ e,wÙ^öBwZU\16F;ÙÝ1A¯åV2u\1fj\8b       TÜ®oDo\99\13&ë|xp½¸&\10&Ùÿ«\91q\7fDËõâø©Ø«\9dzöÕXíÉó\96þ\91n\0\83o\92Ñr¹\16K\8bG\83ÒØQ¯T,ÈÏß\1f\4'\19\83¿3aß\ f\ 3VBs\92Âý4\85T¤téXá\8cûn\7fC\10\1fÝv\83\9e\1ce²·Ùg\89ï\8aÏQQI\9c¾Ô\10
+o
+ÙþÕEñD|,óÝ¡dñç\9bR\9bï¦÷\1c
+ð¹û\1f!X$ßÖn\9e\8eìI\97<ò~`ëÃhêí@\8d³\13\1f´\1fTT:5Ùm)øE;Ñr¨ÐóPr<C\98Úc*z-dn\9aõ
+cëL¾Ý;rQ:Ø',\v\b~\8bE\ 5zø0ßÍ\8f¥Ï¶Þo\95\a®ã
\14¢%;R\17Õ\94\90lîçáßq\92x\8eÊÙ>­\14ºÖ_|·iÙ\9f»9\87æLë}ôoØ\86ó®ëhÚK\9cðó­²/\ fq=²mìT\87ÙËÛZ?Yü&bÆbI|^*L2ñ:2iGë\98\7fl¦\Î\15w\9fêÎ\96=\8d\8b\8dç\1c\1a«\80\87êAçE;åÏ\1e\84v½ª4\ f\92©Ó¾\¯ÊÚ\ fWI\17àp,¨ÙRoê<kµJ·ÂI7T\9aK\ 2Â@\1eøL<\1ema\88uQtÄf/©ä{ôs¾óv\12<Ŭcã¯þáa´\90ù>×\93BäJ\95\98$ëJçîÝyz'Ô8\99ÖUÀùm\röôÿi¯ÎíTµ-ü,ÆÞ\15\15\ 5\ 5\ 1\ 1\8dbAQc\8b\1d\96èû\9fµ\16H1fß}Ç=÷\8fC\98\93Y¿Ùºa\b²f\94ª\8fëw­»)èi\19@õK\91êu¾9°½E\9dOî©\90h\bP\835\9cU\9a§\1d3P^\97¢P\90ß\80\9aR4%L­\88\9c\85Ø©\85\89\ 1\9c|\ 3\89¿\11ÂZ»\ 4î\1aP¡èK£M\a&A     ôJ*ÈvõsÄÉ'/k \15\ 6³ùîG$Á6F½#Pãèèw\869£ä\ 3í\8atQÒ®\11\12     ð*\e|w\8d\84®(ÎÃ\9e\ fä\bhÀÇ-(­Üê\81z\87\0dÐ\\93Çñy\ 4\8cÕêI\88)k
+\ 4R\1e\82\12\7fóEi
+Ï *Û\8b1ÇÊ~/o s\1eÈ¢ð\8dF-.\96\84\\18Q\917»ÈÑàW\9a\8c\9fÓë©\ 4Ì×Ä.Tü\12
+ß²Ì`\95ÌwjM9½zï³\19\14\17±°ï½\92®V¤\12\0y\9a\86ÿ\18DÈçâ|\17òQ\90@\ 1\8fhøº\ 4ùYDHmW$m}\84\1eËéX¨RF\8fð\vÎ\92Û³?C\ 4¼'a\1dø#\ 3\r\12\84ÍÇgÞzl!;\90H[\1a\15\9b¶%\88Ŧ\1aÞ\ 4<>Áp\13~\8bDÁAàf5\14Þ¹`ŧ\8b\86\ 6Ë6+TÈr\ eI3Ü\84\8eÀ¸*è[hS\e½\83j,\ 6K\17\87T£x!¹VôÑO\112\97á¼)Û\82 ð\1e^H\87;F¼\0\ 2Ó3sCYQ*ÁÏ+\967\8c;\90\1cû\v;ñVr©\a\94@5\90Ëb(þmV\7fM)¤J\bx6\ 1¨A¬ÿ\8d\159ö·\80Ó\16@$\94¾; Ý9§,oZÿ\v\ 4\90(\94´¿Ró\f\87\9c\ 5í"Ò\8fÔ\18,P\8d!\ f\1a\81\9c\83j\10º¡N\18KÁ²\8dFh±¤\19\91vG\8eÎ]>ouÛkdçC\10àcÇí\8d\9d\16(òY\8d\80«n«O HA\13\97\b¹w¤ÁÒ\15\9f±"7\9fÅõÙ»Gà\ 3c\15\14R¸Ü¢\ 2´±tG!ý\97eĹ¡- lÀh¶]\80FÞÀúmüfå\7f\0¯C«\15H(¯m·]³nzvÏ6"}G+\95Ç\a     \15\8c\89Ï\8c9` öÈvÕ]\ 3\8dóÃ\b\95Aã(2é´VõWçÀÄ\\bGk\10Pc\fÎ\9bì/\89ó«\12a\8a©\8e'*\fÞj÷\99\19÷9v\17Ç\ 6òx\9e9ùÐ1blJ`ÔGÝGa\9a\0\87R\83Ã\83\fO~=ãòű$²\19ÍWG×\87Û¥(:K
+§z*/Äcj\96o\94\a5Ü|Ëv\8f½>Û»¾\1e\84¨\94\f¹©ºÈ\10þóý\96é\86í³ÏÐð:Q.l»Âu¬Uî\80\ 2\ 3WuÓç\94\ fm}nw\1d\9bM¾¸îwÙü´Þåë_\91\85\16Àæj³W¶1\94Ǧa}¿Výno¿\80\1a\94p\ e¬\bÓ\84u²$þ|²üí½\ 2Eå!Òú³m\83Wåï^rß\99\0\8c
+\97\8a±äg°\97É\9f¯°¿:Á\0J\81\1a\87\7fWþs\ 6vX¶-ò\9fÃyeÿ\89'\8bêÁ¿\ 3+u$\rÂB/òùîæ\ 4\r\8cÛë\98¹9÷ôÙOQæ5\ 3/\82ÿÇAópÍ\18+Ç¿\7fÐܯ\19\944q\ 6\ 1\r/9~\17\ f\97\r\rr\86^\80Å°\1d¬|DG\95ä\9e¦H3_îP¹N \r ?!\92ØÊû$r\9d\1aÚ:A
+\80â\8c\17lúpû\86Ø71j\1aó§[&@\ep·ë SÓ\aöÍ\81\ e\ e´\ e\9a7\87ÃTBÛ6*À¥MT\Ìi\82¯\8eò*§\85\ 5,\85U³ÍG¹²'<}v\eݵ.dtßô£UÐLEг7\82Q\8a\ 5=ñU\83ý\960\9aØ{) ýV_yñ}\16ñ\8aÂñ¶ÀüÄ¡\80 P\8aù\92\93B~-Õ9¹Ã\18Þ\8c\ e-\ 3<ØmägåVo òáMÇ$ØÍù\14HåµÛª\93\92\1a«³ÕNhà&\1eÏ\96Û\81\89)e¬y+\1fS\ f\19¥«ó9B        <<h|\96\0iL48­\19\ 5\aEGµë\97\ 4GYù\9dÓ0Êc\13r\1e\8e\9fCj\8aÜ\1cô\14\9c\1f-\18ð1>Äåã3Õ\10ÐO´ÿ{ª\8d\Ã!}='ähy°¼Ü5(y¦Ø\18½\80ÓõÃã\16Þf{ÕÍ'È\rõ\851}\ f\81
+Ý°-\ 4\9ej\10Ê\1fß7\94fB\ 6ýÕPó¾\ 42\94oa~N¯\98b?\98\10\ 5¬Y02\82åô\97¢zë|²J\7f9\ 2\1aH=%N\99\f\16·z5Í*Ø2\1c¥½Å¡!\\17\r\1a Æ\8d\9b´ÅjU²SÚ_\96\1e\89¨\8c¡\9a_+\19ÃÙ\0¿Ên{¨\92ÿTÆ\ eK`\19ï&b¸£\17E>7Æ¢ôh\16±:´Sä¶ÍW5ÿÖª¸5ø\17»\82\b"Z̶Ür%G\19sÒüã\1eÒú\8dOt7q\86l}j@\8d\14üE<VX©\17¸ \14ÆÏ\97Ó\9e\15\99{H\83ÛäÇö}\ 1CúmZWå)³\9d\ e©\1c\1cþ\18whÓ9×.Ò\82»\0×¾eÆ ÜÝo!\1aÁUÇ\b³Ñ\a\ 1\85û¼\97\ 2C\ e/û¢Z[í\18òMô;¤\19ý\e\8f\ 4x\95%Vh\84\97b#¼\86$Ãò´ç¹É\9a
+       ëÜu\rÒ8.òÛs[B;\ 6î\95²^ø\ eã\eJóÅÖ\9f\1fè\92\ 2&_Ù'ÌSÇ\19¯*¼*ÄNÍ\e\9b\89°îèa¸rÀEÊ^`\8c\86\91Þù5Ð`\89\97üw²5`\15\89\81õHÄ\7f\9a_
+1_qâÆvºÉ\19¹\7f/¨ ñÃ\88så1º\0\8cj\12àF\8a\80µeÚ\17çÅ\8fä£V\8c¾\1c@¦w\1eæR^om\ 2Ì×\8d-¬Î»Dº6\88\99ï@\9a\v\8aï\12\17C'"\8c\b\9d\96^I¯\98\1a¹ÐèV\9cÓ\ f)\15àF\eã4Ù\1e1Å3\91þé\9c\93/_\90O\11ÄbíiO¸ÈÍfuù)h\1cçSÄ8(V¶¸Æ*ü2Íé\ 5o!\85Å.{\86l˺   \1f³Ù\18@2wh\13K^\92éW©õÛ\ 4\14\ fßd»
+sù     \10ïweO5¿\19Rô/ñ2þV­´*\83²µ6\9a°(í×\13þuÝípÙ!vu-·föß½\1e0LR²\18ª\97%¢6\15¯æ\82l$\83J\0¸5ðbÃǪüÎ;ËæÉs¢\ 2ö¤}ä\87(u{\82À\9b\05¥°Ï?\878/     «äøì^Ë\rÛ
+JÀ×\13çÞ@\ fx\18\9d
\9f×5@p½ð3¤Õ«°â"!²\19ÍLXE \18\86À°üjÉ\ 5ü\14\9e±°!\19ýãþ8ý\ 5%5¯Xag`wd^ßD>¦ä¢T}\·¦'´\97ÐXAaóDwGd\17Ü\ 1xÊ¥l®\a\168\17\96ð\96
\8f1ÅZÛÀ\ 5¦\fÊ\1aS¢ÏCN?¦\ 2ÏÕl9-x­sÙÑK¿FM³AWyü櫹ÿáN)¡Ä\94Óµ×\16¸M\84\93+h C3'8\1fë¼\1a¬ùA%g¼à\82\18\13\f2]ð´Äð¨se\e£ôÆ¡\95j´6üæ@Ä\\86\85@Çok;Ô\8a\9då)ÅO\8b\8f\9c£\9c\8d\85Þ\8cHN\88¶N\9f¼JÔu~\15Ùû   iñU\12Yýø\ 2´ö\8e\ f !wGO\9dlU\92S¾Ñ(%a\87F;\1c&÷â¢\90VC"Év_îY\1d\86À P\928%²4\87ûÏ9þu©ÿ(\ 1\84A\80fÿP^^K
+\ 2Y\18¾ßª}\87QÇ,\8a\8a\88Y\90h\ e\18Ç\9cuT\14´jk/öÙ÷4&tp«öbª\18hÏקOú»\8e\1a«\9f-HÖÜ[\19¡\84ö]ª]>\8b\9fG\10øÃ\94·x|A¸ç6Ñ\8fb!¨ ð\18ê1C\19ì\86=.÷õ\ 2\1a\95£Ch\98ù9\1cxÖþÖ0Ñ!$x\97´§\ 1\13[÷Ë6\9e­\96\1a¼ýH@\9fi/VÙ0Ó#\9eEySGðô\94\86\93\8e6l9\1aþÄl\12ó»M0h\89CÐ¥z*Ý\87U\øo±Ù~iÂÅ49\976\1d \9e\12|?/\óõô8@\ 5\ f\98\ 6\1a\ 4LȽ\94Mm\ 4\9dù9]?4
+´²®x\8cW«ÿU²fÙÿÌ´\97\ 2\0\81¾\9dAûÝý\80ÚÈ\10(^!vÒ\10ú\82]\18P\904¿\17Ãâs\91\1f@
+d¿u}\ 2\93·æ\ 2¥\94-±þÊ:ù:oÒ¤Oá=n\1f     ê\88°ÃM#»£\ f3ç>±\88ÍZYõÒÁ\91Xi\1a}\8d\8d\1dl\81!\9dp\8dtgB|Âg½ê?\98Ʊ¿\99f\1cåÇù\92w\15\84\981ÒzÊÖú6ôaG7¦ÇåõN\19"­+fo¥¶\ 6\ 1\95\15\8fWUd\987wL;\9c\9cD\13µJ\95n\\9a¡¿\ 3&¢²Ò~£Á\1ccö°Ë\1dÉ\8fKöØgUP\89'ë¹Ò¼h{\ 6ü.\aß\84\ 6\15S\ 23nª\88\98yn<ÖÉ\8eö\80\9b\8c%+³÷:Lfö\r\8d\86t5Sî@¸7ѧ@\7f³f(À?¾¢\ 1³\1cA EÏ  ä¸T6tÒ­êìð\8eË\11ih\86¸0p\1f\89x\93p)Á7\86U{\17\ 5íÔÏí\98í¶\9ae¥yíÌæ].>)²#)Û\92¥        ô´É^WLÜÙ!Yîh£®ÕEí\8b²y\13·7\85«Úæ(û|tÍ3\82\99\a\8dÍ9\7f9ãÒ\8f\904+\vÐ,39^\1eNÑ¡ñãah\8f2-|?\9b\98\ 5óÖy¯\87\7f\7f`Vt\ìÒq´\91çÂ9Å\8f\80añfè[A84t#\88Æ\87Þ\ 6TWÍû\1e\9b°û\10\ 6\91@LhÂéTbÁv!@S\82vf0j\vZO\9a\9a»ce\vùÁ\89]$\87Ö\97 \8d   \98ÙË#´\91>\1a\ 4d|Zqü??\8fÁ\ 5L\14ùÑy\80ñYçB¦ë;ådLÆö6¬?]\95B\9a¬ö\907òèr@]6Å®"¤\15æB\7fC¦O\1eî\96<üì6®\1e£ùÑÎî\9dìÖÄî\97\91\80lÔÊB{\88hh³9\84\95¤pü\1eb\8f   È]\83\17\9axªÌ\ e\vÊB§×9°ËÚ\99y4\11î\19_~<¸¬!\ f%§>!o2¤\9d"ÉS0Ö\80öÐàQ
+ÀD\9bÐ\14æ·²Ë\0ÖF­ÀE\1f¦+í!L^LþÉ\17ç«Ý\16Ý\88\f/\10æ.LY¹vÑ¿Þn\ 4ú\826-7£òóøb¿Ùm\11\9cß·\rE\89N:*\8fÛÐ\19\8e¸FãÉòñ\19\96ëy1ΤÌz6\81\19
+\fMù¤\14`À¤có6Q>\9dþ=@·òà ¿\99\19])\88\13\18\1d«î{SL\935+7ë.PëLLÚ X\ 2ÜÖÎs1eÃ\r;ëæu\16þ]?&\9b\95\9fí5ûä"ßÿh\9cw\9f\13
+7#Ý\11¦ävoP
+\1c¤\9a\97!z\98ïå^Z\ 3\r\9d\82\9dÿîqX\97Z\81´\ fc\86\14\1ey*L2©>»pA\ 3L\ 6_\81W+\80\ 1C\9eTb\1aÿM±\83M×fH·\87!}$Á4Ø\9bÚ\0\ 3áZn\9d\9dc¬´Ëµi\85\8cñ\82Y\852ÍU`(ºÚó)\86#0h\aH\10n\8a'\9dÜìbÝ !\1dá¦2\17I,â\8e=4\8fºû\ 5Ý£@½\88sh\1e\98\82\12\81ÞÅÐý¦]ó:`¶ás¸sÔù\9blj§â0G¶>ú\90±Tù±k\10BEÑgó\96%~\1f¦°»\9bñÑ0!UÄ:\19ï4§àÍ\82OHÚ`,Ø!át±¦{\93ÇWHY¸\81ÐÇ\fî\92\80\ 6Y]\15xS¥D ºï§6Ñh@[\86iu&\ 5½¿ñ =\18\89\8d¼\É\e\83êóú \96d\8d\9b¥E0Õt\1c¿cM\ eeÚwlÕVao"\81îRCZ^ÏÎh\97ÿIÃÇQâËEKÁÐW^\99~U\8eç\8drоØÉyâþBre\14¥"±¯\80t8\9b,klþ½¸-sÑseºøª²<ÖRÔÕdºðo\95©r]èþ
+4Îêæ°2±Q\9eìï6\12_\81²r®/f\8a:_ÌoïÐX\96b#î0g\95Ùe¿8\9cÑæô·Áà\88Y¬6\ayñ¯óýã?ÿ\11@\1f\8c¯¾â_\ 1º\91\93$*Â\82íùB·ìMGÆQo¦5\rà\ 1\ 3Òæ\1cFO!"Y\8b\87\1f\1fj\8f'ýC"\9c\91Ï\fÜ3\84_ÑVOM@·wÓ\8f¯!oªN®-nU%,¾ÖP\ 2\8c\ 5£|;\8b{¼¤Ð\eÎâ\9bDüx ÕuéÀ\88%ç®\11ZH+ÁvØ_\10hãt\98¡Â\14d÷¾\97ÄƼ¢gáó+.\8e\169UMO\ e®µ\9d2ãR\r)~\1aä¤\97kç¬\9d\80
+´Hfr¼\9c!:ÙÀ9©ÁÏó{\\1cWs\ fjåº_Ý9ÜýMáA¼«æ\96BßBW\86r\13ä\v±½»^ÔT5¤¡3·x{®¼Å+\9cÒ\16×\1c÷[°F¦\ 5\1eb¸Å·ÞÊ\16\8cé\12\7f\9c#|uôÄ\ 4=t\9fÖ\1dIÇÄïí\9bK\9aeàdCδ\95½ÆƸÊ\1fÐ(!\94±\89CøWØásG\975î-¡µÔþ\8e\ 1¢qE\eìR\82½\13ÎÖ\.øYððt\1daP´ÔAÎ\93õ\87\8bÔÅ\9b\16,\8eg0t*¡Ô\e\87OÔ¡:\18­\e\1f¨©qää9â\80y\ 3_©C²WýD\15m»i gNMZ~4[«[}£"Ì\15\K9ÓñÜOÞ\8cêMÌ\88ä\a*i³µzå\889\95èöp\9e!+\bcæ®\95ßRß\87p¢jFÅùåLüHu\84\88.÷FÕ17ð\1c\17\ 4µk~Èü©\19ÊÉStÂ\84ò~Â\ 3ç>~£V\9dη¸\86ÕV`}Í4a\a\999å^Cû£\ eØ\96~Èî¿¡%\ 6ÄÙßÄÌ©G1ÿF½'´\ e&ËxÂö\89:S\87T°cN-s\1eÛ\89¼\94̨\9aíÈ \1döÉ]1\13:\ 4{æTÂÝõ&vͲ)ÕÊO"oTÀ\18C[¨1\1f¨¤Í\1e¡"\99\ fÔî\bç\15Y6§
+ßH\879\8a\8buÓÌ]\¨Q­\8f¾:0\8b\7f}¥rý_þ¥x¬nÍ\99õi\88zíøÈ\e\ 3X\1cíõª\ 5jôøN-JåÁ\8dÚÅ\o¾F#~\7fÏ\9c\18\94ÐÅ}-ú\ 4\e©\92õB\15»3Ê\94ZÙ-Ä\8fÔ\82ÿtô=©(Ó\8cà\1f/Þ(\9e.æÔBxXäù\8cÅ\94*K\eé#\150\8d\12)\8f?¸ûÃâ-|\18û/ëÕÚ\968\ fD\7fKAî\ 5Z\8aî\82".X@\ 1\ 5\14\ 4Q\11_p\15VA.ÿÿMÒ[\12\926\15¿ôQÒÎ\99\99Ì\9c9ÃFm$\83·\93\98\89Ú{*¬\1dTx7$p/:\1d-y¨Må.Y,qPõÄÝÙïU\99\85
+ïæ^¾}â\86;\vÜ6J\1cÔ\87#åqü\9c`£^ußçùÐ\95\8cP\ 1\f\1dîÓS\7fÄE]L\8bÑ¿<Ô¦ò¬7ÎY¨\0\ 6tmW\rô7í\vV¸«ÕU2h¢¾h1ªy\12¹¸®\19¨ãÀ¦JN\9eüj«\95\15\88\8a\ 4\14\1dîu!úõ¤÷Ï\0jaEO\9eüb \9b¨ó\\9cB\r½\ e\ 3¯\b5S\1a¨\17\ e*\80\81\ÑQô«a\15\ 2'wyñ*iM\9eò\86ΰ®ÏR\ 6j1ªË\ 4êá[d\920é  Àh\aùr\9däÅi¢ðûj\bQÓ»¨G¡@aP«\ 1ÔK\89B\952¥ë7\135ßN9¨\90¡a¸³EA\9f#`­Øm4È$\83\80go\v4ïLÅ\86\89°Í\87\94É\7f¾pN·aI\9b|,­!½óB6\ 6\9açôpÊ;]\81\8ah¾sN\81äÐO®uã\14Nj\9a\vJãLË \17vùþ¾¨4:Å,ïô\8fÒ\98Ô\8fX§F   Ü\97\95¦t÷\9b÷¹®\ÿwÑá\9d\8e\94\9bò|Ã9\1dÊÊM/(YIc¼\90RnÏ\9aQÞé¡Ò\95¾RìÓ\13IYm¥_æ)\93¡kJ¯+\15\8c\17è\8eË\ 2\15×û\9b,òN\eÊÝAî\ fëÔHÚðJ¹;Ò˼Ï[Ê}ð×#ït¦<öïã\9cÓ\87_ÊãìU¶\93¶ûBNyê\1ek¼Ó3et4ÊqNG+5\15¯\1f:§tÒÆQ5÷\9cir>\7f       ª¥ðS\85wz£ÖÛ\81K~Òþ[¨WóÌ;çóIL\1dÌêaöéáÓçíñÉæ\9e}\9aY·¤HìòÊJ\1aXv¢5ò\85?Rªvvj\9c\92D\b{ÿ\9ft\92½\9c±O³±\87ÄIæoÛ9¥\93\16{L\9c\1c\7ft°ÏËÉx'»Ö\ eÚ\88ÝN\97ÑÉm¢´X_\19LvZX\86°åM\7f\98\96\9bµx¬VE5\ 4\96Í\b\;\7f\rÎï+\83Ûó{ý$\ 5~S*åRê¿r¹\94®'À\977K\93I\9fCÿ ;\9a\ 1\88A\aµ\bZY\8de¨»ü7$´@ºùû3\ 2öÌþ\16íC\80j_O¬X\9bÁô{á%\ 6Z1 \83e(ß"¨{\15ÈD
+­¤µ\f]71ê\86¨\86TGÀ\87oñÐ\89´`£f\a}>j 2IsQ\95Êm©Mj\ 1<\ \9a¯ß\9bc\1eê³\vj5\99ÃP'á0Ôi\ eðj\9dO¬mT\8dJr¶ÿÖ8¶P«ÿ\88\f\a¢8jöæÀA]m\9fÕ\14©\ 5 0\96dXs\1cT°q\82Õâ\81\8d\9a\1d\f)T\0C$ù#ÃEE«\ 5\17\15î\15\13\1eêÔX£Øá\82¹ßîóQ¡Háf\18\8a\94\91\83
+£!\80Û;W\eÌË&>úË,÷¼à{Çè=\8c\ 5x¯f\1f\1aB&³±\96ñ\9eÁ\e\99Æ\91ýEÆ^
+±&®lÿ)\93È°lvÁ¸SBÂÐà\19+¹Nï\9f©rW\95íÇ\10e               \r\94p\98×%¥:\9f\13\9fÐFÇö£\röÁð\ 2:\b\95þÍ\99CS\ 6þåa(\84\1eðJïpqm"\18\1d   a\80Gçp»¬ ·,ÀË¢É\81Õn\vü\e\ e\99\8fq\1f\13ãÐPÛé`ðòð\Õ\1f×U,`è1\1a\ 4ÈéS=d>äæÂH\90±\11XäìÄ\0ê°Lä\10dßÎa)ý6=\ fÁ\a(Ë¢r\81\92ÆrË~\vs\v÷IÖeãa¦Tý4­ Çð¬o!\8cwâÑÃ\8c°\15\89p"lIÜ\baßXA¢G\87{\8dÆ\1d\ 2     ÞôºÃÑ6nùnìKm4ov\82\Ø7ÍÉ\97ð\1d\1e'\10 ,\ 1á|¹X\93ÝS\ fa¼ËÞ¬ùê`髾\9câ"\864ª/åU\r\füg\9f\95z§Tm²ù~ö\15\81R5ç\r+_K\82\85R\8b\1d\16\1aÈK\ 2Á\8e\7f\97\85\fÉÁ¿\11\1d\ 6RÅlØN\13,\14\v£Úd§o oèöÜñ\bQ=z\98é«Jafúô\87\9eÄ#qn{\1a\9b\11#¸¢Zoø\ f\ e\1fk0¾dP ÝÊ´\95
+\9f.c'Kv\9a«­\ f*.|¬9µ\1f6âbsê\93®L×ó;_!±È\ 6T\10934v¹WëaJÈ\13Wu\9ev\12cUÚ·r3â\ fneºé¦ÍòÁ\vÚX\80\98Ö^Ö¢Ö\18¦\f\17aÒÌ\ 6T\97;\rø\92ù\12m@×î« hæ¹\v\97\v\1dm#@\ 46e\9b¡¢\9cÚ\18W2\8fÛR\9d\bƹUø0ÝÏ.Ø=\r"$§7Q r)jú\84;\96àk\81qEy-§\86\9c0¯Û,uƺ\16g)|Î~í\Ëü÷Ê\9dyEY\bÄÕ_\ 3\18Þ¤\12P\93Î%Wi\8a\94±â\8a^ò¤ª\8e\ f"5ÿ¢\8aÅ\ 2ó\9cä\95¯ÂKTÀ§Lé>wÉ\9d\9e¶G"Zo\9e\vr}r®\ fMO\91k\9c\1f¸ª\8d û\1dâ\f]õÒz>îP\99\8eG]Ç\94QÐ{X\9bM{\ 2\8e\ 1\18!kä\80ñí\98ÁÐ\96µ×ÈWÿ\87\92Fª½}\93ö\9a\8fÞÿ\Ò(vóçXVî\0\18\8c5N7§_Ôv\9b\9fÖßTÎ\8e³\90ÓrÕ¿5ÖÂÈÖºì\99]\ 3\13B«¹s\1a®¾\99\ 2\ 2\844\ füT{Ö\12Ũ^÷Z\ 6ÐÃ\²b\9cÛü[Ó\ e\8eë\r';\94\1c\14L\90\8fÍ°ã¨N:A£\94À.a\b\r^4\14=°úFäªF"[\8dã\89YÐ;Îxð\81\90'\19Zu~+-\1e\ 4@,\8f0i\93\8b=³6§kg\ 2
+-\8f/ZÌ  Î¬!ð\ 5\84\ 1\1f%\91[§¹ÚÁÌòhv\ 1ø`¬\8b#´"\11\1e×\9f\92\8b²a1  ¯Qf\17îZÄQ\9d"nm\82ߤ\ 2\92:Áû\17?F\ 5³\v\87
+XÊÆWâ7\89\88@ÖñyÃw\8b\12\10îÅË\92ùf¥\81\7f¢ç\e5^\9aU~¢´Þ2\14G8k\14o3\8aÿyÑ\19ü    6¢êÃ\97h\95¢h\óå§Ù¹k\11bh\90/\9fÍNäËivøEj·Ó?.\11ÙàÍ®y!\f\92\8dh\aù\01`m\8fa\ e¡\86¶Ò\18\86\8f\ e'}\1f\97.« ÛÎá\8c5ûý¢Z\ f\135bß\bQ èá^n 8\15k(³\ 44F\8dx\ 4§\15{·M¯\W\r·;Î\1aE9\93ûRDâ\9a¶Ra\9e\ 40=ãJ\9d¤}+$zÊÚýH\10`,\8c´\0à@æX+ª\97[\92à=rÃKÌ!\8cÆ;7\18)\8c\ 3\9b*'A/k¡\82v¦W\82\98Éb¾µ¡d¶Vì\86$.\ 22oÂx(m\90ée\9d\94ÙþÒgÜ\ròH\r¹zä¡\92í\97ëô\Ä\ 5\94ßѸ¬\93\9b}Sì\16bîéö,÷eÝ\99\86ö¼áU¼K¹çÛ\129\bù!\99\ 5Í®xPAÙ}© \8eÆ\1f¥Ó¾\97\ejò1\12\83*\r\e~\1c\99\v\13DN>ϹDÈ\\14\r>ü"\0=\18\81Ñ\Ùq\95ÁoÑ\ fï¨ùÝ\87\15tÿ\ 6\8eƪ\0\11òËâ´Úú`\8d?[@yO@ÚÚã¶T÷Ê!|8\8b\a[\8e k¾º\90U¯°yT1\86v-Yxs±¨»\15\18\8d\98¡ø>îÀh,C\89\1f\89KfY±\18Ú\8f¡¤ÿA\88´\0ÛZj\8f±ºÄëà9\16\86\12£}ÐÄóÜ\85K\a\8d\91L¤Ð\94í\1e\89\b\98\82ãÇ\82qëG\81ñ\ 3\1d«\8eVBZ d0¤\9b²\809̤}
+SÀnÄX£Ø\r¬6\871\8aÝÀoù\85\7fv3W\*\ 5Ý\9f`·ÞÂa7sÅõ§ïikÞì\86JÀ"87vë-öa7»=§ë¹¶7\v\80\9b;f\92\92_\16\80\86\98tânÅ,\ 1Ê\90\b\9d\83Ñ\bÙ\9e~\r\91\1dt>w¬¤ß\16\89\82UHÍ\85­lH\89\80O¥õ<Aª\8d\f~ûr)jÒN¡\99f
+\17[uZ-\ 3\97¢8%÷áo"\97\81\91¨þ0¯pæ\r8»àS\92\98bë÷¸\8c\v\93æ\97t{,Íïθø¼Ùµ¦Ö\e{2Î`©\15{·M$ ö\90-ðæl§=ÈÆÓ\90¨ðçZ\81Ñ C{l|\98\83H\8deŦNAC¤rÍ\88êu«\ 4hkü~ôTÿôp\1c\aª        ³oðù8\ e4¾öQÿv©Þ9Ãq\8f¥\10na,õÏ\1a\8e\98\86æÎG`Í\8fúg\rGgñ\0ÖöWÿ¯jàðGÆÚ8Ðü\99±\ 6\f\89èZowÒ?2Ö\80!EÔ\1dgÅe\eREç£ûpDd£\ 6\92{ÏG|8æ£25\1c\11L>êsÉ`ÌG\14?ðd¸aµ¶É\ 2gÊtÓM§ß\83y\19=<ô\ 1pLå:FdÓ\94­0\1a*\ 5xg\8eV¢}îÞäƼ\ 1ÖöísÇ1V\93;,àɼdÒ\8e|Ý&\80á®LàB{âë,\87¦ûHæÛrp\97ô\89²`o²\94Oü²@K¡g\9fQ\93*Sê\ f\92Ô\98\ 2¿=­\85vO\81I5p[ã®ÛªÜUeû1tâÇuÚ5áÛ\9b$\94M\81&+§4l¬±/yÇZU
+ó¬1G\8dM6\ e\99Â\87\7fÖ«t+\91^\8b>\vS\15óì\ 4*6P\80\82-"Р(â'ê\15\95ùýo\92JQ©\90\89áO\9aåª>ûÌgﺮó¬m×Ëâ¤uÝÚ6¼#$¨f¹þ#hhÚ\1agì_\17P\ 2ý\13·\ 5\1cOø¯\9a[}.³\92\f\19>ÒSr<À¯x¬4`v5®Ã`T\98Ï/ï>Ëßíá èy[\19¥3ïÕs©yY7®bK½PjæNºÅÇR·Y|4Σ\0\ 6ü9^*ä£ÿ\15
+ùX5\ 4¬=L±µ\17ß·Ói<\8f\97\9e\94\ e¾»ù\89Æ\16§\15Okúݳ=\89Ý\9eþêñØEg5\9f\9f»zÑTíý\1cµ\0δ\a\86\e\0ÒÕm,Nï3u²É\ 6s7X'õHè¢qü\19ÊþwwK4\r\89\19ô\9d»&\14*ÚÐ\b8Ýí `&ª»ô\16ã¢ÆKÍü=\aõØã»ûßíÐ!qÉpÓÝ\17\ 1j9rF ¾i\9aÇF\9d/2¡Å\1a5\85PM\ 2\85\93\9cî|Ö²\16jùÛ\91\9fDM?xmÔùê%\11å¢\86γ?\r\92\ e¦¨p=³ãU\9f\8d\9aîö¸¨ Ã?I
+\15À\90I\9e4\9b\T­6ú|ã¡\8eø¨§\7fï;N\19å\f7nüí\959¨§\15ïo*;à¡ÞSu\85÷\ 6\8e.v\ 1ýÂ\1d\9fÙh\ 1öwY\85ï\0\f@ï×\94\ 3uó;L3kÇëÿ\91Ü\98àÒêÛ¦\9ekáñ¦]̹\v\8bu\15Áÿè\16×ûhJNÕKè\17\1ahP<­®M¸\8c|}=üÒ\13Þ+&\82ù¯\12\8b\89#\18&á;\99²7\7f]\9b\13\9e\9b\r·\86^½Â\16\b\16c\943÷bèr|vmÑA+¡79\v¦U\a[k¥c¹\81ÝòsSå$Æ\9b>\81g\9d4     7®ë®}Êgî4ìV*×nÞ\1e Uàø\93M\vÚ\1d&Íqü=\ eQÆï\83     \18\8a¡!N\95\9d'Sß\b¬q{t«\bM}Ó\9dRAî\18!·Aí¹QNü`¾½Oèznº\95Ì?\9eÝì\96*çÚ\89NÐÚ!)\a°Ñ\rOe\94Zeí<\e   ãiQ¶\95!\ 5c÷H¹ªáE¼I¤\81ûwK!YõP{Öì4bÕÚu0B9¿Qå\90V¸(^4\1f~\86\9d
+p\83\ 30,å»mp}\8f\98\89cµ¦Á§Áu&>\1a\ eZÒ¸\ 2\1a\8a\8bÕAá\9dS¸[HŨ¢\8c\1aÕ£\9aÍ×éR\89\14\81­R\98\89!V'ÈÍ{Æÿ¨ _¥*\ 5\9a*D{¶)³Ó¶±\96\ e7H¾ü\9a\9cØÌÂLßÐ]££ÞqC¿&W²1F\82
+<\bÐ\\9d.\8dYÕ¡{à\96\17Ãg\16\ 3­\9dà\9fW\83\92    3às'RìY¾\81hR\ 1\8ec·IV\98\16O\8b}NB\17`%\1aaóÁ\9fffDÒ0   Ä\95\86$8Lð?ð«\f\13c\90\b\ 6\80Ù\96\95\ 5§ní'élâ×&PT\91ǧK\19Ç \12É©0ðý\19rhñ\91\12RÚ;2_\16'c\112T\9bÁ*\88.\95Ô­\91\9bç\93\84f\93j\r»E­\7fÒ­»\ 6.\9fZ\ríÝ¿\1eÏ\8d3¼QFN\rÏ|
+5´d\944_íÈ>\1dashl-z°þjÇlSÖ\86ÞÃZü IK\1c4iÉÃ%-µgÒð\81Åí\16\7fyVñ~Y½üQ¡\88<\8b§)ÑÜ
\10\912wìÉ\99\a>!\18\96\8d×TEÕ\ 6Û\80c÷ e³a\ 3ÍyB:ç\1f\15\ 5\16\85\12=¸ÌIçÜâÕ<\ 3\1a\ 1³£\8dËÅ\9aÜòå\ 3\9a\eXn^Z⣯Q{¿*\95Û\13é½Y\13\1d&×Læ;\ 3éÜ\82t\0\18qF¸:\8fî~n: Ç4ÇS\9e\11\11\9f\81!¥Å!áÚøU\18fÎ_\9cS\f3ù´øX*d]ÞÐà\98ºT\9b\91«¥L\ 2õu­\\ 2\11¹¼æò\8e\1dxÚ×µêìÛyâñ4\90*mïT!\9fR¹v\13ê\9b\ 3¤ª\ÿ\11÷\ 1\9a\eBipû ¸\14PZ©O¤¾\81nu§\8aKAæ\93³¥ägM\90*§^\11ùd\8aB\81[ÉüãÙÍn©\9aÚÛÂ<k\17Kh¨A"$n¤²\8fì´ §Ó~n\12ÆÓ¢LvZ\8a=\0åªÆÝÐ)oÆï\15êFSR\0\18¹ª¸¡éûz\96ðh¿h>üà\ 3G\8f\91E P|6\83ß=¸´\9f\15\1c\84±âóÁG\83O\83\9béøh8hIã
+h(.»¯\9c\r\r\vï\9cÂ\9dB:\9b¥¨öq\90[ÔAæ3ªG5Þy¿\ 1\99°ðtbìÕéÌ\r¼¬²ÜÀÛ\8a\9dÎÌØ\83\a²\83\ 6O¡¡9GÚI¤c\9bDzZµ\894Þi\9b\bJDºJ\13i^G -àh
+2æ̽O¶
+Ôt\b\80IåZ'º¼ >³ ¢uZ\ 5ŨÖXÁÙG\9aÓñÎà\ 2âà¸]JÞ\9bêÆ\19\946êf\97\82Â\8f\16ã\7fTHIJQ\ eÉ\85\96îV\13lÉ(b\88s-ßÑ\8e¹q$\86<zNÊáÈ\8d\87ÍD\9d      z/D{
+cL°NÇ$\9báZ&áÂÔ)^\vÿ&é\bûòáhxǯó :\80üj¾²\84\87  a#l>ØóÄ/×\9a\93\8e\12¦P§q\18)×Úöço³Ó`Î\13ûvZ\ 1&Òo[¡dÔ\96\86\82ªî í)0\14:H\a¢¡÷2\14\11[\81\rmµ8¾-C÷²Ì³\16\89e
+\1fé)Ù\a/\81Àæ-ì4i)FO\90H\87Á\rí\98ÇæÞÔ\8ftÌZl6\81\92\1f3n6ß´dL­6è\913\v\1d\1cΣ\04þ×\86\ 1\7fËLÄD\9aVk'SÎì·'Û_\19Jx Ù_\8c%\81«Ò\vh\8a^#<ÖIä°®ë<kÉCl\ 1\90ó\a÷\9eÔ Ó²\ eÁ!\fµÅ-\0;MÍPwº\8f;&OC\86¶$ù\1cwH¢\ 1û0Iʨ«øhÙ\8aá^\92n7P´lÜQýâØ®~ìs\12º°\8e.¦ùèÞ\bçÑè_\ 6éy4ú\ 5q\ e=Ô0Úú\86\9eÇît\9fy4»ú]\9f\99QÃñÜ{\1e\81\ 4±v\1ao\1e\815ZSîBÕaÎû\9e}Û­Í"ü$Ì6\86dó¨"q\91¡ýæѲ\82\87QvÖä\86\9cóÈaý$¹å\11\7fdíuÁ\9an%\r\91\ e7pÒð\88àáW\rÇ\ 4\81¿½éCCD³o'Äò0úã\12µ<ð²)\80ÅÒXì[\8c\7f\òcK\\11ÿ¡­mM~,ªÎ¶\96¨Öö\946ýY*×nÞ\92¢p§­\95pGÖNó­ \r-5\94\bæ¿Jû¸\ 3£A\86ößÆÐÊЫW\14Ô\9aÔ\90@A\86ó~ÜCÄ©ÉÌl\ e½Y·ø{!Ú#wðËMΪþÝ}"ÜJ\84ÑÃ\9dGÇ0\ eæ¸\ 5\9có8\98ï=\8fh\18A\½¥`§9¨\81\1cÇ\9cÌfÆÏW«\88\1a Ú\98ì\0\84nfs0\17ÔÆ\f\932\95øå×\ 6X{Z嫲Æ\83\ f\96\9ep\1dKy³Õ\9aÂxZ$H\98´ã\83iOPжDÉ\12¦\9c\e\fÕ\ 6\8eðønÇ\18¡OD[\980\e\9dA\91F1cLæ;Ý\bÅ\18Áß\9e\89ÃBÖ\86O\1a9õ}]\bv\14¹\14ÂJGº\v£©pN\ 2¹\14àÓceÓÁÓ@¤c±nòPÖ\0`·È¬M¾3óÊ\92æ[?\rÓ·à\9fW\83cm© ÃÔ\98M7\94ËÜßÊîè`\15ä®\11\14\8dUÐøh8h)ZãÜ\8aB4ƺ\816\8cè\°\9a\f\9e\9f®B[ dáÚ°Î\85Mèó`Õ_Ï\19\80\98\13^4\8e?]þ\86÷Ä\15þüzp\ 1\1aUsEN#\ 3\9aM¸ÂÅÆ?\0ã
\9f\1f\áÁ[Ó\15lþ9\86¿êðÓ\82+R\1d\1cÅc\9dñ     ¾O\17\931étÅû\85~ÅnO\7fõx좳\9aÏÏ]þhªö~¾öÄ\ 3W\ 6$P \8dÜÆâ´\1e\8b\93\99\1eÌÝ }õ\bru¡{'Sò zR:@¸ù\89Æ\16G\9fþWocl7\r\89\9a\ eô\11ª}Ö,`\13Õ]z\8epQã¥üñ\1d\aõØãýMe\a\14\8d      Ü}f\85\8bQË®#>j¹<ï®QS\ eÔÓ\8agv¼ê£³f\ 2\97¿\9dI~"QÓ\ f^\ 2õôþªA ¾i\9aÇF\re¿[\7f)TsCã$\a¯þ\ 5§lÔt·ËGu\97>â\Ôxé©â\10\1e)*ɾq¬ýÊC\1d
+PËñ\f\85\8a\96\8d\ 5<_|Üx¸¨®¾ç¸ÅËpX\14ëµf)\ 2»´pt#È\ 5ô\v\17ãïêMé»;Ï\88õ\1dì4êS÷Ý\85KÁä|5\18û\88c
+£Þ ¨Ö\ 4\9b0a?uc¹²\v\86}\15Ù\9a\8b"·uí\aÁè½\82½e\81«\99\89PΪ\9dðº6¥)GqÌbBèÁ\94£\eñ³6?ðéj¦à\13\84\91º5w°³\r\9f`Wù×é\v²\8e£)q{E'7Nªrc\86O+\96O°6üTÕu\9d\93ªºk«òá-ÀpKwï\9d*\94'tù)ÖI\882xüáÝ'¨'¿\ f²!±O\16UWëªlxÇ\b\89C`\ 5ù®Ï:\a\890*\9d\eåÄ\ 3ió¨à\13lh©[ñ\83ÍMü½\96î+¥
+i\ elhJúô\12\9d@\98\ 6ٯݰ¹qÌÕÉÖ^j\99{6\ 4êÃ\92\96¨6åªÆå«\80       Þ-÷V    \10\ 6|\ fè¾ß¨Êè3z\86\9d
+p\83Ky³Õ\1a\97C[ñI\83ë{äJC3E\vwn\9e\r%Yð\12ÐP\ìE\ 5
+OÉ\ 2\92un\13R1êhò\8dö1\9fÑÿY¯Ò®Ä\91(ú[Xd\91}im\98\16l0\80 =.\ 3J» ´éf`PÙþÿTU*IUQ/U!~        \1cNxË}Û½WÙ\18éM\9brð*Ì@n\1e\97þ±\11\81q\86\17\83¦\96'^Z\ e[kf\1f¼\95\ eV\ 4°5\81;L\8aï"q\18\87/¼³Ö>Ò\93âÖ»\ e¹\7f#Õ4yнÕ\ eÅ\84\92Ú×\13\855
\8bq`\15\ 3ûBËnbHêÚBnF+Á\14®\8dýÂiÞÜôs;±MJIi»\8dÃ\97E0ÍÜô=uâR\b\ 64NÎZ½lW\1aÓì4Ï\18Û\18\eÃsÙÆ]ÆH%n\ 2h£×6?g\1cåqØ\8e\9aò\90Õ9ÿºQ]\14e\91ÉË(üç­\8còÐÕ©½j)^<ÃVÜq\14\13ÙiÒ°Ì0ÄÄNÝáÕ\89 ï~\98\89?WC~ý\8b´\95¸Ñe®óÊÁ\9e5\14Ô\9a\85× ói\1d\8a\90µ\9c\92uú±¦¤R¾@+|\1ehÅO\ 5­\14\104Êÿh»¥I÷×*\9dèÌîå?\1dt\83Æ\86\97\ 4\16³¾;k·\e\8fó\96dÄ:\98ú¶}sRÆ\0\99\9b\13Ä\86z÷àC\80ç¼ \9có?\9dâÓ¶ÑóÀÆyÐ*\95ßÝ!\17\bÔ¦®\9cs\9b\17Ŧ\1eSJ\¥\8dÚÚ!·p¹­Zó\98Ø2Êj\19sf\ e\82U©=xWÞ\eÂu@®YlÜ\8f\94s\vÀáRu\84Ha\1c\8dwü#ÂÀ\ 1iDK­IN\1eÀgpJe?\1aÑ¢\97È\8d<¬à\1a±ºv5¢\ 3Z=q¦ä\1dl\94\90\8c\9a\9dó\1a±(\93Q\ eú^¼ò\\7fo\10ü¯âq\88r<­7\11\88rø¢Aç
+ÊáKqÎÎu(\87\1eTõêõ¥/¨\\9c\1c\19\9a*\8eºn\1fäÍõüÎ\8d\89ì4\1fañ1\15uc¢TÝ#¬ß\85ðpO¨\¯øÞ °|\r¶WL¼
+U/\e\ f¨\8eüïO*£\18ÉT\8aVæ9^2uEÉäx\90\878Ì$\0íY\8a\1aÚ3fiO9h\8b®\83+ùoI\90\9eÑãëõB/\ 6*N\ 2\9aûP.\e\94\!\1e8¹R}ðÏ%ù/vÃçÇò\94\15¹ô\98¢\1a.ó:y\99WY¬Ö ËÞݹì{¥\94ÿ\1d_Þó«Sì ku&cdu\ 2¥ênùÛ.\ 5\86¸QaóE\ 3\e\8eÃ\9b\80\ ee6\18 ÉZ\rPD¸ñ4Ãrú\86\ 1¼^½Ú úþÐä\96M©Þ?\byzp\99\15NéøC\ e_õ:\ 2f\8dÇ\93o
+¨#z"#ß]\ 5q\1cNZFÇÉÜ0\9dñÑã\199Ðé\0\93K¸É       Gz·ãáä\84cêÙ¥.OÛ  &ÄÓò}&\18U½$jϽRªµ\87\1f\1a\13\8cE¡Ç\10\7fôÄë¹Ç\ 4#`\88Z\ 3¶7\8b\8d\92\c\80\8eõ\1a\1a\9ad\9e\e'\13ä\95\13\9dÙyÝßz_>rÖ\94ÇϪ\979\1e¥tW²PMz\b\9a(ÔòÒ{\1fhRÚ&Q\ 4®)J díA{Ã\8b\89bk'\9bà\9d\860÷3\85ÒN«µ¯\168\e\84y?°!\81ÍÊZ@Ó\10>\83{\86ãÊ(b(è(ZVx\9dë®NÞ\10îoÚ·Õ¥\875\9eÈJc²MY;\8d³Æ\93м93\13Â-Ä¿e½'(÷o¤\9a&\ fÒ\87\16\17\bÅäó83µ(\12\0E\80­\1dj-6æ\98\81hÞ¾ÉÐ\94Õ\86\15\9b\1eÌ\ 2³8üÊ\rç\ 6ýö\1a\1f\eBÄn§Ù\8b\98Ù\9fÆã¼%\9b\14\97\92È\13ÝëÉÎ~?\b½\10\13FO\87u2\18BB\r[+ô.\82o\81Á»ËïýS\ 3[Fá\95\94
+Ì1\88\95ÂacÖòn\ 1MCÆÓºí+\1c\\e\99!5É×\bÇ\1dFçz2\86Ò\8d\ 4m#\869\83ó\88\ 6E\98ÇÎK·nWÿïkro\91\eò©Ãô1'Û\9d\9bd\1e\85aÄ×Sc\1e\8dÇóU\10Ý\86E!jûÁçÍã\80Ì£Ï\9d\ 6ÎãÀ{\1e5©:Æ<È<Zí\86ÎzÚv\13Ø\90l\1eýJ\Ë\90ïy\94\9c5b(ð<b+üqd\86\91\83ø[Ö\1a?+]\99\14Ñ\9e¶5ʯé\9fâH\16´Sx2~0\134\ e_(h6·<\8e?\\89+6Ùã2p10å+(%®À\7f\83¬\95\8f-£¼ù\ f¶VÞSÚ\10Hq6\14s3\1adkáÍpGè¨Ì
+uãÇÐàÝ\7f\ 5DCÃ\8fÏÈëq©¥ÖÔ\86FÜqH]\16\1d+§ysÓÏÑFBwÆî4T\9bM[zjÆáË"Wý³¹[ýÜô=u\82FÑH\83£M:\82p\ 1{\1eÑ`]¥\85yD¿õ½/\9at\1e\85a´Vçhå1\8f,5\0\8e9\8bæ=Φ\ 3\9f\ e\9cÇ\837\9aÈë$ä\9d¦kÊ®\rò9<\ 3¬M#êÆ;°ú\85\ 4vø}b\0ã\89¬Í5Æ3¢\ 3Z½z}ùIÚs´Ê\9bãQ_S{Þp\87\80]bÕDÖãøúc\8c£\15¹\9e\85ð\10\b\8bm\v=Æ8Yï2ÆÉ\1a»Q\93F\rÆXlÜ¿n¡â\9e\12\89ëî\ 5÷À\80\99-\82'\81[
+èá     ó´É\9a'\10\924\ 5k\85\14rS|Ú6zª\83\8c\1fÔZù\1d´V\8aþÕ»\90\99òÏl\9aÙc\8d;ÊT\13¯\11[Fí\16t\94Õ¶\ 6\fêн\81î\86æ:C8\17\8aí\86bR´\ 5\ 1My.\18\9eTûrù&uHëp±^­\8a\9bh\b)\99f(Ó­\fCéé\fg\83?OC©_Ùn(}vÓÄ\8f»lé¢\12u*\18\13\ 2¤ßF«0¾P\99ÔÉÍÑtµ.\1c¬ØA\8d\94âèoÝE6·þÚÁË&\¬V\Ts\97_ßâùÜÉývµú\16\8e!\87¿¿9\ e#\18Ã$ÚÁacµ}ÉfØ\ 6ἦ¾\15ÿ\ó\e\9au|\14\89ô?þ{\90{-\ f\7f\82^×áÖ¬\0zÅ[ õûÇ-\90îQ$Vè\8e~A^_Y¯åÛ(ãõë\8fÆ­ë\95ì´X,â:^G¦¦»\rK\ 2ȵetáäÚþ\8fó\9a\1c\82^\91\e\ 4òI\91I\97÷\9aoUò?\0¯G\91èÍ¢ø\fx\1d>¹^)O\8br ¯Ë°×vúe\0z\8d\9b\89ã©Ì+Îfõ-\94\85A\ e·.â ×Õº_\v\81^C§O\99\7f\88WûH#ÇfÅ\ e\81|£ÅH6\7f¾.¸\16\0Þ{Þ.ÞÀ÷,7ÔûòÙ¸ÿ[iòË\94v\1f=\9c\r\94õãw\81\8eÒo/\89\ 59¦,ëD\9b¤µ]ÁËɹ| ¾âUe\82\18¨U:Ñ\19Ãl\1eÎøs½+]µÎõ\19\16c-6Ä\97n]F Èc|\7f\86\1d\1e\ 2[þá\8c§Ã\8a\98\90\e\8f°x2\8cÃbcÂ$\8cYìÃLBv\bQåZøHC\1aEäÁ\9e$\18ý\960z`Lx<w¡J\82Pñ×^»|\94Ùpañ\14xo¨þ:t\9bÖn\ 1áÐã\88\12\ e\81\82û oÎÌ\81GL6N\ 44eWåÍõü.H\86\96\e\f(1ýe(prÉÜè\ 3\9fó\15\13ËÓvÃjf\1f\19
\r\14\16\8d\88*\98\ehu%ÝÕe\añl\b2CX\9dú«ËÀá·Ují%\19#\1d\ 6*\82azãMn½w5\ 3\9añ8\b   ËF.lÉãÆJîðûÄ\90&W/ô.Àä\98eCó\ 3\92ËD4\98{Þ¼ÊÆhå¸Hpm,¤ÛW\vu^1+/yo¢Â\vcì¤\84AãKö¿\0\ 3\0\ 36íÿ\r
+endstream\rendobj\r19 0 obj\r<</Length 7243/Filter[/FlateDecode]>>stream\r
+H\89¬WYWêÌ\12}¿kÝ\1f\11¦\0      ¤\ 3x\14\14P ÌÈ  \1cQ\86#\8a 2\ 4þÿ×ÝIH'¦\93 ¾ô\82\ 4vUí\9av\83ò¤_8cò¡vB\8eûÚ\¶7\15\80À5Ú\fÀ¯EéI.\ 1!q\17O\µSqòmFò«G©\16àò\91pG\ 5\98ïâÿÿ\9f?\91m\8e3 <éäDiX\10Ð\ fòà%pwÍeÎJ\1fú[P=óû\95\8a\ 62ëÐÕ\1a\9f\9aÈj\8cË­d     \9a\19m3ëà˽ê\ 4ô     \99Ñ~p\rf»® ¼{S¼ð\9e\9e>`3âij+QЦ²     \8d
+\ 5ÍX )^ª\81\8cÅ5Âè\90\ 4Mc\eû¨\11x0ÆfA\ 5ý7\8cÌhà0\19\ 1ÿTXf\92¥Iñð+J\1ex\89W\ eÕ øe\9dÒiÜ\83̸H\ 6:\14\822-\96ÕSKäuâi\88T(hF\98¯¸ôwßR\e\8ao±M,÷7Yµ\ e\93ÏAªÒ\r^=T:8\13i   ¾Cd:³¼X\83\17ö1¯»\ 5ÿÞ5\94\11×\88\1d\12\9f\13æ³\82Wä»"\8f\8eG\1c\12ôxP ÍèeTBÜ\14ÉÀÇÕ¬\96´fÇÂß %Ã/%ÜiÐ\fQ\8a?MòòboHKaiÊ0Ê\8dRÝðP\93\b\ 2VI\86îO\19{¾P\84\82\95O\984­¤\87ê\96î\8e;\9fæ^Ý'L\1aéÖõ!\83æ4Zæ0+Öê\94\1cv[ <Ú³8\87Ð\8c\8b4Ƴ½ûÆ)9T£ÁiÜ\ 24\9c\7f¥"¶°\ f&\92\ eeÊͱhb8·(ºp\8c\186vh\86-s*iâÄÇ\96\7f\874ãØ=\954ãt;\95´ØÓ>W³F;ø¤9F¬fuÁê¤ñ¸ö3ɲo¡\95ñ[ÙT-ß]m¬\88-+\r\97E\8bÖ*C       \11)iÛ\93Ö]a\8cFÛûe´³Ê.\0 \19\e\8ce²b\8b\81Ç´èØßoe4\ 5èÄë\9a\b\1dj\ e\13\1cî²~ê<D¹1J\ 4\1aFÀ~ÔÛ\ 3àÜì2²ã\9cÑÒM£\ 5Ì\16³\1e\95a\14\8d\9bL\97z+\97«¦cµ\17Pnrý\91x
+#\98\ eû   \82Isfä5\15üëªðñª\9bÆC¦\900ihÛÁ\90\12nCÂ\9aÈƧzbhòIiOE±t­ã2\8aªl°°5\8bª'ùmg\9f9¼=   \9d@i\8alPb\8e\895d\8a\95\88fQq\\ 4\86!\16¾\99J\16eY±\1a\1e\84\19R"8Î\8fEå¨á\81\8e*×½oE\95î\134ã([\RUj}Rë\0ß\bÌz\91\1a\aç¨1¬}\82f¾»5X\1f¡aí|:\94ÔáîùcªF\ e÷\10ì\13¡\ 5lÜrT\16N>!3ª[3j'_+,}\1fâkr\10\8fÓ;äI\87tQ¬î\89\82¶¾v\1a«5L©ÖϪQ,Æ­:\b·g©\16 n\8a¸/\15ô\91a\1e\98³½\ 5Z\93VE­X#B:ô£:\1eÆ\ 1¿z¨[\96Ö\8a\9fÕ¸ï²V7\ 5§\8b[}B8\ 4\97\bÚ\ 6\87û0\80\8e\8eî        *h£3`6\19u\1dã
+\ 5p\Öµ  \13olã¸\95\86v\11Rr\137\f»oå£\1c³V4\80k\13\9bùÖvUhf¸9\9e\e31\87Ý\8eH£s\83v¼êtjC%Èؼô\82¦\88\ 5]У?        ßÕüºfTóß-hãA\93ê4A_Ã\82þ´\8aHµýÄL£\8d\ 2o\8aÇ\87\1ap\89   X\96E¶{ÎR³©î\eýèØ\8eä\1aLF­~|pÆ\82\86ñ\85\8e*Tk\9aM{\94Ü7î\v\15&~&/\1f\8e
+       O\81o)c\\f]\87\ eÎvýg:1¦KáqÜ\18\17§u\a{ñ&Á£\93®\88!A¯ùè£\13A´6Vb%T'\1a\98¬I\e£g\ e\15ánóõï°\99S\e\10\95ÖÁ\96e6\95a#ñÊ¡z.~ÑÑ\f\92\96R\e\9a¤Õu\8cE¥!4«\rxT¥!ÂÅ_¨´<"2è¶\97¡\19[ ð©C\ 1£p\8e£Ó%\10o\8f\82úÆ\1d\85;\84ô\9cxv%\1d\8a\9ci\18-z\ 2\9aQ\84\86Bú"$nký{óuÎÜA®ïr\10ʨû\bq{¼ôC\8e¹\1al~u­u¬\b%Ø|  Ä\ 4\82\ e+Y¡\17´Ú\80,\\9cg!\ 4\9b\81ÏR+{!m¸Z\9d¯McD\17·¥Þêä-\83ö\9deÔÈÌÑò\ 2¡\89Gq\88+­Å²4´ØÉÍ\v    ¿óàÜ\9c¤aû]+\8daBQ+Í\19¨g_\ 2\ e((\1a\15h°þ\8d¸¬\15¾z[;\ 6ÈØ\8f\#vpç\1aÌv]A-$Ã<²¾x ¼]\ 2\vK=ûÂ|Å¥µ¥ëFæ³Ð\f\99°¹\1f¥aÞ\9eC\87\9aq°Æͨ
\1f÷ã+»\ 1.´>ª4\17ý\bÑ\u\10\fÍx¸­ihÇÝ)-ó*\r\87ÞÓ¥z¿ç¢\1fM(Ð\f\ 5è´~ÔPÔfÔï7?\ 5²îG\13Êa­Ù\0ÑûÑ,ü©ª_\1d6\bm*ÿ\18-Áw\88:@\11¢\9f\ 6Á\8b\0=~a'\92M\aÁf'æ\874\\16-\8blâéÈ¿0Ó\1e~(~¬+íÁ¤\7fN\10?\10J¬Õ\8dRý'W\9bá&\9eíÝ7ìG\96\92\eÛ©%z"\a§\7f:ûÐèD@b8·(\9e6D\11
+M\1aáh\8e\ 1\9aøØòñî\98F'\ 42^"c$\10\9f\vªeD¬\9aÔ\86\9a\9a\8f>âÔëfÆÕ¬\96ýf[ä»"\8f\ fwý8Ú\9aúQyvhFuBÿ´\1fa\\8f;ÚL#¤\81\19ö9Éf*H\97\99\ 6i ñVlê\13Z\8bÔ\98\e\8b0Mhâ\17%7\10êi\9f«Ù\93v8T´Ä\8a\8a\16÷]Öê.Ú\93"\82\8c¤ýùµ»'LhÏýM\962ÄúV\9b\974C\17\8d\94"ë¹,\8bÆêp#°\15\8d±\\7f\101)FøìÙr·X)Få\8aK\15\8dSÙæ\ 6G\ e\ 5J\e\9b\96ô\0ES¦¬\ 4r( ãÑ\81Í\\7féqÒi^\13\1a48(PÐ6>gQ£(\1am­Á+ÀT¢ í\\èÜ)\9b\ 1\97\eN{t´\ f;Îå©\ff\93\ 4¥Dc\89FY:ù¨`³\ 3)»B\97\1c\16nÁõ3pQ\16.v\85¢\ 5f»ïë\ 2>£k7uM\ 4±\ 5ÂO\85\ 4-#àµ\9b\12 ÊcÞ´=»)\9bÆVpU2:æ^Ö\9f\1a\92Zk\95\96I\96}\vÅ\85ò¸\95×\a\0\99\9b1÷EîÌA$xà&\aÛè+¯RªA©\7f\eÍP4Ûm¦ó~-쮪7âÅÃ]\8cÍx
+øWQA>+s÷­É\96ñ\ f¹\0ÃB\17\19ö¹<g¢éÅ\rw\99Ù$¹«ËÎ\80»\7f\80$-\ 4 -")P¬µ\v ¸z¯\83R;\19\ 1õÊí\b\r\9búçë\eh~Ìæà®\11O\82ûÊ{\ ftåù+è\81Ý\aè=§÷à!Ò\v\82¿|7\ 4\9e¦\9e&x~î¿\82Q'¾\ 3ãx\9f\ 5ãF°½Ýn%a+\ fW\97Û½øÕÛîG\17A\99=\ f \91ÐÙáhb;6òþRn\96o\93¯×½§¿oL8àï·|\17\97\1f9\7fë®T\rÌ\97~\8f')Ü\ 6½\1fÿü\95D2Ð\9c\85«0\8cÏ#m÷cfϯ\13·c\9c\16\1f/sS¼¿÷\ 3ßì\ 5>k­\94Ñù}\9c¨¹©ËР Yføù¢ÎDr\83\ 4\10úËså'éÎ\9f9wù\91ÊQøJ% \1dû\r\18_=\87p4·\11\8e\1aîv\9b\bõ¹«8{\r\8a¹Z\ e\14_ÿUA©yû){\9fÿL£ñz\92Q\rf6\12\97¾¸}\ 4BqÄÀ¿\rÚ@ê\9d\8f¶ò[Õ\8b¢\11\9a3ÞÔXÆ6
+\18Ê-ø\89k\14?#\82Ó·\11ÉÄ.À\84®n\13Ð\f\13\11Ø\1e\ 3/.\ 5\86û\17m2¾ÂE\11}\92\18®íÉ¡OU\86ûHÔ\ f¿«3á\8d\17Æ:Ù\¨¥]Ü£I\1eãÐ\10õ\89á¼x\99\7f\9f\b"\8akt}Yg¶Jß´VE)Ö¸\80\9fîÖ"ÿö\96\81\9fz\e0kE\ 3@Xz¢øïq_òs\a@0*à¯hB\ 6ÕO\8bY\18þ£\1câ2é\15ì}vá¯\9cú5\15\8c(fÊ\11õI=¡bÀy°\93þ-7I \9cUÀÍçª.ßÔ\1e\1e\9eà<Ø%UW3ç!ý\ 5\19C&Í\11/&¾|\1a\9aÑÞå#ú»Xîo7«½¨\bú\v¨ÉÞn´\17Mñðâ\19&Íÿ\ 1\84R:¬?ÓMã\12(åyâ\1d²®\ 2\95*QÈ9\1f\86»mÈA o(ö$/öðEG\14§\90\9cíÄ!\1dí0Wàýûb°\©\88Ó7.\8a\9eñ\98\9fï<uXÒhè*Ãé?Ú«k9ud\8b¾OÕüÃ\91\8d\ 1!\81¤\169\a\91\ 4[d\13\9c0Ƥªyºß~÷ne\8e}n83/*µºµCï´ÖÒ\9f\92ð\94À¥Ûî­´ÌT1h\1dIÿ©Ó§ráq\9d¼FÕ \7fv #ÔEX\7f\10î?Ôó[Z     \9bÉ&t5   9Ó;Ýåß\ 3Ͼ\{ùÔPêU¦k\91\11\10Kg¶sÆÓ\87\9bN{³"ò\84­\94\92\17BAÍß ·ÓH\99ró¡SÛµ.O\86Ñç\÷ìz-\ eWmQË´\9eÄ\15\a\ f\15\8cÍ\1c`ü4«ÇF\9dÊF¦÷\82¶{P2\91\aظײ\94(\9d\82\80KA#\85ð&\ 2*\9b°ø&YÜ3tO+y\87o²öö\9f;\836ѰȬñwÁþè8Ad\13¾)\9c\95aiý \¯ÎŤv])\1eFÉYè}\91Ù\15\ f\93\14sõ×¹egÞ(Þç÷\ 3\18NùFzïÚ6¬á\84Éà1,®m5\\ f]\80¥¹\ 1j`îÕX\9a2Æ)h\0\90Æ\ 1ôÞ\vËñ\11w\ 5ó^Ç°\8c@³        I^\1aCx¤>a\19ñQ] ¯\eÔ\8b<îÝÓ"§u\13ÊúqгØ\ 5\86\90Ú\83\83ÖgÖíHR\83\ 6Ð\14F_ò«§iv¬\aÃ|à\86Ä{^0Tu\96\86\14Ôh5ÅÇNØ\88ê\9ci4´\89«ê'm\ fh¥÷¢3\88¡E\1do¿\ e\91\8e\f*\85ù&·\923\83ϼQÚq\16£t\v\11ÑÆZTÒzk¹ïŦûÜú\1f¢?>~\e}ÀsÛ\11\99ûü%\8cÍò\86©p\19â\8e@ܸ¸XÛL        \82æ¾.7¥võ\e±.ÍZª÷\82ìnö\9a_\82*m$Ù\19\81a*Ñ{\ fô\19
+ä,\10t8¤\847\8a¶h\8e\8aë«\90`A?úí&ØT:âêæC\81Ã\aÎ\9a\86xi\9a\8cd¦k\93Q\1dó\ 1§\8c\97t\7fæ+ê\83\9b\1cû0\9f\9f\92NÌp\rߢg:³\19÷\90Ô\9cà\16?\8bÅdË\92ÑùYÆÙ!£â®Ø'u°ëѪ\ 5\9b8¤j\93HÅq\1aÚ\ 3_áð-@»\80þY0?Còðݽ(\9c¼\am¶ÁÌ\1cÚRÀðúÅw\93\ 6\8aJ\11\ 3@\85\v×Ý\18R5X\86\r\89ªqâ     \13ÏLm°%©\1c»\ 6baUܸ6\0T¿i\a¼4¤\10\9bãUi%P\ f)l\ 35®»-\99Zq@o|ÚE\96òá\16dÚÃ\19áÐÈq\91·>\9b\83¼0\\ 2¬o7;¸·Pç\85åä¹c7ð\94ÞkÉs\9egeÃ@í¾v\96u0V\17\ 1K\80a\1d;AÉWF
+p\89\16\11Û\95q-6Ë\ 3ßXNµêÁ`½\99ÑÄ
+\86Ã¥ì\99ö´ß       Fy°3\ 5\8cí\ 2\12Û;SÀ\ 3¨ù\95\fõó7\8d\18;bó½\1d¿\921;ü\17\8eP\ 1Vl.e\0Åý=G^Î\96\0ýÒlv8ª`üÍ¥]$c{¶ÿú\9c!ÏÂiíµi¾:´\8e\ 2eI¶\1d"wÌ·"¿u\13Ô8d\1c®L][\9b®Ê­ºt°Û±\99_êØnÓ¤â¸\8er{{áM¹ûá8°>9\96ï\8cÃ\9c\81ãp[Ý9\96\8b\83cùrºôfsv\18=ût,\17{Çrí\90¦¾\1c\1dËÍÉ9\bÒê\87SøÁa¹z¾²/\87××öåbá°d±vX²x9üª§\99±\1cÚc        ýÈ!cã0\7fñá¸æÅþ¬\8d$ O^êÍ)Ã!þ\b\1f\8f'd\86\9f#sÆ»\12y\86¿}x`üQÿ\14\89b\r6ä!¼¹ëhÓ\8dÙ
+;Öä¿Ä\ 2(7¨¼"uåì \158\92\ et\10T`'EP\97¢¸\87âuä\88\11²\ 3\ 65\1a\ 2æ\1c\ré\1f\1aT/¿ÿ\f\82\9f´ó§c\15\17¢\8d9\80öp[¥\1c\15\a2oúOÉ@\11/È£ñK'\8a\ 25\14H}\8d¢4$\ 6´\170lÀ)²C}uè\1f\12ü?o(D\ 3·qNh\96K
+\99­\92\bè\»ã\17\9f
\1cõ\15,ê·\91\94\ 1\b\95äÜí\94 \80ô\b¯åR^¬=¾Üÿ,\\8d\81ä\14o\ 1¨9+è\10åq\7f¯EId]QQºó')X£øÞfI\86½öKåB?#»b'\81(U\9f"\15'Ç2z3àÒ\9b\8f#)&¶iÙ\15\97\12x\87\9f\1a¸UBð'qÉîÛç$`\ 15\f×Ç3DyïÇa Î\12t     \91{P\10í¨°d#Ò¢1*Hå½+(»\99XIx½\8e+d~Ïd$¾ñ\96\95óîû&\r\82ÄmZ\ 5\8cM\91i&\10Í\8eñök\90A\9f9¢¬ä*ñ¤6A2\e¾¥        »möPW\18ü\8açd÷ü5\ 3Â\93UáU\1d\95I\91</hyXÜ\ 4¢)\bæ\r#[\13\9f<{¿yÉQ3G?m`X\ 3È_lho\16àæn=Zº¯OÙ(ÍÒÜv×8"Å\ 5íS\8bXJ\8f®í\18\ eÞ¨!J\15HþaÆc\ 6û\rbiP+\9dxUL¢\ 6.¥KgPsܠƪøh~So¤+^Ï/Ìø§B\0¡L%`þi#jv\ 6\93\ ez©©\94\f\89+¯7nlÄ}Ö\86T\9cÆ\93 ÆØËòÖ\1eñd\1aic£\14°mLÎÓ¬±Ñ\10­\8d\v\ 6EÑ´¥\9aÖM9Ë\99ç§T»q¾ä·6à\ eûÐoË\rAç¯å\96\88uËAÞÞ\84Àë&¡×!-¦7\8fÙD\839À·\ eG\ 1/Ҩŧ\84¥Ûñ\9bat\11OÚ[Áo\ 1zJZ\86\v\88Ã;"\97ñ*\aiYiÑ¥.w9\1cI\1a[\15Ô\12'Üv7\88\13{Z\10\b\e\8e¯@\8d¡¸\17°U&yïÞ\14ù\18;Í&Ä\81\8b6'£Ùq\1f\1aG¼dp&\8d³x\e\b\15¨P¼´¿W®ho#Âõ1Éõ\13\aP\13\83Í\d²òÒ\8eNØa\97ÑX\8d \8e\88\19\9b¹ìJ&çZ¦³çÕƸ\84{Þ*\ 6¢TR\98¥÷\ 1í¾\94aU¢\15\81]@Y¶ôò\80îBô·óh\8aV\16H\91}\9céö\92\82KéÉ\90R½ô7hT9/&\99Ï(\ 6\18\18x\84fÚã\1eS@=@\18\83^ìZhÑìT*\92Û¨^{È>Öok\1cu\15VcKÐ<è\12\1eê.\80Â=Ä\93e&Ôa¬>\1er³ÍC $« Fx}8\ 5Ð\18·ðÊÇ9l\1d\95(Ö4SÍ\87\91\194ëZV\99\ fÚl@M\ 4Ò=\1dam\95éËE ®é\14\aj\f£ëZ\ 2J|_Boê\ 1[\ 3â\9fS\82RKîDZ\94bhQÇÑX\97lGÊù}\18\86Þs\v+ÈgzÈ\82®qÎà\9eÚ ßý\v\ 6PT\94C?¢²L\ 2Áp0úC¸;¿¯\ f­ÃëóëÇ\ fþÏ?\12\7fþ!äª\92ÔÿXíJ\87õº·þë¤ì\96çíúãô#þCÈu\vÕj4¤¬\97»Õ\1a\7fÀ\10Í#66©\8d6\0"8\8aå¯\10\8a9£óÊS¬¼©\ߥ\1e\95'QM\9b»\84\82-\86\95+)\84=w \86\81A\97dØæ0Æð/¯°7\7f
+0Ü9ÞE\84¤0~ñ\96Ð,²ùkrMZTr>*GÃÃðv\98ôÏK»È½,®ì%7[\17(\10\169þ³YËÖcÇt´\92¼\ f\94vÃà x\18\ fEeXR{¥T.µ¤¡´á'#½cß9¬»ä\9b\94\90u\82\ fo\ f\f?\98\16Ñü
+\0<~Æøz¹0Ã\93R\81áÙ¬Âð³UÝv\ e\90_Å      úÜ_\8d1k\86a\8eýccÌ\9aa4\ 5þ©1fÍ0\1cÏÿØ\18³f\98\81\ 2þ\9f1\16Û\9e`Ù'´}\ 1°:Åt\ 1í\ 2\87Gx½þÛU?\82t=íÎFÉ´\e\ 1z
+4<\0\13\89dr\HðXáòA\93\v\11ÐbȺ\ 2¬1Ъ4\9a ¦ %t­j+`¨¡¹\9fXOÙ§ÂK¸ÔÊÿ\9bô*ëJ\1d  Âï\9eã\7f\88\b\98@HÒ!ìÊ\ 5\80(\8b\82(\8b$\17\191`À¹ãËüö©êÎ&£sîÌÈ1'骮®®õ«Uú8í\8bLê_\8a<©´ý2ç\80(\10Ù\91?\93\aÇüw\91\97\9eý³l©Ø\ f禥§TcSì\15Í[\9aUêù(2Æ\80f=j>Xº\8d\ 6ÙÔïäǦ\a{f\80\86¥\17XëÐÚ(B\93)\vìm\16¸\89Ñ7°z7Bß°¡\9dßÅëXÆ\87´)xú:\93\rÎ\ 2\fã\97qb\ 1\a;\ 5 û\v\ 5\80f5­\ 2\1f\vÀɦ·ÆY¯\81Én\1cEWZ\13Ëß\rÖ¾æQäõØBÈ\9f²-\8c\87å0*Í;9×2í°l\e\11·=»W£n\81\80z\8aa¤)TFüÛmeÆZ!\f|\92\9dñØ7!ãÅ\8f\19\ fÃGl\14¥ó\8cÛs¡\82\88­5\e J\12\8c\81]Sj\rÁ\9eS\12\9e\9d¦á\90ý sGâB\ 1Âà\1a§¢°ý \ 4¨\11\86Ò^y`\ 3Ô1\ fé©\8f¨Ò0\98D\11\144bv\e\1d§\f'6\1aPÎR7õÒô¹¨Cz>¯ÎW\ 1³JbÁ\8b'\87åR ^¢ð\88Ô\9a\ 1\89ÞÐ\81µ\18\99-Và\7fÅû\f\8dÕV\ e\88³\a\93\7fa\98Î\ e\vZl,KÝ\16 ¬§ßXx\84\13ë*\1eÓö\85L T\fÀÎÎ\ e\99o\80ùÇ©'\ 3×\ 4¿\0qYÙ\13\80\15º\14üV¡ºIò6QWùÌ0îõGº\16\bä¿Õ\14=d\96-ëlÍ\8a\92×\1a·\81j5ä     P\8c@BÞ\13\0Ç\f\ 6WEWÆ\92÷\ra´S±@E/Uîs±x87"\90\80e\91ÔÆ\14\83µdº\ 6\8e¿\91ØÚÃv\12§ÍÉ ·É\ e\8eù`ýã\13zÉ詺¸\ 6\ 40x³,MxÀN\19`\84ܼÝÂ|\b aøÁ|ö$\88ê?EFVü\11Ò"P±Þ¦\858C6-\93Ò\ 4þÛè\ 1TÕj@\ 3\98æ³\rCêè\emx\87§\1eÑS\95jãôÊç\87üP4©aÀ\90ºLÛ5HN\1eÃ1ÁÎ\8b:öl    ÇÔ¢ö\95ÊÛ®{¥û\8f\9aG¿Ð<K>h\87\18\14´£\91¦     cOAj/\9f\82811ÏQ\19\82 ¼p\e\99\81¿¢U H\98iWk×&+OmÌ/\9cl>Ñ|ìwƪ\7fù\953ä/\9d±ç \1c\a?w\86\10ñÉ\b\9d\1eM\1d\19gª'\83\7f\fvî¿\12à³+\1cóÏz|%CüWJ oþ.#ö\7f/"íY\13\8döo/¢|á\11PÂÏ'þ\83ÑöâQ\14\7fQ¤«~ò8\98ê\b\97\94\ f\92g¡P>\ f@MEòµÈ_º¦¨zg±pggÕ\1a%g\80rXå\88O-3\9e»rÔzQíb\a3!tåÂ\96u\14\1cÂ|\85*_»åY\15ô\ 68\ 4\9ap\8cÝãÚ\86Y\99?¿f°ÑÇÔI]\17éÔË\0\1f6nÜ.Ù\8d»\1f`Ó¬ÓVáM\ f\13¨G   \8dÂ\9b\13ÈÛÂ\1a>³QúÉ°@ç\15V
+TР    \884(r<\89\aOO§\f\ 6ü\18\17\16n\võ«**æÔ%Dü\84RèÑ%Ð\89ÀGë\13Ý¥í\r·?\\82â#ìõgÚ0 5ÏܵèÇù\ 6:ÅÜ¥Å|\82j\9b,Fð¥;Õ\*\14Ù\90\89>¿d(\8a<\8eC®ðë(cyÜ\10LÁë\18\r\ 1»B\ 5Õ\93<_Çe\89\93%\14t­ÐúIæõ6ý´åÎïFÄ\ 1èÕ¨Üê>câõDJU\85dÖ5LOr\8fQ\84`ZQWÝPEÌ\bãBN¹   ~\8a"\18Æ¢÷r\1f~\18Ò\93?\93\aÇü\ f\91\8aO$\91\8f·§Ñ~ÎJæûÚe1õ ó4æUá®{\ 4ÇØa<\1c©.\ e\9fzA¦
+oú³sû[Ñs\9a\9faîß² WËw\17\84E\7fyÞ¶\87×òª¯ºà¶ü6\1a£\96%µ"Ì&.\ eO¹N\v3ðÁ`ñÙ\90§;!3\8a4\15#Nlt76\v¤\e|\ e\9cÆ+ò\8e\97\18\16\98ì\Ì\v\99¼Ë¿*Æo\ 6V¾ºÀðò\8f\93Wú  \8fá\9ae¦zR8z°³ªD1Î\95HG
+y9ØÑ1.,/Ål\94Ö\r8&\1eÌU¾ÿmZ\ 2\1a\8c6\97\r\16\ 3       }»ÇçS\827ìÚsfþ,êhÜ\10mtÜ'ömöSQ.\7f?]+°©©(\89Ç\ 6\ 6ñçÒùk\12\90¢\8dy\13qo(°\12ç ãkmýgþð \ag\14/\b\99TL½gü±+¯ço/\86\890$\ 4K]c÷¶¡,\89ɹ±X\9aÍÙ»a\1d\1e\10\8eý\14øá3\95á\88\9aæÔD\ 2>\12¸Ú\846ÆW\1e\rÓà\88À5M\102\91\8bÖ®¼\9cï\96ksf½sYº6h5û\17e.Ë1î pç8\1etR&À\ e$\81Ã:5AM'\87\a
+WÄÇà'*QÜà{\e\1fL\93g|íxß\r|ejÂ\9ewüú\ eo¿ÁÚONãZÜèAáôC Á&Bâ\92\96T4\8edT)£¦SÜËá\81ªJj&\9eðÖ\9aÞ\9a\9aHI\19¢&qÍÝüé¢\7f7\18FF\93£¹Ñ\ 6
+'W-Ãè\9bú\1aoJ?g/Æ\85©\e\7fØ\vÝÝÚzw\17À\12ì\86\ 3ýð Éñ\ 27¸õûèj5\9b\eèÀêreôÞ7F\96#\87\a#f\86\18ábi¢hR\8a¨\19.\1dO)\92¢\92Ä\ 3\97VàF©\84¦\80ÆZ\9aK'µ\14\90ã*ûÔà§\80G{Ùû{=£hð\84ÿ^¥Û#ÒU¹*Lñ¼\vs¾zÓ\r<6\v\8c\94\ fØ\®Ã\83?m=!´\1c-?\8d
+\1e´¢\7f\ 2^ÞZ\9a\v\8e??/Î!8;ëÝ\fyí°Ð8ùÂÜÑ\80!\1c\95©ÃI%k½é­m\16ò)ËÕlÁlü1¾2\8e=\9bç\9e®4êcØ`B¸­gÍà\8a\90\ 6\8bíìw\83\9b\99&êdl\80Ä-,c\vÞ2¸íÓú'®à&w\ 3$U\eÌð\97\0\ 3\0\ 1'\99}\r
+endstream\rendobj\r9 0 obj\r<</Length 2620>>stream\r
+%%BoundingBox: -70 37 543 830\r
+%%HiResBoundingBox: -69.7129 37.5566 542.2871 829.5562\r
+%AI7_Thumbnail: 100 128 8\r
+%%BeginData: 2466 Hex Bytes\r
+%0000330000660000990000CC0033000033330033660033990033CC0033FF\r
+%0066000066330066660066990066CC0066FF009900009933009966009999\r
+%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66\r
+%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333\r
+%3333663333993333CC3333FF3366003366333366663366993366CC3366FF\r
+%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99\r
+%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033\r
+%6600666600996600CC6600FF6633006633336633666633996633CC6633FF\r
+%6666006666336666666666996666CC6666FF669900669933669966669999\r
+%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33\r
+%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF\r
+%9933009933339933669933999933CC9933FF996600996633996666996699\r
+%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33\r
+%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF\r
+%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399\r
+%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933\r
+%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF\r
+%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC\r
+%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699\r
+%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33\r
+%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100\r
+%000011111111220000002200000022222222440000004400000044444444\r
+%550000005500000055555555770000007700000077777777880000008800\r
+%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB\r
+%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF\r
+%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF\r
+%524C45FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF\r
+%FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF\r
+%FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF\r
+%FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFD8FFF527D527D527D\r
+%527D527D527D52527DFD04FFFD06A8FFFFA8A8FD46FF7D27F827F827F827\r
+%F827F827F827F852FD04FF525252A827282752275227A8FD44FFA8F827F8\r
+%27F827F827F827F827F82752FD05FFA8FD4EFF7D21F827F821F827F821F8\r
+%27F821F852FD54FFA8F827F827F827F827F827F827F82752FD54FF7D27F8\r
+%27F827F827F827F827F827F852FD54FFA8F827F827F827F827F827F827F8\r
+%2752FD54FF7D27F821F827F821F827F821F827F852FD54FFA8F827F827F8\r
+%27F827F827F827F82752FD54FF7D27F827F827F827F827F827F827F852FD\r
+%54FFA8F8FD0D2752FD56FFA8FFA8FFA8FFA8FFA8FFA8FFA8FDFCFFFDFCFF\r
+%FDB7FFA8A8FFA8FD60FF7D7D27527D7D7D537DFD62FFA8FDFCFFFDFCFFFD\r
+%FCFFFDFCFFFDFCFFFDFCFFFD3FFFFF\r
+%%EndData\r
+\r
+endstream\rendobj\r10 0 obj\r<</Length 21090/Filter[/FlateDecode]>>stream\r
+H\89ÔW[oÛ8\16~\ f\90ÿ }(Ð<Ø\12Iñf,\16 $jÆ3\93&h\9cÙí´\v\83±\98X\eYòèÒNúë÷\90²\1dµÈv»o³9H"\9d;¿sxD¾úËõÍL\15Í\9d\9d\91y\14\9c\9f½z\95¶ÖôM»\b<;XVÕÐõ­c½~{\11 PsZj)Ö\aÍ_mÛ\95M½ð²Q\9a;û×í®¼\b^_8ƪì+\v¬ÑÛÜ\94\17§P`\9a\99\1e\842¤!\8e"\1e ´ 8P\97N%i\86º(ë\87¤ùc\11Ìx\14\10\1eÐ\98\ 4\82ø@?\96om÷¥\ e\93s\8e°\ 4Å9¥\8c\816\9ecÁQ °t\1cìì²f3ìlÝ_·ÍÆv]ÚTMÛ-\82ôÉÔÁ¥y\0\89     ÞÙªj>\ 5Ie6\8fS\9b¼©{Ð]\95;ÛÍÞ6;SO¥o¬-lñm\9d¼¬l·X->\142\8a?\14ñ\87\95¾Y¡ùu\96\83\96ZÒµS\0\f\ f¤GT-\11^'CY\15o\86Ý\9d\ 5tãHz>Yûäo;È\1a\16à\9e=\9f¯\97;`Ýؾ\a\17\8fWzùîçé\9a¡h\azýþÚt\9d\85\98í£­ÿyqp¾²»}\ 5åñØ"Êæ4@q4\97,\16\1e\r õ±\10(Fs&Ao\86¹\9c#Ây\10S2'\18\8a\ve\98s\8cùÁè¹\1cöci?-\827Mm\ fX¨¶¿)?ÃÚ\bBs\81P\80\ 5\99Ç,f\aùÛ¡²ím]:¼\91çÉ\11\92˦°Õ"ÀÏ~òÊx$<¡ç¿\a\8d\95i\1fl\ f\rÕTCï;ZDG\19Àþ\8by²í$ÈÕÞÖ«æW\9fï,\96ǼD@æ\b\9a\98`\14H÷ | 8\ e$9\84D>,:¸v~\9c\97£\7f\aÊ«k¨ÝU[>\94õâ\98 _ÿÐ\96ÅsA9\ eÄøÇ/b.&¿òø{È\15VÞ÷¶>&\ fÍ\94^NZ#\9a_Þ¸¨º.Òfç*ÑùÍg!>´KÕ<\1c¤Ï/^\ 6.\86ýùÙûó3"Ãß\87¦·\1dx¬l YøÐ\9a\8f6@X\84zh\eÀ#\9a\99Î\86÷P¤²\1e¹ÅÝÈ\83=Wî»\12Â\87\85yx°íá\1fÈÃMÙB\9bÜWö\8fpoÛ~Û\f\9d©\8bðfcÚ¦\ e\1f`wxß\95½ïÃ+\r\8dIGß\8e\ 1þü3@ºíO!½êñe\14Ý\rÀíC[\17¦Û\86vçÿõ°ñl\bS°°n\7f\80³î« £qcâ\81I×u%ì\ e\19¾+JÛÂ\8a» ìöf\ 3p°8Ü\fmkëÍ\13¼°ð®m`»Ý\19Ø´\88\89ð¨\1fn\9aýÓÁg[ÜÛ]Y\975\98s\1c\ 2þåÆTuÓ\87Û§ýÖÖa\v¥è`i¶\bwfãÒ\ 2X¡Há\1e\86-X\ e\7f\ 1@+\9b6ì·­µ§7³\19z\eî\ 6èS\12z^±\81ú{o\e[\94UeÀ\13\93\ 5$´3Ýf¨|FB8áï\83iÁÆ=nMu?Æ80»\0I\1c\ fàJ\8d\11Õ¤\9ajÄW\9dV¯Ü\ 2B¥Ãô\90B¨½y¨½1xÑ\13s}²[\8eZË1Är¢³<éè~\e¾ñ\ 1ÁÍÕhp5\1a\M\f®Æ\9c®Nv»¡êË}õ\14^u\95ë\89Ûã\82nGãÛ\89ñíÉêÝ(\m\9b\16ºÅ\8d×\1a\vÍ\18Ø\1c×c&Öf\fmNN\8c\87ÃØps\84Ã\8eævôn\9f\8dÁ\95\95£V9j\95\93\10åIÇ\ 2\1cõ\18°\19Õ\9bcNÍÄ 9¨\9cì\8aòcé\18#\18Ãh:\8c\91\86\19N6O£¸÷`<\1dÙçg+=\8eBúÓzÕÁ\87`2ÿÉÚ\ f\1a]o\1a÷\89_\ 4ëÉ7õËïëûp*\v§zãØ]ývî=Â\1c\e\ f9«§ýñk㣭!ü5`Þûmôfïeb}]\r ü¡m\86ý²¾oÎÏ^\8fG¤kÓoá\98\0\83óÎÈSn\f\96\9bíPÃabö\eLªþó®)\86
+4~)?ÚÙ\17
+p Ú_ü\97(7O»»¦*»Ý)Æ\943>Ûïq´j¡Ù`éWwÿ²\9bÞy»Û\9b¡³õäqv3\94ýwy»v\1f\96¶¾ªG\14Ú¡Û\ 6«¦©NY^\ en6í˺³ÕW@$ÐS\81\19î\83ë{Süé\82Á\81á?\arÞþ¯ÂÀ         \ 5\0½\14ìý«óãÚÖÖ°U7\8fßUïÔÀ\17\1avû~[n^Êøçg¹}1ó£ÂýIþwÛ>~¶ÃÃwí\82\8do\81\97"ßìíçÒT/\ 6ýRö§\ e\98Ù{8ù?Wjäþø\81ð\18N&_Ï\92\13?\80;P\0W±ÇÖqÜ\19îÛÁ\ÇÝ\97Pû6ð{ý\14Éùwæ\ f¶³ýç\1e:\aÒ\ 1©3ȽÁÿ0\1c*S\9b\82c\80é\ 2\82¥;i\98Ǿü\18ìLåG\90³±ý?fÎçl9Y\ 5u\83{:\9ag³o\ fm\1a$õTã\87Ö}Rë~áFpma\ 3´\ e±Êm#\ 41^âÂ\87\ 3\aIáϸ\7f=?Ëó\çY\9eæI®r\99\8b\9cç,§y\9c\93\1cç(\8ft®µÎtª\13­´ÔBsÍ4Õ±&\1ak¤£,Ït\96ei\96d*\93\19\\9a2\9e±\8cfqF2\9c¡,JóT§Y\9a¦IªR\99\8a\94§,¥i\9c\92\14§(\8d\92<ÑI\96¤I\92¨D&"á  Kh\12'$Á  Jઠr¥U¦R\95(¥¤\12\8a+¦¨\8a\15QX!\15É\j\99ÉT&RI)\85ä\92I*cI$\96HF"\17Zd"\15\89PB
+ÈQpÁ\ 4\15± \ 2\v$"\9esÍ3\9eò\84+.¹à\9c3NyÌ   Ç\1cñ\88åL³\8c¥,a\8aI&\18g\8cQ¸²\11\86\19b\90#Í©¦\19MiB\15\95TPN\19¥\14î\87\14SD£8\8fu\9cÅi\9cÄ*\86;dÌáfEã8&1\8eáÆIr¢IFR\92\10E$\81\1c      '\8cP\12\13B0\81Ë\ 6αÆ\19Nq\82\15\96X`\8e\19Ü<cL0Æ\bG(G\1ae(E   RH"\818b\88Â\9d\95 \8c\10\82\1c#(g\ 4\ 5\89\92\b@\8b\11\8b µ\b\9cGÈÝ\fÿ\ 6JÁ«uÒúöp\87\f
\8cÈóÜ}j=a%pÎAãë³üÄpÒ${nóc«~oûâ\17Û\17»ö\8d\vé3O\1cH\0IO
+(\ 1J=e@ÚS\1eå\bV\8aÆ\1f@\rÀq\ 4\15\0¨(bîÒ\ 2\ 45\a\0\1dAÿ\0\9c\8e \17\ 1\GÐÕ\0µ#Ø!8òä\9c\8d?P-(\8a#êèü\fÊÄ X\8e\84'èJ(¡#èp(¨£Ì\93ö\ 4;\8fD\9eÆô¼Kâ~bGÐ\1aÔ\13óÄ=      OÒ\93ò\94xJ=ý\9b÷rë\91Ü6¢ðû\0ó\1fú%\8fnð~ylµ¤\87 q\f\ 3\ 1\f\18\81±\88\1dÃqvb8k\ 4ù÷9u\8a\12%MOÏì:q\17°;E\91\94HV}u8Ò&Ú,\16L3.ýñA?8øfú\8bÍ\12-7+Íj³K³a5ä6f¼6\e\19V8«6>1ð#\83?´÷9&\81\98a*ÌL\87\89)1¶5\fL\8d\vÓ£¶\14)mõ\89©\12\99.\81)ãÛ®é\ er7e_Û\ eënëÎ\ fL(±\8a³ªL­ÂôÊL±¤çØÎT§Õ\1f\ 3HÏ_"\81  81      G&"\fñ4Ð4\86*M#+7K´HÓMh\1f­ÓÛå'qkÌÌ4\9e\99Ê\13ÓYíÚlhviV\9b\95Õòj\9a9\88yb\80\9cÕs\fÿ:\b?>Ü\ 2ñ\ 1Ã/\81ø\16\8a\11UÏp¼\ 12q¼\aò\16É[(¯XF\84Ö\r\9a;\9c;\9e\17@\13Ñ-òb\8b8\8d5Ób\8cÑ\85xÒت-\9eR\8b$ß m[ì,Qs]c¥6\84ç5:ø!\88§52\14×\ 2a%¶¤Ø\9b\e*K«+XÀ\e*Ëíº²\84\12\11\9d\89æ\v\91,0\9e aGôF\ 2·\10´C\ 3ìD°ZâT@\9a\bOÁæ\80\12\953\ 1é\88ÅH\10\16Âo ð&BÎ6¨\ 5b,/ß´ª\99EÏ,\8afÑ4\8bªYt\r\94\ruÍ¢l\9a¶YÔÍãêp\16\8d³¨\9cEç,JgÑ:\8bÚ)7\8e±ê¯Ðr³Ô,Ò\16ü*\f\89-\85Ë\9að3\8dk\84à\19i×f\ 3íBÓ×è/Ó\12\8d)³À^Ë\8b\82Q2\15\86\93\996ÑF\1aW\8f\f\1e\98Å\17fre6\17ftnY-y\1d\99Û°Ç\a¢\±«hTHÍ´\89Æ\13@Þ_\99û\ 3óÿB\ 6Tr \90\ 5B\ 3ü@\88ب\10H\ 6O:8\12B\8cø\ 3)\94\15B\8b\91ĸ\92\1a\ 3Éq!=ª\12\ 42O?Y'Ö\9f\163e\8a#WÄ\88Sðen\8c\11Ê\8c­"j\95¼\bq4\1c\e÷ï\9b\7fÕÜb\98ÑÝ´×~æ%Ã\8c­þ¼bÓ]\e»!æÇgv½kÃ]Ãn®Uï\96Õ»Vn\19f|^5\9f[ºk±Û\8aDU¤ó\ 6\83\v\b·(\1c6(ÜÂp\87ÃVgö@|\8eÄçP\fMÛej¹\v\888\9dåS\11é\16/òè\12\11é\19Ñ_\91 \ 3scD®ÌX\9aE&ydVD²ed^E&\ eÌÍ\11¹:ck,rÙ#»cF6"ë\v(p\ 1\15® Ä$ÜÀÖZ\10Å\830\11É\9bÁ 
+&\r\brÍ8\1a\v²y\90."Å3PU¡/@Î\8aU\83ËS\9d\16EÖ#¡"`\90\ 1µ
+\8d2\80Å#4Ë\8cà°Ð0\1eI\17\81\8c\fôUÀw\0\86GàxFhYl¢¿\82AX^\ 2¼
+ ~\ 1ίÀút\9dq\\16À÷Há\b\0e ´¢,\f(\ f#
\8cж(\1d\1ei\1e\81©\fäV\14\98á\88v¹S\9dýÉ\9c\8d\93\7f2.3öÙ\rë¥\ er£j\ f\Á?ÙñiðgãË)Û³\a¥7Ó¼ÖSçsuy[uËÛ¼9KMØÌu¯\97Î\93¤\83¼ÌDíàÎ\12?§íÂ^îó\91·Å/ñ×»\7f\85Vn\8b7Zñ\12·¹-Îó<¡¶_ça¾Ì\15å1£´D Úãj`\ 1¯y\9a¦qº®ò@Å\81J\ 3\15\ 6*\vT\14\80\ f\14\ 5*    (\bT\ e4) B@e\80\8a\0\95\0*\0´ü\1fTöãïÓÙÏ56*õ^eßÖØÏ\15öQ]¯Ú\1al\98\ fÚº+뮫\9bª~\8b ÅMîuI\9a\16\16IÊ[Ò\rQ*×K\91ÜÆhnöÄ´\bCDu\8f×µ\81\ 1®Î.Q{Ó¯\r_w3|Ý1|ï\96··Ø¡dbÆû%õ£íÕ\19ï\17ø\e\86\19?zÌ\1d{IxldÉ'ÞZîÞYn\94è×î,áÅâÜ
+3ÒðX\9a_+Ì7Êò¶(£D³,\7frQ¾\1e\v2pörIöË^38-Ç8\8e\93R\1eXΣê{Þ"ô¾R9Ó\85³É|WÎ)³\8aÍ27\92Ñð\r\1dK¿WÍMU\9f(\ 22\85\80H\81J9p\19ôw¥,\18)\r \ eÄ®\98\91"ÁR(\88T\10\13-¯·\85\90)\1cD:TÊ\a\11\10\ 3E\84È\88\91R\ 2bBlÄ\8c\14\15\96ÂÂñF)ò"è\1d\84÷\1c½M\15\8a\8dJÁqÑ\ fãdú\9bD~\88M\98\912ÄR\8a\88\18ñ\14$\81w\9btS\8a\18_©3l\95Ò\8cx\8dKqß\96í{½\9a(\89¢2D\1d¨ÐHg\93r8È\9a;\9d>\92\9f\7f~zz÷þ»oOß·¦SI\ 2Ð[ÍG\82ÞÉü7\@þßtZfüm\99üº\1dêÈÿ \12µy4ÿ\91\9d\90>7\85Ï'I\1fH\9e&~^\95>o\14?\8f\ f[\ 1tCþ¼$\80nK \88 Ç\87\83\f¢\10ÚÈ ½\10ÚK¡­\18\10r»K¢.\8a\16\84\11ÒM\85ÑØâLÄQm\17Ü´½¤RúF\12DYâ(\82Å\f¥ðL9<Q\12\8f
+8Ò\898&±
+-S$\83@\94Ê\91\94\v\8dx\8e²YÌP<Ï\14ÐSã¥þ\ 6\8aé\v\ 5u¥¨.J[P\99·M2\98\9bÝÈì(¶Å\98T¤øDS\80*\98\a\8að\v\85\18\87\10¥$Ϭ\11\89Õ"¶ÊáiZO,M·ofÜN\8cÝ\91ñ{e\f«!ÆY«*M+X¦¥\16ÝjZï|3­\83\19\93å6¿o#õ\rÔ]Éý"Û\ fð¾Ûï\15~£å\9bÏÿùôÅÏ?<}øáéûÏ>Ûr}ûäñáó\9føÌë³/Þ}øðÝÏO@þ\17¿<ýøáý/ÿ\82+¨ßº'w¶.\9e,n£)ðz+n\96Û©$îï¾ùEÕüå'Uí¢ëžú\8fú¿Çß\7fGë¿OáôÇÓ×\7f1§o\1f¥ý«/åy\9bn\99ý½´í_ø\87ÞÔ^ªMû\ fÙµí\86>égü©m´l³+rhøëôãoó\r\7f[÷ɬû¤Æ\ f\9c³ÌcÏ)z¯_ \8dU\9ab±öÄ.\95Û\ få\eè\87\94Ä\ fÉÕÓ_Û\90\ 4ÊI#Pê¥S\ 2ìØÉ\18\ eÂd|\8f÷q\1d\13A/isò\rðCqA|\ 3uÊ1F|\848Èxº¶A^f\90F«c*\9eÁÅGY\9d#{ñå3\96÷\88Ö\96\98½c\9f\90
+}\9b\93úú\1e\17\14¼KÒ\b®\17vBE\10\1f\99Â\ 5Fkø"hæÒwÁ \a\11ø¤[W¼ø   \ 5\8aJ"~\fyy\13N×k£¯\15\83ÝÙ\83æ§T°ì\98Ä\8fÑgú6¯c²g\97\82|\85W½ü_\11d²)\1eß\942}Èø6Äc\97S\95Fk\1c;¡zYv
+8^ø    \9b"\8fíºsþ\8c\vBbcµAúä\1a¹¾\80m\17¿ÆÄ9"êV\e\14ÎRn¸h/_\11θõ8vÊ\12\1a¡\85\b\9e[ï×A\98\81m\ 5»\ e7\eK¿duQB¹Ùr\82Ë\90\1c=\8fÕÆÈysà©:\9b\v]Y¯ø\90\11ë\18D!\8fÚKÚ\88_\8aãÑGÙ\fø)ÓG\ 4n\ 6AG0¦\10H§Í$(­tM\vÁìCÿ8\¶\98\9fP"Ú)°S­Y_d°\12IYkú b\f\13\ 2\11 _g5ó\ 2â\89K\82\ba²&Ó·Á\87\88\99\106AÞ\84\9aÄ\8f8<      \8e\8cÚ/>Ïl\89\9f\98\r;\ 5Ë\0\82\ 4ª\9cÃÉQá\7f\83\f\84\ f-â6qZø"¬ÞK'\9b*\a\99\9c\98\1a>7¶¤5# B¸ÎZ\9dÓ\8c\bÌñ\82TP?ÒÏ\90{ë =:¬\13Z\8e\9d\8aî\vÆ*\91JÖ}@°,\\10=Ç6\eõEPvô½©ôc*
+:\842\aÍòO\fH\88x@ 4:¿2P\ë:\ 3á\eHÔ=\ 3¥Ñég3À#²#åÎ@ñmH;\ 6¢­¤Ð\19\8d\9d\81âûx``\94TM+\ 3¥\8f\8b\9d\81ôÍ\9e\81\9c7w\ 6ÂW¨7\ 6Ò\8f\a\ 6J#÷°1Püê:\ 3eR\bÚ=\ 3e\95Át\ 6rëlg |×\98Ø\19\88F\10¹3\10>v¥30J\9e¦=\ 3c\ 4gÂÂ@x.\9bÎ@øÁÕ\ 3\ 3Ñ\98\f\84\ fÑÝ\19\18¡¡\8cÝ3\10mPâye |DBg </õÀ@4z\16\80Æ@ø1§Î@ø¸ß\1c\18\88ÆRãÊÀ\98¡ÍÂÊ@q³=0P\1a\f¤\8fx] \bßÊ\82w\10\94FáØ\ 2AørÕX!(¾1\a\bÊ j:\ 47\93\b\ 4Åõñ\0Ai´¾C\90\9dr\87 ýt\80 \e}\87 øÑu\bÊ\12\91\93{\bÊ~æÒ!È\83µ\1d\82\12\1f \88 ªÆ¯\10\84+·Î\15\82\8cA{\80 \ 4\1d\82ð¡Q:\ 4ásð\ e\82\12ò2Ã\ 2A\12'w\bÒ/\a\b²±v\b2\8f|\87  eö\10\14\ 2ÕÚ!H¿t\b\8a_ê-\bâö\10|Ý3PÚb\8a+\ 4ÅG\99X!(>.\9f{\b¢Ñ'\13V\b\8aoLY!\bß©\96_\19\88&[sY\19(>\8eze ø©ÔÿÒ]/¹\9aÜ6\14\80·ÒC\e\blIÔ33\e\9e\ 4\99\ 4ñ
+\1a\1d#nÀ±\ 3£3Èîs\ eY"K\823º ïÿ*\15õÕÑi`í\9b?þ»­âüimSçüi/Wç\8fu6¹\94?Öɾ"øã\89j­ìüñE\96\bU?\96ÃbdèÇË\e²\?]³:]?Ô=çyê\87æLÖTýP/<Ì\¿Ê\r\8aQ\7fë\87\9e,f>ã\ fe7tU?\94£[æ
+ýÐ\UªëW'Ö5u×\ fµHm'\7fh¶'\99)\7f¨u\856\7f¨{)ýä\ fÍñ¸ªü¡F
+\18Î_åÏ\9cóä\ fÍRfø\87\1aï\1dÛ?\94x¬ÌÓ?6\8b©¤þ±Î6\1aê\1fk^òá\1f\9bÈUî\1fêÖ,\9b©\7f¬EÆé\1f\9bÅÒ¦ú÷ú\10úDz?Cèþé·ÛaDýc=\fZõÏÞ4Nÿ´iAEýÓ/²]§þqYVî§\7f\8cÑØþñÖr=¶\7f¸õÕþ\1düqªdÈæ¯Ò].åÃ\9f\ e!Ãæ\9b?\9dÔ:\9c?ÖÒ«óÇñn}\9cüU>üÚpþtO¤åüi\9d×É\9f6¥:\7f\86Ïtþ\14\a\7f\8a\98\81¤üi]²óǺ\18¡\17\7f\82\81%=\87\7fl.×O_²"\ 2²®ý\8a\80hö%Óõc-5" j|X;øcOrD@Ôu\96\88\80ü\7f*W\ 4\14îUñ\bÈ÷¬\12\11P?c\9c\11P{5" ëÚ#\ 2j]®\bȦ\94\88\80¬Û\8a\bÈ\1f\97Ó\15\ 1yÕ|¾m\ 4uéfD@Ô¸ïW\ 4\94Å\ 4\11\11\105æ?" p\97Ê\19\ 1Ñ\e\96\12i ª%#"`åoêW\ 4D³ðlá\bâjW\8d\b\88\9a»ï4\90ûwõ0\10«¼ZD@Ô«õ+\ 2Vܾn\81Ô\fÄí­\12\11°>#r\1a\98¿y°5\ 21ì){\ 4d)ó\8a\80l6\89\bÈÚ\984\ 1÷Yê\100û   Ö\ 4D=g$@Ö}\      \90Í6"\ 1¾>D\ 5D\99Ê\95\0«\9eÜ"\ 1ê\8bj$@­åJ\80ÚL\91\0õ\8bV$@~hiW\ 2ärÖ\16  \90÷\15×ä\ 2rTZº\12 gj$O\80Bz%\12 G0Í+\ 1ê\9cÎH\80¬û\8a\ 4Èá^éJ\80¢\ fÀH\80º#j$@­Û\95\0µÙ#\ 1²\9e)\12 ÖãL\80ìõ\1e        Pë\16     \90\7f\94\0\ 5· µ\9b@4\8b\84\81¼Måe f|¬Û@4\8býl3\10÷º\8f\97\81$«öÓ@ÌG¯/\ 3Ó3[Û@ÔÒn\ 3¹U{\18\88×\94ö2\90\fäç\8e\97\81éA}\e\98\9eûp\18\98\9e\ 6\97\97\81øÐ*·\81øQ5½\fäÒå\97\81¼Òy\eÈu\9c/\ 3q/ª¼\fä>í\97\81\98\8am Fu¤0\10u-ë2\10ÍΣÅ6\10õ|â\9a\1a(òMJù4\10½RÊp\ 3Qc\12Â@þ\7f®Ë@4\85\17¿\rDÝF\ f\ 3Q÷Õ.\ 3Ñ\9c+b àÌ\82\ 6²\1cù2\90ÍÙÃ@­sv\ 4e\9f¥Þ\b²ù\9c`\15AÔ¥ä@\90uJ\17\82|ÓJ\81àëC\88 Ki\17\82¢'·@P_4\ 2A­û\85 6%\10dÝJ ÈKÄ\9e<\11äz\8e\19\bê\8dÍ/\ 41+Sn\ 4aR\92@\90\ 4õ\17\82\9cÁ|#\98\9f\11ÌÌ(/\ 4³½ùD0Û'8\82\14\10d=o\ 4ósë6\82ù9¹m\ 4)Tº\10Ì<¸½\10d=_\b¢\9eë\8f\10,\82¸³N\ 3Ùk½9\82¬«\ 5rE\90u¶Ô\19\b¢)<\90m\ 4Y§4\1dAÔ¥ÎÃ@´ò\1aÓ\rd]çr\ 3Yw;£\86\81E6\7füw{N äOk\9b:çO{¹:\7f¬³É¥ü±Nö\15Á\1f\9aXÍìüñE\96\bU?\96ÃbdèÇË\e²\?]³:]?Ô=Û\897ôCs&kª~¨\17\1ef®_á\ 6Ũ¿õCO\163\9fñ\87²\eºª\1fÊÑ-s\85~h.\9e,¶~¥a]SwýP\v¢ÄÉ\1f\9aíIfÊ\1fj]¡Í\1fê^J?ùCs<®*\7f¨\91\ 2\86óW:~æ\9c'\7fh\962Ã?ÔxïØþ¡Äce\9eþ±YL%õ\8fµ>b\1fÿÊ>L½ýcó9Áª\7f¨[³l¦þ±\16\19§\7fl\16K\9bêßëCè\1fËþ\f¡û§ßn\87\11õ\8fõ0hÕ?{Ó8ýÓ¦\ 5\15õO¿Èv\9dúÇeY¹\9fþqA³\9dsÕ?ÞZ®Çö\ f·¾Ú¿\83?N\95\fÙü\15º\9bªó§CÈ°ùæO'µ\ eç\8fµôêüq¼[\1f'\7f\85\ f¿6\9c\13i9\7fZçuò§M©Î\9fá3\9d?ÅIúÁ\9f"f )\7fZ\97ìü±.FèÅ_ÆÀ\92\9eÃ?6\97ë§/Y\11\ 1Y×~E@4û\92éú±\96\1a\11\105>¬\1dü±'9" ê:KD@þ?\95+\ 2fîUñ\bÈ÷¬\12\11P?c\9c\11P{5" ëÚ#\ 2j]®\bȦ\94\88\80¬Û\8a\bÈ\1f\97Ó\15\ 1yÕ|¾m\ 4uéfD@Ô¸ïW\ 4Ì\9d        "" jÌ\7fDÀÌ]*g\ 4DoXJ¤\81¨\96\8c\88\80yà7õ+\ 2¢Yx¶Ø\b¢®«F\ 4DÍÝw\18\88\1e6Qw\ 3Q\8fÕ"\ 2¢^­_\110OÄS\v¤j êR%" j\1d\91Ã@4\1fl\95@\94#e\8f\80,e^\11\90Í&\11\ 1Y\e\93*`Þg©·\80\13¬
+ÈzÎH\80¬û¸\12 \9bmD\ 2|}\b\ 5d\99Ê\95\0³\9eÜ"\ 1ê\8bj$@­åJ\80ÚL\91\0õ\8bV$@~hiW\ 2ärÖ\16        \90÷\15×ä\ 2rTZº\12 gj$O\80\99ôJ$@\8e`\9aW\ 2Ô9\9d\91\0\15     \90ýÒ\95\0³>\0#\ 1ê\8e¨\91\0µnW\ 2Ôf\8f\ 4Èz¦H\80Z\8f3\ 1²×{$@­[$@Ö­ÿQ\ 2\9cØ\ fú\14|\13\88f\91\14\11prW<(\12AÌ8vÂ:\11D³tK\9d:áØ\1d\18¦å\b¢Îµ\9d\bb\87õZº#8t¶Ä\11D-­¶\13AnÕî\ 6â%¥\99gj ë$ù0\90\1fK\81\81\83¦\8få\ 6²~6S\188t    Å\räî/¶ÅÔ@|è62\fÄE"®\88\eÈ\95ã6ß\ 6B\ 3\90XN\ 3'¾uZ\98R\ 3'v\9a¤á\ 6r\9br_¾\r\84[\98Ù¾\11\øÜÔ²#\b¢Ê2ï\ 2\ 6=\17l\ 4ñ\e\11×Z \88+IùB\10\80\942\ 2A\}\99/\ 4ñÿ¹n\ 4 \8cô@\90ëÞ_\bâÞ¬v#\b,VäÀ\8c\11Àº;\82(G¾\11äÁ¦¿\10d\9ds(¸\ fS\87\82Ù\8f°¦ f¯ä\97\82¨Sº\15Ä\9bVz)\18\1f¢
+f>Ån\ 5õèöR\90/\1a/\ 5Y÷[A6奠êV^
+êθ\15L\9c®P\907\96׿\15Äý\9dr!\88YJ2óF\10¸®np*\82\9cÁ|\198\99cór\ 3'\13Ê\127pê[ëi \9f\7fÅb\9e\1aHpF-n ëy\11ÈÞ>À\92@î")\91\ 2é\13\1f\90o\ 2'Om=R ë'@+\81¨ç²/º\bÄ}\97¹ú\15\ 39\rý±H\11LÌMc\fW\10\8dl\ f\8a7\83\98ªþ\\902\88:Ù*=\ eb\16«=\r_\10Ò\94QzH\988_ËhT
+Ñèº`\87\85i3È\1d\80iÍî \e2Ó: d3sGn      \93­lv
+\13oÇ4+ÃÂd\8b\19\18R\81¶l\98UCü\19}´yr\88k\1d²\8c\90\8b¨1w\83\88\1f\97óÌý\14\11;&e~Ú&\91׬\1a{.Ħ\85tg.Äkqí\1e\fÁ]\8dX\bÎ%Ï+\16\82k\91\10\11\83ÝS¯."6\83à,w\92\88M\85Ø×\9cÄ¢\v\95\9dÄ\82õÆ#é$± ¼\8cW.,L\ 6\96R\95DÁ¯\9c3\9f$
+.r¶'\18âg
+FêY+\9a\88sMªö\18\v\13yØI5»\89¨í±û\98¨\a,é§\89ÂS­Í\96\9a\88£[«\ 6«\9a\88\1aïY§\89h\16Yâ&\8a\1e`Ê6Qxʵ\83E\98ÈodzÖM\94MÊc¢¾iÈi"\9b\16^\94D~O7"\95D¬ÊÊý\14\11Ë\99ó\b\11)V+#r!Vå\89o¯\øM\91!\1e\v\ 1q\92á"r\ 4[Zó4\91\93Z\1f8\15E4Ä2Í£"V§õ!ód\91û\ f±¥º\8bÜ\19¹¦î0j\83\83FveÖé6¾YR\1cyˤÛÉÒu¤qºx\9bG6ðÔ[î#\1a\ 5Ãî>~r\1f¿ýî÷/?|þôåóo¿~üý¿\1fþÌÞWºË1P_\7føöÇ/¿\7fþõ\9f\1f¾úþûï>}úÏ¿þþÛ\97\8f|í×\1fþ¤¯üîõ\92\1f\7fþøï\9f¾ÿå§_ÿñ·\8f_~þË\ fû5\7fý¿¯ù\1fõe¯\ 3YNDáWÙ\10\92\95ËvùGdð\0$ ö\ 1 "!!àí©sÊ.Ûw$D°\12B«Ù\99SÝ}»¯oÕçÏ\7fú×?þ¶Þõ;ü\ f\7fþìä³[å\9f_þåÙþõWü«ýô\9bßþôË_ðÏ\7fú+\7fÜoÀ\7f\7f?\9fNñiÌn\99ï\ e\80\9a¶cÁ\9coïCò\1fY\8a¼ø\a°Z\1a\81\7fäuª!ý-g\7fzÁ~rÄ{\9eèG¶Æ\ eò#·1_ðû0Î\85!u`\13üÌ®\1dÁ}Ö¤\ 6öÉ3Ç9©Oþ\8d\8f\0\ 3\82Ü\85\17óñ&÷]\12\1f±·\ fðq{Füà=׬\8eÀ=ñæ\14>´Ç\9b\93\1cØÛßFû\16¬\aª\fö\ fëI*\ 3Éb=nö\82=Ö¢ù}\1eØc½j©\ 1{0Æh\1f°ç3©úÂ\1e\ f[]]     {>l\99\ 1{\ eYþÀ\1e£hf\1d°Ç\8c§y`\ f\12\18í_Ø\ 3+Fû\80=¸c&¼a\ f*%?~\1cØ£\98]K       {¢«¶\80=ñVê\v{\14\87\1c\ 1\ 6\13y\ 4\°G.¥¿°G1û\11\89°çEr\b0b\9bù\85=¿½\1f\ 1FînÚ\84½\7f¨¿°gñ¢=¿¨\1dÚcY~À=Ñ*=p\8f+®õ îqkþò¡=ÖäÂ=\96°¤\1a¸g\13ª¼´g§Ö\1e°G6Ú\aëñì´õ\17õ|êÚ\83ôl\1do%\82Þó|9Ïb9\98¿àCÊ\13N¥=\90'ÄÊQ`æ,\81xäì\eç¯\8bøßÿ\ f\11ÿßÐÝ\9eþTöÇkøj<\9b\aði\9fg\8eà[OûC¸\ 5\9fê\90oÃ×V«^\86o\8d$s~\f?k±\rý2ü\9c4õq\19¾i#\ 5ã1|{\91O3D?ãäY/ÑÏëäó\88~NÝ?´=¿ÍE\82íùMSù \1f\18±\89ÕÛó\87kBx¾\r\87\1f3nÍ/¶Éõqi¾¦\84ãÁ¥ùÖÆmþ ùÚÝ\9c        ~[\88Bn\1eÉ7\8c÷\8fäSo.ÉoÉ\95xiþ\90é\90\7f4\7fZ\ 3\\9a\9fmG½-\7f¦µ£]\96ßÄ÷ï%ù*#õ[òí¾ä\aÉ\1f\8e\8eíøM\9dàÛñG\9dí\aÇ\1fÕ\ f\ 2Ëñk®%°\ f÷M³þàø8\rÝ\8eO\b\1fÅçí~\14_Ko\97á7á1õ\18þ\98\9e\1fÃ\1f)\8dËðM,´\1fÃWëéù5|´\95\\86oÞí\8d·\fß>4Æ×ð5g\9fÄ¥øZ\97&-Å_Ç\86\8fã³·\8eãg\91ZnÇïEê\ f\8eoíÑ.É\1fMsP\1f\1d(Y\7f\96|ÏÛ\8a?³úöº\14߶µ1å«ø8p:£·â[[ë¼\15\7fú~ò*¾^v\1fHZro\84\80\e\1e?hÜr?F\1e\87üVÀõóÿ\ 3úÿ\19ÿ[RÞêÏ)Éëä­ü<óØÛbA\1eý(9"úèRò\8a¢\ flAO#¹\98¢Ñ,\99k\9d\rÛ\84Ü\8b9I\b¹åº9Ñ<\97ln¿\85Ürn¹»\81Ûb[N³\8c0òf@ÀÜ<J\8eböÍ\99Jn\99\1d¹\95\1c9ÍóË\8cõ\82b\9bî»Pr\8bZݺ©ä\96-\9eÛw%GKK>J\ e      õc\8c+9\9a\12\1d/öê«æJ.>'¡ä6O­\1eÁv'·bÎ=¤\1cû¤\13Á¥\1cÛd?\16æR\ e®§|¤\üZ!åØ\82?Jn\7f\934[É1Dm\1e%·±\930Ä­äVäî¹\95\1coÂV½\95ܲ\ 1÷£äöbIî\9e\r»\1aêå8y£\86_z\r'ÇCIy\86\93#7­áäx\86f\12·\93ó!qη\93óéË\b'G·\94z>D'G\91\ 2°/b}§õH¹e\ef¹¥\9c\13\93Ëú9\90r4s\8d\ fu6»\8e×É1\10Øж\93cÌJ\9báä\9cÔ~>D'·¢IV    '·l\8a ÛÉ-ò©=N\8e\ e¢\94ã\1aÝ\87\84Rn\19ÛÕ+å(¦\1cNn±f\9f>:¹åÒÚ\11y:9\8ae\ e\1f\8a\90ûÛÉ-K½¸àOÎn3÷\12N\8e<ýüJ'\a\9czùH9\8apÈ-å|\93\1f÷(åÈÖ\87\7føÏ`þõq\8b©1ky)\8bIÒy(kyh\vÊZÔ\?\94µ©\9bÞ7>f­&  Ê°{ý`\16óÛå`\16\9bý(\a³özò|a\16<\98õ°V ;\aµ\88\83Z\14S?¨\ 5k\1c\9b\8eZËuä\ fj­X|ö\1dµ \8c\96ÃZûuÒäÃZq³\vÖbáj>¬5º¨×/Ö\9aVT\91ÃZ\9b\19¬Å7Be\1fÖ\ 2\14¥\8d`-îmq\94°ÅÌCu\1fØbÑÆZ4\8e\8ayV\90\16\8f¡¯%lñ~þÌMZä$%HË\9e\1eÒ¢\91ÚºW\90\96#5\ 3´\1cÃ\91_ÐbtÍw\ 2´\98ÿt8\8bÈCïÍY\14u\8eà,³Ó\90\9cE\1e¾2\87³V´óL       Î"Ï\1a\98Eìå¥,jÍ\9f))\e\97X\94EN£½\94å\97·\16\94Å\9b0*\9b²ü\90¯hP\96µ\96\83²ü"íAY\³È\vY¬¦\8a\ 4dq½Y[@\16÷©­¼\94Å
+u'")Û6ò7eÑ\80Øs\1fÊ¢Kk@ÖR×q +±8\17d\85'Ö`,\86Á\1f®3\16\87±²\9eÚf,²_Ø\19\8bÖ+\1fÄ\ 2aY\ fb\91E\ fbeÝç\17±jß,¾ÒÁ>Ô\8a¯:Ù\87\9cU7û\14¿#\97\97}(\96Ù\16ûÔ>\19~\89\90{~ɧ¸V\ fð!ÂÖ7ø\90«ç\ 3>ÅxúfNðáMe\1cò1\97\17|¬¥\16à³l\97Ð\0\1fò\18ò\82\ fEn\b\v|¸HÒ\1càCÖör\ fw©E\82{\´\1aس\98§¼Ô³\1aïqAÏbS\1d\ 1=Å`ÎúBO\15ç­\1eг\9c\87\e%¡g¹Ö\_èYqë ¡gy¬v$÷´\99§\94~sÏJ>µ\8b{\96\83Ð\98"ËeÙñá\9e\15÷¶EîYæ1t\83ÏrO\1fÁ´\9amL=¸§ýçTÛ\fð!\8fúr\ fµ9[p\8fÙO\17ä\9eeɾ»\1dî¡ØD\82{\96M:f\80\ fYò|É\87bò§Êá\8e\8b,ò!×Q_òñëý\84Æ5DV?}\91|þ¡ù\90\8fµ\16àã÷¬\91\ 3øp\87\9b|¶tÖ\9e3ÈÇÇêÐ"ùÐ+³å\97|ÖUæ©\1aäÓê\8d¿ÉÇ.¬å%\1f;ÕÏ¡ì\1fûK´\ 5ú\14xÓù¢\ f\1d¯u\ 6û8\10I\82}ÌÎíÃ>\16s\vö1·@\1fÉ\94ÇË>"ÌyDö1K      ö!§ÅÆ\87}ÕÚU»>ìC\8dz½Ø\87ÜêØìC,Ò^öY±t\7f\9e6ÆHâ|\ 6ý,ææÛà¡\1f\8aâ§\aâϲ4\17\10\ e\10òð|ðW1¥¾Ë\12\7fxS\1f9ðÇìÈ9üã\95ç\fþ!\17\19Á?äÜëË?\14Åg\92üC®U\83\7fÈÓEð\0\10÷´ÈJ\0råÊ! åVÜ"\ f\ 2­8p\83\9b\81\96çT        \ 6V\f©\9fI\ f\ 3­\88©Þ\b´¸éF\ 4Z¶Mµ¿\b´âö4"°\ e\99\ 3\81\96\8b\96\9b\80VÑ^{\10Ðr\1dI\83\80\96Û"â! \15\16\ 4´lm\94\83\80u\1aÝüüp\10hż¬\97\b´\FË\81ÀºÏG7\ 3Q\ª\a\ 4Ö}ÆZ\bDæýÞ\b´¢¦¤\81@ä^r \10Ys~\11\88bõçJ\ 4ÆE\16\ 2ñM£\8f\17\81üz\1d\81@¾É\8fFD ó:èl\ 4²¦5\18È/ª3\18\88×±Ð\ f\ 3± K\97É@>×2\82\81è\95¢ú2\10]¥Î+2°n /\ 6²\vK\7f\19ÈV-y3\10ѯK\ 4¢»»\96\17\81VÔYs \90À\99\1a\bä\88¤ú"\90E\99\81@f¿2\19HBåü2\90W\96\1e\fdN=\18\88\eþÈÀb\r;{}\18hµ!¾ðd rª}3\10\1fYny\18\88¢\8c±\18h©©\9b\1a\18\88\98Z}\19hEÕåú` rê%\18\88\9c=\1f\ 6\16\8c©ï·d Þ$î\89d óêà` ¯ìÇ$2в\8d[\ f\ 6"7?ó\1c\ 6¢ÈÍa1\10\99g¹Å@\´¸\13\1e\ 6âFK.Á@®\9c\ f\18\19hÙ~V~\19X¦!Ú\8bd eÛM\ 3\81\ 5C:Ú\8b@+vvðb e{îõ00a\18Û\87\81)\9cÍ\19\98l±æA`²;õ³CÌ~2lÕv\18\98\ e®É@{}|\11(&ln\8e\8e@üîý& Ð¾nôüA }Ápës\ 4Ú\17ä&\a\818¿øB^\bÄ!g\8cÃ@\1e\82æa ¬#íÃ@+ÖT\ e\ 3ñ³\8a\1c\ 6âÑdù0Ð\8aÃ\9f«3p_d3ÐrîíÃ@|½\1f£\9c\81x\93\1f\91\9c\81rÎ<Á@Ô4\1f\ 6â\8bÖè\91\81v\8bú! ­gw¯r\ 2â©:¼H@´J×ú\12\10M5µ\a\ 1\vy<\82\80ìÁ¢/\ 1Ù¨E6\ 1\11g\1d\81@ËIT^\ 4¢ãK\95@ y3K \90\13âü>\bdQF \90Yó¿Y¯\9b\9eKn"
\7få]N$\94¸üU6¬\12e\83X\80\14\10ÙFdDF \10EÃbþ=çTÙåë\1e!6(\9aè=¾Ý}oûãq9\b\1e\ 2Ú\83×\89\97\ 2ZömÊ\ 4d\1eKÈ[@AEÔõ\16\10mV\ 4o\ 1\85\ 5P\0\88$i<\0Ä´o>\9a\ÃX\18\0\10±úvø\ 2`r\ 4\ 2@äÚõ\0\88Ü=¿\0ÈEê»­\ 3\88\8b\9aÖ\ 3 ³ô\a\80\94\ 3 ²\9f\84Ü?ÄÔûÿäÓ%üãÒ/züKì\8böð\ fï¹duÿÄG5üÃ\µÃÆå\1f¼\99³\1dÿ\ 4\96\ 3 Wè£\ 4,xàlùø\97\83\ f¹\12\97Ë¿\92£b3ÿ\90\87m&\vÀ\82>,9¿\ 2\88¦ÜÊ\f\0\91¥M\r\0Ë\1a\9bK@4Ö\G\b\88ÜÓ*ú( 2pë·\80\85\97\10°`:\12±-`Ù§\98W\ 1Ù(#\87\80e\1f\85\96\80ÌÕGú\bÈF\9d\1a\ 2\16\1eÔr\r\ 1\99\8bÔ[@6f\1fY\130\1e²\ 4dö¹z\0´ooá\9f]âÇ$óÏoi\97\7fÖV{øÇ<ª\84\7fì\951ë- û3yYe\ 2Ú¸\96\ 3`F§T}\0\88¾/\8e\95\ 3¸1Þ\0r\12æù\0PØÍ5\0ä¤ðòÎ\ 1Ä<jµ=\0Ä\fÕR\ f\80äfè\ 1\90\a\80²Æm\ 3\0\ 1¤OR\1f\ 2òIi\1e\ 1\91ó\9cG@ñ±ùLÀ\8c\ 1ÐÞ/\ 1Ù6½ãM@æQæ&\90\97\87@4b\1dÍE SñR\8d\ 4"æÑúM`^Sc\13\88\8c\13n\v\ 2ùyò|\bÌ\¦¾Ù\1a\81¼iz¡h\ 4Z^ó7\b´'Ï\10\90±¥\19\ 42×Þn\ 2Ùh;Ã"\90¹\97\1e\ 4ò×\89\97\84\87@¾¶H\v\ 2­ã|u\19\81ȽÎz\13\989½½Ñ\bÌ\18    ©9\bÌ\¢ú0\10\8dÕ¦ð2\10Ù\16ù6\10\19[ë¸\rDãªØ\8cÀÜÐW~>5\ 2\91\8bfy%\10M\8dݺ        D\ e®¹\9c\90û*_\ f\81hÔî\85£\11\88\96 0wèÖëM \1aÁ¢\ 4\81È5µ\12\ 42WïÊC \eÛ©\ 1-zùf\ 22\8f\a\80hCÝÛ\ 2\99K\0ȬRn\0ÙØ}\\rÀxÈ\ 2\909õq\vhßî')\9bçv\91\9f\92\8c@Ëë̳        ´6/6\8c@æ¼V\1e      ä3óÌ7\81ìÏêe\95\11hãê|\99\81\9c+­öÛ@Î*­3\fÌ\ 6t\10h\930ëM gjÍe\13\98\9d\83- '÷¬å\16\90\8dRJ\b\8c\16\ 2Zv¾\8f\80¶l\ e\80\16k\r\0\8d§g        h\ fZ\87^\ 2ÈÜ}\8f2\0-/ /\0¥A±6/\0Ùf\15ð\ 2\90\99Kq\ 1\88èÒ\1dþØT|0±\84\91ºªnþ\18s»õC\eJ7\rý\98s\9b¡\1fsõ|ô\13®P\rüxMé=ð³\9cÆ\8d\9f=x\94ÐO¸\84S\ eý\98\87/¢£\1f\eÕW£éÇ\87¤uº¢~ÌÍ\v£\1f_s¹júY¯ù\11ÌôC\9evÎxÕO:j\89¡¡\1fri¥\85~Âõé'Æ£\1f\1aUk\rý\90\17l\86\9f(&S\92\e?4îjÍôCn¶\93\90U¤¾ê\87¦Y\8a\84~È£\8c\19úñó¥áÑO\ 6\1aø!æ±ê=â\87\f×Æ\8d\1f\1a{j-ðCÆëõÀOöùå\15?6N­¡\9fìCÐÒ\ fyd?ì\1eþØØ|/4þ\84G4éÁ\1f³¤~óÇÆä\ 3küÅC\16\7f̵ç\9b?ûú\9a\83?»ÈÏHÆ\9fߤ\17\7fÖVFðÇÜK        þø\8a\9b?4\96áE\95ñg\ 3\9bsðÇÉ2˼ùCc\17ÇÊø\93\8dñòϦa\96Û?ÎÕ!}û\87\98¥\1c\0\91S)z\ 3ÈIßr\ f\0\8d\e\9d\ 1 å1n\0må¤\12\ 2º?\1a\ 2\9aO©ß\ 2Ú\93\92\84\80ÌiJ\bh9\95Ï\ 5Ä\84mMï\12\10mZJ\r\ 1\a«\9f\14%à`ué{Ù1p|\99T¥-\ 3\91DýØK\ 3±Tzõ\8að \88F\1c\12Z ¨$Is \88¼\ f¸\aA®Sßk\rA\£ëÔ`\b2'§ë È\a\ f\9fæ\86 \17rr)\rAäÜú\ 3\8d!\a\82ÊÝO5\10DÆ1¢Ý\b\92\ 4\9a³\11dÇIÏ\81 &+<\90\eÁ\81rb´\16\b\82\ 3ÀÓ\ 3A.RuÐ\ e\82\93'\9bÜ\ 3ÁÉ>\1a\81àäÆ:\1f\15àd¹æe¢!8ÑY\vRG0aEK¹\10L(\14ò<\b¦\ 3¶!\988±ë\ 3Á\84jÍëFW0a\80{;
+&¼hë\ f\ 5\13êD/ù\AÁy¯¶£ \9daúCA\1e|¼¿]Af¯ß\AäîÛÝ\8b\82ÂÊW\8f\82<§I;
+"·Ô\1e
+¢±&=
\87l\ 5\85ç\97\a\82üv?I9\82¼æ\94\80~K»\rd[éÇ@|m*r\fÄçiÔ\87\81èÏìe\95\19ÈqÍIÃ@Ì\15Èô0\10³ªU   \ 2\8a\ 6\81\9c\84vlz%\103\15Ç\9e±      \1c,\ 3ÜZ#\10³[íL÷J vÀ\99ý\1e#\90Þ\0\8a \90yôy\13Èu\93ÜZ#Ð\0j\87@\ 2\95Ö\195\bDc]\87^
+È8f    \ 1\87\95\ 5õs\ 11[g\13\7f÷ 0aQæ>O\15\98øÊÕ¿\93\b&V\98¹<\14D« \fª\8b\8e\86Å\·\83ÈøÙþ#\ f\84XcX\.ºI\88\86Ô8¼\9bB4`JÎq[Èå\8a\83I\ e\rq\99´â¥ªqÈ\aÙt½<d«¶\1c\1ebM³v¯\ 1"\eZ*ó\161q§àhl\12Ñ\80\12ï¥0Ä\83K\9er\9bH!l®n\14Ù\93i:¥¦"xè61/\16\13Ê\f\9drjC¸\90UNm\88\8b>jC,¥âÀzmxÈóâ\10ceãq\15\87VÈI¸\88ßi{Ìb1\7fÉÁ¹XD\aH.¡b¦àé¨\88\8f\81¤Ü*B\9bQr \88¾·\15¾Q,än>Pĸz\99´P,¶ÐJ èÇ\9az£È³Po=PÜg£e"ÏOö¶¯&\16¼ÈH§2äÁÍ\9cY&\16S Þ&²qí£6Éâ!ËÄÂC\8d\9f_\ f\8ahLå¥2äEê+ÄT´\9b\ÉP\91mÙ×¢õ\19r5S\96\8a¸´ª¶[Eü\88®/\95!Gu\15}^\19¢[\8aÔGe\b­ø~Q\19\1aÑùT\86\18\aÉíf\113µ/\949}\10gn:ÂEð,yL¹aĬ/ný\92\91\ e©³m22\8fTõ¦1ùðå°Ñ`\9a%ld\9eÚ\1fõ!nã¯\1aÁ#\eF\1e§BL,\19êÌ\9f\ 3ùÕ׿~üöÃß>~ø×Ï?üúéí·l{÷õ\17o_}÷ñ×\ f?ÿýíÝw?ýðËûoþùþç\1fÿôÃÇ\9f~ÿí\17o¿±kþð_¯ùó§_Þ¯«~Çÿñß_ìw¾\81?û÷ý'ÏøëGþÕßÞ}ñöý_ùç¿ý\93\vøß?ÎÝ)îî\93\10½5Ôó\98 .;Û°\10Ø\98\95»\15rÅòf¶]\13\19E\ 4³´M\ 4\1aK\ayh\84¹\9d\17Y  É<«ÝÄ   ÉȱØ÷\bzö­á\10ÐéÉ´\1d\89\19úNËÝ3üóþî\1emMãc\16 Èµ¦\95\8b\b6 ø\8e\86I\8cÆÜÕ~\97`³·,âß\91ü;¤õóð+\b\eS!S¸\bÓ«ULÜäÏÀA\8bYY¬î{0Ù&\eÛÐé½Ví¢Â-\ 1µ¥\88E\9b»û\1eãUß\8d\90mb6,ã\8e\19¦ÜÖ°`\98ñ«W \9d\]4rëäEÖñÜO1}\11¡¾Ý£´eßcû\17\e¹\94ÕÊ>û"Ó\f\19Ç\19{æH}\17øÀ»u{\12Ï\19¼¨v±7\ 4\13\9d¹gï\16;\1dì\9b\94\9b\10\88=ybµÙE\1dOVniû%éþ&j\8d\15f}¥¼¦tµ{\9a\ 2ud\8c¯÷w\7f¹\a¢W\e\14n\vÌRí×L`jÙ^\19y\8crn\1a\9d&f'r#Ä\1c}\1e¿\98yFåì\18rnj¹ØMpÙnÚ\ f±z\89¹¯yØ7®öõjó\8c 3Â8\9b»3î±/2Áâ\1e®\ 3.\92\7f\91/<s\90ý2±!qµ¶Úâ¦ÄÚ¬é\97      »\ 6G\16E'cænª,¸ìS\e³=\e2ç$\e¹\90\90¥°+\95\87ÒîÓ°Ù\ 2·\8dàÌUvUG\7f\ f»\b¿É\16¼*\ f\ 3\98à­ÛçÊ\92gßÔ´Yc·J\9e\8b"\997ØÂÖ"\11ËV\8aî\9b|äð\9aºù±^Á\99É\9f\81\12Æ>\8e\1cs\93
+ë1ËÙsæö4¹Ó\14\87®éÿ²û\9bÿ»Ý¬|PÞ<¤e9Ôæ\91\16y´~¤\15BX\1fÒbÙÍ©GZdÌÃ#­\10 ú\1f²ë-Ëq\10\ 6\ 2è\8eú Äsÿ\e\eU    ¤àùêSJÚ\8e1\Ä\87Z4bS\92ZÁî¦I­}^<'µâG×ðV°³&·\88Z?Ü¢Xfr\8b\8e\11F\n-·U?Ü\8a¿Ùà\16Ð`\ e_oíÇÉ\90\8f·öØ\84üz\8b±³\ 5p½5wÐ\ 4¼ÞV[\ 5"é­-(Áø\1f\ 1ö=^oÑñ)æßñ\16ÍܵT¼_°\16¶¿à¢y[Ö\1e]p-÷Ð\16]ÚÔõj\8bV\r­ýÕ\16¹\88\86¶lK\ßÔ\16\18-´eg´\ 3[¶S«¾Ø¢  ³ÓÄÅ\16\8d\Ik\11ñ\e\1fkQì{\85µÌ¾×ÑZd>í¯µV´Ã\8f\86µÈ>\9bH-¢û\98Ò¢6|s¦´?\97ð\93©å²Æ+-o>Æ\95\16ßÁióJËÿñ½<¥e\11\91\967r§nÇ9\8f&\ 1-\ 6³cò8´h¿7ö\9b\ 3-¦      fô#-&Ô\1c\1d\97ý+-&`ë\1fi1K[Bkqö\95Ð\8a\1f&^hqHêé,\16CÑt\16Yôã¬\9c·v\9c\15_]á,pÒ\ f³P¬öd\16ÙïëÌ\8a\9f
+þg\16ÓXV}ýCQ}Øé\1frí=üã:­úú\87¢î\11þÙ\82ÙÙg"ÕY_ý°¦æ\fü\10ÑØ_ü\90\9bçÀ\ f\ 4LßÔ\89\1f¾£+õcÖ\17?ÖÊ\bü¸øk\ fü\90\97ß'ñCqº¼Ä\8f\1aø!÷ñÚ\87\87ì*a\1fÇ­]ú°ú·¼òYà\13\1eøìïè}\ 5\99?eÂ\87_ÄÉ{àãR=\9d%àãPÔöÂ\87ñbSxàòÃÙíÚ\87÷":_ûð¾qÔ½öá}\1f§¹\968ÝNó\1cöa\9e\96¡aß\9dë\17\8fòi4±Î\8aw\96°\8fKyìÀ\ fyµ×>Ôö\1ea\1f³\ f!íÃÒ>]pÚ\87â\10   û\80\84z\v\90±v\1fýP,*¡ßÏE¨\1feYíÕ\8f·\1fýê\87ØK\výü\7fö«\1f\8b#ðã}|Õ\11?<áô£[ê\aYvÙW?¾VÀuôã\83\8eúêÇ!\1a=ôë¤x\84~\9c\85M_ý8SýHJþðnÄ{"òÇ×í=SòÇ\89ÑvøÇ\ 5Q\9e9aïJ^ÿX¬ãúÇ8\82?ÚT×ë\1f\15s\90è\1f³hø\87\\8e\8f¯\7fÍ.Ûg\7fýCñ4Úô\ f\15þ!«7üé_ÃÏ];üC\16\87\9a\ 2Z¾ó?\ 5DQ\86\ 6\81\96\1e\ 4"/ÏA`ÃRõÝ\96\ 4â;Ó{7\12È\Ûk /ì]"\rDVYa r\9dí5\10Eq i rk=\fDÞÞ\10&\82x$êz\10äài(hq¨\9f\ f\93A+.¼Ìë å½»\84\83\rët­×A+6\19Á Å\10\ e\fZ¶½u¾\fZÑ»µÃ`[6V»\ 6\83\96\15\ fô« Õúô-\8c
+ZnËg<×\94åqTL\ 5­8\9bï\ fTÐò®Þòq\16´mëÕgw2hÅÚ¦\\ 6\1a5\18l÷°ôë \8aÞò\91Áv\ f\\87AäÓ\9e&\83VìÅ{12\88<]\vJ\86Ük}\19D±ù®I\ 6\7f.B\ 6q§5×Ë oï{\12\18äwö\f\ 6\99}\93M\ 6Yì-\1cä\8d\1c\11:\88Ïm5¿\ eb<õl\15æ ß«®p\10sE{\7f\1dĬê}\87\83í¢|\1cä,Ôù:È©ª5\1cDv¤É ¦÷ìú2hž[\r\ 6\89ÎîÁ \97Hi/\83,ʾ\f\85é \8dªõu\90\17\96\19\ e2\97\19\ e"·sÍ×Aµùºýt\9a\ eZq\89\8f<\1dDÆkº\ eâ\9fN\9b\99\ e¢(k\85\83\96Gß5\1cD.£½\ eZ±÷QÃAäâÇ\10:\88\=\87\83\8aµêû.\1dÄwÄÛ8:Èì³8\1dä\85÷
+\a\8a\9bá òð\e¥\83(vW\98\ e"¯ÖÂA\T}\9bI\añ\9cZ5\1cäài½\ eZܳÔ×Aݦ´\17é eÛT\83AÅ:]ãeÐ\8a\93³ø8hÙvü\96\ e\16ì±ãã`9\9dÛu°ØXíd°Øú<\1dx:X\8c\946ÒÁ\12\83öùú2(Ö¹ù       Â\19\14\eöó%2(Fܬ\1f\ 6ÅFÌÛ?2h\87\97:$\19ÄaÆ\aò\87A\9cxÖJ\ay"Úé Ø\93x«úã \15[Ñt\10§5ïôÜAû|Wù8hÅU5\1dÌ\8b¸\83\96ë\1c\1f\aqû>ÃA|g\8ftPâäóã \8a½¦\83¸\91¯>wÐ\1e±\7f\14´á\9cEBA¼U\9d¡ ¦
+Ïs¿
+bRí>CA¥É+\14ä\1cÔþ*È\89ª\12
+"oï\90È å"ÞA%\83\98òêg\r2Hs¼C"\83\!E_\ 6Y\94u\19dôA!\83$꣠¯ë,QAæÒCAäu\94ü((Ö\15\8dùQÐ\8a§\1dv\ 5\ 5]P"hQ¼-ÿAÐæ}_\92\bÚÚØ«'\82\96[_\1f\ 4mAíÞ\13AËmÌDÐòð\9c\bb¥ú®ë\bÚwº÷q\8e ²\8c\ f\82¸ð\96Dв\1fhÜÀâ«þ5°ÄÁÑ\rÄê×\99\ 6Z\9eÞ\eþ\18h\8fI]¯\81\18:?\94Ñ@\89výÇ@ùk{÷4PlGm\9a\bb\91~ZA­öÝ^ÓÀ\9a¼Á@˶Áî×@+zßv\f´¼¸\9f\1c\ 4UíIk}\11´bÅ\15.\82\96¥ï\19\b\83b*hÅVÛ
+\ 5-\8fâÍ\1f\15´lÂ\8dWA+î:ô*¨6\1cÃ%¥\82z\8f4¿
+¢(ÞeRA½ç¢£ òiUSA\14§7eTPñÓýü@\ 5\91UÚ« \8aÕ÷M*øs\11*\88ìS5\11äÝû5\90ßX;\fôÿè¯\81\11\ 6"/'\84\ 6bTÖn¯\82\18βûU\90ïU\13ÁjcÒæ\aA\9bTÚ%\11¼ _\ 41 ëþ hûT©-\11´¬Þæ9\82â?êEÐvÀ©-\11\ 49k&\82È{|\10\94óÞ\ e\82rÎa\17A\b%í£ .Tv*h¹î\9d
+"\9f
+V\9b®ÓOª© \8aÛG\9e
+"/ÝÁ òi5\93A+ê\9e;\18DÖÕ\82AËuõñ2\88¢ö\16\fZ\16\8cÔe\10\9f\17ÏÁ`ÅZõM\97\fâ\7f¶·qd\90Ùçp2È\vïP\10±\97\1d\f"7¿O2\88¢úÄ&\83ÈCG0\88\1f\1a&\83xl\91\1e\frìj»\fZ\1c\97A+Úð¶`°Ú_i5\18¬X¥óã \15\e§ñqв\117ÂA˶î×ÁÚ¼o;\fV{ܽj0hYg\95\97A+vüªË å\8b6\17UÅ»9Ým0hÅÉÅ|\18´l\93@\83Áj³`\8cö2hEûP.\83\16\1a\f"7\1fÊd\10Å\9e½ c\95P\10y}\10´\9a5À=\10DÞÞå\11Aä)ú"\88â\90\1e\bþ\\84\b"\97±^\ 5y÷¶/\83üÎZÁ ³ÏÜd\90Eï9È rõÅG\ 6qÍêg¬d\10ÃÙ¶^\ 6ù^ë\ e\a1W:ÞƯ\83\98U³íp°\12é`\90\93°Î\97AÌÔV5\18\93$\15ÄìÞÞ>¥\82(\8aj(Hr¼?¢\82Ì»¿
+rÙ\ 4\82L>&D\90@}[A^ÇU"\82ÈcÏ@\90ù ù"(6þÒ÷\8b \8a§\17&\82ÈUk hÙµK\ 2QÂ"¿\ 4Z\1esΠ\10¹öW@«Y\ f7C@äÚw\b\88Ü<\87\80Ò¹>.\80ø\8az\ fG\0\99Ëz\ 1äu\97\86\80\82U\8cU{\ 4D^}½\ 2¢8\87\84\80¸Hñ\93\16\ 5DîÞ\18¦\80xJÚz\ 4äÀùq\f\83cq/?½¥\80bÃ8×\f\ 1\ 5\93\e\83\7f\ 4\14,ÑY_\ 1\ 5³®µ\10ÐòÅ\r\0
+&{\91\17@+zÏv\ 4´Ü¹\99\1c\ 1-O\91ö
+hÅ­*! å¥k\87\80øü\88\98\ 2ʲeÕ\ 2@\8buyßG\0-\e\ 5Ð\8a£ô~\ 1´h?j\ 4\80r\ f3¿\0¢¸½Á¤\80rODG@Ëët©I \8aÝ÷C\12(8®ùÑ\81\ 4"K\19/\81(\16ß4IàÏEH r\eõ%\90·oõ\12Èï,     \ 2ý\7fæK \8bº\82@äá\82\90@<¢Qò\12hE]k^\ 2ùbÑÑ\1f\ 21Y¶î\97@+\ ei\1a\ 4Ê\ 5ù\18ÈiXå5\10suÉ\b\ 3-WÑDÐrQ\9d/\82\98õ½\8e@\90ä¸\1fD\90\17\9c¢WA\17h\86\82\14ª\8cWA^¨H(\88\84\82Ìç\9a¯\826_{\9f\9f\8aSýá¨àB\v\15\h4ýw§\83ë¯Ì)ý\1fëeÓ«ÙM\ 4á¿r\97\89\84\88¿?`\95\90\rb\ 1R@d;JF$\ 2B\14\r\8bù÷TUÛí×G\83Ø h¢[ý\1eû\1cÛÝ\8f«\9d\83\83»Y\87s\10åÒʲ\86\ eB\ 4Ñ1T\a!j¬qÆ\r®Ú+\17\bY¬vç
+\84xÄLÇ\ 2!u0|\1d\10rÞa©.\10²\96\83ÑR \84V\11_ ìº \92\83°ó\1aìÝA\b\8d\9e¢Þ $\15BO\ eBî]li\83\10ù\9a\86¹\9d\ 3Â\ 1W1l"\81\10@\0z\9a\83\90\rj\a\84\93]Nj\ eÂÉ|\18\ eÂÉûu>\9cà¤i[v\91 \9cØ«\ 5S\ 3aÀÙÅü\0a@\16\90ÿ\e\84Á±m \f\80Ýr·\a\84\ 1§\91Ç!aÀ-Øê!aÀ\ek{\900À/\9a÷\13       #z¿R\ f   Õд\a    Ù\ 5Ù~\e   ©c>$\84^Fõ\85\84\91\16¸\1f\12²g3\9fg$\84®¡>H\88`    ý\90ðLb$\8clc\1e äÛKt\10ò\91c\ 5mD}p0\1aï\9c\83xmÈñp\10¿\a«£\17\ eb;\13í\95q\90çÊBÝ\1c\0N\ f\ e"«*?ma\90øí±;\ 6\99\84ê\9e^1\88LE÷3\1c\83\83V %Çà`\92×rc\10\97àL6H\18$s\80
+Ç õhóÆ ë&\18p\89A!¨\1e\f\12Q¡Ä\e\83\b¢Iq
+Rr¾MÁ!kP>AA$ë¬1ö\e\83\ 1e\99Ú<n0Ð\b\15{«@\18h6S~\90\10Ñ\b3T\1c\85(\10\96hq\16"\80\8f·O=0D\9d¡Rí\ 2\16\r\11\b¸\9a\86ã\10\ 1äå\1c\17\ fY³hR\92\13\11\9asr$r\9e9\9fLd´Û01\11eM\1f_\1c\8a\fÔ\90çMÅÀ\e#Y\ 3#,"\0«÷b\101qN3Þ\$$\82Ö²ÀÈÍ\fÓpJ2\ 6®\88PºÐ\18à6ºÍe\1e\11ïL=\1e\8f\88\93\1e/\8f\88Æ'·x<â\vöd\12\ 1v\1dÇe\12e碳1a\13Úp4¦_óh\1ehLxiÊNÆD\8e\87CFü\f\9b\8c \9b\92\93\831á¨\89\86\rÆLæÍ\a\183ÊX\86ÉÀ\88\9e\ 6I\97\1d\8cÖã\94\e\8cl\8c\9a\11V\13îFiq\91Í\94\96ûÊEìW\1eá8DnªX³¸\88ßÇ4}¸ÈàºKÅÅ\97ITn\99½\8d\ 1#\82!\1f\87Ègº¥\9eȨ1FÊCF\ 6\93\95£È\b]\16WDF,       µ[o2b?[?\ e\91§ºÌ\9f9DìJ&\13.\87\b`eZ\8aí\10\85ét\1c"\920ZOwÐ\88Lm\8bËB#ôLµ\ fgc \12\87¹²\ 3G¤}Þ¼\17\1dÉ¢ÕÑ\8a\8eÔÚ\83\v\8fÁ\8e/m>
+MÆ:ñ\91zööð\89\813$3eB$\ 3#\8dã\14\ 3mC\99é\13\90üâË_>|ýãw\1f~ü×Oï~ùøö\eÆ>ûòó·/¾ùðË\8f?ýíí³o~x÷óû¯þñþ§ïÿôîÃ\ f¿ÿúó·_é\99?ü×gþüñç÷ë©ßò\7fü÷\17\e¸¢\7fß~4\8d¿¾ç_íí³Ïß¾ý+ÿü·ýòÇý\0ÿûû\19\1d|t\83\19B\ 2\16^i°\17ÿܱ\8aíf\10%LYPÞ\90¨Ô"\r\1f!Í\ûn\8dÉ\r<-lã\8a\ 6ÉER#\13©\99\8fe¨J÷\908»Åàtù\b/%ê\18ÀJêf\1aµÒl»A\9f\ 2\1f\89ÝçÏ´ \90\98¤\81Aè¶\13O1¤0c¼\ 6¨qÝS×:í\15ahJÑ|\ fÂ\95\10\19ÌHW=\ 43 )²P¢Û¢ÆTÃÇ H1\11Ó¾VÛ3®\17ùÌÛ\10\1a\f\96&&|Ð\b\16\ 4FµGÊKhÕRç\9d\ 6\7fVØ+­\8fC,O\142c¸\94!µë\18\ 1\ f@     ä'êHªï!º»\18,Øç.Ûg¯\81\8d¡FGSõ{-ÛàGìPÓL\89ý\ etiQ\v,\80$uKI\93à\ 3ª\ fê¼\81\18$X 'JM\9adé        WúÐ\82\eÌÑ\1a\ 4îÐ\9fi«pÌйu\rÒ×%&\94m7\8fp\8f))è\\91B\9a¸0ExFuÚ -\19G\98\10\1cQ\87-\ e
+xPÓ\ 1P³Oe²\0F>¨¦¬Am²\85:\93tä>e³$DCTÎ\8b\80N%jÂò©A5%r\9eq\rêJtL~\ 6ÑØ°\1a\0x{Ѫ:\9avnËÄ\91\90¢\ f
+ôf\ 5Õ6\90Ï<Zn,´ºÒN¿¥\9fuh;\1d\12M\ 5\83U\19\14\92\ 5l%\82ü\8aÔ¸XÓK¦\16M\14gS\r\80Ë\1a\84¬Ö Ü§ú=´p\8a¯öjAÞgª\89 zÖÕ \1d¥1Ù)>;9,3žà£m\91a\12\9b²¶\81»õ;g\98\ 1©ÑiJ'ÓìΨSÎ\ 69Ìý?¸ýÕÿ\9dÛ\ru\ 1gó ,\82,ëMYÈQÛ¡l¤¯-\ fÊ¢ê¦e\8eQ\16\1aFâP6Ò@\96\e³\88Ñ\8b:f#/¶|0\8bß\83é\17ÌFk\7k#ïÔ\83\9cnÔ2\16úA-\9d¦aÓP\v]Fz 6Z):jI\99\9a\ fkñm±Å\ak±hA|³\96;WÒa-¨Ãëÿfm\ 2üb<¬E9Å:\9dµ-Ùg¾²\16±\9e\99{ÆZÈÍQÁ¶el`ª7l\eýhê\ e[èê¤\85h=\8f\9b´\b\8e\93\96:Äì¤\85\9e\8b¼\87´\r\9e¿µâ¤ml\f¦\83\16\12\1f\9enÐ"\88\1a\9d\ eZh\9a©ÅY*\9aù\8b³\f\92§\9b³ÒFCq\96Z«}å,\82hz²s\96ÚRI\98¥48\1eÊ2Öì^\16e_¦ e)Ãh7eõîÖ\9c²|(\86ê\94Õ \19oÊ*Ø\92SV/ªÝ)ËI\8d$\a²ÜÌ\1a£C¶±?àe³ Ë4a\vxQ\96ùÔ\8d\88¤lÛÈß\94MV\8c7e\99£å@\16²Ã\90:dÙ\86µø\80,\82±\1eƲ\16B>\8c¥\8eùÁظNm36\1a[\9d±$S¾\11K\82¥z\10K\1dëA,t³)\1f\88eÃǯ¿ØÇ`¶m'û(S­Î>u´)ßìc0ÏæìCg9\8f¿¤J=]äcïÙ»\83\8f\92~~\83\8fº\98>à«,Q»Ð >>\93Ç!\9ft¾À§Ph\ e>hLP\1d\1cz\81\8f\b\v|\9c$Ôä࣮íæ\1e\97Xstîi×\8ac\ f2ÍxS\ f1­pA\ f\128\18\ e½ÊÊdi¾@\8fý­\12× §vÖ\1c¥ ÇNµØ[\ fôØ\9a.3(è±5Ís8÷Ø\95ÆÜoîUò®\16ç\1e[ÕM蹺·å\8e\ f÷ØÃ\85\96\9d\13Üàcÿ\18\1e\ 6\93­h0C)î©Ýms\83\8fr\94\9b{\8cÍÙ\9c{ÒÖ[\88{Ð1Ùåv¸Ç`\8bѹWy\96\ 6K\81\8f\9a½íE>\ 6C\8e\97IH>Êb_wȧ··ê䣮Ö{\89|6hÞäS°9øô\9eUr\ 4\1fWØ­_;äÃÎᣦ\93OçjÔ\12ù\98+\934}%\1f\92
+>µnòUa¸9ù\94\83%ßäS\9eæéè\83®±6G\1f´öùB\1f\13¾\96éìS=\98\19\12û¤c¼Ù§`jÎ>éæè\13\98Ò¸Ø'\82\19\8dÄ>icªØG\1d\16\eoö1\95k¯7û\18\94Á6öQ¶2\9c}ÔÙ|þa\1f\82¹Û\89\8a}ÔÑ\10½«1µÖ.ú1\16­\81°«\ 6õÕìc\84?êaúàOd°\9b\96øã3ÝL\9b1\8c:\95\8b\7f\9a×Ì¡øG\9dãpþQ§^nþ1\18{wþmrlþQO3\82\a\80\Ñ4Ã%\0jëò! «^­Ì+\ 2!F
\19ÈÁ³Fg ½q\\fdÅƶ\11¨z5º  \81Ú\8cØo\ 4\96\85`\97u\8f,\ 4ªîòM@\1eq/Ý     ÈÓ\1c¡:\ 1\99!\8b\88\87\80ÌÔR\9b\13\90Ù\9e\96Õ\8bVWèÔÊ\8d@\16[éÑ\11¨\82ni#°ì\ 6é\95\81\f\1a½\84À²\9b¬\85@j-ø\15\81\bÖ\10ª#\90º[£P\96u©5¥\e\81\f\16»0\85À\97\95w\19\bÔÛëp\ 4ê!k\8c\84@éÕä8\ 2\15¬Å\19¨\17\95é\fäï¨ä\9b\81¢KÈÎ@\1dl\1eÎ@-µÖ\9b\81Ú$ã\15\19X6\90\17\ 3\95\83¹ß\fT¢æä\f¤¶yÍ?ñ¼k¾\11ÈL\9f%9\ 2\ 5\9cY\1d\81ª\10»\19\ e\ 2\15\8cÓ\11(]³3P\80Jéb &\8eÝ\19(\1dº3Ъk~\82\81\19³NkI\ f\ 3\11\1cÑv\9e\f¤\f¥;\ 39f¹ËÃ@\ 6ã\18ÎÀÌO\99É\19H\1d\18\88X­Ëî\93\81Ô¡gg u2}\18\98\99\1e\92\81|&\9a\7f\13\ 3¥W\ eo\ 6j^ë\93Ä@h\94[w\ 6R7kz\ e\ 3\19Ôí°\18H=Jq\ 6rÒl\9eð0\90«Ìvm\88\81Ú:ógb ôì!Ý\fÌÈ¡fA1\10:çê\b̬ÒÑ.\ 4\95ÁÆ@H\ôå00ðnm\ f\ 6\ 6wlÆÀ\80\9d\9a\a\81\ 1\19`¹òÂÀ\80ùK;\f\f\a×b ~\1fO\ 4þ\87í:Kr\1c\86a\0z£.\91Úï\7f±\ 1\b\87²\ó     vÚqdê\992Ll\9a\1cE áí÷|(\b4,¨\9aôE aA4õ\89@\9cX\Ý\1e\ 3\8c¤z\11ÈSÎZÇÀ8\ 5íc añõª{\19\88b+õ\18È\13\9aà\94\81øûvû\18\88âòz\f<\17    \ 3\11]/«\97\81üvé"\ 3ù!  %\ 3í\9cw\8e\81,v?\ 6ò\8b\9e­\17\ 6â'ö\8f\80XÎYì\bÈÇ*½B@¶Êìí\16\90=\15\13\84\ 4¬áñJ\ 1£\ 3k¿\ 5\8c\96\ 22ï¶\92@äbÝn\ 2ÙðµY\12\18Þh4
+\ 2c\83\94z\13\18\95\83ÀÈZ\95 0|º\ 5\8cë>'^
+\18¹ô\14\90y=B~\ 44ìß1?\ 2\9a6ÁO@ã\969\0"\9a¦ñ\17\80hû®ç)\0±5öê\a@äÖ×\r ¶ÓÖ\98/\0\91\9bîE\0"\ få\17\80ܨzã\ 6\80øL×\0'\0\99\0òºÛ\ e\80È:ÅÈ?Ä2ÆÇ¿\82\15\1cûøÇ­_çñ\ fyj&|ù\87\1f9õÒ\92\7f\8\r\ fÍZ4u¾ü3tæîÇ?Ã3Ó\18-\0M\ 6¼ýs Å\8exüó¤-üCÆ\8bußþ¡ø\9b×Â?äÕ5Ò\a\80µ¢EÝo\0Qô^w\ 2\88l}Ï\ 4\10¹> \1e\ 1\13_) ò(ÏÐG\ 1\91\81Û¸\ 5Dq»\ 6\8b\10°6ü\161\1aw÷;Ƽ\ 5dÑt\0\b\ 1ëï,ô\bÈÜô \8f\80,Î=SÀÊ\83\9aN\r! sµv\vÈ¢?Ó6\ 5|]\84\ 22\8ey\ 3\18_ÞÓ¿ø\88\ e\9fþ¥ßþE±\8dô\8fy5Kÿ¸(k·[@.gÙ=\ 5\8c\a[\ f\80\8eEió\ 3 ±A-\ 1üaü\ 3Ð\9eÁé\ 2\10ï¨âí\0\88\5Þ    @4woý\ 3 Þ~³¶\ 3 ¹y\ e\ 6\ 1 ³^\v/\0íyn?\0-\8f-\ 2\90<Y»\ 5ä\85Ê>\ 2"ûÞG@f]ó# £]§\8e§G@\16·V\9e\ 22®º\93@ægÂ<\ 4¢X÷ÜI s]-    DöÕÇE kõ\99úÙ.È8áö$\90\7f\87@çVÕ\v\97\ 4ò\7f¶æ· 0òÓÁ?\ 2ãº;\ 5dì:\1f\ 4\81Ìmô\9b@\16«Ú:\bd\1eu$\81¼7ÓHx\bä\8f6ëI`¬\9cf³ \10y´Ýn\ 2QÄê¶$Ð\e\7f­'\81Î=:o\ 3QkÑÂ2\10\11¼\8d4\10\19oÖu\e\88â3¯E?yÇBéô\12\ 4"×év\13\88bßu%\81ÈÉ5÷\13òxÆ×C \8ashp\f\ 2\91w\9b5  tÞåh7\81(\82EK\ 2\91[éõG c\13T\87@\16û\99\ 1#j|\v\ 1\99×\a@Ô0øö\ 4\90yKÍ\0\90yZ½\ 1dqXO\0_\17!\80\8ce¬[Àøò¶\93Àø\90ÎHA`äç¼\93\ 4FQÃF\10ÈìÏÎ#\81¼¨ë`u\bär¶]\93Àx°ò+\fd¯t>\8e·\81\18_e \aÐI`´ Ï\9b@öió\9a\ 4\96\ 2²·w«·\80,b{¤\80Á\8d\ 6£\100òî·\80±k\ e\80\11µ(\ 1`èô\19\ 1ã:Ï¡\97\02\8f=\13ÀÈ\ f\907\80ÖùÐö\r \8b1\ 3\v@F¯\9e\0"KºÃ\1fKU\8f3øC\1esÎä\8fÙû¥\1fJ\98ÝfêÇìº\93Ð\8f¹)\1fý¬Ç\ 5\1eüø\91ªá-ð\8b\85_\vÕÔϸ\85\8b§~ÌK»èèÇâ\1c\96úñ"å9^Q?æ®\81ðèÇßØ5y\85~±l\9aÌB?ä\1d'\8d·~\ 6nâ¤øè\87\{í©\9fq\83N¿ôCmNv\84ôC|`\vü\f÷Ô\8aÝø¡ø\9bÕB?ä\1eo\91G?äiÖnýPܵZê\87¼êÚ©\1fÿþhxô3>¾\96ø!úzæ=âgl\90¾nüPÄ\96é\89\1f2~ßøág¿\ 3Ì\e?\16·fÿÐÏ~§ G?äå:§\1eþXìz\15\ 6\7fÆ}¨\ 3CðÇleÜü±Xô¾\fþ^\17!!\8cmøÍ_|{óä/>¤M\1düé\9fæÍ_\14ëJþ\98G­É\1f\7fâXãæ\ fźÖLþâɺ'\7fl\96]÷Í\9f=OãáÏ~\18?þE\13ºÝþ±S\97\8dô\ fÙ­\1e\0\91K­ó\ 6\90=ß}$\80Á\8dð\b\0#ëµp\0\8c\8dSj
+(\7ff
+\18<\95q   \18\17*\96\ 22\97m)`d]ó# \9f@\9f\9f\11\10ÅÉ\96\7f\ 4\\1c\19\ 1\17çKÝö1\10\8fvNëi Ý\9a\86\81h\85Ñ4\12&\82¨Á¾\9e\b¢\87âö\7f\b\84ûF\90{Uï["\88\8fhÜx\10d.²+\11äe\97ú<\10äF.\822\10Dö>>\bF?oO\ 4\7fÂ7\10D\ eç.\ 4IB\99\9e\brålx"\88ßéKsÎA\10«hKû?\10\8cgTG"Èf\99Å.\ 4Ùu\8d\9d%\ 47}[\89àæ{u\7f&ÀÍaMcb ¸±Ráè\ fÁòWºÕ\ f\82\ 5\93\82ï\83`9`\a\82\ 5¾h|}!XðC47JÁ\826\1aý(X@G\1f\1f\ 5\væD\8d|RÐpàk=\15\8cCÌø(È\93Ïô£ ³æ7)\88<ô¶{)h\1c}çQ\90ç4Ñ)\ 5\91\1f\ 5Qle\1e\ 5ÏEBAãÙå\83 ¿¼ÙA\90\9f9# þ¥\7f\f\8ec ¾¶T;\ 6âïE\9bèe \96ÓWO\ 3ù`Ùl?\ 37\et~\fDSõf?\ 2Iï´\99\ 4²\ 5ãÐô&\10÷\80CÏJ\ 2\17§\0Y\e\ 4rcÇ\81îM ^\80ÛõOA \7f-\9cH\ 2\99×Ø7\81Ü6Ѫ\ f\81\ 1P?\ 4Ò§ò\1cQ\7f\ 4¢Ö\9eC/  a\»¦\80\82ö\1f\ 1Ѭ»\9bÍ\9bÀ\82Mécç\14X8\ 25}g X8czý(\88ªa\fjÉ öG\8f/ü9\88\ 2n]w\9a\10b\97õº\85zH\88BÁKi%\85( +÷º-ä\96\rÒ\1e\rñ)ëµzrÈëìýñ\90Å©\7f\8a\7fÆ\9eæðÞ\12D\16BÂKÄÂW\85Ï\9a\80\11ï5\18âÂÕ·Ý&R\88\12?åA\91KYö\9c©"x\18s\8f}³X0gÌmg6D\ 3ù´3\e\ e¾\17ß³!º¹\ eËÙð\90§á\10Û3\9eÅ5\1cÆ\18gé¢c\rÇJ\16ý\8f\ fæâcἦ\8aNÁËQÑÃ=»Ut<\91ê\89¢ã}Ø\97'\8a\95Üí\ f\8a\95ÛoÌD\11\a\99\aE\9d\8d"\ f\8fD±þý\e\0´Lxq\r
+endstream\rendobj\r11 0 obj\r<</Length 21380/Filter[/FlateDecode]>>stream\r
+H\89¬\97Mëe·\rÆ÷\85~\87»)L ÜX\92%Ûí*/\14J\17-$¥Ù\95\90\84fh\9b\860]äÛ÷\91t¬sý\87ÒM  3\99ç¹~9\96¥\9fí>Úxôñd]ó!Ͼ\96\92k\11]\8fo~ù\8b_ýU\9e*³-7»LE#£6{èe\ 4­s¥6\9ew§ÙÚ\fsµþx\19dôå\92UBNÒ^}\9atvsñ\1aÑh\b\ 6\9eÏ&\8b²Ó\9c®IYª\13óR7\ 5?{£Î=\1a©\90ø\92ú\18ñûhL»S³1±îõ\94¹ìÁO&êâÚ\ 4_IÏ>\84ºë¾\88³\13=yI·0u \rMS\8e1üÿ\84\8f$|\04Ï~õiÏi\11«õ¤eò\80^¬c\86A\93a\fBÐÈ\8dfMw7\13\9a\12sEH\1a¾#6j>\17f\v=[\ f\ 3íÖî\16ÛDZX¦\81fÚðÑ¡'¶Êõ\1afn\98ÍÇgW/ÿ¨\b\99é\88ÉæäIa\f^n\8cÕW\8ck\88Aöû\9dÿõñ'?}øüý7\1fÞÿë\87¯\7fúùñ\e÷Þ}òÑãã/>üôþ\87¿=Þ}ñý×?~÷é?¾ûáÛ?}ýáûß\7fþÑã×Ñæ\ fÿµÍ\97?ÿøÝÕê·þ\97ÿùs|è\ 3+\88?_ý\9c\1aÿúÖÿe\8fw\1f=¾ú\8bÿóßùË\1fw\ 3ÿïïwïV½\rÛè\19\88}C\80ÿ¹-Et{{.C\ 2ºîØ5פ!IÈåT²\8c¹ùö#Áa\ eT\8eËÈ{HßVèÈFH\96»\v­\11¦\19E\eÂ\16¸F®JhK-\86\14þ,;\85n\12\9fEê»Ñ\9e$\18<´Äx\8d°ë5\89"\85ea-´¢\11\89\84n\96\934L\ 2=µÝ_Ö\96WÚzFþ{#6\97:cý4\905\90}îTõ\ 5\ e\89qx2gÌz4B\8dÅ\10X#ô\95¹»Óli\8e9#\ 2\91\96Ðb¨ÃÑ\9eÌ\8dC7½V\ 4S\16*\19&\eÂ\0í\81\87ì\84\90Ã$ú`~®>«K6òB\1e¨Zk1Q°\fZ¤Ç\98Ú.8ÀSµ\18\b\f#oÓ=\82â¥6\96kc\8e1¢Øv§Á#"×\18@\83\19\86F\ 6¢\f\86?3,m÷\ 1\81
+o`\9f¡ÅÆ\88P\1a@\ 3Ý[\862>`wêÜb_Õó×5õØ#,¬\87\8e\15CO¶»Ó¤Ø¤1Á*hÕ\1e3\ 1U3´HhDøî\ 4ÊFÚ!ëè±\aq½°)®íJCÛd\8déG\94\f\8fës\ 6E#Ä{w\1a\91ëëeIN#¯\87µ8'ʲ\9b\12\81\7fËRE\fw§Hv\98CÐØwVU\/ç=v¾çϱi;\eXF´\99-3\88Äk\17cPÖÈò"\86\8ecàÎÕ\1e#!àÞ\ 6À\8d>ݲøL-~împõÑ¡aÆ©\17\ 26<å*\12
+\1d\98ß\9dbç|\996ûE\9f\19\8d\84c¦®\92\1dÿ¬(&ñÉ\r\87d4\12NM+\99Å"\19»ÿÅíOÿïÜ6DvL9)\voéº)K\9e\94V\94\85Tîo(K\9e\1a£(\vÙ\eÝ\94ÅÞÌÑß`\16¦çma\96ü\\93\e³ø½¥~Á¬\ 3\9bµ\14yZ¨u)ü\ 6µn¶q£\16Z\13\9b\89ZJ"\9d¨¥ë6µQëù¤R¬ÅÇ\91Ñ\eÖbÙ\17Ã\93µ\1e¹Î7k)\89\96qº`ùÅZT\13\8e\8fb­9\v\96\9d¬\85\89ª\9aÅZèâ¨ÃÖ\ 4§\aë     [\98ø¬Q°\85Ö"-\84\r\99\aiáÍ¥Z¤uÝüÎv\91\16z]ä½Ik\1d\8bµ^¤\85æ¾
\90øp>@\v\ f
+´Ð£Ý\9cu\89r<9ëf\\89\86Îs.8ë:\16ûÊY\98\93I\8a³®W/̺\1crRÖ=\13)Êî!6e]·i'ecr³¢¬7¢¦EÙè´è lxÆEÙ\98HGQÖǼ@R\90õ`*QAÖü\81Э ëi¢&'e=¡F\121(k\eù\9b²\9e\808sOÊz\96ö\82,ÔÐyC\16óùSã\84,\ 5/\8a±^\fMnƺ&yÃXÊ]+ÆR^\8c\8b±Î&y\83Xg\18ë\8dX×9q"\16Ú®1_\11«=¯ø¯ìsO2èÁ>׬ºÙ\aÙ\16ËÉ>7eÙf\9f¢(îû¥+\1e|\92\ f&¶´Àç2®ó\17ø\÷Ô7øÔë3Oó\0\9f7\92y\93\9cà\v¯Y\81\ f\1aCh\81ϵ#ç\0\9f\9b~$lðù My\83Ï¥ÚÉ=_$\1esŽ\88Z/ìAò¢\93zð|\89\ez\90¦:\v\85¹ú =UàÁFA\ f:2iC\ fºwî'ô`îÛ`@\ f\9aÅ=5\ 4LÆÁ=x,Ú\8b\eÑQFÐr]\8foîÁì\1eÔÍ=h\9dó\ 6\1fôhç\ 5\13\16Î¥QÜÓ\81L´Uàs=ûÉ=÷Ö²â^h\99Å=hâ<Ünî¹é\99¶¹\a\8dKÇ*ð¹&^'ùÜlù\9c
+òíA6ù\÷ÙOòÅôùD\vò¹Ö|~\ 5ù²Ó:È\17\9e\15øb\9e¬¹\0\9f¯Ð#w\90\ f¡³\957¶ _lkB+Èç¹²\8cOò!«pOÕ"\9f\ 6\86­È\17YØå$_dj>D53SI­Ð\a-¢ëD\9fg¼öUì\8b\82hTì\v\9dܾÙ\17&[±/´\15ú\ 2M<Oö\ 5ÃX\8a}¡I\8a}®ÛÅÆWöu$+nÀ\aûÜ\8bÛõÅ>×¾Â\8b}.\85ìd\1fL\19¹\9dÑ\15\92\96\14ý Ùò\1c¼éç&åó!ð\aM6´ðçz¦¾ñ×½Ló\98\rüy£1¹ð\17:o¥7ÿbäµ\8a\7f®\85fñÏ5\8f~òÏMÊ¢\fþ¹î]7ÿ\®¼\aÞ\0ô%]`\r\0Fèä& ´ùCæ@ Ì\89\ 2+\ 6B/à¤\18ؽHç<\19\b³\93\15\ 2!\8bn\8e@h\1cªãD Ì}M\v\ 4ö\89X-.\ 4B\8bÊA@X:ú(\ 2BÇj7\ 1¡í"âM@\98£çÙ\10\ 4\84^<¹\bØá÷\fw!\10\1eã\ 1Z\b\84\96i\\bì×ûè` \9bI¯@`¿ÞX\e\81ýj{ \10¦¶¦\85@×C¸\10èZ\99O\ 4ºÙY\v\81{\90\8d@\9fi\8ey"0¦×Y\b\8cFù6
+\ 4\86¾Þ9ëeES{10&ê«\18è¿Çþ¾2Ðã)y£
+\ 6ƾÊ,\ 6\88êÉ@Ï*M^\ 5\ 3û\ 6òÅÀÈB\19'\ 3#U\857\ 3]渠  \bd7îÞ'\ 2aêê\\b\fâ,-\ 4F\89´~"0LZ\85ÀÐ9r²Ï\11Å|20F¦Q\f\fÝF1Ðu¿\ 6}e ×Ý\1aý` ç7eÜ\83\81®\91³\9b\81Þ%®\96¯\ft\93æÜ\f\84\8bZ0Ðudå+\ 3½®ôºì[Ö\11>Y\8a\81®9õÍ@\a\81æ\81\e\fôF\94÷Ä``hæ\93\811r¾\93
+\ 2\83F1еå£çf \9b~<l\ 6º\9e½o\ 6ú\98\92\9b\81¾Na)\ 6Fè²À\82\81N\81Ñød ~$KsßDq\9a\16\ 2}>ÜÿO\ 4úGy\ 6o\ 6ÆÊ®k_ÔHóÃÕÞ0°Õ\95-\19Ø\10«u#Ðë\8e×É@ßón7\ 3[ñ:\19\88ßç[\ 4"\97¼\8e\v\81Èv»\1aY».\ 4\83O\ 4¢¨fÞú\12\81¨D6º\11èï\97\fä\v\ 2ý\913çÍÀx\ 4­\9b\81^ÞyÔ½0\10for3Ð_h     Îd ~_Lo\18\b\9b'\19x\rR\f\84\ 6çÞ0ЧÏwT2Ð\eå\e)\19\93gÝKÂ\83\97o\ 6úDY{É@,Qß\10\10á\1cy¯J\ 2ú®&¼\82\80¾Ð\91Ûp\13ÐC¶?¼eþ`ÀY\ 4\8c\1c\14=      \18\89*´    èrõY\bô½#¥\13\81\91é\9d
+\81\ 1\9c|½îwËlÉï\e\81aÒ,\ 4\86ν
+\ 4\ 6¡Þ\100\ 6¾^¼NÀÐM\8b\80Q]\17!\ f\ 2ú\986N\ 2Â\vÆo\ 2\92_\7f
+\80PÔæ\e\0¢»æf\ 6\0ÑteMý\87õºé¹ä&¢\0üWÞeFBÄ®ò'¬\12²A,@
+\88lGdDF@\88¢a\91\7fÏ9Uvùº#Ä&\8a&3U·»ïmÛõ¸ì\0".¾\1f¾\0\88\aLoò\1d@Ä¥õ\ 3 âæñ\v\80\\19¾Ý:\80ü\15½\1c\0ׯº\ 1ä\93g>\0"ö£\90û\870µöð\ f?uzIº\7f,}_*æ\1fW¤·\84/þá5\17¬î\1f\aÎ\ f\1fV\ 1\ f\e·\7f\99ë¿\1eÿ°æzÑ\ 3 +ôÑ\ 2ª°ðäø'\87\87¸4_nÇ?$wÃfþ!\1eÕ\97\97\ 1¨\8aêvµ\ 3@ä¤úr2\0\11çº6EV\13b] \1e\ 1\91,²*\82\ 2"niño¿J©[»\ 4DnJÓ\10P\v\86Ì\155\ 1u\9db.\ 1\99ÌCB@]G¡- ãâ\13}\ 4d²Ï\1e\ 2*\ fjRB@Æ6á¯\ 22)¹\87\80û![@ƾT\ f\80öí5ü³Kü\9cdþù-õòÏr¥\85\7f\8cGÉá\1fGeÌr\vÈáLÞV\99\806¯z\0\14\f\ f\0ñ¡:V\ eàÆx\ 3ÈE(ó\ 1 àKR\ 2@ü¥ÞÞ9\80XݵÔ\a\80\80®k9\0Ò\9bÑ\ f\80\8cg{\0\98\ 2Àìç¯\0\90@åò\10\90\1fúþê\ 2"\969\8f\80\8c×C_\ 5\14¬ÖÞÚ% sÓÇÝ\ 4d<tn\ 2\19Z{ùJ \92:½' \81\fÕ;5#\10±\8cÚn\ 2\99ÔÕó\93@Ä8áÖ \90\9f'\8f\ f\81Â:õÝÖ\bäMÓ\eE#Ðâ\n\ 2íÉ3\ 4dXÓ\f\ 2\19£Í¾        d\92{Ã&\90qÓ¶       ä\8fËÞ\11\1e\ 2ùÚ9× ÐFΫË\bDÜ0´7\81HbtK\10(\85ó*A °DûÃ@$\8bz³m\ 6"\ 6o-\fD\8c­uÜ\ 6\1a6#P*\86Ê\8f§F bí\92/\ 2\91«SG\10\88x{mõ\84¸­þõ\10\88d7¶\16\81\88çjê\8d@i\18\8eV.\ 2\91\83\8a9\bD\RÕ \90qñ¡<\ 42YO\ fh¡·o& ãñ\0\10¹j\ 5±\0d<]M\ 3\90±\11ü
\93Í\8f=\ 6à~È\ 6\901jõ\16оÝ\8fRF ]äÇ$#Ðâuä\99ç\85pì-A cñÒ3\ 2ùLñÖð\10Èá,ÞV\19\816¯Î\97\19ȵR½\8f>\ 6rUõ2Ã@1 \83@[\84Òo\ 2¹R\8bè&\90¡\1f\1fM@.îYô\16\90ɬ\1a\ 2\9a\86\80\16;ßG@+\9b\ 3 \85¥\ 4\80æÓ³\ 5´\a­C/\ 1dL¼6\80\16/ _\ 1Ì\15ÝP\9d\17\80ÌY\ 3¼\0d,*\e@\84.Ýá\8f)õ¹$\7f\b[ï=øc,õÖ\ f9´n=ôc,u\86~\8c\8bÇG¿Ì\12í\81\1f¯ÑÖ\ 2?\8b½;=øÙ\83\87\86~\99%\9c$ôc<¼\8a\8e~Lv/GÓ\8f\ fI~¼¢~\fë>:lýø\96\8bUÓÏ\86Í\8f\1fâÉsÆ¥_nè%F\ fý\10\1aúeÖg\97[?${/%ôC¼a#~¹Ãó\94\90ÜÍ\9a­\1eÄ\95\eÉÖ\ f1V~¹ôCnªæÐ\ fñÐ1C?~¾4<úå\81\ 4~\b\16ø!\ 6lãÂ\ f¹\96j\rü\10ãõZà\97×ùåÂ\8fÉÙKè\97×!hë\87x\88\1fv\ f\7fLVß
+\8d¿Ì¹È-øc\9cS»ùc2¥\19üí\87\18\97&7\7föõE\82?»È\ f\9fßÔ/þ,§#øcÜT\83?¾b\eíæ\ fI\1dÞT\19\7f6±"Á\1f\17ËÔyó\87\8e\95ñ\977ÆË?[\86\92oÿ¸VGnÛ?\84\92õ\0\888©ö\e@.ú*-\04oú\f\0-\1eã\ 6Ð*'i\bè\0õ\10Ð\80\16Ð\9e\94r\bÈ8Í\1c\ 2\1eú* \96k­ýn\ 1\91ëª%\ 4\1cì}R´\80\83Í¥oeÇÀ\81µÛ}\93¤\81\bs_§^\1a\88RÁ \95\eA$qJ¨\81 ê«Õ.\81 â}À=\b²P}³5\ 4qM_Ç\ 6C\90qjùF\90\ f\1e¾Î\rA\16²õG\vAÄRÛ\ 3Án[\83\ 4\82\9d5ÒûF\10!\8e\11õF\90"pò7\82\1c9\14\88Å
+\ eò\8d xÉ£Ö@\10\1cÀ\9d\16\bòÚî \1d\ 4'O6Ò\ 2ÁIßF 8¹±ÎG\a8Ù­­6\91\b\95\bbÌjÖ\eA\16°Ì\83`
\1dAÌÃê__\10ä\ 4ê8
+b\82¥Õ£ VA©íV\10\8b«xËç
+bA\8eR\8f\82v\86i\ f\ 5Y\12>Þ® cïß\AÄÍw»\17\ 53;ß~\14ä9Íét\ 5\11×T\1f
+"YüÜã
\87\84\82¬àö@\90ßîG)G\90×\9c\16Ðo©·\81\v\820\10_\9b4\1f\ 3ñy\1aåa \8bÊÛ*3\90ó*Þ\r\99\81X+ªýa ç«ä \90ööÜ\83@.B\9e\9a.\ 2±\ 6\19\9bÀÁ6À­5\ 2±>»\1dé^    Äú\9câ÷\18\81\ 4\aR\ 4\81\8cG\9b7\81¬\9bäÖ\1a\81&P=\ 4R¨TòM \92e\1dz) Ãá\8d±     8¬-(?\13\90£_³¿z\10\98P\93Òæé\ 2\13; â\93I\ 4\13\e\87\82ÈftAe3\88\99®(æ\12\ e\92ç¼!Äú¨:S\v      \91\91FP\88\ 4Öä\1c·\85¬W\9cL$4Äe¹ª7«Æ!\1f4çÓCf{\95ð\90\8b\16Í{       \10\99¨\1cÄKÄĽBº\ 6\89H Ç;\8d!\9e«2óm"\81H|\97\8d"\872M\97ÔTäKw\8còÍ"ǵÏ|zC\14\1eêôô\86,*í\8fÞ\10\87\1du`½7|!Ï\9aC Îù¸\9bCëãr¸(\18Å6\82EùµÚ ¼²(h DCE!áé¨\88\8f\81d¾U\14¼\87J (\18û:$PTz7o\14\15#Æ6i£\88c\fÖ\9c\ 6\8a~¬)7\8a<\v5×ÕP\g£m"ÏOö¶¯&*º¦\91NgÈ\83\e\9dÙ&âó1=>&2\99Ö\81\83\87l\13\95g\1a?¿\1e\14\91LúÒ\19ò¢î\15b*ÚM®d¨È\9cx1\9a\8a\88\8b\99²TT\16I¯·\8aÊÅõÒ\19rVWÓç\9d!\86\83\97Î\10Zii§34¢åt\86xÓ,õf\11¿¢-\94É"Â)µ\8fp\11¥\9eex3v`Ä»¨[¿dä\v¯C¬ÉÈx¤Òo\1a\93O\9f\84\8d&\93;g62\9e½=úCÜÆ_5\82G&\86\8cÓ!&¶\feÊÏ\80üü\8b\1f?}õño\9f>þûû÷?þôö\eæ>ûâÝÛç_\7fúñã÷\7f\7fûìëïÞÿðáË\7f~øþÛ?½ÿôÝï¿z÷ö+»æ\ fÿó\9a?ÿôÃ\87uÕoù?þù\8býÌ7àg\7f¾ùÉcüë[þ«½}öîí\9b¿ò\9fÿñOþ¸/à\7fÿ8w§¸»¡,X\0\8a\ 1Feýkç*{\11$3ða\Xݨµ&ÝâÌS\9fb\83\9f\90ÔÆc\1d\16ÕÄ6ÏØ\1aH\¤ÍnâzäÇ,Ó}O\9eÝ\93     \8b\92qáá\v\ e`\9c-n+ÆìÿÎïaØj¶ßåí§`¢dÅì©ÀQEÉÇwðb&Ó´ß\95±×3¶Êc\9cü;Э\9c\97Á\9e\90\99L\ 4\96\17±\93D]¨ø3:ùC     p}ì{P¥\93É&sú¨\15»¨`7D\88mËB\80\a6Z2són´\ 3ëR\93×Rç¦Ææ\f\95\80MkuÐ`\0ÂX\12¯Â\8blà¹\9fb0\11\ 2}»§Ï:ã\1eß½Py\98è·n]\9f\7f\11»mÄ8ÎØ3q\bÝí=\8aµ6{Òd[ß³\13Ê_Ën¼óM}Xì´³oê¶\ae¶:¼f¢Ö,LxpÇ\88Ê°7VRî÷`.Ø\9dÙPñ×a®Z·\9bl\ fA\\92\ fåH/7\15á{#9³=¹°\969IlÛ\18Û+ã\e±ó\9f\9bFöÙ¦\ 4\88k\85\1f6ûx\18c\1eQ¹Z°QÇMUÔnÒQì¦ý\10û\ 6ÆÍס5 ñMlK¸Xů\ 1\945î±/²í+îiÍë\ 1\9fú\17­ÂÃéËÆ\85¯ÊÂ\9c»     à\88²mÑÂÝÑf¶ò\90\ 6`¹³á²OmÎöj\10N\ e\93¬\8dÎV\88C\89GT¯\91ÉÞ\fß\83ò¬/k\95\18ïd\17A\+øAï¹Àk³Ï{-3nª½z\923lE\91Ì\eÛ\1c\16W}aÁgNÙ+.~lT¬e2\9eÔG¡\89n\16à\98\9b¤uݤâqÃ~ÂXT\1d:,­ÿc÷\97¿¸Ý\r\87>¤Í^£!mfoÑ\8e´\88«\94\87´\99[|?Ò"FÛ~¤EÙ\8e^\1eÔ"i\rȦ6ssÓC->O+\ ejó:¸no³õ\eÁ-C\95\a·L¦~¸e»I#6·Ù»Ê\9bÛìmdpKh¸\86··øq¹å\87·ÄAõx˱\ 3¬ÛÛì}åí-¾µä|¼Å¯Ì\1cÿåm#\aÿåº\ e\13%\86\0\91àþ\17Û\99\84Xý9y}íVùIJ×[ã\92åüÛÞ"\1fK\1d\ø£]}Á5ö¥ø\82\a\dMm\11lÈ|µ5®+ÕÔ\96¹TIm\91×Ö÷jkX±fýh\8bØúJl\11ñÃÛ\8b-\8aX¦+±EöÞw[ËÈCÜc-\8bºfZë9ö:·\96ÙßößZ\14\91´\969f\93\18>^iY³Ø\9c]Ú¿[¸\bÌ|±GZ\7f¸Ù\91\96×Ô¢)­ÿOìåWZ/rkÛÒú\83Â)\97\96÷Ü\9a\1cMåä    h\8d§\ 4î7\eZN\135y¥å\84\1a6RZ;ì\1fi9\ 1»~¤å,í\17ZÄ¡óBËÃ\98Õ\ f´(V½Îr1\14¹Î2Wù8[÷WÛÎÖ\98\9dé,q\92\ f³T¬ée\969\9e\eÌ"[Üòìb\ 4êl¯\7f,J\f»ûÇÜTÓ?ä²\9a¼þ±(ËÒ?ÅØÝ>\93©\8döê\87"\7fÍÁ\8f\91\8e\1cü\98ûÎ\a\1a\8dMÝñã52¯~\9eåÅÏkÅ\12?dÜB\13\19Ϲø±8B^Ç\8f7)Ú\12?fµ×>¾¤JMû|Üú¡\ f©­úÊ\87\9a¿á\86\ fÑTg§\\9b«¿ð©â\17ÙHø\90ýÔuàCî½õ\17>\14£)Üð!OY3íSC»"ãµ\ fÅ&ÚÓ>ät\9ak    Yv\9f|íC±\17\93c\1f¢ÎyñC\1eåÓh¢\86Íi¤}:bù\1fü\98g\7fícm-Kû<ËLû\90k\8b\1dîÚÇ¢Õ\9aö!£ûX\89\1fsmëÕ\8fÅ"5õû»\89ëÇÜg\7fõóÇ\9b\1eý\18µôÔ/þg½úyÑ\12?\7fÎ^uÄ\8fo8âèvõÃÐÙbç\16úùg%\[?Î\95EPÿõìÂ\88iê§=Æõèç³°Ë«\9fÏÔ8\92:\7fÈZ£'rþ\90E¢gºüqÊ3\1cÿ|ADOäþy®õõÏ\8bÍ\8e\7f\1e-ùs\9bÚ|ýsÅ\ 2$÷Ïs\95ô\8f¹l\1f_ÿ:f«\ e}ýcq7Úî\1f³õ\99þ1K4ü×?\14\95þ1×\80Ú\ 5Dnfö
+Èb\8d£\84\13\88\mh\12È<w>\ 4v.ÕØm\9d@^3¢ws\ 2=·þ\1aè7\8e\rd\16.Ým s\eý5\90Å:F\1aÈÜ»¦\81Ì+\1aÂ\8b _ÉuÝ\búàI*\88h\12çÃË \8a³\15I\a\91×â\aØ\ ev®Ó9_\aQäü8\f"\1eá\9cAdì­ãe\10ÅèÖ6\83}b¬VK\ 6\91\85/ô¯ j:úH\ 5\91}&\1e\ 5\91m«x\15DqôØ\1f¨ âj»å£\82}a\8d\8fþ2\88bë£&\83È2­%\83ý\1c\96þ\1dd1Z>g°\9f\ 3×f\90Ù_ø\9fA\14µD/æk\89yHK\ 6\99µµ\97A\16\9aÎàßM\9cA>i\8eù2è\8f×y\18ôkÖH\ 6=Ç&{\19ô¢ötÐ\1f\14\88¸\83ü;Vóë \a\94ï·\1dôïÊÝ`;ȹ"ª¯\83\9cUª+\1dì\aåí ÏB\19¯\83>U¥¥\83Ì\81´3Èé=T^\ 6QÄBlÉ £³4\19ô%RúË \17ë:\fz\8c\eûìs£Z{\1dô\e×\91\ ez.#\1ddîqÏ\8f\83\82ùºâtz\1dDqÖ\18yw\90¹ô\91\ eò\9fv\9by\1dd±Î\99\ e"\9b®\96\ e2\17ë¯\83(ªîÆ\9f\ e2\978\86¸\83Ìmçã p­Æ¾ë\ eò\9a\1am\9c;èyÏâtÐo¼f:\88\8c%7ÒAf\8b\a]\aYÔPØ\1dd\9e½§\83¼©Dox\1dä{J\93\aOÚq\10q\8dÒ^\aeAé(F\ 3¾¸©&\83Âu:íe\10Åá³x;\88¼l·\7fî`á\1ek\1f\aËîÜ\8e\83\ 5cµ.\83¸×jëã üóþä8X.Úî êóË`ÅrÔ\9e\fâo\16×\ 4\83\95ó°}\18¬è\18£û\v\ 6qxiV/\83<ÌÄ@þ1È\13Ï\9c×A?\11­ë /\8eýîÏA\14{\91ë OkR¯\83¼Y«\1f\aQ\9c\83÷&á 'Á°\8f\83\8et\90×,»\ eÖ<ùü9È¢¶ë \1f´W\9f;\88\8f\82\1cföW[A~U\19© §Êà×øW\90\93jéH\ 5ÅM\9e© ÏAÑWA\9f¨RSAæ\15\1d\923\88\jtP\97ANyé5\19ts¢Cr\ 6}\85\14y\19ôb\9d\87A\8f1(±      \93¨\8f\82~ß`É\15ô\4\15d\9e\8f\82u\eõ(\88ân\87CÁÊ.è"\88X£-ÿC\10ó^g½\bbm¬©\17Aä®ó\83 \16Ô\8a½$\10,1\e\12AdÛ9\11äJ\8d]7\10Ä5\1a}\ È\í\83 o¼êE\109\ e4a b1û\18H>l]\ 3¹úe\\ 3\91\86\7f\ 6â5]×c \87®Y\1aX÷ó\1f\ 3ñ·µô\1a\88ÿ\1d].\82\9fV\90?ji»\ 6¶äÍ\rähXY¯\81\1c2ïÛ¶\81\|¾\9fl\ 4ù\19¤µ\17A~õ=F\8e ?¨®\91\br\92l\14¯\82\9c¬­Ï£ ç{ÙÍ\1f\15ôõ`ö*ÈåÖLRA.G\vI]A9G\9a\7f\ 5Y¬Ñfº\82rÎE[Aæ\1e_ú*Èâ\88¦,NV<´µ\9e
+2Kí¯\82,¶Ø7]Á¿\9b¸\82Ì1U/\82þt=\ 6ú\151ìn`ü\87¾\ 6z±[\1aèr\ 5!n C·ú« Ç³,=
+úw\95\8b ^«öñA\90³XëEð\80|\10ä$lë\83 6ªÒúE\10Y¢Í\v\ 4ñ=µë\aAL\8c!ý"Èi>ÇE\90\aÁº¿ÛF°îs\98Ü\93\88ÿêGAÞ¨¬« ²¯Á£ sÜó£`ÃmG\9c\82\18yW\90yÊJ\ 6\99w«y\19lü,c%\83Ì2{2\88\8c\97A\16e÷ÿd\10\19Ç]M\ 6ù÷²óa°q­Æ¦ë\fò\7fV´qΠç=\87\93A¿ñJ\ 5\19µ¬d\90¹Çs.\83í\0¾\19d6±d\90?®öþ2È×®á\9d3èc×úa\10Ñúê/\83(bx{2Ø0\13koÉ`ã*\1d\1f\aQì>\8d·\83ÈÖwïÇ\8b\91±ÃÎ×A\14½oÛ\f6\8d×=\f"Ëhõe\10E]2\93AäD\9b\8b
+Ùv#{\19Dqøb\ e\ 6\11W\1f\92\f6\83pÖ_\ 6Q\ 4\8d5\19DîE%\19dî1\94\97A\16õö\82\1e[M\ 5\99ç\aAÔÐ\0k"ȼ\9a$\82Ìcï,\89 \8bV5\11ü»\89#È\l¾
+úÓû:\fú5s&\83\9ecæ^\ 6½\18=\873ÈÜöâ#\83¼g\8b3Öe\90ãÙ\97\1c\ 6ý»¶\95\ er®h·×AΪÑW:Ø\1cédÐ'a\e/\83\9c©½I2È\1c'IW\90³{Eût\15\8a¤\82NNôG® ç¥¯\82¾l\12AO1&\8e \ 3õm\ 5ý>¡\92#Èlk$\82\9e7\92/\82Uñóu½\b²¸{aG\90\99³á \88\1cÚ]\ 2\9b¾\13\88lc7\ e\84\84¹é+ jèáF
+ÈÜt¥\80Ì}ç#`å2\1d   /\91èá\9c\1aÏe¾\0ú}§¤\80\95«¸´\14\90yê|\ 5dqXM\ 1y\93²OZ\14\90Y£1¼\ 2ò-5v7\17Ð\a®Î# â\9aqz»\ 2VCK1G
+\88,ÊÁß\ 2V.ÑÑ^\ 1Q\1c£÷\14\10yãæ\0Ö\ 1ÓK}\ 1D1z¶- ²úf²\ 5\ 3û+ \8aK¤¦\80ÈÑEn\ 1ù÷-â\15°N4mý\0\88Ôæîû\b 2l\9b/\80(ZQM\0\91ñ~\96\0Ös\98ù\a\90Å\15\1d¦\v\89h\v\88<[\9cY/\81,jì\87N`åq­Z\12È\\8b½\ 4²XbÓt\ 2ÿnâ\ 42wk/\81þøÞ\ e\81~M\80ì\ 4Æÿ\8c\97@/ÊL\ 2\99-\ 4q\ 2ù\8a\16Íô%\10E\99s\1c\ 2ýò£ß\ 4r²,Y/\81(Zí\92\ 4Ö\ 3ò6Чa«¯\81\9c«³Z\1a\88ܪ\\ 4\91\8bÈx\11ä¬×f\89 \93\13~8\82\9eç|\11ô\95Sä(\18\ 2\8d\85*ö*è7*5\15d.«¦\82\9eã\9e\1f\ 51_Uǧ\15D1:ö­àd\vTn+8ÙhÆï¾\ eNh1ª¦\83ÈuèL\a±\¬Gkx!D\11'\ 6M\b±ÆLGK\b\91Ïi7!äb\8d=×!Ä%Ñtl\b\99Kðu!ä}gLu\87\90\84\96\ eá\8fõ²éÝ즡øWù/;\12\9aæÍN\ 2«VÝ \16 \15\15\1dÑ\11PªjXôÛs\8e\9d8O.ElP5\9d9~nîKbÿ|\f\8d\1c{\80°[\83(\ 1ÂÎ6Ø{\80\10\1a3\85Ü $\15\92»o\ 3!÷.kÙ D¾\96ávç\80pÀU\f\91\0!\88\0ôh\80\90\1dj\a\84\93SNÑ\0á$ãF\80p²¿Î\87\13\9c4mn\17\8de\13{µ`ê L(\81\\1f L°\fäÿ\ 6a:Ø6\10&xþån\ f\b\13ñ0\82\84xÉ¢rH\88\a\a     ñ\80æÖÏI\98YÔrHh\ 3\8d>HÈ=óýv\12RçzH\b­Þò^H\98yÌý\90\903[\96CBhIò !\82-õCÂs\13'!÷C\1f äÓ[\ e\10ò\92c\ 5}\85<8È`ÕÃA<6Õ|8\88ß\93×Ñ\v\aÓ\1a6\9d\83\92zp\10¹\ 28=88|\836\ 6\89ß\9e{`\90IhÓÓ+\ 6\91©\98~F`pÐ
+\94\12\18\1c<m\1fí\ e\ 6Ñ\ 5gñEö\92d\ eP\11\18¤\1e:o\f²n\92\ 3\97\184\ 4ÉÁ \11\95Ö´\1a\18D\10CJP\90\1a\14\1cf\rÚ/P\10É:%ç~c0¡,\8bÎã\ 6\13\8dPó§\1a\b\13Íf©\ f\12&¾±¤\16(D\81\b\ 5\v\11ÀËû«\1e\18&c\91³Ýh\88@Bk\1a\81ÃÄ\14`r½ò\905\8b\ 4\11qU\ 6&J \91÷\99óÉDF»/3&¢¬éã[@\91\ 1IuÞTLì\18Å\a\18Ã"\ 2°z/\ 6\117®eæ\9b\8b\84D²oY`äf¦é8%\19A\bíSç\8dF\80HºßË="ª¸ô|<"
+WÙ\1e/\8f\88Á§j>\1eñ`ÏM"\92Õ\8eã2\89fçr°\11\9b`mf¡\11\9b\84£y ±8\986\19\v9\9e\ e\19ñ3@\99o2âäF-\e\8c\ 5]QF       0VÖï|\80±rC´\a\18Q\ 3\1a\19§Ý`ä`¤\8eX\ 3ã\1e\94\16\179LÙç¾r\91\ 58Òq\88\1câ\8c5\8b\8bø}L×\87\8b\f®^j\|¹\89q±r¶ñ,:`D0Õã\10yM÷ÔsçÁ5NÊCF\ 6\8b\97£\91\11º-®\18\19ñI­w¹É\88\1f\87ÈS]æÏ\1d"v¥\92     \97CÄqUZ\8aí\10\rÓå8DlYö\99î \11\8bË\86FèY\98m\9b\8dÌØ2Ü\95\1d8"Eëæ½Ñ\91,Z\13­Ñ\91z$\1f\16\ f\1e\93\1f_Ù|449ë\8c\8fÔ³ëÃ'b\15_j\ 4"\19°\1aÝ\8c\rm\96_\80äç_üôé«\8f\7fùôñ\9f?|ûÓÏo¿fì³/Þ½}þõ§\9f>þð׷ϾþþÛ\1f?|ù÷\ f?|÷\87o?}ÿÛ¯Þ½ýÊ®ùÝ\7f½æ\8f?ÿøa]õ\eþ\8f\7fþd/ú\ 6®Ø\9fo~v\8d\7f\7féÛgïÞ¾ù3ÿù/ÿå÷û\ 2þ÷·³:Åj\85\19B\ 2\16Ar¡\84ÿ±c\82$APÙ¡©\e~¤f-QÃHPKÛ\8c@°*ê\0ÁF§BÍÔ§\1eÕ\161!)ó\88%\19\18¼¢ð\12v%êÌ\83£V×\98\ 2×~#¹K{OûÆ\9féA!\a\99j\1a\r\aÚ\n<\83y\8a *Þ^\vØ«¦Sòg¤a÷\94Öη )d\ 6\eS\82\17\ 1Þ\90\ 53\93IÌ[Ôh}çcP¦¸\11\13_Õ7\8d\1f\8cÜU´Oh\0×´åî^4\92\a­\eAÛbè\84¾ÿÖÙÕàÐÊ\9e     Ð*&ʸ\80\8dx/HÛr´Î\ 43\b       à\17Ó´¿{\89u.\ 6YÅÝL\9f=Â8\ 6\rª\88é)û9\19æEíN\85&\18ºi¶\8f3OÓÙ¨\8aÝDÛF\ 3\82\9dý\87_\8csåE\13\85f\17Á
+½uà´\fß\81©ûI \ eKÛ¶         \82F±Ù"¶\1fÈ\96\9aoµ¼¬i%Ù\99\1aë©s³ó±\94ë\8b®Ô½\9f5#Û9£\8a\85×\88\80\1c\8a\97¦æ\90ʼÐ9c\91\94j\8b\8c\84/7éþnºòO´\9dç´nùe¨¢\ 6Û,\87qÔkQ·\1cg\9f\8dEª^\b³ª?Ç\v\ e\13\9f}`e\9fb\95¶Ý[¸\9dôeEQÁɶ;s\9b¡\15ûÏlhþ³\1dÙN\86b­UIN^\92+7\122yq »2µu\80\93£Índk©«Ú"+?&¶¨ý\9eé$ö"\81\9f\8c\94UC²R\9eìC¦³i\90ôT\83\9f\e>\93\16Ò¹cÛ2\98XÆ¥êÛ°\1d\9eñËY¤ôa¦\8bi\98ÇiºÔê\80C&ÿ\ ff\7fù\7fg¶¢*àj\1e\84Íî®\82°ÐÈ¡CXh)íAX\14ÝôÔqÂBô\1f¢hGo7b³§w 6³«Õ\83\9e\¿ 6ûÔº9\9bÙP\ ff)ky`\96ÁÔ\ ffé3\1d\99\8eYh\10î\81Y\ 4+k\7fc\96\94\91z8\8b\97Ë\9a\1f\9c¥±ã\81nÎrëZ9\9c¥\89ËåÁÙÂÏÍ\87³(¨,38«¤ÁÔà¬Òk1ó\9c³\90ÁP\82Vùw\91\e´J+Zz\80\16Z\82²\10Úë¸)«´C"AYê\94kP\16z.ê\1eÊ*\8c\96j\vÊB\976\ 3²\90xñrC\16ATè\fÈ*\8f.\18KÅÉíb,\832G0Ö´£Ð\18Km_ûÂXe\86ä\1a\8c¥ö4²\1c¤t2\1eÂ2¦Þ\8e\8d°/·èöf\83Îÿ"¬=Y5\bË\8br\92 ¬-\9aù&¬\ 5µ\ 4aí9Ò\83°jÏ¿\ 1Ë­\94\9c\ 3°Ê¹\80mf\ 1\96IÂýº\bËLêNC\12V7î7a\99xì¶\17a\99\9dí\0\16²#ë\ 2°\1c¿4?\0\8b`\96ÃWVAª\87¯Ô¹>ø\9a×\99m¾æ5¿m¾\92JõÆ+éUäà\95:ËÁkö[ý'^\ 5Ù\94G¹¹Ç`õm7îQ\17\91à\1et\9a¥ÞÜc°N\rî  ÒöøJªÒËE=ÄèÏ7ô(iä7ô¨\9bë\ 3=a\85z7'ôxM\1d\87z¦ë\r=\8b%\rèAã\ e\12У\1e#ßÐcÐúÁ\82\1eo\92¤\ 4ô¨Eoæñ\e¥æ`\9em[\väAò\15/â!f\9f¸\80'|E\19\ 1<ai²6W¹\v¶ÂÒÖ\81\aYÆr\92\ 4\9epëý\89\ax\bn\13\83\1eu\8e`\9e 7sí7ó\84I.-\98\a½ÉlE\ 4]\97#>Ì\93U=\9byÐ2Æ\81\1etO\ fc\89\18\1aR\ fæI\7f\9f\9aÎ\r=ÊÑnæ16§\ 6óLû@aÌ\83ÎÅ\9bZ0\8f1Í9\98\a\r»1\ 3zÔ¹Ì\9bz\f¦\9a\83z/7éöj\18\83ÚM={¶JP\8fZ|Ü2êù¢ySÏ\82\1aгÇxµ\19ôø}ÝG´C=ì\9bN:µE=;U'\96Q\8f\992IÒWê!\9dàOeSO\fÁ\1aÔ³ìkõ¦\9eeh\9d\81=hÉ¢\81=èZeÞØcªK\9bÁ=«\ 4÷@Æ=Ó9ßܳ`Ñà\9ei\rì\19\94ʸ¸gôr\10\19÷L;O\8d{Ôɹøà^Ã7K\97\9b{\f\9a±^Ü£Ö6\82{ÔÕ\rþá\1e\82µû\91\1a÷¨³óÙÈ\a]Tõ"\1fcÙ'\aC\1ftV\7f\eC\1fõp}Ð×X¨Þf\89>^ÓÝ«\19úL\97v³Ïnì®ÐØG]ó\böQ\97Þnö1\98{\ föQ·&Á>êé\ 6ðÀ\8f\9f4Ýl\19ülïê¡\1f´Ú\10ó\8a?\ 4GI5ø\a=§äà_c\99Ú,º®ïï¹=\v\7fPA6â\ f\1aÝ´ßøCp»3Ã_\exéY\ 2\7fÐUêM?Ĥ·\1eô\83n#IÐ\ fZ\17\r\ fý\10ìM4è\a=˲x¤_\9b [o7þ\10,­çÀ\1ft\1dZ6þÚ\1e\8b^ùÇ £Ëð×öhµðGm\1fü\82?Ä$%  üQw\1f\ e\f\7fÔRÊ\8d?\ 6\9b÷IÃßËMº¿ÚèãÆ\9f=[FàÏ.òYÈðgzÍ5\81?\vJ\vþÙsÚ\fþñwTñÍ?îfM5øgÇZGð\8f\99REnþ1\9dÄYEþµ\rãÅ?˾ÚoþY\8aÖ\12ü£öû\1aþ\98Ö]ê\8d?\ 4\12ø3ØL      üYmxW8ø³`\9e\81?ÓR\83\7f\ 6§R.þÙ\8ds\ fþ\99N=øGÝÖ=oþUdëô)ôð\ fÁ\91Û\99w©SëÁ?.Z¶òð\8fÁ<Fð\ fZ¹3\9b\7fÔIïy\171\91åóÉ?êÔϼK]úcÞ­¬Ô\11ó.¯ÉnÛ\8c\7f¦Ëcàµ\eû|dü\83F¹õà\1fµú´søÇ õ\86Å?êÑZð\8f7­î\ 5\ fÿø\99µ\9c\81×ö®\9e\81\17\1a\18\ 4\9e=hü\83F3\rüU\96é8ó.t·üuþA¢Å\9fy·%vU}ð/\85Ssþ%lÓ<øKÈ\9c2\1füKð M\ fÿR`Úù÷oºËeW\8fÛ\b¯r\96\12\10ȼ_\92\95\ 3o\f/\12À       â­`\v¶`G1\ 4y¡·wU5§9\1c(0d\9cê\7f\90Ý\1f»ðûxâ/¢Äë6¼Ð©­\87\84¿\b²õ\87ãE\10ß¹\1d/tO-:þh[\fS7üÑÛ\8cmy¥Ó¶¼Ð#Ø\15·ù\87X   Ûò\16Ú2c¦ñ\ f¿Ï\14\1füCp¤mzo\93\eÊòazµví\9b\7f|È<\91ñ/n\8b³ùÇ`ݦWë\94mzù\81õA?lf\ fÛóêP\8d\1f\13¥×rÒ\8fÙ4«{Þ,\16\ f§\9fr/?<¯\124G§\1fõ,ÛôB\87X\1f¦\97©\9eKtü\895s»^\95Fx¸^\ 5ãpüIÛ®\b\7fbÓI?Í\e·ë\95\ eÛõR\8fø%×\9b#²¿õ\aý\10Tû{Ñ/²íÙð\83\8cÖ\86ßà\17Y©qÃ/\90MuÃ\ fºÔqÂ\ fÕ4­¿7øA\17{\19\83\1ft3}\83\1fëÔ®[Á\ fÏTëÛ\f~Ô±=àÇ\89gÜð\836ûbì\83\f­=Ø\17°\87mnö±ôsßì\83îÖ\vÞØ\87¯ìÖx\19û¢\ 1ÈÙ\87t\95Ñ8Ø\17\91\86³nöEänÉ\e~¬ÑÝúå\ 4CÃ|XìK\ekd\1f4®Ôy²\ fÁ«O\13û \87n\90\ 5¿\8c¥X\1e\aü\10L5O\87\1f4R½;ü ó\82á¦\1f\82%\95áô\83na5{¤\1f4ÀÖNú!8SËN¿\Þ\84f\b%ýòe^îôc0Z×/úåË\ 1-úQ\17;d§\1fc}v§_¦;3§ úQ\13p\aý\18LvS\8a~·Iº½[ë'ü´tuöé\11óEb\9f\r©'û\14,ÍÙG=JtöqKÆ,'ý¸\99aV§\9f\8e5oø%lIé\ fø!\9b²\81Jð»@|Á\8fÉ\97æ\ 3\9dB*\e~ÐÙÚ:\83\1fÒº\96ú\80\1fî½\9eË\86\1fQ3ú\86\1fµ]    7øÅuj\17üâr\\17ü\88¦XNúq¢07ý Ó\9c\9b~ÔkÎ\93~¬¸n\8e\8fÁi;/ú©,ótüQ¯Örã\ fÁ<ûtüQçQ\1c\7f¬¡QÛ\81?Æòj÷\89?\15\8e\1eLoü\11
+Ùn[âO\ 5km\9bð'm\19¼ñ§\89§Ó\8f²\86éø\13)Z=ñ'2Xb\v\7fÔ-7Ç\1f_.Z+¸ñǯ\8e±:þ.¢]ø\13)l\v7þ °½e?\8cL\8f%9þ¸bí\9b\7f|#%°ñ\8f_±vKüãN°þ\ fþq·ÆÆ\9f\1c©ðÇ\13è)\9eøãùÎ<\1c\7f\85iU\93òcõ±\8e?å­5\8cÂ\1f\93½ôìøc1´VNü±¬\9a5{Â\9f\92h.\93Vlc6þ\18¬»÷\93´¾Mô£\1e'üH\818«Ã\8fz\1a0\ 5?jÔË        ?\ 6\ e¿Û$]oVC\e'ý´t\99\8e?=d¶Hø\93^\16Çñ§ m²ðG\9d¬è\84?N\9aÌKmüq3ËÌ\8e?Íhì\12ÿø¥µ´\93\7fJà2/þ%ÁÙñ§äKýÄ\1f3´ØK\b\7fÔ½8ýt\96%\9fôc0æìô\13\1f\12ý¤g=é§\12Øð\93´M\11üD¦Gë§yÂ6¾Ômnã+\1d¾d|#f\8du\9eðcP½ï\82\1fuÊÉá\am\94Ûèc(Ûy
+}Э÷îè£Nõ _ä©Zc/òQ'{\15\91/®ù\ fòŪ\^àã#Ùz6\81O:\8c\13|\9awd'_d      \87ää£\1eVE\9b|\fö\16\9d|\9c$\98­\12ù¨«5\82\9b|üÈj]\97ȧ}³®Lä\83\9eò\18wòE$L\1fÝÉ\a\9dëÍõFV¨\9c¢?ßE"#\1fä\ 55\82/vl^\88\10¼z4\91\ fºêúXä\83î1\96\93|\bÎ\9c£\93\ fzä1\9d|ü}\91p\93/\ e¾\86\83\ f2\8dÕç\11|Ð`Ú8Á\87`\vvó    |ÐX¯]à\8b\97\83\8fÁi\r¿È\17/ï³È\a=\92\99SG\1fcÕn@\15]¤/3\93 ôQÇÐNô1\18ì\9a\14ún\93\e¼J:ѧµKrôé!+h¡Ï\ 6õ\13}
+æáè£n9;úø\81\13}\bæ1º£Oç\9a\92£\8f©2ó<Ñ\87`\8b\ 6*¢/^ ^ìSú¥x²\8f9:bsöA§\987ü CÎý\84\1f³½¦æð\13j\8c\e\82\9f´]   \e~*\99\90\9d~\86\9eîô\13\9aB;è§\89BtúQ\87\19\9d~ÒkÎ\93~ÈV\90åÑú!Øs.N¿Á\9e'ìÖo°±´÷Þü\eøÆ\1e«ó\ f:öåtÉ?\14K+«\15¼\0\88X,Ö\88\b\80(°V{r\0B\9b«½\ 3\90¥ÚÜøâ\11ë4\16\0©\83ak\ 3\90ó\ eKt\ 1\90\85\1c\8c\92\ 2 tªí\ 1À®{!9\0;o?#¯\0\b\r\aQO\0\12       A¬2\0rëbK\ e@ä+x\10O\0\ e4\13Ãê_\0\ 4\ e\0\9eæ\0d\99v!Í\9e\9fô3Ì+\ 3à$Û\86\ 3p²¸ç£ó\9blÒV{È¥&3®\94\rÀ\80¥b~\00àKÓÜ\0\f\ ej\ 3`@w¿úØ\rÀ\80ó·~Ñ\b\18pﵺ     \18P¿µ=\b\18Ð\1fZ«g\ 4\8c E©N@Y\97ö  ýNO\9b\80ÔÖ¸\19\ 1¡\9bÝr\9b\80\91\1d\ 4¤93j\1a\ 1¡k¨\ f\ 2"XBß\ 4Ü\93t{7kÏo\0äÒ%n\0ò\99ÝúÙ\90úà\1f\83¹mþaÕ\90ãæ\1f~\ fV?7þa3Ó¨Î?\1ek²fSüC¦\80J\ fþ!\9dj\89\17þ\88Ý\1e»ã\8fÉ'\9b\1f2\146g8þ\ 6ï~ã¬j\ 4iÝåáîøÃÕ7\93\r\12þÈ\9aÞ£ã\8fz´yâ\8f\ 5£D]ø\13{êÆ\1fÙ\14Ì\96\10+s\e_Ê1³Óo¨!(_ \1fRuÖ\18û\89¿\80rLmîî/°ó)¶¨\0\18Ø\¦ü  ¢\11ÝOq\ 4¢<j\9b\ 6R1\10\ 1¼»½ªC\10EVó4¢\8b\82\b\ 4ÜHÃ1\88\0²r\8e\93\83¬Xx\92t\91\10\9asr\14r\9e9\9f,d´Û(±\105Ͷ½8\f\19¨!Ï\93\86\81\17EêÙq\88\0Z»[C\88\893\97=xHB\ 4\ 2"÷2ÌÞ\9d\88ÀCë³Í\13\89\ 1ÕÔgÜ=!®×Õû[O\885\e\v\ 6°8\99\9fºzÂ\eîÔ\14\82å:\88£)Tû\16\9d\89   \eØ\86#1½á©<\90\98Ð:¤ìDL$wØDÄÏ\0d<\89\98оåä@Ä\e¶j\16E@ÌDÝ|\0\11ó[\8b´\80\88m0\83k@47SN Ò\ 2ñÙ\v\88\97%Z<¤kÒçÞxÈ×\1eaw\84tk\82Ìâ!~\1fÓôæ!\83ëö\14\ fo\93t¾Ze>\9f@D0ä[GÈ\87º\15\86\88¨AFÈMD\ 6\93\95¡\88\b\93ED|P\91\87¼\13\11»Ùú­#ä¡®fÏ:B|(_úì\bAª\\9aw\84ÂsÚ\1d!\92/¦z"\11\19Ú´U\v\89Ð3Õ>\9c\89@sLcÆ\13\8aH÷l\9c_T$\83\96s\15\15©G0W¸±\18ìð\92sQL2È\89\8bÔ*°;\181\8a/5\1c\8d\f\8c4vg\18xîe¦/Àñ«¯?~úæý\8f\9fÞÿïÃÛ\8f\9f_þÊØ«¯_¿|õý§\8fï?üüòêû_Þþþî�ûðÓ?ß~úåÛo^¿üEÏ|÷\7f\9fù×çßß­§þÆÿñß¿õ¢/ø\ 2ýûá³iüõ\13ÿj/¯^¿üð\1fþù\87ýò\8fë\ 1þ÷ë\1e\1d|tC\v\94åMx@ÿ½BµÉò\ 4\ 2\9fºðhÑ°U\93h\1e\98j?®1¹\ 5ù>ò\8dR}\ 5»Ç\18©\99\8dü\95Uw\rA\89[\90\9775\8e\80ZW\12u[\1a~Áv»Içbïav\ 2&\16nÇtÖ|\ 1\ 5¹\17©Qï\15Èij\óô \13°\94\ e\a§¿ß\f\97A\94#båñ!üF/\94l]®G/\84»Æ\87 H5O¦\9dÓ\9e\15=\14    \1fè\16q\8bÑæô±\a¡ Ç²)Ú\ 1¥%´j©ó2\v²(¹\\18B0O3D9`\e µñ\18C'\ 6   ØkL\99\18][\bêÖëj÷l¡\81\16\ e\1a\1eFsÖ²\b\89X­M\13µÄ\89A\83\16Í\1f¡g¦F\sÌy\11\ 5Á.ãÕ\88\96Â\87f`c\v\8d\12|ééMHCÛ\12\98v6\bÜacƽâÙ@çÖ5\bæ­Q\97P\96ù¼\r*\89ß\8dà¨\9a¹Äb\87DëD­OÆ\19¦Òö aVW \80®µh¥1°\ 25\9d\ 5\83jÊÊ»ÀkÖ'éì©»t³<Lì¶|%ÀSÉ\1a×ë\0qJæä\83´R½\8f
+¢àY-´ê\8e\8d\10÷e\82\8d¬Ë\19\86\ fR\91"Øquêhe\1d\90ø\8a\99\ fÅ~Ö©]é \f3X,\85bæ^b\8ejE\82\f\8bÔ\8d\9ef'ë\9f¬×K¶ä(\f\ 4Ð-!\90øL»÷¿§R\84@$îAOjT'T\99öK\e]\84òJþÀñ\19\97\99ß±\12Ýç\9dÍÿV\18y¾câèÛStE¡6Ü\1c\98\85Ù;év_¼9\9fE} ÙüLfÌJä©Åc0_\1eÿ&c\8d\7f\90É\#ûàÇ\[\vçêÿÉýÏ_\97»K¼\9eÇY¯ñÄv\9cõ<q ÛÎz´ª\1fg½ëV¬\e:ëQ\8b\g½içÐ\ f´²\ fl\aZÁÎÖ.´þÿeç\v­Äy5µ\15ìª\17[ÄV?Ø¢XÆÅ\16\93\19ØzÆ¿/¶^lÑý\81-\9c±\96Úú\1f']>ÚúÏÞ\8a\87¶xrZ¯¶Î\ e\ 6\80\8a\13\82\m½\9dÄVjÛ\81Á꯶^ôÃÎLm=\1fIÉmÇÐ\íå¶c"õ¿ýpëÙÒZ\ f}´ùXëµ¹ÌÒZä"-­õ¼¶½×Ú®¾´»¦µ\9e«®¤Ö£ÿáõ¥Ö\8bÞ¤+©í8í\i\11qv{¤EÑÖLi\99c«£´Èüµ¿Òv\9c«¤¥´ÈK\13ZÄÐñ:\8bZo-\9dÍKlg\91Ë쯳¼yïé,>$þ\94\8f³üÒ\92ÇYÖzMgy#\eélç¬þ2\8b§i"ÉlÇ       \ 1ÛÍf\16ë\ 4\87\8bÇY¬¨\11&ÒÙ~Ð?Îb\ 5ª}\9cÅ2ÕdÖÓ°y\99ÅA¬Ë\87Y/\8a]eÑ\r¥]e\91¥}\94\95ýÖ\8e²ÈqáPV\bÌ\8b,\10«v\91E\8e\e\a²\12óö\7f\905?z   Öâ\8f~¨µØ\e¨\1fr5;úy,«¶W?\14ÛêG?ó¶¸3&R\1dõµÏ\8bs\8c¤\ f\11#ý¡\ fYwNú\f\1d\1a\e:éÃ\87Ú¼ö1·\97>ÖJOú<û%,éC\9eS^úP䦰éÃE\8aÕC\1f¢õW>üHk\92òñ©iÂç±.yÝó\1a\7fâfÏc7\9bÉ\9e¡3\97¾ì\99\9f5¹r7{\9eëÜS%Øó¬ZõeÏ,'B²g¸ã\9a)\9f¹DÒÆ#\9fáDh\9aòyN¤ÑG\ 6\99öÜ\9còÙ9knù\f2ÍK\9fçQ>C¦×|k\1a)\9fù\8bÒ¾\92>䩯|¨­ÕS>æ6S>ÏRc\7f»ò¡ØER>Ï>x¬¤\ fYêzíC±Ä\99\8aöåE¶}ȸãc\1foß-íC¶8\83ѾøÒzìc­'}¼Ïn:Ð\87_ÈG÷k\9f?º¾bjãrå{\ 5[Û>,\96Õëk\9f/+\9fU-í3BÜÓ>.Cm¯}\ªq\1a\ 5~\1eM¬'~\9e[\8b\81éâ\87%oºR?vD\91Ô\8f9ä¾ú±X{êÇÜ\13?ÚTç«\1f\11«-õc\ e\1frÙ:>ú©/W\eöè\87Ú\1e±©\1fr×yôClÒ_ý¼ØF¼Oè\87(«¥\7f\9ek\8f­ðú\87¢Ä\19\82\0z\96>,\ 1D\9e;'\80\8aF\8d\9d\96\0âCcÖ\ 4\909&Ó+ ¯\1c\13"\ 5Dn2S@ä:ô\15\10E\89®¤\80Ȫv\ 4D\1\v^\ 2ñ\936­$\90\8f®]\ 3=w\9ef~\11Ttci© çµLRAE\97Îù*èE\95\9e\bz<¾\11AϾ¯\8e\17A/\9eQ\8d\b*\96Ôª\89 çfí1ÐK6t¤\81\9eùÑc ç¾M¼\ 6zqhì\ e4Ðóª{Ü\83\81êÍ©ñ¸/\82^¬:$\11ôÜf¯\89 \9eSÒ¯\82(\86_DPÏIk#\88Ì\1fü\8b \17­\14K\ 4\91\89 ²¿Ñ\17A\14µZ"\98\17Ù\bâNsÌ\17AÞÞf"È\ fÅ\ 1\89\b2ÇáÆ~¿3MSAÞHW*\88ÿ÷V~\15Ä\ 3m1UQA¾Xl\ 6[A,\96fö*\88ee!\16\15ÔCòV\90Ë°\8dWA®ÕV\8f\82\88q]"\88å=¬½\b\96ÖD\90ä,K\ 4Ù#E_\ 4Y\94\95\b\95© \8dªõU\90W\96\91
+2\97\91
+"k\ôU°ùO^C\1f\ 5½6%ì¦\82ÈEÇQ\10_á|ù« \8a2çQÐc·\18Ö¨ réú*èE³=ñCAä\12ç\ f*\88\wN\ 5\e:5ö\*\88\ f\8aT\90y¯áT\90W\8e¡\94
+zö\86\e© r\1fíU\10En\10[Aä©z\14Ä5[\8c\85WAüÎV[*ÈG\17\1dF\ 5=¯Qê«`[nt\14© gßP\13Á\86.\9dýEÐ\8b\83Kx+èÙ7{½
+\16ì¯ý£`ɱ-\14,þ¬ÖE°øDQ׫`ñæÓ~\15,Wl*èÿ?¿\b\8a¯%Ó\8b ø\16\18Sv (îÛ¨\1f\ 4ÅÛ*&¿@ÐO-µËE\10§\98x\92?\bâ¨3çU\90G¡u\15\14\7fü±Ûý(èE-í*\88sZÐ\19
+
+\16\81|\14ôâ\8c\83O(x.r\14\14\7f\14Äíã\b\e
+âCqP
+\ 5%Ï=öû\1dØ\90
+âF»ù¨ ÿDû\18èÏsÄl\15\ 6âµ\82¯m ÖÊ0}\rĪZqУ\81\8d"Ï4\90\8b°Ùk Wj\93c âÒ\99\b6Ü0Ƨ\8b \96|SI\ 4)N\9ca\89 [$\ 4¿\b²(3\11\9a\b\92¨\8f\81¼ð>÷Â@æbi òÜF¾\ 6\8a¿Ã>^\ 3½¶\aá0P0\ 2%\81\82?k~\bôeoñ6I wÆ\9av       ô¬±%þ\10èí´bÒ\ f\ 2=k\1f\97@Ï}çK ú4vÜ Ð?dC/\81È1¦þ\10\88+/¹\ 4z\8eóP\bè\11
+Xü\97DO\86\80hþ6R@\8f#ÆÂ\1f\ 1ýgnZC@<¸8\8d\85\80¾Xyâx\ 4\14WjÙ\15P|Ñi»\ 4¢E?c`«Þ\ 2\805q£\80\9e}s]¯\80^<C\e\ 5ô<¹\9bl\ 2[óq¢Ö\87@¯UtÄ!гØ\1aI ç¶I¼\ 6zQ«Î4Ðs/{ð\83\81\9e\9d·þ\1aèE\7fö-\rlê_\ eHi`;g\99_\ 3Q\94\181i`;\a¢m ²Æ\9b¾\ 6¢8ÖH\ 3\e\8ekUÓ@ä&ú\1a\88b\95\91\ 6æE¶\81ȱV/\81¼»¥\80üH\1c\96(`|Å\1e\ 1\9e\ 2"O\95\14\10Oe.}\rÄó,1ZÑ@¾Øv   ¬þPt|\bôUÕ\82« ðp|\b\94 ï%Ð÷©R5       ôØbÄ\v\ 2}y\9bÚ\87\0Ñ?I À\99ã\12\88¼ú\87@Ùïí\10\10v\b\84\1f\ 3q¥²®\81\9eëZ×@ä¸èk`õõ:z\7f\fDm\85Ü4\10y¶u\10\8cù\8b \17Û\1aë \88ØbZ#\82\9eë´þ"\88\83?\10ôìç\K\ 4ñÿeçD°¢ScÃ%\82øÒ\8aa\91\b\15\9c\bòÊ+\rD´²\12Adíö"\88"w\87\8d roý \88?Nb*¼\bâg\8bX"È'\17íE\ 4=w]ú"èE\7fº\9a\bV_ç¢5\11¬èÑñQÐ\8bÊ5¼\15ôìÀõTгï®óUÐ\8b{h#\82ÕüQÍ\9a\bzn£Ê\83 ×lµ\99\bV»b£¡<÷=Ã^\ 4½8ØÉ\eAÏKcÌ&\82\15õ®/\82^t\18%\11ô¬ÅZ"\88¬ñ,/\82\9d\ 3\19«¤\81ÈóC ×\f4\1c\ 2\91W¸I\ 2\91\87´\97@\14{\9c}H`^d\13\88\f\ 6\1e\ 3y÷8È\12A~(ÎJD\909\96®ý|ÇJ\f\1cD\10¹îÞ\ 3\82¸f]õE\10ÏSc´"\82\0l+\88ÅbÚ_\ 5±¬F\9cö¨`%Ñ\89 Wa\1d/\82XªZÛA\10\90üñXÝ+f§k \8ax\9dÇ@\823-\rd\ eÀ¯\81ì\9bK £j\12H ¾c /TF\12\88Ü×H\ 2\997\91\ f\81XÊbë!\90½\18S0    D®­\1e\ 2=\86u\17@\94Z¼L\0\88~\19c$\80ì\1f{ýC\9f\8d\18ñé\1f\95þ±\ fwNÿÐðq]òÇ^î=ùc\8e   õòÇ\vÏ\96þ\1d\14\8e\7f\ 4 Úèú\87â\88\7f¸HÙg¬\1a\98 ¯\7fø\95\eVúÇÇ\16ç0ú\a%xØøõ\ fÿ9æHÿðek\96þá\ ekÔ×?þUªé\1f~JÐ\16\0øãÐ"/\7fxf{`£\7fè;n%Û?¼\a\11}üÃ\voMÒ?¾Ï¹Ò?üÿöðú\87uZ4ùÃÒ\9e{æ+1W¸lóå\ f}VÌ\92?ô¡\86¡äOÎ)æ\97?\14WL\97ôOÎQhû\87Þ®qä½\0¢hs%\80\82\83\9aô\ 4\10YJ\7f\ 1\94\95\0æE6\80T¤×\17@Þ^k\ 2È\ fÅI\89\0Æ\97Æ\ 3 km&\80Ƚµ?¬\97Mï&7\11Ä¿Êÿ¸+¡Äoí\178%ä\828\80\14\10¹®HD" DÑrØoOUõL{üD\88\v\8a6»Õ\8fí\99±»\7f]\ e\0ò\13ûì'\0   \93éÆJ\0ÔÉÒÎ_\0ä÷¯ºN\0r\93²ãJ\0Ì7\8e/\ 2*\ fK>        Èã\99¹ß\ 4\84,¹n\ 4òHk\1d'\ 2\99\eVz PÀ\19+\10(=ç\89@\95NªÁ@'Ð\b\ 6zµô\93\81Z)å` uòÓ\12\ 3¥}Ñ\93\81XÔl\9c6\90\ fªþmbà¤ÿIa\ 3'\1d¦w³MA\f\1dÃû$)È\99ÃfP\103=/\9f\18äÁ6³À Æv\e%0\b}_s7\ 6YªÞo\85A\8c\19×ÝA\18¤N=\9f\18äÂ:»\v\83|)y¤\v\83ÐØþ\17\f\ e5\87\12\18\1cì\80\18ÔÇ{Ùn\f\92     i\94À w.÷\12\18ä¹Ï\9eO\f"\83ò4\v\f"ë@\9e\1e\18d\95\ eGÚÆàâõ¦ôÀà"áf`p±·®\17\17¸èØÜ*
+\83\v{u¡Ô1\98°g¹\9e\18L0\v\9eº\8eÁ´\99-\f&øý\vð\e\83        EPçæ`Âd·ÙÎÁ\84\12·þÂÁ\84ÃpÛç\1cÌÌHÛ\1cÔM¦¿p\90×\1fßpç u®\9b\83ÐÝ\eÞ\83\83\99öwl\ eò¶æðt\ eB\9b·\85\a\a\11l~ùq\ eÞ\8bÜ\1c̼ü`\90\8b¬c\90\rô)vR\90±Ú7\ 5ñXY\84\9b\82ø=9Q\1f\14Ä~\16·V¢ \ f¶ð]/
+"YÀ¦\17
+"­Ìïz\82 ÿ\1ay\ 4\ 4\99\85º:=!\88TÅÝgÞ\10\9ct\ 2¥\ 4\ 4\91ÞC÷º'\ 4Á¶U|\8e Hâ\fï>\82 õìë\84 \v'9m\ 5A!È6\ 4ùWºnª\ 1A\ 4\9b7
+1\90rº9\16\ 3§\9cAû%\ 3\91­Ë²\7f{@0¡*K_Û     &º æ§I\f&ºÌR_8\88h\86\13j7\bQ\1e\86rnAB\ 4ðân 6
+QeØtï½b!\ 2      Mi\ 6\f\13w'­yÒ\90\15\8bo+ÁC\fË·Ç\11\10¹ÐZ¯Ddtø4\11\11UM\aß\ 2\89\f¨Ì\ e&&v\8bâ\17:A\11\ 1ø¼m\ e±n-+\9fT$"\92¾åÂ"·2-g©¸\b>ô±ú:Á\98à4Tj·?D\8bU½Þþ\10eÛëxñ\87\0`uĺ?ÜÐs\83\b¬/wµ\ f\83(/\97\83\8c\ 5»è\9eZ`,\9fñlN0\16x\88R\83\8b\85\10O\9b\8bø\19\98Ì'\17\v\9c\-\81Å\82¦h³\ 4\16+³o½`±ÂBÊ*]XÄe\ 6IW\ 3\8b~¹i'\16y#ê\ eXañ¾!]Tä-J\9fû¤bŧϴÝ!¯o"ÍEEü>\97·ðME\ 6ÓuëàQÅ"\17\15+/6~\8bÝX¬|Ó\87;ä á%".j\92\1es\0\ f\v.B7Qåâ">       )`'\17+÷ùá\ ey¬2~·;ĶT'ÂÃ\1d\82Wµõí\ e\ 5é²Ý!²0\17\88\17\96     ÆÄ\9a±1\83\8c\0t.Ó\rÙF#Ò¾:í/6\92D×UVl¤\9e©\8d\13\8eÉ\8f¯\ 4\1d\85&'\9dèH½F\7fñ\88\89 )6\ 3\90\fÌ2·KLt\r|»_ òó/~þøÕ\ f\7fýøÿ~üðó§·_3öî\8b÷o\9f\7fýñç\1f~üÛÛ»¯¿ÿðÓw_þã»\1f¿ýã\87\8fßÿî«÷o¿Ò\98ßÿ×1\7fúôÓwרßð\7füóg½ç\eð§?ß|r\8d\7f\7fõ·wïß¾ù\vÿùoÿå\ f÷\0þ÷÷=;Åì\ e+Te9ZÅÎþó\8eY\97á©\86S£n¬oÂ\19@¡ÎUf\a=ÿ:,\ 4kO23¹¢J©\95útDC\93\94\90\90\ 4Ã='¯¡`ÂIr\f{\12\etµ¥\a\833ÔHÝßú\f\bï+ü\91\ 6t!õkóÁ¨.z»\14\95® R\18/\ 3˲4\88\98ÀËè$©\93\9ePj`\1c\ 4ºÄ\RöAø\r\8e`Tl\ 3åP;G_ÆÚ÷\1c\14©|ÁHË·L\8d\18;        DB÷\9ce\ 1\98¸÷\94\99²7ë>´cÊJ\94°1]\a{Z¢ýöÞã\16\1ag°°\e\bò³9\88»În:§æ\80ù²ì\15/\17\0Í?o&C®¯Ë×ÓØAã>cºP\0¹×¤\f÷Ò\8b®&shPë\99\1fX
+Ù      \r²sW`pg\8bI\83pÄgÃLhÐB©qPc\93\1då³T¦¶A\1dÃ'\81;Ev   U\87Ì\81®}pRW·\81nI{9u\86÷¤Vä|Ð>º\ fÊM\87¤Ú§æ7ã(G.\8fIho<ØÁ&\ 1\86N?s\ 3
\9bn\v½ÅE§0Á8©\89Y{\11ô\8aêº{\1eÊ\91Ä\93\0O&«ì\ e\83\99<h\92|\12\9f4çÝ\9a\15ë^\r8(\7f\90\97]éÝ÷e±U³V\87Å$Ù/Ù\7f\9d\12,\88n\aµs[h¸ô+ΪG:\94:ª[ô¢\14Ê5¹ýNéÊC\93\85W\eØÉJÒ"\97jÖ d\98Ê}Zõ\ 4·®ßDz]}6Ì\83ô\8aª\8a$Úô\91¯*ÉÒ¸Øn(èäø\996.øhWàO|\r«¾\váóD1'\92ÊXÚ¯c\8d¤¦.U[Ù
+:Þÿ ÷\97ÿwr÷ì-öälö½
+ÎBOë\9b³\99$h/\9cEÝ­56g¡[Ê\9b³¨Ûé\97Ê\ah\11¬#oÐfö¶ºA\8bß\93t\806ûÅ5h\9bÙU7l)ky\81-\83ilØÒlâ4\ 2¶Ð4Ï'l\11¬Ó6lÉ\19dpÐ\16¯\96{~¡->\9a\18¿iË\8dkeÓ\16Ø!\ 4\ eÚ\16ô\96\9c7mQMè\1fAÛN\16\90>OÚ"\88\97\98A[è\8b¤\8eÛ^Q2ÅNÜvzR\98ý\e·Ð\16¬\85è\83Ôx²\16Á¹Ì\82µÔ)×`-ôrö>XÛ\e\IoÁZèÒV \16\12o^NÔ"\88"]\81Zhú©\9b´\94¤ÓAZ\ 6mÍ ­´:\9d\93\96\9a\9f{\90\16A\|j\90\96ZÙä ¥\14\1d\1f\9ce¬«5;g÷\12ÎYê4ûÉY=¼÷à,\aådÁYMR+ß\9cU\f\1frsV\ frJ\89³\ÓY²1ËÝ´\9coÌv^\11h\82/Ì2O¬×\93³Ì¨ÑGp¶_Ì\ fÎ2\ 3±\19'g\99¦mc\16rØÜ\98åU¬ç\17Ì"\98mS\96Õ\90ê¦,u®/\94Í~j7e)}]§,ÑT_ K\86\15Û\90¥öç:d¡ûµä        Yk`Ñ,'ý\18¬¾í¢\1fu1\vúA§UêI?\ 6\9b~\86ÊØ\1e\93ª\8c\ fA\1eý\8d>J\9aú\e}ÔMúF\9f±DÕÐ\1d}\1cQçf\9ft=ѧXê\81>h,a\81>ꩧ<ÐÇà\10u\1d}\$Y     ôQ[?ÉÇO´\9aoòiÓZ\80\ f²¬|p\ f!~Þ\8d=Èn6\ 3{ÆÂ\íÄ\9e\19\8fÀ\1et\99r\95\8e=èÖJ;±\87 \fá\8d=è   Z\ 5ù¬#Íë8É\87`©Ö\82\17¥\9d|ÐÕ=ò\83|\b6"í&\1f´aÍ@\1fôH/&\131´¦\11ä³\81tè+ÐG=ÛI>Æ8ö&\9ft\9dA>è\Ôß\1eäc\10V?È\a\rç±\ 2\1c\8fÁTs°o/âì£Æ¿NöéñÝ\82}Ôüûf\9fOZ\aû\14ë\81>=ÇkNèã\17\ e¿´möaëú¢ksöé\\1d[b\1f\93e\11§Oö!­`U-Øgâp\ fö)\r[=Ù§Tõ˨à\amÙý\90à\a]«û¥\r?¦¼µ\15ôSE¸\1f\12ý¤s>é§`é7ý${ÀOd*ó¤\9f\18æ8R\ 5\1aô£NNÇ\17úµÎ\87ØI?\ 6e²/úQ÷6\83~ÔÕÍþ¦\1f\82\15ô£Î\8e\ fZÇxð\8fÁì×\b\ 1\10:÷a\ 1@ê)}\ 3°±RÕi\1d\80\1c1äÛ\1c\80Ò¥\9d\ 4Ô²r\88N@ê\8aʽ  H]F;    È Þ<\b\9a\ 5\ 1©\97Ìà\ 3\81ü ²õB v®n\ 6B÷ª\9bá\86 b\13\ 5\16\14\84f        \a\ 5\e\8b\93\82\b¶Ü\ 3\82\90\17ß\1c\82Ðh«ã\84`\eîÔn\b6>q\95\80 tÅ÷\1c\fDÌF\eÁ@è\86>\10\f\84îÎÄ\a\ 3\11\1cMÍÁ\19\b½\8aÛ=1°\ 1Jm´\13\82\b\16\C\ 3\82Ðuö\12\10l×5é  \83\ 4Áv]µn\b\8b\ f\b"hI6Ì!H=j   \bR[)'\ 4\19\99\ eÁ½\88C\90O\9ac\9e\10Ôãm\ 6\ 45h\8d\80 ´ßt\ 2\82\8aY\v
+êA\8e\10\95\ f\7fG-\9f\14ä\86ÖTo
+ê`ñR7\ 5\99,Õ줠ÓÊl\ 5\ 5ÛEä\9b\82JÃ:N
+*Wk    
+R;¢\ 5A¦7ü÷      A\ 4QÊ% (ä,\v\bªFR;!¨`^7\ 4%}aQP\84*夠\16Î#((\9dFP\90º]k\9e\14ü\ fÛõ\9a-9\b\ 2\ 1xG÷\88øÀýolª@±Í\99\7fSLwrÛÈ\17TlØ\15çÒ« \8a&±ò® 3¶m*È/í\11ó*È¢\98¥\82Êí»j*È\F{\15D±÷=ôSAæâG\90P\90¹z>
+ªÅßt\14ä'ÄG¸Pгïá\1f\ 5ý²ËRAd4ÜL\ 5\99\87ßæGA\16»\v\1c
+2[k© /ª>\17þ(È_©U\8f\82¾rZSAå\97K}\14TÜ`x-\14DÆû4\11T6©\8d\17\82ô\95
+"ãeß®\82\85¯×ñQ°ÄÔ\96
+bK\ 5\8a\81\92®\8f\82Øî\1cMRÁrÈÞ
+âÿí\8b ú\86\8d\9c\b¢ùF|(\10DsÚ¬\1f\ 4\ 5Ó¢O~\eA\1c\90\8b \8f\92¿\bò¬cv\15ô³Ðº
+
+\96ßßv¿
\88Ö¹
\9c¦r\15Äÿ¯*\1f\ 5QDÿ_\ 5ó"[Aá*\8e\8f\82¼}\9fWA~h\8d« ä¡ç*ÈZ¯WAÞ(z/\14\94¿3´¤\81XÏÉÙj\eÈÇ\1a\81Ü+\93®þ\1aÈ]µúL\ 3ÕA¶4Ð7¡ö×@ß©*i ó\8aéÈ\11D.\12ÓÓE\90[^\9b$\82.NLG\8e ·HÑ\17A/\8a\1d\ 4=Æ¢8\82\ eÔÇ@¿n ä=ì¹ô4\90ÙÂȯ\81øÍ:æÇ@\14}\14>\ 6
+g K ¢ÄHþC \16«\9b\\ 2±NËú%\10¹uû\10\88Å[ñ& \ 2\91\81Ñ%\10yxN\ 2Ù¨þÆÝ\ 4rù}\86Û\ 42Ëø\10ÈË.¹\ 4"ûQf\v\88XÆø\bÈç8Ö\15\90ͯó
+\88<}.ü\15\10?\92\1e\ 1¹nu\\ 1±+\8b\9fÞ~\ 4\94¿\86\86½\ 2
+¾Ûô\12È\ eý\8c\81Zq¾éõ
+X\ fn! 2Þ­ë\15\10E\9fÙ\8e\80ÈÆ\87{\bTÅ4QëK \8aµëJ\ 2\91¥¯\99\ 4"k\90øc \8a­6K\ 3\91G\89ÁÏ\rD\9elÆÇ@\14±ö\9a\ 6jû+Ã!\r\ 3u\1ff\1e\ 3Y\14\1f1Ã@Ý'¢c só'ýc \8bÓç±0Py\«-\rdÆ?^\ 3Y¬þÖ\f\ 3ïEÂ@fߨ?\ 4úÝ{
\1f±\95\ 2ÆWú# ×ÚH\ 1\99-\0q\ 1¹*¶Úk ×³¬~\fô\a«\97À\8a5ióC v\95\ 4n\8d\93@îº>\ 4â5Uj»\ 4"k\8cxA îØ[ÿ\10\88ÛNm\97@\82\12(áÅK Äs;\ 4J\9cÁ\92@ú$íc /TÖ5\90«±Ö5\90y_ó5°b¿Î8£^\ 3Y\±òn ³éJ\ 4\99÷\98y\11DQ×\\89 ³ZK\ 4\91«õñ"È¢îÙ\9f\b"ã¨Û\13\7fñ|\10¬lU\7fá\ 6\82üÆò\11.\10ôì;ø\aA¿ìJ\ 3\191\17&\82ÌÍïò\83 \8bêÛ:\10d\1e:\12Aþiâcá\ f\82üÑ"ý è\vW["\88<°²\ f\82¨am["X±Í!g"XÙ¢ó£ \8a\8d{ø(\88\fàF*\88\8c\97«½
+¢È\99í X;VÊj"\88¬³Ê\8b \8a}©%\82È\9bì@\10\10û\83 \8a\93\9d|\10D^mj"X\a|\eíE\10E´¨$\82È­tM\ 4\99\9b¯å\ f\82,ö;\a\92\ 6\87@Ô:Ûú\10ȼª&\81ÌSô%\90Å!=       ¼\17      \ 2\99Ë°×@¿{[\89 \7fÈ,\11ô\1c\87\9eDÐk1o8\82Ì5ZÏ\11ä5k\9c®.\82\϶ô è\ f6\0s\ 5¹Y:aýU\90Ûj¶\95
+V\17:\11ô]Xç\8b ·j«\9a\b\19Ò\räî^1:]\ 3Y\14Õ4ÐÁ\89ÙÈ\rô¼úk ÷M\12è)ÖÄ      t\9e¾c _'Lò\1efÆ´\94\ 4z\ e"?\ 4JÇDÔ×K \8b>\ao\ 2\99«Ö$\109¬»\0²¤S\13@äAø\ e\80̵¿þ¡\86       n¦\7f̵¯ô\8f¹y>þ    »t&\7fü\80úü\16üy.öòçW5Mÿ\84M\8c?ûøÇ\8cyèõ\8fÅ9$ýãEJ\9c±Ü?æîCá\8f\7fü\8d\94uûç«&\96þ!/ósÛõO\ 6\96Çfú\87¬ÜMÇ?a\7fÎúú\87"{(ýC\ eÚ\82?\99\0½ÈË\1f\8a\1dÿ\90;ß$Ç?ä\89iáõ\ fÅ¥*é\9fð\92¶Ò?þ\7fxøã\9fà·\94\96ü!V\8b\99ÏùC\86löò\87"V¨'\7fÈø\81\93}\8cyøcqùt\19þÉ>\v\1dÿ\90­úiõ\a@\16»¿\r\ 3@±èæ\ 3 ³\94ñ\ 2ÈbñWf\0x/\12\02·Q_\0ýö­&\80þ!÷8\0\8c\a@¯©%\80Ì#üp\0ù\13\87\8d\17@\14Õl\1e\0ýÉb\9c?\0r·,]/\80(\ ei\9a\0ÊÖø\bèû°Ê+ 7«ÉH\ 1\91«è%\10\19\97@îú^G\12èà\84\1eN g³\97@o\9d¢ÇÀðg¦\81îS\19¯\81~¡"i sY\92\ 6zÞ×|\rÄ\86í}~Æ@v¤Æ\8fs\ 3\8d\ 3P¹c qÈ\8c¿û*hØjÞM[Ad\99ÝRA6RÛca2\88"v^O\ 6Ñd\ 3K\91\f²%ã¤{\18d¯úû6\18dOsâ8\f2\17Çë\87A^Õ|£\a\83låâV\ 6\83\84 \8f\ f\83Ó_\ e5\19\9c|\ 5Î\99\f"ã4Ñ_\ 6\89B\99õ0È\85\93Q\93Aòg>ê\\ 6\r\ 3\85ùu\82A|\15ð\8cd\90M:\9d´\1f\ 6\17\8f7u$\83\8bÂY2¸øj]\9f)\90ÍX|T\f\ 6±Æ\9bÒÍ \9eA\17ý0\88GÌ3Q2X\ eÚ\9bÁBÿÚ\87Al&¶r:\88ý\8eO_\aÑ\ fX\90\8f\83è¬æcßv\10íg­_\aý(3>\ eòüãë½\1dd\16½\ e"\ f\7fáý:ÈÆ·y\1däiMúu\10\19·ø8(Üëó:\98\17Ù\ e
+\ f0\1f\ 6y÷&\97A~æ\8e\81ñ\95þ*È\9a\8e« n[T®\82D*ºèGA¬gµ~\14ä\83­e¦\82ø\9d é£ V¨ï¿aÅpݦÌD\90»\90\aA#AÍ\12Aã Pk"\88ç9÷¡î"\88\9d\82\eX"Hq\0E"È\8c\ ez\11\94à\96\b:@ý"È^)M^\ 4QÄ        %\rd´¥i ùdÐþc 
+Ø,2_\ 4q+©cÝI°p\fjqWg°pЬúq\10U\89§½!ä×ÑÒ-%ä×\9bÄ\9fz)Ä5:Û!-D¡ø^:\18¢\80}¹ìGC¶,\8e'5=ÄgÄÛå\80È«¬õ\15\91Õé_\v\11ñ\87\84.\87D\16:?þ\98Xø¶¨~r \14\9c÷3\1câÂZ\97¼*Ò\88Â_²YäJ\96å\96\86\8bØ
+c®±\1e\18¹©¦_jÏ\87xâOï|\88®\1d:?ó!®¨Cî|\98èí\ 1\11ªóY¼\ 3¢\8fr\922V,â°\84±n¦\1e\18+\86\88ªéb¥âåº\88ÿ\ 6\93r\ü7\0\ 3uz»\r
+endstream\rendobj\r12 0 obj\r<</Length 21954/Filter[/FlateDecode]>>stream\r
+H\89¬\97K\v\11\85÷\81ü\87»        Ø\10®Uª\87¤då±      \84,\12b\87x\17\86ñ\10\9bÄ\ fÌxá\7f\9fsJÝR÷\ 5ïÂ03÷\9cÖ[U\9f¤Ç»ßþæwÿªÏÖµ>úÓÄJ<ês\84wjµ\11òÐgéøA=Jè#ëè³v\8bÆJ>ðQ\9fVµ+t¸¢1è(à»\17\1fg%kálih\8d
\18Ã%%\7f<Ƴ4©«\8ek/\ 3¦4v Ï\10\8c\aºª\98C{\1f©5¬ÆªÔKé0­zë\8fÝ\88uÓÔÕ\95Ú½àûY©¨U\98\11^,\v5eË­\99ɬÔÙhï­­:µ\ e\7fHÁ"µÁ2V­S×\88\\16k-¿\9bâÿ£R\89ÖÛCä)Õ±ÞUÄ\94R\ 3«"X\15L\8dº¢\91Y\a¿\87Zd\9dQññ)=¼¦.Ø4y\16ecÐEÆÑQyöàZ¡÷¡\12\ fè\91ë\ 1£»:\f,t\1f\8ds\9bÊ3TºFº1XÌ\ 67
+:\9a\8cÔ½X\1aÞª\9eÕlî#'ë\r¥¼`ÐY¨\8a§\1e-²Y+ª\8fÏ\8eZ\1cT\8eIGå ­÷Úe\16C\1câ¿6lÌv+Ö-ëý\89ÿ|òéO\1f>ÿöÝ\87o\7føþíO¿<þ@ï£O?~|òÅ\87\9f¾ýþß\8f\8f¾øæí\8fïßü÷ý÷_ÿíí\87oþüùÇ\8fßg\99¿üj\99/\7fùñýQê\8fü\87\7fÿ\91\ 3}Ècþýê\97©ñëkþ\8aÇG\1f?¾úç*9¶þy\96üëY\81\7fþ³[+«µ@h" \91\8a\99\8bß\9d\9e\a\ 3¤\95(þ ¶èÐá¢-µ¨@{oýؼ`"\14\16²Þ\94\14e\99\8cxhÆg=Òö¬"£±\8c\8e\86\18£Æ¦@#
+<ëH¤\9eû÷Ù¬Dm\ 5\89ÂïÎx~ö&e\96G¾A7ëÅw'Ψ~ÆèuV\12\ 4\ 1´qû©\v:\11L&\10\91g¥2:£\e¬i9c©\94Z       \bÊ\16ì¨b\80«
\96í\14é~,\1af\8c\88/ÚDh\84\b\8dhµ#\85Îj½¤ë\15É\9eãËÉ\16æ\17\86ôhHéZ\18\8eÅd\8c£^cÔ"±\v¿\a\16\ 3å-@\19ê\16ÊòÒ\99\ egñaÊRµ6îGCþFÉnæbÁP5fKÕ¦çêÁu\ f6\86<&¤\e\97$SÑ\9b\86¢fúDo»V«M\98æ!m\16\1aØC\16\1a\8dliØÃÚ9mÀ\95I7ë\ 1IX\9a\³î 8\f\8dN4\95\82\r¡¶BÌ!p¸\99g-«\85;\{©-\v\89ånYmSsî\18¹ô\13Q4{\86\ 5\18aÙ²;É\82y!
+(U)±uc\ fÏknq\ 3\9fstÖ\93\89H\1dÄ:u\90\17O\9e\f\97ÑYcä\179\ 6\aö1Ʊ«í¨Ó\bc%\19W\9dÈ\843uÄRv\14L\94\10\9e5\\96!<1[w\89\88´<Ür\89±Hî<¸\9a\ 4!`ù\99\e·£\88»\9dÇ\a3
+Z4\8f ³#Y\10d<\824\ 1¼CÖØRm#3\1dÌf\9d\9aý3Î=øY8úUÇ\9b§\99\ 1\91Ù!¬ÄSC\ fÍÔ\1e;ÆÓT.\ 3ú\8b\1035Gg®¹\fÎèøl\ 1-áÔ¬ÔÙ2²6\v1\9d¨«j\12/ôH\8f_\87:²nH\95váö\9b7\9f¾{÷ów\7fÿáÃ[\96=Ñþæÿ\8eÿ\90¤ò\v\9ce\9e\98\vΠ\88\rgh ä\ 5Τ_FÙ\843áWdÃ\99ðköBg\98\0צ³ð\80ÔMg|/©¯t&E\86mD\v\8f\88¦Öú\82h\9a<æODC{âö@´d8¾ \1a¦fË\a¢ùÃu3\1a¥\ 5·È\e£ÑâdÿÁh®\9dÕ\v£Á)Þ$^\18\8d)\9bÈ\85ÑX\13ñ±\19\1d¤Ç\88\17FÃmÀ\17\18\8d_\a~\ fH\a\12¡T¿C:x¹­mC\1a\86oBC\ 5hùBh¸\80\9aoBÓ(¢\9bÐ0ÆDö&t\18î\82a\9bÐ0ª\8d\rhè$ï\1dÐp\91Ú#\17\8c\15Y,/h\a\9f)ye½ñ\99¦\8f¾ø\9c:1:ùLÍißø\f³WÑÅgêa'\9e©\9aÞéL/rs'\9dw\v\93ÎÔ%Ïô\v\9d³ï\88\93Î,#Å\17\9d³Î\90;\9dÓ\8cºè\9c\1dy[tf\9b\13@\eÎ\N\17Yp\ e¾9,\16\9c\19*\1ez§3£ª%I'\9dã8+\16\9d\19\86ù\14¹Ò\99Áj\vÎPÍû\863\ 2|¾­®p\86)¾Ù̬(ºÙL-úÂf\99\9b¶ØL\1d²ÙLLé\v\9a¹5ùð8ÐL-¾Ñ\f\1dÙæDó¾o»al½ÞIHSsÝ'      ©«û"!t\19Uï$¤©#N\12:r£/\ eRÕVï\1c\84Ég×\89AJæÃ\89AjK}Á 3UG]\18d!í¶0\98\14L/_T\93\82ÐhÂ\17\ 5©;\9f'W
+Òä\11qR\90\8d\14\ e
+R{Ü ÈIºÊ\82`.\9bm\ 6B×!/\b\84ÉI.\ 2B\aöl\13Ð\99\9fÃ^\bèþ,\8càòÀ¯Úç­t\12\10\86Yö{! Ìã2y\10\10F×Ñ7\ 4=0lm/\10\84\8b\ 4µ\rA\18'²'\ 4aè¼go\bÂCYÝ\10\84á½_(\b£\95×[*L\9cVmCÐÛ3sठunö\ 5\82ô\18R'\ 4Sç[eB\10Zj\9ey\17\bÒÄ\9baA\10\1aW\97qR\90\92\9b|àÍ\92Û;1¸Û\98\18¤¶\19\8a\e\83Ù{¾ø\12\83\94^lapÖ\19w\f¦\19\8b\82ÙÏ̾¤ 'Øò=xÁ \96\10X\18ÌíM\82M\f2^\ 6ÐzàB\v\97]_\18ô\84r,\ff,\9aÞ1\98\ 1«ãä ¤\8bÇâ ´2{o\1cdä»\8d\ 5ÂÌ\8c"\v\84©Eî L³Æ\ 2aêX\1cLHÕ~\aaâ,É4A\98Zt\81\90ºLP¾\80Ð\10²¸HßAH\93·ô\13\84Ôȱ\ 5BjÍçÂ\ 5\840µå\9e&\b)%\81=Q\b\8d\r\8a;
+iJ¾C&\v¡%r4\93\85Ô=õ\85\85Æ\8cí±XÈBDÕÉÂÔù\8aºÀ0[\1e\90Z¥/\18R×fw\18Ò\94lyÂ\90ÚÌ\17\f©G^\117\r9¥IÙIÃ\;½à\10FðItç!ÜÎlZ@\841puÜ@4æj¾p¯@\84\89ÂÏ\aé\ e\1eÂÀ)Ûî<\84y\Ý\ e\1eZÇb\8dºy\b\ 3\82C\98È\9f¶q\b#K/\1cÂ\88ÉÇ\8dCxÍ<6\ ea\8c\9a\ 3\8760\99f/<\84[ñ¦Ý<\84¡=êâ¡\1d\e\10i&Ê&\ fíx¶\9d<¤æÌo<\84éXÝÅCê\96¯\89ä!¥×zç!MË\r\9e<ÜmL\1e²#dÅ\9d\87Ù»÷\93\87Y&\9fO\93\87©óésáa\9an\v\88Ù\91\8d\ 5D~GVß\81È\15Õ¼kM æþj_@d¼\90O7 2´<á5\81h\a\9eO f,j»\ 31#Vë   DÊlwò\90Q\8e\0»ó\10¦\ f«\8b\87       \9fá\8b\87\99+yL\x\98¦\8cÅÃÔ®\v\88     «Zï@Ì\96¥- ¦.m\ 1\91Ú²ÑW *\82väÓõ\ 2D\98]ré'\10©\11¸\v\88¬4/\9e\17 Ò\94ÞO B\86ç\15n\ 2\91º\84Ý\81\bÓ=\9f\ 2\13\88Ô¥é\ 2"uM}\ 1¢2e»- ²\90´X@L=Ãx\ 31[ÎGÔ\ 4"4r®- RG>\89.@¤ÉÓâ\ 4"5cü\ 4"\eÕ¼-n r\9eZu\ 11×./n\a\10a\8c\v\10u\0Øé\1e@\84\81\13vóP\99«=^x\b·1\94\v¿ãä·\v\10\vOÛx\ 1b9¯q'\10Ña\ 2òä!aUÇ+\10\vBÔâ\ 2IJø}\0\11\v\ f±\ 4=/\95'\ f±N1\v\1d<ÄBöV_y8÷àÂCìd\rÙ<ä;'±uå!\ 1Õû\ 6b>\96Æ\ 6"£䠠   x\ 5"L+º\81È\97\Rt\ 2\91P«ò\ 2D\98=7ø\7f¼×K\8b\15\ 5àyÀÿá\ e%\bíz?\9c\91\84=pì\90 9X\10B\10RÇVbµ\8dÒÂøßg­Uuv\9d:(Ó`l÷Þ÷ܺ§^_í\9a Z\e\13\11Ær<\81È_×]k\80Ègt\8b\9a úãRt\ 6\91É\1c\16\88ü¡±\v\a\88x\83\10½­ª¸&\87\9c]I68är©9í\1creõ\\8dÃ(\9d\9b\95\18óΡÖkô\a\87\f{jæ!bç³ß=äÊ\8fÉ\9b\87²\87_\9e\1ej«¸¸{¨¤oæ¡b\8dÊðPV]8TÃòip¨Øeã\90q\e\^9Ä\9aB//\1c\ 2Ù8ô¬\8b\96\86\b½*õ³\86X¬Y3:4Äöè-/\r\11'\1d\90g\r±â»®\0SCÄI/35D\\14\9f5ÔnjKCÇ\ek_\1a2öå¢![î~i\88Xw\9c\89!·^)\17\f±K»\1a\9e\18\92\80X\17\86\88«ªÅ\13\86èæPvbÈ\91SÕv`\88oó.rÁ\10¿\81\84!Þ¬¦xÒ\90\eõZ\1cF\ e\fÚ\0\86á`nb\88\ 4\8eÚ¾c\88ä,â&\86H4\9e,¦aÄÒ\8c!\4DV\93h\1a"ás¯KC$âàqq\88\
+©-\ e\91(NÕàä\10     ý\7fç\10Ù\1eJ\\1cÆtçpa3\ eã¼íl\1c2é[0\ eã¼2\1d\1c2N\9aò\13\87\1a0\ e#/tºZ\88C\86ѧ\9dC&\83¦xp¸Ú\18\1c2.u×P?\9e\ f\fõ\84nR\ 3Ãñ\8d¼c¨d*\86\96¼aÈAi=í\1cr@\9d
+®Á¡æ7.\rñ\8b\8b\86XYQrM\r'ͦ!\97"\97û¦!FÈñé!¨Âoj\88QÏ)_4ÄÔ`Ä\96\86¤\87ouhÈXgÄYC?¦Í4ôã\8af\1a\92*\9f.\1c²%×\17\87\88\8bCÆjôÊaàÈé\16\90É®¡\1f\1c2n±\9b\87\8cGñyò\10I Ö\ f\ f\19FÕpÃCÄØþe÷\90ɨ\eÁð\10±o%\9b\87üÜ)>y\18¸ek1\ fù¥^\9ay¨x,âå¡ZîÆ!C\f\9f\18Eøî!\93Q+{xȸÄb\1eòí¼\8aÅå!»í}6\ f5t*Ú¦\87H\14\fîÅCd1Àiy\18°Ú±ì\97\87\81;µ^AD6q-;~\ eêÊ\ 2\11      \9cµm\a\11ÉQÄM\ fC\16)ËC$b\rþâ!²¹Ç¶<Dâð{x\88D\19Õíò\10¹ZTSN\ f\91è©Æåa(\80®¤\8b\87ÈâC¿<D"¹\1cÍCÆIj\9d<d2¯êP¡*»Á!ãvÑ\109\94ÆÙ4dÜE¨4d\bGv\r\99,\9aà¡ájchÈØ\8dÕ¸8Ô\8fëº%\ fõ\8c.RÃCź\ 4\9d<TREÈð\90q\18\9bP\1e²Í ë×ÉC\ ehRÁ5<Ôüʲ\ 1"×Kfáq\ 6\91K«¦n \ 6qm\1ej)Rñ³\87\89Ò\f\ f\19Öd\1cr\91÷\14w\ e\99ô1\1a\87¢§eãPqÏ;\87Ú?KC\85\1a\94¡¡¤º\16\87jH<\r\r\19\99\86\8a\87\96\17\r}F\95\94û®!\93¬\8e\ f\r\19\87\18LCÄbïd!SQ\13*\v\11\ e\85\8cCÞ)D\ eSR\8dBÆA¯2(d\9c\14\9f(ôÜ­Õ$ä3Qר!¡b×v  Õp\8bF¡çVvÁ(dÜ´\91N\142YÕò \90\8d¸q÷\12\85\8c³JÅE!{9\8c\1d\14jÜT²M
+\91è¼\86ì\14ú\ 2\8bZ]\14"¡]a\14znS]*Ï\14"[+\96\86ãç\ 3¹)¡¯øËù]B$g\ 17)D"óX1
+\91À[¦\v\85Èö\18ý¢\10\89\16[_\14ò\89aã¢Ð7¼|Z\12"\ eM\85à\94\10    \10×.\12"\8b\15\97\97\84\8fÅ$ôó\9e³IÈ$Ö\90Qèçeé \10q\vºÏ\9e,d2ë\84\1c\16z^åt«\90\85\f½+»\85L:Íð°pµ1,d\9cJØ-Ô¯§pX¨g´Ã\87\85ã;u·PÉØÌBÆ%F³\90=,­ì\16"\19\9bÊ­a¡&8\ 4³\90\v¦Ç¾[\88$\9a\8c\9f4\1f\18j1\ 6¿cÈ%Û|90D\18|\\1a"v\91×ȳ\86\99eíÔPôÔn\1a\19qÒP[\88\87ÌäpPT\8dCQåÊΡZrÞ8dìº7\ e\15«Ñ+\87X´9×Kq\88d\8d1\19\87\8dE\91[Åacé©\17?\81Øî\­>\1f "ô57\ 3\11;fÔ,g\11\91Ä\1d"\9b\88Øg%×`""n\98¹]DîÙÒLD<Ss_µ!c'ÇN"²á¦¥>Dä\86vbs\88\888är\11±ê¤\b&båyÈÍ5EDÜ9Ùg\11     \83«ÁDäÐù\12\96\88X±`Á_Dl¨0\9a\14\98"B\ 5\18T\96\88Ü«UÂ\9dEì¼ü`\89¹[§um\89ØyÒöKmØYÁ©\82\9c"v\f\96D5\11Ñ>æø*"BÞ\97\96\88Î\ 4\9f"â£QÝ\9eDtØQ*)\ f\12ñi(ùD">J¹\It¨!s<\91\88ÑD'\16\89ºë\94\v\89¼ iä'\89\8cUÚM\12\11\17\1d\82g\12ÕD]$ò>'G\a\89\b³Ë\17\12\91Ldì ÑÚ\98$zÞp."òÇuÝ\1a\91U\1c\8e\v\88LƲ@ÄϺè\17\88øÜiC\9dAÄH\ 6\15\\ 3DÎ/\7fá\0\11ë\ 5L]@ÄÒÊÉ\9b\87\84¸új\1er)òbµyØæ\80M\ f\ek\ 3Á;<Ä*¯¼õm\1eâ@ìAß\19\1eÒ\1e\90a\1e2n¬\0Ï\1er\ 3\1e\1eÊ¢¼<¤Un\d\97\87Hâîb\1c2l=\1a\87MÅBú\ 4\87X±=«¼={\88UîCé«>t*\8d¢\81èX}\86x\11\11Y_ºêw\91\88-\92KJÙLDB\9byG\11{-G¬QS\11      \87\13ª\19\8bܾêìæ"w.®-Ádt¼»6Ý^\a\8dl\b?s±\91Ù\9a\83Ù\88­ÍÊ>\19\8eLd\17û®#²YÅýÁ#¥\19\95âô\91\86\ 4î¢\93\8fd±/\a\90\1cJt¢.!¡C©½ô\v\91ø\{r\15\8d8r±YOE#ÖbÑllE#Æ\96\15³c\7f¦~GÕ\bà{L\97ªQ¥\9d_F\86ñúF$§Å\95+\91Ü\96!.!\ 3Ew'!ñ\0Äô\9b\90Ü»1, ±òKna\ 1\19    _¿\ 2\89\ 2\8aCÖrç6K!Å`@\8eÛOÚ\81¤        %\17\ 3r^¡\ e\1fyÍb¿7\1fã(\98½íö"s&\8fø\94Æí<29\8eÖÁ#\9bÀÌ\19\8fñ¸!\9d}D\12\vÌ|ä3U\ 5È\0\11\98\99\fÚ\94\ 3HúE^\ e éW­y\a\12\ 3Êi0 9¹£\18\9c\15#òѧKÅ\b¸b*«b\14×aU\8cX\89>ä]HLNáXM!\11ö\90k3"1¥>4\8dâÉHÌ|\14û\a\92\14    j­ª\91    PXw&±Ì\8cÈ¥Ó \92±\98Ø\8cD;|£fJ2¡5v0éXB$ù5\9c|cN~þìÃã\97ïÞ<¾ûùáõ\87ßn_0÷\ 4û®ã\®Oo\9f¿|üðîá\87Û\93çÏ\9f½yóñý\8b\9f\1f_óÙ§·ßëÉg§G^þøú\97ûç?Ý?¼ýËëÇ\1f¿þòxæ\9bÿùÌw¿ýr?\9fú\ 3ÿÃ\7fÿª.Ý´Íñï«ßF\8c¿Þò¯r{òôöêûùäWøÿ³¯ã?¾R{\8f÷\1f\1efâùý\ fï\1e\8bÛ\93ïï\7fÂo¾ÿø\1fÄO?ûÝ\1eëÞ\10°(Y\90SÅÒ±ò1á%pê*\7fëãz+wz«?âï\7f!ûë-ÝþtûÛßÝíígÌ¿z1¯\1a[»ïÏÉÙøí[õjÿÅ=y|ýÛOµ©äÃx\9b?\8fÕ\80)΢3\ eRU;:²ÿïÿë[ýs¼Õ\8bc\ 2ùÏ7s\17æÛ¯\18¨\82»\98C\11\1fQ]\8fWA\12\e
+\)XÍ\ 5%\88W\88ÛR¸NÎØ\ 2x&á`g²¦Î¯\0öz+  [\96·\ flÆÌ8\8aåYàG\1d\97ãÇÁe¥Ù8Ü\väG­u«°1¡\82Ì(£B\9a{\ 6¿\ e\98\8bªþV2Þ     \95iNwÉ1\1fyügþ.$\98§ùKi\85·Æ¼ì=M<¿ØýÙÓ\ 4iq¯´®&H\91¹\1eÏ]ÅCØÜñèjÂ!\86ÊÛº\9aðӬ̷®&\ e)\ eº£«\88ùzGOS\86H\0}ë)\1aî¨U¬¯±Ý±Ä;º\1aÊ]\ f\9c¥ÙÕ7ÖU\8f·N¨\18·®z\1e8¥ZWq\8f\rx\15ëª\16\10ÄÛº\8a\87bvþè*Â\96b´®úz\87Á\ e{W\ 3Ç4YO}ÇJ@9wtÕc¡\80î­§øm\1c\94Ùzêø\16\1c]ÅWQÄÔø\89¾66\vÊ1\93®¤ÑÕÊ\8b\1ayëÄÛW~\vaF\11\96Ù\17T\1a\1aóØâ\14<WL\1a\84k]Âäe\80\1fP, î­ãMÜh2¡:OÇ©\89\0G\ 1&³âK8\15\11;.1´\SU\8cs/qEà\14Hö¥\8eë'\97\96\85\99\17¹\9a¸\8c2'í¿|WO¯'7\11¼¯´ßá\1dáð"Ûí¿G²×U@B\9c\11Z@Hh\17\14\12åëSÕîòÌ<\1e\91²ÙýÕxzìrwuu\83iJeò9¼y\8díq\16ÁÝ\ 3\\93U\8e\ 2.ÉÏà7\8cí.´@þ\86¿\r÷Ð\1a»úþ:.\ 4?aV&sÜ?\88R¡i\fâö\eHÿÅQ\ 3Ä¡ÿøÁ\98\1cþ\82\ fY\87¹í\ 2\12\9dK=Ì!-Ë\1aõ0W`\a\16\99½3Wè>Ð\91Å\a¥c\17b®ÐÑàæ\1eÌá¥ÚIg0W*\9a$\8b4\98+ØVç\9dÝ\99â¼` Å\1c~wü%â
+ëp­'qeîµb\ e¿aWÛa®\f$\ 3¯èF\1d>^:l£r\ e'\80ci¢n!¡K\9fOê<\81!r\9c¨¸\13\96å\16àÆzBÅÃéÌîÊÛ\a\9d\15¯}½´åcÅKYÛó~\89\f\86O]Üì\9cÙ\15\12c\94¹LL\16ÜÀ\ 6ybÄ^­\9f\97°\9bJV|LBdx¹â\976\9bë\13¦¦ÎçmI\14°\bU:\19\89»éÎ\82\1fÀÍ\15\ 5&wÿ\8d\ 1-\8e\8aµÎQ\93_\87ýc!\17\8eo4VT%8ÍÅl¡\1aÕ8\12"Ãÿ»\84¤
+YÀ\91jç´ÒqDÐ\81ûé\19F3¨û\142\8f\87\9fÙ\86\83:+;ä\83:<óº\15uF½)ùPg\1c\19xÂ;u\16º)ê\10yU\f\86¢Î*g\1d{RgTfÎ=\9b:£¡·q¨3\96h\1d\98QVÛ¡Î(º HÔY\8fl¸S\87¯gf\83¨ÃyQ\ 5åP\a\15N\93©¼©Û*\8c\13À\17\1fê&\13
+Þ5¨ÛNá\ru;\85×æ\ 5\eE        Ì\10áº5$\97Ý\ eá\00Åùo\18ëB\87\90X\81\19ä\17\8b*\82ó¨\8ds\15z\b\86    ¶÷\81T\9a\9c\1fA\eÝJ\ 6×He«³\9fwú¬Ð@è\90±WÑ­ §£¥ú C»\82J8Îè²+lÒØ̤mAÉçÄ#¬\85S»_éþ»Ï\96úͯÀ\ðó\86\92\1dRÝ`Æý
+\85\b\7fÕj7¿R9I`Bi-oË\82þó\8a:\81ù¡ca­\8b¼OÑ$0éÌC\9e«W\9f\87<(\91\a}\90g¼cD\12yø]\f/\89=: \99Û\93=: \96×aÏ\1d\10jAìÑ\ 1õ7ä¹\ 1¢,\ 5\80 ""\8f\ eȲ=É£\ 3\9ahY"¯Jy\83<·@Lë;yn\81j¿Ès\ f\84J   òX¡\86ê\16y[\8aón""\ f.e'U\90\97+\82\ fò`\8fl\814\91\87Å#áe\91ç\9e\93<z*\14ù!Ï=\15{x\90÷Ö\94_\9e
+ê"öÜTÑí\ 6{nª\98MwöJ\18U±ç®
+ª"öèªæ\93»?þú\84Ö\büù\87\7f\ 3æÂ\9f0\1a¾¾\ 6î\93ÛýÉÇ\ f?üÛ\9fÍýìû\1f\7fþÏ?N¬ßüéÛ·¿|ýÛ__Êo?¦\97ß}ü\80áë\97\8f\1f~öÿ\9e\ 3ÛûãÚ\1eÖ^Q\8fî
\97Ðb \1e\9d
\ 4Í\8dY\7fðÏoqÔü\1a\e¾\87ù?ð\15å[ìò÷ü_ò\89÷\9fÿ\e»Z½íedÏñ{pÂ\90Õ¹a:æwvèQ\80ÿ}?B_°\1a\8f:2íë\81Ó´\80\b\10öd\83#£3l°²\1f\9a\e\9eýÍ5u|ì©i/lHÚ¹çô\ 6m\96Ø÷\18C\91\9f[ûrÛtwÓèOಮ]GGæñ;LÑ\ 6\8aMwE\90en\11{4ô\95O\8a°@PD®ÚÜöÕ¾vöüòî\16>iwÐãRr¹}ðëÁSQ\9cT=\ eÀÌ!7@(S\80ç¾à%-vG|%ínå\1a\8b/B}ñ»{¸¶\87.¿z$ F,\91\a\1aé\r¹Pz\ f6|LA\8e'\fQ/\eLeX,^{×4SM\ 1â\9b\81\a\9fõ\ 4¦»®í|Ðùèlë%\82¸¿&8\98\8d\90!ª;2q(MභF\10w\1f`¿"@¢\ 3Ä\853\996^§\9d\b½Çb\83£ÛäùD¹ÁbS ìèµ\87\92\82 ­\e'"9\8a\88àF\9f\99¢\ 6¦a\9a\85\v\e¾¸Åèå_*y\ 5ØÓ\89\80\84S\84\ 6ý\1e¢¦Z¬­I9µú8àTf/>\8e\0¶sÑñÉc\13ÄÕ >\ 2,Ýï·ù(u4¡\88\ 1â4l\91k3Özo\8eú\1a\ 2án\8a¢f¥5%¬ëk\8d½\90 ÒÔÆT%\16\95mn¦-°\14"\ 2Ò\91æjãy\1f\ 2 \84V%\8a4<\11æзÚ-\ 2DB\12Yf\89=À;J:ò´\0[3E`*E\84~\13£v¼à\1cìV¶û\88ÐK»\9db\83hüz}m\vF|àZ\95w-r\9caÇÐnáþ\14¡\1eÅ]¹\\11zk\8aPvApI:\8bÛ\16\8d£¸¶Ç\85\8d\97ª\8b«Ãº®¸\8a\9cn\9180\b©\9f\95W\95À:­sÅ5\96Â\1eõç­\ 3\84ÑZ· 'K\13\8d\1f\11®\9a¸\ 4\15\16:ÓÈ^\1a\19\11\16\92ÌT(\98(\²0R­uÎ\90ÖÑÎ2ÔÑÆM}\8b\95 l\94­\15\ e^=Ñ®\boÕwãWÓðé\85 Ý²\7fæØ\18ºgÖ)ÆLvi©M5x¬\90\94\8eÝ\8fã\1cÓudfèqRe\9b'Îd_¯:\ 33zëàD     ÖÕ\9f\ 1\92\88Z9\97\10¤àØR\11OÝ0ñÓ³ÆÚÕFðH\86\1fc\83\98\aû\15¡3·Î~\9d\9cEÓü¦\0\17\9d~\\95ç\8e\9f{cOß\8e+¥ïâ\8e×ööÄ zeµG`\1c\10©c»sì\98è«àpH5\87\v\83\1f³Iò3¬sÏM\1dr¦8\90ã`üÖ¶ö\86à\92ñ'Öçæõ\8f\9b\8ci06h·â_9ê\11\9d代\1fcÔ½\947¨M\94m¡²¥cg¸³®c\19,::êÃoe\83¥Á\1c±\17WÏäl dlm_;\9b"À:].\94\ 2 Æ¤\12½\e»­®¡\10àcí8\bª\9a2gËjE\rÍ+\1a\ 4wEïÆÔáû¢©\1d)\8b®\16\9a\90)å³Äb\9b\19"\88\11LÕ46\8døgZj\e«\96ª\bÀkV«NQMÙÍc«·\ 4#HO\13DXóZ ÖP»÷\84!uÇö.6ÜÏÂGÓMNh2ߧZê\0\15¶ °²ª\18?úEÜLi\XJ\9f\85÷Ñ\ 2·+°\8d%\8f7ÝUúJ;iWÛ\15\18\8an7z\7f%ê<QÑ:×\15\ 1ÍWg[î\9a3,ÄHçv\}\1c+ªÜUäA\88\9dµ{/ç$8\10U3Ô-\ 2ô¤v
+åhW\80K©zlà\9e\8d\1c\1fÞÎdÓN=\10\1fKöÐ\1d\17±ºV8.÷è\eD¥GÖZ^v\ 5\80\86\1e»R       \e[¡i±>\16+\9f\vu*\166}Í`LnÔdùac\19l\10^""4\9aÁ\rfËqe0Lý\8a\80Ò\16¾¥}\83c\bl\17(7Ú˼ßoV\9d ;+\19zNõÍ\1eÐÓmÄ)Ú¥7ÌÇ.ÚzÏýJÞÒslcæ\10\ 1ü³\89Kã¿6¸Â]qoõ*·4õ½æ#Ä®jÓÆ6\ 4\13U4óøºx½\9f\81\11'Û,\0+ª¿ÖC@Ø\9a4\ 3Qþèõ\92U:m\85P°AÆ>CÛ©Th\89çjò]ÁÖ\12-¥Çb\8c\89Á¶çx\80µ\v\1c§r0\86"'\82Ø\18U\bö\94¤+¹ä\0Ó\94~\8c^o\11\12Úa\9c!Ú#$7w\15/\bò´m\ 5å\7f8\94{w8§¸\83\9ez\8dµCç
+Iñu\9a`|Ò\8d÷9\ 6F×Ýf\89 ¥fF\84±"1h.s\90\80\f¯lWýdÝòÅ\95\1eX\85³Ró#Ô\ 1}\91\8a÷t4\10\9a¢0\axIV´\92\99µ±]ºÀp7:,,\84\ 2ô+\ fG\92ó`ï;\9aí^\94`=ÓÙÚ"K\10=né\bu^]Ò°D\196Ææ\ 1 µª¯\85y\ 1\98ì\94\12Ì\94" Õ[}û9¨J\91Þ¹s$\88FÐ%A\9eÍ\11\ 1\95Þ$\v0X9\16çª\fi6\ f\98L\e³Ó»\f´\87c»*Ú@NÕÆ`rü\14\86S\f\89Ø@6(\ 2\122\9d#³%\7f\96\91ñ³^u±AW©\1d¹î¾
+0wÕ\9a]ÉC¼ªX`ï\15\ 1\84\9e\r·\16`9\1a@,\ 2 ÷¬{GØ\18ú¹\8a*\ 5\b\19\9d"ݧ¨\b@\7fªLmißñû ìQ;ö\88ÎãDèCi]Ûn÷\0KkÊõ\15.\93\99|\84°*\0á\91ÏÕ\17\99\8b².§\8b\8c9\ e\89ø\94=\88û$ÆI4tko¢¬[îtÎ\añÁ~W£²}uÁ½e\15\9c­í±rxùp¥S´\ 3\9fS\1d\f\8dúæ­\87ªËc\ø)æZvÓ\ 5\8eá±\ 3¬*\83ÚÎ5åq3ØÑWr¿Õ²,(l\7f\839\96­;ZMüThøk\8e\bG¹vsç2\95Åí\8esÅyu÷\80\ 1ÖÓ\15G/#ÀÜu¨t\8a\90ðiù5\9f¥Y}ù¿\84WÛj\×\12|7è\1föKÀ>\10³î\97GÛä!Á!!`G"\84`$\9d\\ e\9a\aÇ\8eÉß\9fª¾ìÙ\9aÙcÇÄÈ¥5=kuWWW3\89\86\rç>\1eâv\e[O^m¸<\8b ¶\96àÂYÔ¤\ 5Z3o\94\rÏC\87w:úO\1dl¡ú\82ÇVMÅ\96³µ²âðíó\80Gµ¼&8\1a[ï0?²\8f
+õnØ!¨âv²\15_%+dÁ@ªæºv¶Ö<jÑ%\17ôìÁ\ 2ÄÖmm\8d£º\1fli³ø®[£\ 6x­8¥Û]ñÌ\16\18Ö/¯m\9dR\150lºLXj\91\91ÜQíp\9aÉ\ 3\87\8dpbº\935h&úÞ­\7fT°ggb\80\1f³À\836Î{
+ÃÏ\ 2\ f\8cÌÐÜr·\90%\ 6Ó\16³ëc\93\\ ez$ïõ\80þôÀ\r\ 3/ù.Qª\a®P>g      î¯\81«:D\ 5\8b\18-\82\9b\0èE\ f\f¼{ûB(¢\1f®>nd\1a)X²·Dlk2GÁa·/b\17\bfRÒS\99¥©ÀìÍ\8c\8f«\91&\1e\8bO\90Ô½\1c#nÜVLA¯\16TF\8d\81Òm¡Ïí"»®vÄ\8fþZ\16\82×\8e×2ò\91\85G8O?>\86\13®cm\9dÃ\8985¡½c¾çí:I°m¦@ìè5\ä¿\12¤AåV\97\16\1f\8ex-\8e7ɵ\80ëÚ´\ 1Sòbg·\11\82WÏS(eúá|$A^v¯à·ã\86\12¢7«ø´\87\15_\a£ì\17\ 6N\17l\99B_Ø\92¼^n\0%j^·\96´F}|\85[¹Ý\9b«'syúl¹þùìç¯^|;~ûæp÷òýÇ¿ÿøñÝ\87\ f÷ï\ f\86¾¼ÿýÏÃcüé\9bÃáÝÃýÝ"ð\ 2üÙUX^\=        Ëõ§«'\1fùC\\82ü¹þ\97ÿú\ e\ 5ìÓR\96ï\97_~\rË\1d>qý\13\1e6hÇFöùÎlõ\91\99V¼ë\88¿~\8c§\ 6¼de¸\86Ø\81\9f>ØÅ~À_HÚ\ 2+\89ÿ'.ö?9\8f¡\82òà#h¸\ 2¿ð (\Àl ç@E i \r\ 5L\82)>\9fX4\96\7fôpG\11GR\1cÛÔäaÄ+3&\8dÜ"tJ\ f#\bF¤á8[\97Í¥¡Âãx\ e1
\86öà\96\80 \15\9a\ 6Ú\ 1\84øÙI\1a\b\b\bA8\ fè\15Obö\80\ 2\f+\9e³Ê\ 3\ 2\96Jt±Æ\84Âé\ 4G\ 4d¦O    Ë\11Ï£\11/  M \8c÷\18å\9a§¹Rö3­ø¯!­À@\04®%\173tN\8d2\9es±Òìb\ ec86½G²\84ÑN\95b\97(¥È\83amd Kja6\85ÓÄ9\ 6Ñ\15¨\ f\12Ñ\86Þ9«Ï\ 3Ø\94/7z\98:8\8báLª¾¹Ñà\0ä%¹;ÈÅ 9YÁ1M¢%q½Õ¦wË£h6O\1f÷vMÇ9ËÀ\81&\8f\v¢\8cÑ2\119¢S´/lI\1f\8dÀ1$}\1c.Þ÷3ñÊ#\88i\94ÇE1Óò\8e9\8a¼\98î\ fESª\ 4\f\8a¨\85N`*lî×}b"\88ü
+×'7<\80³<o¸«]\18\ eØ3\91è$ì!³\87
+\15¦\ 4\11ÂñÂgOþ"]ðÆ\99'{zRËz;f        \93¼\10O4Ñ\9e\90\89e\87 R\aÇíÝX°\86\10¶®ÂXZ7Z\8bÒ\98\16ZD!Q\19úð\fß\95\9c\\81kXaC\819\13»­%$ö(    \19\bâ\r³
+\89°Ìr43KÀ\13¨!Í\ fk\b\e¬)­\9c#ra$$h\0\8c«\8f\ 4ç\ 3ïÔ½ªÅ®\96\ 6Ó\18ã²\9b\9e\7f.1\ e¦mn:$·PLb\v(\85º\18\9eèx\0®\1d\ 2\9cU\84\807uÖÀ\83î\8d\8c\f\a\91\87\81\93û\86\1dÆj\19\93KÆdO\9e(:\ 6\93\9f\85º\91ên\15\96\85 èWU2QÑ<ý\16\95½(­Jy\12k
+\ eÀô7Õ2\18\89\18\18ÐÉT\vV\94\95\91z\8c\86*`ÃÑ~\b=Ë×5DP5\ 4ï\vå|7m_`-â\8cõ\89 K\83\9bÔL7´18¨_ª\9b¤¼%\8dêmÜ5ý\15F?%\13®\98á§nõá(x\9d
+gå\86\8déw~ËÃoôëP¹ÔYCªUN\92þF«_\87\82\90   I\1d.&Ó\11 nSMJ4{\8$!¡\82_»¯»(sr·\fú02`N\1dM\ 5\80MÑkÌ^%2@\13\ 6õc7\15¯<\ 2ª\9dµýâ\94\8eâCÄ®I\ 48&'L\87\96µ±{\9fr\98\vÎ\94ñ\15êJ\188ÖL¦¢¥Pn¼Ù¾®cüI\99Ò\1c \94r\ 3ù\99\9dù!8ùu»Oþ"aðFì`C\9b~V\e\8bòF\18\8f¢xã\80ôÃ\9cîÔ¾\1eÇÚ\9aÔ\v}\ ej\1c´Û*t§\8d¡\9a\e\eFxB\82\ 5o\19F®fí¯r4\94\89\98\ 5i2£|bÍ]Þ\r       ª]\19Ç\8d6Y\8e\ 6\8dé\90³\19ëCõ|æ*XÐö!\b³\81tñ]\15æ§y\0.\9a5\89øQ³SZv\93£"÷ñ\ 2åP©\92zWQ\8cX\9f,\99\83\12RL,éÑ(·(\112% \9b\1eÜ^\95\ 4¿ÆúZ4A\93\82\ 5\ fåm£¥(\19$¿8AL¶\97\9a\15+\9cHúñ\86³]\f\1cç      7\14\80=C^´\11È·Ùd\0'Õ*ù¢8Ö\b\93[\9bâ\11:\9c¢\193Ñ*©\90\fk±NUû\0/\90\16¶)\ 2\1a\r\11N¾,L\99zhã2\9a\11\16µa?+¬\8c\97\91\85\9aËYL{lnÚ·!"\897n9G*Ió\88M.ÊÛ
+h¢ÒI{\9c¢e'µÜuBJ\16ÖäΦ¶\ 5)\89AËc\e\8c\8cô<\94¾(0þ)\94*øõ¬.\8eÈoéQé\97²69\1a\0y\91\vs ã\15*\8eÀ±($%»Z\9cQa\17K(ú\bñøo}Üä¡\1dG\13\94\\97F\94ÞÄ·ÁÖ4WÝ`\ 5%Íà\a\80Îydí\82Á-r\97¨º\9e©©\1a4\95#aª\8d\1a\8dÃ\13\1d0\98\ 5àE}\ 2ÓÜàjèE\11\f{k\15bb\ajB\1542"\14§\10Þ\rñ®&)\16!g+T\1a0\ 3e\88\v¤\8f\ eÜxè8$¬Z\198\91\1f9`\9amdHch"\9c}3Q\87~\aÀh\9eZ\15=ô¢÷m±¯Ý\8fYÞ8\85\88Ï8¬$è\ 69;¸j¼õâÕ)\99ÃÉÞt\88Á\85X\8eq´D\9d\8d\15­>\83ç\86\f½õÙ8D,Ñ\1cê\ 4\8cm²a%¤T.Æç\ e]m$\91µºZÎ\f\ e\14­ÊS´\99Ù-1
+\b\ 6µ!\11\90\ 4\8c\182\1c-\82¤Uì_\ f:ËÔ¬\16\92\ 6\17#ëÔÙ&¾\9dÞ\eúñ¼Ð\7fª/EϤÚ\8d\ e°\88Í\ e×Zºq$ZX,\v¥Ë\1dªVG\ 5\ 1þiöQíðT\e\1cõË:\8dþ\8dëA\eb6ÁI\91iµ¥½èçñk¬JË.{o}\ 2&H5ø\8bR¥£1=©ñÃe6\9c1çÆ\r×9Íö\byN^ãô\19×_k\91÷\1a\85.õÛnsî´ñ\85¬]Jñn1Nëö¹\12\9fñá­\1f¦\98k\v\14ɤìJ*úÌä C¶ñ +\18\17\15\82·N\13K;uÑÞ\ 6P6QqUýÂØùÌ\88:\9fg6vÎfßî\90¼<QwÇïî ¾4Õ÷\1cÀ\8eQ¸ä)ö\fÈ®UÙ\1f\17\97fËî\14:\1fY¯>3ß.\râ>RìgnE'gÁf#\1cC\9f\80gÅ7\9b$ÔçÊ\9abô9]\91¿Ò´Uf\ fÝ" e£r¬Õ\92÷Ô_\8dô\9b«'syúl¹þùìç¯^|;~ûæp÷òýÇ¿ÿøñÝ\87\ f÷ï\ f\86¾¼ÿýÏÃcüé\9bÃáÝÃýÝ"ð\ 2|IÏ®Âò\ 2Rµ\\7fR\8bI§.\7f®ÿ忾ÃO\7f\ 1û´\94åûå\97_Ãr\87O\ÿ$t¤\98C\1aP|[tÐÕ M '^ñ×'xhë\14µ\bçÈ泸÷\7fä^?PP\e\ 5\15UB"³  ªÄ.¡wÝ\82FÁÊ´Þ\ 5Å´í\bìPÙ!¯{V°õ8\97\ 3X{q-Ùܺ«Ê­¯éaTÅ}æðKÒØ<H\eVvÜ\153\8dK¸D\19\8f\8fB\ 5§ghΨB\90\8d}ü¢ÄEÎT#ÓUZ\1f\970üp\89Ón«Ã1RÐkZ¡[ÿ4$ðôàhºâ<
+\88      \12]-\90ÀU¢u%\93«\8aõ\10\102\11íM6Þ\ 1B\aÇ\ 6´\bØ\83êL'\87¡z)OÓ!\bÒ#\fé\rÓìÈ       \9eRèvØ\12@°¯\11\82\v¸FÀ\f:=Ì9+ù\ 6\181r\f\84Ñnz¯IÙµ"`FF-\82\r8}Ù´"p\fëðàs­\8c\ 6®iÐmóäph¡\9e\84\85\95Gp-\85g}s\18C\1d5$\8811³W8ôÙ\144S¦¬+J\10ú¨Ü\8d\8a\92j©;&Ìð½+;»\ 4´\b\81{ÆÉa\\ 6f¦kؤCm\83¡1Gö$<ÂG(Ý\9a©¤<t\97\92Ç<b=À\91±\13­|v2\0\1fÍ­\1a¦l5°ý\9fî²ÇÑd·¡hnÀ{\98\r\8a\14%ÅíðmàÅ\ 38óþS_\8a¤¤ª\82³Æ\81Z\9f\8a?\97\97Ì\11[Z>b\9fÜ\89hQ\ft*\1aùeÓh\83\ 1¹\8f8ÉÚë)§¬=ò\9e\r8G{Â\8aOkT/\18N\ 2\81\1cõ{XÕ\fýÿ\85Å\92¶o¸x©y\96\7fZHã§ZKŤ-+àQ\8f+þ³ÇáS\8f3\1cÊ\ 3.#±\9f\90\1c6¶ÛªâÖ\87ÚS\19kÅkô£\8cfȤ>\95ñbX-¤õ\ fl\bõ÷\ 23F}Æa÷»«×%l\1e\9cL\93\eÆ\rì{Ïóð*½þ
\rÛÜÕô଱\92 )§DĨ\87Q4}îѾT\8a\9e\e\ 6û0\18áð\17\9c¨±hkmõ\ 3;+\9f\e\ e\97ÞôõshK¡¼\81°$\0n\80ß©Z_\87×@K%«µ} Â½\1fo\1c\9cÌ=\8f\11¹\98µ¬°ã\aÚXº[a\ 6Û\9a\13\v¶½ñA¤\91¤à\99ú¹\13Çgg\ 4¤åAÑËBû 6î]Gô7>}½\97\vþmM\1f\94«\e\8a¤\99MÛÐo\0\8f\87\91á±Æ%üû´\rõ\r¯IsñáÆÐa\99..c\97\83ý\96?,á~\ 3<î÷°FÌÐ\16¦\86\ e[\ 4,~ë'o\90^»ónF">yRs\98Ã\ 3°\84\f\8d{Ò0V0b~\1d\86ÎP\8b\87­\1dà    19'ÏsCr¤;ã\80Ê Á\9e77ÂþZÉd.¸#\89XËëp{e·y\ 6H¶ª,d\9bÚôÙ`÷,\84o\85ÙÌh\8e¥Ê        ß\9f}\1f&4Ä\8cK\97¹÷ªò\85Ö ÉØé\87/ôrµ\17ØZçPÑ\11^UsƵfp\97D$Ü74Ñù9¼æ¶]Ú\89_¨bѽþ;èh\94O-.qUöÒzAØ\12¢yþÿði;Ò\ 3"\16°x\99¶4ÿ\ 1wÚJ¯ïÃÐ"íq\98Z\91\17´Åw;Îë¹\85\9a?§Õ;\135Ý8\e\0Å\10\10
+ÞN\1em©5\ e\8fW\v\1e\10\86~þúû}\18\ 6\97Ý]\ 2\ eYk\ 6à\8e$>¨QÂÚ¯~C­\rç:5?\99º&¤^?ðª»\83Û¶/Ö\17®\9d\80¥Iê\0ÒÁ\9eÌÑåú`YC\b\18\7feáf5Ã8¶þa\bÝüV>ß\r\9f·"%²E\87ƲZ    \8fða\b¼\ ec%¨5bKÖ\ 3o¨×\e\ eÇ¢\95\85\8a\9aUR\87\92â\8biÞ#»Jtþ\9fÔ_\ 6sJ\94/ Z\ 3\ fp\99\857\\13÷Ü\10\1cÒ\v\87üëym\14Y¼`få\89\90d)\bü Çá5\1dãÃ\áPÐ\fÛü\84Ö^\85ï(l>D2
+¢E¼\7fÒ\r\98°ù\9a`¥¢\bîÏ\96^Y\ 6(ù_ÙÛ\93×\86g}Ó³µ1È\83åbÄ{¹µd«\1em\10/ó»³mN® b/\83     \ eH®¯    \8fºøÀº\ e[\93\87\90à¹Åµ\ 1Pz>aÁí\11°D\8c×á\ 3Mö¸½ \94Örù¹\ 1ßÓ½Ý\r6OÛÜ\1aù\802ø~ÃæµúÆeªäÓ
+\10\96q\ 4T\91vÁ}\ 3\14L?\87\85JuH¡"\80µ\8f,\1dûÕ¸¡Ãäöø\8aeÉÝX\95¶®õA;Âù®_xW     fx«}|ªÄv\9e¦â\1c\ 1\8a\89\8b\9d("¼¤ú_k\8f\84~/»û³÷+É\92À\88£Øаjiþ\9cë7|ÞìzÃدP_Âãu\18\8b\9f\95\9f\8f\7f\98v-9W\96¦ÿì5Ó{v\rd¿À\7\95\88e\8fw]\10\ 1\81»;\8bjru\91ñ\9f\16\v5LB¼\8búì!Þhï\fC$fql\99#~®é\fý­\91¢µ\ eølÃð\94~}Ep$E\ 6Dæ¯äÃSd¡&w$Dii\11ê¢*\11àê\12\ 1÷|¹33ؽ\8bsR¡8,Í-\e{!=aõ\1doßpx\9beD|*¥³oê\8dX,ØJ\17Ü\11\96±\96Âçá¨>{"\13}`9«×ÅÑ÷Ãí\9e]Ë«Ðl\ f);ËJ­;Ôãµ-\92\95\93\87Ç´¥/>\r°øì\7fÀ%\eû\86ÃYJ&´Ï\11»\10µQóaeY
+2a÷¯øÏ?ÿA¿þ\9d\11­3[}UÁ\7f7ç ìÊ\ fD]\12Ö\96¹\86\v¦\vîfê}¼\ f£Z\0BÛH\9fÌô»\16:\17\¼»ï_е\ 6IgÞ·Î\19ªTw# ]\87«>hß\95ɪñ\80>?Hx\87øÁYG\86\0Ã[S-}T\7fCø³B\1c\91\83¹J\ 4÷Âø\8fl%\8c©\91\ 2\ fã\9bµ\8d¹\10¯\18­Ëió\86\17c\97JMÀÊ a$fÝÍ(\9d.¸¿oÔ\94 }\18}9$n\90\ 3\9ciO\1e«Ñ\ 3®z\vØJø\96YyO\ 3Î\89½"Wóì\9c9\90\1fÈu[§Ã\97\9d\99#¾X{\ f8zO\1d\1f\94Zºø\93\1f\96à";fmä,ÑÖ3÷³\95zÁx\83d\87Ý\87ÍUæÃr´\1fhÉ,]Ï\r\87oU3Xb\1f\91âî\1c\1cí«þ\7fö\e\9a\aÒæI\88(,dYBe\19¶Îò\88\rêawa\8d¯TH[6Í\1c¯jFrv\ e\eL;6,.\rê¢v\ 2ÙKúëæûÓjBI(\9c\1dßÕ\9b\9f¬éé\1az\1d¾Z\ 5OÐöbÞU\7f²ßìêêª\8f©Ø9Å\f©%¹ðS\9cû^o\ f¬\10\8dZ/½Mn%ëû\80IoÍï â£\ 4Ao½Å¶F\r\19j}Ä\10Ϲ¼àÜ7\90\96Z>U\92¼Á¨ô,\88Þ}#Àd¯MÃ"\8dIë·Ðä\88ä±HÑ\ 3ÆÝ\8a\9b\9dª¼\99o  \80Ê˽%<O ×ïë0#\akªWò\8azBX!=\ 3|s\82\0Ã\9bÇG\bû4\e{\ 5\83ù\9be5E¸a¦ñ¹\ e[¶¨³_;»\87\ 10\ 65\1eÆe·|µù\9a\É+uy ¯ÔêÆý     m!Ü6øà³2â.)Ë\85Øv\17éÁ\13¢ð\12î\8f\90ʯÃø\1eÆøpX4ôô@Ëú^I\1e|ôp\8a\ 6G\94\88Ùõ\84ä\9aÑ\¾\7fÒrãlöf\1fÛ]W\89â\9b3\4ü\1e\vþÉz\92ÞèsXbí4¨\e\13B¿\8fiW  Ç\f£\9e\ f&]\96Â,w\e\11]T\88\1e¶3±\84âqT\11\84\µZ\15yB\93X34qÁÍ\89æzmm{¸ÚXJÆZÇañÿíwmc<\8f¢VÚ\9e`\8aÏþÛÏ¢{êä\8b;Lå\9eÛ@×[Î'·]x7ï\90Üx\19FI\94MçÁ¹\94\ 6Üß»¾þy¸c\96¸Wë¿u¸ÈÚ\18è5®å9÷\1e\8a#uDñ£ér\8b$Éü®ÞxBT#Ñþ\8a\9b\ 1\96î\89\0ÄGÅ\e°rµ\vî7À\v·×a\85£\93¸¶\ fw\13VÚÄ|Á\937®ïö\1cyébøvWù\v²\95\85\9e\\1cÎêóÙ ¤@ö\9dàîo]hÿw¬\90÷Á\19\ 1Ç\85¬3\92KÅíuÀÏû\1f\87áòãp\r%~@ªýºáâ\19C\[ò±«ÔÞ\90e/B\17Gw\ eÎ\9f³\98:̱jE¡.5\ 1O5jù\1e\1e\95Ø¡h\99\1f8Çv±\17\87ÿH-?\95P=\1f\ 1m\ eùWX=ÿä\rY!\90uØØ×\83¯ðÞp\8c\e\92Ëöz&áÍ}\80y¶)\ 1W\1f\1c¸;\ 2C\98^\87áðâÁÈf\96è\81t¯µ\17\87豫®9ð®Í§bi\92\8d&eù4\f\801ö\µ^óòÃäů¥\96"\905 J\86·µ\16°\8f[K\9b\8fÅÅ%\8b'R\f\18\15\8eP\PÇ Ó\14Ã\r\15æÂ,\92-¥nñ\ 1Ëh\9b\8dd\9dëÕU>9Ì\17¥6\ 1Âl\eD\ 3«Û\1eëå±\ 6\8f­\10fÇâ\ 6\94=4̸m\11\92ç\94%òf~\8b¤åxÁ=\98cE½\ e\93úe\v\8e\16Fï@Fmn³yqqÅ   ;ÄK
+ñÉ\94N\1aZ<=\97\ 1Ï\eØíÐu\18\89\9fË5Ûµ3f­¹©\16¿%f/~Ò °·±q\ 4(\ e\8b\ 1ä1ò\86\ 67~Á\88$\ 6º÷ÕuØ\8a³pÜ \12\85~àã+\1e\9cc\8f³k'E\91\95Rã µ\8evØq\8a\95Ûó(\82\80Âð;³Ó\f\v\1e\8fEM>\87OlsH\Ð\8c|\97o"Ôg¬Ã>8:MÓõß\10\15}Ýp8\926òç¨D\10æäü´²ÛrÁ?ÛçE\82®Ã6õ¼Já\80t¼¡¸ùÞ>ïpìW¹dÌ\88$ÔP{ýÀe\82ö\r\87·\92gÇ\Þí\7ftW]Ëf·\r¼\ fì\7fxn
+m¡`Ù²e_&Û^´¼¥¥\10ØRJ     Ù¥_ì^¤  ¡ÿ¾#Kãs\9ewS6,\9bÁ\8f\8e,K3#ß=k\8c\9a\7fj4»\81'@i[Xï\87ñἶ´=\83ݧã\14òÂG\98Ñ_Å\82ëél2LõðÁ\97íD\12û\96û­\96:\9f\8fB\8bFa\83\18±ç\15ô,§¾\8fT˵¬5Íåto\9aa¹] 31¬1\9dä\8fEk&¸ÛeËD\ 3\7f
+%0âÚyx´s8»\fàÔ;xF­hXÓë°//\83\97´\13%\8cç\ 6͵õ-#$?¹\8f¡s\90\98çí²\8e\0Á,ÔQoà·\Ëzî#O\87'lh~\ e\f\94\15\818¤|\95CÞCR÷\ fý¿~\8a·|$×¹&\12\rºñ\91S$\12±KXè\0«nÁòë\93\v.Pb´Î\1c^¸Â¿òpº\9a\81¥'!\99\99©^û\9a\råï{ãÆG\97.!ª$ï\9e\vn-]®>Á\15VÞMÎÎ8âsþ3)ç\ e\16Ô\9bà\91&\88ÄzuxÐIz×z\13<\81Þ[Ònâváûí2ì\8a[äÃüäK\\8f\84\8f\au¸ë\ 3\1f}<p\9f\8b\0]b¯±zü¡cç\81z±ù|\14|¤#]òL\97ïÛlïûó\10\96y{ ^\85[ɪÊoÉÌ5\ 1\9e\91\9c\7fÜì\97_¿ù\ 2ÿýìËßοýæÓû¯¾ûá?ÿøã7ß\7fÿá»O\89~õáïÿüô\8cÿüëO\9f¾ùøáýcÃ\ fà\ fýÅ\9bòøòÍ\17åñîÇ7_üàÿøµÿ%\8f²ÿ¼û¯ÿßïð¯\7f\ 1ûñ¡\8fß?þò×òx\8f\9f½ûÓ¾K\83\15\9b\ex¯âɽÄpÕ\18,Ý{\vñ\97WøÞî@ /¯âü?ü\16ç\93§õ\aÿËÿÈãß<
+"ÛO°ð\18hñxí­ì\80àí6]á\9c\0×\8a&º}\1f'\9d\1aß\9eï·È\17A[´!@³\9aa\87Æ8\7fþùlC\\1aì3,ϯb\95E\82¿íÕ3i\ 5?vF\a\b­\9fAÞ+Í\ 4@XpÛÓ\80\93möÝã\8eCËË\9a\81+Ä;Ï6å׶\13Ø\aEg~ª\8cìEß~à=Ëd
+>ê`Oбlæõ¯í²\ 1\ 4+Êb-{\19\19¡»\13ÖÁ
+á:/Ä\91±Ý\8b\ 4\10Ï_gË4\9aI\82\1d$<\esÛx;es\9b¿ÁZK\86\9dV\19¡ÎÁÚ;ù]\11ºñÖ\85gmM¾´ibp>=ÏÁýò÷\8a$K\9e]}WÒ±S\a³Ò\13\94¡\99À\18\9e\12\96\8c÷BÜlK\18¾×ÍE\ 2`\8f\ 6Ï\87\97¨:\88£\8d|øZåDv§:²\90â\ 6*"¬ð§\ eJQ\82Kåó»ÁäÅ\18xë´\19÷pÃ8²\1dÚ\18\11Ö©\91=²õ=#\80²Î-Âû\aØ\98X\bMD8]\ 6³\7f\8b\80¢tF°<;\16\ 3è\9c-AìvÙ\91]¡8\11` \e\0ÌÒ\9e \80ºV\82ÛË\ 5\bCcÙè¾Q\9c\b\986>Åä\v\r\89}1bÌ\8c\81¹XÆÔJ\14\1d \16\16ýÈðÆûàÄ\81\159×Làx\ 5É «1åÖö\9d\a(¿Ë      P\19\17°j\1e\1du0,ü\89j&\fr\1a\19Bu²lÞµ\ 1\ e\7f\82¼ñ\Wàñô½\f\8c\91\9d]o\85\v°\ 5-z%¼k\13\f³ä)$\ 3\ 6\ eÊç+OÕÌb\9d\ 6\1e\95QE¯×\14þ\1e®ò¼E\9fÁQ\ 3\ 3àEÍ«\8d¸¯!~ã\15\8c`È|°¼®¨\ 1Z/\ 4·\e\ e\ eµ\1d.\ 2¾\1a_­.\8b\vcïs¥N°&¦\9dT¢þ¼\19\0¸\94¼\84ê9Ü»´×\ 1F%ga¾ô
+0ç4N|oyxI\13V1ÓÂ\b\96ó©yuäò\97\¬B¾$@eÿ×m\9cy2s\10\eó\8a\0DøìcæáÑͨMÃ\12\84\10qTÆ=Â*\95xr\ 6@÷B\8c \f;µ±6Ð×\8c`Èhðv\1dûÌ#ÀäNÒd\80c±ûµ\14½"ô¥|K\ 1­G§\ef^\8f\ e­ .+±ÉF\85K\8dϹ@VÊîXde\8fÀïIô©C½²:-^ÈÁ\8bÕñn×ïÛb\9fö\15¬\ 3pÝÆ'\bÑ|\1d\99ë\96VF\0\1e¼\8aðp=\ 3TÑR\7fæa\83+`)çn\bóå\92ü¢£­\ 4ÁÓ\19aÈUJ\88©\b§°fn8\ÚzÖ&»Kl­Ö¯\b«ð\99û\9aqex)¼b\16ÍÂ\18\ 1lFÎÙ«nF\80\98\80e$rè>O¯+Ù#Ç\8b#3B\87Ö-¹4 0+gàM\bjy\12·\13`T¾\ 6l?IÙ?¸:ÍÊP¦\86áãá\11\ eÄ#Ûekn\99\r\99õÙ\13Ø8Þú2Q\0\ 5\7fgóÚUß\11;`¤ì;^\80VôÐFÖ\17ûä!Éq\r=\ e¯Æ\97ëØDòp\8d%swpXD\8fP\eßØ?\90\11@ªz$O¨±\80Ah\84a\942Fzë\9dZ\ e\11Ø÷ð\91Éq \8e\e³\98\92¥\9c\0-'\ eþ·É¤ê\9e\0\80§õ+³À â»8\12\86)ÀYHõ\98\94q\ 5\98Æ+»h\ 6v)ÿ(\93Y¡Ki·nï\ 3ª-\95\86,Ah?#\f\82õHÓ@¡¯\b·VwB|!®&v³m\ 1ÎJÅÙ\95\f\10F\82Up\1e=\91{\91þê\81pØh\1fàðk\82`¦IËuõ/\ e\86\84m\ ep5!hk?ñô\8ei¬úäåf\1aÙ\80kx\a\a«\fæ\e2\ 4\10¥¦ësº;\11 ·\16\11h\8a\ 1Î\16ª'øn\bâ\9fÚ3\ 5\93\83¸\19é\81ë\8a\11\ 2\b\ 3831´     ÁVó[0\9evE\0}æSLw¼\ eÖ#"r\f\9e³-¡Ö\19\ 1NÎB\86\PÔx8·?¡ktL4\ fÖyl#pü\9e¸KN\82]ù5)\ 4ÁÔ       Jiý\8a°W\98'ã:Û1à\12v5À\8a¥7A7ó\19¡\85ºG¾%sp+9y¸2\80,!Vζ
+|»\8e¸\84»3\aõ°7ê8\12¢-Ê7Íßëq\1fH@k4\ e¤B-\ f\8f\12\86\ 2\9a\87Î\býH)"8£¿\10×fY\87-o\ 1\9aV\1e\9e\8d\9f³Á\b\9b|2òஹ¯\11ËætmSeÍcÛE\84\12ªâ\11ƸRóñ},6\80é
+Äât\8f\9f`eC×\8bN=µäÞÛ%\90\97\f\967Ý;@¼:çÇÊí\122Gç\v\87,x\84Îåmõð|;\82&ï­ËB\ 1ßÜöÜ\92\ 3\ 6}\90\ 5È\18ã\98z  C|"ÌtåþøÜ»\1cn\1c\96­µ\ eºæÙ½\12\ 1\963B7ïêx\9f÷Ñ
+°ÃÖe\81s9\ 1\bÊa
+n\90N\ 4=®x\13í\vñQ\ e¡i\ e\81¹\ 3©¯^Ã\ e\7f£ÀÎ$'òÔ3Zu1\8d9YËýJ     \9a\9eGnã\16Áw\82\18\831\83Ð&*x5ëè    ^S¸{*#̳P!\87|ûåO\90\18×4\80zÆ°ºcË\0ël \1e@óì4ÒCoQôå;\0§sSg\ 4\90\8dÚ
+\9e\ 5XÒõ]Sè p4ë\9cr\8b°¨7Ò\8d\9f«\8d|\86ÝL\13l\8b­Óôp½ã\10}F\8e\89\ 3h½Ýi=À=ÒÙ\róDpÒ\ÔÇ\11®ÄAQÞ¢Ä\8eä`ãIÕY¯\bm\1cÙMé\a8\e¥e{\11\a«K)5¯ñ%\0\83\bY\1e;)Xç\ 4\89dm°\9d8Yå§Î°xàu6\83Ü-\0j\95ůŰ\0´I\82\11\88ñ\15a,¶Ù&\9e\17â( _£çåZèAt¯KN\80[}r(ú)\ f$GØS\9aJ\ 6\90&H¼\ 6Ø'y\ e\84ÇaY\8ai8*Ë\1cÀËJú4\rS\ 1P\85S|SSÇ×¹õ\bR\ 4hÇíH.\9b\0!ÜLl^·p\16gOé\f1ô°ÃòÊè\97qr £­vÌÕÎAÎ\10,æÐ\8b\91Iæ0\82\97\b´~»\85\15\ ebëÊ\84§\92'ÉE~\v«\9c\80vìÙ\82\91}2%Ô\17 \94BIÆÖ\97 l\v_m­+À\16íL!V$\aýòq³\95ó\86­gq\0°1\9e2\80×\17\95·\9b\81ëñ©]®\0ÜÔ\9fÜ\95\8df7\v\ e&½EVc\9b\94T_\80\90»£p±ñ\ 2´É\1cn«ÓÂ2s,ø^\0On\97\9a\9dY\9caÁ"²\12C\96óÖR'ðóÙ\97\ 3OnTÛî\ 5¸É4g\\12ëðã¼Z­WÜ˨R1<\89!vIòÿè®\96,ÛV\148%EAiW7ç?\9eâ\17¸3oUã­\95\87\8d\bDD}i7\ féÒ\17\80\16ʳGªZÏ \99l\95§\8b\14z8?«ÇR\90\8d\r\RWÝÀA\9a¯\8eªûôNm×¢j%]x\fßÛ\ 5.DeJOæà\85Ðd\7fË\17á69h5¥Ñ\1ec\fC\1f$¸L~þÛ\94F\9cr¿3[aM@aßSçPâ¡\96ê\8b0\87þéT\8f\90q'FØáó¼B\9aÿs\13SOtP\87'âŤq\81g`?°»¡\8e M/{oä \8f¥wm\18ûÖ\82P\8d\8dÚ\11îÆ[\98¦¿hTÃ[\12ÆæyxÓò'çÛ\16áSÌ{ϧ)û\83z.Ü^¬Õ;\86\91:Ó×\1a&¸       \ 5æ\12!\ 1óÁ\86\107/     \9a\ 5êê3À«\ 3Bsìõ"\én¿&õ\7f\12÷ImÝ\1e}\19 \1dmOcÊ#ÁM0½±ãÿ\83\b\8f\80£\81:2OÈ4\83\11äé97V\ 1Ùv\83\9cÓq\11\97\92¹ë÷\13\99\85M\8c]âò5Î\11á;\ 3Ò1p\8cÖX>\18\ 1      ýÒx     >ç\12\7foótþ\94wåû%\1fk\95k\99\ 5\1c]\81Û\95Y\1f\1dÃÈÁ@ê\99·]\11àþØ\0Ù§ßݼÚDÍC+8h\14Ë\·Ð9g\81z±{m\ 1     "\18\9b\82\9e¬\11qT.v\19÷Ï\ fVÙ´7¬_\ei.Ü,Lj\81² 1ç)\8c\1eµÄG÷¨üs\94ù\0\1cmyd\95n\r|\13vËÙUÂóQß\1f\906üQ˪ÀçÂH\9a\80]8L¸®±³\16¸\ 6\1eá¸$ï\bÔ<ºÃk\ 6\18´þæ,A3\92íLî'\87K\18¾øÜ\ fðO\83¸\1a\18\9a\9fzà,»\83X8\8ay0f; \e\9b¢Îù¦øúlÔ\0CåW§7Ö&/(¨\ 3°`\ 5Hpn\80o¹(çD맾G»÷m¥·\98\b\ 1n\f\8d«a&|¥c\ 5\17vO¨\8b¯\a\ 3çøt©¹      )Ðn\ 3
+s\r\97\11\f×\16¨Z¯9Í\9blо\9e\,\ 6~nk¤\82\b\86·\13:îóòjs\99æÃ+\87éÌÃZ\vÿ\91\9df'M;#òîqó\b\ 2\13\11Ò"A3Vü\19\8d\8a°\ 4.Mä¾\b[z`Cú\ 6È\f=ph"Â\11\96Ï-:ÂS´öGGPÆ\10      0Y`r\1dýD\8e·*ïZî´¨ùµ07\ 1â\12^\eíKlÛ\10°\v)\18ó0ìö%\fls#pB\81\7fFys?ѶJü\9dZ¿1#·èåJx\8eSD3ï'7\13T»po°\8el\92\98\12ÏEçqkK\ 6§×¯å\963Y³§í\7fýÚR]·~\7f]\1dáÜ\0«y~ý{+4\94³\ e\1cfî%\17î3@Ó¨è¦Ó\8b\87myô\ 3I÷i·\9e}\8b\9e\ eÕÏ\1d´'vV\8f\8d\86æ\95\1aÇÀµ\90ì\87.#\ 5t\1e\88Á\ f\9b\15¨\91\b+\16à[\ eúDÎt[\v¶9Ò\11Ð\8d\80~n¢\rX\9b+þßïÍìÕÇ®.\80§x\8d~=\84ùTÊÍM%Ò\rtr\83îVt\9dÓ`&f\ 2ÆÔ\ 6"\885\ 6,©.Âçn{\95Ð(\15áSdz^\84é\e³Þ\9dqXÎhár´@S3\95üï\16Ò:Éð!\e\11>ó¾p\v^\10é1h\1dá,è$öÉwð¸=¨°&¹.À\8bÆ;p©\81ÏÝ{È:\15\83fl\§{*\f\81ëÅK0\9a³\1a\17\97\ f\1aJD\91\99J=¦ûÎ\82\8d¬Õ¿¿\9f\90ñÿö\1dô¢ð¡\ 2©¥y<b\7f\õta\87üú¸3øDò\10\f~îíµ÷{\7fEE\ 6Ó\a9\ fïjPK\8bfE ÏÃ8ßï:\1c\9bâ\a8Ô½\ 5\ 1y]ë\83tU\ 6ξ\9bôçènz\91¥\1c®\1dVY8¼\ f\7f>\97à\99)\81\r4\11ð"ܱ        \91\1f±\9aÄØZ\1cÚ[Û\ e_PÒ­Q5{J\90ìñz\1dXEÀ\1dÒ:ËÎ\ f"\8cö¨nrA\83>/\95ä\81\9b\14\85¹\ 3«ïc\10¶ÛÁ\ 4÷Á\9d'!3\93\1ax\8eÇ\95æqiT-Ã\95%(³i\91\a²
+A\90\ 1lª_\ 4.çà\8bè{µçjBbàsë\8f*\9cnN1ÂÎí\19\98ÆW×-\8d¢\e¸.Þ~ìÜ"qrÕsÎo\0\12Ü-X/Áð]5j©õ<êBuc¨;\ 2Ú¯l_\85UÅ×&!/®eñ«Û=BwÎ\1cÄuø©îë;ÂAã,F\8b\88¶$³Ã·ÇÛ7Z\96×\8e\8f\96Çö\1f\8fo4\ fä\9eǾT#Þ)Û¿³Hñûh\ eòÃ'÷ÎÈ^MÐÔBé\86\10\9f     \86-\rðÓí\1eù
+x\81."Ü  \91#µÒÉÕ6ßÏsV\ 4g\83î`<\1d}\14\91\9e\3\ 6ò ýOóØ\9cºC)q\99¼o p/\bïð\ 4\17#Y½w½\bx9ïß±ñ5æj©½&RP\13\1fx{ý\ 6Àî\1a\92¤@&\9b\ f^\19\ 3o'ï\10\81H9óE¸þ²y·»ñ5\19 «È°òÚð/¦Ïö'\87Ö\13Ñ÷uxB\9bNI\ 3âß\9a\10J\ 1V\ 4s\ 4\ 3cLÅå\ 6\12£èTîÕÁ\89®Þ\9fn0|´à«µì5[RàN-í\9fò]\ìFú\ 2\98A\84\13ó\89.ð@\14­Ü¾ä\86 \97¡eø\ 2\18\13w3(î°6\18.´?@Á\92£%/\82Ì\rUEÚÓf¶D¨ût~pUjc\81ä®ÖÑ-©=Èäø@\8f\84F¯ï¹}\18\98\8bkýÿ\ 3Ü428§ü\99GVÆj/UCî®P\9fÃ/nK°bzO\81ô+sêûwcCyE^^\ 4!irMê0ñÀ§4¥\96\87ÕvK¼>7³òá0¶º\7f\ e«~RªKrK\ 1\ 5·ÝÂv\ 4=p\15\84í7h*\fÅþ\8c\8f\89×n\aÓãm<\8b¸\r[ÚÃê]\98 \1c\14v¸èí\02\9b\99öÌ=b¢WTÿ0\93Éæ¶KçilÃÃÒýf\0v\81\82Ýp\14u|\83ÂÆ1/ÂÐ\8d\92\8ef\14P\86ùÀÞ\90ôô­\97\87\aÖ\80îÕ5ËE2Z¥;xµ\98â»\9f,·+Å\14<\95q\8b\92Ó£ý\8e\81àò\91\9a·o\ 1åh+}v\0&\ 2VÍ`àÞúïzr#¶ê\12Æax·;Ð¥ä\9c\99ïó¤Ö>m5üÝ\18Îfq*b\aÛ\9fÁ\7f\90û00ñxDa\1efb\80¦K³\ 4ubñvG\9b#`lé/Û\9d\ f\97\87\8fJðî\85\14vQÍù\90Ò>o?\1dË\ 1\9f3\15ÁuØ>\fU³«6\96Ã\9eØ,$û\13á^à£ó]\82\0Ü),\ 5Q\1c\91O
+a³\8aG÷F¾Wÿ¬y»ØYßuþ2à\89æ]E\8dǺ°éçtÔ3W\89\11\95Ùu¼&\10\9aؼßêð\80\85c'k&
\bkp÷cQãó\eó1\85)÷        Ñ\1aΤ"\98ö^
+¡D)<ìÏqõþÖ_\ 6n\81i\9c­÷b@\84q¹Üæ1w\98   y\ 1Î>5iì2½#\18Û1ð\pþ§`,Ã\10ÖÉ\9a\1e\8bõ4ýz\9asäÚJúñû·\ 2;7}j\9a\94:\9c\1a%\15l?ÐéÌìè9X$Fé\1d\16\1eÍet\16Ø\9b£º×®\\8f\19\1d\83«Å£tàs¨¯¼pø2vÙ.\ 5\17\e{T%\17·Rò¦=¸ZlV\a]\ 4ì*Ú\1e\15Á\98úìºÄ\9eÍ
\f&>\17  ÿ\0?\eog\128\83\98Ö!Åê,[j`覿[Òq×\9au\91Ûϱº1½\9c­>\1c7½_w\94Ô¹\ 6ÚPÖa¢Ã\ 5Ú;÷\ 5»\8b\r_I\ 3ÖÏ&å×\8b\1c\e.pë±YA\98n¥=kp=ç\896\8eµú"ÓÄÅ7UEuáý÷\9d(³9\80\ 2IÎ'\0ö¸á{Ñ?å$\ 5f\92­ª¶\ eÍ\17`*\1akÔ®ô\14\9f\81\87\91×åXuQ\ 5ý¼´.Fun_¸\18ÊÀc(@\99}\92Ï'Â\8c.ôÃ\8bqãÃç\16è½\9f i+\84}ìm¸¤\91ðÈÔ     o_Z     º\9eA¿\9eÊA\9f\8er\9c\81\7f>Gæ·\124ï§53:ðêß\1cÜ\95¬ê\9eؼ     .\1a\15Á\84\aö\8c\14âb¶\7f\1eÔú\9a,A{ÈzÞ\91\86Å×ƤjÝé\ e¢\ 3Ð\95ú~Ѽc\829\ e\ fY{k­\ 2\17µ\80ñ¼hÕ«\83¥}Jwp\80§5ÞúäQ%\10Ó\9a/\ 2\9b\8dø<ð\ fp\12\11t\ 3¡\f\ fD\9fû£\10£^\1fq¥ jÿ"Èìúö:ÿ\80¤è<ùh#ÃÏE\8b\bcm8ù-Ü¥M¬³/M¼1C\0Ì\$\9e\9b?AK\9eW\8d\93ËËEWZ\ 6Ï|\16ϲ-·\85KÈý¸\0Ö¹þKw¹µØu\1cQø]0ÿá¼\18\92@ «ïýh+yH\98\90\10p\10\84`\8c¤\\99yplLþ}V]Vï\9e3#\fBúܧvuu]V\1d\86\7fí+\8bl\v=q³E\9eO:[·ÜÈ®HÜ\85¼8Klãemn˨¬\92X\86\94Û¨,Õ`\ e[k\97å«\f{\ e)\94\8f\18sDeÝùz£Ã»?dñ*ñÃËë"ëäO\91í¥\ 6L\14'\80&òÂ\ 2úÿ¬\9d\87
+<\ f¿ÈDI\15+OA\0\ 6[D\ eÍ\ e\98Û:\83é\96\95ï/Ú´q\88±^\99VÕn'øB+á\83i\8e° r\88o\9a§·pÀ\96G<h\89¢\ 1\14é¼\1d\92\81\16 \0¥¯\83;D\15FÐd\96\1e\10ÿ\9bA\13Ù\16\1a\ 5
+â0C´\v\16ÆÚ:\83éÝO0\9cFÉq\12\95K\v\85z×|@\eò\b\v¦xÔ\ 1®\14\v\85 O4>(º±}.Y7]~ÒV¥°¬\ 3d\84\eY+É-§Å}VïR¼Ù\0\96Y#n)R\ 5°v    Ë\13[MX\ 6\97æñÄÛ\14×Ziî\14\9a[\1a\ 2"(3NêF\11\16ð"\8b\9dÜÆhÀÜ"\98\ 3\rÚ ÞH\95\83ëç\83gW3\16ùYãpèB\85ÙgrÂ^\94Mc[×Ú\8d\r¼õI\9e\85¹\rÞ\81Â\88ø2hpòʱU¨å\95£-Ù\87·åì*P-,ïý©\1d¥$QÎ\80+Ùr¥A+\85\ 2\15\1cÊ(|\8b}4Uô\9d\19V¡"=ÀPSyD\9a\f-\820\0>f<]oÞâ\ 1Gv\17\0]z\83õ\9e"\8e(3¹\f\81V|\7fHhU.o,!\p\0ÆR¡'U²\84\85ÌÝF¿\16\8bcR%»Úk\v©2ÏT\99\86\ 5\bçÁ\1a\18½öÛ\17Íâdá["5·\ 5\14Lmá0\87\ 1 ç\ e³d`Q\81à\98óH>µ\0>´©Ñrò³xßÎKø\86\bX1wX\14[]\18_\18)q\18ãÏÒÌ8\16´F×Tþ\ 1\16½\7ft¤¤Ùé°Ö^èBß®©8î|¢¥ÝÀ`r\11¬P\971\87\82]".Ç5\13<ï1\8e\94\1aÍ-dí\eÂTGÍ*\84ô©eçSÞ\16À\17\8b¥«ÌuØUÄ8T!\10p\8cÁBnrY\90²"\ 1WNË\ eëÞQåÈTciµ]Üi»\0ÉÔXC\13E\14\87!f\b\85£ª\96äËBjTZ¢\9b\fàD\9blLÊ6\96\ 4´±äï£ã×-L\95\98só¶âp«WZû\v«\85Ì\9c\9e\94\80àH\82A\15`½Dáð\8fxÌÜ\83v¸Õ9ËÀëÑ\bæÌ3\ e÷EÝTL\87ÛÉÕ©Ø\93>궰\12¹Øðu\88\82epk!\fy¯Ó_\ e\v=/\1eÎ\112äù\10\ eúH'@¾\ 4ê®î\97\0/­ó\85tþ9\94ZCÞ¤±ÍÊÕ\90µ\87\86\ 5\9d³²\a\99ç?àµb\14\95k\ e1É8yµ\8a·\ 5\1dºÂ\vv¢ùén\11\13§z0åX lM0Vû`      ^\9d`h\1e±Vê²\1c\19xÎÅ<ÍÙót`+\e\veÇßë"Ñ£cØr\ 1ØU/·8\9b\8a'I¯G\92\95´¯Ö\v\82Ê\112 1n\ 1\13#ÙWª\ 1\ 5_\8c;hCÙ\16\8d=ÇÓLá\91\93\93\16rê»      ì(¨åÎ$)Õ\1f¨C-/¦\99ï\13\ esa\87Ì\8dIÒÑs\ 6%AÑ]G!:\86\b\ 3¹¼\ 2\9bn2e\10îTok\vcµì\19¥p®~*.·0w\8f\1dÛ\að2¨U\8a
+\94ÇÍkâ\ec\9dÚ8'>HM+\87m´Aº\\a½\90U\ 3n%\ eÞ½xÀGè\1d@\9dþ\95Ã[3E!\1aê`,\91Èì\10-i\vçÓ\8dl\85\8e*\ 5l­^\9d\9a\16
+úcX¨\1dj\8f\97\9e\87ÚT³SDwOëª54ζ\11\160²¶â\1e"~\18¥ÜY\9d+\8d|ûËû¿ûú\8a>±w ]ð\9e\88er¹2\89 \10y\W4\1aëJq²ØÔ)Z=[¢)ï6¢À±GÖ8\9c\9c\e.¼§sx\88åò¸\88wקÍ}aQ^]ºë«¹\96)âª:`ÛpNÊcµ\90í*à-6¿IÝ\ 3fZ4`·Ö¨\a[\19\87\81ÙâpóÕHÙ\1a\9d\1e\14zpw\87ëz\9d\e\88\9e_\90IO\9b\8fÞî\1cé\90\96)<\1e-\8c#_²mh
+ÇÞ\9a^[~Ü\1f­;"\90\18øQìT9\ fçÐê¾÷VUj% ~\17\10\16;aÚ1­\94\82ʵúãss\84Yéíö¦\vï\ fïb³Ó\võ|x\17\82Çn?é]k+ 6\86\11\10\ 3=\82\87ö9.ï .ã\1dôYx¿9è\89
+¿7}¸ÜÓ$ZqE\e\15O\9b\8b\84\1d\94­Û\11\1d¼qõ¤©ãPº©~\vsã>¢\87[ja!ù¾\965µl\80\ 2Ö\94êíM\1f¶{²8Öôî½±\9a\95c_
+n*Ôarh\82\84þ¥\ 1Ù\9b.
+³'^E\87\15\ f7º\üÒjµHX\95:ëeáεÈH\93Ã5ÏÈlk\86\98\7f%\92X\13æqs_+õ|BÁ=~ÁÎþÄL¨\87Á\9fh\97x"\8fY\0n©ì0×*ì\rs\12âá\ 2\96­\8dÕr§\85F]
\9dåW4 oúð\9eî\rL\99\a½Ò4þÓæËo\9a|\8a<n>e:/úËÇ/Øñ\b|ûð\7f7¿ûíó§o~øé¿ÿüÓ÷?þøù\87ç ß|þÇ¿\9e_ò_|ûüüýÓçO7Ã7ð[ûåCº}ýð.Ý>üüðî'ý\8bÜ\92ý÷á\7fú¯ßãoÿ\ 6ûùVo\7f¸ýõoéö  ¿øðg\9f\ 6\91&õJʤÃyÉÁ\1fïxê\10\82\9b\897Ðñkxþ+x&·ß¨C\7fÄ\1fè\1a7\8c\9f\8a?P2éö\1f~\ 2-Â&\ e\1aåLër)\1e\19¼jc\r\7f\86\ 5\e­<\8bÏ\15@dd\ f8j½}¤\85\99fðRJ\9c]âÓwpT$\95B=Î\8d\ûõûÞyÖ·*\83²JhvSõáV§Ø¨©²\v\e\97\93¿8\t\19¼.v@Ôïö!\8dT^v\vu¬®È^4\1do\17È>\17t|\84(v(PIõÕÓ\8a\19\8f\86\11w\v¶ØÎòp\9d\0X"Á}j|äïû.×\11\81\0Ä\80áØ\96ecGª¶órÀ°p©\95\17\87\bĨ+\98ug\ fB\9b×ï¯\9e.1\9a\ 1kLákt\ 2ö"'Ü\16fïùî°J¼\14\81Ī°î øê\19\16N^L¨:Ì[$B\9e\ 6äB\15p[0ù}\7fx$.Z\82-"à,6Øl¯+û%:Ö\90Ü¢\ 3¥åO9)·5\8e\12C\1aå'ãu\8edø0ï\v8$ÍÈ\9cU2·°j¡%\17\84v(3¼\15%êZ,A\1c\99ÉK\v¦\9a½\10L!ðÙ\995F\85ÈÁjó\850\fèfÆ.°\ f#G\96É88\13:æ`ÓåÉÇ-}\83#húpn\95\12\ 1£d\85\ 3½¹`2\14¿Ö|Ë/\ fb´DM£oØêu\a+æàõû\8bï¯#Û;7ÛeëÑ\1dÄ\1f\97\81\v\979\19A{þ{híè\82û    Öän»\ f'4:.¶ØóÖ\1d\f\85àºUDÃ2\19@i\97\93d\ 61³1\19ܯ¸fYw\87ÃbJ®\9f÷²¶Æö½ùÃ'-\1c·?\8bµ\17d,\95§\96n¯ý\80\8b©\9có0¦P³nx\9aŵÜm\1d5Ü!\8d£4\82£\98\4ª~K+`÷\1e©Y_K9 û\90u\84¤þê°\89\16\9fxªÚî!f\¹,\907ÏP/·*Þ\1e4\9e\89«\0\9aà  Ã\ 2\82&¦fÏÃ\88ðtÏÙçìK\88\86¹;ý\81Çî³øY\11\8f\r\1aB\1dî\17FEjã\80\1f©÷³VÊËÃ\r\97h1^mL¾\84\r\ eäÅá\9aä\12\9d¦CV\17|X©\9c0,\14\7fÂûÃ\16k\83Ø3$®¶z\ f8*jñý\ edÏñ\14i
+\ f\8f\f\99Á\89]\81p?Eõ~z\1eÖ}©\ady\1dPc·\93úàx\80ÿ\ f\0·8*:\r
+endstream\rendobj\r13 0 obj\r<</Length 9158/Filter[/FlateDecode]>>stream\r
+H\89t\97]«^Ç\r\85ï\rþ\ fïM¡\rt3\1ai>t\99\9cö¢Å¥¥\10H(¥\ 4ÛýľH\13\87þû®\19I³gï×!Á\1c\99=3\92ÖÒ4~üº§Ì\87\8fÎ9\1fT\85&\94C²ìðíëW\83×\83\v\97[p?ª\96\19,\a·¦7Xñ\ 1áXaqNG&²àr´Â2 \1dã_\aË`\9dOf¿OzÔT¯¡Ô\ fIÚlMª)_aÖ£Km±ÀÎ+åy   cÕ¢Ù UÕ\eì\87VlõÜÂâ5\8b\7fMK¥ÁÚѪT\879׺A_ \1eµò=¸à\ev]E. \1c\9d¨Äï\9e´¶Þ\1e\1c\12\18\10\97é\90Tx\83ëÛ\92\98oÁíÈ5g\83­Kv(b\19t¸.0im·`=2\938ÌZ\1c\v£"ÙQ\ 3é(½Ì`F5\88Õ!RG¶ad¾i@V\15\83)7ÞVà27L¸Ëy\røI¹ÍÚL\87\10\92É`\1eûz±\ 5À[nÎ\v\18ÎëÖ\f[\83\942³8ÎÃ\96-\1ch\1e\1d\10\99×F±.x\9bU\8bàT©Dp\131HÙ\eä\ 2µÇõ\9e|\1c\9eü\1eP\ 3ÊÕÎ\9b\93÷]=z·Îuè+´£7)·`=
\rÏ;-å
+\91lÍ«Â7\8e\1cm\9eZ\9dP\8e^{\8e\80¥ 4_B(j\9fÉ Fe°ø)ªÌl\12\9d{`hÆ\ 5®\14k\9aå·\a'Ô^k¶lâJ7(·"     ^\ e4Nõ`íSjF\87°\84ÖÐh\85\13¾=Ëá3ÁÙS< \ 5ä\ 2Ù0\98\13\9du\96¥\91Ý°t\13\vÀ$Ú-õ9­J=!\94\90PàÉ\137#¼YZÔéÔÃO!Mø\90\8b¦îm(ª.Úµö\10·¬¦äH\0W=»[©\17ëÙR¹\84\96\8eÂ\9fÁ¹ôþ\ 4gU\9f\ 2{r\b\8e\a\17V²=H¡ü\ 4YÊ&ÑÁ\91úQâ&GJâ-\90\1a±ÃÚSÞ ¯Ð\ eêOÁ0"75:¤&}\82:\12´tRO\a\f\9b\0,ö9\14\81ø)\0\9b©<N¡]<qc\ fÈ£ÝÃì\9cë\86ýÚï°÷ÜÏS\ 4\87~²«};R\11\87}\88£í!«ö\rú\1eð·\14\8df¥Ñ0wvk\9e×û)\82ÃGÚê¸-\18ý_¼¢\86Ï\9bªv\14\Zæ\82í·ææL%ÙÞFnS¿:6ÁÓôÙÜ\13Ôdî`\v\85\qñ5\93\14½At\ 2ó¶\80sH\98t\93\1d|,)±í\16¢_\1czc\ 2\8aòr7\94FîÍx\b\17\8e\90S-v3¹Rs(¹e\83©iÈ/8®©;§\14Á1eÕÃ\f`*XwË\97¶¬\89FaXgÂØ£\87\ 1%<^\93f\87ÚÃtKî«úѹR\9c\93z\1a\ 4MZ½±g\91}»rÆf±bòl°õNV\91*\8d\9f ä3k'Ç\95t\ fÎH%{göÊ\ 1!\1eºÁueHly
+F*\1dª\9cÅä0[c¿¬\15zé¡q>Àíp\9aê§çà\9e\eyp5­Ç= \ 2\16¬qióÈççJ!WÉÄñ¹TÙ\83SªQé\18\93]\rç¸ù\12\95\1aó1T\92L\1d\12|·6÷þ¦¦\ e'\84.BFB%7^p\1e\8aZ\17\9d\e\9b   (ù\11*`vîpé\v[»íÁ°\90JÝÜ´=1To*tNÂÁ±T)1õ%\94³»[\98Åù)\87Kf\e§r\vF?Ô9¢Çpu\87\8d+o\ 3íâ¥H\8cÄ¥Åx6\9dÅ¿Õ³CÚR1ÚÔ\ 6¼19\85Ê\12ÆX÷íð\8a\1dÎ\19øt\eçõ,_Ø\ 2O#EzP¨ê3½O¾\ 1WÇJ\9d\acðlÓ\ 6Dz\î°]ryò\ em-ÑóØ\82O¹Rj\d¯S\8f\ 3\9eÉt¯8\83Ç°\b\9dô\8bĬr\838¤æ|\ e\ÁÑèìy+ñØAmªºg¢bËôç\80ëuCÕ.m\v\16\fÓ¨KÌ\ 2ÍWкŠ\98ÅâU\85¾Ì\ 6Ekl)u]£%ÅÐ:²\93Ú\9cì`Dá\96HH\9dÕ\81\86\83»Ë\13Ì¥ösÿÁñ4Ädü¸,\9bP\96ÙÞ\ 4Ã\10\e\þ3ÿv\r\1e\17;Å45Ó¿+DCÐæ\80Nñìí\14"Ä:ýzÈ\ eQèë|v\9cp\89qks\a{0D\8a«\asIõ       Né[µè|¿²\1dB·úUt\ 3®=àíô\1cì\e\ 6\9c¯,\17]\95\1d®{\9cÏÐk0LßÆ\ 3@xo»AÏÙZ!øè4\7fçb\12ȳpG&²\86Kh"ÙàªG\7f\14ìÁbi\99\9fcq½:!\1e\83­m\15í\1c7\ÂRÆ`®\ e\97\13ÌÞ#\7f«\1e\8aðÔ&(D6s\1e\97:\1e\rþj³\11\ 30\15S\90bÒõ\12>ã|¼)\86×½        îV3,WZ\14%\15îawn\1fè&\7f\95\8cÁ\11Þpº(Û
+xß\12Gcà#bãOÌس\8eÊ\1aYÓÔÍ¿¿~\95\1e¿1å\19ch\r¹FÛ<>Üù9½ÎA¶\869øg1«a\ 4Ó\rº¦a\ 6§y k°øÛ\14C¢¯:L\80̦ãé6, \15ÛU«þ\0E[\93:¬dz\ 6H¥ð\ 6ßÆ
+sº}
+Ne­`O\931+6Z+àxk\ f>ÏÚáypUñ'ìt\b\83\98ùGÂ×)\1a´ÜV.kJØ.¶ÚdúÙ,X\96Æ?\8d¢´\9aÅ\v\12#D$hç\84\17×àRòyeÎ8\ 3\14Þ¡_Q\89\8aÛ\83a:b¦\832´>\1f5\96Ì\9d\86ÛrT!j\12\ 2âÍ >m\8c\19Ð\9a\7fLAä\e¨þ!ø\a¯Ñsl,ÙnÑ­Ö`\83Q\8b\9f\1c\17X\97Î\ðü¨ÁÒm¸Ã?Û¸?^\8c)ù]ÕÞ¢AÇuUòØÒóã~¯\82ü=Á\99\843?°Ûl\15­ö\[ù\81\ay\ 1RNq\13Úb´\91lÃQ\1eÖg\96îpå§)?\aã\ 5B\ 1iÁ1<9äU\80Hf\8f\8eI=îr\8e\a6"\8a\1fúé\10/ó|_|ýú\15þÿÅ\97¿ë\7fûíÇw_}ÿã\7fÿù§ï~øáý÷\1f\9d~õþ\1fÿúxå¿üúãÇï>¼\7f÷\98ø\ 1þh¿z\9d\1e_\ eÕùæ§×¯~\1c?Ð#Íÿ¾ùßøÛïñÓ¿Á~zÈã\ f\8f¿ü5=Þá7¾ù3\8e\81{Ç£ Ï§\vC÷j±+Þùt|H\9fé+ÿ\f\8aß~ó3«\82cû_Ìíý\11\7f Ô\1e°gÁ\1fÊØà\7fì÷\90NmQ\vCù>\ 4çbéBCÂP\8c¡ó¼\9bR¥;Dýu¶~¼ñ\82\19g\ 6\8f\95èhRX\8fm½å\9c7ø6\8e$õ3Á8¡û\e~zbIÝ5/\1c#c\87úùª.*\18\rR°)t×Aròî\9d\ 6>\84Ù r,PQ\95OPƲk\85\93³ø-\88½B'$,\11\87èìnÞ\ 5\12+À­Å]~t\96Aj\11lsÑ^\ 2Ãì\9bKÿ¥°0À\8c©q\95LíS\1cÁç;È2Ô\92\r60\87\f\8f\1e\10Õ'¢\e\9v¯Û\83Çã)êXÕS\84\97\16fmû\16\ 2\ 6ßı\8d\bf\8d\rÛ£kBL(¼Á·±\ 2®û9¸s\93§e{×\98ÙRY9Òa\99Ý7ìU­Q%ãd\91yLÒMe\83\80"\a\1a¬Ð`\1f0¹êFÆ\8c¬©Çï.\88\16h\1eÆZ\ 2\8e:1\98É\9e\96\ eý×ó\92à-8\ fÓð`\18±:ÄÄJ1\8c·È\80B,»¶\87?\14¬Bq¢n{\18S_\eÆgÇLsÙ\80ëø¹ês0d*_\97Å\ 5V\13\9b\80+\ 3qÛ[ð\9a"0 wåê\103\9b?¬ð2Û*±çÌÆË\1co&Lµz\15`KÝkY¨\94\rú
\86Úkð\12\ 6,\9b\95õ\ 6ñèë\92Ï^?y\1fõe˲ªÜ\ 4`Uý\10¦Q\1e«\96Eõ.XXÌ\95\98Ì\18íz©Ö=råB¼\1e(j\19\99OTɵI\1a;äµ*ã¹sÖcT\1fÙÌi\10¿Vop\98\eô\15p\91P\9f§àêOÄ\9f\81s&]+l<Ù­\ f\98ÔupÚ»\7fËgÒd\ 5ð\12+̹fraSy\1dãZ\8d\ epQ¸@D\97s\ fÁÿÏw\99ÜhvëP8\15'`CÔ¬uo;\81·î\1c^ü>\9c$J·àE\ 1\85\ füy%\8aÃá@\81d-,hÜ\95\9eæ¸ÆÞúBsÄÜàmg^Íñ\82¼õ©"½`\9bD_\ fØ\ 6\8f\87:\96W¼vþ\85\91Ù\1dà-÷z\9b"õª\97Ú\ eB\84mõq\1c\1c^<õpð¡AÀ©¦Å\96«.[\17!\1e\8aÛ\83,trµµ¬7à_\1a\ 6'çÞ\v\aWÇöpx\1d£=\9fã#\16÷@\9a!\ eÍ\ 3w{Ñ\17Ñ\98GÚ°ØBæ×\ f\94±j\1e6gÍÐæôW[Ã\95H\9b¢×\13g·&¤A{JT\1eͯq\1fc(Ì\90u\ 6çôäÇS¸úM\18ù¹yЪ.pø\17{Yq\81\ 3Þ°:ÂÅì÷\ fý}(µÀÿ\13æ\bÿ\1c\ få'ã\9fáúùd\17׳áþ­®é\7*¬\ 4ÔGóD+²\ 5Ð\11±\163=\e¯\9f©\97\80ÝZçy
\85Zù¼\e/\10\10\a·1\96¡Y\97w¸ÙÚ\rc#¹¸åµÂF©Ä¹"kËL²\f9üã;\19\ 6Ö|\8c!\ 6©ÔX\16\ fì|0ó\10ùðßO«b.°å'ð/¡(ZÚ\9b\17F\84U±U·ÂJþ\122\ 6_X\97Õàñ¥ÚçL«Ê*!ÁömР=ÂdU5\1fcTût\8f³\8dú\81tzqà>ÜãÛr~±^Ö\83ZM:´\v\14Ì$*\8f1&~\1f¦\19fn/4Ýb\1e\ e\ f!ÀþÚE}áj%s\7fÔoMMFH.Þ\97ö\19Ú\98=L;\83»ÉO\96\1a/\\8dÂ-\9c\96ä\1e\91/cXá\80Ú{f³Ü¢ Ú\8f\ 1ªNi\97;਽\ah\1e8_\eÝÆ\ 5[Yqåó\85\9cL½{Y\a\8e9\90\85cV-\9fÑ\17å\85KÆcÏ\12 9ÈÿPõ\99²\8d   Yìå·ª¶\9b»X³¹\96Ûñ\0ýU³Uû°Î\9214r\8að\7fzc>}\9d\1fã¢}\9eaF \f¶e9Ò3\94À/÷\90\ 3ãYª\19S#K´â/Ï\13µç\0wÔËò+oã\ 1¹±ì`$\8b\8bÀ\9a\86\8b\81Úv\eâÅm\8b÷¢¹Î\eÞV\13\9eÓ\9dWH
\1ct\9f\81·1v
+z½\1eV\Ü^\9c5H±ûz  w¿\0\82uVX_ÓôyÐ\80oc<d¢l\8bÞÒÖÂ\8f»ª­\9a{Q\14\9e5£÷V)°\8c½jÊþ)°\15Õ'aY\15Þçj\1fcϱËí\1a®?ÑÈ\8ae\ 2g©Ýw-\rWa¥\9f/U*)ÞÊ\8cÐN\0}\7fvX7®\9c\12ÖÇ\88´±\14;æD\ eøÇMb\8aæþíµ\88e6[¯*s\98?\9bd\80£628R2ËÉÒ÷×SÍ<MÓôÒ/¨\ 4\85\19çüÀ²j;ýàðÆcË\ eVj\ f\9aà\86X\8aÖ\18ÇÃáxÍ}\86©W\v°`\92¬\16à\8ekÚRc\e£ÏhÆ1Ìv\v^ÇF\ fð\8f¿ìhý5&~¤ª\90çØ\a.Þn¶\aç8Mi\9e\1dC[\a õfÌ5f\81¢Ø%^X«Táõ\9fÔ\87\87\ 1\93\8bm\8b´Qi& ]y3
\81±\91*ºäN\8eªª*ó#«HA¤Ä\v 6Èn!©EöK\94x¦6OÅV¤6s(\9f¡ÕÉmoL\83²
\10m$\8d~<\18çÒ«ä]¶¯%\10\11kÃã\84\ f\83:\8b(çh\8c@åjÆ\ 4aðÀÄ\eÇ\bQU\9ey»Z~e\98u\85\99¼\8euL(:ßï4\1fÃZ\8b!\11f
+\8b6~\87»å¬ü1\8e\10+ÇÃ0ÿ2­¯\ 3Ì\9eÒ=/mXò`\19ý¯û¤Êöõ1ºÛm
+uQ\9a}ßUü\81ÜhG\ f¥å\9cX\84ùh·þÆÉÃa³7,r\ 2\87{ø¡Ý\8fÛ8\8b\98ná¹.\98y*¯v<\1cn\ 1;^ñ\1f\91©?ÄnH\97ãáºÊ<\13<UQ\7f<_çôIEI\93`¨¬úÀ4c*oÎýÞ¦ý"ÒÂY«ù¹LÏ9|%@4æàÖª°¢\9c\1fH\97\87ÃQM\9a  ¨l¨9i\aS\a\83       B­0\87ï\b\ eÆ\b\7f\9dd^iÐz W\18ÑÉFç\99å\8f+¡¶4÷ÑÏFj\7f]:ÓáÖ1¤*-\1a\88ì6¿\f\99½R?2äpßKá5éÆ\9bÏ\14;\92IÖ-\1f£\92\ 1Í°ÏÌ£Å\0k±N\15a®A\8a\19Æ\ e³æ>\ 1\12±+\94Ô5-fÝÿÎçæ²'\1a\8bù\14Z\80\195\9föS\1e\8e\ 1Á\1dòú\1cþ\93W3=¦\83Íán\f­×u\eóÈXÙ\9e²¥¶\1e\880ä½R\1d\8eQ\ 45ä½%5\8dCCø\9bOâÔ5b\ 6ÏÈT\r\1d\8dñ¬CÇ`ß;Î\ 53åu<\1c\8e?÷0T\82\12«Ên\8b\9c.v9\1c\9a83ý÷U»\88±ý­¬\9d0\98r¯Ôñ\8c\ 2^ëa\18Ù\9dÂ,8\9c%º±¬\8b\1e˨¾ìÉ\96\ ed@B¶\9cú\1dØÎT8ø\8eÄ}\10ÒDaÅ\92d°¨¨ux\1a)Õú1&\1e,\ 2[*ë\ 3ûI\9b\8bÏ>½í"\93\8b\1ex¯X\11ÆEäp<YÍÓK\8d<\97\10dÏçÔDÇ;Üå3µ\95\86\ 2¬î¡\94\ fKë4óÃûV§ìuH7\aìɺP\84\88xðpø¾DëڬoÙ\f\b\ 3Ü\1eº\ 52\18#RÚ\9bØ­G\17z~¦\15à\9e\a\8bF{\8c\8b\8f\1f$\19\840}`C \8e\87Ã\13©\1cd·K:7?f³t¨.\e\1d\9e>T{û\18\ fm¼1\1djHê\99àë×\8e\ 3¥\1aÒä\ e¯\1døï¸Á>·@5\9ezsãá¢\96øèÖb\ fÄ,ÅÁ\8f\açP\8bͺ?Î@Ót¾ì¡z\8b´\16\ 5h\1e0·,\ eÇ\98§ì\98þ9nZ7Dÿ¬ä\ 2\9eX\16OËÕÁ]V¡,\802±KÅÏþïÆËö\1d.ÿl¶k\96¥¬OÝ5бÓ\9c\11Úy1åòÌ\8f1íz;û-`)²²:4\ fÜM\v}\8c±1\90ºM¥Ó\ 3!¢&õãÁ8¢×W/v\vK(<Ê4]È¿k\92#Üí`n\1eHd\9dñ>uÃÁ\97×\926Ïú\8c\vWÝ5\148\7fcäçsG´\ 3\8aF|\15>xí\12ö`\9cy\95[ö¹Ôó\v¹CÕ\93:\a\13
+ÇlÇê&XEºÞ\90çZȽ\83\8aO,ð\84\15\v\ 2ÏtM=\87»\88ýjÁ\98wÆib\ 2Í¥\7fà\ç)\ f\1fª\93o·¸oOõ\ 3\8b\980¾*Ö\1dÛ©\rÁZ\8e\96û½)ñ>kÚôl5¼Ñv²Wëv\89ÈÖJû\b\9bc*cµ ë\ 2ÐA¶\80"ÊÞÓ\11¥\b÷%F\96l\8aÆG¶/\16 þ>eø\ 2*pwdÒi\11\8d±6M\91j\10R;ºÐT\98à\ 1îª\9aMê5\1a\8bв\ 3£Úó\arÞl\a\8e\9c\9e\8fÖß\0Óª\ f|.\11yËäÙ\9fú´¥³Ò¸;\83±}\ 2TâcÊâ\89ü\0]gþé¥~T«I^\80\86ï¬\96
+hSÒ|®5\94{0\89Ô»wVâ ¤z\e'îMÍÎÐVz -\86ê `V1£\9b-
+ÉT»Ü\9c?\85µ\8bd+ãL©;\1dÁ±\19TåÉÆ\1aÎ\85yPµ\97NU9\17£Ö˹\83sTO_dÆ2t\ 4\8e²ÜC.%Âí!5*\8f1\9fkØç\90òÕnÖª\ e\1f\86ͧÚ\97ÿ\ e¼\ 5þ\9f0Gøçx \9f\8c\7f\84?\9fì{.Üsöþ\\8egY\19w\18\12ÆSÓÅá\8a\19x¯¹\7f\8c[\99ý~\8a\0¯w»¸½±\9c\9d\f\80\94;sÒYùN\9a\ 1â!¾    éðI^Ã1Ñ·H\8a\9bñ]?)£¹çò\18£÷LIÿP\96\ 6\ejx¬Åû\\ 5\ fÈkB*¡3\b£Aën"\82Qòt\9bbl\96q5¦\aî.\16ùnyâµ\96\1c\rO#}°6]\81ÙF\84·g=ë·\97Ë\11\9aê\9bhÌÚØG\aN@\ 6±Mä\0Í\ 36\9dÑÚÇXRH\9f\97\92^\82g\97è9¾\ 4Æ\9f{\80|^Ò\9eJ6%"0·f\aËyi ±8h\87wh\1e\8a>ök\9c\8bl\81{T>P~³=\1c^Gën¼t"\90©\16\81H\\83ÔK\88C\1e©©h@ûò[ð\f1=Ukñàôlu"¾¶\a,@ÆI´¦À:\\ f%ËQì]½õÃö[f\93\ 1Ç42¤ã|à\91\89\17vI   È¢&Q\14\9f
+u\93\88JUø*®-\©¦½ \ 4\ 1\1cà¥\96/îÒ\9aaé¦u»\aæ|+(váÕ\8aÍåýUÁ¾\bD\18·\86\8bû\8a!°Ì$Ð\97\11\81£J©ÅÍE:\vâß\1ec\9c]\ 53\7f.¯e·HÙÇ\89À}\vÉã`\1c\83Ãkhi\1eI«?Þzçé\8fØ¿Zµ-p$Êw+ä\9dµ¶\7fÙ¯¶å¸m$úî*ÿ\83^\\95lY1\0\ 2$\98<ébk]ë[\95\92쾩¨\19HÃ5EÎrH[òÏìÇì\8fm\ 3h\90 Çñ\90ëx©\91\99J¹ì3\r\10};}:Þ\ 2Íènnp¸[.}ÎjÖPSæn1ôvVÛ@¶P}ãFø\0(\ 5\r{ |\vö3wC\8bÃ\83)v¶\16u\94Ú8P­\814\b\89µÝãÀö\r\94Å=ã\0º*Àà\888r^Ðæ[&\ e'\8e\9f\ 2\12¢1Ç÷rWeT¯\15±\ 3E\18q\ fl\1a\9bÈ(î\197\8d\r ñ±\vv\9dðñ ÂÚiø\ 2ª\fædÃ\9bÄ\90¬\ 3\e\92\ 5B\ e\10\ 6\88\83½V\82\8d\ 3\99Õo\b\81´lØ5n£\eë'vA 2\8f |ÜЭ\ 5#aF\ 5\80!ab\v\8c@d´7´x\1cF\12\8d\r[v»­YO{­©\97\ 4\9b\98Ø\9a3`\0«h\ fä¶Þð\ 6\1f\8f\18²\11Ìj\8cd\0\93¸¹¡\ 5Ãп¡Å\ 5   b4\86s\91\ 5aTK÷\ 6;\96\1cØÜ\80óÕ3\96ZÁ |\98#\18\ f\84\ 1\1e7\91ôð\10n Ö8\ 2Å!̵Z¬qÄ\ 4\16¯Åð|¤ë\90wM[nÐ
+Âa  Ã\16Ãã\10gi½mMu+Rü:\ 1©Ð\ 5õ~Æ\ 2×S\1e®«JJü\18¨h\9cvT\a\\83þ\9eD½,°f&´Æº×5\87\9a\eù-\b2+nÅ\93\8f\aFs[\16\89\8c4¦z\ 6RGNnÁ0PCn@'¢g
+\9b\1f\98pv@\88\ 2¬\94\1e=¶8\8d±ìàZ«\92\0\84éH\11\94ÄYrHº#7è\a\0\17nØi\15Å©\ 5\88\1e\88Þ6qlq¨)÷\ 6'y\81ä\1da\11hð(ö@Ì%\8cl\19É®1\14(j:}mh%¤\aBgh¹ÕT3â\10´H\92\0\13Ï©Y^`\8eÓ@ºé#mÎ\1cØæ2°7xÆ@¶\bÐ\18t}\ fìJÈ\16×%\1dº¦\8e\81\ 5\95t\ 6l\9a\9aÆ\94w\8dÁ   \18­¨ÕôþÔÇ\ 2"Ã6\8e\1e.qÜjñ$\98\ 5¹\94\ 1\82\94Ú¬GV|\9f¸'\88Àn?\10\ 5*\1a"´Ä\ f\ 2\ eV¬-,ò\94x\83\83ð\ f\9cújnmV5Ë5° \1dt÷:ÓÃ\82ó¸glb\8b«\ 3ç¶Î=\10×'¼¡Áµ¶d4FjàT <§±UâR¯J\8cy`CnPôqÏ\18þ\1a\124æ" [`Ä)k\v²Å\1d\8f\88:(4|CDmñ#ؼ!äNx{ÆîÁZ8FÎ\v\ f6\91\8c\84-\aÏ\18\88»ûm\8bA )kÖË\ e\8e\15ݾ@/PFÍûsÃ\81MA"AúÆP¥Dàn\18¢\9ejAx\96$\91\88\91\89\0\141C\90E\967á±!\8fýM§©\ 6\14\96\99\82J\9c¡\8c³ jv`~\ 2\8d\82-ÑâT÷\ fLºW\ e\a\bE(¨ØÐE\92[ÊáVg`~â\b\875Óu\ 5/»zü\88\1e\9c\1a\9dM!\f\96DHÉM\1fÖ\9cÆ\8c\80\aÉ\8cwADí>\a`àêÊ\81VÀk)M"Ñ3\ 6\19\10\92\10;\14v\80.¨W?J"wC\8b\ 3OpælI\8c,Cx\14#(d\80\9c\16º*¶8\86\1aIÑ`\8cÛ\81\ 1\19\91°qj\10´\94°\90\89\e\1eod6dÊ\94\85u+dvG\84YKì\96é\81¨\a\9a\188\9cA\9ax\88\1fCEß\fî\8e_Þ|\ 3\1crJ¤è\19GnÛÐCÀtg\aä6cxC\8bC       \ 5Ò>8´¼iÒË(B"¢\98\81vNÜ\v ²C\8b\8b8\ eÑ\98s\86Ý\1d\11N·Aï\ 5>.CÂ\ fú×Æ´}\ 3\8f¸\a6>@ªâ\9e1ð«\150:ë.\13-\b±\ f\9a\85ÔÃ\1d\87\9bkÍ:ãÉP\93\89\18·3\ 4Ûj\90qÔ3nÛ\ 4¤L\14°\1eh[Êv\9c^j!\82¨þ\ 5T!öZ\1f}Õ¢Txø\17\83\8bö\86àsÆ\9f\ac\ f<ñn\88·ÞF\89k,\83kr\a\90\v \f¹\ 3¥\90¨Ô¹Ûc\f\1e\87\ 1âMgh9ÈP\83\e\92µ r¾\ 3ñ\ 6æF\94o\f\8d*\ 2\7f      è` Û¹ð\12êð\0E\97yW(\88y\17°V \83\ 3?A /8äø¤\9b6bg(¦\r|\171^ ¢È\94*áp\17ÁO1mÜ\ 5;ïòðÆ\a¢[(èEF\7f*¤r+2D\v8ÊzÆZÀ\19\ 2Nô<\15áVv\0\8fx\18vSIäOBØϵIï×îISê0ÌCé7âM\1f\96h-ëä\86ëoÂôJà3\ 4>\ ep\19Ë-c3Í;\1cÓ\ 1=BêâÈ^\9dk\1dÏi\90:Éã\91\81\10\1dþ$z\9f\92=\9eõÀ\ e){8\14\ 4\17î\ 6)C\86\OCëC\0\1c\aâ\r\ 1øÞ\f\ 6\a¡É\acv\11ì\82 -B&Ü\r>Þ¼A\ f\ 6\80\86\10,ÂJ\rmíh/\9cÞ68,\ 588\8d\ f\8b\ 2\81\92'Ò³Ð\82\82P̺¡ß\13çE\10G\88ËP0ç2\95n\93p¹ôA©\95C\13\a\87Ã\1a\16\ 6î\r ø"Ô\1eZ\18[×BjHË\81\84\91d=c\10|Ü°½\93÷\1d°%ö.Ü\ e\ 1\88\rÐ\0ë\8e\vx\17¥\84\16ȼ)îqÛ)íÈÚn+;\þòÛãGðÿ\93£\97òây¾<.ëÍê]RUªÌ\r*4zñ¦Èß\95i^¥ùõá!âÇê:Íý_\1e?z³6¿Qb\7f<ÿýìE\9aÁU\8f\1f=kþ~ð3üë\1f¯_½)\96Êüý4]Ti\91'åÝ\8e\9f~9øáö&ËáÇCx`\99\95Úüxð\14\f\8fÊ2éÛ,Vi¶,Un,ØÁ³\97yÕþ¨ÿ¨îÖÊüøÃÑË\8b£Ëku\95%\8bU¥þ\96ä\95z\9d\8b\95\ eD~A\7f<xö[\9e.àÌ9|7¿îÞó!Éj¼(]\82éçlòäÆ\9aÀ\ 3µÑÓ\89<=däÉ`oî¾léût·'.Ý\ ewév:\97(\1fáÒÇtY­\86»\85æ{áÚJ¥×«j¸oÎþé0\ fî\e\r\9d\17u¹PGÙz\95\fg\9c|xxÒ|º¼_fu9Ø©RmêlDÞ\9dýTÎñÁ\9emªå©ú\90&úYÃýë\9e\1a\7fä
\92+\9f\9f^\9e\ 3Wê,©7\9b\8fmFw¼ýË)¹ÿ¥¸/ý5¼\ 4\97#fàrÂ!8£\11Be9¡R)®®6ª:þ?1á\94\1cñÖx:³Ã}a\87Lë"½¼-\8a¬(\7fþ¸J+5bfÝe;¬»ÃÊ\98Oåêf­\16\1d-³ÇZC\fÏ[]^%\vu¾HF¥¯sj²5a¸\97\90ï:KÊ\93"ßTI>"\93Û''ó\96\8cv÷ùíºÈÕÿân{rOפCFà¿Á\11û4<D\9f¦+\81C:Ê©\11\8agBÁs(Æø4B\97ÞN®pÞ\15i^½Òcu\90ÊùVÏ8Ǧ~\85\ 3~/%×Ø\91½/ªë¡K\91ó¢.\17ê([¯\92\11¹cc\92ǦónW\95yN\15kU&U±coð=kOLÌc'ÅͺØØu`ÿ\98ÃVàY\99¬WéâÁñÇðÑù\9e\ f÷HÛî\81G;6\80\8eGt:\8f²´z\97¤»tø\1e\93üðMìý\bf\7f?!±\8f\97\eû2²Fä*\18\91«`:\8f\922­V7ª\1aÁîó0\1eæÄ}\9båÅÕÕFUÇY½#s_7ȧLïkU^+\1d×½ÔZ£'Ý\83ÎÎ7}Å\94/H³J\95»\1fðìT]\1dü\ 2y9ÿýì\859s\1f9åèå\85YO/\86OÆt¹Ûyc4\99\86~2Ø\97»á\r\17\ eÝ\ ewèvB\19FF¸ô1]V«án¡ù^¸¶RéõjĪãì§r®¸ü§ZTÇE\9d\9dÇÅ\8ejÛbM°­6ÃÝí\1c\1a8üî\eÁVuyYg*_¨Á±²\87\87\ 6©ùÔdî\rv¬T\9b:\eQîÎ~*çòâ¼J«Å\ eòñ\1cÜ\18ó_ÓL\8d¨òΡ©\e\83}Ìë\9b·\8b*ù0ÆEÿÌdCô'"\ 6;y\99\8bRý«\86Æ\1d¡\11zÇ&Öë¿úÔ³\7fëÔyQ\97\vuV&ëUºø\96;Õý'Î4ßÑ\9f]¯Øtní
+¿çT±VeR\15åpÏÚ\13\13wÖIq³.6i5ï¡\7fú\1eÊç=tÞCïå²6ï¡ó\1eº¿{èU\99\80\ 2ÏÞ\14éfÞDçMô³^Þ\8bMt¸\0ØßM\94Î\8bè¼\88Î\8bè¼\88Î\8bè}kvXDOÕ*WùEðM6Ñ}Ô\8e\ f\9b\0\87ç¹L\96i=Bl8û©<[¦YR\rWû{Ì\83¯\8br½*²âún&Â?\9d\bÃ\99\b¿\v"\1c\9eç\99\bg"ü\9e\88ðyY,SU΢ð»áÂ\87+
+\15ÔòL\853\15~5\15βðû Â\87+\vg*\9c©ð+¨ð,©ÿóïÍb¥Ê¿«t±ú¤ÿÈUyÁgbDÿ\86GbS-OÕ\874ÑÏ\1aÞ`ÝS\137\19\94Ãf\93&ùqV\ f¨ò¹Í¾¶Í¢¹Íпá\91\98Ûln³?h³¿\16Ù§\9bd£Ê:¿þ&\9d5\89c\87\94<\19ìÍÝð\96¸Û\13\97n\87»t;\9dKT\8cpécú_öËh7\8d\18\88¢¿Ò\1fH\15\87ô      h\9b\97´TÚü\80ñz±\8bÙ±¼¶Òôë˲\10 (]O$2;«}\ 4y\84\ f3sïu\1et:Öî8\v4­ÌR\87t¶ýy*8XüR2L!\96ùæ\9eSh\99¶3ùÜ\9c\r\88÷âI\11S¯^4¶\85\90×Ä?\87Re3\88^ª;/\9c62\9d\ e\11ALIG\87j\99WU´\88\15Þ\9f§\82\e\9ehÿË\8e]S\ f(\8aJµL\17CýÀ\89"\13ÙH߬\1c\91ÒrÂ\98\86 BDé\9c0K7ûTË\81WùÄ:-ÞBè)%p¾W\10~â'ÁBÿ²Sa\ 1ò«-ÛíÂ
+¹úü®ù
+\9c\90&<Ý^¿Çxô\93U\18\1e§BÇ5\94éÂ}«\9bÉrß*-rx\9cõrë\90ZÂ$rÐØ\197TS\8e\1cÓA¶ÍÝ\11\148åEh\9béc²C\ 5±BÎ`í 2A±TÉÜ\14E¬ZL\97¡BöòM\86m\167U|ÔÍ\1a¥ÑY³Ôasà*Á\r\8f)ÿ­£¢\1d\98I\81IÇ'EÝgÜÍö\fÊ*\88\121´g\85\1fÓß9Ñ\17B*dCO«\12]¯k~³]¾\96\0ÃÐnF7éÝ\17\7fÌ:\ 6\9d\ eö\@E÷é:\19NÙͧúRéxG%ÄQî\8bÙJÈ}=£Iiîr\17ÙjÚýΩX&Ë^&°Ê)\19­ðóØâPC
+c\92ÂÞܵ;\9eÃö\13\8e\ f\95d´é~µ¿ô×ß\ e\1aÜC%çH6$²!\91\r\89ìå\8bd»mg\1dÉ^\93^\86\9dd\96AôRM¬Ó\ 2Ñ¿1¦\81c:º¶I;\82\ 2§¼\b\98¸y¨ V´\19¬\1dTMÂ槠Í\ 4Þyá´\91½Ó\90tS]}H'ªÏv?÷¯Z\8e\9e\10\8dè\88¬       ?\85i\vê\8cE\1e1\84\be_\11
+{n\8a"Vª\87\96\85èÕ\r¢W7tDÂ\9b ×* Ô}0c.R8ø0\ 3¢Á\87»áÃ\88èÄÄ\87+§d´ÂÏ#F2¸x1¢_\83\17÷Ù\8bS ºfåP\14\95
+S\e½WùÄ:-.iê\94mþ®üRÕÿï\10¹Øw碷`9\1f\85\172\bû\ 3\fâ½Û\94§NÉó\8f\91\0f\10½T\17W(\12\87è\17ѪR¦·\8e[¨-!\v&H\9d\fXm\8f?\18[_ \95ò¤è\ 5Ô¿\ 2\f\0aÝC.\r
+endstream\rendobj\r14 0 obj\r<</Length 3720/Filter[/FlateDecode]>>stream\r
+H\89ì\97Qo\e7\12Çß\vô;èå\80\16hbI\89/Åéɲ`#¸È.¢\з\80âÎJL¸¤Â%\15«\9fíÞî\8b\1dµ+Å»v\9b\9dq\9a\8e¨\1aF\92\8d=cñ·3üÏ\7f\84Ûôþõýw£Þ\ f7\8566\83'Â{§æÁCùcï§ï¿;9sNÜ\8d\91K¥3\a¦\8a\18öN^\1a\7fûÃí_~³\82ê\87?\fú?öNþc\94\8cß\9dÅßl\16íȵÐa\17jBq-½Xo?ùK)F\14uF<Q3g{Ú_§¯®bÈö¼'\13%½²F|kħýS4ã\\94páàc\0#7xÌ;i?}\1dÎàK8½\93\ e\84\1cÞ\ 47\ f:\1e%~çw£\eGÿrQXêU\88øënÐ%«\13±\95úü1,h­Êàð\94ÁÃ)Ã\87v\19³K)4\9eÌA\19´ÇÓíã¹\b\a½þîë÷\9e>\7f\aÍ_=\12´t\1fϬ.çV[7ÝßÑôäef\83\93p¦WKqt\97\83s\90ÑàR»\87ÏÑd¥Ï&°Vb{,<_;\8bù¶]\8aP\96J\98me\93¼n\ fjÉTîÛ\13|/f\1d\8e¦\89´\8deCÂ\9bå\8cà\90³\r\1fÒu\9e\97àÿjmäT\8d\9a8I½ ûÈTÄâÜ\16«m\13n\97\80£\1dÎ_q×\94\19R
+9ä\83ìê¸\ 6\94]\81\13Þ:<Ùm\ 6»Ñ/V¶T\1e\92Ô\91\aݶ\14¥¤ãÒ$¬%\83§x/òhõù¯Üq\8fî_sp\17Êáá¾±w<´ê{1'T¾Îþ\9aÏ\9fÂB6ìõñ\Û·ðvûÿ\92\80×LbV¡\8b`äë$åçx\eðé\8b^¿÷÷jÁËÇ\16\16\1cüÝDp\8cêÀoº|\19\8d\13¦\8cÖ#Éûð ß\94\92)\9cÙà$üU¶\90\ 5³F\8cÞ~µT\92\8e½´]Å!\1f_W»5 ì
+\9cðÖáÉn3\98\15­Ò\93RyHRG¦à\16p¦õãîõ§JÑ\ 3\94\96³\87«.ؾ[ÖÉ\\9d\82ó\ 4J{\8c\1d8\99\eźÌÞ^^T9\87عg/ßýû\7fÿ]j\18;U\12:7ë~\ 1U\10×Tyò¼ÿ\ f\ 6\7f\r7\8cH§x¢\e\r\1fÑ`@(Ò'\95ù%\1ek\17Î\86Fé¿%¨Å\920-÷ñ\pvþ\1e¤\1fÛ`²xαíè¶{â\19c=a3m%%ê\10\ 4MZ±¦\80Qak¿s¦WK\ 2["«%\9e(µmrð´c/l²\89L\ 5Â=ÝÇs±eJ\v\8f÷0        o\93SëVK«íb\93ä:9?:1<>      Ä×èQ\ 2\1f%ðQ\ 2©×kpt\1aHPõD4ðÉs4R¶Á#mcÙ\8a\84ﻯÐuNa¸Îó\12|\92¢\90;!½ÐWV\95x\r¯Ó±Eúüa<Ý\87\9f¼É¨\1e\13\91=B\95Ró~Æμòr\89\ 6,«ð7J\ 3Á\ 5\92¸POÑ\8c&\14×QwÖ\14Äf\ e\17a\9f`äç¢\84\v\a\1f\ 3\18I\18ÕwÒ\98\9bàæAÇ£@\92ãmþìQý\ f_ýñE*¥Ð\ 4ë±\vg+\15\1e,µ©F±U¦#¶Ý\86C>¨×h¦\9bó¥0\ 6ô\f4Ho\1d\1eð~&\17í\19\9avó`Úû\99Ìól¢Ê\95\16\12
+0~*VI\ eµBÄ_ws\9cÛÚóã\9b×\ 4\v\92ȼ&T)µ¹Öïí¿z÷\1e\a­Gô+¨\1e    {Î>\9eY)Ï­¶nº\97\9aôTr\8eßF\93\91\12\82:¦"%ø*¥&%ø=­ôÙ\ 4ÖJl\8fEXnZYHµ8´[\9a;\80ß:ìIS\96\94Öø7TGsÕ_èObÓ¡ûíööÂÑú»N`\9b\95x¸9,(\8a´\v\9b\9b;[\10ú±\8aæ¢:Å\97+\v\84\1d¯
+f\83¯A\96°\ 4Y>"\aÕ\82\8aæ\12Y¦¼Z\13V¼Û\f.Fc\r\ 1PÊP\ 4-<\ 5±\91Ã\ 5©\95\ 1Ñq\8f\1a\98Rh9\8dßÂCÞfp!â\8d\9eû3\U,è\92¶ÓX·#aTQ÷c÷^ô­ö³K\11ÊR  3Ö\95X§· Iü\98MfA;ºýìÉÏxÓ°!x\86\r\1f\12¡ï¾båä\13§\1c®ó¼\ 4\9f¤(äNH/ô\95U%Þ!Ôéhs·ÿ0\9eî\e\1e\9dêQ\84<\11Ù#Té+4\82É{ϼòr\89\ 6,«ð7JCÇ\ 2Ù¤l%q¡\ eúhH\13\8aë(<k
+c3\87\v±ÿ´\7f\8a\86\9c\8b\12.\1c|\f`$aXßIc\1eno\82\9b\a\1d\8f\82³ß\876àä³Gý?|ýÇ»ÞR
+M0\1f»p¶Rá»/µ¹F1V¦#¶Ý\86C>¨×h¦\9bó¥0\ 6ô\f4Ho\1d\1eð~&\17í\19\9avó`Úû\99Ìól¢Ê\95\16\12
+0~*VI\ eµBÄ_ws\9cûÚóã\9b×\ 4\v\92ȼ&T)µ¹Öïí¿vÿ\fþè\11ý
+ªG¢³\8fgVÊs«­\9bî¥&=\95\94øM-\19)!¨c*R\82¯RjR\82ßÓJ\9fM`­ÄöX\84å¦\95Ŭ\16\97"\94¥\12\83ûZ¹Àp¤¬6ô«ÉYÙ)¸\ 5lßg\92S`þX\97\83¬\8bx,Ë\9d\93þù§à<\81Ò\1e\10\83àd\ 2yo\14ë2{{yQå\1c¢¸\9f½|÷\8bº\ 1\14èwø¹^ùÊC6\94§ýÞ)~\91©\8bú\9a²Ë4R¸\18íü=H?¶Ádñ¨c{Cä\8d±\9eL¼KBjÑ¡õ»\83®\81ò\9e\ 5i¾n\10ú\93Øt\94³½sxáhKG\9dÀ\ 5ØÇÃÍaA\19®»p¶u\8a@\96UK\b\92«
+f£ê\rFÃ~op\1aÿî÷â\9fQ|\8eÿ\8eâ\ fzhÞê\91 Rûx.je2ÈUÔH¼È8X\81ð\13Ja\e)\ ñ\bZH<¥È2åU\97ö6!o3¸\18\8d5\ 4@)C\11´èª|\v±\91Ã\ 5Y®´"`J¡åÔf\ 4ÈÛ\f.D¤½k\16s\7f\80«
+\ 4]Ïv\1aëÂ&\8c*êfì^\95\ eͦÍu\97\1aÞÝE\90\ 5â\If68      gzµ\14x6\82\8bá´0¤\82E'\194ÍyVñ\p/Ðd¥Ï&°Vb{,<_;\8bU4r¸\14¡,\950㺢Ǯ\1d\89Ü/i\8b\95-£«¼\ e\1d\17'á{V\vä¥\13«¥\92\84\12\ e)5\1c\ 6h(»\ 2'¼%¬\ 4·\19Ì\ 2r¾oÕ$ÕãA\17-\15\15é£\89><Ç\13mc\13 \1a\10\88\ 6\87¡ô\1dGNXêñd\1f\bêþ\81\1fæîS\19]\84z=#Ôë\19\1f\91pÊ/\vð\ 4§ñ8\94q\10\87<Óñ\8dü\80¡ÎYá)¸\ 5l_-ªÂßô\14\9c'PÚ\ 3bo=\99\eźÌÞ^^T9\87ظg/ßý¢n@\97+\ 5ú]Ǭh¶nÖý\ 6ª .ñ=í÷NñÖ­.êëígc/d#\85\8bÑÎß\83ôc\eL\16\8f:¶7DÞ\18ëÉÄ»$¤\16\1dZ¿;(ì\1a(ïI\93^\90\eú\93Øt\94³íç½p4C_'°mbx¸9,(Ãu\17Îf}    dY \98Ã*\98U\81GÃ~oØ\1fÑÔ¸z$\bÓ>\9e\8bT\99\frejï\8b½}+\10~B)f#\85\v4\1eA\v\89§\14Y¦¼êÒÛ&äm\ 6\17£±\86\0(e(\82\16]\95o!6r¸ µ2 :z¯\81)\85\96S\9b\11 o3¸\10\91\96®YÌý\ 1®*\10t=Ûi¬K\9a0ª¨\9b±{=:4k6×]jxwÿ@\16\88s\r\99Ùà$\9céÕRàÙ\bÎ\85Ó¶\90
+\16ÝcÐ4·YÅsÁ½@\93\95>\9bÀZ\89í±ð|í,VÑÈáR\84²TÂ\8cë\8a¦§\1d\99ÊóPâçv*òAÓÄDt\83Z¬Ô¤c\ 3ZÛOh<­\16K\1f\ 3\9eH«-a\1f¸\9bǶ½\12\v9\8bÞ\90`¯ZI\87ϸkîskJ/\f¡kï%r±\9eâ'_py\\a\89\ 5mg!'ß¡\r\1c\a\85íÚk\9b#Vi\8d\7fCu4Wý\85þ$6ø­)ÞO/\1cM\9eë\ 4.À>\1en\ e\vÊTÝ\85³©Ô)\9e,ë2\16-m
+\8có¥\1e§£\85\ 30£h\88`¤L¦\16v´VV\83\1f9ÈFÖ    ³À_Çê±ã]5ù÷ñ\¯ \ 2\8cò\14Ó´\ 2á'\94*7R¸@ã\11t\9c\rhJ\91eÊ«.!nBÞfp1\1ak\b\80R\86"hÑUù\16b#\87\vR+\ 3\ 2¿ºD/ §ñ[xÈÛ\f>D¼ooVt\7f\8a«\8a\ 6]Ôv\1aÒ6ý\11ÙàKd½\93.\ 4£\8aº#;NýåÒðÌÈ\9fûøRý¦\8aà\97\84\13¸zò\9fx8Ðñ\7fÛCáñ\1a)¬ý\97ÃDUKÒ«í\15Dµá·;Hµµ½ÚiA\92W"z*¼|Qì0§\17.W ã\ftסc5i¯2AÓ6\99*\9eÏ-eh6Ê´ú?ûeÔÓ6\10Ãñ¯ÂË\1e'(°iR\9f(ݪI0&UÚ+º&NspÍE\97; ûô»$íH@ãl\10r®ë\e \eù\17ûüÿ»Ëø4\8fï¶A£VÎdÞDνE \bl?\8b\r\13¿À·\13\8bf\19\12P\9feÆÐÕMÑ_\1fJo _\83û\98\89T¯¡-j\ 3+\1dºuºê$\95Â\7f¥6\9ak\10\84º\17ë\8a²©­0´UÝ&p\ 1\1eáá\16°¤¨ì&\9cï     ãÉÒ\90Ñèr5Á\T²HåR\8f\97\ 6 \18¯A)}?ö>     ÆwR+°c/½cmD±Ä?ÇæÇÀ·êòoã\19?\ 1\90\16\8f\ 4\94.wRølT©¼òãÏÂ4\95V\86\16qï.ü\9bÁÅXxåÃ\ 3&\89[yÅ\f\87ØÉá\82\0\81?e¼ÓK.ý\9fð\90\8f\19|\88x\eßíè¶\8a\1f\r\rº©ý4¤mú\17Ùè%²\83Ã\10B!WíD\ 6ª~¹5|]C7K\ 6®ºn\87êX6åÿ\82?VÄo¹r6'\8cÞ6\81\8bî3\1e\ e\94ÿ­.
+\8f×Ia}U\19Les\ 3^lF4ü¸Þ«\90ùæL»Ø¬¸(_úöÖ¼r\84÷N\98\eN§ÿ\1a6\7fw9E»Ó\9ax.ƹv&\813Uæ\82пcJ\ 3\8f9-=\1aJ\97`\84\rY\8c.Ùc\ 6óF;׫RW2R¯ÐNàÌ\882\97ÉÎí\10¼¨Þ\9eâ\89êX6\17\84'
+\84ö\88F\9c7\86ý)d±»K\9e0\84\84Í~˸ØS\99
+\vQJ\16¡W'\84^\9dð\11  #m¾\ 2KØî{1\8ee\15îu8\ 2¢Èt\18ï0b\13b\82w\8aD\88«\12\12§\84¹r\94\9d\11\8b\18\13úµ\17ã]\16c\fÄPµ\1c?į\10sÎî^\82YBýYQÝ}×*8+\90Ê\82  \17p8\85ì`ìû2ÿ5ûÖä\fqhϾ_Ï\93ÜÿS(®     \83\9b\86ù\9b ®µ«\177\90Ø\89vEêk\9cè\a4ZÛ^\1fk+üãì%!_éÐ&a®\9dIàL\95¹Ø¹kd¡\@N#6¹\ 1s×!«l:\85;)ê²ð|ý,f\r\9a     WUR\14\93¶£o2\19Ã\1fÅXÞ×)\9a(\rlâ.Q\1d\e\ 1Ñ\9a@´f\94Ä,«ÀÖïÆ@J[óoØ\88\9c»âª!þ\1fO\917ôz§o\92¡õ©õ\3#Ê\&û\16íÏÆ\18ÏF¼ÿ\1cüÙøqôé\ 3\9a\86 û\8c²OB"\983Fo6:=Â#ÝËÔæx¬M8\eÚ  \ 1-\a¹Ì   ¶l\eÏæ@\177\90Ø\89vEêë\9cèÀ´=[\9e>ÖVxÜ^\12R\ 3\87¶g[\83ðî\ e\8e\85máíéË\95þ\11`\00\15\r
+endstream\rendobj\r15 0 obj\r<</Length 17883/Filter[/FlateDecode]>>stream\r
+H\89ìW]oÔX\12}\8f\94ÿà\17$\90&ÎýþX\9e\92aaÙ]Âì\ 4\18V£Qät;Äà¶\83Û\ 6òï÷Ô½î¤\e\ 2í^X9\99m%ju\97ï½®SuêTÝ\ fYÙå\ f\92\9fvwî7ù¼+Û\aÉþ˪\98ÔÓü¸m\8aêMrÿÓ¬¬ðs\8f>ªl\16W?L®Öã×þëgÿ<Âãä/øþ¨\98´E]eÍ%ý|x}@ÖâÄÓ®ÍçqÓAÓd\9f¯\99\9c\17å´É«°B$ûO«vÕ\83öò¢÷×|ÛÕ\ f×ÈæíôQþ¡ÈÈ­áøVwýô}Pø· $ûk\0\9cåO²n>/²ê°ì\9a\a7¯_òýÛ)\19%[§Ñña    +6HSQ\8dGA7\18ÑôÓpD´ö\ e ºÜ\0Ñåx\88ê³³yÞRÝ4ùô ¼8Ï\ 6\ eE\1cS+\9e\aÄß«\12C\10Ü6\91ù\8e\ÿ\17\923f\8e\9fåÍ\9b\9câ{'\9bÁqÝ5\93üI\93]\9c\17\93m\8a>óôÇ{1¦\aEÙæ\ 3F\96ýGùYò\10y9~õäqØs\e\ 5æàéÉq\8b\89p>9\1fNÛézôaÑh\1dòôm>i\ fë®\9aÂÇÃzͨòEr±¶\9d\ f\95M\ 3kô¶ñà¬É&mV\1eÕÅ<\1f\1c­¸}h\98®^6
\89Ø\8cßCeyD\9a\9fîþ±A\96¾c\96\1d\ 5ZU\1f·E»\81ÌÎÃò\17E\99o E+\9bÆ\82ÊÙ`\90U7{\ eáù°        Æå=cAd©\1e\8cñ4\9bç\8f\9bü}\97W\93\rî\98\9fm»£\8d¥Égõ\87á-\ 5½´Ü¨ó\96ãq +?f\97kx»*XmÖl¦XqÃ] ùYSÏ6H\X=\16.=<iÓ®\19\8e*,\1e/YvøàVo0¶Õãa*ªi~V`°\1e. M~\91gí£MÒ¶´e, p¡Ì&ÃQfÓiÑ\16ëtu\19äõ\8eñ\ 6 j\ 3\80\93I7ëÊl]æW .í\19\vdYTy¶\86{K0'Y9y\ 6Óp\90×;Æ\82¸Á8³\9cÐ\85\13G\ 1Ìà\9c®n\e8\ 4}\r\18ÿ\16°d\7f\1d\84ª\98EB®ñú§ÿ\95\a\8b®9íJD~\98\e·m\1aÜà~wW®¬Çu×Lò\83òâ<Û\0Û\9a\82\13cvàÁ ê\8b¼ÉÚz\83Æ{½cÔº>Ë\7f®g\17õ¼\18·¶\8b²Í\9bõ\ eì?ÊÏ\92\87\88Êñ«'\8fÃ\9eÛxí;xzò*o>\16Íi^vÕ\9b\139¼6¦ëc\10\16\8d6hß\e\8ceM{\Fty'\0}\1a\ eèÓx\80\0ÒÇbÚ\9e\ f\87Õ/¿\13ÐÎóâÍy;\1cÛbýXàêÓ·ù¤=¬»j
+?\ fë5lûB<±¶\9d\ f\87»²i`\aºm:Û.Ï\83Ãb\157\ f\rÒÕ«F\837\18X\93Ï»r\ 3º/Ö\8f\ 5®ª\8fÛ¢\9d¬\11\9f%\80ó°üEQæ\e°|eÓXPÝ`\8cU7{>i³\ f\9b@\Þ3Z\13M\99\1e\fò4\9bç\8f\9bü}\87ÂÝ`FølÛÈCó\1d¿\8an$-ÛËèö2º½\8cþY.£Ã\85z{\19½Å\80\97Ñíet{\19½E:{Öd\18ÃË£º\98o¯£Ûëè\8d(oÅuTý\1f\G\87cÜÞFÇ\97Îímt{\eÝÞF\7fÐmôÞÁSÎNþZM¯n¥Á¦ÉtrTW¿à\94\16\aííõöÃüMQ-?ÙÝ9ºX\9c\13\1e\1e_ÎNë\12¾\1c\96Y\97'\87e\87·î²ä`w\87%¯?îîtá\9f%\8fèã9>Rá\13\962\81\ f\8f\8fä\1d=øõ\86\aÿ \a\1c_èïõ%ýú;¾½Ås©lò1Qɳä÷?X2Åû^ã\84\94I\99\152q«Ôx%\93\v\912o,ÙeÊ\9cL`ã&µJ
+جLµ4<y\15ÖJ\97\1dìƤ\82[\97Üxð¿wwN\11\8a\13P­]-­{'÷÷Xj­g\9a-%çðð`2éf¿ÖmF\8bCnî\9dPZNvw^îîøäþ\83äõo1^©¡X8úÐ1H<ù¸»g½µ©\16\'Nz\9f
+cM@\b»H=\17<q\8a«\94s#\12\94\vça\1425Fr2:\9dj¯-­Ô)SÎ%?\87\13\1cÐzü
+v\e\97Ú\94[\19Lx(\8d\fF\97
+­}4â\8bYì·\b\8c\95ô2øh\9c¢Å\9e-\ e\95<~##\9e+E'H\96:'\2   \91g2åJ\98h\ f'\93Ѧ\92ã0\1ckR'­\ f¹ã©´\96\8c\9c\11\ 3ì\ 2KL\7f²ñf\91h%½&£M\ 13\18\85N\1d\17Á¨S/µî}\90ðÁ\99`Wx±\ f\8bñ\95\81\a\ 6¾$q%\16
+òÁ§ÖáÛÕ        N*:\81»T\83ÏÑ&\85ç1f\8aùh\141L0J\10\1e\84bKY\93\ e´%#XÉC \ 5N\15J\91Q\83\8bÂ.bCQ\8a.\18\95:\15R,ÈI\e^g\10S\17ó\86\1a0&\9eÀ\11hc\88N\88³å¼÷A\9b\94\eO\8b\19\12\1dp\82\17¡@R,}#£M\95æ\14\ 6æSe\99í}°\ e\91\92\ 1\1d¨)xÈ\9b\ 3\1d\f\18@*\162lá­7\81ÒH\9fq¢÷Á!\ 1\86\ 3\9dGHa$B1\10\19F\80ç\öFã\19Þ%AÎ\10èè\ 3ìà\80';Þ\ 1ÌÁ\a\9b
\b2\\fg\91\ f(&\ 1ßa\14\b´Xä\ 2\ es\10(!VAv"%±ÏhI\8e!ÐVFBY\14\8d\b\914\ 4Í,\b\91¥lJ¤Ð\b\1e^§ADÃ\82\91ªUÈ\15\8d\91$AF\9bþ\ 4¢8#BI\90ÖJ\bB¬b®Ãbz\1d\8a\86ÊÝ¥Ê\18\0×¹\98
+Øu\ 4\8f0@\97\8c\8a\8b\81S\87Ø\90$¢,\92\eÕ\ 5a8û\9a̱¾{Q;H&Ô\10»j\9aÌϳ\8b<\99¡\ 5­J\1cdíþ/]õ®\9duóжH×ù\95ÂÓßï|a\84ÿ\ 6    \ 5á¤Pâ\8fä"²\92$F\13h'á=Êa¶°\v\98"\83Bì£\8eÇÀ+Æ\81\9f\ 5\1d\87
+\ 5¹\80Q-gIÀ®´\8eÔF\91\ 6åq\91þ\82j\9b~+èHä)\a\ 1ø¢Ú@eÁC2Á"¼!\8a\ eJ׳@\a\9b¢Å\84´\v\15+$\10\87ãÉB2tjd8\ 1Éìßn8d)2Ïõr
+ È°\82z\84\0\ 4Q\8b\aÀ\1e%#\10\9dÇRA\r+R;\18Q?:\1e\v#tÖÇRá\16e\89\13\1e\7fµ\91¡°¸\85È\ eícï©wY\90\97:\174?¡úñ¡\8fÑ[ßE¸\8b¦ eßAb\1a¥\87r\92BQ\ 1 Z¶¯
+\13\89N\8fu\ fM-\8c\92öôÅ\ 6\7f\83l¡TQ\v,\88\ eU.S\14ulÓ½\96¡ç\eA        §\90\17=\88\82o\b;×±¶\11TôRZìÐx\9crý     }2Q\8b\16R{-¾FÇ°£ýj\17¸£ý\95\91\1aOl+ZF\15\rÄñ(¼kñe¡?R\8eD(xÄA^¥\18'ØHqR\aûz\10Â^· Øñ¨à¹q!\f\82\p"J\9cT±­ ohT=ÁE\9c-¾E\17\ 4\11*\84\aR"ud\1fä'\bXð+\bTì®=2T\85 \9aì«\ 2ý\84Z{Ð\17HW_A:r\14Z\15\100\11{:>PÛ$\84q\98\80ü@úûJ÷ÂÛ$\1aÑÀTl\b\92ó(\84¾oJ\0\fýd²\17= 7ÒÙØ(\98\16á\ 4k®ê\87G¸Qô\1cú@Ä\8ah]\1fг\94XÅu\98¨¨Cù Å
\f9XÀò4&I´nÍå"\rÐ\0o"Ï¡Öý4"0¾zêúdô,Jÿ\97\15\81\13þ¶»ó[¨Í\7f-\r\87/i\ eƼ;ÝÝ1Ë\ 3c\1c¡!\99qzF\rÆ\11\9a\93Î\84Ù\11\8cE×öªW   N\rs¶h´Ì{Ó§°ç\9b\83\92\ 6­%¥\8c\19À  <ÖDÐÔ¥F\vÎk\1a\8bBß \10FQ\96Úªxj¨k2\8a(ÅpÁƬ ßÇ?L~n|ÃU\8f0:Ì\bÄGd²¯áÅL¤Ra#rM3\84ãq\80\v$\89 !):N4è\16\82\86\1c¤U©0Mó8ËÆú3\96\85Ö#ãÀó£Q"\95\98\vLL%#Êõ©¤î¥ú\12Å \1d´\8e\0»Ð^¨\11ôÝ\ 1U\81\8aYh\84»ê\844VE       µ½"ô\83\94\r\13\84\ 5É|4¢2YL:I\1e\15È\8f\1fÚËmG¯ê\bÂ÷\91x\87ÿ\ 6ÉÜ\84u>\b\8bD\84DDNH,E\11\ 4\11|@ö8ÄoOUW÷Þc\f\91\90þ\bK\8c\97÷ì½V¯îª¯l¶{_C®l\ 3¯°Ã/g#z¨Ï*µøl»\7fw:\8e&xiÔ0¶\83v{íkÈÌg\9a\1cø}:\9c,\93µ-\ 3`NRÕ5@ë\1aº\8b\8b°qú      \ 5\ 5¢5²/Â8[¨\ f\ 48OÇê\90¯U\ eM\83òï#¤9Ýá]½Ë\ 4®;RÌ,ÅÅ\18À\1fº\ 1Ss@ç\1e\1c0FÇÎFVI\105ä¶E~!O¤\8d=   ¼\9e\0<µ±Y\16\1ff\10mî   ­µ\1a\93*n\99T¸¾®~ʶ\95' ÁYV¤S\ 2ĺ\84y;P@\ 5\ 1\ff\ 2\19\94!!`\82\18Õ(\ 3yg×À\ 1¸uÕõ >ÅÃ\8bVÕÜ\8bÓ¨:7Ó\8að\1d\14\81L\98ÌaI2\ 1w\98éf\9eÃýu\ 5\13&\bK\94\95ù­¤\ 3(\88ýÆ\ 3ØC¢U)Íu§\f\9c·J¹ÞWO×¾\12é\86£Ôu'e\ 5\85!a\98Ìi1T\ 1\ eéªà\16\13E)Êbå¸jô®!µ\13E[nóFë\aQàHEëc9¤cï­\f1Tt\10Tw\ 1\98ÕAÚCÂ],\9b\1f<\9c\9bR\93\85ËøÜ>\87ÊÙ\99\e#\92{\94j\9evÙÝ\96@\94»ú0(\98\9aU|o«\ e\93éä\18l\0Y÷>\99"\b@\81\9f\ 2\96ÓQ\82ËÏ6$Þðúªòµ\1c¨èñ\9d»uùÂß\9al\11¢\9aÄnèïjÖ_èiizõ\93\10@g÷CÂñá-´PD\1ep¤U\ 4&âD\81ïf ÔEO¢Y\9bôÏ&á:\1aýë²éÿ®\85¹ v\8d®*\8a\82øÑ¥¼"\1fv\ 1\ f\0\eTÈ'1\ 3s9\89\1a"\18\9bc\1d\13\81f2D\98
+uV\8cÀùé:ÛrÑDú\v`~x\8cë\80G\90ÌE\991ÛðA\e\8e|øÿ\ 2\8f_WÍ/ïðjº|A0-\9b\11°8\9d2\a:\93¢Éw#T\81&\81\87·ÀsJ¶,\b\10å\18H²*mÆÔ8Â\19\83\8b\82\11Ôx£\ 4\80\12«\80­\a³P,W\véN;ÂY®\16Uø$XÈëÞ\91ëRÍâú\90nLmÓ\86\11RM\19t\8aª\b\81»Ês\1d²    È*\83rQÛoÙ\17\9eÚÖNCs]RÏ~\9dµ\98\96¢yÌ6\1fÄÝ'È\93êS\96Ú¯\12 L¥Q\9cª\93a\8b%\eä¡     >íTîÖºo-M½\0a²Bºýd\9eÅ°Ù\9eU00eÍÑ¿t\95læÝpâ]\9a[ÍÖk;1pÙU4$ÓÖÍ\ 3¡y³5?\ 4>âÁ\ 3Õ\v£àXàK\8aRئ­aت\ e±14éN \85â®wm\18gßb]x\v\90k^Þêa¦8#Xüdz¯ÅÔ"a­¼ëå?Ç\9b\8fJ\0m\82ß\9d¢Q    /\19¾Ö\15\92P\85~V\aw\88qå³½\1d\85à]é2Æ\99¨
+L_\86\vF2_Su \9d\e»\92;\9blj\11u³R¢\12KåÁ¢Å6«om\87@\94¢û²úú\19ÊQóFÚt\9f\81\91$Ëdè\80A      >^\0c\1fª{R;@¬ÆVã@¸á`^^¼ÃÙ¥\9d7\ f\9fÈê\80ËÜà=//\84¬h\84:Cà°\8bK´ïÑu\8c\18\0³\12óKä¯ÆþuÏÎaÏôK\9fX¼a.ÝÚ8bNb¡¶í\ 1Ç\19+\ e\97ù{Å' \8f¢Ó\15±²Í\9b\89µN\a\17*sW½¤¯\1coV"¤@tÇ5;\85\199\9a\11\ 3\97\8a\1cÜ
+\9fìs\ 6\19;'ÛðV¯r±xú¬&*\8e\9eý\96\94\9f\8bØX7\0Æç\8a\95\8e%\949\10Ãð\aV3u\9b\86`¾]\9f\8a\8e½è\rð\13pR\97hÜ     \81ô\1f6¨I\94Ý=\17\1dn$Õ®\ 3\99Û\92>Mk=\7f\ 1î"\ f_¶ÞTçØ»°HÍn~\ fS\93R(é)ª\bnpÆÆØ\84ör±è\ 5]=¢±ÊÒ\8cBAØ\91-°>¶\81(6¾\96OE\8d\1eÁE\9b\fh_òâ\8a»Ca\8e#\f\9aõ*¸<ë\15\1d\17y¥p\91È6º7\7fÙÔ\96\82\14\ 3t\8c{\0:à.ù0\b»*¥nB\ 4\1d\ 10å m\10$\8d.4ð\91ÊÙ\bÛ×\8bB\ f\17\9b'¡büÝ¢s3$!\93¤Ê¤Éí\15û\9d4G 9\1eÞ1\97T\aÊ+Ö×)P\1c\14"\1e\86\9a\9dé%o¾¶\94\17¼º\ 3$\ 2§D!\9aD_ì\8fýðÒÒÙ6T\ fM;\0¾÷1NátoÌY\86%\95\9d³ó*òP\8a\92\1c\17Å\17ÞTÚët\85ºâæ{;\9e\95ààª[u°ªâM,6¹÷ñ\ 2\11)û      ]\9d\83¡Ònz\98\97é\86     )Mdö ¬qKüÑæË£ÙûH\83\9aÿëjÜþ\86\90P5ÈS\98\18@U\ 5T}ε.¬bÚR\1a%\95R?\85\9b\8b\16\fq\8e>üÚ`^Ý=Ð\9b\1a\8b¹Y\19èÿ\9e\ 4¯\80\92'q\9b­l\97àÅ\r\1c
+CxÂ,È÷h\83\ 1`e·¨6\8a\91\89;*¤h/ç£å÷Êæ,\ 2·$\ 3÷Sf3\12ëÝux2\ 2í\1eÛ\ 5Ð\92¢\89G\12\ 2@BïØlnK8xG} \1eu\89\ 1M\18Qwúp(©\a(¡ÊO±\ fß\ 1_`\ 3F\11wÌD\9b\8f$þ½3t\11P̧±ó8\ 2\1eÖÑp\84>½bI\ 3$\17XǶ\96\89\ 4\17­\Ç\16Ò6¹ÅçZÙÓÅÒ)\86DÔ\\98\1ddm\ f\13Ít¾as\ 6µ\87\CC§×¶\1cÉ\ 5{p䬥©ðtÝvk\1e`é4æ\aj·Êq5¨Âzb\87\8d\14ì@A¬@\98Ö³÷ \95ÑU \a\ 2â\94k¤æ<î<CiHs8\85zÒÀ·`°ñ\ 6xAJa­\85à¬\8dõb(RI\8e±\94m¬Ñm\963\8e\94\0\8bhz4\1a\v\1fÛ>\1d¸\9evh©]»üz\8e¸)r0¢\94ê_g\1cA%ðñÔ\ 6<M4gkÿõ\1e~\8f_ªëÀèI*\11]ÐÖ¤ð5YvÁÄ\99®<88úh\95ä\8c\85â¯Ù]®\904º¿¡d\9dkjJý\r\vvc\b¦×Z^°ÏE\8e¬G\ f\97©\ 6½v³Q?´GÞ>Jÿ<Ø9+«òd`ýàªnJË\1aÄL\9eO6%\ 1g;ò¹i5zÆr¢Ø\8e\96««ò¼\92\1e#\1e\11ùA¼À£_åØO#ò\£YÙ?5tÉ\90C\13y:\7f&u\b§\11\f\fy|ÝM\rÈÀ3º\e¡uûÕË\8c÷Nc<3\8d4b¦\93\93\97\fß·\83Ñ2æ©\99­\9fÃæ\9aæ!¿sJN\87t\1d \98\8bÊ\84\ 3m      \0@1bGag&#¡¥Ù}\12±.\89Ó@HeGüb\v\1a=\ 2PTçÀ\85²p£ãDhìlØï¯êã\9f\bB\8d\9fêìõÝ=8©}
+À£SE®Zå/?ø;Üûèòèïïýüó_È\97\8f?{q{¹÷Ég¹þùñííÍ«\17\ fo¾ùöõí+{û_ß~\7fã_(ï?ùé\7f¿\7fùêöÎ3éòñý\97/\9f½ûÐ\8bÇ_?»ùý\9bo\9fÞ¼~w³Çî>Äãé«O_<ýËÛç_¿|\16\v÷±\91\17±tïþ³Çon^]þöò\9b\9bg\1f}\90.\9f\90¬\1eý`\88õ\93?éò\ 5é
+\82Ù\8d¹0w4[X@Ò-\7fÇg°hÿ=zË¿ý\ 1\ek?\ÚåO\97\7fü3]\9eâ#\8f\1eÊ3\ e¦¥BÑ[Õ¹\90UK;fû«\8déª[jw\16\8b\99%\a©\9d;îôÌnFs¦\99½*\15ªÉò¶ùìP<\97\rä\93>,gö\ 6Ï\9d\81|*\94¦î\96\85&ÎðÀ¾Óòw\1a\83Øb]}\9e\8d»kòõÖGö7T\7f8EöË\87k58Ì\1aw_0¦\99  $ª\95\0-ãX«\81ý³\18§\r-õ¾"Y`uÑ\9a´>dfå0ïÆèÒ\ 3\18¾\88\84\13\150ª³[\80·O0\8aï\0Æ6´Xzð\94©<®ÍrË\93\90y\ 4\87.Îë{\ 6§5D\ 4-fF1ÉL\96\98b\11S½Ï#ÌbvlHîøGÁ¶$\ 5éÞ½dW5\10ûÒ¢    Æ\83_h°?Z
+A\19Ù³\16\1d&:ô»\b2è²,[\81\95\ 4\1cAR,bÚz/j&ö@\v²mZ\82Ô\17\13â\ 6o-%\9a±ã÷\93*\91µ;,\8e¬\10f[¶Ìª'\8b\834P¤ç¸Ì\8eÛVô"\89ùU /f­\9eѲÓ5ñY\11Á\82\91òP\97f\85ç\ròlî\1c\9e\13  jk»\8b¡ZYo\18\e2§Îü\95\e\12Ó3ww\8cÍJ\b\19¢P\95\10Àw\80ÂpíuD\1a\18t\11N¡{×\1d\83Ïb\11¤TdÛE\17áo\0\ 5\8câ)a:Ì%\9cL\93\86E8±í+Ñæ\9a\87\f¨Ä\9d=DO³5\8a>\a\93ÉúÜ\0¢©\f8\85ù\90\16OeÉhÑ\94bZ\92\8b\bj\9dM\1aøZ¿\1f\a0öúªã,¤·\ 3ë0Rä\ 1Ü w0òF÷ÉÞ){\8fä>ã\14õ\90\ 1\90
+²Ã\b,\86$8¼zÞ£TîÞï´4\ 6ãw¦æ\1f~õFÞòÐþ\87Ëm&ëkp62tÂd\1d\1aó9\1fÐË\0SNM\95
+üÜÿ\ 5rVs÷\8dÚá¸xVêGÒË%G\8f\1c\aÂWé\vØ\10)Q\8fum\vs\89\ 1f×ÀÜ\7f5A2¨Ìn»\17\83\7f\10¥bêA\ 6?
\99\8dÚ|Ã\9b®\10\83Ú¿\19c6öõð\8bHæéK\ 6\93\14Q#e\0`{\9dûF\80«Ûì¬vÜB\\80ÿa\84p\1a\9d  jÞ_ö\88bÀ$\80\ 4¾!|¢hÁûa_ç\10Àû\9c\9a\87ÿåé\9a1\16\89'bÀÑ­çoÀ2*\87|;Ì8Úi\eÂ\1cÛ9\ 68\86Êé7\ 6RÒk\96\1d\90å
+ÂUÎ\17¸Ú\93Sgó,ËÄë[\9eËðÂÒp\a\9cv\13³\10\1dÙ)\86Óf­Ä$\98\ 5ähvc\0\93סµãßú£à;®\b\ 6T\13U\90º\95èuuo\ 3}hJçop(\96\86­pZ\ fÜç¡\97\f;UD^\17¯\eÕyo£\96\89ëØ\91X!8z-3FÝ\1dïËÂ\92m\97+±òc¸KÐÀÇÛRú*Ða½ÒüËc\ 4M\ 6ð]À\ 2-ý7þ\7f1Óÿ\a@¿«¨ÏëéÓjú¸\96>¯¤ÏëèÓ*ú¼\86>¯ Ïëçóêù¼vþõë\fñÏÍ\86(\86wl«¾è\9fù³t\10æ¡îÝ÷»t\eY0Î\1cöÒÿ\16'\ 1\90µ×ª5:\8cÿye\1c¿¾ð\8eÔOc¤Ùe?ºXã\97ûn\87mwÙ© %ýõs_¯\8dDv'^v\8c
+w'\92¥í\91ýÛdÔ¡\14ÇN\16\ 5\8a\9fy\16#\80\81
+\7f±x×6Æ !âGð&7â|÷Û=Üí!)&±Í\8b«\19·çŪ\8dÞµ¶)/ä×õ÷Ê\ 19"9\93øà¸ëÎ]W!èÇ\90÷ýÌ@1\e!IÇJÎñi£+3W»Ô`ÓuIfî¶V7\0]§¬ÔO;w\93Ã_í0ÓY\82°\19\fZ=wn\85Ã`d=¼ð\83\8c¯È\80ú\9e\11ÖO·åï\92\9c!NO\93\86\88q\91ïS³\1c¼°ÍÍÄ        fÿ*¸\83\7fì_\17§\17º¸µð\1d\14ÈG\vÖ¿\11fWÎ+g%K¢\86×Z\95\v\98ÓBt0]<\9cY«ÃAï6+\1d\9apíPå~\87ô\12cvÉ\1c]"\15\9c\12®\ 5B=\98]b1.jgOA×Zièñ²1\0t\1f\ 5\ 6Î*#\84\88°\9b\11\94¾r\1dFXþ\14Ì~Áâ\1cçÐ4\1c®\7fä|$\8dâ¢f0\89\9aû\86ÏY\f`¯gë\96ó'Ä©UÇa\80\8c\80;¥è#Ï\8d\80\91¦®AûfÇ\9c­î¬¹ß¦\18\13c¬Ü¶GE@¢Ê`\ 4\9cò\94í ÊV~Ñ     \80{óNÚ(\9e\95\93\ 5DCí02üª"£Õ±ó#²äTêa[M\16KfÝ\99é¨qÃ\1d\83\11@\16kòs¶²\88pëvê\89¢\94\9bgУ¬sqA\ 2\1ey)?gÒë\911ÅUØqOáÝëîa´\ 4\15÷\80^\8f\1c](ÅÕ7#\ 4²0\82'\87U¢Ý\\171\96\9b\98ETET\9dëÕ\ 5é\ 4è\fÖfõ¼4)\ 4\1d5¹¡åÊ\1få\8cYm++ûë\9f\1d3u@\eÛ1:vÍ\84¤@w®l7p92\98\93ÝS\85°ÊÃ\92Ý?'xîñÕàÇlþ'ÝÄÇR\92$\1cvÍAÜ\92\99\83­ÀÎðSF\16ç¤ÞIL-\89\0"Ê%piæ\80\9a\Ó%a\aÎu=
\86ç$î´\99_s\8a\1aÁ\19^P`+\8aç\84\16\96\9bùW¡\15\0×R\aª\1d~\r-»§(cWX`ÜIâ[ýô'B\93EF>Ö
\0\18<YÕ·3_\8f6\ 2q´V¹ÓÜú\ 3;¼pö\8c\17jn\eB±x«\81®g#b\8eñDp\86¬\b¢Õù \83¨¸\vÔl\95=8\15/J\9eD.MÆ\86EL>Æê¥Á*¹38éó=3½'¹\r\11\9bÆÌ@x\fØKqj\ 6Ñ;q\80\9fkk0ÿqkÙõ\9d\9bò\10\15Û¨\b¼Mô\94±ús\9b\9dÉ\86KY¼zU%3l\90"_TLÈ\0{ÌWNÈ<¥¯\9bï¨\ f\\e\e»ÓMfë\19³'¿"ú\9d.F\18\87b\8fíf+¦°\1e\1e¡\8e\11£\13\88¶áãÐÈJ\1c\89$9ËȺ%\ e}ؤ¾Ní\fÞ¡\16\9b@]\8f\9e\84\83þ\8dd\1c)\96\85v\8fg\Ù\1f\e÷¦\9a\19á\11\8eIù­\1eF\98¢½Z\9fnîÁ'¼§I\ 59a\8fÑR~Ĥ7\1cuâh·u¢\10-ÌZ\9d±o\933$n\v·\ 5\90ô\96\ 6\ 6\97;§aØ\8câ\89+\17½>5=\91:\81\ 5\ 3`,Æ\ 4\v'cÕV3CXMçòqw\Î3\1fA\ 6\93²fEÓ\9ch3uz¶\ 1CjµÎ\14Y¾1Fp=ùèäÌð]ºH£®-±ÇÀh=ñÆ\r4«Åïg)\9dÙ\dd°Û¨©Êý\9c\1düøs\10Yue\ 2B\ 4ßT\8ct$h8ZMeONá\91ÎÈ\1d{\80Û6\86;Øî©\8b\8b\86Ã¥èÎ\90âD\81g]\9có`\8bGP6ª3vE\88ÎÍ°«D¼\19ûÜ\ 1n=\11Ðß8\aZ>¨OPzØæ\82Ó(®C\8cö\89󫦪©»äMpBªcë)
+zlM\9cç\94èsÙ\8d0ÆØ©7\9a\89\ fa&D¯\80ù\14QY\)òà\9fÏyµ_\8c\05ÆEE\86\ 6Xu       ó/\ 1bÎ͵g½FI\18y­7Þ¤£ºñ\1c¶í\1e¸ó\16ç\19ý9\eì\91~FërmÏSoÙëv\8fDgð7;úºÞ#\8b)\85\8cZOê¨ÔX$\83ð\86\87\97É }[9\ 4,\9e+c\ e½\ f¿z?U\ 4È\97\ey­A}]CÁ\rVap\1eð
+\18ʲX·WGÅ%ïºÉdÅymæ ãÈbI«¨zZðp\18¸ýɼ×Lv\97¶²?\99#KÜ\9aO\v|
\8d,¬ácåx\19]u8¹Ä\fçauÃy\ 2ýiGrªí\99ÙcS]\86U;ÜÕ}\rÝWó\8bús\13§ >^\17¾\99"<\9e½sY¯\82\831Â^É2£Ü\12µÓ\ 2c=ìNX4Ï9å·°ßk\80(JSîypruñ\14:ÕÔèâRnÌÜ\a\19á\94+úéè·°ñ@Á¸´,YHgoú²j«F4±@vYm6Th«\17Ho\16\9c/l\ 5ÒQÛ¯\0±µÏt>|mû\b\10|¯h\98\14õ¤Ã\ 1\88ú¹\9d¨ù¼À\ eeûr\17\8e\86mD\10öo\17\9d\ 5r Ð¼¦\14Õ²\0p9mÞô\83>.Z°eà&÷Éd\17\9c®íz !\14c<º\ f\84ç_©£ª«!¶ÄÕÞ²        d\92D±GG^\98h+\829\13\9fÔmÜ\ 4&\1c\93À\vÑ@\8d)¾<Ñ|ï3\16#   ºUÓBÛ'\b­Å\81\16¦Ø\94\\81Ùåe\8a8ÒL=úéwé}FZúú2w\8c\ 1rJ\9c9\1fBÄõTä\87\ 1 ÷-7B²¿\8b'R\ 5bc'3Gç
+ðòk0ºE\7f\ 1 \9dN\ f\1eÞ¿,Åh\80)\82x(\ e\94À\13\ 1ä¯ÔµßÅ¿\13c\8b)>]\vß8AB\90Ã8R\94>\88~@\8c4`d\97ä³i\82,#8\ 5FÏP¯ùy­\1d¼ÔÂz\÷yõÑõ\90\1f³d]\9a\9b\12.])\ 2\9c¹\89õ\18³\97eK
+\ 6A\ 1\95\ 3\89\10»\7fÌY\17CÔÞ\84Ò\98¬ÈÆ^1Â\9dɼ\19\81\f\8b\eH²u¶¸:HYHÂþâÔÁ\86Hû×z\17\91ò2x¡qÐ\1fAã­µû|\97{üÙÏ\90z\94»\18VÏçë-Û\9f¯\R¢Oª7\ 2¨\97ϺGRG1xÂÿL@ö½\9fª\8f°%Fp\16ÞU\1fÛ\94\8buç£BÔ´á\Yi<o\95«\eA´)\87÷\9e\8bÅ»t\8a\80\19Â\978\88\ 4)ªc¬Ö\8b\bLEÓ\88a\9e\aA!\9c\84\ euÀÜ\1c¢,ÃÂ/_\8dÎõ\1e§p\1d\96Q\93\18\ eÒ¦¥C\a\8aý\88©í¬É\96_M\ 6Ãà±(\4\89\a\f}FlÕNÊ&0PÂÖV\8a\18§\8cë\9dês`ѪQ×µº\97zäÜZÃujØ\87×\9b¥U`10'>\87DÒÌîæÓ`\8c1QÅÝ\9e½!\8fgêaöߥ¯\1d\ f\15¾q6çÚeaÜá\ fZîi\90\10öÊÈ;Ûwè\81)¼N<\8f\14¾\1cKøðÅ\16\99\85=ßÈç'J:N\8dÇ=·eB·\13MÅuoWߥ³áA\1f\96c%>×vtGGÛDLñ×IÔA6\r\11ï°1µ¸\8eÛ¨Å-ïø\81r_é} ÅöD@ëoy\9dàNåçzá!¶\80³\9dÊÂ\11õì\16þL!®¯Å\9b\88öñ]úZ\9d\ f\88"­ü\ eê\89;\ eÆw\117\98Ó\ 5\92ez\ 4FF¼¶Æ\vþKï¶ÈK}\o\82>l\14\9eÉ-\a\99Ìf«ûÀ-laæ¯\96\8f*>sÅ@\ 51*\0\eùOÖ;Êgÿ\8fñªé­ëÆ¡{\ 3þ\ fw\13 \ 6:\88>(JjW\8eã.Zw\12$\rj (\8cÔÎ4îÄváÚ0òïçP"%½:\19Ä\8bë÷Îå£(\89<<$U=Õ¡{\\r¼sTÃ\9d%ºà1k\rÖ®¨\ 4ëñ5¬O¹\8f\1d\8f5q#Æ\10¥³ÍÕ\1c,v\ 6\8e\93\89\93\r»\18bm:©MËÆÖ\ 2¶Ï:îk¾Ýß«ÛÓ\83íô\97¯ûüôðâæ÷÷ÛáíÝËëWïî>lÏoïÿþ°ý|sóñ`ó\9bÛÐ\86O_íï=qä"(Ó£!8°ð÷n÷Ï÷78=\ 4ÃÇ\19É\ 2ùR\993\ 5\87\9f\87\17à3:\8aÏ\8fø\98\8f\9d@gÏ°ê\8bËó»Ë\9bëw·\9f¶o\ 5Û\9e½¹»½¼þcë\81\9dµpÞ_\9cIl\aÛ7bò\9d<v·ã\10èéÅþ\1e\eæ¶\97xȸ\996\14#á¢$\1d@)Nfʺý×\9a:è·µ\86ÒEË\95áÑ7îC\930\ 1\bY\û\18&\14¯I\88ß\95Ð< \f+Ãò¼'OSQÍØ\8d\8bÄïBl]\0T§Â]J\9d\eIz\95¶çVÕ,\ 5\0\1cTÖE,>I\89v,\93\92\rø(¶Ò\932Nè\9aç£ôBP\9c©\92zÈ}"@,\99\8c\15*:\84`,\82oq\90k#M¿Ó
+#·QÉ\8b éUá1 r*
+R\18{¨ cR<ëÜ\89
+Uöǧ ]^ʶ´~\87OQô\80z\10á\1fÕ¸R\9fíÄØõ³ÅÂZ\84\ 1R°f\10Ô\88\ 1\9d·v\89µ(\rð$)è»\12Ç\95µØ\e(evn2A§8¨\12ÆÜ´u\r\ 5«ØµÃ\10n¨Sní\15`J1O©ù\8f,;iµz/\89Ü\1en{Ýþý\9f\84ý±\eàõÃþ\93³\7fµ\11,wù\12åø±î\95\98È\e4\1dðaç\ 6'=ü£½ÁÆ((ÕeFËkoÞÈã­<ê, Ã¿ÚS\1e§\ f-X×\b¡ÕÚ'ùö\ 3>ý       ìa£í§í×ßÜv±\8fw¯mB|\1cÞ\97\82ûRhÿnëÞëê_UÒðãÉfÞ\96SW\8fqÜ¢u"Á3\17µ§B\v¾ëçÄH]BÍM¼â\15¾-K4\81ÚqÉñéª\ 4VW\93ì\e\1e\15\87Pj©¹8G3)\1c·Ï®x´\ 6SX\9dH¿\9b±Ô¢±x$\9eº\81¬õj+\1aDÁئ\98\16u¶1Qp\9fêt¬\18\86\16\v.\8fàv"\98±EÙ®º &£WÁKò\86\17ëþ\8fíO\16WÈ&}µ4RÁ³E\19\òÓ\15£\ 4õlµÂYtNµ\8bàÎh\0©W­ÝÎ\91yÀÔPÍx\88\81\1a]¶íê!b¶,ɲ(õI\0`\ e#\85\ 4TÏ¡\93wÇýP©,SdÐ[\ 6\'\9e]5?\91Êb?ò§iÒ\ eªÆkNâ\0\83e\83ËCã\ 3§\1aÃçV\84(µ½§>Ù\ 2Ä\10´\86Ñ/¿p6\ f\92å#{JÎ\96=2_\8c\9cg.V\86¢ý;\98¤\90»\13\1d>%×(Ù9§ºæe\b\96Ù¼\14Yä¨>B¬\96\9a\94\¶ºI\96Ädkq\99^\89#\19\85\1e¨\ 6õ\80ùÕB#Lb¶¹Q¸\98&ìx8MÇÉ\e)\84èÒt\9cª·xuTm§cL\11JµÓÁÔg      Zòâ\19=Õ<K§Ös§q\föû\92\9c·R`\9a¿¯¾Ö%\82qù>\17=øHÁ2\88²QÇà*Ñô\96°Ð{3«pdÁjÒ[\99\99`Ícxm\ 5\9f\r$\8a³ö\1e\13\81Ö^2\1e¤\90\8a:\891èÁ\93\1f\18òR±T\96\9aN¬¦±ÄÅoÎ\16\a²¨ï\8e¤~ô|\13¨XÁ\14,²6Шg\92\82¥êö\12­*Ò½\92\ 2TU =ÈJ8gu\90L\99 \ e¡b¡%h>«º
+\13uRCTÇ\ e\1a\9d\15]1)HulZ\ 4ba3\9e\1d\8eå"õ\9aªËA\9dd\17´=£ÆYA\99BÔRøzx\ 6E\92õrm\a2oR²Mk1\8b\96ìt ¢Ïçe×¥®óÎØu\1a1GÖBH\92¦ÿ\18\8eäàs×\r\1að¸\10ÎAW\84Ö\vjL)©\aÌ|Õî\99X\ 3æ\94ÃL\96\1aX\ f9¹>\ 4H¦h_\85 \15±¬}¥d=\87âcZÒ¸8\1dÜ`1Z\85\vê¶p\97´Bå¾\93Zm\992*)h^V\90ïpà"{UVª\89\859J\1fLkg\8eI?Z·µWÒ.µÖ.AT\8dÔ¬!¬W\84öîIcÀ4³\10\18æ\v]q4\1a\80±¨çDÅ@\97\9cz\8e\1f'"¹ÃÐãæØaܵ\90qËÃ\ae\95\93\8c\86¥\86Ð&\97éÙuQ\80\8eç\1cÕ¾\8dJ
+\16.æD\v\f`2Ë\962GÃ\83ÐÔîq~É­\12±ÄàãôPJ²Ã0"\ 5È\9cmwÞ<@MÚùPÊ\8b\87\10\83áÞbÀ8\97ôÐ\92&+Àâ4\ 6_\1dM\ fÖQjk¡\8a9òfKÑÀh">Ê´7CðvÀìb\9a\a\\9c\85\96 \9a\17|øIµ\8eý\85`'\94Ê\0É
+\81Ñ<\96\15\v®g\1c\8aî#\936\1a¹\8d¤\96èca¹º\1cÌ8O\82]qæ\91mÞN3û\99Æä\r\fuéÃpâ\1f;ö]\e4¼ðhæ\8e«î/eg2eZf\9a!Cg8+=^ç\ 6(<ó\91ØÊ\97ªÓ£g?X\81\90\9bÒ\9b\8e\88àP¦(£Âh\80ìGb
+\99\ f\aì-â&´GhÙ[1\95\10l{LdQ\88Ö6õ\12l¹\\16ºÉa\14\93\\82©L+»,*ßt\8d\1f\96qñPЮ\16ª\98º¦Ø¥®I\v\92\rÅ£!vc\1e§\11\92au\90\82\9f\87\ 1m\94È?r\90À\ 5\1aÝ\14ç,\13\92z\88\8b\ egg«Q¬iUø\96Ëä\86ç\Fýgë\1fÅ[\ e\ 6\9a\17\1dD\86Ó\12òn\aZ\1dÔd\94@\81\16ÅäÙê.DOë¨\96FW\18óU\bÁúJV\19%\9amr\88[µØ(^'ò_ÛkôJ,\ eó\816èY\8d\1el<[<(É(+ÑHBàH3í°¡ú\ 5×>¤\9dwâÅdZ\11\85¡ª\80\9dê\8a\1a\ 1¬Õ@7õ*u\9dÛqZ#i\92¿{.ÎôF;0Ýc0Ï°Q       Qý¢b\9a¦QÇ%LÇM\15uÇ5¥\ 5Ϧ³jLÃwõj\fòµýÅ<À\92\97­d6\894<$Ì©^O\béP\14lU×Õ\8dèÊ¡é0s\99±w\8b\92mVÝ>Ä\1dÜ\8e\1f\ 3M\9a¸\8d·e2\1a\ 4c2ç4åpI¬\9e\89çP\a<\9b\14M\94ëô\8cÑKq
+z-\90É:¿a9N\86¹`\8e\ 3¯\92Z3R¤a)SR\9b\86\82è,)«\93X\8b)Q\9b§\18\15o¡Å\18§ã\1cÒнÊ\9f\182Éé\bP\9c\1f\ eÊ\98#vBãJ:µ\14\99\81FhM+vû\12ld\bät\ 4h­Ë6mC\168z\91êäÍv\19dåF,:Æ\18µ\+%uSb¶9\80\929\19\ 3\1ct}$\9d©\1a1\8f\15\ 3\a5\86RôÓsðÞìmZC\8a\91Ñ\849Àh\93(3ùéÙ\açmEϳ|ê\b¯\ 4íÎ\0c±ù\92¼qR\9e±-É\ f\1c\13\80â2\12\rÏ\90\88\86ã\85:áb3_ÊÞ\96C\ 6\e\18ââ\99\8bÍ®\90z\v«1ÔCÇC\8dÆ1\14\87q\9a¼cÇL2>.\1cc\87Ôtæ$/foöÅBöy\18\83\8c\8d \8b\85\10É-\9e½\v\1a\80¸CÄÅìËrüÈ>\8d\10<\9cf³É\89\ 6\9e\1asüÇ\1a\vU\97ððµ]\rÜ\e:sò\91õt$³\84×Þ\95+\8eìjÊÃ\1d9yò\ 5ûîêíþ^Ý\9e\1el§¿|Ýç§\87\177¿¿ß\ eoï^^¿zw÷a{~{ÿ÷\87íç\9b\9b\8f\a\9bßÜ\86{:}µ¿÷\ 4\14\80#tÞá\ f"û{·ûçû\eT.\ e\88\8f3etv®\98*@pøyx\11p¾Gñù\11\1fó±\13èì\19V}qy~wysýîöÓö­`Û³7w·\97×\7fl=°³\16Îû\8b3\89í`ûFL¾\93Çîv\1c\ 2=½ØßcÃîŦ=Üöºý\ 3¿ !\1d¨\frÂ!1@ùøæ\90°?v\ 3¼~Ø\7fr¦â):­\96 zïJL\94ºc\9fs\85ô\1do\1fí\rVPV\80\rÃm{óF\1eoå1âuÛá_í)\8fÓ\87\16¬kgݶñI¾ý\80O\7f\ 2{Øhûiûõ7·]ìÿ\8fýªéÕò6¢ûHü\87g\83\14¤\8aØ\9e±=nWä\86.Ú´D´Q\91ª
\9064\ 5*\ 2Eüû\8e\1fÏ\19ÏËåRÚnËâåÞóÎ=\1e\8fçã\8c\10itݽ\9b\9c»Éµß\9eç¾±Ó\1fèÇG"ô£ó\94\95sçLá\9d£½¬JÕ._òØ9\8aõMíµ\e\aü\92'\96A\97ÑÖW\85{\ eGH\ 5>µÎ¦âÞ@Uã\11mUZÓ        ¹÷ѾÖF\1d\94\9d|s½<ñ*8#i­fúUÓãÝ\19ÉK1è¡9U_'\19ÆÅ\94Á\ 4á^\9e½v¯\93\85,\ 2:\86Ü\93Ñà^\ 3ö\9e\vW¡õè¢"\81ûùÆ3hÆÞ\8d®ÙÇ.\ 65pJ\96ͤû\8bå\8d\84þ©ùÇ\96Md\8bÚÜA¤\ 6S[Xdí u       ^ß
+ÈB®8\85\ 5I_\16æÐôån"\80®\auÅâ\ 6p΢½zÕb^\8c=I\14.Õ¢\9d\82òS\9cÖ\18®K\93ì-R\ 4þ5Â\16©«%\19I\1d¾\9fÊðÊ\12    û©\14{÷Ô$0«\90@>¤\82Û\90f\83\81Å\96¤¬¯U\ 5éTÛf.¥[bc\84,\\13Ñp¢r`v$ϲî\19\89GLI.HjU÷»\92Ä\1eqVØ`0çf§\95\f¨¢   ÐT\89Î;*BA³)í\ 1&   \ eK\16'ñ2×ñ\ fPÐF\8a\8c\1c\98e\10\98wígma\1dm\87ø@x\ 6°Þ\81µ\8cÃj\v\8f\97§\8e\¶ûùKa7¶\8aU\90\ 5w\b       ®¸\94\18\8cEàqÚ9¤«Uhm\vÔýÎÁ\98ác ÎÆ°]±hÚøE¦ örGVMizus\e\13#±ºWp\11äk¶}@A[kÌÒ\999'$=\ fÙÌ\90\99óQ½7è$²ãÒH+\9e¤îg\8b|®Ãµ?©fíÞý9\9b±®gxÒÙ\ e\99â\9e\85×\83zÍä5\96:\a\91©+\13ìÉ\17Ö\84çËäÌ$LÁá-_\ 5/u\86È\99«to\93\1dÌ\92\91ʹ`¹UíÔ\83á^xdÍ\88Ù\85ÄG^ÄG\1a\8e\9fÏl©Ñ)c_­N.\±«p«\ 4\86\1eV¬Bèì2ç²í*<¼újÁN\92¼;ñ\bÛGÂÔÍ9ùª\92P$Uå \815oÉТdo^f³;\99\89\ 5¹¢Ïa.¨rá\90+Þ-zucí\b\10äÈcÒ:\17{{½m`ÈD&¯rór\1a    Su$»Z¹;?À@aÀI\19v\*\12Fp§Â ñr\82\9aèsáDyô\19¿ÅÐJÝÌ\ 1\9fKÌ®1F\8d\9d\19·%\1etÏ)\f°\ré\10\8f©Dæ\ 67j\1d\81yt\88MIðY;
+\16\19-d\80ÖO\15\9cãÏ\99U¸t\18\17>>FÛ|\97\f\1dY\ 5G\1fÆì¡×¨`·\9bÁ6»\82\ 5næÜþsNf\9bºÛjÏ°¤
+\9d\94;rõT\e»µU$öÈäÆ%!%\98Øi\eÁU\ emWÛ\81¹FQóèЬ¸q AO%_¿\9d0lÅÁ\96/vÙ\1dt\16\9c\87Â\9fûç\12\ 4\ 4Äd\8fãç\90\ eì¦r\91ÂYp\9e4çm\fcÚÌÖ§\14ä\8bâ°¢\99Ì-0KEúh·÷\14îÅï,¸³ê9ø\)ïÂMT\e¢F\1e\8b\93@\a)8\90\95¤\82\ 1 Áç¬o\1aZBj\fæ´û\a*\86(c*\9dõ°À,±©\8c\81ã8ËöíÜ ,þ\ 3\1c\1a
+4 '¦$¸\\8dÄ¥2jf*\ 53\1e\9e\83\96\18UtÖ¡3ÐH9\94¢»Ö
+\92ðlL\ 1\9b©Æ\ 2Æ\9d\19 \r\14C¯a\9e÷á\ 59L\aiCïÈØ\3\18T_£¢§êv\86\91HPéÁe\15¡ \9e\12ÄÆG!ôÌ\9c0Îu×°\ 1$Râ\0Ò$ºÆ\90³\9f¦n\0\90³\15;\83\ 6Ñ\ 6Ó\99Ñ.\b¨d4\9c2\Uèxµi5ü8\156°Ìu\133At7Û»X;¦8\86\81«òÄæZ\ f«\ 3/¹°ð9èÝ1iPø!3y®\82\8d¬\ 4|`Ô0z¡rwì©UË\ 2à\80\9aç0\1eë\f¢\8dÁ\1aö±©\84Ø\1c´&Rý9Ôt\14q°À\83Ù\9b\9c7çæNHÛ¼[\1f«ò\91\803ðZ¹o\9c\v\16\0\16\86\ eÒ\12°\97Ê\9dàÉÈ\88E\14\85\8a\17¨\ 5\15\9eáÄÁ.7y\ fÙ¹®b¾ÌÁå\92N5Ç\86\83¹¸P˹\17øbéQ×¾k\96\92Mêµ¼w'\95\88=\9b±Ng
+â²'Ãk/\117\9d\\97\9a·\90È\8a_]"Î@+\8bù\13\85\13[\ 5C\15í\1fάr\ 5Ìhvu­S\ 6&Üeu£zfÿÎ%Yêi
\84\ 2\1aÜ\ 4·Ë(\v)    \96s:xYl¼\87öÇ+0K%\93×\9bÊ,óâT\9dV¯¶/(s\8e\ 5«Kç0ü¢\13è41¼\ f     ³`/´É.=enCx\8aÏ\82^8ãÒ­\87¾:\85¿y·+\ñÌ\10ö\18ÚÚÆ+áÞ$hã­Uì\97E\ 2sc<µô\927sm       \8aß\16\1a\15Û\92q½­À©\ f¬C\85$\f\1fÁ."sRí¹X»\91Ì\1eh\98Íýº\ 5×\9c\8bìëP\8aS-#Ã¥\8dàqÙ\99\f\13·xí\8c\82\81\94\b\99yFmË\fvæ´ç¢®\b\ 3\v\98N'HÚ\91ý©²-\98Sê4¼GKQ\1aÍÉn)\9a¢4¢\94=H\ 1.½!\8fz\94ì\89áàÚuÿ²¾É\81h\88^þùƳãì\89sÍ~S\95õ¶K®Í©ú|\vÇ\vAùõ\rö\8bêÛ[\9f\8dãó;Ç£?|ÚÏ\9fß{úòÏß\1f÷^½~ðâ\9bï^ÿp|ùêÍO?\1c¿\7fùòïw\8e|¤CSëÑ7·>»\9d8iUê¼×\7fZÕ¿L\97ÿòúF\13¦ôÚîwîÔ¹\8dÖtCMúçå«¢\85zE_^µûí~\9aÐã/ôÔ¯\9e=yýìå\8bï^½;~>±ã\8bß½~õìÅ_\8fåØãÓ\9dï\9f>\9e¾Ý9~6M~1?.¯\93ÔÑGOo}Ö\80½\99Ø\ 3ý\98\1eISL[g\9a\rDæo\89Æñã\19È*\9að«
+\86&¨&Ésà*\85ÏJ\92\16¨\12®/\90f§øç2î\9a\96ëÁÕbj4\ 3m\82¨q\93b äb`aí}OÀ ÂÃðl\8d©ª°0\88u¯9Þ-Síf:\8e\17.¶Í((´ä\9e\9c\ 5î\8ea¯SXÛ®Ý"ÛÖ;îÚd»\1e\86'g>Ý~üf~¤ãáùßGÂùëePd¦åÛ[·\1fß\14\|ó\89á]æÿ[\80ÁñI!^Æ\9f\1ad§þïÃ|ûñOóãÛùáY\9d\8e{ÿ8?çÇ£·\96Ò³"Ïd\7f7\7fû\95þô7ÅÞ\1e|üæøã\9fÒñô\96~÷ðÿ\89ýo"þâ\fç\9bÿ°OäV,\12CÍv8³\8anszT\88Í\89÷åËô»\ 5ø\92ÆGÀüJ\92½Áà\8b\13\13F$òsÏñ¸ñ\9c\10D<\8e>I\1a\88Vëxó÷λ\8a®´\ 1çIÿr»¢¯\f\9e<â­.ì÷­t<U¤Û(\9anÏ7Π\9a
+æë\eì#\95>¢ØS\96Ê\9b\8ahm5\8aïÅcâ½[:¤´\ 4µ\82*k\8b\81=#£Ï\95Ì\18\bÚäÄ\19'6ª\9bY\95á0\9c%8\7fn\88\1f²gÇɧøɳ$êû\9ew\1ev£3¥­Â\12õ@\ 2PÀ<7\f÷üT<\16+       é¡3\9aão<{\86ô\11ÒXGzEz\v[æ¤ÁÈ\1c\15\9cH§ÆÈì\19Í+Ï\rBUÏ\ 2ÞÄ£\81C³3às5û@^'\11¾\9e/²^Ñ\1c\1c\1cðymóq\17 6/!ã9eè\aðA)âJ\ 6\7föS0\81|\14tÀî=tÔ\92÷Sè\ e\80§ \82\f\86Ü\f«<ÜåZ7Áõ\92°ìÔµ\13ö\1c®¨ý׫tÄz((9i\15\8eäNè\17³\7f-ðL°\ 5ê¦\ 1\19ë\91\vï"Þ¡\93\98±v\ 12p÷gu²n\86Fb>ôÚý.\8a'ôÅÞR7\92Ê\ 4\12j`®½\82AÕæf®âÆeGCñÄ\ 385¸ÇlÆ\8d7è]¬rx?õ\fã®ó\8e¦ö ã¥\11\13,g$6\15A\99\16ÂÓêýÑ\8a4\e@\1c¢<»NaÌ×\82\16U\8bØ;\9d/fYÄ\88r¡Ê!å\9aOèÙ\a,ië0\87ÏÙa`+F[fܯv9à8n\r\13C{\r®ÌÒ0[¸\14\9cÕþÅ~ÕôÚa\13Ñ}¤ü\87»©ÔHðê±Ç_°JÓt\ 1\81V-\15\91\10\8aJÓÒ\0IPHUõßsæËöM^\ 2\vvôI¹ïeì;¶gæ\9c9sà\1e¥ºt\ 6\0nFÎ\91~ð]\18\83§¥\80\88·\a\1eQ)9¶"\bÍ\8dè4«Åg\8fø¨ÈÄú~ÉQ)£òA=h\1e3ì=8\8dS\1c§ \vÏ\8bèhCZìi\91\ 2\1e´=óbÑäP\10Ïó\84£{àÙ\82,Æá¸\97Õ¨ÇÁrÑâÞ²·¥2ÆIóÈÄâ¢udÏ«    Q\.·Õ\86\85ÉvöÒ\12\aW\9d>\17\8eÎ\97òy\8f\12\8d\92çy?\11r\9bû¶½×hÙè½ÛÎ-GË>\1a¥\bÅ\11ûK=ü0-;¥x(s\8bˤº*¯z\v>ê«·vË[j~Ëc\99\ 1\9d    ù\1c\1eû
+ÑÈWe\ezm ÜÏ7Dq,y\vãì^\aPcm= ²ªÆå¹\96T\82\1f7æ°ÖC!\ 2ÙA|<.oÞ\ 1Å\10ÇÕº\1851\9d\ f  \1eê\12 ßÜòbÎVW(\8a¿¢\95Ö\8f\v\13\87=÷3͸¿s\ 3\97£is\8aÐq©Ëy\89à/2\93\82\8b\9eX®1O´Æ\10:\v\8eú\f¦äãÄ<ÃN3ó¢´èäÔGÔ\0În\87\87\8d\14
+EµhU\9d\85Û\15$\88gw@WAJ+üÔû\91Õ=\ eQY·Hy9\1e½.ch\17ÂÇ!\ 2K´¨\1cõ\ 6DÄÖQBx\f
+²O­ó)"ó²_ÉYZçI|\ e{0\1dµ£#B\0ÅCò᥵\15\8ft6ÖVBdP\9e3:]\8ab\ 6¤\97`\1aQ\8b\84n|\b¦\1eä\9aÆ.;ØÛJ¶Èêmï\81+Ì     \87\9d)D\89úñVÞ¢\ 5ed(T\14M\8aâ\98\87\f\87=6çSU¦¹ìõ\1c Òìùíòm`\98é1Écó¢ØÃ˹Yf<ÃFp
+\8cÔ\ 3\18©\84t\83ΤØYûÖR\80B8î©nÏèÏ\ 1ÅÖ\8f\13\11W¿\1eËôà«\85æ\ 1÷Ò2FýU)©­Þj4¬z4\10Ø)\94h\93\8c¼®Ý÷[¸\ah\95^\ f]\98BËV:ua\vÕ\81\88\1e!Ý*p\b\97Ä\ 3\97à\97>kÆ\8eñ-ÔÁØ\aö\16\82\bcRÙ\8eûX=Y&\9b\10ÏQz³×ÈÕ ´\86®Ü\ eù½HlæÝ\94a÷Î.Oç\1cNf\14ïqem_î¡\1d\9bú\9d[¹­îÎqQìëéçD\12S¤´õ\12\80I=\03[\råJk>\98½×\1305\86\*\a`2-a\0\8c\1eö´\ 4\ 3º9ßÒÛÅ\9cÃý¡/D\8aÏ\90\fP\87bÿn\91\9aKw,A³^\9e\18\87ýÑ;öoW[1¸\1a\1fUÏõ~sõÕÝ;óòá½Ëã?þw\7f\7fxÿéË¿|{¹ÿêõg/>ÿúõ÷\97\8f_ýð¯ï/\7fxùò\1f÷.tI\17t\8cÇ\9fß½óAâ\ 4%\rÕ\83\9f\91ʧéú\87l%%ÆØÕ\1evTLç6\e`\94\13¾\9e?É©ñ\83òñ\83ö°=Lbzò\11NýäÙ7¯\9f½|ñõ«\9f.¿\12Ûå£/_¿zöâ¯\17»Ø\13½Î·O\9fÈÝî]~![~-\1f×ÏI¸èã§wï´ÿ\91í½¾?xòÃ-\1féò\99þ\ 2îÑÓ\93\94\87Ö\83ÒÁÿ\12
+þï²\ 1¹ã\826aP  mjÙØ
+#ÛQ8\83\9böuü©óÛ(,`¶VS24\9a濦\eô\9czùÆ}d\11=
+\9f\8as\8a\81\9b&D\aKåÉôFF\8bÄAs\95\81CÔVø z£\ e2ª´è%HÆIí\11\95n*æ\1a÷:X\11       cÁ¸´\1d\0¹%ù
+×Fî£øvÜÙô\14l¹h}3øi´k\17Öª¸\9bV\96Ç%¨íá±Ðe1æ\e\15\92,\8d\ 2l²"\91áqt_i6Ìe¹\ fe3j_3#Qw#¦È\1d   \1cØMÿpŨÙâ\16\83\95¶`ÌÖ½`Sí\85\14\82²x; äLÇ3Î\b\·ó\90çAlFªSY9wÓ\88jÌ2Õ\1e\ féÆX\8cÀ15ß>¤ÔP+Hi5\r\97'Baz
+\ 2¥Ù<ó\8e¢{$+ßYÑ\16©Ñ,\1f\1då¾
\81ZLºH¬ÐÆV¡Nè6­'¬Ôì\1d\84\90KN\1fp+Üjó`\12uºË´ÂC²¸\90Ý\14ÆF&ùõú\85\9aIî)*ZßT¬K/\1f¨\81¤\11+\88¾'\87\85\a¢\1c²\1d¯×æ\a\ 6\e>$N¬©\90¬&S\11\b£j\a5¦1ôr¹ \11\10\99\ fPÛöA\82\11¹¢Ä­T\81\1dí\83ÈqÖ\9c\11\b¡\98¶CÇ\17\r\17.\12T'G\9fî\99´L\12`X-ï\84æäÆbÊWËD\93²|ðÍhV@\ 5Þ\8bVUÂû\f\890R·\18%\844\ef\0q¼ç¼GÔ»\14L¶#ÑlÈ\8el\10ï\16\ e¼\85\9b¦E\8c'\ 3\11ÊWúª¡É5\18\8c.2űç\8apÏi§e\e9\8e\90zyèä\9a\8c\84ÆÒ\9e(y\10\8e£\7f\9a\81>Øo)\8b,J\ 5Grs6Å\88Э\9a\8ahA+ô1Mrx¡+l>}\93â¿0´\8cÎJñ£       n\b\14\ f6úíFN\9b6î \90\85³\ 39 ¾BÕ¯«O\14ã\8e\18áµ.\92åÒÃ\99CG\98xXCµ·H_Õ\ 2\85=^EÞbÈ    \8a`\93t\v\14¶²A1½ÉòEu\81*ÎÍf\ 3éHCGX\94ÿ\14ù¾¢ës\15V\84âl\16\93\90·\96Í\18\95\9c%\9b\8fÞy\93#Ø¿\16[\81D\17ÕjÍGG\ 2ÍPNL^mR\87\16¶A³\9c\15+(ö\9eé\0N(<\1cï\*%fÈQ\85\8c\ 2,ãÄ\r`\96\951ðÚ\91\1d7\18ëD¸«QÙØp3\ 6;:\88è¸ÅD\9a§7\0üë¾=Ù\10
+RÊ\ e\90·b\14\84\1d¸\19\8d\8a¯àQ\ e\11\f¬ä\8eK\9bÎ-\g\80IÐqD4·\15\8dØ\8e\9a\1fFE¢\9cm\92@.Ð\97\13Æ\\99\ 5\11\1cÀÉ\86Q­%N=;×Bjô£Ì\157_ÊÇWò1·hJ\97ûÿôßöëñ\8f\a²DjªÒúÉþÿ\eüý7X\7f¼ðåw\97?ý9]\9eÞÕ/}ñ3Â~FØÿ=Â~ÿ¾        äÝíi    ;d8õ8_\ e}¾W ^§¯Hï~´W*\e¬D»Ô«\957¼miéHMÑ\Eö??\16\10\9a8ëÚc\99É=¶Bã\¡\9aü\16e¤éí»×\19\8eÂt}è\837®¤X0ùZ0\9e\1cw"£\ 4ñ/wp\1dÌÙ\8d<LíBúÏ6»û\80²ÚR\eÛG\\87Ù\15\84¢õ\v\89z¼õ\1eW×D\ 15\17\85\ 2ÉT×5\ 5æ99ûõQó
+ÐÛß¹J\ 6$\14\91ÍD2\9c\8e\9d\rYÉäC\86\ e\9c\8föÊl:£¡¸¹\9b\8e\92y§d¯ø\(\86«\92;YÅ\8f\9avL°\92\eu[\99i\1e\17fÉèt\948\84AV\18ù\8a½¢\86\0\87*ÏÓÓ0\81\95í\1dÃD1\1fýFhþÑ^\0\ 43\8bÑ>\8c\18`=s1Y\82WS\e^X:+\84\80\87ÆÛÛ\8dWÅ8r\8c\rÐ\9b\9eN\9d2\ e\1f­d\9f\97f7å
+\16è½G\9d`jT£\báî\8f¬5íGb¥Ô\16Å\92ÈwsÎ~k¦\12F\9d\9d¬\86;ÑvÁ7\8d\94ÿ \88'f'Ý\8e\90\rëTè\87ÝZ\84fZG\8f"CÈQÝ* ³ûPÒ3#\1c\ f÷QlÊ\95\9d\8f.iY\b!l·Á\12­H$ý/mF£äÆî¶
+j\89     \94eÖ[.ê\91Ä"S¡\19[\ eÔ+\99º\ f\8d2t\1d>0TE8r\19Þ\8f[\8aè%áo3êôª;G\1d¼} |\89Ý\a^;7U\ 1\89ÝÎ\15\9dá7\94N\9dÜ8»Í50Vàʽ\83ã¶w4R×\17ð\8eÙÑ··\14sM§\16Ñ«\99\11~Y> `zó#k7\80!\ 3uFÂVøRè!MúQ{XQàÛö\90"HzÏ~d¥\12IÇ<\19\8eùx\8btÆu\ fN&\89\84'J$]û\9b\19{\19îCÅÑò!åR£ø\16\ 6\88ªC\91jU¿\19~sëG\87]\\81ÞRS\8b\8ejd\ 6·\1c3$Z:]\82I\r\89Ýpÿàý\1ck+\10\8aÞò¡
+bBuí)\fg-\v|èªOÔä\89Q\10ëtH\8f\9b\ 6\ryò°*W\13\19Ó8\87ÚÒ°`äÞØ\ 5\1e5½:ò<\vþ
+ï$ʬ\14×hÉ\94\a\8c\80\92Ê3iz\83]E\152i\ 5\86\fB\11 vy\95\9a\9d\8d\bÜ æÜ8§\92\b\85þÃ\aV ¯«­@\1eN?\11\98\91x\84cHÇi:³\97YN\1f\89ºkôYÿÍv\95%Ár\83°\13å\95\8dÁË\1dÞýÏ\13\ 1ÂíIåWîa¼\80\96\12ö\85ç+\ 6p§9B|\0jk_?5\97\8b05>T{Æ{5§\96\1c^\83¿\9f\8dæVõ­áîµjtùt\13\vpqÜ\v¦ú£\ 6ød¼1½,zlò\1f@$\93O³Fa Vî\ f¼ûþ«\99Ü3=\82\8aí#¿Ðº\86ÍLpJ\16\92\9b\7fàák\83\90\f}æÝWv\9eIî@\0ì².Ø´jðn¡EºÆ{·\18Ë\9dM\88\vZ|
+\11¡ÿØð¦|ãn\9d^bëüé\93>O­¬g\160?¸B\1a\ 4wNÙÇGçH\a\8d\7f¸YG\83`\ 4;mO\1f#\1d\8eà\12qK¢\83¶fh\b\8eG4ÍYÕ48\99®úz\88\0+j\93+ë|û\ 3Ë\88ÅV0ý:Ò3Á\ 5 M5Á"Ýá5\8d_\8e\97ü]\98³K¼Æ±^\1c-\875f\97QÒ)\9bûðìùJ\ø1ì4Äè\9fH¡êæ)\8e\17£jAðâîþ\11ICS·`hØ\9bÑ\920\r\ eD2\fô\9b íäpÅõwy8mz{\rÚ\1fÄÓø|6l­s²K
+QX\92ã\0v}\1c¤y(R6k%YÃ/%S(Úi¤|\18Ú­\r6ÍòÍÝ\1a¾\92\8eëdfùû­tØaÚÙ\96FÊàüFÚ%'Ü\9c$¿©%dssðV\87'ÔÊ{®\ 2×  \1c\7f\1eÚbYÙ\98\0á\98ªN²\170\1c±\12ãÛix´£¹s/ñH\8e:ãí\91+½Oá\e\a#&è\f\92à\ 4        äÌ\9có\1a!¯!\94º£»j\84\a`áU Þ\90Jy`âÞ\1aÐH&UË'ö\1c'\87B\19\ e\90à:4ëh\95¯\ 2\ 6Rv-lÚ1\f\ 1\ e\90`\87R\13´s
+ô|øÔPÕ\9d+\8d¤ãaÐ:-]\ 4\87\ 41wü²÷×Zzæ¬]#pT \8c\89\rPû-±ê2æ\7fJ@Py¡zÖO´\ 5ý×o\8c·ê¡Àx\1eÛv\ f>x\9fóèxÏ\b:%÷\91æ\1cÛóÔÛ\8eºéÓCQü\ 5\8fü\õé\8b\8d\86>[o;I¯8Ö\95Æ\10­Ð'\v\8dmÅ#\10\ 6~©{\8f·\15Ö\18§F\ 4=ôT_K¹².õà>kl\98?|:T82ëQý\98ÉtÕNG9\93\19¯Ü\ 4Y:bp\ 3i[ÝX<êf®T\93ÊÔVª\9b¹       \8a\eôtÂ\87q~ɱS\8f¶úC\8b¥\90ý:sp\14\19\0\1c\15Q\83ÄÕOɦ\99½\946ºZ        êþ4Ü á\92ÿ+\7f6m\1aÀ\8f\e\83i\13\842P\7f\97\8do A¥ dú#-~Ådµ0Ë^x§\195ïDá¿a×\ fablM¸w\1di\e\1c<eÉ*·:¸\84\9b3gÍ[ã\14\8bú)ÉÑ ÿ0\9aq}9Ô\80ÎÞär\91ö\89ØÄ'}\179§(\ 3[£,ûæ@ú\87­,{LÿO\89lV\fòL\96Ä?n\8f\1c\91&\ 4\82KPNr!,Ö8\8f\8a5O(Ô7Û\8f\9fÃ\11±\99(D\1fà »\8a\8c \92\17\96 X\8e\ 6®©Í§)±¢×¨Plp«ûä\18t\9c²íz.í\ 4#\96\85\86\82É/Imi\89GKéȶ     B\bU_Ú\9eÆ6÷Þ'WLocÓn\ 1\94\93\1a Á\93&øàæ'\98ñ9ÚbX   \1eì\ 3­Õ\ 2÷\16\856¡CA^ú¡P\1cmæJ(òßoeÌhWÿMI\ 2bG?\ 5ÎL¨\0qQUýu\13X\19»ß\1a\995\1c<Ñ>\0\eUÐÜ W\89\1f\8eG"°P&\98®3ÈÚêÚg       \86|&\b\aEP1\1co\r$\rá\8a\8cûùÿ\81±Í\ 4_ÅÃÿ\9cðVX\bzI°\ f¥©\84]IÂFÇõ|DI£ü¯\0\ 3\0\8e\15\r
+endstream\rendobj\r16 0 obj\r<</Length 23138/Filter[/FlateDecode]>>stream\r
+H\89¬W[\8fXG\r~GÊ\7f8/\95\1a      Nçâñ\8cÛ§t\e\1e ½¨\ 5\11 UQÛ\14\1ahvQH\14õßóyl\9f3'Y\84@äa³kÏùÆãËgûæÁ¯>xö\9b\91¨ì$µo£\96²\8fÁ}{rjr¢æ\9a\96ø¢)"¦é²¹\88\87\8bX¤¸°r®~®KÝn\1c¡ö}$ɪÉ{\e)ëñ\8ak\8a°      «^\ba\19{\1a\83\f£´1\ e\fhJËn_æ\9a\ fûJÇçÍ5ÄYV\rUʦ©#\8fSÃ{É0ûüF\85\99æ\ 3ª=Y\85´§\94\9a    ©årZTw\11C\87&\1fÇs5àº×Ôúæ'{\ eai\17\8cÒ\88L3\88ì8|\9a\8bÛѹ³\v\81;o£½À}'\ 64484­øñ2,Ð\10\96Þ¶ã¤cdN\8b\1d\99iG\83Ïìx\1e;\r\13ö½¤4\81s\87?Æ4Nö$å\8c\1dQ\1aÐÔ´\ fÆ\ 3TH{\13Ò§#Þ\8d VaE\16LàJ\16»\ 3\ 3\9a:ߢ\9a$g\16f<(±Æ¡òÎ-\93\ 2%\81cY\1fTak7³Sߥu=Ii\aÎ\ 1\ eEN3¹(ã·b§\19\8f\94nÂÆÕ\84\rV\17}
\1f{>1 )¥¹FÑÃÀ\ 4ç\96<¿Aö´Q\1c\88%Ï+\91\Å2\1fvpMS\880¤ÚV\v\91ãl\9aBt&94}ÌÐ\91&¤L?¦±÷&Õ\85¹t\17¶ÂdvôÚ\96÷\ f\94|\12Ópëåt.\ 2\96YÌ     ¢IîÇÛÌ8Ø~ Ë\8eÂ\9fïG¸\ 5      { \v|Öºk\12\9fÅ\ 6M¯YLC­M'àÊ4:\99\10Éä²ZeÊ\90eÔäÌ\vä§Ôæ\1ax&\8e'ó8\84Í\8aGO¦\9a]\98V\8c¼÷dÎ\1d\b\95_\89X\91=\92\11 £7ÍB\9a5\ f¿\8a²Ã\9a\9f½»Oà±\93k é½zPQÈ\91ýTÍ[(ü\96g%gxS&\e"\85X1\ et`&ó   \18´Õ\ 5½áó.¦A\90ƪ¡Fl\1aÊKÁ\80â\84=Û[x\a>\19Ùk£'\v4ê<çÑM8+d\1aô\97à\ 6\14Ù ±Ê\93TëörÑ\18¯MM:\8bA5µ{µJ\9eÙª2³tÊjÞî\ 5¿Ü\8dH\ 5§\fc¨¸\eÑ\ 5\ 6\9b\ 6T~Þ=5ä¤PJ\9e\ fW¡äîBKÁ÷ÁÏ»ÿ¨?dûðáöôOÿËß\1f>z~÷ý\8fÛ£W¯¿¼ýê»×?m\9f¾zóÏ\9f¶?ÜÝýüpË[ÚêØ\9e~¥'?H\94*\b8£Í$ðúoÓõ_6\r¼\v\13ùqGjubaîTÒ\ 4(\9f\81\19é¦~zÃ\8fùq\9aÂ\8fpóg/~xýâîö»W¿l\1f«lûè\9bׯ^Üþu3ã\9eM\93~|þLí{¸ýZ\8f|¢?î{Z\82ÉO\9fëo|jÔ\87\1f>D\eF×?\ 2ÔP\9dÙH\1e|\97\8cX[±F2\93²³\98\10$9\86sêäå\1f\1c\83\1cÉÝfÑó1§ h¨-C\90}tk\ e\ 2î   \84Ö\8dÔ¡Á\94Q«Ç\1d,Ó¬Ù\15ï¯Zµ#:±t9\8dÐüJ\93ò1¨\8cn}\1e-®2\17\13ÎY(&\82ê}¾w \ 5\ 6ê®UÓ\80\ 2\8bÍ\e³tÛLT\8c\ 1\89\82\17\95zÍm#\83Ý\ 3Cù8Í\96^ñÜdE\95t\90áèTbý5Õ½;ÍÏ©ç@Ðæ\15\1c5\9c\ 1\ 1\9bÄX\14\15q\9aÇ\18\16Í,çÅ
+A\98ç4\88ãÕ'\16\bÓ(NÏ\85\9c\98ÒBÈè\1f\8770úÙ¤¨\1a\9de\82ZÅ;\1cØ@\82@[\10háÔW\8f\16\11ÇE\a\v1aÒNjQi\9c=cfË>"\9bÑ6\863RgëpàÀ9xÎ\¢Ô\8bÓ\aÆ\94¾¤ù¤\8a/ôGF=ÝÞÝnYr\14FÚ¾\9cÿ!  \90\95èt\ 4¶SnEßÆ_    Ìþ÷sºÆÄ3g24î\86È¿<55[Þ%$\7fµ¼kJ§*ÔÉÊY\1d_\8e21àsa\9c\8c\17êôj\81Ѿè\\88/K\9d\95\994Z\12½\94çL\ 2\88AéL\1aüÍÚW ÁÔÀÝc¥\1dÐd\9d¼££í×\19@\reCY\1d\10\14×0        9FOÝ_Ò)\1a¯äI\ f\0#ÐÝ
+ÑeN(ù2\8bVnÅ\84Q\11È\ 1â6\HeyÉ\91ÔÐ\0|xóó\91\v¿\ 5\19hG\1c\93OðÛLò%í\86T?.\94(\8e\eCèåÞÙp\92\89\x!\943K\95PΡ\1f\ 5I.̹ù61_0\85Úµ\8e¸jj\15ßJ¸d륬\13h5^;6*4>\9eó-\84­Õs`{?ó\9e\1cíïÍñ#m_ÿ§Tþ½\1d\80úí\83 ínÛDÕ`àöÈiƬ\87±Ãj1é ýshð@*e©Å©ùæ¾æ\9a¶Gÿðÿí¿§o\17{µ»Îvõ\8býý;üþ7Hßn´}¾ýùÛ´=\7f0?úúì2ÿ/s¿¸:ïÍ\7fI\ 6@ÍdcS·\f|y\9f\ 6ñ>GCÕtö\86\91ÑÃ.\9a\19`\7fB'oÐI\19r¹l²²i´:VÈQØ!שkjªk°Ý̤^®Àt7¸n÷Þ{ó®Y\83\1dH\87ÑÕ*\19nUFÒ:\18¶Óì§uepa\1d\12ö£¦oN\f\f%r\82»,Õ\98bG?\8c¼Xqµ±êã\1d\86\98NÒVÍh94ã\1cÔßÿæÉ;\90ÈAW_&]Õô°¹¤\96WHFI»Ï\9d3xöÑ\b\11\eSBHÆ\ 2\11·\9b\13\83F\968¾l4Ð\14J%\à®-pQ\8blÃ4áÂ^\8eDSá\81^¬=\98&/+'4,ų\0
+Y5=I U\1a\97o\8e\1c\9b+¦ }Y\9b\10\96È\95¤\eÛb\11Ù\8cvϽØ1Ã\13M\8a\ 3¥QWc,9\ 6÷ÀÐzXòkô\1eù%e¬õÁ<¢\80É\86=\b\9bÒ\80\ 1\15\97Zø½É5{K\89
+àKYV®\8eSªD
+SK=ê¬E²SÜ\aÿ-ÈÄ\95\82\85^H\8a£Äx8\85=\ 2!G±·\92ÃUÜVð\96\83NJMm\ 5o6{ªFS(<\15\1cS\86\84§:çHàÑ/èèå\81.\1c\ 6\ e:\1c\12\b£¥\1cÅ´"H\16Y¬XR"÷\11Û\r\95È-êA9\aÓ!i[¤3\16´5ßà¾\12Õ\9b£\1ccóì
+\16\85\9b¥\87\90¨®5z\1fux\8d¶àRÂÜê@Ø5<\10\94\ f\19rÖem\꿱\1f®£^°{\ f{\90]öNÒ\1aso7Pº\v[      ûz«r¢ë:ÖýÚ!þPl]Ͳ\1e\83\93S\bæ»BîT!øü\80h1'ªFW´'§\ 6ÂÐà\90\ 3\ e\9e¸[Ö³v]_\ 1\12Éò|\1dZm\ 5Ðãk÷d\r®\aN|\ f\80°§â\ 3\ 1Ø\80\e\82\9fTÎ_ÐA®\14ó\83·\16Æ£c\83=\8a^ç[#\ e\1dCs¿¼\7f\88_9Gøåýí°\1d\eP\ eçzC\1cÇįaè6­¸ÙK\80¸\17¿\17ógñã±\98\8e½g¯yD\9eØÍæÖË\9aBRØ]Þ\92-*\9a=Þ­1(w[Å´7\8dîþ\18¹¶K\8a\ f#«¡g\8ef\93\8a\ 3\ f¶a[\9b@6\12\94\99=K¥\15ÏW]G\ f\88T9ûlçóº2Ì 6ád\98\95ª¼¶Å*íJÈbC\8eÏ;ÒÝ\8ckÀ0:dr;°w]è\ e{\90ß{´*\bëpôF#\84©%G×\95u\ 1O-Ö^\fÿKCM»H\98\8e¸\1f8Ô}´eÄp;Nº\19sËZÑ\93\8d\1a°¥¾\83Þ«\7f3\97;\17\ e\1e\ 1ä\ 5\ba\8b\933\8dn\16\f¥µ«sÿ\1d°Ó·Ú\91ë\8a1F\vÇ\ 4ùBÈÜã\95900Ã\86§¨õ\vF©%49ìÀ\12ÚÜ}Í\93\18Â\91Ü\8e,\89V\8cèG2[±Ë\12å8M5\845\96\8bª;êjF\ egsªmuöHa`Ãä~Ñ\1chMäxi)á­6\ e!E\99ð¿X¯¾\1e¿n"ú    ú\1dî\vR#¡Ô3\1eÛcxJ·á\81?mÕ\82\88\84PUH¡\81f\17\85TQ¿}Ç×s|Ç¿\rEBäa³;ã{<¶çÏ96x¶}{¦àñ\egõó4ñ15Þ¦øJ\9b\83¼=ec,o±)GO­+\v      wÛèJq!\18¹o\13Ý`è}à4ÙÆéѺ¨AªÝOZZ\ 2ù¹V6\89¡\ewI(Ϻ+\18ã\91À)\15e.=ùSTZýCróÐO6\19ÁWi\r\12ã=EW\rÊ2VZ);\86@\80¨\84ÈOz\1f\ 2l\84rSf\1c´\8a \96ÁñÁ\89\18[6Ý\9aSãUnãQÀgQ\98m(\fð%Z+ó\86¡6ðBS\89|IñÐ{J[sfE\98²Èunëf¸ÀÖWû x1Æ»\8aÐ#\88b]ã¼$A\1d\9aÍ1òÆþkÂ\8e\92{Ùµ\ 5r]ÒBoº:EÃüQBv²ÄÇçAþ%\84¾Ï°\bÑ\v\9a\87°ll\8c*j\933É.\1fË\9a*Kë13&Ss\8a68áÕqÒÎõV\91§!<|Pgò6\94L\99ø°¿*\96¬\8bGÂ`M\fM®HHOóX\ 2ú´æN\9bǧ\99ÏñèQPA\1d¼Å\99FMÎVzvÒhÆÞaL\91\1dËäÕÓ#{D§Ü\98è\9aÀcÎëóó2Ðm\8d\13\93N\e?:ù\92\83+Gð\93sMð^Êæiàr=\97µC'_n\8d\e'Ím\19µm\87j\15\14la\94§Dä·ei¢n<«s2§Á`\ 3s4ý\87å\946æ|®\9cßp¾ñàALV\95è©\9ak@srZ°\85\\14\Kut©Qf\9a§\81ú\16i=¢\9b\10t\8f°?\95\91sW\94¶e-°%\ 6\9dÊ{Î\ e\1aª\1a©<¸\9a\91\-Í\81rW0_h»jý\ 1\ 1æ\9c#x㲸¶÷Þf\19\9f\\80\ 5¡KÉÜ\ 4X»¸vÒ¡ÆB\80'7\9dß(C´°$\17 ç\18Äñ!ø¬Ço2A\b«sÚ\1e®\15DYMÒm\8f-ÅÁ47(\11)\0Z\92ÒTE\16Wxgc\ fûre_nÌ\94":\13á\eèGKáª\90²\90\ 5fÌÍ1j\15\8aèÄ\89°/ÕXd}\85©ìSß\8cYý¨"\84^Ö®\b·\ 21\8f©\10÷\fy\16Ð\8d\94Âc.\aª
+%Z\1aaKËp\189oèU+\82±`#z5v2=Ü3ú\92äµ¼\½
+×.CÖn} Wv²ÛØôj%|£\b\9dÚZn\r\1dM^\11F\96´¡Sb\8f%\9bp½iå\8aot{\10ËN\8fÕ:y\89£«\15Y\9eâÝæo×Øl©ûfd\98Çëà!ØcÞ>úb\a\1cú\86|*¶nWù:xvBûÛÿøÍ\ 5ù\87ñ£\1f\1f>9^üñ\7fùûÃg/\1fþòÍñìÍÛÏî?ÿúí·ÇÇo¾ÿ÷·Çï\1f\1e¾{rÐ\91\ e\17\9f\8f\95?³vb×\9d(Ù?\93\0¿Jû?\9a\1eë\0v\8dõy\93f\8c¢vÓ>Ö2O\0þ\84í%îòÇwõy}\9eNãG¶ó'¯þúöÕÃý×o~8~1lÇG_¾}óêþïÇ\fî«3¤o^~5â{rü|,ùåøñ¾£%\vùÅËñ[½<.u\1a\88ÇIE×½WëûɧÙ9s¿»¸$Ë,Î:Ê´Mϧã\aYp÷\ f÷\auÆ.߯\1féøâü϶´¢IÖ\88\8d6%K[\e^öW²¢úÍ\`îw\1f oJN^Õ<xî
+ÐÆO\96³½\8fá\95ê\15 íà]ÌÖT\83==_¾ï¡Óñì_þÿüïÅ»\10ïxéóê~\98\7fÿÚ~ÿ\87\1drüîøÓ\9fÓñò\83ó£/®4ÿ\7f\85ûé~y\1eÑgÿí\ 6ÿ\19P\99ü\95ljJ¬¨Æ³ÛØ\fcê±¢ |í\e\9b3\9bgG»-ߦ½N7K£m3-ð\fÎ\17!¥U@\96}³:{E5Và½öÌÔ>\8dÔ²\1eïÝ÷î&,MSØ\9a»Z\18!,¥É\99lsJÅÑl\8ec9;3\1aF\84Ic\96Ü\ 5\fÎ~'6tWD½"Ì
+ÛM\18{\94¦³rÕ°Ãëè!\80õ¨+\1f}sÛ\9fÁ\89\16\11Mýy®é6%,sÅs0»à\1dêMKXìbO§z+S\18\ 4-\95ý1Ì\937\89i/\8f\83øiÊ0.¶l2U*\8ccþF\ 1[Øcéqv\9a\83\8b¿BÚx±yòì`e2´àiª\88´æì{7\9aüÁ\80J¯n4ê³jS5\ 6T\95=/RÕ\rÝH\152&1N\96-[ÜÈ.4­\93æ¢H¸R#:só\12¸ÆåôXºº'g>0#ÓÊĶ².÷\ 5Þ÷Ä\15\9b"\8a\95§þ¸£&»\0\9dªïÈ\ 4SA\vÉ\83E\aì^p-y´¹8®5!p%]@«=\18 \82\86X;mèÚ3ÐcÏ k\86\r­+Ë\81«ê°µ\ 6[%lXêö 4\98ö\}%\ 5³¬å^ãc\0*N²\95\80y\94ãC\84øD\15\91§+»L \86æ8\8d=]ƽ\ 6zG=öÞÈë\88x\1dh\88\8fÕ\1e\90m\83¼ßýtãpOË\82\94k«ÚY\91Ëä\1aÊ\8c.      }e@\17J(
\1aÑAÄÇC¯^bóηL=ÍÛÍv\fòw Ò\83^ÊÆëÛ\9a%B¾Ü$.\1ey4\ f'îNFq¶\8dáS^u\98\9al$Ü$'¾ÉàÛFî\18G]èY%\87°#ÅW¼Ýy]\ 1½h[\r\ 1]      \89NÞ(ÊSc\8c-,\8crQç¼\19]KÃ(\8d\9e\9e\9cÏï)Ó²«+Ó\90k\v\1dBd\1a¥\96\f\8c¶ÉTÎ\98\r:f¿«<é«F\vCË¥ÕϤoª-a¢\13¥%ò\12ʨ\18\1dvc¡\8b\9cÔ]àÔU\8a£\9f¹\82¡\94A\15\14\19dÏãa\18S\92-\83Vgie-·Î\ 1Ñ\82\1cÏÖ\rÔ³ÁμaPÎNñ¨®\82ë      \93º'? ?\1d?\80\91·Q©Ü}Ëĺ\rö\96Y\0´
+\ elÅXe]ÅÓÆMN\8cÊ%¢\aÏ\90
+\ 5Uhã\15±\9f,~êC\16\18\ 6"\9bxG¯\b¦\94¾¡÷\ 6òkZ\b\84\9f\95;\8cÞ\85Í8Æh@7\82Ô°\9cåø)àÚ\ 5qÄL1*Óº£¯§°\e*8cGë´Qå"wdb\ 4\90ä«S[«­»xª\85î+\r9|²\98Ø
+\vR¾S^Ë9!M$Ë\ 2®\19áÊÖ¬­ix\80ygT6~\vÎÎÛ\13$¦ÇçTÁj]ÆJÉ\9fÑ\bÆþ\ 4¢Ø\15íÁ^=M\8aÑ,\\98$ûSIo´¥\88¬Åz\93Þ¤ØUë®\82åùB÷\9efF¹)\1e\81^7t-H+\9b\14\e¯Ó+No¬\11±\97L±¼S.\157\98ÃÝ\9a\87\17\10X\96\19;ò5\e\ 5\811#v²wÞ\9a\ 2ôtõ\1aTTÎ\84¹vVË4\92î\r¨wl)¤1ÂSËø\8btàØ¥ ]-ð\9c\14\87,;8\17AU\röáËûÊÃÖ\0\9c\ 5UvVjÀÈ=Q(×\10`e¤çÙÈ6OzÜ\84í^°¼\89À\98;Ê¥\95\8d\1f´¾Ê¶;DzaÐ\90ÍT\b\18ÆêQù\83ë\a\8c\9e²¢'l¡\eå\ 5ø 6>~8£ÓR\ 2=0µã#L\95÷\11fÉõ\b\83híhÁÀXQAg\v\ f\18v¥>ÜÎl\ f\14#3¡Aq_\Å\ 6µO¼¾¶4Ê\84\95T"¸dPýê*P¬Ïê²at\eíñéØ6á"\93\80LÏ \r!<­Ð\16[ÖÊ\90¨¾\81µ?Þ<\1dãJÐCm\87Æ\8eS¬p`ìÐ\11²\8dÚ2.Õ\ajÙôá`Zâ¡zÓ)ë\81lqg]FF\14£\9b\ 5l¢ºBÑ\1a±/Vn¼J7\8fÀS\8a´è\11\86\0\11\15ð,+\13\7f?j\19\11u½ì\ 4Ô<\f\1ebDwÛ·Ë¢·\12ǶyÖ¤\1ac0\90Gã4\97cûD\17%$j\8c¨<yÊè®0ZËuZY)j9#¤\8d|¹Íü¼ÑÙ\96ÜS\1aï\1eçèeê      ¿"\9d7Z&et£\17Ðø-oûÖ\ 2\8c¢Ös\ 2ºQ" £U\96)ñÜ\98pªÙÅÊY%1×tò´A¬\13\8a­KU\9c\93P@Ê       +Ç\94     \ 5tyÚÖ<e^ÓdèyU§\11:\8fåäº^ß®Z\f\9dö\ 2§4\e_yÔ=l2¹§uݦJ×\ e¹ó#ûU×[Õ­Dß+ñ\1füR\89H-øc<¶Û§\10Ò«ÛK/\b\8a\1a©ª\10\10
+iÉÉU\bEù÷w\8díñ¶ÃA\15<7B\87sfö\1e\8fçcÍ\9a\1e\0¡Ø¬¡òcª$ON¯ÏiAfY>º\973*@ãH\97\v%\ 4\18\ 61h\fBÖaÀ\1c{U 5\17ëLZ\09y7[\8fluïè\v\16è~vzÑm\a\b©èzæC^\86YÖ½(Ëì\9b§mLÝ\90 h\97u^\117\82\96Æzf×Ié´\a2\97Ås¿Uºò`Ìr?:¬x\1dp6hÕÖ\bÎT\86\86u;O[¬+E×BÌ;%ÔÅ\8dô¹\10\95(EÖü°]i\980\87^Âv¥aÁº\11²Eá\13k\8d¥uu°¤®¦^\1f¿«ÖM\ 6KF0Îg\8d\e\1a\9a
+ë£wV\93¾å¾QE\99Üç\93f¥µ\ f>ùÎfò©|\14sûÀ\9cüò%¿o\1f\9e^¼xe\ e\1eî\1e=¿zcî]¾\7f÷Æü|qñöÀ8c\rJòä\91<ùµ%\8bî\ 6ÛÀ\1fðá\a»þ¹¦A\99ù\14ù8Q
+\89¸0'¬\1eÕ\80¿ïÑîGáÞ\11\1fó±­Â»8ùþÙË«³\8bÝóËkó\9dÈÌÝ'W\97g»×¦9÷¬ºôêô\99øw`¾\91\97\8f}W³pùäT¾ñ¦é»H°ºÊ        ¿\1cq\17P#íâhÙ¼U\8d\ 5FhÇ\82\13\97¦ù¯|88·»Ø\19\10P=å};ÿaýO01\1a\8b\b°\ 2~Y~Y\18ù³\9b\8f\19íÙz¶ \95àÜù¦ÁjP\9dÍm\8a7!(lj (÷\97>\9eÐ@­\18ñ\8cpÔ.ìS\11\8fsö]\98\9dïBO\88ÂËÍ\ 6ÈV׸\ e¬\11\8b\b{\9f¹Ö\87\81Ç \1dM\93û¶\aa\ e\8dðæ
+K\93{ìÕtÁ\0é·q®\8d·r§Ïì\8f\ 3òrÔy\ fîã¿\vî\7fÚ\ 3>KÃ|¸õO ?#Ðïö\ 1\845\87ÿëÿ·ÿN>Lù\10\84¨-wÝ~ÿ\88ï\7f@úÁ\90ùÉüú\9b5§·êK\8fÿ)úÏÊÅn\ 4ùý\14îÏÁ\16ǾG§àÁ9Ì\ eëH¿F\89\eí\16MjÞÉ]xQ¬Æ\96\91&êl{\8e
+Ý8«p?«¬\ 6\87\ f\95\ 6Ì\1ag5È\9a@¤Í\16\8d%'­\8c\e§\1eÝt\8a\8b^&àíÙ)Ô\83Zse½çòÎzO\fߨ\ 5Z<
+ô|Ö\90\9a\14\16÷à\93ïÜ4\89´ç\9e|\1fi6\19\b¡\99×5ѤÔ\8bÈÚ¶v@\bÚï»09í\86ºÖv\eachUCz.\878[\ac.]Cy¹JòmÕÝó\ e\rM\98\98KµÖ(üÇ·HTúýjSôNµ!M\86T\98ÕºleÓ-*ÿëÑËK\19\81\87ÐT\1c³Æ\8dZJe)\7fP\97¨\8d\91©W\99-¤U\ 6B®¥Ç¤ý \11>\9a*((F\b\1cÌÆ\v«\1dTó¢\91\15wo/Ø\9ci_Uå\96ãîj¡E#\81èþÎM\fhÌ¡[«t}¯¦\ 4»j`R}Û\92DA\8f(^16\r\9c.Ñ»9IØ\9e4I!èãìHm8î²He¸\1eãlb_\13õ:NI3!,nÖÄ­ËËÚ?^\9b5sT\87\
+\8a;\82\8aMX\8b°       ±§m\1e\ 1öqpÓ¤\9cÇ,°¹?\ e\1c      ]¸Í\ 1¸\1ag\e\1cr÷#Å4Ý
+\1a«x\9bئn(RPC\81ÕzLQm\80wÏÖc\1e\8fû92ÐX*ª        ¬n\12õÇ\996áÀÃHKNá\9f\8eÙDsl\81bÝv(kù9§\r\10|ÖÖöAS\8eX(\94¡JÔø\12uA-O:ݽ\82\ô¹g®æ°×\17iÔ}\88´\94#\ f\86 èÑK:\96îv\9dL]Ⱦ\eö\92\85£¹aôHbÖy\ 4\94Ò«Sf\9d\ä½\9eÆ\v\90\aÛ\ 1 4!y-        ¥
+\15塞\1cÍ6(kýx}\18Áà.Ä\f\e\14Ã÷Øç\88¬L\16\82×úÉ\91\16ÀÂ8*ªI\8a\86dõÈÚ\88j}@¤\9b[_4vÀ\a.6[§\81¶·\8aX/sËv\eTX\81%/ÆS\18¤ /訣s\8f\86\aÃÉëÀ@v\ 6~\8d£\93\1fcÍ©\93\9eǨ\17ô\9b3j\a!¹Á+| \9d©Ö¯þ\ 4\1dÃTVO\85bn¨9kRTb\80ù>k\88½\12\83e\f\v\95ÍúN\88\8b5rCã¬^\9c\88Õ-\eGmÆ>ä\97
+LÌ{o\16ýGVCÑ&+ új5\8d e\7f£¸\95;f´Åz\e-\9eAÄ!,©×  x!\8f\8bh¾«p²\1e\83\r
+±.-\9e\93ÊãÂY\81\ 6
+\9b\94ÍMOP*zh\8c\ 3\93-¹õJ\8a_IÂÕ\1fg?\90\97ã\bKè·áÀiqÜ\91j|ZÓ\8f\9btD¡°\90\ 2²\1aJ
+q\1c\114\1d\ 3\b¥ uÒ\86\9bHáÜX¢ÜZ\90.\15ÅZZÎõE5®x\1a\90¨LÁ¥¬µ\ 1\ fx²1w\95S&7 ¹\9aSÃ#d õÝ\84»\112;\12âRZr½­t.\f\1fÆs\8a\1cÉác!¡AG\9e×ZD×èÃ9(½ÉN\87\86åD+\8dõCs\83X»qªÄjÑ(V:^æ,è\96^É/¶\98G|ì:´9(\99\14\9d VË\1d\100(ZÖZu\98ô\vEK
+Ó6Ïe   \r\8f"\10¢?k\92ö ö\98ECN PµÖÉ\ 2ëhóÈ\9bò6W\9c\16NY\96\ 3hôq¿²Z[\86&®+\8e-Éï+r\ 6:\95\1e#\9fgl\15\8dÚZ_\90Mµu\92â\11\84.i\13Ù ´\11l×é\93\1c\ eM£Æ\93\8d³u0\ 1m^N˹\88vw\94d¿é\94\8f\95g\ 1ÅÝ\10j\95F)»\99;F\1d\86q\19KÐ8eÄ,\9bN\13Ò¸@ÚnEIÛ¼\82ôÂL­²êèVfÊÊt\10ã%È\e\13Í\82CzÕ±\88È4oÂ\84\95SÙH\9e\8fM¬T\f+]\98\8d§<f¿l`Jæµ8K\8a\9a¿ììX\11=/\vÁ\0Áâçá\ fMg\11\12\bòj¨h\81O®×±Ømðâ{õ¸ûÎa\7f\8b®hF Ö\9dɺ2\bDÐæ²I\9b«pT\16íÆîRR\8aksŤ\ 3>,ÍåÝ !èêEc\aÕð´´»÷{Y\84\1e³0\1aY\12\8aR\140Õ¦ù}\82ǾX@\r&mÎgMÎ\93æÁ'ßYMnL¥3²óIóiÞµ¾³\99|*\1fÅÜ>0'¿|ÉïÛ\87§\17/^\99ÃË«\87»GϯÞ\98{\97ïß½1?_\¼=0ÎX\83\19uòH\9eüÚ\92\ 5ÿ\a\ fÃ_¶á\a»þ¹¦±\96°@òqB¥%âÂhEo«\ 1\7fß[¦£pï\88\8fùØVá]\9c|ÿìåÕÙÅîùåµùNdæî\93«Ë³ÝkÓ\9c{V]zuúLü;0ßÈ#ßËǾ«Y¸|r*ßxÓè\121JM8Û\14÷\18ÜX¡Æ6â½âN Ð\80¿¦­Í¹yTta\18ë g?Fµ\1f\\aÐör\1a\95Y;\ 2\13J¡N1\9d"\bØõÖ\81\e»\18<\15\9d\1fòÀ§8»Ç[³\95 ä°\8eÌzy\19/{\ 3R½ÛÉ\87Cäw\17;ãJøûà~¡f;\83\9aôé§Ê¡çzËôá¿\9d}v¼;}r}þââ­
+î½z}¶SÑí\7f]>\7fwpË\9aÃ[_áü\ f·¾z¿þ³æ!>@,\8dEãã\ 3\9a?E!U_½¾\96_?âÛ\1f\90}0d~2¿þfÍ)Ì\9e<¾õÕ·à\89\ 1\15#+\ eÒ\82\10§ÚÍ\90\13\82\94/\ 1\85TÇ'(\91Ð\ 2\89¸C>@¥«0¶á\95±§\81r!I/«\ 5\17Q\r\15\998Þ!_·Xçd\9aTxu\ 5\8b\11S\17\16ª¸a\91ÜÜ\12ù­\f\18\1c\82w á¥Òæ\82yêëª\18}C'\b\13NæZ3\11f\93ï\16,\17Yà¤3p\9f\98Î\82­u 8ºÃ®\95\18\97\15ô,Ì\8acÍBr°W\a½\ 5ÒÚFÿp\1c\\92\87e\19\12ú'åè\9b︯»\933\9el\16 \a\8f\97 \91\ 3Y\89µÝÄlfñÁ\87öZó\16äO\82c\91\15\19\86Í\ 2\91l(±ù\16(Ö+\93įî\ 3\f\10|m   \ f}ªã\14\11ym\16\9cl¡¹ÆÁÞ\91t\8b\ 1\87èV¶\8dT¸¶O@&o#ݨ&°ìö¶'4?Õ\18Xij­/H;Q\14\93øVBãW\b¨íü
+ç'tu³ y\95\1d\12\ f[ðõÿ\93^.;\96\1dE\14ý\ 2ÿÃ\9d0-åû1D5\ 3\ 3\92\91\91\11BL\90\a $&­\96ÿ\9e\15;"ϽmjR:²Tî\8aÎ\8e\93\19\8f\1d+\96.@Ú3Áó<¤å\1a\92ml*9|K\19    \ f¶¥\89\1e\12·Ùî\81\ 2áª\91ÉÜ\96.F\8cP7]\8c\8cÔî\99\9c{ï˾ßVãåfìäOÅKá4rlÆE¼\8bV\87NO0»ÃìçÉ­\18¿ÊAFë¤z¹D\18äµ9¯\92HÜ]Wh.\7f²çM«¸±ä±üÅi\9a¶a¬á\81-\84R¸<Ì\ 2/é¾¼\98{ØÙÙ=ÿüÊ×Ú\96\ 3\9e³\86\b\9e\ e/\16qwÐ"z\1c¦\88{Ó}ñº{.\11²m$Ä\ eÃ\87\87? ³\87\83\81\ 3µ5õD\17T}\8d\ f\1f@ªÀCÖ½\8c\8c·ÂUË[KÑ\94\93}\95bÌýE0ì¾TÖòþ£KH´yµè\8f\16ý`Mï\ eªá\98F\aµà\8b©¼ª\ 2ô\86.]À\88²ìa\ 1·º²\87¹\a\93!E§Ð÷ÝHÅ\8dL|ÅvxÓ\9b\91\9cd!\99åwS®î!m_\ 6eo]\11ËÜw\89r¨AU\90\1dd\86\8e\16\ f\9b'\8aX³¯\9aöÜTõ\ 4ò\8f\12Ìè3[?ç"ý±ú$ëܬõáCÝ\86¨~Ö\f:óê\9aV?¾\8c\9e/6\8a¾øXûAÿ#Ú6A\9aM\90Ê?ý½Y­fP˯ßÙH¦:yÃ(>\ff'\8c\81\1e¹Ñûiéo\bõ\\1a\13Ô\0åÕ]\1a\86IKÌv@\81ÝC\11êÍ\81Âå\9f\7fméä;Ôÿ\96±\10\16ù\18¦\1déZ\ 6Á\0Z'Kø\9a/\83>*¢Ö\10_-¬~²g©\ e\1a<ú.\a_l6ÕªOÒ\ fi\8a1²ÕþT]Öü¶}¶5XHØQL¬úå\80_\9bu\9a\ 4\rOzHafúCP«Ü¥ô¹ZÚ$\10´Qµ¥é<¤ph©Þ(\97Õg;\97 \87\8b\ 6ÃÇ\ 3Ò\1fbsDCÖ¢X}\7fbÀEßL*ªÅÔ\8bÌa¬\84e<W¶  fU5ï\98Þz²ñ\1c\ 5¹¸|Ä\94MÂA\83ËZÚ\85\83+ÛÖ\94¿Ék¢V¢t    #\ 3Cck[á\8fé\81ë¥<CJ}׶Æ7Oá\19ôò>²ß/¤¤ÚÒ°ûÙ¨R\8aì\16¦mÞëÒ÷C\94È\eê6}ú\91I\8dJ\1ah\10\98\96k\ e¤ÜSÐ\8cQÓþZô¨\ 4Ga#å\9d\9d@ùöª1(úP\ 6c\13Õ\94èHR\1dOhf
\1eH>KR@\14:ë­\97\84§\89®åU\\1e\fw\8f\v2\143\93på¹æu\8d\1c\1a\91iW3Ú'\96§d"PëzIµÓk:#¤5µö\9a\12/!\ 6%#ª>\91\ 6\1dVW#20võKCSÉ%Ü\ 6\9c-\13\1c\92\10\84'jh-y¾ñ\1cG*\9a×\1e\8aH\0u\9cÊ\10?I?Ú\9e9h¡$½Ü^6)ïó L='%\9e=àÔ\825ÊöÕ\85{¤¦°Ò-1\ ehÕÑÊ35LÓéÞyo\9d{Ç=R¯!Òh[¹\82BY¢rëÛW\12üÒ\84\8aÜuNf¶¿R#^øªËt\91\ eÆr$\84R\-iZP\rk»ì5\8fö{øX´K\12ëPFÆC\ f7\96"bDÇöXÇÇv\$RÔð\8cWò7Ô|¯Õ\15®\94)fãm\9e`C\r\ 5Å/\17ja\18\96}pþÊÇ    \8a\ 1\ 4YOÒdzo\ eG#\8a\18\ 2\95x.×äã\ 3I\9fUìz5\ 2FKI\1aÎ\8e¢Ï_Îq\93 %\98´!+z%u*ÀåÚ =Ã÷ñ\97§÷\91}&1ôKÕ\83è\11\80¥x¡åºôI\e\v.\94¶¬¤k¿\ 5=¶_AÚUÆt\1ea](Þ
+\14c\9fº\87ÁHòÕ\83\99¯\8cÙ\18\9c)¿\ e\19\8cäÉ\ 6\89Ja4g\17þHwéé40Ý\7fÝ\ 3ïÓ¯Í\9eÐI\84îAZW\8fä 5çrÖ¬\9eÆ5J}¾%Ç\18\ 4ü\9c\1eÉ\9bƦd\9b\ 2\18¾\8e\9cm\8fG6Ø8>Jt§\96\ 5\19       \1ayt-Ï\9b=ë¯ç8\91Z\17J%}ÑÆ]ÑË\91rJ"\a ArAÄu½Ô*.`í\1c\1cuM\ 4\8a\94ÜV· ?\1eà(dŧ\96:>Ò³\ 2©\16fB\1c\87C²ß£\8d¤\97\9b\8aÒ~ó\8f\8f\1fíÇ\85OéñÛÿê§ýøé«x*=ò#é¿\9f~±ß~Ç\9fþ\85íë£=þðøÛßÓã\9fßñw?8·}\84R\9f\ 2©û\18u\1f¢n"Ô}\80º\8fO÷áé6:Ý\a§O`Ó' é>2Ý\a¦Û¸t\e\96>\85J\9f\ 2¥OaÒ}Hº\8fH\9f\ 2¤OáÑ}8º\8fF÷Áè>\16}
+\8a>\85\81è>\ eÝ\87¡û(t\1f\84>\85A·!è>\ 2Ý\ 5 ?\8a\ 4ãü\89\1fäûAË7~ðôôø·\7f$Sú.[ÕEç?Ç.UÑw\98\aóñ½Û\vQR1\99ݲçF|Ä¥¤ðn\¥ÇIµÊûñÀt*¡ª&\8dn¤e\8fÔ\8eênÿïnxøÙ\9d \9bkV§\82A.εû\ 1\9et´RÆQs\1c\9bÓ\8c}O7*ñïÇCô\0­Õs\1c¶|û[èd\12 #ù.\9eù\180áÁ.\9b\82\91ñ¹ìC}ºH\7fø\8a×\aö!}GÔùÞËó$ð¹ÆdÇ\b\194}/\1f\f\91±\8c\1a\956ë~y\1e³µ¸\87Ý×q\90E\ 1T\97ªþ\83\v\7CÕ*3$º6_\15\9bÕ_Ìq\93áïÏùÌ\18u;c2\94\91F\1a§ów{|èøúæ´j\9c\1a\8d&áñE¬\8eãf¥3ã\83\98\ 3\ 2Ñ­Y¼ÉÀj\9e¤!1\9d\8bÈZq\81& =\82ÄSf\f×ú<lЫd   j×\ e#<væ\81©óå!¡Ð®w\9c8\87£¡\19ÃÂý\bO\17U\91\90¶ÖI\94Ù×\8c¬æÆ?»Â9ª\9f\8fwúë
+\8c\14ì\9d]^m[Yey}f\83ÿ÷3QvÑ`³)h3'âf:´\8b+l\9f(ïe/it·§\19Ó\11Üiy»ñ
+\11\9e\9b\89\83Í*ñýõÅVkv{\9dÞ>\18\1e\ 3¯ù\8c·;gÃI3N0øx \93íÀ\8aÃ\1c\ 3\ f\ 6êÒnkÀ½Ïh\1cYñ¡§´\ 2¼\9f)\88\b\8f\10zë57æ­\91@\ 5\8d\88[#c©\b>l_hç\15ü\86\83âöÜË9Ì\98±;´\ 2       ¯cäàvã()?=¤¢\ 5§Yev\1fxvDS\ 5\82N9Ƴ\95
\r_\1dÞÏ\14DF²Û+\8bS\1c\8e\84âa\ 6"à6ÛÒ)#sûÅ\ 3\1d\ f>@Ø\13Z\11\0Á¼\ 2#\9b£\84·:ÚÓ<|öÐÀòÑ%VFX\ f:\80QÍÑ!Ïz\8c\88P   \9e°Á\17\1e\f\184Ä°W\7f1¶6[v¯Òc7¢ÅůÐVnÇ\ 1\9a6E\ e¶ud\97y\8c£9Ò\10¥Yv\18\97\8f\98Æxñ°\86\83ʺ2o\1e|&Øs\bo\18[Ùg\93é/7¨\12]\1a\7fÍy"V·÷,\91é~-\12Q\8d\81¥®eæþR\fÛ§\12\1fó(b[uGE÷ZJ\10Q\19\18Ì«_\ eì¶%6\8eÓ\82v8ÕPÖ3ë0¶íÝ\93l(\97§\87\1c\83\91üT\8f¹Õñ.±\8fÕylJ\89\7fêY\8e\16\91­\12á¾°ùa@
+¯ÇTCH\1e\8e\90\909TæÊ\ 3\9405\1d²ÅyxÝÐ\12­\87öµ\19yP+\8d\17A\f\ f\8c\1eìå·\11\f¨\1dWLÅZÒ\83ßbÉËÆ\ 1WccoM\e(öe\bçFø§\a}\85X\83\90\1dÁsã¸Â\80Y\1a/3MÙâl°iA²ê8´8\93î\85±\18£\87\87q\8a\f{­Gì\ 5\97+\8eW[\9f\ 4]v­\97\97=\91¬°wÜ?íCxevëË^ç\8c;\8ex8E6<tûÍ\87',\8bÜ\ 5\89v[\1aß/ÆM~\r[&÷\99ÀE      Ú>èf,\17f\9c=0\174\99a,eõÀìrµ'ví©Ø\8dm\9döauÄ ¶\9eZ.cÉ#@UÄ\1d\1el\aÚ\ 1ë¢ê\13\ et{{­pr\ 3 ~R\9ayå¤ä\1dv½?\8cEÈ@Å\97êzoéÈ\auw\9eÏ+¬ì\8dÐÅ'nk£ÅP®Ë7·bã«\ 5^Îz1\80EÁ²"\92lÉõ\84ü\0\0¡\eLPÙÊ¡\eÓ\92\94\8d\18\86BM\8c¤u/5-\ 4qÖO\12\15÷"àã   \v¤eûØ4¸4        7cw¶öM36Júº»\98d#¬qî\80¿^Ô\1c\98³\93\87*¤­Ø\8eL\1f{\94\8dä7\98\15\1cY)*r5\1fz\ 6¸m\8e('ä/\8cd5{9iézR¯ëjî\970sxM\r^«RÞ\17ØK-T÷0ÆUNÆÈU)²%-\95ó9vÙx\ 5»\90{\80\87V\8bÛR®×+l\9d­±~"½5\9e<§ \12#CnDp:\ 5êÆôl
+"¹öÅ\8fËA\8c°¯¹"¼ê\1932ÝÚ:qØû\99ÌY%I¶\14äÈ{Ù-\1a\8dûy=Û\bwAÌÞ´ñï·Uwì\ 4Jeô;)N;ö\98bc1\ eÏ\9e}î±½®(ÔÙdLÿ£ºÊ\8e%¹q +ãÀlð>|\18ÿíÙ<\0VëG!¥øÐ,\10È\83?Üóf\18j\10o®ö´\90ðpó¾ã\81öÈñoÅjÈ&\8cöíJÙgÅ®\8c\96Û*­        på¶\16î\8d³æ·­°dÓg±Ä¡D\×áuÅ´,·¼ÑhXcIo?7\18MKÈ\18ÕO\12\1c\ 2Ûr\7fç´Gå]Ë\8cw\18ðÒß\15®U \92&nò1üîÈ\99>-Á[cúÅn_\85:\ 2¿ËùN \ f\9f\8f
+\ 1^y3.ÛÏ\1dp·î½º\Ç\91\17î3\14\12ësóÓZ\8b\93\87&øU\0Y\86Z !÷S\ 5¼x(ª¬ÉÃ\91\92BEæÞõ\aï%\1cûÂïÿâ#ê¬
+\7fñï}ûÔd\0O3\ 2\15^[Þ\98C\8aõI¾.#äP\ eå1~­2\85ÂGÿ\91áQB\9d\7f\7f\11þ¦\94\90çZÎ\b\9f²÷Ñ\9e§\7fÜmU;\9fB\86\fß\ 2&Z3\96©í\92ÞéLm36i\97tÑ9¯`\99ûü_ç»I;I{ådpÀS7\ f÷¸v\1dÌ#ÝZX\7f_jpgô½ÀkL,@\15\93×+×w\0\b\85N±Ôç ib×Î
+#\ f\87Ò\ 3l§d&ÂzFÙ\9f\8cµDj¥¿­aÀò«QegÍ\9c´\15\89¸\8aý¾`G몽E\7fÛè¶\9bÇ\12ä\81Ý\ 1\82Û\87<¨üÓ\13zxÓ«,Ë\14x\7f<è~Á!⩲@Qî\80åÃ\7f\7fi`y\15\90S\90®òð¹\99\93Ê\88\88\11\81\a
+òM\ 3$\8eøD#q\85\7f\ f\ 3\0ÜÛÛ\râGÞ\9føz\13ÙÉ\e+píÞ_Å\92°o³Ù"yª0   ×'\7fÄ\96¸·\8b8\1cNV\ 6\9fØëMfÓûn\ 2\16.'Î˵?ü\94\16çë\9d¹Kèf_-\1ap\97½á\b·ê\9c\17´\85\a\a\8f«Ù0!\9f³ã\80nç¼î\ e\13\84\119\1aåQ¬Û\ 4±9Gv S´W>\17óìÕJvN­\1d\10¢èuB!Q\1dËãdâ\927\ 4\9f¶þ*L\8eå\8eP\17\8edQ¶ÓÅõe¢^ø3ß\8b\8b\83
+Q\0x¿\99Ó¤Q\ 6åòþ\93Çx²Ë£3¼Õç\ 6\16&­ö\boµUÝw\815\ eǨ]ÌÜ2#í\12v\1cÑ\85\ôî\80\a¸\14\váåF\81»Z\9c­mÆß\97\8b\a\a\9dÖü÷Àa\90·ñ5jÚ\7fÞ\8cù\fø²\eua\1c\89"\9aQ\83us\       B\88Æw3«¦p&²\7f\89\7f7Y«Öï\17ïæ°ñÖ­\9eóá»\96ëvôY~o¸\94:\vsÏ;¾m\1ae\ 1ðì~ÖõcYÊr¸\ 3XW:!\1c̹\0\ eA\98\96û\1dvyMwÁr\1f        uÑ\92Ú\ 3,\85\83(0³0Åð\9aÔ\17í\9ccÝLË\8f\83­Ié¡B{?N\a¾¶ö\14\fÖÈÔ\ 6A\84\1c×Î\883Û7m¢=îWú ]9\8f7\97Æ^yC
+¦n\80\ 2)
+\eÔ=ÊôOÁ\98ä\15¶&36©»a\ak_×µµéN\fg¦ÜÂô\9dónp85\19È\144\0^¨Æ(¹HW«q©øÚã\12ßê\ 2\97îöÆ&ÎÒâïGø\1dn¬>àâíjÝñ0_\8äFùYx\8aB?E\10\ fz¥ë\1d/ÓÍ\ fü,³%Hö²YÑ\ 2Ä-p\bé\b\1f\ 2\9b3¸ÅÃø³a/È\93Wqa\92»ëý*¬ÒÄ«\18;\10h\1cÞ¦\9d\85;Ìh#Ö»+}.°U}\ 6\ 3¸ê\ 1G¾Ä\eÅ\94\13?\12L\ eÛçr\88Ã/\19oõù6ár\84ÄÇÈ¥;xþ#åæ$ñ\97\bÖ$g\ eø\1c3ZW¶z\8fý\0\9b¿\87nh\88\8c)pÉâ¿Ä1bÛ¸t<pÌ^=+\8b¿uÆ Éïù\86˽Â\14\89\93\0\ es­_6F\16½RÞz\13#\1d\87½&A´\8d\97\1e?ÐN}¥\90s\1câïoª&Ó\ 5ÃêßSÈ×Ýd0#ñ\ 1\9c©£ \93ÑÃÍ\ 1Ç\7fm»9L¯\94\ee`B¦\1aQ\9aù\8b $¥*g\0\86Q\ 18xà\ 6Î9 x0 J\ f\ 4O[\ 1Â=D\ 5\98Õ\9e\15@»cG\85C:6\88«\9f\0oT \9b÷ؼ\9b\9b#üT-    Ü\ÛkÄÏed\83\92ôUß\1dÄ> àÑbî\8dï\16\9eTaåßÃç\1aÆ'ÓÓ\87·\16fóysá{®ÀÏ(çÃWÓ¬\903Ω\89c2"?b¶öJ\18\ 4Òü\86]4ýàpÔ4õr\87\ 2Qp\19ì£&8\97\89¯\91+ò3é9Ų
+j%\9f»N¹=ð\ eØÒ \r·\15á`áZÎ\8b\84zØÃd§\ 1®Ú\82çGíî4Xî\8a\1f@è=å[8\b\85\89\7f|¯¹ú#4Ï,){~,wó\ e\82\98d|V<±\ f£@\18çu°¼1³[¯ÇÔ\12L/\18^0®\80Ïßß#%­R\1cÇ\a\ f§[Â\bº\81£[³\89+\99\ 1¹S\0Ù\16;/æ+\91Â)ð\94åôx}\90`~      \13RËiD Ð\90\83º\91KÃyÉ
+\13\\f$\91¥`Frû\80\9f!\ 3Oüô8\v\ f\10alµ,º[\8aÛªe|7¸Õ\8bºßöâºõÈ{`
+\16\ 6\8d\81\16\12\8f\85!Éoàë\1e½³¶p¸\vü\111\b\89)\ 6\15r=\8fß­Ñ\18äþÃI\9c±·ß\13ÿàÙ\86ÛLi)Ü´Í\9cÀ^-Nëwy\81×mâ.\ e\ 3\ 6ÃU\81\88AË.{Ü~\80÷Ù\1fÝ mÝ\f°EVgç\91{\81ãìgø\eJz{\80\83\8f\13]ÀcWK$j­\92#Õ¹\92´\8eÔ\14u'p4\bÃ\1fjX¶ö\88\88<(\13ki5Ðß2«Àê\90ò^nÎ\16Z?ÆöËaà\9b\b²\1d\8b2@(üµ"ãå\ 6è)* \89åª\19|QZgßmÒE8\ f`=îÖ~áFß mì%Aô`×\1d\98\ 1\1c\ 3t­6\\82¦
+\9b.ôÆ°\97qO\80×*O©a¢\8c
+Ó7Õ\f\9fVz\1cÆb§Á\1aófY\a¨ÂÜu³?°\89c\96p^\r\7fñ'.V=¬\9fPà+à¯5ÙË·u\85µ\1d|ÐÌ\16©\16 '{5w8%\97\19¬jaðÞ\10ðä:x(xçæÉÞ³Ýx\ e4U
+¿ÂÔ\1a\\1eíþ3\98\93íéÛ\13/\v®££­\18\bxK\814fE¤Á)¡ã\8coèØ{qפÊz5>·\8fZ\aTøÇ_\8bÅ\17ØìC£\8fôaâk\\17ÞOCÉæ\9aÄA\vx,\83üÿf|òNÍ.ÐS\9a9rQ\ 1\1ez\f\reãÎ\9a¯\ f?Òo6~]Ê¡î{t £ÃlpÙ\9b\12Cvhèþ\9e\8a)BsÒ¥°\96\8dý\ f\93´=ON¨\0±e»FÆ\8a1­,Öå/©\9cu&SÂkíªÊ\98\925Ý4$Íyjæ¦ã\89ÄÅf\7f¹éëÃ\rû\1diÆÄN¿xäR°Ð\88\9c\ e´ì÷í\15mîÐè`0\1a\bGm\87\8c¢_\ 4\9a\9b\ 3pN»óH0ñ\16áþÄG\13\9fÃ\vÔÑMj29\ 4q\9d¡°\8aÇ>ug\1f\ e*\14=\1c"\eÚ \15\ 28¯(\1cc$KËï}\ e\80SX\92­/Ã\8dâ\13\86\16#\17-;µ\a³cLj6w\8d\98ÈyÛÉ·¤f­ig\11\8a\82\91Þ°¬\ eOàéí\9b[Ýæ\8c\99®x,ôåX\r¹\1a<\8cÔ8Ë  Ç©\r#x\98ÚÂ\1f\7foY¡\18}\9fk\9cö\b\18´\ 1×\9a¦§¦½&\16ñ­`Ùkr/ñ¾Sw\87\r\ f\8bîzºÁ      )\b°_'Ðcq\8b\eÄ&\88ßú)7®\8b\19­\1eÞ6ÔGø\et_\rÇVÕòU@«\8b´©ÑÃÞ\1a]\b£AQTkÙ­Ðçisæ¿Ç\1eÜ-n\81aØ]
+[ëË«\ 3\17o.J\83è@A-B\È\97ÄÚ\rÝ\8c\9a3{\1e\ 63_\8fM®*Ì\14Ìtd9ÄÒw\a&  ë.úq\97³\9cp        ¨ô¸ÐJ\13¤MÓ®-\12\85ñÁKJ\83Ñ]d§¨L\ 5Z\91\12aÍÔ_|2^ ÒÝ®ò5\9c2ìmó\85ñËoÊpý9¶·¸ÁgÆs\9e\81\99\1dÆ¿F\1fø\12t\981%pmG\158Ô)Ð`      \8cµìJÝn\vÀ\ 1\9aHYwÝ\8c\11Ò$\8bNï]³ïÀ;\a\148ÝJ\r·\82­\ 1o;\89¡pu\r¼QK%îZ÷\8aï©/Í,&\ 6×%[õ\19±\ f\82\98\17\86¦ÁPàû\1a\13«¬
+ÏÂëDÈD[Ô_\8aßÑPÃûNä°,<h\82º\vÜ.W­ª¼\90«^\ f
+\ 6¬¢Ë\ 4\8f\8dCTX|\8cæù.\1c°ÒTaØ\89\e¤
+\10Dûß\15(¶w       ^oceên÷Ùê\9c\vw\80/[Í'ï|\1a\84\91\ 1qΨÀ\8cI\10«Qn\\ 11N\1a\84ñ¼rÊ\ 4!bùn\8b\°U\ 1£¼îÿé®\92$IR\18ø£1@¬\7f¨ÿ¿g|\11DÎa.mÙn\14\ 1BòE\8b\17ý\18\8e)\102®2Lºæ\9d+?gF\1cH.f\93ç\vMzD×\92îþÝ\ e\r\19¹xÈ<på:5w\9es|åA#\ eW\ 2\17ò=Ð÷¹\16\94Ôø\12gîp\19`*îÀA½\8a,\8c\ e\81Áî\13\98ÝÇ\85>+°µ^\93àÃ{    g¸\1dÞ\0Í\15+ß}$\9b\f\8auÏ6\93?ʹ8W\86hQkys\ 1y+\8a\ 2À\91ö<p"¢mºïÓ\Àì\15vÄ(\19\9ddÌÙnéFS¤k¨\80Ãcßú¹üPD;\88\14(Âú\ 4\a\ 3Ð\1c\9eN~\r\f\83\9d=      5\0a-åQÓôÑ}\9b\19³nû\91£¼-N~JQyp\9a\8dlc\ e\97\1d\80ÛÎ\ 2\1f=ÏPyà\ 41\99\96\f\f1J\a³ûH\153ÙµÃ\88÷D\8d\162R\1dVóp\83iWié\12`Dæ':{I\ e\99õl&ÉÕk¶t;'l\ 5AìàX\85:F¬¸u`ØY#RJj»²5\97<*'dË\95HD,ò\0\11]ú':\10¬n¼#9ý\88ÎØ\ fßÿ\83\9fÛV\105d\85\96\1fu<à]NññPÏi\ 1¥H\85Þ\14ÔÐ9Hy\12Ú@{©ý\9f\93\0/ç®\8f5>¼®\99r\19ð¹?x-\89£;/qS1×Ý\aab|x\9f\91\95ikÇ\87£ÿºk»\9c¯x}ä¤,¸Êh°\9f\9eò*ÇøjÛ¶\9a\ 1¯ÖG}\ fQ|<<årÛ\0\1cC#\ 5\137LãÙqýpô~Û)\94\8f:\1dÝtUÑÝá>/V\95ìsìÜlÓgÏ\86FYÂ\8e¾\94s­a)²\1eèjx\97ø1f[\96\11\1f­¥\\17×·\1eP\8e¥\8ck\ eýJ\85ñp\"\ 3~ÎÅ\v\1eL\8bI\a-µüú\11\80sÉû\97mîÏ\1d        -2ÙÈeü=¼;3\81"÷{7áíáÑ?¼M9&ÐÖ }%خӠ÷\r³!@8\870\eÖþXGxï\17Çhþ=|\8a!\88Sþ?\9cþ_8èü\a\am\9fÄ!Ïï\80£y{\8c;$öÃA6-y8­\fêª\10 PSa°8\9d\96ø=¸\9e×^\ 6Å17\ fRÃ24-ö Ð¶Å×L\rôbùç\10û\1di\91\10ýÞ¤áEWË34\98\9a\9cy4Ðrùu\vÏÒ8jzðDÛÏÉà\7f³H¼*y-\17\17\17KÍ8·9´¤(H_´mN\b)nËn\86§:Çf\8a\1a \14ÍêPD/Óa Hý¹A£\16\ f\8fHÈq\14\84âs\98@&\8eDÌu}ëy\ 6\8dm¹!\12Öa,Q\ 2ôyfê=Zr<¸ÛÑ\ 1\95û\and\e<íjQÙ\98\98£\vO:Å\eB§Zp²´N±\8bIl\98$öøR,\94³I§\19\14\ 3ë,ÙfÍã\14
+°à­ÌÇÐ\8d\ec7É¡qñbþ\92q#\88±;\ 6áÔ¼m\W±Ø­ñÎ\10l¢Ä\97[\81`\fy\82EË?\12k]³²h\95ãû{xàm¸Ý\ e\13lV#\1c­ÿàM\ fD\9cû%\ eBêb\î>\8fëF¦\9ey\8cÓå\ay;<f®\94k}¥Øn\aà\83ÞïïâðÏ\89«\ f\1e\8eIÉ}
+´6a<¤|\9dd2\1f\9d\9bö\86ÃT3úÈàÍfÇ \ 6Ê\83`zptö`8\86²\83 ?]sD6\8bênå\18
+Äh<\8b^\98\19v$\8cã]ö\81M\9c]®C\ eÆÞ\94¼ÐEU\95\ 2\94c\84r-)2\95lì«k$\97u\9añ+!¤\80!N¯zìsw¨#¥b~þ­Ð1ÍH\v\99q\92äY5H ú=ì|
+ã¤^\14¿Îií\9b{T'¹x\9cz9      øP\f"\89*\9d~øð>xIÆ\86\ fGêK|½\10ÁýëIû|<?UIÒRÔið\13³\92¡ÙwÝ¿´4oÒ\ëçsWZ\88Ç\ f<_0\ 5%þà\1eyâ5~OWjâ?á\145\9aÅr\86NYíJ\vk4.³·[oðÝéyEÌJËg\84Á\9f\ 6G=?/V\19¥\84ËË'¸o\91à²wn\8bè\13w\87ëïئhØ\f*ÈsæIôö\16#ñ`GÚD\9e\1cáj0\~L\8b\bVåÔJRÞßåÏ\1e¢/JN¨\1fÉ {\97ô\18HW'Áô\98Ô\13ºÇ\1c\8dÖ[Ë\8bå%<\81\88\0i<æ\19\ 6ñwá&Å·f\\ 2[ Þ¥\1d CÝ\1cL*´6uð\92\12c\ 1ÃCv5îàåòîFæo\92èq®i/Zr\96ÁÕLÁü9ÔáL\13m_\12Çb°\xqß3r\aX\96ãÏ­%\ 3Y(IEçâ¯y¥° Ín7\ 4~\95\90±\14Ø\87Î\0\8eß}æ\ e ®a-\94±Ï\1d0 ]s\8d\b6¢µ<pvI'Y«ù
+\18ðÆ=\9cá\95q21\88Z Ò¥\84y³\Ã\8bx¥ôA\10~\r\96\ 2ü5ïCt[0Q\ eÚè2ò\82ö5\8d\f('­\ 6Á\943¼æt~\82jbD¤\17håCîÎ\9d¡#ELM<\ 5q½$\8a\19ë°Cw\871Ó@\8a\ e\9dÍ¥\1dú6}\ 3ÔG<˳×\ 4k¿³\89\18y~n7I\b\8dã´\8fÏ\0çÓÍa°NÍÝ\8bæ\83w:^¹ö%Î2·Ãªð\f\9d\85¹Å>\9fê0«Î01ȳ§íkï\89Õ~i^#â¶\ 3B«Ç
\93Ò\ f\10\93Àý­ùx\08\84\99\1a=h\90Ïö«)\0y%¼]®\14ñæ\ eÔ¾­Å\aC.C\\98\85VO#\18V\ f\82\9c\95Æ#Þ\S:G[-   üv\14ÀÙdÃÚr$4¸«Ø\fVòç\16ýÙÉ@ËvO[ÇÁªº·£\19Âg\88ͳs%îsv»\13\8f¾\17sç¼6\9d\ 1\1e´U\99.ø¾9ìU õ\10\814\13ík'\8cÈ\1eÒ@<ê,7\19\11oM\16\1c6¯ÅM@ÄñÒݸÄ*qrÞI[ØáÞ\7fp¦Vã/a\11\87û¼ø½&\f\97\1d/Ƶ\8c¢GQJÙy\92µ\1fÓ8½ìÄ)\88\7f\ fï\1a^âsÎ\ fïçÞHSöp4tV ¦ç·±CÅy,WzQ\80(¶ü0¸­¿\81bMÂ>\19]Zýè\8dÆèT\e5ðÅx`ݦÒ\ 3§rwXÌ\9bËô6jh \ 2\1f\99C½4\1c\1eLA"\10PPûé%|9T\rà=Î}GôØ^3Ùi\9fliH|;i|Öv²@\97\8eÐ\8bÐq\8dyÏÆþ\9f­¦Ä7Ï5vØd\ es\bM0A\98¯¥\97\ 2\ 34ìýs¶iÅ,\1e\ f\82¸èZ¹ím\04\7fäiÑ
+Ïë±\14\90®\9aN­Úõ\ 6Ã\9a(\8b\16RoÔ¥ï\15ÜA\1eË
\17\b\ fuZ\1cÛpÑ¢IÁ¼\1f»       ÈCÅ¿©\1e£ß\ 2Ã讣¯a\94d\16      ¢fK\8ePC·\fÎk\1fqìS^>©ÓîDr\ 5qÓç`\95÷´\e§¸ºM\b\ eÙk\rþk\13àH,¹x\14ùãR\1fG\ 2\fú5\82¸ÏÖÍ\82¶äY\ 4
+\8diP»z
+`­òe80J¦ÚTºy\95\1cäT\9e\89#>¦\88\13]¹O\9byà:íÑÏõâ,N
+9Þgì7.À×tN`«îÛª¨póÌÁ+]ó¡²\8fç×B\f\87\8fÄÚi¸\a\ÜÝ\19\83½®Õ\95\83öÒÒ\1e*¥y¥Ò\81\r&Ë÷^\99ÐÕÌÈ{Hû\84¡ü'\1f\v¬Ì\91õ+p_+UðØã\16Ü\a½\91£µ§\9b¯h¨·oVñNÚa\9dÃKÔLFJ\1f\ 4¹\83;\15Q\82\1f \881\1e²vä0\ e\80JM9\12òÍ2\ 1\1anr\ eì`Y3\80èÛ¢vgÿ\ 5\8b\ e\10ªÜDhè\92³²¾Z\f'Í#wØ)\1cêî\8c\ 1o:2x¡c\17m\ 2\11\1ej÷A\9fv|\ f\92íê¶\87¯'\18MA\8cR\7f\b\99í\a@4ÐQáA¡¸i\13\88n<\11&Û>ç-ÛÆÙBÔ\ 1\9c\8cªÅqÙ\ fF$\98d\r\96#»5ÓAå\ eí\1axà°ýºÅÆ\18LM8l%¬öI\90­\92ß\8a·\ 1\88¬ë\99'ÌÎÌ#TfÚ´Ú\93\1e\93 zÃC4øBñmÐvMû\8d\19¹/\87åËÑ\8e¦\1a]\95{\f\9bÑÁQ]5ÁÝ\94\85:½ïWßrëÛ)·eÝSXÏ:5Þo¯£é¼\ 3LXk|;\8cÕ\92\88~¡!m\0¿\9e\18nKth\93)\ 1-ôkV\84¯e¾¦]\9d¯{0\96Sl\a*\93\at«¡6Iî­Þ®¬*Z¡åN\v#\1c2TÍ\ 62h\ 6O\1dir\8f\8c\98¿´\14\9c\18\1f×;\18\13Ayú´ýÆ Ó3Ó=\1f\1a\1aß\17~!L0¸î=\ 2ðkÖ9³í^m\93O-raåw\aw[%f\80È\8eè\18\bÊþ»\1cÛº\9aÒx£ôUë,RdüËx\95µÈu\áwÁü\87~1X\10pUÝZ\93'YV     \89\8d\94E!\ 4aK\8a­`Í\80,Ûèßç[Nu÷\18\19"Ä0súvÝSgù\96ê¢ÕIS\86`÷#h\aÖº\r½\ e"~%]\1aòÊ\8cú\1f\1dQ9ï\ 2F\10·8üí9>s(Ð\ 2p\8cW"\ em.+Jï²ÔlÚ±cÄ!"\9a\8f\9e\1c/\9dh        Wç`_H\8e`\9d·\8ewªÌå8Ì Q\9aÁ¶øF\ 6\1cÄîÄ  ¢ÑÇû\ 4\94¡D<\v»\19Ì\9dJ\87ÁAAûÑ\1c\9cÞßn\1e¬Ó§\ fOÏÿñÿýþé£Wwß¼>=z÷þËÛ¯¾~ÿÝéów?þðÝé¯wwß?<åS:\ 1o\9e\7fuóà\93T15%å\84\7fÐ-¿O÷ÿe\7f\ 2t)p\84O°Ë\98;:\80²$|½|\ 1/Y\1f\1f\9f?îOú\93ÄÐ\8bÏðÖ/Þ¼|ÿæîöëw\1fN¿eìôÙ³÷ïÞÜ~{rb/\94ÎëW/\98ÛÃÓoøÈïøãþu\12\12}þêæAß±O^ FгwU\13àÞÐ\99·ñ        ZºÒ\8c:/Ò-\82\87p°Y\15töþ§x¼d[\1eY\97R¥¤³¤\90 \0ï\91\15d\90ô¬3h9BÚê\f@@^B\14 s±H\82¢Æ\9c´ÃìPª4\a\9flÙHYL\19\19t\9aze%JHäd\b@y!QâÒxas\80ÔÕ\90\ 6Qs>\0\7fÖ*c\ 6E\81\93t\11
+w_\84\1c\ fÉ¡b\0\88]\96ôß\17\ 1\1fç)\1fG\9c\80\ 1ÚI,ë\1elX\91Îg\85°F\92èËâÿ|\11°iØ\îÌ\94F\99\10µI¶l¤\0\1a\ 4£s\b\1e\91G\ 2z\b­eoº5\1cb¸N\rö"Ð2¸l
+ET\ 5°²ÓHà*|%ßë+\88\19À.\81Pj\900\82\87ø¶\90²Ê¥¤Da\b½{WÉÔyÖ³\89 vú\10/\=¤C!\11°EÌ\ 2\8f\88$`n*`÷§}AÚ(\e*¼£t).\90u?d/11\95@\89 \8dØ°-ÌÄ·K\91p/H0Ý\1d*hYÔ\ 2;¤#¬jº:\98\bIFt\82 dȹJ8½ÑXX^\95¤\82¨t½Ükx\1a\15\989CeB1\9c\8f@\87rOAZòW;\r)\10\ 6§Ý\13_1Ý\12òò<ßäàÓs\8b\98i\ 3\ 6{\ 3-Û<2`\97q®4EpÓ"B\17¬ÃIÃ\1e\rP\99¬ë®5\15Åj\81Ò\8b\8aÌN®vùÑ}Çý8 ¢zöàHQÀ\19"Ý~\92øQ×È¡±¯´éèõ|!Ø\eX,Ù\9bu\9e\ 5.ÊR¿\8e\80\15\b_Q"ÞVË¥5àÍáÓ3}ÓZ\91Gj\92\ 2°­\9c\8b²Eú½[ÒçV[\19ÐË\0\vû\96¡_V\98À\86­\rý\11\10BÝXÓÜbrÕШªöã8\83\92+ÉûP%¦´e_)\16mÕ"Òg¬C½D¥$n_î30óí\bÑ_Ê\90¿ÄÝÜ`\8a#\15ÅÉ\ 5ZàVPQë#gì¢PV ëÉ*\8f~.KQb\88a\ e«\9d\870y\9f\ 1H\1fÈøz\11\10dKìs\9bÍÒ\87ý8!H\r\0+V2\89*K-\18\10£@à¿_NïÙ\9c\ 4%Vl@Z³\99Õ åcê\95¤\ 5\ 3%\baPÆî\f9ëEKBñDñÍ`\ 5<z\15úYQÁ\14\ 1Ô\9b\98ö]:\8348R¾&\19\ 4ѧÜc.{µw;¨]4ð`\8b\8cí?çqÐn*í\82)\ f9[ÑÖÙ¢9\80\9a\9d\9cm\bÛ8{9.wÉA\83\ 5ÆQâØy$/\r\ eÉ\¼\1dp¶\\8fÜó¥\1e\13\9f wc)\ f\18\92\9d\85\9c\fÉûÏý8*ejÃ*PM3FJ±\86Æ:ÀÚ(HM¼B\13\1fójVqDm\92¯\89\8brHK\12\ 4\8a\90\r®\1e. ë§áÓJí3Òe\ 21-à\84x\1c:$\1cBíI7'.õº§:Hé/7\ f2äÓíÝí¯ë£_\89}\\93ýRp}òè\ f9½xrûêÙ\87·ßÜ}¿\ 3\9f¿þöÍí\ e}úôî\87×ïß¿~x\93N\8fø²ç?ß<øQÿÓé)~\0\89\1d~@اÓ\9fø\ 1\ 5§òúÀ¿þ\88ßþ\8bØϧzúóé_ÿN§W8íùSJåt\8c]S\80ÂĤK\83'\8cx\83³óöv\8b\99\84¥[UÖ¦\ 2\ 6z\vÎLES\80uJ N\16\8fq°îa\ 2j\0\f\8c\9côL\fò{µx¯fÐ\1d3\83\8eÉMq<1\85ë\88\81Nb\7f@A3¸.\0\ 2WHu\7f\1d2`¨Ñ\95¨\1a´\b`£>A\ 2ë,l07\98ðá+\88[|\ 2d\9c¨\ 3'\90\ 5}B¦\10Q\ 686åÕ\82*Z\96pàƦ¼¯\80\15YÃÅÅ~æC\ f\ 3\18JéÝÁ\9eÍMÄêÒªï '\13·À¸VéGBG\10\190,\#îS\87I\19\94\14\rv´11\9f\0Ö«M'`ôC£3áÈ!\93
\16,©·\9c\9b\13\900\9aÔ\82\1d»\ 5\14Ò   î!\ e$+"vâèÁ0Wu@U°c\87ñ´Õc\85\8aèbQ.]>\86Å\fÐü(%²¥jð        \ 1á\9f°   \18ï\87É;#àqðÅ\96j\r\9d4]\1cÔ\9d1\90ÀÁeé\89ú$\936æIZSÐ\eR\99¤\94$\13Ø
+*+@ú3ߣ[øâ£ÃZÃÛ\ 2Ê\1a±DTh}kª*\10$3ì\12CðL\1d UÈ{[PØäkC£
+z=¬1\7f(6l£\a\85VGÚ\90\1fCùì\12ç-á\88í-y²án«&\e[\fÀ\e{X\93r(Ù\9b\19Ã\8a\ 1«-J\9cG^1¬\ 1å¸\8fz\18e\10ù2\87¼Ö9\aØ¢Ã\ fs%£ÍH§\1e1\978O\83\82\85êIl\8fl0ß}7©o\9d\r'´ò\bù\98ûZî\91´\8a\9b4g\99nÒbm|@-þKñ½\1a\1c\89¥\87é\0\86±\b]\11\0\88\9f       |q\0êÛE\82\10\ 1\88·õC\12\9b
+n\a±\85E\vG\19\9b®\81G2\90¥ËQ0Ì\7f\13ì°9eì\95ß°E\81\98ûeÎP\9e­*\ eìÿÜs\86\81\1f]&i\8c @ÍT*e\e8LÚÉãP¦\86\18\98\ 6\9c,W\87\1fÛDà\86y\9d\87\98\98n\86ÆWfqæ\95\r\11.A\91fÚ¿{\eÒþÄÍ9yB\15¢kñ\1eHj¨ÿ\8dR£­\bBO\84\96\1alÃ9½L)ëyÓÌ¿Ý(\ 6ª\89ÑêË«NS\b?\e+]5Y\10\12}í¥\99µîõG<gA\10\1d­\84#È%\ 5G@\83\97X\9aêf!\b\95\/¹\81\11Z\11ðrl1\93L\ er\19·íÚ=*!Ù\18©þ>K7\ e\81s¤> I\81\9fÙ*wÒ
+Ev\98˪ë¡\vÇPá\12u°ð±rÒÌup;Z\17q\92êpN®ð\9b"<<\94(\89]:ly`\Ær\1c&]®\17G\16à\vÒ=Â\ 6¢\9e¡\8c´\ 3\81\v\1dkÛÂ\8dö\96MÄH\98ü-U©å2X\98]\19,\17ø¯ÙÒØ\92|ävÚ\8bf/K÷5\83\12rîÅ´\94Ö¼^   \88õ.A\bºV>ç©\95t×íàY\84\9c\18)Äf        bà<Ø\86áÊ\83øuFNH\0\96\14í=¤§\8dÞ\91 \1a5Û¸¿T9èú\9c\1edP\85Ô\ eà"ç;½NßÚ"\9e£x°F@ål\ 4Þ\94<8®G\80ê1ʦ\86ÑP\89¤\81\86¿Í.^ï&GÍ\vê¤\vb\19k\17  X²a\97ôê¦p\fã\ 2\92\ 5\9e \94C­Å}Åg<¦zJî¡xÇR\98\1cÈ|ØïÍË\1cR\83\181+õàå4×4\1dÚ\82    Úqýî ´ÐG\8a·Á*\8aG  `èÀ\97§¡\838´´ô¸oi\ eâ\8dª#\82Í\8bür_°$\9dÜgø>)\81\0\1f\ 4k7Ñ\ 1\vÓjÃ'È0]ÒËÛGÐ1¶r\UÏD
+\89\9bx7_\13\190ç2[\ 1ù`Ùªsníz®/\92¢wË\92·[tÕ$)5\82\82­'\8b-× ²´¦ Ü³t\1c4p\9b\86°\ e£¤áDFÕ%a \80 Ã\0}\1cõ\17ê7¸æ\92[¶ÙÃ\11Pà°\89\eQέÄ\e\ 1|G¤ÑMÓh[\ fù\80¡\aµ\8aSª5ÞõH¶CK\0ÚZs\9e«Zï\1eØ\88 ê²\95É\80È­\81\15Í\r\85e\ 5\16áçÅ6`\12\8aã£y|±R³Ëh\ el\ eYÛ%.]Õ ±iW¹Q\9af©Í¾ï\f¸-Ë,\8b\1cÌà\8c%á>SÍ\96\94¤Ñ¶\ew%ÐH;æAÄ·ÔÄØ\1e¹{\12{\v+°\S\15¦.àÍ\85\e\9bO¼|\14ìHÚQ-\ 6º>\83      Ù\eO\16äéjrº\8bJF*\18]\82v6\ 1\89\98Z©Õ«\86õêÁV¹Ô\90!£Í\19'\80ù\9aù¼\93ì^n\12\ 4Û\86\1a)±îf]¬\bú\1d\14ݦ\9d\19uóh\1f½`òÒù\82@ì6ä\11y\17\f¦ÎÉ{éi6ÃUd\96Ù²î\97\ 4\89÷¦)÷IØ\856ØôÝ6Á\818ײB\85\9dÊÕlAûãA$\81ÎÌ \1cR¹Î\1c×Ï%x\b       ¬Ý\1a\8aËQMi#\97}Nî5¨¶ôò?¶Ë%Ë\92\14\a¢[É\rt\1dþ\88õÔ8÷?mû\bw\8f¬\1c\ 6ñ\ e.@2»¶3Õi\8aqgd\8c\a[\ 6+Ârq\ 2òUç-19\8dæÇ¢©é¹±g%\eú]\ 2íz¤^¸\1a7)~ÜÝ\11\82r\bD¿\rS\85N@\89³0$y:}\11¥\9fÏ¿òêà\9d\18¬\ç\10cq¯\v\1c0\9b\ 6óã\1a4\7fH^á\13øèí;\f4ì8y\86\93à\aÃmG¯ûõãñþh\1a\15·Ü¦\98±\16\89\ 6j_\10Þ¶Iêqx\1d\10\9b¥\90\v\93ì§èî"n\98¥a\9d\ e­\ e¥µéÑ\1cEuÍd\ 1I\19µ×\9c\93¼\ 5\18õ\1dª\1c       ¬\87â\97N7êÈx\19
+#>rraU\18yúj1\1f9Ff\ ez¼qna\ 1Æð\10      ¹¸\8d@r¤J\84#@àÙ\97f\acR(¹     \16H\1dMOÂ\81%\8føÇÔÛ_JEè¬ÈmûÑ,\90äxü·<ÜÂìõãlY\1e(!l§\84\81âÍ·\9fG?Î$\80\ 6@ûé|(>\1eê\8cÎo\1e\9f{4ÛÉÆH{(\a\8f²¼«\80ddk\95\1fæú\ 4\15ö\19Èû\9aë¼v\10Ó<\9dHëS\1eÜùÊh\15sq)ÐÓë    \89À¿h\9aÊèN·^l¥_\8f\99Ö(\8c×\81Ìr\11\9a3¾9\f<Ú¦\ra(ëþ¾Ë\10híMä­õ\92\ry\90S/\rdhØ       ö¯¹¢Ë-Ò\17¤óY\18\e%\99\85\vûå7Üe\8bå\ 1øáÍ'm\8ce4Ü\86(ðßë\83\ 2Åh\10\16\fè\r\84\98síÀ\báÇz}¬p\87\19\7f#* 7Bç\e\12yB\v\11\1f\93!\10öë´Æ* qC\93  µ\ñµ\90çZ\196öèí\ 3T\fQ\ 1\82Âë=\1eÙ£r1\88pn\84G\88Ñìp°O¢tíü\97°>y\b.×9ÿ-\88\84nlfÅÝ[\86!Æ"»Á0·çÁßAê\97º\99`iæÞ{ÓÚ\15\vðÍyüb\98\83i\8e£ÁB>¸\18\15\ 2*\19\84w\rÂá3I\9bü§(\83.]9v3t\94¶Í\ 1\ÄfCØ\ 3Â\e}|Ë{²Ea2zâ\17ù\7fÚÉØ\ egä>ð§\9dïH=¼cÚçÇ;S\86@\ 3»\85­¨\16w\1fpHn\82JðüÅþÄoUÁäÍXOyB=û\19¯\ 6gwyÁ\9cæ³óeLÁè\vì\90>\17L±^,§^­~&\1dÂ\9cJ\81v\9e:\1d¤\0J\10É4Í\81\f÷¹\97h\16­©×~jÃcåìb\8aϬ÷êXó©\99Éö2Ìcsh\r\7fÜ\8bñ%µp\8a=ÑÜ\aÍq_\16\8f2d\94°-\ 5\13~\ e¨tô9D\8b\b
+©"ù»ø\94Ç©êr}¸çÆ\9c¸¼ª¡Õ\130bN÷/­6JzI0¤rqptª%\V\94w\87ùiõ²¦\a\8e\9fô\166\1dÌ\1eÞç|L$Ï\87\95±IPï\9bF0­ÞU\9algÙ|4ý²ü\0³ \9a\8bl\a!6/\1f¢V\91Q\13\13) üéAqbGØg7ã\aCfK\18\91\ fû\ê"\7fîkÍx®DP<}ÍèÆ\84Ú5\13t\97ã\83Ó\90\97F\16\aèq¾\ 3\a­\89Èø6Ûº$Ì\936\r\1c\ 6G\1cÄ}âòdÔ'\17\ 2ä¡L7æ2\18þ\ 5Vñ{ôæ\r\9dÈ\87uön¿ÃH\.\1dE\r\12ô)s=tÌ\ 4\8a.\ eÚUâ*صú8\f\8e^\11¡
+\ 4j64̧LÓÁ\7fJ\vzáüÓ\15!]³ëÕQ\ 4þï*øJþÞ\e{hxÎYøà\81Û}@\11\93;g2S¥Ñ\19\14É\84æ4<Ȫ8\r\7fLá)j¾å\96\81\15\8aV( \1foÀ9å³J(R\85ß÷\9bç´vÏ\7f´7nw\1fÉ\12äÝÉ\ 5\8bív\b^\1c q\11\197\|t|³ò£\\9càÔ#\11:¦}£~ë\8a\9e\\84l~¦|ü³\8aô\1e3ºJ\1e\1dS\8e~)J4\ 4JÈbNù®::î\15¢\199å°\1fåZ\08Dë\ eéqç
+M&\14-\87\14ã8½8ª!fóÔ\9e\vx1sï;¤¨wé÷w~\7f\14zaÞÞò\94¢ÇÚÊ    \90Õÿ\14\80?;êuVê     é>­\v\8dÔå¬xê2ÇÎI\1aÍ\8bÛéÖ\b\92¸\82×\84Ñ]}b\82(:ú\19\8f\1a\ 2\91[\13b\ 5³\84ËÃ"\ 4n{^ú\8cñ7Tû9\8b\84¡\12\ f\8eºãÇF\a¬\1cP\918\17Ù\8aê\85K¹_b\89Ú²\98½\1f\15\ 6)ë¡·$OÖ+98{XX+-K§9xõ^®k#K®-\90ÁÑ\81&w\1eåNø\1aÀ»îøÒ\14æ\16\0ò98©É=\82\7f±;nm\90õ!m9lIC>ébø]Ð\92µè±PD
+m\10éÊÇÕ^ÙþA\98\18\eÕ\85e¦HKóa7*jà´\97\85Þ\8eD=\12\94w\96¨\8d\84Æ\a\93r\96\82\ 3\8dniè\87éE¼\f\8d^iÇ\19½Ê0Þ½í\801cF\13w÷ví\98<~ø)\91j\85\ 3ª1g:lcïÐ*m*§±×\1asÈ)wP'M\98\0Ö8ÕEÕ\81`ælüíbñÞUà~\9a\17ç\15"<ÌÍ2p]\14\133\93ɦ     cWì\95tI®Z\fz\8d\ fsÊgÒ\a4¸µê°ÁîÏó\raËöùnðDy
+)X,\8ev\ e\eÆ·F\95á\rý{\ 1ßÙ\86ëhiWBZÐu¢\92FÕú\9f\92\9eÉ\8b¼\1ec}@²"Ï\ 6\a\8cÿÒ`¸¼B\8b\18ú(îDÎ\bmG¥½/ßè*Ý"\8c\8bÜûø\8b\13>~e\1cMN>ÖÃV\ 6#ÿø2;\9d§öÜ\16\1etܤ\14½×d\0©cd\16\82Í\9fk2×\8eùÍ\81\9bÐ6\9bÚ¹\1cÊT\88\ 3\ fâYýoºÁïû\93\rÑûHq×\1d\97ßC\99±\8e©SîÇÖ
+/!\17Ñö»%âC»ïÑ7\15\9b÷ÄYâ0r\8dGÓ×0DG\ e\81\8b¥\16\10.$\91ú©näi\98b&Æþ\1e½Þ\ 3\ 1^p7vÇ}U«âP´2[&bÐÌ,PÑõÏä§\13\8bx(\1f\1a³¹\9d\11vm'_ks¬_\92\7fÊ\83ÿÄ\94¿¢=I1Y\1e\8e\ e\8fW.¨O\8b,q\14+\81\9e##ª<PFLå#HÀÂ\0fy\9cA\ 6S9ôÒàës£k\a²\ 2oãÇí]\8c~Ê{ÿuãI\96ǿ䥨dÖ}\9f\ 6Ã,Và°\9eK'\18\9cm6®\10³OW\ 2x\965\1e\ eÂqÊ\99©îQ\99Õ\1aGÇD\97e\9e\8d÷ìL\ 5ÓÆ\81\82ZFW=Í\19%w\8e\95ï\bâôÓ\80    
+<:ßKYà/þ_ú?%\94.pÚÑÊyË\eG>Ã\91Þ9{hñ¦WÀgÚ\ºX\r\9bq\8d,\8c2²<
+¢Ü\98¬Ê\9dÝ\90C\82\14\8bk±UCixñU\1cF:ûë:m¼¼[\16Ü6\ 6\86q÷Ó³­q\8b|-\10ÚÌ\93£¸\85×I$\88óI\9eðÇRõføQ£yçÉ!ECF\ 5\9e\15\15øä\18\8cä\ré<\17a\ 5MúÄé9ñ1*ä¦Zf\92Ae\ 5iTxu9/+\9f\11â\1fx}-\14?°à»H|;É\10m\9ck3í\ 1\1fèVÚ1~[<\ 5XÄEô_?\bâ^Þ[\1d>¸äé\84b ïµ\19PÝXºWP\15Ìín>Öñ}\0=úu\8e²VÂÌ\9a_ZÅ]\94\9b\9a¿/ÅF8>A£ö¼\89WÑU¨u2øÁ¡ì@D­JÌôÙ!«"ZW\92.\88\8c\0\1dÙ~öZ]\1e,\18\7f\ eÿRSà\1d\90>`#Ý;«W¹\b÷¬þ\1c   gµ\LZCa\8dTô&[\92«\84\1cZ |Ïð   \81ij&Æ\ eã\ 2\95aµî\8bj\19û0\10»Hlév\98õ{@üÕÜ5\10î0\80Q\ fC!$vÆ¡\1fØÞIK\1fª=\9c{\89êjøý>\17ÀÔFÓ±
+\bÄ}p_\ e\14R³é0SI\8e[5£]áCÙ{D8h\ 2¯zÀ8fåí1#ÁR·µ}-÷\fݲ
+\96\81Kí¬/\1fâA('Ø\84|¶ç-\8f=¬ò0;\10ÂöË\8b8`XWg¨æ\82§+¸\ 1×\8c\87û\9c\1dw\f\99\96\eã\8c\88\837)Í\9cTrÕME\91t     @Ù\8e>|\82\89Î\89c>Ä5ÏÏÓ\0ALr@\r\13æ"*\ eÿ¸­3\13;§Ò\ 3q\ 3³÷Q36öÚõ?åA¿\13ï E\94FU\12\97بlsÖìv\0\98\bl9ÍdcoçS\ 1âÉ!Eyg\99®  \fN`\93·K\9b~\10ó-¯xKóVܧQ%s\84Yi%]£\ 3\95ßT\89\1f\ 6ÆzæªþÝÞõ{r\90n/º>¶óºàάÛBÔ\8cÙ\8b\91ÃÛä\8cm2(=\17Í,Ã¥Åwx¨}7\11:×9HV·Y¨\9cmImoÆT`\15¶#>~\ 4ë\99%>-üýR-\1c
+Á2I\9fÊeý\1e¡\17Çp]¥E\153|8|\9aìôìÝQ\ 1\87\1eÿbÀ¸!\ eC1}\1c\12é¸æºiîÚºÖ-\19Â\0ÌpÛ\85\ 1îM\88\13>52É\8cý\88x\r£9ö¡]ûi0Ò£Ý^¿\16\93æÊ\96\89\15\1f^{P\ eO\83úòµÀ>èÓÑtS\953(,]\9c\fI\11¤à\143&nÒ\9cO\^\9f\19\95O\v\1dÐ%l¡»5Îàø¤\8f\97\96È,u\14G\97ó'È\ 1ø+3ãË\99¼ÍÙÿ\83Á\94ý#Râú\98B\11\80\92Ø\98Êl\9f\97Ì\88ÊÀØ:\8caæÿd\97K\92Ý0\f\ 3¯¤¿ìód=÷ߦ\ 1R¶'Ù½R½\92%
+\ 4\9af=ߧ¯Ì\bCi\1dN\19«ëòØ\83\ 4\fì,\82\15\9fdôu¨¼I¿Ehåñ(kq\0AÎkìÀ`\95ÉXÕáõ\15øÄãõH\13\16\9bé\95\82\16\10\8b­e\87á\8fØ~¬ã>Å6R«jlBî3´«Åý,b\ 47\85\rÛ¯êoS_Ó4£ã9M¨ô\8e!\ 2Ån/JãÒµ\86\ 5\ fUïñ\8a
+?"\11öÝ\8eë\v\ 5®\95%ÔðÃ÷ÐÖöÃPk<ßA\85\8c\17«¸æD\12ijël;\15âHZ×Êzò½ëwjü3\9exo\1aé{ì,Ý\15\15\82+G\95æ\ 1°ò8­\8e\8c`Vô@\9f'5\94\98\99\1a|Þ¶§\93\8c\0
+KÝ\8f¨Å\1aÓ£»ÂHô-Ý©êGÕ\11ÓÃLʯZVıXÒ-*\ e\10ßF\1c\1fcÿ\7fóO7º"×Ô%\e\80\92i§­\91O\ f\ f\8f\89\1aÑ\85Á-°!\9dY(ÕÊ\fó¬\18ý\13®¾¤¦µ\9d\07\ 40;üª Û\17\15\9ab\91ȼ^T¸\87\8d\99\84½´¡2\94E¨2LØwÔb        ¼µíÝÊÐ7\91\90Ñ4¦Þ\19)\99HX8&'\18§çg<ÙX\87Ð[\ f"ýRô8îôF
+ý=,Ëßø¯\e\9a¬\ 6wØÁ`\9e       Àn-®\1c8\9c)\90´      \96oKÍo¦\94Äcý\7f\92³¹9\8d\ 1wk\9d\96Äó|H\94[4¹j¤¡o¼wÕÕcÞÀEôÎ\7f\9eɧùt\129Êt\ 2A\1cò\ 2¾F    \13\99Õa¥û\bè\16bûÄ\12\82èï\80Ä\9f\13W\80\99\8dBz\1f:O]Á\17Ť-£j:ë\87´ü\8e-\18\ 1²Û{\7fjòó$JÝ9±9ûd\95\8c¥\18\93\1cJ³µÄî6kzû\96O\ fÏ2*Ì°ý\82j\90\9dêϯ»ÚÚ¯þLº\18ÓÝ?Ö®\11RÞúÎCq4M\8b=Ρ    2BF\ 2\9d%\89>\90ù¯\0\ 3\0* O\ 3\r
+endstream\rendobj\r17 0 obj\r<</Length 18715/Filter[/FlateDecode]>>stream\r
+H\89lWK\92%7\ eÛ;Âw¨\v8CâOÒz\8e0GèuÝ\7fk\80dæËj÷ÆÑæS1ù\ 1Ap\9d\1d×
+Y_[÷¼¶Éþúßß\7fýÿï¿þY'â²u\1c?ùºbÌøúN»Ïkì8°\87^j±¾`´sM\1f\ 6£Æ5Ä\8dÆ\18\97\9bÒ\83®Kç¶?:\1f×Ü\1fçë:Zv»\86K:÷s\9d°\r£MD²Êy\gYÐ8.Ù./çp\12\8a\båÈ¥cìv\8exÆtü\89ì}©Î\99\91ïë\9cí|<.$'i\\97\9cÅ\1cǸÖüú\95\7fo\8e§1iÝ×\8cÈØô2å\9fëD\8eðÜ\ 1\ fß\8cm\9eËG¼«º/óLpÌk\8d!wâ~í\ba\18H|\89¦\9f}     
+A?\8aÇ\15Û\93\9dN\94\1aÎ>ÎÑ\9aÐÍnN8  \14ª\9c\9b\g.\7fÙaTE5ƪÈ\87\9fLG\11Æ\9c|)\b\9d:\1a\18®ÊVâÅöÕU\8a%§ú2ÌNÆl¨¢²Hzð3¢)\ f°ÛQ)û\8cÝo§\1d+\9bí¥]Ñ\98«\1fÊ\89w~~!N\86,\ 2üø\e\92\0\ 3@3ÿª¤]\86\97ñ®¨ÙµÑ\10\1a        IÔ¶[ËRJB\15¾æñß"ñÇ­Çå;{¢\82\96}p·ç@\12\88S\17\94\v_üNûD$\9a¸\81]\8d\95f\91¯ØY~TA\f\95¡q_[4\8d³bþ\95\1e\90î\8aL\105\1f\a\88æc\94Gós\ 6t\9cr\80üö\91jÉZHÿ\8enltkgc\80þ\15]¼=\80·\88Á?Á\0¨»ÓÏ@}#ý\1cÅW\8e~ýÈ\ f¾&;_Ñ!jüF\1c,´Ü´ò\eÄ\ f+½0\9f*\96\1e\0\8e³fq\87+þõ\84w03`\19þÄqß»\8b\87H\86'n\16\8a`3Ó\1c\vS7Ó¸/\8f(ç@\7fìS\f{Voáy££ùxk\8f=\8cJ\9aê\98÷\922\ e\84_\89p\98ѨOõP\ 6ɹ=~ͳ¥«\87J\9cI\1a2Î3zB?\e\19\18     \v\15¸\ 2¿§qÂ\ 3Ã0Ô+4V\87·ìÂÿ ç&D¬åc\f¹»Ñ8Y\97éi\ 4×\18I\96n}|\90G\1f{\1e\8eç)fªàP\9cX\87pBuE²1c£ º2bG\8bNF\8c\97kï4vA;8$\e\9c\17\14\1e´\9f±¡\9f>        F:8á;cc\15Éõ60 ëÝY2yÎ\96\ 1\9d\87S^Ña\92ÆÌ@0IGÀ\140\8a1\10:Ç \82\7fÒ¹`ü,£\9bd\91ùÊ\1c\83\e(k\ 5\bö^íÜ8±\91µ"îW\16\10\84\ 2겪êì¾`a\ 1¬iä¿î\99\e\19\14ú\99ÕNê¢\11\85\97­L\13Ã0LÛ(Á©ýCî\80Ç!l\805lH\7få®BT\8b\82ã-{ÀöOf) .áV.£\ 2\980\ 6à-ç¼R\a2°0ù\13v¨ap¿oû\9aè
+¾©×>'³Ä\924Ï5ç$\8bN<æf\fäUG':q2 5\81`ÿL\ 2µ\8cÈNù1ÔE½ê\89\8d94\8dÈsÉúxð\8e\f\846\92®hL6ÏÇHìv»Öi\ fÎÍô¤G°Då=ÑýN\ ee_ggrü\ 3Í8ÆîUÆLr1ÃÆ\18$\1f\82_Eî=t\ 25\99Q\85pµÜ©Ð     èå)c`½Ò\88Ñ^aù2J\8b\94\87ŵtvÕ}¥\88À\98H=ÅpÔ&Ý£¸\ 6¦S\12áÉ\fcãÁÍĤÇ\9aÚk\fÌr\80\87ú `\94û\ 6ÄCpJPIøéhãdã~s\8d@\90\1d\b\87\12g\14|Ë5¸\13³\93Ñh­¦\96)\96\89,\88¿[»\80eÝX
+pàÀ2¹7$\9b\18D\ 6Ød\92\98¾e    ï¤¼\9dÅ\84¢\8bÔ\82\ 2\92]?\94\19¾cB®\83`C ûV?ÄÔ\8a¨°\95       Ô¶\1f#\9bBêÔj\8a3(®   9\13\13>_¹\ 3÷á'%T\\80Çþ¨\9fá\199ÿÄ5ËJ\90o?­·º°Ð<\92¹ëPä¨Ñ¹\vÒLè*\16ÏÁ^ný´'ÉDå#\19\94Â1u\ 4y\9b\13\1ev&ô\ 2\9d@ö,}ÂÓ\12ÀùѳÍÚO«[<Æ\88I\e×Jé\81)ÀN\90\978«Å\a\ e\ 4od.à:\ fkÍç­ùH,É®\9aò\ 3Süë\11\88n³4¥Æ¨Ç\13\bÊíÁÇËv\e\97y{p\1fû\87:\9b\15u\1dVè­Î\90V¤lÀ\ 2\ 3´Ó\ fÈ'\95P^\179{UÒ5R§Bþ\0
+z'8o\1d\fZßǽ\1f§³<9\8a.\11\1e´F¤ªR¬D¨\95Wx\8f\9a\83ä\17\8aéï[ÕÏÁM\81¼\ 1\8fyë`\8b\94¶,n\83\9dÛt\9c?  Ómw]1\80ØÁ·ðÆZÍ\85\aéAÁ:V_.~Ö*=²¤\ 2Ç\ 4\8cÔ\11ôð\12Þ¤`R{É(ë\13\80·ZÞ\17<±´8\bT+É\8cz3ã¯û\1a\82\92é;\ eÿ9}DÔFMc7üsRá«\83\9dàڥ°Hx~T\82\9bG\8cdâÆ\e£É0G8S\99¹z\93\80\ 4
+\87FL\v¥M\93)´9Q\84T\18\92­û±¥$\r+\90Ñ\b\9dtRP²VþnmPV&(Qp\0ï\8e\8e·å)\15K\ 1\anæÊk\12eÌSåÇå\84Ôý¼aͫѲ®d/¾\7f\1cÌê9©±¿h\89`
\ 6\13\8c«@\19\9e`úu_-)$3¡Æ\18\9c\8a\ 5ò}ö\19Ø£üß¾\90\ 4KøÁõ\91\ax`,Oy\våwd\9cî/rL\9dBy_\83\18Ïí\ 4éHÚ¸£óÞ\ 3)x\9fc7¥\14\90ë\ 5ì
+\19ÚAJv£ÅûÇ6\ 2.òý©¹lºG\1a;ùô@È7\9f2˪ó\86\1arBrÎY2\1dòé\86\rì)¶K¾ïO~3i\ 2[dD\11}x\91j\1a\97Â\0ßB¿§Â\eÔÄóÖ\18è\17×M*õyj86§¿d:t\ 3÷b\95¿\8e\1cT~\8dj\90Ï*¡     àõµ\vã¢\ 6Gù±:\8a\90\89Wn¤¬\ 4Äð~E\axPqçeñ( l\7fÞ\88k\96\18\ e\10Ù­6\84ã\ 5MZ\8b\95Fò"\ 5¶b!\ 6Wöã\\ e K\9c1\9b}Æ}1`Ó\ 1\11,  øsäÖàÖGàÔ\8efyì[si~\11
+vÙ\93:ðÖZ\1d´¼zkC\bL§Päçfë+¼\f±¼\vУåïð\0ë\14iÏOß·}íÌ]@Cb),±²\18\ 4\8d\18Id\9dFÌöÉk\v)      ·fIS(ô¾¡xThæGÕ\9epä­\90Á\97ÐôºN~\8b.;0õdñÐ>"þÑok\8c,      ÖÇ\16ë&xpBY'\99{?â0S\a\e\a7ÜðjuýÔ\1e_Qâ"?\865ºÚØE\16*O¿)eñþ\10­[òX!\17\13Ò'\15Òs¨\8c\1fò\94È5;/\91F$z\95HJôwz$àÓÁÝ\8a\822sç¬\88\17tZ9ã\92­;\v\84\e\7f ,^[ç³H0\1c¶OG®\r`ðº¥,¡óT`¥Zg®á§1\ fay*C\9ef7\1fSXzVopT-zSZ\eI×ïð\1eýl\0\10dòͧä¡Q5Á0¶Ä
+n}\97òs+7èk\e®Å¼áÓ^\9b\ 4.kc\0AÙõïÛ¾,±
+bPëM\ 2 êl¶x6\ 1\18Kòª¥,üð\8dE\1f\´¯]G\8dÝ\12\97Æ\ey\14¨û\8eaB|Þ\12Kî­xFé¡[.ÖÒ>õáZ[\83D\9cF´ù|Ö\19\92\8f\92\15«\ f+ÅË\185\11Ï}@\9bF¼ ÷¨{lz\84üHx\9e\ 2\99\8c\95«¤ó\10Mc*ªRsªµø¨¸\1et@ekIH\80SÅ+:èT\9cr4Z­ö2bSY-9å\9dú\91ð sr\ 6ÅÊG½wdÁ\86\8d[\85B#K\19\137¬0x{§â\ 5þæ\ fõn9A\94\f2*\bp'f²õ\96óD,#\96J\16\ e¹\81þ>\1e|HÚW1~\ 5&ZFúªv dó¤\1em¹öÁ&òHºã\81\bo\1f\91\83\9c\1e53í\1aç\ 2Ä\9dzJµ6°N^kApûGºç\95\ 6¿þ¹M\9e\es7\84\1al)úx6ÊK\³K\93¤F\17Ï2(­\15Ò7­¬\a²ð\97\8f©\97kl¸¶Ê5
+\94Y4(xlr-       äy\9e#U£½#oTÔh\14\13AûÿËv¹¬Úu\1caxnð;ìI@\86 õý\92\8cd2ñ,8\84x\16\84b\8c\ 6\92A9\19äíóýUÕkí\13{bä:½{U×å¿øz\945\/ÿVû\97þj«gü\1fqºuÐ!\87Ì/]\12Ås\1e\ 2ÖbAñt¾\10\8dêÚV\97\11»år´))\82 lqÛI÷z\96\ e9Ý»\ 1í\b\8c"Û!\9dv        DS6vw\9f¾\ f\94LäZ¸.v\95\91Äí,ÿ\9a\89åËTìí\15¥máa¤å§7ª½õ¦òW×oô\a¸ïOâðv\92GÕzfpçQ»ükº¹)ìç\Ý%ôQ_Ð}Á\95ø>¤u±¨ÄÍ,a@ö½\93+´¨\8c£w\15°Ìæò~«\r¡\8bducüæq\8bÄéU±n7F©zO\18Ø>lÈq\86)R\ 6g\f\7f\b\8a\ e#7>dÊ\80\84\86\87c¢=v\949+\ eoZ|\11\10§\99é\9aëí\98\8a©±¢I\95úpJ3ëJp»Sóæµf£Â\eä\ 1n\8aÇpìó\97ëuÄ©W\91\94ÒëL\eG\ fë´\ f2\86%Äì!Êë\86{äxb\1dv¾:Ô^X\82çÐÖ\ 3
+%D±Þ\96lÀè¶Y\1f\9d\84\8c¨²\ fm¢Ã7L-¦Ðv\1eº1u\19\14Ú}\88­(&0\9cB\8dM    RÖ\16f\f*1»¢ÄóºÝXåm9@m\84\8d®Ù·d¦\96\1fÏ4n{"ª¸u+mȳE\eúX15zð\1a65"?vD\87\99H\93`EZ{&\vâ\17ÐHÍ\83\9bäC¶R»f5\95´\f4§[ËD¿&dt4Ü«ÁåÑø\84þ\94]a\ 5ì\92.³1çQÕ0Þ¶oÒà\91\9b%\82E\yµèb­¡ù\ 3\)\8c<áuõ%·-¿´¯u¡\80Kü_L*o\97ÖX\8eb8\81\eØ¢9\17ÏcØ\94!Øm\abaä_\97 \8du\1f\97¦ÎÕÆT2Ù\f\89\ 5éëô}[«=[©vz.Äïh\86È\8eáÛ~Orm«D²kBëÀì.\9bоîþT¢ÚÚ¼/\17\90¯Þ|ôT\1d¿\9by2\8a¶ú5í\8f\aÝ\91©LîP       fÔ\82-4¯i£\9d\9eÓ?×7ª\bÖ˼
+\90e\ f ØiP¶\ej\b\a;\99D\ 4~C½\88Z5\8d±Cw÷dD\r\rÃ\92v\83D÷JÛ\8bWE\7f×û4\13N}-Døçóîa.HHƾÛôQÇ\92¬\8b5\85ñår).Ã\8a\ 3\b×åæ\89JdØS?\97WÁK¶\11a!Ê6ËIÐüîbO\99÷aÏ\91\96Ð#\br\97tr¼=\85\8ba<\ 2hmÒ1¶#\ eç\87[Ê5­ \jÖÔ\7f/W¹m\f¤øsÔN\ròÚ%wM
+²¨ã,ìóºÍkÌé$`rÞFáð\9c>þ]
+]\87í\9fÍ\1f\8cBi\91[rp,¡á"·}(\0ªÓÈyLÜ©<*ïè\17Äì\ 3\eÐ}½³\93\8e0¹nx§JE[åØ\1c$¸Ñä¨\ 5gw\19\90Ü\96\9d­N2<#²\e\ 6éø0;\8c\11ë\92;\ 6Ü;Þ7$\89\r µ\18¬UÜ 38Vu\8c®ÓÎÂ\91kÎíP<rò\vÄô\1e¬Þ¤ë}\b\1f÷.\17Jûû\90k\94¥ÇO\92¯ J¿§óÁ´\9b\8d\9btB1ì\12\98×|²ÃÂÎì\vÁ\8cT\9b\81)=dÚ©9Õú+V\90\ 17\89<¢>ó@¼\1c\ 23ý}\rÿ=\90äÀ0}\99½<2p7èPÎî@¢rÎ\vuÖ5õTilK\ 4%BÁ\96\ f¢¤ùIÎ\9a\aw,mçïÜý\1a-EôÅw{ø¦ÅddÛ\b\ 1\80ظ\9bp\15Äì³Rò7>EBÖ\15g×[8z{5\fÀ\15¤\bÅK,®HO}}Ý\95\9b\89\9cJ÷¬g²k¶é\95h«A\87_0\8bKð°\ 5÷ÌlgLK°å}ÐhÉ\83\95à\9bÔJÜÝ\8a\v9\18\ 1\ 5iÁ~\92àá-\84üÊ      ,*Æ¥µz±\15$%·/æ\fmfr\1a§åçáq\ 3\99-ëI\17ìûÔî\1e\9e\f­jϯ§\96.$üË«Ò\9d\973\11x\87»tnW\v[ººo÷ÞÎãf_òrþÚÒ´>æ\8cÀÚg¤¡Ç9F¼%e\aÛ%Q2\83\90·\19 [Ë9\r\aÄd¹Ýx\99ÅÆ¥ôÿO\8frpÐãÈS\1c\86
+\95\93\ 3¢µ6rÎYc\95\9eô\89\17O\ 4\ 2Ð\8b7-;»Ý\8f\10\98W.ÒÖÙ\1c×tÖó\e\88ïmEE÷6´¾Ý\10\92\10O\88"\{EW{²\11âù\r\8a¿ËOñº«\90\ 3Vñ>\18h\99
+9q\ 5Ù¦mk1\8a\13²\a\96\1ee\1e¥ßÓaVÄì_ªÓç\vØ«VþÙB¶Û$¢+\96\9fD@Þk¯ç4ʤ̩m9\8b\95aJ\ 3\18\8f\e\rªÓ-V]&*\88\0\9b6\8eØ\8b\8aô;Å\83\a\87\87\98\83\85\97\1f[:\14,®   \14¬ám«\92\9fk>\rÇ]W®ká\16m8`o}t1YyzoÇÑu }î«D°e£]V\17ªÜg:P/ÉÌ×\96¬l+Æ\8b\81tm"\14c9±jÙ\83åI`>'Þ5ô!\7f57TL¦S\12Ôü\14ËËá\9c\87¿Ò¶Ý\83À1ïÀè1&-¨\1e\e\14߬h\97²Ì$ \8eQÕZd\ 5g˧x;     ú«Tõ¸í\9eíE5\19À\1e\91Æ:\9b\95å*ä@°!ì^ó62Z\12b\ 4ÓYü\ä\95ì!üÆ\901zK&&\96\ 5ÌòL°\0}ÚazÒ£á<Ä_Í\rfgïôXpnáO\12\9f\9a¦¨\1e/¶¨(Û\14CF;õfɵ\8b\834`¹#\11WíÙýZ$W¥Ìu\188@±õH.\9b\93ª²\87¦-|¯´ÉUÆ\böy\9a\91å*ê\ 6\eøÞµ\14°\1cW7\1an~À)!Ë)­\96çy7ÕÆj±L\ 4ɽ¶'º\ 15éZõ»g;\97\v\80\9bx>\ 2Q\890úY_\94ÂÈ%\18\0Ü\1f
+V7`\81Çè¾,\91£øê® X\1céT&!¤¯lÔ\9eö}é\8bùD\15\e§7\9aÞÇd X/¬\1a¡/\9a\9a<\ 2T\18è^\94\ 5\9d0¡ë©u ©Õä­\98\87£\9eV |\13EJ\81:ñî..\ 4wÞºI\94~\93Ù ÄïÇE5(­9\97Õ\13Ý:r\8eÃìÚðó\96\16\9al\1ag*¸\91÷OÏ\93DÍö<\18oóËϧ۾(M\r¾\88>o{²ælæ\1d\82±\89Ñ8È\14IHùÝ\7føç»÷__þòéã˧_¿|øúßÇ\9f\14{#/\ 2\16·ï\1eïþöòõÓ\97_\1eo¾ÿþýÇ\8fÿùüã¯/\1ftö»Ç\1fuòÏú\8f¿³\ 6¹ë\9d­]ú|*  ñ²¥\83\92\8e§ú\946ø·»Î\19#\b¼Ui´ul%#Þ»\9dE(\8díµ\82ãÝi¨+Ìä
+c\8a¾²\97\ 3 \8cÑ\93{(A
+M°#åëÙI¸e/à¼tÊ\14ìÛa°e\16×fÜÐzÍ'Ø\8f{0}3Û\89û0ÉH\18\18³øÐ\òØfQcw{V)Þ\}\9eV_\97¹Ñ\9c[ß«\ 4¡\ fOC~\19\ 1°\81oQ¹î5AxxUU\1a.
+==\f\17òE\87MÔ»=\12Ãy¯LïÚØ0õSv\90\14ºáÌ\9d\via\1dägG_sa<R(·\8dò\13*       PßÞEhÔ=¯Ìk± \9c{RÃâ±­ª(ÿ*ÆcÉ\84\17b\1e'¥ß\98\8e¿\8as#ñ\ 5ÒLTÅ:\1e\87\13Ð\12=(\8bþ4m\15Úe»\12r,F\ eM\87\19¼ß\91(\14a\8e\ 3_ôêp\ 2\82ëÂâC²\82®\91^e'9_ì\83\94\94ª\1f0æK\80©âãÔH\89ðãîà\96\9bÓ\18[]\91\1d
+2!Ȩ£\ 1\90\9eÙFàI¢\90\89¹>\ e7\9f/\ 5)òNå     ³¯ô\8aéH£!\86«\96# ª Æ2é\92MÙEÀ\94\9dÕåæ Ê  \82®z únã\90\8e\b\18BcÝ ù¹C«ò»f\9f[\92[Ý{Â?\rø+\9aT+ôÄdëh\11¾(MôùH\97iâ¸"\8e\83WT<Æv9!Öd\88¬`¨\ 5 eäVo}7A}e'e3Cl\99\1a Æ,®V\1e¯ú7\993ªñT»}jmR»\9eì\98äY\8d¢J\05AY£eTÆT9J+\ 6µë\83²X2­\9e\1cîvìa*\ 2d\GD\14¦B"B]¨1Ì¥i\14ah&5?IOñOµ
+\1daõùÈ\8bè·$\93\8bL¼ JeûÙÞ½p\ 4M#\93CV×÷­íò0\9dT5·nl´(Õ¶J\vßk\ fÁÇSv\9c,åI<±ÃØ?  c\ 6²\96\8b©\ 1wTls\89>¤i\14ÄFnÛcæ\18\85ÜCz\8eÐv¬ù^ãér\92\99­Ý\8a7ºÂÛtÎ\94>NÎ\9f\ e\11\1a\87KëÎìÒàî+Û4Úó6ó§RÝW\0Àuî§\96\ f\95U:ÝÒñÍ\0\vd\87ætÔñ\93fvÌÌ\fuÿãI/\99ô(b\9e:\8effeux\0\1ea\18\f\96\82\eèOOë¢în{ºÀf\8e;;0¹¹µ(\81\14ºfºYco\97QªV`\8deY nЫq÷ß¿ý&=Òã§\7f}ûÍx¼ùîñÓ?,öûÊ!?Þýðååñæý\ f¹þõÃËËÏ_¿üøó/\9fþýò?º«­UÏ«\bß\17ò\1f¾\e¡½0®óáÒ\84*HDð\18\10\11Û¤ ÍNJ5Ôü{\9fì÷Û1-MC2Y{½3³f\9eÃ÷R\r\7füðÝëP\ eåÓ\93_þ÷»wßÿçÑ\99tûųwïÞ||èí?¾zóú×ïÿùêõ¿?\16!ûd÷3\1cO\7fÿòí«?|xøêÝ\9b\13x\86\9eÐç\102¯oÏÞ¼\7fxýÅ\93tû%\8b|ùÃ\93ÏÞëWºý\ e¿\81qoô\9fø\rÛ\97nßò\1fò-é¿\97\1fø·ßàOÿBì\87[»ýöö׿¥Û+Üöò÷"8j²\9diëàúJ\8aidx¯ÅA"}y¨SI6~\b.8².Þä\1aqZ±A@ô~\14\11\9e\1a£Ï\15ÂL\ 2â¤.\b-\93ö\ 3ûìñd\90\16\97\88\8d\ f\ 4\92ì\8d­¥\a+\98{)³Ê\0ìí\b\81=äÑ8±\92Ïñóô\\93\95Aûï\14
+b\85\8b­øl\9b\96M\bº\ 4\18UPD\99÷\e,¼èu\808f\7fR\v\95F\1dÔÂE×\ 2\18\9aÚE\8eÇ\94\1eÏ\0Y2EÆ\15K­ý        Mb]\88\96÷å\v \9e±\86Ô\ fÙW=÷\ 5èÓ°Ö@\9f\81\17\8e#{î\84î\185tM·:\90Ç\ 1á\8føÚ®\96\1f\84¹Kó\13Ü\87\ e\ f\8a×áàº\99ôíh\ f\82\1aí©\976B\1c:/z)³\19\85\10ÎÕõ\100jpeÅ|¢|\14\ 2õà\18{û9Ë\88Ç\10F0\b`]t\ 1\9e\ 5\94Ì ®\92\v\8c)£ö\98\9a\9dJ-4b ,T\vþYjÇ£g\8bZH"T\7f×\9cö"졸¦pd\10mX*\ 2Ó\ fÎ^1è=±å\85°\8b\89~¥U´HGK»¡pÐ\9c>\1cQ_4\ 1\8c§añNy\92\92 ²\9a´\19\1c\87\17ð3£\1c\94\9eÀKî\ 1ð´\96\9eÂ\ 2]Ô»\0\9d­kô«\b\81\7fb\88Ø\eL\11ã\98N\94ðâ\8c÷\90ï,ÔPö,ÔíT\ 4H\82Ê%\95Ȭ\92I\95.$y\98\8a\8d\rïÊ\17C
+_*\a\92-\16UîÙPüÔ,^Û¡\ f=ÿ\89\96!¯o\ 4Ü\17L¾?öj\17U\8bgÔ*\87õh\94\1fÝqÉ=ú«\Å\10òWEO\aIÒÖ®~|ØÐ3\7f;\fg!\91Yí%ª\8d¤vÃ\16å°3ø±B\87¤à\82n\8c\12\84\ 1é\8a\ 4\18­ÍìswüX¿Ê\869HG3v¤\ 60l'ß~°\a\98\aI\]ZP+ë­£\vk©Pæ±lS²\90Á\ 5À\8aÜ>mÚ§íűDÓÖ¥u\1aGõ8§D\94JÝ2Å%Ì\r\14³Ï­\84\9dA§67¥\86A#\91\vB2 \ eÑѵõ\9b\89\13yJ{¸ûÓ\1eÓ\8co\19v\98\83ÚøµV\8bD\94\ 3°)Å$\7f#=¼CS\1cFiS #»\11\16\8eg%\9f\19$öP\9e\15\18\19ÌçA/ä\9a\r>RõFÐ\f\1cß\8d\89¬i\1dä\14\0\7f¡\ 61±ûQvPòcg_.\85üpâ±\9ek9;Ä ¡³$/>\8dnøîuP\18ÁÔ/êÑ@ºÑH)µCµµh&лPq$å1\84%x\9c\8d£ç\ 6ä:ÅË\94|Uþ&q¤\93F\90\8fƧr²\9b´©¢K\7f\\1fQ³º\ e\8cüº_\8e¼eóÚÈ;21Ù1¸ííXàR!:¹Æa÷̹OqC²¾Èxü$  ¼\12p¦D×ì\9a¨øF»È\a/en.\13<\8fô⥠\94%\ fÑ ì\ 6±ïF/)ÚYî\rjY\ 30% \18\ 2\9eT1\a.­d,÷\0\85K\9dB\98Ïvï\ e rÎ\83\80»\ 3a/Ì7åbE\9fâ\83;@p\8báù¹`}À!ì\92bX¬¼Oqø±Õrðå,\9e\9fI\e4j\14\17Z\ 2?7§d\16Nvj+ß0ã%%ÂɸÎ`\19\7f\80Ò³9+´q¶a\f\86¢\9b÷ê:X\b{ïãª"@\97Öç\3¶y\ 3ÁÍ)\15EÀiÌ\ 3W]ÐB\86H\17î\82nrW%c\98.L2½¸\99èýp\83:\ 5\92\85\ 3\7f\8e\8b{@]p\88n\9cðÞm·Y¢\9f9\82\11,\95\97Þ\ 2óS.ÚïLh\f\8f_¥*2w\8c¤|'þ\99¸î`\ 3\ 42\98í»â\ 6ò\84È\96:ð`1\9e±
+\8b9\11-\8a`Ã$Rа\8aç¼÷¸M+     q;ôðé1¤O \1e:0ð\9d\9b\8b\16$_÷#%ж&¹\84\84 Y\8e¶â\83\fa!¿á\ 1hÔú\1a7äy@\ 5J\12²2T@\9eë \10âe¯e1Q\93Å/\82\ 2þnsþ§EÜë»Ô .\91¡x8ñh?\8aªÅà\84{v\93\11ÀÌ\1ew\80\93ã\9a\95Ùæ\91¯\14/æy\fî¥\1d\17à[X\88Z¸ª?\9aÂ}ÂÛÁ&î8@õL8ä\829\8a²"D\10](\ 5±ÅB7\9bqT=r\90\9aTV±¿\8b\86Vr\95 W[\8c'\06G00\13û§|!pû\98\8fÆ{f!2\85oO+v\ 1\1cY{=ÿI\15«\92Ó¼¯Ø6¸Q\14\ 4»!ØJ\rEP\9bµ\11\82ɲ\962\81\93~\7f=\8c@Sz%dêÃ\99Úh3ùaÍ\1eËÞ=\\15À1½\92P1ÅÚUÚtßg\và*Ù\ eÍ\91«_\9aö1Ç­+V\92þ\aèí\142dýñEýP!©\bR2ü\ f4@¶\96:yÑ)UQ\95н\95{}ò\9bbo<)\0õ\9aÎr5\15oÖr\89Ë\83\88H\1cu\9dË5¨Ð\85\18=j¬K³÷ª·Êýî£.C
+J
+ÊC}\81\r"º|u\bX#ÏÅøô\0лΡKñ0ÕÀ\v\ fE\fs\ 6»_Ò\16ÃÒJqiG*à\824Ý´âyÿ¹­«Ù\9f®\87Cqï\ fpßÉ\91ÚûÅ\0x´>õMª^b\8e¿8d>9³2\1f\fR\92ì3àe\1dz*óè
+Ä¡\84Õ\1f\8cu@\16dJ\89\9aÑ\a@­?µá¿\1emoBº\9cæ
+\93\86%¼¶\179-"\ 3°\1aìáD\0\87M\89T®tpC#ö$\1a[^N´¾ÆSè\88\eö%\ 3\10\84ôV\10ÿ\1cÐÎMH´PüV)\17\81\13ÊÒ¨ÎmÆS\ 1ÔÇ XT\88\97|\16ø^EõCÝ\vÄ\17E]\15\95t\110»Ó³Ó;\96\92\1a\866\10µÜå,pÔà      \93\16ø´O7غ\|\98ûçkËQ_ĬLðtviÝ\ 1ÊÈÉø\ 6c\a?u!\89¾\16\13@ÔêSõ-àWz\ 4¿\93"\9d(Y\89\18\9c\1d×\a\16\87\83qKp\84\9aÔ^å\8e÷\15z\b¬Ä|ñ4êq\14\87¿õ¤³ó\ e¾ ÉAÄ©MrÓà\v\8d\9f3«Àf<ò^\83ª\9eʧV.\9aµ%0½dg\ 5Ä,F\1c4²J¨ÕJ'XO\83Q\1aÆ\84\9fÃ\0ã·È×n\13Â\ 5\85«¿\10mY\8a£\12¾Û>ý\85þ\98BÞZ\82\86\19Ü\81\15\9cá\16M_ùñ\r½\9d\1a U§ä       ÄÍ¥ôu\83\ e£³\81@ÔJ>ÈeÍçç']çn®LØoµÙå  \19\ 2\89r6õíZåèüÂï¯G\16ëñú
+P<\1a\99ªz©ÇܽrQä\9cÕ\15\1aV\ 6í\r\1dY%\ 1äQî\13\bk×½»ùÐ\r`E^VÃ6ÊQ¡\98\98îÅ\ 5\8cï \90~<\fwwÒY¾8Ø\8dDdÉhlGÀt\95^¡M+!ö\80\9c\9a¢E¹^Ü\84ǯö\8bè\124{\\fºiuF|`C¯ðTÑe7w(ò dQ\ eñ\9b\93\9bc`\ 1g*¸½®V\9d6p\¼Æ·z~ô\8dØK\95K\10¿8ÀR%$Ù&%î\86æ\9d\9b\e:\97\a\ 6P\13+J\9aÍ\97¹\1c!k4\9fý¬S§\ 4ê1ôÉMâtxKµ!XÁç?1\17Èí\9b'\9fýéÉgûöù\17·\97\7f9\13\94ÀpY\16\7f\95ã²Ð\0\ f.\rn\eáÿB,nÀ¡U3\ 1J\10]\16Ð\12\13çï³SKG×2\9d»7âqqä"r¹2@j¦eCp<ÍÐ\ 6a\16\8d?e\91ÄóQÞØn¬á¶_¼\88\10\98¶õö\13\92¡\18Õ*ÝMÊv1\10\ f+r\ 3ê ¼eË¡\8dzqâ¥Ì8¯\99¿â\98\96î8\18üQ<\8f\12ç{i\16\fÃDåà\84üùó!õ\8c\16}\9c¡De\9d¶I}\9b\931
+a9\16Ýi½
+O\86aÄû\85\ ey\1dy\89Ö\1d.EósÎÑdñO<J5\91ëQ2ììy\14ö_2bÑÍj\13ðüY|Ì·F\95Ê\17³\82?mÏJ"à;µÔ\ 3þµ\92Û¯\9aø\80\ eéÉ`9*{w\9ftj\89\8aI^a£«\e\93ãÔ\12E¥4$ÎWÎ)\83ãxCÜ\8cQ¯·\1f\9dã¯?\99øÿ\9b~ü"­ßÐXü¿oéöíQ÷\9döf\ 1\1f\9eR]\ 6¦&âUg\98ºkÔ \18\19,PÏ}¯±}\eïÏ 80­ug¾Ñ\b \8d\9f¨\16\ 1\80\vSx£\ 6^¦C`\vps3\98ùÂwÈé½\14\87\ 3<\ 1O£ûc(¼Û\96Á­\8eA~\ 1Æa..aOߺ³\ e£Ïeï\80¡Ñ)é\1aïOë\18\17ð13\0ìO¸»Ã\fÒì:Lô
+\eIñA\0ga³\8e\ 3¦y'Ý\80\1cæ¹\0UÂrè\82\10­\ eî\9a¢cë®      áIx+}ʾ\80\17\87Á«\11ßÛ\ 6\12u®Ímd°\ 5£²#--·á\7f¼W[\8b\11~\17ü\ fçe@!\8eë~I\9e´3\84I\b       \9a0B\b\83Ó6\83\19»[Ú\16ã¿Ï÷Õeí}Îqò$ó"ÝåêÚµjU}\17)öÂ-\b¨¾ëç\10v©ÞìÆiÑ\eA$µ©7Ë\14e\97\87(O\89»+QP
+\14B\16cx\88d;>ªf-Êm¶ÎØW¼\98¶a\ eE\ f\1c\9e\958VÄÃM\85\14
\12í\12ô  \97î\1f(Pt\18\9cÁP\17|NÑ`j­\19(á+¼.Øpn\fÆx\fMã;\ 4\8b\83B\15°\rR*Ù\82X»¡A^÷ÂK\0è\14M0¬^Z¢F\84æY\bÀd¨\16&E_¡ \99Á\85\ 6a>SX\17Ü\1d#;ͪ\84IÝÇ  \8e~\v\88dÁÒ6/\ 6dí2ÿ\88ws» \84Ö«\1c\86\9c÷à ²\9cZCk«\vd\14\92>ÏúKà>Ö\854\97\1fa÷Z¶\93Â\10+CÖ\91\ 1\14eµI»\ 5\ 1\8bZTAÑ\r&j\9a\ 2Q\94³ã'µH%i@N \1dJ\ e\        }Iñ¨Ý\r\91\16\ 1\ 4Ó¤\b|Ì& ðRA^\1dÍw\1fY\88üÅ»\98\83_\ 1q\83,\11ºJEHÛu­9ÅmF³TefIËgj\9e\ 1\90\83\99ã\85¡.Cén\fs\10x$ÉÏá\88\0\87U×(\0O¦N)\f\99\e¯¶°\18A\11¨OÄ,\80    »f\95\12LU\83à\9a &=@T \ 3l\83\9c\86Á¶Ë1,ó\8c2äùHÓan2¥\bã£\86æõ²\1cá\ 3\17-\b\96¦\eQ\14¶U\97\87Ã\v¡\95|àÚâ\1f\80a8üÅçÄ\0\8d«EMsíq\98\90¡$\12GW8\82$\bÙ6\19P\\fåÀìC\83²\9c\vTí>%m\ 3Ður%(ØeoZR·\f¹,Ï\19Ñ\9cQ7ÆQº1 ¥¸Þ¨©\15\ 1ÚÌå\äÆ\96\82\88´!þ5¼\7fo2\98hþz\7f
+ÊPt\ fkÙ¦\98í\11ôKüI±\807VôÃÎ\ 5Ã(z\0\91p\ 5¨ ;\7féb\1f.*ëçF³­E\e\94óPX0\95Å`\97\95\ 3T\b\ 3X\ 6Æås\80\16\ 4ç¬ön®Çñ#l\8d\81j"ü"ÃË\87\ fâáÙ{\8eÁß¾0\ 6¿x«a\0»¥#¬^\9fÇ\179\ 3b\876«/§\89`\87\eÝ\ 5\179Ç|v8qÂãIÚ}PjX\19¶ø\18q\1c\8eÓ
+,Ö\93\1a\ 6É\v>:¼]m¥=ë\83J6\ 5\19ÐiÖç¡\ 5ñ\16íã5*q#\98z\9d\1aL=\17\vÖ¡\enÁKÏ0FK'\87±aY¸e\9fv\1f\94\1aÖ\ 5=\ eªÌy\1c\8eÓ\82¹»5y«Á\82«\ 6/øè°_í(íI\1fV\8b°Ý-\ 5\1fJ"öõy\1cÛÚ\röCJU\aCä¢\ 6Õ<®àb\13x\85tr\18\b\10E»îÓî\83RÃÊàñ¹¸`\97\96\94:Ok°àÂ\ 2/xwx»Ú.íY\1f\16\r§K¢\ f-εǫÁD\¢\9d\fØ\8aaJmª£Qs.Ñ\82\88í.\b~Y\19\92·hæa\ 6\17\84Q\12\81\83àq\8b`R\f\19g\1aÞÏl\87\ 1\88\0\85UQÜ\b\8a:¸Ün!,È\f9øCgp }.+e\9f÷A[ôÍ\8fO\9fÝÝÿñíåýÛÛ\9b×w\9f\ f¿gìÑ\13\8eg\1f9>><}y\7f÷öæçãçÏ\9f]^~¼~q{ÿ\9a\87\1f\1f~Ç£\7fà?ÿ\9fóÀLmL#ÏÞ!\99¯\97\r\98Ýâøm\9aâoªNpU(p\7f`ìH1NÎyÇ\16¡\99K[¢i¸\ç×6w\92Á=¶Ý¤\90-\83\92in®áù±ª\93Û\96\1eeYI+h{éI\89\16ÊJ`w \8b\8b\86FÕÌÉY\13\90àÃ×|\80_g\9bÂ9H\86Lsë?lc\99\86AeZû0`£\96ã\8e@T\85R\1c¬Ú¦YgJëïí,ä/\85µ~ËGRÞ×H)\97¥Ö$\83*(\b÷V\9a}ÍÉ\1a\b`^\94eÙ¾vÂìÊ\90Ö¸0\83©\1e0XT\91\85Ïå\18\ f_jÂ×]\0û\82Ê5L©\98¿ÕgßRhá¤.\8d¾4w;\1c{[·\1c\90·që\93cÐ.C¦ ³ \90\8c\ 5£¶ÿhS\98@½WáûÎõ5å&\88Ú\1c˪+XÐ\81Â/¡Bp\97\81R!ºVN}5ú¸\r¿!Ô æ"»\v}\18v\8c\88\v6'\1eÈ{\9fJ\18\9ai\ 4\13r¶=\8døG\83¢\ 3Ö¢×XãI\86ê\ 2\88\9fs \81\10\1fE¯×\8f2XT\ 6XC¢FUàgÕD,««f\87:\8a\eïУe\98ªª¸Y\8a\18\8b]øºX£2;×bâ¹Ñð^{\1c>Å Ïé\vÁÙ\86Mß°\1dE¹XM=([n·äÝúJ ö\8bÝ1P©\e) ;YÕ7Ü\19øsË0C4XZ>\16\9f\8bÝ`Ée1몹\19ÒÏe¥x      C dhÑ/\91R°`èJ«çmøíP\1d\92<çâô\99\83?Á.\ eëÕͲa)¡Çl)\9bZI\ 41\9ee\174q
+`(*9w\873ù­\9c¤Ý\82VÃÊ°Å\93É«]Ú²yÉ­\ 6\v.\17â\ 5\1f\1dÞ®¼Ò\9eõaS\7f°¡­wÕhPBm\83\ 3\8f\1f­\92\87\16\99Á\1f4]z\v®UvO»;\fÍÞr<Iº\ 5­\ 2Ë°\8fïàÀÓ&\o\9cÖ`Á\ 5\a½\9f\1cÝ_w%=ë\81¶'\98IU0-\98-\8c4
+¦ð-\87O\ f\1d\12\1eÂ(aù|Ó\9b/*åwȺ$²GC\83hA´`\r\8a\92\94a8y¡\19ÀØ\0/ÆÛj\18\15¼â,
+wýÀ5+
+©äE´he\18uL=\f-Sìsc\889+\94jQÀ\82N/     û£°N®»ð[\80«ävPr¦Õ\90¶ª\aóBê\16\1c\12\bN4\8ce\80\8aí
+¶X\16Â\10\83\98Ùª·@Z(o \82-ËH»Nâ%^J\92\ 6,s[D!f\9b\ fòTëÇ DѬ&\8f:\9e_\82m\111¬B\82¢Õâ*n2§³\96=\122´^\87q\86\92\ e>\ 5\19eL\ 40ó7ÂÙ\12f722\89\8d¬\ 6\85HPM¸£\84\18\861\91hµUB\9e"(\90a\92\ eyß@e]´?!*%4ôu&kÚà\9c¬þ ¼\14\ 4¾ÓP«píåuåõ\84\11i)[y.a\83N\v\83U}¬®ìÈ>\0µ¹wD\860G³\ eÅ*#\94úb\v\ 4Mê'(ã\80å]\17\84;íz\18\84\95­\eaÈ­Q°+£JÐ\12Æbµ\EË\80áÄ\bØçâ\·P\0Äç`Ý\86\10Ç\93*×2m·ÈIûÐ\96ï¬Ü      ÙÐÄM\8b\8e\96S'Å\v³\f\14\12É>7ò\1cÖ4Ó7\89(¤ËÈÂ\82ÀxÊî\ 6^.\85R\86äÀSCÏ8ÜfÞjè_D»JÙ>XtÌÍ\10Äi\1fì¹ù\10qíg´Ã½¸ø\9c*u\91u¹¿äÛ\88\12z\1c¾\b\88÷Ø\86\17=]\0\eÖ¤º9\rdHÑ\9eYÈß2D\f\90>sU'¡A\ 1\13\ 4QMW¤@\10\88Ü´\ 6\90RÛ2\94\1aºÖ°¼btsÀ\16G\13pÑá#\11}\83\ f\0\bÅ\9eÙ\eI} \9fK«0¬{HúHIAp½\12hÀÞ\8fÔ\11³ï\12\8bhÄ¡\1a\90M§¤ÒÔ¦\04EÚ©\1d\89u\81)\ eë\860\1eTyI²nÁ\14µÉ¬aº¡\91·»ð\1a \14£ÅS+VC\86QÑàäê*ìÖ\91\8cõ;GÓ2`Öú(¦\1f»êtÒ!¼\8c\1e\9e²âØÀ9U=JèÂ{S[±\83ΠâmÔ¿Õå¾øÿ\90ã¦\11¹fëû\8aäx8\85#äL¦h±ÝÀ~û|nÁ}kØQA\8d\8b\0\aþp¸\85©|û\994Þ|ÅÃBâ¶\19\ e\ 2\ 6ÀQzL\e\9eÉ·\9azÖQ\eÁjþ\ 1,\9eæ
+æÖôS½m\ 3\8c¡\8aÙI´f=<tè\94n¹ô\f\82ýulèzè\ 1-\ 3\ 4\80¶ÒiX\83¥\8b±ÁuâPÏÀ\1atB\80Xâf´Cÿ|ø B\98\ 4¨\94Wo\1e>h\87G\8f\ f¯~\90ø\97b_\16âñðôû\9bûãgßÇü÷×÷÷Ww7/®~~ûáþN4ø?>¿¿2\1d\9eÎO~÷ß÷·w÷»3áðôùíí»ãC7¯\7fzwõ§\8foß\}8\96ôÓ«û\ 6ÇÃ\8fßݼyùùú§Ûw\1ex\8eBn<ôè\87Ûw¿\=Æu\9fñ~¯>=|ðqs\ 5\94jAý@8DûåÕgþögüô\1fÄ>\1dÊá¯\87\7fý;\1cÞ É+\88½'}\ e®2¡,\ 1ËÁ¸\8a\0}ò!\ 6\91!á!r\fx\88>³i3p\ 5\r,\84øg9\f\ 4«1Þð¨-g\1e\8ep\9emH°Øþö\19\1c¨S\ f:¤T°}L|\8e\ 2\ fñdò¦\8fAp\r¬at\15\8b<\99T\93àPWݬ\19z\ 6N\12.Ò$\85R½!\b\f\89\1cû·\9e\950ÆÉÍ([D\88\95\80\81\väÓÌÍïY\12à\e­§É t@iZ\ 2\98K\83\18óÐj±\f\83»BpÊÕ\80\96% #ÿ#¼ZZì<\8eè~`þÃÝ\ 4$\88¤~VwÇ+Éq\82     ±\85\9d`C\16bd\rò\84É\1dq5\82èßû\9cSÕ÷:h\91\8d\1e5=ýU×ã<(¬\10\ 4æ\95n
+RU\9anhÏ/¿\ f\ e\9a3î]mÔ(BY-2\18\ 4\ fÿ}.\16\83Ru¶\8b\0\14\ac0n\80\92®\a\e\14Ô¢)B\1eÏë\84 d\10Ý)Öý[Ú.¿\ 1ê
+O`ºÐeîw\91C¦6äa|8OÛ\8d\98y°^#»\ e\8bW`\8eРƩߧ\1eÌÒ4½b\ 1\ 2å\18q\ 30¤ë[¨è¢ÖÕ\r\1a\92®Ï-*\eJ.\ 4!\80óÒ\r\8dÐ34c\99\9a\8f\aD\a~C®\8eØ\88\ 3\v«-\1dFS\ 6ê¯Ä\\ 3áZ\8c´·g²vý\9c\ 3\84Ö¨\8a\ 3z\8bé\15\98ÒQ\a\9fÆ\8aHÊëäèYÅ1òHÙ9\14Ì\86Ç\eM\15÷$=\1fÅ3\0\1a÷d
+ÒÛT\ 5¡lmD/\17hÁL\1dÂ\(\17\ fÎ\9ey\18ã:²F\8ck  ­ß½\8eÜ.¿\80ê¥k QÆÞ½b\98Ì\82NÄÙÕô\ 4Ê8¡.\1f\v\ e¯û\ 6º\ 3\91x¢Ì\1f\ 2\81II#ºJÌW\ 3\8d±ÄØPR×\85ràî¸a°ÅükÝ´Â\8bÓ?¼ï¨QÕ¦-T$\95Þ|B\80ô#n04\96¤¨¸ \8a\87\9b\e4=mä¢2`\fµ4\b\ e\97"q\ 3F K\a&Päªûp¶ÑýÉֲŵ\16Á ü¯7H\1a«¢\84\17\96\84\87ñÐ<jõ\1cÐ6\89\99DÐ+Ùo(LÌs@F\18úâe\a\9f\96­;L4\ e¬\84\1e!á2\86Ý¿5ö\r\129p\9bdg¬Ç´ÔªåÖô4ªl¥`Ø¿:b{\12æ0.Àãú²â»\ 2`\13µb=ðÌáC
+\8b\80\97­Ò5û\0\9f\16{93Ê×"\8e¶&½\81À½|ö°'#éVV\89æG)\94U"\ 3îhª±ï¶ü       \8b\95V\19'-îP\ 6Ì°hlô¯z¾\ 1c\bÐññOÙM\b\92Ä\bGÅzË\11\93BÕÜIíÇ\ 5\80ØQöD7\8eÞÌÙ\\1d\1d\ 3øXtlh{&õu\0$\ ec\16\12Ý\1cç1ìU¦ÇY{\ 3ÅY\f¢4â:\9dä\88ù\r\95\ 6£´\18=×8\fB\ fw\87\16ëª\rô8-ÐrÜ-­ïF4\82÷\14ôb\9aÜQ\ 2&Q\86"¼ÁVeî%\82Øg\8c\8e÷wq{ü\ 6ì\ 4\9e=\1ct\1ai?\ e\8fUüÉâ\11\ f¦\9c\15¤"+û\15ø\1cpt9ì\99\8bë\f­°Ì\ 1\12B\1dRMAÈà¹46\18MKkß\80\1e9ð-\96\94-\87Ä`%1HSA0X*%NÂ\vÆ\rDQL«\8fIq\11\9a\89Âi\16O¬-ï&KR\85p¶Ükú\r\98\aW\13Dd©\89g\13\13\0¢\10ät
+ÚáAb·\1aDʶÙâ\ 6\8c½\ f_\95\8cWß0\87p\ e\92\12@\14Ö\8c\9f\ 2ȶÉ2Я\8cóV¡\ 1½ÏÍÙ£é\ 6\82,Ŷ¾\ 6\8a\98qCM¦ \ 6=\8f]\ 6t«K\8bW\18\ 6h*\7fq\ f\89\ f\9eqz`\10³5\85\9b\8d\9cTö4\90Õ\15¦\9d\0ó\ 2èç{\v\13L\9eAò7"H\ 4¶ý\ 6<8¯ÊxîÎa\f\ 2¯S¡|\93`\12\11.%(ÓrKv©\ 2\9cäÖ#d\1c|FáX\9bkEà\97Å|¬:CjÊ\12Å0Á\12M   K+\81M\19\82  mU\f\14Ðü  e\84¸(Ø\1dìÙ\9eF\8aÁIo
+\12\ 2\ e­²á\91\82IÁäEH(Â\98\92¥È\v\f°\9c\ 4b\7f\17++4&À\12u\99×¾\16Òj\96\ýd\1a\eÚ·\8cäÌ8Þæ\16®\a\8dëÅ3,'zÂßC\ eÈö¼Sh)\80\95,Q:\89Ñm\19\14\84\87Ù£Æ\8aâ\ 2Z 46Qió\8d} hUñ"ÑtZõæ$\97Æ$E\b\84á)Ì\vÝ¢<\18\83ìU/Ml\8bõtá\84Ù\88:"Hé¥â\ e&\93Ö%\ 5ÉrÄ\81=¢E\ 4±à\bð\86\8btúÒ¼à\86¿Ðóü@S\ 4üî\a´¨a#(î\81\1fjwø\9b~\8c¡\83\174$\ 5iü%{Ä»Q\96N\ 6)\189@j\ ecD\15?º*\!ü¦\9eÒ²¯¹R^\14\99n\8cjv\85\848p-KM\83¦1'-{1¤H©"A7Iö\ 5c9È£¡Cñ¹¬±\ 4\9a\15Üxp«\ 2Bbó¨\ 2-\8f°*¥\bN\ 1U\96˶VȨT9¹E¥3[\18\88æZ\89\9a´úµ\ 4Ñɱ¬\95LoÛ\13\90¢\17_Gä\12xºHw|\82YZmg xG\10ã    ·tùýZºð©\ 3\9b\97\9c\15\90\17»(|²-o'\1a\8ao\10GÚð\ 5\bOÁM\96× \e%?x\15\80óÝáPìè7ÈÍ(1ámT\81Ú\\14B\81Õ¥{çHÑ6ÂátÇ\87%\83}Èþ©´­\19í\92\89\89if%<ð-sµ j´Úæv\8c©\ 5㶳\1d ]Ââ4'øeÝ\ f£2Ú\15É\14w\19l9       Íu¬4Y\8c\ 2F\ 4®Ò¥ÖÖÒP\8e%¹Ú\eÛs.\b\1a!¶H\14Ó¿\97;ϳ©ÁBN7V\99û/M\85ÚåîN\ 5ÆÊ\8aÞ\8b\8d·¾\87\89ñæ-\ 6ºË\ex½ÈSP6ÓjúÉî\8c\8bâ´\96ÎÖ\8c[/Îæ\fN\99\16Ì\8br\18g\93K¯3J\8aÄÎ\1a\ e+\80ºvu\r;
\95\ f\1e´*í²ØªTb-1­Ù]Ée%0®X\ 4W\1e!dÝ\ 35Ù5\9emE­ \1a1\17þxn*{+±úÍØÌ\96Sh\7fá\19Ä7\15z.\81½\b"\9b°P\94Ocß\80ñ\9fØ@o&¼è\b<\83äX®\9b\eí¬[(ÊÃ-¦ë\86I\12t\1f!q¥ýu\168;ýaàJ\95\91±=LaXÙÎ\8a\16\88ïD\1c\90\83¤Ã\86\ 1\9c,¼ÙJûÚæA."Ò
+[ÄñÌÍK&¼ ±P\ 2J"0\ 5i\89\94°SÍ\85%*ogÆ\ 4\86ôásjþHR\eßE²\81N@s\9aè\8a*hÌèN¾Ü\80e¦Â\80\8e\804\9a&r\ 5uV
+Vªù\8aýf\10\f3\8a?\v»\ 3\8cÝ\9cMßê&\ eJ\9a®\93\96\84
+\9c\88ÎU%<`°äÆ\µ/«Û\14u÷y*\18@HÊ\83¨=»¹/\83ÕUe\88\f.\92\90Ã\804\8a\1cÐ>\vÇ7κ\ 1ųáe,®\88ãdîá"Ë&   ù­dsﻪ\0pìsOÍ\96\12\bJ%+\ 3Z\930Ehj_+¦Ù}Y.ìcWm§#\80\9b\1f\ 1\8f\0¤\9f½%V\17e\1c±}V\92\14(\14\950F=\13£S\93U*Tó\93\9d¶ L\11\ 1ie\7fo\14\87ü(\14\ 2\11\18\85á\88GÔ]m7¢\11¸]ÊSGw½\ 2[­4¥ï\9b¹C\80\12\ 3×\99£MËÛ\13\81\rÂ\9eb\ f'\19ßÏ.³°§\ 6R\8bàXª7ÖX8\19"\14ý3\8bÔÄnns\90Lóá×úùÉé\84&\95¼ÎJ\1c\1drÌ#\ 2\84j\87\8e
+\9aB!Ýà2YT¯ÅÁ\90>®Ðá\88\86×q\84\17 ¥\ì%ÝÞj!ð±r¥\15÷\8bò;q\ 3ôB)\81ÅØ46¾dN\8e\80\85\ 2\¨-\9fÔ³ÚÓ¦;NÝP\ 4'"*\10ó¤A£\e\0XTÕ\ 6²<³fn\110¤á\9e\12\1cÏΡq\19\83­\95\8dÛ\1c°íôÏÕè\8fPJM\83N\16­\86#\81hK\82\16(÷Ý7v%i|\ 1à ï\11uh¦§\81\16ÚÊ»\15\834­¸Ä¶ê ³V\95XÅ`¬áå¥\93ÑD\16ÌS:O$Ç\1e¢\9e®hn1Î`\9eR·ä\99â¶l\84\90 D\83¤\\972@µRk¢)®Ò\94\17´rwÝ-\89ê#2Ê\16\9aä\9b\18H:Yn\eUsë^²\ 6åe\12«Æ¥\9b
+â9£ù\ 5æ6&ö\92²¸-\97Ø\107}\ 3äH\11ljeB\11º\8d\16¾ª¦\8d°Ø\90áò\139Âxé0}h¯ÕóÚ·â\9f\96È~:YÊ\86'èÃÑs\ f½\ý0ý\9e(\\ f®©\aKT\93\89DE×y«\12\e+\13·IqBÂ\81\7fÝ@\ 1\ fâ)\8ap\95\96\1e/×íªÈi\8bò¤ #=H\91`:j4§ç%ÕÃ\15\a\85ûµåµTQy\16¯¹Ø\8374ê¦åFReD\f\95©*-ú ö\8a\14ðJº4ù²\9e<]HÑ!#j\17Õô¥oÁ\ 5?^_ýóúê\ fo^¼<=þùî\97Ç»\87ãÍéóáO\8cåÃ\8bo\8f\8f\87'/¿ÍõõÍããíéøÃíû»\8f\8f§\e\9eûÇç\ f·O\ f\7fäÉòåÉoþûááôø»3éðâÕÃÃýÿ\1e:Þ¼½¿ý맻w·\1fãØWüãúj\1d\9e<=üü\13þ\83ãéÍ7Çw?~þÏÛ\87{\ 5:ÿÿæ»\87ãëÓÝññîøþÙ³\88¿B~Çßÿäúê»\ fúÙô\9f½¾ÿ\84?¿\7fûïÛ_\1e¯¯\9e¼|÷ðööðêôéã¯\87¿ß\1coÞß\9e\ eß\9fÞÝ\9e\9eþ¿\1f\1eü§_ßÜÿÆ~Õí¶\8dcá½.ÐwàÍ.l`cë×\92Qä"N2ÅL\9aÆHÚi»\9d¢ %ÚV-S\ 6%7\93¾Ì¾ÈÜõÅö\90\14\96\1d;\89§ÙÆUíXäÇÃóÇï\1cÆÑ\88áÙ8
+rè\e°²\8d,ÔÏPò\15ÃÏ\1ad\13\81Æ\r\1dosü0ÆÁ¸vÁ\12\94Í¥\f\1aÞ\8awW\8b\962j\17¬Ô]Gz\80\942@¡R\15\v
+1\1eWÀ=L)aµ\18)£DÎi\96fÑ0C\a\ 3\ f 4J×\8b?KÆ1içÚH`\9ef5àÿD\841<\9e\12
++Zy\86@VUóc\a¹¶Â\95\8a\94á/&d\10<\1d\ 4Ì    \14\aÿ\rdÂÇX¯î\1d·.³OîmÃÓ\85Gílìvg\9e;åƦa\88\8föìdkwÁh\17IS»âÿÎw.#Í76Ŧ\aÐ\aÙ2Ôæ\8eööª\ e÷àÙÚá\ f}(ê\ e4WO2\86<\e\96R<%a\8e\ 1x\e©\a\\ 6\17\82\8e\ 3m\97Áo¬Ð»Á\ f(r.TÑvN·âü¨Ï½B»R_\9d·¾ÿEé¢êV©2W£\8dD wª\93 Å\95.DN½F-kS\9d\1e:\17Vq67¡díÕ\ 6yu\83îò Ì\89L\85\84g\90cA\aßå\19\ 6\12\bî\9b@ÁÂ)[¤Î]\Ò\95s\10Å«ì&&éógí3\9a\SñÆû±Æ\11Mh\13µ_\83\15¼Uj\1fA·ö\95\14óíãd:Kà\ÿ\12Åà@±äx\8c#\8a$D\ e7\85þí\1cóïúeW\19\ e&·,ëá4
+´5k\92P8M[ÛèEq\88ð|\88úC\1c¶p\ 4mH[:\11@D\19(`³\88¦\ 4D´ßDY,\86-!*¾`W\19K&Ò\15
+\1eJ²K\12$Щ\85bö%\84æ\92\faªæ\80¢µ\9a·õØ¢\17H¶l¢U\85³rI0ô³W\ 1\8e!\92bÐ(\ 6g8P\83ª\8f>Nâ\84EßDó,&\1a}B\83(\ 6\8c#\1eÛ·4
+\92\10b
+Ù1B\8d\93(\9dÅøF¾*ùBÔÛY
+=ó     ä\87\18nK_ä¹\0Þ¾\ 4(Ü!!\85\r\87\rcg|y\9e¿èý\r\7fû\r~}AvË2M\1f]#\a\9d£\8f\9f\f\14>\aÀ%W\1cþ\86Ü¿à½\17èù3°«ÜH)$»ú>KxÃÏ£\10W¬>
+¿ÌÓ\f\8elV±à\18r\ eò!\88\93`r\1d¥RÚ\v$B\89à\12\0®Ç,«Mµã\84\86ó([\95\9aë\17óܹ%µ×g\13\17P:ºÎ\9ff\8d+\8deW\16\82ª\8e|\9b\92Ó¯\84^\84áj\97¬7±\17\13\1aÞËF!a{#5ãJ       k­\80\7f\92`Îu\91\93BD=ù!³kî    pO\80\e\13 ï9¼¬\e~\aø¯e:.ï\ e\rÃóWsa]ZïipO\83\8f\8b\ 6­=\rîipc\1aô¼\8e AÇæüg\1a]_РÝ]M\83Ð<º{&Ü3á£gB{Ï\84{&Ü-\13Z¾ëû{2¼\v\19^¬wúd\9b.\9c\84yoÂt\1e\ faÞq·Å`嬷vÑö\14¹È\1f÷¨ë\8b¬°Ù9ÞI\ eZ;ÉÁ\87\aJ\88\9f¢£û9òáéÑìK\92Bs\12\8c        X\80Î\12\9aÍÙãaܧqRþ\9e\82\86Ò3½®ò\8a       "|\eå\7f¶ë.\1f¾\1f|zÇõ
+Nª¸h<\8d\13z!\ f\1f\7f~`óýP\85^ÞS/\86Ã\94d\88ßT\9b mI£?Ä!úJX\1a\8c#2 ´\85£Yq\89\ 5\1cQq_B\ 2êM\94Å\eP\83å¨;n2Lå=®\18\99ÆÑ´\99\13\8e¸Ù}¡Ùl\8bÓ»\8bøo\eôÞ Ì\9aÞ\98\9bÒxK)ø-D#\86Ã\b.¯Èï4s\84\99Ë\97ß½\11_Ûëí\8cìe\ eü2ÿöí\ 6\9dãt²\9c\ 2bîàt8$\93luøß\11^´Ñ\19¦\19Ù<ô\8e¡\ 2}  \8e\98§wm\93\7fÒ;̾öÜR{b<\ 2¾ÁYF\1eq\rÚ'çßÂËÐEBsصx\87èýØ\ 2½    å\9e°d\86®Æ8L®\97\9aÚ«Ywé\blÈ»«Ú\1aóÞ^K\83\98I\87µ:EY\9fá@\8c\99Ê\893\1cI\94­0Ð9ÈÒï\17%!ÄlR\ 5\8d\13öM     \12Ý@\902)ÙU\90A<g\15È ¦ÛÔÃ\9f\93(Y4\18pi{\8a\14ù@Mý.\98Õæ"Z]÷\a_{ê\89Te777®£R9½\8eD\8bã±!}\16\14uDG¹%Å\8då
+È.¢£f\ 5\97o\11Q\92¦ê:\93Ï\88Äz\17\85üö%h³ ²ÓpD.\80\17c<«JÓ&~Ç,Â\Ñ|±Ñ]Ø\92\16Ô¬ÎÞ¡\98í"Ý:\90l\10Æ\96ñ\83\13î     V\8a\92á<\18GûZ±ãZñ\88éÞó:.?~\8eÍO¡it}þfØÝGÈþ\97Ü\87è8a\94°t\99ýO\83      ¡\b\ f\18 Ö5ÒUÜæ\95ÀT|Êp\18ÍÓM¹ä\81\82/]p1\1c¦$C}ÌKÈ¢\ 3úC\1c\15pG\88È`\9d\v\16\91\9b;Áj\99fÇ/ºýa\9a5+¾\99ÆÑT\ 5\ôä_h6Û"Ò»Èq«ËsÚÊo\8c\8f§Êü\\99á\94ÝÌÿGZð\96£åñ¬x\94½î    Kfèj\8cÃ亮Ó\1dÇx\ 4AÂY¶.\9cUÜæÁ¬ñ\97ð\8cyoG¥AÌò\ 6Ö.\13\ 6:T\950Òq3\1cI\98\15¤¥L+¿hmCÌ&\8b°q¾Ur-HY\90\83ü\82º\ 6ñ\9cUP\83\98Þ¹?Üæò÷ô:Í\8fÐúQ\88TøIï4¯¢é,.;M-ÉòÓxY&ÝÙ6Igª¤ë\ 3\97f\15Íþyôk÷ó)\r\8fX&6NÅ\90Ë\87>¿Nh\9fÁ\ 2¸)\1d\1cäã=\ 2\aª\8fc\ 2§GjÓ\1fÈ\røÓøØÇiJØ\14\92\90ÐO<PïSnouøù³~P1­ñ\8eDßÿ[\19\17ç\8a\9fÖk\fÉ«fLa3\9f9>ÿp\ 6ýO¦-ªL½$ñ \9f3\97æØ÷¿¨6iè\93Ç7¸\9c3«s½\18Ï5]*sçxDh\86ÕtËt9\82SiKÚr|\b\87¦a \ f\87]\ 3\9dÁÏR{\ 1ô]%ñÐ\0h\97#aììP\aò~´[\ 5úBä"Ð-­\16(\97£øöU\98í.ï\fc\8b\viQ\e\0È­)l)q\96îîCËÈQ\v\e·Ü
+Ì]\ 5óª8Ï]\81ã\ 6´DÀ
+wûÒÝ\ 5¸t·p¶\9dû\11~H|WX^¸Ò^P"ÿ³ \87Wu\92/ö7ZN   õ\r¥\86SÅòJkºe\16\1dz\ 2É]_c\9b\ e\14\96\89pê@S\19d\94\9bsËϹ=\1f\ eÝ
+\94\83-W~éP\99\9e\16\a[®î\0SW´LäÅ ê0×X\ 1³åÙ°]-Zv)Óv«Ñ\92ÚêF\15Pw1\9b\85\ 3¬ê1âÖ[\vIê*û\9d2U¹\ 6\16\a;U°\93\a´\95;WÂ\1d.Ûq\95\12®\9eÙâÓѽë\16'°cT}ë*lGª\93ã¹2\1d\81çÞp\16Twr¼®ºS 5Oçºx\15W\17ºx\v\9e\95.¾®»]èâ/è®Ô\90\aªâ\99\8e«¨Á®â½<\9a\1aÖ+\ f©[a\bqF|ñWs£W¨â)t\ fª\90\85\1a¯"J0\83®àwÂ\80«\87Èl"UOL¤\8a\84\81z#\9e\1eȬYR\8aT5ª7\16â/á\9e\vµo\eñ5KÖklm¯±µ\85Æ·\8b¯Y"ÅC\95\8e¡\11\9aÎÓ¢    SBäóQ\93ø Í\16WäRús:ɶ\11¢/PôÕ8aó`2ÄLÜÈ \v\19åÅLæ\8c^ÊD\9e\eK¥L¿èäÅÌ«©f\86Ên\8dü]U\9b½¥ÃV­Í¶ªjÕÚ,N\98\14\b;âP.c¥PsY¦i,É4«äß)*Ïr\91\8aT_ínV+Jã%ÃàùùPw3|58mh\fmÀ¿N>ÑÕ¸
+\86M+\1f÷5£8ÞÎÇ=\8diùx7\1fïèT \874vèè[jôèé[j5Ü×·´´V@ßRo\11\M\8eb°~¯ì\8f\8b.¸l\8cõ\96ùù³×³¼¿\16sªÃ~\15¥Yõ
+ ú\\16\r\ 6\90=/\89x\vÚxIÒ\8c
+\17\1dt\96ÐlÎ\9aËWX>2\8eX2\9c\a㨹ÜÒË\roïêk\957\r9yu3\1d$1\17õ\ fq'ÃsN\10É\88Ä|ÿwI<\11ºCCN K\9e\9b\80\95¯\90\ 4¥ÜqMµ\ 1hU\11¿FÕÜ\97'I\02iv\823\fã\9fÛj\80ß\9bø«v\1f\14\ 3ïÏ_½NB²bú\ 5jü9\8d)\0\ eÀ¥\10\89yFRqÓ\ 3ð\11cøo\15ó@»h8È\8b8dü\ 4\v\94\85Ú¿\82«\8a\95ÝÌH>Ýø\17M?\7fÅ,}\ 1\97Óÿq_mËmÛ@ôW0Ó\97d¦¡%Å\92-¿)ÎeÜqâÔJûR÷\ 1\1a\15\ 4`\0P±óaý\81þX\17\14A\91\14     2MÚ*y\14u°ØËÙ=\8b%Ü Ò:v\8byV\82Ý\1f¦\ 3(àe[à
+oLýç7\9f*!\ 5\1d\92%.\935%\83Òä¡?\1eE\801\13\ 4\1c\1e\ f \128³¤ö]\1eÍ\80@«ð¯I\8a/OÊ8\9c\94a©`\18æù Î\18Réÿ\9d\b\9f?\14.¶ÃÇ\82Ã\1e\aá]\9c       l<rs\ 4ãï_¥è\85Á\eÅ©ÓPèÃáLý/ú\ 6\1c:6\7f¾¯V6«\8fGÀïo`\92\eÎ\92ïg\8c??\8b¦Ó\19\80n)æ\81¨\1f\a\95üñH\86ö³Ù<:\eOæ½a=\f\91\845\e÷\17ê##ö~PT\ 5ò(";\9b÷GvOYz?H\ 5JèQÄ\ 6\85\94¡Èbia½¸¦+{£\19¼f\aÅxxèh6\89|D.e¦\13úBf\82\1cÇ*\ 1
+w\14~l¨Å\ 4v¬¯àÌü\8b\9dù\81È$ÛP1¬¯*èÝñßÞ2k9Õ\14\15ÿëO\93\89ôw0õ\8b`      \9cö\16\17Wã1zY\9cE°;e
+½æÀO*¨Fï55Ô¢ÊÃï IË\1e2JúËGþ\eæÌ3|Z$$\91\{\85\e\8d\8a\8fD±È\7f\9cùq£0!M\83\elÖû \17W\10\9c\95è\16\eK5ûD\9bðÅÕ\1c)¬ \12Ã6\19\84\ 5\9e7Øâ XÛXbM\108'õ¡\11H\91O/Z\v\99¬efQªe¦¼±éÈ{íì½¥æ¾t*¿\14ÝR#yV¹¿Ã<\ 3\18\14Á"+\bTÈëËtú|Úé1\1a#MÉPhªiIÓéätrÞ\r\9e|\8eÝxOÞ^³U\1f&\15 ÕX\18\85¡\8f\92G\01\ 2\85û4ØjÅ\83\9c\8aÜdVAÍzj2®Õ$'¿ÞRô\81>Xô\8a0\8b\99õ«ÔéÞñÃ\1eºÆ"ÍpJÑ{©J\9a4¦ü¥\96j¡)οúýÈó²ü\13Úm[\8añ¾\0ã\11Z\95}ªó¸\9emib!\111æX$\a"×8\ 3\1cæLPd¬\96ëR\88ºÐ       g
+òì^¡\ f@\8a\14\92fZ\98Üv\81\85ôõXW>ÕrKµ\82Éd½ñÓJ½\8b¹äæÖÏ\19v\95@×tKy9\10 à\89Ô\84\92\96Y\85NÞI[ÿ¿êÍ\ 4Á0¹)<^ÖR2ê\82\ 5æë²\834㨷û«÷Ë\1e+\ 5¦i¦/$?POö\eÆÉ\1f2\8e CÜXy\1aFiȦ6ÔÙóSp¯=M°\ 2vC·¦´á|\13gÖLÅ@ÈÚÜÎÛ\vâB?ÉøJ¬$rqµµn\91\88k\97©\85\b\v²ëÇÃæ\9d\1e\1e{£1a®)ݱÝTn\1e«¶ÔîÐnH\9cüºk¦\17\9dÍT/c\9d3\rù½{>\9by\ 1®)¯³\10\92ÛÃû.]#^\16\8dx[kÄzâr\1e\ eÈ[5\ 1ù\99PüÃâÊÍ\f\r+\a\a¢ª×5G\ f(ë?i\14¥t\94d\ 6\0¥\1d\88Ð\15θçët>\8dÊ7R\13Z}Ê\9d\9f\8e£ùy\17²ö2zò\12Vô{ôAS\16C\ 6áB&\18Õöp\81k\9a©¬\85£¶«\92¦Wݨ\9aGm     ËQ¹d{·Ãþ¹qP÷ïÐ$×Ñ\ 6\8e\a\9dÓ$\92:\8dÂ\11\14 ­¯å¨\13f\12Ìii­\17¸\r¹\9f£\14O\1e\ 3\14Ú\81\12a\82¹\ 5\90\85u£\\ 1[\19\9b\91±\8f<\94Ò\1c\ 4û$%} \ 4v\8e\80ß+a#ÂëÕi\ 5\99,.c\9b´]f"^\11îV\7fL\143×½a\8c )®ìGm\97%\9b\b\84\86²ýÓèR\82\14\12ôúæÍíbr\86î\9e\-oÐx2;={6¹\98\8cF§wOÃ<\ 6\93\15ã!í\ 3P%Uí:ª\89\91ÓÓAù\ 1,\84\fQ'\a­2\91|æ[°jãAõu* ¤"Y\1fÂôÚHd \8b\80p«gS«\1a\90\83\8d·eÄBJ@\91\ 45-rÙ\0\9a{\f\ePu\ 1l¥ðØíÃ8T     @%RX)öú¹´ ZðhéÉ¿[Øh®`uÙ<¸ÂXîõ(ß\14ËÍ­\87Iî\q Rè!\87\14q¼æb¸_\8a\f7¿ë\86ý\91ö\1a\81î°\r, 0GVv\18Ò\96³Í   ö¨S±wh]\91>§Ûç³0>\96vßÄ\ 1á\95«\15ìBýÒÛĵ®Ö\84\1a\96
+\Y{º\90y¥c\99      \12"u\89¬Î¶ \10\9b\98Ù\rV=Ø\1dH7\97´®\ 5\0z\ 6\1e"Ö(iCî:èß\ 2\f\0ùí¨Ø\r
+endstream\rendobj\r28 0 obj\r<</CreationDate(D:20070905115256+02'00')/Creator(Adobe Illustrator CS3)/Producer(Adobe PDF library 8.00)/ModDate(D:20070905115256+02'00')/Title(Illust)>>\rendobj\rxref\r
+0 35\r
+0000000003 65535 f\r
+0000000016 00000 n\r
+0000041498 00000 n\r
+0000000004 00001 f\r
+0000000021 00000 f\r
+0000041549 00000 n\r
+0000046667 00000 n\r
+0000046739 00000 n\r
+0000047121 00000 n\r
+0000071032 00000 n\r
+0000073703 00000 n\r
+0000094867 00000 n\r
+0000116321 00000 n\r
+0000138349 00000 n\r
+0000147580 00000 n\r
+0000151373 00000 n\r
+0000169330 00000 n\r
+0000192542 00000 n\r
+0000048157 00000 n\r
+0000063716 00000 n\r
+0000042565 00000 n\r
+0000000022 00001 f\r
+0000000000 00001 f\r
+0000042678 00000 n\r
+0000044445 00000 n\r
+0000043034 00000 n\r
+0000043264 00000 n\r
+0000042048 00000 n\r
+0000211331 00000 n\r
+0000044694 00000 n\r
+0000043509 00000 n\r
+0000046105 00000 n\r
+0000046153 00000 n\r
+0000042339 00000 n\r
+0000000077 00000 n\r
+trailer\r
+<</Size 35/Root 1 0 R/Info 28 0 R/ID[<2CDA11A34E27D74294B3341065281964><2E3A232DA26DAD40B4BA526B7F172E8A>]>>\r
+startxref\r
+211501\r
+%%EOF\r
diff --git a/test/CreationTest/resources/watzmann.jpg b/test/CreationTest/resources/watzmann.jpg
new file mode 100644 (file)
index 0000000..349cb4b
Binary files /dev/null and b/test/CreationTest/resources/watzmann.jpg differ
diff --git a/test/FilterTest/CMakeLists.txt b/test/FilterTest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f47f20e
--- /dev/null
@@ -0,0 +1,4 @@
+ADD_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})
diff --git a/test/FilterTest/FilterTest.cpp b/test/FilterTest/FilterTest.cpp
new file mode 100644 (file)
index 0000000..edfa7d5
--- /dev/null
@@ -0,0 +1,307 @@
+
+
+/***************************************************************************
+ *   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 <stdlib.h>
+#include <cstdio>
+
+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<char>(0xFE), 0x6B, static_cast<char>(0x80), 0x45, 0x32,
+    static_cast<char>(0x88), 0x12, static_cast<char>(0x71), static_cast<char>(0xEA), 0x01,
+    0x01, 0x64, 0x65, static_cast<char>(0xFE), 0x6B, static_cast<char>(0x80), 0x45, 0x32,
+    static_cast<char>(0x88), 0x12, static_cast<char>(0x71), static_cast<char>(0xEA), 0x03,
+    0x01, 0x64, 0x65, static_cast<char>(0xFE), 0x6B, static_cast<char>(0x80), 0x45, 0x32,
+    static_cast<char>(0x88), 0x12, static_cast<char>(0x71), static_cast<char>(0xEA), 0x02,
+    0x01, 0x64, 0x65, static_cast<char>(0xFE), 0x6B, static_cast<char>(0x80), 0x45, 0x32,
+    static_cast<char>(0x88), 0x12, static_cast<char>(0x71), static_cast<char>(0xEA), 0x00,
+    0x01, 0x64, 0x65, static_cast<char>(0xFE), 0x6B, static_cast<char>(0x80), 0x45, 0x32,
+    static_cast<char>(0x88), 0x12, static_cast<char>(0x71), static_cast<char>(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;
+
+    PODOFO_UNIQUEU_PTR<PdfFilter> 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: %" PDF_FORMAT_INT64 "\n", static_cast<pdf_int64>(lTestLength) );
+    printf("\t-> Encoded  Data Length: %" PDF_FORMAT_INT64 "\n", static_cast<pdf_int64>(lEncoded) );
+    printf("\t-> Decoded  Data Length: %" PDF_FORMAT_INT64 "\n", static_cast<pdf_int64>(lDecoded) );
+
+    if( static_cast<pdf_long>(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: %" PDF_FORMAT_INT64 "\n", static_cast<pdf_int64>(lEncoded) );
+    printf("\t-> Decoded  Data Length: %" PDF_FORMAT_INT64 "\n", static_cast<pdf_int64>(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<char*>(pBuffer), lLen );
+    stream.GetFilteredCopy( &pDecoded, &lDecoded );
+
+    printf("\t-> Original Data Length: %" PDF_FORMAT_INT64 "\n", static_cast<pdf_int64>(lLen) );
+    printf("\t-> Encoded  Data Length: %" PDF_FORMAT_UINT64 "\n", static_cast<pdf_uint64>(stream.GetLength()) );
+    printf("\t-> Decoded  Data Length: %" PDF_FORMAT_INT64 "\n", static_cast<pdf_int64>(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<char*>(malloc( strlen(pszInputAscii85Lzw) * 6 ));
+    char*    pLargeBuffer2 = static_cast<char*>(malloc( strlen(pszInputAscii85Lzw) * 6 ));
+
+    try {
+        PODOFO_UNIQUEU_PTR<PdfFilter> 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<pdf_long>(strlen(pszInputAscii85Lzw)) != lLargeBufer2 )
+        {
+            fprintf( stderr, "ROACH Error: Decoded Length != Original Length\n");
+            fprintf( stderr, "ROACH Original: %" PDF_FORMAT_UINT64 "\n", static_cast<pdf_uint64>(strlen(pszInputAscii85Lzw)) );
+            fprintf( stderr, "ROACH Encode: %" PDF_FORMAT_INT64 "\n", static_cast<pdf_int64>(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<EPdfFilter>(i), pTestBuffer1, lTestLength1 );
+            test_filter( static_cast<EPdfFilter>(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;
+}
diff --git a/test/FormTest/CMakeLists.txt b/test/FormTest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a2dd067
--- /dev/null
@@ -0,0 +1,4 @@
+ADD_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})
diff --git a/test/FormTest/FormTest.cpp b/test/FormTest/FormTest.cpp
new file mode 100644 (file)
index 0000000..0ba096d
--- /dev/null
@@ -0,0 +1,355 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+#include "../PdfTest.h"
+
+#include <iostream>
+#include <cstdio>
+
+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( "<?xml version=\"1.0\"?><body xmlns=\"http://www.w3.org/1999/xtml\" xmlns:xfa=\"http://www.xfa.org/schema/xfa-data/1.0/\" xfa:contentType=\"text/html\" xfa:APIVersion=\"Acrobat:8.0.0\" xfa:spec=\"2.4\"><p style=\"text-align:left\"><b><i>Here is some bold italic text</i></b></p><p style=\"font-size:16pt\">This text uses default text state parameters but changes the font size to 16.</p></body>");
+
+    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<int>(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\r
+        {\r
+                char buff[10240];\r
+                if (gets(buff))\r
+                        value = buff;\r
+        }\r
+#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<static_cast<int>(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<int>(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;i<nPageCount;i++ )
+    {
+        pPage       = doc.GetPage( i );
+        nFieldCount = pPage->GetNumFields();
+
+        std::cout << "Page " << i + 1 << " contains " << nFieldCount << " fields." << std::endl;
+
+        for( int n=0;n<nFieldCount;n++ )
+        {
+            PdfField  field = pPage->GetField( 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;
+}
diff --git a/test/LargeTest/CMakeLists.txt b/test/LargeTest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a142ec2
--- /dev/null
@@ -0,0 +1,8 @@
+IF(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)
diff --git a/test/LargeTest/LargeTest.cpp b/test/LargeTest/LargeTest.cpp
new file mode 100644 (file)
index 0000000..b89ce14
--- /dev/null
@@ -0,0 +1,205 @@
+/***************************************************************************
+ *   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 <podofo.h>
+#include <fontconfig/fontconfig.h>
+#include <cstdio>
+
+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<const char*>(v.u.s) );
+            AddPage( pDoc, reinterpret_cast<const char*>(v.u.s), pszImagePath );
+        }
+
+        FcFontSetDestroy( pFontSet );
+    }
+    
+
+    if( writeImmediately )
+        static_cast<PdfStreamedDocument*>(pDoc)->Close();
+    else
+        static_cast<PdfMemDocument*>(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;
+}
diff --git a/test/ObjectParserTest/CMakeLists.txt b/test/ObjectParserTest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6a44f19
--- /dev/null
@@ -0,0 +1,11 @@
+ADD_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"
+    )
diff --git a/test/ObjectParserTest/ObjectParserTest.cpp b/test/ObjectParserTest/ObjectParserTest.cpp
new file mode 100644 (file)
index 0000000..3ed42db
--- /dev/null
@@ -0,0 +1,478 @@
+/***************************************************************************
+ *   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"
+
+#ifdef _WIN32
+// Get access to POSIX unlink()
+#include <io.h>
+#define unlink _unlink
+#else
+#include <unistd.h>
+#endif
+
+#include <cstdio>
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+#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 <<endl;
+        PODOFO_RAISE_ERROR( ePdfError_TestFailed );
+    }
+    fclose(f);
+    return string(buf, bytesRead);
+}
+
+// Parameters:
+//
+//    sFileName: Path to a file containing `sData'
+//    lObjNo: object number in data
+//    lGenNo: Generation number in data
+//    pTestExpected: Should we test against sExpectedData?
+//    sExpectedData: Parsed & written object's expected data
+//
+//    You'll probably want to call this with a wrapper that creates
+//    the input temp file when working with small amounts of data, and
+//    one that reads the expected results file for larger amounts of data.
+//
+void TestObject( const string & sFilename,
+                       unsigned long lObjNo, unsigned long lGenNo,
+                       bool bTestExpected,
+                       const string & sExpectedData,
+                       bool bHasStream
+                       )
+{
+    // We end up re-reading a temp file we just wrote sometimes,
+    // but this isn't exactly perf critical code.
+    const string sOrigData = ReadFile(sFilename);
+
+    PdfVecObjects parser;
+
+    PdfRefCountedInputDevice device( sFilename.c_str(), "r" );
+    if( !device.Device() )
+    {
+        cerr << "Cannot open " << sFilename << " for reading." << endl;
+        PODOFO_RAISE_ERROR( ePdfError_TestFailed );
+    }
+
+    cerr << "Parsing Object: " << lObjNo << ' ' << lGenNo << endl;
+
+    PdfRefCountedBuffer      buffer( BUFFER_SIZE );
+    PdfParserObject obj( &parser, device, buffer );
+    TRY {
+        obj.ParseFile( NULL, false );
+#ifdef CATCH_EXCEPTIONS
+    } catch( PdfError & e ) {
+        cerr << "Error during test: " << e.GetError() << endl;
+        device = PdfRefCountedInputDevice();
+
+        e.AddToCallstack( __FILE__, __LINE__ );
+        throw e;
+#endif
+    }
+
+    device = PdfRefCountedInputDevice();
+
+    cerr << "  -> 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<PdfMemStream*>(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<ff00ffaa>>>\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<AAFF>/Key4(Hallo \\(Welt!)\n"
+                        "/ID[<530464995927cef8aaf46eb953b93373><530464995927cef8aaf46eb953b93373>]\n"
+                        ">>\n"
+                        "endobj\n";
+
+const char* pszObject3 = "12 0 obj\n"
+                        "<<\n" 
+                        "/Type/Test3\n"
+                        "/Font<</F1 13 0 R>>\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&<!J9%_[umg\"B7/Z7KNXbN'S+,*Q/&\"OLT'F\n"
+        "LIDK#!n`$\"<Atdi`\\Vn%b%)&'cA*VnK\\CJY(sF>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`ViJglLb8<W9k6Yl\\0McJQkDeLWdPN?9A'jX*\n"
+        "al>iG1p&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;
+}
diff --git a/test/ObjectParserTest/objects/27_0_R.exp b/test/ObjectParserTest/objects/27_0_R.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/ObjectParserTest/objects/27_0_R.info b/test/ObjectParserTest/objects/27_0_R.info
new file mode 100644 (file)
index 0000000..05ae082
--- /dev/null
@@ -0,0 +1,2 @@
+- This sample object has an invalid LZW decode dictionary and produces
+  bad results.
diff --git a/test/ObjectParserTest/objects/27_0_R.obj b/test/ObjectParserTest/objects/27_0_R.obj
new file mode 100644 (file)
index 0000000..bdb6191
Binary files /dev/null and b/test/ObjectParserTest/objects/27_0_R.obj differ
diff --git a/test/ObjectParserTest/objects/613_0_R.obj b/test/ObjectParserTest/objects/613_0_R.obj
new file mode 100644 (file)
index 0000000..d3e7802
--- /dev/null
@@ -0,0 +1,8 @@
+613 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
diff --git a/test/ParserTest/CMakeLists.txt b/test/ParserTest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9d58672
--- /dev/null
@@ -0,0 +1,4 @@
+ADD_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})
diff --git a/test/ParserTest/ParserTest.cpp b/test/ParserTest/ParserTest.cpp
new file mode 100644 (file)
index 0000000..cd57fa0
--- /dev/null
@@ -0,0 +1,262 @@
+/***************************************************************************
+ *   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 <podofo-base.h>
+
+#include <iostream>
+#include <string>
+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] <input_filename> [<output_filename>]\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<const char*>(enc.GetUValue()), 32 );
+    std::string oValue( reinterpret_cast<const char*>(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<char*>(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<unsigned char*>(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<unsigned char*>(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<argc; i++ ) 
+    {
+        if( argv[i][0] == '-' ) 
+        {
+
+            if (string("-d") == argv[i]) 
+            {
+                useDemandLoading = true;
+            }
+            else if (string("-s") == argv[1]) 
+            {
+                useStrictMode = true;
+            } 
+            else if (string("-clean") == argv[i])
+            {
+                eWriteMode = ePdfWriteMode_Clean;
+            }
+            else if (string("-compact") == argv[i])
+            {
+                eWriteMode = ePdfWriteMode_Compact;
+            }
+        }
+        else
+        {
+            if( pszInput == NULL ) 
+            {
+                pszInput = argv[i];
+            }
+            else if( pszFilename == NULL )
+            {
+                pszFilename = argv[i];
+            }
+            else
+            {
+                print_help();
+                return 0;
+            }
+        }
+    }
+
+    if( pszInput == NULL )
+    {
+        print_help();
+        cerr << "Usage: ParserTest [-d] [-s] [-clean] [-compact] <input_filename> [<output_filename>]\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<PdfObject*>(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;
+}
diff --git a/test/PdfTest.h b/test/PdfTest.h
new file mode 100644 (file)
index 0000000..9b5c3b0
--- /dev/null
@@ -0,0 +1,22 @@
+
+#include <podofo.h>
+
+/* 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();\
+                     }
+
+// prefer std::unique_ptr over std::auto_ptr
+#ifdef PODOFO_HAVE_UNIQUE_PTR
+#define PODOFO_UNIQUEU_PTR std::unique_ptr
+#else
+#define PODOFO_UNIQUEU_PTR std::auto_ptr
+#endif
diff --git a/test/SignTest/CMakeLists.txt b/test/SignTest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f6ace68
--- /dev/null
@@ -0,0 +1,4 @@
+ADD_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})
diff --git a/test/SignTest/SignTest.cpp b/test/SignTest/SignTest.cpp
new file mode 100644 (file)
index 0000000..3252f2c
--- /dev/null
@@ -0,0 +1,108 @@
+/***************************************************************************
+ *   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 <iostream>
+#include <cstdio>
+#include <fstream>
+
+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;
+}
diff --git a/test/SignatureTest/CMakeLists.txt b/test/SignatureTest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6f90589
--- /dev/null
@@ -0,0 +1,16 @@
+SET(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})
diff --git a/test/SignatureTest/NSSSignatureGenerator.cpp b/test/SignatureTest/NSSSignatureGenerator.cpp
new file mode 100644 (file)
index 0000000..2ea6344
--- /dev/null
@@ -0,0 +1,168 @@
+/** 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 <podofo.h>
+
+void NSSSignatureGenerator::sm_write_stream(void *arg, const char *buf, unsigned long len) 
+{
+    NSSSignatureGenerator* pThis = static_cast<NSSSignatureGenerator*>(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;
+}
diff --git a/test/SignatureTest/NSSSignatureGenerator.h b/test/SignatureTest/NSSSignatureGenerator.h
new file mode 100644 (file)
index 0000000..9df5ef1
--- /dev/null
@@ -0,0 +1,53 @@
+/** 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 <cms.h>
+#include <cert.h>
+#include <secoid.h>
+#include <string>
+
+#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_
diff --git a/test/SignatureTest/SignTest.cpp b/test/SignatureTest/SignTest.cpp
new file mode 100644 (file)
index 0000000..b99174d
--- /dev/null
@@ -0,0 +1,169 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+#include "../PdfTest.h"
+
+#include "SignatureGenerator.h"
+#include "SimpleSignatureGenerator.h"
+//#include "NSSSignatureGenerator.h"
+
+//#include <cert.h>
+//#include <certt.h>
+
+#include <iostream>
+#include <cstdio>
+#include <fstream>
+
+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;
+}
diff --git a/test/SignatureTest/SignatureGenerator.h b/test/SignatureTest/SignatureGenerator.h
new file mode 100644 (file)
index 0000000..2991c72
--- /dev/null
@@ -0,0 +1,18 @@
+
+#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_
diff --git a/test/SignatureTest/SimpleSignatureGenerator.h b/test/SignatureTest/SimpleSignatureGenerator.h
new file mode 100644 (file)
index 0000000..f603a68
--- /dev/null
@@ -0,0 +1,35 @@
+
+#ifndef _SIMPLE_SIGNATURE_GENERATOR_H_
+#define _SIMPLE_SIGNATURE_GENERATOR_H_
+
+#include "SignatureGenerator.h"
+
+#include <podofo.h>
+
+/** 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_
diff --git a/test/TokenizerTest/CMakeLists.txt b/test/TokenizerTest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..30ea2df
--- /dev/null
@@ -0,0 +1,4 @@
+ADD_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})
diff --git a/test/TokenizerTest/TokenizerTest.cpp b/test/TokenizerTest/TokenizerTest.cpp
new file mode 100644 (file)
index 0000000..8cd053d
--- /dev/null
@@ -0,0 +1,57 @@
+/***************************************************************************
+ *   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 <stdio.h>
+
+#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;
+}
diff --git a/test/VariantTest/CMakeLists.txt b/test/VariantTest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..62cd974
--- /dev/null
@@ -0,0 +1,4 @@
+ADD_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})
diff --git a/test/VariantTest/VariantTest.cpp b/test/VariantTest/VariantTest.cpp
new file mode 100644 (file)
index 0000000..d829618
--- /dev/null
@@ -0,0 +1,275 @@
+/***************************************************************************
+ *   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 <iostream>
+#include <stdlib.h>
+#include <string.h>
+#include <cstdio>
+
+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");
+
+    PODOFO_UNIQUEU_PTR<PdfFilter> 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( "<FFEB0400A0CC>", ePdfDataType_HexString ) );
+    TEST_SAFE_OP( Test( "<FFEB0400A0C>", ePdfDataType_HexString, "<FFEB0400A0C0>" ) );
+    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( "[<</key/name>>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<char*>(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<char*>(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();
+}
diff --git a/test/WatermarkTest/CMakeLists.txt b/test/WatermarkTest/CMakeLists.txt
new file mode 100644 (file)
index 0000000..355333c
--- /dev/null
@@ -0,0 +1,4 @@
+ADD_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})
diff --git a/test/WatermarkTest/WatermarkTest.cpp b/test/WatermarkTest/WatermarkTest.cpp
new file mode 100644 (file)
index 0000000..486c184
--- /dev/null
@@ -0,0 +1,82 @@
+/***************************************************************************
+ *   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 <cstdio>
+
+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;i<doc.GetPageCount();i++)
+    {
+        pPage = doc.GetPage( i );
+        if( !pPage ) 
+        {
+            PODOFO_RAISE_ERROR( ePdfError_InvalidHandle );
+        }
+        
+        rect = pPage->GetPageSize();
+
+        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;
+}
diff --git a/test/WatermarkTest/WatermarkTest.vcproj b/test/WatermarkTest/WatermarkTest.vcproj
new file mode 100644 (file)
index 0000000..9deb805
--- /dev/null
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.10"\r
+       Name="WatermarkTest"\r
+       ProjectGUID="{76E51E53-633D-41E8-AC94-AB6584C107D8}"\r
+       Keyword="Win32Proj">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..\src;..\..\freetype\include;..\..\zlib;..\..\jpeg"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"\r
+                               MinimalRebuild="TRUE"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="5"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="4"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="wsock32.lib"\r
+                               OutputFile="$(OutDir)/WatermarkTest.exe"\r
+                               LinkIncremental="2"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(OutDir)/WatermarkTest.pdb"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"\r
+                               RuntimeLibrary="4"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="3"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(OutDir)/WatermarkTest.exe"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="TRUE"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">\r
+                       <File\r
+                               RelativePath=".\WatermarkTest.cpp">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/test/pdfs/README.txt b/test/pdfs/README.txt
new file mode 100644 (file)
index 0000000..10ce22a
--- /dev/null
@@ -0,0 +1,6 @@
+This 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).
diff --git a/test/pdfs/inline-image.pdf b/test/pdfs/inline-image.pdf
new file mode 100644 (file)
index 0000000..13f2793
Binary files /dev/null and b/test/pdfs/inline-image.pdf differ
diff --git a/test/pdfs/inline-image.txt b/test/pdfs/inline-image.txt
new file mode 100644 (file)
index 0000000..fd62a50
--- /dev/null
@@ -0,0 +1,24 @@
+This 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
diff --git a/test/system/podofo-system.sh b/test/system/podofo-system.sh
new file mode 100755 (executable)
index 0000000..6fb9183
--- /dev/null
@@ -0,0 +1,81 @@
+#!/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
diff --git a/test/unit/BasicTypeTest.cpp b/test/unit/BasicTypeTest.cpp
new file mode 100644 (file)
index 0000000..0acf7f8
--- /dev/null
@@ -0,0 +1,47 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+#include <limits>
+
+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<pdf_uint64>::max() >= PODOFO_ULL_LITERAL(9999999999) );
+}
+
+void BasicTypeTest::testDefaultMaximumNumberOfObjects()
+{
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("PdfReference allows 8,388,607 indirect objects.", 8388607L, PdfParser::GetMaxObjectCount() );
+}
diff --git a/test/unit/BasicTypeTest.h b/test/unit/BasicTypeTest.h
new file mode 100644 (file)
index 0000000..32ddb2a
--- /dev/null
@@ -0,0 +1,51 @@
+/***************************************************************************
+ *   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 <cppunit/extensions/HelperMacros.h>
+
+/** 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( testDefaultMaximumNumberOfObjects );
+    CPPUNIT_TEST_SUITE_END();
+    
+ public:
+    void setUp();
+    void tearDown();
+    
+    void testXrefOffsetTypeSize();
+    void testDefaultMaximumNumberOfObjects();
+    
+ private:
+};
+
+#endif
+
+
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f4dbdf9
--- /dev/null
@@ -0,0 +1,14 @@
+
+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 ParserTest.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)
diff --git a/test/unit/ColorTest.cpp b/test/unit/ColorTest.cpp
new file mode 100644 (file)
index 0000000..e621b23
--- /dev/null
@@ -0,0 +1,2476 @@
+/***************************************************************************
+ *   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 <podofo.h>
+#include "cppunitextensions.h"
+
+#include <map>
+#include <utility>
+#include <string>
+
+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<int>(rgb.GetRed() * 255.0), 0xFF);
+        ASSERT_EQ(static_cast<int>(rgb.GetGreen() * 255.0), 0x0A);
+        ASSERT_EQ(static_cast<int>(rgb.GetBlue() * 255.0), 0xEF);
+    }
+
+    {
+        PdfColor rgb = PdfColor::FromString( "#012345");
+        ASSERT_TRUE(rgb.IsRGB());
+        ASSERT_EQ(static_cast<int>(rgb.GetRed() * 255.0), 0x01);
+        ASSERT_EQ(static_cast<int>(rgb.GetGreen() * 255.0), 0x23);
+        ASSERT_EQ(static_cast<int>(rgb.GetBlue() * 255.0), 0x45);
+    }
+
+    {
+        PdfColor rgb = PdfColor::FromString( "#ABCDEF");
+        ASSERT_TRUE(rgb.IsRGB());
+        ASSERT_EQ(static_cast<int>(rgb.GetRed() * 255.0), 0xAB);
+        ASSERT_EQ(static_cast<int>(rgb.GetGreen() * 255.0), 0xCD);
+        ASSERT_EQ(static_cast<int>(rgb.GetBlue() * 255.0), 0xEF);
+    }
+
+    {
+        PdfColor rgb = PdfColor::FromString( "#abcdef");
+        ASSERT_TRUE(rgb.IsRGB());
+        ASSERT_EQ(static_cast<int>(rgb.GetRed() * 255.0), 0xAB);
+        ASSERT_EQ(static_cast<int>(rgb.GetGreen() * 255.0), 0xCD);
+        ASSERT_EQ(static_cast<int>(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<int>(cmyk.GetCyan() * 255.0), 0xAB);
+    ASSERT_EQ(static_cast<int>(cmyk.GetMagenta() * 255.0), 0xCD);
+    ASSERT_EQ(static_cast<int>(cmyk.GetYellow() * 255.0), 0xEF);
+    ASSERT_EQ(static_cast<int>(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<double>(0xF0)/255.0);
+    ASSERT_EQ(aliceBlue.GetGreen(), static_cast<double>(0xF8)/255.0);
+    ASSERT_EQ(aliceBlue.GetBlue(),  static_cast<double>(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<double>(r)/255.0),
+        m_g(static_cast<double>(g)/255.0),
+        m_b(static_cast<double>(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<SIZE_OF_TABLE_OF_TEST_COLORS; ++i)
+    {
+        const TestColor& TEST_COLOR(TABLE_OF_TEST_COLORS[i]);
+
+        const PdfColor COLOR_FROM_NAME(PdfColor::FromString(TEST_COLOR.getColorName()));
+        const PdfColor EXPECTED_COLOR(TEST_COLOR.getR(), TEST_COLOR.getG(), TEST_COLOR.getB());
+
+        if (PdfColor() == COLOR_FROM_NAME)
+        {
+#ifdef DEBUG_INFO
+            std::cout << "Color " << TEST_COLOR.getColorName() << " is not supported" << std::endl;
+#endif
+        }
+        else
+        {
+            bool result = EXPECTED_COLOR == COLOR_FROM_NAME;
+            ASSERT_TRUE(result);
+        }
+    }
+}
+
+void ColorTest::testColorGreyConstructor() 
+{
+#ifdef DEBUG_INFO
+    std::cout << "testColorGreyConstructor" << std::endl;
+#endif
+
+    const double GREY_VALUE = 0.123;
+    PdfColorGray 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);
+
+    ASSERT_EQ(color.GetGrayScale(), GREY_VALUE);
+}
+
+void ColorTest::testColorRGBConstructor() 
+{
+#ifdef DEBUG_INFO
+    std::cout << "testColorRGBConstructor" << std::endl;
+#endif
+
+    const double R_VALUE = 0.023;
+    const double G_VALUE = 0.345;
+    const double B_VALUE = 0.678;
+    PdfColorRGB 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);
+
+    ASSERT_EQ(color.GetRed(), R_VALUE);
+    ASSERT_EQ(color.GetGreen(), G_VALUE);
+    ASSERT_EQ(color.GetBlue(), B_VALUE);
+}
+
+void ColorTest::testColorCMYKConstructor() 
+{
+#ifdef DEBUG_INFO
+    std::cout << "testColorCMYKConstructor" << 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;
+    PdfColorCMYK 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);
+
+    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::testColorSeparationAllConstructor() 
+{
+#ifdef DEBUG_INFO
+    std::cout << "testColorSeparationAllConstructor" << std::endl;
+#endif
+
+    PdfColorSeparationAll color;
+
+    ASSERT_FALSE(color.IsGrayScale());
+    ASSERT_FALSE(color.IsRGB());
+    ASSERT_FALSE(color.IsCMYK());
+    ASSERT_TRUE(color.IsSeparation());
+    ASSERT_FALSE(color.IsCieLab());
+    ASSERT_EQ(color.GetColorSpace(), ePdfColorSpace_Separation);
+    ASSERT_EQ(color.GetAlternateColorSpace(), ePdfColorSpace_DeviceCMYK);
+
+    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(), 1.0);
+    ASSERT_EQ(color.GetMagenta(), 1.0);
+    ASSERT_EQ(color.GetYellow(), 1.0);
+    ASSERT_EQ(color.GetBlack(), 1.0);
+
+    ASSERT_EQ(color.GetName(), std::string("All"));
+    ASSERT_EQ(color.GetDensity(), 1.0);
+
+    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.0, 0.0, 0.0) == color.ConvertToGrayScale());
+    ASSERT_TRUE(PdfColor(0.0, 0.0, 0.0) == color.ConvertToRGB());
+
+    CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( 
+        color.ConvertToCMYK(), 
+        PdfError, 
+        ePdfError_CannotConvertColor);
+
+    const PdfArray COLOR_ARRAY = color.ToArray();
+    ASSERT_TRUE(1 == COLOR_ARRAY.GetSize());
+    ASSERT_TRUE(PdfObject(1.0) == COLOR_ARRAY[0]);
+}
+
+void ColorTest::testColorSeparationNoneConstructor() 
+{
+#ifdef DEBUG_INFO
+    std::cout << "testColorSeparationNoneConstructor" << std::endl;
+#endif
+
+    PdfColorSeparationNone color;
+
+    ASSERT_FALSE(color.IsGrayScale());
+    ASSERT_FALSE(color.IsRGB());
+    ASSERT_FALSE(color.IsCMYK());
+    ASSERT_TRUE(color.IsSeparation());
+    ASSERT_FALSE(color.IsCieLab());
+    ASSERT_EQ(color.GetColorSpace(), ePdfColorSpace_Separation);
+    ASSERT_EQ(color.GetAlternateColorSpace(), ePdfColorSpace_DeviceCMYK);
+
+    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(), 0.0);
+    ASSERT_EQ(color.GetMagenta(), 0.0);
+    ASSERT_EQ(color.GetYellow(), 0.0);
+    ASSERT_EQ(color.GetBlack(), 0.0);
+
+    ASSERT_EQ(color.GetName(), std::string("None"));
+    ASSERT_EQ(color.GetDensity(), 0.0);
+
+    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(1.0, 1.0, 1.0) == color.ConvertToGrayScale());
+    ASSERT_TRUE(PdfColor(1.0, 1.0, 1.0) == color.ConvertToRGB());
+
+    CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( 
+        color.ConvertToCMYK(), 
+        PdfError, 
+        ePdfError_CannotConvertColor);
+
+    const PdfArray COLOR_ARRAY = color.ToArray();
+    ASSERT_TRUE(1 == COLOR_ARRAY.GetSize());
+    ASSERT_TRUE(PdfObject(0.0) == COLOR_ARRAY[0]);
+}
+
+void ColorTest::testColorSeparationConstructor() 
+{
+#ifdef DEBUG_INFO
+    std::cout << "testColorSeparationConstructor" << std::endl;
+#endif
+
+    { //alternate color is Greyscale
+        const PdfColorGray ALTERNATE_COLOR(0.1234);
+        const double DENSITY = 0.523456;
+        const std::string NAME("Hello");
+        PdfColorSeparation color("Hello", DENSITY, ALTERNATE_COLOR);
+
+        ASSERT_FALSE(color.IsGrayScale());
+        ASSERT_FALSE(color.IsRGB());
+        ASSERT_FALSE(color.IsCMYK());
+        ASSERT_TRUE(color.IsSeparation());
+        ASSERT_FALSE(color.IsCieLab());
+        ASSERT_EQ(color.GetColorSpace(), ePdfColorSpace_Separation);
+        ASSERT_EQ(color.GetAlternateColorSpace(), ePdfColorSpace_DeviceGray);
+
+        ASSERT_EQ(ALTERNATE_COLOR.GetGrayScale(), color.GetGrayScale());
+
+        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.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_EQ(color.GetName(), NAME);
+        ASSERT_EQ(color.GetDensity(), DENSITY);
+
+        CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( 
+            color.ConvertToGrayScale(), 
+            PdfError, 
+            ePdfError_NotImplemented);
+
+        CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( 
+            color.ConvertToRGB(), 
+            PdfError, 
+            ePdfError_NotImplemented);
+
+        CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( 
+            color.ConvertToCMYK(), 
+            PdfError, 
+            ePdfError_CannotConvertColor);
+
+        const PdfArray COLOR_ARRAY = color.ToArray();
+        ASSERT_TRUE(1 == COLOR_ARRAY.GetSize());
+        ASSERT_TRUE(PdfObject(0.0) == COLOR_ARRAY[0]);
+    }
+
+    { //alternate color is RGB
+        const double R_VALUE = 0.023;
+        const double G_VALUE = 0.345;
+        const double B_VALUE = 0.678;
+        const PdfColor ALTERNATE_COLOR(R_VALUE, G_VALUE, B_VALUE);
+        const double DENSITY = 0.523456;
+        const std::string NAME("Hello");
+        PdfColorSeparation color("Hello", DENSITY, ALTERNATE_COLOR);
+
+        ASSERT_FALSE(color.IsGrayScale());
+        ASSERT_FALSE(color.IsRGB());
+        ASSERT_FALSE(color.IsCMYK());
+        ASSERT_TRUE(color.IsSeparation());
+        ASSERT_FALSE(color.IsCieLab());
+        ASSERT_EQ(color.GetColorSpace(), ePdfColorSpace_Separation);
+        ASSERT_EQ(color.GetAlternateColorSpace(), ePdfColorSpace_DeviceRGB);
+
+        CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( 
+            color.GetGrayScale(), 
+            PdfError, 
+            ePdfError_InternalLogic);
+
+        ASSERT_EQ(ALTERNATE_COLOR.GetRed(), color.GetRed());
+        ASSERT_EQ(ALTERNATE_COLOR.GetGreen(), color.GetGreen());
+        ASSERT_EQ(ALTERNATE_COLOR.GetBlue(), color.GetBlue());
+
+        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.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_EQ(color.GetName(), NAME);
+        ASSERT_EQ(color.GetDensity(), DENSITY);
+
+        CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( 
+            color.ConvertToGrayScale(), 
+            PdfError, 
+            ePdfError_NotImplemented);
+
+        CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( 
+            color.ConvertToRGB(), 
+            PdfError, 
+            ePdfError_NotImplemented);
+
+        CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( 
+            color.ConvertToCMYK(), 
+            PdfError, 
+            ePdfError_CannotConvertColor);
+
+        const PdfArray COLOR_ARRAY = color.ToArray();
+        ASSERT_TRUE(1 == COLOR_ARRAY.GetSize());
+        ASSERT_TRUE(PdfObject(0.0) == COLOR_ARRAY[0]);
+    }
+
+    { //alternate color is CMYK
+        const double C_VALUE = 0.023;
+        const double M_VALUE = 0.345;
+        const double Y_VALUE = 0.678;
+        const double K_VALUE = 0.18;
+        const PdfColor ALTERNATE_COLOR(C_VALUE, M_VALUE, Y_VALUE, K_VALUE);
+        const double DENSITY = 0.123456;
+        const std::string NAME("Hello");
+        PdfColorSeparation color("Hello", DENSITY, ALTERNATE_COLOR);
+
+        ASSERT_FALSE(color.IsGrayScale());
+        ASSERT_FALSE(color.IsRGB());
+        ASSERT_FALSE(color.IsCMYK());
+        ASSERT_TRUE(color.IsSeparation());
+        ASSERT_FALSE(color.IsCieLab());
+        ASSERT_EQ(color.GetColorSpace(), ePdfColorSpace_Separation);
+        ASSERT_EQ(color.GetAlternateColorSpace(), ePdfColorSpace_DeviceCMYK);
+
+        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(ALTERNATE_COLOR.GetCyan(), color.GetCyan());
+        ASSERT_EQ(ALTERNATE_COLOR.GetMagenta(), color.GetMagenta());
+        ASSERT_EQ(ALTERNATE_COLOR.GetYellow(), color.GetYellow());
+        ASSERT_EQ(ALTERNATE_COLOR.GetBlack(), color.GetBlack());
+
+        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_EQ(color.GetName(), NAME);
+        ASSERT_EQ(color.GetDensity(), DENSITY);
+
+        CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( 
+            color.ConvertToCMYK(), 
+            PdfError, 
+            ePdfError_CannotConvertColor);
+
+        const PdfArray COLOR_ARRAY = color.ToArray();
+        ASSERT_TRUE(1 == COLOR_ARRAY.GetSize());
+        ASSERT_TRUE(PdfObject(0.0) == COLOR_ARRAY[0]);
+    }
+
+    { //alternate color is CieLab
+        const double dCieL = 0.023;
+        const double dCieA = 0.345;
+        const double dCieB = 0.678;
+        const PdfColorCieLab ALTERNATE_COLOR(dCieL, dCieA, dCieB);
+        const double DENSITY = 0.523456;
+        const std::string NAME("Hello");
+        PdfColorSeparation color("Hello", DENSITY, ALTERNATE_COLOR);
+
+        ASSERT_FALSE(color.IsGrayScale());
+        ASSERT_FALSE(color.IsRGB());
+        ASSERT_FALSE(color.IsCMYK());
+        ASSERT_TRUE(color.IsSeparation());
+        ASSERT_FALSE(color.IsCieLab());
+        ASSERT_EQ(color.GetColorSpace(), ePdfColorSpace_Separation);
+        ASSERT_EQ(color.GetAlternateColorSpace(), ePdfColorSpace_CieLab);
+
+        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);
+
+        ASSERT_EQ(ALTERNATE_COLOR.GetCieL(), color.GetCieL());
+        ASSERT_EQ(ALTERNATE_COLOR.GetCieA(), color.GetCieA());
+        ASSERT_EQ(ALTERNATE_COLOR.GetCieB(), color.GetCieB());
+
+        ASSERT_EQ(color.GetName(), NAME);
+        ASSERT_EQ(color.GetDensity(), DENSITY);
+
+        CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( 
+            color.ConvertToGrayScale(), 
+            PdfError, 
+            ePdfError_NotImplemented);
+
+        CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( 
+            color.ConvertToRGB(), 
+            PdfError, 
+            ePdfError_NotImplemented);
+
+        CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( 
+            color.ConvertToCMYK(), 
+            PdfError, 
+            ePdfError_CannotConvertColor);
+
+        const PdfArray COLOR_ARRAY = color.ToArray();
+        ASSERT_TRUE(1 == COLOR_ARRAY.GetSize());
+        ASSERT_TRUE(PdfObject(0.0) == COLOR_ARRAY[0]);
+    }
+}
+
+void ColorTest::testColorCieLabConstructor() 
+{
+#ifdef DEBUG_INFO
+    std::cout << "testColorCieLabConstructor" << std::endl;
+#endif
+
+    const double dCieL = 0.023;
+    const double dCieA = 0.345;
+    const double dCieB = 0.678;
+    PdfColorCieLab color(dCieL, dCieA, dCieB);
+
+    ASSERT_FALSE(color.IsGrayScale());
+    ASSERT_FALSE(color.IsRGB());
+    ASSERT_FALSE(color.IsCMYK());
+    ASSERT_FALSE(color.IsSeparation());
+    ASSERT_TRUE(color.IsCieLab());
+    ASSERT_EQ(color.GetColorSpace(), ePdfColorSpace_CieLab);
+
+    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);
+
+    ASSERT_EQ(dCieL, color.GetCieL());
+    ASSERT_EQ(dCieA, color.GetCieA());
+    ASSERT_EQ(dCieB, color.GetCieB());
+
+    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);
+
+    const PdfArray COLOR_ARRAY = color.ToArray();
+    ASSERT_TRUE(3 == COLOR_ARRAY.GetSize());
+    ASSERT_TRUE(PdfObject(dCieL) == COLOR_ARRAY[0]);
+    ASSERT_TRUE(PdfObject(dCieA) == COLOR_ARRAY[1]);
+    ASSERT_TRUE(PdfObject(dCieB) == COLOR_ARRAY[2]);
+}
+
+void ColorTest::testRGBtoCMYKConversions() 
+{
+#ifdef DEBUG_INFO
+    std::cout << "testRGBtoCMYKConversions" << std::endl;
+#endif
+
+    typedef std::pair<PdfColor, PdfColor> TPairOfColors;
+    typedef std::map<std::string, TPairOfColors> 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());
+    }
+}
+
diff --git a/test/unit/ColorTest.h b/test/unit/ColorTest.h
new file mode 100644 (file)
index 0000000..cd2d26d
--- /dev/null
@@ -0,0 +1,91 @@
+/***************************************************************************
+ *   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 <cppunit/extensions/HelperMacros.h>
+
+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();
+
+    void testAssignNull();
+};
+
+#endif
+
+
diff --git a/test/unit/DateTest.cpp b/test/unit/DateTest.cpp
new file mode 100644 (file)
index 0000000..237147d
--- /dev/null
@@ -0,0 +1,156 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+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);
+    if( pszDate != NULL )
+    {
+      CPPUNIT_ASSERT_EQUAL_MESSAGE(pszDate,bExpected,date.IsValid());
+    }
+    else
+    {
+      CPPUNIT_ASSERT_EQUAL_MESSAGE("NULL",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);
+
+    checkExpected("INVALID", false);
+}
+
+void DateTest::testDateValue()
+{
+    const char* pszDate = "D:20120530235959Z00'00'";
+    PdfString tmp(pszDate);
+    PdfDate date(tmp);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE(std::string(pszDate),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);
+}
+
+void DateTest::testAdditional()
+{
+  struct name_date {
+    std::string name;
+    std::string date;
+  };
+
+  const name_date data[] = {
+                           {"sample from pdf_reference_1_7.pdf", "D:199812231952-08'00'"},
+                           // UTC 1998-12-24 03:52:00
+                           {"all fields set", "D:20201223195200-08'00'"},   // UTC 2020-12-03:52:00
+                           {"set year", "D:2020"},   // UTC 2020-01-01 00:00:00
+                           {"set year, month", "D:202001"},   // UTC 2020-01-01 00:00:00
+                           {"set year, month, day", "D:20200101"},   // UTC 202001-01 00:00:00
+                           {"only year and timezone set", "D:2020-08'00'"},   // UTC 2020-01-01 08:00:00
+                           {"berlin", "D:20200315120820+01'00'"},   // UTC 2020-03-15 11:08:20
+  };
+
+  for (const auto& d : data) {
+    std::cout << "Parse " << d.name << "\n";
+    assert(PoDoFo::PdfDate(d.date).IsValid());
+  }
+}
+
+
+void DateTest::testParseDateInvalid()
+{
+    PdfString tmp("D:2012020");
+    PdfDate date(tmp);
+
+    struct tm  _tm;
+    memset (&_tm, 0, sizeof(struct tm));
+
+    const time_t t = date.GetTime();
+
+    CPPUNIT_ASSERT_EQUAL(false, date.IsValid());
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Invalid date should be equal to time_t(-1)", time_t(-1), t);
+}
+
+void DateTest::testParseDateValid()
+{
+    PdfString tmp("D:20120205132456");
+    PdfDate date(tmp);
+
+    struct tm  _tm;
+    memset (&_tm, 0, sizeof(struct tm));
+
+    const time_t t = date.GetTime();
+    localtime_r(&t, &_tm);
+
+    CPPUNIT_ASSERT_EQUAL(true, date.IsValid());
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Year", 2012, _tm.tm_year + 1900);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Month", 2, _tm.tm_mon + 1);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Day", 5, _tm.tm_mday);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Hour", 13, _tm.tm_hour);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Minute", 24, _tm.tm_min);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Second", 56, _tm.tm_sec);
+
+}
+
+
+
diff --git a/test/unit/DateTest.h b/test/unit/DateTest.h
new file mode 100644 (file)
index 0000000..ed68a5c
--- /dev/null
@@ -0,0 +1,48 @@
+/***************************************************************************
+ *   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 <cppunit/extensions/HelperMacros.h>
+
+class DateTest : public CppUnit::TestFixture
+{
+    CPPUNIT_TEST_SUITE( DateTest );
+    CPPUNIT_TEST( testCreateDateFromString );
+    CPPUNIT_TEST( testDateValue );
+    CPPUNIT_TEST( testAdditional );
+    CPPUNIT_TEST( testParseDateValid );
+    CPPUNIT_TEST( testParseDateInvalid );
+    CPPUNIT_TEST_SUITE_END();
+
+public:
+    void setUp();
+    void tearDown();
+
+    void testCreateDateFromString();
+    void testDateValue();
+    void testAdditional();
+    void testParseDateInvalid();
+    void testParseDateValid();
+};
+
+#endif
diff --git a/test/unit/DeviceTest.cpp b/test/unit/DeviceTest.cpp
new file mode 100644 (file)
index 0000000..f81a811
--- /dev/null
@@ -0,0 +1,122 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+#include <stdio.h>
+#include <string.h>
+#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<long>(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<long>(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<long>(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<long>(buffer1.GetSize()) != (lLen * 100 + lLen) ) 
+    {
+        fprintf( stderr, "Buffer1 size is wrong after 100 attaches: %li\n", buffer1.GetSize() );
+        PODOFO_RAISE_ERROR( ePdfError_TestFailed );
+    }
+    
+}
+
diff --git a/test/unit/DeviceTest.h b/test/unit/DeviceTest.h
new file mode 100644 (file)
index 0000000..5b0b784
--- /dev/null
@@ -0,0 +1,38 @@
+/***************************************************************************
+ *   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 <cppunit/extensions/HelperMacros.h>
+
+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_
diff --git a/test/unit/ElementTest.cpp b/test/unit/ElementTest.cpp
new file mode 100644 (file)
index 0000000..4a83c33
--- /dev/null
@@ -0,0 +1,79 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+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() );
+}
diff --git a/test/unit/ElementTest.h b/test/unit/ElementTest.h
new file mode 100644 (file)
index 0000000..97f44a8
--- /dev/null
@@ -0,0 +1,49 @@
+/***************************************************************************
+ *   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 <cppunit/extensions/HelperMacros.h>
+
+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_
+
+
diff --git a/test/unit/EncodingTest.cpp b/test/unit/EncodingTest.cpp
new file mode 100644 (file)
index 0000000..94d6178
--- /dev/null
@@ -0,0 +1,481 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+#include <ostream>
+
+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 redefinition 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( 0, static_cast<int>(difference.GetCount()) );
+
+
+    // Adding 0 should work
+    difference.AddDifference( 0, 0, PdfName("A") );
+    CPPUNIT_ASSERT_EQUAL( 1, static_cast<int>(difference.GetCount()) );
+
+    // Adding 255 should work
+    difference.AddDifference( 255, 0, PdfName("B") );
+    CPPUNIT_ASSERT_EQUAL( 2, static_cast<int>(difference.GetCount()) );
+
+    // 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<int>(difference.GetCount()), 2 );
+
+    // Convert to array
+    PdfArray data;
+    PdfArray expected;
+    expected.push_back( static_cast<pdf_int64>(0LL) );
+    expected.push_back( PdfName("A") );
+    expected.push_back( static_cast<pdf_int64>(255LL) );
+    expected.push_back( PdfName("B") );
+
+    difference.ToArray( data );
+
+    CPPUNIT_ASSERT_EQUAL( expected.GetSize(), data.GetSize() );
+    for( unsigned int i=0;i<data.GetSize(); i++ )
+        CPPUNIT_ASSERT_EQUAL( expected[i], data[i] );
+
+
+    // Test replace
+    expected.Clear();
+    expected.push_back( static_cast<pdf_int64>(0LL) );
+    expected.push_back( PdfName("A") );
+    expected.push_back( static_cast<pdf_int64>(255LL) );
+    expected.push_back( PdfName("X") );
+
+    difference.AddDifference( 255, 0, PdfName("X") );
+
+    difference.ToArray( data );
+
+    CPPUNIT_ASSERT_EQUAL( expected.GetSize(), data.GetSize() );
+    for( unsigned int i=0;i<data.GetSize(); i++ )
+        CPPUNIT_ASSERT_EQUAL( expected[i], data[i] );
+
+
+    // Test more complicated array
+    expected.Clear();
+    expected.push_back( static_cast<pdf_int64>(0LL) );
+    expected.push_back( PdfName("A") );
+    expected.push_back( PdfName("B") );
+    expected.push_back( PdfName("C") );
+    expected.push_back( static_cast<pdf_int64>(4LL) );
+    expected.push_back( PdfName("D") );
+    expected.push_back( PdfName("E") );
+    expected.push_back( static_cast<pdf_int64>(9LL) );
+    expected.push_back( PdfName("F") );
+    expected.push_back( static_cast<pdf_int64>(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( expected.GetSize(), data.GetSize() );
+    for( unsigned int i=0;i<data.GetSize(); i++ )
+        CPPUNIT_ASSERT_EQUAL( expected[i], data[i] );
+
+
+    // Test if contains works correctly
+    PdfName name;
+    pdf_utf16be value;
+    CPPUNIT_ASSERT_EQUAL( true, difference.Contains( 0, name, value ) );
+    CPPUNIT_ASSERT_EQUAL( PdfName("A"), name ); 
+#ifdef PODOFO_IS_LITTLE_ENDIAN
+    CPPUNIT_ASSERT_EQUAL( 0x4100, static_cast<int>(value) ); 
+#else
+    CPPUNIT_ASSERT_EQUAL( 0x0041, static_cast<int>(value) ); 
+#endif //PODOFO_IS_LITTLE_ENDIAN
+
+    CPPUNIT_ASSERT_EQUAL( true, difference.Contains( 9, name, value ) );
+    CPPUNIT_ASSERT_EQUAL( PdfName("F"), name ); 
+#ifdef PODOFO_IS_LITTLE_ENDIAN
+    CPPUNIT_ASSERT_EQUAL( 0x4600, static_cast<int>(value) ); 
+#else
+    CPPUNIT_ASSERT_EQUAL( 0x0046, static_cast<int>(value) ); 
+#endif //PODOFO_IS_LITTLE_ENDIAN
+
+    CPPUNIT_ASSERT_EQUAL( true, difference.Contains( 255, name, value ) );
+    CPPUNIT_ASSERT_EQUAL( PdfName("X"), name ); 
+#ifdef PODOFO_IS_LITTLE_ENDIAN
+    CPPUNIT_ASSERT_EQUAL( 0x5800, static_cast<int>(value) ); 
+#else
+    CPPUNIT_ASSERT_EQUAL( 0x0058, static_cast<int>(value) ); 
+#endif //PODOFO_IS_LITTLE_ENDIAN
+
+    CPPUNIT_ASSERT_EQUAL( false, difference.Contains( 100, name,value ) );
+   
+}
+
+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( PdfName("MacRomanEncoding"), pBase->GetName() );
+    
+    // Test differences
+    PdfObject* pDiff = pEncoding->GetDictionary().GetKey( PdfName("Differences" ) );
+    PdfArray   expected;
+
+    expected.push_back( static_cast<pdf_int64>(1LL) );
+    expected.push_back( PdfName("B") );
+    expected.push_back( PdfName("C") );
+    expected.push_back( static_cast<pdf_int64>(4LL) );
+    expected.push_back( PdfName("D") );
+    expected.push_back( PdfName("E") );
+    expected.push_back( static_cast<pdf_int64>(9LL) );
+    expected.push_back( PdfName("F") );
+
+    const PdfArray & data = pDiff->GetArray();
+    CPPUNIT_ASSERT_EQUAL( expected.GetSize(), data.GetSize() );
+    for( unsigned int i=0;i<data.GetSize(); i++ )
+        CPPUNIT_ASSERT_EQUAL( expected[i], data[i] );
+}
+
+void EncodingTest::testDifferencesEncoding()
+{
+    PdfMemDocument doc;
+
+    // Create a differences encoding where A and B are exchanged
+    PdfEncodingDifference difference;
+    difference.AddDifference( 0x0041, 0, PdfName("B") );
+    difference.AddDifference( 0x0042, 0, PdfName("A") );
+    difference.AddDifference( 0x0043, 0, PdfName("D") );
+
+    PdfDifferenceEncoding encoding( difference, PdfDifferenceEncoding::eBaseEncoding_WinAnsi, &doc );
+
+    PdfString unicodeStr = encoding.ConvertToUnicode( PdfString("BAABC"), NULL );
+    CPPUNIT_ASSERT_EQUAL( PdfString("ABBAD"), unicodeStr );
+
+    PdfRefCountedBuffer encodingStr = encoding.ConvertToEncoding( PdfString("ABBAD"), NULL );
+    CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(5), encodingStr.GetSize() );
+    CPPUNIT_ASSERT_EQUAL( 0, memcmp("BAABC", encodingStr.GetBuffer(), encodingStr.GetSize()) );
+}
+
+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<pdf_utf16be>(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 too many duplicates...
+            //CPPUNIT_ASSERT_EQUAL_MESSAGE( name.GetName(), id, static_cast<pdf_utf16be>(i) );
+            if( id == static_cast<pdf_utf16be>(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, true, ret );
+
+    PdfMacRomanEncoding cMacRomanEncoding;
+    ret = outofRangeHelper( &cMacRomanEncoding, msg, "PdfMacRomanEncoding" );
+    CPPUNIT_ASSERT_EQUAL_MESSAGE( msg, true, ret );
+
+    PdfIdentityEncoding cIdentityEncoding;
+    ret = outofRangeHelper( &cIdentityEncoding, msg, "PdfIdentityEncoding" );
+    CPPUNIT_ASSERT_EQUAL_MESSAGE( msg, true, ret );
+
+    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, true, ret );
+
+#ifdef PODOFO_IS_LITTLE_ENDIAN
+    CPPUNIT_ASSERT_EQUAL( static_cast<pdf_utf16be>(0x4200), cDifferenceEncoding.GetCharCode( 0x0041 ) );
+    CPPUNIT_ASSERT_EQUAL( static_cast<pdf_utf16be>(0x4100), cDifferenceEncoding.GetCharCode( 0x0042 ) );
+#else
+    CPPUNIT_ASSERT_EQUAL( static_cast<pdf_utf16be>(0x0042), cDifferenceEncoding.GetCharCode( 0x0041 ) );
+    CPPUNIT_ASSERT_EQUAL( static_cast<pdf_utf16be>(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<const pdf_utf16be *>( 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] );
+    }
+    
+    const char* toUnicodeInvalidTests[] =
+    {
+        // missing object numbers
+        "beginbfrange\n",
+        "beginbfchar\n",
+
+        // invalid hex digits
+        "2 beginbfrange <WXYZ> endbfrange\n",
+        "2 beginbfrange <-123> endbfrange\n",
+        "2 beginbfrange <<00>> endbfrange\n",
+
+        // missing hex digits
+        "2 beginbfrange <> endbfrange\n",
+        
+        // empty array
+        "2 beginbfrange [] endbfrange\n",
+
+        NULL
+    };
+    
+    for ( size_t i = 0 ; toUnicodeInvalidTests[i] != NULL ; ++i )
+    {
+        try
+        {
+            PdfVecObjects vecInvalid;
+            PdfObject *strmInvalidObject;
+            
+            vec.SetAutoDelete( true );
+            
+            strmInvalidObject = vecInvalid.CreateObject( PdfVariant( PdfDictionary() ) );
+            strmInvalidObject->GetStream()->Set( toUnicodeInvalidTests[i], strlen( toUnicodeInvalidTests[i] ) );
+            
+            PdfIdentityEncoding encodingTestInvalid(0x0001, 0x000F, true, strmInvalidObject);
+            
+            PdfString unicodeStringTestInvalid = encoding.ConvertToUnicode( PdfString( encodedStr ), NULL );
+            
+            // exception not thrown - should never get here
+            // TODO not all invalid input throws an exception (e.g. no hex digits in <WXYZ>)
+            //CPPUNIT_ASSERT( false );
+        }
+        catch ( PoDoFo::PdfError& error )
+        {
+            // parsing every invalid test string should throw an exception
+            CPPUNIT_ASSERT( true );
+        }
+        catch( std::exception& ex )
+        {
+            CPPUNIT_FAIL( "Unexpected exception type" );
+        }
+    }
+}
+
+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;
+}
diff --git a/test/unit/EncodingTest.h b/test/unit/EncodingTest.h
new file mode 100644 (file)
index 0000000..29cdd30
--- /dev/null
@@ -0,0 +1,61 @@
+/***************************************************************************
+ *   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 <cppunit/extensions/HelperMacros.h>
+
+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_
+
+
diff --git a/test/unit/EncryptTest.cpp b/test/unit/EncryptTest.cpp
new file mode 100644 (file)
index 0000000..3634fe6
--- /dev/null
@@ -0,0 +1,397 @@
+/***************************************************************************
+ *   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 <stdlib.h>
+
+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<char*>(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 PODOFO_HAVE_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 // PODOFO_HAVE_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[nOutputLen];
+
+    // Encrypt buffer
+    try {
+        pEncrypt->Encrypt( reinterpret_cast<unsigned char*>(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 PODOFO_HAVE_OPENSSL_NO_RC4
+    CPPUNIT_ASSERT( PdfEncrypt::IsEncryptionEnabled( PdfEncrypt::ePdfEncryptAlgorithm_RC4V1 ) );
+    CPPUNIT_ASSERT( PdfEncrypt::IsEncryptionEnabled( PdfEncrypt::ePdfEncryptAlgorithm_RC4V2 ) );
+#endif // PODOFO_HAVE_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
+
+    int testAlgorithms = PdfEncrypt::ePdfEncryptAlgorithm_AESV2;
+#ifndef PODOFO_HAVE_OPENSSL_NO_RC4
+    testAlgorithms |= PdfEncrypt::ePdfEncryptAlgorithm_RC4V1 | PdfEncrypt::ePdfEncryptAlgorithm_RC4V2;
+#endif // PODOFO_HAVE_OPENSSL_NO_RC4
+#ifdef PODOFO_HAVE_LIBIDN
+    testAlgorithms |= PdfEncrypt::ePdfEncryptAlgorithm_AESV3;
+#endif // PODOFO_HAVE_LIBIDN
+    CPPUNIT_ASSERT_EQUAL( testAlgorithms, PdfEncrypt::GetEnabledEncryptionAlgorithms() );
+
+    // Disable AES
+#ifndef PODOFO_HAVE_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 // PODOFO_HAVE_OPENSSL_NO_RC4
+    CPPUNIT_ASSERT( !PdfEncrypt::IsEncryptionEnabled( PdfEncrypt::ePdfEncryptAlgorithm_AESV2 ) );
+
+#ifndef PODOFO_HAVE_OPENSSL_NO_RC4
+    CPPUNIT_ASSERT_EQUAL( PdfEncrypt::ePdfEncryptAlgorithm_RC4V1 |
+                          PdfEncrypt::ePdfEncryptAlgorithm_RC4V2,
+                          PdfEncrypt::GetEnabledEncryptionAlgorithms() );
+#endif // PODOFO_HAVE_OPENSSL_NO_RC4
+
+
+    PdfObject object;
+    object.GetDictionary().AddKey(PdfName("Filter"), PdfName("Standard"));
+    object.GetDictionary().AddKey(PdfName("V"), static_cast<pdf_int64>(4L));
+    object.GetDictionary().AddKey(PdfName("R"), static_cast<pdf_int64>(4L));
+    object.GetDictionary().AddKey(PdfName("P"), static_cast<pdf_int64>(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<unsigned char*>(pEncBuffer), lLen );
+    printf("Decrypted buffer: %s\n", pEncBuffer );
+    */
+
diff --git a/test/unit/EncryptTest.h b/test/unit/EncryptTest.h
new file mode 100644 (file)
index 0000000..fe6324c
--- /dev/null
@@ -0,0 +1,97 @@
+/***************************************************************************
+ *   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 <podofo.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+namespace PoDoFo {
+    class PdfEncrypt;
+}
+
+/** This test tests the class PdfString
+ */
+class EncryptTest : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE( EncryptTest );
+  CPPUNIT_TEST( testDefault );
+#ifndef PODOFO_HAVE_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 // PODOFO_HAVE_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 PODOFO_HAVE_OPENSSL_NO_RC4
+  void testRC4();
+  void testRC4v2_40();
+  void testRC4v2_56();
+  void testRC4v2_80();
+  void testRC4v2_96();
+  void testRC4v2_128();
+#endif // PODOFO_HAVE_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;
+  PoDoFo::pdf_long m_lLen;
+  int   m_protection;
+  
+};
+
+#endif // _ENCRYPT_TEST_H_
+
+
diff --git a/test/unit/FilterTest.cpp b/test/unit/FilterTest.cpp
new file mode 100644 (file)
index 0000000..850cb71
--- /dev/null
@@ -0,0 +1,141 @@
+/***************************************************************************
+ *   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 <cppunit/Asserter.h>
+
+#include <stdlib.h>
+
+// prefer std::unique_ptr over std::auto_ptr
+#ifdef PODOFO_HAVE_UNIQUE_PTR
+#define PODOFO_UNIQUEU_PTR std::unique_ptr
+#else
+#define PODOFO_UNIQUEU_PTR std::auto_ptr
+#endif
+
+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<char>(0xFE), 0x6B, static_cast<char>(0x80), 0x45, 0x32, static_cast<char>(0x88), 0x12, static_cast<char>(0x71), static_cast<char>(0xEA), 0x01,
+    0x01, 0x64, 0x65, static_cast<char>(0xFE), 0x6B, static_cast<char>(0x80), 0x45, 0x32, static_cast<char>(0x88), 0x12, static_cast<char>(0x71), static_cast<char>(0xEA), 0x03,
+    0x01, 0x64, 0x65, static_cast<char>(0xFE), 0x6B, static_cast<char>(0x80), 0x45, 0x32, static_cast<char>(0x88), 0x12, static_cast<char>(0x71), static_cast<char>(0xEA), 0x02,
+    0x01, 0x64, 0x65, static_cast<char>(0xFE), 0x6B, static_cast<char>(0x80), 0x45, 0x32, static_cast<char>(0x88), 0x12, static_cast<char>(0x71), static_cast<char>(0xEA), 0x00,
+    0x01, 0x64, 0x65, static_cast<char>(0xFE), 0x6B, static_cast<char>(0x80), 0x45, 0x32, static_cast<char>(0x88), 0x12, static_cast<char>(0x71), static_cast<char>(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;
+   
+    PODOFO_UNIQUEU_PTR<PdfFilter> 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<long>(lTestLength), static_cast<long>(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<EPdfFilter>(i), s_pTestBuffer1, s_lTestLength1 );
+        TestFilter( static_cast<EPdfFilter>(i), s_pTestBuffer2, s_lTestLength2 );
+    }
+}
+
+void FilterTest::testCCITT()
+{
+    PODOFO_UNIQUEU_PTR<PdfFilter> pFilter( PdfFilterFactory::Create( ePdfFilter_CCITTFaxDecode ) );
+    if( !pFilter.get() )
+    {
+        printf("!!! ePdfFilter_CCITTFaxDecode not implemented skipping test!\n");
+        return;
+    }
+
+
+}
diff --git a/test/unit/FilterTest.h b/test/unit/FilterTest.h
new file mode 100644 (file)
index 0000000..235a1d6
--- /dev/null
@@ -0,0 +1,51 @@
+/***************************************************************************
+ *   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 <cppunit/extensions/HelperMacros.h>
+
+#include <podofo.h>
+
+/** 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_
+
+
diff --git a/test/unit/FontTest.cpp b/test/unit/FontTest.cpp
new file mode 100644 (file)
index 0000000..b2d30f6
--- /dev/null
@@ -0,0 +1,191 @@
+/***************************************************************************
+ *   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 <cppunit/Asserter.h>
+
+#include <ft2build.h>
+#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 ) 
+        {
+            try
+            {
+                // 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 );
+            }
+            catch( PdfError &error )
+            {
+                if( error.GetError() == ePdfError_UnsupportedFontFormat )
+                {
+                    printf("Unsupported font format: %s\n", sPodofoFontPath.c_str());
+                }
+                else
+                {
+                    throw error;
+                }
+            }
+        }
+        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<char*>(family);
+        if( FcPatternGetString(pFont, FC_FILE, 0, &file) == FcResultMatch )
+        {
+            rsPath = reinterpret_cast<char*>(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
diff --git a/test/unit/FontTest.h b/test/unit/FontTest.h
new file mode 100644 (file)
index 0000000..f69c92c
--- /dev/null
@@ -0,0 +1,69 @@
+/***************************************************************************
+ *   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 <cppunit/extensions/HelperMacros.h>
+
+#include <podofo.h>
+
+#if defined(PODOFO_HAVE_FONTCONFIG)
+#include <fontconfig/fontconfig.h>
+#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_
+
+
diff --git a/test/unit/NameTest.cpp b/test/unit/NameTest.cpp
new file mode 100644 (file)
index 0000000..b0c22ed
--- /dev/null
@@ -0,0 +1,190 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+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  );
+}
diff --git a/test/unit/NameTest.h b/test/unit/NameTest.h
new file mode 100644 (file)
index 0000000..ffcfc88
--- /dev/null
@@ -0,0 +1,69 @@
+/***************************************************************************
+ *   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 <cppunit/extensions/HelperMacros.h>
+
+/** 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_
+
+
diff --git a/test/unit/PageTest.cpp b/test/unit/PageTest.cpp
new file mode 100644 (file)
index 0000000..aa352e2
--- /dev/null
@@ -0,0 +1,78 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+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<PdfObject*> 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() );
+}
+
diff --git a/test/unit/PageTest.h b/test/unit/PageTest.h
new file mode 100644 (file)
index 0000000..161307c
--- /dev/null
@@ -0,0 +1,49 @@
+/***************************************************************************
+ *   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 <cppunit/extensions/HelperMacros.h>
+
+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_
+
+
diff --git a/test/unit/PagesTreeTest.cpp b/test/unit/PagesTreeTest.cpp
new file mode 100644 (file)
index 0000000..f8f4e31
--- /dev/null
@@ -0,0 +1,599 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+#include <sstream>
+
+#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<PdfPage*>(NULL) );
+
+    pPage = writer.GetPagesTree()->GetPage( -1 );
+    CPPUNIT_ASSERT_EQUAL( pPage, static_cast<PdfPage*>(NULL) );
+
+    pPage = writer.GetPagesTree()->GetPage( 1 );
+    CPPUNIT_ASSERT_EQUAL( pPage, static_cast<PdfPage*>(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::testCyclicTree()
+{
+    for (int pass=0; pass < 2; pass++)
+    {
+        PdfMemDocument doc;
+        CreateCyclicTree( doc, pass==1);
+        //doc.Write(pass==0?"tree_valid.pdf":"tree_cyclic.pdf");
+        for (int pagenum=0; pagenum < doc.GetPageCount(); pagenum++)
+        {
+            if (pass==0)
+            {    
+                // pass 0:
+                // valid tree without cycles should yield all pages
+                PdfPage* pPage = doc.GetPage( pagenum );
+                CPPUNIT_ASSERT_EQUAL( pPage != NULL, true );
+                CPPUNIT_ASSERT_EQUAL( IsPageNumber( pPage, pagenum ), true );
+            }
+            else
+            {
+                // pass 1:
+                // cyclic tree must throw exception to prevent infinite recursion
+                CPPUNIT_ASSERT_THROW( doc.GetPage( pagenum ), PdfError );
+            }
+        }
+    }
+}
+
+void PagesTreeTest::testEmptyKidsTree()
+{
+    PdfMemDocument doc;
+    CreateEmptyKidsTree(doc);
+    //doc.Write("tree_zerokids.pdf");
+    for (int pagenum=0; pagenum < doc.GetPageCount(); pagenum++)
+    {
+        PdfPage* pPage = doc.GetPage( pagenum );
+        CPPUNIT_ASSERT_EQUAL( pPage != NULL, true );
+        CPPUNIT_ASSERT_EQUAL( IsPageNumber( pPage, pagenum ), true );
+    }
+}
+
+void PagesTreeTest::testNestedArrayTree()
+{
+    PdfMemDocument doc;
+    CreateNestedArrayTree(doc);
+    //doc.Write("tree_nested_array.pdf");
+    for (int pagenum=0; pagenum < doc.GetPageCount(); pagenum++)
+    {
+        PdfPage* pPage = doc.GetPage( pagenum );
+        CPPUNIT_ASSERT_EQUAL( pPage == NULL, true );
+    }
+}
+
+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; i<PODOFO_TEST_NUM_PAGES; 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=0; i<PODOFO_TEST_NUM_PAGES - 1; i++) 
+    {
+        PdfPage* pPage = doc.GetPage( i );
+
+        CPPUNIT_ASSERT_EQUAL( pPage != NULL, true );
+        
+        CPPUNIT_ASSERT_EQUAL( IsPageNumber( pPage, i + 1 ), true );
+    }
+
+    // Now delete any page
+    const int DELETED_PAGE = 50;
+    doc.GetPagesTree()->DeletePage( DELETED_PAGE );
+
+    for(int i=0; i<PODOFO_TEST_NUM_PAGES - 2; i++) 
+    {
+        PdfPage* pPage = doc.GetPage( i );
+
+        CPPUNIT_ASSERT_EQUAL( pPage != NULL, true );
+        
+        if( i < DELETED_PAGE )
+        {
+            CPPUNIT_ASSERT_EQUAL( IsPageNumber( pPage, i + 1 ), true );
+        }
+        else
+        {
+            CPPUNIT_ASSERT_EQUAL( IsPageNumber( pPage, i + 2 ), true );
+        }
+    }
+}
+
+void PagesTreeTest::testGetPagesReverseCustom() 
+{
+    PdfMemDocument doc;
+    
+    CreateTestTreeCustom( doc );
+
+    testGetPagesReverse( doc );
+}
+
+void PagesTreeTest::testGetPagesReversePoDoFo() 
+{
+    PdfMemDocument doc;
+    
+    CreateTestTreePoDoFo( doc );
+
+    testGetPagesReverse( doc );
+}
+
+void PagesTreeTest::testGetPagesReverse( PdfMemDocument & doc ) 
+{
+    for(int i=PODOFO_TEST_NUM_PAGES-1; 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<pdf_int64>(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<pdf_int64>(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<pdf_int64>(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; i<PODOFO_TEST_NUM_PAGES; i++) 
+    {
+        doc.GetPagesTree()->DeletePage(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; i<PODOFO_TEST_NUM_PAGES; i++) 
+    {
+        PdfPage* pPage = rDoc.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) );
+        pPage->GetObject()->GetDictionary().AddKey( PODOFO_TEST_PAGE_KEY, static_cast<pdf_int64>(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; z<COUNT; z++) 
+    {
+        PdfObject* pNode = rDoc.GetObjects().CreateObject("Pages");
+        PdfArray nodeKids;
+
+        for(int i=0; i<COUNT; i++) 
+        {
+            PdfPage* pPage = new PdfPage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ),
+                                          &(rDoc.GetObjects()) );
+            pPage->GetObject()->GetDictionary().AddKey( PODOFO_TEST_PAGE_KEY, 
+                                                        static_cast<pdf_int64>(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<pdf_int64>(COUNT) );
+        rootKids.push_back( pNode->Reference() );
+    }
+
+    pRoot->GetDictionary().AddKey( PdfName("Kids"), rootKids );
+    pRoot->GetDictionary().AddKey( PdfName("Count"), static_cast<pdf_int64>(PODOFO_TEST_NUM_PAGES) );
+}
+
+std::vector<PdfPage*> PagesTreeTest::CreateSamplePages( PdfMemDocument & rDoc,
+                                                        int nPageCount)
+{
+    PdfFont* pFont;
+
+    // create font
+    pFont = rDoc.CreateFont( "Arial" );
+    if( !pFont )
+    {
+        PODOFO_RAISE_ERROR( ePdfError_InvalidHandle );
+    }
+    pFont->SetFontSize( 16.0 );
+
+    std::vector<PdfPage*> pPage(nPageCount);
+    for (int i = 0; i < nPageCount; ++i)
+    {
+        pPage[i] = new PdfPage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ),
+                                &(rDoc.GetObjects()) );
+        pPage[i]->GetObject()->GetDictionary().AddKey( PODOFO_TEST_PAGE_KEY, 
+                                                       static_cast<pdf_int64>(i) );
+
+        PdfPainter painter;
+        painter.SetPage( pPage[i] );
+        painter.SetFont( pFont );
+        std::ostringstream os;
+        os << "Page " << i+1;
+        painter.DrawText( 200, 200, os.str()  );
+        painter.FinishPage();
+    }
+
+    return pPage;
+}
+
+std::vector<PdfObject*> PagesTreeTest::CreateNodes( PdfMemDocument & rDoc,
+                                                    int nNodeCount)
+{
+    std::vector<PdfObject*> pNode(nNodeCount);
+
+    for (int i = 0; i < nNodeCount; ++i)
+    {
+        pNode[i]=rDoc.GetObjects().CreateObject("Pages");
+        // init required keys
+        pNode[i]->GetDictionary().AddKey( "Kids", PdfArray());
+        pNode[i]->GetDictionary().AddKey( "Count", PdfVariant(static_cast<pdf_int64>(0L)));
+    }
+
+    return pNode;
+}
+
+void PagesTreeTest::CreateCyclicTree( PoDoFo::PdfMemDocument & rDoc,
+                                      bool bCreateCycle )
+{
+    const int COUNT = 3;
+
+    std::vector<PdfPage*> pPage=CreateSamplePages( rDoc, COUNT );
+    std::vector<PdfObject*> pNode=CreateNodes( rDoc, 2 );
+    
+    // manually insert pages into pagetree
+    PdfObject* pRoot = rDoc.GetPagesTree()->GetObject();
+
+    // tree layout (for !bCreateCycle):
+    //
+    //    root
+    //    +-- node0
+    //        +-- node1
+    //        |   +-- page0
+    //        |   +-- page1
+    //        \-- page2
+
+    // root node
+    AppendChildNode(pRoot, pNode[0]);
+
+    // tree node 0
+    AppendChildNode(pNode[0], pNode[1]);
+    AppendChildNode(pNode[0], pPage[2]->GetObject());
+
+    // tree node 1
+    AppendChildNode(pNode[1], pPage[0]->GetObject());
+    AppendChildNode(pNode[1], pPage[1]->GetObject());
+
+    if (bCreateCycle)
+    {
+        // invalid tree: Cycle!!!
+        // was not detected in PdfPagesTree::GetPageNode() rev. 1937
+        pNode[0]->GetIndirectKey("Kids")->GetArray()[0]=pRoot->Reference();
+    }
+}
+
+void PagesTreeTest::CreateEmptyKidsTree( PoDoFo::PdfMemDocument & rDoc )
+{
+    const int COUNT = 3;
+
+    std::vector<PdfPage*> pPage=CreateSamplePages( rDoc, COUNT );
+    std::vector<PdfObject*> pNode=CreateNodes( rDoc, 3 );
+    
+    // manually insert pages into pagetree
+    PdfObject* pRoot = rDoc.GetPagesTree()->GetObject();
+    
+    // tree layout:
+    //
+    //    root
+    //    +-- node0
+    //    |   +-- page0
+    //    |   +-- page1
+    //    |   +-- page2
+    //    +-- node1
+    //    \-- node2
+
+    // root node
+    AppendChildNode(pRoot, pNode[0]);
+    AppendChildNode(pRoot, pNode[1]);
+    AppendChildNode(pRoot, pNode[2]);
+    
+    // tree node 0
+    AppendChildNode(pNode[0], pPage[0]->GetObject());
+    AppendChildNode(pNode[0], pPage[1]->GetObject());
+    AppendChildNode(pNode[0], pPage[2]->GetObject());
+
+    // tree node 1 and node 2 are left empty: this is completely valid
+    // according to the PDF spec, i.e. the required keys may have the
+    // values "/Kids [ ]" and "/Count 0"
+}
+
+void PagesTreeTest::CreateNestedArrayTree( PoDoFo::PdfMemDocument & rDoc )
+{
+    const int COUNT = 3;
+
+    std::vector<PdfPage*> pPage=CreateSamplePages( rDoc, COUNT );
+    PdfObject* pRoot = rDoc.GetPagesTree()->GetObject();
+
+    // create kids array
+    PdfArray kids;
+    for (int i=0; i < COUNT; i++)
+    {
+        kids.push_back( pPage[i]->GetObject()->Reference() );
+        pPage[i]->GetObject()->GetDictionary().AddKey( PdfName("Parent"), pRoot->Reference());
+    }
+
+    // create nested kids array
+    PdfArray nested;
+    nested.push_back(kids);
+
+    // manually insert pages into pagetree
+    pRoot->GetDictionary().AddKey( PdfName("Count"), static_cast<pdf_int64>(COUNT) );
+    pRoot->GetDictionary().AddKey( PdfName("Kids"), nested);
+}
+
+bool PagesTreeTest::IsPageNumber( PoDoFo::PdfPage* pPage, int nNumber )
+{
+    pdf_int64 lPageNumber = pPage->GetObject()->GetDictionary().GetKeyAsLong( PODOFO_TEST_PAGE_KEY, -1 );
+
+    if( lPageNumber != static_cast<pdf_int64>(nNumber) )
+    {
+        printf("PagesTreeTest: Expected page number %i but got %" PDF_FORMAT_INT64 ".\n", nNumber, lPageNumber);
+        return false;
+    }
+    else
+        return true;
+}
+
+void PagesTreeTest::AppendChildNode(PdfObject* pParent, PdfObject* pChild)
+{
+    // 1. Add the reference of the new child to the kids array of pParent
+    PdfArray kids;
+    PdfObject* oldKids=pParent->GetIndirectKey("Kids");
+    if (oldKids && oldKids->IsArray()) kids=oldKids->GetArray();
+    kids.push_back(pChild->Reference());
+    pParent->GetDictionary().AddKey( PdfName("Kids"), kids);
+
+    // 2. If the child is a page (leaf node), increase count of every parent
+    //    (which also includes pParent)
+    if( pChild->GetDictionary().GetKeyAsName( PdfName( "Type" ) )
+        == PdfName( "Page" ) )
+    {
+        PdfObject* node=pParent;
+        while (node)
+        {
+            pdf_int64 count=0;
+            if (node->GetIndirectKey("Count")) count=node->GetIndirectKey("Count")->GetNumber();
+            count++;
+            node->GetDictionary().AddKey( PdfName("Count"), count);
+            
+            node=node->GetIndirectKey("Parent");
+        }
+    }
+    
+    // 3. Add Parent key to the child
+    pChild->GetDictionary().AddKey( PdfName("Parent"), pParent->Reference());
+}
diff --git a/test/unit/PagesTreeTest.h b/test/unit/PagesTreeTest.h
new file mode 100644 (file)
index 0000000..dd3edc0
--- /dev/null
@@ -0,0 +1,166 @@
+/***************************************************************************
+ *   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 <vector>
+
+#include <cppunit/extensions/HelperMacros.h>
+
+namespace PoDoFo {
+class PdfMemDocument;
+class PdfPage;
+class PdfObject;
+};
+
+/** This test tests the class PdfPagesTree
+ */
+class PagesTreeTest : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE( PagesTreeTest );
+  CPPUNIT_TEST( testEmptyTree );
+  CPPUNIT_TEST( testEmptyDoc );
+  CPPUNIT_TEST( testCyclicTree );
+  CPPUNIT_TEST( testEmptyKidsTree );
+  CPPUNIT_TEST( testNestedArrayTree );
+  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 testCyclicTree();
+  void testEmptyKidsTree();
+  void testNestedArrayTree();
+  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 );
+
+  /**
+   * Create a pages tree with cycles to test prevention of endless
+   * recursion as mentioned in different CVE reports.
+   *
+   * \param bCreateCycle if true a cyclic tree is created, otherwise a
+   *                     valid tree without cycles
+   */
+  void CreateCyclicTree( PoDoFo::PdfMemDocument & rDoc,
+                         bool bCreateCycle );
+
+  /**
+   * Create a pages tree with nodes containing empty kids.
+   *
+   * This is completely valid according to the PDF spec, i.e. the
+   * required keys may have the values "/Kids [ ]" and "/Count 0"
+   * Such a tree must still be parsable by a conforming reader:
+   *
+   * <BLOCKQUOTE>The tree contains nodes of two types—intermediate
+   * nodes, called page tree nodes, and leaf nodes, called page
+   * objects—whose form is described in the subsequent subclauses.
+   * Conforming products shall be prepared to handle any form
+   * of tree structure built of such nodes.</BLOCKQUOTE>
+   */
+  void CreateEmptyKidsTree( PoDoFo::PdfMemDocument & rDoc );
+  
+  /**
+  * Ceate a pages tree with a nested kids array.
+  *
+  * Such a tree is not valid to the PDF spec, which requires they key
+  * "Kids" to be an array of indirect references. And the children shall
+  * only be page objects or other page tree nodes.
+  */
+  void CreateNestedArrayTree( PoDoFo::PdfMemDocument & rDoc );
+
+ /**
+  * Create page object nodes (leaf nodes),
+  * where every page object has an additional
+  * key PoDoFoTestPageNumber with the original 
+  * page number of the page.
+  */  
+  std::vector<PoDoFo::PdfPage*> CreateSamplePages( PoDoFo::PdfMemDocument & rDoc,
+                                                   int nPageCount);
+
+  /**
+  * Create page tree nodes (internal nodes)
+  */
+  std::vector<PoDoFo::PdfObject*> CreateNodes( PoDoFo::PdfMemDocument & rDoc,
+                                               int nNodeCount);
+
+  bool IsPageNumber( PoDoFo::PdfPage* pPage, int nNumber );
+
+  void AppendChildNode(PoDoFo::PdfObject* pParent, PoDoFo::PdfObject* pChild);
+};
+
+#endif // _PAGES_TREE_TEST_H_
+
+
diff --git a/test/unit/PainterTest.cpp b/test/unit/PainterTest.cpp
new file mode 100644 (file)
index 0000000..c9001ea
--- /dev/null
@@ -0,0 +1,72 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+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());
+}
diff --git a/test/unit/PainterTest.h b/test/unit/PainterTest.h
new file mode 100644 (file)
index 0000000..dae4a48
--- /dev/null
@@ -0,0 +1,60 @@
+/***************************************************************************
+ *   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 <cppunit/extensions/HelperMacros.h>
+
+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_
diff --git a/test/unit/ParserTest.cpp b/test/unit/ParserTest.cpp
new file mode 100644 (file)
index 0000000..2c7936d
--- /dev/null
@@ -0,0 +1,2112 @@
+/***************************************************************************
+ *   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.             *
+ ***************************************************************************/
+
+/* 
+    Notes: 
+
+    1) out of memory tests don't run if Address Santizer (ASAN) is enabled because
+       ASAN terminates the unit test process the first time it attempts to allocate
+       too much memory (so running the tests with and without ASAN is recommended)
+
+    2) PoDoFo log warnings about inconsistencies or values out of range are expected
+       because the tests are supplying invalid values to check PoDoFo behaves correctly 
+       in those situations
+*/
+
+#include "ParserTest.h"
+
+#include <cppunit/Asserter.h>
+
+#if defined( __APPLE__ )
+#include <sys/resource.h>
+#endif
+
+#include <limits>
+
+CPPUNIT_TEST_SUITE_REGISTRATION( ParserTest );
+
+// this value is from Table C.1 in Appendix C.2 Architectural Limits in PDF 32000-1:2008
+// on 32-bit systems sizeof(PoDoFo::PdfParser::TXRefEntry)=16 => max size of m_offsets=16*8,388,607 = 134 MB
+// on 64-bit systems sizeof(PoDoFo::PdfParser::TXRefEntry)=24 => max size of m_offsets=16*8,388,607 = 201 MB
+const long maxNumberOfIndirectObjects = 8388607;    
+
+class PdfParserTestWrapper : public PoDoFo::PdfParser
+{
+public:
+    PdfParserTestWrapper( PoDoFo::PdfVecObjects* pVecObjects, const char* pBuffer, long lLen )
+    : PoDoFo::PdfParser( pVecObjects )
+    {
+        // sets up parser ready to read pBuffer
+        m_device = PoDoFo::PdfRefCountedInputDevice( pBuffer, lLen );
+    }
+
+    void SetupTrailer()
+    {
+        // this creates m_pTrailer
+        PoDoFo::PdfParser::ReadTrailer();
+    }
+    
+    PoDoFo::PdfRefCountedInputDevice& GetDevice() { return m_device; }
+    PoDoFo::PdfRefCountedBuffer&      GetBuffer() { return m_buffer; }
+
+    void ReadXRefContents( PoDoFo::pdf_long lOffset, bool bPositionAtEnd )
+    {
+        // call protected method
+        PoDoFo::PdfParser::ReadXRefContents( lOffset, bPositionAtEnd );
+    }
+
+    void ReadXRefSubsection( PoDoFo::pdf_int64 nFirstObject, PoDoFo::pdf_int64 nNumObjects )
+    {
+        // call protected method
+        PoDoFo::PdfParser::ReadXRefSubsection( nFirstObject, nNumObjects );
+    }
+
+    void ReadXRefStreamContents( PoDoFo::pdf_long lOffset, bool bReadOnlyTrailer )
+    {
+        // call protected method
+        PoDoFo::PdfParser::ReadXRefStreamContents( lOffset, bReadOnlyTrailer );        
+    }
+
+    void ReadObjects()
+    {
+        // call protected method
+        PoDoFo::PdfParser::ReadObjects();
+    }
+
+    void ReadTrailer()
+    {
+        // call protected method
+        PoDoFo::PdfParser::ReadTrailer();
+    }
+    
+    bool IsPdfFile()
+    {
+        // call protected method
+        return PoDoFo::PdfParser::IsPdfFile();
+    }
+};
+
+void ParserTest::setUp()
+{
+    // Nothing todo here
+}
+
+void ParserTest::tearDown()
+{
+    // Nothing todo here
+}
+
+void ParserTest::testMaxObjectCount()
+{
+    const long defaultObjectCount = PoDoFo::PdfParser::GetMaxObjectCount();
+
+    CPPUNIT_ASSERT( defaultObjectCount == maxNumberOfIndirectObjects );
+        
+    // test methods that use PdfParser::s_nMaxObjects or GetMaxObjectCount
+    // with a range of different maximums
+    PoDoFo::PdfParser::SetMaxObjectCount( std::numeric_limits<long>::max() );
+    testReadXRefSubsection();
+    testReadDocumentStructure();
+
+    PoDoFo::PdfParser::SetMaxObjectCount( maxNumberOfIndirectObjects );
+    testReadXRefSubsection();
+    testReadDocumentStructure();
+
+    PoDoFo::PdfParser::SetMaxObjectCount( std::numeric_limits<short>::max() );
+    testReadXRefSubsection();        
+    testReadDocumentStructure();
+
+    PoDoFo::PdfParser::SetMaxObjectCount( std::numeric_limits<int>::max() );
+    testReadXRefSubsection();        
+    testReadDocumentStructure();
+    
+    PoDoFo::PdfParser::SetMaxObjectCount( std::numeric_limits<long>::max() );
+    testReadXRefSubsection();
+    testReadDocumentStructure();
+
+    PoDoFo::PdfParser::SetMaxObjectCount( defaultObjectCount );
+}
+
+void ParserTest::testReadDocumentStructure()
+{
+    // TODO no tests yet - stub method needed by testMaxObjectCount
+}
+
+void ParserTest::testReadXRefContents()
+{
+    try
+    {
+        // generate an xref section
+        // xref
+        // 0 3
+        // 0000000000 65535 f 
+        // 0000000018 00000 n 
+        // 0000000077 00000 n
+        // trailer << /Root 1 0 R /Size 3 >>
+        // startxref
+        // 0
+        // %%EOF
+        std::ostringstream oss;        
+        oss << "xref\r\n0 3\r\n";
+        oss << generateXRefEntries(3);
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref 0\r\n";
+        oss << "%EOF";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        parser.SetupTrailer();
+        parser.ReadXRefContents( 0, false );
+        // expected to succeed
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_FAIL( "should not throw PdfError" );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }
+
+    try
+    {
+        // generate an xref section with missing xref entries
+        // xref
+        // 0 3
+        // 0000000000 65535 f 
+        // 0000000018 00000 n 
+        // 
+        // trailer << /Root 1 0 R /Size 3 >>
+        // startxref
+        // 0
+        // %%EOF        
+        std::ostringstream oss;        
+        oss << "xref\r\n0 3\r\n";
+        oss << generateXRefEntries(2); // 2 entries supplied, but expecting 3 entries
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref 0\r\n";
+        oss << "%EOF";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        parser.SetupTrailer();
+        parser.ReadXRefContents( 0, false );
+        // expected to succeed
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_FAIL( "should not throw PdfError" );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }
+    
+    try
+    {
+        // TODO malformed entries are not detected
+        // generate an xref section with badly formed xref entries
+        // xref
+        // 0 3        
+        // 000000000 65535
+        // 00000000065535 x
+        // 0000000
+        // 0000000018 00000 n
+        // 0000000077 00000 n        
+        // trailer << /Root 1 0 R /Size 3 >>
+        // startxref
+        // 0
+        // %%EOF
+        std::ostringstream oss;        
+        oss << "xref\r\n0 5\r\n";
+        oss << "000000000 65535\r\n";
+        oss << "00000000065535 x\r\n";
+        oss << "0000000\r\n";
+        oss << generateXRefEntries(2); 
+        oss << "trailer << /Root 1 0 R /Size 5 >>\r\n";
+        oss << "startxref 0\r\n";
+        oss << "%EOF";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        parser.SetupTrailer();
+        parser.ReadXRefContents( 0, false );
+        // succeeds reading badly formed xref entries  - should it?
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }
+
+    // CVE-2017-8053 ReadXRefContents and ReadXRefStreamContents are mutually recursive   
+    // and can cause stack overflow
+
+    try
+    {
+        // generate an xref section and one XRef stream that references itself
+        // via the /Prev entry (but use a slightly lower offset by linking to
+        // to whitespace discarded by the tokenizer just before the xref section)
+        // xref
+        // 0 1
+        // 000000000 65535
+        // 2 0 obj << /Type XRef /Prev offsetXrefStmObj2 >> stream ... endstream
+        // trailer << /Root 1 0 R /Size 3 >>
+        // startxref
+        // offsetXrefStmObj2
+        // %%EOF
+        std::ostringstream oss;
+
+        // object stream contents - length excludes trailing whitespace
+        std::string streamContents = 
+            "01 0E8A 0\r\n"
+            "02 0002 00\r\n";
+        size_t streamContentsLength = streamContents.size() - strlen("\r\n");
+        
+        // xref section at offset 0
+        //size_t offsetXref = 0;
+        oss << "xref\r\n0 1\r\n";
+        oss << generateXRefEntries(1);
+        
+        // XRef stream at offsetXrefStm1, but any /Prev entries pointing to any offet between
+        // offsetXrefStm1Whitespace and offsetXrefStm1 point to the same /Prev section
+        // because the PDF processing model says tokenizer must discard whitespace and comments
+        size_t offsetXrefStm1Whitespace = oss.str().length();
+        oss << "    \r\n";
+        oss << "% comments and leading white space are ignored - see PdfTokenizer::GetNextToken\r\n";
+        size_t offsetXrefStm1 = oss.str().length();
+        oss << "2 0 obj ";
+        oss << "<< /Type /XRef ";
+        oss << "/Length " << streamContentsLength << " ";
+        oss << "/Index [2 2] ";
+        oss << "/Size 3 ";
+        oss << "/Prev " << offsetXrefStm1Whitespace << " ";     // xref /Prev offset points back to start of this stream object
+        oss << "/W [1 2 1] ";
+        oss << "/Filter /ASCIIHexDecode ";
+        oss << ">>\r\n";
+        oss << "stream\r\n";
+        oss << streamContents;
+        oss << "endstream\r\n";
+        oss << "endobj\r\n";
+        
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref " << offsetXrefStm1 << "\r\n";
+        oss << "%EOF";
+        
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        parser.SetupTrailer();
+        parser.ReadXRefContents( offsetXrefStm1, false );
+        // succeeds in current code - should it?
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }
+
+    try
+    {
+        // generate an xref section and two XRef streams that reference each other
+        // via the /Prev entry
+        // xref
+        // 0 1
+        // 000000000 65535
+        // 2 0 obj << /Type XRef /Prev offsetXrefStmObj3 >> stream ...  endstream
+        // 3 0 obj << /Type XRef /Prev offsetXrefStmObj2 >> stream ...  endstream
+        // trailer << /Root 1 0 R /Size 3 >>
+        // startxref
+        // offsetXrefStmObj2
+        // %%EOF
+        std::ostringstream oss;
+
+        // object stream contents - length excludes trailing whitespace
+        std::string streamContents = 
+            "01 0E8A 0\r\n"
+            "02 0002 00\r\n";
+        size_t streamContentsLength = streamContents.size() - strlen("\r\n");
+        
+        // xref section at offset 0
+        //size_t offsetXref = 0;
+        oss << "xref\r\n0 1\r\n";
+        oss << generateXRefEntries(1);
+        
+        // xrefstm at offsetXrefStm1
+        size_t offsetXrefStm1 = oss.str().length();
+        oss << "2 0 obj ";
+        oss << "<< /Type /XRef ";
+        oss << "/Length " << streamContentsLength << " ";
+        oss << "/Index [2 2] ";
+        oss << "/Size 3 ";
+        oss << "/Prev 185 ";     // xref stream 1 sets xref stream 2 as previous in chain
+        oss << "/W [1 2 1] ";
+        oss << "/Filter /ASCIIHexDecode ";
+        oss << ">>\r\n";
+        oss << "stream\r\n";
+        oss << streamContents;
+        oss << "endstream\r\n";
+        oss << "endobj\r\n";
+        
+        // xrefstm at offsetXrefStm2
+        size_t offsetXrefStm2 = oss.str().length();
+        CPPUNIT_ASSERT( offsetXrefStm2 == 185 ); // hard-coded in /Prev entry in XrefStm1 above
+        oss << "3 0 obj ";
+        oss << "<< /Type /XRef ";
+        oss << "/Length " << streamContentsLength << " ";
+        oss << "/Index [2 2] ";
+        oss << "/Size 3 ";
+        oss << "/Prev " << offsetXrefStm1 << " ";     // xref stream 2 sets xref stream 1 as previous in chain
+        oss << "/W [1 2 1] ";
+        oss << "/Filter /ASCIIHexDecode ";
+        oss << ">>\r\n";
+        oss << "stream\r\n";
+        oss << streamContents;
+        oss << "endstream\r\n";
+        oss << "endobj\r\n";
+        
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref " << offsetXrefStm2 << "\r\n";
+        oss << "%EOF";
+        
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        parser.SetupTrailer();
+        parser.ReadXRefContents( offsetXrefStm2, false );
+        // succeeds in current code - should it?
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }
+
+    try
+    {
+        // generate an xref section and lots of XRef streams without loops but reference 
+        // the previous stream via the /Prev entry
+        // xref
+        // 0 1
+        // 000000000 65535
+        // 2 0 obj << /Type XRef >> stream ...  endstream
+        // 3 0 obj << /Type XRef /Prev offsetStreamObj(2) >> stream ...  endstream
+        // 4 0 obj << /Type XRef /Prev offsetStreamObj(3) >> stream ...  endstream
+        // ...
+        // N 0 obj << /Type XRef /Prev offsetStreamObj(N-1) >> stream ...  endstream
+        // trailer << /Root 1 0 R /Size 3 >>
+        // startxref
+        // offsetStreamObj(N)
+        // %%EOF
+        std::ostringstream oss;
+        size_t prevOffset = 0;
+        size_t currentOffset = 0;
+        
+        // object stream contents - length excludes trailing whitespace
+        std::string streamContents = 
+            "01 0E8A 0\r\n"
+            "02 0002 00\r\n";
+        size_t streamContentsLength = streamContents.size() - strlen("\r\n");
+        
+        // xref section at offset 0
+        //size_t offsetXref = 0;
+        oss << "xref\r\n0 1\r\n";
+        oss << generateXRefEntries(1);
+
+        // this caused stack overflow on macOS 64-bit with around 3000 streams
+        // and on Windows 32-bit with around 1000 streams
+        
+        const int maxXrefStreams = 10000;
+        for ( int i = 0 ; i < maxXrefStreams ; ++i )
+        {
+            int objNo = i + 2;
+
+            // xrefstm at currentOffset linked back to stream at prevOffset
+            prevOffset = currentOffset;
+            currentOffset = oss.str().length();
+            oss << objNo << " 0 obj ";
+            oss << "<< /Type /XRef ";
+            oss << "/Length " << streamContentsLength << " ";
+            oss << "/Index [2 2] ";
+            oss << "/Size 3 ";
+            if ( prevOffset > 0 )
+                oss << "/Prev " << prevOffset << " ";
+            oss << "/W [1 2 1] ";
+            oss << "/Filter /ASCIIHexDecode ";
+            oss << ">>\r\n";
+            oss << "stream\r\n";
+            oss << streamContents;
+            oss << "endstream\r\n";
+            oss << "endobj\r\n";
+        }
+        
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref " << currentOffset << "\r\n";
+        oss << "%EOF";
+        
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        parser.SetupTrailer();
+        parser.ReadXRefContents( currentOffset, false );
+        // succeeds in current code - should it?
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }    
+}
+
+void ParserTest::testReadXRefSubsection()
+{
+    PoDoFo::pdf_int64 nFirstObject = 0;
+    PoDoFo::pdf_int64 nNumObjects = 0;
+    
+    // TODO does ReadXRefSubsection with nNumObjects = 0 make sense ???
+
+    // CVE-2017-5855 m_offsets.resize() NULL ptr read
+    // CVE-2017-6844 m_offsets.resize() buffer overwrite 
+    // false positives due to AFL setting allocator_may_return_null=1 which causes
+    // ASAN to return NULL instead of throwing std::bad_alloc for out-of-memory conditions
+    // https://github.com/mirrorer/afl/blob/master/docs/env_variables.txt#L248
+    // https://github.com/google/sanitizers/issues/295#issuecomment-234273218 
+    // the test for CVE-2018-5296 below checks that PoDoFo restricts allocations
+
+    // CVE-2018-5296 m_offsets.resize() malloc failure when large size specified
+    // check PoDoFo throws PdfError and not anything derived from std::exception
+    // check PoDoFo can't allocate unrestricted amounts of memory
+
+    if ( PoDoFo::PdfParser::GetMaxObjectCount() <= maxNumberOfIndirectObjects )
+    {
+        try
+        {
+            std::string strInputStream = generateXRefEntries( PoDoFo::PdfParser::GetMaxObjectCount() );
+            PoDoFo::PdfVecObjects objects;
+            PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+            nFirstObject = 0;
+            nNumObjects = PoDoFo::PdfParser::GetMaxObjectCount();
+            parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+            // expected to succeed
+        }
+        catch ( PoDoFo::PdfError& error )
+        {
+            CPPUNIT_FAIL( "should not throw PdfError" );
+        }
+        catch( std::exception& ex )
+        {
+            CPPUNIT_FAIL( "Unexpected exception type" );
+        }
+    }
+    else
+    {
+        // test has been called from testMaxObjectCount with PoDoFo::PdfParser::SetMaxObjectCount()
+        // set to a large value (large allocs are tested in address space tests below)
+    }
+
+    // don't run the following test if PoDoFo::PdfParser::GetMaxObjectCount()+1 will overflow
+       // in the numXRefEntries calculation below (otherwise we get an ASAN error)
+    if ( PoDoFo::PdfParser::GetMaxObjectCount() < std::numeric_limits<long>::max() )
+    {
+               // don't generate xrefs for high values of GetMaxObjectCount() e.g. don't try to generate 2**63 xrefs
+               size_t numXRefEntries = std::min(maxNumberOfIndirectObjects + 1, PoDoFo::PdfParser::GetMaxObjectCount() + 1);
+
+               try
+        {
+            std::string strInputStream = generateXRefEntries( numXRefEntries );
+            PoDoFo::PdfVecObjects objects;
+            PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+            nFirstObject = 0;
+            nNumObjects = PoDoFo::PdfParser::GetMaxObjectCount()+1;
+            parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+            CPPUNIT_FAIL( "PdfError not thrown" );
+        }
+        catch ( PoDoFo::PdfError& error )
+        {
+            // too many indirect objects in Trailer /Size key throws ePdfError_ValueOutOfRange
+            // but too many indirect objects in xref table throws ePdfError_InvalidXRef
+            CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef );
+        }
+        catch( std::exception& ex )
+        {
+            CPPUNIT_FAIL( "Wrong exception type" );
+        }
+    }
+
+    // CVE-2018-5296 try to allocate more than address space size 
+    // should throw a std::bad_length exception in STL which is rethrown as a PdfError
+    try
+    {
+        // this attempts to allocate std::numeric_limits<size_t>::max()/2 * sizeof(TXRefEntry)
+        // on 32-bit systems this allocates 2**31 * sizeof(TXRefEntry) = 2**31 * 16 (larger than 32-bit address space)
+        // on LP64 (macOS,*nix) systems this allocates 2**63 * sizeof(TXRefEntry) = 2**63 * 24 (larger than 64-bit address space)
+        // on LLP64 (Win64) systems this allocates 2**31 * sizeof(TXRefEntry) = 2**31 * 16 (smaller than 64-bit address space)
+        std::string strInputStream = " ";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        nFirstObject = 1;
+        nNumObjects = std::numeric_limits<size_t>::max() / 2 - 1;
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        // if nNumObjects > PdfParser::GetMaxObjectCount() then we'll see ePdfError_InvalidXRef
+        // otherwise we'll see ePdfError_ValueOutOfRange or ePdfError_OutOfMemory (see testMaxObjectCount)
+       CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef || error.GetError() == PoDoFo::ePdfError_ValueOutOfRange || error.GetError() == PoDoFo::ePdfError_OutOfMemory );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }            
+
+    // CVE-2018-5296 try to allocate 95% of VM address space size (which should always fail)
+    if ( !canOutOfMemoryKillUnitTests() )
+    {
+        size_t maxObjects = std::numeric_limits<size_t>::max() / sizeof(PoDoFo::PdfParser::TXRefEntry) / 100 * 95;
+
+        try
+        {
+            std::string strInputStream = " ";
+            PoDoFo::PdfVecObjects objects;
+            PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+            nFirstObject = 1;
+            nNumObjects = maxObjects;
+            parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+            CPPUNIT_FAIL( "PdfError not thrown" );
+        }
+        catch ( PoDoFo::PdfError& error )
+        {
+            if ( maxObjects >= (size_t)PoDoFo::PdfParser::GetMaxObjectCount() )
+                CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef );
+            else
+                CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_OutOfMemory );
+        }
+        catch( std::exception& ex )
+        {
+            CPPUNIT_FAIL( "Wrong exception type" );
+        }
+    } 
+
+    // CVE-2015-8981 happens because this->GetNextNumber() can return negative numbers 
+    // in range (LONG_MIN to LONG_MAX) so the xref section below causes a buffer underflow
+    // because m_offsets[-5].bParsed is set to true when first entry is read
+    // NOTE: std::vector operator[] is not bounds checked
+
+    // xref
+    // -5 5
+    // 0000000000 65535 f 
+    // 0000000018 00000 n 
+    // 0000000077 00000 n 
+    // 0000000178 00000 n 
+    // 0000000457 00000 n 
+    // trailer
+    // <<  /Root 1 0 R
+    //    /Size 5
+    //>>
+    // startxref
+    // 565
+    // %%EOF
+    
+    try
+    {
+        std::string strInputStream = "0000000000 65535 f\r\n";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        nFirstObject = -5LL;
+        nNumObjects = 5;
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_ValueOutOfRange || error.GetError() == PoDoFo::ePdfError_NoXRef );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+    
+    // CVE-2015-8981 can also happen due to integer overflow in nFirstObject+nNumObjects
+    // in the example below 2147483647=0x7FFF, so 0x7FFF + 0x7FFF = 0XFFFE = -2 on a 32-bit system
+    // which means m_offsets.size()=5 because m_offsets.resize() is never called and 
+    // m_offsets[2147483647].bParsed is set to true when first entry is read
+    // NOTE: std::vector operator[] is not bounds checked
+
+    // 2147483647 2147483647 
+    // 0000000000 65535 f 
+    // 0000000018 00000 n 
+    // 0000000077 00000 n 
+    // 0000000178 00000 n 
+    // 0000000457 00000 n 
+    // trailer
+    // <<  /Root 1 0 R
+    //    /Size 5
+    //>>
+    // startxref
+    // 565
+    // %%EOF
+
+    try
+    {
+        std::string strInputStream = "0000000000 65535 f\r\n";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        nFirstObject = std::numeric_limits<long>::max();
+        nNumObjects = std::numeric_limits<long>::max();
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+    
+    try
+    {
+        std::string strInputStream = "0000000000 65535 f\r\n";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        nFirstObject = std::numeric_limits<PoDoFo::pdf_int64>::max();
+        nNumObjects = std::numeric_limits<PoDoFo::pdf_int64>::max();
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }            
+
+    // test for integer overflows in ReadXRefSubsection (CVE-2017-5853) which caused
+    // wrong buffer size to be calculated and then triggered buffer overflow (CVE-2017-6844)   
+    // the overflow checks in ReadXRefSubsection depend on the value returned by GetMaxObjectCount
+    // if the value changes these checks need looked at again
+    CPPUNIT_ASSERT( PoDoFo::PdfParser::GetMaxObjectCount() <= std::numeric_limits<long>::max() );
+
+    // test CVE-2017-5853 signed integer overflow in nFirstObject + nNumObjects
+    // CVE-2017-5853 1.1 - nFirstObject < 0
+    try
+    {
+        std::string strInputStream = " ";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        nFirstObject = -1LL;
+        nNumObjects = 1;
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_ValueOutOfRange );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+    
+    // CVE-2017-5853 1.2 - nFirstObject = min value of long
+    try
+    {
+        std::string strInputStream = " ";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        nFirstObject = std::numeric_limits<long>::min();
+        nNumObjects = 1;
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_ValueOutOfRange );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+    
+    // CVE-2017-5853 1.3 - nFirstObject = min value of pdf_int64
+    try
+    {
+        std::string strInputStream = " ";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        nFirstObject = std::numeric_limits<PoDoFo::pdf_int64>::min();
+        nNumObjects = 1;
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_ValueOutOfRange );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+    
+    // CVE-2017-5853 1.4 - nFirstObject = min value of size_t is zero (size_t is unsigned)
+    // and zero is a valid value for nFirstObject
+    
+    // CVE-2017-5853 1.5 - nFirstObject = max value of long
+    try
+    {
+        std::string strInputStream = " ";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        nFirstObject = std::numeric_limits<long>::max();
+        nNumObjects = 1;
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+    
+    // CVE-2017-5853 1.6 - nFirstObject = max value of pdf_int64
+    try
+    {
+        std::string strInputStream = " ";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        nFirstObject = std::numeric_limits<PoDoFo::pdf_int64>::max();
+        nNumObjects = 1;
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+    
+    // CVE-2017-5853 1.7 - nFirstObject = max value of size_t
+    try
+    {
+        std::string strInputStream = " ";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        nFirstObject = std::numeric_limits<size_t>::max();
+        nNumObjects = 1;
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+               // weird: different errors returned depending on architecture 
+               CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_ValueOutOfRange || sizeof(size_t) == 4 );
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef || sizeof(size_t) == 8 );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+    
+    // CVE-2017-5853 1.8 - nFirstObject = PdfParser::GetMaxObjectCount()
+    try
+    {
+        std::string strInputStream = " ";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        CPPUNIT_ASSERT( PoDoFo::PdfParser::GetMaxObjectCount() > 0 );
+        nFirstObject = PoDoFo::PdfParser::GetMaxObjectCount();
+        nNumObjects = 1;
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+    
+    // CVE-2017-5853 2.1 - nNumObjects < 0
+    try
+    {
+        std::string strInputStream = " ";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        nFirstObject = 1;
+        nNumObjects = -1LL;
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_ValueOutOfRange );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+    
+    // CVE-2017-5853 2.2 - nNumObjects = min value of long
+    try
+    {
+        std::string strInputStream = " ";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        nFirstObject = 1;
+        nNumObjects = std::numeric_limits<long>::min();
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+       CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_ValueOutOfRange );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+    
+    // CVE-2017-5853 2.3 - nNumObjects = min value of pdf_int64
+    try
+    {
+        std::string strInputStream = " ";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        nFirstObject = 1;
+        nNumObjects = std::numeric_limits<PoDoFo::pdf_int64>::min();
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_ValueOutOfRange );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+    
+    // CVE-2017-5853 2.4 - nNumObjects = min value of size_t is zero (size_t is unsigned)
+    // and zero is a valid value for nFirstObject
+    // TODO
+    
+    // CVE-2017-5853 2.5 - nNumObjects = max value of long
+    try
+    {
+        std::string strInputStream = " ";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        nFirstObject = 1;
+        nNumObjects = std::numeric_limits<long>::max();
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+    
+    // CVE-2017-5853 2.6 - nNumObjects = max value of pdf_int64
+    try
+    {
+        std::string strInputStream = " ";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        nFirstObject = 1;
+        nNumObjects = std::numeric_limits<PoDoFo::pdf_int64>::max();
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+    
+    // CVE-2017-5853 2.7 - nNumObjects = max value of size_t
+    try
+    {
+        std::string strInputStream = " ";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        nFirstObject = 1;
+        nNumObjects = std::numeric_limits<size_t>::max();
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+               // weird: different errors returned depending on architecture 
+               CPPUNIT_ASSERT(error.GetError() == PoDoFo::ePdfError_ValueOutOfRange || sizeof(size_t) == 4);
+               CPPUNIT_ASSERT(error.GetError() == PoDoFo::ePdfError_InvalidXRef || sizeof(size_t) == 8);
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+    
+    // CVE-2017-5853 2.8 - nNumObjects = PdfParser::GetMaxObjectCount()
+    try
+    {
+        std::string strInputStream = " ";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        nFirstObject = 1;
+        nNumObjects = PoDoFo::PdfParser::GetMaxObjectCount();
+        parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+        CPPUNIT_FAIL( "PdfError not thrown" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+
+    // CVE-2017-5853 2.9 - finally - loop through a set of interesting bit patterns
+    static PoDoFo::pdf_uint64 s_values[] =
+    {
+        //(1ull << 64) - 1,
+        //(1ull << 64),
+        //(1ull << 64) + 1,
+        (1ull << 63) - 1,
+        (1ull << 63),
+        (1ull << 63) + 1,
+        (1ull << 62) - 1,
+        (1ull << 62),
+        (1ull << 62) + 1,
+
+        (1ull << 49) - 1,
+        (1ull << 49),
+        (1ull << 49) + 1,
+        (1ull << 48) - 1,
+        (1ull << 48),
+        (1ull << 48) + 1,
+        (1ull << 47) - 1,
+        (1ull << 47),
+        (1ull << 47) + 1,        
+
+        (1ull << 33) - 1,
+        (1ull << 33),
+        (1ull << 33) + 1,
+        (1ull << 32) - 1,
+        (1ull << 32),
+        (1ull << 32) + 1,
+        (1ull << 31) - 1,
+        (1ull << 31),
+        (1ull << 31) + 1,
+
+        (1ull << 25) - 1,
+        (1ull << 33),
+        (1ull << 33) + 1,
+        (1ull << 24) - 1,
+        (1ull << 24),
+        (1ull << 24) + 1,
+        (1ull << 31) - 1,
+        (1ull << 31),
+        (1ull << 31) + 1,        
+
+        (1ull << 17) - 1,
+        (1ull << 17),
+        (1ull << 17) + 1,
+        (1ull << 16) - 1,
+        (1ull << 16),
+        (1ull << 16) + 1,
+        (1ull << 15) - 1,
+        (1ull << 15),
+        (1ull << 15) + 1,
+
+        (PoDoFo::pdf_uint64)-1,
+        0,
+        1
+    };
+    const size_t numValues = sizeof(s_values)/sizeof(s_values[0]);
+
+    for ( int i = 0 ; i < static_cast<int>(numValues) ; ++i )
+    {
+        for ( size_t j = 0 ; j < numValues ; ++j )
+        {
+            try
+            {
+                std::string strInputStream = " ";
+                PoDoFo::PdfVecObjects objects;
+                PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+                nFirstObject = s_values[i];
+                nNumObjects = s_values[j];
+                
+                if ( canOutOfMemoryKillUnitTests() && (nFirstObject > maxNumberOfIndirectObjects || nNumObjects > maxNumberOfIndirectObjects) )
+                {
+                    // can't call this in test environments where an out-of-memory condition terminates
+                    // unit test process before all tests have run (e.g. AddressSanitizer)
+                }
+                else
+                {
+                    parser.ReadXRefSubsection( nFirstObject, nNumObjects );
+                    // some combinations of nFirstObject/nNumObjects from s_values are legal - so we expect to reach here sometimes
+                }
+            }
+            catch ( PoDoFo::PdfError& error )
+            {
+                // other combinations of nFirstObject/nNumObjects from s_values are illegal 
+                // if we reach here it should be an invalid xref value of some type
+                CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef || error.GetError() == PoDoFo::ePdfError_ValueOutOfRange || error.GetError() == PoDoFo::ePdfError_NoXRef || error.GetError() == PoDoFo::ePdfError_OutOfMemory );
+            }
+            catch( std::exception& ex )
+            {
+                // and should never reach here
+                CPPUNIT_FAIL( "Wrong exception type" );
+            }
+        }
+    }
+}
+
+void ParserTest::testReadXRefStreamContents()
+{
+    // test valid stream
+    try
+    {
+        // generate an XRef stream with valid /W values
+        std::ostringstream oss;
+        size_t offsetStream;
+        size_t offsetEndstream;
+
+        // XRef stream with 5 entries
+        size_t lengthXRefObject = 57; 
+        size_t offsetXRefObject = oss.str().length();        
+        oss << "2 0 obj ";
+        oss << "<< /Type /XRef ";
+        oss << "/Length " << lengthXRefObject << " ";
+        oss << "/Index [2 2] ";
+        oss << "/Size 5 ";
+        oss << "/W [1 2 1] ";
+        oss << "/Filter /ASCIIHexDecode ";
+        oss << ">>\r\n";
+        oss << "stream\r\n";
+        offsetStream = oss.str().length();
+        oss << "01 0E8A 0\r\n";
+        oss << "02 0002 00\r\n";
+        oss << "02 0002 01\r\n";
+        oss << "02 0002 02\r\n";
+        oss << "02 0002 03\r\n";
+        offsetEndstream = oss.str().length();
+        oss << "endstream\r\n";
+        oss << "endobj\r\n";
+        CPPUNIT_ASSERT( offsetEndstream-offsetStream-strlen("\r\n") == lengthXRefObject ); // hard-coded in /Length entry in XRef stream above
+
+        // trailer        
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref " << offsetXRefObject << "\r\n";
+        oss << "%EOF";
+        
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        
+        parser.SetupTrailer();
+        parser.ReadXRefStreamContents( offsetXRefObject, false );
+        // should succeed
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_FAIL( "Unexpected PdfError" );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }
+
+    // CVE-2018-5295: integer overflow caused by checking sum of /W entry values /W [ 1 2 9223372036854775807 ]
+    // see https://bugzilla.redhat.com/show_bug.cgi?id=1531897 (/W values used were extracted from PoC file)
+    try
+    {
+        std::ostringstream oss;
+        size_t offsetStream;
+        size_t offsetEndstream;
+        
+        // XRef stream
+        size_t lengthXRefObject = 57;
+        size_t offsetXRefObject = 0;
+        oss << "2 0 obj ";
+        oss << "<< /Type /XRef ";
+        oss << "/Length " << lengthXRefObject << " ";
+        oss << "/Index [2 2] ";
+        oss << "/Size 5 ";
+        oss << "/W [ 1 2 9223372036854775807 ] ";
+        oss << "/Filter /ASCIIHexDecode ";
+        oss << ">>\r\n";
+        oss << "stream\r\n";
+        offsetStream = oss.str().length();
+        oss << "01 0E8A 0\r\n";
+        oss << "02 0002 00\r\n";
+        oss << "02 0002 01\r\n";
+        oss << "02 0002 02\r\n";
+        oss << "02 0002 03\r\n";
+        offsetEndstream = oss.str().length();
+        oss << "endstream\r\n";
+        oss << "endobj\r\n";
+        CPPUNIT_ASSERT( offsetEndstream-offsetStream-strlen("\r\n") == lengthXRefObject ); // check /Length entry in XRef stream above
+        
+        // trailer
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref " << offsetXRefObject << "\r\n";
+        oss << "%EOF";
+        
+        PoDoFo::PdfVecObjects objects;
+        PoDoFo::PdfParser::TVecOffsets offsets;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        
+        PoDoFo::PdfXRefStreamParserObject xrefStreamParser(&objects, parser.GetDevice(),
+                                                             parser.GetBuffer(), &offsets );
+        
+        // parse the dictionary then try reading the XRef stream using the invalid /W entries
+        offsets.resize(5);
+        xrefStreamParser.Parse();
+        xrefStreamParser.ReadXRefTable();
+        CPPUNIT_FAIL( "Should throw exception" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_NoXRef || error.GetError() == PoDoFo::ePdfError_InvalidXRefStream );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }    
+
+    // CVE-2017-8787: heap based overflow caused by unchecked /W entry values /W [ 1 -4 2 ]
+    // see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=861738 for value of /W array
+    try
+    {
+        std::ostringstream oss;
+        size_t offsetStream;
+        size_t offsetEndstream;
+        
+        // XRef stream
+        size_t lengthXRefObject = 57;
+        size_t offsetXRefObject = 0;
+        oss << "2 0 obj ";
+        oss << "<< /Type /XRef ";
+        oss << "/Length " << lengthXRefObject << " ";
+        oss << "/Index [2 2] ";
+        oss << "/Size 5 ";
+        oss << "/W [ 1 -4 2 ] ";
+        oss << "/Filter /ASCIIHexDecode ";
+        oss << ">>\r\n";
+        oss << "stream\r\n";
+        offsetStream = oss.str().length();
+        oss << "01 0E8A 0\r\n";
+        oss << "02 0002 00\r\n";
+        oss << "02 0002 01\r\n";
+        oss << "02 0002 02\r\n";
+        oss << "02 0002 03\r\n";
+        offsetEndstream = oss.str().length();
+        oss << "endstream\r\n";
+        oss << "endobj\r\n";
+        CPPUNIT_ASSERT( offsetEndstream-offsetStream-strlen("\r\n") == lengthXRefObject ); // check /Length entry in XRef stream above
+        
+        // trailer
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref " << offsetXRefObject << "\r\n";
+        oss << "%EOF";
+        
+        PoDoFo::PdfVecObjects objects;
+        PoDoFo::PdfParser::TVecOffsets offsets;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        
+        PoDoFo::PdfXRefStreamParserObject xrefStreamParser(&objects, parser.GetDevice(),
+                                                             parser.GetBuffer(), &offsets );
+        
+        // parse the dictionary then try reading the XRef stream using the invalid /W entries
+        offsets.resize(5);
+        xrefStreamParser.Parse();
+        xrefStreamParser.ReadXRefTable();
+        CPPUNIT_FAIL( "Should throw exception" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_NoXRef );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }
+    
+    // /W entry values /W [ 4095 1 1 ] for data in form 02 0002 00 (doesn't match size of entry)
+    try
+    {
+        std::ostringstream oss;
+        size_t offsetStream;
+        size_t offsetEndstream;
+        
+        // XRef stream
+        size_t lengthXRefObject = 57;
+        size_t offsetXRefObject = 0;
+        oss << "2 0 obj ";
+        oss << "<< /Type /XRef ";
+        oss << "/Length " << lengthXRefObject << " ";
+        oss << "/Index [2 2] ";
+        oss << "/Size 5 ";
+        oss << "/W [ 4095 1 1 ] ";
+        oss << "/Filter /ASCIIHexDecode ";
+        oss << ">>\r\n";
+        oss << "stream\r\n";
+        offsetStream = oss.str().length();
+        oss << "01 0E8A 0\r\n";
+        oss << "02 0002 00\r\n";
+        oss << "02 0002 01\r\n";
+        oss << "02 0002 02\r\n";
+        oss << "02 0002 03\r\n";
+        offsetEndstream = oss.str().length();
+        oss << "endstream\r\n";
+        oss << "endobj\r\n";
+        CPPUNIT_ASSERT( offsetEndstream-offsetStream-strlen("\r\n") == lengthXRefObject ); // check /Length entry in XRef stream above
+        
+        // trailer
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref " << offsetXRefObject << "\r\n";
+        oss << "%EOF";
+        
+        PoDoFo::PdfVecObjects objects;
+        PoDoFo::PdfParser::TVecOffsets offsets;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        
+        PoDoFo::PdfXRefStreamParserObject xrefStreamParser(&objects, parser.GetDevice(),
+                                                           parser.GetBuffer(), &offsets );
+        
+        // parse the dictionary then try reading the XRef stream using the invalid /W entries
+        offsets.resize(5);
+        xrefStreamParser.Parse();
+        xrefStreamParser.ReadXRefTable();
+        CPPUNIT_FAIL( "Should throw exception" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRefStream );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }
+    
+    // /W entry values /W [ 4 4 4 ] for data in form 02 0002 00 (doesn't match size of entry)
+    try
+    {
+        std::ostringstream oss;
+        size_t offsetStream;
+        size_t offsetEndstream;
+        
+        // XRef stream
+        size_t lengthXRefObject = 57;
+        size_t offsetXRefObject = 0;
+        oss << "2 0 obj ";
+        oss << "<< /Type /XRef ";
+        oss << "/Length " << lengthXRefObject << " ";
+        oss << "/Index [2 2] ";
+        oss << "/Size 5 ";
+        oss << "/W [ 4 4 4 ] ";
+        oss << "/Filter /ASCIIHexDecode ";
+        oss << ">>\r\n";
+        oss << "stream\r\n";
+        offsetStream = oss.str().length();
+        oss << "01 0E8A 0\r\n";
+        oss << "02 0002 00\r\n";
+        oss << "02 0002 01\r\n";
+        oss << "02 0002 02\r\n";
+        oss << "02 0002 03\r\n";
+        offsetEndstream = oss.str().length();
+        oss << "endstream\r\n";
+        oss << "endobj\r\n";
+        CPPUNIT_ASSERT( offsetEndstream-offsetStream-strlen("\r\n") == lengthXRefObject ); // check /Length entry in XRef stream above
+        
+        // trailer
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref " << offsetXRefObject << "\r\n";
+        oss << "%EOF";
+        
+        PoDoFo::PdfVecObjects objects;
+        PoDoFo::PdfParser::TVecOffsets offsets;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        
+        PoDoFo::PdfXRefStreamParserObject xrefStreamParser(&objects, parser.GetDevice(),
+                                                           parser.GetBuffer(), &offsets );
+        
+        // parse the dictionary then try reading the XRef stream using the invalid /W entries
+        offsets.resize(5);
+        xrefStreamParser.Parse();
+        xrefStreamParser.ReadXRefTable();
+        CPPUNIT_FAIL( "Should throw exception" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRefType );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }
+    
+    // /W entry values /W [ 1 4 4 ] (size=9) for data 01 0E8A 0\r\n02 0002 00\r\n (size=8 bytes)
+    try
+    {
+        std::ostringstream oss;
+        size_t offsetStream;
+        size_t offsetEndstream;
+        
+        // XRef stream
+        size_t lengthXRefObject = 21;
+        size_t offsetXRefObject = 0;
+        oss << "2 0 obj ";
+        oss << "<< /Type /XRef ";
+        oss << "/Length " << lengthXRefObject << " ";
+        oss << "/Index [2 2] ";
+        oss << "/Size 2 ";
+        oss << "/W [ 1 4 4 ] ";
+        oss << "/Filter /ASCIIHexDecode ";
+        oss << ">>\r\n";
+        oss << "stream\r\n";
+        offsetStream = oss.str().length();
+        oss << "01 0E8A 0\r\n";
+        oss << "02 0002 00\r\n";
+        offsetEndstream = oss.str().length();
+        oss << "endstream\r\n";
+        oss << "endobj\r\n";
+        CPPUNIT_ASSERT( offsetEndstream-offsetStream-strlen("\r\n") == lengthXRefObject ); // check /Length entry in XRef stream above
+        
+        // trailer
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref " << offsetXRefObject << "\r\n";
+        oss << "%EOF";
+        
+        PoDoFo::PdfVecObjects objects;
+        PoDoFo::PdfParser::TVecOffsets offsets;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        
+        PoDoFo::PdfXRefStreamParserObject xrefStreamParser(&objects, parser.GetDevice(),
+                                                           parser.GetBuffer(), &offsets );
+        
+        // parse the dictionary then try reading the XRef stream using the invalid /W entries
+        offsets.resize(5);
+        xrefStreamParser.Parse();
+        xrefStreamParser.ReadXRefTable();
+        CPPUNIT_FAIL( "Should throw exception" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_NoXRef );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }
+    
+    // XRef stream with 5 entries but /Size 2 specified
+    try
+    {
+        std::ostringstream oss;
+        size_t offsetStream;
+        size_t offsetEndstream;
+        
+        size_t lengthXRefObject = 57;
+        size_t offsetXRefObject = oss.str().length();
+        oss << "2 0 obj ";
+        oss << "<< /Type /XRef ";
+        oss << "/Length " << lengthXRefObject << " ";
+        oss << "/Index [2 2] ";
+        oss << "/Size 2 ";
+        oss << "/W [1 2 1] ";
+        oss << "/Filter /ASCIIHexDecode ";
+        oss << ">>\r\n";
+        oss << "stream\r\n";
+        offsetStream = oss.str().length();
+        oss << "01 0E8A 0\r\n";
+        oss << "02 0002 00\r\n";
+        oss << "02 0002 01\r\n";
+        oss << "02 0002 02\r\n";
+        oss << "02 0002 03\r\n";
+        offsetEndstream = oss.str().length();
+        oss << "endstream\r\n";
+        oss << "endobj\r\n";
+        CPPUNIT_ASSERT( offsetEndstream-offsetStream-strlen("\r\n") == lengthXRefObject ); // hard-coded in /Length entry in XRef stream above
+        
+        // trailer
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref " << offsetXRefObject << "\r\n";
+        oss << "%EOF";
+        
+        PoDoFo::PdfVecObjects objects;
+        PoDoFo::PdfParser::TVecOffsets offsets;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        
+        PoDoFo::PdfXRefStreamParserObject xrefStreamParser(&objects, parser.GetDevice(),
+                                                           parser.GetBuffer(), &offsets );
+        
+        offsets.resize(2);
+        xrefStreamParser.Parse();
+        xrefStreamParser.ReadXRefTable();
+        // should this succeed ???
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_FAIL( "Unexpected PdfError" );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }
+    
+    // XRef stream with 5 entries but /Size 10 specified
+    try
+    {
+        std::ostringstream oss;
+        size_t offsetStream;
+        size_t offsetEndstream;
+        
+        size_t lengthXRefObject = 57;
+        size_t offsetXRefObject = oss.str().length();
+        oss << "2 0 obj ";
+        oss << "<< /Type /XRef ";
+        oss << "/Length " << lengthXRefObject << " ";
+        oss << "/Index [2 2] ";
+        oss << "/Size 10 ";
+        oss << "/W [1 2 1] ";
+        oss << "/Filter /ASCIIHexDecode ";
+        oss << ">>\r\n";
+        oss << "stream\r\n";
+        offsetStream = oss.str().length();
+        oss << "01 0E8A 0\r\n";
+        oss << "02 0002 00\r\n";
+        oss << "02 0002 01\r\n";
+        oss << "02 0002 02\r\n";
+        oss << "02 0002 03\r\n";
+        offsetEndstream = oss.str().length();
+        oss << "endstream\r\n";
+        oss << "endobj\r\n";
+        CPPUNIT_ASSERT( offsetEndstream-offsetStream-strlen("\r\n") == lengthXRefObject ); // hard-coded in /Length entry in XRef stream above
+        
+        // trailer
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref " << offsetXRefObject << "\r\n";
+        oss << "%EOF";
+        
+        PoDoFo::PdfVecObjects objects;
+        PoDoFo::PdfParser::TVecOffsets offsets;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        
+        PoDoFo::PdfXRefStreamParserObject xrefStreamParser(&objects, parser.GetDevice(),
+                                                           parser.GetBuffer(), &offsets );
+        
+        offsets.resize(2);
+        xrefStreamParser.Parse();
+        xrefStreamParser.ReadXRefTable();
+        // should this succeed ???
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_FAIL( "Unexpected PdfError" );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }
+    
+    // XRef stream with /Index [0 0] array
+    try
+    {
+        std::ostringstream oss;
+        size_t offsetStream;
+        size_t offsetEndstream;
+        
+        size_t lengthXRefObject = 57;
+        size_t offsetXRefObject = oss.str().length();
+        oss << "2 0 obj ";
+        oss << "<< /Type /XRef ";
+        oss << "/Length " << lengthXRefObject << " ";
+        oss << "/Index [0 0] ";
+        oss << "/Size 5 ";
+        oss << "/W [1 2 1] ";
+        oss << "/Filter /ASCIIHexDecode ";
+        oss << ">>\r\n";
+        oss << "stream\r\n";
+        offsetStream = oss.str().length();
+        oss << "01 0E8A 0\r\n";
+        oss << "02 0002 00\r\n";
+        oss << "02 0002 01\r\n";
+        oss << "02 0002 02\r\n";
+        oss << "02 0002 03\r\n";
+        offsetEndstream = oss.str().length();
+        oss << "endstream\r\n";
+        oss << "endobj\r\n";
+        CPPUNIT_ASSERT( offsetEndstream-offsetStream-strlen("\r\n") == lengthXRefObject ); // hard-coded in /Length entry in XRef stream above
+        
+        // trailer
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref " << offsetXRefObject << "\r\n";
+        oss << "%EOF";
+        
+        PoDoFo::PdfVecObjects objects;
+        PoDoFo::PdfParser::TVecOffsets offsets;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        
+        PoDoFo::PdfXRefStreamParserObject xrefStreamParser(&objects, parser.GetDevice(),
+                                                           parser.GetBuffer(), &offsets );
+        
+        offsets.resize(5);
+        xrefStreamParser.Parse();
+        xrefStreamParser.ReadXRefTable();
+        // should this succeed ???
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_FAIL( "Unexpected PdfError" );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }
+    
+    // XRef stream with /Index [-1 -1] array
+    try
+    {
+        std::ostringstream oss;
+        size_t offsetStream;
+        size_t offsetEndstream;
+        
+        size_t lengthXRefObject = 57;
+        size_t offsetXRefObject = oss.str().length();
+        oss << "2 0 obj ";
+        oss << "<< /Type /XRef ";
+        oss << "/Length " << lengthXRefObject << " ";
+        oss << "/Index [-1 -1] ";
+        oss << "/Size 5 ";
+        oss << "/W [1 2 1] ";
+        oss << "/Filter /ASCIIHexDecode ";
+        oss << ">>\r\n";
+        oss << "stream\r\n";
+        offsetStream = oss.str().length();
+        oss << "01 0E8A 0\r\n";
+        oss << "02 0002 00\r\n";
+        oss << "02 0002 01\r\n";
+        oss << "02 0002 02\r\n";
+        oss << "02 0002 03\r\n";
+        offsetEndstream = oss.str().length();
+        oss << "endstream\r\n";
+        oss << "endobj\r\n";
+        CPPUNIT_ASSERT( offsetEndstream-offsetStream-strlen("\r\n") == lengthXRefObject ); // hard-coded in /Length entry in XRef stream above
+        
+        // trailer
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref " << offsetXRefObject << "\r\n";
+        oss << "%EOF";
+        
+        PoDoFo::PdfVecObjects objects;
+        PoDoFo::PdfParser::TVecOffsets offsets;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        
+        PoDoFo::PdfXRefStreamParserObject xrefStreamParser(&objects, parser.GetDevice(),
+                                                           parser.GetBuffer(), &offsets );
+        
+        offsets.resize(5);
+        xrefStreamParser.Parse();
+        xrefStreamParser.ReadXRefTable();
+        // should this succeed ???
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_FAIL( "Unexpected PdfError" );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }
+    
+    // XRef stream with /Index array with no entries
+    try
+    {
+        std::ostringstream oss;
+        size_t offsetStream;
+        size_t offsetEndstream;
+        
+        size_t lengthXRefObject = 57;
+        size_t offsetXRefObject = oss.str().length();
+        oss << "2 0 obj ";
+        oss << "<< /Type /XRef ";
+        oss << "/Length " << lengthXRefObject << " ";
+        oss << "/Index [ ] ";
+        oss << "/Size 5 ";
+        oss << "/W [1 2 1] ";
+        oss << "/Filter /ASCIIHexDecode ";
+        oss << ">>\r\n";
+        oss << "stream\r\n";
+        offsetStream = oss.str().length();
+        oss << "01 0E8A 0\r\n";
+        oss << "02 0002 00\r\n";
+        oss << "02 0002 01\r\n";
+        oss << "02 0002 02\r\n";
+        oss << "02 0002 03\r\n";
+        offsetEndstream = oss.str().length();
+        oss << "endstream\r\n";
+        oss << "endobj\r\n";
+        CPPUNIT_ASSERT( offsetEndstream-offsetStream-strlen("\r\n") == lengthXRefObject ); // hard-coded in /Length entry in XRef stream above
+        
+        // trailer
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref " << offsetXRefObject << "\r\n";
+        oss << "%EOF";
+        
+        PoDoFo::PdfVecObjects objects;
+        PoDoFo::PdfParser::TVecOffsets offsets;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        
+        PoDoFo::PdfXRefStreamParserObject xrefStreamParser(&objects, parser.GetDevice(),
+                                                           parser.GetBuffer(), &offsets );
+        
+        offsets.resize(5);
+        xrefStreamParser.Parse();
+        xrefStreamParser.ReadXRefTable();
+        // should this succeed ???
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_FAIL( "Unexpected PdfError" );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }
+    
+    // XRef stream with /Index array with 3 entries
+    try
+    {
+        std::ostringstream oss;
+        size_t offsetStream;
+        size_t offsetEndstream;
+        
+        size_t lengthXRefObject = 57;
+        size_t offsetXRefObject = oss.str().length();
+        oss << "2 0 obj ";
+        oss << "<< /Type /XRef ";
+        oss << "/Length " << lengthXRefObject << " ";
+        oss << "/Index [2 2 2] ";
+        oss << "/Size 5 ";
+        oss << "/W [1 2 1] ";
+        oss << "/Filter /ASCIIHexDecode ";
+        oss << ">>\r\n";
+        oss << "stream\r\n";
+        offsetStream = oss.str().length();
+        oss << "01 0E8A 0\r\n";
+        oss << "02 0002 00\r\n";
+        oss << "02 0002 01\r\n";
+        oss << "02 0002 02\r\n";
+        oss << "02 0002 03\r\n";
+        offsetEndstream = oss.str().length();
+        oss << "endstream\r\n";
+        oss << "endobj\r\n";
+        CPPUNIT_ASSERT( offsetEndstream-offsetStream-strlen("\r\n") == lengthXRefObject ); // hard-coded in /Length entry in XRef stream above
+        
+        // trailer
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref " << offsetXRefObject << "\r\n";
+        oss << "%EOF";
+        
+        PoDoFo::PdfVecObjects objects;
+        PoDoFo::PdfParser::TVecOffsets offsets;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        
+        PoDoFo::PdfXRefStreamParserObject xrefStreamParser(&objects, parser.GetDevice(),
+                                                           parser.GetBuffer(), &offsets );
+        
+        offsets.resize(5);
+        xrefStreamParser.Parse();
+        xrefStreamParser.ReadXRefTable();
+        CPPUNIT_FAIL( "Should throw exception" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_NoXRef );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }
+    
+    // XRef stream with /Index array with 22 entries
+    try
+    {
+        std::ostringstream oss;
+        size_t offsetStream;
+        size_t offsetEndstream;
+        
+        size_t lengthXRefObject = 57;
+        size_t offsetXRefObject = oss.str().length();
+        oss << "2 0 obj ";
+        oss << "<< /Type /XRef ";
+        oss << "/Length " << lengthXRefObject << " ";
+        oss << "/Index [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22] ";
+        oss << "/Size 5 ";
+        oss << "/W [1 2 1] ";
+        oss << "/Filter /ASCIIHexDecode ";
+        oss << ">>\r\n";
+        oss << "stream\r\n";
+        offsetStream = oss.str().length();
+        oss << "00 0000 0\r\n";
+        oss << "00 0000 00\r\n";
+        oss << "00 0000 00\r\n";
+        oss << "00 0000 00\r\n";
+        oss << "00 0000 00\r\n";
+        offsetEndstream = oss.str().length();
+        oss << "endstream\r\n";
+        oss << "endobj\r\n";
+        CPPUNIT_ASSERT( offsetEndstream-offsetStream-strlen("\r\n") == lengthXRefObject ); // hard-coded in /Length entry in XRef stream above
+        
+        // trailer
+        oss << "trailer << /Root 1 0 R /Size 3 >>\r\n";
+        oss << "startxref " << offsetXRefObject << "\r\n";
+        oss << "%EOF";
+        
+        PoDoFo::PdfVecObjects objects;
+        PoDoFo::PdfParser::TVecOffsets offsets;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        
+        PoDoFo::PdfXRefStreamParserObject xrefStreamParser(&objects, parser.GetDevice(),
+                                                           parser.GetBuffer(), &offsets );
+        
+        offsets.resize(5);
+        xrefStreamParser.Parse();
+        xrefStreamParser.ReadXRefTable();
+        CPPUNIT_FAIL( "Should throw exception" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_NoXRef );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }
+}
+
+void ParserTest::testReadObjects()
+{
+    // CVE-2017-8378 - m_offsets out-of-bounds access when referenced encryption dictionary object doesn't exist
+    try
+    {
+        // generate an xref section
+        // xref
+        // 0 3
+        // 0000000000 65535 f 
+        // 0000000018 00000 n 
+        // 0000000077 00000 n
+        // trailer << /Root 1 0 R /Size 3 >>
+        // startxref
+        // 0
+        // %%EOF
+        std::ostringstream oss;     
+        oss << "%PDF–1.0\r\n"; 
+        oss << "xref\r\n0 3\r\n";
+        oss << generateXRefEntries(3);
+        oss << "trailer << /Root 1 0 R /Size 3 /Encrypt 2 0 R >>\r\n";
+        oss << "startxref 0\r\n";
+        oss << "%EOF";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() );
+        parser.ReadTrailer();
+        parser.ReadObjects();
+        CPPUNIT_FAIL( "Should throw exception" );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidEncryptionDict );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Unexpected exception type" );
+    }    
+}
+
+void ParserTest::testIsPdfFile()
+{
+    try
+    {
+        std::string strInputStream = "%PDF-1.0";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        CPPUNIT_ASSERT( parser.IsPdfFile() );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_FAIL( "Unexpected PdfError" );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+
+    try
+    {
+        std::string strInputStream = "%PDF-1.1";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        CPPUNIT_ASSERT( parser.IsPdfFile() );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_FAIL( "Unexpected PdfError" );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+
+    try
+    {
+        std::string strInputStream = "%PDF-1.7";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        CPPUNIT_ASSERT( parser.IsPdfFile() );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_FAIL( "Unexpected PdfError" );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+
+    try
+    {
+        std::string strInputStream = "%PDF-1.9";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        CPPUNIT_ASSERT( parser.IsPdfFile() );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_FAIL( "Unexpected PdfError" );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }
+
+    try
+    {
+        std::string strInputStream = "%PDF-1.99";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        CPPUNIT_ASSERT( parser.IsPdfFile() );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_FAIL( "Unexpected PdfError" );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }    
+
+    try
+    {
+        std::string strInputStream = "%!PS-Adobe-2.0";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        CPPUNIT_ASSERT( !parser.IsPdfFile() );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_FAIL( "Unexpected PdfError" );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }     
+
+    try
+    {
+        std::string strInputStream = "GIF89a";
+        PoDoFo::PdfVecObjects objects;
+        PdfParserTestWrapper parser( &objects, strInputStream.c_str(), strInputStream.length() );
+        CPPUNIT_ASSERT( !parser.IsPdfFile() );
+    }
+    catch ( PoDoFo::PdfError& error )
+    {
+        CPPUNIT_FAIL( "Unexpected PdfError" );
+    }
+    catch( std::exception& ex )
+    {
+        CPPUNIT_FAIL( "Wrong exception type" );
+    }     
+}
+
+void ParserTest::testRoundTripIndirectTrailerID()
+{
+    std::ostringstream oss;
+    oss << "%PDF-1.1\n";
+    int nCurObj = 0;
+    int objPos[20];
+
+    // Pages
+
+    int nPagesObj = nCurObj;
+    objPos[nCurObj] = oss.tellp();
+    oss << nCurObj++ << " 0 obj\n";
+    oss << "<</Type /Pages /Count 0 /Kids []>>\n";
+    oss << "endobj";
+
+    // Root catalog
+
+    int rootObj = nCurObj;
+    objPos[nCurObj] = oss.tellp();
+    oss << nCurObj++ << " 0 obj\n";
+    oss << "<</Type /Catalog /Pages " << nPagesObj << " 0 R>>\n";
+    oss << "endobj\n";
+
+    // ID
+    int nIdObj = nCurObj;
+    objPos[nCurObj] = oss.tellp();
+    oss << nCurObj++ << " 0 obj\n";
+    oss << "[<F1E375363A6314E3766EDF396D614748> <F1E375363A6314E3766EDF396D614748>]\n";
+    oss << "endobj\n";
+
+    int nXrefPos = oss.tellp();
+    oss << "xref\n";
+    oss << "0 " << nCurObj << "\n";
+    char objRec[21];
+    for ( int i = 0; i < nCurObj; i++ ) {
+        snprintf( objRec, 21, "%010d 00000 n \n", objPos[i] );
+        oss << objRec;
+    }
+    oss << "trailer <<\n"
+        << "  /Size " << nCurObj << "\n"
+        << "  /Root " << rootObj << " 0 R\n"
+        << "  /ID " << nIdObj << " 0 R\n" // indirect ID
+        << ">>\n"
+        << "startxref\n"
+        << nXrefPos << "\n"
+        << "%%EOF\n";
+
+    std::string sInBuf = oss.str();
+    try {
+        PoDoFo::PdfMemDocument doc;
+        // load for update
+        doc.LoadFromBuffer( sInBuf.c_str(), sInBuf.size(), true );
+
+        PoDoFo::PdfRefCountedBuffer outBuf;
+        PoDoFo::PdfOutputDevice outDev( &outBuf );
+
+        doc.WriteUpdate( &outDev );
+        // should not throw
+        CPPUNIT_ASSERT( true );
+    } catch ( PoDoFo::PdfError& error ) {
+        CPPUNIT_FAIL( "Unexpected PdfError" );
+    }
+}
+
+std::string ParserTest::generateXRefEntries( size_t count )
+{
+    std::string strXRefEntries;
+
+    // generates a block of 20-byte xref entries
+    // 0000000000 65535 f\r\n
+    // 0000000120 00000 n\r\n    
+    // 0000000120 00000 n\r\n
+    // 0000000120 00000 n\r\n
+       try
+       {
+               strXRefEntries.reserve(count * 20);
+               for (size_t i = 0; i < count; ++i)
+               {
+                       if (i == 0)
+                               strXRefEntries.append("0000000000 65535 f\r\n");
+                       else
+                               strXRefEntries.append("0000000120 00000 n\r\n");
+               }
+       }
+       catch (std::exception& ex)
+       {
+               // if this fails it's a bug in the unit tests and not PoDoFo
+               CPPUNIT_FAIL("generateXRefEntries memory allocation failure");
+       }
+
+    return strXRefEntries;
+}
+
+bool ParserTest::canOutOfMemoryKillUnitTests()
+{
+    // test if out of memory conditions will kill the unit test process
+    // which prevents tests completing
+
+#if defined(_WIN32) || defined(_WIN64)
+    // on Windows 32/64 allocations close to size of VM address space always fail gracefully
+    bool bCanTerminateProcess = false;
+#elif defined( __APPLE__ )
+    // on macOS/iOS allocations close to size of VM address space fail gracefully
+    // unless Address Sanitizer (ASAN) is enabled
+    #if __has_feature(address_sanitizer)
+        // ASAN terminates the process if alloc fails - and using allocator_may_return_null=1
+        // to continue after an allocation doesn't work in C++ because new returns null which is
+        // forbidden by the C++ spec and terminates process when 'this' is dereferenced in constructor
+        // see https://github.com/google/sanitizers/issues/295
+        bool bCanTerminateProcess = true;   
+    #else
+        // if alloc fails following message is logged
+        // *** mach_vm_map failed (error code=3)
+        // *** error: can't allocate region
+        // *** set a breakpoint in malloc_error_break to debug
+        bool bCanTerminateProcess = false;
+    #endif
+#elif defined( __linux__ )
+    // TODO do big allocs succeed then trigger OOM-killer fiasco??
+    bool bCanTerminateProcess = false;
+#else
+    // other systems - assume big allocs faily gracefully and throw bad_alloc
+    bool bCanTerminateProcess = false;
+#endif
+
+    return bCanTerminateProcess;
+}
+
+
diff --git a/test/unit/ParserTest.h b/test/unit/ParserTest.h
new file mode 100644 (file)
index 0000000..cffcaaa
--- /dev/null
@@ -0,0 +1,90 @@
+/***************************************************************************
+ *   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 _PARSER_TEST_H_
+#define _PARSER_TEST_H_
+
+#include <cppunit/extensions/HelperMacros.h>
+
+#include <podofo.h>
+
+/** This test tests the class PdfParser
+ *
+ *  PdfParser was responsible for 14% of the PoDoFo CVEs reported up to April 2018
+ *  so this class tests CVE fixes along with additional tests to test boundary conditions
+ */
+class ParserTest : public CppUnit::TestFixture
+{
+    CPPUNIT_TEST_SUITE( ParserTest );
+    CPPUNIT_TEST( testMaxObjectCount );
+    CPPUNIT_TEST( testReadDocumentStructure );
+    CPPUNIT_TEST( testReadXRefContents );
+    CPPUNIT_TEST( testReadXRefContents );
+    CPPUNIT_TEST( testReadXRefSubsection );
+    CPPUNIT_TEST( testReadXRefStreamContents );
+    CPPUNIT_TEST( testReadObjects );
+    CPPUNIT_TEST( testIsPdfFile );
+    CPPUNIT_TEST( testRoundTripIndirectTrailerID );
+    CPPUNIT_TEST_SUITE_END();
+
+public:
+    void setUp();
+    void tearDown();
+
+    // commented out tests still need implemented
+
+    void testMaxObjectCount();
+
+    // CVE-2018-8002
+    // testParseFile();
+
+    void testReadDocumentStructure();
+    //void testReadTrailer();
+    //void testReadXRef();
+
+    // CVE-2017-8053 tested
+    void testReadXRefContents();
+
+    // CVE-2015-8981, CVE-2017-5853, CVE-2018-5296 - tested
+    // CVE-2017-6844, CVE-2017-5855 - symptoms are false postives due to ASAN allocator_may_return_null=1 not throwing bad_alloc
+    void testReadXRefSubsection();
+
+    // CVE-2017-8787, CVE-2018-5295 - tested
+    void testReadXRefStreamContents();
+
+    // CVE-2017-8378 - tested
+    // CVE-2018-6352 - no fix yet, so no test yet
+    void testReadObjects();
+
+    //void testReadObjectFromStream();
+    void testIsPdfFile();
+    //void testReadNextTrailer();
+    //void testCheckEOFMarker();
+
+    void testRoundTripIndirectTrailerID();
+
+private:
+    std::string generateXRefEntries( size_t count );
+    bool canOutOfMemoryKillUnitTests();
+};
+
+#endif // _PARSER_TEST_H_
+
+
diff --git a/test/unit/StringTest.cpp b/test/unit/StringTest.cpp
new file mode 100644 (file)
index 0000000..a7841f7
--- /dev/null
@@ -0,0 +1,394 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+#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 print(pdf_utf16be* pszUtf16, pdf_long lLen)
+{
+    printf("start lLen=%li\n", static_cast<long>(lLen));
+  
+    const char* pszTmp = reinterpret_cast<const char*>(pszUtf16);
+    for(int i=0;i<lLen*2;i++) {
+        printf("pos=%i %02x\n", i, pszTmp[i] );
+    }
+
+    printf("UTF16:\n");
+    for(int i=0;i<lLen;i++) {
+        printf("pos=%i %02x\n", i, pszUtf16[i] );
+    }
+    
+    
+    printf("ende\n");
+}
+
+void StringTest::TestLibUnistringInternal(const char* pszString, const long lLenUtf8, const long lLenUtf16)
+{
+    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Test initial string len.", static_cast<size_t>(lLenUtf8), strlen(pszString) );
+    
+    pdf_utf16be* pszUtf16 = static_cast< pdf_utf16be* >( podofo_malloc( sizeof( pdf_utf16be ) * ( lLenUtf16 + 1 ) ) );
+    CPPUNIT_ASSERT( pszUtf16!= NULL );
+    pdf_long result1 = PdfString::ConvertUTF8toUTF16( reinterpret_cast<const pdf_utf8*>(pszString), lLenUtf8, pszUtf16, lLenUtf16 + 1 );
+
+    print(pszUtf16, result1);
+    
+    // Buffer is one byte longer, because it ends with two zero bytes
+    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Comparing length of output buffer after utf8 -> utf16 conversion.", lLenUtf16 + 1, static_cast<long>(result1) );
+    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Make sure utf16 string is 0 terminated.", static_cast<pdf_utf16be>(0), pszUtf16[result1-1] );
+    
+    pdf_utf8* pszUtf8 = static_cast< pdf_utf8* >( podofo_malloc( sizeof( pdf_utf8 ) * ( lLenUtf8 + 1 ) ) );
+    CPPUNIT_ASSERT( pszUtf8 != NULL );
+    pdf_long result2 = PdfString::ConvertUTF16toUTF8( pszUtf16, lLenUtf16, pszUtf8, lLenUtf8 + 1 );
+    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Comparing length of output buffer after utf8 -> utf16 -> utf8 conversion.", lLenUtf8 + 1, static_cast<long>(result2) );
+    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Make sure utf8 string is 0 terminated.", static_cast<pdf_utf8>(0), pszUtf8[result2 - 1] );
+
+    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Comparing input string after utf8 -> utf16 -> utf8", strncmp(pszString, reinterpret_cast<char*>(pszUtf8), lLenUtf8 ), 0);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Comparing string length after utf8 -> utf16 -> utf8", static_cast<size_t>(lLenUtf8), strlen(reinterpret_cast<char*>(pszUtf8)) );
+
+    podofo_free( pszUtf8 );
+    podofo_free( pszUtf16 );
+}
+
+void StringTest::testLibUnistringSimple()
+{
+    const pdf_long lLenUtf8 = 13;
+    const char* pszString = "Hallo PoDoFo!";
+    const pdf_long lLenUtf16 = lLenUtf8;
+    
+    TestLibUnistringInternal(pszString, lLenUtf8, lLenUtf16);
+}
+
+void StringTest::testLibUnistringUtf8()
+{
+    const char* pszStringJapUtf8 = "「PoDoFo」は今から日本語も話せます。";
+    const pdf_long lLenUtf8 = strlen(pszStringJapUtf8);
+    const pdf_long lLenUtf16 = 21;
+
+    TestLibUnistringInternal(pszStringJapUtf8, lLenUtf8, lLenUtf16);
+}
+
+
+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<const pdf_utf8*>(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<char>(0xca), 0x30, 0x4b, 0x30, static_cast<char>(0x89), 
+                                          0x65, static_cast<char>(0xe5), 0x67, 0x2c, static_cast<char>(0x8a), static_cast<char>(0x9e), 
+                                          0x30, static_cast<char>(0x82), static_cast<char>(0x8a), static_cast<char>(0x71), 0x30, 0x5b, 
+                                          0x30, static_cast<char>(0x7e), 0x30, 0x59, 0x30, 0x02, 
+                                          0x00, 0x00 };
+
+    PdfString strUtf8( reinterpret_cast<const pdf_utf8*>(pszStringJapUtf8) );
+    PdfString strUtf16( reinterpret_cast<const pdf_utf16be*>(psStringJapUtf16BE), 21 );
+    PdfString strUtf16b( reinterpret_cast<const pdf_utf16be*>(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<char>(0xFE), static_cast<char>(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<char>(0x72), 0x00, 0x6C, 0x00, 
+                                  0x64, 0x29, 0x00, 0x00 };
+    
+    // Force unicode string
+    PdfString   sUnic( reinterpret_cast<const pdf_utf8*>(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<char>(0xFE), static_cast<char>(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<const pdf_utf8*>(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("(1Hello\\nWorld)", "(1Hello\\nWorld)");
+    TestWriteEscapeSequences("(Hello\nWorld)", "(Hello\\nWorld)");
+    TestWriteEscapeSequences("(Hello\012World)", "(Hello\\nWorld)");
+    TestWriteEscapeSequences("(Hello\\012World)", "(Hello\\nWorld)");
+
+    TestWriteEscapeSequences("(2Hello\\rWorld)", "(2Hello\\rWorld)");
+    TestWriteEscapeSequences("(Hello\rWorld)", "(Hello\\rWorld)");
+    TestWriteEscapeSequences("(Hello\015World)", "(Hello\\rWorld)");
+    TestWriteEscapeSequences("(Hello\\015World)", "(Hello\\rWorld)");
+
+    TestWriteEscapeSequences("(3Hello\\tWorld)", "(3Hello\\tWorld)");
+    TestWriteEscapeSequences("(Hello\tWorld)", "(Hello\\tWorld)");
+    TestWriteEscapeSequences("(Hello\011World)", "(Hello\\tWorld)");
+    TestWriteEscapeSequences("(Hello\\011World)", "(Hello\\tWorld)");
+
+    TestWriteEscapeSequences("(4Hello\\fWorld)", "(4Hello\\fWorld)");
+    TestWriteEscapeSequences("(Hello\fWorld)", "(Hello\\fWorld)");
+    TestWriteEscapeSequences("(Hello\014World)", "(Hello\\fWorld)");
+    TestWriteEscapeSequences("(Hello\\014World)", "(Hello\\fWorld)");
+
+    TestWriteEscapeSequences("(5Hello\\(World)", "(5Hello\\(World)");
+    TestWriteEscapeSequences("(Hello\\050World)", "(Hello\\(World)");
+
+    TestWriteEscapeSequences("(6Hello\\)World)", "(6Hello\\)World)");
+    TestWriteEscapeSequences("(Hello\\051World)", "(Hello\\)World)");
+
+    TestWriteEscapeSequences("(7Hello\\\\World)", "(7Hello\\\\World)");
+    TestWriteEscapeSequences("(Hello\\\134World)", "(Hello\\\\World)");
+
+    // Special case, \ at end of line
+    TestWriteEscapeSequences("(8Hello\\\nWorld)", "(8HelloWorld)");
+
+
+    TestWriteEscapeSequences("(9Hello\003World)", "(9Hello\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<const pdf_utf8*>(pszEmpty) );
+    PdfString str7( reinterpret_cast<const pdf_utf8*>(pszEmpty), 0 );
+    PdfString str8( reinterpret_cast<const pdf_utf16be*>(L""), 0 );
+
+    CPPUNIT_ASSERT( !str1.IsValid() );
+
+    CPPUNIT_ASSERT( str2.IsValid() );
+    CPPUNIT_ASSERT_EQUAL( static_cast<pdf_long>(0), str2.GetLength() );
+    CPPUNIT_ASSERT_EQUAL( static_cast<pdf_long>(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<pdf_long>(0), str3.GetLength() );
+    CPPUNIT_ASSERT_EQUAL( static_cast<pdf_long>(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<pdf_long>(0), str4.GetLength() );
+    CPPUNIT_ASSERT_EQUAL( static_cast<pdf_long>(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<pdf_long>(0), str5.GetLength() );
+    CPPUNIT_ASSERT_EQUAL( static_cast<pdf_long>(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<pdf_long>(0), str6.GetLength() );
+    CPPUNIT_ASSERT_EQUAL( static_cast<pdf_long>(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<pdf_long>(0), str7.GetLength() );
+    CPPUNIT_ASSERT_EQUAL( static_cast<pdf_long>(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<pdf_long>(0), str8.GetLength() );
+    CPPUNIT_ASSERT_EQUAL( static_cast<pdf_long>(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<const pdf_utf8*>(pszUtf8) );
+    
+    CPPUNIT_ASSERT_EQUAL( true, str.IsUnicode() );
+    CPPUNIT_ASSERT_EQUAL( static_cast<pdf_long>(43*2), str.GetLength() );
+    CPPUNIT_ASSERT_EQUAL( static_cast<pdf_long>(43), str.GetCharacterLength() );
+    CPPUNIT_ASSERT_EQUAL( std::string(pszUtf8), str.GetStringUtf8() );
+    
+}
+
+#endif // __clang__
diff --git a/test/unit/StringTest.h b/test/unit/StringTest.h
new file mode 100644 (file)
index 0000000..dbafd5b
--- /dev/null
@@ -0,0 +1,68 @@
+/***************************************************************************
+ *   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 <cppunit/extensions/HelperMacros.h>
+
+#ifndef __clang__
+
+/** This test tests the class PdfString
+ */
+class StringTest : public CppUnit::TestFixture
+{
+    CPPUNIT_TEST_SUITE( StringTest );
+    CPPUNIT_TEST( testLibUnistringSimple );
+    CPPUNIT_TEST( testLibUnistringUtf8 );
+    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 testLibUnistringSimple();
+    void testLibUnistringUtf8();
+    void testGetStringUtf8();
+    void testUtf16beContructor();
+    void testWCharConstructor();
+    void testEscapeBrackets();
+    void testWriteEscapeSequences();
+    void testEmptyString();
+    void testInitFromUtf8();
+    
+ private:
+    void TestWriteEscapeSequences(const char* pszSource, const char* pszExpected);
+    void TestLibUnistringInternal(const char* pszString, const long lLenUtf8, const long lLenUtf16);
+};
+
+#endif // __clang__
+
+#endif // _STRING_TEST_H_
+
+
diff --git a/test/unit/TestUtils.cpp b/test/unit/TestUtils.cpp
new file mode 100644 (file)
index 0000000..e23e94f
--- /dev/null
@@ -0,0 +1,84 @@
+/***************************************************************************
+ *   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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if defined(_WIN32) || defined(_WIN64)
+#include <windows.h>
+
+#ifdef CreateFont
+#undef CreateFont
+#endif // CreateFont
+
+#ifdef DrawText
+#undef DrawText
+#endif // DrawText
+
+#endif // _WIN32 || _WIN64
+
+#include <podofo.h>
+
+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<char*>(malloc(sizeof(char) * lLen));
+    stream.Read(pBuffer, lLen);
+
+    return pBuffer;
+}
+
+
diff --git a/test/unit/TestUtils.h b/test/unit/TestUtils.h
new file mode 100644 (file)
index 0000000..11a0650
--- /dev/null
@@ -0,0 +1,44 @@
+/***************************************************************************
+ *   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 <string>
+
+/**
+ * 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_
diff --git a/test/unit/TokenizerTest.cpp b/test/unit/TokenizerTest.cpp
new file mode 100644 (file)
index 0000000..26f20eb
--- /dev/null
@@ -0,0 +1,264 @@
+/***************************************************************************
+ *   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 <cppunit/Asserter.h>
+
+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( "[<</key/name>>2 0 R]", ePdfDataType_Array, "[ <<\n/key /name\n>> 2 0 R ]" );
+    Test( "[<<//name>>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( "<FFEB0400A0CC>", ePdfDataType_HexString );
+    Test( "<FFEB0400A0C>", ePdfDataType_HexString, "<FFEB0400A0C0>" );
+    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 );
+}
diff --git a/test/unit/TokenizerTest.h b/test/unit/TokenizerTest.h
new file mode 100644 (file)
index 0000000..12affd2
--- /dev/null
@@ -0,0 +1,93 @@
+/***************************************************************************
+ *   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 <cppunit/extensions/HelperMacros.h>
+
+#include <podofo.h>
+
+/** 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_
+
+
diff --git a/test/unit/VariantTest.cpp b/test/unit/VariantTest.cpp
new file mode 100644 (file)
index 0000000..406ad13
--- /dev/null
@@ -0,0 +1,255 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+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"
+    "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\"3.1.1-111\">\n"
+    " <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n"
+    "  <rdf:Description rdf:about=\"\"\n"
+    "    xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n"
+    "    xmlns:xap=\"http://ns.adobe.com/xap/1.0/\"\n"
+    "    xmlns:xapGImg=\"http://ns.adobe.com/xap/1.0/g/img/\"\n"
+    "    xmlns:xapMM=\"http://ns.adobe.com/xap/1.0/mm/\"\n"
+    "    xmlns:stRef=\"http://ns.adobe.com/xap/1.0/sType/ResourceRef#\"\n"
+    "   dc:format=\"application/pdf\"\n"
+    "   xap:CreatorTool=\"Adobe Illustrator CS2\"\n"
+    "   xap:CreateDate=\"2006-01-22T11:41:01-08:00\"\n"
+    "   xap:ModifyDate=\"2006-01-22T16:11:11-08:00\"\n"
+    "   xap:MetadataDate=\"2006-01-22T16:11:11-08:00\"\n"
+    "   xapMM:DocumentID=\"uuid:9D3BA55D8CCC11DA9C1EF28F08BA9E2D\"\n"
+    "   xapMM:InstanceID=\"uuid:c2536d1f-8ba4-11da-9a3c-000d937692d2\">\n"
+    "   <xap:Thumbnails>\n"
+    "    <rdf:Alt>\n"
+    "     <rdf:li\n"
+    "      xapGImg:width=\"256\"\n"
+    "      xapGImg:height=\"92\"\n"
+    "      xapGImg:format=\"JPEG\"\n"
+    "      xapGImg:image=\"/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAXAEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FWmZVU&#xA;sxCqNyTsAMEpACzyUBK5vNGhRNxN0GI/kVmH3gEZqMnb+jgaM79wJ+4U5MdJkPREWmt6VdkLBcoz&#xA;HohPFj8g1DmRp+1dNmNQmCfkfkaYTwTjzCNzYNLsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV&#xA;dirsVdirsVdirsVdirsVdirsVdirsVWSSog3OKsH8165Jd3LWcTUtoTRwP23HWvsM889o+1JZcpw&#xA;xP7uHPzP7HcaLAIx4jzKVWGmXl85S3SoH2nJoo+nNNouzs2pNYxdcz0Dk5c0YcyjrjynrMKc1jWY&#xA;DqI2qfuNCfozYZ/ZzV4xfCJf1S0x1uM9aVtD8wapZ3UdnIGnjZxH6L15qSafCTuPkcu7J7Z1GHIM&#xA;UrnEmuE8x7v1MdRpoSHENmeZ6M6Z2KuxV2KrJpoYY2lmdY41+07GgH0nK8mWOOJlIgRHUpjEk0Eo&#xA;k84aGjUErP7qjU/GmaWftLo4muIn3AuUNFkPRGWGtaZftwtpg8gFShBVqD2IGZ2j7U0+oNY5We7k&#xA;WrJgnDmFtlrum3twbe3kLSqCSCrDYGh3IyGl7X0+fJ4cDcvcU5NPOAs8kwzZtDmIVSx6AVOAmhao&#xA;DT9c07UJWitZC7ovJgVK7Vp3Ga7RdrYNTIxxmyBfIhuy6ecBckfmyaXYq7FUvstf0y8ufq1vIWmo&#xA;TQqw+z13IzV6XtjT58nhwNy9x6N89NOIsjZLvN/5g+TfJ9sk/mPVIbAS1MMTcnmkA6lIow8jD3C0&#xA;zaNDB7b/AJyi/J+a49J9RuIErQTyWs3DrT9gO3/C4rT0rQtf0bX9Lh1TRruO+0+evpXERqp4kqw8&#xA;QQRQg4qj8VdirsVdirsVdirsVdiq2Rwqk4qxzUtQdpCqnbChhTEsxZupNT888WnIyJJ5l6YCgyfT&#xA;YpoLKFo/ssockeLb56p2Lhjj0mMR6xs+88/1Og1UichtVtfN0UU7RTqwRTT1F36e22a0+1GGOWUJ&#xA;RIETXEN7/HxbxoZGIILz3/nIv8wovL/ljT7/AMu3q2/mG8u1SGeMKXWGJS8jFHB6Eou475n4sek1&#xA;eQZ4ESnDu+yx91tZOTGDE7AvBrP/AJyO/OS2lEn+IGmH7Uc1vbOp/wCSVR9BzbuO9O8if85fStcR&#xA;WnnXTUWBzxOqaeGBT3kt2L8h4lG+SnFafSOl6rp2radb6lptzHd2N0gkt7iJgyOp7gj8cUIrFWE+&#xA;d72V7+O0qRFEgbj2LNXf7s4D2r1UpZhi/hiL+JdvoIAR4upRth5e0Wz0xLzVPjLqrMzFgq86UUBf&#xA;nmfo+xdJg04y6jewD1oX02acmpySnwwRGjw+W11MSaZMfVMbKYfiK02NasK9vHMrszFoBqOLTy9X&#xA;CfTvX2/rYZ5ZeCpjZJPKs0cOs3E0h4xxxSs7eABBOaD2fyRhqpyltEQkT8w5esiTjAHeEW3mvW72&#xA;4ddNtv3aCvEKXani3bMuXtDq88yNPDYeXEfi1jR44D1lF6N5pkvJHsr2MR3BVuDrUAkDdSp6HM7s&#xA;vt+WeRxZRU6NH9BHe1Z9IIjijyY9oNzqkFzIdOh9aZ0owKlqLUGvUZzHY+fUY8h8CPFIx7roOdqI&#xA;QIHGaCf6H5pupr4WOoIFkclUcAqQ4/ZYHOk7J9oMk83g5xUjsDy37iHC1GkiI8UXPrPmi6SSeytF&#xA;jtUqQzULED/WIr9Axn2n2jmBnixgYx8/tIv4BRgwx2kd0R5Z8xz6lJJbXKKJUXmroCAQCAajx3GZ&#xA;PYPbc9VI48gHEBdj8ebXq9KMYsckk8pf8pAf9WTNB7Of478JOZrP7r5PkMfpv83PzZWGW74XGt3T&#xA;rDLLVkgtYw0gVF22jiQ0Xap67mueiunfS0H/ADip+UyaYLSW3u5brgFbUPrLrLypu4QfuR8uFMVt&#xA;D695j0v8gPy2sNGt3OtahPPcjSopR6NVZzKzy8eXwxeooNKciRSnZV5mf+cg/wA/bbTIvNFzo8P+&#xA;HZXolw9jKtqwJoAJQ/KhOwbl1xVm/mn/AJyPvZfylsPOPlm3gt9UbVU0zUrG6DTrCTbzTHiVMXIN&#xA;6aFW+Y64qwLUP+csvzAn0vTU021tEv4kd9XuDAzo8jTOIkjTmeKelwqa1LHandWmQ+fP+chPzT8s&#xA;+cbXQRYWMtz9WsHurJIJWdrm4gjkmhjIkLf3jlV2J+eKoC+/5yO/OjynrcMfnDQLeG3uaTCykgkt&#xA;39HlQ+jJzbft8Qb3xV9N6DrVjrmi2OsWDFrPUII7m3JFDwlUMAw7EV3GKEdirsVQ1+SITTFWKt8V&#xA;xv44WKVa1pMtpIJlUm2m3Vh0BPVT/DPMu3uy5afKZgfu5mx5eX6vJ3ukzica/iCvo/mH6nF9WuY/&#xA;VtxXiR9pa/PqMv7H9oDpo+HMcWPpXMfrYanR8ZsbFAak1g1xWyVliIqQ1ftfTXNX2lLTSyXpwRCu&#xA;ve34BMD181TTtE0K6dLzU9Ntr6aIlbWS5hjmMYNORj5q3HkQK08M632S05jilkP8Rr5f2/Y6/tDJ&#xA;cgO5NNQ8neQNetTZ6poNjPEwIB9BEkWu1UkQK6H3U51jr7fJ/wCef5Sj8v8AX4GsJGn0DVA8mnvJ&#xA;u8bRkepC578eYKt3B8QcWTOv+cRvPV7beYbvybcSl9Pvonu7KNjX07iKhcJ4CSOpb3Ue+Kl9XYoY&#xA;l5z0e4klXUIFLqFCTKoqRQ7N8t84v2o7NnKQzwFiql+t2ehzgDhKXw+Zo30xdP1C2NxEgUKyvwJV&#xA;fsg0HamazF27GWnGDPDjiK5GthybpaQifFE035PHLXOSKQnB9utAegrh9mhessDaiut/u1DQ7V7q&#xA;9vbdNnkglVPnUUzH7JwHNlywHOWOdfMM9RPhjE+YVNA1kaLPcx3MDkycQyjZlZK7UNP5ss7H7T/I&#xA;TnHJE+qveCL7/ex1ODxQCC3o8U+o67JerHxiV5JpD2XlUha+NTh7Mxz1WsOYCo3KR8rvb8e9c5EM&#xA;Yj15KHl3WItLu5JpY2kSROB40qNwe/yzH7F7SjpMplIEgitmepwHJGgrWBm1XzMl1FGVX1lmcD9l&#xA;UIO596Uy/RmWs7QGSIocYkfID+z5sMlY8NHupr9K/XryX9Lzyx26q3C2jqBzBoE4j+OD+UPzGWX5&#xA;qUowANRF8+ka/X80+DwRHABfe35Qu4rbV6S1rOnopQftM6kV+7JezWpji1Xq/jHCPeSEa2BlDbpu&#xA;qeUv+UgP+rJlns5/jvwkjWf3XyfKn5i+TPNf5UfmINVsI3hso7s3eg6iE5QlCxZYmJqvJAeDqeo3&#xA;6EZ6K6d6UP8AnM2UacoPlZTqPGjOLwiDl/MF9IvT/J5fTitMc/N3/Gnnz8r/ACx+YF9Z1NvLfxah&#xA;FbxMqQQyTD0JApLN6dIqFyfDffFULrf/ADkBp2o/knb+Qk0mRNTS1trCa6LJ9XEVo0ZWVQPjLv6W&#xA;4IAB3qemKpLqPlHWNE/5x9i1HUoXtv0z5itpbSCQFWMEVjdKsvE9OZY023AB6UxV9E/84y6NpkX5&#xA;NaXMtshk1OW6mviyhvUeO6khQtXrRIlAxQXhn5+6nHpX/OQbapKhkjsJdNuXjWgZlhjicgV7njil&#xA;Q/PX819P/NLVNBsvLmmXQFj6qRCVVNxNNd+l+7WKIyfZMVB8RqTir6x/Lfy/deXfIehaJd0F3Y2c&#xA;UdyFPICXjykAPcBiRihkeKuxVSuY+cZGKsWvIHimJphYoqK8jktjDKAyEUKtuD9+QyY4ziYyFxPQ&#xA;shIjcJFdaRbNIfRYxgnp1GczqvZTBM3jkYfaP1/a5uPtCY5i1K+0J7LSrzVLi4jSzsYJLm4dqikc&#xA;KF3PT+Vc1UvZHNe04/a5A7Rj3Fhv5PfnR5Z822EOj6q8Wl+Y4/gSF24w3Irs0LN+34oTXuK9u10m&#xA;mjgxjHH6YutySMpEl6RcRPbyeGZLU+c/+cn/AD3perT6X5bsZluJtLeWbUJENVSR1VEiqP2gAxYd&#xA;tu9cDIJX/wA4paVc3n5rR3kY/c6bZ3E07dqSKIFHzJlr9GKS+0MUOxVDvp2nu/N7WFn/AJjGpP3k&#xA;Ziy0WCRswgT/AFQzGWQ6lWjijjXjGgRf5VAA/DL4Y4xFRAA8mJJPNZFaWsT84oY43OxZVAO/uBkI&#xA;abHA3GMQfIBJnI8y1PZWc5BngjlI6F0Vv1jBl0uLIbnGMveAUxySHIkKkcUUacI0VE/lUAD7hlkM&#xA;cYiogAMSSeakLCxUELbRAMKMAi7jrvtlQ0eEWBCO/kGXiS7yqQwQQrwhjWNf5UAUfcMsx4oYxUQI&#xA;jyFMZSJ5rDZ2Zm9YwRmYdJSi8v8AgqVyB0uIy4+GPF30L+aeOVVezaWdokplSCNZTuZAqhj9IFcY&#xA;6bFGXEIxEu+hamciKt0dnaRPzjgjR/5lVQd/cDGGmxQNxjEHyAUzkdiW7m1truB7e6hSe3kFJIZV&#xA;Dow60ZWqDl7FJ7XyH5HtJ/rFr5d0y3nJ5GaKzt0fl48lQGuKp2VUrxIHGlKdqYqkkXkTyPDefXof&#xA;L2mR3oNfrSWdustQa15hOXbxxVMdS0jStUgW31OygvoFYSLDcxJMgcAgMFcMK0YiuKqljYWNhapa&#xA;WFtFaWsVfTt4EWONeRLHiiAKKsScVfLv5seTPN1//wA5D2uqWehahd6SLvS2e+htJpLcLGIvUJlV&#xA;ClFoeW+2KX0nYeUfKmnXrX2n6LYWd6wo11b20MUpHu6KG/HFCbYq7FXYq7FULdWSTDpviqUz6M4J&#xA;4jCikJJYSQkMw2GKFbVdI0vzF5cvtBv3dLTUIWgnaF+EgVv5W/zHjgSHyH+Yf/OO/nrynNLcWUDa&#xA;7ooJMd5ZqWlVe3rQCrqfEryX3xZWwX/F3nCK0bTv01qEdotUaz+tTiMU2KmPlx7dKYqh9C8va55g&#xA;1KPTdFsZtQvpT8MMCljSv2mPRVHdm2HfFL7Z/Ir8pV/L3yy63hSXX9TKy6nKh5IgSvpwIe4Tkanu&#xA;xPamLF6ViqSXtxrsOo2tqlxBxvGlCExNVBGvPf499tsVXJra2l7PbalOi+kkJWRUYAl+XIn7VBsO&#xA;uKo6bV9NhuRayXCrOSAV32LdAx6CvauKoHV9TurfUYbaK4gto3haVpZxUVVgKfaXxxV1h5nsZLOB&#xA;7yRYLiUf3YDUNWKqw2J4nj3xVFjXNJN0bUXKGcMU4b/aHVQaUJ9sVXjVtN9OGT6wvCdWeJjsCqCr&#xA;H2A71xVYmuaS9vJcLcr6UXH1GIIoGPFTQitCehxVWstQs71Xa2kEgQ8X2IIPXowBxVIrTzXIscwv&#xA;YSZSzixEYNJuL8OA60YNiqMsfMESadHPqsiQTvJJHxUEisb8TQDl07nFUXca5pVvIsc1wqu4VlAD&#xA;NVX+ydgdsVU7DV45IlFy6rNJNNFEgBqRE5Fab9ANz0xVcNf0gxzOtwrCBS70B3UbVXb4hXaoxVUh&#xA;1GK505ry3rQIWAYEUIXlQ1xVqwvxJpEF9dMsfOJZJW+yoqKnriq39PaR9Xe4+sqIoyFeoYMC3QcS&#xA;OW9Ntt8VXNrWlrax3RuFMMxpEwBJYjYgKAWqPliqFsvMFqdNhur2ZY2maUIADuqSMoPEVPQCpxVE&#xA;3Gu6RbmMS3Kgyqrx0q1VYkBhxB22xVHYq7FXYq7FXUGKoO/tvUjIAxVIHhuYGqOmFi017clab4ql&#xA;V35X0XVrgS3+mWt5L09SeCORqfN1JxVlHl7QdO0q39KxtIbSI7mOCNI1r8kAGBknOKuxVA3llNNq&#xA;en3KU9O1Mplqd/jj4in04qhr3SrmdtVK8f8ATYI44an9pA4NdtvtDFUFc+W7o3czosU0NwUdlllm&#xA;TgygA/DGQrjaoriqZ3OmevrEF3IiSW8ULoVcVPMsCCAR7YqvhsGTVprshfSeCOKMDqOLMSKeG4xV&#xA;LI9E1MJDYOYfqEE/ricFvWYBy4FKUDb0JrirZ8rcm1EGWkVwpSzXf90HPqPt4c/wxVTTy/fG3mV4&#xA;4UlYQorLNPIWEcquf7wkKKDYAYqnFrZyxalfXLU9O59LhTr8CcTXFVLSNMNtaJHcqjyxyySxsPi4&#xA;82YggkbGjYql8+iao1mLeN4wjvcmVebJUTMSnxKpNB3XviqK0vTLuC8W4uAgpaR29FJb4kJr1A2I&#xA;piqEg8vXkEzzoyM1wZormNidopXZg0bU+Fhy3HQ4qstPLV5GjwyrDxFvJbpcCSZnPqLxBCMeC+9P&#xA;oxVNbK31AaUbW6EQlWP0o/SLEEBOIJ5AdTiqWDStcm0ldJnSCO3EYT11di1U3Xag6sorircWi6rH&#xA;HK0aQwzu0YZlmmd3VCeQ9STmUqDtQVxVuz0TVLQQSx+iZbV5/ThLuVZJiD9srVWHToa4qpf4cv8A&#xA;0bWWkbXEQmWWEyyxqRLK0g4vHQ7ct8VTDTNIltbtJWSNUW0W34oWYBhIzsBzq3H4h1OKptirsVdi&#xA;rsVdirqYqpSW0bjcYqhzpkJPTFFKkVjFGagYpRIAA2xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2K&#xA;uxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Ku&#xA;xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux&#xA;V2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV&#xA;2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV//9k=\"/>\n"
+    "    </rdf:Alt>\n"
+    "   </xap:Thumbnails>\n"
+    "   <xapMM:DerivedFrom\n"
+    "    stRef:instanceID=\"uuid:80a15048-8a07-11da-95c4-000d937692d2\"\n"
+    "    stRef:documentID=\"uuid:912BD87F8B5211DA82D09FC838327668\"/>\n"
+    "  </rdf:Description>\n"
+    " </rdf:RDF>\n"
+    "</x:xmpmeta>\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<</Length 0>>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<pdf_long>(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<pdf_int64>(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<pdf_int64>(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<long>(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<pdf_int64>(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<const PdfVariant>(varArray).GetArray();
+    (void)static_cast<const PdfVariant>(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<const PdfParserObject*>(&parser)->GetStream();
+    CPPUNIT_ASSERT_EQUAL( static_cast<long>(pStream->GetLength()), 9381L );
+    CPPUNIT_ASSERT_EQUAL_MESSAGE( "STREAM    IsDirty() == false", false, parser.IsDirty() );
+}
diff --git a/test/unit/VariantTest.h b/test/unit/VariantTest.h
new file mode 100644 (file)
index 0000000..0521a84
--- /dev/null
@@ -0,0 +1,54 @@
+/***************************************************************************
+ *   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 <cppunit/extensions/HelperMacros.h>
+
+/** 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_
+
+
diff --git a/test/unit/cppunitextensions.h b/test/unit/cppunitextensions.h
new file mode 100644 (file)
index 0000000..ab99bbe
--- /dev/null
@@ -0,0 +1,100 @@
+/***************************************************************************
+ *   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 <cppunit/extensions/HelperMacros.h>
+#include <new>
+#include <exception>
+
+// 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<int> 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<int> v;
+ *  CPPUNIT_ASSERT_THROW_MESSAGE( "- std::vector<int> 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)
+
diff --git a/test/unit/main.cpp b/test/unit/main.cpp
new file mode 100644 (file)
index 0000000..43d497b
--- /dev/null
@@ -0,0 +1,104 @@
+/***************************************************************************
+ *   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 <cppunit/CompilerOutputter.h>
+#include <cppunit/XmlOutputter.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+
+#include <iostream>
+#include <podofo.h>
+
+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<argc;i++)
+      {
+          std::string argument(argv[i]);
+          
+          if( argument=="--help" || argument=="-help")
+          {
+              show_help();
+              return 0;
+          }
+          else if(argument=="--selftest" || argument=="-selftest")
+          {
+              bSelfTest = true;
+          }
+          else if((argument=="--test" || argument=="-test") && i+1 < argc) 
+          {
+              if( i == argc - 1 ) 
+              {
+                  show_help();
+                  return 0;
+              }
+
+              i++;
+              sTestName = argv[i];
+          }
+      }
+  }
+
+  if( bSelfTest ) 
+  {
+      // Change the default outputter to a compiler error format outputter
+      runner.setOutputter( new CppUnit::CompilerOutputter( &runner.result(),
+                                                           std::cerr ) );
+  }
+  else
+  {
+      // Change the default outputter to a xml format outputter
+      // The test runner owns the new outputter.
+      CppUnit::XmlOutputter *xmlOutputter = new 
+          CppUnit::XmlOutputter( &runner.result(), std::cerr ) ;
+      runner.setOutputter(xmlOutputter);
+  }
+
+  // Enable PoDoFo debugging and logging
+  PoDoFo::PdfError::EnableLogging( true );
+  PoDoFo::PdfError::EnableDebug( true );
+
+  // Run the tests.
+  bool wasSucessful = runner.run( sTestName );
+
+  // Return error code 1 if the one of test failed.
+  return wasSucessful ? 0 : 1;
+}
diff --git a/test/valgrind.suppressions b/test/valgrind.suppressions
new file mode 100644 (file)
index 0000000..dab13ee
--- /dev/null
@@ -0,0 +1,7 @@
+{
+   SeeZLibFAQ
+   Memcheck:Cond
+   obj:/usr/lib/libz.so.1.2.3
+   obj:/usr/lib/libz.so.1.2.3
+   fun:deflate
+}
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b1f513c
--- /dev/null
@@ -0,0 +1,24 @@
+SUBDIRS(
+       podofobox
+       podofocolor
+        podofocountpages
+        podofocrop
+       podofoencrypt
+       podofogc
+       podofoimgextract
+       podofoimg2pdf
+       podofomerge
+       podofopages
+       podofopdfinfo
+       podofotxt2pdf
+       podofotxtextract
+       podofouncompress
+       podofoimpose
+       podofoincrementalupdates
+       podofoxmp
+       podofonooc
+       )
+
+IF(PODOFO_HAVE_OPENSSL)
+       SUBDIRS(podofosign)
+ENDIF(PODOFO_HAVE_OPENSSL)
diff --git a/tools/podofobox/CMakeLists.txt b/tools/podofobox/CMakeLists.txt
new file mode 100644 (file)
index 0000000..68db3a4
--- /dev/null
@@ -0,0 +1,7 @@
+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")
diff --git a/tools/podofobox/boxsetter.cpp b/tools/podofobox/boxsetter.cpp
new file mode 100644 (file)
index 0000000..5b3ae4d
--- /dev/null
@@ -0,0 +1,71 @@
+/***************************************************************************
+ *   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();
+}
+
diff --git a/tools/podofobox/boxsetter.h b/tools/podofobox/boxsetter.h
new file mode 100644 (file)
index 0000000..fd0b87e
--- /dev/null
@@ -0,0 +1,40 @@
+/***************************************************************************
+ *   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
diff --git a/tools/podofobox/podofobox.cpp b/tools/podofobox/podofobox.cpp
new file mode 100644 (file)
index 0000000..1616fa0
--- /dev/null
@@ -0,0 +1,68 @@
+/***************************************************************************
+ *   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;
+}
diff --git a/tools/podofocolor/CMakeLists.txt b/tools/podofocolor/CMakeLists.txt
new file mode 100644 (file)
index 0000000..07a4fea
--- /dev/null
@@ -0,0 +1,29 @@
+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")
diff --git a/tools/podofocolor/colorchanger.cpp b/tools/podofocolor/colorchanger.cpp
new file mode 100644 (file)
index 0000000..4e45a2d
--- /dev/null
@@ -0,0 +1,609 @@
+/***************************************************************************
+ *   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;
+
+            if( pInfo->nNumArguments > 0 && args.size() != static_cast<size_t>( pInfo->nNumArguments ) )
+            {
+                std::ostringstream oss;
+                oss << "Expected " << pInfo->nNumArguments << " argument(s) for keyword '" << pszKeyword << "', but " << args.size() << " given instead.";
+                PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidContentStream, oss.str().c_str() );
+            }
+
+            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;
+}
diff --git a/tools/podofocolor/colorchanger.h b/tools/podofocolor/colorchanger.h
new file mode 100644 (file)
index 0000000..e83fb96
--- /dev/null
@@ -0,0 +1,136 @@
+/***************************************************************************
+ *   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_
diff --git a/tools/podofocolor/colorspace.cpp b/tools/podofocolor/colorspace.cpp
new file mode 100644 (file)
index 0000000..c534be0
--- /dev/null
@@ -0,0 +1,70 @@
+/***************************************************************************
+ *   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);
+}
diff --git a/tools/podofocolor/colorspace.h b/tools/podofocolor/colorspace.h
new file mode 100644 (file)
index 0000000..9c1a2e2
--- /dev/null
@@ -0,0 +1,81 @@
+/***************************************************************************
+ *   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_
diff --git a/tools/podofocolor/dummyconverter.cpp b/tools/podofocolor/dummyconverter.cpp
new file mode 100644 (file)
index 0000000..1a9b979
--- /dev/null
@@ -0,0 +1,79 @@
+/***************************************************************************
+ *   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 );
+}
diff --git a/tools/podofocolor/dummyconverter.h b/tools/podofocolor/dummyconverter.h
new file mode 100644 (file)
index 0000000..d566002
--- /dev/null
@@ -0,0 +1,87 @@
+/***************************************************************************
+ *   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_
diff --git a/tools/podofocolor/example.lua b/tools/podofocolor/example.lua
new file mode 100644 (file)
index 0000000..913f907
--- /dev/null
@@ -0,0 +1,195 @@
+-- /***************************************************************************
+--  *   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
diff --git a/tools/podofocolor/graphicsstack.cpp b/tools/podofocolor/graphicsstack.cpp
new file mode 100644 (file)
index 0000000..060824d
--- /dev/null
@@ -0,0 +1,55 @@
+/***************************************************************************
+ *   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();
+}
diff --git a/tools/podofocolor/graphicsstack.h b/tools/podofocolor/graphicsstack.h
new file mode 100644 (file)
index 0000000..21458cb
--- /dev/null
@@ -0,0 +1,140 @@
+/***************************************************************************
+ *   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_
diff --git a/tools/podofocolor/grayscaleconverter.cpp b/tools/podofocolor/grayscaleconverter.cpp
new file mode 100644 (file)
index 0000000..a8d0779
--- /dev/null
@@ -0,0 +1,76 @@
+/***************************************************************************
+ *   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();
+}
diff --git a/tools/podofocolor/grayscaleconverter.h b/tools/podofocolor/grayscaleconverter.h
new file mode 100644 (file)
index 0000000..209f5d5
--- /dev/null
@@ -0,0 +1,86 @@
+/***************************************************************************
+ *   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_
diff --git a/tools/podofocolor/iconverter.cpp b/tools/podofocolor/iconverter.cpp
new file mode 100644 (file)
index 0000000..31bc4a6
--- /dev/null
@@ -0,0 +1,29 @@
+/***************************************************************************
+ *   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()
+{
+}
diff --git a/tools/podofocolor/iconverter.h b/tools/podofocolor/iconverter.h
new file mode 100644 (file)
index 0000000..cffc3d9
--- /dev/null
@@ -0,0 +1,127 @@
+/***************************************************************************
+ *   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_
diff --git a/tools/podofocolor/lua_compat.h b/tools/podofocolor/lua_compat.h
new file mode 100644 (file)
index 0000000..1d0e92d
--- /dev/null
@@ -0,0 +1,48 @@
+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
diff --git a/tools/podofocolor/luaconverter.cpp b/tools/podofocolor/luaconverter.cpp
new file mode 100644 (file)
index 0000000..b3d3d0d
--- /dev/null
@@ -0,0 +1,222 @@
+/***************************************************************************
+ *   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 );
+}
+
diff --git a/tools/podofocolor/luaconverter.h b/tools/podofocolor/luaconverter.h
new file mode 100644 (file)
index 0000000..88bfc7d
--- /dev/null
@@ -0,0 +1,154 @@
+/***************************************************************************
+ *   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_
diff --git a/tools/podofocolor/podofocolor.cpp b/tools/podofocolor/podofocolor.cpp
new file mode 100644 (file)
index 0000000..273af23
--- /dev/null
@@ -0,0 +1,127 @@
+/***************************************************************************
+ *   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;
+}
diff --git a/tools/podofocountpages/CMakeLists.txt b/tools/podofocountpages/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c2d8a6f
--- /dev/null
@@ -0,0 +1,7 @@
+ADD_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")
diff --git a/tools/podofocountpages/countpages.cpp b/tools/podofocountpages/countpages.cpp
new file mode 100644 (file)
index 0000000..5a0c4f7
--- /dev/null
@@ -0,0 +1,102 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+#include <cstdlib>
+#include <cstdio>
+
+using namespace PoDoFo;
+
+#ifdef _HAVE_CONFIG
+#include <config.h>
+#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<argc;i++) 
+        {
+            const char* pszArg = argv[i];
+
+            if( strcmp(pszArg, "-s") == 0 ) 
+            {
+                bShortFormat = true;
+            }
+            else if( strcmp(pszArg, "-t") == 0 ) 
+            {
+                bTotal = true;
+            }
+            else
+            {
+                sum += count_pages( pszArg, bShortFormat );
+            }
+        }
+
+        if( bTotal ) 
+        {
+            printf("Total:\t%i\n", sum );
+        }
+    } 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;
+}
+
diff --git a/tools/podofocrop/CMakeLists.txt b/tools/podofocrop/CMakeLists.txt
new file mode 100644 (file)
index 0000000..fc107dc
--- /dev/null
@@ -0,0 +1,7 @@
+ADD_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")
diff --git a/tools/podofocrop/podofocrop.cpp b/tools/podofocrop/podofocrop.cpp
new file mode 100644 (file)
index 0000000..1e2ecf4
--- /dev/null
@@ -0,0 +1,244 @@
+/***************************************************************************
+ *   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 <cstdio>
+
+#include <vector>
+
+#ifdef _WIN32
+# include <windows.h>
+# ifdef GetObject
+#  undef GetObject
+# endif 
+#else
+# include <unistd.h>
+# include <sys/types.h> 
+# include <sys/wait.h> 
+#endif // _WIN32
+
+using namespace PoDoFo;
+
+#ifdef _HAVE_CONFIG
+#include <config.h>
+#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 );
+    if (!pPage)
+    {
+        PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle,
+                                "crop_page: No page pointer given" );
+    }
+    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];
+
+    STARTUPINFOA si;\r
+    PROCESS_INFORMATION pi;\r
+\r
+    ZeroMemory( &si, sizeof(si) );\r
+    si.cb = sizeof(si);\r
+    ZeroMemory( &pi, sizeof(pi) );\r
+\r
+    // Fenster nicht sichtbar\r
+    si.dwFlags=STARTF_USESHOWWINDOW;\r
+    si.wShowWindow=SW_HIDE;\r
+\r
+    // Ausgabe umleiten\r
+    HANDLE pipe;\r
+    CreatePipe(&pipe, 0, 0, 0 );\r
+    si.dwFlags|=STARTF_USESTDHANDLES;\r
+    //si.hStdOutput=pipe_wr;\r
+       si.hStdError = pipe;\r
+\r
+       \r
+       _snprintf(cmd, lBufferLen, "gs -dSAFER -sDEVICE=bbox -sNOPAUSE -q %s -c quit", pszInput);
+       printf("Running %s\n", cmd );\r
+    if( !CreateProcessA( NULL, cmd, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi ) ) \r
+    {\r
+               printf("CreateProcess failed.");\r
+        exit(1);\r
+    }\r
+\r
+    while( ReadFile(pipe,buffer,lBufferLen,&count,NULL) && GetLastError() != ERROR_BROKEN_PIPE && count > 0)\r
+    {
+               printf("%s",buffer);
+        sOutput.append( buffer, count );
+    }
+\r
+       // eigenes Handle schliessen\r
+    CloseHandle(pipe);\r
+       CloseHandle( pi.hProcess );\r
+       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<PdfRect> get_crop_boxes( const char* pszInput )
+{
+    std::vector<PdfRect> 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<double>(x), 
+                               static_cast<double>(y),
+                               static_cast<double>(w-x),
+                               static_cast<double>(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<PdfRect> cropBoxes = get_crop_boxes( pszInput );
+
+        PdfMemDocument doc;
+        doc.Load( pszInput );
+
+        if( static_cast<int>(cropBoxes.size()) != doc.GetPageCount() ) 
+        {
+            printf("Number of cropboxes obtained form ghostscript does not match with page count (%i, %i)\n",
+                   static_cast<int>(cropBoxes.size()), doc.GetPageCount() );
+            PODOFO_RAISE_ERROR( ePdfError_InvalidHandle );
+        }
+
+        for( int i=0;i<doc.GetPageCount(); i++ ) 
+        {
+            PdfPage* pPage = doc.GetPage( i ); 
+            crop_page( pPage, cropBoxes[i] );
+        }
+
+        doc.Write( pszOutput );
+        
+    } catch( PdfError & e ) {
+        fprintf( stderr, "Error: An error %i ocurred during croppping pages in the pdf file.\n", e.GetError() );
+        e.PrintErrorMsg();
+        return e.GetError();
+    }
+    
+    return 0;
+}
+
diff --git a/tools/podofoencrypt/CMakeLists.txt b/tools/podofoencrypt/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9d97e9c
--- /dev/null
@@ -0,0 +1,6 @@
+ADD_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")
diff --git a/tools/podofoencrypt/podofoencrypt.cpp b/tools/podofoencrypt/podofoencrypt.cpp
new file mode 100644 (file)
index 0000000..85c86d7
--- /dev/null
@@ -0,0 +1,238 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+using namespace PoDoFo;
+
+#include <cstdlib>
+#include <cstdio>
+
+#ifdef _HAVE_CONFIG
+#include <config.h>
+#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 PODOFO_HAVE_OPENSSL_NO_RC4
+        case PdfEncrypt::ePdfEncryptAlgorithm_RC4V1:
+            eKeyLength = PdfEncrypt::ePdfKeyLength_40;
+            eVersion   = ePdfVersion_1_3;
+            break;
+#endif // PODOFO_HAVE_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 PODOFO_HAVE_OPENSSL_NO_RC4
+        case PdfEncrypt::ePdfEncryptAlgorithm_RC4V2:
+#endif // PODOFO_HAVE_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 <userpassword>]\n");
+    printf("                     -o <ownerpassword> <inputfile> <outputfile>\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 <password> An optional userpassword\n");
+    printf("       -o <password> 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 changing 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 the creation 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<argc;i++ ) 
+  {
+      if( argv[i][0] == '-' ) 
+      {
+#ifndef PODOFO_HAVE_OPENSSL_NO_RC4
+          if( strcmp( argv[i], "--rc4v1" ) == 0 ) 
+              eAlgorithm = PdfEncrypt::ePdfEncryptAlgorithm_RC4V1;
+          else if( strcmp( argv[i], "--rc4v2" ) == 0 ) 
+              eAlgorithm = PdfEncrypt::ePdfEncryptAlgorithm_RC4V2;
+          else
+#endif // PODOFO_HAVE_OPENSSL_NO_RC4
+          if( strcmp( argv[i], "--aesv2" ) == 0 ) 
+              eAlgorithm = PdfEncrypt::ePdfEncryptAlgorithm_AESV2;
+#ifdef PODOFO_HAVE_LIBIDN
+          else if( strcmp( argv[i], "--aesv3" ) == 0 ) 
+              eAlgorithm = PdfEncrypt::ePdfEncryptAlgorithm_AESV3;
+#endif // PODOFO_HAVE_LIBIDN
+          else if( strcmp( argv[i], "-u" ) == 0 ) 
+          {
+              ++i;
+              if( i < argc ) 
+                  userPass = argv[i];
+              else
+              {
+                  fprintf( stderr, "ERROR: -u given on the commandline but no userpassword!\n");
+                  exit( -1 );
+              }
+          }
+          else if( strcmp( argv[i], "-o" ) == 0 ) 
+          {
+              ++i;
+              if( i < argc ) 
+                  ownerPass = argv[i];
+              else
+              {
+                  fprintf( stderr, "ERROR: -o given on the commandline but no ownerpassword!\n");
+                  exit( -1 );
+              }
+          }
+          else if( strcmp( argv[i], "--help" ) == 0 ) 
+          {
+              print_help();
+              exit( -1 );
+          }
+          else if( strcmp( argv[i], "--print" ) == 0 ) 
+              nPerm |= PdfEncrypt::ePdfPermissions_Print;
+          else if( strcmp( argv[i], "--edit" ) == 0 ) 
+              nPerm |= PdfEncrypt::ePdfPermissions_Edit;
+          else if( strcmp( argv[i], "--copy" ) == 0 ) 
+              nPerm |= PdfEncrypt::ePdfPermissions_Copy;
+          else if( strcmp( argv[i], "--editnotes" ) == 0 ) 
+              nPerm |= PdfEncrypt::ePdfPermissions_EditNotes;
+          else if( strcmp( argv[i], "--fillandsign" ) == 0 ) 
+              nPerm |= PdfEncrypt::ePdfPermissions_FillAndSign;
+          else if( strcmp( argv[i], "--accessible" ) == 0 ) 
+              nPerm |= PdfEncrypt::ePdfPermissions_Accessible;
+          else if( strcmp( argv[i], "--assemble" ) == 0 ) 
+              nPerm |= PdfEncrypt::ePdfPermissions_DocAssembly;
+          else if( strcmp( argv[i], "--highprint" ) == 0 ) 
+              nPerm |= PdfEncrypt::ePdfPermissions_HighPrint;
+          else
+          {
+              fprintf( stderr, "WARNING: Do not know what to do with argument: %s\n", argv[i] );
+          }
+      }
+      else
+      {
+          if( !pszInput )
+          {
+              pszInput = argv[i];
+          }
+          else if( !pszOutput )
+          {
+              pszOutput = argv[i];
+          }
+          else
+          {
+              fprintf( stderr, "WARNING: Do not know what to do with argument: %s\n", argv[i] );
+          }
+
+      }
+  }
+
+  // Check for errors in the commandline options
+  if( !pszInput ) 
+  {
+      fprintf( stderr, "ERROR: No input file specified\n");
+      exit( -1 );
+  }
+
+  if( !pszOutput )
+  {
+      fprintf( stderr, "ERROR: No output file specified\n");
+      exit( -1 );
+  }
+
+  if( !ownerPass.length() )
+  {
+      fprintf( stderr, "ERROR: No owner password specified\n");
+      exit( -1 );
+  }
+      
+
+  // Do the actual encryption
+  try {
+      encrypt( pszInput, pszOutput, userPass, ownerPass, eAlgorithm, nPerm );
+  } catch( PdfError & e ) {
+      fprintf( stderr, "Error: An error %i ocurred during encrypting the pdf file.\n", e.GetError() );
+      e.PrintErrorMsg();
+      return e.GetError();
+  }
+
+
+  printf("%s was successfully encrypted to: %s\n", pszInput, pszOutput );
+  
+  return 0;
+}
+
diff --git a/tools/podofogc/CMakeLists.txt b/tools/podofogc/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3367bf0
--- /dev/null
@@ -0,0 +1,7 @@
+ADD_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")
diff --git a/tools/podofogc/podofogc.cpp b/tools/podofogc/podofogc.cpp
new file mode 100644 (file)
index 0000000..ff95087
--- /dev/null
@@ -0,0 +1,97 @@
+/***************************************************************************
+ *   Copyright (C) 2010 by Ian Ashley                                      *
+ *   Ian Ashley <Ian.Ashley@opentext.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 <iostream>
+#include <cstdlib>
+#include <cstdio>
+
+#include <podofo.h>
+
+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 <input_filename> <output_filename>\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;
+}
diff --git a/tools/podofoimg2pdf/CMakeLists.txt b/tools/podofoimg2pdf/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6192147
--- /dev/null
@@ -0,0 +1,6 @@
+ADD_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")
diff --git a/tools/podofoimg2pdf/ImageConverter.cpp b/tools/podofoimg2pdf/ImageConverter.cpp
new file mode 100644 (file)
index 0000000..4406835
--- /dev/null
@@ -0,0 +1,81 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+ImageConverter::ImageConverter() 
+    : m_bUseImageSize( false )
+{
+}
+
+ImageConverter::~ImageConverter() 
+{
+}
+
+void ImageConverter::Work() 
+{
+    PoDoFo::PdfMemDocument document;
+
+    std::vector<std::string>::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() );
+}
+
diff --git a/tools/podofoimg2pdf/ImageConverter.h b/tools/podofoimg2pdf/ImageConverter.h
new file mode 100644 (file)
index 0000000..c9b09a8
--- /dev/null
@@ -0,0 +1,47 @@
+/***************************************************************************
+ *   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 <string>
+#include <vector>
+
+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<std::string> m_vecImages;
+    std::string              m_sOutputFilename;
+    bool                     m_bUseImageSize;
+};
diff --git a/tools/podofoimg2pdf/podofoimg2pdf.cpp b/tools/podofoimg2pdf/podofoimg2pdf.cpp
new file mode 100644 (file)
index 0000000..c03a382
--- /dev/null
@@ -0,0 +1,94 @@
+/***************************************************************************
+ *   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 <stdio.h>
+#include <stdlib.h>
+
+#ifdef _HAVE_CONFIG
+#include <config.h>
+#endif // _HAVE_CONFIG
+
+#include "ImageConverter.h"
+#include <podofo.h>
+
+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<argc;i++ ) 
+  {
+      std::string sOption = argv[i];
+      if( sOption == "-useimgsize" ) 
+      {
+          converter.SetUseImageSize( true );
+      }
+      else 
+      {
+          printf("Adding image: %s\n", argv[i]);
+          converter.AddImage( argv[i] );
+      }
+  }
+  
+  try {
+      converter.Work();
+  } catch( PoDoFo::PdfError & e ) {
+      fprintf( stderr, "Error: An error %i ocurred during processing the pdf file.\n", e.GetError() );
+      e.PrintErrorMsg();
+      return e.GetError();
+  }
+
+  printf("Wrote PDF successfully: %s.\n", pszOutput );
+  
+  return 0;
+}
diff --git a/tools/podofoimgextract/CMakeLists.txt b/tools/podofoimgextract/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b3d5af8
--- /dev/null
@@ -0,0 +1,6 @@
+ADD_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")
diff --git a/tools/podofoimgextract/ImageExtractor.cpp b/tools/podofoimgextract/ImageExtractor.cpp
new file mode 100644 (file)
index 0000000..eec08ed
--- /dev/null
@@ -0,0 +1,150 @@
+/***************************************************************************
+ *   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 <sys/stat.h>
+#include <stdlib.h>
+#include <cstdio>
+
+#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<char*>(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<PdfMemStream*>(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%" PDF_FORMAT_INT64 " %" PDF_FORMAT_INT64 "\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;
+}
diff --git a/tools/podofoimgextract/ImageExtractor.h b/tools/podofoimgextract/ImageExtractor.h
new file mode 100644 (file)
index 0000000..7ed79f9
--- /dev/null
@@ -0,0 +1,81 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+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_
diff --git a/tools/podofoimgextract/podofoimgextract.cpp b/tools/podofoimgextract/podofoimgextract.cpp
new file mode 100644 (file)
index 0000000..0c8db90
--- /dev/null
@@ -0,0 +1,66 @@
+/***************************************************************************
+ *   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 <stdio.h>
+#include <stdlib.h>
+
+#ifdef _HAVE_CONFIG
+#include <config.h>
+#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 successfully from the PDF file.\n", nNum );
+  
+  return 0;
+}
diff --git a/tools/podofoimgextract/podofoimgextract.vcproj b/tools/podofoimgextract/podofoimgextract.vcproj
new file mode 100644 (file)
index 0000000..1758b0e
--- /dev/null
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.10"\r
+       Name="podofoimgextract"\r
+       ProjectGUID="{BA4F7BBC-F203-4EC5-AD49-61F8D688ED48}"\r
+       Keyword="Win32Proj">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..\src;..\..\freetype\include;..\..\zlib;..\..\jpeg"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"\r
+                               MinimalRebuild="TRUE"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="4"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="wsock32.lib"\r
+                               OutputFile="$(OutDir)/podofoimgextract.exe"\r
+                               LinkIncremental="2"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(OutDir)/podofoimgextract.pdb"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"\r
+                               RuntimeLibrary="4"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="3"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(OutDir)/podofoimgextract.exe"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="TRUE"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">\r
+                       <File\r
+                               RelativePath=".\ImageExtractor.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\podofoimgextract.cpp">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">\r
+                       <File\r
+                               RelativePath=".\ImageExtractor.h">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/tools/podofoimpose/CMakeLists.txt b/tools/podofoimpose/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d9aa3d2
--- /dev/null
@@ -0,0 +1,29 @@
+# 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")
diff --git a/tools/podofoimpose/README.html b/tools/podofoimpose/README.html
new file mode 100644 (file)
index 0000000..3c04ed7
--- /dev/null
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+  <title>PodofoImpose - some words</title>
+  <meta name="AUTHOR" content="Pierre Marchand"/>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+  <style type="text/css">
+body{
+       width:360pt;
+       margin:auto;
+       font-family:sans-serif;
+       font-size:11.2pt;
+}
+.section{
+/*     background-color:#ddd; */
+       border-left:1pt solid #333;
+       padding-left:12pt;
+       
+}
+.code-abs{
+       font-family:mono;
+       font-weight:bold;
+       font-size:9pt;
+       background-color:#eee;
+       color:#222;
+}
+.command{
+       font-family:monospace;
+       font-size:9pt;
+       background-color:#222;
+       color:#eee;
+       padding:6pt;
+}
+.file{
+       border:1pt dotted black;
+       width:90%;
+       margin:12pt auto;
+}
+.file .name{
+       text-align:right;
+       font-family:monospace;
+       font-weight:bold;
+       font-size:8pt;
+       background-color:#eee;
+}
+.file .content{
+       margin:0;
+       padding:0;
+       border:0;
+       white-space:pre;
+}
+  </style>
+</head>
+<body>
+       <h2>PodofoImpose</h2>
+       <div id="intro">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).
+       </div>
+       
+       <h3>Plan (built-in)</h3>
+       <div class="section"><!-- Plan own -->
+               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.
+               <h4>Records</h4>
+               <div>
+                       Most of the PLAN file is composed of record lines of the form:
+                       <div class="code-abs">
+                               source page; target page; rotation; horizontal translation; vertical translation;
+                       </div>
+                       Each element of the record can be a numeric value, a constant or an expression involving both numerics and constants.
+               </div>
+               <h4>Constants</h4>
+               <div>
+                       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:
+                       <div class="code-abs">
+                               $MyConstant = 123.456
+                       </div>
+                       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:
+                       <div class="code-abs">
+                               $MyConstant = $AnotherConst * .5;
+                       </div>
+                       Source document pages count is provided as "$PageCount".
+                       Source first page geometry is provided as "$SourceWidth" and "$SourceHeight", reflecting geometry given by the MediaBox.
+               </div>
+               <h4>Expressions</h4>
+               <div>
+                       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.
+                       <div class="code-abs">
+                               $ValueA / ( $ValueB | 0.000001 )
+                       </div>
+                       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:
+                       <div class="code-abs">
+                               123.456 * ( $ConstantA - ( $ConstantB / 3.14 ) )
+                       </div>
+               </div>
+               <h4>Loops</h4>
+               <div>
+                       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.
+               </div>
+               <div>
+                       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.
+                       <div class="file">
+                               <div class="name">A4onA3.plan</div>
+                               <div class="content">$PageWidth=842.6 
+$PageHeight=1195.2
+## SourceWidth &#38; SourceHeight
+$sw=597.6
+$sh=842.4
+$page=1
+&#60;$PageCount/2[$page+1]
+$page; $page; 0; ($PageWidth-$sw)/2; ($PageHeight-$sh)/2;
+&#62;
+</div> 
+                       </div>
+                       The loop is what’s enclosed by "&#60;" and "&#62;"characters, the second just indicates the end of the loop. The first first indicates how many iterations (loops) have to be performed &#8212; 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.
+               </div>
+               <div>
+                       Constants (which finally turn into variables ;-)) must be declared before the loop. Many constants can be put in loop declaration, separate them with semicolons.
+               </div>
+               <div>
+                       <!-- No, loops can’t be nested! -->
+                       There is an experimental support of nested loops.
+               </div>
+               <h4>Running</h4>
+               <div>
+               Once you’ve wrote the PLAN file you can run the program: 
+                       <div class="command">
+                               podofoimpose source.pdf target.pdf plan.plan
+                       </div>
+               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.
+               </div>
+        </div> <!-- Plan -->
+         <h3>Plan (Lua)</h3>
+       <div class="section"><!-- lua plan -->
+           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().
+           <h4>Format</h4>
+           <div>
+            Records are pushed with:
+            <div class="command">
+             PushRecord(source page, target page, rotation, x, y);
+             </div>
+               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".
+            </div>
+               <h4>Running</h4>
+                <div>
+                 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.
+                 </div>
+
+        </div> <!-- lua plan -->
+       
+       <h3>Examples</h3>
+       <div class="section"><!-- Examples -->
+        <div>
+         For Lua scripts, some samples can be found in directory tools/podofoimpose/plans/lua of PoDoFo sources tree.
+         </div>
+       <h5>Add a stamp to a document</h5>
+       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:
+       <div class="file">
+               <div class="name">
+               pdf.list
+               </div>
+               <div class="content">official.pdf
+stamp.pdf</div>
+       </div>
+       <div class="file">
+               <div class="name">stamponator.plan</div>
+<div class="content">$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;</div>
+       </div>
+       Now you can run:
+       <div class="command">podofoimpose  pdf.list stamped-official.pdf stamponator.plan</div>
+
+       <h5>Make a tiled poster</h5>
+       <div>
+               Printing a large graphic onto a set of little paper sheets can be handful. Doing it automatically is even better! <!--You can find files used in this example here: <a href="poster.pdf">poster.pdf</a>,
+                                                        <a href="poster_mask.pdf">poster_mask.pdf</a>,
+                                                         <a href="poster.plan">poster.plan</a> and 
+                                                         <a href="poster.list">poster.list</a>. Here constants are a bit abbreviated in order to fit in the frame.-->
+               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 !").
+               <div class="file">
+                       <div class="name">poster.plan</div>
+                       <div class="content">
+##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
+&#60;$rows[$R+1]
+       &#60;$cols[$C+1]
+               1; (($R - 1)*$cols) + $C; 0; $hm - (($C -1) * $hbox); $vm - (($R-1) * $vbox);
+       &#62;
+&#62;
+
+</div>
+                       </div>
+               </div>
+       <div class="command">podofoimpose poster.pdf poster_tiled.pdf poster.plan </div>
+       <div>Etc.</div>
+       </div><!-- Examples -->
+</body>
+</html>
diff --git a/tools/podofoimpose/charpainter.cpp b/tools/podofoimpose/charpainter.cpp
new file mode 100644 (file)
index 0000000..51aaab2
--- /dev/null
@@ -0,0 +1,88 @@
+/***************************************************************************
+ *   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 <vector>
+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<int> & 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<int> d;
+    digits(n, d);
+
+    vector<int>::const_reverse_iterator itEnd = d.rend();
+    int i = d.size() - 1;
+    for ( vector<int>::const_reverse_iterator it = d.rbegin(); it != itEnd; ++it, --i )
+        paint(s, *it, size, x + (size * i / 1.6), y );
+}
diff --git a/tools/podofoimpose/charpainter.h b/tools/podofoimpose/charpainter.h
new file mode 100644 (file)
index 0000000..14968f7
--- /dev/null
@@ -0,0 +1,62 @@
+/***************************************************************************
+ *   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 <pierre@moulindetouvois.com>
+*/
+
+#include <ostream>
+
+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
diff --git a/tools/podofoimpose/impositionplan.cpp b/tools/podofoimpose/impositionplan.cpp
new file mode 100644 (file)
index 0000000..4d07970
--- /dev/null
@@ -0,0 +1,354 @@
+//
+// C++ Implementation: impositionplan
+//
+// Description:
+//
+//
+// Author: Pierre Marchand <pierremarc@oep-h.com>, (C) 2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#include "impositionplan.h"
+
+
+#include <fstream>
+#include <stdexcept>
+#include <algorithm>
+#include <cmath>
+#include <istream>
+#include <ostream>
+#include <cstdio>
+
+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 <iostream> //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<std::string, std::string>& vars )
+{
+       int blen ( buffer.length() );
+       std::vector<std::string> 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() <<") "<<buffer<<std::endl;
+               for ( unsigned int i = 0;i<tokens.size();++i )
+                       std::cerr<<"\t+ "<<tokens.at ( i ) <<std::endl;
+       }
+
+       sourcePage      = static_cast<int>(calc ( tokens.at ( 0 ) , vars));
+       destPage        = static_cast<int>(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<<" "<<sourcePage<<" "<<destPage<<" "<<rotate<<" "<<transX<<" "<<transY <<std::endl;
+
+}
+
+double PageRecord::calc ( const std::string& s , const std::map<std::string, std::string>& vars)
+{
+//     std::cerr<< s;
+       std::vector<std::string> 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<std::string, std::string>::const_iterator vit = vars.find ( ts );
+                               if ( vit != vars.end() )
+                               {
+//                                     std::cerr<<"A Found "<<ts<<" "<< vit->second <<std::endl;
+                                       tokens.push_back ( Util::dToStr ( calc ( vit->second, vars ) ) );
+                               }
+                               else
+                               {
+//                                     std::cerr<<"A Not Found "<<ts<<std::endl;
+                                       tokens.push_back ( ts );
+                               }
+                       }
+                       ts.clear();
+                       // append operator
+                       ts += ci;
+                       tokens.push_back ( ts );
+                       ts.clear();
+               }
+               else if ( ci > 32 )
+               {
+                       ts += ci;
+               }
+//             else
+//                     std::cerr<<"Wrong char : "<< ci <<std::endl;
+       }
+       if ( ts.length() > 0 )
+       {
+               std::map<std::string, std::string>::const_iterator vit2 = vars.find ( ts );
+               if ( vit2 != vars.end() )
+               {
+//                     std::cerr<<std::endl<<"Found "<<ts<<std::endl;
+                       tokens.push_back ( Util::dToStr ( calc ( vit2->second , vars) ) );
+               }
+               else
+               {
+//                     if((ts.length() > 0) && (ts[0] == '$'))
+//                     {
+//                             std::cerr<<std::endl<<"Not Found \"";
+//                             for(unsigned int c(0);c < ts.length(); ++c)
+//                             {
+//                                     std::cerr<<ts[c]<<"/";
+//                             }
+//                             std::cerr<<"\""<<std::endl;
+//                             for(std::map<std::string,std::string>::iterator i(PoDoFoImpose::vars.begin());i != PoDoFoImpose::vars.end(); ++i)
+//                             {
+// //                                  std::cerr<<"VA \""<< i->first << "\" => " <<(i->first == ts ? "True" : "False") <<std::endl;
+//                                     for(unsigned int c(0);c < i->first.length(); ++c)
+//                                     {
+//                                             std::cerr<<     i->first[c]<<"/";
+//                                     }
+//                                     std::cerr<<std::endl;
+//                             }
+//                     }
+                       tokens.push_back ( ts );
+               }
+       }
+       double result ( calc ( tokens ) );
+//     std::cerr<<" = "<<result<<std::endl;
+       return result;
+
+}
+
+double PageRecord::calc ( const std::vector<std::string>& t )
+{
+//     std::cerr<<"C =";
+//     for(uint i(0);i<t.size();++i)
+//             std::cerr<<" "<< t.at(i) <<" ";
+//     std::cerr<<std::endl;
+
+
+       if ( t.size() == 0 )
+               return 0.0;
+
+       double ret ( 0.0 );
+
+       std::vector<double> values;
+       std::vector<std::string> ops;
+       ops.push_back ( "+" );
+
+       for ( unsigned int vi = 0; vi < t.size(); ++vi )
+       {
+               if ( t.at ( vi ) == "(" )
+               {
+                       std::vector<std::string> tokens;
+                       int cdeep ( 0 );
+//                     std::cerr<<"(";
+                       for ( ++vi ; vi < t.size(); ++vi )
+                       {
+//                             std::cerr<<t.at ( ti );
+                               if ( t.at ( vi ) == ")" )
+                               {
+                                       if ( cdeep == 0 )
+                                               break;
+                                       else
+                                       {
+                                               --cdeep;
+                                       }
+                               }
+                               else if ( t.at ( vi ) == "(" )
+                               {
+                                       ++cdeep;
+                               }
+//                             std::cerr<<std::endl<<"\t";
+                               tokens.push_back ( t.at ( vi ) );
+                       }
+//                     std::cerr<<std::endl;
+                       values.push_back ( calc ( tokens ) );
+               }
+               else if ( t.at ( vi ) == "+" )
+                       ops.push_back ( "+" );
+               else if ( t.at ( vi ) == "-" )
+                       ops.push_back ( "-" );
+               else if ( t.at ( vi ) == "*" )
+                       ops.push_back ( "*" );
+               else if ( t.at ( vi ) == "/" )
+                       ops.push_back ( "/" );
+               else if ( t.at ( vi ) == "%" )
+                       ops.push_back ( "%" );
+               else if ( t.at ( vi ) == "|" )
+                       ops.push_back ( "|" );
+               else if ( t.at ( vi ) == "\"" )
+                       ops.push_back ( "\"" );
+               else
+                       values.push_back ( std::atof ( t.at ( vi ).c_str() ) );
+       }
+
+       if ( values.size() == 1 )
+               ret =   values.at ( 0 );
+       else
+       {
+               for ( unsigned int vi = 0; vi < ops.size(); ++vi )
+               {
+//                     std::cerr<<"OP>> \""<<ret<<"\" " << ops.at ( vi )<<" \""<<values.at( vi ) <<"\" = ";
+                       if ( ops.at ( vi ) == "+" )
+                               ret += values.at ( vi );
+                       else if ( ops.at ( vi ) == "-" )
+                               ret -= values.at ( vi );
+                       else if ( ops.at ( vi ) == "*" )
+                               ret *= values.at ( vi );
+                       /// I know it’s not good (tm)
+                       /// + http://gcc.gnu.org/ml/gcc/2001-08/msg00853.html
+                       else if ( ops.at ( vi ) == "/" )
+                       {
+                               if ( values.at ( vi ) == 0.0 )
+                                       ret = 0.0;
+                               else
+                                       ret /= values.at ( vi );
+                       }
+                       else if ( ops.at ( vi ) == "%" )
+                       {
+                               if ( values.at ( vi ) == 0.0 )
+                                       ret = 0.0;
+                               else
+                                       ret = static_cast<int> ( ret ) % static_cast<int> ( 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<<ret<<std::endl;
+               }
+       }
+//     std::cerr<<" <"<< values.size() <<"> "<<ret<<std::endl;
+       return ret;
+}
+
+bool PageRecord::isValid() const
+{
+       //TODO
+       if ( !sourcePage || !destPage )
+               return false;
+       return true;
+}
+
+ImpositionPlan::ImpositionPlan(const SourceVars& sv) :
+               sourceVars(sv),
+               m_destWidth ( 0.0 ),
+               m_destHeight ( 0.0 ),
+               m_scale ( 1.0 )
+{
+}
+
+ImpositionPlan::~ ImpositionPlan()
+{
+}
+
+bool ImpositionPlan::valid() const
+{
+       if ( destWidth() <= 0.0 )
+               return false;
+       else if ( destHeight() <= 0.0 )
+               return false;
+//     else if ( scale() <= 0.0 )
+//             return false;
+       else if(size() == 0)
+               return false;
+
+       return true;
+
+}
+
+void ImpositionPlan::setDestWidth ( double theValue )
+{
+       m_destWidth = theValue;
+}
+
+
+void ImpositionPlan::setDestHeight ( double theValue )
+{
+       m_destHeight = theValue;
+}
+
+
+void ImpositionPlan::setScale ( double theValue )
+{
+       m_scale = theValue;
+}
+
+void ImpositionPlan::setBoundingBox( const std::string& theString )
+{
+       m_boundingBox = theString;
+}
+
+};};
diff --git a/tools/podofoimpose/impositionplan.h b/tools/podofoimpose/impositionplan.h
new file mode 100644 (file)
index 0000000..29eaf12
--- /dev/null
@@ -0,0 +1,140 @@
+//
+// C++ Interface: impositionplan
+//
+// Description:
+//
+//
+// Author: Pierre Marchand <pierremarc@oep-h.com>, (C) 2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#ifndef IMPOSITIONPLAN_H
+#define IMPOSITIONPLAN_H
+
+#include "podofo.h"
+
+#include <map>
+#include <string>
+#include <vector>
+#include <cstdio>
+
+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 <pierre@moulindetouvois.com>
+ */
+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<std::string, std::string>& vars );
+               static double calc ( const std::vector<std::string>& t );
+               void load ( const std::string& s, const std::map<std::string, std::string>& vars );
+};
+
+class ImpositionPlan : public std::vector<PageRecord>
+{
+       public:
+
+
+               ImpositionPlan(const SourceVars& sv);
+               ~ImpositionPlan();
+               
+               // legacy
+               std::map<std::string, std::string> 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
+
+
+
diff --git a/tools/podofoimpose/lua_compat.h b/tools/podofoimpose/lua_compat.h
new file mode 100644 (file)
index 0000000..eb471b2
--- /dev/null
@@ -0,0 +1,36 @@
+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();
+}
+#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
diff --git a/tools/podofoimpose/pdftranslator.cpp b/tools/podofoimpose/pdftranslator.cpp
new file mode 100644 (file)
index 0000000..d43f8ed
--- /dev/null
@@ -0,0 +1,594 @@
+/***************************************************************************
+ *   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 <fstream>
+#include <stdexcept>
+#include <algorithm>
+#include <cmath>
+#include <istream>
+#include <ostream>
+#include <cstdlib>
+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 <iostream> //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"<<std::endl;
+                       sourceDoc = NULL;
+                       targetDoc = NULL;
+                       planImposition = NULL;
+                       duplicate = 0;
+                       extraSpace = 0;
+                       scaleFactor = 1.0;
+                       pcount = 0;
+                       sourceWidth = 0.0;
+                       sourceHeight = 0.0;
+                       destWidth = 0.0;
+                       destHeight = 0.0;
+               }
+
+               void PdfTranslator::setSource ( const std::string & source )
+               {
+                       int dbg(0);
+//                     std::cerr<<"PdfTranslator::setSource "<<source<<std::endl;
+                       std::cerr<< ++dbg <<std::endl;
+                       if ( checkIsPDF ( source ) )
+                       {
+//             std::cerr << "Appending "<<source<<" to source" << endl;
+                               multiSource.push_back ( source );
+                       }
+                       else
+                       {
+
+                               ifstream in ( source.c_str(), ifstream::in );
+                               if ( !in.good() )
+                                       throw runtime_error ( "setSource() failed to open input file" );
+
+
+                               char *filenameBuffer = new char[1000];
+                               do
+                               {
+                                       if ( !in.getline ( filenameBuffer, 1000 ) )
+                                               throw runtime_error ( "failed reading line from input file" );
+
+                                       std::string ts ( filenameBuffer, in.gcount() );
+                                       if ( ts.size() > 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 <<std::endl;
+
+                       if (multiSource.empty())
+                               throw runtime_error( "No recognized source given" );
+
+                       for ( std::vector<std::string>::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::PdfPage* pFirstPage = sourceDoc->GetPage ( 0 );
+                if ( NULL == pFirstPage ) // Fixes CVE-2019-9199 (issue #40)
+                {
+                    PODOFO_RAISE_ERROR_INFO( ePdfError_PageNotFound, "First page (0) of source document not found" );
+                }
+                PoDoFo::PdfRect rect ( pFirstPage->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<<std::endl;
+                       if ( !sourceDoc )
+                               return;
+
+                       PdfMemDocument extraDoc ( source.c_str() );
+                       sourceDoc->InsertPages ( extraDoc, 0,  extraDoc.GetPageCount() );
+                       multiSource.push_back ( source );
+
+               }
+
+               PdfObject* PdfTranslator::migrateResource ( const PdfObject * obj )
+               {
+//                     std::cerr<<"PdfTranslator::migrateResource"<<std::endl;
+                       PdfObject *ret ( 0 );
+
+                       if ( !obj )
+                               PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "migrateResource called"
+                                         " with NULL object" );
+
+                       if ( obj->IsDictionary() )
+                       {
+                               if ( obj->Reference().IsIndirect() )
+                               {
+                                       ret = targetDoc->GetObjects().CreateObject ( *obj );
+                               }
+                               else
+                               {
+                                       ret = new PdfObject( *obj );
+                               }
+                               TKeyMap resmap = obj->GetDictionary().GetKeys();
+                               for ( TCIKeyMap itres = resmap.begin(); itres != resmap.end(); ++itres )
+                               {
+                                       PdfObject *o = itres->second;
+                                       std::pair<std::set<PdfObject*>::iterator,bool> res = setMigrationPending.insert( o );
+                                       if (!res.second)
+                                       {
+                                               std::ostringstream oss;
+                                               oss << "Cycle detected: Object with ref " << o->Reference().ToString()
+                                                       << " is already pending migration to the target.\n";
+                                               PdfError::LogMessage( eLogSeverity_Warning, oss.str().c_str() );
+                                               continue;
+                                       }
+                                       PdfObject *migrated = migrateResource ( o );
+                                       if (NULL != migrated)
+                                       {
+                                               ret->GetDictionary().AddKey ( itres->first, migrated );
+                                               if ( !(migrated->Reference().IsIndirect()) )
+                                               {
+                                                       delete migrated;
+                                               }
+                                       }
+                               }
+
+                               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] ) );
+                                       if ( NULL == co )
+                                               continue;
+                                       narray.push_back ( *co );
+
+                                       if ( !(co->Reference().IsIndirect()) )
+                                       {
+                                               delete co;
+                                       }
+                               }
+                               if ( obj->Reference().IsIndirect() )
+                               {
+                                       ret = targetDoc->GetObjects().CreateObject ( narray );
+                               }
+                               else
+                               {
+                                       ret = new PdfObject( narray );
+                               }
+                       }
+                       else if ( obj->IsReference() )
+                       {
+                               if ( migrateMap.find ( obj->GetReference().ToString() ) != migrateMap.end() )
+                               {
+                                       std::ostringstream oss;
+                                       oss << "Referenced object " << obj->GetReference().ToString()
+                                           << " already migrated." << std::endl;
+                                       PdfError::DebugMessage( oss.str().c_str() );
+
+                                       const PdfObject* const found = migrateMap[ obj->GetReference().ToString() ];
+                                       return new PdfObject( found->Reference() );
+                               }
+
+                               PdfObject *to_migrate = sourceDoc->GetObjects().GetObject ( obj->GetReference() );
+
+                               std::pair<std::set<PdfObject*>::iterator, bool> res
+                                               = setMigrationPending.insert( to_migrate );
+                               if (!res.second)
+                               {
+                                       std::ostringstream oss;
+                                       oss << "Cycle detected: Object with ref " << obj->GetReference().ToString()
+                                               << " is already pending migration to the target.\n";
+                                       PdfError::LogMessage( eLogSeverity_Warning, oss.str().c_str() );        
+                                       return NULL; // skip this migration
+                               }
+                               PdfObject * o ( migrateResource ( to_migrate ) );
+                               if ( NULL != o )
+                                       ret  = new PdfObject ( o->Reference() );
+                               else
+                                       return NULL; // avoid going through rest of method
+                       }
+                       else
+                       {
+                               ret = new PdfObject ( *obj );//targetDoc->GetObjects().CreateObject(*obj);
+                       }
+
+                       if ( obj->Reference().IsIndirect() )
+                       {
+                               migrateMap.insert ( std::pair<std::string, PdfObject*> ( obj->Reference().ToString(), ret ) );
+                       }
+
+                       return ret;
+               }
+
+               PdfObject* PdfTranslator::getInheritedResources ( PdfPage* page )
+               {
+//                     std::cerr<<"PdfTranslator::getInheritedResources"<<std::endl;
+                       PdfObject *res ( 0 );
+                       // mabri: resources are inherited as whole dict, not at all if the page has the dict
+                       // mabri: specified in PDF32000_2008.pdf section 7.7.3.4 Inheritance of Page Attributes
+                       // mabri: and in section 7.8.3 Resource Dictionaries
+                       const PdfObject *sourceRes = page->GetInheritedKey( PdfName ( "Resources" ) );
+                       if ( sourceRes )
+                       {
+                           res = migrateResource( sourceRes );
+                       }
+                       return res;
+               }
+
+               void PdfTranslator::setTarget ( const std::string & target )
+               {
+//                     std::cerr<<"PdfTranslator::setTarget "<<target<<std::endl;
+                       if ( !sourceDoc )
+                               throw std::logic_error ( "setTarget() called before setSource()" );
+
+                       targetDoc = new PdfMemDocument;
+                       outFilePath  = target;
+
+                       for ( int i = 0; i < pcount ; ++i )
+                       {
+                               PdfPage * page = sourceDoc->GetPage ( i );
+                               PdfMemoryOutputStream outMemStream ( 1 );
+
+                               if (!page) // Fix issue #32
+                {
+                    std::ostringstream oss;
+                    oss << "Page " << i << " (0-based) of " << pcount << " in source doc not found!";
+                    PODOFO_RAISE_ERROR_INFO( ePdfError_PageNotFound, oss.str() );
+                }
+                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<std::string> pageKeys;
+                               std::vector<std::string>::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 ) )
+                                       {
+                                               PdfObject* migObj = migrateResource ( page->GetObject()->GetDictionary().GetKey ( keyname ) );
+                                               if ( NULL == migObj )
+                                                       continue;
+                                               xobj->GetObject()->GetDictionary().AddKey ( keyname, migObj ); 
+                                       }
+                               }
+
+                               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<<std::endl;
+                       SourceVars sv;
+                       sv.PageCount = pcount;
+                       sv.PageHeight = sourceHeight;
+                       sv.PageWidth = sourceWidth;
+                       planImposition = new ImpositionPlan ( sv );
+                       if ( loader == PoDoFo::Impose::Legacy )
+                       {
+                               PlanReader_Legacy ( planFile, planImposition );
+                       }
+#if defined(PODOFO_HAVE_LUA)
+                       else if ( loader == PoDoFo::Impose::Lua )
+                       {
+                               PlanReader_Lua ( planFile, planImposition );
+                       }
+#endif
+
+                       if ( !planImposition->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() <<endl;
+
+               }
+
+               void PdfTranslator::impose()
+               {
+//                     std::cerr<<"PdfTranslator::impose"<<std::endl;
+                       if ( !targetDoc )
+                               throw std::invalid_argument ( "impose() called with empty target" );
+
+//                     PdfObject trimbox;
+//                     PdfRect trim ( 0, 0, destWidth, destHeight );
+//                     trim.ToVariant ( trimbox );
+                       std::map<int, PdfRect>* 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<int, vector<PageRecord> > 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<<curRecord.sourcePage<< " " << curRecord.destPage<<std::endl;
+                                       if(curRecord.sourcePage <= pcount)
+                                       {
+                                               double cosR = cos ( curRecord.rotate  *  3.14159 / 180.0 );
+                                               double sinR = sin ( curRecord.rotate  *  3.14159 / 180.0 );
+                                               double tx = curRecord.transX ;
+                                               double ty = curRecord.transY ;
+       
+                                               int resourceIndex ( /*(curRecord.duplicateOf > 0) ? curRecord.duplicateOf : */curRecord.sourcePage );
+                                               PdfXObject *xo = xobjects[resourceIndex];
+                                               if(NULL != bbIndex)
+                                               {
+                                                       PdfObject bb;
+                                                       // DominikS: Fix compilation using Visual Studio on Windows
+                                                       // mabri: ML post archive URL is https://sourceforge.net/p/podofo/mailman/message/24609746/
+                                                       // 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 "<<resources[resourceIndex]->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() );
+
+                       // The following is necessary to avoid line 195 being detected as allocation having a memory leak
+                       // without changing other files than this one (thorough leak prevention shall be applied later).
+                       for (std::map<int, PdfObject*>::iterator it = resources.begin(); it != resources.end(); it++)
+                       {
+                               delete (*it).second;
+                       }
+                       resources.clear(); 
+               }
+
+
+       };
+}; // end of namespace
diff --git a/tools/podofoimpose/pdftranslator.h b/tools/podofoimpose/pdftranslator.h
new file mode 100644 (file)
index 0000000..ec14d84
--- /dev/null
@@ -0,0 +1,149 @@
+/***************************************************************************
+ *   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 <string>
+#include <map>
+#include <set>
+#include <vector>
+#include <sstream>
+#include <istream>
+#include <string>
+
+
+
+// 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<int, PdfXObject*> xobjects;
+               std::map<int,PdfObject*> resources;
+               std::map<int, PdfRect> cropRect;
+               std::map<int,PdfRect> bleedRect;
+               std::map<int, PdfRect> trimRect;
+               std::map<int,PdfRect> artRect;
+               std::map<int, PdfDictionary*> pDict;
+               std::map<int, int> virtualMap;
+//             int maxPageDest;
+               int duplicate;
+
+               bool checkIsPDF ( std::string path );
+               PdfObject* getInheritedResources ( PdfPage* page );
+               void mergeResKey ( PdfObject *base, PdfName key,  PdfObject *tomerge );
+               PdfObject* migrateResource(const 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<int> & pages, std::ostringstream & a );
+               
+               // An attempt to allow nested loops
+               // returns new position in records list.
+               int sortLoop(std::vector<std::string>& memfile, int numline);
+
+               std::string useFont;
+               PdfReference useFontRef;
+               double extraSpace;
+
+               std::vector<std::string> multiSource;
+               
+               std::map<std::string, PdfObject*> migrateMap;
+               std::set<PdfObject*> setMigrationPending;
+       public:
+               int pcount;
+               double sourceWidth;
+               double sourceHeight;
+               double destWidth;
+               double destHeight;
+               double scaleFactor;
+               std::string boundingBox;
+
+
+};
+
+       };}; // end of namespace
+#endif
diff --git a/tools/podofoimpose/planreader_legacy.cpp b/tools/podofoimpose/planreader_legacy.cpp
new file mode 100644 (file)
index 0000000..2aa1b91
--- /dev/null
@@ -0,0 +1,275 @@
+//
+// C++ Implementation: planreader_legacy
+//
+// Description: 
+//
+//
+// Author: Pierre Marchand <pierremarc@oep-h.com>, (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 <fstream>
+#include <stdexcept>
+#include <algorithm>
+#include <cmath>
+#include <istream>
+#include <ostream>
+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 <iostream> //XXX#define MAX_SOURCE_PAGES 5000
+#define MAX_RECORD_SIZE 2048
+
+int PlanReader_Legacy::sortLoop(std::vector<std::string>& memfile, int numline)
+{
+//     std::cerr<<"===================================== "<<numline<<std::endl;
+       //Debug
+//     for(std::map<std::string, double>::iterator dit(localvars.begin());dit!=localvars.end();++dit)
+//     {
+//             std::cerr<<"R "<<dit->first<<" = "<<dit->second<<std::endl;
+//     }
+       //
+       std::map<std::string,std::string> 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<blen;++a)
+       {
+               ca = buffer.at(a);
+               if(ca == '[')
+                       break;
+               else if(ca == 0x20 || ca == 0x9 )
+                       continue;
+               iterN += buffer.at(a);
+       }
+                       
+       std::map<std::string, double> increments;
+       std::string tvar;
+       std::string tinc;
+       ++a;
+       bool varside(true);
+       for(;a<blen;++a)
+       {
+               ca = buffer.at(a);
+//             if(ca == 0x20 || ca == 0x9 )
+//                     continue;
+               if( (ca == ']') || (ca == ';') ) // time to commit
+               {
+                       if(I->vars.find(tvar) != I->vars.end())
+                       {
+//                             std::cerr<< "I " << tvar <<" = "<< tinc <<std::endl;
+                               increments.insert(std::pair<std::string, double>( 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 ) <<" |"<<std::endl;
+               if(memfile.at ( bolb2 ).at( 0 ) == '<')
+                       ++openLoop;
+               else if(memfile.at ( bolb2 ).at( 0 ) == '>')
+               {
+                       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<std::string, double>::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 <<" - "<<memfile.at(subi) <<std::endl;
+                       
+                       if(memfile.at ( subi ).at( 0 ) == '<')
+                       {
+                               subi += sortLoop(memfile , subi);
+//                             std::cerr<< "||  "  << memfile.at ( subi )  <<std::endl;
+                       }
+                       else
+                       {
+                               PoDoFo::Impose::PageRecord p;
+                               p.load ( memfile.at(subi), I->vars ) ;
+                               if(!p.isValid() || p.sourcePage > I->sourceVars.PageCount)
+                               {
+//                                     std::cerr<< "Error p("<<(p.isValid()?"valid":"invalid")<<") "<< p.sourcePage  <<std::endl;
+                                       continue;
+                               }
+//                             maxPageDest = std::max ( maxPageDest, p.destPage );
+//                             bool isDup(false);
+//                             for(ImpositionPlan::const_iterator ipIt(planImposition.begin());ipIt != planImposition.end(); ++ipIt)
+//                             {
+//                                     if(ipIt->sourcePage == p.sourcePage)
+//                                     {
+//                                             isDup = true;
+//                                             break;
+//                                     }
+//                             }
+//                             if ( isDup )
+//                             {
+//                                     p.duplicateOf = p.sourcePage;
+//                             }
+                               I->push_back ( p );
+                       }
+               }
+                               
+       }
+//     numline = endOfloopBlock;
+//     std::cerr<<"EOL"<<std::endl;
+       int retvalue(endOfloopBlock - startAt + 1);
+       I->vars = storedvars;
+//     std::cerr<<"------------------------------------- "<<retvalue<<std::endl;
+       return retvalue;
+}
+
+PlanReader_Legacy::PlanReader_Legacy(const std::string & plan, PoDoFo::Impose::ImpositionPlan *Imp)
+       :I(Imp)
+{
+       ifstream in ( plan.c_str(), ifstream::in );
+       if ( !in.good() )
+               throw runtime_error ( "Failed to open plan file" );
+
+//     duplicate = MAX_SOURCE_PAGES;
+       std::vector<std::string> memfile;
+       do
+       {
+               std::string buffer;
+               if ( !std::getline ( in, buffer ) && ( !in.eof() || in.bad() ) )
+               {
+                       throw runtime_error ( "Failed to read line from plan" );
+               }
+
+#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 ( buffer.length() < 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<<buffer<<std::endl;
+               }
+       }
+       while(!in.eof());
+       /// PROVIDED 
+       I->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
+       
+       
+       
+}
diff --git a/tools/podofoimpose/planreader_legacy.h b/tools/podofoimpose/planreader_legacy.h
new file mode 100644 (file)
index 0000000..975dca2
--- /dev/null
@@ -0,0 +1,32 @@
+//
+// C++ Interface: planreader_legacy
+//
+// Description: 
+//
+//
+// Author: Pierre Marchand <pierremarc@oep-h.com>, (C) 2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef PLANREADER_LEGACY_H
+#define PLANREADER_LEGACY_H
+
+#include "impositionplan.h"
+
+#include <string>
+#include <vector>
+
+
+
+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<std::string>& memfile, int numline);
+};
+
+#endif
diff --git a/tools/podofoimpose/planreader_lua.cpp b/tools/podofoimpose/planreader_lua.cpp
new file mode 100644 (file)
index 0000000..334232f
--- /dev/null
@@ -0,0 +1,165 @@
+//
+// C++ Implementation: planreader_lua
+//
+// Description: 
+//
+//
+// Author: Pierre Marchand <pierremarc@oep-h.com>, (C) 2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#include "planreader_lua.h"
+
+#include <stdexcept>
+#include <iostream>
+
+// 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 <<std::endl;
+       plan = ip;
+       
+       lua_pushcfunction(L.State(), &PlanReader_Lua::PushRecord);
+       lua_setglobal(L.State(), "PushRecord");
+       
+       lua_pushlightuserdata(L.State(), static_cast<void*>(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:\"" <<lua_tostring(L.State(), -1)<<"\""<<std::endl ;
+       }
+       else // if not reached, the plan remains invalid
+       {
+               if(hasGlobal("PageWidth"))
+                       plan->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<PlanReader_Lua*> ( lua_touserdata ( L, -1 ) );
+       lua_pop ( L, 1 );
+
+//     std::cerr<<"PlanReader_Lua::PushRecord "<<lua_tonumber ( L, 1 )<<" "<<lua_tonumber ( L, 2 )<<" "<<lua_tonumber ( L, 3 )<<" "<<lua_tonumber ( L, 4 )<<" "<<lua_tonumber ( L, 5 )<<std::endl;
+       
+       /* and add a new record to it */
+       PoDoFo::Impose::PageRecord P(
+                                   lua_tonumber ( L, 1 ),
+                                   lua_tonumber ( L, 2 ),
+                                   lua_tonumber ( L, 3 ),
+                                   lua_tonumber ( L, 4 ),
+                                   lua_tonumber ( L, 5 ));
+       if(P.isValid())
+               that->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;
+}
+
diff --git a/tools/podofoimpose/planreader_lua.h b/tools/podofoimpose/planreader_lua.h
new file mode 100644 (file)
index 0000000..728e110
--- /dev/null
@@ -0,0 +1,61 @@
+//
+// C++ Header: planreader_lua
+//
+// Description:
+//
+//
+// Author: Pierre Marchand <pierremarc@oep-h.com>, (C) 2008
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+
+#ifndef PLANREADERLUA_H
+#define PLANREADERLUA_H
+
+#include "impositionplan.h"
+
+#include <string>
+
+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
diff --git a/tools/podofoimpose/plans/lua/Booklet-A4-duplex.plan b/tools/podofoimpose/plans/lua/Booklet-A4-duplex.plan
new file mode 100644 (file)
index 0000000..f6bb0a1
--- /dev/null
@@ -0,0 +1,165 @@
+---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
diff --git a/tools/podofoimpose/plans/lua/Booklet-USlegal-duplex.plan b/tools/podofoimpose/plans/lua/Booklet-USlegal-duplex.plan
new file mode 100644 (file)
index 0000000..6ae2fcc
--- /dev/null
@@ -0,0 +1,165 @@
+---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
diff --git a/tools/podofoimpose/plans/lua/Booklet-USletter-bottom.plan b/tools/podofoimpose/plans/lua/Booklet-USletter-bottom.plan
new file mode 100644 (file)
index 0000000..dcc131d
--- /dev/null
@@ -0,0 +1,165 @@
+---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
diff --git a/tools/podofoimpose/plans/lua/Booklet-USletter-duplex.plan b/tools/podofoimpose/plans/lua/Booklet-USletter-duplex.plan
new file mode 100644 (file)
index 0000000..13da9d0
--- /dev/null
@@ -0,0 +1,165 @@
+---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
diff --git a/tools/podofoimpose/plans/lua/Booklet-USletter-top.plan b/tools/podofoimpose/plans/lua/Booklet-USletter-top.plan
new file mode 100644 (file)
index 0000000..dcc131d
--- /dev/null
@@ -0,0 +1,165 @@
+---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
diff --git a/tools/podofoimpose/plans/lua/Booklet.plan b/tools/podofoimpose/plans/lua/Booklet.plan
new file mode 100644 (file)
index 0000000..612c4de
--- /dev/null
@@ -0,0 +1,56 @@
+-- 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
+end
\ No newline at end of file
diff --git a/tools/podofoimpose/plans/lua/Identity.plan b/tools/podofoimpose/plans/lua/Identity.plan
new file mode 100644 (file)
index 0000000..c998a73
--- /dev/null
@@ -0,0 +1,15 @@
+-- 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
+
+               
\ No newline at end of file
diff --git a/tools/podofoimpose/plans/lua/In4.plan b/tools/podofoimpose/plans/lua/In4.plan
new file mode 100644 (file)
index 0000000..96d29e6
--- /dev/null
@@ -0,0 +1,32 @@
+-- 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
diff --git a/tools/podofoimpose/plans/lua/Test.plan b/tools/podofoimpose/plans/lua/Test.plan
new file mode 100644 (file)
index 0000000..a442335
--- /dev/null
@@ -0,0 +1,9 @@
+-- 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);
\ No newline at end of file
diff --git a/tools/podofoimpose/podofoimpose.cpp b/tools/podofoimpose/podofoimpose.cpp
new file mode 100644 (file)
index 0000000..6053f1c
--- /dev/null
@@ -0,0 +1,126 @@
+/***************************************************************************
+ *   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 <cstdlib>
+#include <iostream>
+#include <string>
+#include <cstdio>
+
+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 [Interpreter]" << 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" <<endl<< endl;
+       cerr << "\t[Interpreter] Can be \"native\" (default value) or \"lua\""<< endl<< endl;
+    cerr << "PoDoFo Version: " << PODOFO_VERSION_STRING << endl << endl;
+}
+
+int parseCommandLine ( int argc, char* argv[] )
+{
+       params.executablePath = argv[0];
+
+       if ( argc <  4 )
+       {
+               usage();
+               return 1;
+       }
+
+       params.inFilePath = argv[1];
+       params.outFilePath = argv[2];
+       params.planFilePath = argv[3];
+       params.planReader = PoDoFo::Impose::Legacy;
+       if ( argc >= 5 )
+       {
+               std::string native ( "native" );
+               std::string lua ( "lua" );
+               std::string interpreter ( argv[4] );
+
+               if ( !interpreter.compare ( native ) )
+                       params.planReader = PoDoFo::Impose::Legacy;
+               else if ( !interpreter.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 : "<<params.inFilePath<<std::endl;
+       std::cerr<<"Target : "<<params.outFilePath<<std::endl;
+       std::cerr<<"Plan   : "<<params.planFilePath<<std::endl;
+
+
+       try
+       {
+               PoDoFo::Impose::PdfTranslator *translator = new  PoDoFo::Impose::PdfTranslator;
+
+               translator->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;
+}
+
diff --git a/tools/podofoimpose/sample.pdf b/tools/podofoimpose/sample.pdf
new file mode 100644 (file)
index 0000000..1280931
Binary files /dev/null and b/tools/podofoimpose/sample.pdf differ
diff --git a/tools/podofoimpose/sample.plan b/tools/podofoimpose/sample.plan
new file mode 100644 (file)
index 0000000..03ac4b5
--- /dev/null
@@ -0,0 +1,57 @@
+##### 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;
diff --git a/tools/podofoincrementalupdates/CMakeLists.txt b/tools/podofoincrementalupdates/CMakeLists.txt
new file mode 100644 (file)
index 0000000..92d0496
--- /dev/null
@@ -0,0 +1,7 @@
+ADD_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")
diff --git a/tools/podofoincrementalupdates/incrementalupdates.cpp b/tools/podofoincrementalupdates/incrementalupdates.cpp
new file mode 100644 (file)
index 0000000..2f7879f
--- /dev/null
@@ -0,0 +1,107 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+#include <cstdlib>
+#include <cstdio>
+
+using namespace PoDoFo;
+
+#ifdef _HAVE_CONFIG
+#include <config.h>
+#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;
+}
+
diff --git a/tools/podofomerge/CMakeLists.txt b/tools/podofomerge/CMakeLists.txt
new file mode 100644 (file)
index 0000000..14f34f2
--- /dev/null
@@ -0,0 +1,6 @@
+ADD_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")
diff --git a/tools/podofomerge/podofomerge.cpp b/tools/podofomerge/podofomerge.cpp
new file mode 100644 (file)
index 0000000..fa14a6b
--- /dev/null
@@ -0,0 +1,104 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+#include <stdlib.h>
+#include <cstdio>
+
+using namespace PoDoFo;
+
+#ifdef _HAVE_CONFIG
+#include <config.h>
+#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;
+}
+
diff --git a/tools/podofomerge/podofomerge.vcproj b/tools/podofomerge/podofomerge.vcproj
new file mode 100644 (file)
index 0000000..781ada8
--- /dev/null
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.10"\r
+       Name="podofomerge"\r
+       ProjectGUID="{C3575F5A-959C-4B1B-8635-F2E874FE3608}"\r
+       Keyword="Win32Proj">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..\src;..\..\freetype\include;..\..\zlib;..\..\jpeg"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"\r
+                               MinimalRebuild="TRUE"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="5"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="4"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="wsock32.lib"\r
+                               OutputFile="$(OutDir)/podofomerge.exe"\r
+                               LinkIncremental="2"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(OutDir)/podofomerge.pdb"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"\r
+                               RuntimeLibrary="4"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="3"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(OutDir)/podofomerge.exe"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="TRUE"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">\r
+                       <File\r
+                               RelativePath=".\podofomerge.cpp">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/tools/podofonooc/CMakeLists.txt b/tools/podofonooc/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3be8374
--- /dev/null
@@ -0,0 +1,7 @@
+ADD_EXECUTABLE(podofonooc podofonooc.cpp)
+
+TARGET_LINK_LIBRARIES(podofonooc ${PODOFO_LIB})
+SET_TARGET_PROPERTIES(podofonooc PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}")
+ADD_DEPENDENCIES(podofonooc ${PODOFO_DEPEND_TARGET})
+INSTALL(TARGETS podofonooc
+       RUNTIME DESTINATION "bin")
diff --git a/tools/podofonooc/podofonooc.cpp b/tools/podofonooc/podofonooc.cpp
new file mode 100644 (file)
index 0000000..02a3d35
--- /dev/null
@@ -0,0 +1,141 @@
+/***************************************************************************
+ *   Copyright (C) 2020  Ivan Romanov <drizt72@zoho.eu                     *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110, USA                *
+ ***************************************************************************/
+
+#include <iostream>
+#include <iterator>
+#include <string>
+#include <cstdlib>
+#include <cstdio>
+#include <algorithm>
+
+#ifdef _MSC_VER
+    #include <io.h>
+    #include <fcntl.h>
+#endif
+
+#include <podofo.h>
+
+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 < 3)
+        {
+            cout << "Usage" << endl;
+            cout << "  " << argv[0] << " <in.pdf> <out.pdf> [OC_name]..." << 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->LoadFromBuffer( buffer.c_str(), static_cast<long>(buffer.size()) );
+        }
+        else
+        {
+            doc = new PoDoFo::PdfMemDocument(argv[1]);
+        }
+
+        vector<string> ocToRemove;
+
+        for (int i = 3; i < argc; i++)
+        {
+            ocToRemove.push_back(string(argv[i]));
+        }
+
+        int ocCount = 0;
+        PdfObject * ocProperties = doc->GetTrailer()->MustGetIndirectKey("Root")->GetIndirectKey("OCProperties");
+
+        if (ocProperties) {
+            PdfObject * ocgs = ocProperties->GetIndirectKey("OCGs");
+
+            if (ocgs)
+            {
+                PdfVecObjects & docObjects = doc->GetObjects();
+                PdfArray ocgsArr = ocgs->GetArray();
+                for (PdfArray::iterator it = ocgsArr.begin(); it != ocgsArr.end(); it++)
+                {
+                    PdfReference ocgRef = (*it).GetReference();
+                    if (!docObjects.GetObject(ocgRef))
+                        continue;
+
+                    const string &ocgName = docObjects.GetObject(ocgRef)->MustGetIndirectKey("Name")->GetString().GetStringUtf8();
+
+                    if (!ocToRemove.empty() && find(ocToRemove.begin(), ocToRemove.end(), ocgName) == ocToRemove.end())
+                    {
+                        continue;
+                    }
+
+                    for (int i = docObjects.GetSize() - 1; i >= 0; i--)
+                    {
+                        PdfObject * ob = docObjects[i];
+
+                        if (ob->IsDictionary())
+                        {
+                            PdfObject * oc = ob->GetDictionary().GetKey("OC");
+                            if (oc) {
+                                PdfReference ocRef = oc->GetReference();
+                                if (ocRef == ocgRef || (docObjects.GetObject(ocRef)->GetIndirectKey("OCGs") && docObjects.GetObject(ocRef)->GetDictionary().GetKey("OCGs")->GetReference() == ocgRef))
+                                {
+                                    docObjects.RemoveObject(ob->Reference());
+                                    ocCount++;
+                                }
+                            }
+                        }
+                    }
+
+                    docObjects.RemoveObject(ocgRef);
+                }
+            }
+        }
+
+        if (ocCount)
+        {
+            doc->Write(argv[2]);
+        }
+        else
+        {
+            cout << "No optional content in this PDF" << endl;
+        }
+    } catch( PdfError & e ) {
+        std::cerr << "Error: An error " << e.GetError() << " occurred during the process of the pdf file:" << std::endl;
+        e.PrintErrorMsg();
+
+        result = e.GetError();
+    }
+
+    if( doc )
+        delete doc;
+
+    return result;
+}
diff --git a/tools/podofopages/CMakeLists.txt b/tools/podofopages/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5cac5cf
--- /dev/null
@@ -0,0 +1,6 @@
+ADD_EXECUTABLE(podofopages podofopages.cpp DeleteOperation.cpp MoveOperation.cpp)
+TARGET_LINK_LIBRARIES(podofopages ${PODOFO_LIB})
+SET_TARGET_PROPERTIES(podofopages PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}")
+ADD_DEPENDENCIES(podofopages ${PODOFO_DEPEND_TARGET})
+INSTALL(TARGETS podofopages
+       RUNTIME DESTINATION "bin")
diff --git a/tools/podofopages/DeleteOperation.cpp b/tools/podofopages/DeleteOperation.cpp
new file mode 100644 (file)
index 0000000..7238b4e
--- /dev/null
@@ -0,0 +1,43 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+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();
+}
diff --git a/tools/podofopages/DeleteOperation.h b/tools/podofopages/DeleteOperation.h
new file mode 100644 (file)
index 0000000..ae9411b
--- /dev/null
@@ -0,0 +1,45 @@
+/***************************************************************************
+ *   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__
diff --git a/tools/podofopages/MoveOperation.cpp b/tools/podofopages/MoveOperation.cpp
new file mode 100644 (file)
index 0000000..cfb0da1
--- /dev/null
@@ -0,0 +1,56 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+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();
+}
+
diff --git a/tools/podofopages/MoveOperation.h b/tools/podofopages/MoveOperation.h
new file mode 100644 (file)
index 0000000..77ceb43
--- /dev/null
@@ -0,0 +1,47 @@
+/***************************************************************************
+ *   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__
diff --git a/tools/podofopages/Operation.h b/tools/podofopages/Operation.h
new file mode 100644 (file)
index 0000000..4da7ede
--- /dev/null
@@ -0,0 +1,47 @@
+/***************************************************************************
+ *   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 <string>
+
+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__
diff --git a/tools/podofopages/podofopages.cpp b/tools/podofopages/podofopages.cpp
new file mode 100644 (file)
index 0000000..7a81c85
--- /dev/null
@@ -0,0 +1,185 @@
+/***************************************************************************
+ *   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 <podofo.h>
+#include <stdlib.h>
+
+#include <iostream>
+#include <iostream>
+#include <string>
+#include <stdexcept>
+#include <vector>
+#include <cstdio>
+
+#include "DeleteOperation.h"
+#include "MoveOperation.h"
+
+using namespace PoDoFo;
+
+#ifdef _HAVE_CONFIG
+#include <config.h>
+#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<Operation*> & 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<Operation*>::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<Operation*> vecOperations;
+  for( int i=1; i < argc; i++ )
+  {
+      std::string argument = argv[i];
+      if( argument == "--delete" || argument == "-delete" )
+      {
+          int page = static_cast<int>(convertToInt( std::string(argv[i+1]) ));
+          vecOperations.push_back( new DeleteOperation( page ) );
+          ++i;
+      }
+      else if( argument == "--move" || argument == "-move" )
+      {
+          int from = static_cast<int>(convertToInt( std::string(argv[i+1]) ));
+          int to = static_cast<int>(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<Operation*>::iterator it = vecOperations.begin();
+  while( it != vecOperations.end() )
+  {
+      delete (*it);
+      ++it;
+  }
+
+  return 0;
+}
+
diff --git a/tools/podofopdfinfo/CMakeLists.txt b/tools/podofopdfinfo/CMakeLists.txt
new file mode 100644 (file)
index 0000000..bb6124b
--- /dev/null
@@ -0,0 +1,6 @@
+ADD_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")
diff --git a/tools/podofopdfinfo/pdfinfo.cpp b/tools/podofopdfinfo/pdfinfo.cpp
new file mode 100644 (file)
index 0000000..86051d1
--- /dev/null
@@ -0,0 +1,246 @@
+/***************************************************************************
+*   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<int>(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<PoDoFo::PdfMemDocument*>(mDoc)->GetStructTreeRoot() != NULL ? "Yes" : "No") << std::endl;
+    sOutStream << "\tEncrypted: " << (static_cast<PoDoFo::PdfMemDocument*>(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; pg<pgCount; pg++ ) 
+    {
+        sOutStream << "Page " << pg << ":" << std::endl;
+        
+        curPage = mDoc->GetPage( 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<level;i++ )
+        sOutStream << "-";
+
+    sOutStream << ">" << 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<double,double> 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; pg<pgCount; pg++ ) 
+       {
+               curPage = mDoc->GetPage( pg );
+               if( !curPage )
+               {
+                       PODOFO_RAISE_ERROR( PoDoFo::ePdfError_PageNotFound );
+               }
+               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<Format,int>(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 "<<std::string(sizes.size(), '*');
+       }
+       
+       return ss.str();
+}
diff --git a/tools/podofopdfinfo/pdfinfo.h b/tools/podofopdfinfo/pdfinfo.h
new file mode 100644 (file)
index 0000000..7a097bd
--- /dev/null
@@ -0,0 +1,48 @@
+/***************************************************************************
+*   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 _PDFINFO_H_
+#define _PDFINFO_H_
+
+#include <ostream>
+#include <podofo.h>
+
+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
+
diff --git a/tools/podofopdfinfo/podofopdfinfo.cpp b/tools/podofopdfinfo/podofopdfinfo.cpp
new file mode 100644 (file)
index 0000000..d60b1d5
--- /dev/null
@@ -0,0 +1,161 @@
+/***************************************************************************
+ *   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 <iostream>
+#include "pdfinfo.h"
+
+#include <stdlib.h>
+#include <cstdio>
+
+#ifdef _HAVE_CONFIG
+#include <config.h>
+#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 successfully.\n" << std::endl << std::endl;
+
+  return 0;
+}
+
diff --git a/tools/podofosign/CMakeLists.txt b/tools/podofosign/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a3fa046
--- /dev/null
@@ -0,0 +1,14 @@
+ADD_EXECUTABLE(podofosign podofosign.cpp)
+
+TARGET_INCLUDE_DIRECTORIES(podofosign PUBLIC ${LIBCRYPTO_INCLUDE_DIR})
+
+TARGET_LINK_LIBRARIES(podofosign
+       ${LIBCRYPTO_LDFLAGS}
+       ${LIBCRYPTO_LIBRARIES}
+       ${OPENSSL_LIBRARIES}
+       ${PODOFO_LIB}
+)
+SET_TARGET_PROPERTIES(podofosign PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}")
+ADD_DEPENDENCIES(podofosign ${PODOFO_DEPEND_TARGET})
+INSTALL(TARGETS podofosign
+       RUNTIME DESTINATION "bin")
diff --git a/tools/podofosign/podofosign.cpp b/tools/podofosign/podofosign.cpp
new file mode 100644 (file)
index 0000000..0c58e23
--- /dev/null
@@ -0,0 +1,1107 @@
+/***************************************************************************
+ *   Copyright (C) 2016 by zyx at litePDF dot cz                           *
+ *                                                                         *
+ *   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 <cstdio>
+#include <string>
+#include <iostream>
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+
+#if defined(_WIN64)
+#define fseeko _fseeki64
+#define ftello _ftelli64
+#else
+#define fseeko fseek
+#define ftello ftell
+#endif
+
+using namespace PoDoFo;
+
+static int print_errors_string( const char *str, size_t len, void *u )
+{
+    std::string *pstr = reinterpret_cast<std::string *>( 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<const char *>(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<char *>( 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<char *>( 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<unsigned int>( 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<size_t>( 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<double>( rr ) / 255.0, static_cast<double>( gg ) / 255.0, static_cast<double>( 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<const pdf_utf8 *>( 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<char>( 0xFE ) && rDV.GetString()[1] == static_cast<char>( 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;
+    }
+
+#ifdef PODOFO_HAVE_OPENSSL_1_1
+    OPENSSL_init_crypto(0, NULL);
+#else
+    OpenSSL_add_all_algorithms();
+    ERR_load_crypto_strings();
+    ERR_load_PEM_strings();
+    ERR_load_ASN1_strings();
+    ERR_load_EVP_strings();
+#endif
+
+    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<pdf_int64>( 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<const pdf_utf8 *>( 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();
+    }
+
+#ifndef PODOFO_HAVE_OPENSSL_1_1
+    ERR_free_strings();
+#endif
+
+    if( pSignField )
+        delete pSignField;
+
+    if( pTemporaryAnnot )
+        delete pTemporaryAnnot;
+
+    if( pkey )
+        EVP_PKEY_free( pkey );
+
+    if( cert )
+        X509_free( cert );
+
+    return result;
+}
diff --git a/tools/podofotxt2pdf/CMakeLists.txt b/tools/podofotxt2pdf/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5f30c09
--- /dev/null
@@ -0,0 +1,6 @@
+ADD_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")
diff --git a/tools/podofotxt2pdf/podofotxt2pdf.cpp b/tools/podofotxt2pdf/podofotxt2pdf.cpp
new file mode 100644 (file)
index 0000000..5493c63
--- /dev/null
@@ -0,0 +1,221 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <cstdio>
+
+using namespace PoDoFo;
+
+#ifdef _HAVE_CONFIG
+#include <config.h>
+#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<const pdf_utf8*>(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<char*>(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<long>( 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<argc;i++) 
+  {
+      if( strcmp("-utf8", argv[i]) == 0 ) 
+      {
+          bUtf8 = true;
+      }
+      else if( strcmp("-fontname", argv[i]) == 0 ) 
+      {
+          ++i;
+          pszFontName = argv[i];
+      }
+      else 
+      {
+          if( pszInput == NULL )
+          {
+              pszInput = argv[i];
+          }
+          else
+          {
+              pszOutput = argv[i];
+          }
+      }
+  }
+
+  try {
+      init( pszInput, pszOutput, bUtf8, pszFontName );
+  } catch( PdfError & e ) {
+      fprintf( stderr, "Error %i occurred!\n", e.GetError() );
+      e.PrintErrorMsg();
+      return e.GetError();
+  }
+
+  return 0;
+}
+
diff --git a/tools/podofotxt2pdf/podofotxt2pdf.vcproj b/tools/podofotxt2pdf/podofotxt2pdf.vcproj
new file mode 100644 (file)
index 0000000..aa86a01
--- /dev/null
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.10"\r
+       Name="podofotxt2pdf"\r
+       ProjectGUID="{7DFBD6DE-B262-4047-84E4-B630C40D688C}"\r
+       Keyword="Win32Proj">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..\src;..\..\freetype\include;..\..\zlib;..\..\jpeg"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"\r
+                               MinimalRebuild="TRUE"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="4"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="wsock32.lib"\r
+                               OutputFile="$(OutDir)/podofotxt2pdf.exe"\r
+                               LinkIncremental="2"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(OutDir)/podofotxt2pdf.pdb"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"\r
+                               RuntimeLibrary="4"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="3"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(OutDir)/podofotxt2pdf.exe"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="TRUE"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">\r
+                       <File\r
+                               RelativePath=".\podofotxt2pdf.cpp">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/tools/podofotxtextract/CMakeLists.txt b/tools/podofotxtextract/CMakeLists.txt
new file mode 100644 (file)
index 0000000..948bf36
--- /dev/null
@@ -0,0 +1,7 @@
+ADD_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")
diff --git a/tools/podofotxtextract/TextExtractor.cpp b/tools/podofotxtextract/TextExtractor.cpp
new file mode 100644 (file)
index 0000000..32dc2b4
--- /dev/null
@@ -0,0 +1,215 @@
+/***************************************************************************
+ *   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 <stack>
+
+TextExtractor::TextExtractor()
+{
+
+}
+
+TextExtractor::~TextExtractor()
+{
+}
+
+void TextExtractor::Init( const char* pszInput )
+{
+    if( !pszInput )
+    {
+        PODOFO_RAISE_ERROR( ePdfError_InvalidHandle );
+    }
+
+    PdfMemDocument document;
+
+    document.Load( pszInput );
+
+    int nCount = document.GetPageCount();
+    for( int i=0; i<nCount; i++ ) 
+    {
+        PdfPage* pPage = document.GetPage( i );
+        
+        this->ExtractText( &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<PdfVariant> 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 )
+            {
+                if( stack.size() == 2 )
+                {
+                    dCurPosX = stack.top().GetReal();
+                    stack.pop();
+                    dCurPosY = stack.top().GetReal();
+                    stack.pop();
+                }
+                else
+                {
+                    fprintf( stderr, "WARNING: Token '%s' expects two arguments, but %" PDF_FORMAT_INT64 " given; ignoring\n",
+                        pszToken, static_cast<pdf_int64>( stack.size() ) );
+
+                    while( !stack.empty() )
+                        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 ) 
+                {
+                    if( stack.size() < 2 )
+                    {
+                        fprintf( stderr, "WARNING: Expects two arguments for 'Tf', ignoring\n" );
+                        pCurFont = NULL;
+                        continue;
+                    }
+
+                    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 %" PDF_FORMAT_INT64 " %" PDF_FORMAT_INT64 " R\n",
+                                 static_cast<pdf_int64>( pFont->Reference().ObjectNumber() ),
+                                 static_cast<pdf_int64>( pFont->Reference().GenerationNumber() ) );
+                    }
+                }
+                else if( strcmp( pszToken, "Tj" ) == 0 ||
+                         strcmp( pszToken, "'" ) == 0 ) 
+                {
+                    if( stack.size() < 1 )
+                    {
+                        fprintf( stderr, "WARNING: Expects one argument for '%s', ignoring\n", pszToken );
+                        continue;
+                    }
+
+                    AddTextElement( dCurPosX, dCurPosY, pCurFont, stack.top().GetString() );
+                    stack.pop();
+                }
+                else if( strcmp( pszToken, "\"" ) == 0 )
+                {
+                    if( stack.size() < 3 )
+                    {
+                        fprintf( stderr, "WARNING: Expects three arguments for '%s', ignoring\n", pszToken );
+
+                        while( !stack.empty() )
+                            stack.pop();
+
+                        continue;
+                    }
+
+                    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 ) 
+                {
+                    if( stack.size() < 3 )
+                    {
+                        fprintf( stderr, "WARNING: Expects one argument for '%s', ignoring\n", pszToken );
+                        continue;
+                    }
+
+                    PdfArray array = stack.top().GetArray();
+                    stack.pop();
+                    
+                    for( int i=0; i<static_cast<int>(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<unsigned char>(*pszData) );
+        ++pszData;
+    }
+       printf("(%.3f,%.3f) %s \n", dCurPosX, dCurPosY, unicode.GetStringUtf8().c_str() );
+}
diff --git a/tools/podofotxtextract/TextExtractor.h b/tools/podofotxtextract/TextExtractor.h
new file mode 100644 (file)
index 0000000..ec91ae8
--- /dev/null
@@ -0,0 +1,65 @@
+/***************************************************************************
+ *   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 <podofo.h>
+#include <cstdio>
+
+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_
diff --git a/tools/podofotxtextract/podofotxtextract.cpp b/tools/podofotxtextract/podofotxtextract.cpp
new file mode 100644 (file)
index 0000000..e2cf052
--- /dev/null
@@ -0,0 +1,60 @@
+/***************************************************************************
+ *   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 <stdio.h>
+#include <stdlib.h>
+#include <cstdio>
+
+#ifdef _HAVE_CONFIG
+#include <config.h>
+#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;
+}
diff --git a/tools/podofouncompress/CMakeLists.txt b/tools/podofouncompress/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f01f340
--- /dev/null
@@ -0,0 +1,6 @@
+ADD_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")
diff --git a/tools/podofouncompress/Uncompress.cpp b/tools/podofouncompress/Uncompress.cpp
new file mode 100644 (file)
index 0000000..23c63ee
--- /dev/null
@@ -0,0 +1,90 @@
+/***************************************************************************
+ *   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 <cstdio>
+
+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<PdfMemStream*>((*it)->GetStream());
+                if( !pStream )
+                    PODOFO_RAISE_ERROR( ePdfError_InvalidHandle );
+                printf("-> Original Length: %" PDF_FORMAT_INT64 "\n", 
+                       static_cast<pdf_int64>(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<pdf_int64>(pStream->GetLength()) );
+            } catch( PdfError & e ) {
+                e.PrintErrorMsg();
+                if( e.GetError() != ePdfError_UnsupportedFilter )
+                    throw e;
+            }
+        }
+
+        ++it;
+    }
+}
diff --git a/tools/podofouncompress/Uncompress.h b/tools/podofouncompress/Uncompress.h
new file mode 100644 (file)
index 0000000..80720c8
--- /dev/null
@@ -0,0 +1,43 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+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_
diff --git a/tools/podofouncompress/podofouncompress.cpp b/tools/podofouncompress/podofouncompress.cpp
new file mode 100644 (file)
index 0000000..954e526
--- /dev/null
@@ -0,0 +1,74 @@
+/***************************************************************************
+ *   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 <podofo.h>
+
+#include <stdlib.h>
+#include <cstdio>
+
+using namespace PoDoFo;
+
+#ifdef _HAVE_CONFIG
+#include <config.h>
+#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 successfully uncompressed to: %s\n", pszInput, pszOutput );
+  
+  return 0;
+}
+
diff --git a/tools/podofoxmp/CMakeLists.txt b/tools/podofoxmp/CMakeLists.txt
new file mode 100644 (file)
index 0000000..17922e9
--- /dev/null
@@ -0,0 +1,7 @@
+ADD_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")
diff --git a/tools/podofoxmp/podofoxmp.cpp b/tools/podofoxmp/podofoxmp.cpp
new file mode 100644 (file)
index 0000000..cf290d4
--- /dev/null
@@ -0,0 +1,166 @@
+/***************************************************************************
+ *   Copyright (C) 2010 by Ian Ashley                                      *
+ *   Ian Ashley <Ian.Ashley@opentext.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 <iostream>
+#include <iterator>
+#include <string>
+#include <cstdlib>
+#include <cstdio>
+
+#ifdef _MSC_VER
+    #include <io.h>
+    #include <fcntl.h>
+#endif
+
+#include <podofo.h>
+
+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] << " <pdf file> - display the XMP in a file (use \"-\" to specify stdin)" << endl;
+            cout << "or" << endl;
+            cout << "  " << argv[0] << " <src pdf file> <xmp file> <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->LoadFromBuffer( 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;
+}
diff --git a/vcincludes/unistd.h b/vcincludes/unistd.h
new file mode 100644 (file)
index 0000000..3dc75a5
--- /dev/null
@@ -0,0 +1,6 @@
+/*\r
+ * This file exists solely to keep VC++ happy\r
+ * because it doesn't provide a <unistd.h>\r
+ * and flex doesn't provide us with any way to\r
+ * prevent the inclusion of it.\r
+ */
\ No newline at end of file