From c70248a520408d876a49d9b428b5f4313b34fcea Mon Sep 17 00:00:00 2001 From: Devin Jankowski Date: Wed, 21 Jun 2023 12:46:23 -0400 Subject: [PATCH] Initial Commit --- Ionic/Ionic.Zip.dll | Bin 0 -> 492032 bytes Ionic/Ionic.Zip.pdb | Bin 0 -> 765440 bytes Ionic/Ionic.Zip.xml | 18132 ++++++++++++++++ .../Interpreter/Interpreter/RtfInterpreter.cs | 497 + .../Interpreter/Interpreter2005.csproj | 133 + RtfConverter/Parser/Parser2005.csproj | 79 + .../bin/Debug/Itenso.Rtf.Interpreter.dll | Bin 0 -> 90112 bytes RtfConverter/bin/Debug/Itenso.Rtf.Parser.dll | Bin 0 -> 49152 bytes iTechSharp/AssemblyInfo.cs | 58 + iTechSharp/System/Drawing/Dimension.cs | 158 + iTechSharp/System/Drawing/Dimension2D.cs | 69 + iTechSharp/System/util/ListIterator.cs | 43 + iTechSharp/System/util/Properties.cs | 209 + iTechSharp/System/util/StringTokenizer.cs | 130 + iTechSharp/System/util/Util.cs | 27 + .../System/util/collections/Algorithm.cs | 49 + .../System/util/collections/Container.cs | 64 + iTechSharp/System/util/collections/Deque.cs | 470 + .../System/util/collections/HashTable.cs | 658 + .../System/util/collections/Iterator.cs | 323 + iTechSharp/System/util/collections/List.cs | 537 + iTechSharp/System/util/collections/Queue.cs | 108 + .../System/util/collections/SkipList.cs | 699 + iTechSharp/System/util/collections/Stack.cs | 101 + iTechSharp/System/util/collections/Tree.cs | 830 + iTechSharp/System/util/collections/Vector.cs | 143 + iTechSharp/System/util/zlib/Adler32.cs | 88 + iTechSharp/System/util/zlib/Deflate.cs | 1639 ++ iTechSharp/System/util/zlib/InfBlocks.cs | 618 + iTechSharp/System/util/zlib/InfCodes.cs | 611 + iTechSharp/System/util/zlib/InfTree.cs | 523 + iTechSharp/System/util/zlib/Inflate.cs | 387 + iTechSharp/System/util/zlib/JZlib.cs | 70 + iTechSharp/System/util/zlib/StaticTree.cs | 152 + iTechSharp/System/util/zlib/Tree.cs | 367 + .../System/util/zlib/ZDeflaterOutputStream.cs | 196 + .../System/util/zlib/ZInflaterInputStream.cs | 174 + iTechSharp/System/util/zlib/ZStream.cs | 214 + iTechSharp/iTextSharp/text/Anchor.cs | 284 + iTechSharp/iTextSharp/text/Annotation.cs | 525 + .../iTextSharp/text/BadElementException.cs | 66 + iTechSharp/iTextSharp/text/Cell.cs | 873 + iTechSharp/iTextSharp/text/Chapter.cs | 142 + .../iTextSharp/text/ChapterAutoNumber.cs | 101 + iTechSharp/iTextSharp/text/Chunk.cs | 733 + iTechSharp/iTextSharp/text/Color.cs | 150 + iTechSharp/iTextSharp/text/DocWriter.cs | 416 + iTechSharp/iTextSharp/text/Document.cs | 684 + .../iTextSharp/text/DocumentException.cs | 77 + iTechSharp/iTextSharp/text/Element.cs | 285 + iTechSharp/iTextSharp/text/ElementTags.cs | 521 + iTechSharp/iTextSharp/text/Font.cs | 698 + iTechSharp/iTextSharp/text/FontFactory.cs | 426 + iTechSharp/iTextSharp/text/FontFactoryImp.cs | 677 + iTechSharp/iTextSharp/text/GreekList.cs | 124 + iTechSharp/iTextSharp/text/Header.cs | 94 + iTechSharp/iTextSharp/text/HeaderFooter.cs | 234 + iTechSharp/iTextSharp/text/IDocListener.cs | 149 + iTechSharp/iTextSharp/text/IElement.cs | 126 + .../iTextSharp/text/IElementListener.cs | 16 + iTechSharp/iTextSharp/text/ILargeElement.cs | 84 + .../iTextSharp/text/IRtfElementInterface.cs | 60 + iTechSharp/iTextSharp/text/ISplitCharacter.cs | 94 + .../iTextSharp/text/ITextElementArray.cs | 22 + iTechSharp/iTextSharp/text/Image.cs | 1483 ++ iTechSharp/iTextSharp/text/ImgCCITT.cs | 107 + iTechSharp/iTextSharp/text/ImgRaw.cs | 88 + iTechSharp/iTextSharp/text/ImgTemplate.cs | 88 + iTechSharp/iTextSharp/text/ImgWMF.cs | 176 + iTechSharp/iTextSharp/text/Jpeg.cs | 335 + iTechSharp/iTextSharp/text/Jpeg2000.cs | 239 + iTechSharp/iTextSharp/text/List.cs | 555 + iTechSharp/iTextSharp/text/ListItem.cs | 239 + iTechSharp/iTextSharp/text/MarkedObject.cs | 154 + iTechSharp/iTextSharp/text/MarkedSection.cs | 297 + iTechSharp/iTextSharp/text/Meta.cs | 234 + iTechSharp/iTextSharp/text/PageSize.cs | 244 + iTechSharp/iTextSharp/text/Paragraph.cs | 408 + iTechSharp/iTextSharp/text/Phrase.cs | 509 + iTechSharp/iTextSharp/text/Rectangle.cs | 733 + .../iTextSharp/text/RectangleReadOnly.cs | 329 + iTechSharp/iTextSharp/text/RomanList.cs | 116 + iTechSharp/iTextSharp/text/Row.cs | 376 + iTechSharp/iTextSharp/text/Section.cs | 756 + iTechSharp/iTextSharp/text/SimpleCell.cs | 453 + iTechSharp/iTextSharp/text/SimpleTable.cs | 302 + iTechSharp/iTextSharp/text/SpecialSymbol.cs | 202 + iTechSharp/iTextSharp/text/Table.cs | 1577 ++ iTechSharp/iTextSharp/text/Utilities.cs | 267 + .../iTextSharp/text/ZapfDingbatsList.cs | 85 + .../iTextSharp/text/ZapfDingbatsNumberList.cs | 100 + .../text/factories/ElementFactory.cs | 533 + .../text/factories/GreekAlphabetFactory.cs | 122 + .../text/factories/RomanAlphabetFactory.cs | 122 + .../text/factories/RomanNumberFactory.cs | 180 + .../iTextSharp/text/html/HtmlEncoder.cs | 213 + iTechSharp/iTextSharp/text/html/HtmlParser.cs | 239 + iTechSharp/iTextSharp/text/html/HtmlPeer.cs | 102 + iTechSharp/iTextSharp/text/html/HtmlTagMap.cs | 289 + iTechSharp/iTextSharp/text/html/HtmlTags.cs | 325 + iTechSharp/iTextSharp/text/html/HtmlWriter.cs | 1041 + .../text/html/ITextmyHtmlHandler.cs | 239 + iTechSharp/iTextSharp/text/html/Markup.cs | 427 + iTechSharp/iTextSharp/text/html/WebColors.cs | 263 + .../html/simpleparser/ChainedProperties.cs | 135 + .../html/simpleparser/FactoryProperties.cs | 338 + .../text/html/simpleparser/HTMLWorker.cs | 624 + .../text/html/simpleparser/IALink.cs | 54 + .../text/html/simpleparser/IImageProvider.cs | 55 + .../iTextSharp/text/html/simpleparser/IImg.cs | 55 + .../text/html/simpleparser/IncCell.cs | 153 + .../text/html/simpleparser/IncTable.cs | 124 + .../text/html/simpleparser/StyleSheet.cs | 117 + iTechSharp/iTextSharp/text/pdf/AcroFields.cs | 2126 ++ .../iTextSharp/text/pdf/ArabicLigaturizer.cs | 772 + .../text/pdf/BadPasswordException.cs | 59 + .../text/pdf/BadPdfFormatException.cs | 72 + iTechSharp/iTextSharp/text/pdf/Barcode.cs | 430 + iTechSharp/iTextSharp/text/pdf/Barcode128.cs | 809 + iTechSharp/iTextSharp/text/pdf/Barcode39.cs | 370 + .../iTextSharp/text/pdf/BarcodeCodabar.cs | 324 + .../iTextSharp/text/pdf/BarcodeDatamatrix.cs | 1265 ++ iTechSharp/iTextSharp/text/pdf/BarcodeEAN.cs | 697 + .../iTextSharp/text/pdf/BarcodeEANSUPP.cs | 150 + .../iTextSharp/text/pdf/BarcodeInter25.cs | 317 + .../iTextSharp/text/pdf/BarcodePDF417.cs | 1551 ++ .../iTextSharp/text/pdf/BarcodePostnet.cs | 219 + iTechSharp/iTextSharp/text/pdf/BaseField.cs | 630 + iTechSharp/iTextSharp/text/pdf/BaseFont.cs | 1433 ++ iTechSharp/iTextSharp/text/pdf/BidiLine.cs | 946 + iTechSharp/iTextSharp/text/pdf/BidiOrder.cs | 1296 ++ iTechSharp/iTextSharp/text/pdf/ByteBuffer.cs | 673 + iTechSharp/iTextSharp/text/pdf/CFFFont.cs | 1111 + .../iTextSharp/text/pdf/CFFFontSubset.cs | 1578 ++ iTechSharp/iTextSharp/text/pdf/CJKFont.cs | 646 + iTechSharp/iTextSharp/text/pdf/CMYKColor.cs | 112 + iTechSharp/iTextSharp/text/pdf/CodeFile1.cs | 0 .../iTextSharp/text/pdf/ColorDetails.cs | 107 + iTechSharp/iTextSharp/text/pdf/ColumnText.cs | 1534 ++ .../text/pdf/DefaultSplitCharacter.cs | 109 + .../iTextSharp/text/pdf/DocumentFont.cs | 633 + .../iTextSharp/text/pdf/EnumerateTTC.cs | 123 + .../iTextSharp/text/pdf/ExtendedColor.cs | 101 + iTechSharp/iTextSharp/text/pdf/FdfReader.cs | 218 + iTechSharp/iTextSharp/text/pdf/FdfWriter.cs | 324 + iTechSharp/iTextSharp/text/pdf/FontDetails.cs | 278 + .../iTextSharp/text/pdf/FontSelector.cs | 145 + iTechSharp/iTextSharp/text/pdf/GlyphList.cs | 124 + iTechSharp/iTextSharp/text/pdf/GrayColor.cs | 86 + .../iTextSharp/text/pdf/HyphenationAuto.cs | 130 + iTechSharp/iTextSharp/text/pdf/ICC_Profile.cs | 108 + .../iTextSharp/text/pdf/IExtraEncoding.cs | 84 + .../iTextSharp/text/pdf/IHyphenationEvent.cs | 83 + iTechSharp/iTextSharp/text/pdf/IPdfOCG.cs | 73 + .../iTextSharp/text/pdf/IPdfPCellEvent.cs | 29 + .../iTextSharp/text/pdf/IPdfPTableEvent.cs | 96 + .../iTextSharp/text/pdf/IPdfPageEvent.cs | 189 + .../iTextSharp/text/pdf/IntHashtable.cs | 312 + iTechSharp/iTextSharp/text/pdf/LZWDecoder.cs | 240 + .../iTextSharp/text/pdf/MultiColumnText.cs | 605 + .../text/pdf/OutputStreamCounter.cs | 81 + .../text/pdf/OutputStreamEncryption.cs | 170 + iTechSharp/iTextSharp/text/pdf/PRAcroForm.cs | 225 + .../text/pdf/PRIndirectReference.cs | 107 + iTechSharp/iTextSharp/text/pdf/PRStream.cs | 205 + iTechSharp/iTextSharp/text/pdf/PRTokeniser.cs | 565 + .../iTextSharp/text/pdf/PageResources.cs | 194 + .../iTextSharp/text/pdf/PatternColor.cs | 82 + iTechSharp/iTextSharp/text/pdf/PdfAcroForm.cs | 490 + iTechSharp/iTextSharp/text/pdf/PdfAction.cs | 521 + .../iTextSharp/text/pdf/PdfAnnotation.cs | 824 + .../iTextSharp/text/pdf/PdfAppearance.cs | 175 + iTechSharp/iTextSharp/text/pdf/PdfArray.cs | 295 + iTechSharp/iTextSharp/text/pdf/PdfBoolean.cs | 137 + .../iTextSharp/text/pdf/PdfBorderArray.cs | 82 + .../text/pdf/PdfBorderDictionary.cs | 101 + iTechSharp/iTextSharp/text/pdf/PdfCell.cs | 875 + iTechSharp/iTextSharp/text/pdf/PdfChunk.cs | 841 + iTechSharp/iTextSharp/text/pdf/PdfColor.cs | 80 + .../iTextSharp/text/pdf/PdfContentByte.cs | 2898 +++ .../iTextSharp/text/pdf/PdfContentParser.cs | 211 + iTechSharp/iTextSharp/text/pdf/PdfContents.cs | 148 + iTechSharp/iTextSharp/text/pdf/PdfCopy.cs | 759 + .../iTextSharp/text/pdf/PdfCopyFields.cs | 244 + .../iTextSharp/text/pdf/PdfCopyFieldsImp.cs | 600 + .../iTextSharp/text/pdf/PdfDashPattern.cs | 142 + iTechSharp/iTextSharp/text/pdf/PdfDate.cs | 215 + .../iTextSharp/text/pdf/PdfDestination.cs | 221 + .../iTextSharp/text/pdf/PdfDictionary.cs | 375 + iTechSharp/iTextSharp/text/pdf/PdfDocument.cs | 2987 +++ .../iTextSharp/text/pdf/PdfEncodings.cs | 782 + .../iTextSharp/text/pdf/PdfEncryption.cs | 512 + .../iTextSharp/text/pdf/PdfEncryptor.cs | 314 + .../iTextSharp/text/pdf/PdfException.cs | 68 + .../text/pdf/PdfFileSpecification.cs | 261 + iTechSharp/iTextSharp/text/pdf/PdfFont.cs | 193 + .../iTextSharp/text/pdf/PdfFormField.cs | 353 + .../iTextSharp/text/pdf/PdfFormXObject.cs | 104 + iTechSharp/iTextSharp/text/pdf/PdfFunction.cs | 141 + iTechSharp/iTextSharp/text/pdf/PdfGState.cs | 170 + iTechSharp/iTextSharp/text/pdf/PdfICCBased.cs | 33 + iTechSharp/iTextSharp/text/pdf/PdfImage.cs | 281 + .../iTextSharp/text/pdf/PdfImportedPage.cs | 162 + .../iTextSharp/text/pdf/PdfIndirectObject.cs | 157 + .../text/pdf/PdfIndirectReference.cs | 137 + iTechSharp/iTextSharp/text/pdf/PdfLayer.cs | 321 + .../iTextSharp/text/pdf/PdfLayerMembership.cs | 145 + iTechSharp/iTextSharp/text/pdf/PdfLine.cs | 539 + iTechSharp/iTextSharp/text/pdf/PdfLiteral.cs | 101 + .../iTextSharp/text/pdf/PdfMediaClipData.cs | 63 + iTechSharp/iTextSharp/text/pdf/PdfName.cs | 1257 ++ iTechSharp/iTextSharp/text/pdf/PdfNameTree.cs | 161 + iTechSharp/iTextSharp/text/pdf/PdfNull.cs | 85 + iTechSharp/iTextSharp/text/pdf/PdfNumber.cs | 163 + .../iTextSharp/text/pdf/PdfNumberTree.cs | 157 + .../iTextSharp/text/pdf/PdfOCProperties.cs | 52 + iTechSharp/iTextSharp/text/pdf/PdfObject.cs | 369 + iTechSharp/iTextSharp/text/pdf/PdfOutline.cs | 485 + iTechSharp/iTextSharp/text/pdf/PdfPCell.cs | 696 + iTechSharp/iTextSharp/text/pdf/PdfPKCS7.cs | 1170 + iTechSharp/iTextSharp/text/pdf/PdfPRow.cs | 649 + .../iTextSharp/text/pdf/PdfPSXObject.cs | 101 + iTechSharp/iTextSharp/text/pdf/PdfPTable.cs | 1050 + iTechSharp/iTextSharp/text/pdf/PdfPage.cs | 172 + .../iTextSharp/text/pdf/PdfPageEventHelper.cs | 202 + .../iTextSharp/text/pdf/PdfPageLabels.cs | 289 + iTechSharp/iTextSharp/text/pdf/PdfPages.cs | 195 + iTechSharp/iTextSharp/text/pdf/PdfPattern.cs | 79 + .../iTextSharp/text/pdf/PdfPatternPainter.cs | 360 + .../text/pdf/PdfPublicKeyRecipient.cs | 41 + .../text/pdf/PdfPublicKeySecurityHandler.cs | 197 + iTechSharp/iTextSharp/text/pdf/PdfReader.cs | 3386 +++ .../iTextSharp/text/pdf/PdfReaderInstance.cs | 185 + .../iTextSharp/text/pdf/PdfRectangle.cs | 290 + .../iTextSharp/text/pdf/PdfRendition.cs | 60 + .../iTextSharp/text/pdf/PdfResources.cs | 92 + iTechSharp/iTextSharp/text/pdf/PdfShading.cs | 277 + .../iTextSharp/text/pdf/PdfShadingPattern.cs | 137 + .../iTextSharp/text/pdf/PdfSigGenericPKCS.cs | 196 + .../iTextSharp/text/pdf/PdfSignature.cs | 115 + .../text/pdf/PdfSignatureAppearance.cs | 1445 ++ .../iTextSharp/text/pdf/PdfSmartCopy.cs | 228 + .../iTextSharp/text/pdf/PdfSpotColor.cs | 126 + iTechSharp/iTextSharp/text/pdf/PdfStamper.cs | 742 + .../iTextSharp/text/pdf/PdfStamperImp.cs | 1625 ++ iTechSharp/iTextSharp/text/pdf/PdfStream.cs | 324 + iTechSharp/iTextSharp/text/pdf/PdfString.cs | 232 + .../text/pdf/PdfStructureElement.cs | 136 + .../text/pdf/PdfStructureTreeRoot.cs | 146 + iTechSharp/iTextSharp/text/pdf/PdfTable.cs | 319 + iTechSharp/iTextSharp/text/pdf/PdfTemplate.cs | 281 + .../iTextSharp/text/pdf/PdfTextArray.cs | 134 + .../iTextSharp/text/pdf/PdfTransition.cs | 257 + .../text/pdf/PdfTransparencyGroup.cs | 90 + iTechSharp/iTextSharp/text/pdf/PdfWriter.cs | 2973 +++ .../text/pdf/PdfXConformanceException.cs | 67 + iTechSharp/iTextSharp/text/pdf/Pfm2afm.cs | 805 + .../iTextSharp/text/pdf/PushbuttonField.cs | 628 + .../iTextSharp/text/pdf/RadioCheckField.cs | 401 + .../text/pdf/RandomAccessFileOrArray.cs | 607 + .../iTextSharp/text/pdf/SequenceList.cs | 317 + .../iTextSharp/text/pdf/ShadingColor.cs | 78 + .../iTextSharp/text/pdf/SimpleBookmark.cs | 799 + .../text/pdf/SimpleNamedDestination.cs | 325 + iTechSharp/iTextSharp/text/pdf/SpotColor.cs | 95 + .../iTextSharp/text/pdf/StampContent.cs | 86 + .../iTextSharp/text/pdf/StandardDecryption.cs | 111 + iTechSharp/iTextSharp/text/pdf/TextField.cs | 641 + .../iTextSharp/text/pdf/TrueTypeFont.cs | 1517 ++ .../iTextSharp/text/pdf/TrueTypeFontSubSet.cs | 423 + .../text/pdf/TrueTypeFontUnicode.cs | 487 + iTechSharp/iTextSharp/text/pdf/Type1Font.cs | 796 + iTechSharp/iTextSharp/text/pdf/Type3Font.cs | 317 + iTechSharp/iTextSharp/text/pdf/Type3Glyph.cs | 94 + .../iTextSharp/text/pdf/VerticalText.cs | 344 + iTechSharp/iTextSharp/text/pdf/XfaForm.cs | 995 + iTechSharp/iTextSharp/text/pdf/XfdfReader.cs | 223 + .../iTextSharp/text/pdf/codec/BmpImage.cs | 1278 ++ .../text/pdf/codec/CCITTG4Encoder.cs | 601 + .../iTextSharp/text/pdf/codec/GifImage.cs | 597 + .../iTextSharp/text/pdf/codec/PngImage.cs | 971 + .../text/pdf/codec/TIFFConstants.cs | 282 + .../text/pdf/codec/TIFFDirectory.cs | 669 + .../text/pdf/codec/TIFFFaxDecoder.cs | 1502 ++ .../iTextSharp/text/pdf/codec/TIFFField.cs | 487 + .../text/pdf/codec/TIFFLZWDecoder.cs | 272 + .../iTextSharp/text/pdf/codec/TiffImage.cs | 546 + .../text/pdf/codec/wmf/InputMeta.cs | 117 + .../text/pdf/codec/wmf/MetaBrush.cs | 101 + .../iTextSharp/text/pdf/codec/wmf/MetaDo.cs | 764 + .../iTextSharp/text/pdf/codec/wmf/MetaFont.cs | 206 + .../text/pdf/codec/wmf/MetaObject.cs | 76 + .../iTextSharp/text/pdf/codec/wmf/MetaPen.cs | 98 + .../text/pdf/codec/wmf/MetaState.cs | 390 + .../text/pdf/collection/PdfCollection.cs | 67 + .../text/pdf/collection/PdfCollectionField.cs | 127 + .../text/pdf/collection/PdfCollectionItem.cs | 112 + .../pdf/collection/PdfCollectionSchema.cs | 22 + .../text/pdf/collection/PdfCollectionSort.cs | 63 + .../pdf/collection/PdfTargetDictionary.cs | 101 + .../iTextSharp/text/pdf/crypto/AESCipher.cs | 105 + .../text/pdf/crypto/ARCFOUREncryption.cs | 108 + .../iTextSharp/text/pdf/crypto/IVGenerator.cs | 97 + .../text/pdf/draw/DottedLineSeparator.cs | 91 + .../text/pdf/draw/IDrawInterface.cs | 74 + .../iTextSharp/text/pdf/draw/LineSeparator.cs | 192 + .../text/pdf/draw/VerticalPositionMark.cs | 173 + .../text/pdf/events/FieldPositioningEvents.cs | 183 + .../iTextSharp/text/pdf/events/IndexEvents.cs | 389 + .../text/pdf/events/PdfPCellEventForwarder.cs | 86 + .../pdf/events/PdfPTableEventForwarder.cs | 85 + .../text/pdf/events/PdfPageEventForwarder.cs | 286 + .../text/pdf/fonts/Courier-Bold.afm | 342 + .../text/pdf/fonts/Courier-BoldOblique.afm | 342 + .../text/pdf/fonts/Courier-Oblique.afm | 342 + .../iTextSharp/text/pdf/fonts/Courier.afm | 342 + .../text/pdf/fonts/Helvetica-Bold.afm | 2827 +++ .../text/pdf/fonts/Helvetica-BoldOblique.afm | 2827 +++ .../text/pdf/fonts/Helvetica-Oblique.afm | 3051 +++ .../iTextSharp/text/pdf/fonts/Helvetica.afm | 3051 +++ .../iTextSharp/text/pdf/fonts/Symbol.afm | 213 + .../iTextSharp/text/pdf/fonts/Times-Bold.afm | 2588 +++ .../text/pdf/fonts/Times-BoldItalic.afm | 2384 ++ .../text/pdf/fonts/Times-Italic.afm | 2667 +++ .../iTextSharp/text/pdf/fonts/Times-Roman.afm | 2419 +++ .../text/pdf/fonts/ZapfDingbats.afm | 225 + .../iTextSharp/text/pdf/fonts/glyphlist.txt | 5430 +++++ .../text/pdf/hyphenation/ByteVector.cs | 119 + .../text/pdf/hyphenation/CharVector.cs | 128 + .../iTextSharp/text/pdf/hyphenation/Hyphen.cs | 67 + .../text/pdf/hyphenation/Hyphenation.cs | 79 + .../pdf/hyphenation/HyphenationException.cs | 27 + .../text/pdf/hyphenation/HyphenationTree.cs | 451 + .../text/pdf/hyphenation/Hyphenator.cs | 220 + .../text/pdf/hyphenation/IPatternConsumer.cs | 54 + .../pdf/hyphenation/SimplePatternParser.cs | 247 + .../text/pdf/hyphenation/TernaryTree.cs | 631 + .../text/pdf/interfaces/IPdfAnnotations.cs | 87 + .../pdf/interfaces/IPdfDocumentActions.cs | 87 + .../pdf/interfaces/IPdfEncryptionSettings.cs | 96 + .../text/pdf/interfaces/IPdfPageActions.cs | 85 + .../text/pdf/interfaces/IPdfRunDirection.cs | 63 + .../text/pdf/interfaces/IPdfVersion.cs | 94 + .../pdf/interfaces/IPdfViewerPreferences.cs | 202 + .../text/pdf/interfaces/IPdfXConformance.cs | 71 + .../text/pdf/intern/PdfAnnotationsImp.cs | 230 + .../text/pdf/intern/PdfVersionImp.cs | 172 + .../pdf/intern/PdfViewerPreferencesImp.cs | 359 + .../text/pdf/intern/PdfXConformanceImp.cs | 256 + .../iTextSharp/text/rtf/IEventListener.cs | 6 + .../iTextSharp/text/rtf/IRtfBasicElement.cs | 87 + .../text/rtf/IRtfExtendedElement.cs | 70 + .../iTextSharp/text/rtf/RtfAddableElement.cs | 134 + iTechSharp/iTextSharp/text/rtf/RtfElement.cs | 159 + iTechSharp/iTextSharp/text/rtf/RtfMapper.cs | 173 + iTechSharp/iTextSharp/text/rtf/RtfWriter2.cs | 334 + .../text/rtf/direct/RtfDirectContent.cs | 101 + .../text/rtf/document/RtfCodePage.cs | 99 + .../text/rtf/document/RtfDocument.cs | 347 + .../text/rtf/document/RtfDocumentHeader.cs | 321 + .../text/rtf/document/RtfDocumentSettings.cs | 566 + .../text/rtf/document/RtfGenerator.cs | 92 + .../text/rtf/document/RtfInfoElement.cs | 168 + .../text/rtf/document/RtfInfoGroup.cs | 125 + .../text/rtf/document/RtfPageSetting.cs | 425 + .../text/rtf/document/RtfProtection.cs | 273 + .../text/rtf/document/RtfProtectionSetting.cs | 182 + .../text/rtf/document/output/IRtfDataCache.cs | 92 + .../rtf/document/output/RtfByteArrayBuffer.cs | 306 + .../text/rtf/document/output/RtfDiskCache.cs | 107 + .../output/RtfEfficientMemoryCache.cs | 86 + .../rtf/document/output/RtfMemoryCache.cs | 91 + .../rtf/document/output/RtfNilOutputStream.cs | 139 + .../iTextSharp/text/rtf/field/RtfAnchor.cs | 111 + .../iTextSharp/text/rtf/field/RtfField.cs | 427 + .../text/rtf/field/RtfPageNumber.cs | 75 + .../iTextSharp/text/rtf/field/RtfTOCEntry.cs | 146 + .../text/rtf/field/RtfTableOfContents.cs | 105 + .../text/rtf/field/RtfTotalPageNumber.cs | 118 + .../iTextSharp/text/rtf/graphic/RtfImage.cs | 384 + .../iTextSharp/text/rtf/graphic/RtfShape.cs | 379 + .../text/rtf/graphic/RtfShapePosition.cs | 249 + .../text/rtf/graphic/RtfShapeProperty.cs | 356 + .../text/rtf/headerfooter/RtfHeaderFooter.cs | 326 + .../rtf/headerfooter/RtfHeaderFooterGroup.cs | 377 + .../iTextSharp/text/rtf/list/RtfList.cs | 629 + .../iTextSharp/text/rtf/list/RtfListItem.cs | 187 + .../iTextSharp/text/rtf/list/RtfListTable.cs | 198 + .../text/rtf/parser/PushbackStream.cs | 86 + .../text/rtf/parser/RtfImportMappings.cs | 170 + .../text/rtf/parser/RtfImportMgr.cs | 281 + .../iTextSharp/text/rtf/parser/RtfParser.cs | 1457 ++ .../text/rtf/parser/RtfParserState.cs | 138 + .../parser/ctrlwords/IRtfCtrlWordListener.cs | 78 + .../rtf/parser/ctrlwords/RtfCtrlWordData.cs | 132 + .../parser/ctrlwords/RtfCtrlWordHandler.cs | 358 + .../rtf/parser/ctrlwords/RtfCtrlWordMap.cs | 1903 ++ .../rtf/parser/ctrlwords/RtfCtrlWordMgr.cs | 204 + .../rtf/parser/ctrlwords/RtfCtrlWordType.cs | 97 + .../destinations/IRtfDestinationListener.cs | 98 + .../rtf/parser/destinations/RtfDestination.cs | 254 + .../destinations/RtfDestinationColorTable.cs | 317 + .../destinations/RtfDestinationDocument.cs | 592 + .../destinations/RtfDestinationFontTable.cs | 600 + .../parser/destinations/RtfDestinationInfo.cs | 174 + .../destinations/RtfDestinationListTable.cs | 130 + .../parser/destinations/RtfDestinationMgr.cs | 227 + .../parser/destinations/RtfDestinationNull.cs | 147 + .../destinations/RtfDestinationShppict.cs | 488 + .../RtfDestinationStylesheetTable.cs | 585 + .../rtf/parser/enumerations/RtfColorThemes.cs | 29 + .../parser/exceptions/RtfParserException.cs | 87 + .../exceptions/RtfUnknownCtrlWordException.cs | 15 + .../parser/properties/IRtfPropertyListener.cs | 71 + .../properties/RtfCtrlWordPropertyType.cs | 58 + .../text/rtf/parser/properties/RtfProperty.cs | 575 + .../iTextSharp/text/rtf/style/RtfColor.cs | 285 + .../iTextSharp/text/rtf/style/RtfColorList.cs | 131 + .../iTextSharp/text/rtf/style/RtfFont.cs | 730 + .../iTextSharp/text/rtf/style/RtfFontList.cs | 147 + .../text/rtf/style/RtfParagraphStyle.cs | 675 + .../text/rtf/style/RtfStyleTypes.cs | 81 + .../text/rtf/style/RtfStylesheetList.cs | 110 + .../iTextSharp/text/rtf/table/RtfBorder.cs | 561 + .../text/rtf/table/RtfBorderGroup.cs | 213 + .../iTextSharp/text/rtf/table/RtfCell.cs | 493 + .../iTextSharp/text/rtf/table/RtfRow.cs | 377 + .../iTextSharp/text/rtf/table/RtfTable.cs | 271 + .../iTextSharp/text/rtf/text/RtfAnnotation.cs | 123 + .../iTextSharp/text/rtf/text/RtfChapter.cs | 96 + .../iTextSharp/text/rtf/text/RtfChunk.cs | 191 + .../iTextSharp/text/rtf/text/RtfNewPage.cs | 44 + .../iTextSharp/text/rtf/text/RtfParagraph.cs | 196 + .../iTextSharp/text/rtf/text/RtfPhrase.cs | 198 + .../iTextSharp/text/rtf/text/RtfSection.cs | 183 + iTechSharp/iTextSharp/text/rtf/text/RtfTab.cs | 135 + .../iTextSharp/text/rtf/text/RtfTabGroup.cs | 121 + .../iTextSharp/text/xml/ITextHandler.cs | 872 + .../iTextSharp/text/xml/ITextmyHandler.cs | 112 + iTechSharp/iTextSharp/text/xml/ParserBase.cs | 99 + iTechSharp/iTextSharp/text/xml/TagMap.cs | 215 + iTechSharp/iTextSharp/text/xml/XmlParser.cs | 245 + iTechSharp/iTextSharp/text/xml/XmlPeer.cs | 175 + .../text/xml/simpleparser/EntitiesToSymbol.cs | 381 + .../xml/simpleparser/EntitiesToUnicode.cs | 442 + .../xml/simpleparser/ISimpleXMLDocHandler.cs | 81 + .../ISimpleXMLDocHandlerComment.cs | 61 + .../text/xml/simpleparser/IanaEncodings.cs | 551 + .../text/xml/simpleparser/SimpleXMLParser.cs | 740 + .../text/xml/xmp/DublinCoreSchema.cs | 185 + .../text/xml/xmp/EncodingNoPreamble.cs | 163 + iTechSharp/iTextSharp/text/xml/xmp/LangAlt.cs | 100 + .../iTextSharp/text/xml/xmp/PdfA1Schema.cs | 92 + .../iTextSharp/text/xml/xmp/PdfSchema.cs | 104 + .../iTextSharp/text/xml/xmp/XmpArray.cs | 98 + .../iTextSharp/text/xml/xmp/XmpBasicSchema.cs | 139 + .../iTextSharp/text/xml/xmp/XmpMMSchema.cs | 94 + .../iTextSharp/text/xml/xmp/XmpSchema.cs | 165 + .../iTextSharp/text/xml/xmp/XmpWriter.cs | 276 + iTechSharp/itextsharp.csproj | 6789 ++++++ iTechSharp/itextsharp.dll | Bin 0 -> 3567616 bytes iTechSharp/itextsharp.sln | 21 + iTechSharp/itextsharp.snk | Bin 0 -> 596 bytes iTechSharp/srcbc/asn1/ASN1Generator.cs | 27 + iTechSharp/srcbc/asn1/ASN1ObjectParser.cs | 10 + .../srcbc/asn1/ASN1OctetStringParser.cs | 10 + iTechSharp/srcbc/asn1/ASN1SequenceParser.cs | 8 + iTechSharp/srcbc/asn1/ASN1SetParser.cs | 8 + iTechSharp/srcbc/asn1/ASN1StreamParser.cs | 154 + .../srcbc/asn1/ASN1TaggedObjectParser.cs | 10 + iTechSharp/srcbc/asn1/Asn1Encodable.cs | 78 + iTechSharp/srcbc/asn1/Asn1EncodableVector.cs | 76 + iTechSharp/srcbc/asn1/Asn1InputStream.cs | 307 + iTechSharp/srcbc/asn1/Asn1Null.cs | 18 + iTechSharp/srcbc/asn1/Asn1Object.cs | 48 + iTechSharp/srcbc/asn1/Asn1OctetString.cs | 128 + iTechSharp/srcbc/asn1/Asn1OutputStream.cs | 35 + iTechSharp/srcbc/asn1/Asn1Sequence.cs | 231 + iTechSharp/srcbc/asn1/Asn1Set.cs | 307 + iTechSharp/srcbc/asn1/Asn1TaggedObject.cs | 177 + iTechSharp/srcbc/asn1/Asn1Tags.cs | 36 + iTechSharp/srcbc/asn1/BERGenerator.cs | 102 + .../srcbc/asn1/BEROctetStringGenerator.cs | 117 + iTechSharp/srcbc/asn1/BEROctetStringParser.cs | 36 + iTechSharp/srcbc/asn1/BERSequenceGenerator.cs | 24 + iTechSharp/srcbc/asn1/BERSequenceParser.cs | 24 + iTechSharp/srcbc/asn1/BERSetGenerator.cs | 24 + iTechSharp/srcbc/asn1/BERSetParser.cs | 24 + .../srcbc/asn1/BERTaggedObjectParser.cs | 128 + iTechSharp/srcbc/asn1/BerNull.cs | 35 + iTechSharp/srcbc/asn1/BerOctetString.cs | 150 + iTechSharp/srcbc/asn1/BerOutputStream.cs | 36 + iTechSharp/srcbc/asn1/BerSequence.cs | 69 + iTechSharp/srcbc/asn1/BerSet.cs | 70 + iTechSharp/srcbc/asn1/BerTaggedObject.cs | 108 + .../srcbc/asn1/ConstructedOctetStream.cs | 102 + iTechSharp/srcbc/asn1/DERGenerator.cs | 107 + iTechSharp/srcbc/asn1/DEROctetStringParser.cs | 36 + iTechSharp/srcbc/asn1/DERSequenceGenerator.cs | 40 + iTechSharp/srcbc/asn1/DERSequenceParser.cs | 24 + iTechSharp/srcbc/asn1/DERSetGenerator.cs | 40 + iTechSharp/srcbc/asn1/DERSetParser.cs | 24 + .../srcbc/asn1/DefiniteLengthInputStream.cs | 86 + .../srcbc/asn1/DerApplicationSpecific.cs | 150 + iTechSharp/srcbc/asn1/DerBMPString.cs | 118 + iTechSharp/srcbc/asn1/DerBitString.cs | 245 + iTechSharp/srcbc/asn1/DerBoolean.cs | 110 + iTechSharp/srcbc/asn1/DerEnumerated.cs | 103 + iTechSharp/srcbc/asn1/DerGeneralString.cs | 79 + iTechSharp/srcbc/asn1/DerGeneralizedTime.cs | 289 + iTechSharp/srcbc/asn1/DerIA5String.cs | 146 + iTechSharp/srcbc/asn1/DerInteger.cs | 128 + iTechSharp/srcbc/asn1/DerNull.cs | 41 + iTechSharp/srcbc/asn1/DerNumericString.cs | 139 + iTechSharp/srcbc/asn1/DerObjectIdentifier.cs | 260 + iTechSharp/srcbc/asn1/DerOctetString.cs | 34 + iTechSharp/srcbc/asn1/DerOutputStream.cs | 147 + iTechSharp/srcbc/asn1/DerPrintableString.cs | 164 + iTechSharp/srcbc/asn1/DerSequence.cs | 85 + iTechSharp/srcbc/asn1/DerSet.cs | 108 + iTechSharp/srcbc/asn1/DerStringBase.cs | 22 + iTechSharp/srcbc/asn1/DerT61String.cs | 105 + iTechSharp/srcbc/asn1/DerTaggedObject.cs | 72 + iTechSharp/srcbc/asn1/DerUTCTime.cs | 259 + iTechSharp/srcbc/asn1/DerUTF8String.cs | 99 + iTechSharp/srcbc/asn1/DerUniversalString.cs | 105 + iTechSharp/srcbc/asn1/DerUnknownTag.cs | 64 + iTechSharp/srcbc/asn1/DerVisibleString.cs | 109 + iTechSharp/srcbc/asn1/IAsn1Convertible.cs | 7 + iTechSharp/srcbc/asn1/IAsn1String.cs | 10 + .../srcbc/asn1/IndefiniteLengthInputStream.cs | 95 + iTechSharp/srcbc/asn1/LazyASN1InputStream.cs | 33 + iTechSharp/srcbc/asn1/LazyDERSequence.cs | 84 + iTechSharp/srcbc/asn1/LazyDERSet.cs | 84 + iTechSharp/srcbc/asn1/LimitedInputStream.cs | 26 + iTechSharp/srcbc/asn1/OidTokenizer.cs | 45 + iTechSharp/srcbc/asn1/cmp/PKIFailureInfo.cs | 73 + iTechSharp/srcbc/asn1/cmp/PKIFreeText.cs | 97 + iTechSharp/srcbc/asn1/cmp/PKIStatus.cs | 14 + iTechSharp/srcbc/asn1/cmp/PKIStatusInfo.cs | 165 + iTechSharp/srcbc/asn1/cms/Attribute.cs | 68 + iTechSharp/srcbc/asn1/cms/AttributeTable.cs | 155 + iTechSharp/srcbc/asn1/cms/CMSAttributes.cs | 13 + .../srcbc/asn1/cms/CMSObjectIdentifiers.cs | 15 + iTechSharp/srcbc/asn1/cms/CompressedData.cs | 100 + .../srcbc/asn1/cms/CompressedDataParser.cs | 47 + iTechSharp/srcbc/asn1/cms/ContentInfo.cs | 87 + .../srcbc/asn1/cms/ContentInfoParser.cs | 40 + .../srcbc/asn1/cms/EncryptedContentInfo.cs | 98 + .../asn1/cms/EncryptedContentInfoParser.cs | 46 + iTechSharp/srcbc/asn1/cms/EncryptedData.cs | 95 + iTechSharp/srcbc/asn1/cms/EnvelopedData.cs | 152 + .../srcbc/asn1/cms/EnvelopedDataParser.cs | 106 + .../srcbc/asn1/cms/IssuerAndSerialNumber.cs | 70 + iTechSharp/srcbc/asn1/cms/KEKIdentifier.cs | 133 + iTechSharp/srcbc/asn1/cms/KEKRecipientInfo.cs | 110 + .../asn1/cms/KeyAgreeRecipientIdentifier.cs | 90 + .../srcbc/asn1/cms/KeyAgreeRecipientInfo.cs | 143 + .../srcbc/asn1/cms/KeyTransRecipientInfo.cs | 103 + .../asn1/cms/OriginatorIdentifierOrKey.cs | 115 + iTechSharp/srcbc/asn1/cms/OriginatorInfo.cs | 125 + .../srcbc/asn1/cms/OriginatorPublicKey.cs | 91 + .../srcbc/asn1/cms/OtherKeyAttribute.cs | 74 + .../srcbc/asn1/cms/OtherRecipientInfo.cs | 89 + .../srcbc/asn1/cms/PasswordRecipientInfo.cs | 137 + .../srcbc/asn1/cms/RecipientEncryptedKey.cs | 88 + .../srcbc/asn1/cms/RecipientIdentifier.cs | 94 + iTechSharp/srcbc/asn1/cms/RecipientInfo.cs | 151 + .../srcbc/asn1/cms/RecipientKeyIdentifier.cs | 135 + iTechSharp/srcbc/asn1/cms/SignedData.cs | 292 + iTechSharp/srcbc/asn1/cms/SignedDataParser.cs | 112 + iTechSharp/srcbc/asn1/cms/SignerIdentifier.cs | 94 + iTechSharp/srcbc/asn1/cms/SignerInfo.cs | 158 + iTechSharp/srcbc/asn1/cms/Time.cs | 124 + .../cryptopro/CryptoProObjectIdentifiers.cs | 48 + .../asn1/cryptopro/ECGOST3410NamedCurves.cs | 178 + .../cryptopro/ECGOST3410ParamSetParameters.cs | 86 + .../asn1/cryptopro/GOST28147Parameters.cs | 63 + .../asn1/cryptopro/GOST3410NamedParameters.cs | 122 + .../cryptopro/GOST3410ParamSetParameters.cs | 87 + .../GOST3410PublicKeyAlgParameters.cs | 99 + .../srcbc/asn1/esf/CertificateValues.cs | 85 + .../asn1/esf/CommitmentTypeIdentifier.cs | 17 + .../asn1/esf/CommitmentTypeIndication.cs | 95 + .../srcbc/asn1/esf/CommitmentTypeQualifier.cs | 119 + .../srcbc/asn1/esf/CompleteCertificateRefs.cs | 84 + .../srcbc/asn1/esf/CompleteRevocationRefs.cs | 84 + iTechSharp/srcbc/asn1/esf/CrlIdentifier.cs | 110 + iTechSharp/srcbc/asn1/esf/CrlListID.cs | 89 + iTechSharp/srcbc/asn1/esf/CrlOcspRef.cs | 111 + iTechSharp/srcbc/asn1/esf/CrlValidatedID.cs | 89 + iTechSharp/srcbc/asn1/esf/ESFAttributes.cs | 24 + iTechSharp/srcbc/asn1/esf/OcspIdentifier.cs | 77 + iTechSharp/srcbc/asn1/esf/OcspListID.cs | 88 + iTechSharp/srcbc/asn1/esf/OcspResponsesID.cs | 92 + iTechSharp/srcbc/asn1/esf/OtherCertID.cs | 93 + iTechSharp/srcbc/asn1/esf/OtherHash.cs | 89 + .../srcbc/asn1/esf/OtherHashAlgAndValue.cs | 94 + iTechSharp/srcbc/asn1/esf/OtherRevRefs.cs | 78 + iTechSharp/srcbc/asn1/esf/OtherRevVals.cs | 78 + .../srcbc/asn1/esf/OtherSigningCertificate.cs | 138 + iTechSharp/srcbc/asn1/esf/RevocationValues.cs | 175 + .../srcbc/asn1/esf/SigPolicyQualifierInfo.cs | 71 + .../srcbc/asn1/esf/SignaturePolicyId.cs | 145 + .../asn1/esf/SignaturePolicyIdentifier.cs | 65 + iTechSharp/srcbc/asn1/esf/SignerLocation.cs | 144 + iTechSharp/srcbc/asn1/ess/ContentHints.cs | 92 + .../srcbc/asn1/ess/ContentIdentifier.cs | 65 + iTechSharp/srcbc/asn1/ess/ESSCertID.cs | 93 + iTechSharp/srcbc/asn1/ess/ESSCertIDv2.cs | 138 + iTechSharp/srcbc/asn1/ess/OtherCertID.cs | 132 + .../srcbc/asn1/ess/OtherSigningCertificate.cs | 109 + .../srcbc/asn1/ess/SigningCertificate.cs | 108 + .../srcbc/asn1/ess/SigningCertificateV2.cs | 106 + .../srcbc/asn1/gnu/GNUObjectIdentifiers.cs | 31 + .../srcbc/asn1/iana/IANAObjectIdentifiers.cs | 18 + iTechSharp/srcbc/asn1/icao/DataGroupHash.cs | 90 + .../srcbc/asn1/icao/ICAOObjectIdentifiers.cs | 16 + .../srcbc/asn1/icao/LDSSecurityObject.cs | 113 + .../asn1/isismtt/ISISMTTObjectIdentifiers.cs | 177 + .../srcbc/asn1/isismtt/ocsp/CertHash.cs | 121 + .../asn1/isismtt/ocsp/RequestedCertificate.cs | 187 + .../x509/AdditionalInformationSyntax.cs | 74 + .../asn1/isismtt/x509/AdmissionSyntax.cs | Bin 0 -> 20844 bytes .../srcbc/asn1/isismtt/x509/Admissions.cs | 186 + .../isismtt/x509/DeclarationOfMajority.cs | 171 + .../srcbc/asn1/isismtt/x509/MonetaryLimit.cs | 122 + .../asn1/isismtt/x509/NamingAuthority.cs | 214 + .../asn1/isismtt/x509/ProcurationSyntax.cs | 232 + .../srcbc/asn1/isismtt/x509/ProfessionInfo.cs | 386 + .../srcbc/asn1/isismtt/x509/Restriction.cs | 85 + .../srcbc/asn1/kisa/KISAObjectIdentifiers.cs | 8 + .../microsoft/MicrosoftObjectIdentifiers.cs | 18 + .../srcbc/asn1/misc/CAST5CBCParameters.cs | 74 + iTechSharp/srcbc/asn1/misc/IDEACBCPar.cs | 68 + .../srcbc/asn1/misc/MiscObjectIdentifiers.cs | 48 + .../srcbc/asn1/misc/NetscapeCertType.cs | 54 + .../srcbc/asn1/misc/NetscapeRevocationURL.cs | 18 + .../srcbc/asn1/misc/VerisignCzagExtension.cs | 18 + .../asn1/mozilla/PublicKeyAndChallenge.cs | 67 + iTechSharp/srcbc/asn1/nist/NISTNamedCurves.cs | 100 + .../srcbc/asn1/nist/NISTObjectIdentifiers.cs | 55 + .../srcbc/asn1/ntt/NTTObjectIdentifiers.cs | 14 + .../srcbc/asn1/ocsp/BasicOCSPResponse.cs | 131 + iTechSharp/srcbc/asn1/ocsp/CertID.cs | 98 + iTechSharp/srcbc/asn1/ocsp/CertStatus.cs | 94 + iTechSharp/srcbc/asn1/ocsp/CrlID.cs | 82 + .../srcbc/asn1/ocsp/OCSPObjectIdentifiers.cs | 23 + iTechSharp/srcbc/asn1/ocsp/OCSPRequest.cs | 89 + iTechSharp/srcbc/asn1/ocsp/OCSPResponse.cs | 90 + .../srcbc/asn1/ocsp/OCSPResponseStatus.cs | 41 + iTechSharp/srcbc/asn1/ocsp/Request.cs | 90 + iTechSharp/srcbc/asn1/ocsp/ResponderID.cs | 77 + iTechSharp/srcbc/asn1/ocsp/ResponseBytes.cs | 82 + iTechSharp/srcbc/asn1/ocsp/ResponseData.cs | 158 + iTechSharp/srcbc/asn1/ocsp/RevokedInfo.cs | 96 + iTechSharp/srcbc/asn1/ocsp/ServiceLocator.cs | 95 + iTechSharp/srcbc/asn1/ocsp/Signature.cs | 110 + iTechSharp/srcbc/asn1/ocsp/SingleResponse.cs | 137 + iTechSharp/srcbc/asn1/ocsp/TBSRequest.cs | 147 + iTechSharp/srcbc/asn1/oiw/ElGamalParameter.cs | 47 + .../srcbc/asn1/oiw/OIWObjectIdentifiers.cs | 24 + iTechSharp/srcbc/asn1/pkcs/Attribute.cs | 79 + .../srcbc/asn1/pkcs/AuthenticatedSafe.cs | 37 + iTechSharp/srcbc/asn1/pkcs/CertBag.cs | 46 + .../srcbc/asn1/pkcs/CertificationRequest.cs | 81 + .../asn1/pkcs/CertificationRequestInfo.cs | 123 + iTechSharp/srcbc/asn1/pkcs/ContentInfo.cs | 80 + iTechSharp/srcbc/asn1/pkcs/DHParameter.cs | 72 + iTechSharp/srcbc/asn1/pkcs/EncryptedData.cs | 104 + .../asn1/pkcs/EncryptedPrivateKeyInfo.cs | 78 + .../srcbc/asn1/pkcs/EncryptionScheme.cs | 31 + .../srcbc/asn1/pkcs/IssuerAndSerialNumber.cs | 71 + .../srcbc/asn1/pkcs/KeyDerivationFunc.cs | 21 + iTechSharp/srcbc/asn1/pkcs/MacData.cs | 81 + iTechSharp/srcbc/asn1/pkcs/PBEParameter.cs | 64 + iTechSharp/srcbc/asn1/pkcs/PBES2Parameters.cs | 48 + iTechSharp/srcbc/asn1/pkcs/PBKDF2Params.cs | 85 + iTechSharp/srcbc/asn1/pkcs/PKCS12PBEParams.cs | 63 + .../srcbc/asn1/pkcs/PKCSObjectIdentifiers.cs | 251 + iTechSharp/srcbc/asn1/pkcs/Pfx.cs | 65 + iTechSharp/srcbc/asn1/pkcs/PrivateKeyInfo.cs | 130 + iTechSharp/srcbc/asn1/pkcs/RC2CBCParameter.cs | 81 + iTechSharp/srcbc/asn1/pkcs/RSAESOAEPparams.cs | 145 + .../srcbc/asn1/pkcs/RSAPrivateKeyStructure.cs | 131 + iTechSharp/srcbc/asn1/pkcs/RSASSAPSSparams.cs | 165 + iTechSharp/srcbc/asn1/pkcs/SafeBag.cs | 70 + iTechSharp/srcbc/asn1/pkcs/SignedData.cs | 163 + iTechSharp/srcbc/asn1/pkcs/SignerInfo.cs | 154 + .../srcbc/asn1/sec/ECPrivateKeyStructure.cs | 82 + iTechSharp/srcbc/asn1/sec/SECNamedCurves.cs | 1191 + .../srcbc/asn1/sec/SECObjectIdentifiers.cs | 52 + .../srcbc/asn1/smime/SMIMEAttributes.cs | 11 + .../srcbc/asn1/smime/SMIMECapabilities.cs | 112 + .../asn1/smime/SMIMECapabilitiesAttribute.cs | 16 + .../srcbc/asn1/smime/SMIMECapability.cs | 101 + .../srcbc/asn1/smime/SMIMECapabilityVector.cs | 37 + .../SMIMEEncryptionKeyPreferenceAttribute.cs | 44 + .../asn1/teletrust/TeleTrusTNamedCurves.cs | 427 + .../teletrust/TeleTrusTObjectIdentifiers.cs | 45 + iTechSharp/srcbc/asn1/tsp/Accuracy.cs | 149 + iTechSharp/srcbc/asn1/tsp/MessageImprint.cs | 74 + iTechSharp/srcbc/asn1/tsp/TSTInfo.cs | 244 + iTechSharp/srcbc/asn1/tsp/TimeStampReq.cs | 164 + iTechSharp/srcbc/asn1/tsp/TimeStampResp.cs | 80 + iTechSharp/srcbc/asn1/util/Asn1Dump.cs | 250 + iTechSharp/srcbc/asn1/util/Dump.cs | 28 + iTechSharp/srcbc/asn1/util/FilterStream.cs | 67 + iTechSharp/srcbc/asn1/x500/DirectoryString.cs | 76 + .../srcbc/asn1/x509/AccessDescription.cs | 88 + .../srcbc/asn1/x509/AlgorithmIdentifier.cs | 110 + iTechSharp/srcbc/asn1/x509/AttCertIssuer.cs | 86 + .../srcbc/asn1/x509/AttCertValidityPeriod.cs | 78 + iTechSharp/srcbc/asn1/x509/Attribute.cs | 77 + .../srcbc/asn1/x509/AttributeCertificate.cs | 85 + .../asn1/x509/AttributeCertificateInfo.cs | 156 + iTechSharp/srcbc/asn1/x509/AttributeTable.cs | 54 + .../asn1/x509/AuthorityInformationAccess.cs | 87 + .../srcbc/asn1/x509/AuthorityKeyIdentifier.cs | 211 + .../srcbc/asn1/x509/BasicConstraints.cs | 133 + iTechSharp/srcbc/asn1/x509/CRLDistPoint.cs | 93 + iTechSharp/srcbc/asn1/x509/CRLNumber.cs | 30 + iTechSharp/srcbc/asn1/x509/CRLReason.cs | 61 + iTechSharp/srcbc/asn1/x509/CertPolicyId.cs | 20 + iTechSharp/srcbc/asn1/x509/CertificateList.cs | 112 + iTechSharp/srcbc/asn1/x509/CertificatePair.cs | 160 + iTechSharp/srcbc/asn1/x509/DSAParameter.cs | 77 + iTechSharp/srcbc/asn1/x509/DigestInfo.cs | 76 + iTechSharp/srcbc/asn1/x509/DisplayText.cs | 172 + .../srcbc/asn1/x509/DistributionPoint.cs | 161 + .../srcbc/asn1/x509/DistributionPointName.cs | 130 + .../srcbc/asn1/x509/ExtendedKeyUsage.cs | 107 + iTechSharp/srcbc/asn1/x509/GeneralName.cs | 240 + iTechSharp/srcbc/asn1/x509/GeneralNames.cs | 91 + iTechSharp/srcbc/asn1/x509/GeneralSubtree.cs | 177 + iTechSharp/srcbc/asn1/x509/Holder.cs | 257 + iTechSharp/srcbc/asn1/x509/IetfAttrSyntax.cs | 161 + iTechSharp/srcbc/asn1/x509/IssuerSerial.cs | 98 + .../asn1/x509/IssuingDistributionPoint.cs | 247 + iTechSharp/srcbc/asn1/x509/KeyPurposeId.cs | 36 + iTechSharp/srcbc/asn1/x509/KeyUsage.cs | 79 + iTechSharp/srcbc/asn1/x509/NameConstraints.cs | 90 + iTechSharp/srcbc/asn1/x509/NoticeReference.cs | 128 + .../srcbc/asn1/x509/ObjectDigestInfo.cs | 177 + .../srcbc/asn1/x509/PolicyInformation.cs | 80 + iTechSharp/srcbc/asn1/x509/PolicyMappings.cs | 62 + .../srcbc/asn1/x509/PolicyQualifierId.cs | 28 + .../srcbc/asn1/x509/PolicyQualifierInfo.cs | 91 + .../srcbc/asn1/x509/PrivateKeyUsagePeriod.cs | 82 + .../srcbc/asn1/x509/RSAPublicKeyStructure.cs | 82 + iTechSharp/srcbc/asn1/x509/ReasonFlags.cs | 46 + iTechSharp/srcbc/asn1/x509/RoleSyntax.cs | 234 + .../asn1/x509/SubjectDirectoryAttributes.cs | 128 + .../srcbc/asn1/x509/SubjectKeyIdentifier.cs | 95 + .../srcbc/asn1/x509/SubjectPublicKeyInfo.cs | 106 + iTechSharp/srcbc/asn1/x509/TBSCertList.cs | 274 + .../asn1/x509/TBSCertificateStructure.cs | 189 + iTechSharp/srcbc/asn1/x509/Target.cs | 140 + .../srcbc/asn1/x509/TargetInformation.cs | 123 + iTechSharp/srcbc/asn1/x509/Targets.cs | 121 + iTechSharp/srcbc/asn1/x509/Time.cs | 126 + iTechSharp/srcbc/asn1/x509/UserNotice.cs | 104 + .../asn1/x509/V1TBSCertificateGenerator.cs | 108 + .../V2AttributeCertificateInfoGenerator.cs | 137 + iTechSharp/srcbc/asn1/x509/V2Form.cs | 125 + .../srcbc/asn1/x509/V2TBSCertListGenerator.cs | 196 + .../asn1/x509/V3TBSCertificateGenerator.cs | 144 + iTechSharp/srcbc/asn1/x509/X509Attributes.cs | 9 + .../asn1/x509/X509CertificateStructure.cs | 133 + .../asn1/x509/X509DefaultEntryConverter.cs | 62 + iTechSharp/srcbc/asn1/x509/X509Extension.cs | 74 + iTechSharp/srcbc/asn1/x509/X509Extensions.cs | 348 + .../asn1/x509/X509ExtensionsGenerator.cs | 79 + iTechSharp/srcbc/asn1/x509/X509Name.cs | 1057 + .../srcbc/asn1/x509/X509NameEntryConverter.cs | 89 + .../srcbc/asn1/x509/X509NameTokenizer.cs | 101 + .../srcbc/asn1/x509/X509ObjectIdentifiers.cs | 56 + .../asn1/x509/qualified/BiometricData.cs | 112 + .../x509/qualified/ETSIQCObjectIdentifiers.cs | 19 + .../x509/qualified/Iso4217CurrencyCode.cs | 84 + .../asn1/x509/qualified/MonetaryValue.cs | 83 + .../srcbc/asn1/x509/qualified/QCStatement.cs | 85 + .../qualified/RFC3739QCObjectIdentifiers.cs | 21 + .../x509/qualified/SemanticsInformation.cs | 124 + .../x509/qualified/TypeOfBiometricData.cs | 91 + .../srcbc/asn1/x509/sigi/NameOrPseudonym.cs | 178 + .../srcbc/asn1/x509/sigi/PersonalData.cs | 210 + .../asn1/x509/sigi/SigIObjectIdentifiers.cs | 49 + iTechSharp/srcbc/asn1/x9/KeySpecificInfo.cs | 58 + iTechSharp/srcbc/asn1/x9/OtherInfo.cs | 88 + iTechSharp/srcbc/asn1/x9/X962NamedCurves.cs | 732 + iTechSharp/srcbc/asn1/x9/X962Parameters.cs | 53 + iTechSharp/srcbc/asn1/x9/X9Curve.cs | 147 + iTechSharp/srcbc/asn1/x9/X9ECParameters.cs | 165 + .../srcbc/asn1/x9/X9ECParametersHolder.cs | 22 + iTechSharp/srcbc/asn1/x9/X9ECPoint.cs | 44 + iTechSharp/srcbc/asn1/x9/X9FieldElement.cs | 69 + iTechSharp/srcbc/asn1/x9/X9FieldID.cs | 102 + .../srcbc/asn1/x9/X9IntegerConverter.cs | 46 + .../srcbc/asn1/x9/X9ObjectIdentifiers.cs | 132 + iTechSharp/srcbc/bcpg/ArmoredInputStream.cs | 492 + iTechSharp/srcbc/bcpg/ArmoredOutputStream.cs | 328 + iTechSharp/srcbc/bcpg/BcpgInputStream.cs | 355 + iTechSharp/srcbc/bcpg/BcpgObject.cs | 22 + iTechSharp/srcbc/bcpg/BcpgOutputStream.cs | 390 + iTechSharp/srcbc/bcpg/CompressedDataPacket.cs | 24 + .../srcbc/bcpg/CompressionAlgorithmTags.cs | 11 + iTechSharp/srcbc/bcpg/ContainedPacket.cs | 22 + iTechSharp/srcbc/bcpg/Crc24.cs | 46 + iTechSharp/srcbc/bcpg/DsaPublicBcpgKey.cs | 80 + iTechSharp/srcbc/bcpg/DsaSecretBcpgKey.cs | 61 + iTechSharp/srcbc/bcpg/ElGamalPublicBcpgKey.cs | 71 + iTechSharp/srcbc/bcpg/ElGamalSecretBcpgKey.cs | 61 + iTechSharp/srcbc/bcpg/ExperimentalPacket.cs | 38 + iTechSharp/srcbc/bcpg/HashAlgorithmTags.cs | 19 + iTechSharp/srcbc/bcpg/IBcpgKey.cs | 16 + iTechSharp/srcbc/bcpg/InputStreamPacket.cs | 20 + iTechSharp/srcbc/bcpg/LiteralDataPacket.cs | 51 + iTechSharp/srcbc/bcpg/MPInteger.cs | 59 + iTechSharp/srcbc/bcpg/MarkerPacket.cs | 24 + .../srcbc/bcpg/ModDetectionCodePacket.cs | 42 + .../srcbc/bcpg/OnePassSignaturePacket.cs | 93 + iTechSharp/srcbc/bcpg/OutputStreamPacket.cs | 24 + iTechSharp/srcbc/bcpg/Packet.cs | 7 + iTechSharp/srcbc/bcpg/PacketTags.cs | 30 + .../srcbc/bcpg/PublicKeyAlgorithmTags.cs | 28 + .../srcbc/bcpg/PublicKeyEncSessionPacket.cs | 103 + iTechSharp/srcbc/bcpg/PublicKeyPacket.cs | 115 + iTechSharp/srcbc/bcpg/PublicSubkeyPacket.cs | 30 + iTechSharp/srcbc/bcpg/RsaPublicBcpgKey.cs | 66 + iTechSharp/srcbc/bcpg/RsaSecretBcpgKey.cs | 114 + iTechSharp/srcbc/bcpg/S2k.cs | 147 + iTechSharp/srcbc/bcpg/SecretKeyPacket.cs | 163 + iTechSharp/srcbc/bcpg/SecretSubkeyPacket.cs | 43 + iTechSharp/srcbc/bcpg/SignaturePacket.cs | 459 + iTechSharp/srcbc/bcpg/SignatureSubpacket.cs | 76 + .../srcbc/bcpg/SignatureSubpacketTags.cs | 30 + .../srcbc/bcpg/SignatureSubpacketsReader.cs | 88 + .../srcbc/bcpg/SymmetricEncDataPacket.cs | 15 + .../srcbc/bcpg/SymmetricEncIntegrityPacket.cs | 18 + .../srcbc/bcpg/SymmetricKeyAlgorithmTags.cs | 20 + .../bcpg/SymmetricKeyEncSessionPacket.cs | 91 + iTechSharp/srcbc/bcpg/TrustPacket.cs | 43 + iTechSharp/srcbc/bcpg/UserAttributePacket.cs | 59 + .../srcbc/bcpg/UserAttributeSubpacket.cs | 86 + .../srcbc/bcpg/UserAttributeSubpacketTags.cs | 10 + .../bcpg/UserAttributeSubpacketsReader.cs | 63 + iTechSharp/srcbc/bcpg/UserIdPacket.cs | 37 + iTechSharp/srcbc/bcpg/attr/ImageAttrib.cs | 68 + iTechSharp/srcbc/bcpg/sig/Exportable.cs | 47 + iTechSharp/srcbc/bcpg/sig/IssuerKeyId.cs | 61 + .../srcbc/bcpg/sig/KeyExpirationTime.cs | 56 + iTechSharp/srcbc/bcpg/sig/KeyFlags.cs | 36 + iTechSharp/srcbc/bcpg/sig/NotationData.cs | 101 + .../srcbc/bcpg/sig/PreferredAlgorithms.cs | 54 + iTechSharp/srcbc/bcpg/sig/PrimaryUserId.cs | 48 + iTechSharp/srcbc/bcpg/sig/Revocable.cs | 48 + .../srcbc/bcpg/sig/SignatureCreationTime.cs | 47 + .../srcbc/bcpg/sig/SignatureExpirationTime.cs | 54 + iTechSharp/srcbc/bcpg/sig/SignerUserId.cs | 52 + iTechSharp/srcbc/bcpg/sig/TrustSignature.cs | 56 + iTechSharp/srcbc/cms/BaseDigestCalculator.cs | 23 + .../CMSAttributeTableGenerationException.cs | 25 + .../srcbc/cms/CMSAttributeTableGenerator.cs | 25 + iTechSharp/srcbc/cms/CMSCompressedData.cs | 73 + .../srcbc/cms/CMSCompressedDataGenerator.cs | 69 + .../srcbc/cms/CMSCompressedDataParser.cs | 57 + .../cms/CMSCompressedDataStreamGenerator.cs | 124 + iTechSharp/srcbc/cms/CMSContentInfoParser.cs | 47 + iTechSharp/srcbc/cms/CMSEnvelopedData.cs | 139 + .../srcbc/cms/CMSEnvelopedDataGenerator.cs | 174 + .../srcbc/cms/CMSEnvelopedDataParser.cs | 189 + .../cms/CMSEnvelopedDataStreamGenerator.cs | 273 + iTechSharp/srcbc/cms/CMSEnvelopedGenerator.cs | 551 + iTechSharp/srcbc/cms/CMSEnvelopedHelper.cs | 99 + iTechSharp/srcbc/cms/CMSException.cs | 25 + iTechSharp/srcbc/cms/CMSPBEKey.cs | 68 + iTechSharp/srcbc/cms/CMSProcessable.cs | 27 + .../srcbc/cms/CMSProcessableByteArray.cs | 36 + iTechSharp/srcbc/cms/CMSProcessableFile.cs | 53 + iTechSharp/srcbc/cms/CMSSignedData.cs | 430 + .../srcbc/cms/CMSSignedDataGenerator.cs | 501 + iTechSharp/srcbc/cms/CMSSignedDataParser.cs | 565 + .../srcbc/cms/CMSSignedDataStreamGenerator.cs | 690 + iTechSharp/srcbc/cms/CMSSignedGenerator.cs | 240 + iTechSharp/srcbc/cms/CMSSignedHelper.cs | 332 + iTechSharp/srcbc/cms/CMSTypedStream.cs | 88 + iTechSharp/srcbc/cms/CMSUtils.cs | 161 + .../cms/CounterSignatureDigestCalculator.cs | 29 + .../DefaultSignedAttributeTableGenerator.cs | 104 + iTechSharp/srcbc/cms/IDigestCalculator.cs | 9 + .../srcbc/cms/KEKRecipientInformation.cs | 65 + .../srcbc/cms/KeyAgreeRecipientInformation.cs | 122 + .../srcbc/cms/KeyTransRecipientInformation.cs | 111 + iTechSharp/srcbc/cms/PKCS5Scheme2PBEKey.cs | 35 + .../srcbc/cms/PasswordRecipientInformation.cs | 74 + iTechSharp/srcbc/cms/RecipientId.cs | 58 + iTechSharp/srcbc/cms/RecipientInformation.cs | 137 + .../srcbc/cms/RecipientInformationStore.cs | 79 + iTechSharp/srcbc/cms/SignerId.cs | 51 + iTechSharp/srcbc/cms/SignerInformation.cs | 631 + .../srcbc/cms/SignerInformationStore.cs | 72 + .../cms/SimpleAttributeTableGenerator.cs | 28 + .../srcbc/crypto/AsymmetricCipherKeyPair.cs | 52 + .../srcbc/crypto/AsymmetricKeyParameter.cs | 47 + .../srcbc/crypto/BufferedAeadBlockCipher.cs | 259 + .../crypto/BufferedAsymmetricBlockCipher.cs | 152 + .../srcbc/crypto/BufferedBlockCipher.cs | 372 + iTechSharp/srcbc/crypto/BufferedCipherBase.cs | 113 + iTechSharp/srcbc/crypto/BufferedIesCipher.cs | 113 + .../srcbc/crypto/BufferedStreamCipher.cs | 131 + iTechSharp/srcbc/crypto/CipherKeyGenerator.cs | 83 + iTechSharp/srcbc/crypto/CryptoException.cs | 25 + .../srcbc/crypto/DataLengthException.cs | 39 + .../srcbc/crypto/IAsymmetricBlockCipher.cs | 30 + .../IAsymmetricCipherKeyPairGenerator.cs | 24 + iTechSharp/srcbc/crypto/IBasicAgreement.cs | 24 + iTechSharp/srcbc/crypto/IBlockCipher.cs | 36 + iTechSharp/srcbc/crypto/IBufferedCipher.cs | 44 + iTechSharp/srcbc/crypto/ICipherParameters.cs | 11 + iTechSharp/srcbc/crypto/IDSA.cs | 40 + .../srcbc/crypto/IDerivationFunction.cs | 24 + .../srcbc/crypto/IDerivationParameters.cs | 11 + iTechSharp/srcbc/crypto/IDigest.cs | 61 + iTechSharp/srcbc/crypto/IMac.cs | 69 + iTechSharp/srcbc/crypto/ISigner.cs | 50 + .../srcbc/crypto/ISignerWithRecovery.cs | 28 + iTechSharp/srcbc/crypto/IStreamCipher.cs | 45 + iTechSharp/srcbc/crypto/IWrapper.cs | 18 + .../crypto/InvalidCipherTextException.cs | 37 + .../srcbc/crypto/KeyGenerationParameters.cs | 55 + .../srcbc/crypto/MaxBytesExceededException.cs | 29 + .../srcbc/crypto/PbeParametersGenerator.cs | 169 + iTechSharp/srcbc/crypto/StreamBlockCipher.cs | 109 + .../srcbc/crypto/agreement/DHAgreement.cs | 89 + .../crypto/agreement/DHBasicAgreement.cs | 60 + .../crypto/agreement/ECDHBasicAgreement.cs | 50 + .../crypto/agreement/ECDHCBasicAgreement.cs | 58 + .../agreement/ECDHWithKdfBasicAgreement.cs | 68 + .../crypto/agreement/kdf/DHKdfParameters.cs | 57 + .../crypto/agreement/kdf/DHKekGenerator.cs | 129 + .../crypto/agreement/kdf/ECDHKekGenerator.cs | 70 + .../srcbc/crypto/digests/GOST3411Digest.cs | 338 + .../srcbc/crypto/digests/GeneralDigest.cs | 118 + iTechSharp/srcbc/crypto/digests/LongDigest.cs | 380 + iTechSharp/srcbc/crypto/digests/MD2Digest.cs | 247 + iTechSharp/srcbc/crypto/digests/MD4Digest.cs | 271 + iTechSharp/srcbc/crypto/digests/MD5Digest.cs | 301 + .../srcbc/crypto/digests/RipeMD128Digest.cs | 462 + .../srcbc/crypto/digests/RipeMD160Digest.cs | 423 + .../srcbc/crypto/digests/RipeMD256Digest.cs | 409 + .../srcbc/crypto/digests/RipeMD320Digest.cs | 438 + iTechSharp/srcbc/crypto/digests/Sha1Digest.cs | 285 + .../srcbc/crypto/digests/Sha224Digest.cs | 287 + .../srcbc/crypto/digests/Sha256Digest.cs | 310 + .../srcbc/crypto/digests/Sha384Digest.cs | 85 + .../srcbc/crypto/digests/Sha512Digest.cs | 88 + .../srcbc/crypto/digests/ShortenedDigest.cs | 82 + .../srcbc/crypto/digests/TigerDigest.cs | 868 + .../srcbc/crypto/digests/WhirlpoolDigest.cs | 397 + .../crypto/encodings/ISO9796d1Encoding.cs | 253 + .../srcbc/crypto/encodings/OaepEncoding.cs | 334 + .../srcbc/crypto/encodings/Pkcs1Encoding.cs | 229 + iTechSharp/srcbc/crypto/engines/AesEngine.cs | 550 + .../srcbc/crypto/engines/AesFastEngine.cs | 865 + .../srcbc/crypto/engines/AesLightEngine.cs | 438 + .../srcbc/crypto/engines/AesWrapEngine.cs | 16 + .../srcbc/crypto/engines/BlowfishEngine.cs | 577 + .../srcbc/crypto/engines/CamelliaEngine.cs | 579 + .../crypto/engines/CamelliaWrapEngine.cs | 16 + .../srcbc/crypto/engines/Cast5Engine.cs | 829 + .../srcbc/crypto/engines/Cast6Engine.cs | 277 + .../srcbc/crypto/engines/DesEdeEngine.cs | 96 + .../srcbc/crypto/engines/DesEdeWrapEngine.cs | 299 + iTechSharp/srcbc/crypto/engines/DesEngine.cs | 493 + .../srcbc/crypto/engines/ElGamalEngine.cs | 178 + .../srcbc/crypto/engines/GOST28147Engine.cs | 364 + .../srcbc/crypto/engines/HC128Engine.cs | 241 + .../srcbc/crypto/engines/HC256Engine.cs | 207 + .../srcbc/crypto/engines/ISAACEngine.cs | 252 + iTechSharp/srcbc/crypto/engines/IdeaEngine.cs | 333 + iTechSharp/srcbc/crypto/engines/IesEngine.cs | 236 + .../crypto/engines/NaccacheSternEngine.cs | 432 + .../srcbc/crypto/engines/NoekeonEngine.cs | 256 + iTechSharp/srcbc/crypto/engines/NullEngine.cs | 70 + iTechSharp/srcbc/crypto/engines/RC2Engine.cs | 312 + .../srcbc/crypto/engines/RC2WrapEngine.cs | 372 + iTechSharp/srcbc/crypto/engines/RC4Engine.cs | 147 + .../srcbc/crypto/engines/RC532Engine.cs | 294 + .../srcbc/crypto/engines/RC564Engine.cs | 295 + iTechSharp/srcbc/crypto/engines/RC6Engine.cs | 362 + .../srcbc/crypto/engines/RFC3211WrapEngine.cs | 166 + .../srcbc/crypto/engines/RFC3394WrapEngine.cs | 181 + .../srcbc/crypto/engines/RSABlindedEngine.cs | 139 + .../srcbc/crypto/engines/RSABlindingEngine.cs | 139 + .../srcbc/crypto/engines/RSACoreEngine.cs | 156 + .../srcbc/crypto/engines/RijndaelEngine.cs | 740 + iTechSharp/srcbc/crypto/engines/RsaEngine.cs | 78 + iTechSharp/srcbc/crypto/engines/SEEDEngine.cs | 361 + .../srcbc/crypto/engines/SEEDWrapEngine.cs | 16 + .../srcbc/crypto/engines/Salsa20Engine.cs | 363 + .../srcbc/crypto/engines/SerpentEngine.cs | 779 + .../srcbc/crypto/engines/SkipjackEngine.cs | 255 + iTechSharp/srcbc/crypto/engines/TEAEngine.cs | 191 + .../srcbc/crypto/engines/TwofishEngine.cs | 673 + iTechSharp/srcbc/crypto/engines/VMPCEngine.cs | 139 + .../srcbc/crypto/engines/VMPCKSA3Engine.cs | 51 + iTechSharp/srcbc/crypto/engines/XTEAEngine.cs | 185 + .../generators/BaseKdfBytesGenerator.cs | 141 + .../generators/DHBasicKeyPairGenerator.cs | 40 + .../crypto/generators/DHKeyGeneratorHelper.cs | 78 + .../crypto/generators/DHKeyPairGenerator.cs | 40 + .../generators/DHParametersGenerator.cs | 45 + .../crypto/generators/DHParametersHelper.cs | 244 + .../crypto/generators/DesEdeKeyGenerator.cs | 66 + .../crypto/generators/DesKeyGenerator.cs | 34 + .../crypto/generators/DsaKeyPairGenerator.cs | 56 + .../generators/DsaParametersGenerator.cs | 184 + .../crypto/generators/ECKeyPairGenerator.cs | 130 + .../generators/ElGamalKeyPairGenerator.cs | 40 + .../generators/ElGamalParametersGenerator.cs | 46 + .../generators/GOST3410KeyPairGenerator.cs | 73 + .../generators/GOST3410ParametersGenerator.cs | 530 + .../crypto/generators/Kdf1BytesGenerator.cs | 27 + .../crypto/generators/Kdf2BytesGenerator.cs | 28 + .../crypto/generators/Mgf1BytesGenerator.cs | 117 + .../NaccacheSternKeyPairGenerator.cs | 330 + .../OpenSSLPBEParametersGenerator.cs | 167 + .../generators/Pkcs12ParametersGenerator.cs | 245 + .../generators/Pkcs5S1ParametersGenerator.cs | 162 + .../generators/Pkcs5S2ParametersGenerator.cs | 175 + .../generators/RSABlindingFactorGenerator.cs | 69 + .../crypto/generators/RsaKeyPairGenerator.cs | 139 + iTechSharp/srcbc/crypto/io/CipherStream.cs | 224 + iTechSharp/srcbc/crypto/io/DigestStream.cs | 116 + iTechSharp/srcbc/crypto/io/MacStream.cs | 116 + iTechSharp/srcbc/crypto/macs/CMac.cs | 240 + .../srcbc/crypto/macs/CbcBlockCipherMac.cs | 213 + .../srcbc/crypto/macs/CfbBlockCipherMac.cs | 368 + iTechSharp/srcbc/crypto/macs/GOST28147Mac.cs | 296 + iTechSharp/srcbc/crypto/macs/HMac.cs | 141 + .../srcbc/crypto/macs/ISO9797Alg3Mac.cs | 259 + iTechSharp/srcbc/crypto/macs/VMPCMac.cs | 173 + .../srcbc/crypto/modes/CbcBlockCipher.cs | 230 + .../srcbc/crypto/modes/CcmBlockCipher.cs | 345 + .../srcbc/crypto/modes/CfbBlockCipher.cs | 218 + .../srcbc/crypto/modes/CtsBlockCipher.cs | 253 + .../srcbc/crypto/modes/EAXBlockCipher.cs | 302 + .../srcbc/crypto/modes/GCMBlockCipher.cs | 447 + .../srcbc/crypto/modes/GOFBBlockCipher.cs | 223 + .../srcbc/crypto/modes/IAeadBlockCipher.cs | 90 + .../srcbc/crypto/modes/OfbBlockCipher.cs | 178 + .../crypto/modes/OpenPgpCfbBlockCipher.cs | 344 + .../srcbc/crypto/modes/SicBlockCipher.cs | 106 + .../crypto/paddings/BlockCipherPadding.cs | 43 + .../crypto/paddings/ISO10126d2Padding.cs | 76 + .../srcbc/crypto/paddings/ISO7816d4Padding.cs | 79 + .../paddings/PaddedBufferedBlockCipher.cs | 287 + .../srcbc/crypto/paddings/Pkcs7Padding.cs | 77 + .../srcbc/crypto/paddings/TbcPadding.cs | 79 + .../srcbc/crypto/paddings/X923Padding.cs | 82 + .../srcbc/crypto/paddings/ZeroBytePadding.cs | 68 + .../srcbc/crypto/parameters/AEADParameters.cs | 53 + .../srcbc/crypto/parameters/CcmParameters.cs | 25 + .../parameters/DHKeyGenerationParameters.cs | 25 + .../crypto/parameters/DHKeyParameters.cs | 59 + .../srcbc/crypto/parameters/DHParameters.cs | 178 + .../parameters/DHPrivateKeyParameters.cs | 50 + .../parameters/DHPublicKeyParameters.cs | 53 + .../parameters/DHValidationParameters.cs | 59 + .../crypto/parameters/DesEdeParameters.cs | 95 + .../srcbc/crypto/parameters/DesParameters.cs | 130 + .../parameters/DsaKeyGenerationParameters.cs | 26 + .../crypto/parameters/DsaKeyParameters.cs | 59 + .../srcbc/crypto/parameters/DsaParameters.cs | 85 + .../parameters/DsaPrivateKeyParameters.cs | 53 + .../parameters/DsaPublicKeyParameters.cs | 52 + .../parameters/DsaValidationParameters.cs | 59 + .../crypto/parameters/ECDomainParameters.cs | 116 + .../parameters/ECKeyGenerationParameters.cs | 55 + .../crypto/parameters/ECKeyParameters.cs | 121 + .../parameters/ECPrivateKeyParameters.cs | 74 + .../parameters/ECPublicKeyParameters.cs | 73 + .../ElGamalKeyGenerationParameters.cs | 25 + .../crypto/parameters/ElGamalKeyParameters.cs | 59 + .../crypto/parameters/ElGamalParameters.cs | 81 + .../parameters/ElGamalPrivateKeyParameters.cs | 53 + .../parameters/ElGamalPublicKeyParameters.cs | 53 + .../GOST3410KeyGenerationParameters.cs | 55 + .../parameters/GOST3410KeyParameters.cs | 58 + .../crypto/parameters/GOST3410Parameters.cs | 86 + .../GOST3410PrivateKeyParameters.cs | 41 + .../parameters/GOST3410PublicKeyParameters.cs | 40 + .../GOST3410ValidationParameters.cs | 51 + .../parameters/ISO18033KDFParameters.cs | 25 + .../srcbc/crypto/parameters/IesParameters.cs | 49 + .../parameters/IesWithCipherParameters.cs | 33 + .../srcbc/crypto/parameters/KdfParameters.cs | 33 + .../srcbc/crypto/parameters/KeyParameter.cs | 43 + .../srcbc/crypto/parameters/MgfParameters.cs | 31 + .../NaccacheSternKeyGenerationParameters.cs | 101 + .../parameters/NaccacheSternKeyParameters.cs | 44 + .../NaccacheSternPrivateKeyParameters.cs | 56 + .../crypto/parameters/ParametersWithIV.cs | 44 + .../crypto/parameters/ParametersWithRandom.cs | 48 + .../crypto/parameters/ParametersWithSBox.cs | 24 + .../crypto/parameters/ParametersWithSalt.cs | 39 + .../srcbc/crypto/parameters/RC2Parameters.cs | 47 + .../srcbc/crypto/parameters/RC5Parameters.cs | 27 + .../parameters/RSABlindingParameters.cs | 34 + .../parameters/RsaKeyGenerationParameters.cs | 55 + .../crypto/parameters/RsaKeyParameters.cs | 54 + .../parameters/RsaPrivateCrtKeyParameters.cs | 89 + .../crypto/prng/CryptoApiRandomGenerator.cs | 61 + .../crypto/prng/DigestRandomGenerator.cs | 107 + .../srcbc/crypto/prng/IRandomGenerator.cs | 26 + .../crypto/prng/ReversedWindowGenerator.cs | 98 + .../crypto/prng/ThreadedSeedGenerator.cs | 97 + .../srcbc/crypto/prng/VMPCRandomGenerator.cs | 115 + .../srcbc/crypto/signers/DsaDigestSigner.cs | 158 + iTechSharp/srcbc/crypto/signers/DsaSigner.cs | 136 + .../srcbc/crypto/signers/ECDsaSigner.cs | 150 + .../srcbc/crypto/signers/ECGOST3410Signer.cs | 154 + iTechSharp/srcbc/crypto/signers/ECNRSigner.cs | 186 + .../crypto/signers/GOST3410DigestSigner.cs | 145 + .../srcbc/crypto/signers/GOST3410Signer.cs | 132 + .../crypto/signers/Iso9796d2PssSigner.cs | 561 + .../srcbc/crypto/signers/Iso9796d2Signer.cs | 451 + iTechSharp/srcbc/crypto/signers/PssSigner.cs | 299 + .../srcbc/crypto/signers/RsaDigestSigner.cs | 213 + .../srcbc/crypto/tls/AlwaysValidVerifyer.cs | 23 + iTechSharp/srcbc/crypto/tls/ByteQueue.cs | 125 + iTechSharp/srcbc/crypto/tls/Certificate.cs | 78 + iTechSharp/srcbc/crypto/tls/CombinedHash.cs | 70 + .../srcbc/crypto/tls/ICertificateVerifyer.cs | 17 + iTechSharp/srcbc/crypto/tls/RecordStream.cs | 107 + .../crypto/tls/TlsBlockCipherCipherSuite.cs | 196 + iTechSharp/srcbc/crypto/tls/TlsCipherSuite.cs | 26 + .../srcbc/crypto/tls/TlsCipherSuiteManager.cs | 72 + iTechSharp/srcbc/crypto/tls/TlsException.cs | 11 + iTechSharp/srcbc/crypto/tls/TlsInputStream.cs | 42 + iTechSharp/srcbc/crypto/tls/TlsMac.cs | 86 + .../srcbc/crypto/tls/TlsNullCipherSuite.cs | 45 + .../srcbc/crypto/tls/TlsOutputStream.cs | 50 + .../srcbc/crypto/tls/TlsProtocolHandler.cs | 1152 + iTechSharp/srcbc/crypto/tls/TlsUtilities.cs | 223 + iTechSharp/srcbc/math/BigInteger.cs | 3152 +++ iTechSharp/srcbc/math/ec/ECAlgorithms.cs | 94 + iTechSharp/srcbc/math/ec/ECCurve.cs | 661 + iTechSharp/srcbc/math/ec/ECFieldElement.cs | 1253 ++ iTechSharp/srcbc/math/ec/ECPoint.cs | 566 + iTechSharp/srcbc/math/ec/IntArray.cs | 486 + .../srcbc/math/ec/abc/SimpleBigDecimal.cs | 241 + iTechSharp/srcbc/math/ec/abc/Tnaf.cs | 834 + iTechSharp/srcbc/math/ec/abc/ZTauElement.cs | 36 + .../srcbc/math/ec/multiplier/ECMultiplier.cs | 18 + .../math/ec/multiplier/FpNafMultiplier.cs | 39 + .../srcbc/math/ec/multiplier/PreCompInfo.cs | 11 + .../math/ec/multiplier/ReferenceMultiplier.cs | 30 + .../math/ec/multiplier/WNafMultiplier.cs | 241 + .../math/ec/multiplier/WNafPreCompInfo.cs | 46 + .../math/ec/multiplier/WTauNafMultiplier.cs | 120 + .../math/ec/multiplier/WTauNafPreCompInfo.cs | 41 + iTechSharp/srcbc/ocsp/BasicOCSPResp.cs | 215 + .../srcbc/ocsp/BasicOCSPRespGenerator.cs | 318 + iTechSharp/srcbc/ocsp/CertificateID.cs | 118 + iTechSharp/srcbc/ocsp/CertificateStatus.cs | 9 + iTechSharp/srcbc/ocsp/OCSPException.cs | 25 + iTechSharp/srcbc/ocsp/OCSPReq.cs | 263 + iTechSharp/srcbc/ocsp/OCSPReqGenerator.cs | 242 + iTechSharp/srcbc/ocsp/OCSPResp.cs | 100 + iTechSharp/srcbc/ocsp/OCSPRespGenerator.cs | 54 + iTechSharp/srcbc/ocsp/OCSPRespStatus.cs | 22 + iTechSharp/srcbc/ocsp/OCSPUtil.cs | 132 + iTechSharp/srcbc/ocsp/Req.cs | 38 + iTechSharp/srcbc/ocsp/RespData.cs | 60 + iTechSharp/srcbc/ocsp/RespID.cs | 86 + iTechSharp/srcbc/ocsp/RevokedStatus.cs | 58 + iTechSharp/srcbc/ocsp/SingleResp.cs | 81 + iTechSharp/srcbc/ocsp/UnknownStatus.cs | 15 + iTechSharp/srcbc/openpgp/IStreamGenerator.cs | 7 + iTechSharp/srcbc/openpgp/PGPKeyRing.cs | 77 + iTechSharp/srcbc/openpgp/PGPObject.cs | 9 + ...GPUserAttributeSubpacketVectorGenerator.cs | 28 + iTechSharp/srcbc/openpgp/PgpCompressedData.cs | 50 + .../openpgp/PgpCompressedDataGenerator.cs | 177 + .../openpgp/PgpDataValidationException.cs | 15 + iTechSharp/srcbc/openpgp/PgpEncryptedData.cs | 151 + .../openpgp/PgpEncryptedDataGenerator.cs | 495 + .../srcbc/openpgp/PgpEncryptedDataList.cs | 71 + iTechSharp/srcbc/openpgp/PgpException.cs | 19 + iTechSharp/srcbc/openpgp/PgpExperimental.cs | 16 + iTechSharp/srcbc/openpgp/PgpKeyFlags.cs | 13 + iTechSharp/srcbc/openpgp/PgpKeyPair.cs | 67 + .../srcbc/openpgp/PgpKeyRingGenerator.cs | 166 + .../openpgp/PgpKeyValidationException.cs | 15 + iTechSharp/srcbc/openpgp/PgpLiteralData.cs | 56 + .../srcbc/openpgp/PgpLiteralDataGenerator.cs | 177 + iTechSharp/srcbc/openpgp/PgpMarker.cs | 18 + iTechSharp/srcbc/openpgp/PgpObjectFactory.cs | 130 + .../srcbc/openpgp/PgpOnePassSignature.cs | 179 + .../srcbc/openpgp/PgpOnePassSignatureList.cs | 51 + .../srcbc/openpgp/PgpPbeEncryptedData.cs | 135 + iTechSharp/srcbc/openpgp/PgpPrivateKey.cs | 42 + iTechSharp/srcbc/openpgp/PgpPublicKey.cs | 835 + .../openpgp/PgpPublicKeyEncryptedData.cs | 233 + iTechSharp/srcbc/openpgp/PgpPublicKeyRing.cs | 187 + .../srcbc/openpgp/PgpPublicKeyRingBundle.cs | 269 + iTechSharp/srcbc/openpgp/PgpSecretKey.cs | 707 + iTechSharp/srcbc/openpgp/PgpSecretKeyRing.cs | 208 + .../srcbc/openpgp/PgpSecretKeyRingBundle.cs | 270 + iTechSharp/srcbc/openpgp/PgpSignature.cs | 409 + .../srcbc/openpgp/PgpSignatureGenerator.cs | 393 + iTechSharp/srcbc/openpgp/PgpSignatureList.cs | 51 + .../openpgp/PgpSignatureSubpacketGenerator.cs | 141 + .../openpgp/PgpSignatureSubpacketVector.cs | 193 + .../PgpUserAttributeSubpacketVector.cs | 81 + iTechSharp/srcbc/openpgp/PgpUtilities.cs | 431 + .../srcbc/openpgp/PgpV3SignatureGenerator.cs | 199 + .../srcbc/openpgp/WrappedGeneratorStream.cs | 25 + iTechSharp/srcbc/openssl/IPasswordFinder.cs | 9 + iTechSharp/srcbc/openssl/PEMReader.cs | 453 + iTechSharp/srcbc/openssl/PEMUtilities.cs | 138 + iTechSharp/srcbc/openssl/PEMWriter.cs | 278 + iTechSharp/srcbc/pkcs/AsymmetricKeyEntry.cs | 32 + .../pkcs/EncryptedPrivateKeyInfoFactory.cs | 75 + .../srcbc/pkcs/Pkcs10CertificationRequest.cs | 447 + iTechSharp/srcbc/pkcs/Pkcs12Entry.cs | 64 + iTechSharp/srcbc/pkcs/Pkcs12Store.cs | 1129 + .../srcbc/pkcs/PrivateKeyInfoFactory.cs | 211 + iTechSharp/srcbc/pkcs/X509CertificateEntry.cs | 32 + .../srcbc/security/AgreementUtilities.cs | 99 + iTechSharp/srcbc/security/CipherUtilities.cs | 566 + iTechSharp/srcbc/security/DigestUtilities.cs | 150 + iTechSharp/srcbc/security/DotNetUtilities.cs | 163 + .../security/GeneralSecurityException.cs | 26 + .../srcbc/security/GeneratorUtilities.cs | 352 + .../srcbc/security/InvalidKeyException.cs | 11 + .../security/InvalidParameterException.cs | 11 + iTechSharp/srcbc/security/KeyException.cs | 11 + iTechSharp/srcbc/security/MacUtilities.cs | 220 + .../security/NoSuchAlgorithmException.cs | 12 + .../srcbc/security/ParameterUtilities.cs | 318 + iTechSharp/srcbc/security/PbeUtilities.cs | 554 + .../srcbc/security/PrivateKeyFactory.cs | 177 + iTechSharp/srcbc/security/PublicKeyFactory.cs | 210 + iTechSharp/srcbc/security/SecureRandom.cs | 224 + .../security/SecurityUtilityException.cs | 33 + .../srcbc/security/SignatureException.cs | 11 + iTechSharp/srcbc/security/SignerUtilities.cs | 517 + iTechSharp/srcbc/security/WrapperUtilities.cs | 145 + .../cert/CertificateEncodingException.cs | 11 + .../security/cert/CertificateException.cs | 11 + .../cert/CertificateExpiredException.cs | 11 + .../cert/CertificateNotYetValidException.cs | 11 + .../cert/CertificateParsingException.cs | 11 + .../srcbc/security/cert/CrlException.cs | 11 + iTechSharp/srcbc/tsp/GenTimeAccuracy.cs | 33 + iTechSharp/srcbc/tsp/TSPAlgorithms.cs | 47 + iTechSharp/srcbc/tsp/TSPException.cs | 25 + iTechSharp/srcbc/tsp/TSPUtil.cs | 115 + .../srcbc/tsp/TSPValidationException.cs | 39 + iTechSharp/srcbc/tsp/TimeStampRequest.cs | 179 + .../srcbc/tsp/TimeStampRequestGenerator.cs | 99 + iTechSharp/srcbc/tsp/TimeStampResponse.cs | 173 + .../srcbc/tsp/TimeStampResponseGenerator.cs | 150 + iTechSharp/srcbc/tsp/TimeStampToken.cs | 304 + .../srcbc/tsp/TimeStampTokenGenerator.cs | 252 + iTechSharp/srcbc/tsp/TimeStampTokenInfo.cs | 102 + iTechSharp/srcbc/util/Arrays.cs | 134 + iTechSharp/srcbc/util/BigIntegers.cs | 28 + iTechSharp/srcbc/util/Platform.cs | 72 + iTechSharp/srcbc/util/Strings.cs | 34 + iTechSharp/srcbc/util/bzip2/BZip2Constants.cs | 139 + .../srcbc/util/bzip2/CBZip2InputStream.cs | 954 + .../srcbc/util/bzip2/CBZip2OutputStream.cs | 1731 ++ iTechSharp/srcbc/util/bzip2/CRC.cs | 170 + .../util/collections/CollectionUtilities.cs | 48 + .../srcbc/util/collections/EmptyEnumerable.cs | 44 + .../srcbc/util/collections/EnumerableProxy.cs | 25 + iTechSharp/srcbc/util/collections/HashSet.cs | 63 + iTechSharp/srcbc/util/collections/ISet.cs | 13 + iTechSharp/srcbc/util/date/DateTimeObject.cs | 25 + .../srcbc/util/date/DateTimeUtilities.cs | 47 + iTechSharp/srcbc/util/encoders/Base64.cs | 115 + .../srcbc/util/encoders/Base64Encoder.cs | 307 + .../srcbc/util/encoders/BufferedDecoder.cs | 117 + .../srcbc/util/encoders/BufferedEncoder.cs | 117 + iTechSharp/srcbc/util/encoders/Hex.cs | 114 + iTechSharp/srcbc/util/encoders/HexEncoder.cs | 164 + .../srcbc/util/encoders/HexTranslator.cs | 108 + iTechSharp/srcbc/util/encoders/IEncoder.cs | 18 + iTechSharp/srcbc/util/encoders/Translator.cs | 19 + iTechSharp/srcbc/util/encoders/UrlBase64.cs | 127 + .../srcbc/util/encoders/UrlBase64Encoder.cs | 31 + iTechSharp/srcbc/util/io/BaseInputStream.cs | 47 + iTechSharp/srcbc/util/io/BaseOutputStream.cs | 47 + iTechSharp/srcbc/util/io/PushbackStream.cs | 52 + iTechSharp/srcbc/util/io/Streams.cs | 57 + iTechSharp/srcbc/util/net/IPAddress.cs | 112 + iTechSharp/srcbc/util/zlib/Adler32.cs | 88 + iTechSharp/srcbc/util/zlib/Deflate.cs | 1640 ++ iTechSharp/srcbc/util/zlib/InfBlocks.cs | 618 + iTechSharp/srcbc/util/zlib/InfCodes.cs | 611 + iTechSharp/srcbc/util/zlib/InfTree.cs | 523 + iTechSharp/srcbc/util/zlib/Inflate.cs | 387 + iTechSharp/srcbc/util/zlib/JZlib.cs | 70 + iTechSharp/srcbc/util/zlib/StaticTree.cs | 152 + iTechSharp/srcbc/util/zlib/Tree.cs | 367 + .../srcbc/util/zlib/ZDeflaterOutputStream.cs | 150 + .../srcbc/util/zlib/ZInflaterInputStream.cs | 126 + iTechSharp/srcbc/util/zlib/ZStream.cs | 214 + .../srcbc/x509/AttributeCertificateHolder.cs | 420 + .../srcbc/x509/AttributeCertificateIssuer.cs | 177 + .../srcbc/x509/IX509AttributeCertificate.cs | 57 + iTechSharp/srcbc/x509/IX509Extension.cs | 27 + iTechSharp/srcbc/x509/PEMParser.cs | 94 + iTechSharp/srcbc/x509/PrincipalUtil.cs | 70 + .../srcbc/x509/SubjectPublicKeyInfoFactory.cs | 178 + iTechSharp/srcbc/x509/X509AttrCertParser.cs | 172 + iTechSharp/srcbc/x509/X509Attribute.cs | 76 + iTechSharp/srcbc/x509/X509CertPairParser.cs | 94 + iTechSharp/srcbc/x509/X509Certificate.cs | 579 + iTechSharp/srcbc/x509/X509CertificatePair.cs | 117 + .../srcbc/x509/X509CertificateParser.cs | 182 + iTechSharp/srcbc/x509/X509Crl.cs | 409 + iTechSharp/srcbc/x509/X509CrlEntry.cs | 201 + iTechSharp/srcbc/x509/X509CrlParser.cs | 194 + iTechSharp/srcbc/x509/X509ExtensionBase.cs | 82 + iTechSharp/srcbc/x509/X509KeyUsage.cs | 59 + iTechSharp/srcbc/x509/X509SignatureUtil.cs | 128 + iTechSharp/srcbc/x509/X509Utilities.cs | 183 + .../srcbc/x509/X509V1CertificateGenerator.cs | 205 + .../srcbc/x509/X509V2AttributeCertificate.cs | 239 + .../X509V2AttributeCertificateGenerator.cs | 180 + iTechSharp/srcbc/x509/X509V2CRLGenerator.cs | 261 + .../srcbc/x509/X509V3CertificateGenerator.cs | 303 + .../AuthorityKeyIdentifierStructure.cs | 105 + .../SubjectKeyIdentifierStructure.cs | 51 + .../srcbc/x509/extension/X509ExtensionUtil.cs | 88 + iTechSharp/srcbc/x509/store/IX509Selector.cs | 10 + iTechSharp/srcbc/x509/store/IX509Store.cs | 11 + .../srcbc/x509/store/IX509StoreParameters.cs | 8 + .../srcbc/x509/store/NoSuchStoreException.cs | 25 + .../x509/store/X509AttrCertStoreSelector.cs | 376 + .../x509/store/X509CertPairStoreSelector.cs | 92 + .../srcbc/x509/store/X509CertStoreSelector.cs | 329 + .../srcbc/x509/store/X509CollectionStore.cs | 49 + .../store/X509CollectionStoreParameters.cs | 58 + .../srcbc/x509/store/X509CrlStoreSelector.cs | 283 + .../srcbc/x509/store/X509StoreException.cs | 25 + .../srcbc/x509/store/X509StoreFactory.cs | 44 + 1352 files changed, 336780 insertions(+) create mode 100644 Ionic/Ionic.Zip.dll create mode 100644 Ionic/Ionic.Zip.pdb create mode 100644 Ionic/Ionic.Zip.xml create mode 100644 RtfConverter/Interpreter/Interpreter/RtfInterpreter.cs create mode 100644 RtfConverter/Interpreter/Interpreter2005.csproj create mode 100644 RtfConverter/Parser/Parser2005.csproj create mode 100644 RtfConverter/bin/Debug/Itenso.Rtf.Interpreter.dll create mode 100644 RtfConverter/bin/Debug/Itenso.Rtf.Parser.dll create mode 100644 iTechSharp/AssemblyInfo.cs create mode 100644 iTechSharp/System/Drawing/Dimension.cs create mode 100644 iTechSharp/System/Drawing/Dimension2D.cs create mode 100644 iTechSharp/System/util/ListIterator.cs create mode 100644 iTechSharp/System/util/Properties.cs create mode 100644 iTechSharp/System/util/StringTokenizer.cs create mode 100644 iTechSharp/System/util/Util.cs create mode 100644 iTechSharp/System/util/collections/Algorithm.cs create mode 100644 iTechSharp/System/util/collections/Container.cs create mode 100644 iTechSharp/System/util/collections/Deque.cs create mode 100644 iTechSharp/System/util/collections/HashTable.cs create mode 100644 iTechSharp/System/util/collections/Iterator.cs create mode 100644 iTechSharp/System/util/collections/List.cs create mode 100644 iTechSharp/System/util/collections/Queue.cs create mode 100644 iTechSharp/System/util/collections/SkipList.cs create mode 100644 iTechSharp/System/util/collections/Stack.cs create mode 100644 iTechSharp/System/util/collections/Tree.cs create mode 100644 iTechSharp/System/util/collections/Vector.cs create mode 100644 iTechSharp/System/util/zlib/Adler32.cs create mode 100644 iTechSharp/System/util/zlib/Deflate.cs create mode 100644 iTechSharp/System/util/zlib/InfBlocks.cs create mode 100644 iTechSharp/System/util/zlib/InfCodes.cs create mode 100644 iTechSharp/System/util/zlib/InfTree.cs create mode 100644 iTechSharp/System/util/zlib/Inflate.cs create mode 100644 iTechSharp/System/util/zlib/JZlib.cs create mode 100644 iTechSharp/System/util/zlib/StaticTree.cs create mode 100644 iTechSharp/System/util/zlib/Tree.cs create mode 100644 iTechSharp/System/util/zlib/ZDeflaterOutputStream.cs create mode 100644 iTechSharp/System/util/zlib/ZInflaterInputStream.cs create mode 100644 iTechSharp/System/util/zlib/ZStream.cs create mode 100644 iTechSharp/iTextSharp/text/Anchor.cs create mode 100644 iTechSharp/iTextSharp/text/Annotation.cs create mode 100644 iTechSharp/iTextSharp/text/BadElementException.cs create mode 100644 iTechSharp/iTextSharp/text/Cell.cs create mode 100644 iTechSharp/iTextSharp/text/Chapter.cs create mode 100644 iTechSharp/iTextSharp/text/ChapterAutoNumber.cs create mode 100644 iTechSharp/iTextSharp/text/Chunk.cs create mode 100644 iTechSharp/iTextSharp/text/Color.cs create mode 100644 iTechSharp/iTextSharp/text/DocWriter.cs create mode 100644 iTechSharp/iTextSharp/text/Document.cs create mode 100644 iTechSharp/iTextSharp/text/DocumentException.cs create mode 100644 iTechSharp/iTextSharp/text/Element.cs create mode 100644 iTechSharp/iTextSharp/text/ElementTags.cs create mode 100644 iTechSharp/iTextSharp/text/Font.cs create mode 100644 iTechSharp/iTextSharp/text/FontFactory.cs create mode 100644 iTechSharp/iTextSharp/text/FontFactoryImp.cs create mode 100644 iTechSharp/iTextSharp/text/GreekList.cs create mode 100644 iTechSharp/iTextSharp/text/Header.cs create mode 100644 iTechSharp/iTextSharp/text/HeaderFooter.cs create mode 100644 iTechSharp/iTextSharp/text/IDocListener.cs create mode 100644 iTechSharp/iTextSharp/text/IElement.cs create mode 100644 iTechSharp/iTextSharp/text/IElementListener.cs create mode 100644 iTechSharp/iTextSharp/text/ILargeElement.cs create mode 100644 iTechSharp/iTextSharp/text/IRtfElementInterface.cs create mode 100644 iTechSharp/iTextSharp/text/ISplitCharacter.cs create mode 100644 iTechSharp/iTextSharp/text/ITextElementArray.cs create mode 100644 iTechSharp/iTextSharp/text/Image.cs create mode 100644 iTechSharp/iTextSharp/text/ImgCCITT.cs create mode 100644 iTechSharp/iTextSharp/text/ImgRaw.cs create mode 100644 iTechSharp/iTextSharp/text/ImgTemplate.cs create mode 100644 iTechSharp/iTextSharp/text/ImgWMF.cs create mode 100644 iTechSharp/iTextSharp/text/Jpeg.cs create mode 100644 iTechSharp/iTextSharp/text/Jpeg2000.cs create mode 100644 iTechSharp/iTextSharp/text/List.cs create mode 100644 iTechSharp/iTextSharp/text/ListItem.cs create mode 100644 iTechSharp/iTextSharp/text/MarkedObject.cs create mode 100644 iTechSharp/iTextSharp/text/MarkedSection.cs create mode 100644 iTechSharp/iTextSharp/text/Meta.cs create mode 100644 iTechSharp/iTextSharp/text/PageSize.cs create mode 100644 iTechSharp/iTextSharp/text/Paragraph.cs create mode 100644 iTechSharp/iTextSharp/text/Phrase.cs create mode 100644 iTechSharp/iTextSharp/text/Rectangle.cs create mode 100644 iTechSharp/iTextSharp/text/RectangleReadOnly.cs create mode 100644 iTechSharp/iTextSharp/text/RomanList.cs create mode 100644 iTechSharp/iTextSharp/text/Row.cs create mode 100644 iTechSharp/iTextSharp/text/Section.cs create mode 100644 iTechSharp/iTextSharp/text/SimpleCell.cs create mode 100644 iTechSharp/iTextSharp/text/SimpleTable.cs create mode 100644 iTechSharp/iTextSharp/text/SpecialSymbol.cs create mode 100644 iTechSharp/iTextSharp/text/Table.cs create mode 100644 iTechSharp/iTextSharp/text/Utilities.cs create mode 100644 iTechSharp/iTextSharp/text/ZapfDingbatsList.cs create mode 100644 iTechSharp/iTextSharp/text/ZapfDingbatsNumberList.cs create mode 100644 iTechSharp/iTextSharp/text/factories/ElementFactory.cs create mode 100644 iTechSharp/iTextSharp/text/factories/GreekAlphabetFactory.cs create mode 100644 iTechSharp/iTextSharp/text/factories/RomanAlphabetFactory.cs create mode 100644 iTechSharp/iTextSharp/text/factories/RomanNumberFactory.cs create mode 100644 iTechSharp/iTextSharp/text/html/HtmlEncoder.cs create mode 100644 iTechSharp/iTextSharp/text/html/HtmlParser.cs create mode 100644 iTechSharp/iTextSharp/text/html/HtmlPeer.cs create mode 100644 iTechSharp/iTextSharp/text/html/HtmlTagMap.cs create mode 100644 iTechSharp/iTextSharp/text/html/HtmlTags.cs create mode 100644 iTechSharp/iTextSharp/text/html/HtmlWriter.cs create mode 100644 iTechSharp/iTextSharp/text/html/ITextmyHtmlHandler.cs create mode 100644 iTechSharp/iTextSharp/text/html/Markup.cs create mode 100644 iTechSharp/iTextSharp/text/html/WebColors.cs create mode 100644 iTechSharp/iTextSharp/text/html/simpleparser/ChainedProperties.cs create mode 100644 iTechSharp/iTextSharp/text/html/simpleparser/FactoryProperties.cs create mode 100644 iTechSharp/iTextSharp/text/html/simpleparser/HTMLWorker.cs create mode 100644 iTechSharp/iTextSharp/text/html/simpleparser/IALink.cs create mode 100644 iTechSharp/iTextSharp/text/html/simpleparser/IImageProvider.cs create mode 100644 iTechSharp/iTextSharp/text/html/simpleparser/IImg.cs create mode 100644 iTechSharp/iTextSharp/text/html/simpleparser/IncCell.cs create mode 100644 iTechSharp/iTextSharp/text/html/simpleparser/IncTable.cs create mode 100644 iTechSharp/iTextSharp/text/html/simpleparser/StyleSheet.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/AcroFields.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/ArabicLigaturizer.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/BadPasswordException.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/BadPdfFormatException.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/Barcode.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/Barcode128.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/Barcode39.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/BarcodeCodabar.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/BarcodeDatamatrix.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/BarcodeEAN.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/BarcodeEANSUPP.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/BarcodeInter25.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/BarcodePDF417.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/BarcodePostnet.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/BaseField.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/BaseFont.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/BidiLine.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/BidiOrder.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/ByteBuffer.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/CFFFont.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/CFFFontSubset.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/CJKFont.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/CMYKColor.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/CodeFile1.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/ColorDetails.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/ColumnText.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/DefaultSplitCharacter.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/DocumentFont.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/EnumerateTTC.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/ExtendedColor.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/FdfReader.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/FdfWriter.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/FontDetails.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/FontSelector.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/GlyphList.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/GrayColor.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/HyphenationAuto.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/ICC_Profile.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/IExtraEncoding.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/IHyphenationEvent.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/IPdfOCG.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/IPdfPCellEvent.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/IPdfPTableEvent.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/IPdfPageEvent.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/IntHashtable.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/LZWDecoder.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/MultiColumnText.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/OutputStreamCounter.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/OutputStreamEncryption.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PRAcroForm.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PRIndirectReference.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PRStream.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PRTokeniser.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PageResources.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PatternColor.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfAcroForm.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfAction.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfAnnotation.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfAppearance.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfArray.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfBoolean.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfBorderArray.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfBorderDictionary.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfCell.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfChunk.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfColor.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfContentByte.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfContentParser.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfContents.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfCopy.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfCopyFields.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfCopyFieldsImp.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfDashPattern.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfDate.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfDestination.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfDictionary.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfDocument.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfEncodings.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfEncryption.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfEncryptor.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfException.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfFileSpecification.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfFont.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfFormField.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfFormXObject.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfFunction.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfGState.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfICCBased.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfImage.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfImportedPage.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfIndirectObject.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfIndirectReference.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfLayer.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfLayerMembership.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfLine.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfLiteral.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfMediaClipData.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfName.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfNameTree.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfNull.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfNumber.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfNumberTree.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfOCProperties.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfObject.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfOutline.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfPCell.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfPKCS7.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfPRow.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfPSXObject.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfPTable.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfPage.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfPageEventHelper.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfPageLabels.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfPages.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfPattern.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfPatternPainter.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfPublicKeyRecipient.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfPublicKeySecurityHandler.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfReader.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfReaderInstance.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfRectangle.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfRendition.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfResources.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfShading.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfShadingPattern.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfSigGenericPKCS.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfSignature.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfSignatureAppearance.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfSmartCopy.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfSpotColor.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfStamper.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfStamperImp.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfStream.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfString.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfStructureElement.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfStructureTreeRoot.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfTable.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfTemplate.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfTextArray.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfTransition.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfTransparencyGroup.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfWriter.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PdfXConformanceException.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/Pfm2afm.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/PushbuttonField.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/RadioCheckField.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/RandomAccessFileOrArray.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/SequenceList.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/ShadingColor.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/SimpleBookmark.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/SimpleNamedDestination.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/SpotColor.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/StampContent.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/StandardDecryption.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/TextField.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/TrueTypeFont.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/TrueTypeFontSubSet.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/TrueTypeFontUnicode.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/Type1Font.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/Type3Font.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/Type3Glyph.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/VerticalText.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/XfaForm.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/XfdfReader.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/codec/BmpImage.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/codec/CCITTG4Encoder.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/codec/GifImage.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/codec/PngImage.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/codec/TIFFConstants.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/codec/TIFFDirectory.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/codec/TIFFFaxDecoder.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/codec/TIFFField.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/codec/TIFFLZWDecoder.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/codec/TiffImage.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/codec/wmf/InputMeta.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaBrush.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaDo.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaFont.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaObject.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaPen.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/codec/wmf/MetaState.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/collection/PdfCollection.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/collection/PdfCollectionField.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/collection/PdfCollectionItem.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/collection/PdfCollectionSchema.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/collection/PdfCollectionSort.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/collection/PdfTargetDictionary.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/crypto/AESCipher.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/crypto/ARCFOUREncryption.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/crypto/IVGenerator.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/draw/DottedLineSeparator.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/draw/IDrawInterface.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/draw/LineSeparator.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/draw/VerticalPositionMark.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/events/FieldPositioningEvents.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/events/IndexEvents.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/events/PdfPCellEventForwarder.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/events/PdfPTableEventForwarder.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/events/PdfPageEventForwarder.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/fonts/Courier-Bold.afm create mode 100644 iTechSharp/iTextSharp/text/pdf/fonts/Courier-BoldOblique.afm create mode 100644 iTechSharp/iTextSharp/text/pdf/fonts/Courier-Oblique.afm create mode 100644 iTechSharp/iTextSharp/text/pdf/fonts/Courier.afm create mode 100644 iTechSharp/iTextSharp/text/pdf/fonts/Helvetica-Bold.afm create mode 100644 iTechSharp/iTextSharp/text/pdf/fonts/Helvetica-BoldOblique.afm create mode 100644 iTechSharp/iTextSharp/text/pdf/fonts/Helvetica-Oblique.afm create mode 100644 iTechSharp/iTextSharp/text/pdf/fonts/Helvetica.afm create mode 100644 iTechSharp/iTextSharp/text/pdf/fonts/Symbol.afm create mode 100644 iTechSharp/iTextSharp/text/pdf/fonts/Times-Bold.afm create mode 100644 iTechSharp/iTextSharp/text/pdf/fonts/Times-BoldItalic.afm create mode 100644 iTechSharp/iTextSharp/text/pdf/fonts/Times-Italic.afm create mode 100644 iTechSharp/iTextSharp/text/pdf/fonts/Times-Roman.afm create mode 100644 iTechSharp/iTextSharp/text/pdf/fonts/ZapfDingbats.afm create mode 100644 iTechSharp/iTextSharp/text/pdf/fonts/glyphlist.txt create mode 100644 iTechSharp/iTextSharp/text/pdf/hyphenation/ByteVector.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/hyphenation/CharVector.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/hyphenation/Hyphen.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/hyphenation/Hyphenation.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/hyphenation/HyphenationException.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/hyphenation/HyphenationTree.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/hyphenation/Hyphenator.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/hyphenation/IPatternConsumer.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/hyphenation/SimplePatternParser.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/hyphenation/TernaryTree.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/interfaces/IPdfAnnotations.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/interfaces/IPdfDocumentActions.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/interfaces/IPdfEncryptionSettings.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/interfaces/IPdfPageActions.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/interfaces/IPdfRunDirection.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/interfaces/IPdfVersion.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/interfaces/IPdfViewerPreferences.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/interfaces/IPdfXConformance.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/intern/PdfAnnotationsImp.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/intern/PdfVersionImp.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/intern/PdfViewerPreferencesImp.cs create mode 100644 iTechSharp/iTextSharp/text/pdf/intern/PdfXConformanceImp.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/IEventListener.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/IRtfBasicElement.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/IRtfExtendedElement.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/RtfAddableElement.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/RtfElement.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/RtfMapper.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/RtfWriter2.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/direct/RtfDirectContent.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/document/RtfCodePage.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/document/RtfDocument.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/document/RtfDocumentHeader.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/document/RtfDocumentSettings.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/document/RtfGenerator.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/document/RtfInfoElement.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/document/RtfInfoGroup.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/document/RtfPageSetting.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/document/RtfProtection.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/document/RtfProtectionSetting.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/document/output/IRtfDataCache.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/document/output/RtfByteArrayBuffer.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/document/output/RtfDiskCache.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/document/output/RtfEfficientMemoryCache.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/document/output/RtfMemoryCache.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/document/output/RtfNilOutputStream.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/field/RtfAnchor.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/field/RtfField.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/field/RtfPageNumber.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/field/RtfTOCEntry.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/field/RtfTableOfContents.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/field/RtfTotalPageNumber.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/graphic/RtfImage.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/graphic/RtfShape.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/graphic/RtfShapePosition.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/graphic/RtfShapeProperty.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/headerfooter/RtfHeaderFooter.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/headerfooter/RtfHeaderFooterGroup.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/list/RtfList.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/list/RtfListItem.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/list/RtfListTable.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/PushbackStream.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/RtfImportMappings.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/RtfImportMgr.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/RtfParser.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/RtfParserState.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/IRtfCtrlWordListener.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordData.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordHandler.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordMap.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordMgr.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/ctrlwords/RtfCtrlWordType.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/destinations/IRtfDestinationListener.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestination.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationColorTable.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationDocument.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationFontTable.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationInfo.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationListTable.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationMgr.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationNull.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationShppict.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/destinations/RtfDestinationStylesheetTable.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/enumerations/RtfColorThemes.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/exceptions/RtfParserException.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/exceptions/RtfUnknownCtrlWordException.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/properties/IRtfPropertyListener.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/properties/RtfCtrlWordPropertyType.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/parser/properties/RtfProperty.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/style/RtfColor.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/style/RtfColorList.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/style/RtfFont.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/style/RtfFontList.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/style/RtfParagraphStyle.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/style/RtfStyleTypes.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/style/RtfStylesheetList.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/table/RtfBorder.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/table/RtfBorderGroup.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/table/RtfCell.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/table/RtfRow.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/table/RtfTable.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/text/RtfAnnotation.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/text/RtfChapter.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/text/RtfChunk.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/text/RtfNewPage.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/text/RtfParagraph.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/text/RtfPhrase.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/text/RtfSection.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/text/RtfTab.cs create mode 100644 iTechSharp/iTextSharp/text/rtf/text/RtfTabGroup.cs create mode 100644 iTechSharp/iTextSharp/text/xml/ITextHandler.cs create mode 100644 iTechSharp/iTextSharp/text/xml/ITextmyHandler.cs create mode 100644 iTechSharp/iTextSharp/text/xml/ParserBase.cs create mode 100644 iTechSharp/iTextSharp/text/xml/TagMap.cs create mode 100644 iTechSharp/iTextSharp/text/xml/XmlParser.cs create mode 100644 iTechSharp/iTextSharp/text/xml/XmlPeer.cs create mode 100644 iTechSharp/iTextSharp/text/xml/simpleparser/EntitiesToSymbol.cs create mode 100644 iTechSharp/iTextSharp/text/xml/simpleparser/EntitiesToUnicode.cs create mode 100644 iTechSharp/iTextSharp/text/xml/simpleparser/ISimpleXMLDocHandler.cs create mode 100644 iTechSharp/iTextSharp/text/xml/simpleparser/ISimpleXMLDocHandlerComment.cs create mode 100644 iTechSharp/iTextSharp/text/xml/simpleparser/IanaEncodings.cs create mode 100644 iTechSharp/iTextSharp/text/xml/simpleparser/SimpleXMLParser.cs create mode 100644 iTechSharp/iTextSharp/text/xml/xmp/DublinCoreSchema.cs create mode 100644 iTechSharp/iTextSharp/text/xml/xmp/EncodingNoPreamble.cs create mode 100644 iTechSharp/iTextSharp/text/xml/xmp/LangAlt.cs create mode 100644 iTechSharp/iTextSharp/text/xml/xmp/PdfA1Schema.cs create mode 100644 iTechSharp/iTextSharp/text/xml/xmp/PdfSchema.cs create mode 100644 iTechSharp/iTextSharp/text/xml/xmp/XmpArray.cs create mode 100644 iTechSharp/iTextSharp/text/xml/xmp/XmpBasicSchema.cs create mode 100644 iTechSharp/iTextSharp/text/xml/xmp/XmpMMSchema.cs create mode 100644 iTechSharp/iTextSharp/text/xml/xmp/XmpSchema.cs create mode 100644 iTechSharp/iTextSharp/text/xml/xmp/XmpWriter.cs create mode 100644 iTechSharp/itextsharp.csproj create mode 100644 iTechSharp/itextsharp.dll create mode 100644 iTechSharp/itextsharp.sln create mode 100644 iTechSharp/itextsharp.snk create mode 100644 iTechSharp/srcbc/asn1/ASN1Generator.cs create mode 100644 iTechSharp/srcbc/asn1/ASN1ObjectParser.cs create mode 100644 iTechSharp/srcbc/asn1/ASN1OctetStringParser.cs create mode 100644 iTechSharp/srcbc/asn1/ASN1SequenceParser.cs create mode 100644 iTechSharp/srcbc/asn1/ASN1SetParser.cs create mode 100644 iTechSharp/srcbc/asn1/ASN1StreamParser.cs create mode 100644 iTechSharp/srcbc/asn1/ASN1TaggedObjectParser.cs create mode 100644 iTechSharp/srcbc/asn1/Asn1Encodable.cs create mode 100644 iTechSharp/srcbc/asn1/Asn1EncodableVector.cs create mode 100644 iTechSharp/srcbc/asn1/Asn1InputStream.cs create mode 100644 iTechSharp/srcbc/asn1/Asn1Null.cs create mode 100644 iTechSharp/srcbc/asn1/Asn1Object.cs create mode 100644 iTechSharp/srcbc/asn1/Asn1OctetString.cs create mode 100644 iTechSharp/srcbc/asn1/Asn1OutputStream.cs create mode 100644 iTechSharp/srcbc/asn1/Asn1Sequence.cs create mode 100644 iTechSharp/srcbc/asn1/Asn1Set.cs create mode 100644 iTechSharp/srcbc/asn1/Asn1TaggedObject.cs create mode 100644 iTechSharp/srcbc/asn1/Asn1Tags.cs create mode 100644 iTechSharp/srcbc/asn1/BERGenerator.cs create mode 100644 iTechSharp/srcbc/asn1/BEROctetStringGenerator.cs create mode 100644 iTechSharp/srcbc/asn1/BEROctetStringParser.cs create mode 100644 iTechSharp/srcbc/asn1/BERSequenceGenerator.cs create mode 100644 iTechSharp/srcbc/asn1/BERSequenceParser.cs create mode 100644 iTechSharp/srcbc/asn1/BERSetGenerator.cs create mode 100644 iTechSharp/srcbc/asn1/BERSetParser.cs create mode 100644 iTechSharp/srcbc/asn1/BERTaggedObjectParser.cs create mode 100644 iTechSharp/srcbc/asn1/BerNull.cs create mode 100644 iTechSharp/srcbc/asn1/BerOctetString.cs create mode 100644 iTechSharp/srcbc/asn1/BerOutputStream.cs create mode 100644 iTechSharp/srcbc/asn1/BerSequence.cs create mode 100644 iTechSharp/srcbc/asn1/BerSet.cs create mode 100644 iTechSharp/srcbc/asn1/BerTaggedObject.cs create mode 100644 iTechSharp/srcbc/asn1/ConstructedOctetStream.cs create mode 100644 iTechSharp/srcbc/asn1/DERGenerator.cs create mode 100644 iTechSharp/srcbc/asn1/DEROctetStringParser.cs create mode 100644 iTechSharp/srcbc/asn1/DERSequenceGenerator.cs create mode 100644 iTechSharp/srcbc/asn1/DERSequenceParser.cs create mode 100644 iTechSharp/srcbc/asn1/DERSetGenerator.cs create mode 100644 iTechSharp/srcbc/asn1/DERSetParser.cs create mode 100644 iTechSharp/srcbc/asn1/DefiniteLengthInputStream.cs create mode 100644 iTechSharp/srcbc/asn1/DerApplicationSpecific.cs create mode 100644 iTechSharp/srcbc/asn1/DerBMPString.cs create mode 100644 iTechSharp/srcbc/asn1/DerBitString.cs create mode 100644 iTechSharp/srcbc/asn1/DerBoolean.cs create mode 100644 iTechSharp/srcbc/asn1/DerEnumerated.cs create mode 100644 iTechSharp/srcbc/asn1/DerGeneralString.cs create mode 100644 iTechSharp/srcbc/asn1/DerGeneralizedTime.cs create mode 100644 iTechSharp/srcbc/asn1/DerIA5String.cs create mode 100644 iTechSharp/srcbc/asn1/DerInteger.cs create mode 100644 iTechSharp/srcbc/asn1/DerNull.cs create mode 100644 iTechSharp/srcbc/asn1/DerNumericString.cs create mode 100644 iTechSharp/srcbc/asn1/DerObjectIdentifier.cs create mode 100644 iTechSharp/srcbc/asn1/DerOctetString.cs create mode 100644 iTechSharp/srcbc/asn1/DerOutputStream.cs create mode 100644 iTechSharp/srcbc/asn1/DerPrintableString.cs create mode 100644 iTechSharp/srcbc/asn1/DerSequence.cs create mode 100644 iTechSharp/srcbc/asn1/DerSet.cs create mode 100644 iTechSharp/srcbc/asn1/DerStringBase.cs create mode 100644 iTechSharp/srcbc/asn1/DerT61String.cs create mode 100644 iTechSharp/srcbc/asn1/DerTaggedObject.cs create mode 100644 iTechSharp/srcbc/asn1/DerUTCTime.cs create mode 100644 iTechSharp/srcbc/asn1/DerUTF8String.cs create mode 100644 iTechSharp/srcbc/asn1/DerUniversalString.cs create mode 100644 iTechSharp/srcbc/asn1/DerUnknownTag.cs create mode 100644 iTechSharp/srcbc/asn1/DerVisibleString.cs create mode 100644 iTechSharp/srcbc/asn1/IAsn1Convertible.cs create mode 100644 iTechSharp/srcbc/asn1/IAsn1String.cs create mode 100644 iTechSharp/srcbc/asn1/IndefiniteLengthInputStream.cs create mode 100644 iTechSharp/srcbc/asn1/LazyASN1InputStream.cs create mode 100644 iTechSharp/srcbc/asn1/LazyDERSequence.cs create mode 100644 iTechSharp/srcbc/asn1/LazyDERSet.cs create mode 100644 iTechSharp/srcbc/asn1/LimitedInputStream.cs create mode 100644 iTechSharp/srcbc/asn1/OidTokenizer.cs create mode 100644 iTechSharp/srcbc/asn1/cmp/PKIFailureInfo.cs create mode 100644 iTechSharp/srcbc/asn1/cmp/PKIFreeText.cs create mode 100644 iTechSharp/srcbc/asn1/cmp/PKIStatus.cs create mode 100644 iTechSharp/srcbc/asn1/cmp/PKIStatusInfo.cs create mode 100644 iTechSharp/srcbc/asn1/cms/Attribute.cs create mode 100644 iTechSharp/srcbc/asn1/cms/AttributeTable.cs create mode 100644 iTechSharp/srcbc/asn1/cms/CMSAttributes.cs create mode 100644 iTechSharp/srcbc/asn1/cms/CMSObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/cms/CompressedData.cs create mode 100644 iTechSharp/srcbc/asn1/cms/CompressedDataParser.cs create mode 100644 iTechSharp/srcbc/asn1/cms/ContentInfo.cs create mode 100644 iTechSharp/srcbc/asn1/cms/ContentInfoParser.cs create mode 100644 iTechSharp/srcbc/asn1/cms/EncryptedContentInfo.cs create mode 100644 iTechSharp/srcbc/asn1/cms/EncryptedContentInfoParser.cs create mode 100644 iTechSharp/srcbc/asn1/cms/EncryptedData.cs create mode 100644 iTechSharp/srcbc/asn1/cms/EnvelopedData.cs create mode 100644 iTechSharp/srcbc/asn1/cms/EnvelopedDataParser.cs create mode 100644 iTechSharp/srcbc/asn1/cms/IssuerAndSerialNumber.cs create mode 100644 iTechSharp/srcbc/asn1/cms/KEKIdentifier.cs create mode 100644 iTechSharp/srcbc/asn1/cms/KEKRecipientInfo.cs create mode 100644 iTechSharp/srcbc/asn1/cms/KeyAgreeRecipientIdentifier.cs create mode 100644 iTechSharp/srcbc/asn1/cms/KeyAgreeRecipientInfo.cs create mode 100644 iTechSharp/srcbc/asn1/cms/KeyTransRecipientInfo.cs create mode 100644 iTechSharp/srcbc/asn1/cms/OriginatorIdentifierOrKey.cs create mode 100644 iTechSharp/srcbc/asn1/cms/OriginatorInfo.cs create mode 100644 iTechSharp/srcbc/asn1/cms/OriginatorPublicKey.cs create mode 100644 iTechSharp/srcbc/asn1/cms/OtherKeyAttribute.cs create mode 100644 iTechSharp/srcbc/asn1/cms/OtherRecipientInfo.cs create mode 100644 iTechSharp/srcbc/asn1/cms/PasswordRecipientInfo.cs create mode 100644 iTechSharp/srcbc/asn1/cms/RecipientEncryptedKey.cs create mode 100644 iTechSharp/srcbc/asn1/cms/RecipientIdentifier.cs create mode 100644 iTechSharp/srcbc/asn1/cms/RecipientInfo.cs create mode 100644 iTechSharp/srcbc/asn1/cms/RecipientKeyIdentifier.cs create mode 100644 iTechSharp/srcbc/asn1/cms/SignedData.cs create mode 100644 iTechSharp/srcbc/asn1/cms/SignedDataParser.cs create mode 100644 iTechSharp/srcbc/asn1/cms/SignerIdentifier.cs create mode 100644 iTechSharp/srcbc/asn1/cms/SignerInfo.cs create mode 100644 iTechSharp/srcbc/asn1/cms/Time.cs create mode 100644 iTechSharp/srcbc/asn1/cryptopro/CryptoProObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/cryptopro/ECGOST3410NamedCurves.cs create mode 100644 iTechSharp/srcbc/asn1/cryptopro/ECGOST3410ParamSetParameters.cs create mode 100644 iTechSharp/srcbc/asn1/cryptopro/GOST28147Parameters.cs create mode 100644 iTechSharp/srcbc/asn1/cryptopro/GOST3410NamedParameters.cs create mode 100644 iTechSharp/srcbc/asn1/cryptopro/GOST3410ParamSetParameters.cs create mode 100644 iTechSharp/srcbc/asn1/cryptopro/GOST3410PublicKeyAlgParameters.cs create mode 100644 iTechSharp/srcbc/asn1/esf/CertificateValues.cs create mode 100644 iTechSharp/srcbc/asn1/esf/CommitmentTypeIdentifier.cs create mode 100644 iTechSharp/srcbc/asn1/esf/CommitmentTypeIndication.cs create mode 100644 iTechSharp/srcbc/asn1/esf/CommitmentTypeQualifier.cs create mode 100644 iTechSharp/srcbc/asn1/esf/CompleteCertificateRefs.cs create mode 100644 iTechSharp/srcbc/asn1/esf/CompleteRevocationRefs.cs create mode 100644 iTechSharp/srcbc/asn1/esf/CrlIdentifier.cs create mode 100644 iTechSharp/srcbc/asn1/esf/CrlListID.cs create mode 100644 iTechSharp/srcbc/asn1/esf/CrlOcspRef.cs create mode 100644 iTechSharp/srcbc/asn1/esf/CrlValidatedID.cs create mode 100644 iTechSharp/srcbc/asn1/esf/ESFAttributes.cs create mode 100644 iTechSharp/srcbc/asn1/esf/OcspIdentifier.cs create mode 100644 iTechSharp/srcbc/asn1/esf/OcspListID.cs create mode 100644 iTechSharp/srcbc/asn1/esf/OcspResponsesID.cs create mode 100644 iTechSharp/srcbc/asn1/esf/OtherCertID.cs create mode 100644 iTechSharp/srcbc/asn1/esf/OtherHash.cs create mode 100644 iTechSharp/srcbc/asn1/esf/OtherHashAlgAndValue.cs create mode 100644 iTechSharp/srcbc/asn1/esf/OtherRevRefs.cs create mode 100644 iTechSharp/srcbc/asn1/esf/OtherRevVals.cs create mode 100644 iTechSharp/srcbc/asn1/esf/OtherSigningCertificate.cs create mode 100644 iTechSharp/srcbc/asn1/esf/RevocationValues.cs create mode 100644 iTechSharp/srcbc/asn1/esf/SigPolicyQualifierInfo.cs create mode 100644 iTechSharp/srcbc/asn1/esf/SignaturePolicyId.cs create mode 100644 iTechSharp/srcbc/asn1/esf/SignaturePolicyIdentifier.cs create mode 100644 iTechSharp/srcbc/asn1/esf/SignerLocation.cs create mode 100644 iTechSharp/srcbc/asn1/ess/ContentHints.cs create mode 100644 iTechSharp/srcbc/asn1/ess/ContentIdentifier.cs create mode 100644 iTechSharp/srcbc/asn1/ess/ESSCertID.cs create mode 100644 iTechSharp/srcbc/asn1/ess/ESSCertIDv2.cs create mode 100644 iTechSharp/srcbc/asn1/ess/OtherCertID.cs create mode 100644 iTechSharp/srcbc/asn1/ess/OtherSigningCertificate.cs create mode 100644 iTechSharp/srcbc/asn1/ess/SigningCertificate.cs create mode 100644 iTechSharp/srcbc/asn1/ess/SigningCertificateV2.cs create mode 100644 iTechSharp/srcbc/asn1/gnu/GNUObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/iana/IANAObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/icao/DataGroupHash.cs create mode 100644 iTechSharp/srcbc/asn1/icao/ICAOObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/icao/LDSSecurityObject.cs create mode 100644 iTechSharp/srcbc/asn1/isismtt/ISISMTTObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/isismtt/ocsp/CertHash.cs create mode 100644 iTechSharp/srcbc/asn1/isismtt/ocsp/RequestedCertificate.cs create mode 100644 iTechSharp/srcbc/asn1/isismtt/x509/AdditionalInformationSyntax.cs create mode 100644 iTechSharp/srcbc/asn1/isismtt/x509/AdmissionSyntax.cs create mode 100644 iTechSharp/srcbc/asn1/isismtt/x509/Admissions.cs create mode 100644 iTechSharp/srcbc/asn1/isismtt/x509/DeclarationOfMajority.cs create mode 100644 iTechSharp/srcbc/asn1/isismtt/x509/MonetaryLimit.cs create mode 100644 iTechSharp/srcbc/asn1/isismtt/x509/NamingAuthority.cs create mode 100644 iTechSharp/srcbc/asn1/isismtt/x509/ProcurationSyntax.cs create mode 100644 iTechSharp/srcbc/asn1/isismtt/x509/ProfessionInfo.cs create mode 100644 iTechSharp/srcbc/asn1/isismtt/x509/Restriction.cs create mode 100644 iTechSharp/srcbc/asn1/kisa/KISAObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/microsoft/MicrosoftObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/misc/CAST5CBCParameters.cs create mode 100644 iTechSharp/srcbc/asn1/misc/IDEACBCPar.cs create mode 100644 iTechSharp/srcbc/asn1/misc/MiscObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/misc/NetscapeCertType.cs create mode 100644 iTechSharp/srcbc/asn1/misc/NetscapeRevocationURL.cs create mode 100644 iTechSharp/srcbc/asn1/misc/VerisignCzagExtension.cs create mode 100644 iTechSharp/srcbc/asn1/mozilla/PublicKeyAndChallenge.cs create mode 100644 iTechSharp/srcbc/asn1/nist/NISTNamedCurves.cs create mode 100644 iTechSharp/srcbc/asn1/nist/NISTObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/ntt/NTTObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/ocsp/BasicOCSPResponse.cs create mode 100644 iTechSharp/srcbc/asn1/ocsp/CertID.cs create mode 100644 iTechSharp/srcbc/asn1/ocsp/CertStatus.cs create mode 100644 iTechSharp/srcbc/asn1/ocsp/CrlID.cs create mode 100644 iTechSharp/srcbc/asn1/ocsp/OCSPObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/ocsp/OCSPRequest.cs create mode 100644 iTechSharp/srcbc/asn1/ocsp/OCSPResponse.cs create mode 100644 iTechSharp/srcbc/asn1/ocsp/OCSPResponseStatus.cs create mode 100644 iTechSharp/srcbc/asn1/ocsp/Request.cs create mode 100644 iTechSharp/srcbc/asn1/ocsp/ResponderID.cs create mode 100644 iTechSharp/srcbc/asn1/ocsp/ResponseBytes.cs create mode 100644 iTechSharp/srcbc/asn1/ocsp/ResponseData.cs create mode 100644 iTechSharp/srcbc/asn1/ocsp/RevokedInfo.cs create mode 100644 iTechSharp/srcbc/asn1/ocsp/ServiceLocator.cs create mode 100644 iTechSharp/srcbc/asn1/ocsp/Signature.cs create mode 100644 iTechSharp/srcbc/asn1/ocsp/SingleResponse.cs create mode 100644 iTechSharp/srcbc/asn1/ocsp/TBSRequest.cs create mode 100644 iTechSharp/srcbc/asn1/oiw/ElGamalParameter.cs create mode 100644 iTechSharp/srcbc/asn1/oiw/OIWObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/Attribute.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/AuthenticatedSafe.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/CertBag.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/CertificationRequest.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/CertificationRequestInfo.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/ContentInfo.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/DHParameter.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/EncryptedData.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/EncryptedPrivateKeyInfo.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/EncryptionScheme.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/IssuerAndSerialNumber.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/KeyDerivationFunc.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/MacData.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/PBEParameter.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/PBES2Parameters.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/PBKDF2Params.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/PKCS12PBEParams.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/PKCSObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/Pfx.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/PrivateKeyInfo.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/RC2CBCParameter.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/RSAESOAEPparams.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/RSAPrivateKeyStructure.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/RSASSAPSSparams.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/SafeBag.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/SignedData.cs create mode 100644 iTechSharp/srcbc/asn1/pkcs/SignerInfo.cs create mode 100644 iTechSharp/srcbc/asn1/sec/ECPrivateKeyStructure.cs create mode 100644 iTechSharp/srcbc/asn1/sec/SECNamedCurves.cs create mode 100644 iTechSharp/srcbc/asn1/sec/SECObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/smime/SMIMEAttributes.cs create mode 100644 iTechSharp/srcbc/asn1/smime/SMIMECapabilities.cs create mode 100644 iTechSharp/srcbc/asn1/smime/SMIMECapabilitiesAttribute.cs create mode 100644 iTechSharp/srcbc/asn1/smime/SMIMECapability.cs create mode 100644 iTechSharp/srcbc/asn1/smime/SMIMECapabilityVector.cs create mode 100644 iTechSharp/srcbc/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.cs create mode 100644 iTechSharp/srcbc/asn1/teletrust/TeleTrusTNamedCurves.cs create mode 100644 iTechSharp/srcbc/asn1/teletrust/TeleTrusTObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/tsp/Accuracy.cs create mode 100644 iTechSharp/srcbc/asn1/tsp/MessageImprint.cs create mode 100644 iTechSharp/srcbc/asn1/tsp/TSTInfo.cs create mode 100644 iTechSharp/srcbc/asn1/tsp/TimeStampReq.cs create mode 100644 iTechSharp/srcbc/asn1/tsp/TimeStampResp.cs create mode 100644 iTechSharp/srcbc/asn1/util/Asn1Dump.cs create mode 100644 iTechSharp/srcbc/asn1/util/Dump.cs create mode 100644 iTechSharp/srcbc/asn1/util/FilterStream.cs create mode 100644 iTechSharp/srcbc/asn1/x500/DirectoryString.cs create mode 100644 iTechSharp/srcbc/asn1/x509/AccessDescription.cs create mode 100644 iTechSharp/srcbc/asn1/x509/AlgorithmIdentifier.cs create mode 100644 iTechSharp/srcbc/asn1/x509/AttCertIssuer.cs create mode 100644 iTechSharp/srcbc/asn1/x509/AttCertValidityPeriod.cs create mode 100644 iTechSharp/srcbc/asn1/x509/Attribute.cs create mode 100644 iTechSharp/srcbc/asn1/x509/AttributeCertificate.cs create mode 100644 iTechSharp/srcbc/asn1/x509/AttributeCertificateInfo.cs create mode 100644 iTechSharp/srcbc/asn1/x509/AttributeTable.cs create mode 100644 iTechSharp/srcbc/asn1/x509/AuthorityInformationAccess.cs create mode 100644 iTechSharp/srcbc/asn1/x509/AuthorityKeyIdentifier.cs create mode 100644 iTechSharp/srcbc/asn1/x509/BasicConstraints.cs create mode 100644 iTechSharp/srcbc/asn1/x509/CRLDistPoint.cs create mode 100644 iTechSharp/srcbc/asn1/x509/CRLNumber.cs create mode 100644 iTechSharp/srcbc/asn1/x509/CRLReason.cs create mode 100644 iTechSharp/srcbc/asn1/x509/CertPolicyId.cs create mode 100644 iTechSharp/srcbc/asn1/x509/CertificateList.cs create mode 100644 iTechSharp/srcbc/asn1/x509/CertificatePair.cs create mode 100644 iTechSharp/srcbc/asn1/x509/DSAParameter.cs create mode 100644 iTechSharp/srcbc/asn1/x509/DigestInfo.cs create mode 100644 iTechSharp/srcbc/asn1/x509/DisplayText.cs create mode 100644 iTechSharp/srcbc/asn1/x509/DistributionPoint.cs create mode 100644 iTechSharp/srcbc/asn1/x509/DistributionPointName.cs create mode 100644 iTechSharp/srcbc/asn1/x509/ExtendedKeyUsage.cs create mode 100644 iTechSharp/srcbc/asn1/x509/GeneralName.cs create mode 100644 iTechSharp/srcbc/asn1/x509/GeneralNames.cs create mode 100644 iTechSharp/srcbc/asn1/x509/GeneralSubtree.cs create mode 100644 iTechSharp/srcbc/asn1/x509/Holder.cs create mode 100644 iTechSharp/srcbc/asn1/x509/IetfAttrSyntax.cs create mode 100644 iTechSharp/srcbc/asn1/x509/IssuerSerial.cs create mode 100644 iTechSharp/srcbc/asn1/x509/IssuingDistributionPoint.cs create mode 100644 iTechSharp/srcbc/asn1/x509/KeyPurposeId.cs create mode 100644 iTechSharp/srcbc/asn1/x509/KeyUsage.cs create mode 100644 iTechSharp/srcbc/asn1/x509/NameConstraints.cs create mode 100644 iTechSharp/srcbc/asn1/x509/NoticeReference.cs create mode 100644 iTechSharp/srcbc/asn1/x509/ObjectDigestInfo.cs create mode 100644 iTechSharp/srcbc/asn1/x509/PolicyInformation.cs create mode 100644 iTechSharp/srcbc/asn1/x509/PolicyMappings.cs create mode 100644 iTechSharp/srcbc/asn1/x509/PolicyQualifierId.cs create mode 100644 iTechSharp/srcbc/asn1/x509/PolicyQualifierInfo.cs create mode 100644 iTechSharp/srcbc/asn1/x509/PrivateKeyUsagePeriod.cs create mode 100644 iTechSharp/srcbc/asn1/x509/RSAPublicKeyStructure.cs create mode 100644 iTechSharp/srcbc/asn1/x509/ReasonFlags.cs create mode 100644 iTechSharp/srcbc/asn1/x509/RoleSyntax.cs create mode 100644 iTechSharp/srcbc/asn1/x509/SubjectDirectoryAttributes.cs create mode 100644 iTechSharp/srcbc/asn1/x509/SubjectKeyIdentifier.cs create mode 100644 iTechSharp/srcbc/asn1/x509/SubjectPublicKeyInfo.cs create mode 100644 iTechSharp/srcbc/asn1/x509/TBSCertList.cs create mode 100644 iTechSharp/srcbc/asn1/x509/TBSCertificateStructure.cs create mode 100644 iTechSharp/srcbc/asn1/x509/Target.cs create mode 100644 iTechSharp/srcbc/asn1/x509/TargetInformation.cs create mode 100644 iTechSharp/srcbc/asn1/x509/Targets.cs create mode 100644 iTechSharp/srcbc/asn1/x509/Time.cs create mode 100644 iTechSharp/srcbc/asn1/x509/UserNotice.cs create mode 100644 iTechSharp/srcbc/asn1/x509/V1TBSCertificateGenerator.cs create mode 100644 iTechSharp/srcbc/asn1/x509/V2AttributeCertificateInfoGenerator.cs create mode 100644 iTechSharp/srcbc/asn1/x509/V2Form.cs create mode 100644 iTechSharp/srcbc/asn1/x509/V2TBSCertListGenerator.cs create mode 100644 iTechSharp/srcbc/asn1/x509/V3TBSCertificateGenerator.cs create mode 100644 iTechSharp/srcbc/asn1/x509/X509Attributes.cs create mode 100644 iTechSharp/srcbc/asn1/x509/X509CertificateStructure.cs create mode 100644 iTechSharp/srcbc/asn1/x509/X509DefaultEntryConverter.cs create mode 100644 iTechSharp/srcbc/asn1/x509/X509Extension.cs create mode 100644 iTechSharp/srcbc/asn1/x509/X509Extensions.cs create mode 100644 iTechSharp/srcbc/asn1/x509/X509ExtensionsGenerator.cs create mode 100644 iTechSharp/srcbc/asn1/x509/X509Name.cs create mode 100644 iTechSharp/srcbc/asn1/x509/X509NameEntryConverter.cs create mode 100644 iTechSharp/srcbc/asn1/x509/X509NameTokenizer.cs create mode 100644 iTechSharp/srcbc/asn1/x509/X509ObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/x509/qualified/BiometricData.cs create mode 100644 iTechSharp/srcbc/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/x509/qualified/Iso4217CurrencyCode.cs create mode 100644 iTechSharp/srcbc/asn1/x509/qualified/MonetaryValue.cs create mode 100644 iTechSharp/srcbc/asn1/x509/qualified/QCStatement.cs create mode 100644 iTechSharp/srcbc/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/x509/qualified/SemanticsInformation.cs create mode 100644 iTechSharp/srcbc/asn1/x509/qualified/TypeOfBiometricData.cs create mode 100644 iTechSharp/srcbc/asn1/x509/sigi/NameOrPseudonym.cs create mode 100644 iTechSharp/srcbc/asn1/x509/sigi/PersonalData.cs create mode 100644 iTechSharp/srcbc/asn1/x509/sigi/SigIObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/asn1/x9/KeySpecificInfo.cs create mode 100644 iTechSharp/srcbc/asn1/x9/OtherInfo.cs create mode 100644 iTechSharp/srcbc/asn1/x9/X962NamedCurves.cs create mode 100644 iTechSharp/srcbc/asn1/x9/X962Parameters.cs create mode 100644 iTechSharp/srcbc/asn1/x9/X9Curve.cs create mode 100644 iTechSharp/srcbc/asn1/x9/X9ECParameters.cs create mode 100644 iTechSharp/srcbc/asn1/x9/X9ECParametersHolder.cs create mode 100644 iTechSharp/srcbc/asn1/x9/X9ECPoint.cs create mode 100644 iTechSharp/srcbc/asn1/x9/X9FieldElement.cs create mode 100644 iTechSharp/srcbc/asn1/x9/X9FieldID.cs create mode 100644 iTechSharp/srcbc/asn1/x9/X9IntegerConverter.cs create mode 100644 iTechSharp/srcbc/asn1/x9/X9ObjectIdentifiers.cs create mode 100644 iTechSharp/srcbc/bcpg/ArmoredInputStream.cs create mode 100644 iTechSharp/srcbc/bcpg/ArmoredOutputStream.cs create mode 100644 iTechSharp/srcbc/bcpg/BcpgInputStream.cs create mode 100644 iTechSharp/srcbc/bcpg/BcpgObject.cs create mode 100644 iTechSharp/srcbc/bcpg/BcpgOutputStream.cs create mode 100644 iTechSharp/srcbc/bcpg/CompressedDataPacket.cs create mode 100644 iTechSharp/srcbc/bcpg/CompressionAlgorithmTags.cs create mode 100644 iTechSharp/srcbc/bcpg/ContainedPacket.cs create mode 100644 iTechSharp/srcbc/bcpg/Crc24.cs create mode 100644 iTechSharp/srcbc/bcpg/DsaPublicBcpgKey.cs create mode 100644 iTechSharp/srcbc/bcpg/DsaSecretBcpgKey.cs create mode 100644 iTechSharp/srcbc/bcpg/ElGamalPublicBcpgKey.cs create mode 100644 iTechSharp/srcbc/bcpg/ElGamalSecretBcpgKey.cs create mode 100644 iTechSharp/srcbc/bcpg/ExperimentalPacket.cs create mode 100644 iTechSharp/srcbc/bcpg/HashAlgorithmTags.cs create mode 100644 iTechSharp/srcbc/bcpg/IBcpgKey.cs create mode 100644 iTechSharp/srcbc/bcpg/InputStreamPacket.cs create mode 100644 iTechSharp/srcbc/bcpg/LiteralDataPacket.cs create mode 100644 iTechSharp/srcbc/bcpg/MPInteger.cs create mode 100644 iTechSharp/srcbc/bcpg/MarkerPacket.cs create mode 100644 iTechSharp/srcbc/bcpg/ModDetectionCodePacket.cs create mode 100644 iTechSharp/srcbc/bcpg/OnePassSignaturePacket.cs create mode 100644 iTechSharp/srcbc/bcpg/OutputStreamPacket.cs create mode 100644 iTechSharp/srcbc/bcpg/Packet.cs create mode 100644 iTechSharp/srcbc/bcpg/PacketTags.cs create mode 100644 iTechSharp/srcbc/bcpg/PublicKeyAlgorithmTags.cs create mode 100644 iTechSharp/srcbc/bcpg/PublicKeyEncSessionPacket.cs create mode 100644 iTechSharp/srcbc/bcpg/PublicKeyPacket.cs create mode 100644 iTechSharp/srcbc/bcpg/PublicSubkeyPacket.cs create mode 100644 iTechSharp/srcbc/bcpg/RsaPublicBcpgKey.cs create mode 100644 iTechSharp/srcbc/bcpg/RsaSecretBcpgKey.cs create mode 100644 iTechSharp/srcbc/bcpg/S2k.cs create mode 100644 iTechSharp/srcbc/bcpg/SecretKeyPacket.cs create mode 100644 iTechSharp/srcbc/bcpg/SecretSubkeyPacket.cs create mode 100644 iTechSharp/srcbc/bcpg/SignaturePacket.cs create mode 100644 iTechSharp/srcbc/bcpg/SignatureSubpacket.cs create mode 100644 iTechSharp/srcbc/bcpg/SignatureSubpacketTags.cs create mode 100644 iTechSharp/srcbc/bcpg/SignatureSubpacketsReader.cs create mode 100644 iTechSharp/srcbc/bcpg/SymmetricEncDataPacket.cs create mode 100644 iTechSharp/srcbc/bcpg/SymmetricEncIntegrityPacket.cs create mode 100644 iTechSharp/srcbc/bcpg/SymmetricKeyAlgorithmTags.cs create mode 100644 iTechSharp/srcbc/bcpg/SymmetricKeyEncSessionPacket.cs create mode 100644 iTechSharp/srcbc/bcpg/TrustPacket.cs create mode 100644 iTechSharp/srcbc/bcpg/UserAttributePacket.cs create mode 100644 iTechSharp/srcbc/bcpg/UserAttributeSubpacket.cs create mode 100644 iTechSharp/srcbc/bcpg/UserAttributeSubpacketTags.cs create mode 100644 iTechSharp/srcbc/bcpg/UserAttributeSubpacketsReader.cs create mode 100644 iTechSharp/srcbc/bcpg/UserIdPacket.cs create mode 100644 iTechSharp/srcbc/bcpg/attr/ImageAttrib.cs create mode 100644 iTechSharp/srcbc/bcpg/sig/Exportable.cs create mode 100644 iTechSharp/srcbc/bcpg/sig/IssuerKeyId.cs create mode 100644 iTechSharp/srcbc/bcpg/sig/KeyExpirationTime.cs create mode 100644 iTechSharp/srcbc/bcpg/sig/KeyFlags.cs create mode 100644 iTechSharp/srcbc/bcpg/sig/NotationData.cs create mode 100644 iTechSharp/srcbc/bcpg/sig/PreferredAlgorithms.cs create mode 100644 iTechSharp/srcbc/bcpg/sig/PrimaryUserId.cs create mode 100644 iTechSharp/srcbc/bcpg/sig/Revocable.cs create mode 100644 iTechSharp/srcbc/bcpg/sig/SignatureCreationTime.cs create mode 100644 iTechSharp/srcbc/bcpg/sig/SignatureExpirationTime.cs create mode 100644 iTechSharp/srcbc/bcpg/sig/SignerUserId.cs create mode 100644 iTechSharp/srcbc/bcpg/sig/TrustSignature.cs create mode 100644 iTechSharp/srcbc/cms/BaseDigestCalculator.cs create mode 100644 iTechSharp/srcbc/cms/CMSAttributeTableGenerationException.cs create mode 100644 iTechSharp/srcbc/cms/CMSAttributeTableGenerator.cs create mode 100644 iTechSharp/srcbc/cms/CMSCompressedData.cs create mode 100644 iTechSharp/srcbc/cms/CMSCompressedDataGenerator.cs create mode 100644 iTechSharp/srcbc/cms/CMSCompressedDataParser.cs create mode 100644 iTechSharp/srcbc/cms/CMSCompressedDataStreamGenerator.cs create mode 100644 iTechSharp/srcbc/cms/CMSContentInfoParser.cs create mode 100644 iTechSharp/srcbc/cms/CMSEnvelopedData.cs create mode 100644 iTechSharp/srcbc/cms/CMSEnvelopedDataGenerator.cs create mode 100644 iTechSharp/srcbc/cms/CMSEnvelopedDataParser.cs create mode 100644 iTechSharp/srcbc/cms/CMSEnvelopedDataStreamGenerator.cs create mode 100644 iTechSharp/srcbc/cms/CMSEnvelopedGenerator.cs create mode 100644 iTechSharp/srcbc/cms/CMSEnvelopedHelper.cs create mode 100644 iTechSharp/srcbc/cms/CMSException.cs create mode 100644 iTechSharp/srcbc/cms/CMSPBEKey.cs create mode 100644 iTechSharp/srcbc/cms/CMSProcessable.cs create mode 100644 iTechSharp/srcbc/cms/CMSProcessableByteArray.cs create mode 100644 iTechSharp/srcbc/cms/CMSProcessableFile.cs create mode 100644 iTechSharp/srcbc/cms/CMSSignedData.cs create mode 100644 iTechSharp/srcbc/cms/CMSSignedDataGenerator.cs create mode 100644 iTechSharp/srcbc/cms/CMSSignedDataParser.cs create mode 100644 iTechSharp/srcbc/cms/CMSSignedDataStreamGenerator.cs create mode 100644 iTechSharp/srcbc/cms/CMSSignedGenerator.cs create mode 100644 iTechSharp/srcbc/cms/CMSSignedHelper.cs create mode 100644 iTechSharp/srcbc/cms/CMSTypedStream.cs create mode 100644 iTechSharp/srcbc/cms/CMSUtils.cs create mode 100644 iTechSharp/srcbc/cms/CounterSignatureDigestCalculator.cs create mode 100644 iTechSharp/srcbc/cms/DefaultSignedAttributeTableGenerator.cs create mode 100644 iTechSharp/srcbc/cms/IDigestCalculator.cs create mode 100644 iTechSharp/srcbc/cms/KEKRecipientInformation.cs create mode 100644 iTechSharp/srcbc/cms/KeyAgreeRecipientInformation.cs create mode 100644 iTechSharp/srcbc/cms/KeyTransRecipientInformation.cs create mode 100644 iTechSharp/srcbc/cms/PKCS5Scheme2PBEKey.cs create mode 100644 iTechSharp/srcbc/cms/PasswordRecipientInformation.cs create mode 100644 iTechSharp/srcbc/cms/RecipientId.cs create mode 100644 iTechSharp/srcbc/cms/RecipientInformation.cs create mode 100644 iTechSharp/srcbc/cms/RecipientInformationStore.cs create mode 100644 iTechSharp/srcbc/cms/SignerId.cs create mode 100644 iTechSharp/srcbc/cms/SignerInformation.cs create mode 100644 iTechSharp/srcbc/cms/SignerInformationStore.cs create mode 100644 iTechSharp/srcbc/cms/SimpleAttributeTableGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/AsymmetricCipherKeyPair.cs create mode 100644 iTechSharp/srcbc/crypto/AsymmetricKeyParameter.cs create mode 100644 iTechSharp/srcbc/crypto/BufferedAeadBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/BufferedAsymmetricBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/BufferedBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/BufferedCipherBase.cs create mode 100644 iTechSharp/srcbc/crypto/BufferedIesCipher.cs create mode 100644 iTechSharp/srcbc/crypto/BufferedStreamCipher.cs create mode 100644 iTechSharp/srcbc/crypto/CipherKeyGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/CryptoException.cs create mode 100644 iTechSharp/srcbc/crypto/DataLengthException.cs create mode 100644 iTechSharp/srcbc/crypto/IAsymmetricBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/IAsymmetricCipherKeyPairGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/IBasicAgreement.cs create mode 100644 iTechSharp/srcbc/crypto/IBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/IBufferedCipher.cs create mode 100644 iTechSharp/srcbc/crypto/ICipherParameters.cs create mode 100644 iTechSharp/srcbc/crypto/IDSA.cs create mode 100644 iTechSharp/srcbc/crypto/IDerivationFunction.cs create mode 100644 iTechSharp/srcbc/crypto/IDerivationParameters.cs create mode 100644 iTechSharp/srcbc/crypto/IDigest.cs create mode 100644 iTechSharp/srcbc/crypto/IMac.cs create mode 100644 iTechSharp/srcbc/crypto/ISigner.cs create mode 100644 iTechSharp/srcbc/crypto/ISignerWithRecovery.cs create mode 100644 iTechSharp/srcbc/crypto/IStreamCipher.cs create mode 100644 iTechSharp/srcbc/crypto/IWrapper.cs create mode 100644 iTechSharp/srcbc/crypto/InvalidCipherTextException.cs create mode 100644 iTechSharp/srcbc/crypto/KeyGenerationParameters.cs create mode 100644 iTechSharp/srcbc/crypto/MaxBytesExceededException.cs create mode 100644 iTechSharp/srcbc/crypto/PbeParametersGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/StreamBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/agreement/DHAgreement.cs create mode 100644 iTechSharp/srcbc/crypto/agreement/DHBasicAgreement.cs create mode 100644 iTechSharp/srcbc/crypto/agreement/ECDHBasicAgreement.cs create mode 100644 iTechSharp/srcbc/crypto/agreement/ECDHCBasicAgreement.cs create mode 100644 iTechSharp/srcbc/crypto/agreement/ECDHWithKdfBasicAgreement.cs create mode 100644 iTechSharp/srcbc/crypto/agreement/kdf/DHKdfParameters.cs create mode 100644 iTechSharp/srcbc/crypto/agreement/kdf/DHKekGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/agreement/kdf/ECDHKekGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/digests/GOST3411Digest.cs create mode 100644 iTechSharp/srcbc/crypto/digests/GeneralDigest.cs create mode 100644 iTechSharp/srcbc/crypto/digests/LongDigest.cs create mode 100644 iTechSharp/srcbc/crypto/digests/MD2Digest.cs create mode 100644 iTechSharp/srcbc/crypto/digests/MD4Digest.cs create mode 100644 iTechSharp/srcbc/crypto/digests/MD5Digest.cs create mode 100644 iTechSharp/srcbc/crypto/digests/RipeMD128Digest.cs create mode 100644 iTechSharp/srcbc/crypto/digests/RipeMD160Digest.cs create mode 100644 iTechSharp/srcbc/crypto/digests/RipeMD256Digest.cs create mode 100644 iTechSharp/srcbc/crypto/digests/RipeMD320Digest.cs create mode 100644 iTechSharp/srcbc/crypto/digests/Sha1Digest.cs create mode 100644 iTechSharp/srcbc/crypto/digests/Sha224Digest.cs create mode 100644 iTechSharp/srcbc/crypto/digests/Sha256Digest.cs create mode 100644 iTechSharp/srcbc/crypto/digests/Sha384Digest.cs create mode 100644 iTechSharp/srcbc/crypto/digests/Sha512Digest.cs create mode 100644 iTechSharp/srcbc/crypto/digests/ShortenedDigest.cs create mode 100644 iTechSharp/srcbc/crypto/digests/TigerDigest.cs create mode 100644 iTechSharp/srcbc/crypto/digests/WhirlpoolDigest.cs create mode 100644 iTechSharp/srcbc/crypto/encodings/ISO9796d1Encoding.cs create mode 100644 iTechSharp/srcbc/crypto/encodings/OaepEncoding.cs create mode 100644 iTechSharp/srcbc/crypto/encodings/Pkcs1Encoding.cs create mode 100644 iTechSharp/srcbc/crypto/engines/AesEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/AesFastEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/AesLightEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/AesWrapEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/BlowfishEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/CamelliaEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/CamelliaWrapEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/Cast5Engine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/Cast6Engine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/DesEdeEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/DesEdeWrapEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/DesEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/ElGamalEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/GOST28147Engine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/HC128Engine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/HC256Engine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/ISAACEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/IdeaEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/IesEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/NaccacheSternEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/NoekeonEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/NullEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/RC2Engine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/RC2WrapEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/RC4Engine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/RC532Engine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/RC564Engine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/RC6Engine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/RFC3211WrapEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/RFC3394WrapEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/RSABlindedEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/RSABlindingEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/RSACoreEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/RijndaelEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/RsaEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/SEEDEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/SEEDWrapEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/Salsa20Engine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/SerpentEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/SkipjackEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/TEAEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/TwofishEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/VMPCEngine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/VMPCKSA3Engine.cs create mode 100644 iTechSharp/srcbc/crypto/engines/XTEAEngine.cs create mode 100644 iTechSharp/srcbc/crypto/generators/BaseKdfBytesGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/DHBasicKeyPairGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/DHKeyGeneratorHelper.cs create mode 100644 iTechSharp/srcbc/crypto/generators/DHKeyPairGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/DHParametersGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/DHParametersHelper.cs create mode 100644 iTechSharp/srcbc/crypto/generators/DesEdeKeyGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/DesKeyGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/DsaKeyPairGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/DsaParametersGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/ECKeyPairGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/ElGamalKeyPairGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/ElGamalParametersGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/GOST3410KeyPairGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/GOST3410ParametersGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/Kdf1BytesGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/Kdf2BytesGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/Mgf1BytesGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/NaccacheSternKeyPairGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/OpenSSLPBEParametersGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/Pkcs12ParametersGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/Pkcs5S1ParametersGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/Pkcs5S2ParametersGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/RSABlindingFactorGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/generators/RsaKeyPairGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/io/CipherStream.cs create mode 100644 iTechSharp/srcbc/crypto/io/DigestStream.cs create mode 100644 iTechSharp/srcbc/crypto/io/MacStream.cs create mode 100644 iTechSharp/srcbc/crypto/macs/CMac.cs create mode 100644 iTechSharp/srcbc/crypto/macs/CbcBlockCipherMac.cs create mode 100644 iTechSharp/srcbc/crypto/macs/CfbBlockCipherMac.cs create mode 100644 iTechSharp/srcbc/crypto/macs/GOST28147Mac.cs create mode 100644 iTechSharp/srcbc/crypto/macs/HMac.cs create mode 100644 iTechSharp/srcbc/crypto/macs/ISO9797Alg3Mac.cs create mode 100644 iTechSharp/srcbc/crypto/macs/VMPCMac.cs create mode 100644 iTechSharp/srcbc/crypto/modes/CbcBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/modes/CcmBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/modes/CfbBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/modes/CtsBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/modes/EAXBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/modes/GCMBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/modes/GOFBBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/modes/IAeadBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/modes/OfbBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/modes/OpenPgpCfbBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/modes/SicBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/paddings/BlockCipherPadding.cs create mode 100644 iTechSharp/srcbc/crypto/paddings/ISO10126d2Padding.cs create mode 100644 iTechSharp/srcbc/crypto/paddings/ISO7816d4Padding.cs create mode 100644 iTechSharp/srcbc/crypto/paddings/PaddedBufferedBlockCipher.cs create mode 100644 iTechSharp/srcbc/crypto/paddings/Pkcs7Padding.cs create mode 100644 iTechSharp/srcbc/crypto/paddings/TbcPadding.cs create mode 100644 iTechSharp/srcbc/crypto/paddings/X923Padding.cs create mode 100644 iTechSharp/srcbc/crypto/paddings/ZeroBytePadding.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/AEADParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/CcmParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/DHKeyGenerationParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/DHKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/DHParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/DHPrivateKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/DHPublicKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/DHValidationParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/DesEdeParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/DesParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/DsaKeyGenerationParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/DsaKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/DsaParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/DsaPrivateKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/DsaPublicKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/DsaValidationParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/ECDomainParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/ECKeyGenerationParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/ECKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/ECPrivateKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/ECPublicKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/ElGamalKeyGenerationParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/ElGamalKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/ElGamalParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/ElGamalPrivateKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/ElGamalPublicKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/GOST3410KeyGenerationParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/GOST3410KeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/GOST3410Parameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/GOST3410PrivateKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/GOST3410PublicKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/GOST3410ValidationParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/ISO18033KDFParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/IesParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/IesWithCipherParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/KdfParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/KeyParameter.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/MgfParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/NaccacheSternKeyGenerationParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/NaccacheSternKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/NaccacheSternPrivateKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/ParametersWithIV.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/ParametersWithRandom.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/ParametersWithSBox.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/ParametersWithSalt.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/RC2Parameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/RC5Parameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/RSABlindingParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/RsaKeyGenerationParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/RsaKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/parameters/RsaPrivateCrtKeyParameters.cs create mode 100644 iTechSharp/srcbc/crypto/prng/CryptoApiRandomGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/prng/DigestRandomGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/prng/IRandomGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/prng/ReversedWindowGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/prng/ThreadedSeedGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/prng/VMPCRandomGenerator.cs create mode 100644 iTechSharp/srcbc/crypto/signers/DsaDigestSigner.cs create mode 100644 iTechSharp/srcbc/crypto/signers/DsaSigner.cs create mode 100644 iTechSharp/srcbc/crypto/signers/ECDsaSigner.cs create mode 100644 iTechSharp/srcbc/crypto/signers/ECGOST3410Signer.cs create mode 100644 iTechSharp/srcbc/crypto/signers/ECNRSigner.cs create mode 100644 iTechSharp/srcbc/crypto/signers/GOST3410DigestSigner.cs create mode 100644 iTechSharp/srcbc/crypto/signers/GOST3410Signer.cs create mode 100644 iTechSharp/srcbc/crypto/signers/Iso9796d2PssSigner.cs create mode 100644 iTechSharp/srcbc/crypto/signers/Iso9796d2Signer.cs create mode 100644 iTechSharp/srcbc/crypto/signers/PssSigner.cs create mode 100644 iTechSharp/srcbc/crypto/signers/RsaDigestSigner.cs create mode 100644 iTechSharp/srcbc/crypto/tls/AlwaysValidVerifyer.cs create mode 100644 iTechSharp/srcbc/crypto/tls/ByteQueue.cs create mode 100644 iTechSharp/srcbc/crypto/tls/Certificate.cs create mode 100644 iTechSharp/srcbc/crypto/tls/CombinedHash.cs create mode 100644 iTechSharp/srcbc/crypto/tls/ICertificateVerifyer.cs create mode 100644 iTechSharp/srcbc/crypto/tls/RecordStream.cs create mode 100644 iTechSharp/srcbc/crypto/tls/TlsBlockCipherCipherSuite.cs create mode 100644 iTechSharp/srcbc/crypto/tls/TlsCipherSuite.cs create mode 100644 iTechSharp/srcbc/crypto/tls/TlsCipherSuiteManager.cs create mode 100644 iTechSharp/srcbc/crypto/tls/TlsException.cs create mode 100644 iTechSharp/srcbc/crypto/tls/TlsInputStream.cs create mode 100644 iTechSharp/srcbc/crypto/tls/TlsMac.cs create mode 100644 iTechSharp/srcbc/crypto/tls/TlsNullCipherSuite.cs create mode 100644 iTechSharp/srcbc/crypto/tls/TlsOutputStream.cs create mode 100644 iTechSharp/srcbc/crypto/tls/TlsProtocolHandler.cs create mode 100644 iTechSharp/srcbc/crypto/tls/TlsUtilities.cs create mode 100644 iTechSharp/srcbc/math/BigInteger.cs create mode 100644 iTechSharp/srcbc/math/ec/ECAlgorithms.cs create mode 100644 iTechSharp/srcbc/math/ec/ECCurve.cs create mode 100644 iTechSharp/srcbc/math/ec/ECFieldElement.cs create mode 100644 iTechSharp/srcbc/math/ec/ECPoint.cs create mode 100644 iTechSharp/srcbc/math/ec/IntArray.cs create mode 100644 iTechSharp/srcbc/math/ec/abc/SimpleBigDecimal.cs create mode 100644 iTechSharp/srcbc/math/ec/abc/Tnaf.cs create mode 100644 iTechSharp/srcbc/math/ec/abc/ZTauElement.cs create mode 100644 iTechSharp/srcbc/math/ec/multiplier/ECMultiplier.cs create mode 100644 iTechSharp/srcbc/math/ec/multiplier/FpNafMultiplier.cs create mode 100644 iTechSharp/srcbc/math/ec/multiplier/PreCompInfo.cs create mode 100644 iTechSharp/srcbc/math/ec/multiplier/ReferenceMultiplier.cs create mode 100644 iTechSharp/srcbc/math/ec/multiplier/WNafMultiplier.cs create mode 100644 iTechSharp/srcbc/math/ec/multiplier/WNafPreCompInfo.cs create mode 100644 iTechSharp/srcbc/math/ec/multiplier/WTauNafMultiplier.cs create mode 100644 iTechSharp/srcbc/math/ec/multiplier/WTauNafPreCompInfo.cs create mode 100644 iTechSharp/srcbc/ocsp/BasicOCSPResp.cs create mode 100644 iTechSharp/srcbc/ocsp/BasicOCSPRespGenerator.cs create mode 100644 iTechSharp/srcbc/ocsp/CertificateID.cs create mode 100644 iTechSharp/srcbc/ocsp/CertificateStatus.cs create mode 100644 iTechSharp/srcbc/ocsp/OCSPException.cs create mode 100644 iTechSharp/srcbc/ocsp/OCSPReq.cs create mode 100644 iTechSharp/srcbc/ocsp/OCSPReqGenerator.cs create mode 100644 iTechSharp/srcbc/ocsp/OCSPResp.cs create mode 100644 iTechSharp/srcbc/ocsp/OCSPRespGenerator.cs create mode 100644 iTechSharp/srcbc/ocsp/OCSPRespStatus.cs create mode 100644 iTechSharp/srcbc/ocsp/OCSPUtil.cs create mode 100644 iTechSharp/srcbc/ocsp/Req.cs create mode 100644 iTechSharp/srcbc/ocsp/RespData.cs create mode 100644 iTechSharp/srcbc/ocsp/RespID.cs create mode 100644 iTechSharp/srcbc/ocsp/RevokedStatus.cs create mode 100644 iTechSharp/srcbc/ocsp/SingleResp.cs create mode 100644 iTechSharp/srcbc/ocsp/UnknownStatus.cs create mode 100644 iTechSharp/srcbc/openpgp/IStreamGenerator.cs create mode 100644 iTechSharp/srcbc/openpgp/PGPKeyRing.cs create mode 100644 iTechSharp/srcbc/openpgp/PGPObject.cs create mode 100644 iTechSharp/srcbc/openpgp/PGPUserAttributeSubpacketVectorGenerator.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpCompressedData.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpCompressedDataGenerator.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpDataValidationException.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpEncryptedData.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpEncryptedDataGenerator.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpEncryptedDataList.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpException.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpExperimental.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpKeyFlags.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpKeyPair.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpKeyRingGenerator.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpKeyValidationException.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpLiteralData.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpLiteralDataGenerator.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpMarker.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpObjectFactory.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpOnePassSignature.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpOnePassSignatureList.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpPbeEncryptedData.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpPrivateKey.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpPublicKey.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpPublicKeyEncryptedData.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpPublicKeyRing.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpPublicKeyRingBundle.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpSecretKey.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpSecretKeyRing.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpSecretKeyRingBundle.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpSignature.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpSignatureGenerator.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpSignatureList.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpSignatureSubpacketGenerator.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpSignatureSubpacketVector.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpUserAttributeSubpacketVector.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpUtilities.cs create mode 100644 iTechSharp/srcbc/openpgp/PgpV3SignatureGenerator.cs create mode 100644 iTechSharp/srcbc/openpgp/WrappedGeneratorStream.cs create mode 100644 iTechSharp/srcbc/openssl/IPasswordFinder.cs create mode 100644 iTechSharp/srcbc/openssl/PEMReader.cs create mode 100644 iTechSharp/srcbc/openssl/PEMUtilities.cs create mode 100644 iTechSharp/srcbc/openssl/PEMWriter.cs create mode 100644 iTechSharp/srcbc/pkcs/AsymmetricKeyEntry.cs create mode 100644 iTechSharp/srcbc/pkcs/EncryptedPrivateKeyInfoFactory.cs create mode 100644 iTechSharp/srcbc/pkcs/Pkcs10CertificationRequest.cs create mode 100644 iTechSharp/srcbc/pkcs/Pkcs12Entry.cs create mode 100644 iTechSharp/srcbc/pkcs/Pkcs12Store.cs create mode 100644 iTechSharp/srcbc/pkcs/PrivateKeyInfoFactory.cs create mode 100644 iTechSharp/srcbc/pkcs/X509CertificateEntry.cs create mode 100644 iTechSharp/srcbc/security/AgreementUtilities.cs create mode 100644 iTechSharp/srcbc/security/CipherUtilities.cs create mode 100644 iTechSharp/srcbc/security/DigestUtilities.cs create mode 100644 iTechSharp/srcbc/security/DotNetUtilities.cs create mode 100644 iTechSharp/srcbc/security/GeneralSecurityException.cs create mode 100644 iTechSharp/srcbc/security/GeneratorUtilities.cs create mode 100644 iTechSharp/srcbc/security/InvalidKeyException.cs create mode 100644 iTechSharp/srcbc/security/InvalidParameterException.cs create mode 100644 iTechSharp/srcbc/security/KeyException.cs create mode 100644 iTechSharp/srcbc/security/MacUtilities.cs create mode 100644 iTechSharp/srcbc/security/NoSuchAlgorithmException.cs create mode 100644 iTechSharp/srcbc/security/ParameterUtilities.cs create mode 100644 iTechSharp/srcbc/security/PbeUtilities.cs create mode 100644 iTechSharp/srcbc/security/PrivateKeyFactory.cs create mode 100644 iTechSharp/srcbc/security/PublicKeyFactory.cs create mode 100644 iTechSharp/srcbc/security/SecureRandom.cs create mode 100644 iTechSharp/srcbc/security/SecurityUtilityException.cs create mode 100644 iTechSharp/srcbc/security/SignatureException.cs create mode 100644 iTechSharp/srcbc/security/SignerUtilities.cs create mode 100644 iTechSharp/srcbc/security/WrapperUtilities.cs create mode 100644 iTechSharp/srcbc/security/cert/CertificateEncodingException.cs create mode 100644 iTechSharp/srcbc/security/cert/CertificateException.cs create mode 100644 iTechSharp/srcbc/security/cert/CertificateExpiredException.cs create mode 100644 iTechSharp/srcbc/security/cert/CertificateNotYetValidException.cs create mode 100644 iTechSharp/srcbc/security/cert/CertificateParsingException.cs create mode 100644 iTechSharp/srcbc/security/cert/CrlException.cs create mode 100644 iTechSharp/srcbc/tsp/GenTimeAccuracy.cs create mode 100644 iTechSharp/srcbc/tsp/TSPAlgorithms.cs create mode 100644 iTechSharp/srcbc/tsp/TSPException.cs create mode 100644 iTechSharp/srcbc/tsp/TSPUtil.cs create mode 100644 iTechSharp/srcbc/tsp/TSPValidationException.cs create mode 100644 iTechSharp/srcbc/tsp/TimeStampRequest.cs create mode 100644 iTechSharp/srcbc/tsp/TimeStampRequestGenerator.cs create mode 100644 iTechSharp/srcbc/tsp/TimeStampResponse.cs create mode 100644 iTechSharp/srcbc/tsp/TimeStampResponseGenerator.cs create mode 100644 iTechSharp/srcbc/tsp/TimeStampToken.cs create mode 100644 iTechSharp/srcbc/tsp/TimeStampTokenGenerator.cs create mode 100644 iTechSharp/srcbc/tsp/TimeStampTokenInfo.cs create mode 100644 iTechSharp/srcbc/util/Arrays.cs create mode 100644 iTechSharp/srcbc/util/BigIntegers.cs create mode 100644 iTechSharp/srcbc/util/Platform.cs create mode 100644 iTechSharp/srcbc/util/Strings.cs create mode 100644 iTechSharp/srcbc/util/bzip2/BZip2Constants.cs create mode 100644 iTechSharp/srcbc/util/bzip2/CBZip2InputStream.cs create mode 100644 iTechSharp/srcbc/util/bzip2/CBZip2OutputStream.cs create mode 100644 iTechSharp/srcbc/util/bzip2/CRC.cs create mode 100644 iTechSharp/srcbc/util/collections/CollectionUtilities.cs create mode 100644 iTechSharp/srcbc/util/collections/EmptyEnumerable.cs create mode 100644 iTechSharp/srcbc/util/collections/EnumerableProxy.cs create mode 100644 iTechSharp/srcbc/util/collections/HashSet.cs create mode 100644 iTechSharp/srcbc/util/collections/ISet.cs create mode 100644 iTechSharp/srcbc/util/date/DateTimeObject.cs create mode 100644 iTechSharp/srcbc/util/date/DateTimeUtilities.cs create mode 100644 iTechSharp/srcbc/util/encoders/Base64.cs create mode 100644 iTechSharp/srcbc/util/encoders/Base64Encoder.cs create mode 100644 iTechSharp/srcbc/util/encoders/BufferedDecoder.cs create mode 100644 iTechSharp/srcbc/util/encoders/BufferedEncoder.cs create mode 100644 iTechSharp/srcbc/util/encoders/Hex.cs create mode 100644 iTechSharp/srcbc/util/encoders/HexEncoder.cs create mode 100644 iTechSharp/srcbc/util/encoders/HexTranslator.cs create mode 100644 iTechSharp/srcbc/util/encoders/IEncoder.cs create mode 100644 iTechSharp/srcbc/util/encoders/Translator.cs create mode 100644 iTechSharp/srcbc/util/encoders/UrlBase64.cs create mode 100644 iTechSharp/srcbc/util/encoders/UrlBase64Encoder.cs create mode 100644 iTechSharp/srcbc/util/io/BaseInputStream.cs create mode 100644 iTechSharp/srcbc/util/io/BaseOutputStream.cs create mode 100644 iTechSharp/srcbc/util/io/PushbackStream.cs create mode 100644 iTechSharp/srcbc/util/io/Streams.cs create mode 100644 iTechSharp/srcbc/util/net/IPAddress.cs create mode 100644 iTechSharp/srcbc/util/zlib/Adler32.cs create mode 100644 iTechSharp/srcbc/util/zlib/Deflate.cs create mode 100644 iTechSharp/srcbc/util/zlib/InfBlocks.cs create mode 100644 iTechSharp/srcbc/util/zlib/InfCodes.cs create mode 100644 iTechSharp/srcbc/util/zlib/InfTree.cs create mode 100644 iTechSharp/srcbc/util/zlib/Inflate.cs create mode 100644 iTechSharp/srcbc/util/zlib/JZlib.cs create mode 100644 iTechSharp/srcbc/util/zlib/StaticTree.cs create mode 100644 iTechSharp/srcbc/util/zlib/Tree.cs create mode 100644 iTechSharp/srcbc/util/zlib/ZDeflaterOutputStream.cs create mode 100644 iTechSharp/srcbc/util/zlib/ZInflaterInputStream.cs create mode 100644 iTechSharp/srcbc/util/zlib/ZStream.cs create mode 100644 iTechSharp/srcbc/x509/AttributeCertificateHolder.cs create mode 100644 iTechSharp/srcbc/x509/AttributeCertificateIssuer.cs create mode 100644 iTechSharp/srcbc/x509/IX509AttributeCertificate.cs create mode 100644 iTechSharp/srcbc/x509/IX509Extension.cs create mode 100644 iTechSharp/srcbc/x509/PEMParser.cs create mode 100644 iTechSharp/srcbc/x509/PrincipalUtil.cs create mode 100644 iTechSharp/srcbc/x509/SubjectPublicKeyInfoFactory.cs create mode 100644 iTechSharp/srcbc/x509/X509AttrCertParser.cs create mode 100644 iTechSharp/srcbc/x509/X509Attribute.cs create mode 100644 iTechSharp/srcbc/x509/X509CertPairParser.cs create mode 100644 iTechSharp/srcbc/x509/X509Certificate.cs create mode 100644 iTechSharp/srcbc/x509/X509CertificatePair.cs create mode 100644 iTechSharp/srcbc/x509/X509CertificateParser.cs create mode 100644 iTechSharp/srcbc/x509/X509Crl.cs create mode 100644 iTechSharp/srcbc/x509/X509CrlEntry.cs create mode 100644 iTechSharp/srcbc/x509/X509CrlParser.cs create mode 100644 iTechSharp/srcbc/x509/X509ExtensionBase.cs create mode 100644 iTechSharp/srcbc/x509/X509KeyUsage.cs create mode 100644 iTechSharp/srcbc/x509/X509SignatureUtil.cs create mode 100644 iTechSharp/srcbc/x509/X509Utilities.cs create mode 100644 iTechSharp/srcbc/x509/X509V1CertificateGenerator.cs create mode 100644 iTechSharp/srcbc/x509/X509V2AttributeCertificate.cs create mode 100644 iTechSharp/srcbc/x509/X509V2AttributeCertificateGenerator.cs create mode 100644 iTechSharp/srcbc/x509/X509V2CRLGenerator.cs create mode 100644 iTechSharp/srcbc/x509/X509V3CertificateGenerator.cs create mode 100644 iTechSharp/srcbc/x509/extension/AuthorityKeyIdentifierStructure.cs create mode 100644 iTechSharp/srcbc/x509/extension/SubjectKeyIdentifierStructure.cs create mode 100644 iTechSharp/srcbc/x509/extension/X509ExtensionUtil.cs create mode 100644 iTechSharp/srcbc/x509/store/IX509Selector.cs create mode 100644 iTechSharp/srcbc/x509/store/IX509Store.cs create mode 100644 iTechSharp/srcbc/x509/store/IX509StoreParameters.cs create mode 100644 iTechSharp/srcbc/x509/store/NoSuchStoreException.cs create mode 100644 iTechSharp/srcbc/x509/store/X509AttrCertStoreSelector.cs create mode 100644 iTechSharp/srcbc/x509/store/X509CertPairStoreSelector.cs create mode 100644 iTechSharp/srcbc/x509/store/X509CertStoreSelector.cs create mode 100644 iTechSharp/srcbc/x509/store/X509CollectionStore.cs create mode 100644 iTechSharp/srcbc/x509/store/X509CollectionStoreParameters.cs create mode 100644 iTechSharp/srcbc/x509/store/X509CrlStoreSelector.cs create mode 100644 iTechSharp/srcbc/x509/store/X509StoreException.cs create mode 100644 iTechSharp/srcbc/x509/store/X509StoreFactory.cs diff --git a/Ionic/Ionic.Zip.dll b/Ionic/Ionic.Zip.dll new file mode 100644 index 0000000000000000000000000000000000000000..1dc0338471b05df9931bb9518a41784d7c43b56d GIT binary patch literal 492032 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


RQd4A9r&V>Eov9Ld6 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�OnU&CPTI;}gFvoE59E$jI4GD7b( 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
  • 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 + + + Ionic.Zip + + + + + An enum that specifies the source of the ZipEntry. + + + + + Default value. Invalid on a bonafide ZipEntry. + + + + + The entry was instantiated by calling AddFile() or another method that + added an entry from the filesystem. + + + + + The entry was instantiated via or + . + + + + + The ZipEntry was instantiated by reading a zipfile. + + + + + The content for the ZipEntry will be or was provided by the WriteDelegate. + + + + + The content for the ZipEntry will be obtained from the stream dispensed by the OpenDelegate. + The entry was instantiated via . + + + + + The content for the ZipEntry will be or was obtained from a ZipOutputStream. + + + + + Provides a stream metaphor for generating zip files. + + + + + This class writes zip files, as defined in the specification + for zip files described by PKWare. The compression for this + implementation is provided by a managed-code version of Zlib, included with + DotNetZip in the classes in the Ionic.Zlib namespace. + + + + This class provides an alternative programming model to the one enabled by the + class. Use this when creating zip files, as an + alternative to the class, when you would like to use a + Stream type to write the zip file. + + + + Both the ZipOutputStream class and the ZipFile class can be used + to create zip files. Both of them support many of the common zip features, + including Unicode, different compression levels, and ZIP64. They provide + very similar performance when creating zip files. + + + + The ZipFile class is generally easier to use than + ZipOutputStream and should be considered a higher-level interface. For + example, when creating a zip file via calls to the PutNextEntry() and + Write() methods on the ZipOutputStream class, the caller is + responsible for opening the file, reading the bytes from the file, writing + those bytes into the ZipOutputStream, setting the attributes on the + ZipEntry, and setting the created, last modified, and last accessed + timestamps on the zip entry. All of these things are done automatically by a + call to ZipFile.AddFile(). + For this reason, the ZipOutputStream is generally recommended for use + only when your application emits arbitrary data, not necessarily data from a + filesystem file, directly into a zip file, and does so using a Stream + metaphor. + + + + Aside from the differences in programming model, there are other + differences in capability between the two classes. + + + + + ZipFile can be used to read and extract zip files, in addition to + creating zip files. ZipOutputStream cannot read zip files. If you want + to use a stream to read zip files, check out the class. + + + + ZipOutputStream does not support the creation of segmented or spanned + zip files. + + + + ZipOutputStream cannot produce a self-extracting archive. + + + + + Be aware that the ZipOutputStream class implements the interface. In order for + ZipOutputStream to produce a valid zip file, you use use it within + a using clause (Using in VB), or call the Dispose() method + explicitly. See the examples for how to employ a using clause. + + + + Also, a note regarding compression performance: On the desktop .NET + Framework, DotNetZip can use a multi-threaded compression implementation + that provides significant speed increases on large files, over 300k or so, + at the cost of increased memory use at runtime. (The output of the + compression is almost exactly the same size). But, the multi-threaded + approach incurs a performance hit on smaller files. There's no way for the + ZipOutputStream to know whether parallel compression will be beneficial, + because the ZipOutputStream does not know how much data you will write + through the stream. You may wish to set the property to zero, if you are compressing + large files through ZipOutputStream. This will cause parallel + compression to be used, always. + + + + + + Create a ZipOutputStream, wrapping an existing stream. + + + + + The class is generally easier to use when creating + zip files. The ZipOutputStream offers a different metaphor for creating a + zip file, based on the class. + + + + + + The stream to wrap. It must be writable. This stream will be closed at + the time the ZipOutputStream is closed. + + + + + This example shows how to create a zip file, using the + ZipOutputStream class. + + + private void Zipup() + { + if (filesToZip.Count == 0) + { + System.Console.WriteLine("Nothing to do."); + return; + } + + using (var raw = File.Open(_outputFileName, FileMode.Create, FileAccess.ReadWrite )) + { + using (var output= new ZipOutputStream(raw)) + { + output.Password = "VerySecret!"; + output.Encryption = EncryptionAlgorithm.WinZipAes256; + + foreach (string inputFileName in filesToZip) + { + System.Console.WriteLine("file: {0}", inputFileName); + + output.PutNextEntry(inputFileName); + using (var input = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Write )) + { + byte[] buffer= new byte[2048]; + int n; + while ((n= input.Read(buffer,0,buffer.Length)) > 0) + { + output.Write(buffer,0,n); + } + } + } + } + } + } + + + + Private Sub Zipup() + Dim outputFileName As String = "XmlData.zip" + Dim filesToZip As String() = Directory.GetFiles(".", "*.xml") + If (filesToZip.Length = 0) Then + Console.WriteLine("Nothing to do.") + Else + Using raw As FileStream = File.Open(outputFileName, FileMode.Create, FileAccess.ReadWrite) + Using output As ZipOutputStream = New ZipOutputStream(raw) + output.Password = "VerySecret!" + output.Encryption = EncryptionAlgorithm.WinZipAes256 + Dim inputFileName As String + For Each inputFileName In filesToZip + Console.WriteLine("file: {0}", inputFileName) + output.PutNextEntry(inputFileName) + Using input As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) + Dim n As Integer + Dim buffer As Byte() = New Byte(2048) {} + Do While (n = input.Read(buffer, 0, buffer.Length) > 0) + output.Write(buffer, 0, n) + Loop + End Using + Next + End Using + End Using + End If + End Sub + + + + + + Create a ZipOutputStream that writes to a filesystem file. + + + + The class is generally easier to use when creating + zip files. The ZipOutputStream offers a different metaphor for creating a + zip file, based on the class. + + + + The name of the zip file to create. + + + + + This example shows how to create a zip file, using the + ZipOutputStream class. + + + private void Zipup() + { + if (filesToZip.Count == 0) + { + System.Console.WriteLine("Nothing to do."); + return; + } + + using (var output= new ZipOutputStream(outputFileName)) + { + output.Password = "VerySecret!"; + output.Encryption = EncryptionAlgorithm.WinZipAes256; + + foreach (string inputFileName in filesToZip) + { + System.Console.WriteLine("file: {0}", inputFileName); + + output.PutNextEntry(inputFileName); + using (var input = File.Open(inputFileName, FileMode.Open, FileAccess.Read, + FileShare.Read | FileShare.Write )) + { + byte[] buffer= new byte[2048]; + int n; + while ((n= input.Read(buffer,0,buffer.Length)) > 0) + { + output.Write(buffer,0,n); + } + } + } + } + } + + + + Private Sub Zipup() + Dim outputFileName As String = "XmlData.zip" + Dim filesToZip As String() = Directory.GetFiles(".", "*.xml") + If (filesToZip.Length = 0) Then + Console.WriteLine("Nothing to do.") + Else + Using output As ZipOutputStream = New ZipOutputStream(outputFileName) + output.Password = "VerySecret!" + output.Encryption = EncryptionAlgorithm.WinZipAes256 + Dim inputFileName As String + For Each inputFileName In filesToZip + Console.WriteLine("file: {0}", inputFileName) + output.PutNextEntry(inputFileName) + Using input As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) + Dim n As Integer + Dim buffer As Byte() = New Byte(2048) {} + Do While (n = input.Read(buffer, 0, buffer.Length) > 0) + output.Write(buffer, 0, n) + Loop + End Using + Next + End Using + End If + End Sub + + + + + + Create a ZipOutputStream. + + + + See the documentation for the ZipOutputStream(Stream) + constructor for an example. + + + + The stream to wrap. It must be writable. + + + + true if the application would like the stream + to remain open after the ZipOutputStream has been closed. + + + + Provides a string representation of the instance. + + + This can be useful for debugging purposes. + + + a string representation of the instance. + + + + Returns true if an entry by the given name has already been written + to the ZipOutputStream. + + + + The name of the entry to scan for. + + + + true if an entry by the given name has already been written. + + + + + Write the data from the buffer to the stream. + + + + As the application writes data into this stream, the data may be + compressed and encrypted before being written out to the underlying + stream, depending on the settings of the + and the properties. + + + The buffer holding data to write to the stream. + the offset within that data array to find the first byte to write. + the number of bytes to write. + + + + Specify the name of the next entry that will be written to the zip file. + + + + + Call this method just before calling , to + specify the name of the entry that the next set of bytes written to + the ZipOutputStream belongs to. All subsequent calls to Write, + until the next call to PutNextEntry, + will be inserted into the named entry in the zip file. + + + + If the used in PutNextEntry() ends in + a slash, then the entry added is marked as a directory. Because directory + entries do not contain data, a call to Write(), before an + intervening additional call to PutNextEntry(), will throw an + exception. + + + + If you don't call Write() between two calls to + PutNextEntry(), the first entry is inserted into the zip file as a + file of zero size. This may be what you want. + + + + Because PutNextEntry() closes out the prior entry, if any, this + method may throw if there is a problem with the prior entry. + + + + This method returns the ZipEntry. You can modify public properties + on the ZipEntry, such as , , and so on, until the first call to + ZipOutputStream.Write(), or until the next call to + PutNextEntry(). If you modify the ZipEntry after + having called Write(), you may get a runtime exception, or you may + silently get an invalid zip archive. + + + + + + + This example shows how to create a zip file, using the + ZipOutputStream class. + + + private void Zipup() + { + using (FileStream fs raw = File.Open(_outputFileName, FileMode.Create, FileAccess.ReadWrite )) + { + using (var output= new ZipOutputStream(fs)) + { + output.Password = "VerySecret!"; + output.Encryption = EncryptionAlgorithm.WinZipAes256; + output.PutNextEntry("entry1.txt"); + byte[] buffer= System.Text.Encoding.ASCII.GetBytes("This is the content for entry #1."); + output.Write(buffer,0,buffer.Length); + output.PutNextEntry("entry2.txt"); // this will be zero length + output.PutNextEntry("entry3.txt"); + buffer= System.Text.Encoding.ASCII.GetBytes("This is the content for entry #3."); + output.Write(buffer,0,buffer.Length); + } + } + } + + + + + The name of the entry to be added, including any path to be used + within the zip file. + + + + The ZipEntry created. + + + + + + Dispose the stream + + + + + This method writes the Zip Central directory, then closes the stream. The + application must call Dispose() (or Close) in order to produce a valid zip file. + + + + Typically the application will call Dispose() implicitly, via a using + statement in C#, or a Using statement in VB. + + + + + set this to true, always. + + + + This is a no-op. + + + + + This method always throws a NotSupportedException. + + ignored + ignored + ignored + nothing + + + + This method always throws a NotSupportedException. + + ignored + ignored + nothing + + + + This method always throws a NotSupportedException. + + ignored + + + + Sets the password to be used on the ZipOutputStream instance. + + + + + + When writing a zip archive, this password is applied to the entries, not + to the zip archive itself. It applies to any ZipEntry subsequently + written to the ZipOutputStream. + + + + Using a password does not encrypt or protect the "directory" of the + archive - the list of entries contained in the archive. If you set the + Password property, the password actually applies to individual + entries that are added to the archive, subsequent to the setting of this + property. The list of filenames in the archive that is eventually created + will appear in clear text, but the contents of the individual files are + encrypted. This is how Zip encryption works. + + + + If you set this property, and then add a set of entries to the archive via + calls to PutNextEntry, then each entry is encrypted with that + password. You may also want to change the password between adding + different entries. If you set the password, add an entry, then set the + password to null (Nothing in VB), and add another entry, the + first entry is encrypted and the second is not. + + + + When setting the Password, you may also want to explicitly set the property, to specify how to encrypt the entries added + to the ZipFile. If you set the Password to a non-null value and do not + set , then PKZip 2.0 ("Weak") encryption is used. + This encryption is relatively weak but is very interoperable. If + you set the password to a null value (Nothing in VB), + Encryption is reset to None. + + + + Special case: if you wrap a ZipOutputStream around a non-seekable stream, + and use encryption, and emit an entry of zero bytes, the Close() or + PutNextEntry() following the entry will throw an exception. + + + + + + + The Encryption to use for entries added to the ZipOutputStream. + + + + + The specified Encryption is applied to the entries subsequently + written to the ZipOutputStream instance. + + + + If you set this to something other than + EncryptionAlgorithm.None, you will also need to set the + to a non-null, non-empty value in + order to actually get encryption on the entry. + + + + + ZipOutputStream.Password + ZipEntry.Encryption + + + + Size of the work buffer to use for the ZLIB codec during compression. + + + + Setting this may affect performance. For larger files, setting this to a + larger size may improve performance, but I'm not sure. Sorry, I don't + currently have good recommendations on how to set it. You can test it if + you like. + + + + + The compression strategy to use for all entries. + + + + Set the Strategy used by the ZLIB-compatible compressor, when compressing + data for the entries in the zip archive. Different compression strategies + work better on different sorts of data. The strategy parameter can affect + the compression ratio and the speed of compression but not the correctness + of the compresssion. For more information see . + + + + + The type of timestamp attached to the ZipEntry. + + + + Set this in order to specify the kind of timestamp that should be emitted + into the zip file for each entry. + + + + + Sets the compression level to be used for entries subsequently added to + the zip archive. + + + + + Varying the compression level used on entries can affect the + size-vs-speed tradeoff when compression and decompressing data streams + or files. + + + + As with some other properties on the ZipOutputStream class, like , and , + setting this property on a ZipOutputStream + instance will cause the specified CompressionLevel to be used on all + items that are subsequently added to the + ZipOutputStream instance. + + + + If you do not set this property, the default compression level is used, + which normally gives a good balance of compression efficiency and + compression speed. In some tests, using BestCompression can + double the time it takes to compress, while delivering just a small + increase in compression efficiency. This behavior will vary with the + type of data you compress. If you are in doubt, just leave this setting + alone, and accept the default. + + + + + + The compression method used on each entry added to the ZipOutputStream. + + + + + A comment attached to the zip archive. + + + + + + The application sets this property to specify a comment to be embedded + into the generated zip archive. + + + + According to PKWARE's + zip specification, the comment is not encrypted, even if there is a + password set on the zip file. + + + + The specification does not describe how to indicate the encoding used + on a comment string. Many "compliant" zip tools and libraries use + IBM437 as the code page for comments; DotNetZip, too, follows that + practice. On the other hand, there are situations where you want a + Comment to be encoded with something else, for example using code page + 950 "Big-5 Chinese". To fill that need, DotNetZip will encode the + comment following the same procedure it follows for encoding + filenames: (a) if is + Never, it uses the default encoding (IBM437). (b) if is Always, it always uses the + alternate encoding (). (c) if is AsNecessary, it uses the + alternate encoding only if the default encoding is not sufficient for + encoding the comment - in other words if decoding the result does not + produce the original string. This decision is taken at the time of + the call to ZipFile.Save(). + + + + + + + Specify whether to use ZIP64 extensions when saving a zip archive. + + + + + The default value for the property is . is + safest, in the sense that you will not get an Exception if a + pre-ZIP64 limit is exceeded. + + + + You must set this property before calling Write(). + + + + + + + Indicates whether ZIP64 extensions were used when saving the zip archive. + + + + The value is defined only after the ZipOutputStream has been closed. + + + + + Whether the ZipOutputStream should use case-insensitive comparisons when + checking for uniqueness of zip entries. + + + + + Though the zip specification doesn't prohibit zipfiles with duplicate + entries, Sane zip files have no duplicates, and the DotNetZip library + cannot create zip files with duplicate entries. If an application attempts + to call with a name that duplicates one + already used within the archive, the library will throw an Exception. + + + This property allows the application to specify whether the + ZipOutputStream instance considers ordinal case when checking for + uniqueness of zip entries. + + + + + + Indicates whether to encode entry filenames and entry comments using + Unicode (UTF-8). + + + + + The + PKWare zip specification provides for encoding file names and file + comments in either the IBM437 code page, or in UTF-8. This flag selects + the encoding according to that specification. By default, this flag is + false, and filenames and comments are encoded into the zip file in the + IBM437 codepage. Setting this flag to true will specify that filenames + and comments that cannot be encoded with IBM437 will be encoded with + UTF-8. + + + + Zip files created with strict adherence to the PKWare specification with + respect to UTF-8 encoding can contain entries with filenames containing + any combination of Unicode characters, including the full range of + characters from Chinese, Latin, Hebrew, Greek, Cyrillic, and many other + alphabets. However, because at this time, the UTF-8 portion of the PKWare + specification is not broadly supported by other zip libraries and + utilities, such zip files may not be readable by your favorite zip tool or + archiver. In other words, interoperability will decrease if you set this + flag to true. + + + + In particular, Zip files created with strict adherence to the PKWare + specification with respect to UTF-8 encoding will not work well with + Explorer in Windows XP or Windows Vista, because Windows compressed + folders, as far as I know, do not support UTF-8 in zip files. Vista can + read the zip files, but shows the filenames incorrectly. Unpacking from + Windows Vista Explorer will result in filenames that have rubbish + characters in place of the high-order UTF-8 bytes. + + + + Also, zip files that use UTF-8 encoding will not work well with Java + applications that use the java.util.zip classes, as of v5.0 of the Java + runtime. The Java runtime does not correctly implement the PKWare + specification in this regard. + + + + As a result, we have the unfortunate situation that "correct" behavior by + the DotNetZip library with regard to Unicode encoding of filenames during + zip creation will result in zip files that are readable by strictly + compliant and current tools (for example the most recent release of the + commercial WinZip tool); but these zip files will not be readable by + various other tools or libraries, including Windows Explorer. + + + + The DotNetZip library can read and write zip files with UTF8-encoded + entries, according to the PKware spec. If you use DotNetZip for both + creating and reading the zip file, and you use UTF-8, there will be no + loss of information in the filenames. For example, using a self-extractor + created by this library will allow you to unpack files correctly with no + loss of information in the filenames. + + + + If you do not set this flag, it will remain false. If this flag is false, + the ZipOutputStream will encode all filenames and comments using + the IBM437 codepage. This can cause "loss of information" on some + filenames, but the resulting zipfile will be more interoperable with other + utilities. As an example of the loss of information, diacritics can be + lost. The o-tilde character will be down-coded to plain o. The c with a + cedilla (Unicode 0xE7) used in Portugese will be downcoded to a c. + Likewise, the O-stroke character (Unicode 248), used in Danish and + Norwegian, will be down-coded to plain o. Chinese characters cannot be + represented in codepage IBM437; when using the default encoding, Chinese + characters in filenames will be represented as ?. These are all examples + of "information loss". + + + + The loss of information associated to the use of the IBM437 encoding is + inconvenient, and can also lead to runtime errors. For example, using + IBM437, any sequence of 4 Chinese characters will be encoded as ????. If + your application creates a ZipOutputStream, does not set the + encoding, then adds two files, each with names of four Chinese characters + each, this will result in a duplicate filename exception. In the case + where you add a single file with a name containing four Chinese + characters, the zipfile will save properly, but extracting that file + later, with any zip tool, will result in an error, because the question + mark is not legal for use within filenames on Windows. These are just a + few examples of the problems associated to loss of information. + + + + This flag is independent of the encoding of the content within the entries + in the zip file. Think of the zip file as a container - it supports an + encoding. Within the container are other "containers" - the file entries + themselves. The encoding within those entries is independent of the + encoding of the zip archive container for those entries. + + + + Rather than specify the encoding in a binary fashion using this flag, an + application can specify an arbitrary encoding via the property. Setting the encoding + explicitly when creating zip archives will result in non-compliant zip + files that, curiously, are fairly interoperable. The challenge is, the + PKWare specification does not provide for a way to specify that an entry + in a zip archive uses a code page that is neither IBM437 nor UTF-8. + Therefore if you set the encoding explicitly when creating a zip archive, + you must take care upon reading the zip archive to use the same code page. + If you get it wrong, the behavior is undefined and may result in incorrect + filenames, exceptions, stomach upset, hair loss, and acne. + + + + + + + The text encoding to use when emitting entries into the zip archive, for + those entries whose filenames or comments cannot be encoded with the + default (IBM437) encoding. + + + + + In its + zip specification, PKWare describes two options for encoding + filenames and comments: using IBM437 or UTF-8. But, some archiving tools + or libraries do not follow the specification, and instead encode + characters using the system default code page. For example, WinRAR when + run on a machine in Shanghai may encode filenames with the Big-5 Chinese + (950) code page. This behavior is contrary to the Zip specification, but + it occurs anyway. + + + + When using DotNetZip to write zip archives that will be read by one of + these other archivers, set this property to specify the code page to use + when encoding the and for each ZipEntry in the zip file, for + values that cannot be encoded with the default codepage for zip files, + IBM437. This is why this property is "provisional". In all cases, IBM437 + is used where possible, in other words, where no loss of data would + result. It is possible, therefore, to have a given entry with a + Comment encoded in IBM437 and a FileName encoded with the + specified "provisional" codepage. + + + + Be aware that a zip file created after you've explicitly set the + ProvisionalAlternateEncoding property to a value other than + IBM437 may not be compliant to the PKWare specification, and may not be + readable by compliant archivers. On the other hand, many (most?) + archivers are non-compliant and can read zip files created in arbitrary + code pages. The trick is to use or specify the proper codepage when + reading the zip. + + + + When creating a zip archive using this library, it is possible to change + the value of ProvisionalAlternateEncoding between each entry you + add, and between adding entries and the call to Close(). Don't do + this. It will likely result in a zipfile that is not readable. For best + interoperability, either leave ProvisionalAlternateEncoding + alone, or specify it only once, before adding any entries to the + ZipOutputStream instance. There is one exception to this + recommendation, described later. + + + + When using an arbitrary, non-UTF8 code page for encoding, there is no + standard way for the creator application - whether DotNetZip, WinZip, + WinRar, or something else - to formally specify in the zip file which + codepage has been used for the entries. As a result, readers of zip files + are not able to inspect the zip file and determine the codepage that was + used for the entries contained within it. It is left to the application + or user to determine the necessary codepage when reading zip files encoded + this way. If you use an incorrect codepage when reading a zipfile, you + will get entries with filenames that are incorrect, and the incorrect + filenames may even contain characters that are not legal for use within + filenames in Windows. Extracting entries with illegal characters in the + filenames will lead to exceptions. It's too bad, but this is just the way + things are with code pages in zip files. Caveat Emptor. + + + + One possible approach for specifying the code page for a given zip file is + to describe the code page in a human-readable form in the Zip comment. For + example, the comment may read "Entries in this archive are encoded in the + Big5 code page". For maximum interoperability, the zip comment in this + case should be encoded in the default, IBM437 code page. In this case, + the zip comment is encoded using a different page than the filenames. To + do this, Specify ProvisionalAlternateEncoding to your desired + region-specific code page, once before adding any entries, and then set + the property and reset + ProvisionalAlternateEncoding to IBM437 before calling Close(). + + + + + + A Text Encoding to use when encoding the filenames and comments for + all the ZipEntry items, during a ZipFile.Save() operation. + + + + Whether the encoding specified here is used during the save depends + on . + + + + + + A flag that tells if and when this instance should apply + AlternateEncoding to encode the filenames and comments associated to + of ZipEntry objects contained within this instance. + + + + + The default text encoding used in zip archives. It is numeric 437, also + known as IBM437. + + + + + + The size threshold for an entry, above which a parallel deflate is used. + + + + + + DotNetZip will use multiple threads to compress any ZipEntry, when + the CompressionMethod is Deflate, and if the entry is + larger than the given size. Zero means "always use parallel + deflate", while -1 means "never use parallel deflate". + + + + If the entry size cannot be known before compression, as with any entry + added via a ZipOutputStream, then Parallel deflate will never be + performed, unless the value of this property is zero. + + + + A parallel deflate operations will speed up the compression of + large files, on computers with multiple CPUs or multiple CPU + cores. For files above 1mb, on a dual core or dual-cpu (2p) + machine, the time required to compress the file can be 70% of the + single-threaded deflate. For very large files on 4p machines the + compression can be done in 30% of the normal time. The downside + is that parallel deflate consumes extra memory during the deflate, + and the deflation is slightly less effective. + + + + Parallel deflate tends to not be as effective as single-threaded deflate + because the original data stream is split into multiple independent + buffers, each of which is compressed in parallel. But because they are + treated independently, there is no opportunity to share compression + dictionaries, and additional framing bytes must be added to the output + stream. For that reason, a deflated stream may be slightly larger when + compressed using parallel deflate, as compared to a traditional + single-threaded deflate. For files of about 512k, the increase over the + normal deflate is as much as 5% of the total compressed size. For larger + files, the difference can be as small as 0.1%. + + + + Multi-threaded compression does not give as much an advantage when using + Encryption. This is primarily because encryption tends to slow down + the entire pipeline. Also, multi-threaded compression gives less of an + advantage when using lower compression levels, for example . You may have to perform + some tests to determine the best approach for your situation. + + + + The default value for this property is -1, which means parallel + compression will not be performed unless you set it to zero. + + + + + + + The maximum number of buffer pairs to use when performing + parallel compression. + + + + + This property sets an upper limit on the number of memory + buffer pairs to create when performing parallel + compression. The implementation of the parallel + compression stream allocates multiple buffers to + facilitate parallel compression. As each buffer fills up, + the stream uses + ThreadPool.QueueUserWorkItem() to compress those + buffers in a background threadpool thread. After a buffer + is compressed, it is re-ordered and written to the output + stream. + + + + A higher number of buffer pairs enables a higher degree of + parallelism, which tends to increase the speed of compression on + multi-cpu computers. On the other hand, a higher number of buffer + pairs also implies a larger memory consumption, more active worker + threads, and a higher cpu utilization for any compression. This + property enables the application to limit its memory consumption and + CPU utilization behavior depending on requirements. + + + + For each compression "task" that occurs in parallel, there are 2 + buffers allocated: one for input and one for output. This property + sets a limit for the number of pairs. The total amount of storage + space allocated for buffering will then be (N*S*2), where N is the + number of buffer pairs, S is the size of each buffer (). By default, DotNetZip allocates 4 buffer + pairs per CPU core, so if your machine has 4 cores, and you retain + the default buffer size of 128k, then the + ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer + memory in total, or 4mb, in blocks of 128kb. If you then set this + property to 8, then the number will be 8 * 2 * 128kb of buffer + memory, or 2mb. + + + + CPU utilization will also go up with additional buffers, because a + larger number of buffer pairs allows a larger number of background + threads to compress in parallel. If you find that parallel + compression is consuming too much memory or CPU, you can adjust this + value downward. + + + + The default value is 16. Different values may deliver better or + worse results, depending on your priorities and the dynamic + performance characteristics of your storage and compute resources. + + + + This property is not the number of buffer pairs to use; it is an + upper limit. An illustration: Suppose you have an application that + uses the default value of this property (which is 16), and it runs + on a machine with 2 CPU cores. In that case, DotNetZip will allocate + 4 buffer pairs per CPU core, for a total of 8 pairs. The upper + limit specified by this property has no effect. + + + + The application can set this value at any time, but it is + effective only if set before calling + ZipOutputStream.Write() for the first time. + + + + + + + + + Always returns false. + + + + + Always returns false. + + + + + Always returns true. + + + + + Always returns a NotSupportedException. + + + + + Setting this property always returns a NotSupportedException. Getting it + returns the value of the Position on the underlying stream. + + + + + Provides a stream metaphor for reading zip files. + + + + + This class provides an alternative programming model for reading zip files to + the one enabled by the class. Use this when reading zip + files, as an alternative to the class, when you would + like to use a Stream class to read the file. + + + + Some application designs require a readable stream for input. This stream can + be used to read a zip file, and extract entries. + + + + Both the ZipInputStream class and the ZipFile class can be used + to read and extract zip files. Both of them support many of the common zip + features, including Unicode, different compression levels, and ZIP64. The + programming models differ. For example, when extracting entries via calls to + the GetNextEntry() and Read() methods on the + ZipInputStream class, the caller is responsible for creating the file, + writing the bytes into the file, setting the attributes on the file, and + setting the created, last modified, and last accessed timestamps on the + file. All of these things are done automatically by a call to ZipEntry.Extract(). For this reason, the + ZipInputStream is generally recommended for when your application wants + to extract the data, without storing that data into a file. + + + + Aside from the obvious differences in programming model, there are some + differences in capability between the ZipFile class and the + ZipInputStream class. + + + + + ZipFile can be used to create or update zip files, or read and + extract zip files. ZipInputStream can be used only to read and + extract zip files. If you want to use a stream to create zip files, check + out the . + + + + ZipInputStream cannot read segmented or spanned + zip files. + + + + ZipInputStream will not read Zip file comments. + + + + When reading larger files, ZipInputStream will always underperform + ZipFile. This is because the ZipInputStream does a full scan on the + zip file, while the ZipFile class reads the central directory of the + zip file. + + + + + + + + + Create a ZipInputStream, wrapping it around an existing stream. + + + + + + While the class is generally easier + to use, this class provides an alternative to those + applications that want to read from a zipfile directly, + using a . + + + + Both the ZipInputStream class and the ZipFile class can be used + to read and extract zip files. Both of them support many of the common zip + features, including Unicode, different compression levels, and ZIP64. The + programming models differ. For example, when extracting entries via calls to + the GetNextEntry() and Read() methods on the + ZipInputStream class, the caller is responsible for creating the file, + writing the bytes into the file, setting the attributes on the file, and + setting the created, last modified, and last accessed timestamps on the + file. All of these things are done automatically by a call to ZipEntry.Extract(). For this reason, the + ZipInputStream is generally recommended for when your application wants + to extract the data, without storing that data into a file. + + + + Aside from the obvious differences in programming model, there are some + differences in capability between the ZipFile class and the + ZipInputStream class. + + + + + ZipFile can be used to create or update zip files, or read and extract + zip files. ZipInputStream can be used only to read and extract zip + files. If you want to use a stream to create zip files, check out the . + + + + ZipInputStream cannot read segmented or spanned + zip files. + + + + ZipInputStream will not read Zip file comments. + + + + When reading larger files, ZipInputStream will always underperform + ZipFile. This is because the ZipInputStream does a full scan on the + zip file, while the ZipFile class reads the central directory of the + zip file. + + + + + + + + The stream to read. It must be readable. This stream will be closed at + the time the ZipInputStream is closed. + + + + + This example shows how to read a zip file, and extract entries, using the + ZipInputStream class. + + + private void Unzip() + { + byte[] buffer= new byte[2048]; + int n; + using (var raw = File.Open(inputFileName, FileMode.Open, FileAccess.Read)) + { + using (var input= new ZipInputStream(raw)) + { + ZipEntry e; + while (( e = input.GetNextEntry()) != null) + { + if (e.IsDirectory) continue; + string outputPath = Path.Combine(extractDir, e.FileName); + using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite)) + { + while ((n= input.Read(buffer, 0, buffer.Length)) > 0) + { + output.Write(buffer,0,n); + } + } + } + } + } + } + + + + Private Sub UnZip() + Dim inputFileName As String = "MyArchive.zip" + Dim extractDir As String = "extract" + Dim buffer As Byte() = New Byte(2048) {} + Using raw As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read) + Using input As ZipInputStream = New ZipInputStream(raw) + Dim e As ZipEntry + Do While (Not e = input.GetNextEntry Is Nothing) + If Not e.IsDirectory Then + Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _ + FileMode.Create, FileAccess.ReadWrite) + Dim n As Integer + Do While (n = input.Read(buffer, 0, buffer.Length) > 0) + output.Write(buffer, 0, n) + Loop + End Using + End If + Loop + End Using + End Using + End Sub + + + + + + Create a ZipInputStream, given the name of an existing zip file. + + + + + + This constructor opens a FileStream for the given zipfile, and + wraps a ZipInputStream around that. See the documentation for the + constructor for full details. + + + + While the class is generally easier + to use, this class provides an alternative to those + applications that want to read from a zipfile directly, + using a . + + + + + + The name of the filesystem file to read. + + + + + This example shows how to read a zip file, and extract entries, using the + ZipInputStream class. + + + private void Unzip() + { + byte[] buffer= new byte[2048]; + int n; + using (var input= new ZipInputStream(inputFileName)) + { + ZipEntry e; + while (( e = input.GetNextEntry()) != null) + { + if (e.IsDirectory) continue; + string outputPath = Path.Combine(extractDir, e.FileName); + using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite)) + { + while ((n= input.Read(buffer, 0, buffer.Length)) > 0) + { + output.Write(buffer,0,n); + } + } + } + } + } + + + + Private Sub UnZip() + Dim inputFileName As String = "MyArchive.zip" + Dim extractDir As String = "extract" + Dim buffer As Byte() = New Byte(2048) {} + Using input As ZipInputStream = New ZipInputStream(inputFileName) + Dim e As ZipEntry + Do While (Not e = input.GetNextEntry Is Nothing) + If Not e.IsDirectory Then + Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _ + FileMode.Create, FileAccess.ReadWrite) + Dim n As Integer + Do While (n = input.Read(buffer, 0, buffer.Length) > 0) + output.Write(buffer, 0, n) + Loop + End Using + End If + Loop + End Using + End Sub + + + + + + Create a ZipInputStream, explicitly specifying whether to + keep the underlying stream open. + + + + See the documentation for the ZipInputStream(Stream) + constructor for a discussion of the class, and an example of how to use the class. + + + + The stream to read from. It must be readable. + + + + true if the application would like the stream + to remain open after the ZipInputStream has been closed. + + + + Provides a string representation of the instance. + + + This can be useful for debugging purposes. + + + a string representation of the instance. + + + + Read the data from the stream into the buffer. + + + + + The data for the zipentry will be decrypted and uncompressed, as + necessary, before being copied into the buffer. + + + + You must set the property before calling + Read() the first time for an encrypted entry. To determine if an + entry is encrypted and requires a password, check the ZipEntry.Encryption property. + + + + The buffer to hold the data read from the stream. + the offset within the buffer to copy the first byte read. + the number of bytes to read. + the number of bytes read, after decryption and decompression. + + + + Read the next entry from the zip file. + + + + + Call this method just before calling , + to position the pointer in the zip file to the next entry that can be + read. Subsequent calls to Read(), will decrypt and decompress the + data in the zip file, until Read() returns 0. + + + + Each time you call GetNextEntry(), the pointer in the wrapped + stream is moved to the next entry in the zip file. If you call , and thus re-position the pointer within + the file, you will need to call GetNextEntry() again, to insure + that the file pointer is positioned at the beginning of a zip entry. + + + + This method returns the ZipEntry. Using a stream approach, you will + read the raw bytes for an entry in a zip file via calls to Read(). + Alternatively, you can extract an entry into a file, or a stream, by + calling , or one of its siblings. + + + + + + The ZipEntry read. Returns null (or Nothing in VB) if there are no more + entries in the zip file. + + + + + + Dispose the stream. + + + + + This method disposes the ZipInputStream. It may also close the + underlying stream, depending on which constructor was used. + + + + Typically the application will call Dispose() implicitly, via + a using statement in C#, or a Using statement in VB. + + + + Application code won't call this code directly. This method may + be invoked in two distinct scenarios. If disposing == true, the + method has been called directly or indirectly by a user's code, + for example via the public Dispose() method. In this case, both + managed and unmanaged resources can be referenced and disposed. + If disposing == false, the method has been called by the runtime + from inside the object finalizer and this method should not + reference other objects; in that case only unmanaged resources + must be referenced or disposed. + + + + + true if the Dispose method was invoked by user code. + + + + + This is a no-op. + + + + + This method always throws a NotSupportedException. + + ignored + ignored + ignored + + + + This method seeks in the underlying stream. + + + + + Call this method if you want to seek around within the zip file for random access. + + + + Applications can intermix calls to Seek() with calls to . After a call to Seek(), + GetNextEntry() will get the next ZipEntry that falls after + the current position in the input stream. You're on your own for finding + out just where to seek in the stream, to get to the various entries. + + + + + the offset point to seek to + the reference point from which to seek + The new position + + + + This method always throws a NotSupportedException. + + ignored + + + + The text encoding to use when reading entries into the zip archive, for + those entries whose filenames or comments cannot be encoded with the + default (IBM437) encoding. + + + + + In its + zip specification, PKWare describes two options for encoding + filenames and comments: using IBM437 or UTF-8. But, some archiving tools + or libraries do not follow the specification, and instead encode + characters using the system default code page. For example, WinRAR when + run on a machine in Shanghai may encode filenames with the Big-5 Chinese + (950) code page. This behavior is contrary to the Zip specification, but + it occurs anyway. + + + + When using DotNetZip to read zip archives that use something other than + UTF-8 or IBM437, set this property to specify the code page to use when + reading encoded filenames and comments for each ZipEntry in the zip + file. + + + + This property is "provisional". When the entry in the zip archive is not + explicitly marked as using UTF-8, then IBM437 is used to decode filenames + and comments. If a loss of data would result from using IBM436 - + specifically when encoding and decoding is not reflexive - the codepage + specified here is used. It is possible, therefore, to have a given entry + with a Comment encoded in IBM437 and a FileName encoded with + the specified "provisional" codepage. + + + + When a zip file uses an arbitrary, non-UTF8 code page for encoding, there + is no standard way for the reader application - whether DotNetZip, WinZip, + WinRar, or something else - to know which codepage has been used for the + entries. Readers of zip files are not able to inspect the zip file and + determine the codepage that was used for the entries contained within it. + It is left to the application or user to determine the necessary codepage + when reading zip files encoded this way. If you use an incorrect codepage + when reading a zipfile, you will get entries with filenames that are + incorrect, and the incorrect filenames may even contain characters that + are not legal for use within filenames in Windows. Extracting entries with + illegal characters in the filenames will lead to exceptions. It's too bad, + but this is just the way things are with code pages in zip files. Caveat + Emptor. + + + + + + + Size of the work buffer to use for the ZLIB codec during decompression. + + + + Setting this affects the performance and memory efficiency of compression + and decompression. For larger files, setting this to a larger size may + improve performance, but the exact numbers vary depending on available + memory, and a bunch of other variables. I don't have good firm + recommendations on how to set it. You'll have to test it yourself. Or + just leave it alone and accept the default. + + + + + Sets the password to be used on the ZipInputStream instance. + + + + + + When reading a zip archive, this password is used to read and decrypt the + entries that are encrypted within the zip file. When entries within a zip + file use different passwords, set the appropriate password for the entry + before the first call to Read() for each entry. + + + + When reading an entry that is not encrypted, the value of this property is + ignored. + + + + + + + This example uses the ZipInputStream to read and extract entries from a + zip file, using a potentially different password for each entry. + + + byte[] buffer= new byte[2048]; + int n; + using (var raw = File.Open(_inputFileName, FileMode.Open, FileAccess.Read )) + { + using (var input= new ZipInputStream(raw)) + { + ZipEntry e; + while (( e = input.GetNextEntry()) != null) + { + input.Password = PasswordForEntry(e.FileName); + if (e.IsDirectory) continue; + string outputPath = Path.Combine(_extractDir, e.FileName); + using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite)) + { + while ((n= input.Read(buffer,0,buffer.Length)) > 0) + { + output.Write(buffer,0,n); + } + } + } + } + } + + + + + + + Always returns true. + + + + + Returns the value of CanSeek for the underlying (wrapped) stream. + + + + + Always returns false. + + + + + Returns the length of the underlying stream. + + + + + Gets or sets the position of the underlying stream. + + + Setting the position is equivalent to calling Seek(value, SeekOrigin.Begin). + + + + + Sort-of like a factory method, ForUpdate is used only when + the application needs to update the zip entry metadata for + a segmented zip file, when the starting segment is earlier + than the ending segment, for a particular entry. + + + + The update is always contiguous, never rolls over. As a + result, this method doesn't need to return a ZSS; it can + simply return a FileStream. That's why it's "sort of" + like a Factory method. + + + Caller must Close/Dispose the stream object returned by + this method. + + + + + + Read from the stream + + the buffer to read + the offset at which to start + the number of bytes to read + the number of bytes actually read + + + + Write to the stream. + + the buffer from which to write + the offset at which to start writing + the number of bytes to write + + + + Name of the filesystem file corresponding to the current segment. + + + + The name is not always the name currently being used in the + filesystem. When rwMode is RwMode.Write, the filesystem file has a + temporary name until the stream is closed or until the next segment is + started. + + + + + + This class exposes a set of COM-accessible wrappers for static + methods available on the ZipFile class. You don't need this + class unless you are using DotNetZip from a COM environment. + + + + + A wrapper for ZipFile.IsZipFile(string) + + The filename to of the zip file to check. + true if the file contains a valid zip file. + + + + A wrapper for ZipFile.IsZipFile(string, bool) + + + We cannot use "overloaded" Method names in COM interop. + So, here, we use a unique name. + + The filename to of the zip file to check. + true if the file contains a valid zip file. + + + + A wrapper for ZipFile.CheckZip(string) + + The filename to of the zip file to check. + + true if the named zip file checks OK. Otherwise, false. + + + + A COM-friendly wrapper for the static method . + + + The filename to of the zip file to check. + + The password to check. + + true if the named zip file checks OK. Otherwise, false. + + + + A wrapper for ZipFile.FixZipDirectory(string) + + The filename to of the zip file to fix. + + + + A wrapper for ZipFile.LibraryVersion + + + the version number on the DotNetZip assembly, formatted as a string. + + + + + An enum providing the options when an error occurs during opening or reading + of a file or directory that is being saved to a zip file. + + + + + This enum describes the actions that the library can take when an error occurs + opening or reading a file, as it is being saved into a Zip archive. + + + + In some cases an error will occur when DotNetZip tries to open a file to be + added to the zip archive. In other cases, an error might occur after the + file has been successfully opened, while DotNetZip is reading the file. + + + + The first problem might occur when calling AddDirectory() on a directory + that contains a Clipper .dbf file; the file is locked by Clipper and + cannot be opened by another process. An example of the second problem is + the ERROR_LOCK_VIOLATION that results when a file is opened by another + process, but not locked, and a range lock has been taken on the file. + Microsoft Outlook takes range locks on .PST files. + + + + + + Throw an exception when an error occurs while zipping. This is the default + behavior. (For COM clients, this is a 0 (zero).) + + + + + When an error occurs during zipping, for example a file cannot be opened, + skip the file causing the error, and continue zipping. (For COM clients, + this is a 1.) + + + + + When an error occurs during zipping, for example a file cannot be opened, + retry the operation that caused the error. Be careful with this option. If + the error is not temporary, the library will retry forever. (For COM + clients, this is a 2.) + + + + + When an error occurs, invoke the zipError event. The event type used is + . A typical use of this option: + a GUI application may wish to pop up a dialog to allow the user to view the + error that occurred, and choose an appropriate action. After your + processing in the error event, if you want to skip the file, set on the + ZipProgressEventArgs.CurrentEntry to Skip. If you want the + exception to be thrown, set ZipErrorAction on the CurrentEntry + to Throw. If you want to cancel the zip, set + ZipProgressEventArgs.Cancel to true. Cancelling differs from using + Skip in that a cancel will not save any further entries, if there are any. + (For COM clients, the value of this enum is a 3.) + + + + + An enum that provides the various encryption algorithms supported by this + library. + + + + + + PkzipWeak implies the use of Zip 2.0 encryption, which is known to be + weak and subvertible. + + + + A note on interoperability: Values of PkzipWeak and None are + specified in PKWARE's zip + specification, and are considered to be "standard". Zip archives + produced using these options will be interoperable with many other zip tools + and libraries, including Windows Explorer. + + + + Values of WinZipAes128 and WinZipAes256 are not part of the Zip + specification, but rather imply the use of a vendor-specific extension from + WinZip. If you want to produce interoperable Zip archives, do not use these + values. For example, if you produce a zip archive using WinZipAes256, you + will be able to open it in Windows Explorer on Windows XP and Vista, but you + will not be able to extract entries; trying this will lead to an "unspecified + error". For this reason, some people have said that a zip archive that uses + WinZip's AES encryption is not actually a zip archive at all. A zip archive + produced this way will be readable with the WinZip tool (Version 11 and + beyond). + + + + There are other third-party tools and libraries, both commercial and + otherwise, that support WinZip's AES encryption. These will be able to read + AES-encrypted zip archives produced by DotNetZip, and conversely applications + that use DotNetZip to read zip archives will be able to read AES-encrypted + archives produced by those tools or libraries. Consult the documentation for + those other tools and libraries to find out if WinZip's AES encryption is + supported. + + + + In case you care: According to the WinZip specification, the + actual AES key used is derived from the via an + algorithm that complies with RFC 2898, using an iteration + count of 1000. The algorithm is sometimes referred to as PBKDF2, which stands + for "Password Based Key Derivation Function #2". + + + + A word about password strength and length: The AES encryption technology is + very good, but any system is only as secure as the weakest link. If you want + to secure your data, be sure to use a password that is hard to guess. To make + it harder to guess (increase its "entropy"), you should make it longer. If + you use normal characters from an ASCII keyboard, a password of length 20 will + be strong enough that it will be impossible to guess. For more information on + that, I'd encourage you to read this + article. + + + + The WinZip AES algorithms are not supported with the version of DotNetZip that + runs on the .NET Compact Framework. This is because .NET CF lacks the + HMACSHA1 class that is required for producing the archive. + + + + + + No encryption at all. + + + + + Traditional or Classic pkzip encryption. + + + + + WinZip AES encryption (128 key bits). + + + + + WinZip AES encryption (256 key bits). + + + + + An encryption algorithm that is not supported by DotNetZip. + + + + + An enum for the options when extracting an entry would overwrite an existing file. + + + + + This enum describes the actions that the library can take when an + Extract() or ExtractWithPassword() method is called to extract an + entry to a filesystem, and the extraction would overwrite an existing filesystem + file. + + + + + + + Throw an exception when extraction would overwrite an existing file. (For + COM clients, this is a 0 (zero).) + + + + + When extraction would overwrite an existing file, overwrite the file silently. + The overwrite will happen even if the target file is marked as read-only. + (For COM clients, this is a 1.) + + + + + When extraction would overwrite an existing file, don't overwrite the file, silently. + (For COM clients, this is a 2.) + + + + + When extraction would overwrite an existing file, invoke the ExtractProgress + event, using an event type of . In + this way, the application can decide, just-in-time, whether to overwrite the + file. For example, a GUI application may wish to pop up a dialog to allow + the user to choose. You may want to examine the property before making + the decision. If, after your processing in the Extract progress event, you + want to NOT extract the file, set + on the ZipProgressEventArgs.CurrentEntry to DoNotOverwrite. + If you do want to extract the file, set ZipEntry.ExtractExistingFile + to OverwriteSilently. If you want to cancel the Extraction, set + ZipProgressEventArgs.Cancel to true. Cancelling differs from using + DoNotOverwrite in that a cancel will not extract any further entries, if + there are any. (For COM clients, the value of this enum is a 3.) + + + + + Enumerates the options for a logical conjunction. This enum is intended for use + internally by the FileSelector class. + + + + + FileSelector encapsulates logic that selects files from a source - a zip file + or the filesystem - based on a set of criteria. This class is used internally + by the DotNetZip library, in particular for the AddSelectedFiles() methods. + This class can also be used independently of the zip capability in DotNetZip. + + + + + + The FileSelector class is used internally by the ZipFile class for selecting + files for inclusion into the ZipFile, when the method, or one of + its overloads, is called. It's also used for the methods. Typically, an + application that creates or manipulates Zip archives will not directly + interact with the FileSelector class. + + + + Some applications may wish to use the FileSelector class directly, to + select files from disk volumes based on a set of criteria, without creating or + querying Zip archives. The file selection criteria include: a pattern to + match the filename; the last modified, created, or last accessed time of the + file; the size of the file; and the attributes of the file. + + + + Consult the documentation for + for more information on specifying the selection criteria. + + + + + + + Constructor that allows the caller to specify file selection criteria. + + + + + This constructor allows the caller to specify a set of criteria for + selection of files. + + + + See for a description of + the syntax of the selectionCriteria string. + + + + By default the FileSelector will traverse NTFS Reparse Points. To + change this, use FileSelector(String, bool). + + + + The criteria for file selection. + + + + Constructor that allows the caller to specify file selection criteria. + + + + + This constructor allows the caller to specify a set of criteria for + selection of files. + + + + See for a description of + the syntax of the selectionCriteria string. + + + + The criteria for file selection. + + whether to traverse NTFS reparse points (junctions). + + + + + Returns a string representation of the FileSelector object. + + The string representation of the boolean logic statement of the file + selection criteria for this instance. + + + + Returns the names of the files in the specified directory + that fit the selection criteria specified in the FileSelector. + + + + This is equivalent to calling + with recurseDirectories = false. + + + + The name of the directory over which to apply the FileSelector + criteria. + + + + A collection of strings containing fully-qualified pathnames of files + that match the criteria specified in the FileSelector instance. + + + + + Returns the names of the files in the specified directory that fit the + selection criteria specified in the FileSelector, optionally recursing + through subdirectories. + + + + This method applies the file selection criteria contained in the + FileSelector to the files contained in the given directory, and + returns the names of files that conform to the criteria. + + + + The name of the directory over which to apply the FileSelector + criteria. + + + + Whether to recurse through subdirectories when applying the file + selection criteria. + + + + A collection of strings containing fully-qualified pathnames of files + that match the criteria specified in the FileSelector instance. + + + + + Retrieve the ZipEntry items in the ZipFile that conform to the specified criteria. + + + + + This method applies the criteria set in the FileSelector instance (as described in + the ) to the specified ZipFile. Using this + method, for example, you can retrieve all entries from the given ZipFile that + have filenames ending in .txt. + + + + Normally, applications would not call this method directly. This method is used + by the ZipFile class. + + + + Using the appropriate SelectionCriteria, you can retrieve entries based on size, + time, and attributes. See for a + description of the syntax of the SelectionCriteria string. + + + + + The ZipFile from which to retrieve entries. + + a collection of ZipEntry objects that conform to the criteria. + + + + Retrieve the ZipEntry items in the ZipFile that conform to the specified criteria. + + + + + This method applies the criteria set in the FileSelector instance (as described in + the ) to the specified ZipFile. Using this + method, for example, you can retrieve all entries from the given ZipFile that + have filenames ending in .txt. + + + + Normally, applications would not call this method directly. This method is used + by the ZipFile class. + + + + This overload allows the selection of ZipEntry instances from the ZipFile to be restricted + to entries contained within a particular directory in the ZipFile. + + + + Using the appropriate SelectionCriteria, you can retrieve entries based on size, + time, and attributes. See for a + description of the syntax of the SelectionCriteria string. + + + + + The ZipFile from which to retrieve entries. + + + the directory in the archive from which to select entries. If null, then + all directories in the archive are used. + + + a collection of ZipEntry objects that conform to the criteria. + + + + The string specifying which files to include when retrieving. + + + + + Specify the criteria in statements of 3 elements: a noun, an operator, + and a value. Consider the string "name != *.doc" . The noun is + "name". The operator is "!=", implying "Not Equal". The value is + "*.doc". That criterion, in English, says "all files with a name that + does not end in the .doc extension." + + + + Supported nouns include "name" (or "filename") for the filename; + "atime", "mtime", and "ctime" for last access time, last modfied time, + and created time of the file, respectively; "attributes" (or "attrs") + for the file attributes; "size" (or "length") for the file length + (uncompressed); and "type" for the type of object, either a file or a + directory. The "attributes", "type", and "name" nouns all support = + and != as operators. The "size", "atime", "mtime", and "ctime" nouns + support = and !=, and >, >=, <, <= as well. The times are + taken to be expressed in local time. + + + + Specify values for the file attributes as a string with one or more of + the characters H,R,S,A,I,L in any order, implying file attributes of + Hidden, ReadOnly, System, Archive, NotContextIndexed, and ReparsePoint + (symbolic link) respectively. + + + + To specify a time, use YYYY-MM-DD-HH:mm:ss or YYYY/MM/DD-HH:mm:ss as + the format. If you omit the HH:mm:ss portion, it is assumed to be + 00:00:00 (midnight). + + + + The value for a size criterion is expressed in integer quantities of + bytes, kilobytes (use k or kb after the number), megabytes (m or mb), + or gigabytes (g or gb). + + + + The value for a name is a pattern to match against the filename, + potentially including wildcards. The pattern follows CMD.exe glob + rules: * implies one or more of any character, while ? implies one + character. If the name pattern contains any slashes, it is matched to + the entire filename, including the path; otherwise, it is matched + against only the filename without the path. This means a pattern of + "*\*.*" matches all files one directory level deep, while a pattern of + "*.*" matches all files in all directories. + + + + To specify a name pattern that includes spaces, use single quotes + around the pattern. A pattern of "'* *.*'" will match all files that + have spaces in the filename. The full criteria string for that would + be "name = '* *.*'" . + + + + The value for a type criterion is either F (implying a file) or D + (implying a directory). + + + + Some examples: + + + + + criteria + Files retrieved + + + + name != *.xls + any file with an extension that is not .xls + + + + + name = *.mp3 + any file with a .mp3 extension. + + + + + *.mp3 + (same as above) any file with a .mp3 extension. + + + + + attributes = A + all files whose attributes include the Archive bit. + + + + + attributes != H + all files whose attributes do not include the Hidden bit. + + + + + mtime > 2009-01-01 + all files with a last modified time after January 1st, 2009. + + + + + ctime > 2009/01/01-03:00:00 + all files with a created time after 3am (local time), + on January 1st, 2009. + + + + + size > 2gb + all files whose uncompressed size is greater than 2gb. + + + + + type = D + all directories in the filesystem. + + + + + + You can combine criteria with the conjunctions AND, OR, and XOR. Using + a string like "name = *.txt AND size >= 100k" for the + selectionCriteria retrieves entries whose names end in .txt, and whose + uncompressed size is greater than or equal to 100 kilobytes. + + + + For more complex combinations of criteria, you can use parenthesis to + group clauses in the boolean logic. Absent parenthesis, the + precedence of the criterion atoms is determined by order of + appearance. Unlike the C# language, the AND conjunction does not take + precendence over the logical OR. This is important only in strings + that contain 3 or more criterion atoms. In other words, "name = *.txt + and size > 1000 or attributes = H" implies "((name = *.txt AND size + > 1000) OR attributes = H)" while "attributes = H OR name = *.txt + and size > 1000" evaluates to "((attributes = H OR name = *.txt) + AND size > 1000)". When in doubt, use parenthesis. + + + + Using time properties requires some extra care. If you want to + retrieve all entries that were last updated on 2009 February 14, + specify "mtime >= 2009-02-14 AND mtime < 2009-02-15". Read this + to say: all files updated after 12:00am on February 14th, until + 12:00am on February 15th. You can use the same bracketing approach to + specify any time period - a year, a month, a week, and so on. + + + + The syntax allows one special case: if you provide a string with no + spaces, it is treated as a pattern to match for the filename. + Therefore a string like "*.xls" will be equivalent to specifying "name + = *.xls". This "shorthand" notation does not work with compound + criteria. + + + + There is no logic in this class that insures that the inclusion + criteria are internally consistent. For example, it's possible to + specify criteria that says the file must have a size of less than 100 + bytes, as well as a size that is greater than 1000 bytes. Obviously + no file will ever satisfy such criteria, but this class does not check + for or detect such inconsistencies. + + + + + + Thrown in the setter if the value has an invalid syntax. + + + + + Indicates whether searches will traverse NTFS reparse points, like Junctions. + + + + + Summary description for EnumUtil. + + + + + Returns the value of the DescriptionAttribute if the specified Enum + value has one. If not, returns the ToString() representation of the + Enum value. + + The Enum to get the description for + + + + + Converts the string representation of the name or numeric value of one + or more enumerated constants to an equivalent enumerated object. + Note: use the DescriptionAttribute on enum values to enable this. + + The System.Type of the enumeration. + + A string containing the name or value to convert. + + + + + + Converts the string representation of the name or numeric value of one + or more enumerated constants to an equivalent enumerated object. A + parameter specified whether the operation is case-sensitive. Note: + use the DescriptionAttribute on enum values to enable this. + + The System.Type of the enumeration. + + A string containing the name or value to convert. + + + Whether the operation is case-sensitive or not. + + + + + This is a helper class supporting WinZip AES encryption. + This class is intended for use only by the DotNetZip library. + + + + Most uses of the DotNetZip library will not involve direct calls into + the WinZipAesCrypto class. Instead, the WinZipAesCrypto class is + instantiated and used by the ZipEntry() class when WinZip AES + encryption or decryption on an entry is employed. + + + + + A stream that encrypts as it writes, or decrypts as it reads. The + Crypto is AES in CTR (counter) mode, which is compatible with the AES + encryption employed by WinZip 12.0. + + + + The AES/CTR encryption protocol used by WinZip works like this: + + - start with a counter, initialized to zero. + + - to encrypt, take the data by 16-byte blocks. For each block: + - apply the transform to the counter + - increement the counter + - XOR the result of the transform with the plaintext to + get the ciphertext. + - compute the mac on the encrypted bytes + - when finished with all blocks, store the computed MAC. + + - to decrypt, take the data by 16-byte blocks. For each block: + - compute the mac on the encrypted bytes, + - apply the transform to the counter + - increement the counter + - XOR the result of the transform with the ciphertext to + get the plaintext. + - when finished with all blocks, compare the computed MAC against + the stored MAC + + + + + + + The constructor. + + The underlying stream + To either encrypt or decrypt. + The pre-initialized WinZipAesCrypto object. + The maximum number of bytes to read from the stream. + + + + Close the stream. + + + + + Flush the content in the stream. + + + + + This method throws a NotImplementedException. + + + + + This method throws a NotImplementedException. + + + + + Returns the final HMAC-SHA1-80 for the data that was encrypted. + + + + + Returns true if the stream can be read. + + + + + Always returns false. + + + + + Returns true if the CryptoMode is Encrypt. + + + + + Getting this property throws a NotImplementedException. + + + + + Getting or Setting this property throws a NotImplementedException. + + + + + Issued when an ZipEntry.ExtractWithPassword() method is invoked + with an incorrect password. + + + + + Base class for all exceptions defined by and throw by the Zip library. + + + + + Default ctor. + + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + The innerException for this exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The serialization info for the exception. + The streaming context from which to deserialize. + + + + Default ctor. + + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + The innerException for this exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The serialization info for the exception. + The streaming context from which to deserialize. + + + + Indicates that a read was attempted on a stream, and bad or incomplete data was + received. + + + + + Default ctor. + + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + The innerException for this exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The serialization info for the exception. + The streaming context from which to deserialize. + + + + Issued when an CRC check fails upon extracting an entry from a zip archive. + + + + + Default ctor. + + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The serialization info for the exception. + The streaming context from which to deserialize. + + + + Issued when errors occur saving a self-extracting archive. + + + + + Default ctor. + + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The serialization info for the exception. + The streaming context from which to deserialize. + + + + Indicates that an operation was attempted on a ZipFile which was not possible + given the state of the instance. For example, if you call Save() on a ZipFile + which has no filename set, you can get this exception. + + + + + Default ctor. + + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The message in the exception. + The innerException for this exception. + + + + Come on, you know how exceptions work. Why are you looking at this documentation? + + The serialization info for the exception. + The streaming context from which to deserialize. + + + + Collects general purpose utility methods. + + + + private null constructor + + + + Utility routine for transforming path names from filesystem format (on Windows that means backslashes) to + a format suitable for use within zipfiles. This means trimming the volume letter and colon (if any) And + swapping backslashes for forward slashes. + + source path. + transformed path + + + + Finds a signature in the zip stream. This is useful for finding + the end of a zip entry, for example, or the beginning of the next ZipEntry. + + + + + Scans through 64k at a time. + + + + If the method fails to find the requested signature, the stream Position + after completion of this method is unchanged. If the method succeeds in + finding the requested signature, the stream position after completion is + direct AFTER the signature found in the stream. + + + + The stream to search + The 4-byte signature to find + The number of bytes read + + + + Create a pseudo-random filename, suitable for use as a temporary + file, and open it. + + + + The System.IO.Path.GetRandomFileName() method is not available on + the Compact Framework, so this library provides its own substitute + on NETCF. + + + This method produces a filename of the form + DotNetZip-xxxxxxxx.tmp, where xxxxxxxx is replaced by randomly + chosen characters, and creates that file. + + + + + + Workitem 7889: handle ERROR_LOCK_VIOLATION during read + + + This could be gracefully handled with an extension attribute, but + This assembly is built for .NET 2.0, so I cannot use them. + + + + + A decorator stream. It wraps another stream, and performs bookkeeping + to keep track of the stream Position. + + + + In some cases, it is not possible to get the Position of a stream, let's + say, on a write-only output stream like ASP.NET's + Response.OutputStream, or on a different write-only stream + provided as the destination for the zip by the application. In this + case, programmers can use this counting stream to count the bytes read + or written. + + + Consider the scenario of an application that saves a self-extracting + archive (SFX), that uses a custom SFX stub. + + + Saving to a filesystem file, the application would open the + filesystem file (getting a FileStream), save the custom sfx stub + into it, and then call ZipFile.Save(), specifying the same + FileStream. ZipFile.Save() does the right thing for the zipentry + offsets, by inquiring the Position of the FileStream before writing + any data, and then adding that initial offset into any ZipEntry + offsets in the zip directory. Everything works fine. + + + Now suppose the application is an ASPNET application and it saves + directly to Response.OutputStream. It's not possible for DotNetZip to + inquire the Position, so the offsets for the SFX will be wrong. + + + The workaround is for the application to use this class to wrap + HttpResponse.OutputStream, then write the SFX stub and the ZipFile + into that wrapper stream. Because ZipFile.Save() can inquire the + Position, it will then do the right thing with the offsets. + + + + + + The constructor. + + The underlying stream + + + + Adjust the byte count on the stream. + + + + the number of bytes to subtract from the count. + + + + + Subtract delta from the count of bytes written to the stream. + This is necessary when seeking back, and writing additional data, + as happens in some cases when saving Zip files. + + + + + + The read method. + + The buffer to hold the data read from the stream. + the offset within the buffer to copy the first byte read. + the number of bytes to read. + the number of bytes read, after decryption and decompression. + + + + Write data into the stream. + + The buffer holding data to write to the stream. + the offset within that data array to find the first byte to write. + the number of bytes to write. + + + + Flushes the underlying stream. + + + + + Seek in the stream. + + the offset point to seek to + the reference point from which to seek + The new position + + + + Set the length of the underlying stream. Be careful with this! + + + the length to set on the underlying stream. + + + + Gets the wrapped stream. + + + + + The count of bytes written out to the stream. + + + + + the count of bytes that have been read from the stream. + + + + + Whether the stream can be read. + + + + + Whether it is possible to call Seek() on the stream. + + + + + Whether it is possible to call Write() on the stream. + + + + + The length of the underlying stream. + + + + + Returns the sum of number of bytes written, plus the initial + offset before writing. + + + + + The Position of the stream. + + + + + This class implements the "traditional" or "classic" PKZip encryption, + which today is considered to be weak. On the other hand it is + ubiquitous. This class is intended for use only by the DotNetZip + library. + + + + Most uses of the DotNetZip library will not involve direct calls into + the ZipCrypto class. Instead, the ZipCrypto class is instantiated and + used by the ZipEntry() class when encryption or decryption on an entry + is employed. If for some reason you really wanted to use a weak + encryption algorithm in some other application, you might use this + library. But you would be much better off using one of the built-in + strong encryption libraries in the .NET Framework, like the AES + algorithm or SHA. + + + + + The default constructor for ZipCrypto. + + + + This class is intended for internal use by the library only. It's + probably not useful to you. Seriously. Stop reading this + documentation. It's a waste of your time. Go do something else. + Check the football scores. Go get an ice cream with a friend. + Seriously. + + + + + + Call this method on a cipher text to render the plaintext. You must + first initialize the cipher with a call to InitCipher. + + + + + var cipher = new ZipCrypto(); + cipher.InitCipher(Password); + // Decrypt the header. This has a side effect of "further initializing the + // encryption keys" in the traditional zip encryption. + byte[] DecryptedMessage = cipher.DecryptMessage(EncryptedMessage); + + + + The encrypted buffer. + + The number of bytes to encrypt. + Should be less than or equal to CipherText.Length. + + + The plaintext. + + + + This is the converse of DecryptMessage. It encrypts the plaintext + and produces a ciphertext. + + + The plain text buffer. + + + The number of bytes to encrypt. + Should be less than or equal to plainText.Length. + + + The ciphertext. + + + + This initializes the cipher with the given password. + See AppNote.txt for details. + + + + The passphrase for encrypting or decrypting with this cipher. + + + + + Step 1 - Initializing the encryption keys + ----------------------------------------- + Start with these keys: + Key(0) := 305419896 (0x12345678) + Key(1) := 591751049 (0x23456789) + Key(2) := 878082192 (0x34567890) + + Then, initialize the keys with a password: + + loop for i from 0 to length(password)-1 + update_keys(password(i)) + end loop + + Where update_keys() is defined as: + + update_keys(char): + Key(0) := crc32(key(0),char) + Key(1) := Key(1) + (Key(0) bitwiseAND 000000ffH) + Key(1) := Key(1) * 134775813 + 1 + Key(2) := crc32(key(2),key(1) rightshift 24) + end update_keys + + Where crc32(old_crc,char) is a routine that given a CRC value and a + character, returns an updated CRC value after applying the CRC-32 + algorithm described elsewhere in this document. + + + + + After the keys are initialized, then you can use the cipher to + encrypt the plaintext. + + + + Essentially we encrypt the password with the keys, then discard the + ciphertext for the password. This initializes the keys for later use. + + + + + + + From AppNote.txt: + unsigned char decrypt_byte() + local unsigned short temp + temp :=- Key(2) | 2 + decrypt_byte := (temp * (temp ^ 1)) bitshift-right 8 + end decrypt_byte + + + + + A Stream for reading and concurrently decrypting data from a zip file, + or for writing and concurrently encrypting data to a zip file. + + + + The constructor. + The underlying stream + To either encrypt or decrypt. + The pre-initialized ZipCrypto object. + + + + Delegate in which the application writes the ZipEntry content for the named entry. + + + The name of the entry that must be written. + The stream to which the entry data should be written. + + + When you add an entry and specify a WriteDelegate, via , the application + code provides the logic that writes the entry data directly into the zip file. + + + + + This example shows how to define a WriteDelegate that obtains a DataSet, and then + writes the XML for the DataSet into the zip archive. There's no need to + save the XML to a disk file first. + + + private void WriteEntry (String filename, Stream output) + { + DataSet ds1 = ObtainDataSet(); + ds1.WriteXml(output); + } + + private void Run() + { + using (var zip = new ZipFile()) + { + zip.AddEntry(zipEntryName, WriteEntry); + zip.Save(zipFileName); + } + } + + + + Private Sub WriteEntry (ByVal filename As String, ByVal output As Stream) + DataSet ds1 = ObtainDataSet() + ds1.WriteXml(stream) + End Sub + + Public Sub Run() + Using zip = New ZipFile + zip.AddEntry(zipEntryName, New WriteDelegate(AddressOf WriteEntry)) + zip.Save(zipFileName) + End Using + End Sub + + + + + + + Delegate in which the application opens the stream, just-in-time, for the named entry. + + + + The name of the ZipEntry that the application should open the stream for. + + + + When you add an entry via , the application code provides the logic that + opens and closes the stream for the given ZipEntry. + + + + + + + Delegate in which the application closes the stream, just-in-time, for the named entry. + + + + The name of the ZipEntry that the application should close the stream for. + + + The stream to be closed. + + + When you add an entry via , the application code provides the logic that + opens and closes the stream for the given ZipEntry. + + + + + + + Delegate for the callback by which the application tells the + library the CompressionLevel to use for a file. + + + + + Using this callback, the application can, for example, specify that + previously-compressed files (.mp3, .png, .docx, etc) should use a + CompressionLevel of None, or can set the compression level based + on any other factor. + + + + + + + In an EventArgs type, indicates which sort of progress event is being + reported. + + + There are events for reading, events for saving, and events for + extracting. This enumeration allows a single EventArgs type to be sued to + describe one of multiple subevents. For example, a SaveProgress event is + invoked before, after, and during the saving of a single entry. The value + of an enum with this type, specifies which event is being triggered. The + same applies to Extraction, Reading and Adding events. + + + + + Indicates that a Add() operation has started. + + + + + Indicates that an individual entry in the archive has been added. + + + + + Indicates that a Add() operation has completed. + + + + + Indicates that a Read() operation has started. + + + + + Indicates that an individual entry in the archive is about to be read. + + + + + Indicates that an individual entry in the archive has just been read. + + + + + Indicates that a Read() operation has completed. + + + + + The given event reports the number of bytes read so far + during a Read() operation. + + + + + Indicates that a Save() operation has started. + + + + + Indicates that an individual entry in the archive is about to be written. + + + + + Indicates that an individual entry in the archive has just been saved. + + + + + Indicates that a Save() operation has completed. + + + + + Indicates that the zip archive has been created in a + temporary location during a Save() operation. + + + + + Indicates that the temporary file is about to be renamed to the final archive + name during a Save() operation. + + + + + Indicates that the temporary file is has just been renamed to the final archive + name during a Save() operation. + + + + + Indicates that the self-extracting archive has been compiled + during a Save() operation. + + + + + The given event is reporting the number of source bytes that have run through the compressor so far + during a Save() operation. + + + + + Indicates that an entry is about to be extracted. + + + + + Indicates that an entry has just been extracted. + + + + + Indicates that extraction of an entry would overwrite an existing + filesystem file. You must use + + ExtractExistingFileAction.InvokeExtractProgressEvent in the call + to ZipEntry.Extract() in order to receive this event. + + + + + The given event is reporting the number of bytes written so far for + the current entry during an Extract() operation. + + + + + Indicates that an ExtractAll operation is about to begin. + + + + + Indicates that an ExtractAll operation has completed. + + + + + Indicates that an error has occurred while saving a zip file. + This generally means the file cannot be opened, because it has been + removed, or because it is locked by another process. It can also + mean that the file cannot be Read, because of a range lock conflict. + + + + + Provides information about the progress of a save, read, or extract operation. + This is a base class; you will probably use one of the classes derived from this one. + + + + + The total number of entries to be saved or extracted. + + + + + The name of the last entry saved or extracted. + + + + + In an event handler, set this to cancel the save or extract + operation that is in progress. + + + + + The type of event being reported. + + + + + Returns the archive name associated to this event. + + + + + The number of bytes read or written so far for this entry. + + + + + Total number of bytes that will be read or written for this entry. + This number will be -1 if the value cannot be determined. + + + + + Provides information about the progress of a Read operation. + + + + + Provides information about the progress of a Add operation. + + + + + Provides information about the progress of a save operation. + + + + + Constructor for the SaveProgressEventArgs. + + the name of the zip archive. + whether this is before saving the entry, or after + The total number of entries in the zip archive. + Number of entries that have been saved. + The entry involved in the event. + + + + Number of entries saved so far. + + + + + Provides information about the progress of the extract operation. + + + + + Constructor for the ExtractProgressEventArgs. + + the name of the zip archive. + whether this is before saving the entry, or after + The total number of entries in the zip archive. + Number of entries that have been extracted. + The entry involved in the event. + The location to which entries are extracted. + + + + Number of entries extracted so far. This is set only if the + EventType is Extracting_BeforeExtractEntry or Extracting_AfterExtractEntry, and + the Extract() is occurring witin the scope of a call to ExtractAll(). + + + + + Returns the extraction target location, a filesystem path. + + + + + Provides information about the an error that occurred while zipping. + + + + + Returns the exception that occurred, if any. + + + + + Returns the name of the file that caused the exception, if any. + + + + + Represents a single entry in a ZipFile. Typically, applications get a ZipEntry + by enumerating the entries within a ZipFile, or by adding an entry to a ZipFile. + + + + + Reads one entry from the zip directory structure in the zip file. + + + + The zipfile for which a directory entry will be read. From this param, the + method gets the ReadStream and the expected text encoding + (ProvisionalAlternateEncoding) which is used if the entry is not marked + UTF-8. + + + + a list of previously seen entry names; used to prevent duplicates. + + + the entry read from the archive. + + + + Returns true if the passed-in value is a valid signature for a ZipDirEntry. + + the candidate 4-byte signature value. + true, if the signature is valid according to the PKWare spec. + + + + Default constructor. + + + Applications should never need to call this directly. It is exposed to + support COM Automation environments. + + + + + Sets the NTFS Creation, Access, and Modified times for the given entry. + + + + + When adding an entry from a file or directory, the Creation, Access, and + Modified times for the given entry are automatically set from the + filesystem values. When adding an entry from a stream or string, the + values are implicitly set to DateTime.Now. The application may wish to + set these values to some arbitrary value, before saving the archive, and + can do so using the various setters. If you want to set all of the times, + this method is more efficient. + + + + The values you set here will be retrievable with the , and properties. + + + + When this method is called, if both and are false, then the + EmitTimesInWindowsFormatWhenSaving flag is automatically set. + + + + DateTime values provided here without a DateTimeKind are assumed to be Local Time. + + + + the creation time of the entry. + the last access time of the entry. + the last modified time of the entry. + + + + + + + + + Provides a string representation of the instance. + a string representation of the instance. + + + + Extract the entry to the filesystem, starting at the current + working directory. + + + + This method has a bunch of overloads! One of them is sure to + be the right one for you... If you don't like these, check + out the ExtractWithPassword() methods. + + + + + + + + + This method extracts an entry from a zip file into the current + working directory. The path of the entry as extracted is the full + path as specified in the zip archive, relative to the current + working directory. After the file is extracted successfully, the + file attributes and timestamps are set. + + + + The action taken when extraction an entry would overwrite an + existing file is determined by the property. + + + + Within the call to Extract(), the content for the entry is + written into a filesystem file, and then the last modified time of the + file is set according to the property on + the entry. See the remarks the property for + some details about the last modified time. + + + + + + + Extract the entry to a file in the filesystem, using the specified + behavior when extraction would overwrite an existing file. + + + + + See the remarks on the property, for some + details about how the last modified time of the file is set after + extraction. + + + + + The action to take if extraction would overwrite an existing file. + + + + + Extracts the entry to the specified stream. + + + + + The caller can specify any write-able stream, for example a , a , or ASP.NET's + Response.OutputStream. The content will be decrypted and + decompressed as necessary. If the entry is encrypted and no password + is provided, this method will throw. + + + The position on the stream is not reset by this method before it extracts. + You may want to call stream.Seek() before calling ZipEntry.Extract(). + + + + + the stream to which the entry should be extracted. + + + + + + Extract the entry to the filesystem, starting at the specified base + directory. + + + the pathname of the base directory + + + + + + This example extracts only the entries in a zip file that are .txt files, + into a directory called "textfiles". + + using (ZipFile zip = ZipFile.Read("PackedDocuments.zip")) + { + foreach (string s1 in zip.EntryFilenames) + { + if (s1.EndsWith(".txt")) + { + zip[s1].Extract("textfiles"); + } + } + } + + + Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip") + Dim s1 As String + For Each s1 In zip.EntryFilenames + If s1.EndsWith(".txt") Then + zip(s1).Extract("textfiles") + End If + Next + End Using + + + + + + + Using this method, existing entries in the filesystem will not be + overwritten. If you would like to force the overwrite of existing + files, see the property, or call + . + + + + See the remarks on the property, for some + details about how the last modified time of the created file is set. + + + + + + Extract the entry to the filesystem, starting at the specified base + directory, and using the specified behavior when extraction would + overwrite an existing file. + + + + + See the remarks on the property, for some + details about how the last modified time of the created file is set. + + + + + + String sZipPath = "Airborne.zip"; + String sFilePath = "Readme.txt"; + String sRootFolder = "Digado"; + using (ZipFile zip = ZipFile.Read(sZipPath)) + { + if (zip.EntryFileNames.Contains(sFilePath)) + { + // use the string indexer on the zip file + zip[sFileName].Extract(sRootFolder, + ExtractExistingFileAction.OverwriteSilently); + } + } + + + + Dim sZipPath as String = "Airborne.zip" + Dim sFilePath As String = "Readme.txt" + Dim sRootFolder As String = "Digado" + Using zip As ZipFile = ZipFile.Read(sZipPath) + If zip.EntryFileNames.Contains(sFilePath) + ' use the string indexer on the zip file + zip(sFilePath).Extract(sRootFolder, _ + ExtractExistingFileAction.OverwriteSilently) + End If + End Using + + + + the pathname of the base directory + + The action to take if extraction would overwrite an existing file. + + + + + Extract the entry to the filesystem, using the current working directory + and the specified password. + + + + This method has a bunch of overloads! One of them is sure to be + the right one for you... + + + + + + + + + Existing entries in the filesystem will not be overwritten. If you + would like to force the overwrite of existing files, see the property, or call + . + + + + See the remarks on the property for some + details about how the "last modified" time of the created file is + set. + + + + + In this example, entries that use encryption are extracted using a + particular password. + + using (var zip = ZipFile.Read(FilePath)) + { + foreach (ZipEntry e in zip) + { + if (e.UsesEncryption) + e.ExtractWithPassword("Secret!"); + else + e.Extract(); + } + } + + + Using zip As ZipFile = ZipFile.Read(FilePath) + Dim e As ZipEntry + For Each e In zip + If (e.UsesEncryption) + e.ExtractWithPassword("Secret!") + Else + e.Extract + End If + Next + End Using + + + The Password to use for decrypting the entry. + + + + Extract the entry to the filesystem, starting at the specified base + directory, and using the specified password. + + + + + + + + Existing entries in the filesystem will not be overwritten. If you + would like to force the overwrite of existing files, see the property, or call + . + + + + See the remarks on the property, for some + details about how the last modified time of the created file is set. + + + + The pathname of the base directory. + The Password to use for decrypting the entry. + + + + Extract the entry to a file in the filesystem, relative to the + current directory, using the specified behavior when extraction + would overwrite an existing file. + + + + + See the remarks on the property, for some + details about how the last modified time of the created file is set. + + + + The Password to use for decrypting the entry. + + + The action to take if extraction would overwrite an existing file. + + + + + Extract the entry to the filesystem, starting at the specified base + directory, and using the specified behavior when extraction would + overwrite an existing file. + + + + See the remarks on the property, for some + details about how the last modified time of the created file is set. + + + the pathname of the base directory + + The action to take if extraction would + overwrite an existing file. + + The Password to use for decrypting the entry. + + + + Extracts the entry to the specified stream, using the specified + Password. For example, the caller could extract to Console.Out, or + to a MemoryStream. + + + + + The caller can specify any write-able stream, for example a , a , or ASP.NET's + Response.OutputStream. The content will be decrypted and + decompressed as necessary. If the entry is encrypted and no password + is provided, this method will throw. + + + The position on the stream is not reset by this method before it extracts. + You may want to call stream.Seek() before calling ZipEntry.Extract(). + + + + + + the stream to which the entry should be extracted. + + + The password to use for decrypting the entry. + + + + + Opens a readable stream corresponding to the zip entry in the + archive. The stream decompresses and decrypts as necessary, as it + is read. + + + + + + DotNetZip offers a variety of ways to extract entries from a zip + file. This method allows an application to extract an entry by + reading a . + + + + The return value is of type . Use it as you would any + stream for reading. When an application calls on that stream, it will + receive data from the zip entry that is decrypted and decompressed + as necessary. + + + + CrcCalculatorStream adds one additional feature: it keeps a + CRC32 checksum on the bytes of the stream as it is read. The CRC + value is available in the property on the + CrcCalculatorStream. When the read is complete, your + application + should check this CRC against the + property on the ZipEntry to validate the content of the + ZipEntry. You don't have to validate the entry using the CRC, but + you should, to verify integrity. Check the example for how to do + this. + + + + If the entry is protected with a password, then you need to provide + a password prior to calling , either by + setting the property on the entry, or the + property on the ZipFile + itself. Or, you can use , the + overload of OpenReader that accepts a password parameter. + + + + If you want to extract entry data into a write-able stream that is + already opened, like a , do not + use this method. Instead, use . + + + + Your application may use only one stream created by OpenReader() at + a time, and you should not call other Extract methods before + completing your reads on a stream obtained from OpenReader(). This + is because there is really only one source stream for the compressed + content. A call to OpenReader() seeks in the source stream, to the + beginning of the compressed content. A subsequent call to + OpenReader() on a different entry will seek to a different position + in the source stream, as will a call to Extract() or one of its + overloads. This will corrupt the state for the decompressing stream + from the original call to OpenReader(). + + + + The OpenReader() method works only when the ZipEntry is + obtained from an instance of ZipFile. This method will throw + an exception if the ZipEntry is obtained from a . + + + + + This example shows how to open a zip archive, then read in a named + entry via a stream. After the read loop is complete, the code + compares the calculated during the read loop with the expected CRC + on the ZipEntry, to verify the extraction. + + using (ZipFile zip = new ZipFile(ZipFileToRead)) + { + ZipEntry e1= zip["Elevation.mp3"]; + using (Ionic.Zlib.CrcCalculatorStream s = e1.OpenReader()) + { + byte[] buffer = new byte[4096]; + int n, totalBytesRead= 0; + do { + n = s.Read(buffer,0, buffer.Length); + totalBytesRead+=n; + } while (n>0); + if (s.Crc32 != e1.Crc32) + throw new Exception(string.Format("The Zip Entry failed the CRC Check. (0x{0:X8}!=0x{1:X8})", s.Crc32, e1.Crc32)); + if (totalBytesRead != e1.UncompressedSize) + throw new Exception(string.Format("We read an unexpected number of bytes. ({0}!={1})", totalBytesRead, e1.UncompressedSize)); + } + } + + + Using zip As New ZipFile(ZipFileToRead) + Dim e1 As ZipEntry = zip.Item("Elevation.mp3") + Using s As Ionic.Zlib.CrcCalculatorStream = e1.OpenReader + Dim n As Integer + Dim buffer As Byte() = New Byte(4096) {} + Dim totalBytesRead As Integer = 0 + Do + n = s.Read(buffer, 0, buffer.Length) + totalBytesRead = (totalBytesRead + n) + Loop While (n > 0) + If (s.Crc32 <> e1.Crc32) Then + Throw New Exception(String.Format("The Zip Entry failed the CRC Check. (0x{0:X8}!=0x{1:X8})", s.Crc32, e1.Crc32)) + End If + If (totalBytesRead <> e1.UncompressedSize) Then + Throw New Exception(String.Format("We read an unexpected number of bytes. ({0}!={1})", totalBytesRead, e1.UncompressedSize)) + End If + End Using + End Using + + + + The Stream for reading. + + + + Opens a readable stream for an encrypted zip entry in the archive. + The stream decompresses and decrypts as necessary, as it is read. + + + + + See the documentation on the method for + full details. This overload allows the application to specify a + password for the ZipEntry to be read. + + + + The password to use for decrypting the entry. + The Stream for reading. + + + + Validates that the args are consistent. + + + Only one of {baseDir, outStream} can be non-null. + If baseDir is non-null, then the outputFile is created. + + + + + Reads one ZipEntry from the given stream. The content for + the entry does not get decompressed or decrypted. This method + basically reads metadata, and seeks. + + the ZipContainer this entry belongs to. + + true of this is the first entry being read from the stream. + + the ZipEntry read from the stream. + + + + Finds a particular segment in the given extra field. + This is used when modifying a previously-generated + extra field, in particular when removing the AES crypto + segment in the extra field. + + + + + At current cursor position in the stream, read the extra + field, and set the properties on the ZipEntry instance + appropriately. This can be called when processing the + Extra field in the Central Directory, or in the local + header. + + + + + generate and return a byte array that encodes the filename + for the entry. + + + + side effects: generate and store into _CommentBytes the + byte array for any comment attached to the entry. Also + sets _actualEncoding to indicate the actual encoding + used. The same encoding is used for both filename and + comment. + + + + + + Stores the position of the entry source stream, or, if the position is + already stored, seeks to that position. + + + + + This method is called in prep for reading the source stream. If PKZIP + encryption is used, then we need to calc the CRC32 before doing the + encryption, because the CRC is used in the 12th byte of the PKZIP + encryption header. So, we need to be able to seek backward in the source + when saving the ZipEntry. This method is called from the place that + calculates the CRC, and also from the method that does the encryption of + the file data. + + + + The first time through, this method sets the _sourceStreamOriginalPosition + field. Subsequent calls to this method seek to that position. + + + + + + Copy metadata that may have been changed by the app. We do this when + resetting the zipFile instance. If the app calls Save() on a ZipFile, then + tries to party on that file some more, we may need to Reset() it , which + means re-reading the entries and then copying the metadata. I think. + + + + + Set the input stream and get its length, if possible. The length is + used for progress updates, AND, to allow an optimization in case of + a stream/file of zero length. In that case we skip the Encrypt and + compression Stream. (like DeflateStream or BZip2OutputStream) + + + + + Prepare the given stream for output - wrap it in a CountingStream, and + then in a CRC stream, and an encryptor and deflator as appropriate. + + + + Previously this was used in ZipEntry.Write(), but in an effort to + introduce some efficiencies in that method I've refactored to put the + code inline. This method still gets called by ZipOutputStream. + + + + + + True if the referenced entry is a directory. + + + + + Provides a human-readable string with information about the ZipEntry. + + + + + The time and date at which the file indicated by the ZipEntry was + last modified. + + + + + The DotNetZip library sets the LastModified value for an entry, equal to + the Last Modified time of the file in the filesystem. If an entry is + added from a stream, the library uses System.DateTime.Now for this + value, for the given entry. + + + + This property allows the application to retrieve and possibly set the + LastModified value on an entry, to an arbitrary value. values with a + setting of DateTimeKind.Unspecified are taken to be expressed as + DateTimeKind.Local. + + + + Be aware that because of the way PKWare's + Zip specification describes how times are stored in the zip file, + the full precision of the System.DateTime datatype is not stored + for the last modified time when saving zip files. For more information on + how times are formatted, see the PKZip specification. + + + + The actual last modified time of a file can be stored in multiple ways in + the zip file, and they are not mutually exclusive: + + + + + In the so-called "DOS" format, which has a 2-second precision. Values + are rounded to the nearest even second. For example, if the time on the + file is 12:34:43, then it will be stored as 12:34:44. This first value + is accessible via the LastModified property. This value is always + present in the metadata for each zip entry. In some cases the value is + invalid, or zero. + + + + In the so-called "Windows" or "NTFS" format, as an 8-byte integer + quantity expressed as the number of 1/10 milliseconds (in other words + the number of 100 nanosecond units) since January 1, 1601 (UTC). This + format is how Windows represents file times. This time is accessible + via the ModifiedTime property. + + + + In the "Unix" format, a 4-byte quantity specifying the number of seconds since + January 1, 1970 UTC. + + + + In an older format, now deprecated but still used by some current + tools. This format is also a 4-byte quantity specifying the number of + seconds since January 1, 1970 UTC. + + + + + + Zip tools and libraries will always at least handle (read or write) the + DOS time, and may also handle the other time formats. Keep in mind that + while the names refer to particular operating systems, there is nothing in + the time formats themselves that prevents their use on other operating + systems. + + + + When reading ZIP files, the DotNetZip library reads the Windows-formatted + time, if it is stored in the entry, and sets both LastModified and + ModifiedTime to that value. When writing ZIP files, the DotNetZip + library by default will write both time quantities. It can also emit the + Unix-formatted time if desired (See .) + + + + The last modified time of the file created upon a call to + ZipEntry.Extract() may be adjusted during extraction to compensate + for differences in how the .NET Base Class Library deals with daylight + saving time (DST) versus how the Windows filesystem deals with daylight + saving time. Raymond Chen provides + some good context. + + + + In a nutshell: Daylight savings time rules change regularly. In 2007, for + example, the inception week of DST changed. In 1977, DST was in place all + year round. In 1945, likewise. And so on. Win32 does not attempt to + guess which time zone rules were in effect at the time in question. It + will render a time as "standard time" and allow the app to change to DST + as necessary. .NET makes a different choice. + + + + Compare the output of FileInfo.LastWriteTime.ToString("f") with what you + see in the Windows Explorer property sheet for a file that was last + written to on the other side of the DST transition. For example, suppose + the file was last modified on October 17, 2003, during DST but DST is not + currently in effect. Explorer's file properties reports Thursday, October + 17, 2003, 8:45:38 AM, but .NETs FileInfo reports Thursday, October 17, + 2003, 9:45 AM. + + + + Win32 says, "Thursday, October 17, 2002 8:45:38 AM PST". Note: Pacific + STANDARD Time. Even though October 17 of that year occurred during Pacific + Daylight Time, Win32 displays the time as standard time because that's + what time it is NOW. + + + + .NET BCL assumes that the current DST rules were in place at the time in + question. So, .NET says, "Well, if the rules in effect now were also in + effect on October 17, 2003, then that would be daylight time" so it + displays "Thursday, October 17, 2003, 9:45 AM PDT" - daylight time. + + + + So .NET gives a value which is more intuitively correct, but is also + potentially incorrect, and which is not invertible. Win32 gives a value + which is intuitively incorrect, but is strictly correct. + + + + Because of this funkiness, this library adds one hour to the LastModified + time on the extracted file, if necessary. That is to say, if the time in + question had occurred in what the .NET Base Class Library assumed to be + DST. This assumption may be wrong given the constantly changing DST rules, + but it is the best we can do. + + + + + + + + Last Modified time for the file represented by the entry. + + + + + + This value corresponds to the "last modified" time in the NTFS file times + as described in the Zip + specification. When getting this property, the value may be + different from . When setting the property, + the property also gets set, but with a lower + precision. + + + + Let me explain. It's going to take a while, so get + comfortable. Originally, waaaaay back in 1989 when the ZIP specification + was originally described by the esteemed Mr. Phil Katz, the dominant + operating system of the time was MS-DOS. MSDOS stored file times with a + 2-second precision, because, c'mon, who is ever going to need better + resolution than THAT? And so ZIP files, regardless of the platform on + which the zip file was created, store file times in exactly the same format that DOS used + in 1989. + + + + Since then, the ZIP spec has evolved, but the internal format for file + timestamps remains the same. Despite the fact that the way times are + stored in a zip file is rooted in DOS heritage, any program on any + operating system can format a time in this way, and most zip tools and + libraries DO - they round file times to the nearest even second and store + it just like DOS did 25+ years ago. + + + + PKWare extended the ZIP specification to allow a zip file to store what + are called "NTFS Times" and "Unix(tm) times" for a file. These are the + last write, last access, and file creation + times of a particular file. These metadata are not actually specific + to NTFS or Unix. They are tracked for each file by NTFS and by various + Unix filesystems, but they are also tracked by other filesystems, too. + The key point is that the times are formatted in the zip file + in the same way that NTFS formats the time (ticks since win32 epoch), + or in the same way that Unix formats the time (seconds since Unix + epoch). As with the DOS time, any tool or library running on any + operating system is capable of formatting a time in one of these ways + and embedding it into the zip file. + + + + These extended times are higher precision quantities than the DOS time. + As described above, the (DOS) LastModified has a precision of 2 seconds. + The Unix time is stored with a precision of 1 second. The NTFS time is + stored with a precision of 0.0000001 seconds. The quantities are easily + convertible, except for the loss of precision you may incur. + + + + A zip archive can store the {C,A,M} times in NTFS format, in Unix format, + or not at all. Often a tool running on Unix or Mac will embed the times + in Unix format (1 second precision), while WinZip running on Windows might + embed the times in NTFS format (precision of of 0.0000001 seconds). When + reading a zip file with these "extended" times, in either format, + DotNetZip represents the values with the + ModifiedTime, AccessedTime and CreationTime + properties on the ZipEntry. + + + + While any zip application or library, regardless of the platform it + runs on, could use any of the time formats allowed by the ZIP + specification, not all zip tools or libraries do support all these + formats. Storing the higher-precision times for each entry is + optional for zip files, and many tools and libraries don't use the + higher precision quantities at all. The old DOS time, represented by + , is guaranteed to be present, though it + sometimes unset. + + + + Ok, getting back to the question about how the LastModified + property relates to this ModifiedTime + property... LastModified is always set, while + ModifiedTime is not. (The other times stored in the NTFS + times extension, CreationTime and AccessedTime also + may not be set on an entry that is read from an existing zip file.) + When reading a zip file, then LastModified takes the DOS time + that is stored with the file. If the DOS time has been stored as zero + in the zipfile, then this library will use DateTime.Now for the + LastModified value. If the ZIP file was created by an evolved + tool, then there will also be higher precision NTFS or Unix times in + the zip file. In that case, this library will read those times, and + set LastModified and ModifiedTime to the same value, the + one corresponding to the last write time of the file. If there are no + higher precision times stored for the entry, then ModifiedTime + remains unset (likewise AccessedTime and CreationTime), + and LastModified keeps its DOS time. + + + + When creating zip files with this library, by default the extended time + properties (ModifiedTime, AccessedTime, and + CreationTime) are set on the ZipEntry instance, and these data are + stored in the zip archive for each entry, in NTFS format. If you add an + entry from an actual filesystem file, then the entry gets the actual file + times for that file, to NTFS-level precision. If you add an entry from a + stream, or a string, then the times get the value DateTime.Now. In + this case LastModified and ModifiedTime will be identical, + to 2 seconds of precision. You can explicitly set the + CreationTime, AccessedTime, and ModifiedTime of an + entry using the property setters. If you want to set all of those + quantities, it's more efficient to use the method. Those + changes are not made permanent in the zip file until you call or one of its cousins. + + + + When creating a zip file, you can override the default behavior of + this library for formatting times in the zip file, disabling the + embedding of file times in NTFS format or enabling the storage of file + times in Unix format, or both. You may want to do this, for example, + when creating a zip file on Windows, that will be consumed on a Mac, + by an application that is not hip to the "NTFS times" format. To do + this, use the and + properties. A valid zip + file may store the file times in both formats. But, there are no + guarantees that a program running on Mac or Linux will gracefully + handle the NTFS-formatted times when Unix times are present, or that a + non-DotNetZip-powered application running on Windows will be able to + handle file times in Unix format. DotNetZip will always do something + reasonable; other libraries or tools may not. When in doubt, test. + + + + I'll bet you didn't think one person could type so much about time, eh? + And reading it was so enjoyable, too! Well, in appreciation, maybe you + should donate? + + + + + + + + + + + Last Access time for the file represented by the entry. + + + This value may or may not be meaningful. If the ZipEntry was read from an existing + Zip archive, this information may not be available. For an explanation of why, see + . + + + + + + + + The file creation time for the file represented by the entry. + + + + This value may or may not be meaningful. If the ZipEntry was read + from an existing zip archive, and the creation time was not set on the entry + when the zip file was created, then this property may be meaningless. For an + explanation of why, see . + + + + + + + + Specifies whether the Creation, Access, and Modified times for the given + entry will be emitted in "Windows format" when the zip archive is saved. + + + + + An application creating a zip archive can use this flag to explicitly + specify that the file times for the entry should or should not be stored + in the zip archive in the format used by Windows. The default value of + this property is true. + + + + When adding an entry from a file or directory, the Creation (), Access (), and Modified + () times for the given entry are automatically + set from the filesystem values. When adding an entry from a stream or + string, all three values are implicitly set to DateTime.Now. Applications + can also explicitly set those times by calling . + + + + PKWARE's + zip specification describes multiple ways to format these times in a + zip file. One is the format Windows applications normally use: 100ns ticks + since Jan 1, 1601 UTC. The other is a format Unix applications typically + use: seconds since January 1, 1970 UTC. Each format can be stored in an + "extra field" in the zip entry when saving the zip archive. The former + uses an extra field with a Header Id of 0x000A, while the latter uses a + header ID of 0x5455. + + + + Not all zip tools and libraries can interpret these fields. Windows + compressed folders is one that can read the Windows Format timestamps, + while I believe the Infozip + tools can read the Unix format timestamps. Although the time values are + easily convertible, subject to a loss of precision, some tools and + libraries may be able to read only one or the other. DotNetZip can read or + write times in either or both formats. + + + + The times stored are taken from , , and . + + + + This property is not mutually exclusive from the property. It is + possible that a zip entry can embed the timestamps in both forms, one + form, or neither. But, there are no guarantees that a program running on + Mac or Linux will gracefully handle NTFS Formatted times, or that a + non-DotNetZip-powered application running on Windows will be able to + handle file times in Unix format. When in doubt, test. + + + + Normally you will use the ZipFile.EmitTimesInWindowsFormatWhenSaving + property, to specify the behavior for all entries in a zip, rather than + the property on each individual entry. + + + + + + + + + + + + + Specifies whether the Creation, Access, and Modified times for the given + entry will be emitted in "Unix(tm) format" when the zip archive is saved. + + + + + An application creating a zip archive can use this flag to explicitly + specify that the file times for the entry should or should not be stored + in the zip archive in the format used by Unix. By default this flag is + false, meaning the Unix-format times are not stored in the zip + archive. + + + + When adding an entry from a file or directory, the Creation (), Access (), and Modified + () times for the given entry are automatically + set from the filesystem values. When adding an entry from a stream or + string, all three values are implicitly set to DateTime.Now. Applications + can also explicitly set those times by calling . + + + + PKWARE's + zip specification describes multiple ways to format these times in a + zip file. One is the format Windows applications normally use: 100ns ticks + since Jan 1, 1601 UTC. The other is a format Unix applications typically + use: seconds since Jan 1, 1970 UTC. Each format can be stored in an + "extra field" in the zip entry when saving the zip archive. The former + uses an extra field with a Header Id of 0x000A, while the latter uses a + header ID of 0x5455. + + + + Not all tools and libraries can interpret these fields. Windows + compressed folders is one that can read the Windows Format timestamps, + while I believe the Infozip + tools can read the Unix format timestamps. Although the time values are + easily convertible, subject to a loss of precision, some tools and + libraries may be able to read only one or the other. DotNetZip can read or + write times in either or both formats. + + + + The times stored are taken from , , and . + + + + This property is not mutually exclusive from the property. It is + possible that a zip entry can embed the timestamps in both forms, one + form, or neither. But, there are no guarantees that a program running on + Mac or Linux will gracefully handle NTFS Formatted times, or that a + non-DotNetZip-powered application running on Windows will be able to + handle file times in Unix format. When in doubt, test. + + + + Normally you will use the ZipFile.EmitTimesInUnixFormatWhenSaving + property, to specify the behavior for all entries, rather than the + property on each individual entry. + + + + + + + + + + + + + The type of timestamp attached to the ZipEntry. + + + + This property is valid only for a ZipEntry that was read from a zip archive. + It indicates the type of timestamp attached to the entry. + + + + + + + + The file attributes for the entry. + + + + + + The attributes in NTFS include + ReadOnly, Archive, Hidden, System, and Indexed. When adding a + ZipEntry to a ZipFile, these attributes are set implicitly when + adding an entry from the filesystem. When adding an entry from a stream + or string, the Attributes are not set implicitly. Regardless of the way + an entry was added to a ZipFile, you can set the attributes + explicitly if you like. + + + + When reading a ZipEntry from a ZipFile, the attributes are + set according to the data stored in the ZipFile. If you extract the + entry from the archive to a filesystem file, DotNetZip will set the + attributes on the resulting file accordingly. + + + + The attributes can be set explicitly by the application. For example the + application may wish to set the FileAttributes.ReadOnly bit for all + entries added to an archive, so that on unpack, this attribute will be set + on the extracted file. Any changes you make to this property are made + permanent only when you call a Save() method on the ZipFile + instance that contains the ZipEntry. + + + + For example, an application may wish to zip up a directory and set the + ReadOnly bit on every file in the archive, so that upon later extraction, + the resulting files will be marked as ReadOnly. Not every extraction tool + respects these attributes, but if you unpack with DotNetZip, as for + example in a self-extracting archive, then the attributes will be set as + they are stored in the ZipFile. + + + + These attributes may not be interesting or useful if the resulting archive + is extracted on a non-Windows platform. How these attributes get used + upon extraction depends on the platform and tool used. + + + + This property is only partially supported in the Silverlight version + of the library: applications can read attributes on entries within + ZipFiles. But extracting entries within Silverlight will not set the + attributes on the extracted files. + + + + + + + The name of the filesystem file, referred to by the ZipEntry. + + + + + This property specifies the thing-to-be-zipped on disk, and is set only + when the ZipEntry is being created from a filesystem file. If the + ZipFile is instantiated by reading an existing .zip archive, then + the LocalFileName will be null (Nothing in VB). + + + + When it is set, the value of this property may be different than , which is the path used in the archive itself. If you + call Zip.AddFile("foop.txt", AlternativeDirectory), then the path + used for the ZipEntry within the zip archive will be different + than this path. + + + + If the entry is being added from a stream, then this is null (Nothing in VB). + + + + + + + + The name of the file contained in the ZipEntry. + + + + + + This is the name of the entry in the ZipFile itself. When creating + a zip archive, if the ZipEntry has been created from a filesystem + file, via a call to or , or a related overload, the value + of this property is derived from the name of that file. The + FileName property does not include drive letters, and may include a + different directory path, depending on the value of the + directoryPathInArchive parameter used when adding the entry into + the ZipFile. + + + + In some cases there is no related filesystem file - for example when a + ZipEntry is created using or one of the similar overloads. In this case, the value of + this property is derived from the fileName and the directory path passed + to that method. + + + + When reading a zip file, this property takes the value of the entry name + as stored in the zip file. If you extract such an entry, the extracted + file will take the name given by this property. + + + + Applications can set this property when creating new zip archives or when + reading existing archives. When setting this property, the actual value + that is set will replace backslashes with forward slashes, in accordance + with the Zip + specification, for compatibility with Unix(tm) and ... get + this.... Amiga! + + + + If an application reads a ZipFile via or a related overload, and then explicitly + sets the FileName on an entry contained within the ZipFile, and + then calls , the application will effectively + rename the entry within the zip archive. + + + + If an application sets the value of FileName, then calls + Extract() on the entry, the entry is extracted to a file using the + newly set value as the filename. The FileName value is made + permanent in the zip archive only after a call to one of the + ZipFile.Save() methods on the ZipFile that contains the + ZipEntry. + + + + If an application attempts to set the FileName to a value that + would result in a duplicate entry in the ZipFile, an exception is + thrown. + + + + When a ZipEntry is contained within a ZipFile, applications + cannot rename the entry within the context of a foreach (For + Each in VB) loop, because of the way the ZipFile stores + entries. If you need to enumerate through all the entries and rename one + or more of them, use ZipFile.EntriesSorted as the + collection. See also, ZipFile.GetEnumerator(). + + + + + + + The stream that provides content for the ZipEntry. + + + + + + The application can use this property to set the input stream for an + entry on a just-in-time basis. Imagine a scenario where the application + creates a ZipFile comprised of content obtained from hundreds of + files, via calls to AddFile(). The DotNetZip library opens streams + on these files on a just-in-time basis, only when writing the entry out to + an external store within the scope of a ZipFile.Save() call. Only + one input stream is opened at a time, as each entry is being written out. + + + + Now imagine a different application that creates a ZipFile + with content obtained from hundreds of streams, added through . Normally the + application would supply an open stream to that call. But when large + numbers of streams are being added, this can mean many open streams at one + time, unnecessarily. + + + + To avoid this, call and specify delegates that open and close the stream at + the time of Save. + + + + + Setting the value of this property when the entry was not added from a + stream (for example, when the ZipEntry was added with or , or when the entry was added by + reading an existing zip archive) will throw an exception. + + + + + + + + A flag indicating whether the InputStream was provided Just-in-time. + + + + + + When creating a zip archive, an application can obtain content for one or + more of the ZipEntry instances from streams, using the method. At the time + of calling that method, the application can supply null as the value of + the stream parameter. By doing so, the application indicates to the + library that it will provide a stream for the entry on a just-in-time + basis, at the time one of the ZipFile.Save() methods is called and + the data for the various entries are being compressed and written out. + + + + In this case, the application can set the + property, typically within the SaveProgress event (event type: ) for that entry. + + + + The application will later want to call Close() and Dispose() on that + stream. In the SaveProgress event, when the event type is , the application can + do so. This flag indicates that the stream has been provided by the + application on a just-in-time basis and that it is the application's + responsibility to call Close/Dispose on that stream. + + + + + + + + An enum indicating the source of the ZipEntry. + + + + + The version of the zip engine needed to read the ZipEntry. + + + + + This is a readonly property, indicating the version of the Zip + specification that the extracting tool or library must support to + extract the given entry. Generally higher versions indicate newer + features. Older zip engines obviously won't know about new features, and + won't be able to extract entries that depend on those newer features. + + + + + value + Features + + + + 20 + a basic Zip Entry, potentially using PKZIP encryption. + + + + + 45 + The ZIP64 extension is used on the entry. + + + + + 46 + File is compressed using BZIP2 compression* + + + + 50 + File is encrypted using PkWare's DES, 3DES, (broken) RC2 or RC4 + + + + 51 + File is encrypted using PKWare's AES encryption or corrected RC2 encryption. + + + + 52 + File is encrypted using corrected RC2-64 encryption** + + + + 61 + File is encrypted using non-OAEP key wrapping*** + + + + 63 + File is compressed using LZMA, PPMd+, Blowfish, or Twofish + + + + + + There are other values possible, not listed here. DotNetZip supports + regular PKZip encryption, and ZIP64 extensions. DotNetZip cannot extract + entries that require a zip engine higher than 45. + + + + This value is set upon reading an existing zip file, or after saving a zip + archive. + + + + + + The comment attached to the ZipEntry. + + + + + Each entry in a zip file can optionally have a comment associated to + it. The comment might be displayed by a zip tool during extraction, for + example. + + + + By default, the Comment is encoded in IBM437 code page. You can + specify an alternative with and + . + + + + + + + + Indicates whether the entry requires ZIP64 extensions. + + + + + + This property is null (Nothing in VB) until a Save() method on the + containing instance has been called. The property is + non-null (HasValue is true) only after a Save() method has + been called. + + + + After the containing ZipFile has been saved, the Value of this + property is true if any of the following three conditions holds: the + uncompressed size of the entry is larger than 0xFFFFFFFF; the compressed + size of the entry is larger than 0xFFFFFFFF; the relative offset of the + entry within the zip archive is larger than 0xFFFFFFFF. These quantities + are not known until a Save() is attempted on the zip archive and + the compression is applied. + + + + If none of the three conditions holds, then the Value is false. + + + + A Value of false does not indicate that the entry, as saved in the + zip archive, does not use ZIP64. It merely indicates that ZIP64 is + not required. An entry may use ZIP64 even when not required if + the property on the containing + ZipFile instance is set to , or if + the property on the containing + ZipFile instance is set to + and the output stream was not seekable. + + + + + + + + Indicates whether the entry actually used ZIP64 extensions, as it was most + recently written to the output file or stream. + + + + + + This Nullable property is null (Nothing in VB) until a Save() + method on the containing instance has been + called. HasValue is true only after a Save() method has been + called. + + + + The value of this property for a particular ZipEntry may change + over successive calls to Save() methods on the containing ZipFile, + even if the file that corresponds to the ZipEntry does not. This + may happen if other entries contained in the ZipFile expand, + causing the offset for this particular entry to exceed 0xFFFFFFFF. + + + + + + + The bitfield for the entry as defined in the zip spec. You probably + never need to look at this. + + + + + You probably do not need to concern yourself with the contents of this + property, but in case you do: + + + + + bit + meaning + + + + 0 + set if encryption is used. + + + + 1-2 + + set to determine whether normal, max, fast deflation. DotNetZip library + always leaves these bits unset when writing (indicating "normal" + deflation"), but can read an entry with any value here. + + + + + 3 + + Indicates that the Crc32, Compressed and Uncompressed sizes are zero in the + local header. This bit gets set on an entry during writing a zip file, when + it is saved to a non-seekable output stream. + + + + + + 4 + reserved for "enhanced deflating". This library doesn't do enhanced deflating. + + + + 5 + set to indicate the zip is compressed patched data. This library doesn't do that. + + + + 6 + + set if PKWare's strong encryption is used (must also set bit 1 if bit 6 is + set). This bit is not set if WinZip's AES encryption is set. + + + + 7 + not used + + + + 8 + not used + + + + 9 + not used + + + + 10 + not used + + + + 11 + + Language encoding flag (EFS). If this bit is set, the filename and comment + fields for this file must be encoded using UTF-8. This library currently + does not support UTF-8. + + + + + 12 + Reserved by PKWARE for enhanced compression. + + + + 13 + + Used when encrypting the Central Directory to indicate selected data + values in the Local Header are masked to hide their actual values. See + the section in the Zip + specification describing the Strong Encryption Specification for + details. + + + + + 14 + Reserved by PKWARE. + + + + 15 + Reserved by PKWARE. + + + + + + + + + The compression method employed for this ZipEntry. + + + + + + The + Zip specification allows a variety of compression methods. This + library supports just two: 0x08 = Deflate. 0x00 = Store (no compression), + for reading or writing. + + + + When reading an entry from an existing zipfile, the value you retrieve + here indicates the compression method used on the entry by the original + creator of the zip. When writing a zipfile, you can specify either 0x08 + (Deflate) or 0x00 (None). If you try setting something else, you will get + an exception. + + + + You may wish to set CompressionMethod to CompressionMethod.None (0) + when zipping already-compressed data like a jpg, png, or mp3 file. + This can save time and cpu cycles. + + + + When setting this property on a ZipEntry that is read from an + existing zip file, calling ZipFile.Save() will cause the new + CompressionMethod to be used on the entry in the newly saved zip file. + + + + Setting this property may have the side effect of modifying the + CompressionLevel property. If you set the CompressionMethod to a + value other than None, and CompressionLevel is previously + set to None, then CompressionLevel will be set to + Default. + + + + + + + In this example, the first entry added to the zip archive uses the default + behavior - compression is used where it makes sense. The second entry, + the MP3 file, is added to the archive without being compressed. + + using (ZipFile zip = new ZipFile(ZipFileToCreate)) + { + ZipEntry e1= zip.AddFile(@"notes\Readme.txt"); + ZipEntry e2= zip.AddFile(@"music\StopThisTrain.mp3"); + e2.CompressionMethod = CompressionMethod.None; + zip.Save(); + } + + + + Using zip As New ZipFile(ZipFileToCreate) + zip.AddFile("notes\Readme.txt") + Dim e2 as ZipEntry = zip.AddFile("music\StopThisTrain.mp3") + e2.CompressionMethod = CompressionMethod.None + zip.Save + End Using + + + + + + Sets the compression level to be used for the entry when saving the zip + archive. This applies only for CompressionMethod = DEFLATE. + + + + + When using the DEFLATE compression method, Varying the compression + level used on entries can affect the size-vs-speed tradeoff when + compression and decompressing data streams or files. + + + + If you do not set this property, the default compression level is used, + which normally gives a good balance of compression efficiency and + compression speed. In some tests, using BestCompression can + double the time it takes to compress, while delivering just a small + increase in compression efficiency. This behavior will vary with the + type of data you compress. If you are in doubt, just leave this setting + alone, and accept the default. + + + + When setting this property on a ZipEntry that is read from an + existing zip file, calling ZipFile.Save() will cause the new + CompressionLevel to be used on the entry in the newly saved zip file. + + + + Setting this property may have the side effect of modifying the + CompressionMethod property. If you set the CompressionLevel + to a value other than None, CompressionMethod will be set + to Deflate, if it was previously None. + + + + Setting this property has no effect if the CompressionMethod is something + other than Deflate or None. + + + + + + + + The compressed size of the file, in bytes, within the zip archive. + + + + When reading a ZipFile, this value is read in from the existing + zip file. When creating or updating a ZipFile, the compressed + size is computed during compression. Therefore the value on a + ZipEntry is valid after a call to Save() (or one of its + overloads) in that case. + + + + + + + The size of the file, in bytes, before compression, or after extraction. + + + + When reading a ZipFile, this value is read in from the existing + zip file. When creating or updating a ZipFile, the uncompressed + size is computed during compression. Therefore the value on a + ZipEntry is valid after a call to Save() (or one of its + overloads) in that case. + + + + + + + The ratio of compressed size to uncompressed size of the ZipEntry. + + + + + This is a ratio of the compressed size to the uncompressed size of the + entry, expressed as a double in the range of 0 to 100+. A value of 100 + indicates no compression at all. It could be higher than 100 when the + compression algorithm actually inflates the data, as may occur for small + files, or uncompressible data that is encrypted. + + + + You could format it for presentation to a user via a format string of + "{3,5:F0}%" to see it as a percentage. + + + + If the size of the original uncompressed file is 0, implying a + denominator of 0, the return value will be zero. + + + + This property is valid after reading in an existing zip file, or after + saving the ZipFile that contains the ZipEntry. You cannot know the + effect of a compression transform until you try it. + + + + + + + The 32-bit CRC (Cyclic Redundancy Check) on the contents of the ZipEntry. + + + + + You probably don't need to concern yourself with this. It is used + internally by DotNetZip to verify files or streams upon extraction. + + The value is a 32-bit + CRC using 0xEDB88320 for the polynomial. This is the same CRC-32 used in + PNG, MPEG-2, and other protocols and formats. It is a read-only property; when + creating a Zip archive, the CRC for each entry is set only after a call to + Save() on the containing ZipFile. When reading an existing zip file, the value + of this property reflects the stored CRC for the entry. + + + + + + True if the entry is a directory (not a file). + This is a readonly property on the entry. + + + + + A derived property that is true if the entry uses encryption. + + + + + This is a readonly property on the entry. When reading a zip file, + the value for the ZipEntry is determined by the data read + from the zip file. After saving a ZipFile, the value of this + property for each ZipEntry indicates whether encryption was + actually used (which will have been true if the was set and the property + was something other than . + + + + + + Set this to specify which encryption algorithm to use for the entry when + saving it to a zip archive. + + + + + + Set this property in order to encrypt the entry when the ZipFile is + saved. When setting this property, you must also set a on the entry. If you set a value other than on this property and do not set a + Password then the entry will not be encrypted. The ZipEntry + data is encrypted as the ZipFile is saved, when you call or one of its cousins on the containing + ZipFile instance. You do not need to specify the Encryption + when extracting entries from an archive. + + + + The Zip specification from PKWare defines a set of encryption algorithms, + and the data formats for the zip archive that support them, and PKWare + supports those algorithms in the tools it produces. Other vendors of tools + and libraries, such as WinZip or Xceed, typically support a + subset of the algorithms specified by PKWare. These tools can + sometimes support additional different encryption algorithms and data + formats, not specified by PKWare. The AES Encryption specified and + supported by WinZip is the most popular example. This library supports a + subset of the complete set of algorithms specified by PKWare and other + vendors. + + + + There is no common, ubiquitous multi-vendor standard for strong encryption + within zip files. There is broad support for so-called "traditional" Zip + encryption, sometimes called Zip 2.0 encryption, as specified + by PKWare, but this encryption is considered weak and + breakable. This library currently supports the Zip 2.0 "weak" encryption, + and also a stronger WinZip-compatible AES encryption, using either 128-bit + or 256-bit key strength. If you want DotNetZip to support an algorithm + that is not currently supported, call the author of this library and maybe + we can talk business. + + + + The class also has a property. In most cases you will use + that property when setting encryption. This property takes + precedence over any Encryption set on the ZipFile itself. + Typically, you would use the per-entry Encryption when most entries in the + zip archive use one encryption algorithm, and a few entries use a + different one. If all entries in the zip file use the same Encryption, + then it is simpler to just set this property on the ZipFile itself, when + creating a zip archive. + + + + Some comments on updating archives: If you read a ZipFile, you can + modify the Encryption on an encrypted entry: you can remove encryption + from an entry that was encrypted; you can encrypt an entry that was not + encrypted previously; or, you can change the encryption algorithm. The + changes in encryption are not made permanent until you call Save() on the + ZipFile. To effect changes in encryption, the entry content is + streamed through several transformations, depending on the modification + the application has requested. For example if the entry is not encrypted + and the application sets Encryption to PkzipWeak, then at + the time of Save(), the original entry is read and decompressed, + then re-compressed and encrypted. Conversely, if the original entry is + encrypted with PkzipWeak encryption, and the application sets the + Encryption property to WinZipAes128, then at the time of + Save(), the original entry is decrypted via PKZIP encryption and + decompressed, then re-compressed and re-encrypted with AES. This all + happens automatically within the library, but it can be time-consuming for + large entries. + + + + Additionally, when updating archives, it is not possible to change the + password when changing the encryption algorithm. To change both the + algorithm and the password, you need to Save() the zipfile twice. First + set the Encryption to None, then call Save(). Then set the + Encryption to the new value (not "None"), then call Save() + once again. + + + + The WinZip AES encryption algorithms are not supported on the .NET Compact + Framework. + + + + + + This example creates a zip archive that uses encryption, and then extracts + entries from the archive. When creating the zip archive, the ReadMe.txt + file is zipped without using a password or encryption. The other file + uses encryption. + + + // Create a zip archive with AES Encryption. + using (ZipFile zip = new ZipFile()) + { + zip.AddFile("ReadMe.txt") + ZipEntry e1= zip.AddFile("2008-Regional-Sales-Report.pdf"); + e1.Encryption= EncryptionAlgorithm.WinZipAes256; + e1.Password= "Top.Secret.No.Peeking!"; + zip.Save("EncryptedArchive.zip"); + } + + // Extract a zip archive that uses AES Encryption. + // You do not need to specify the algorithm during extraction. + using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) + { + // Specify the password that is used during extraction, for + // all entries that require a password: + zip.Password= "Top.Secret.No.Peeking!"; + zip.ExtractAll("extractDirectory"); + } + + + + ' Create a zip that uses Encryption. + Using zip As New ZipFile() + zip.AddFile("ReadMe.txt") + Dim e1 as ZipEntry + e1= zip.AddFile("2008-Regional-Sales-Report.pdf") + e1.Encryption= EncryptionAlgorithm.WinZipAes256 + e1.Password= "Top.Secret.No.Peeking!" + zip.Save("EncryptedArchive.zip") + End Using + + ' Extract a zip archive that uses AES Encryption. + ' You do not need to specify the algorithm during extraction. + Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) + ' Specify the password that is used during extraction, for + ' all entries that require a password: + zip.Password= "Top.Secret.No.Peeking!" + zip.ExtractAll("extractDirectory") + End Using + + + + + + Thrown in the setter if EncryptionAlgorithm.Unsupported is specified. + + + ZipEntry.Password + ZipFile.Encryption + + + + The Password to be used when encrypting a ZipEntry upon + ZipFile.Save(), or when decrypting an entry upon Extract(). + + + + + This is a write-only property on the entry. Set this to request that the + entry be encrypted when writing the zip archive, or set it to specify the + password to be used when extracting an existing entry that is encrypted. + + + + The password set here is implicitly used to encrypt the entry during the + operation, or to decrypt during the or operation. If you set + the Password on a ZipEntry after calling Save(), there is no + effect. + + + + Consider setting the property when using a + password. Answering concerns that the standard password protection + supported by all zip tools is weak, WinZip has extended the ZIP + specification with a way to use AES Encryption to protect entries in the + Zip file. Unlike the "PKZIP 2.0" encryption specified in the PKZIP + specification, AES + Encryption uses a standard, strong, tested, encryption + algorithm. DotNetZip can create zip archives that use WinZip-compatible + AES encryption, if you set the property. But, + archives created that use AES encryption may not be readable by all other + tools and libraries. For example, Windows Explorer cannot read a + "compressed folder" (a zip file) that uses AES encryption, though it can + read a zip file that uses "PKZIP encryption." + + + + The class also has a + property. This property takes precedence over any password set on the + ZipFile itself. Typically, you would use the per-entry Password when most + entries in the zip archive use one password, and a few entries use a + different password. If all entries in the zip file use the same password, + then it is simpler to just set this property on the ZipFile itself, + whether creating a zip archive or extracting a zip archive. + + + + Some comments on updating archives: If you read a ZipFile, you + cannot modify the password on any encrypted entry, except by extracting + the entry with the original password (if any), removing the original entry + via , and then adding a new + entry with a new Password. + + + + For example, suppose you read a ZipFile, and there is an encrypted + entry. Setting the Password property on that ZipEntry and then + calling Save() on the ZipFile does not update the password + on that entry in the archive. Neither is an exception thrown. Instead, + what happens during the Save() is the existing entry is copied + through to the new zip archive, in its original encrypted form. Upon + re-reading that archive, the entry can be decrypted with its original + password. + + + + If you read a ZipFile, and there is an un-encrypted entry, you can set the + Password on the entry and then call Save() on the ZipFile, and get + encryption on that entry. + + + + + + + This example creates a zip file with two entries, and then extracts the + entries from the zip file. When creating the zip file, the two files are + added to the zip file using password protection. Each entry uses a + different password. During extraction, each file is extracted with the + appropriate password. + + + // create a file with encryption + using (ZipFile zip = new ZipFile()) + { + ZipEntry entry; + entry= zip.AddFile("Declaration.txt"); + entry.Password= "123456!"; + entry = zip.AddFile("Report.xls"); + entry.Password= "1Secret!"; + zip.Save("EncryptedArchive.zip"); + } + + // extract entries that use encryption + using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) + { + ZipEntry entry; + entry = zip["Declaration.txt"]; + entry.Password = "123456!"; + entry.Extract("extractDir"); + entry = zip["Report.xls"]; + entry.Password = "1Secret!"; + entry.Extract("extractDir"); + } + + + + + Using zip As New ZipFile + Dim entry as ZipEntry + entry= zip.AddFile("Declaration.txt") + entry.Password= "123456!" + entry = zip.AddFile("Report.xls") + entry.Password= "1Secret!" + zip.Save("EncryptedArchive.zip") + End Using + + + ' extract entries that use encryption + Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) + Dim entry as ZipEntry + entry = zip("Declaration.txt") + entry.Password = "123456!" + entry.Extract("extractDir") + entry = zip("Report.xls") + entry.Password = "1Secret!" + entry.Extract("extractDir") + End Using + + + + + + + ZipFile.Password + + + + The action the library should take when extracting a file that already exists. + + + + + This property affects the behavior of the Extract methods (one of the + Extract() or ExtractWithPassword() overloads), when + extraction would would overwrite an existing filesystem file. If you do + not set this property, the library throws an exception when extracting + an entry would overwrite an existing file. + + + + This property has no effect when extracting to a stream, or when the file to be + extracted does not already exist. + + + + + + + This example shows how to set the ExtractExistingFile property in + an ExtractProgress event, in response to user input. The + ExtractProgress event is invoked if and only if the + ExtractExistingFile property was previously set to + ExtractExistingFileAction.InvokeExtractProgressEvent. + + public static void ExtractProgress(object sender, ExtractProgressEventArgs e) + { + if (e.EventType == ZipProgressEventType.Extracting_BeforeExtractEntry) + Console.WriteLine("extract {0} ", e.CurrentEntry.FileName); + + else if (e.EventType == ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite) + { + ZipEntry entry = e.CurrentEntry; + string response = null; + // Ask the user if he wants overwrite the file + do + { + Console.Write("Overwrite {0} in {1} ? (y/n/C) ", entry.FileName, e.ExtractLocation); + response = Console.ReadLine(); + Console.WriteLine(); + + } while (response != null && response[0]!='Y' && + response[0]!='N' && response[0]!='C'); + + if (response[0]=='C') + e.Cancel = true; + else if (response[0]=='Y') + entry.ExtractExistingFile = ExtractExistingFileAction.OverwriteSilently; + else + entry.ExtractExistingFile= ExtractExistingFileAction.DoNotOverwrite; + } + } + + + + + + The action to take when an error is encountered while + opening or reading files as they are saved into a zip archive. + + + + + Errors can occur within a call to ZipFile.Save, as the various files contained + in a ZipFile are being saved into the zip archive. During the + Save, DotNetZip will perform a File.Open on the file + associated to the ZipEntry, and then will read the entire contents of + the file as it is zipped. Either the open or the Read may fail, because + of lock conflicts or other reasons. Using this property, you can + specify the action to take when such errors occur. + + + + Typically you will NOT set this property on individual ZipEntry + instances. Instead, you will set the ZipFile.ZipErrorAction property on + the ZipFile instance, before adding any entries to the + ZipFile. If you do this, errors encountered on behalf of any of + the entries in the ZipFile will be handled the same way. + + + + But, if you use a handler, you will want + to set this property on the ZipEntry within the handler, to + communicate back to DotNetZip what you would like to do with the + particular error. + + + + + + + + + Indicates whether the entry was included in the most recent save. + + + An entry can be excluded or skipped from a save if there is an error + opening or reading the entry. + + + + + + A callback that allows the application to specify the compression to use + for a given entry that is about to be added to the zip archive. + + + + + See + + + + + + Set to indicate whether to use UTF-8 encoding for filenames and comments. + + + + + + If this flag is set, the comment and filename for the entry will be + encoded with UTF-8, as described in the Zip + specification, if necessary. "Necessary" means, the filename or + entry comment (if any) cannot be reflexively encoded and decoded using the + default code page, IBM437. + + + + Setting this flag to true is equivalent to setting to System.Text.Encoding.UTF8. + + + + This flag has no effect or relation to the text encoding used within the + file itself. + + + + + + + The text encoding to use for the FileName and Comment on this ZipEntry, + when the default encoding is insufficient. + + + + + + Don't use this property. See . + + + + + + + Specifies the alternate text encoding used by this ZipEntry + + + + The default text encoding used in Zip files for encoding filenames and + comments is IBM437, which is something like a superset of ASCII. In + cases where this is insufficient, applications can specify an + alternate encoding. + + + When creating a zip file, the usage of the alternate encoding is + governed by the property. + Typically you would set both properties to tell DotNetZip to employ an + encoding that is not IBM437 in the zipfile you are creating. + + + Keep in mind that because the ZIP specification states that the only + valid encodings to use are IBM437 and UTF-8, if you use something + other than that, then zip tools and libraries may not be able to + successfully read the zip archive you generate. + + + The zip specification states that applications should presume that + IBM437 is in use, except when a special bit is set, which indicates + UTF-8. There is no way to specify an arbitrary code page, within the + zip file itself. When you create a zip file encoded with gb2312 or + ibm861 or anything other than IBM437 or UTF-8, then the application + that reads the zip file needs to "know" which code page to use. In + some cases, the code page used when reading is chosen implicitly. For + example, WinRar uses the ambient code page for the host desktop + operating system. The pitfall here is that if you create a zip in + Copenhagen and send it to Tokyo, the reader of the zipfile may not be + able to decode successfully. + + + + This example shows how to create a zipfile encoded with a + language-specific encoding: + + using (var zip = new ZipFile()) + { + zip.AlternateEnoding = System.Text.Encoding.GetEncoding("ibm861"); + zip.AlternateEnodingUsage = ZipOption.Always; + zip.AddFileS(arrayOfFiles); + zip.Save("Myarchive-Encoded-in-IBM861.zip"); + } + + + + + + + Describes if and when this instance should apply + AlternateEncoding to encode the FileName and Comment, when + saving. + + + + + + Indicates whether an entry is marked as a text file. Be careful when + using on this property. Unless you have a good reason, you should + probably ignore this property. + + + + + The ZIP format includes a provision for specifying whether an entry in + the zip archive is a text or binary file. This property exposes that + metadata item. Be careful when using this property: It's not clear + that this property as a firm meaning, across tools and libraries. + + + + To be clear, when reading a zip file, the property value may or may + not be set, and its value may or may not be valid. Not all entries + that you may think of as "text" entries will be so marked, and entries + marked as "text" are not guaranteed in any way to be text entries. + Whether the value is set and set correctly depends entirely on the + application that produced the zip file. + + + + There are many zip tools available, and when creating zip files, some + of them "respect" the IsText metadata field, and some of them do not. + Unfortunately, even when an application tries to do "the right thing", + it's not always clear what "the right thing" is. + + + + There's no firm definition of just what it means to be "a text file", + and the zip specification does not help in this regard. Twenty years + ago, text was ASCII, each byte was less than 127. IsText meant, all + bytes in the file were less than 127. These days, it is not the case + that all text files have all bytes less than 127. Any unicode file + may have bytes that are above 0x7f. The zip specification has nothing + to say on this topic. Therefore, it's not clear what IsText really + means. + + + + This property merely tells a reading application what is stored in the + metadata for an entry, without guaranteeing its validity or its + meaning. + + + + When DotNetZip is used to create a zipfile, it attempts to set this + field "correctly." For example, if a file ends in ".txt", this field + will be set. Your application may override that default setting. When + writing a zip file, you must set the property before calling + Save() on the ZipFile. + + + + When reading a zip file, a more general way to decide just what kind + of file is contained in a particular entry is to use the file type + database stored in the operating system. The operating system stores + a table that says, a file with .jpg extension is a JPG image file, a + file with a .xml extension is an XML document, a file with a .txt is a + pure ASCII text document, and so on. To get this information on + Windows, you + need to read and parse the registry. + + + + + using (var zip = new ZipFile()) + { + var e = zip.UpdateFile("Descriptions.mme", ""); + e.IsText = true; + zip.Save(zipPath); + } + + + + Using zip As New ZipFile + Dim e2 as ZipEntry = zip.AddFile("Descriptions.mme", "") + e.IsText= True + zip.Save(zipPath) + End Using + + + + + + An enum that specifies the type of timestamp available on the ZipEntry. + + + + + + The last modified time of a file can be stored in multiple ways in + a zip file, and they are not mutually exclusive: + + + + + In the so-called "DOS" format, which has a 2-second precision. Values + are rounded to the nearest even second. For example, if the time on the + file is 12:34:43, then it will be stored as 12:34:44. This first value + is accessible via the LastModified property. This value is always + present in the metadata for each zip entry. In some cases the value is + invalid, or zero. + + + + In the so-called "Windows" or "NTFS" format, as an 8-byte integer + quantity expressed as the number of 1/10 milliseconds (in other words + the number of 100 nanosecond units) since January 1, 1601 (UTC). This + format is how Windows represents file times. This time is accessible + via the ModifiedTime property. + + + + In the "Unix" format, a 4-byte quantity specifying the number of seconds since + January 1, 1970 UTC. + + + + In an older format, now deprecated but still used by some current + tools. This format is also a 4-byte quantity specifying the number of + seconds since January 1, 1970 UTC. + + + + + + This bit field describes which of the formats were found in a ZipEntry that was read. + + + + + + + Default value. + + + + + A DOS timestamp with 2-second precision. + + + + + A Windows timestamp with 100-ns precision. + + + + + A Unix timestamp with 1-second precision. + + + + + A Unix timestamp with 1-second precision, stored in InfoZip v1 format. This + format is outdated and is supported for reading archives only. + + + + + The method of compression to use for a particular ZipEntry. + + + + PKWare's + ZIP Specification describes a number of distinct + cmopression methods that can be used within a zip + file. DotNetZip supports a subset of them. + + + + + No compression at all. For COM environments, the value is 0 (zero). + + + + + DEFLATE compression, as described in IETF RFC + 1951. This is the "normal" compression used in zip + files. For COM environments, the value is 8. + + + + + BZip2 compression, a compression algorithm developed by Julian Seward. + For COM environments, the value is 12. + + + + + The ZipFile type represents a zip archive file. + + + + + This is the main type in the DotNetZip class library. This class reads and + writes zip files, as defined in the specification + for zip files described by PKWare. The compression for this + implementation is provided by a managed-code version of Zlib, included with + DotNetZip in the classes in the Ionic.Zlib namespace. + + + + This class provides a general purpose zip file capability. Use it to read, + create, or update zip files. When you want to create zip files using a + Stream type to write the zip file, you may want to consider the class. + + + + Both the ZipOutputStream class and the ZipFile class can + be used to create zip files. Both of them support many of the common zip + features, including Unicode, different compression methods and levels, + and ZIP64. They provide very similar performance when creating zip + files. + + + + The ZipFile class is generally easier to use than + ZipOutputStream and should be considered a higher-level interface. For + example, when creating a zip file via calls to the PutNextEntry() and + Write() methods on the ZipOutputStream class, the caller is + responsible for opening the file, reading the bytes from the file, writing + those bytes into the ZipOutputStream, setting the attributes on the + ZipEntry, and setting the created, last modified, and last accessed + timestamps on the zip entry. All of these things are done automatically by a + call to ZipFile.AddFile(). + For this reason, the ZipOutputStream is generally recommended for use + only when your application emits arbitrary data, not necessarily data from a + filesystem file, directly into a zip file, and does so using a Stream + metaphor. + + + + Aside from the differences in programming model, there are other + differences in capability between the two classes. + + + + + ZipFile can be used to read and extract zip files, in addition to + creating zip files. ZipOutputStream cannot read zip files. If you want + to use a stream to read zip files, check out the class. + + + + ZipOutputStream does not support the creation of segmented or spanned + zip files. + + + + ZipOutputStream cannot produce a self-extracting archive. + + + + + Be aware that the ZipFile class implements the interface. In order for ZipFile to + produce a valid zip file, you use use it within a using clause (Using + in VB), or call the Dispose() method explicitly. See the examples + for how to employ a using clause. + + + + + + + Adds an item, either a file or a directory, to a zip file archive. + + + + + This method is handy if you are adding things to zip archive and don't + want to bother distinguishing between directories or files. Any files are + added as single entries. A directory added through this method is added + recursively: all files and subdirectories contained within the directory + are added to the ZipFile. + + + + The name of the item may be a relative path or a fully-qualified + path. Remember, the items contained in ZipFile instance get written + to the disk only when you call or a similar + save method. + + + + The directory name used for the file within the archive is the same + as the directory name (potentially a relative path) specified in the + . + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + + + This method has two overloads. + + the name of the file or directory to add. + + The ZipEntry added. + + + + Adds an item, either a file or a directory, to a zip file archive, + explicitly specifying the directory path to be used in the archive. + + + + + If adding a directory, the add is recursive on all files and + subdirectories contained within it. + + + The name of the item may be a relative path or a fully-qualified path. + The item added by this call to the ZipFile is not read from the + disk nor written to the zip file archive until the application calls + Save() on the ZipFile. + + + + This version of the method allows the caller to explicitly specify the + directory path to be used in the archive, which would override the + "natural" path of the filesystem file. + + + + Encryption will be used on the file data if the Password has + been set on the ZipFile object, prior to calling this method. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + Thrown if the file or directory passed in does not exist. + + + the name of the file or directory to add. + + + + The name of the directory path to use within the zip archive. This path + need not refer to an extant directory in the current filesystem. If the + files within the zip are later extracted, this is the path used for the + extracted file. Passing null (Nothing in VB) will use the + path on the fileOrDirectoryName. Passing the empty string ("") will + insert the item at the root path within the archive. + + + + + + + + This example shows how to zip up a set of files into a flat hierarchy, + regardless of where in the filesystem the files originated. The resulting + zip archive will contain a toplevel directory named "flat", which itself + will contain files Readme.txt, MyProposal.docx, and Image1.jpg. A + subdirectory under "flat" called SupportFiles will contain all the files + in the "c:\SupportFiles" directory on disk. + + + String[] itemnames= { + "c:\\fixedContent\\Readme.txt", + "MyProposal.docx", + "c:\\SupportFiles", // a directory + "images\\Image1.jpg" + }; + + try + { + using (ZipFile zip = new ZipFile()) + { + for (int i = 1; i < itemnames.Length; i++) + { + // will add Files or Dirs, recurses and flattens subdirectories + zip.AddItem(itemnames[i],"flat"); + } + zip.Save(ZipToCreate); + } + } + catch (System.Exception ex1) + { + System.Console.Error.WriteLine("exception: {0}", ex1); + } + + + + Dim itemnames As String() = _ + New String() { "c:\fixedContent\Readme.txt", _ + "MyProposal.docx", _ + "SupportFiles", _ + "images\Image1.jpg" } + Try + Using zip As New ZipFile + Dim i As Integer + For i = 1 To itemnames.Length - 1 + ' will add Files or Dirs, recursing and flattening subdirectories. + zip.AddItem(itemnames(i), "flat") + Next i + zip.Save(ZipToCreate) + End Using + Catch ex1 As Exception + Console.Error.WriteLine("exception: {0}", ex1.ToString()) + End Try + + + The ZipEntry added. + + + + Adds a File to a Zip file archive. + + + + + This call collects metadata for the named file in the filesystem, + including the file attributes and the timestamp, and inserts that metadata + into the resulting ZipEntry. Only when the application calls Save() on + the ZipFile, does DotNetZip read the file from the filesystem and + then write the content to the zip file archive. + + + + This method will throw an exception if an entry with the same name already + exists in the ZipFile. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + In this example, three files are added to a Zip archive. The ReadMe.txt + file will be placed in the root of the archive. The .png file will be + placed in a folder within the zip called photos\personal. The pdf file + will be included into a folder within the zip called Desktop. + + + try + { + using (ZipFile zip = new ZipFile()) + { + zip.AddFile("c:\\photos\\personal\\7440-N49th.png"); + zip.AddFile("c:\\Desktop\\2008-Regional-Sales-Report.pdf"); + zip.AddFile("ReadMe.txt"); + + zip.Save("Package.zip"); + } + } + catch (System.Exception ex1) + { + System.Console.Error.WriteLine("exception: " + ex1); + } + + + + Try + Using zip As ZipFile = New ZipFile + zip.AddFile("c:\photos\personal\7440-N49th.png") + zip.AddFile("c:\Desktop\2008-Regional-Sales-Report.pdf") + zip.AddFile("ReadMe.txt") + zip.Save("Package.zip") + End Using + Catch ex1 As Exception + Console.Error.WriteLine("exception: {0}", ex1.ToString) + End Try + + + + This method has two overloads. + + + + + + + The name of the file to add. It should refer to a file in the filesystem. + The name of the file may be a relative path or a fully-qualified path. + + The ZipEntry corresponding to the File added. + + + + Adds a File to a Zip file archive, potentially overriding the path to be + used within the zip archive. + + + + + The file added by this call to the ZipFile is not written to the + zip file archive until the application calls Save() on the ZipFile. + + + + This method will throw an exception if an entry with the same name already + exists in the ZipFile. + + + + This version of the method allows the caller to explicitly specify the + directory path to be used in the archive. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + In this example, three files are added to a Zip archive. The ReadMe.txt + file will be placed in the root of the archive. The .png file will be + placed in a folder within the zip called images. The pdf file will be + included into a folder within the zip called files\docs, and will be + encrypted with the given password. + + + try + { + using (ZipFile zip = new ZipFile()) + { + // the following entry will be inserted at the root in the archive. + zip.AddFile("c:\\datafiles\\ReadMe.txt", ""); + // this image file will be inserted into the "images" directory in the archive. + zip.AddFile("c:\\photos\\personal\\7440-N49th.png", "images"); + // the following will result in a password-protected file called + // files\\docs\\2008-Regional-Sales-Report.pdf in the archive. + zip.Password = "EncryptMe!"; + zip.AddFile("c:\\Desktop\\2008-Regional-Sales-Report.pdf", "files\\docs"); + zip.Save("Archive.zip"); + } + } + catch (System.Exception ex1) + { + System.Console.Error.WriteLine("exception: {0}", ex1); + } + + + + Try + Using zip As ZipFile = New ZipFile + ' the following entry will be inserted at the root in the archive. + zip.AddFile("c:\datafiles\ReadMe.txt", "") + ' this image file will be inserted into the "images" directory in the archive. + zip.AddFile("c:\photos\personal\7440-N49th.png", "images") + ' the following will result in a password-protected file called + ' files\\docs\\2008-Regional-Sales-Report.pdf in the archive. + zip.Password = "EncryptMe!" + zip.AddFile("c:\Desktop\2008-Regional-Sales-Report.pdf", "files\documents") + zip.Save("Archive.zip") + End Using + Catch ex1 As Exception + Console.Error.WriteLine("exception: {0}", ex1) + End Try + + + + + + + + + The name of the file to add. The name of the file may be a relative path + or a fully-qualified path. + + + + Specifies a directory path to use to override any path in the fileName. + This path may, or may not, correspond to a real directory in the current + filesystem. If the files within the zip are later extracted, this is the + path used for the extracted file. Passing null (Nothing in + VB) will use the path on the fileName, if any. Passing the empty string + ("") will insert the item at the root path within the archive. + + + The ZipEntry corresponding to the file added. + + + + This method removes a collection of entries from the ZipFile. + + + + A collection of ZipEntry instances from this zip file to be removed. For + example, you can pass in an array of ZipEntry instances; or you can call + SelectEntries(), and then add or remove entries from that + ICollection<ZipEntry> (ICollection(Of ZipEntry) in VB), and pass + that ICollection to this method. + + + + + + + + This method removes a collection of entries from the ZipFile, by name. + + + + A collection of strings that refer to names of entries to be removed + from the ZipFile. For example, you can pass in an array or a + List of Strings that provide the names of entries to be removed. + + + + + + + + This method adds a set of files to the ZipFile. + + + + + Use this method to add a set of files to the zip archive, in one call. + For example, a list of files received from + System.IO.Directory.GetFiles() can be added to a zip archive in one + call. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to each + ZipEntry added. + + + + + The collection of names of the files to add. Each string should refer to a + file in the filesystem. The name of the file may be a relative path or a + fully-qualified path. + + + + This example shows how to create a zip file, and add a few files into it. + + String ZipFileToCreate = "archive1.zip"; + String DirectoryToZip = "c:\\reports"; + using (ZipFile zip = new ZipFile()) + { + // Store all files found in the top level directory, into the zip archive. + String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); + zip.AddFiles(filenames); + zip.Save(ZipFileToCreate); + } + + + + Dim ZipFileToCreate As String = "archive1.zip" + Dim DirectoryToZip As String = "c:\reports" + Using zip As ZipFile = New ZipFile + ' Store all files found in the top level directory, into the zip archive. + Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) + zip.AddFiles(filenames) + zip.Save(ZipFileToCreate) + End Using + + + + + + + + Adds or updates a set of files in the ZipFile. + + + + + Any files that already exist in the archive are updated. Any files that + don't yet exist in the archive are added. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to each + ZipEntry added. + + + + + The collection of names of the files to update. Each string should refer to a file in + the filesystem. The name of the file may be a relative path or a fully-qualified path. + + + + + + Adds a set of files to the ZipFile, using the + specified directory path in the archive. + + + + + Any directory structure that may be present in the + filenames contained in the list is "flattened" in the + archive. Each file in the list is added to the archive in + the specified top-level directory. + + + + For ZipFile properties including , , , , , , and , their respective values at the + time of this call will be applied to each ZipEntry added. + + + + + The names of the files to add. Each string should refer to + a file in the filesystem. The name of the file may be a + relative path or a fully-qualified path. + + + + Specifies a directory path to use to override any path in the file name. + Th is path may, or may not, correspond to a real directory in the current + filesystem. If the files within the zip are later extracted, this is the + path used for the extracted file. Passing null (Nothing in + VB) will use the path on each of the fileNames, if any. Passing + the empty string ("") will insert the item at the root path within the + archive. + + + + + + + Adds a set of files to the ZipFile, using the specified directory + path in the archive, and preserving the full directory structure in the + filenames. + + + + + If preserveDirHierarchy is true, any directory structure present in the + filenames contained in the list is preserved in the archive. On the other + hand, if preserveDirHierarchy is false, any directory structure that may + be present in the filenames contained in the list is "flattened" in the + archive; Each file in the list is added to the archive in the specified + top-level directory. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to each + ZipEntry added. + + + + + + The names of the files to add. Each string should refer to a file in the + filesystem. The name of the file may be a relative path or a + fully-qualified path. + + + + Specifies a directory path to use to override any path in the file name. + This path may, or may not, correspond to a real directory in the current + filesystem. If the files within the zip are later extracted, this is the + path used for the extracted file. Passing null (Nothing in + VB) will use the path on each of the fileNames, if any. Passing + the empty string ("") will insert the item at the root path within the + archive. + + + + whether the entries in the zip archive will reflect the directory + hierarchy that is present in the various filenames. For example, if + includes two paths, \Animalia\Chordata\Mammalia\Info.txt and + \Plantae\Magnoliophyta\Dicotyledon\Info.txt, then calling this method with + = false will result in an + exception because of a duplicate entry name, while calling this method + with = true will result in the + full direcory paths being included in the entries added to the ZipFile. + + + + + + Adds or updates a set of files to the ZipFile, using the specified + directory path in the archive. + + + + + + Any files that already exist in the archive are updated. Any files that + don't yet exist in the archive are added. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to each + ZipEntry added. + + + + + The names of the files to add or update. Each string should refer to a + file in the filesystem. The name of the file may be a relative path or a + fully-qualified path. + + + + Specifies a directory path to use to override any path in the file name. + This path may, or may not, correspond to a real directory in the current + filesystem. If the files within the zip are later extracted, this is the + path used for the extracted file. Passing null (Nothing in + VB) will use the path on each of the fileNames, if any. Passing + the empty string ("") will insert the item at the root path within the + archive. + + + + + + + Adds or Updates a File in a Zip file archive. + + + + + This method adds a file to a zip archive, or, if the file already exists + in the zip archive, this method Updates the content of that given filename + in the zip archive. The UpdateFile method might more accurately be + called "AddOrUpdateFile". + + + + Upon success, there is no way for the application to learn whether the file + was added versus updated. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + This example shows how to Update an existing entry in a zipfile. The first + call to UpdateFile adds the file to the newly-created zip archive. The + second call to UpdateFile updates the content for that file in the zip + archive. + + + using (ZipFile zip1 = new ZipFile()) + { + // UpdateFile might more accurately be called "AddOrUpdateFile" + zip1.UpdateFile("MyDocuments\\Readme.txt"); + zip1.UpdateFile("CustomerList.csv"); + zip1.Comment = "This zip archive has been created."; + zip1.Save("Content.zip"); + } + + using (ZipFile zip2 = ZipFile.Read("Content.zip")) + { + zip2.UpdateFile("Updates\\Readme.txt"); + zip2.Comment = "This zip archive has been updated: The Readme.txt file has been changed."; + zip2.Save(); + } + + + + Using zip1 As New ZipFile + ' UpdateFile might more accurately be called "AddOrUpdateFile" + zip1.UpdateFile("MyDocuments\Readme.txt") + zip1.UpdateFile("CustomerList.csv") + zip1.Comment = "This zip archive has been created." + zip1.Save("Content.zip") + End Using + + Using zip2 As ZipFile = ZipFile.Read("Content.zip") + zip2.UpdateFile("Updates\Readme.txt") + zip2.Comment = "This zip archive has been updated: The Readme.txt file has been changed." + zip2.Save + End Using + + + + + + + + + The name of the file to add or update. It should refer to a file in the + filesystem. The name of the file may be a relative path or a + fully-qualified path. + + + + The ZipEntry corresponding to the File that was added or updated. + + + + + Adds or Updates a File in a Zip file archive. + + + + + This method adds a file to a zip archive, or, if the file already exists + in the zip archive, this method Updates the content of that given filename + in the zip archive. + + + + This version of the method allows the caller to explicitly specify the + directory path to be used in the archive. The entry to be added or + updated is found by using the specified directory path, combined with the + basename of the specified filename. + + + + Upon success, there is no way for the application to learn if the file was + added versus updated. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + + + The name of the file to add or update. It should refer to a file in the + filesystem. The name of the file may be a relative path or a + fully-qualified path. + + + + Specifies a directory path to use to override any path in the + fileName. This path may, or may not, correspond to a real + directory in the current filesystem. If the files within the zip are + later extracted, this is the path used for the extracted file. Passing + null (Nothing in VB) will use the path on the + fileName, if any. Passing the empty string ("") will insert the + item at the root path within the archive. + + + + The ZipEntry corresponding to the File that was added or updated. + + + + + Add or update a directory in a zip archive. + + + + If the specified directory does not exist in the archive, then this method + is equivalent to calling AddDirectory(). If the specified + directory already exists in the archive, then this method updates any + existing entries, and adds any new entries. Any entries that are in the + zip archive but not in the specified directory, are left alone. In other + words, the contents of the zip file will be a union of the previous + contents and the new files. + + + + + + + + The path to the directory to be added to the zip archive, or updated in + the zip archive. + + + + The ZipEntry corresponding to the Directory that was added or updated. + + + + + Add or update a directory in the zip archive at the specified root + directory in the archive. + + + + If the specified directory does not exist in the archive, then this method + is equivalent to calling AddDirectory(). If the specified + directory already exists in the archive, then this method updates any + existing entries, and adds any new entries. Any entries that are in the + zip archive but not in the specified directory, are left alone. In other + words, the contents of the zip file will be a union of the previous + contents and the new files. + + + + + + + + The path to the directory to be added to the zip archive, or updated + in the zip archive. + + + + Specifies a directory path to use to override any path in the + directoryName. This path may, or may not, correspond to a real + directory in the current filesystem. If the files within the zip are + later extracted, this is the path used for the extracted file. Passing + null (Nothing in VB) will use the path on the + directoryName, if any. Passing the empty string ("") will insert + the item at the root path within the archive. + + + + The ZipEntry corresponding to the Directory that was added or updated. + + + + + Add or update a file or directory in the zip archive. + + + + + This is useful when the application is not sure or does not care if the + item to be added is a file or directory, and does not know or does not + care if the item already exists in the ZipFile. Calling this method + is equivalent to calling RemoveEntry() if an entry by the same name + already exists, followed calling by AddItem(). + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + + + the path to the file or directory to be added or updated. + + + + + Add or update a file or directory. + + + + + This method is useful when the application is not sure or does not care if + the item to be added is a file or directory, and does not know or does not + care if the item already exists in the ZipFile. Calling this method + is equivalent to calling RemoveEntry(), if an entry by that name + exists, and then calling AddItem(). + + + + This version of the method allows the caller to explicitly specify the + directory path to be used for the item being added to the archive. The + entry or entries that are added or updated will use the specified + DirectoryPathInArchive. Extracting the entry from the archive will + result in a file stored in that directory path. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + + + The path for the File or Directory to be added or updated. + + + Specifies a directory path to use to override any path in the + itemName. This path may, or may not, correspond to a real + directory in the current filesystem. If the files within the zip are + later extracted, this is the path used for the extracted file. Passing + null (Nothing in VB) will use the path on the + itemName, if any. Passing the empty string ("") will insert the + item at the root path within the archive. + + + + + Adds a named entry into the zip archive, taking content for the entry + from a string. + + + + Calling this method creates an entry using the given fileName and + directory path within the archive. There is no need for a file by the + given name to exist in the filesystem; the name is used within the zip + archive only. The content for the entry is encoded using the default text + encoding for the machine, or on Silverlight, using UTF-8. + + + + The content of the file, should it be extracted from the zip. + + + + The name, including any path, to use for the entry within the archive. + + + The ZipEntry added. + + + + This example shows how to add an entry to the zipfile, using a string as + content for that entry. + + + string Content = "This string will be the content of the Readme.txt file in the zip archive."; + using (ZipFile zip1 = new ZipFile()) + { + zip1.AddFile("MyDocuments\\Resume.doc", "files"); + zip1.AddEntry("Readme.txt", Content); + zip1.Comment = "This zip file was created at " + System.DateTime.Now.ToString("G"); + zip1.Save("Content.zip"); + } + + + + Public Sub Run() + Dim Content As String = "This string will be the content of the Readme.txt file in the zip archive." + Using zip1 As ZipFile = New ZipFile + zip1.AddEntry("Readme.txt", Content) + zip1.AddFile("MyDocuments\Resume.doc", "files") + zip1.Comment = ("This zip file was created at " & DateTime.Now.ToString("G")) + zip1.Save("Content.zip") + End Using + End Sub + + + + + + Adds a named entry into the zip archive, taking content for the entry + from a string, and using the specified text encoding. + + + + + + Calling this method creates an entry using the given fileName and + directory path within the archive. There is no need for a file by the + given name to exist in the filesystem; the name is used within the zip + archive only. + + + + The content for the entry, a string value, is encoded using the given + text encoding. A BOM (byte-order-mark) is emitted into the file, if the + Encoding parameter is set for that. + + + + Most Encoding classes support a constructor that accepts a boolean, + indicating whether to emit a BOM or not. For example see . + + + + + + The name, including any path, to use within the archive for the entry. + + + + The content of the file, should it be extracted from the zip. + + + + The text encoding to use when encoding the string. Be aware: This is + distinct from the text encoding used to encode the fileName, as specified + in . + + + The ZipEntry added. + + + + + Create an entry in the ZipFile using the given Stream + as input. The entry will have the given filename. + + + + + + The application should provide an open, readable stream; in this case it + will be read during the call to or one of + its overloads. + + + + The passed stream will be read from its current position. If + necessary, callers should set the position in the stream before + calling AddEntry(). This might be appropriate when using this method + with a MemoryStream, for example. + + + + In cases where a large number of streams will be added to the + ZipFile, the application may wish to avoid maintaining all of the + streams open simultaneously. To handle this situation, the application + should use the + overload. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + This example adds a single entry to a ZipFile via a Stream. + + + + String zipToCreate = "Content.zip"; + String fileNameInArchive = "Content-From-Stream.bin"; + using (System.IO.Stream streamToRead = MyStreamOpener()) + { + using (ZipFile zip = new ZipFile()) + { + ZipEntry entry= zip.AddEntry(fileNameInArchive, streamToRead); + zip.AddFile("Readme.txt"); + zip.Save(zipToCreate); // the stream is read implicitly here + } + } + + + + Dim zipToCreate As String = "Content.zip" + Dim fileNameInArchive As String = "Content-From-Stream.bin" + Using streamToRead as System.IO.Stream = MyStreamOpener() + Using zip As ZipFile = New ZipFile() + Dim entry as ZipEntry = zip.AddEntry(fileNameInArchive, streamToRead) + zip.AddFile("Readme.txt") + zip.Save(zipToCreate) '' the stream is read implicitly, here + End Using + End Using + + + + + + + The name, including any path, which is shown in the zip file for the added + entry. + + + The input stream from which to grab content for the file + + The ZipEntry added. + + + + Add a ZipEntry for which content is written directly by the application. + + + + + When the application needs to write the zip entry data, use this + method to add the ZipEntry. For example, in the case that the + application wishes to write the XML representation of a DataSet into + a ZipEntry, the application can use this method to do so. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + About progress events: When using the WriteDelegate, DotNetZip does + not issue any SaveProgress events with EventType = + Saving_EntryBytesRead. (This is because it is the + application's code that runs in WriteDelegate - there's no way for + DotNetZip to know when to issue a EntryBytesRead event.) + Applications that want to update a progress bar or similar status + indicator should do so from within the WriteDelegate + itself. DotNetZip will issue the other SaveProgress events, + including + Saving_Started, + + Saving_BeforeWriteEntry, and + Saving_AfterWriteEntry. + + + + Note: When you use PKZip encryption, it's normally necessary to + compute the CRC of the content to be encrypted, before compressing or + encrypting it. Therefore, when using PKZip encryption with a + WriteDelegate, the WriteDelegate CAN BE called twice: once to compute + the CRC, and the second time to potentially compress and + encrypt. Surprising, but true. This is because PKWARE specified that + the encryption initialization data depends on the CRC. + If this happens, for each call of the delegate, your + application must stream the same entry data in its entirety. If your + application writes different data during the second call, it will + result in a corrupt zip file. + + + + The double-read behavior happens with all types of entries, not only + those that use WriteDelegate. It happens if you add an entry from a + filesystem file, or using a string, or a stream, or an opener/closer + pair. But in those cases, DotNetZip takes care of reading twice; in + the case of the WriteDelegate, the application code gets invoked + twice. Be aware. + + + + As you can imagine, this can cause performance problems for large + streams, and it can lead to correctness problems when you use a + WriteDelegate. This is a pretty big pitfall. There are two + ways to avoid it. First, and most preferred: don't use PKZIP + encryption. If you use the WinZip AES encryption, this problem + doesn't occur, because the encryption protocol doesn't require the CRC + up front. Second: if you do choose to use PKZIP encryption, write out + to a non-seekable stream (like standard output, or the + Response.OutputStream in an ASP.NET application). In this case, + DotNetZip will use an alternative encryption protocol that does not + rely on the CRC of the content. This also implies setting bit 3 in + the zip entry, which still presents problems for some zip tools. + + + + In the future I may modify DotNetZip to *always* use bit 3 when PKZIP + encryption is in use. This seems like a win overall, but there will + be some work involved. If you feel strongly about it, visit the + DotNetZip forums and vote up the Workitem + tracking this issue. + + + + + the name of the entry to add + the delegate which will write the entry content + the ZipEntry added + + + + This example shows an application filling a DataSet, then saving the + contents of that DataSet as XML, into a ZipEntry in a ZipFile, using an + anonymous delegate in C#. The DataSet XML is never saved to a disk file. + + + var c1= new System.Data.SqlClient.SqlConnection(connstring1); + var da = new System.Data.SqlClient.SqlDataAdapter() + { + SelectCommand= new System.Data.SqlClient.SqlCommand(strSelect, c1) + }; + + DataSet ds1 = new DataSet(); + da.Fill(ds1, "Invoices"); + + using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile()) + { + zip.AddEntry(zipEntryName, (name,stream) => ds1.WriteXml(stream) ); + zip.Save(zipFileName); + } + + + + + + This example uses an anonymous method in C# as the WriteDelegate to provide + the data for the ZipEntry. The example is a bit contrived - the + AddFile() method is a simpler way to insert the contents of a file + into an entry in a zip file. On the other hand, if there is some sort of + processing or transformation of the file contents required before writing, + the application could use the WriteDelegate to do it, in this way. + + + using (var input = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite )) + { + using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile()) + { + zip.AddEntry(zipEntryName, (name,output) => + { + byte[] buffer = new byte[BufferSize]; + int n; + while ((n = input.Read(buffer, 0, buffer.Length)) != 0) + { + // could transform the data here... + output.Write(buffer, 0, n); + // could update a progress bar here + } + }); + + zip.Save(zipFileName); + } + } + + + + + + This example uses a named delegate in VB to write data for the given + ZipEntry (VB9 does not have anonymous delegates). The example here is a bit + contrived - a simpler way to add the contents of a file to a ZipEntry is to + simply use the appropriate AddFile() method. The key scenario for + which the WriteDelegate makes sense is saving a DataSet, in XML + format, to the zip file. The DataSet can write XML to a stream, and the + WriteDelegate is the perfect place to write into the zip file. There may be + other data structures that can write to a stream, but cannot be read as a + stream. The WriteDelegate would be appropriate for those cases as + well. + + + Private Sub WriteEntry (ByVal name As String, ByVal output As Stream) + Using input As FileStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) + Dim n As Integer = -1 + Dim buffer As Byte() = New Byte(BufferSize){} + Do While n <> 0 + n = input.Read(buffer, 0, buffer.Length) + output.Write(buffer, 0, n) + Loop + End Using + End Sub + + Public Sub Run() + Using zip = New ZipFile + zip.AddEntry(zipEntryName, New WriteDelegate(AddressOf WriteEntry)) + zip.Save(zipFileName) + End Using + End Sub + + + + + + Add an entry, for which the application will provide a stream, + just-in-time. + + + + + In cases where the application wishes to open the stream that holds + the content for the ZipEntry, on a just-in-time basis, the application + can use this method and provide delegates to open and close the + stream. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + This example uses anonymous methods in C# to open and close the + source stream for the content for a zip entry. In a real + application, the logic for the OpenDelegate would probably be more + involved. + + + using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile()) + { + zip.AddEntry(zipEntryName, + (name) => File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ), + (name, stream) => stream.Close() + ); + + zip.Save(zipFileName); + } + + + + + + + This example uses delegates in VB.NET to open and close the + the source stream for the content for a zip entry. VB 9.0 lacks + support for "Sub" lambda expressions, and so the CloseDelegate must + be an actual, named Sub. + + + + Function MyStreamOpener(ByVal entryName As String) As Stream + '' This simply opens a file. You probably want to do somethinig + '' more involved here: open a stream to read from a database, + '' open a stream on an HTTP connection, and so on. + Return File.OpenRead(entryName) + End Function + + Sub MyStreamCloser(entryName As String, stream As Stream) + stream.Close() + End Sub + + Public Sub Run() + Dim dirToZip As String = "fodder" + Dim zipFileToCreate As String = "Archive.zip" + Dim opener As OpenDelegate = AddressOf MyStreamOpener + Dim closer As CloseDelegate = AddressOf MyStreamCloser + Dim numFilestoAdd As Int32 = 4 + Using zip As ZipFile = New ZipFile + Dim i As Integer + For i = 0 To numFilesToAdd - 1 + zip.AddEntry(String.Format("content-{0:000}.txt"), opener, closer) + Next i + zip.Save(zipFileToCreate) + End Using + End Sub + + + + + the name of the entry to add + + the delegate that will be invoked to open the stream + + + the delegate that will be invoked to close the stream + + the ZipEntry added + + + + + Updates the given entry in the ZipFile, using the given + string as content for the ZipEntry. + + + + + + Calling this method is equivalent to removing the ZipEntry for + the given file name and directory path, if it exists, and then calling + . See the documentation for + that method for further explanation. The string content is encoded + using the default encoding for the machine, or on Silverlight, using + UTF-8. This encoding is distinct from the encoding used for the + filename itself. See . + + + + + + The name, including any path, to use within the archive for the entry. + + + + The content of the file, should it be extracted from the zip. + + + The ZipEntry added. + + + + + Updates the given entry in the ZipFile, using the given string as + content for the ZipEntry. + + + + Calling this method is equivalent to removing the ZipEntry for the + given file name and directory path, if it exists, and then calling . See the + documentation for that method for further explanation. + + + + The name, including any path, to use within the archive for the entry. + + + + The content of the file, should it be extracted from the zip. + + + + The text encoding to use when encoding the string. Be aware: This is + distinct from the text encoding used to encode the filename. See . + + + The ZipEntry added. + + + + + Updates the given entry in the ZipFile, using the given delegate + as the source for content for the ZipEntry. + + + + Calling this method is equivalent to removing the ZipEntry for the + given file name and directory path, if it exists, and then calling . See the + documentation for that method for further explanation. + + + + The name, including any path, to use within the archive for the entry. + + + the delegate which will write the entry content. + + The ZipEntry added. + + + + + Updates the given entry in the ZipFile, using the given delegates + to open and close the stream that provides the content for the ZipEntry. + + + + Calling this method is equivalent to removing the ZipEntry for the + given file name and directory path, if it exists, and then calling . See the + documentation for that method for further explanation. + + + + The name, including any path, to use within the archive for the entry. + + + + the delegate that will be invoked to open the stream + + + the delegate that will be invoked to close the stream + + + The ZipEntry added or updated. + + + + + Updates the given entry in the ZipFile, using the given stream as + input, and the given filename and given directory Path. + + + + + Calling the method is equivalent to calling RemoveEntry() if an + entry by the same name already exists, and then calling AddEntry() + with the given fileName and stream. + + + + The stream must be open and readable during the call to + ZipFile.Save. You can dispense the stream on a just-in-time basis + using the property. Check the + documentation of that property for more information. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to the + ZipEntry added. + + + + + + + + + The name, including any path, to use within the archive for the entry. + + + The input stream from which to read file data. + The ZipEntry added. + + + + Add an entry into the zip archive using the given filename and + directory path within the archive, and the given content for the + file. No file is created in the filesystem. + + + The data to use for the entry. + + + The name, including any path, to use within the archive for the entry. + + + The ZipEntry added. + + + + Updates the given entry in the ZipFile, using the given byte + array as content for the entry. + + + + Calling this method is equivalent to removing the ZipEntry + for the given filename and directory path, if it exists, and then + calling . See the + documentation for that method for further explanation. + + + + The name, including any path, to use within the archive for the entry. + + + The content to use for the ZipEntry. + + The ZipEntry added. + + + + + Adds the contents of a filesystem directory to a Zip file archive. + + + + + + The name of the directory may be a relative path or a fully-qualified + path. Any files within the named directory are added to the archive. Any + subdirectories within the named directory are also added to the archive, + recursively. + + + + Top-level entries in the named directory will appear as top-level entries + in the zip archive. Entries in subdirectories in the named directory will + result in entries in subdirectories in the zip archive. + + + + If you want the entries to appear in a containing directory in the zip + archive itself, then you should call the AddDirectory() overload that + allows you to explicitly specify a directory path for use in the archive. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to each + ZipEntry added. + + + + + + + + + + This method has 2 overloads. + + The name of the directory to add. + The ZipEntry added. + + + + Adds the contents of a filesystem directory to a Zip file archive, + overriding the path to be used for entries in the archive. + + + + + The name of the directory may be a relative path or a fully-qualified + path. The add operation is recursive, so that any files or subdirectories + within the name directory are also added to the archive. + + + + Top-level entries in the named directory will appear as top-level entries + in the zip archive. Entries in subdirectories in the named directory will + result in entries in subdirectories in the zip archive. + + + + For ZipFile properties including , , , , , + , and , their + respective values at the time of this call will be applied to each + ZipEntry added. + + + + + + + In this code, calling the ZipUp() method with a value of "c:\reports" for + the directory parameter will result in a zip file structure in which all + entries are contained in a toplevel "reports" directory. + + + + public void ZipUp(string targetZip, string directory) + { + using (var zip = new ZipFile()) + { + zip.AddDirectory(directory, System.IO.Path.GetFileName(directory)); + zip.Save(targetZip); + } + } + + + + + + + + The name of the directory to add. + + + Specifies a directory path to use to override any path in the + DirectoryName. This path may, or may not, correspond to a real directory + in the current filesystem. If the zip is later extracted, this is the + path used for the extracted file or directory. Passing null + (Nothing in VB) or the empty string ("") will insert the items at + the root path within the archive. + + + The ZipEntry added. + + + + Creates a directory in the zip archive. + + + + + + Use this when you want to create a directory in the archive but there is + no corresponding filesystem representation for that directory. + + + + You will probably not need to do this in your code. One of the only times + you will want to do this is if you want an empty directory in the zip + archive. The reason: if you add a file to a zip archive that is stored + within a multi-level directory, all of the directory tree is implicitly + created in the zip archive. + + + + + + The name of the directory to create in the archive. + + The ZipEntry added. + + + + Checks a zip file to see if its directory is consistent. + + + + + + In cases of data error, the directory within a zip file can get out + of synch with the entries in the zip file. This method checks the + given zip file and returns true if this has occurred. + + + This method may take a long time to run for large zip files. + + + This method is not supported in the Reduced or Compact Framework + versions of DotNetZip. + + + + Developers using COM can use the ComHelper.CheckZip(String) + method. + + + + + The filename to of the zip file to check. + + true if the named zip file checks OK. Otherwise, false. + + + + + + + Checks a zip file to see if its directory is consistent, + and optionally fixes the directory if necessary. + + + + + + In cases of data error, the directory within a zip file can get out of + synch with the entries in the zip file. This method checks the given + zip file, and returns true if this has occurred. It also optionally + fixes the zipfile, saving the fixed copy in Name_Fixed.zip. + + + + This method may take a long time to run for large zip files. It + will take even longer if the file actually needs to be fixed, and if + fixIfNecessary is true. + + + + This method is not supported in the Reduced or Compact + Framework versions of DotNetZip. + + + + + The filename to of the zip file to check. + + If true, the method will fix the zip file if + necessary. + + + a TextWriter in which messages generated while checking will be written. + + + true if the named zip is OK; false if the file needs to be fixed. + + + + + + + Rewrite the directory within a zipfile. + + + + + + In cases of data error, the directory in a zip file can get out of + synch with the entries in the zip file. This method attempts to fix + the zip file if this has occurred. + + + This can take a long time for large zip files. + + This won't work if the zip file uses a non-standard + code page - neither IBM437 nor UTF-8. + + + This method is not supported in the Reduced or Compact Framework + versions of DotNetZip. + + + + Developers using COM can use the ComHelper.FixZipDirectory(String) + method. + + + + + The filename to of the zip file to fix. + + + + + + + Verify the password on a zip file. + + + + + Keep in mind that passwords in zipfiles are applied to + zip entries, not to the entire zip file. So testing a + zipfile for a particular password doesn't work in the + general case. On the other hand, it's often the case + that a single password will be used on all entries in a + zip file. This method works for that case. + + + There is no way to check a password without doing the + decryption. So this code decrypts and extracts the given + zipfile into + + + + The filename to of the zip file to fix. + + The password to check. + + a bool indicating whether the password matches. + + + + Returns true if an entry by the given name exists in the ZipFile. + + + the name of the entry to find + true if an entry with the given name exists; otherwise false. + + + + Provides a string representation of the instance. + a string representation of the instance. + + + + Creates a new ZipFile instance, using the specified filename. + + + + + Applications can use this constructor to create a new ZipFile for writing, + or to slurp in an existing zip archive for read and update purposes. + + + + To create a new zip archive, an application can call this constructor, + passing the name of a file that does not exist. The name may be a fully + qualified path. Then the application can add directories or files to the + ZipFile via AddDirectory(), AddFile(), AddItem() + and then write the zip archive to the disk by calling Save(). The + zip file is not actually opened and written to the disk until the + application calls ZipFile.Save(). At that point the new zip file + with the given name is created. + + + + If you won't know the name of the Zipfile until the time you call + ZipFile.Save(), or if you plan to save to a stream (which has no + name), then you should use the no-argument constructor. + + + + The application can also call this constructor to read an existing zip + archive. passing the name of a valid zip file that does exist. But, it's + better form to use the static method, + passing the name of the zip file, because using ZipFile.Read() in + your code communicates very clearly what you are doing. In either case, + the file is then read into the ZipFile instance. The app can then + enumerate the entries or can modify the zip file, for example adding + entries, removing entries, changing comments, and so on. + + + + One advantage to this parameterized constructor: it allows applications to + use the same code to add items to a zip archive, regardless of whether the + zip file exists. + + + + Instances of the ZipFile class are not multi-thread safe. You may + not party on a single instance with multiple threads. You may have + multiple threads that each use a distinct ZipFile instance, or you + can synchronize multi-thread access to a single instance. + + + + By the way, since DotNetZip is so easy to use, don't you think you should + donate $5 or $10? + + + + + + Thrown if name refers to an existing file that is not a valid zip file. + + + + This example shows how to create a zipfile, and add a few files into it. + + String ZipFileToCreate = "archive1.zip"; + String DirectoryToZip = "c:\\reports"; + using (ZipFile zip = new ZipFile()) + { + // Store all files found in the top level directory, into the zip archive. + String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); + zip.AddFiles(filenames, "files"); + zip.Save(ZipFileToCreate); + } + + + + Dim ZipFileToCreate As String = "archive1.zip" + Dim DirectoryToZip As String = "c:\reports" + Using zip As ZipFile = New ZipFile() + Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) + zip.AddFiles(filenames, "files") + zip.Save(ZipFileToCreate) + End Using + + + + The filename to use for the new zip archive. + + + + + Creates a new ZipFile instance, using the specified name for the + filename, and the specified Encoding. + + + + + See the documentation on the ZipFile + constructor that accepts a single string argument for basic + information on all the ZipFile constructors. + + + + The Encoding is used as the default alternate encoding for entries with + filenames or comments that cannot be encoded with the IBM437 code page. + This is equivalent to setting the property on the ZipFile + instance after construction. + + + + Instances of the ZipFile class are not multi-thread safe. You may + not party on a single instance with multiple threads. You may have + multiple threads that each use a distinct ZipFile instance, or you + can synchronize multi-thread access to a single instance. + + + + + + Thrown if name refers to an existing file that is not a valid zip file. + + + The filename to use for the new zip archive. + The Encoding is used as the default alternate + encoding for entries with filenames or comments that cannot be encoded + with the IBM437 code page. + + + + Create a zip file, without specifying a target filename or stream to save to. + + + + + See the documentation on the ZipFile + constructor that accepts a single string argument for basic + information on all the ZipFile constructors. + + + + After instantiating with this constructor and adding entries to the + archive, the application should call or + to save to a file or a + stream, respectively. The application can also set the + property and then call the no-argument method. (This + is the preferred approach for applications that use the library through + COM interop.) If you call the no-argument method + without having set the Name of the ZipFile, either through + the parameterized constructor or through the explicit property , the + Save() will throw, because there is no place to save the file. + + + Instances of the ZipFile class are not multi-thread safe. You may + have multiple threads that each use a distinct ZipFile instance, or + you can synchronize multi-thread access to a single instance. + + + + + This example creates a Zip archive called Backup.zip, containing all the files + in the directory DirectoryToZip. Files within subdirectories are not zipped up. + + using (ZipFile zip = new ZipFile()) + { + // Store all files found in the top level directory, into the zip archive. + // note: this code does not recurse subdirectories! + String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); + zip.AddFiles(filenames, "files"); + zip.Save("Backup.zip"); + } + + + + Using zip As New ZipFile + ' Store all files found in the top level directory, into the zip archive. + ' note: this code does not recurse subdirectories! + Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) + zip.AddFiles(filenames, "files") + zip.Save("Backup.zip") + End Using + + + + + + Create a zip file, specifying a text Encoding, but without specifying a + target filename or stream to save to. + + + + + See the documentation on the ZipFile + constructor that accepts a single string argument for basic + information on all the ZipFile constructors. + + + + + + The Encoding is used as the default alternate encoding for entries with + filenames or comments that cannot be encoded with the IBM437 code page. + + + + + Creates a new ZipFile instance, using the specified name for the + filename, and the specified status message writer. + + + + + See the documentation on the ZipFile + constructor that accepts a single string argument for basic + information on all the ZipFile constructors. + + + + This version of the constructor allows the caller to pass in a TextWriter, + to which verbose messages will be written during extraction or creation of + the zip archive. A console application may wish to pass + System.Console.Out to get messages on the Console. A graphical or headless + application may wish to capture the messages in a different + TextWriter, for example, a StringWriter, and then display + the messages in a TextBox, or generate an audit log of ZipFile operations. + + + + To encrypt the data for the files added to the ZipFile instance, + set the Password property after creating the ZipFile instance. + + + + Instances of the ZipFile class are not multi-thread safe. You may + not party on a single instance with multiple threads. You may have + multiple threads that each use a distinct ZipFile instance, or you + can synchronize multi-thread access to a single instance. + + + + + + Thrown if name refers to an existing file that is not a valid zip file. + + + + + using (ZipFile zip = new ZipFile("Backup.zip", Console.Out)) + { + // Store all files found in the top level directory, into the zip archive. + // note: this code does not recurse subdirectories! + // Status messages will be written to Console.Out + String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); + zip.AddFiles(filenames); + zip.Save(); + } + + + + Using zip As New ZipFile("Backup.zip", Console.Out) + ' Store all files found in the top level directory, into the zip archive. + ' note: this code does not recurse subdirectories! + ' Status messages will be written to Console.Out + Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) + zip.AddFiles(filenames) + zip.Save() + End Using + + + + The filename to use for the new zip archive. + A TextWriter to use for writing + verbose status messages. + + + + Creates a new ZipFile instance, using the specified name for the + filename, the specified status message writer, and the specified Encoding. + + + + + This constructor works like the ZipFile + constructor that accepts a single string argument. See that + reference for detail on what this constructor does. + + + + This version of the constructor allows the caller to pass in a + TextWriter, and an Encoding. The TextWriter will collect + verbose messages that are generated by the library during extraction or + creation of the zip archive. A console application may wish to pass + System.Console.Out to get messages on the Console. A graphical or + headless application may wish to capture the messages in a different + TextWriter, for example, a StringWriter, and then display + the messages in a TextBox, or generate an audit log of + ZipFile operations. + + + + The Encoding is used as the default alternate encoding for entries + with filenames or comments that cannot be encoded with the IBM437 code + page. This is a equivalent to setting the property on the ZipFile + instance after construction. + + + + To encrypt the data for the files added to the ZipFile instance, + set the Password property after creating the ZipFile + instance. + + + + Instances of the ZipFile class are not multi-thread safe. You may + not party on a single instance with multiple threads. You may have + multiple threads that each use a distinct ZipFile instance, or you + can synchronize multi-thread access to a single instance. + + + + + + Thrown if fileName refers to an existing file that is not a valid zip file. + + + The filename to use for the new zip archive. + A TextWriter to use for writing verbose + status messages. + + The Encoding is used as the default alternate encoding for entries with + filenames or comments that cannot be encoded with the IBM437 code page. + + + + + Initialize a ZipFile instance by reading in a zip file. + + + + + + This method is primarily useful from COM Automation environments, when + reading or extracting zip files. In COM, it is not possible to invoke + parameterized constructors for a class. A COM Automation application can + update a zip file by using the default (no argument) + constructor, then calling Initialize() to read the contents + of an on-disk zip archive into the ZipFile instance. + + + + .NET applications are encouraged to use the ZipFile.Read() methods + for better clarity. + + + + the name of the existing zip file to read in. + + + + Removes the given ZipEntry from the zip archive. + + + + + After calling RemoveEntry, the application must call Save to + make the changes permanent. + + + + + Thrown if the specified ZipEntry does not exist in the ZipFile. + + + + In this example, all entries in the zip archive dating from before + December 31st, 2007, are removed from the archive. This is actually much + easier if you use the RemoveSelectedEntries method. But I needed an + example for RemoveEntry, so here it is. + + String ZipFileToRead = "ArchiveToModify.zip"; + System.DateTime Threshold = new System.DateTime(2007,12,31); + using (ZipFile zip = ZipFile.Read(ZipFileToRead)) + { + var EntriesToRemove = new System.Collections.Generic.List<ZipEntry>(); + foreach (ZipEntry e in zip) + { + if (e.LastModified < Threshold) + { + // We cannot remove the entry from the list, within the context of + // an enumeration of said list. + // So we add the doomed entry to a list to be removed later. + EntriesToRemove.Add(e); + } + } + + // actually remove the doomed entries. + foreach (ZipEntry zombie in EntriesToRemove) + zip.RemoveEntry(zombie); + + zip.Comment= String.Format("This zip archive was updated at {0}.", + System.DateTime.Now.ToString("G")); + + // save with a different name + zip.Save("Archive-Updated.zip"); + } + + + + Dim ZipFileToRead As String = "ArchiveToModify.zip" + Dim Threshold As New DateTime(2007, 12, 31) + Using zip As ZipFile = ZipFile.Read(ZipFileToRead) + Dim EntriesToRemove As New System.Collections.Generic.List(Of ZipEntry) + Dim e As ZipEntry + For Each e In zip + If (e.LastModified < Threshold) Then + ' We cannot remove the entry from the list, within the context of + ' an enumeration of said list. + ' So we add the doomed entry to a list to be removed later. + EntriesToRemove.Add(e) + End If + Next + + ' actually remove the doomed entries. + Dim zombie As ZipEntry + For Each zombie In EntriesToRemove + zip.RemoveEntry(zombie) + Next + zip.Comment = String.Format("This zip archive was updated at {0}.", DateTime.Now.ToString("G")) + 'save as a different name + zip.Save("Archive-Updated.zip") + End Using + + + + + The ZipEntry to remove from the zip. + + + + + + + + Removes the ZipEntry with the given filename from the zip archive. + + + + + After calling RemoveEntry, the application must call Save to + make the changes permanent. + + + + + + Thrown if the ZipFile is not updatable. + + + + Thrown if a ZipEntry with the specified filename does not exist in + the ZipFile. + + + + + This example shows one way to remove an entry with a given filename from + an existing zip archive. + + + String zipFileToRead= "PackedDocuments.zip"; + string candidate = "DatedMaterial.xps"; + using (ZipFile zip = ZipFile.Read(zipFileToRead)) + { + if (zip.EntryFilenames.Contains(candidate)) + { + zip.RemoveEntry(candidate); + zip.Comment= String.Format("The file '{0}' has been removed from this archive.", + Candidate); + zip.Save(); + } + } + + + Dim zipFileToRead As String = "PackedDocuments.zip" + Dim candidate As String = "DatedMaterial.xps" + Using zip As ZipFile = ZipFile.Read(zipFileToRead) + If zip.EntryFilenames.Contains(candidate) Then + zip.RemoveEntry(candidate) + zip.Comment = String.Format("The file '{0}' has been removed from this archive.", Candidate) + zip.Save + End If + End Using + + + + + The name of the file, including any directory path, to remove from the zip. + The filename match is not case-sensitive by default; you can use the + CaseSensitiveRetrieval property to change this behavior. The + pathname can use forward-slashes or backward slashes. + + + + + + Closes the read and write streams associated + to the ZipFile, if necessary. + + + + The Dispose() method is generally employed implicitly, via a using(..) {..} + statement. (Using...End Using in VB) If you do not employ a using + statement, insure that your application calls Dispose() explicitly. For + example, in a Powershell application, or an application that uses the COM + interop interface, you must call Dispose() explicitly. + + + + This example extracts an entry selected by name, from the Zip file to the + Console. + + using (ZipFile zip = ZipFile.Read(zipfile)) + { + foreach (ZipEntry e in zip) + { + if (WantThisEntry(e.FileName)) + zip.Extract(e.FileName, Console.OpenStandardOutput()); + } + } // Dispose() is called implicitly here. + + + + Using zip As ZipFile = ZipFile.Read(zipfile) + Dim e As ZipEntry + For Each e In zip + If WantThisEntry(e.FileName) Then + zip.Extract(e.FileName, Console.OpenStandardOutput()) + End If + Next + End Using ' Dispose is implicity called here + + + + + + Disposes any managed resources, if the flag is set, then marks the + instance disposed. This method is typically not called explicitly from + application code. + + + + Applications should call the no-arg Dispose method. + + + + indicates whether the method should dispose streams or not. + + + + + Default size of the buffer used for IO. + + + + + Extracts all of the items in the zip archive, to the specified path in the + filesystem. The path can be relative or fully-qualified. + + + + + This method will extract all entries in the ZipFile to the + specified path. + + + + If an extraction of a file from the zip archive would overwrite an + existing file in the filesystem, the action taken is dictated by the + ExtractExistingFile property, which overrides any setting you may have + made on individual ZipEntry instances. By default, if you have not + set that property on the ZipFile instance, the entry will not + be extracted, the existing file will not be overwritten and an + exception will be thrown. To change this, set the property, or use the + overload that allows you to + specify an ExtractExistingFileAction parameter. + + + + The action to take when an extract would overwrite an existing file + applies to all entries. If you want to set this on a per-entry basis, + then you must use one of the ZipEntry.Extract methods. + + + + This method will send verbose output messages to the , if it is set on the ZipFile + instance. + + + + You may wish to take advantage of the ExtractProgress event. + + + + About timestamps: When extracting a file entry from a zip archive, the + extracted file gets the last modified time of the entry as stored in + the archive. The archive may also store extended file timestamp + information, including last accessed and created times. If these are + present in the ZipEntry, then the extracted file will also get + these times. + + + + A Directory entry is somewhat different. It will get the times as + described for a file entry, but, if there are file entries in the zip + archive that, when extracted, appear in the just-created directory, + then when those file entries are extracted, the last modified and last + accessed times of the directory will change, as a side effect. The + result is that after an extraction of a directory and a number of + files within the directory, the last modified and last accessed + timestamps on the directory will reflect the time that the last file + was extracted into the directory, rather than the time stored in the + zip archive for the directory. + + + + To compensate, when extracting an archive with ExtractAll, + DotNetZip will extract all the file and directory entries as described + above, but it will then make a second pass on the directories, and + reset the times on the directories to reflect what is stored in the + zip archive. + + + + This compensation is performed only within the context of an + ExtractAll. If you call ZipEntry.Extract on a directory + entry, the timestamps on directory in the filesystem will reflect the + times stored in the zip. If you then call ZipEntry.Extract on + a file entry, which is extracted into the directory, the timestamps on + the directory will be updated to the current time. + + + + + This example extracts all the entries in a zip archive file, to the + specified target directory. The extraction will overwrite any + existing files silently. + + + String TargetDirectory= "unpack"; + using(ZipFile zip= ZipFile.Read(ZipFileToExtract)) + { + zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently; + zip.ExtractAll(TargetDirectory); + } + + + + Dim TargetDirectory As String = "unpack" + Using zip As ZipFile = ZipFile.Read(ZipFileToExtract) + zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently + zip.ExtractAll(TargetDirectory) + End Using + + + + + + + + The path to which the contents of the zipfile will be extracted. + The path can be relative or fully-qualified. + + + + + + Extracts all of the items in the zip archive, to the specified path in the + filesystem, using the specified behavior when extraction would overwrite an + existing file. + + + + + + This method will extract all entries in the ZipFile to the specified + path. For an extraction that would overwrite an existing file, the behavior + is dictated by , which overrides any + setting you may have made on individual ZipEntry instances. + + + + The action to take when an extract would overwrite an existing file + applies to all entries. If you want to set this on a per-entry basis, + then you must use or one of the similar methods. + + + + Calling this method is equivalent to setting the property and then calling . + + + + This method will send verbose output messages to the + , if it is set on the ZipFile instance. + + + + + This example extracts all the entries in a zip archive file, to the + specified target directory. It does not overwrite any existing files. + + String TargetDirectory= "c:\\unpack"; + using(ZipFile zip= ZipFile.Read(ZipFileToExtract)) + { + zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite); + } + + + + Dim TargetDirectory As String = "c:\unpack" + Using zip As ZipFile = ZipFile.Read(ZipFileToExtract) + zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite) + End Using + + + + + The path to which the contents of the zipfile will be extracted. + The path can be relative or fully-qualified. + + + + The action to take if extraction would overwrite an existing file. + + + + + + Reads a zip file archive and returns the instance. + + + + + The stream is read using the default System.Text.Encoding, which is the + IBM437 codepage. + + + + + Thrown if the ZipFile cannot be read. The implementation of this method + relies on System.IO.File.OpenRead, which can throw a variety of exceptions, + including specific exceptions if a file is not found, an unauthorized access + exception, exceptions for poorly formatted filenames, and so on. + + + + The name of the zip archive to open. This can be a fully-qualified or relative + pathname. + + + . + + The instance read from the zip archive. + + + + + Reads a zip file archive from the named filesystem file using the + specified options. + + + + + This version of the Read() method allows the caller to pass + in a TextWriter an Encoding, via an instance of the + ReadOptions class. The ZipFile is read in using the + specified encoding for entries where UTF-8 encoding is not + explicitly specified. + + + + + + + This example shows how to read a zip file using the Big-5 Chinese + code page (950), and extract each entry in the zip file, while + sending status messages out to the Console. + + + + For this code to work as intended, the zipfile must have been + created using the big5 code page (CP950). This is typical, for + example, when using WinRar on a machine with CP950 set as the + default code page. In that case, the names of entries within the + Zip archive will be stored in that code page, and reading the zip + archive must be done using that code page. If the application did + not use the correct code page in ZipFile.Read(), then names of + entries within the zip archive would not be correctly retrieved. + + + + string zipToExtract = "MyArchive.zip"; + string extractDirectory = "extract"; + var options = new ReadOptions + { + StatusMessageWriter = System.Console.Out, + Encoding = System.Text.Encoding.GetEncoding(950) + }; + using (ZipFile zip = ZipFile.Read(zipToExtract, options)) + { + foreach (ZipEntry e in zip) + { + e.Extract(extractDirectory); + } + } + + + + + Dim zipToExtract as String = "MyArchive.zip" + Dim extractDirectory as String = "extract" + Dim options as New ReadOptions + options.Encoding = System.Text.Encoding.GetEncoding(950) + options.StatusMessageWriter = System.Console.Out + Using zip As ZipFile = ZipFile.Read(zipToExtract, options) + Dim e As ZipEntry + For Each e In zip + e.Extract(extractDirectory) + Next + End Using + + + + + + + + This example shows how to read a zip file using the default + code page, to remove entries that have a modified date before a given threshold, + sending status messages out to a StringWriter. + + + + var options = new ReadOptions + { + StatusMessageWriter = new System.IO.StringWriter() + }; + using (ZipFile zip = ZipFile.Read("PackedDocuments.zip", options)) + { + var Threshold = new DateTime(2007,7,4); + // We cannot remove the entry from the list, within the context of + // an enumeration of said list. + // So we add the doomed entry to a list to be removed later. + // pass 1: mark the entries for removal + var MarkedEntries = new System.Collections.Generic.List<ZipEntry>(); + foreach (ZipEntry e in zip) + { + if (e.LastModified < Threshold) + MarkedEntries.Add(e); + } + // pass 2: actually remove the entry. + foreach (ZipEntry zombie in MarkedEntries) + zip.RemoveEntry(zombie); + zip.Comment = "This archive has been updated."; + zip.Save(); + } + // can now use contents of sw, eg store in an audit log + + + + Dim options as New ReadOptions + options.StatusMessageWriter = New System.IO.StringWriter + Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip", options) + Dim Threshold As New DateTime(2007, 7, 4) + ' We cannot remove the entry from the list, within the context of + ' an enumeration of said list. + ' So we add the doomed entry to a list to be removed later. + ' pass 1: mark the entries for removal + Dim MarkedEntries As New System.Collections.Generic.List(Of ZipEntry) + Dim e As ZipEntry + For Each e In zip + If (e.LastModified < Threshold) Then + MarkedEntries.Add(e) + End If + Next + ' pass 2: actually remove the entry. + Dim zombie As ZipEntry + For Each zombie In MarkedEntries + zip.RemoveEntry(zombie) + Next + zip.Comment = "This archive has been updated." + zip.Save + End Using + ' can now use contents of sw, eg store in an audit log + + + + + Thrown if the zipfile cannot be read. The implementation of + this method relies on System.IO.File.OpenRead, which + can throw a variety of exceptions, including specific + exceptions if a file is not found, an unauthorized access + exception, exceptions for poorly formatted filenames, and so + on. + + + + The name of the zip archive to open. + This can be a fully-qualified or relative pathname. + + + + The set of options to use when reading the zip file. + + + The ZipFile instance read from the zip archive. + + + + + + + Reads a zip file archive using the specified text encoding, the specified + TextWriter for status messages, and the specified ReadProgress event handler, + and returns the instance. + + + + The name of the zip archive to open. + This can be a fully-qualified or relative pathname. + + + + An event handler for Read operations. + + + + The System.IO.TextWriter to use for writing verbose status messages + during operations on the zip archive. A console application may wish to + pass System.Console.Out to get messages on the Console. A graphical + or headless application may wish to capture the messages in a different + TextWriter, such as a System.IO.StringWriter. + + + + The System.Text.Encoding to use when reading in the zip archive. Be + careful specifying the encoding. If the value you use here is not the same + as the Encoding used when the zip archive was created (possibly by a + different archiver) you will get unexpected results and possibly exceptions. + + + The instance read from the zip archive. + + + + + Reads a zip archive from a stream. + + + + + + When reading from a file, it's probably easier to just use + ZipFile.Read(String, ReadOptions). This + overload is useful when when the zip archive content is + available from an already-open stream. The stream must be + open and readable and seekable when calling this method. The + stream is left open when the reading is completed. + + + + Using this overload, the stream is read using the default + System.Text.Encoding, which is the IBM437 + codepage. If you want to specify the encoding to use when + reading the zipfile content, see + ZipFile.Read(Stream, ReadOptions). This + + + + Reading of zip content begins at the current position in the + stream. This means if you have a stream that concatenates + regular data and zip data, if you position the open, readable + stream at the start of the zip data, you will be able to read + the zip archive using this constructor, or any of the ZipFile + constructors that accept a as + input. Some examples of where this might be useful: the zip + content is concatenated at the end of a regular EXE file, as + some self-extracting archives do. (Note: SFX files produced + by DotNetZip do not work this way; they can be read as normal + ZIP files). Another example might be a stream being read from + a database, where the zip content is embedded within an + aggregate stream of data. + + + + + + + This example shows how to Read zip content from a stream, and + extract one entry into a different stream. In this example, + the filename "NameOfEntryInArchive.doc", refers only to the + name of the entry within the zip archive. A file by that + name is not created in the filesystem. The I/O is done + strictly with the given streams. + + + + using (ZipFile zip = ZipFile.Read(InputStream)) + { + zip.Extract("NameOfEntryInArchive.doc", OutputStream); + } + + + + Using zip as ZipFile = ZipFile.Read(InputStream) + zip.Extract("NameOfEntryInArchive.doc", OutputStream) + End Using + + + + the stream containing the zip data. + + The ZipFile instance read from the stream + + + + + Reads a zip file archive from the given stream using the + specified options. + + + + + + When reading from a file, it's probably easier to just use + ZipFile.Read(String, ReadOptions). This + overload is useful when when the zip archive content is + available from an already-open stream. The stream must be + open and readable and seekable when calling this method. The + stream is left open when the reading is completed. + + + + Reading of zip content begins at the current position in the + stream. This means if you have a stream that concatenates + regular data and zip data, if you position the open, readable + stream at the start of the zip data, you will be able to read + the zip archive using this constructor, or any of the ZipFile + constructors that accept a as + input. Some examples of where this might be useful: the zip + content is concatenated at the end of a regular EXE file, as + some self-extracting archives do. (Note: SFX files produced + by DotNetZip do not work this way; they can be read as normal + ZIP files). Another example might be a stream being read from + a database, where the zip content is embedded within an + aggregate stream of data. + + + + the stream containing the zip data. + + + The set of options to use when reading the zip file. + + + + Thrown if the zip archive cannot be read. + + + The ZipFile instance read from the stream. + + + + + + + Reads a zip archive from a stream, using the specified text Encoding, the + specified TextWriter for status messages, + and the specified ReadProgress event handler. + + + + + Reading of zip content begins at the current position in the stream. This + means if you have a stream that concatenates regular data and zip data, if + you position the open, readable stream at the start of the zip data, you + will be able to read the zip archive using this constructor, or any of the + ZipFile constructors that accept a as + input. Some examples of where this might be useful: the zip content is + concatenated at the end of a regular EXE file, as some self-extracting + archives do. (Note: SFX files produced by DotNetZip do not work this + way). Another example might be a stream being read from a database, where + the zip content is embedded within an aggregate stream of data. + + + + the stream containing the zip data. + + + The System.IO.TextWriter to which verbose status messages are written + during operations on the ZipFile. For example, in a console + application, System.Console.Out works, and will get a message for each entry + added to the ZipFile. If the TextWriter is null, no verbose messages + are written. + + + + The text encoding to use when reading entries that do not have the UTF-8 + encoding bit set. Be careful specifying the encoding. If the value you use + here is not the same as the Encoding used when the zip archive was created + (possibly by a different archiver) you will get unexpected results and + possibly exceptions. See the + property for more information. + + + + An event handler for Read operations. + + + an instance of ZipFile + + + + Checks the given file to see if it appears to be a valid zip file. + + + + + Calling this method is equivalent to calling with the testExtract parameter set to false. + + + + The file to check. + true if the file appears to be a zip file. + + + + Checks a file to see if it is a valid zip file. + + + + + This method opens the specified zip file, reads in the zip archive, + verifying the ZIP metadata as it reads. + + + + If everything succeeds, then the method returns true. If anything fails - + for example if an incorrect signature or CRC is found, indicating a + corrupt file, the the method returns false. This method also returns + false for a file that does not exist. + + + + If is true, as part of its check, this + method reads in the content for each entry, expands it, and checks CRCs. + This provides an additional check beyond verifying the zip header and + directory data. + + + + If is true, and if any of the zip entries + are protected with a password, this method will return false. If you want + to verify a ZipFile that has entries which are protected with a + password, you will need to do that manually. + + + + + The zip file to check. + true if the caller wants to extract each entry. + true if the file contains a valid zip file. + + + + Checks a stream to see if it contains a valid zip archive. + + + + + This method reads the zip archive contained in the specified stream, verifying + the ZIP metadata as it reads. If testExtract is true, this method also extracts + each entry in the archive, dumping all the bits into . + + + + If everything succeeds, then the method returns true. If anything fails - + for example if an incorrect signature or CRC is found, indicating a corrupt + file, the the method returns false. This method also returns false for a + file that does not exist. + + + + If testExtract is true, this method reads in the content for each + entry, expands it, and checks CRCs. This provides an additional check + beyond verifying the zip header data. + + + + If testExtract is true, and if any of the zip entries are protected + with a password, this method will return false. If you want to verify a + ZipFile that has entries which are protected with a password, you will need + to do that manually. + + + + + + The stream to check. + true if the caller wants to extract each entry. + true if the stream contains a valid zip archive. + + + + Delete file with retry on UnauthorizedAccessException. + + + + + When calling File.Delete() on a file that has been "recently" + created, the call sometimes fails with + UnauthorizedAccessException. This method simply retries the Delete 3 + times with a sleep between tries. + + + + the name of the file to be deleted + + + + Saves the Zip archive to a file, specified by the Name property of the + ZipFile. + + + + + The ZipFile instance is written to storage, typically a zip file + in a filesystem, only when the caller calls Save. In the typical + case, the Save operation writes the zip content to a temporary file, and + then renames the temporary file to the desired name. If necessary, this + method will delete a pre-existing file before the rename. + + + + The property is specified either explicitly, + or implicitly using one of the parameterized ZipFile constructors. For + COM Automation clients, the Name property must be set explicitly, + because COM Automation clients cannot call parameterized constructors. + + + + When using a filesystem file for the Zip output, it is possible to call + Save multiple times on the ZipFile instance. With each + call the zip content is re-written to the same output file. + + + + Data for entries that have been added to the ZipFile instance is + written to the output when the Save method is called. This means + that the input streams for those entries must be available at the time + the application calls Save. If, for example, the application + adds entries with AddEntry using a dynamically-allocated + MemoryStream, the memory stream must not have been disposed + before the call to Save. See the property for more discussion of the + availability requirements of the input stream for an entry, and an + approach for providing just-in-time stream lifecycle management. + + + + + + + + Thrown if you haven't specified a location or stream for saving the zip, + either in the constructor or by setting the Name property, or if you try + to save a regular zip archive to a filename with a .exe extension. + + + + Thrown if is non-zero, and the number + of segments that would be generated for the spanned zip file during the + save operation exceeds 99. If this happens, you need to increase the + segment size. + + + + + + Save the file to a new zipfile, with the given name. + + + + + This method allows the application to explicitly specify the name of the zip + file when saving. Use this when creating a new zip file, or when + updating a zip archive. + + + + An application can also save a zip archive in several places by calling this + method multiple times in succession, with different filenames. + + + + The ZipFile instance is written to storage, typically a zip file in a + filesystem, only when the caller calls Save. The Save operation writes + the zip content to a temporary file, and then renames the temporary file + to the desired name. If necessary, this method will delete a pre-existing file + before the rename. + + + + + + Thrown if you specify a directory for the filename. + + + + The name of the zip archive to save to. Existing files will + be overwritten with great prejudice. + + + + This example shows how to create and Save a zip file. + + using (ZipFile zip = new ZipFile()) + { + zip.AddDirectory(@"c:\reports\January"); + zip.Save("January.zip"); + } + + + + Using zip As New ZipFile() + zip.AddDirectory("c:\reports\January") + zip.Save("January.zip") + End Using + + + + + + This example shows how to update a zip file. + + using (ZipFile zip = ZipFile.Read("ExistingArchive.zip")) + { + zip.AddFile("NewData.csv"); + zip.Save("UpdatedArchive.zip"); + } + + + + Using zip As ZipFile = ZipFile.Read("ExistingArchive.zip") + zip.AddFile("NewData.csv") + zip.Save("UpdatedArchive.zip") + End Using + + + + + + + Save the zip archive to the specified stream. + + + + + The ZipFile instance is written to storage - typically a zip file + in a filesystem, but using this overload, the storage can be anything + accessible via a writable stream - only when the caller calls Save. + + + + Use this method to save the zip content to a stream directly. A common + scenario is an ASP.NET application that dynamically generates a zip file + and allows the browser to download it. The application can call + Save(Response.OutputStream) to write a zipfile directly to the + output stream, without creating a zip file on the disk on the ASP.NET + server. + + + + Be careful when saving a file to a non-seekable stream, including + Response.OutputStream. When DotNetZip writes to a non-seekable + stream, the zip archive is formatted in such a way that may not be + compatible with all zip tools on all platforms. It's a perfectly legal + and compliant zip file, but some people have reported problems opening + files produced this way using the Mac OS archive utility. + + + + + + + This example saves the zipfile content into a MemoryStream, and + then gets the array of bytes from that MemoryStream. + + + using (var zip = new Ionic.Zip.ZipFile()) + { + zip.CompressionLevel= Ionic.Zlib.CompressionLevel.BestCompression; + zip.Password = "VerySecret."; + zip.Encryption = EncryptionAlgorithm.WinZipAes128; + zip.AddFile(sourceFileName); + MemoryStream output = new MemoryStream(); + zip.Save(output); + + byte[] zipbytes = output.ToArray(); + } + + + + + + This example shows a pitfall you should avoid. DO NOT read + from a stream, then try to save to the same stream. DO + NOT DO THIS: + + + + using (var fs = new FileSteeam(filename, FileMode.Open)) + { + using (var zip = Ionic.Zip.ZipFile.Read(inputStream)) + { + zip.AddEntry("Name1.txt", "this is the content"); + zip.Save(inputStream); // NO NO NO!! + } + } + + + + Better like this: + + + + using (var zip = Ionic.Zip.ZipFile.Read(filename)) + { + zip.AddEntry("Name1.txt", "this is the content"); + zip.Save(); // YES! + } + + + + + + The System.IO.Stream to write to. It must be + writable. If you created the ZipFile instanct by calling + ZipFile.Read(), this stream must not be the same stream + you passed to ZipFile.Read(). + + + + + Adds to the ZipFile a set of files from the current working directory on + disk, that conform to the specified criteria. + + + + + This method selects files from the the current working directory matching + the specified criteria, and adds them to the ZipFile. + + + + Specify the criteria in statements of 3 elements: a noun, an operator, and + a value. Consider the string "name != *.doc" . The noun is "name". The + operator is "!=", implying "Not Equal". The value is "*.doc". That + criterion, in English, says "all files with a name that does not end in + the .doc extension." + + + + Supported nouns include "name" (or "filename") for the filename; "atime", + "mtime", and "ctime" for last access time, last modfied time, and created + time of the file, respectively; "attributes" (or "attrs") for the file + attributes; "size" (or "length") for the file length (uncompressed), and + "type" for the type of object, either a file or a directory. The + "attributes", "name" and "type" nouns both support = and != as operators. + The "size", "atime", "mtime", and "ctime" nouns support = and !=, and + >, >=, <, <= as well. The times are taken to be expressed in + local time. + + + + Specify values for the file attributes as a string with one or more of the + characters H,R,S,A,I,L in any order, implying file attributes of Hidden, + ReadOnly, System, Archive, NotContextIndexed, and ReparsePoint (symbolic + link) respectively. + + + + To specify a time, use YYYY-MM-DD-HH:mm:ss or YYYY/MM/DD-HH:mm:ss as the + format. If you omit the HH:mm:ss portion, it is assumed to be 00:00:00 + (midnight). + + + + The value for a size criterion is expressed in integer quantities of bytes, + kilobytes (use k or kb after the number), megabytes (m or mb), or gigabytes + (g or gb). + + + + The value for a name is a pattern to match against the filename, potentially + including wildcards. The pattern follows CMD.exe glob rules: * implies one + or more of any character, while ? implies one character. If the name + pattern contains any slashes, it is matched to the entire filename, + including the path; otherwise, it is matched against only the filename + without the path. This means a pattern of "*\*.*" matches all files one + directory level deep, while a pattern of "*.*" matches all files in all + directories. + + + + To specify a name pattern that includes spaces, use single quotes around the + pattern. A pattern of "'* *.*'" will match all files that have spaces in + the filename. The full criteria string for that would be "name = '* *.*'" . + + + + The value for a type criterion is either F (implying a file) or D (implying + a directory). + + + + Some examples: + + + + + criteria + Files retrieved + + + + name != *.xls + any file with an extension that is not .xls + + + + + name = *.mp3 + any file with a .mp3 extension. + + + + + *.mp3 + (same as above) any file with a .mp3 extension. + + + + + attributes = A + all files whose attributes include the Archive bit. + + + + + attributes != H + all files whose attributes do not include the Hidden bit. + + + + + mtime > 2009-01-01 + all files with a last modified time after January 1st, 2009. + + + + + size > 2gb + all files whose uncompressed size is greater than 2gb. + + + + + type = D + all directories in the filesystem. + + + + + + You can combine criteria with the conjunctions AND or OR. Using a string + like "name = *.txt AND size >= 100k" for the selectionCriteria retrieves + entries whose names end in .txt, and whose uncompressed size is greater than + or equal to 100 kilobytes. + + + + For more complex combinations of criteria, you can use parenthesis to group + clauses in the boolean logic. Without parenthesis, the precedence of the + criterion atoms is determined by order of appearance. Unlike the C# + language, the AND conjunction does not take precendence over the logical OR. + This is important only in strings that contain 3 or more criterion atoms. + In other words, "name = *.txt and size > 1000 or attributes = H" implies + "((name = *.txt AND size > 1000) OR attributes = H)" while "attributes = + H OR name = *.txt and size > 1000" evaluates to "((attributes = H OR name + = *.txt) AND size > 1000)". When in doubt, use parenthesis. + + + + Using time properties requires some extra care. If you want to retrieve all + entries that were last updated on 2009 February 14, specify a time range + like so:"mtime >= 2009-02-14 AND mtime < 2009-02-15". Read this to + say: all files updated after 12:00am on February 14th, until 12:00am on + February 15th. You can use the same bracketing approach to specify any time + period - a year, a month, a week, and so on. + + + + The syntax allows one special case: if you provide a string with no spaces, it is + treated as a pattern to match for the filename. Therefore a string like "*.xls" + will be equivalent to specifying "name = *.xls". + + + + There is no logic in this method that insures that the file inclusion + criteria are internally consistent. For example, it's possible to specify + criteria that says the file must have a size of less than 100 bytes, as well + as a size that is greater than 1000 bytes. Obviously no file will ever + satisfy such criteria, but this method does not detect such logical + inconsistencies. The caller is responsible for insuring the criteria are + sensible. + + + + Using this method, the file selection does not recurse into + subdirectories, and the full path of the selected files is included in the + entries added into the zip archive. If you don't like these behaviors, + see the other overloads of this method. + + + + + This example zips up all *.csv files in the current working directory. + + using (ZipFile zip = new ZipFile()) + { + // To just match on filename wildcards, + // use the shorthand form of the selectionCriteria string. + zip.AddSelectedFiles("*.csv"); + zip.Save(PathToZipArchive); + } + + + Using zip As ZipFile = New ZipFile() + zip.AddSelectedFiles("*.csv") + zip.Save(PathToZipArchive) + End Using + + + + The criteria for file selection + + + + Adds to the ZipFile a set of files from the disk that conform to the + specified criteria, optionally recursing into subdirectories. + + + + + This method selects files from the the current working directory matching + the specified criteria, and adds them to the ZipFile. If + recurseDirectories is true, files are also selected from + subdirectories, and the directory structure in the filesystem is + reproduced in the zip archive, rooted at the current working directory. + + + + Using this method, the full path of the selected files is included in the + entries added into the zip archive. If you don't want this behavior, use + one of the overloads of this method that allows the specification of a + directoryInArchive. + + + + For details on the syntax for the selectionCriteria parameter, see . + + + + + + + This example zips up all *.xml files in the current working directory, or any + subdirectory, that are larger than 1mb. + + + using (ZipFile zip = new ZipFile()) + { + // Use a compound expression in the selectionCriteria string. + zip.AddSelectedFiles("name = *.xml and size > 1024kb", true); + zip.Save(PathToZipArchive); + } + + + Using zip As ZipFile = New ZipFile() + ' Use a compound expression in the selectionCriteria string. + zip.AddSelectedFiles("name = *.xml and size > 1024kb", true) + zip.Save(PathToZipArchive) + End Using + + + + The criteria for file selection + + + If true, the file selection will recurse into subdirectories. + + + + + Adds to the ZipFile a set of files from a specified directory in the + filesystem, that conform to the specified criteria. + + + + + This method selects files that conform to the specified criteria, from the + the specified directory on disk, and adds them to the ZipFile. The search + does not recurse into subdirectores. + + + + Using this method, the full filesystem path of the files on disk is + reproduced on the entries added to the zip file. If you don't want this + behavior, use one of the other overloads of this method. + + + + For details on the syntax for the selectionCriteria parameter, see . + + + + + + + This example zips up all *.xml files larger than 1mb in the directory + given by "d:\rawdata". + + + using (ZipFile zip = new ZipFile()) + { + // Use a compound expression in the selectionCriteria string. + zip.AddSelectedFiles("name = *.xml and size > 1024kb", "d:\\rawdata"); + zip.Save(PathToZipArchive); + } + + + + Using zip As ZipFile = New ZipFile() + ' Use a compound expression in the selectionCriteria string. + zip.AddSelectedFiles("name = *.xml and size > 1024kb", "d:\rawdata) + zip.Save(PathToZipArchive) + End Using + + + + The criteria for file selection + + + The name of the directory on the disk from which to select files. + + + + + Adds to the ZipFile a set of files from the specified directory on disk, + that conform to the specified criteria. + + + + + + This method selects files from the the specified disk directory matching + the specified selection criteria, and adds them to the ZipFile. If + recurseDirectories is true, files are also selected from + subdirectories. + + + + The full directory structure in the filesystem is reproduced on the + entries added to the zip archive. If you don't want this behavior, use + one of the overloads of this method that allows the specification of a + directoryInArchive. + + + + For details on the syntax for the selectionCriteria parameter, see . + + + + + + This example zips up all *.csv files in the "files" directory, or any + subdirectory, that have been saved since 2009 February 14th. + + + using (ZipFile zip = new ZipFile()) + { + // Use a compound expression in the selectionCriteria string. + zip.AddSelectedFiles("name = *.csv and mtime > 2009-02-14", "files", true); + zip.Save(PathToZipArchive); + } + + + Using zip As ZipFile = New ZipFile() + ' Use a compound expression in the selectionCriteria string. + zip.AddSelectedFiles("name = *.csv and mtime > 2009-02-14", "files", true) + zip.Save(PathToZipArchive) + End Using + + + + + This example zips up all files in the current working + directory, and all its child directories, except those in + the excludethis subdirectory. + + Using Zip As ZipFile = New ZipFile(zipfile) + Zip.AddSelectedFfiles("name != 'excludethis\*.*'", datapath, True) + Zip.Save() + End Using + + + + The criteria for file selection + + + The filesystem path from which to select files. + + + + If true, the file selection will recurse into subdirectories. + + + + + Adds to the ZipFile a selection of files from the specified directory on + disk, that conform to the specified criteria, and using a specified root + path for entries added to the zip archive. + + + + + This method selects files from the specified disk directory matching the + specified selection criteria, and adds those files to the ZipFile, using + the specified directory path in the archive. The search does not recurse + into subdirectories. For details on the syntax for the selectionCriteria + parameter, see . + + + + + + + This example zips up all *.psd files in the "photos" directory that have + been saved since 2009 February 14th, and puts them all in a zip file, + using the directory name of "content" in the zip archive itself. When the + zip archive is unzipped, the folder containing the .psd files will be + named "content". + + + using (ZipFile zip = new ZipFile()) + { + // Use a compound expression in the selectionCriteria string. + zip.AddSelectedFiles("name = *.psd and mtime > 2009-02-14", "photos", "content"); + zip.Save(PathToZipArchive); + } + + + Using zip As ZipFile = New ZipFile + zip.AddSelectedFiles("name = *.psd and mtime > 2009-02-14", "photos", "content") + zip.Save(PathToZipArchive) + End Using + + + + + The criteria for selection of files to add to the ZipFile. + + + + The path to the directory in the filesystem from which to select files. + + + + Specifies a directory path to use to in place of the + directoryOnDisk. This path may, or may not, correspond to a real + directory in the current filesystem. If the files within the zip are + later extracted, this is the path used for the extracted file. Passing + null (nothing in VB) will use the path on the file name, if any; in other + words it would use directoryOnDisk, plus any subdirectory. Passing + the empty string ("") will insert the item at the root path within the + archive. + + + + + Adds to the ZipFile a selection of files from the specified directory on + disk, that conform to the specified criteria, optionally recursing through + subdirectories, and using a specified root path for entries added to the + zip archive. + + + + This method selects files from the specified disk directory that match the + specified selection criteria, and adds those files to the ZipFile, using + the specified directory path in the archive. If recurseDirectories + is true, files are also selected from subdirectories, and the directory + structure in the filesystem is reproduced in the zip archive, rooted at + the directory specified by directoryOnDisk. For details on the + syntax for the selectionCriteria parameter, see . + + + + + This example zips up all files that are NOT *.pst files, in the current + working directory and any subdirectories. + + + using (ZipFile zip = new ZipFile()) + { + zip.AddSelectedFiles("name != *.pst", SourceDirectory, "backup", true); + zip.Save(PathToZipArchive); + } + + + Using zip As ZipFile = New ZipFile + zip.AddSelectedFiles("name != *.pst", SourceDirectory, "backup", true) + zip.Save(PathToZipArchive) + End Using + + + + + The criteria for selection of files to add to the ZipFile. + + + + The path to the directory in the filesystem from which to select files. + + + + Specifies a directory path to use to in place of the + directoryOnDisk. This path may, or may not, correspond to a real + directory in the current filesystem. If the files within the zip are + later extracted, this is the path used for the extracted file. Passing + null (nothing in VB) will use the path on the file name, if any; in other + words it would use directoryOnDisk, plus any subdirectory. Passing + the empty string ("") will insert the item at the root path within the + archive. + + + + If true, the method also scans subdirectories for files matching the + criteria. + + + + + Updates the ZipFile with a selection of files from the disk that conform + to the specified criteria. + + + + This method selects files from the specified disk directory that match the + specified selection criteria, and Updates the ZipFile with those + files, using the specified directory path in the archive. If + recurseDirectories is true, files are also selected from + subdirectories, and the directory structure in the filesystem is + reproduced in the zip archive, rooted at the directory specified by + directoryOnDisk. For details on the syntax for the + selectionCriteria parameter, see . + + + + The criteria for selection of files to add to the ZipFile. + + + + The path to the directory in the filesystem from which to select files. + + + + Specifies a directory path to use to in place of the + directoryOnDisk. This path may, or may not, correspond to a + real directory in the current filesystem. If the files within the zip + are later extracted, this is the path used for the extracted file. + Passing null (nothing in VB) will use the path on the file name, if + any; in other words it would use directoryOnDisk, plus any + subdirectory. Passing the empty string ("") will insert the item at + the root path within the archive. + + + + If true, the method also scans subdirectories for files matching the criteria. + + + + + + + Retrieve entries from the zipfile by specified criteria. + + + + + This method allows callers to retrieve the collection of entries from the zipfile + that fit the specified criteria. The criteria are described in a string format, and + can include patterns for the filename; constraints on the size of the entry; + constraints on the last modified, created, or last accessed time for the file + described by the entry; or the attributes of the entry. + + + + For details on the syntax for the selectionCriteria parameter, see . + + + + This method is intended for use with a ZipFile that has been read from storage. + When creating a new ZipFile, this method will work only after the ZipArchive has + been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip + archive from storage.) Calling SelectEntries on a ZipFile that has not yet been + saved will deliver undefined results. + + + + + Thrown if selectionCriteria has an invalid syntax. + + + + This example selects all the PhotoShop files from within an archive, and extracts them + to the current working directory. + + using (ZipFile zip1 = ZipFile.Read(ZipFileName)) + { + var PhotoShopFiles = zip1.SelectEntries("*.psd"); + foreach (ZipEntry psd in PhotoShopFiles) + { + psd.Extract(); + } + } + + + Using zip1 As ZipFile = ZipFile.Read(ZipFileName) + Dim PhotoShopFiles as ICollection(Of ZipEntry) + PhotoShopFiles = zip1.SelectEntries("*.psd") + Dim psd As ZipEntry + For Each psd In PhotoShopFiles + psd.Extract + Next + End Using + + + the string that specifies which entries to select + a collection of ZipEntry objects that conform to the inclusion spec + + + + Retrieve entries from the zipfile by specified criteria. + + + + + This method allows callers to retrieve the collection of entries from the zipfile + that fit the specified criteria. The criteria are described in a string format, and + can include patterns for the filename; constraints on the size of the entry; + constraints on the last modified, created, or last accessed time for the file + described by the entry; or the attributes of the entry. + + + + For details on the syntax for the selectionCriteria parameter, see . + + + + This method is intended for use with a ZipFile that has been read from storage. + When creating a new ZipFile, this method will work only after the ZipArchive has + been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip + archive from storage.) Calling SelectEntries on a ZipFile that has not yet been + saved will deliver undefined results. + + + + + Thrown if selectionCriteria has an invalid syntax. + + + + + using (ZipFile zip1 = ZipFile.Read(ZipFileName)) + { + var UpdatedPhotoShopFiles = zip1.SelectEntries("*.psd", "UpdatedFiles"); + foreach (ZipEntry e in UpdatedPhotoShopFiles) + { + // prompt for extract here + if (WantExtract(e.FileName)) + e.Extract(); + } + } + + + Using zip1 As ZipFile = ZipFile.Read(ZipFileName) + Dim UpdatedPhotoShopFiles As ICollection(Of ZipEntry) = zip1.SelectEntries("*.psd", "UpdatedFiles") + Dim e As ZipEntry + For Each e In UpdatedPhotoShopFiles + ' prompt for extract here + If Me.WantExtract(e.FileName) Then + e.Extract + End If + Next + End Using + + + the string that specifies which entries to select + + + the directory in the archive from which to select entries. If null, then + all directories in the archive are used. + + + a collection of ZipEntry objects that conform to the inclusion spec + + + + Remove entries from the zipfile by specified criteria. + + + + + This method allows callers to remove the collection of entries from the zipfile + that fit the specified criteria. The criteria are described in a string format, and + can include patterns for the filename; constraints on the size of the entry; + constraints on the last modified, created, or last accessed time for the file + described by the entry; or the attributes of the entry. + + + + For details on the syntax for the selectionCriteria parameter, see . + + + + This method is intended for use with a ZipFile that has been read from storage. + When creating a new ZipFile, this method will work only after the ZipArchive has + been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip + archive from storage.) Calling SelectEntries on a ZipFile that has not yet been + saved will deliver undefined results. + + + + + Thrown if selectionCriteria has an invalid syntax. + + + + This example removes all entries in a zip file that were modified prior to January 1st, 2008. + + using (ZipFile zip1 = ZipFile.Read(ZipFileName)) + { + // remove all entries from prior to Jan 1, 2008 + zip1.RemoveEntries("mtime < 2008-01-01"); + // don't forget to save the archive! + zip1.Save(); + } + + + Using zip As ZipFile = ZipFile.Read(ZipFileName) + ' remove all entries from prior to Jan 1, 2008 + zip1.RemoveEntries("mtime < 2008-01-01") + ' do not forget to save the archive! + zip1.Save + End Using + + + the string that specifies which entries to select + the number of entries removed + + + + Remove entries from the zipfile by specified criteria, and within the specified + path in the archive. + + + + + This method allows callers to remove the collection of entries from the zipfile + that fit the specified criteria. The criteria are described in a string format, and + can include patterns for the filename; constraints on the size of the entry; + constraints on the last modified, created, or last accessed time for the file + described by the entry; or the attributes of the entry. + + + + For details on the syntax for the selectionCriteria parameter, see . + + + + This method is intended for use with a ZipFile that has been read from storage. + When creating a new ZipFile, this method will work only after the ZipArchive has + been Saved to the disk (the ZipFile class subsequently and implicitly reads the Zip + archive from storage.) Calling SelectEntries on a ZipFile that has not yet been + saved will deliver undefined results. + + + + + Thrown if selectionCriteria has an invalid syntax. + + + + + using (ZipFile zip1 = ZipFile.Read(ZipFileName)) + { + // remove all entries from prior to Jan 1, 2008 + zip1.RemoveEntries("mtime < 2008-01-01", "documents"); + // a call to ZipFile.Save will make the modifications permanent + zip1.Save(); + } + + + Using zip As ZipFile = ZipFile.Read(ZipFileName) + ' remove all entries from prior to Jan 1, 2008 + zip1.RemoveEntries("mtime < 2008-01-01", "documents") + ' a call to ZipFile.Save will make the modifications permanent + zip1.Save + End Using + + + + the string that specifies which entries to select + + the directory in the archive from which to select entries. If null, then + all directories in the archive are used. + + the number of entries removed + + + + Selects and Extracts a set of Entries from the ZipFile. + + + + + The entries are extracted into the current working directory. + + + + If any of the files to be extracted already exist, then the action taken is as + specified in the property on the + corresponding ZipEntry instance. By default, the action taken in this case is to + throw an exception. + + + + For information on the syntax of the selectionCriteria string, + see . + + + + + This example shows how extract all XML files modified after 15 January 2009. + + using (ZipFile zip = ZipFile.Read(zipArchiveName)) + { + zip.ExtractSelectedEntries("name = *.xml and mtime > 2009-01-15"); + } + + + the selection criteria for entries to extract. + + + + + + Selects and Extracts a set of Entries from the ZipFile. + + + + + The entries are extracted into the current working directory. When extraction would would + overwrite an existing filesystem file, the action taken is as specified in the + parameter. + + + + For information on the syntax of the string describing the entry selection criteria, + see . + + + + + This example shows how extract all XML files modified after 15 January 2009, + overwriting any existing files. + + using (ZipFile zip = ZipFile.Read(zipArchiveName)) + { + zip.ExtractSelectedEntries("name = *.xml and mtime > 2009-01-15", + ExtractExistingFileAction.OverwriteSilently); + } + + + + the selection criteria for entries to extract. + + + The action to take if extraction would overwrite an existing file. + + + + + Selects and Extracts a set of Entries from the ZipFile. + + + + + The entries are selected from the specified directory within the archive, and then + extracted into the current working directory. + + + + If any of the files to be extracted already exist, then the action taken is as + specified in the property on the + corresponding ZipEntry instance. By default, the action taken in this case is to + throw an exception. + + + + For information on the syntax of the string describing the entry selection criteria, + see . + + + + + This example shows how extract all XML files modified after 15 January 2009, + and writes them to the "unpack" directory. + + using (ZipFile zip = ZipFile.Read(zipArchiveName)) + { + zip.ExtractSelectedEntries("name = *.xml and mtime > 2009-01-15","unpack"); + } + + + + the selection criteria for entries to extract. + + + the directory in the archive from which to select entries. If null, then + all directories in the archive are used. + + + + + + + Selects and Extracts a set of Entries from the ZipFile. + + + + + The entries are extracted into the specified directory. If any of the files to be + extracted already exist, an exception will be thrown. + + + For information on the syntax of the string describing the entry selection criteria, + see . + + + + the selection criteria for entries to extract. + + + the directory in the archive from which to select entries. If null, then + all directories in the archive are used. + + + + the directory on the disk into which to extract. It will be created + if it does not exist. + + + + + Selects and Extracts a set of Entries from the ZipFile. + + + + + The entries are extracted into the specified directory. When extraction would would + overwrite an existing filesystem file, the action taken is as specified in the + parameter. + + + + For information on the syntax of the string describing the entry selection criteria, + see . + + + + + This example shows how extract all files with an XML extension or with a size larger than 100,000 bytes, + and puts them in the unpack directory. For any files that already exist in + that destination directory, they will not be overwritten. + + using (ZipFile zip = ZipFile.Read(zipArchiveName)) + { + zip.ExtractSelectedEntries("name = *.xml or size > 100000", + null, + "unpack", + ExtractExistingFileAction.DontOverwrite); + } + + + + the selection criteria for entries to extract. + + + The directory on the disk into which to extract. It will be created if it does not exist. + + + + The directory in the archive from which to select entries. If null, then + all directories in the archive are used. + + + + The action to take if extraction would overwrite an existing file. + + + + + + Saves the ZipFile instance to a self-extracting zip archive. + + + + + + The generated exe image will execute on any machine that has the .NET + Framework 2.0 installed on it. The generated exe image is also a + valid ZIP file, readable with DotNetZip or another Zip library or tool + such as WinZip. + + + + There are two "flavors" of self-extracting archive. The + WinFormsApplication version will pop up a GUI and allow the + user to select a target directory into which to extract. There's also + a checkbox allowing the user to specify to overwrite existing files, + and another checkbox to allow the user to request that Explorer be + opened to see the extracted files after extraction. The other flavor + is ConsoleApplication. A self-extractor generated with that + flavor setting will run from the command line. It accepts command-line + options to set the overwrite behavior, and to specify the target + extraction directory. + + + + There are a few temporary files created during the saving to a + self-extracting zip. These files are created in the directory pointed + to by , which defaults to . These temporary files are + removed upon successful completion of this method. + + + + When a user runs the WinForms SFX, the user's personal directory (Environment.SpecialFolder.Personal) + will be used as the default extract location. If you want to set the + default extract location, you should use the other overload of + SaveSelfExtractor()/ The user who runs the SFX will have the + opportunity to change the extract directory before extracting. When + the user runs the Command-Line SFX, the user must explicitly specify + the directory to which to extract. The .NET Framework 2.0 is required + on the computer when the self-extracting archive is run. + + + + NB: This method is not available in the version of DotNetZip build for + the .NET Compact Framework, nor in the "Reduced" DotNetZip library. + + + + + + + string DirectoryPath = "c:\\Documents\\Project7"; + using (ZipFile zip = new ZipFile()) + { + zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath)); + zip.Comment = "This will be embedded into a self-extracting console-based exe"; + zip.SaveSelfExtractor("archive.exe", SelfExtractorFlavor.ConsoleApplication); + } + + + Dim DirectoryPath As String = "c:\Documents\Project7" + Using zip As New ZipFile() + zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath)) + zip.Comment = "This will be embedded into a self-extracting console-based exe" + zip.SaveSelfExtractor("archive.exe", SelfExtractorFlavor.ConsoleApplication) + End Using + + + + + a pathname, possibly fully qualified, to be created. Typically it + will end in an .exe extension. + + Indicates whether a Winforms or Console self-extractor is + desired. + + + + Saves the ZipFile instance to a self-extracting zip archive, using + the specified save options. + + + + + This method saves a self extracting archive, using the specified save + options. These options include the flavor of the SFX, the default extract + directory, the icon file, and so on. See the documentation + for for more + details. + + + + The user who runs the SFX will have the opportunity to change the extract + directory before extracting. If at the time of extraction, the specified + directory does not exist, the SFX will create the directory before + extracting the files. + + + + + + This example saves a WinForms-based self-extracting archive EXE that + will use c:\ExtractHere as the default extract location. The C# code + shows syntax for .NET 3.0, which uses an object initializer for + the SelfExtractorOptions object. + + string DirectoryPath = "c:\\Documents\\Project7"; + using (ZipFile zip = new ZipFile()) + { + zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath)); + zip.Comment = "This will be embedded into a self-extracting WinForms-based exe"; + var options = new SelfExtractorOptions + { + Flavor = SelfExtractorFlavor.WinFormsApplication, + DefaultExtractDirectory = "%USERPROFILE%\\ExtractHere", + PostExtractCommandLine = ExeToRunAfterExtract, + SfxExeWindowTitle = "My Custom Window Title", + RemoveUnpackedFilesAfterExecute = true + }; + zip.SaveSelfExtractor("archive.exe", options); + } + + + Dim DirectoryPath As String = "c:\Documents\Project7" + Using zip As New ZipFile() + zip.AddDirectory(DirectoryPath, System.IO.Path.GetFileName(DirectoryPath)) + zip.Comment = "This will be embedded into a self-extracting console-based exe" + Dim options As New SelfExtractorOptions() + options.Flavor = SelfExtractorFlavor.WinFormsApplication + options.DefaultExtractDirectory = "%USERPROFILE%\\ExtractHere" + options.PostExtractCommandLine = ExeToRunAfterExtract + options.SfxExeWindowTitle = "My Custom Window Title" + options.RemoveUnpackedFilesAfterExecute = True + zip.SaveSelfExtractor("archive.exe", options) + End Using + + + + The name of the EXE to generate. + provides the options for creating the + Self-extracting archive. + + + + Generic IEnumerator support, for use of a ZipFile in an enumeration. + + + + You probably do not want to call GetEnumerator explicitly. Instead + it is implicitly called when you use a loop in C#, or a + For Each loop in VB.NET. + + + + This example reads a zipfile of a given name, then enumerates the + entries in that zip file, and displays the information about each + entry on the Console. + + using (ZipFile zip = ZipFile.Read(zipfile)) + { + bool header = true; + foreach (ZipEntry e in zip) + { + if (header) + { + System.Console.WriteLine("Zipfile: {0}", zip.Name); + System.Console.WriteLine("Version Needed: 0x{0:X2}", e.VersionNeeded); + System.Console.WriteLine("BitField: 0x{0:X2}", e.BitField); + System.Console.WriteLine("Compression Method: 0x{0:X2}", e.CompressionMethod); + System.Console.WriteLine("\n{1,-22} {2,-6} {3,4} {4,-8} {0}", + "Filename", "Modified", "Size", "Ratio", "Packed"); + System.Console.WriteLine(new System.String('-', 72)); + header = false; + } + + System.Console.WriteLine("{1,-22} {2,-6} {3,4:F0}% {4,-8} {0}", + e.FileName, + e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"), + e.UncompressedSize, + e.CompressionRatio, + e.CompressedSize); + + e.Extract(); + } + } + + + + Dim ZipFileToExtract As String = "c:\foo.zip" + Using zip As ZipFile = ZipFile.Read(ZipFileToExtract) + Dim header As Boolean = True + Dim e As ZipEntry + For Each e In zip + If header Then + Console.WriteLine("Zipfile: {0}", zip.Name) + Console.WriteLine("Version Needed: 0x{0:X2}", e.VersionNeeded) + Console.WriteLine("BitField: 0x{0:X2}", e.BitField) + Console.WriteLine("Compression Method: 0x{0:X2}", e.CompressionMethod) + Console.WriteLine(ChrW(10) & "{1,-22} {2,-6} {3,4} {4,-8} {0}", _ + "Filename", "Modified", "Size", "Ratio", "Packed" ) + Console.WriteLine(New String("-"c, 72)) + header = False + End If + Console.WriteLine("{1,-22} {2,-6} {3,4:F0}% {4,-8} {0}", _ + e.FileName, _ + e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"), _ + e.UncompressedSize, _ + e.CompressionRatio, _ + e.CompressedSize ) + e.Extract + Next + End Using + + + + A generic enumerator suitable for use within a foreach loop. + + + + An IEnumerator, for use of a ZipFile in a foreach construct. + + + + This method is included for COM support. An application generally does not call + this method directly. It is called implicitly by COM clients when enumerating + the entries in the ZipFile instance. In VBScript, this is done with a For Each + statement. In Javascript, this is done with new Enumerator(zipfile). + + + + The IEnumerator over the entries in the ZipFile. + + + + + Provides a human-readable string with information about the ZipFile. + + + + + The information string contains 10 lines or so, about each ZipEntry, + describing whether encryption is in use, the compressed and uncompressed + length of the entry, the offset of the entry, and so on. As a result the + information string can be very long for zip files that contain many + entries. + + + This information is mostly useful for diagnostic purposes. + + + + + + Indicates whether to perform a full scan of the zip file when reading it. + + + + + + You almost never want to use this property. + + + + When reading a zip file, if this flag is true (True in + VB), the entire zip archive will be scanned and searched for entries. + For large archives, this can take a very, long time. The much more + efficient default behavior is to read the zip directory, which is + stored at the end of the zip file. But, in some cases the directory is + corrupted and you need to perform a full scan of the zip file to + determine the contents of the zip file. This property lets you do + that, when necessary. + + + + This flag is effective only when calling . Normally you would read a ZipFile with the + static ZipFile.Read + method. But you can't set the FullScan property on the + ZipFile instance when you use a static factory method like + ZipFile.Read. + + + + + + + This example shows how to read a zip file using the full scan approach, + and then save it, thereby producing a corrected zip file. + + + using (var zip = new ZipFile()) + { + zip.FullScan = true; + zip.Initialize(zipFileName); + zip.Save(newName); + } + + + + Using zip As New ZipFile + zip.FullScan = True + zip.Initialize(zipFileName) + zip.Save(newName) + End Using + + + + + + + Whether to sort the ZipEntries before saving the file. + + + + The default is false. If you have a large number of zip entries, the sort + alone can consume significant time. + + + + + using (var zip = new ZipFile()) + { + zip.AddFiles(filesToAdd); + zip.SortEntriesBeforeSaving = true; + zip.Save(name); + } + + + + Using zip As New ZipFile + zip.AddFiles(filesToAdd) + zip.SortEntriesBeforeSaving = True + zip.Save(name) + End Using + + + + + + + Indicates whether NTFS Reparse Points, like junctions, should be + traversed during calls to AddDirectory(). + + + + By default, calls to AddDirectory() will traverse NTFS reparse + points, like mounted volumes, and directory junctions. An example + of a junction is the "My Music" directory in Windows Vista. In some + cases you may not want DotNetZip to traverse those directories. In + that case, set this property to false. + + + + + using (var zip = new ZipFile()) + { + zip.AddDirectoryWillTraverseReparsePoints = false; + zip.AddDirectory(dirToZip,"fodder"); + zip.Save(zipFileToCreate); + } + + + + + + Size of the IO buffer used while saving. + + + + + + First, let me say that you really don't need to bother with this. It is + here to allow for optimizations that you probably won't make! It will work + fine if you don't set or get this property at all. Ok? + + + + Now that we have that out of the way, the fine print: This + property affects the size of the buffer that is used for I/O for each + entry contained in the zip file. When a file is read in to be compressed, + it uses a buffer given by the size here. When you update a zip file, the + data for unmodified entries is copied from the first zip file to the + other, through a buffer given by the size here. + + + + Changing the buffer size affects a few things: first, for larger buffer + sizes, the memory used by the ZipFile, obviously, will be larger + during I/O operations. This may make operations faster for very much + larger files. Last, for any given entry, when you use a larger buffer + there will be fewer progress events during I/O operations, because there's + one progress event generated for each time the buffer is filled and then + emptied. + + + + The default buffer size is 8k. Increasing the buffer size may speed + things up as you compress larger files. But there are no hard-and-fast + rules here, eh? You won't know til you test it. And there will be a + limit where ever larger buffers actually slow things down. So as I said + in the beginning, it's probably best if you don't set or get this property + at all. + + + + + + This example shows how you might set a large buffer size for efficiency when + dealing with zip entries that are larger than 1gb. + + using (ZipFile zip = new ZipFile()) + { + zip.SaveProgress += this.zip1_SaveProgress; + zip.AddDirectory(directoryToZip, ""); + zip.UseZip64WhenSaving = Zip64Option.Always; + zip.BufferSize = 65536*8; // 65536 * 8 = 512k + zip.Save(ZipFileToCreate); + } + + + + + + Size of the work buffer to use for the ZLIB codec during compression. + + + + + When doing ZLIB or Deflate compression, the library fills a buffer, + then passes it to the compressor for compression. Then the library + reads out the compressed bytes. This happens repeatedly until there + is no more uncompressed data to compress. This property sets the + size of the buffer that will be used for chunk-wise compression. In + order for the setting to take effect, your application needs to set + this property before calling one of the ZipFile.Save() + overloads. + + + Setting this affects the performance and memory efficiency of + compression and decompression. For larger files, setting this to a + larger size may improve compression performance, but the exact + numbers vary depending on available memory, the size of the streams + you are compressing, and a bunch of other variables. I don't have + good firm recommendations on how to set it. You'll have to test it + yourself. Or just leave it alone and accept the default. + + + + + + Indicates whether extracted files should keep their paths as + stored in the zip archive. + + + + + This property affects Extraction. It is not used when creating zip + archives. + + + + With this property set to false, the default, extracting entries + from a zip file will create files in the filesystem that have the full + path associated to the entry within the zip file. With this property set + to true, extracting entries from the zip file results in files + with no path: the folders are "flattened." + + + + An example: suppose the zip file contains entries /directory1/file1.txt and + /directory2/file2.txt. With FlattenFoldersOnExtract set to false, + the files created will be \directory1\file1.txt and \directory2\file2.txt. + With the property set to true, the files created are file1.txt and file2.txt. + + + + + + + The compression strategy to use for all entries. + + + + Set the Strategy used by the ZLIB-compatible compressor, when + compressing entries using the DEFLATE method. Different compression + strategies work better on different sorts of data. The strategy + parameter can affect the compression ratio and the speed of + compression but not the correctness of the compresssion. For more + information see Ionic.Zlib.CompressionStrategy. + + + + + The name of the ZipFile, on disk. + + + + + + When the ZipFile instance was created by reading an archive using + one of the ZipFile.Read methods, this property represents the name + of the zip file that was read. When the ZipFile instance was + created by using the no-argument constructor, this value is null + (Nothing in VB). + + + + If you use the no-argument constructor, and you then explicitly set this + property, when you call , this name will + specify the name of the zip file created. Doing so is equivalent to + calling . When instantiating a + ZipFile by reading from a stream or byte array, the Name + property remains null. When saving to a stream, the Name + property is implicitly set to null. + + + + + + Sets the compression level to be used for entries subsequently added to + the zip archive. + + + + + Varying the compression level used on entries can affect the + size-vs-speed tradeoff when compression and decompressing data streams + or files. + + + + As with some other properties on the ZipFile class, like , , and , setting this property on a ZipFile + instance will cause the specified CompressionLevel to be used on all + items that are subsequently added to the + ZipFile instance. If you set this property after you have added + items to the ZipFile, but before you have called Save(), + those items will not use the specified compression level. + + + + If you do not set this property, the default compression level is used, + which normally gives a good balance of compression efficiency and + compression speed. In some tests, using BestCompression can + double the time it takes to compress, while delivering just a small + increase in compression efficiency. This behavior will vary with the + type of data you compress. If you are in doubt, just leave this setting + alone, and accept the default. + + + + + + The compression method for the zipfile. + + + + By default, the compression method is CompressionMethod.Deflate. + + + + + + + A comment attached to the zip archive. + + + + + + This property is read/write. It allows the application to specify a + comment for the ZipFile, or read the comment for the + ZipFile. After setting this property, changes are only made + permanent when you call a Save() method. + + + + According to PKWARE's + zip specification, the comment is not encrypted, even if there is a + password set on the zip file. + + + + The specification does not describe how to indicate the encoding used + on a comment string. Many "compliant" zip tools and libraries use + IBM437 as the code page for comments; DotNetZip, too, follows that + practice. On the other hand, there are situations where you want a + Comment to be encoded with something else, for example using code page + 950 "Big-5 Chinese". To fill that need, DotNetZip will encode the + comment following the same procedure it follows for encoding + filenames: (a) if is + Never, it uses the default encoding (IBM437). (b) if is Always, it always uses the + alternate encoding (). (c) if is AsNecessary, it uses the + alternate encoding only if the default encoding is not sufficient for + encoding the comment - in other words if decoding the result does not + produce the original string. This decision is taken at the time of + the call to ZipFile.Save(). + + + + When creating a zip archive using this library, it is possible to change + the value of between each + entry you add, and between adding entries and the call to + Save(). Don't do this. It will likely result in a zip file that is + not readable by any tool or application. For best interoperability, leave + alone, or specify it only + once, before adding any entries to the ZipFile instance. + + + + + + + Specifies whether the Creation, Access, and Modified times for entries + added to the zip file will be emitted in “Windows format” + when the zip archive is saved. + + + + + An application creating a zip archive can use this flag to explicitly + specify that the file times for the entries should or should not be stored + in the zip archive in the format used by Windows. By default this flag is + true, meaning the Windows-format times are stored in the zip + archive. + + + + When adding an entry from a file or directory, the Creation (), Access (), and Modified () times for the given entry are + automatically set from the filesystem values. When adding an entry from a + stream or string, all three values are implicitly set to + DateTime.Now. Applications can also explicitly set those times by + calling . + + + + PKWARE's + zip specification describes multiple ways to format these times in a + zip file. One is the format Windows applications normally use: 100ns ticks + since January 1, 1601 UTC. The other is a format Unix applications typically + use: seconds since January 1, 1970 UTC. Each format can be stored in an + "extra field" in the zip entry when saving the zip archive. The former + uses an extra field with a Header Id of 0x000A, while the latter uses a + header ID of 0x5455, although you probably don't need to know that. + + + + Not all tools and libraries can interpret these fields. Windows + compressed folders is one that can read the Windows Format timestamps, + while I believe the Infozip + tools can read the Unix format timestamps. Some tools and libraries + may be able to read only one or the other. DotNetZip can read or write + times in either or both formats. + + + + The times stored are taken from , , and . + + + + The value set here applies to all entries subsequently added to the + ZipFile. + + + + This property is not mutually exclusive of the property. It is possible and + legal and valid to produce a zip file that contains timestamps encoded in + the Unix format as well as in the Windows format, in addition to the LastModified time attached to each + entry in the archive, a time that is always stored in "DOS format". And, + notwithstanding the names PKWare uses for these time formats, any of them + can be read and written by any computer, on any operating system. But, + there are no guarantees that a program running on Mac or Linux will + gracefully handle a zip file with "Windows" formatted times, or that an + application that does not use DotNetZip but runs on Windows will be able to + handle file times in Unix format. + + + + When in doubt, test. Sorry, I haven't got a complete list of tools and + which sort of timestamps they can use and will tolerate. If you get any + good information and would like to pass it on, please do so and I will + include that information in this documentation. + + + + + This example shows how to save a zip file that contains file timestamps + in a format normally used by Unix. + + using (var zip = new ZipFile()) + { + // produce a zip file the Mac will like + zip.EmitTimesInWindowsFormatWhenSaving = false; + zip.EmitTimesInUnixFormatWhenSaving = true; + zip.AddDirectory(directoryToZip, "files"); + zip.Save(outputFile); + } + + + + Using zip As New ZipFile + '' produce a zip file the Mac will like + zip.EmitTimesInWindowsFormatWhenSaving = False + zip.EmitTimesInUnixFormatWhenSaving = True + zip.AddDirectory(directoryToZip, "files") + zip.Save(outputFile) + End Using + + + + + + + + + Specifies whether the Creation, Access, and Modified times + for entries added to the zip file will be emitted in "Unix(tm) + format" when the zip archive is saved. + + + + + An application creating a zip archive can use this flag to explicitly + specify that the file times for the entries should or should not be stored + in the zip archive in the format used by Unix. By default this flag is + false, meaning the Unix-format times are not stored in the zip + archive. + + + + When adding an entry from a file or directory, the Creation (), Access (), and Modified () times for the given entry are + automatically set from the filesystem values. When adding an entry from a + stream or string, all three values are implicitly set to DateTime.Now. + Applications can also explicitly set those times by calling . + + + + PKWARE's + zip specification describes multiple ways to format these times in a + zip file. One is the format Windows applications normally use: 100ns ticks + since January 1, 1601 UTC. The other is a format Unix applications + typically use: seconds since January 1, 1970 UTC. Each format can be + stored in an "extra field" in the zip entry when saving the zip + archive. The former uses an extra field with a Header Id of 0x000A, while + the latter uses a header ID of 0x5455, although you probably don't need to + know that. + + + + Not all tools and libraries can interpret these fields. Windows + compressed folders is one that can read the Windows Format timestamps, + while I believe the Infozip + tools can read the Unix format timestamps. Some tools and libraries may be + able to read only one or the other. DotNetZip can read or write times in + either or both formats. + + + + The times stored are taken from , , and . + + + + This property is not mutually exclusive of the property. It is possible and + legal and valid to produce a zip file that contains timestamps encoded in + the Unix format as well as in the Windows format, in addition to the LastModified time attached to each + entry in the zip archive, a time that is always stored in "DOS + format". And, notwithstanding the names PKWare uses for these time + formats, any of them can be read and written by any computer, on any + operating system. But, there are no guarantees that a program running on + Mac or Linux will gracefully handle a zip file with "Windows" formatted + times, or that an application that does not use DotNetZip but runs on + Windows will be able to handle file times in Unix format. + + + + When in doubt, test. Sorry, I haven't got a complete list of tools and + which sort of timestamps they can use and will tolerate. If you get any + good information and would like to pass it on, please do so and I will + include that information in this documentation. + + + + + + + + + Indicates whether verbose output is sent to the during AddXxx() and + ReadXxx() operations. + + + + This is a synthetic property. It returns true if the is non-null. + + + + + Indicates whether to perform case-sensitive matching on the filename when + retrieving entries in the zipfile via the string-based indexer. + + + + The default value is false, which means don't do case-sensitive + matching. In other words, retrieving zip["ReadMe.Txt"] is the same as + zip["readme.txt"]. It really makes sense to set this to true only + if you are not running on Windows, which has case-insensitive + filenames. But since this library is not built for non-Windows platforms, + in most cases you should just leave this property alone. + + + + + Indicates whether to encode entry filenames and entry comments using Unicode + (UTF-8). + + + + + The + PKWare zip specification provides for encoding file names and file + comments in either the IBM437 code page, or in UTF-8. This flag selects + the encoding according to that specification. By default, this flag is + false, and filenames and comments are encoded into the zip file in the + IBM437 codepage. Setting this flag to true will specify that filenames + and comments that cannot be encoded with IBM437 will be encoded with + UTF-8. + + + + Zip files created with strict adherence to the PKWare specification with + respect to UTF-8 encoding can contain entries with filenames containing + any combination of Unicode characters, including the full range of + characters from Chinese, Latin, Hebrew, Greek, Cyrillic, and many other + alphabets. However, because at this time, the UTF-8 portion of the PKWare + specification is not broadly supported by other zip libraries and + utilities, such zip files may not be readable by your favorite zip tool or + archiver. In other words, interoperability will decrease if you set this + flag to true. + + + + In particular, Zip files created with strict adherence to the PKWare + specification with respect to UTF-8 encoding will not work well with + Explorer in Windows XP or Windows Vista, because Windows compressed + folders, as far as I know, do not support UTF-8 in zip files. Vista can + read the zip files, but shows the filenames incorrectly. Unpacking from + Windows Vista Explorer will result in filenames that have rubbish + characters in place of the high-order UTF-8 bytes. + + + + Also, zip files that use UTF-8 encoding will not work well with Java + applications that use the java.util.zip classes, as of v5.0 of the Java + runtime. The Java runtime does not correctly implement the PKWare + specification in this regard. + + + + As a result, we have the unfortunate situation that "correct" behavior by + the DotNetZip library with regard to Unicode encoding of filenames during + zip creation will result in zip files that are readable by strictly + compliant and current tools (for example the most recent release of the + commercial WinZip tool); but these zip files will not be readable by + various other tools or libraries, including Windows Explorer. + + + + The DotNetZip library can read and write zip files with UTF8-encoded + entries, according to the PKware spec. If you use DotNetZip for both + creating and reading the zip file, and you use UTF-8, there will be no + loss of information in the filenames. For example, using a self-extractor + created by this library will allow you to unpack files correctly with no + loss of information in the filenames. + + + + If you do not set this flag, it will remain false. If this flag is false, + your ZipFile will encode all filenames and comments using the + IBM437 codepage. This can cause "loss of information" on some filenames, + but the resulting zipfile will be more interoperable with other + utilities. As an example of the loss of information, diacritics can be + lost. The o-tilde character will be down-coded to plain o. The c with a + cedilla (Unicode 0xE7) used in Portugese will be downcoded to a c. + Likewise, the O-stroke character (Unicode 248), used in Danish and + Norwegian, will be down-coded to plain o. Chinese characters cannot be + represented in codepage IBM437; when using the default encoding, Chinese + characters in filenames will be represented as ?. These are all examples + of "information loss". + + + + The loss of information associated to the use of the IBM437 encoding is + inconvenient, and can also lead to runtime errors. For example, using + IBM437, any sequence of 4 Chinese characters will be encoded as ????. If + your application creates a ZipFile, then adds two files, each with + names of four Chinese characters each, this will result in a duplicate + filename exception. In the case where you add a single file with a name + containing four Chinese characters, calling Extract() on the entry that + has question marks in the filename will result in an exception, because + the question mark is not legal for use within filenames on Windows. These + are just a few examples of the problems associated to loss of information. + + + + This flag is independent of the encoding of the content within the entries + in the zip file. Think of the zip file as a container - it supports an + encoding. Within the container are other "containers" - the file entries + themselves. The encoding within those entries is independent of the + encoding of the zip archive container for those entries. + + + + Rather than specify the encoding in a binary fashion using this flag, an + application can specify an arbitrary encoding via the property. Setting the encoding + explicitly when creating zip archives will result in non-compliant zip + files that, curiously, are fairly interoperable. The challenge is, the + PKWare specification does not provide for a way to specify that an entry + in a zip archive uses a code page that is neither IBM437 nor UTF-8. + Therefore if you set the encoding explicitly when creating a zip archive, + you must take care upon reading the zip archive to use the same code page. + If you get it wrong, the behavior is undefined and may result in incorrect + filenames, exceptions, stomach upset, hair loss, and acne. + + + + + + + Specify whether to use ZIP64 extensions when saving a zip archive. + + + + + + When creating a zip file, the default value for the property is . is + safest, in the sense that you will not get an Exception if a pre-ZIP64 + limit is exceeded. + + + + You may set the property at any time before calling Save(). + + + + When reading a zip file via the Zipfile.Read() method, DotNetZip + will properly read ZIP64-endowed zip archives, regardless of the value of + this property. DotNetZip will always read ZIP64 archives. This property + governs only whether DotNetZip will write them. Therefore, when updating + archives, be careful about setting this property after reading an archive + that may use ZIP64 extensions. + + + + An interesting question is, if you have set this property to + AsNecessary, and then successfully saved, does the resulting + archive use ZIP64 extensions or not? To learn this, check the property, after calling Save(). + + + + Have you thought about + donating? + + + + + + + + Indicates whether the archive requires ZIP64 extensions. + + + + + + This property is null (or Nothing in VB) if the archive has + not been saved, and there are fewer than 65334 ZipEntry items + contained in the archive. + + + + The Value is true if any of the following four conditions holds: + the uncompressed size of any entry is larger than 0xFFFFFFFF; the + compressed size of any entry is larger than 0xFFFFFFFF; the relative + offset of any entry within the zip archive is larger than 0xFFFFFFFF; or + there are more than 65534 entries in the archive. (0xFFFFFFFF = + 4,294,967,295). The result may not be known until a Save() is attempted + on the zip archive. The Value of this + property may be set only AFTER one of the Save() methods has been called. + + + + If none of the four conditions holds, and the archive has been saved, then + the Value is false. + + + + A Value of false does not indicate that the zip archive, as saved, + does not use ZIP64. It merely indicates that ZIP64 is not required. An + archive may use ZIP64 even when not required if the property is set to , or if the property is set to and the output stream was not + seekable. Use the property to determine if + the most recent Save() method resulted in an archive that utilized + the ZIP64 extensions. + + + + + + + + + Indicates whether the most recent Save() operation used ZIP64 extensions. + + + + + The use of ZIP64 extensions within an archive is not always necessary, and + for interoperability concerns, it may be desired to NOT use ZIP64 if + possible. The property can be + set to use ZIP64 extensions only when necessary. In those cases, + Sometimes applications want to know whether a Save() actually used ZIP64 + extensions. Applications can query this read-only property to learn + whether ZIP64 has been used in a just-saved ZipFile. + + + + The value is null (or Nothing in VB) if the archive has not + been saved. + + + + Non-null values (HasValue is true) indicate whether ZIP64 + extensions were used during the most recent Save() operation. The + ZIP64 extensions may have been used as required by any particular entry + because of its uncompressed or compressed size, or because the archive is + larger than 4294967295 bytes, or because there are more than 65534 entries + in the archive, or because the UseZip64WhenSaving property was set + to , or because the + UseZip64WhenSaving property was set to and the output stream was not seekable. + The value of this property does not indicate the reason the ZIP64 + extensions were used. + + + + + + + + + Indicates whether the most recent Read() operation read a zip file that uses + ZIP64 extensions. + + + + This property will return null (Nothing in VB) if you've added an entry after reading + the zip file. + + + + + The text encoding to use when writing new entries to the ZipFile, + for those entries that cannot be encoded with the default (IBM437) + encoding; or, the text encoding that was used when reading the entries + from the ZipFile. + + + + + In its + zip specification, PKWare describes two options for encoding + filenames and comments: using IBM437 or UTF-8. But, some archiving tools + or libraries do not follow the specification, and instead encode + characters using the system default code page. For example, WinRAR when + run on a machine in Shanghai may encode filenames with the Big-5 Chinese + (950) code page. This behavior is contrary to the Zip specification, but + it occurs anyway. + + + + When using DotNetZip to write zip archives that will be read by one of + these other archivers, set this property to specify the code page to use + when encoding the and for each ZipEntry in the zip file, for + values that cannot be encoded with the default codepage for zip files, + IBM437. This is why this property is "provisional". In all cases, IBM437 + is used where possible, in other words, where no loss of data would + result. It is possible, therefore, to have a given entry with a + Comment encoded in IBM437 and a FileName encoded with the + specified "provisional" codepage. + + + + Be aware that a zip file created after you've explicitly set the property to a value other than + IBM437 may not be compliant to the PKWare specification, and may not be + readable by compliant archivers. On the other hand, many (most?) + archivers are non-compliant and can read zip files created in arbitrary + code pages. The trick is to use or specify the proper codepage when + reading the zip. + + + + When creating a zip archive using this library, it is possible to change + the value of between each + entry you add, and between adding entries and the call to + Save(). Don't do this. It will likely result in a zipfile that is + not readable. For best interoperability, either leave alone, or specify it only once, + before adding any entries to the ZipFile instance. There is one + exception to this recommendation, described later. + + + + When using an arbitrary, non-UTF8 code page for encoding, there is no + standard way for the creator application - whether DotNetZip, WinZip, + WinRar, or something else - to formally specify in the zip file which + codepage has been used for the entries. As a result, readers of zip files + are not able to inspect the zip file and determine the codepage that was + used for the entries contained within it. It is left to the application + or user to determine the necessary codepage when reading zip files encoded + this way. In other words, if you explicitly specify the codepage when you + create the zipfile, you must explicitly specify the same codepage when + reading the zipfile. + + + + The way you specify the code page to use when reading a zip file varies + depending on the tool or library you use to read the zip. In DotNetZip, + you use a ZipFile.Read() method that accepts an encoding parameter. It + isn't possible with Windows Explorer, as far as I know, to specify an + explicit codepage to use when reading a zip. If you use an incorrect + codepage when reading a zipfile, you will get entries with filenames that + are incorrect, and the incorrect filenames may even contain characters + that are not legal for use within filenames in Windows. Extracting entries + with illegal characters in the filenames will lead to exceptions. It's too + bad, but this is just the way things are with code pages in zip + files. Caveat Emptor. + + + + Example: Suppose you create a zipfile that contains entries with + filenames that have Danish characters. If you use equal to "iso-8859-1" (cp 28591), + the filenames will be correctly encoded in the zip. But, to read that + zipfile correctly, you have to specify the same codepage at the time you + read it. If try to read that zip file with Windows Explorer or another + application that is not flexible with respect to the codepage used to + decode filenames in zipfiles, you will get a filename like "Inf°.txt". + + + + When using DotNetZip to read a zip archive, and the zip archive uses an + arbitrary code page, you must specify the encoding to use before or when + the Zipfile is READ. This means you must use a ZipFile.Read() + method that allows you to specify a System.Text.Encoding parameter. Setting + the ProvisionalAlternateEncoding property after your application has read in + the zip archive will not affect the entry names of entries that have already + been read in. + + + + And now, the exception to the rule described above. One strategy for + specifying the code page for a given zip file is to describe the code page + in a human-readable form in the Zip comment. For example, the comment may + read "Entries in this archive are encoded in the Big5 code page". For + maximum interoperability, the zip comment in this case should be encoded + in the default, IBM437 code page. In this case, the zip comment is + encoded using a different page than the filenames. To do this, Specify + ProvisionalAlternateEncoding to your desired region-specific code + page, once before adding any entries, and then reset + ProvisionalAlternateEncoding to IBM437 before setting the property and calling Save(). + + + + + This example shows how to read a zip file using the Big-5 Chinese code page + (950), and extract each entry in the zip file. For this code to work as + desired, the Zipfile must have been created using the big5 code page + (CP950). This is typical, for example, when using WinRar on a machine with + CP950 set as the default code page. In that case, the names of entries + within the Zip archive will be stored in that code page, and reading the zip + archive must be done using that code page. If the application did not use + the correct code page in ZipFile.Read(), then names of entries within the + zip archive would not be correctly retrieved. + + using (var zip = ZipFile.Read(zipFileName, System.Text.Encoding.GetEncoding("big5"))) + { + // retrieve and extract an entry using a name encoded with CP950 + zip[MyDesiredEntry].Extract("unpack"); + } + + + + Using zip As ZipFile = ZipFile.Read(ZipToExtract, System.Text.Encoding.GetEncoding("big5")) + ' retrieve and extract an entry using a name encoded with CP950 + zip(MyDesiredEntry).Extract("unpack") + End Using + + + + DefaultEncoding + + + + A Text Encoding to use when encoding the filenames and comments for + all the ZipEntry items, during a ZipFile.Save() operation. + + + + Whether the encoding specified here is used during the save depends + on . + + + + + + A flag that tells if and when this instance should apply + AlternateEncoding to encode the filenames and comments associated to + of ZipEntry objects contained within this instance. + + + + + The default text encoding used in zip archives. It is numeric 437, also + known as IBM437. + + + + + + Gets or sets the TextWriter to which status messages are delivered + for the instance. + + + + If the TextWriter is set to a non-null value, then verbose output is sent + to the TextWriter during Add, Read, Save and + Extract operations. Typically, console applications might use + Console.Out and graphical or headless applications might use a + System.IO.StringWriter. The output of this is suitable for viewing + by humans. + + + + + In this example, a console application instantiates a ZipFile, then + sets the StatusMessageTextWriter to Console.Out. At that + point, all verbose status messages for that ZipFile are sent to the + console. + + + + using (ZipFile zip= ZipFile.Read(FilePath)) + { + zip.StatusMessageTextWriter= System.Console.Out; + // messages are sent to the console during extraction + zip.ExtractAll(); + } + + + + Using zip As ZipFile = ZipFile.Read(FilePath) + zip.StatusMessageTextWriter= System.Console.Out + 'Status Messages will be sent to the console during extraction + zip.ExtractAll() + End Using + + + + In this example, a Windows Forms application instantiates a + ZipFile, then sets the StatusMessageTextWriter to a + StringWriter. At that point, all verbose status messages for that + ZipFile are sent to the StringWriter. + + + + var sw = new System.IO.StringWriter(); + using (ZipFile zip= ZipFile.Read(FilePath)) + { + zip.StatusMessageTextWriter= sw; + zip.ExtractAll(); + } + Console.WriteLine("{0}", sw.ToString()); + + + + Dim sw as New System.IO.StringWriter + Using zip As ZipFile = ZipFile.Read(FilePath) + zip.StatusMessageTextWriter= sw + zip.ExtractAll() + End Using + 'Status Messages are now available in sw + + + + + + + Gets or sets the name for the folder to store the temporary file + this library writes when saving a zip archive. + + + + + This library will create a temporary file when saving a Zip archive to a + file. This file is written when calling one of the Save() methods + that does not save to a stream, or one of the SaveSelfExtractor() + methods. + + + + By default, the library will create the temporary file in the directory + specified for the file itself, via the property or via + the method. + + + + Setting this property allows applications to override this default + behavior, so that the library will create the temporary file in the + specified folder. For example, to have the library create the temporary + file in the current working directory, regardless where the ZipFile + is saved, specfy ".". To revert to the default behavior, set this + property to null (Nothing in VB). + + + + When setting the property to a non-null value, the folder specified must + exist; if it does not an exception is thrown. The application should have + write and delete permissions on the folder. The permissions are not + explicitly checked ahead of time; if the application does not have the + appropriate rights, an exception will be thrown at the time Save() + is called. + + + + There is no temporary file created when reading a zip archive. When + saving to a Stream, there is no temporary file created. For example, if + the application is an ASP.NET application and calls Save() + specifying the Response.OutputStream as the output stream, there is + no temporary file created. + + + + + Thrown when setting the property if the directory does not exist. + + + + + + Sets the password to be used on the ZipFile instance. + + + + + + When writing a zip archive, this password is applied to the entries, not + to the zip archive itself. It applies to any ZipEntry subsequently + added to the ZipFile, using one of the AddFile, + AddDirectory, AddEntry, or AddItem methods, etc. + When reading a zip archive, this property applies to any entry + subsequently extracted from the ZipFile using one of the Extract + methods on the ZipFile class. + + + + When writing a zip archive, keep this in mind: though the password is set + on the ZipFile object, according to the Zip spec, the "directory" of the + archive - in other words the list of entries or files contained in the archive - is + not encrypted with the password, or protected in any way. If you set the + Password property, the password actually applies to individual entries + that are added to the archive, subsequent to the setting of this property. + The list of filenames in the archive that is eventually created will + appear in clear text, but the contents of the individual files are + encrypted. This is how Zip encryption works. + + + + One simple way around this limitation is to simply double-wrap sensitive + filenames: Store the files in a zip file, and then store that zip file + within a second, "outer" zip file. If you apply a password to the outer + zip file, then readers will be able to see that the outer zip file + contains an inner zip file. But readers will not be able to read the + directory or file list of the inner zip file. + + + + If you set the password on the ZipFile, and then add a set of files + to the archive, then each entry is encrypted with that password. You may + also want to change the password between adding different entries. If you + set the password, add an entry, then set the password to null + (Nothing in VB), and add another entry, the first entry is + encrypted and the second is not. If you call AddFile(), then set + the Password property, then call ZipFile.Save, the file + added will not be password-protected, and no warning will be generated. + + + + When setting the Password, you may also want to explicitly set the property, to specify how to encrypt the entries added + to the ZipFile. If you set the Password to a non-null value and do not + set , then PKZip 2.0 ("Weak") encryption is used. + This encryption is relatively weak but is very interoperable. If you set + the password to a null value (Nothing in VB), Encryption is + reset to None. + + + + All of the preceding applies to writing zip archives, in other words when + you use one of the Save methods. To use this property when reading or an + existing ZipFile, do the following: set the Password property on the + ZipFile, then call one of the Extract() overloads on the . In this case, the entry is extracted using the + Password that is specified on the ZipFile instance. If you + have not set the Password property, then the password is + null, and the entry is extracted with no password. + + + + If you set the Password property on the ZipFile, then call + Extract() an entry that has not been encrypted with a password, the + password is not used for that entry, and the ZipEntry is extracted + as normal. In other words, the password is used only if necessary. + + + + The class also has a Password property. It takes precedence + over this property on the ZipFile. Typically, you would use the + per-entry Password when most entries in the zip archive use one password, + and a few entries use a different password. If all entries in the zip + file use the same password, then it is simpler to just set this property + on the ZipFile itself, whether creating a zip archive or extracting + a zip archive. + + + + + + + This example creates a zip file, using password protection for the + entries, and then extracts the entries from the zip file. When creating + the zip file, the Readme.txt file is not protected with a password, but + the other two are password-protected as they are saved. During extraction, + each file is extracted with the appropriate password. + + + // create a file with encryption + using (ZipFile zip = new ZipFile()) + { + zip.AddFile("ReadMe.txt"); + zip.Password= "!Secret1"; + zip.AddFile("MapToTheSite-7440-N49th.png"); + zip.AddFile("2008-Regional-Sales-Report.pdf"); + zip.Save("EncryptedArchive.zip"); + } + + // extract entries that use encryption + using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) + { + zip.Password= "!Secret1"; + zip.ExtractAll("extractDir"); + } + + + + + Using zip As New ZipFile + zip.AddFile("ReadMe.txt") + zip.Password = "123456!" + zip.AddFile("MapToTheSite-7440-N49th.png") + zip.Password= "!Secret1"; + zip.AddFile("2008-Regional-Sales-Report.pdf") + zip.Save("EncryptedArchive.zip") + End Using + + + ' extract entries that use encryption + Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) + zip.Password= "!Secret1" + zip.ExtractAll("extractDir") + End Using + + + + + + ZipFile.Encryption + ZipEntry.Password + + + + The action the library should take when extracting a file that already + exists. + + + + + This property affects the behavior of the Extract methods (one of the + Extract() or ExtractWithPassword() overloads), when + extraction would would overwrite an existing filesystem file. If you do + not set this property, the library throws an exception when extracting an + entry would overwrite an existing file. + + + + This property has no effect when extracting to a stream, or when the file + to be extracted does not already exist. + + + + + + + The action the library should take when an error is encountered while + opening or reading files as they are saved into a zip archive. + + + + + Errors can occur as a file is being saved to the zip archive. For + example, the File.Open may fail, or a File.Read may fail, because of + lock conflicts or other reasons. + + + + The first problem might occur after having called AddDirectory() on a + directory that contains a Clipper .dbf file; the file is locked by + Clipper and cannot be opened for read by another process. An example of + the second problem might occur when trying to zip a .pst file that is in + use by Microsoft Outlook. Outlook locks a range on the file, which allows + other processes to open the file, but not read it in its entirety. + + + + This property tells DotNetZip what you would like to do in the case of + these errors. The primary options are: ZipErrorAction.Throw to + throw an exception (this is the default behavior if you don't set this + property); ZipErrorAction.Skip to Skip the file for which there + was an error and continue saving; ZipErrorAction.Retry to Retry + the entry that caused the problem; or + ZipErrorAction.InvokeErrorEvent to invoke an event handler. + + + + This property is implicitly set to ZipErrorAction.InvokeErrorEvent + if you add a handler to the event. If you set + this property to something other than + ZipErrorAction.InvokeErrorEvent, then the ZipError + event is implicitly cleared. What it means is you can set one or the + other (or neither), depending on what you want, but you never need to set + both. + + + + As with some other properties on the ZipFile class, like , , and , setting this property on a ZipFile + instance will cause the specified ZipErrorAction to be used on all + items that are subsequently added to the + ZipFile instance. If you set this property after you have added + items to the ZipFile, but before you have called Save(), + those items will not use the specified error handling action. + + + + If you want to handle any errors that occur with any entry in the zip + file in the same way, then set this property once, before adding any + entries to the zip archive. + + + + If you set this property to ZipErrorAction.Skip and you'd like to + learn which files may have been skipped after a Save(), you can + set the on the ZipFile before + calling Save(). A message will be emitted into that writer for + each skipped file, if any. + + + + + + This example shows how to tell DotNetZip to skip any files for which an + error is generated during the Save(). + + Public Sub SaveZipFile() + Dim SourceFolder As String = "fodder" + Dim DestFile As String = "eHandler.zip" + Dim sw as New StringWriter + Using zipArchive As ZipFile = New ZipFile + ' Tell DotNetZip to skip any files for which it encounters an error + zipArchive.ZipErrorAction = ZipErrorAction.Skip + zipArchive.StatusMessageTextWriter = sw + zipArchive.AddDirectory(SourceFolder) + zipArchive.Save(DestFile) + End Using + ' examine sw here to see any messages + End Sub + + + + + + + + + + The Encryption to use for entries added to the ZipFile. + + + + + Set this when creating a zip archive, or when updating a zip archive. The + specified Encryption is applied to the entries subsequently added to the + ZipFile instance. Applications do not need to set the + Encryption property when reading or extracting a zip archive. + + + + If you set this to something other than EncryptionAlgorithm.None, you + will also need to set the . + + + + As with some other properties on the ZipFile class, like and , setting this + property on a ZipFile instance will cause the specified + EncryptionAlgorithm to be used on all items + that are subsequently added to the ZipFile instance. In other + words, if you set this property after you have added items to the + ZipFile, but before you have called Save(), those items will + not be encrypted or protected with a password in the resulting zip + archive. To get a zip archive with encrypted entries, set this property, + along with the property, before calling + AddFile, AddItem, or AddDirectory (etc.) on the + ZipFile instance. + + + + If you read a ZipFile, you can modify the Encryption on an + encrypted entry, only by setting the Encryption property on the + ZipEntry itself. Setting the Encryption property on the + ZipFile, once it has been created via a call to + ZipFile.Read(), does not affect entries that were previously read. + + + + For example, suppose you read a ZipFile, and there is an encrypted + entry. Setting the Encryption property on that ZipFile and + then calling Save() on the ZipFile does not update the + Encryption used for the entries in the archive. Neither is an + exception thrown. Instead, what happens during the Save() is that + all previously existing entries are copied through to the new zip archive, + with whatever encryption and password that was used when originally + creating the zip archive. Upon re-reading that archive, to extract + entries, applications should use the original password or passwords, if + any. + + + + Suppose an application reads a ZipFile, and there is an encrypted + entry. Setting the Encryption property on that ZipFile and + then adding new entries (via AddFile(), AddEntry(), etc) + and then calling Save() on the ZipFile does not update the + Encryption on any of the entries that had previously been in the + ZipFile. The Encryption property applies only to the + newly-added entries. + + + + + + + This example creates a zip archive that uses encryption, and then extracts + entries from the archive. When creating the zip archive, the ReadMe.txt + file is zipped without using a password or encryption. The other files + use encryption. + + + + // Create a zip archive with AES Encryption. + using (ZipFile zip = new ZipFile()) + { + zip.AddFile("ReadMe.txt"); + zip.Encryption= EncryptionAlgorithm.WinZipAes256; + zip.Password= "Top.Secret.No.Peeking!"; + zip.AddFile("7440-N49th.png"); + zip.AddFile("2008-Regional-Sales-Report.pdf"); + zip.Save("EncryptedArchive.zip"); + } + + // Extract a zip archive that uses AES Encryption. + // You do not need to specify the algorithm during extraction. + using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) + { + zip.Password= "Top.Secret.No.Peeking!"; + zip.ExtractAll("extractDirectory"); + } + + + + ' Create a zip that uses Encryption. + Using zip As New ZipFile() + zip.Encryption= EncryptionAlgorithm.WinZipAes256 + zip.Password= "Top.Secret.No.Peeking!" + zip.AddFile("ReadMe.txt") + zip.AddFile("7440-N49th.png") + zip.AddFile("2008-Regional-Sales-Report.pdf") + zip.Save("EncryptedArchive.zip") + End Using + + ' Extract a zip archive that uses AES Encryption. + ' You do not need to specify the algorithm during extraction. + Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) + zip.Password= "Top.Secret.No.Peeking!" + zip.ExtractAll("extractDirectory") + End Using + + + + + ZipFile.Password + ZipEntry.Encryption + + + + A callback that allows the application to specify the compression level + to use for entries subsequently added to the zip archive. + + + + + + With this callback, the DotNetZip library allows the application to + determine whether compression will be used, at the time of the + Save. This may be useful if the application wants to favor + speed over size, and wants to defer the decision until the time of + Save. + + + + Typically applications set the property on + the ZipFile or on each ZipEntry to determine the level of + compression used. This is done at the time the entry is added to the + ZipFile. Setting the property to + Ionic.Zlib.CompressionLevel.None means no compression will be used. + + + + This callback allows the application to defer the decision on the + CompressionLevel to use, until the time of the call to + ZipFile.Save(). The callback is invoked once per ZipEntry, + at the time the data for the entry is being written out as part of a + Save() operation. The application can use whatever criteria it + likes in determining the level to return. For example, an application may + wish that no .mp3 files should be compressed, because they are already + compressed and the extra compression is not worth the CPU time incurred, + and so can return None for all .mp3 entries. + + + + The library determines whether compression will be attempted for an entry + this way: If the entry is a zero length file, or a directory, no + compression is used. Otherwise, if this callback is set, it is invoked + and the CompressionLevel is set to the return value. If this + callback has not been set, then the previously set value for + CompressionLevel is used. + + + + + + + The maximum size of an output segment, when saving a split Zip file. + + + + Set this to a non-zero value before calling or to specify that the ZipFile should be saved as a + split archive, also sometimes called a spanned archive. Some also + call them multi-file archives. + + + + A split zip archive is saved in a set of discrete filesystem files, + rather than in a single file. This is handy when transmitting the + archive in email or some other mechanism that has a limit to the size of + each file. The first file in a split archive will be named + basename.z01, the second will be named basename.z02, and + so on. The final file is named basename.zip. According to the zip + specification from PKWare, the minimum value is 65536, for a 64k segment + size. The maximum number of segments allows in a split archive is 99. + + + + The value of this property determines the maximum size of a split + segment when writing a split archive. For example, suppose you have a + ZipFile that would save to a single file of 200k. If you set the + MaxOutputSegmentSize to 65536 before calling Save(), you + will get four distinct output files. On the other hand if you set this + property to 256k, then you will get a single-file archive for that + ZipFile. + + + + The size of each split output file will be as large as possible, up to + the maximum size set here. The zip specification requires that some data + fields in a zip archive may not span a split boundary, and an output + segment may be smaller than the maximum if necessary to avoid that + problem. Also, obviously the final segment of the archive may be smaller + than the maximum segment size. Segments will never be larger than the + value set with this property. + + + + You can save a split Zip file only when saving to a regular filesystem + file. It's not possible to save a split zip file as a self-extracting + archive, nor is it possible to save a split zip file to a stream. When + saving to a SFX or to a Stream, this property is ignored. + + + + About interoperability: Split or spanned zip files produced by DotNetZip + can be read by WinZip or PKZip, and vice-versa. Segmented zip files may + not be readable by other tools, if those other tools don't support zip + spanning or splitting. When in doubt, test. I don't believe Windows + Explorer can extract a split archive. + + + + This property has no effect when reading a split archive. You can read + a split archive in the normal way with DotNetZip. + + + + When saving a zip file, if you want a regular zip file rather than a + split zip file, don't set this property, or set it to Zero. + + + + If you read a split archive, with and + then subsequently call ZipFile.Save(), unless you set this + property before calling Save(), you will get a normal, + single-file archive. + + + + + + + + Returns the number of segments used in the most recent Save() operation. + + + + This is normally zero, unless you have set the property. If you have set , and then you save a file, after the call to + Save() completes, you can read this value to learn the number of segments that + were created. + + + If you call Save("Archive.zip"), and it creates 5 segments, then you + will have filesystem files named Archive.z01, Archive.z02, Archive.z03, + Archive.z04, and Archive.zip, and the value of this property will be 5. + + + + + + + The size threshold for an entry, above which a parallel deflate is used. + + + + + + DotNetZip will use multiple threads to compress any ZipEntry, + if the entry is larger than the given size. Zero means "always + use parallel deflate", while -1 means "never use parallel + deflate". The default value for this property is 512k. Aside + from the special values of 0 and 1, the minimum value is 65536. + + + + If the entry size cannot be known before compression, as with a + read-forward stream, then Parallel deflate will never be + performed, unless the value of this property is zero. + + + + A parallel deflate operations will speed up the compression of + large files, on computers with multiple CPUs or multiple CPU + cores. For files above 1mb, on a dual core or dual-cpu (2p) + machine, the time required to compress the file can be 70% of the + single-threaded deflate. For very large files on 4p machines the + compression can be done in 30% of the normal time. The downside + is that parallel deflate consumes extra memory during the deflate, + and the deflation is not as effective. + + + + Parallel deflate tends to yield slightly less compression when + compared to as single-threaded deflate; this is because the original + data stream is split into multiple independent buffers, each of which + is compressed in parallel. But because they are treated + independently, there is no opportunity to share compression + dictionaries. For that reason, a deflated stream may be slightly + larger when compressed using parallel deflate, as compared to a + traditional single-threaded deflate. Sometimes the increase over the + normal deflate is as much as 5% of the total compressed size. For + larger files it can be as small as 0.1%. + + + + Multi-threaded compression does not give as much an advantage when + using Encryption. This is primarily because encryption tends to slow + down the entire pipeline. Also, multi-threaded compression gives less + of an advantage when using lower compression levels, for example . You may have to + perform some tests to determine the best approach for your situation. + + + + + + + + + + The maximum number of buffer pairs to use when performing + parallel compression. + + + + + This property sets an upper limit on the number of memory + buffer pairs to create when performing parallel + compression. The implementation of the parallel + compression stream allocates multiple buffers to + facilitate parallel compression. As each buffer fills up, + the stream uses + ThreadPool.QueueUserWorkItem() to compress those + buffers in a background threadpool thread. After a buffer + is compressed, it is re-ordered and written to the output + stream. + + + + A higher number of buffer pairs enables a higher degree of + parallelism, which tends to increase the speed of compression on + multi-cpu computers. On the other hand, a higher number of buffer + pairs also implies a larger memory consumption, more active worker + threads, and a higher cpu utilization for any compression. This + property enables the application to limit its memory consumption and + CPU utilization behavior depending on requirements. + + + + For each compression "task" that occurs in parallel, there are 2 + buffers allocated: one for input and one for output. This property + sets a limit for the number of pairs. The total amount of storage + space allocated for buffering will then be (N*S*2), where N is the + number of buffer pairs, S is the size of each buffer (). By default, DotNetZip allocates 4 buffer + pairs per CPU core, so if your machine has 4 cores, and you retain + the default buffer size of 128k, then the + ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer + memory in total, or 4mb, in blocks of 128kb. If you then set this + property to 8, then the number will be 8 * 2 * 128kb of buffer + memory, or 2mb. + + + + CPU utilization will also go up with additional buffers, because a + larger number of buffer pairs allows a larger number of background + threads to compress in parallel. If you find that parallel + compression is consuming too much memory or CPU, you can adjust this + value downward. + + + + The default value is 16. Different values may deliver better or + worse results, depending on your priorities and the dynamic + performance characteristics of your storage and compute resources. + + + + This property is not the number of buffer pairs to use; it is an + upper limit. An illustration: Suppose you have an application that + uses the default value of this property (which is 16), and it runs + on a machine with 2 CPU cores. In that case, DotNetZip will allocate + 4 buffer pairs per CPU core, for a total of 8 pairs. The upper + limit specified by this property has no effect. + + + + The application can set this value at any time + before calling ZipFile.Save(). + + + + + + + + + Returns the version number on the DotNetZip assembly. + + + + + This property is exposed as a convenience. Callers could also get the + version value by retrieving GetName().Version on the + System.Reflection.Assembly object pointing to the DotNetZip + assembly. But sometimes it is not clear which assembly is being loaded. + This property makes it clear. + + + This static property is primarily useful for diagnostic purposes. + + + + + + This is an integer indexer into the Zip archive. + + + + + This property is read-only. + + + + Internally, the ZipEntry instances that belong to the + ZipFile are stored in a Dictionary. When you use this + indexer the first time, it creates a read-only + List<ZipEntry> from the Dictionary.Values Collection. + If at any time you modify the set of entries in the ZipFile, + either by adding an entry, removing an entry, or renaming an + entry, a new List will be created, and the numeric indexes for the + remaining entries may be different. + + + + This means you cannot rename any ZipEntry from + inside an enumeration of the zip file. + + + + The index value. + + + + + + The ZipEntry within the Zip archive at the specified index. If the + entry does not exist in the archive, this indexer throws. + + + + + + This is a name-based indexer into the Zip archive. + + + + + This property is read-only. + + + + The property on the ZipFile + determines whether retrieval via this indexer is done via case-sensitive + comparisons. By default, retrieval is not case sensitive. This makes + sense on Windows, in which filesystems are not case sensitive. + + + + Regardless of case-sensitivity, it is not always the case that + this[value].FileName == value. In other words, the FileName + property of the ZipEntry retrieved with this indexer, may or may + not be equal to the index value. + + + + This is because DotNetZip performs a normalization of filenames passed to + this indexer, before attempting to retrieve the item. That normalization + includes: removal of a volume letter and colon, swapping backward slashes + for forward slashes. So, zip["dir1\\entry1.txt"].FileName == + "dir1/entry.txt". + + + + Directory entries in the zip file may be retrieved via this indexer only + with names that have a trailing slash. DotNetZip automatically appends a + trailing slash to the names of any directory entries added to a zip. + + + + + + This example extracts only the entries in a zip file that are .txt files. + + using (ZipFile zip = ZipFile.Read("PackedDocuments.zip")) + { + foreach (string s1 in zip.EntryFilenames) + { + if (s1.EndsWith(".txt")) + zip[s1].Extract("textfiles"); + } + } + + + Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip") + Dim s1 As String + For Each s1 In zip.EntryFilenames + If s1.EndsWith(".txt") Then + zip(s1).Extract("textfiles") + End If + Next + End Using + + + + + + Thrown if the caller attempts to assign a non-null value to the indexer. + + + + The name of the file, including any directory path, to retrieve from the + zip. The filename match is not case-sensitive by default; you can use the + property to change this behavior. The + pathname can use forward-slashes or backward slashes. + + + + The ZipEntry within the Zip archive, given by the specified + filename. If the named entry does not exist in the archive, this indexer + returns null (Nothing in VB). + + + + + + The list of filenames for the entries contained within the zip archive. + + + + According to the ZIP specification, the names of the entries use forward + slashes in pathnames. If you are scanning through the list, you may have + to swap forward slashes for backslashes. + + + + + + This example shows one way to test if a filename is already contained + within a zip archive. + + String zipFileToRead= "PackedDocuments.zip"; + string candidate = "DatedMaterial.xps"; + using (ZipFile zip = new ZipFile(zipFileToRead)) + { + if (zip.EntryFilenames.Contains(candidate)) + Console.WriteLine("The file '{0}' exists in the zip archive '{1}'", + candidate, + zipFileName); + else + Console.WriteLine("The file, '{0}', does not exist in the zip archive '{1}'", + candidate, + zipFileName); + Console.WriteLine(); + } + + + Dim zipFileToRead As String = "PackedDocuments.zip" + Dim candidate As String = "DatedMaterial.xps" + Using zip As ZipFile.Read(ZipFileToRead) + If zip.EntryFilenames.Contains(candidate) Then + Console.WriteLine("The file '{0}' exists in the zip archive '{1}'", _ + candidate, _ + zipFileName) + Else + Console.WriteLine("The file, '{0}', does not exist in the zip archive '{1}'", _ + candidate, _ + zipFileName) + End If + Console.WriteLine + End Using + + + + + The list of strings for the filenames contained within the Zip archive. + + + + + + Returns the readonly collection of entries in the Zip archive. + + + + + + If there are no entries in the current ZipFile, the value returned is a + non-null zero-element collection. If there are entries in the zip file, + the elements are returned in no particular order. + + + This is the implied enumerator on the ZipFile class. If you use a + ZipFile instance in a context that expects an enumerator, you will + get this collection. + + + + + + + Returns a readonly collection of entries in the Zip archive, sorted by FileName. + + + + If there are no entries in the current ZipFile, the value returned + is a non-null zero-element collection. If there are entries in the zip + file, the elements are returned sorted by the name of the entry. + + + + + This example fills a Windows Forms ListView with the entries in a zip file. + + + using (ZipFile zip = ZipFile.Read(zipFile)) + { + foreach (ZipEntry entry in zip.EntriesSorted) + { + ListViewItem item = new ListViewItem(n.ToString()); + n++; + string[] subitems = new string[] { + entry.FileName.Replace("/","\\"), + entry.LastModified.ToString("yyyy-MM-dd HH:mm:ss"), + entry.UncompressedSize.ToString(), + String.Format("{0,5:F0}%", entry.CompressionRatio), + entry.CompressedSize.ToString(), + (entry.UsesEncryption) ? "Y" : "N", + String.Format("{0:X8}", entry.Crc)}; + + foreach (String s in subitems) + { + ListViewItem.ListViewSubItem subitem = new ListViewItem.ListViewSubItem(); + subitem.Text = s; + item.SubItems.Add(subitem); + } + + this.listView1.Items.Add(item); + } + } + + + + + + + + Returns the number of entries in the Zip archive. + + + + + An event handler invoked when a Save() starts, before and after each + entry has been written to the archive, when a Save() completes, and + during other Save events. + + + + + Depending on the particular event, different properties on the parameter are set. The following + table summarizes the available EventTypes and the conditions under + which this event handler is invoked with a + SaveProgressEventArgs with the given EventType. + + + + + value of EntryType + Meaning and conditions + + + + ZipProgressEventType.Saving_Started + Fired when ZipFile.Save() begins. + + + + + ZipProgressEventType.Saving_BeforeSaveEntry + + Fired within ZipFile.Save(), just before writing data for each + particular entry. + + + + + ZipProgressEventType.Saving_AfterSaveEntry + + Fired within ZipFile.Save(), just after having finished writing data + for each particular entry. + + + + + ZipProgressEventType.Saving_Completed + Fired when ZipFile.Save() has completed. + + + + + ZipProgressEventType.Saving_AfterSaveTempArchive + + Fired after the temporary file has been created. This happens only + when saving to a disk file. This event will not be invoked when + saving to a stream. + + + + + ZipProgressEventType.Saving_BeforeRenameTempArchive + + Fired just before renaming the temporary file to the permanent + location. This happens only when saving to a disk file. This event + will not be invoked when saving to a stream. + + + + + ZipProgressEventType.Saving_AfterRenameTempArchive + + Fired just after renaming the temporary file to the permanent + location. This happens only when saving to a disk file. This event + will not be invoked when saving to a stream. + + + + + ZipProgressEventType.Saving_AfterCompileSelfExtractor + + Fired after a self-extracting archive has finished compiling. This + EventType is used only within SaveSelfExtractor(). + + + + + ZipProgressEventType.Saving_BytesRead + + Set during the save of a particular entry, to update progress of the + Save(). When this EventType is set, the BytesTransferred is the + number of bytes that have been read from the source stream. The + TotalBytesToTransfer is the number of bytes in the uncompressed + file. + + + + + + + + + This example uses an anonymous method to handle the + SaveProgress event, by updating a progress bar. + + + progressBar1.Value = 0; + progressBar1.Max = listbox1.Items.Count; + using (ZipFile zip = new ZipFile()) + { + // listbox1 contains a list of filenames + zip.AddFiles(listbox1.Items); + + // do the progress bar: + zip.SaveProgress += (sender, e) => { + if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry) { + progressBar1.PerformStep(); + } + }; + + zip.Save(fs); + } + + + + + This example uses a named method as the + SaveProgress event handler, to update the user, in a + console-based application. + + + static bool justHadByteUpdate= false; + public static void SaveProgress(object sender, SaveProgressEventArgs e) + { + if (e.EventType == ZipProgressEventType.Saving_Started) + Console.WriteLine("Saving: {0}", e.ArchiveName); + + else if (e.EventType == ZipProgressEventType.Saving_Completed) + { + justHadByteUpdate= false; + Console.WriteLine(); + Console.WriteLine("Done: {0}", e.ArchiveName); + } + + else if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry) + { + if (justHadByteUpdate) + Console.WriteLine(); + Console.WriteLine(" Writing: {0} ({1}/{2})", + e.CurrentEntry.FileName, e.EntriesSaved, e.EntriesTotal); + justHadByteUpdate= false; + } + + else if (e.EventType == ZipProgressEventType.Saving_EntryBytesRead) + { + if (justHadByteUpdate) + Console.SetCursorPosition(0, Console.CursorTop); + Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer, + e.BytesTransferred / (0.01 * e.TotalBytesToTransfer )); + justHadByteUpdate= true; + } + } + + public static ZipUp(string targetZip, string directory) + { + using (var zip = new ZipFile()) { + zip.SaveProgress += SaveProgress; + zip.AddDirectory(directory); + zip.Save(targetZip); + } + } + + + + + Public Sub ZipUp(ByVal targetZip As String, ByVal directory As String) + Using zip As ZipFile = New ZipFile + AddHandler zip.SaveProgress, AddressOf MySaveProgress + zip.AddDirectory(directory) + zip.Save(targetZip) + End Using + End Sub + + Private Shared justHadByteUpdate As Boolean = False + + Public Shared Sub MySaveProgress(ByVal sender As Object, ByVal e As SaveProgressEventArgs) + If (e.EventType Is ZipProgressEventType.Saving_Started) Then + Console.WriteLine("Saving: {0}", e.ArchiveName) + + ElseIf (e.EventType Is ZipProgressEventType.Saving_Completed) Then + justHadByteUpdate = False + Console.WriteLine + Console.WriteLine("Done: {0}", e.ArchiveName) + + ElseIf (e.EventType Is ZipProgressEventType.Saving_BeforeWriteEntry) Then + If justHadByteUpdate Then + Console.WriteLine + End If + Console.WriteLine(" Writing: {0} ({1}/{2})", e.CurrentEntry.FileName, e.EntriesSaved, e.EntriesTotal) + justHadByteUpdate = False + + ElseIf (e.EventType Is ZipProgressEventType.Saving_EntryBytesRead) Then + If justHadByteUpdate Then + Console.SetCursorPosition(0, Console.CursorTop) + End If + Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, _ + e.TotalBytesToTransfer, _ + (CDbl(e.BytesTransferred) / (0.01 * e.TotalBytesToTransfer))) + justHadByteUpdate = True + End If + End Sub + + + + + + This is a more complete example of using the SaveProgress + events in a Windows Forms application, with a + Thread object. + + + delegate void SaveEntryProgress(SaveProgressEventArgs e); + delegate void ButtonClick(object sender, EventArgs e); + + public class WorkerOptions + { + public string ZipName; + public string Folder; + public string Encoding; + public string Comment; + public int ZipFlavor; + public Zip64Option Zip64; + } + + private int _progress2MaxFactor; + private bool _saveCanceled; + private long _totalBytesBeforeCompress; + private long _totalBytesAfterCompress; + private Thread _workerThread; + + + private void btnZipup_Click(object sender, EventArgs e) + { + KickoffZipup(); + } + + private void btnCancel_Click(object sender, EventArgs e) + { + if (this.lblStatus.InvokeRequired) + { + this.lblStatus.Invoke(new ButtonClick(this.btnCancel_Click), new object[] { sender, e }); + } + else + { + _saveCanceled = true; + lblStatus.Text = "Canceled..."; + ResetState(); + } + } + + private void KickoffZipup() + { + _folderName = tbDirName.Text; + + if (_folderName == null || _folderName == "") return; + if (this.tbZipName.Text == null || this.tbZipName.Text == "") return; + + // check for existence of the zip file: + if (System.IO.File.Exists(this.tbZipName.Text)) + { + var dlgResult = MessageBox.Show(String.Format("The file you have specified ({0}) already exists." + + " Do you want to overwrite this file?", this.tbZipName.Text), + "Confirmation is Required", MessageBoxButtons.YesNo, MessageBoxIcon.Question); + if (dlgResult != DialogResult.Yes) return; + System.IO.File.Delete(this.tbZipName.Text); + } + + _saveCanceled = false; + _nFilesCompleted = 0; + _totalBytesAfterCompress = 0; + _totalBytesBeforeCompress = 0; + this.btnOk.Enabled = false; + this.btnOk.Text = "Zipping..."; + this.btnCancel.Enabled = true; + lblStatus.Text = "Zipping..."; + + var options = new WorkerOptions + { + ZipName = this.tbZipName.Text, + Folder = _folderName, + Encoding = "ibm437" + }; + + if (this.comboBox1.SelectedIndex != 0) + { + options.Encoding = this.comboBox1.SelectedItem.ToString(); + } + + if (this.radioFlavorSfxCmd.Checked) + options.ZipFlavor = 2; + else if (this.radioFlavorSfxGui.Checked) + options.ZipFlavor = 1; + else options.ZipFlavor = 0; + + if (this.radioZip64AsNecessary.Checked) + options.Zip64 = Zip64Option.AsNecessary; + else if (this.radioZip64Always.Checked) + options.Zip64 = Zip64Option.Always; + else options.Zip64 = Zip64Option.Never; + + options.Comment = String.Format("Encoding:{0} || Flavor:{1} || ZIP64:{2}\r\nCreated at {3} || {4}\r\n", + options.Encoding, + FlavorToString(options.ZipFlavor), + options.Zip64.ToString(), + System.DateTime.Now.ToString("yyyy-MMM-dd HH:mm:ss"), + this.Text); + + if (this.tbComment.Text != TB_COMMENT_NOTE) + options.Comment += this.tbComment.Text; + + _workerThread = new Thread(this.DoSave); + _workerThread.Name = "Zip Saver thread"; + _workerThread.Start(options); + this.Cursor = Cursors.WaitCursor; + } + + + private void DoSave(Object p) + { + WorkerOptions options = p as WorkerOptions; + try + { + using (var zip1 = new ZipFile()) + { + zip1.ProvisionalAlternateEncoding = System.Text.Encoding.GetEncoding(options.Encoding); + zip1.Comment = options.Comment; + zip1.AddDirectory(options.Folder); + _entriesToZip = zip1.EntryFileNames.Count; + SetProgressBars(); + zip1.SaveProgress += this.zip1_SaveProgress; + + zip1.UseZip64WhenSaving = options.Zip64; + + if (options.ZipFlavor == 1) + zip1.SaveSelfExtractor(options.ZipName, SelfExtractorFlavor.WinFormsApplication); + else if (options.ZipFlavor == 2) + zip1.SaveSelfExtractor(options.ZipName, SelfExtractorFlavor.ConsoleApplication); + else + zip1.Save(options.ZipName); + } + } + catch (System.Exception exc1) + { + MessageBox.Show(String.Format("Exception while zipping: {0}", exc1.Message)); + btnCancel_Click(null, null); + } + } + + + + void zip1_SaveProgress(object sender, SaveProgressEventArgs e) + { + switch (e.EventType) + { + case ZipProgressEventType.Saving_AfterWriteEntry: + StepArchiveProgress(e); + break; + case ZipProgressEventType.Saving_EntryBytesRead: + StepEntryProgress(e); + break; + case ZipProgressEventType.Saving_Completed: + SaveCompleted(); + break; + case ZipProgressEventType.Saving_AfterSaveTempArchive: + // this event only occurs when saving an SFX file + TempArchiveSaved(); + break; + } + if (_saveCanceled) + e.Cancel = true; + } + + + + private void StepArchiveProgress(SaveProgressEventArgs e) + { + if (this.progressBar1.InvokeRequired) + { + this.progressBar1.Invoke(new SaveEntryProgress(this.StepArchiveProgress), new object[] { e }); + } + else + { + if (!_saveCanceled) + { + _nFilesCompleted++; + this.progressBar1.PerformStep(); + _totalBytesAfterCompress += e.CurrentEntry.CompressedSize; + _totalBytesBeforeCompress += e.CurrentEntry.UncompressedSize; + + // reset the progress bar for the entry: + this.progressBar2.Value = this.progressBar2.Maximum = 1; + + this.Update(); + } + } + } + + + private void StepEntryProgress(SaveProgressEventArgs e) + { + if (this.progressBar2.InvokeRequired) + { + this.progressBar2.Invoke(new SaveEntryProgress(this.StepEntryProgress), new object[] { e }); + } + else + { + if (!_saveCanceled) + { + if (this.progressBar2.Maximum == 1) + { + // reset + Int64 max = e.TotalBytesToTransfer; + _progress2MaxFactor = 0; + while (max > System.Int32.MaxValue) + { + max /= 2; + _progress2MaxFactor++; + } + this.progressBar2.Maximum = (int)max; + lblStatus.Text = String.Format("{0} of {1} files...({2})", + _nFilesCompleted + 1, _entriesToZip, e.CurrentEntry.FileName); + } + + int xferred = e.BytesTransferred >> _progress2MaxFactor; + + this.progressBar2.Value = (xferred >= this.progressBar2.Maximum) + ? this.progressBar2.Maximum + : xferred; + + this.Update(); + } + } + } + + private void SaveCompleted() + { + if (this.lblStatus.InvokeRequired) + { + this.lblStatus.Invoke(new MethodInvoker(this.SaveCompleted)); + } + else + { + lblStatus.Text = String.Format("Done, Compressed {0} files, {1:N0}% of original.", + _nFilesCompleted, (100.00 * _totalBytesAfterCompress) / _totalBytesBeforeCompress); + ResetState(); + } + } + + private void ResetState() + { + this.btnCancel.Enabled = false; + this.btnOk.Enabled = true; + this.btnOk.Text = "Zip it!"; + this.progressBar1.Value = 0; + this.progressBar2.Value = 0; + this.Cursor = Cursors.Default; + if (!_workerThread.IsAlive) + _workerThread.Join(); + } + + + + + + + + + + + An event handler invoked before, during, and after the reading of a zip archive. + + + + + Depending on the particular event being signaled, different properties on the + parameter are set. The following table + summarizes the available EventTypes and the conditions under which this + event handler is invoked with a ReadProgressEventArgs with the given EventType. + + + + + value of EntryType + Meaning and conditions + + + + ZipProgressEventType.Reading_Started + Fired just as ZipFile.Read() begins. Meaningful properties: ArchiveName. + + + + + ZipProgressEventType.Reading_Completed + Fired when ZipFile.Read() has completed. Meaningful properties: ArchiveName. + + + + + ZipProgressEventType.Reading_ArchiveBytesRead + Fired while reading, updates the number of bytes read for the entire archive. + Meaningful properties: ArchiveName, CurrentEntry, BytesTransferred, TotalBytesToTransfer. + + + + + ZipProgressEventType.Reading_BeforeReadEntry + Indicates an entry is about to be read from the archive. + Meaningful properties: ArchiveName, EntriesTotal. + + + + + ZipProgressEventType.Reading_AfterReadEntry + Indicates an entry has just been read from the archive. + Meaningful properties: ArchiveName, EntriesTotal, CurrentEntry. + + + + + + + + + + + + + An event handler invoked before, during, and after extraction of + entries in the zip archive. + + + + + Depending on the particular event, different properties on the parameter are set. The following + table summarizes the available EventTypes and the conditions under + which this event handler is invoked with a + ExtractProgressEventArgs with the given EventType. + + + + + value of EntryType + Meaning and conditions + + + + ZipProgressEventType.Extracting_BeforeExtractAll + + Set when ExtractAll() begins. The ArchiveName, Overwrite, and + ExtractLocation properties are meaningful. + + + + ZipProgressEventType.Extracting_AfterExtractAll + + Set when ExtractAll() has completed. The ArchiveName, Overwrite, + and ExtractLocation properties are meaningful. + + + + + ZipProgressEventType.Extracting_BeforeExtractEntry + + Set when an Extract() on an entry in the ZipFile has begun. + Properties that are meaningful: ArchiveName, EntriesTotal, + CurrentEntry, Overwrite, ExtractLocation, EntriesExtracted. + + + + + ZipProgressEventType.Extracting_AfterExtractEntry + + Set when an Extract() on an entry in the ZipFile has completed. + Properties that are meaningful: ArchiveName, EntriesTotal, + CurrentEntry, Overwrite, ExtractLocation, EntriesExtracted. + + + + + ZipProgressEventType.Extracting_EntryBytesWritten + + Set within a call to Extract() on an entry in the ZipFile, as data + is extracted for the entry. Properties that are meaningful: + ArchiveName, CurrentEntry, BytesTransferred, TotalBytesToTransfer. + + + + + ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite + + Set within a call to Extract() on an entry in the ZipFile, when the + extraction would overwrite an existing file. This event type is used + only when ExtractExistingFileAction on the ZipFile or + ZipEntry is set to InvokeExtractProgressEvent. + + + + + + + + + + private static bool justHadByteUpdate = false; + public static void ExtractProgress(object sender, ExtractProgressEventArgs e) + { + if(e.EventType == ZipProgressEventType.Extracting_EntryBytesWritten) + { + if (justHadByteUpdate) + Console.SetCursorPosition(0, Console.CursorTop); + + Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer, + e.BytesTransferred / (0.01 * e.TotalBytesToTransfer )); + justHadByteUpdate = true; + } + else if(e.EventType == ZipProgressEventType.Extracting_BeforeExtractEntry) + { + if (justHadByteUpdate) + Console.WriteLine(); + Console.WriteLine("Extracting: {0}", e.CurrentEntry.FileName); + justHadByteUpdate= false; + } + } + + public static ExtractZip(string zipToExtract, string directory) + { + string TargetDirectory= "extract"; + using (var zip = ZipFile.Read(zipToExtract)) { + zip.ExtractProgress += ExtractProgress; + foreach (var e in zip1) + { + e.Extract(TargetDirectory, true); + } + } + } + + + + Public Shared Sub Main(ByVal args As String()) + Dim ZipToUnpack As String = "C1P3SML.zip" + Dim TargetDir As String = "ExtractTest_Extract" + Console.WriteLine("Extracting file {0} to {1}", ZipToUnpack, TargetDir) + Using zip1 As ZipFile = ZipFile.Read(ZipToUnpack) + AddHandler zip1.ExtractProgress, AddressOf MyExtractProgress + Dim e As ZipEntry + For Each e In zip1 + e.Extract(TargetDir, True) + Next + End Using + End Sub + + Private Shared justHadByteUpdate As Boolean = False + + Public Shared Sub MyExtractProgress(ByVal sender As Object, ByVal e As ExtractProgressEventArgs) + If (e.EventType = ZipProgressEventType.Extracting_EntryBytesWritten) Then + If ExtractTest.justHadByteUpdate Then + Console.SetCursorPosition(0, Console.CursorTop) + End If + Console.Write(" {0}/{1} ({2:N0}%)", e.BytesTransferred, e.TotalBytesToTransfer, (CDbl(e.BytesTransferred) / (0.01 * e.TotalBytesToTransfer))) + ExtractTest.justHadByteUpdate = True + ElseIf (e.EventType = ZipProgressEventType.Extracting_BeforeExtractEntry) Then + If ExtractTest.justHadByteUpdate Then + Console.WriteLine + End If + Console.WriteLine("Extracting: {0}", e.CurrentEntry.FileName) + ExtractTest.justHadByteUpdate = False + End If + End Sub + + + + + + + + + + An event handler invoked before, during, and after Adding entries to a zip archive. + + + + Adding a large number of entries to a zip file can take a long + time. For example, when calling on a + directory that contains 50,000 files, it could take 3 minutes or so. + This event handler allws an application to track the progress of the Add + operation, and to optionally cancel a lengthy Add operation. + + + + + + int _numEntriesToAdd= 0; + int _numEntriesAdded= 0; + void AddProgressHandler(object sender, AddProgressEventArgs e) + { + switch (e.EventType) + { + case ZipProgressEventType.Adding_Started: + Console.WriteLine("Adding files to the zip..."); + break; + case ZipProgressEventType.Adding_AfterAddEntry: + _numEntriesAdded++; + Console.WriteLine(String.Format("Adding file {0}/{1} :: {2}", + _numEntriesAdded, _numEntriesToAdd, e.CurrentEntry.FileName)); + break; + case ZipProgressEventType.Adding_Completed: + Console.WriteLine("Added all files"); + break; + } + } + + void CreateTheZip() + { + using (ZipFile zip = new ZipFile()) + { + zip.AddProgress += AddProgressHandler; + zip.AddDirectory(System.IO.Path.GetFileName(DirToZip)); + zip.Save(ZipFileToCreate); + } + } + + + + + + Private Sub AddProgressHandler(ByVal sender As Object, ByVal e As AddProgressEventArgs) + Select Case e.EventType + Case ZipProgressEventType.Adding_Started + Console.WriteLine("Adding files to the zip...") + Exit Select + Case ZipProgressEventType.Adding_AfterAddEntry + Console.WriteLine(String.Format("Adding file {0}", e.CurrentEntry.FileName)) + Exit Select + Case ZipProgressEventType.Adding_Completed + Console.WriteLine("Added all files") + Exit Select + End Select + End Sub + + Sub CreateTheZip() + Using zip as ZipFile = New ZipFile + AddHandler zip.AddProgress, AddressOf AddProgressHandler + zip.AddDirectory(System.IO.Path.GetFileName(DirToZip)) + zip.Save(ZipFileToCreate); + End Using + End Sub + + + + + + + + + + + + An event that is raised when an error occurs during open or read of files + while saving a zip archive. + + + + + Errors can occur as a file is being saved to the zip archive. For + example, the File.Open may fail, or a File.Read may fail, because of + lock conflicts or other reasons. If you add a handler to this event, + you can handle such errors in your own code. If you don't add a + handler, the library will throw an exception if it encounters an I/O + error during a call to Save(). + + + + Setting a handler implicitly sets to + ZipErrorAction.InvokeErrorEvent. + + + + The handler you add applies to all items that are + subsequently added to the ZipFile instance. If you set this + property after you have added items to the ZipFile, but before you + have called Save(), errors that occur while saving those items + will not cause the error handler to be invoked. + + + + If you want to handle any errors that occur with any entry in the zip + file using the same error handler, then add your error handler once, + before adding any entries to the zip archive. + + + + In the error handler method, you need to set the property on the + ZipErrorEventArgs.CurrentEntry. This communicates back to + DotNetZip what you would like to do with this particular error. Within + an error handler, if you set the ZipEntry.ZipErrorAction property + on the ZipEntry to ZipErrorAction.InvokeErrorEvent or if + you don't set it at all, the library will throw the exception. (It is the + same as if you had set the ZipEntry.ZipErrorAction property on the + ZipEntry to ZipErrorAction.Throw.) If you set the + ZipErrorEventArgs.Cancel to true, the entire Save() will be + canceled. + + + + In the case that you use ZipErrorAction.Skip, implying that + you want to skip the entry for which there's been an error, DotNetZip + tries to seek backwards in the output stream, and truncate all bytes + written on behalf of that particular entry. This works only if the + output stream is seekable. It will not work, for example, when using + ASPNET's Response.OutputStream. + + + + + + + This example shows how to use an event handler to handle + errors during save of the zip file. + + + public static void MyZipError(object sender, ZipErrorEventArgs e) + { + Console.WriteLine("Error saving {0}...", e.FileName); + Console.WriteLine(" Exception: {0}", e.exception); + ZipEntry entry = e.CurrentEntry; + string response = null; + // Ask the user whether he wants to skip this error or not + do + { + Console.Write("Retry, Skip, Throw, or Cancel ? (R/S/T/C) "); + response = Console.ReadLine(); + Console.WriteLine(); + + } while (response != null && + response[0]!='S' && response[0]!='s' && + response[0]!='R' && response[0]!='r' && + response[0]!='T' && response[0]!='t' && + response[0]!='C' && response[0]!='c'); + + e.Cancel = (response[0]=='C' || response[0]=='c'); + + if (response[0]=='S' || response[0]=='s') + entry.ZipErrorAction = ZipErrorAction.Skip; + else if (response[0]=='R' || response[0]=='r') + entry.ZipErrorAction = ZipErrorAction.Retry; + else if (response[0]=='T' || response[0]=='t') + entry.ZipErrorAction = ZipErrorAction.Throw; + } + + public void SaveTheFile() + { + string directoryToZip = "fodder"; + string directoryInArchive = "files"; + string zipFileToCreate = "Archive.zip"; + using (var zip = new ZipFile()) + { + // set the event handler before adding any entries + zip.ZipError += MyZipError; + zip.AddDirectory(directoryToZip, directoryInArchive); + zip.Save(zipFileToCreate); + } + } + + + + Private Sub MyZipError(ByVal sender As Object, ByVal e As Ionic.Zip.ZipErrorEventArgs) + ' At this point, the application could prompt the user for an action to take. + ' But in this case, this application will simply automatically skip the file, in case of error. + Console.WriteLine("Zip Error, entry {0}", e.CurrentEntry.FileName) + Console.WriteLine(" Exception: {0}", e.exception) + ' set the desired ZipErrorAction on the CurrentEntry to communicate that to DotNetZip + e.CurrentEntry.ZipErrorAction = Zip.ZipErrorAction.Skip + End Sub + + Public Sub SaveTheFile() + Dim directoryToZip As String = "fodder" + Dim directoryInArchive As String = "files" + Dim zipFileToCreate as String = "Archive.zip" + Using zipArchive As ZipFile = New ZipFile + ' set the event handler before adding any entries + AddHandler zipArchive.ZipError, AddressOf MyZipError + zipArchive.AddDirectory(directoryToZip, directoryInArchive) + zipArchive.Save(zipFileToCreate) + End Using + End Sub + + + + + + + + + Options for using ZIP64 extensions when saving zip archives. + + + + + + Designed many years ago, the original zip + specification from PKWARE allowed for 32-bit quantities for the + compressed and uncompressed sizes of zip entries, as well as a 32-bit quantity + for specifying the length of the zip archive itself, and a maximum of 65535 + entries. These limits are now regularly exceeded in many backup and archival + scenarios. Recently, PKWare added extensions to the original zip spec, called + "ZIP64 extensions", to raise those limitations. This property governs whether + DotNetZip will use those extensions when writing zip archives. The use of + these extensions is optional and explicit in DotNetZip because, despite the + status of ZIP64 as a bona fide standard, many other zip tools and libraries do + not support ZIP64, and therefore a zip file with ZIP64 extensions may be + unreadable by some of those other tools. + + + + Set this property to to always use ZIP64 + extensions when saving, regardless of whether your zip archive needs it. + Suppose you add 5 files, each under 100k, to a ZipFile. If you specify Always + for this flag, you will get a ZIP64 archive, though the archive does not need + to use ZIP64 because none of the original zip limits had been exceeded. + + + + Set this property to to tell the DotNetZip + library to never use ZIP64 extensions. This is useful for maximum + compatibility and interoperability, at the expense of the capability of + handling large files or large archives. NB: Windows Explorer in Windows XP + and Windows Vista cannot currently extract files from a zip64 archive, so if + you want to guarantee that a zip archive produced by this library will work in + Windows Explorer, use Never. If you set this property to , and your application creates a zip that would + exceed one of the Zip limits, the library will throw an exception while saving + the zip file. + + + + Set this property to to tell the + DotNetZip library to use the ZIP64 extensions when required by the + entry. After the file is compressed, the original and compressed sizes are + checked, and if they exceed the limits described above, then zip64 can be + used. That is the general idea, but there is an additional wrinkle when saving + to a non-seekable device, like the ASP.NET Response.OutputStream, or + Console.Out. When using non-seekable streams for output, the entry + header - which indicates whether zip64 is in use - is emitted before it is + known if zip64 is necessary. It is only after all entries have been saved + that it can be known if ZIP64 will be required. On seekable output streams, + after saving all entries, the library can seek backward and re-emit the zip + file header to be consistent with the actual ZIP64 requirement. But using a + non-seekable output stream, the library cannot seek backward, so the header + can never be changed. In other words, the archive's use of ZIP64 extensions is + not alterable after the header is emitted. Therefore, when saving to + non-seekable streams, using is the same + as using : it will always produce a zip + archive that uses ZIP64 extensions. + + + + + + + The default behavior, which is "Never". + (For COM clients, this is a 0 (zero).) + + + + + Do not use ZIP64 extensions when writing zip archives. + (For COM clients, this is a 0 (zero).) + + + + + Use ZIP64 extensions when writing zip archives, as necessary. + For example, when a single entry exceeds 0xFFFFFFFF in size, or when the archive as a whole + exceeds 0xFFFFFFFF in size, or when there are more than 65535 entries in an archive. + (For COM clients, this is a 1.) + + + + + Always use ZIP64 extensions when writing zip archives, even when unnecessary. + (For COM clients, this is a 2.) + + + + + An enum representing the values on a three-way toggle switch + for various options in the library. This might be used to + specify whether to employ a particular text encoding, or to use + ZIP64 extensions, or some other option. + + + + + The default behavior. This is the same as "Never". + (For COM clients, this is a 0 (zero).) + + + + + Never use the associated option. + (For COM clients, this is a 0 (zero).) + + + + + Use the associated behavior "as necessary." + (For COM clients, this is a 1.) + + + + + Use the associated behavior Always, whether necessary or not. + (For COM clients, this is a 2.) + + + + + A class for collecting the various options that can be used when + Reading zip files for extraction or update. + + + + + When reading a zip file, there are several options an + application can set, to modify how the file is read, or what + the library does while reading. This class collects those + options into one container. + + + + Pass an instance of the ReadOptions class into the + ZipFile.Read() method. + + + . + . + + + + + An event handler for Read operations. When opening large zip + archives, you may want to display a progress bar or other + indicator of status progress while reading. This parameter + allows you to specify a ReadProgress Event Handler directly. + When you call Read(), the progress event is invoked as + necessary. + + + + + The System.IO.TextWriter to use for writing verbose status messages + during operations on the zip archive. A console application may wish to + pass System.Console.Out to get messages on the Console. A graphical + or headless application may wish to capture the messages in a different + TextWriter, such as a System.IO.StringWriter. + + + + + The System.Text.Encoding to use when reading in the zip archive. Be + careful specifying the encoding. If the value you use here is not the same + as the Encoding used when the zip archive was created (possibly by a + different archiver) you will get unexpected results and possibly exceptions. + + + + + + + + An enum that provides the different self-extractor flavors + + + + + A self-extracting zip archive that runs from the console or + command line. + + + + + A self-extracting zip archive that presents a graphical user + interface when it is executed. + + + + + The options for generating a self-extracting archive. + + + + + The type of SFX to create. + + + + + The command to run after extraction. + + + + + This is optional. Leave it empty (null in C# or Nothing in + VB) to run no command after extraction. + + + + If it is non-empty, the SFX will execute the command specified in this + string on the user's machine, and using the extract directory as the + working directory for the process, after unpacking the archive. The + program to execute can include a path, if you like. If you want to execute + a program that accepts arguments, specify the program name, followed by a + space, and then the arguments for the program, each separated by a space, + just as you would on a normal command line. Example: program.exe arg1 + arg2. The string prior to the first space will be taken as the + program name, and the string following the first space specifies the + arguments to the program. + + + + If you want to execute a program that has a space in the name or path of + the file, surround the program name in double-quotes. The first character + of the command line should be a double-quote character, and there must be + a matching double-quote following the end of the program file name. Any + optional arguments to the program follow that, separated by + spaces. Example: "c:\project files\program name.exe" arg1 arg2. + + + + If the flavor of the SFX is SelfExtractorFlavor.ConsoleApplication, + then the SFX starts a new process, using this string as the post-extract + command line. The SFX waits for the process to exit. The exit code of + the post-extract command line is returned as the exit code of the + command-line self-extractor exe. A non-zero exit code is typically used to + indicated a failure by the program. In the case of an SFX, a non-zero exit + code may indicate a failure during extraction, OR, it may indicate a + failure of the run-after-extract program if specified, OR, it may indicate + the run-after-extract program could not be fuond. There is no way to + distinguish these conditions from the calling shell, aside from parsing + the output of the SFX. If you have Quiet set to true, you may not + see error messages, if a problem occurs. + + + + If the flavor of the SFX is + SelfExtractorFlavor.WinFormsApplication, then the SFX starts a new + process, using this string as the post-extract command line, and using the + extract directory as the working directory for the process. The SFX does + not wait for the command to complete, and does not check the exit code of + the program. If the run-after-extract program cannot be fuond, a message + box is displayed indicating that fact. + + + + You can specify environment variables within this string, with a format like + %NAME%. The value of these variables will be expanded at the time + the SFX is run. Example: %WINDIR%\system32\xcopy.exe may expand at + runtime to c:\Windows\System32\xcopy.exe. + + + + By combining this with the RemoveUnpackedFilesAfterExecute + flag, you can create an SFX that extracts itself, runs a file that + was extracted, then deletes all the files that were extracted. If + you want it to run "invisibly" then set Flavor to + SelfExtractorFlavor.ConsoleApplication, and set Quiet + to true. The user running such an EXE will see a console window + appear, then disappear quickly. You may also want to specify the + default extract location, with DefaultExtractDirectory. + + + + If you set Flavor to + SelfExtractorFlavor.WinFormsApplication, and set Quiet to + true, then a GUI with progressbars is displayed, but it is + "non-interactive" - it accepts no input from the user. Instead the SFX + just automatically unpacks and exits. + + + + + + + The default extract directory the user will see when + running the self-extracting archive. + + + + + Passing null (or Nothing in VB) here will cause the Self Extractor to use + the the user's personal directory () for the default extract + location. + + + + This is only a default location. The actual extract location will be + settable on the command line when the SFX is executed. + + + + You can specify environment variables within this string, + with %NAME%. The value of these variables will be + expanded at the time the SFX is run. Example: + %USERPROFILE%\Documents\unpack may expand at runtime to + c:\users\melvin\Documents\unpack. + + + + + + The name of an .ico file in the filesystem to use for the application icon + for the generated SFX. + + + + + Normally, DotNetZip will embed an "zipped folder" icon into the generated + SFX. If you prefer to use a different icon, you can specify it here. It + should be a .ico file. This file is passed as the /win32icon + option to the csc.exe compiler when constructing the SFX file. + + + + + + + Whether the ConsoleApplication SFX will be quiet during extraction. + + + + + This option affects the way the generated SFX runs. By default it is + false. When you set it to true,... + + + + + Flavor + Behavior + + + + ConsoleApplication + no messages will be emitted during successful + operation. Double-clicking the SFX in Windows + Explorer or as an attachment in an email will cause a console + window to appear briefly, before it disappears. If you run the + ConsoleApplication SFX from the cmd.exe prompt, it runs as a + normal console app; by default, because it is quiet, it displays + no messages to the console. If you pass the -v+ command line + argument to the Console SFX when you run it, you will get verbose + messages to the console. + + + + + WinFormsApplication + the SFX extracts automatically when the application + is launched, with no additional user input. + + + + + + + When you set it to false,... + + + + + Flavor + Behavior + + + + ConsoleApplication + the extractor will emit a + message to the console for each entry extracted. + + When double-clicking to launch the SFX, the console window will + remain, and the SFX will emit a message for each file as it + extracts. The messages fly by quickly, they won't be easily + readable, unless the extracted files are fairly large. + + + + + + WinFormsApplication + the SFX presents a forms UI and allows the user to select + options before extracting. + + + + + + + + + + Specify what the self-extractor will do when extracting an entry + would overwrite an existing file. + + + + The default behavvior is to Throw. + + + + + + Whether to remove the files that have been unpacked, after executing the + PostExtractCommandLine. + + + + + If true, and if there is a + PostExtractCommandLine, and if the command runs successfully, + then the files that the SFX unpacked will be removed, afterwards. If + the command does not complete successfully (non-zero return code), + that is interpreted as a failure, and the extracted files will not be + removed. + + + + Setting this flag, and setting Flavor to + SelfExtractorFlavor.ConsoleApplication, and setting Quiet to + true, results in an SFX that extracts itself, runs a file that was + extracted, then deletes all the files that were extracted, with no + intervention by the user. You may also want to specify the default + extract location, with DefaultExtractDirectory. + + + + + + + The file version number to embed into the generated EXE. It will show up, for + example, during a mouseover in Windows Explorer. + + + + + + The product version to embed into the generated EXE. It will show up, for + example, during a mouseover in Windows Explorer. + + + + You can use any arbitrary string, but a human-readable version number is + recommended. For example "v1.2 alpha" or "v4.2 RC2". If you specify nothing, + then there is no product version embedded into the EXE. + + + + + + The copyright notice, if any, to embed into the generated EXE. + + + + It will show up, for example, while viewing properties of the file in + Windows Explorer. You can use any arbitrary string, but typically you + want something like "Copyright © Dino Chiesa 2011". + + + + + + The description to embed into the generated EXE. + + + + Use any arbitrary string. This text will be displayed during a + mouseover in Windows Explorer. If you specify nothing, then the string + "DotNetZip SFX Archive" is embedded into the EXE as the description. + + + + + + The product name to embed into the generated EXE. + + + + Use any arbitrary string. This text will be displayed + while viewing properties of the EXE file in + Windows Explorer. + + + + + + The title to display in the Window of a GUI SFX, while it extracts. + + + + + By default the title show in the GUI window of a self-extractor + is "DotNetZip Self-extractor (http://DotNetZip.codeplex.com/)". + You can change that by setting this property before saving the SFX. + + + + This property has an effect only when producing a Self-extractor + of flavor SelfExtractorFlavor.WinFormsApplication. + + + + + + + Additional options for the csc.exe compiler, when producing the SFX + EXE. + + + + + + Reset the BitWriter. + + + + This is useful when the BitWriter writes into a MemoryStream, and + is used by a BZip2Compressor, which itself is re-used for multiple + distinct data blocks. + + + + + + Write some number of bits from the given value, into the output. + + + + The nbits value should be a max of 25, for safety. For performance + reasons, this method does not check! + + + + + + Write a full 8-bit byte into the output. + + + + + Write four 8-bit bytes into the output. + + + + + Write all available byte-aligned bytes. + + + + This method writes no new output, but flushes any accumulated + bits. At completion, the accumulator may contain up to 7 + bits. + + + This is necessary when re-assembling output from N independent + compressors, one for each of N blocks. The output of any + particular compressor will in general have some fragment of a byte + remaining. This fragment needs to be accumulated into the + parent BZip2OutputStream. + + + + + + Writes all available bytes, and emits padding for the final byte as + necessary. This must be the last method invoked on an instance of + BitWriter. + + + + + Delivers the remaining bits, left-aligned, in a byte. + + + + This is valid only if NumRemainingBits is less than 8; + in other words it is valid only after a call to Flush(). + + + + + Knuth's increments seem to work better than Incerpi-Sedgewick here. + Possibly because the number of elems to sort is usually small, typically + <= 20. + + + + BZip2Compressor writes its compressed data out via a BitWriter. This + is necessary because BZip2 does byte shredding. + + + + + Accept new bytes into the compressor data buffer + + + + This method does the first-level (cheap) run-length encoding, and + stores the encoded data into the rle block. + + + + + + Process one input byte into the block. + + + + + To "process" the byte means to do the run-length encoding. + There are 3 possible return values: + + 0 - the byte was not written, in other words, not + encoded into the block. This happens when the + byte b would require the start of a new run, and + the block has no more room for new runs. + + 1 - the byte was written, and the block is not full. + + 2 - the byte was written, and the block is full. + + + + 0 if the byte was not written, non-zero if written. + + + + Append one run to the output block. + + + + + This compressor does run-length-encoding before BWT and etc. This + method simply appends a run to the output block. The append always + succeeds. The return value indicates whether the block is full: + false (not full) implies that at least one additional run could be + processed. + + + true if the block is now full; otherwise false. + + + + Compress the data that has been placed (Run-length-encoded) into the + block. The compressed data goes into the CompressedBytes array. + + + + Side effects: 1. fills the CompressedBytes array. 2. sets the + AvailableBytesOut property. + + + + + This is the most hammered method of this class. + +

    + This is the version using unrolled loops. +

    +
    + + Method "mainQSort3", file "blocksort.c", BZip2 1.0.2 + + + + The number of uncompressed bytes being held in the buffer. + + + + I am thinking this may be useful in a Stream that uses this + compressor class. In the Close() method on the stream it could + check this value to see if anything has been written at all. You + may think the stream could easily track the number of bytes it + wrote, which would eliminate the need for this. But, there is the + case where the stream writes a complete block, and it is full, and + then writes no more. In that case the stream may want to check. + + + + + Array instance identical to sfmap, both are used only + temporarily and independently, so we do not need to allocate + additional memory. + + + + A read-only decorator stream that performs BZip2 decompression on Read. + + + + + Create a BZip2InputStream, wrapping it around the given input Stream. + + + + The input stream will be closed when the BZip2InputStream is closed. + + + The stream from which to read compressed data + + + + Create a BZip2InputStream with the given stream, and + specifying whether to leave the wrapped stream open when + the BZip2InputStream is closed. + + The stream from which to read compressed data + + Whether to leave the input stream open, when the BZip2InputStream closes. + + + + + This example reads a bzip2-compressed file, decompresses it, + and writes the decompressed data into a newly created file. + + + var fname = "logfile.log.bz2"; + using (var fs = File.OpenRead(fname)) + { + using (var decompressor = new Ionic.BZip2.BZip2InputStream(fs)) + { + var outFname = fname + ".decompressed"; + using (var output = File.Create(outFname)) + { + byte[] buffer = new byte[2048]; + int n; + while ((n = decompressor.Read(buffer, 0, buffer.Length)) > 0) + { + output.Write(buffer, 0, n); + } + } + } + } + + + + + + Read data from the stream. + + + + + To decompress a BZip2 data stream, create a BZip2InputStream, + providing a stream that reads compressed data. Then call Read() on + that BZip2InputStream, and the data read will be decompressed + as you read. + + + + A BZip2InputStream can be used only for Read(), not for Write(). + + + + The buffer into which the read data should be placed. + the offset within that data array to put the first byte read. + the number of bytes to read. + the number of bytes actually read + + + + Read a single byte from the stream. + + the byte read from the stream, or -1 if EOF + + + + Flush the stream. + + + + + Calling this method always throws a . + + this is irrelevant, since it will always throw! + this is irrelevant, since it will always throw! + irrelevant! + + + + Calling this method always throws a . + + this is irrelevant, since it will always throw! + + + + Calling this method always throws a . + + this parameter is never used + this parameter is never used + this parameter is never used + + + + Dispose the stream. + + + indicates whether the Dispose method was invoked by user code. + + + + + Close the stream. + + + + + Read n bits from input, right justifying the result. + + + + For example, if you read 1 bit, the result is either 0 + or 1. + + + + The number of bits to read, always between 1 and 32. + + + + Called by createHuffmanDecodingTables() exclusively. + + + Called by recvDecodingTables() exclusively. + + + + Indicates whether the stream can be read. + + + The return value depends on whether the captive stream supports reading. + + + + + Indicates whether the stream supports Seek operations. + + + Always returns false. + + + + + Indicates whether the stream can be written. + + + The return value depends on whether the captive stream supports writing. + + + + + Reading this property always throws a . + + + + + The position of the stream pointer. + + + + Setting this property always throws a . Reading will return the + total number of uncompressed bytes read in. + + + + + Compressor State + + + + Freq table collected to save a pass over the data during + decompression. + + + Initializes the tt array. + + This method is called when the required length of the array is known. + I don't initialize it at construction time to avoid unneccessary + memory allocation when compressing small files. + + + + A write-only decorator stream that compresses data as it is + written using the BZip2 algorithm. + + + + + Constructs a new BZip2OutputStream, that sends its + compressed output to the given output stream. + + + + The destination stream, to which compressed output will be sent. + + + + + This example reads a file, then compresses it with bzip2 file, + and writes the compressed data into a newly created file. + + + var fname = "logfile.log"; + using (var fs = File.OpenRead(fname)) + { + var outFname = fname + ".bz2"; + using (var output = File.Create(outFname)) + { + using (var compressor = new Ionic.BZip2.BZip2OutputStream(output)) + { + byte[] buffer = new byte[2048]; + int n; + while ((n = fs.Read(buffer, 0, buffer.Length)) > 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + + + + Constructs a new BZip2OutputStream with specified blocksize. + + the destination stream. + + The blockSize in units of 100000 bytes. + The valid range is 1..9. + + + + + Constructs a new BZip2OutputStream. + + the destination stream. + + whether to leave the captive stream open upon closing this stream. + + + + + Constructs a new BZip2OutputStream with specified blocksize, + and explicitly specifies whether to leave the wrapped stream open. + + + the destination stream. + + The blockSize in units of 100000 bytes. + The valid range is 1..9. + + + whether to leave the captive stream open upon closing this stream. + + + + + Close the stream. + + + + This may or may not close the underlying stream. Check the + constructors that accept a bool value. + + + + + + Flush the stream. + + + + + Write data to the stream. + + + + + Use the BZip2OutputStream to compress data while writing: + create a BZip2OutputStream with a writable output stream. + Then call Write() on that BZip2OutputStream, providing + uncompressed data as input. The data sent to the output stream will + be the compressed form of the input data. + + + + A BZip2OutputStream can be used only for Write() not for Read(). + + + + + The buffer holding data to write to the stream. + the offset within that data array to find the first byte to write. + the number of bytes to write. + + + + Calling this method always throws a . + + this is irrelevant, since it will always throw! + this is irrelevant, since it will always throw! + irrelevant! + + + + Calling this method always throws a . + + this is irrelevant, since it will always throw! + + + + Calling this method always throws a . + + this parameter is never used + this parameter is never used + this parameter is never used + never returns anything; always throws + + + + The blocksize parameter specified at construction time. + + + + + Indicates whether the stream can be read. + + + The return value is always false. + + + + + Indicates whether the stream supports Seek operations. + + + Always returns false. + + + + + Indicates whether the stream can be written. + + + The return value should always be true, unless and until the + object is disposed and closed. + + + + + Reading this property always throws a . + + + + + The position of the stream pointer. + + + + Setting this property always throws a . Reading will return the + total number of uncompressed bytes written through. + + + + + A write-only decorator stream that compresses data as it is + written using the BZip2 algorithm. This stream compresses by + block using multiple threads. + + + This class performs BZIP2 compression through writing. For + more information on the BZIP2 algorithm, see + . + + + + This class is similar to , + except that this implementation uses an approach that employs multiple + worker threads to perform the compression. On a multi-cpu or multi-core + computer, the performance of this class can be significantly higher than + the single-threaded BZip2OutputStream, particularly for larger streams. + How large? Anything over 10mb is a good candidate for parallel + compression. + + + + The tradeoff is that this class uses more memory and more CPU than the + vanilla BZip2OutputStream. Also, for small files, the + ParallelBZip2OutputStream can be much slower than the vanilla + BZip2OutputStream, because of the overhead associated to using the + thread pool. + + + + + + + Constructs a new ParallelBZip2OutputStream, that sends its + compressed output to the given output stream. + + + + The destination stream, to which compressed output will be sent. + + + + + This example reads a file, then compresses it with bzip2 file, + and writes the compressed data into a newly created file. + + + var fname = "logfile.log"; + using (var fs = File.OpenRead(fname)) + { + var outFname = fname + ".bz2"; + using (var output = File.Create(outFname)) + { + using (var compressor = new Ionic.BZip2.ParallelBZip2OutputStream(output)) + { + byte[] buffer = new byte[2048]; + int n; + while ((n = fs.Read(buffer, 0, buffer.Length)) > 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + + + + Constructs a new ParallelBZip2OutputStream with specified blocksize. + + the destination stream. + + The blockSize in units of 100000 bytes. + The valid range is 1..9. + + + + + Constructs a new ParallelBZip2OutputStream. + + the destination stream. + + whether to leave the captive stream open upon closing this stream. + + + + + Constructs a new ParallelBZip2OutputStream with specified blocksize, + and explicitly specifies whether to leave the wrapped stream open. + + + the destination stream. + + The blockSize in units of 100000 bytes. + The valid range is 1..9. + + + whether to leave the captive stream open upon closing this stream. + + + + + Close the stream. + + + + This may or may not close the underlying stream. Check the + constructors that accept a bool value. + + + + + + Flush the stream. + + + + + Write data to the stream. + + + + + Use the ParallelBZip2OutputStream to compress data while + writing: create a ParallelBZip2OutputStream with a writable + output stream. Then call Write() on that + ParallelBZip2OutputStream, providing uncompressed data as + input. The data sent to the output stream will be the compressed + form of the input data. + + + + A ParallelBZip2OutputStream can be used only for + Write() not for Read(). + + + + + The buffer holding data to write to the stream. + the offset within that data array to find the first byte to write. + the number of bytes to write. + + + + Calling this method always throws a . + + this is irrelevant, since it will always throw! + this is irrelevant, since it will always throw! + irrelevant! + + + + Calling this method always throws a . + + this is irrelevant, since it will always throw! + + + + Calling this method always throws a . + + this parameter is never used + this parameter is never used + this parameter is never used + never returns anything; always throws + + + + The maximum number of concurrent compression worker threads to use. + + + + + This property sets an upper limit on the number of concurrent worker + threads to employ for compression. The implementation of this stream + employs multiple threads from the .NET thread pool, via + ThreadPool.QueueUserWorkItem(), to compress the incoming data by + block. As each block of data is compressed, this stream re-orders the + compressed blocks and writes them to the output stream. + + + + A higher number of workers enables a higher degree of + parallelism, which tends to increase the speed of compression on + multi-cpu computers. On the other hand, a higher number of buffer + pairs also implies a larger memory consumption, more active worker + threads, and a higher cpu utilization for any compression. This + property enables the application to limit its memory consumption and + CPU utilization behavior depending on requirements. + + + + By default, DotNetZip allocates 4 workers per CPU core, subject to the + upper limit specified in this property. For example, suppose the + application sets this property to 16. Then, on a machine with 2 + cores, DotNetZip will use 8 workers; that number does not exceed the + upper limit specified by this property, so the actual number of + workers used will be 4 * 2 = 8. On a machine with 4 cores, DotNetZip + will use 16 workers; again, the limit does not apply. On a machine + with 8 cores, DotNetZip will use 16 workers, because of the limit. + + + + For each compression "worker thread" that occurs in parallel, there is + up to 2mb of memory allocated, for buffering and processing. The + actual number depends on the property. + + + + CPU utilization will also go up with additional workers, because a + larger number of buffer pairs allows a larger number of background + threads to compress in parallel. If you find that parallel + compression is consuming too much memory or CPU, you can adjust this + value downward. + + + + The default value is 16. Different values may deliver better or + worse results, depending on your priorities and the dynamic + performance characteristics of your storage and compute resources. + + + + The application can set this value at any time, but it is effective + only before the first call to Write(), which is when the buffers are + allocated. + + + + + + The blocksize parameter specified at construction time. + + + + + Indicates whether the stream can be read. + + + The return value is always false. + + + + + Indicates whether the stream supports Seek operations. + + + Always returns false. + + + + + Indicates whether the stream can be written. + + + The return value depends on whether the captive stream supports writing. + + + + + Reading this property always throws a . + + + + + The position of the stream pointer. + + + + Setting this property always throws a . Reading will return the + total number of uncompressed bytes written through. + + + + + The total number of bytes written out by the stream. + + + This value is meaningful only after a call to Close(). + + + + + Returns the "random" number at a specific index. + + the index + the random number + + + + A class for compressing and decompressing streams using the Deflate algorithm. + + + + + + The DeflateStream is a Decorator on a . It adds DEFLATE compression or decompression to any + stream. + + + + Using this stream, applications can compress or decompress data via stream + Read and Write operations. Either compresssion or decompression + can occur through either reading or writing. The compression format used is + DEFLATE, which is documented in IETF RFC 1951, "DEFLATE + Compressed Data Format Specification version 1.3.". + + + + This class is similar to , except that + ZlibStream adds the RFC + 1950 - ZLIB framing bytes to a compressed stream when compressing, or + expects the RFC1950 framing bytes when decompressing. The DeflateStream + does not. + + + + + + + + + + Create a DeflateStream using the specified CompressionMode. + + + + When mode is CompressionMode.Compress, the DeflateStream will use + the default compression level. The "captive" stream will be closed when + the DeflateStream is closed. + + + + This example uses a DeflateStream to compress data from a file, and writes + the compressed data to another file. + + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (var raw = System.IO.File.Create(fileToCompress + ".deflated")) + { + using (Stream compressor = new DeflateStream(raw, CompressionMode.Compress)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n; + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + + Using input As Stream = File.OpenRead(fileToCompress) + Using raw As FileStream = File.Create(fileToCompress & ".deflated") + Using compressor As Stream = New DeflateStream(raw, CompressionMode.Compress) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + End Using + + + The stream which will be read or written. + Indicates whether the DeflateStream will compress or decompress. + + + + Create a DeflateStream using the specified CompressionMode and the specified CompressionLevel. + + + + + + When mode is CompressionMode.Decompress, the level parameter is + ignored. The "captive" stream will be closed when the DeflateStream is + closed. + + + + + + + This example uses a DeflateStream to compress data from a file, and writes + the compressed data to another file. + + + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (var raw = System.IO.File.Create(fileToCompress + ".deflated")) + { + using (Stream compressor = new DeflateStream(raw, + CompressionMode.Compress, + CompressionLevel.BestCompression)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n= -1; + while (n != 0) + { + if (n > 0) + compressor.Write(buffer, 0, n); + n= input.Read(buffer, 0, buffer.Length); + } + } + } + } + + + + Using input As Stream = File.OpenRead(fileToCompress) + Using raw As FileStream = File.Create(fileToCompress & ".deflated") + Using compressor As Stream = New DeflateStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + End Using + + + The stream to be read or written while deflating or inflating. + Indicates whether the DeflateStream will compress or decompress. + A tuning knob to trade speed for effectiveness. + + + + Create a DeflateStream using the specified + CompressionMode, and explicitly specify whether the + stream should be left open after Deflation or Inflation. + + + + + + This constructor allows the application to request that the captive stream + remain open after the deflation or inflation occurs. By default, after + Close() is called on the stream, the captive stream is also + closed. In some cases this is not desired, for example if the stream is a + memory stream that will be re-read after compression. Specify true for + the parameter to leave the stream open. + + + + The DeflateStream will use the default compression level. + + + + See the other overloads of this constructor for example code. + + + + + The stream which will be read or written. This is called the + "captive" stream in other places in this documentation. + + + + Indicates whether the DeflateStream will compress or decompress. + + + true if the application would like the stream to + remain open after inflation/deflation. + + + + Create a DeflateStream using the specified CompressionMode + and the specified CompressionLevel, and explicitly specify whether + the stream should be left open after Deflation or Inflation. + + + + + + When mode is CompressionMode.Decompress, the level parameter is ignored. + + + + This constructor allows the application to request that the captive stream + remain open after the deflation or inflation occurs. By default, after + Close() is called on the stream, the captive stream is also + closed. In some cases this is not desired, for example if the stream is a + that will be re-read after + compression. Specify true for the parameter + to leave the stream open. + + + + + + + This example shows how to use a DeflateStream to compress data from + a file, and store the compressed data into another file. + + + using (var output = System.IO.File.Create(fileToCompress + ".deflated")) + { + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (Stream compressor = new DeflateStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, true)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n= -1; + while (n != 0) + { + if (n > 0) + compressor.Write(buffer, 0, n); + n= input.Read(buffer, 0, buffer.Length); + } + } + } + // can write additional data to the output stream here + } + + + + Using output As FileStream = File.Create(fileToCompress & ".deflated") + Using input As Stream = File.OpenRead(fileToCompress) + Using compressor As Stream = New DeflateStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, True) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + ' can write additional data to the output stream here. + End Using + + + The stream which will be read or written. + Indicates whether the DeflateStream will compress or decompress. + true if the application would like the stream to remain open after inflation/deflation. + A tuning knob to trade speed for effectiveness. + + + + Dispose the stream. + + + + This may or may not result in a Close() call on the captive + stream. See the constructors that have a leaveOpen parameter + for more information. + + + Application code won't call this code directly. This method may be + invoked in two distinct scenarios. If disposing == true, the method + has been called directly or indirectly by a user's code, for example + via the public Dispose() method. In this case, both managed and + unmanaged resources can be referenced and disposed. If disposing == + false, the method has been called by the runtime from inside the + object finalizer and this method should not reference other objects; + in that case only unmanaged resources must be referenced or + disposed. + + + + true if the Dispose method was invoked by user code. + + + + + Flush the stream. + + + + + Read data from the stream. + + + + + If you wish to use the DeflateStream to compress data while + reading, you can create a DeflateStream with + CompressionMode.Compress, providing an uncompressed data stream. + Then call Read() on that DeflateStream, and the data read will be + compressed as you read. If you wish to use the DeflateStream to + decompress data while reading, you can create a DeflateStream with + CompressionMode.Decompress, providing a readable compressed data + stream. Then call Read() on that DeflateStream, and the data read + will be decompressed as you read. + + + + A DeflateStream can be used for Read() or Write(), but not both. + + + + The buffer into which the read data should be placed. + the offset within that data array to put the first byte read. + the number of bytes to read. + the number of bytes actually read + + + + Calling this method always throws a . + + this is irrelevant, since it will always throw! + this is irrelevant, since it will always throw! + irrelevant! + + + + Calling this method always throws a . + + this is irrelevant, since it will always throw! + + + + Write data to the stream. + + + + + If you wish to use the DeflateStream to compress data while + writing, you can create a DeflateStream with + CompressionMode.Compress, and a writable output stream. Then call + Write() on that DeflateStream, providing uncompressed data + as input. The data sent to the output stream will be the compressed form + of the data written. If you wish to use the DeflateStream to + decompress data while writing, you can create a DeflateStream with + CompressionMode.Decompress, and a writable output stream. Then + call Write() on that stream, providing previously compressed + data. The data sent to the output stream will be the decompressed form of + the data written. + + + + A DeflateStream can be used for Read() or Write(), + but not both. + + + + + The buffer holding data to write to the stream. + the offset within that data array to find the first byte to write. + the number of bytes to write. + + + + Compress a string into a byte array using DEFLATE (RFC 1951). + + + + Uncompress it with . + + + DeflateStream.UncompressString(byte[]) + DeflateStream.CompressBuffer(byte[]) + GZipStream.CompressString(string) + ZlibStream.CompressString(string) + + + A string to compress. The string will first be encoded + using UTF8, then compressed. + + + The string in compressed form + + + + Compress a byte array into a new byte array using DEFLATE. + + + + Uncompress it with . + + + DeflateStream.CompressString(string) + DeflateStream.UncompressBuffer(byte[]) + GZipStream.CompressBuffer(byte[]) + ZlibStream.CompressBuffer(byte[]) + + + A buffer to compress. + + + The data in compressed form + + + + Uncompress a DEFLATE'd byte array into a single string. + + + DeflateStream.CompressString(String) + DeflateStream.UncompressBuffer(byte[]) + GZipStream.UncompressString(byte[]) + ZlibStream.UncompressString(byte[]) + + + A buffer containing DEFLATE-compressed data. + + + The uncompressed string + + + + Uncompress a DEFLATE'd byte array into a byte array. + + + DeflateStream.CompressBuffer(byte[]) + DeflateStream.UncompressString(byte[]) + GZipStream.UncompressBuffer(byte[]) + ZlibStream.UncompressBuffer(byte[]) + + + A buffer containing data that has been compressed with DEFLATE. + + + The data in uncompressed form + + + + This property sets the flush behavior on the stream. + + See the ZLIB documentation for the meaning of the flush behavior. + + + + + The size of the working buffer for the compression codec. + + + + + The working buffer is used for all stream operations. The default size is + 1024 bytes. The minimum size is 128 bytes. You may get better performance + with a larger buffer. Then again, you might not. You would have to test + it. + + + + Set this before the first call to Read() or Write() on the + stream. If you try to set it afterwards, it will throw. + + + + + + The ZLIB strategy to be used during compression. + + + + By tweaking this parameter, you may be able to optimize the compression for + data with particular characteristics. + + + + Returns the total number of bytes input so far. + + + Returns the total number of bytes output so far. + + + + Indicates whether the stream can be read. + + + The return value depends on whether the captive stream supports reading. + + + + + Indicates whether the stream supports Seek operations. + + + Always returns false. + + + + + Indicates whether the stream can be written. + + + The return value depends on whether the captive stream supports writing. + + + + + Reading this property always throws a . + + + + + The position of the stream pointer. + + + + Setting this property always throws a . Reading will return the total bytes + written out, if used in writing, or the total bytes read in, if used in + reading. The count may refer to compressed bytes or uncompressed bytes, + depending on how you've used the stream. + + + + + A class for compressing and decompressing GZIP streams. + + + + + The GZipStream is a Decorator on a + . It adds GZIP compression or decompression to any + stream. + + + + Like the System.IO.Compression.GZipStream in the .NET Base Class Library, the + Ionic.Zlib.GZipStream can compress while writing, or decompress while + reading, but not vice versa. The compression method used is GZIP, which is + documented in IETF RFC + 1952, "GZIP file format specification version 4.3". + + + A GZipStream can be used to decompress data (through Read()) or + to compress data (through Write()), but not both. + + + + If you wish to use the GZipStream to compress data, you must wrap it + around a write-able stream. As you call Write() on the GZipStream, the + data will be compressed into the GZIP format. If you want to decompress data, + you must wrap the GZipStream around a readable stream that contains an + IETF RFC 1952-compliant stream. The data will be decompressed as you call + Read() on the GZipStream. + + + + Though the GZIP format allows data from multiple files to be concatenated + together, this stream handles only a single segment of GZIP format, typically + representing a single file. + + + + This class is similar to and . + ZlibStream handles RFC1950-compliant streams. + handles RFC1951-compliant streams. This class handles RFC1952-compliant streams. + + + + + + + + + + The last modified time for the GZIP stream. + + + + GZIP allows the storage of a last modified time with each GZIP entry. + When compressing data, you can set this before the first call to + Write(). When decompressing, you can retrieve this value any time + after the first call to Read(). + + + + + Create a GZipStream using the specified CompressionMode. + + + + + When mode is CompressionMode.Compress, the GZipStream will use the + default compression level. + + + + As noted in the class documentation, the CompressionMode (Compress + or Decompress) also establishes the "direction" of the stream. A + GZipStream with CompressionMode.Compress works only through + Write(). A GZipStream with + CompressionMode.Decompress works only through Read(). + + + + + + This example shows how to use a GZipStream to compress data. + + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (var raw = System.IO.File.Create(outputFile)) + { + using (Stream compressor = new GZipStream(raw, CompressionMode.Compress)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n; + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + Dim outputFile As String = (fileToCompress & ".compressed") + Using input As Stream = File.OpenRead(fileToCompress) + Using raw As FileStream = File.Create(outputFile) + Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + End Using + + + + + This example shows how to use a GZipStream to uncompress a file. + + private void GunZipFile(string filename) + { + if (!filename.EndsWith(".gz)) + throw new ArgumentException("filename"); + var DecompressedFile = filename.Substring(0,filename.Length-3); + byte[] working = new byte[WORKING_BUFFER_SIZE]; + int n= 1; + using (System.IO.Stream input = System.IO.File.OpenRead(filename)) + { + using (Stream decompressor= new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, true)) + { + using (var output = System.IO.File.Create(DecompressedFile)) + { + while (n !=0) + { + n= decompressor.Read(working, 0, working.Length); + if (n > 0) + { + output.Write(working, 0, n); + } + } + } + } + } + } + + + + Private Sub GunZipFile(ByVal filename as String) + If Not (filename.EndsWith(".gz)) Then + Throw New ArgumentException("filename") + End If + Dim DecompressedFile as String = filename.Substring(0,filename.Length-3) + Dim working(WORKING_BUFFER_SIZE) as Byte + Dim n As Integer = 1 + Using input As Stream = File.OpenRead(filename) + Using decompressor As Stream = new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, True) + Using output As Stream = File.Create(UncompressedFile) + Do + n= decompressor.Read(working, 0, working.Length) + If n > 0 Then + output.Write(working, 0, n) + End IF + Loop While (n > 0) + End Using + End Using + End Using + End Sub + + + + The stream which will be read or written. + Indicates whether the GZipStream will compress or decompress. + + + + Create a GZipStream using the specified CompressionMode and + the specified CompressionLevel. + + + + + The CompressionMode (Compress or Decompress) also establishes the + "direction" of the stream. A GZipStream with + CompressionMode.Compress works only through Write(). A + GZipStream with CompressionMode.Decompress works only + through Read(). + + + + + + + This example shows how to use a GZipStream to compress a file into a .gz file. + + + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (var raw = System.IO.File.Create(fileToCompress + ".gz")) + { + using (Stream compressor = new GZipStream(raw, + CompressionMode.Compress, + CompressionLevel.BestCompression)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n; + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + + Using input As Stream = File.OpenRead(fileToCompress) + Using raw As FileStream = File.Create(fileToCompress & ".gz") + Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + End Using + + + The stream to be read or written while deflating or inflating. + Indicates whether the GZipStream will compress or decompress. + A tuning knob to trade speed for effectiveness. + + + + Create a GZipStream using the specified CompressionMode, and + explicitly specify whether the stream should be left open after Deflation + or Inflation. + + + + + This constructor allows the application to request that the captive stream + remain open after the deflation or inflation occurs. By default, after + Close() is called on the stream, the captive stream is also + closed. In some cases this is not desired, for example if the stream is a + memory stream that will be re-read after compressed data has been written + to it. Specify true for the parameter to leave + the stream open. + + + + The (Compress or Decompress) also + establishes the "direction" of the stream. A GZipStream with + CompressionMode.Compress works only through Write(). A GZipStream + with CompressionMode.Decompress works only through Read(). + + + + The GZipStream will use the default compression level. If you want + to specify the compression level, see . + + + + See the other overloads of this constructor for example code. + + + + + + The stream which will be read or written. This is called the "captive" + stream in other places in this documentation. + + + Indicates whether the GZipStream will compress or decompress. + + + + true if the application would like the base stream to remain open after + inflation/deflation. + + + + + Create a GZipStream using the specified CompressionMode and the + specified CompressionLevel, and explicitly specify whether the + stream should be left open after Deflation or Inflation. + + + + + + This constructor allows the application to request that the captive stream + remain open after the deflation or inflation occurs. By default, after + Close() is called on the stream, the captive stream is also + closed. In some cases this is not desired, for example if the stream is a + memory stream that will be re-read after compressed data has been written + to it. Specify true for the parameter to + leave the stream open. + + + + As noted in the class documentation, the CompressionMode (Compress + or Decompress) also establishes the "direction" of the stream. A + GZipStream with CompressionMode.Compress works only through + Write(). A GZipStream with CompressionMode.Decompress works only + through Read(). + + + + + + This example shows how to use a GZipStream to compress data. + + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (var raw = System.IO.File.Create(outputFile)) + { + using (Stream compressor = new GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression, true)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n; + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + Dim outputFile As String = (fileToCompress & ".compressed") + Using input As Stream = File.OpenRead(fileToCompress) + Using raw As FileStream = File.Create(outputFile) + Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression, True) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + End Using + + + The stream which will be read or written. + Indicates whether the GZipStream will compress or decompress. + true if the application would like the stream to remain open after inflation/deflation. + A tuning knob to trade speed for effectiveness. + + + + Dispose the stream. + + + + This may or may not result in a Close() call on the captive + stream. See the constructors that have a leaveOpen parameter + for more information. + + + This method may be invoked in two distinct scenarios. If disposing + == true, the method has been called directly or indirectly by a + user's code, for example via the public Dispose() method. In this + case, both managed and unmanaged resources can be referenced and + disposed. If disposing == false, the method has been called by the + runtime from inside the object finalizer and this method should not + reference other objects; in that case only unmanaged resources must + be referenced or disposed. + + + + indicates whether the Dispose method was invoked by user code. + + + + + Flush the stream. + + + + + Read and decompress data from the source stream. + + + + With a GZipStream, decompression is done through reading. + + + + + byte[] working = new byte[WORKING_BUFFER_SIZE]; + using (System.IO.Stream input = System.IO.File.OpenRead(_CompressedFile)) + { + using (Stream decompressor= new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, true)) + { + using (var output = System.IO.File.Create(_DecompressedFile)) + { + int n; + while ((n= decompressor.Read(working, 0, working.Length)) !=0) + { + output.Write(working, 0, n); + } + } + } + } + + + The buffer into which the decompressed data should be placed. + the offset within that data array to put the first byte read. + the number of bytes to read. + the number of bytes actually read + + + + Calling this method always throws a . + + irrelevant; it will always throw! + irrelevant; it will always throw! + irrelevant! + + + + Calling this method always throws a . + + irrelevant; this method will always throw! + + + + Write data to the stream. + + + + + If you wish to use the GZipStream to compress data while writing, + you can create a GZipStream with CompressionMode.Compress, and a + writable output stream. Then call Write() on that GZipStream, + providing uncompressed data as input. The data sent to the output stream + will be the compressed form of the data written. + + + + A GZipStream can be used for Read() or Write(), but not + both. Writing implies compression. Reading implies decompression. + + + + The buffer holding data to write to the stream. + the offset within that data array to find the first byte to write. + the number of bytes to write. + + + + Compress a string into a byte array using GZip. + + + + Uncompress it with . + + + + + + + A string to compress. The string will first be encoded + using UTF8, then compressed. + + + The string in compressed form + + + + Compress a byte array into a new byte array using GZip. + + + + Uncompress it with . + + + + + + + A buffer to compress. + + + The data in compressed form + + + + Uncompress a GZip'ed byte array into a single string. + + + + + + + A buffer containing GZIP-compressed data. + + + The uncompressed string + + + + Uncompress a GZip'ed byte array into a byte array. + + + + + + + A buffer containing data that has been compressed with GZip. + + + The data in uncompressed form + + + + The comment on the GZIP stream. + + + + + The GZIP format allows for each file to optionally have an associated + comment stored with the file. The comment is encoded with the ISO-8859-1 + code page. To include a comment in a GZIP stream you create, set this + property before calling Write() for the first time on the + GZipStream. + + + + When using GZipStream to decompress, you can retrieve this property + after the first call to Read(). If no comment has been set in the + GZIP bytestream, the Comment property will return null + (Nothing in VB). + + + + + + The FileName for the GZIP stream. + + + + + + The GZIP format optionally allows each file to have an associated + filename. When compressing data (through Write()), set this + FileName before calling Write() the first time on the GZipStream. + The actual filename is encoded into the GZIP bytestream with the + ISO-8859-1 code page, according to RFC 1952. It is the application's + responsibility to insure that the FileName can be encoded and decoded + correctly with this code page. + + + + When decompressing (through Read()), you can retrieve this value + any time after the first Read(). In the case where there was no filename + encoded into the GZIP bytestream, the property will return null (Nothing + in VB). + + + + + + The CRC on the GZIP stream. + + + This is used for internal error checking. You probably don't need to look at this property. + + + + + This property sets the flush behavior on the stream. + + + + + The size of the working buffer for the compression codec. + + + + + The working buffer is used for all stream operations. The default size is + 1024 bytes. The minimum size is 128 bytes. You may get better performance + with a larger buffer. Then again, you might not. You would have to test + it. + + + + Set this before the first call to Read() or Write() on the + stream. If you try to set it afterwards, it will throw. + + + + + Returns the total number of bytes input so far. + + + Returns the total number of bytes output so far. + + + + Indicates whether the stream can be read. + + + The return value depends on whether the captive stream supports reading. + + + + + Indicates whether the stream supports Seek operations. + + + Always returns false. + + + + + Indicates whether the stream can be written. + + + The return value depends on whether the captive stream supports writing. + + + + + Reading this property always throws a . + + + + + The position of the stream pointer. + + + + Setting this property always throws a . Reading will return the total bytes + written out, if used in writing, or the total bytes read in, if used in + reading. The count may refer to compressed bytes or uncompressed bytes, + depending on how you've used the stream. + + + + + A class for compressing streams using the + Deflate algorithm with multiple threads. + + + + + This class performs DEFLATE compression through writing. For + more information on the Deflate algorithm, see IETF RFC 1951, + "DEFLATE Compressed Data Format Specification version 1.3." + + + + This class is similar to , except + that this class is for compression only, and this implementation uses an + approach that employs multiple worker threads to perform the DEFLATE. On + a multi-cpu or multi-core computer, the performance of this class can be + significantly higher than the single-threaded DeflateStream, particularly + for larger streams. How large? Anything over 10mb is a good candidate + for parallel compression. + + + + The tradeoff is that this class uses more memory and more CPU than the + vanilla DeflateStream, and also is less efficient as a compressor. For + large files the size of the compressed data stream can be less than 1% + larger than the size of a compressed data stream from the vanialla + DeflateStream. For smaller files the difference can be larger. The + difference will also be larger if you set the BufferSize to be lower than + the default value. Your mileage may vary. Finally, for small files, the + ParallelDeflateOutputStream can be much slower than the vanilla + DeflateStream, because of the overhead associated to using the thread + pool. + + + + + + + + Create a ParallelDeflateOutputStream. + + + + + This stream compresses data written into it via the DEFLATE + algorithm (see RFC 1951), and writes out the compressed byte stream. + + + + The instance will use the default compression level, the default + buffer sizes and the default number of threads and buffers per + thread. + + + + This class is similar to , + except that this implementation uses an approach that employs + multiple worker threads to perform the DEFLATE. On a multi-cpu or + multi-core computer, the performance of this class can be + significantly higher than the single-threaded DeflateStream, + particularly for larger streams. How large? Anything over 10mb is + a good candidate for parallel compression. + + + + + + + This example shows how to use a ParallelDeflateOutputStream to compress + data. It reads a file, compresses it, and writes the compressed data to + a second, output file. + + + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n= -1; + String outputFile = fileToCompress + ".compressed"; + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (var raw = System.IO.File.Create(outputFile)) + { + using (Stream compressor = new ParallelDeflateOutputStream(raw)) + { + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Dim outputFile As String = (fileToCompress & ".compressed") + Using input As Stream = File.OpenRead(fileToCompress) + Using raw As FileStream = File.Create(outputFile) + Using compressor As Stream = New ParallelDeflateOutputStream(raw) + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + End Using + + + The stream to which compressed data will be written. + + + + Create a ParallelDeflateOutputStream using the specified CompressionLevel. + + + See the + constructor for example code. + + The stream to which compressed data will be written. + A tuning knob to trade speed for effectiveness. + + + + Create a ParallelDeflateOutputStream and specify whether to leave the captive stream open + when the ParallelDeflateOutputStream is closed. + + + See the + constructor for example code. + + The stream to which compressed data will be written. + + true if the application would like the stream to remain open after inflation/deflation. + + + + + Create a ParallelDeflateOutputStream and specify whether to leave the captive stream open + when the ParallelDeflateOutputStream is closed. + + + See the + constructor for example code. + + The stream to which compressed data will be written. + A tuning knob to trade speed for effectiveness. + + true if the application would like the stream to remain open after inflation/deflation. + + + + + Create a ParallelDeflateOutputStream using the specified + CompressionLevel and CompressionStrategy, and specifying whether to + leave the captive stream open when the ParallelDeflateOutputStream is + closed. + + + See the + constructor for example code. + + The stream to which compressed data will be written. + A tuning knob to trade speed for effectiveness. + + By tweaking this parameter, you may be able to optimize the compression for + data with particular characteristics. + + + true if the application would like the stream to remain open after inflation/deflation. + + + + + Write data to the stream. + + + + + + To use the ParallelDeflateOutputStream to compress data, create a + ParallelDeflateOutputStream with CompressionMode.Compress, passing a + writable output stream. Then call Write() on that + ParallelDeflateOutputStream, providing uncompressed data as input. The + data sent to the output stream will be the compressed form of the data + written. + + + + To decompress data, use the class. + + + + The buffer holding data to write to the stream. + the offset within that data array to find the first byte to write. + the number of bytes to write. + + + + Flush the stream. + + + + + Close the stream. + + + You must call Close on the stream to guarantee that all of the data written in has + been compressed, and the compressed data has been written out. + + + + Dispose the object + + + Because ParallelDeflateOutputStream is IDisposable, the + application must call this method when finished using the instance. + + + This method is generally called implicitly upon exit from + a using scope in C# (Using in VB). + + + + + The Dispose method + + indicates whether the Dispose method was invoked by user code. + + + + + Resets the stream for use with another stream. + + + Because the ParallelDeflateOutputStream is expensive to create, it + has been designed so that it can be recycled and re-used. You have + to call Close() on the stream first, then you can call Reset() on + it, to use it again on another stream. + + + + The new output stream for this era. + + + + + ParallelDeflateOutputStream deflater = null; + foreach (var inputFile in listOfFiles) + { + string outputFile = inputFile + ".compressed"; + using (System.IO.Stream input = System.IO.File.OpenRead(inputFile)) + { + using (var outStream = System.IO.File.Create(outputFile)) + { + if (deflater == null) + deflater = new ParallelDeflateOutputStream(outStream, + CompressionLevel.Best, + CompressionStrategy.Default, + true); + deflater.Reset(outStream); + + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + deflater.Write(buffer, 0, n); + } + } + } + } + + + + + + This method always throws a NotSupportedException. + + + The buffer into which data would be read, IF THIS METHOD + ACTUALLY DID ANYTHING. + + + The offset within that data array at which to insert the + data that is read, IF THIS METHOD ACTUALLY DID + ANYTHING. + + + The number of bytes to write, IF THIS METHOD ACTUALLY DID + ANYTHING. + + nothing. + + + + This method always throws a NotSupportedException. + + + The offset to seek to.... + IF THIS METHOD ACTUALLY DID ANYTHING. + + + The reference specifying how to apply the offset.... IF + THIS METHOD ACTUALLY DID ANYTHING. + + nothing. It always throws. + + + + This method always throws a NotSupportedException. + + + The new value for the stream length.... IF + THIS METHOD ACTUALLY DID ANYTHING. + + + + + The ZLIB strategy to be used during compression. + + + + + + The maximum number of buffer pairs to use. + + + + + This property sets an upper limit on the number of memory buffer + pairs to create. The implementation of this stream allocates + multiple buffers to facilitate parallel compression. As each buffer + fills up, this stream uses + ThreadPool.QueueUserWorkItem() + to compress those buffers in a background threadpool thread. After a + buffer is compressed, it is re-ordered and written to the output + stream. + + + + A higher number of buffer pairs enables a higher degree of + parallelism, which tends to increase the speed of compression on + multi-cpu computers. On the other hand, a higher number of buffer + pairs also implies a larger memory consumption, more active worker + threads, and a higher cpu utilization for any compression. This + property enables the application to limit its memory consumption and + CPU utilization behavior depending on requirements. + + + + For each compression "task" that occurs in parallel, there are 2 + buffers allocated: one for input and one for output. This property + sets a limit for the number of pairs. The total amount of storage + space allocated for buffering will then be (N*S*2), where N is the + number of buffer pairs, S is the size of each buffer (). By default, DotNetZip allocates 4 buffer + pairs per CPU core, so if your machine has 4 cores, and you retain + the default buffer size of 128k, then the + ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer + memory in total, or 4mb, in blocks of 128kb. If you then set this + property to 8, then the number will be 8 * 2 * 128kb of buffer + memory, or 2mb. + + + + CPU utilization will also go up with additional buffers, because a + larger number of buffer pairs allows a larger number of background + threads to compress in parallel. If you find that parallel + compression is consuming too much memory or CPU, you can adjust this + value downward. + + + + The default value is 16. Different values may deliver better or + worse results, depending on your priorities and the dynamic + performance characteristics of your storage and compute resources. + + + + This property is not the number of buffer pairs to use; it is an + upper limit. An illustration: Suppose you have an application that + uses the default value of this property (which is 16), and it runs + on a machine with 2 CPU cores. In that case, DotNetZip will allocate + 4 buffer pairs per CPU core, for a total of 8 pairs. The upper + limit specified by this property has no effect. + + + + The application can set this value at any time, but it is effective + only before the first call to Write(), which is when the buffers are + allocated. + + + + + + The size of the buffers used by the compressor threads. + + + + + The default buffer size is 128k. The application can set this value + at any time, but it is effective only before the first Write(). + + + + Larger buffer sizes implies larger memory consumption but allows + more efficient compression. Using smaller buffer sizes consumes less + memory but may result in less effective compression. For example, + using the default buffer size of 128k, the compression delivered is + within 1% of the compression delivered by the single-threaded . On the other hand, using a + BufferSize of 8k can result in a compressed data stream that is 5% + larger than that delivered by the single-threaded + DeflateStream. Excessively small buffer sizes can also cause + the speed of the ParallelDeflateOutputStream to drop, because of + larger thread scheduling overhead dealing with many many small + buffers. + + + + The total amount of storage space allocated for buffering will be + (N*S*2), where N is the number of buffer pairs, and S is the size of + each buffer (this property). There are 2 buffers used by the + compressor, one for input and one for output. By default, DotNetZip + allocates 4 buffer pairs per CPU core, so if your machine has 4 + cores, then the number of buffer pairs used will be 16. If you + accept the default value of this property, 128k, then the + ParallelDeflateOutputStream will use 16 * 2 * 128kb of buffer memory + in total, or 4mb, in blocks of 128kb. If you set this property to + 64kb, then the number will be 16 * 2 * 64kb of buffer memory, or + 2mb. + + + + + + + The CRC32 for the data that was written out, prior to compression. + + + This value is meaningful only after a call to Close(). + + + + + The total number of uncompressed bytes processed by the ParallelDeflateOutputStream. + + + This value is meaningful only after a call to Close(). + + + + + Indicates whether the stream supports Seek operations. + + + Always returns false. + + + + + Indicates whether the stream supports Read operations. + + + Always returns false. + + + + + Indicates whether the stream supports Write operations. + + + Returns true if the provided stream is writable. + + + + + Reading this property always throws a NotSupportedException. + + + + + Returns the current position of the output stream. + + + + Because the output gets written by a background thread, + the value may change asynchronously. Setting this + property always throws a NotSupportedException. + + + + + + Map from a distance to a distance code. + + + No side effects. _dist_code[256] and _dist_code[257] are never used. + + + + + Describes how to flush the current deflate operation. + + + The different FlushType values are useful when using a Deflate in a streaming application. + + + + No flush at all. + + + Closes the current block, but doesn't flush it to + the output. Used internally only in hypothetical + scenarios. This was supposed to be removed by Zlib, but it is + still in use in some edge cases. + + + + + Use this during compression to specify that all pending output should be + flushed to the output buffer and the output should be aligned on a byte + boundary. You might use this in a streaming communication scenario, so that + the decompressor can get all input data available so far. When using this + with a ZlibCodec, AvailableBytesIn will be zero after the call if + enough output space has been provided before the call. Flushing will + degrade compression and so it should be used only when necessary. + + + + + Use this during compression to specify that all output should be flushed, as + with FlushType.Sync, but also, the compression state should be reset + so that decompression can restart from this point if previous compressed + data has been damaged or if random access is desired. Using + FlushType.Full too often can significantly degrade the compression. + + + + Signals the end of the compression/decompression stream. + + + + The compression level to be used when using a DeflateStream or ZlibStream with CompressionMode.Compress. + + + + + None means that the data will be simply stored, with no change at all. + If you are producing ZIPs for use on Mac OSX, be aware that archives produced with CompressionLevel.None + cannot be opened with the default zip reader. Use a different CompressionLevel. + + + + + Same as None. + + + + + The fastest but least effective compression. + + + + + A synonym for BestSpeed. + + + + + A little slower, but better, than level 1. + + + + + A little slower, but better, than level 2. + + + + + A little slower, but better, than level 3. + + + + + A little slower than level 4, but with better compression. + + + + + The default compression level, with a good balance of speed and compression efficiency. + + + + + A synonym for Default. + + + + + Pretty good compression! + + + + + Better compression than Level7! + + + + + The "best" compression, where best means greatest reduction in size of the input data stream. + This is also the slowest compression. + + + + + A synonym for BestCompression. + + + + + Describes options for how the compression algorithm is executed. Different strategies + work better on different sorts of data. The strategy parameter can affect the compression + ratio and the speed of compression but not the correctness of the compresssion. + + + + + The default strategy is probably the best for normal data. + + + + + The Filtered strategy is intended to be used most effectively with data produced by a + filter or predictor. By this definition, filtered data consists mostly of small + values with a somewhat random distribution. In this case, the compression algorithm + is tuned to compress them better. The effect of Filtered is to force more Huffman + coding and less string matching; it is a half-step between Default and HuffmanOnly. + + + + + Using HuffmanOnly will force the compressor to do Huffman encoding only, with no + string matching. + + + + + An enum to specify the direction of transcoding - whether to compress or decompress. + + + + + Used to specify that the stream should compress the data. + + + + + Used to specify that the stream should decompress the data. + + + + + A general purpose exception class for exceptions in the Zlib library. + + + + + The ZlibException class captures exception information generated + by the Zlib library. + + + + + This ctor collects a message attached to the exception. + + the message for the exception. + + + + Performs an unsigned bitwise right shift with the specified number + + Number to operate on + Ammount of bits to shift + The resulting number from the shift operation + + + + Reads a number of characters from the current source TextReader and writes + the data to the target array at the specified index. + + + The source TextReader to read from + Contains the array of characteres read from the source TextReader. + The starting index of the target array. + The maximum number of characters to read from the source TextReader. + + + The number of characters read. The number will be less than or equal to + count depending on the data available in the source TextReader. Returns -1 + if the end of the stream is reached. + + + + + Computes an Adler-32 checksum. + + + The Adler checksum is similar to a CRC checksum, but faster to compute, though less + reliable. It is used in producing RFC1950 compressed streams. The Adler checksum + is a required part of the "ZLIB" standard. Applications will almost never need to + use this class directly. + + + + + + + Calculates the Adler32 checksum. + + + + This is used within ZLIB. You probably don't need to use this directly. + + + + To compute an Adler32 checksum on a byte array: + + var adler = Adler.Adler32(0, null, 0, 0); + adler = Adler.Adler32(adler, buffer, index, length); + + + + + + Encoder and Decoder for ZLIB and DEFLATE (IETF RFC1950 and RFC1951). + + + + This class compresses and decompresses data according to the Deflate algorithm + and optionally, the ZLIB format, as documented in RFC 1950 - ZLIB and RFC 1951 - DEFLATE. + + + + + The buffer from which data is taken. + + + + + An index into the InputBuffer array, indicating where to start reading. + + + + + The number of bytes available in the InputBuffer, starting at NextIn. + + + Generally you should set this to InputBuffer.Length before the first Inflate() or Deflate() call. + The class will update this number as calls to Inflate/Deflate are made. + + + + + Total number of bytes read so far, through all calls to Inflate()/Deflate(). + + + + + Buffer to store output data. + + + + + An index into the OutputBuffer array, indicating where to start writing. + + + + + The number of bytes available in the OutputBuffer, starting at NextOut. + + + Generally you should set this to OutputBuffer.Length before the first Inflate() or Deflate() call. + The class will update this number as calls to Inflate/Deflate are made. + + + + + Total number of bytes written to the output so far, through all calls to Inflate()/Deflate(). + + + + + used for diagnostics, when something goes wrong! + + + + + The compression level to use in this codec. Useful only in compression mode. + + + + + The number of Window Bits to use. + + + This gauges the size of the sliding window, and hence the + compression effectiveness as well as memory consumption. It's best to just leave this + setting alone if you don't know what it is. The maximum value is 15 bits, which implies + a 32k window. + + + + + The compression strategy to use. + + + This is only effective in compression. The theory offered by ZLIB is that different + strategies could potentially produce significant differences in compression behavior + for different data sets. Unfortunately I don't have any good recommendations for how + to set it differently. When I tested changing the strategy I got minimally different + compression performance. It's best to leave this property alone if you don't have a + good feel for it. Or, you may want to produce a test harness that runs through the + different strategy options and evaluates them on different file types. If you do that, + let me know your results. + + + + + Create a ZlibCodec. + + + If you use this default constructor, you will later have to explicitly call + InitializeInflate() or InitializeDeflate() before using the ZlibCodec to compress + or decompress. + + + + + Create a ZlibCodec that either compresses or decompresses. + + + Indicates whether the codec should compress (deflate) or decompress (inflate). + + + + + Initialize the inflation state. + + + It is not necessary to call this before using the ZlibCodec to inflate data; + It is implicitly called when you call the constructor. + + Z_OK if everything goes well. + + + + Initialize the inflation state with an explicit flag to + govern the handling of RFC1950 header bytes. + + + + By default, the ZLIB header defined in RFC 1950 is expected. If + you want to read a zlib stream you should specify true for + expectRfc1950Header. If you have a deflate stream, you will want to specify + false. It is only necessary to invoke this initializer explicitly if you + want to specify false. + + + whether to expect an RFC1950 header byte + pair when reading the stream of data to be inflated. + + Z_OK if everything goes well. + + + + Initialize the ZlibCodec for inflation, with the specified number of window bits. + + The number of window bits to use. If you need to ask what that is, + then you shouldn't be calling this initializer. + Z_OK if all goes well. + + + + Initialize the inflation state with an explicit flag to govern the handling of + RFC1950 header bytes. + + + + If you want to read a zlib stream you should specify true for + expectRfc1950Header. In this case, the library will expect to find a ZLIB + header, as defined in RFC + 1950, in the compressed stream. If you will be reading a DEFLATE or + GZIP stream, which does not have such a header, you will want to specify + false. + + + whether to expect an RFC1950 header byte pair when reading + the stream of data to be inflated. + The number of window bits to use. If you need to ask what that is, + then you shouldn't be calling this initializer. + Z_OK if everything goes well. + + + + Inflate the data in the InputBuffer, placing the result in the OutputBuffer. + + + You must have set InputBuffer and OutputBuffer, NextIn and NextOut, and AvailableBytesIn and + AvailableBytesOut before calling this method. + + + + private void InflateBuffer() + { + int bufferSize = 1024; + byte[] buffer = new byte[bufferSize]; + ZlibCodec decompressor = new ZlibCodec(); + + Console.WriteLine("\n============================================"); + Console.WriteLine("Size of Buffer to Inflate: {0} bytes.", CompressedBytes.Length); + MemoryStream ms = new MemoryStream(DecompressedBytes); + + int rc = decompressor.InitializeInflate(); + + decompressor.InputBuffer = CompressedBytes; + decompressor.NextIn = 0; + decompressor.AvailableBytesIn = CompressedBytes.Length; + + decompressor.OutputBuffer = buffer; + + // pass 1: inflate + do + { + decompressor.NextOut = 0; + decompressor.AvailableBytesOut = buffer.Length; + rc = decompressor.Inflate(FlushType.None); + + if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) + throw new Exception("inflating: " + decompressor.Message); + + ms.Write(decompressor.OutputBuffer, 0, buffer.Length - decompressor.AvailableBytesOut); + } + while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); + + // pass 2: finish and flush + do + { + decompressor.NextOut = 0; + decompressor.AvailableBytesOut = buffer.Length; + rc = decompressor.Inflate(FlushType.Finish); + + if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) + throw new Exception("inflating: " + decompressor.Message); + + if (buffer.Length - decompressor.AvailableBytesOut > 0) + ms.Write(buffer, 0, buffer.Length - decompressor.AvailableBytesOut); + } + while (decompressor.AvailableBytesIn > 0 || decompressor.AvailableBytesOut == 0); + + decompressor.EndInflate(); + } + + + + The flush to use when inflating. + Z_OK if everything goes well. + + + + Ends an inflation session. + + + Call this after successively calling Inflate(). This will cause all buffers to be flushed. + After calling this you cannot call Inflate() without a intervening call to one of the + InitializeInflate() overloads. + + Z_OK if everything goes well. + + + + I don't know what this does! + + Z_OK if everything goes well. + + + + Initialize the ZlibCodec for deflation operation. + + + The codec will use the MAX window bits and the default level of compression. + + + + int bufferSize = 40000; + byte[] CompressedBytes = new byte[bufferSize]; + byte[] DecompressedBytes = new byte[bufferSize]; + + ZlibCodec compressor = new ZlibCodec(); + + compressor.InitializeDeflate(CompressionLevel.Default); + + compressor.InputBuffer = System.Text.ASCIIEncoding.ASCII.GetBytes(TextToCompress); + compressor.NextIn = 0; + compressor.AvailableBytesIn = compressor.InputBuffer.Length; + + compressor.OutputBuffer = CompressedBytes; + compressor.NextOut = 0; + compressor.AvailableBytesOut = CompressedBytes.Length; + + while (compressor.TotalBytesIn != TextToCompress.Length && compressor.TotalBytesOut < bufferSize) + { + compressor.Deflate(FlushType.None); + } + + while (true) + { + int rc= compressor.Deflate(FlushType.Finish); + if (rc == ZlibConstants.Z_STREAM_END) break; + } + + compressor.EndDeflate(); + + + + Z_OK if all goes well. You generally don't need to check the return code. + + + + Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel. + + + The codec will use the maximum window bits (15) and the specified + CompressionLevel. It will emit a ZLIB stream as it compresses. + + The compression level for the codec. + Z_OK if all goes well. + + + + Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, + and the explicit flag governing whether to emit an RFC1950 header byte pair. + + + The codec will use the maximum window bits (15) and the specified CompressionLevel. + If you want to generate a zlib stream, you should specify true for + wantRfc1950Header. In this case, the library will emit a ZLIB + header, as defined in RFC + 1950, in the compressed stream. + + The compression level for the codec. + whether to emit an initial RFC1950 byte pair in the compressed stream. + Z_OK if all goes well. + + + + Initialize the ZlibCodec for deflation operation, using the specified CompressionLevel, + and the specified number of window bits. + + + The codec will use the specified number of window bits and the specified CompressionLevel. + + The compression level for the codec. + the number of window bits to use. If you don't know what this means, don't use this method. + Z_OK if all goes well. + + + + Initialize the ZlibCodec for deflation operation, using the specified + CompressionLevel, the specified number of window bits, and the explicit flag + governing whether to emit an RFC1950 header byte pair. + + + The compression level for the codec. + whether to emit an initial RFC1950 byte pair in the compressed stream. + the number of window bits to use. If you don't know what this means, don't use this method. + Z_OK if all goes well. + + + + Deflate one batch of data. + + + You must have set InputBuffer and OutputBuffer before calling this method. + + + + private void DeflateBuffer(CompressionLevel level) + { + int bufferSize = 1024; + byte[] buffer = new byte[bufferSize]; + ZlibCodec compressor = new ZlibCodec(); + + Console.WriteLine("\n============================================"); + Console.WriteLine("Size of Buffer to Deflate: {0} bytes.", UncompressedBytes.Length); + MemoryStream ms = new MemoryStream(); + + int rc = compressor.InitializeDeflate(level); + + compressor.InputBuffer = UncompressedBytes; + compressor.NextIn = 0; + compressor.AvailableBytesIn = UncompressedBytes.Length; + + compressor.OutputBuffer = buffer; + + // pass 1: deflate + do + { + compressor.NextOut = 0; + compressor.AvailableBytesOut = buffer.Length; + rc = compressor.Deflate(FlushType.None); + + if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END) + throw new Exception("deflating: " + compressor.Message); + + ms.Write(compressor.OutputBuffer, 0, buffer.Length - compressor.AvailableBytesOut); + } + while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); + + // pass 2: finish and flush + do + { + compressor.NextOut = 0; + compressor.AvailableBytesOut = buffer.Length; + rc = compressor.Deflate(FlushType.Finish); + + if (rc != ZlibConstants.Z_STREAM_END && rc != ZlibConstants.Z_OK) + throw new Exception("deflating: " + compressor.Message); + + if (buffer.Length - compressor.AvailableBytesOut > 0) + ms.Write(buffer, 0, buffer.Length - compressor.AvailableBytesOut); + } + while (compressor.AvailableBytesIn > 0 || compressor.AvailableBytesOut == 0); + + compressor.EndDeflate(); + + ms.Seek(0, SeekOrigin.Begin); + CompressedBytes = new byte[compressor.TotalBytesOut]; + ms.Read(CompressedBytes, 0, CompressedBytes.Length); + } + + + whether to flush all data as you deflate. Generally you will want to + use Z_NO_FLUSH here, in a series of calls to Deflate(), and then call EndDeflate() to + flush everything. + + Z_OK if all goes well. + + + + End a deflation session. + + + Call this after making a series of one or more calls to Deflate(). All buffers are flushed. + + Z_OK if all goes well. + + + + Reset a codec for another deflation session. + + + Call this to reset the deflation state. For example if a thread is deflating + non-consecutive blocks, you can call Reset() after the Deflate(Sync) of the first + block and before the next Deflate(None) of the second block. + + Z_OK if all goes well. + + + + Set the CompressionStrategy and CompressionLevel for a deflation session. + + the level of compression to use. + the strategy to use for compression. + Z_OK if all goes well. + + + + Set the dictionary to be used for either Inflation or Deflation. + + The dictionary bytes to use. + Z_OK if all goes well. + + + + The Adler32 checksum on the data transferred through the codec so far. You probably don't need to look at this. + + + + + A bunch of constants used in the Zlib interface. + + + + + The maximum number of window bits for the Deflate algorithm. + + + + + The default number of window bits for the Deflate algorithm. + + + + + indicates everything is A-OK + + + + + Indicates that the last operation reached the end of the stream. + + + + + The operation ended in need of a dictionary. + + + + + There was an error with the stream - not enough data, not open and readable, etc. + + + + + There was an error with the data - not enough data, bad data, etc. + + + + + There was an error with the working buffer. + + + + + The size of the working buffer used in the ZlibCodec class. Defaults to 8192 bytes. + + + + + The minimum size of the working buffer used in the ZlibCodec class. Currently it is 128 bytes. + + + + + Represents a Zlib stream for compression or decompression. + + + + + The ZlibStream is a Decorator on a . It adds ZLIB compression or decompression to any + stream. + + + Using this stream, applications can compress or decompress data via + stream Read() and Write() operations. Either compresssion or + decompression can occur through either reading or writing. The compression + format used is ZLIB, which is documented in IETF RFC 1950, "ZLIB Compressed + Data Format Specification version 3.3". This implementation of ZLIB always uses + DEFLATE as the compression method. (see IETF RFC 1951, "DEFLATE + Compressed Data Format Specification version 1.3.") + + + The ZLIB format allows for varying compression methods, window sizes, and dictionaries. + This implementation always uses the DEFLATE compression method, a preset dictionary, + and 15 window bits by default. + + + + This class is similar to , except that it adds the + RFC1950 header and trailer bytes to a compressed stream when compressing, or expects + the RFC1950 header and trailer bytes when decompressing. It is also similar to the + . + + + + + + + + Create a ZlibStream using the specified CompressionMode. + + + + + When mode is CompressionMode.Compress, the ZlibStream + will use the default compression level. The "captive" stream will be + closed when the ZlibStream is closed. + + + + + + This example uses a ZlibStream to compress a file, and writes the + compressed data to another file. + + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (var raw = System.IO.File.Create(fileToCompress + ".zlib")) + { + using (Stream compressor = new ZlibStream(raw, CompressionMode.Compress)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n; + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + Using input As Stream = File.OpenRead(fileToCompress) + Using raw As FileStream = File.Create(fileToCompress & ".zlib") + Using compressor As Stream = New ZlibStream(raw, CompressionMode.Compress) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + End Using + + + + The stream which will be read or written. + Indicates whether the ZlibStream will compress or decompress. + + + + Create a ZlibStream using the specified CompressionMode and + the specified CompressionLevel. + + + + + + When mode is CompressionMode.Decompress, the level parameter is ignored. + The "captive" stream will be closed when the ZlibStream is closed. + + + + + + This example uses a ZlibStream to compress data from a file, and writes the + compressed data to another file. + + + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (var raw = System.IO.File.Create(fileToCompress + ".zlib")) + { + using (Stream compressor = new ZlibStream(raw, + CompressionMode.Compress, + CompressionLevel.BestCompression)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n; + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + compressor.Write(buffer, 0, n); + } + } + } + } + + + + Using input As Stream = File.OpenRead(fileToCompress) + Using raw As FileStream = File.Create(fileToCompress & ".zlib") + Using compressor As Stream = New ZlibStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + End Using + + + + The stream to be read or written while deflating or inflating. + Indicates whether the ZlibStream will compress or decompress. + A tuning knob to trade speed for effectiveness. + + + + Create a ZlibStream using the specified CompressionMode, and + explicitly specify whether the captive stream should be left open after + Deflation or Inflation. + + + + + + When mode is CompressionMode.Compress, the ZlibStream will use + the default compression level. + + + + This constructor allows the application to request that the captive stream + remain open after the deflation or inflation occurs. By default, after + Close() is called on the stream, the captive stream is also + closed. In some cases this is not desired, for example if the stream is a + that will be re-read after + compression. Specify true for the parameter to leave the stream + open. + + + + See the other overloads of this constructor for example code. + + + + + The stream which will be read or written. This is called the + "captive" stream in other places in this documentation. + Indicates whether the ZlibStream will compress or decompress. + true if the application would like the stream to remain + open after inflation/deflation. + + + + Create a ZlibStream using the specified CompressionMode + and the specified CompressionLevel, and explicitly specify + whether the stream should be left open after Deflation or Inflation. + + + + + + This constructor allows the application to request that the captive + stream remain open after the deflation or inflation occurs. By + default, after Close() is called on the stream, the captive + stream is also closed. In some cases this is not desired, for example + if the stream is a that will be + re-read after compression. Specify true for the parameter to leave the stream open. + + + + When mode is CompressionMode.Decompress, the level parameter is + ignored. + + + + + + + This example shows how to use a ZlibStream to compress the data from a file, + and store the result into another file. The filestream remains open to allow + additional data to be written to it. + + + using (var output = System.IO.File.Create(fileToCompress + ".zlib")) + { + using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress)) + { + using (Stream compressor = new ZlibStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, true)) + { + byte[] buffer = new byte[WORKING_BUFFER_SIZE]; + int n; + while ((n= input.Read(buffer, 0, buffer.Length)) != 0) + { + compressor.Write(buffer, 0, n); + } + } + } + // can write additional data to the output stream here + } + + + Using output As FileStream = File.Create(fileToCompress & ".zlib") + Using input As Stream = File.OpenRead(fileToCompress) + Using compressor As Stream = New ZlibStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, True) + Dim buffer As Byte() = New Byte(4096) {} + Dim n As Integer = -1 + Do While (n <> 0) + If (n > 0) Then + compressor.Write(buffer, 0, n) + End If + n = input.Read(buffer, 0, buffer.Length) + Loop + End Using + End Using + ' can write additional data to the output stream here. + End Using + + + + The stream which will be read or written. + + Indicates whether the ZlibStream will compress or decompress. + + + true if the application would like the stream to remain open after + inflation/deflation. + + + + A tuning knob to trade speed for effectiveness. This parameter is + effective only when mode is CompressionMode.Compress. + + + + + Dispose the stream. + + + + This may or may not result in a Close() call on the captive + stream. See the constructors that have a leaveOpen parameter + for more information. + + + This method may be invoked in two distinct scenarios. If disposing + == true, the method has been called directly or indirectly by a + user's code, for example via the public Dispose() method. In this + case, both managed and unmanaged resources can be referenced and + disposed. If disposing == false, the method has been called by the + runtime from inside the object finalizer and this method should not + reference other objects; in that case only unmanaged resources must + be referenced or disposed. + + + + indicates whether the Dispose method was invoked by user code. + + + + + Flush the stream. + + + + + Read data from the stream. + + + + + + If you wish to use the ZlibStream to compress data while reading, + you can create a ZlibStream with CompressionMode.Compress, + providing an uncompressed data stream. Then call Read() on that + ZlibStream, and the data read will be compressed. If you wish to + use the ZlibStream to decompress data while reading, you can create + a ZlibStream with CompressionMode.Decompress, providing a + readable compressed data stream. Then call Read() on that + ZlibStream, and the data will be decompressed as it is read. + + + + A ZlibStream can be used for Read() or Write(), but + not both. + + + + + + The buffer into which the read data should be placed. + + + the offset within that data array to put the first byte read. + + the number of bytes to read. + + the number of bytes read + + + + Calling this method always throws a . + + + The offset to seek to.... + IF THIS METHOD ACTUALLY DID ANYTHING. + + + The reference specifying how to apply the offset.... IF + THIS METHOD ACTUALLY DID ANYTHING. + + + nothing. This method always throws. + + + + Calling this method always throws a . + + + The new value for the stream length.... IF + THIS METHOD ACTUALLY DID ANYTHING. + + + + + Write data to the stream. + + + + + + If you wish to use the ZlibStream to compress data while writing, + you can create a ZlibStream with CompressionMode.Compress, + and a writable output stream. Then call Write() on that + ZlibStream, providing uncompressed data as input. The data sent to + the output stream will be the compressed form of the data written. If you + wish to use the ZlibStream to decompress data while writing, you + can create a ZlibStream with CompressionMode.Decompress, and a + writable output stream. Then call Write() on that stream, + providing previously compressed data. The data sent to the output stream + will be the decompressed form of the data written. + + + + A ZlibStream can be used for Read() or Write(), but not both. + + + The buffer holding data to write to the stream. + the offset within that data array to find the first byte to write. + the number of bytes to write. + + + + Compress a string into a byte array using ZLIB. + + + + Uncompress it with . + + + + + + + + A string to compress. The string will first be encoded + using UTF8, then compressed. + + + The string in compressed form + + + + Compress a byte array into a new byte array using ZLIB. + + + + Uncompress it with . + + + + + + + A buffer to compress. + + + The data in compressed form + + + + Uncompress a ZLIB-compressed byte array into a single string. + + + + + + + A buffer containing ZLIB-compressed data. + + + The uncompressed string + + + + Uncompress a ZLIB-compressed byte array into a byte array. + + + + + + + A buffer containing ZLIB-compressed data. + + + The data in uncompressed form + + + + This property sets the flush behavior on the stream. + Sorry, though, not sure exactly how to describe all the various settings. + + + + + The size of the working buffer for the compression codec. + + + + + The working buffer is used for all stream operations. The default size is + 1024 bytes. The minimum size is 128 bytes. You may get better performance + with a larger buffer. Then again, you might not. You would have to test + it. + + + + Set this before the first call to Read() or Write() on the + stream. If you try to set it afterwards, it will throw. + + + + + Returns the total number of bytes input so far. + + + Returns the total number of bytes output so far. + + + + Indicates whether the stream can be read. + + + The return value depends on whether the captive stream supports reading. + + + + + Indicates whether the stream supports Seek operations. + + + Always returns false. + + + + + Indicates whether the stream can be written. + + + The return value depends on whether the captive stream supports writing. + + + + + Reading this property always throws a . + + + + + The position of the stream pointer. + + + + Setting this property always throws a . Reading will return the total bytes + written out, if used in writing, or the total bytes read in, if used in + reading. The count may refer to compressed bytes or uncompressed bytes, + depending on how you've used the stream. + + + + + Computes a CRC-32. The CRC-32 algorithm is parameterized - you + can set the polynomial and enable or disable bit + reversal. This can be used for GZIP, BZip2, or ZIP. + + + This type is used internally by DotNetZip; it is generally not used + directly by applications wishing to create, read, or manipulate zip + archive files. + + + + + Returns the CRC32 for the specified stream. + + The stream over which to calculate the CRC32 + the CRC32 calculation + + + + Returns the CRC32 for the specified stream, and writes the input into the + output stream. + + The stream over which to calculate the CRC32 + The stream into which to deflate the input + the CRC32 calculation + + + + Get the CRC32 for the given (word,byte) combo. This is a + computation defined by PKzip for PKZIP 2.0 (weak) encryption. + + The word to start with. + The byte to combine it with. + The CRC-ized result. + + + + Update the value for the running CRC32 using the given block of bytes. + This is useful when using the CRC32() class in a Stream. + + block of bytes to slurp + starting point in the block + how many bytes within the block to slurp + + + + Process one byte in the CRC. + + the byte to include into the CRC . + + + + Process a run of N identical bytes into the CRC. + + + + This method serves as an optimization for updating the CRC when a + run of identical bytes is found. Rather than passing in a buffer of + length n, containing all identical bytes b, this method accepts the + byte value and the length of the (virtual) buffer - the length of + the run. + + + the byte to include into the CRC. + the number of times that byte should be repeated. + + + + Combines the given CRC32 value with the current running total. + + + This is useful when using a divide-and-conquer approach to + calculating a CRC. Multiple threads can each calculate a + CRC32 on a segment of the data, and then combine the + individual CRC32 values at the end. + + the crc value to be combined with this one + the length of data the CRC value was calculated on + + + + Create an instance of the CRC32 class using the default settings: no + bit reversal, and a polynomial of 0xEDB88320. + + + + + Create an instance of the CRC32 class, specifying whether to reverse + data bits or not. + + + specify true if the instance should reverse data bits. + + + + In the CRC-32 used by BZip2, the bits are reversed. Therefore if you + want a CRC32 with compatibility with BZip2, you should pass true + here. In the CRC-32 used by GZIP and PKZIP, the bits are not + reversed; Therefore if you want a CRC32 with compatibility with + those, you should pass false. + + + + + + Create an instance of the CRC32 class, specifying the polynomial and + whether to reverse data bits or not. + + + The polynomial to use for the CRC, expressed in the reversed (LSB) + format: the highest ordered bit in the polynomial value is the + coefficient of the 0th power; the second-highest order bit is the + coefficient of the 1 power, and so on. Expressed this way, the + polynomial for the CRC-32C used in IEEE 802.3, is 0xEDB88320. + + + specify true if the instance should reverse data bits. + + + + + In the CRC-32 used by BZip2, the bits are reversed. Therefore if you + want a CRC32 with compatibility with BZip2, you should pass true + here for the reverseBits parameter. In the CRC-32 used by + GZIP and PKZIP, the bits are not reversed; Therefore if you want a + CRC32 with compatibility with those, you should pass false for the + reverseBits parameter. + + + + + + Reset the CRC-32 class - clear the CRC "remainder register." + + + + Use this when employing a single instance of this class to compute + multiple, distinct CRCs on multiple, distinct data blocks. + + + + + + Indicates the total number of bytes applied to the CRC. + + + + + Indicates the current CRC for all blocks slurped in. + + + + + A Stream that calculates a CRC32 (a checksum) on all bytes read, + or on all bytes written. + + + + + This class can be used to verify the CRC of a ZipEntry when + reading from a stream, or to calculate a CRC when writing to a + stream. The stream should be used to either read, or write, but + not both. If you intermix reads and writes, the results are not + defined. + + + + This class is intended primarily for use internally by the + DotNetZip library. + + + + + + The default constructor. + + + + Instances returned from this constructor will leave the underlying + stream open upon Close(). The stream uses the default CRC32 + algorithm, which implies a polynomial of 0xEDB88320. + + + The underlying stream + + + + The constructor allows the caller to specify how to handle the + underlying stream at close. + + + + The stream uses the default CRC32 algorithm, which implies a + polynomial of 0xEDB88320. + + + The underlying stream + true to leave the underlying stream + open upon close of the CrcCalculatorStream; false otherwise. + + + + A constructor allowing the specification of the length of the stream + to read. + + + + The stream uses the default CRC32 algorithm, which implies a + polynomial of 0xEDB88320. + + + Instances returned from this constructor will leave the underlying + stream open upon Close(). + + + The underlying stream + The length of the stream to slurp + + + + A constructor allowing the specification of the length of the stream + to read, as well as whether to keep the underlying stream open upon + Close(). + + + + The stream uses the default CRC32 algorithm, which implies a + polynomial of 0xEDB88320. + + + The underlying stream + The length of the stream to slurp + true to leave the underlying stream + open upon close of the CrcCalculatorStream; false otherwise. + + + + A constructor allowing the specification of the length of the stream + to read, as well as whether to keep the underlying stream open upon + Close(), and the CRC32 instance to use. + + + + The stream uses the specified CRC32 instance, which allows the + application to specify how the CRC gets calculated. + + + The underlying stream + The length of the stream to slurp + true to leave the underlying stream + open upon close of the CrcCalculatorStream; false otherwise. + the CRC32 instance to use to calculate the CRC32 + + + + Read from the stream + + the buffer to read + the offset at which to start + the number of bytes to read + the number of bytes actually read + + + + Write to the stream. + + the buffer from which to write + the offset at which to start writing + the number of bytes to write + + + + Flush the stream. + + + + + Seeking is not supported on this stream. This method always throws + + + N/A + N/A + N/A + + + + This method always throws + + + N/A + + + + Closes the stream. + + + + + Gets the total number of bytes run through the CRC32 calculator. + + + + This is either the total number of bytes read, or the total number of + bytes written, depending on the direction of this stream. + + + + + Provides the current CRC for all blocks slurped in. + + + + The running total of the CRC is kept as data is written or read + through the stream. read this property after all reads or writes to + get an accurate CRC for the entire stream. + + + + + + Indicates whether the underlying stream will be left open when the + CrcCalculatorStream is Closed. + + + + Set this at any point before calling . + + + + + + Indicates whether the stream supports reading. + + + + + Indicates whether the stream supports seeking. + + + + Always returns false. + + + + + + Indicates whether the stream supports writing. + + + + + Returns the length of the underlying stream. + + + + + The getter for this property returns the total bytes read. + If you use the setter, it will throw + . + + + + diff --git a/RtfConverter/Interpreter/Interpreter/RtfInterpreter.cs b/RtfConverter/Interpreter/Interpreter/RtfInterpreter.cs new file mode 100644 index 0000000..374b746 --- /dev/null +++ b/RtfConverter/Interpreter/Interpreter/RtfInterpreter.cs @@ -0,0 +1,497 @@ +// -- FILE ------------------------------------------------------------------ +// name : RtfInterpreter.cs +// project : RTF Framelet +// created : Leon Poyyayil - 2008.05.20 +// language : c# +// environment: .NET 2.0 +// copyright : (c) 2004-2008 by Itenso GmbH, Switzerland +// -------------------------------------------------------------------------- +using System; +using Itenso.Rtf.Model; +using Itenso.Rtf.Support; + +namespace Itenso.Rtf.Interpreter +{ + + // ------------------------------------------------------------------------ + public sealed class RtfInterpreter : RtfInterpreterBase, IRtfElementVisitor + { + + // ---------------------------------------------------------------------- + public RtfInterpreter( params IRtfInterpreterListener[] listeners ) + : base( listeners ) + { + this.fontTableBuilder = new RtfFontTableBuilder( Context.WritableFontTable ); + this.colorTableBuilder = new RtfColorTableBuilder( Context.WritableColorTable ); + this.documentInfoBuilder = new RtfDocumentInfoBuilder( Context.WritableDocumentInfo ); + this.userPropertyBuilder = new RtfUserPropertyBuilder( Context.WritableUserProperties ); + this.imageBuilder = new RtfImageBuilder(); + } // RtfInterpreter + + // ---------------------------------------------------------------------- + public bool IsSupportedDocument( IRtfGroup rtfDocument ) + { + try + { + GetSupportedDocument( rtfDocument ); + } + catch ( RtfException ) + { + return false; + } + return true; + } // IsSupportedDocument + + // ---------------------------------------------------------------------- + public IRtfGroup GetSupportedDocument( IRtfGroup rtfDocument ) + { + if ( rtfDocument == null ) + { + throw new RtfException( "document is null" ); + } + if ( rtfDocument.Contents.Count == 0 ) + { + throw new RtfException( "document has not contents" ); + } + IRtfElement firstElement = rtfDocument.Contents[ 0 ]; + if ( firstElement.Kind != RtfElementKind.Tag ) + { + throw new RtfException( "first element in document is not a tag" ); + } + IRtfTag firstTag = (IRtfTag)firstElement; + if ( !RtfSpec.TagRtf.Equals( firstTag.Name ) ) + { + throw new RtfException( "first tag in document is not " + RtfSpec.TagRtf ); + } + if ( !firstTag.HasValue ) + { + throw new RtfException( "unspecified RTF version" ); + } + if ( firstTag.ValueAsNumber != RtfSpec.RtfVersion1 ) + { + throw new RtfException( "unsupported RTF version: " + firstTag.ValueAsText ); + } + return rtfDocument; + } // GetSupportedDocument + + // ---------------------------------------------------------------------- + protected override void DoInterpret( IRtfGroup rtfDocument ) + { + InterpretContents( GetSupportedDocument( rtfDocument ) ); + } // DoInterpret + + // ---------------------------------------------------------------------- + private void InterpretContents( IRtfGroup rtfDocument ) + { + // by getting here we already know that the given document is supported, and hence + // we know it has version 1 + Context.Reset(); // clears all previous content and sets the version to 1 + NotifyBeginDocument(); + VisitChildrenOf( rtfDocument ); + Context.State = RtfInterpreterState.Ended; + NotifyEndDocument(); + } // InterpretContents + + // ---------------------------------------------------------------------- + private void VisitChildrenOf( IRtfGroup group ) + { + bool pushedTextFormat = false; + if ( Context.State == RtfInterpreterState.InDocument ) + { + Context.PushCurrentTextFormat(); + pushedTextFormat = true; + } + try + { + foreach ( IRtfElement child in group.Contents ) + { + child.Visit( this ); + } + } + finally + { + if ( pushedTextFormat ) + { + Context.PopCurrentTextFormat(); + } + } + } // VisitChildrenOf + + // ---------------------------------------------------------------------- + void IRtfElementVisitor.VisitTag( IRtfTag tag ) + { + if ( Context.State != RtfInterpreterState.InDocument ) + { + if ( Context.FontTable.Count > 0 ) + { + // somewhat of a hack to detect state change from header to in-document for + // rtf-docs which do neither have a generator group nor encapsulate the + // actual document content in a group. + if ( Context.ColorTable.Count > 0 || RtfSpec.TagViewKind.Equals( tag.Name ) ) + { + Context.State = RtfInterpreterState.InDocument; + } + } + } + + switch ( Context.State ) + { + case RtfInterpreterState.Init: + if ( RtfSpec.TagRtf.Equals( tag.Name ) ) + { + Context.State = RtfInterpreterState.InHeader; + Context.RtfVersion = tag.ValueAsNumber; + } + else + { + throw new RtfException( "Init: illegal state for tag '" + tag + "'" ); + } + break; + case RtfInterpreterState.InHeader: + switch ( tag.Name ) + { + case RtfSpec.TagDefaultFont: + Context.DefaultFontId = RtfSpec.TagFont + tag.ValueAsNumber.ToString(); + break; + } + break; + case RtfInterpreterState.InDocument: + switch ( tag.Name ) + { + case RtfSpec.TagPlain: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveNormal(); + break; + case RtfSpec.TagParagraphDefaults: + case RtfSpec.TagSectionDefaults: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithAlignment( RtfTextAlignment.Left ); + break; + case RtfSpec.TagBold: + bool bold = !tag.HasValue || tag.ValueAsNumber != 0; + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithBold( bold ); + break; + case RtfSpec.TagItalic: + bool italic = !tag.HasValue || tag.ValueAsNumber != 0; + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithItalic( italic ); + break; + case RtfSpec.TagUnderLine: + bool underline = !tag.HasValue || tag.ValueAsNumber != 0; + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithUnderline( underline ); + break; + case RtfSpec.TagUnderLineNone: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithUnderline( false ); + break; + case RtfSpec.TagStrikeThrough: + bool strikeThrough = !tag.HasValue || tag.ValueAsNumber != 0; + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithStrikeThrough( strikeThrough ); + break; + case RtfSpec.TagHidden: + bool hidden = !tag.HasValue || tag.ValueAsNumber != 0; + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithHidden( hidden ); + break; + case RtfSpec.TagFont: + string fontId = tag.FullName; + if ( Context.FontTable.ContainsFontWithId( fontId ) ) + { + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithFont( + Context.FontTable[ fontId ] ); + } + else + { + throw new RtfException( "undefined font: " + fontId ); + } + break; + case RtfSpec.TagFontSize: + int fontSize = tag.ValueAsNumber; + if ( fontSize > 0 ) + { + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithFontSize( fontSize ); + } + else + { + throw new RtfException( "invalid font size: " + fontSize ); + } + break; + case RtfSpec.TagFontSubscript: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithSuperScript( false ); + break; + case RtfSpec.TagFontSuperscript: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithSuperScript( true ); + break; + case RtfSpec.TagFontNoSuperSub: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithSuperScript( 0 ); + break; + case RtfSpec.TagFontDown: + int moveDown = tag.ValueAsNumber; + if ( moveDown == -1 ) + { + moveDown = 6; // the default value according to rtf spec + } + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithSuperScript( -moveDown ); + break; + case RtfSpec.TagFontUp: + int moveUp = tag.ValueAsNumber; + if ( moveUp == -1 ) + { + moveUp = 6; // the default value according to rtf spec + } + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithSuperScript( moveUp ); + break; + case RtfSpec.TagAlignLeft: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithAlignment( RtfTextAlignment.Left ); + break; + case RtfSpec.TagAlignCenter: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithAlignment( RtfTextAlignment.Center ); + break; + case RtfSpec.TagAlignRight: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithAlignment( RtfTextAlignment.Right ); + break; + case RtfSpec.TagAlignJustify: + Context.WritableCurrentTextFormat = + Context.WritableCurrentTextFormat.DeriveWithAlignment( RtfTextAlignment.Justify ); + break; + case RtfSpec.TagColorBackground: + case RtfSpec.TagColorBackgroundWord: + case RtfSpec.TagColorForeground: + int colorIndex = tag.ValueAsNumber; + if ( colorIndex >= 0 && colorIndex < Context.ColorTable.Count ) + { + IRtfColor newColor = Context.ColorTable[ colorIndex ]; + bool isForeground = RtfSpec.TagColorForeground.Equals( tag.Name ); + Context.WritableCurrentTextFormat = isForeground ? + Context.WritableCurrentTextFormat.DeriveWithForegroundColor( newColor ) : + Context.WritableCurrentTextFormat.DeriveWithBackgroundColor( newColor ); + } + else + { + throw new RtfException( "undefined color index: " + colorIndex ); + } + break; + case RtfSpec.TagSection: + NotifyInsertBreak( RtfVisualBreakKind.Section ); + break; + case RtfSpec.TagParagraph: + NotifyInsertBreak( RtfVisualBreakKind.Paragraph ); + break; + case RtfSpec.TagLine: + NotifyInsertBreak( RtfVisualBreakKind.Line ); + break; + case RtfSpec.TagPage: + NotifyInsertBreak( RtfVisualBreakKind.Page ); + break; + case RtfSpec.TagTabulator: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.Tabulator ); + break; + case RtfSpec.TagTilde: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.NonBreakingSpace ); + break; + case RtfSpec.TagEmDash: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.EmDash ); + break; + case RtfSpec.TagEnDash: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.EnDash ); + break; + case RtfSpec.TagEmSpace: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.EmSpace ); + break; + case RtfSpec.TagEnSpace: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.EnSpace ); + break; + case RtfSpec.TagQmSpace: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.QmSpace ); + break; + case RtfSpec.TagBulltet: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.Bullet ); + break; + case RtfSpec.TagLeftSingleQuote: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.LeftSingleQuote ); + break; + case RtfSpec.TagRightSingleQuote: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.RightSingleQuote ); + break; + case RtfSpec.TagLeftDoubleQuote: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.LeftDoubleQuote ); + break; + case RtfSpec.TagRightDoubleQuote: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.RightDoubleQuote ); + break; + case RtfSpec.TagHyphen: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.OptionalHyphen ); + break; + case RtfSpec.TagUnderscore: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.NonBreakingHyphen ); + break; + } + break; + } + } // IRtfElementVisitor.VisitTag + + // ---------------------------------------------------------------------- + void IRtfElementVisitor.VisitGroup( IRtfGroup group ) + { + string groupDestination = group.Destination; + switch ( Context.State ) + { + case RtfInterpreterState.Init: + if ( RtfSpec.TagRtf.Equals( groupDestination ) ) + { + VisitChildrenOf( group ); + } + else + { + throw new RtfException( "Init: illegal state for group '" + groupDestination + "'" ); + } + break; + case RtfInterpreterState.InHeader: + switch ( groupDestination ) + { + case RtfSpec.TagFontTable: + this.fontTableBuilder.VisitGroup( group ); + break; + case RtfSpec.TagColorTable: + this.colorTableBuilder.VisitGroup( group ); + break; + case RtfSpec.TagGenerator: + // last group with a destination in header, but no need to process its contents + Context.State = RtfInterpreterState.InDocument; + IRtfText generator = group.Contents.Count == 3 ? group.Contents[ 2 ] as IRtfText : null; + if ( generator != null ) + { + string generatorName = generator.Text; + Context.Generator = generatorName.EndsWith( ";" ) ? + generatorName.Substring( 0, generatorName.Length - 1 ) : generatorName; + } + else + { + throw new RtfException( "invalid generator group: " + group ); + } + break; + case null: + // group without destination cannot be part of header, but need to process its contents + Context.State = RtfInterpreterState.InDocument; + if ( !group.IsExtensionDestination ) + { + VisitChildrenOf( group ); + } + break; + } + break; + case RtfInterpreterState.InDocument: + switch ( groupDestination ) + { + case RtfSpec.TagUserProperties: + this.userPropertyBuilder.VisitGroup( group ); + break; + case RtfSpec.TagInfo: + this.documentInfoBuilder.VisitGroup( group ); + break; + case RtfSpec.TagUnicodeAlternativeChoices: + IRtfGroup alternativeWithUnicodeSupport = + group.SelectChildGroupWithDestination( RtfSpec.TagUnicodeAlternativeUnicode ); + if ( alternativeWithUnicodeSupport != null ) + { + // there is an alternative with unicode formatted content -> use this + VisitChildrenOf( alternativeWithUnicodeSupport ); + } + else + { + // try to locate the alternative without unicode -> only ANSI fallbacks + IRtfGroup alternativeWithoutUnicode = // must be the third element if present + group.Contents.Count > 2 ? group.Contents[ 2 ] as IRtfGroup : null; + if ( alternativeWithoutUnicode != null ) + { + VisitChildrenOf( alternativeWithoutUnicode ); + } + } + break; + case RtfSpec.TagHeader: + case RtfSpec.TagHeaderFirst: + case RtfSpec.TagHeaderLeft: + case RtfSpec.TagHeaderRight: + case RtfSpec.TagFooter: + case RtfSpec.TagFooterFirst: + case RtfSpec.TagFooterLeft: + case RtfSpec.TagFooterRight: + case RtfSpec.TagFootnote: + case RtfSpec.TagStyleSheet: + // groups we currently ignore, so their content doesn't intermix with + // the actual document content + break; + case RtfSpec.TagPictureWrapper: + VisitChildrenOf( group ); + break; + case RtfSpec.TagPicture: + this.imageBuilder.VisitGroup( group ); + NotifyInsertImage( + this.imageBuilder.Format, + this.imageBuilder.Width, + this.imageBuilder.Height, + this.imageBuilder.DesiredWidth, + this.imageBuilder.DesiredHeight, + this.imageBuilder.ScaleWidthPercent, + this.imageBuilder.ScaleHeightPercent, + this.imageBuilder.ImageDataHex ); + break; + case RtfSpec.TagParagraphNumberText: + case RtfSpec.TagListNumberText: + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.ParagraphNumberBegin ); + VisitChildrenOf( group ); + NotifyInsertSpecialChar( RtfVisualSpecialCharKind.ParagraphNumberEnd ); + break; + default: + if ( !group.IsExtensionDestination ) + { + // nested text group + VisitChildrenOf( group ); + } + break; + } + break; + } + } // IRtfElementVisitor.VisitGroup + + // ---------------------------------------------------------------------- + void IRtfElementVisitor.VisitText( IRtfText text ) + { + switch ( Context.State ) + { + case RtfInterpreterState.Init: + throw new RtfException( "Init: illegal state for text '" + text.Text + "'" ); + case RtfInterpreterState.InHeader: + Context.State = RtfInterpreterState.InDocument; + break; + case RtfInterpreterState.InDocument: + break; + } + NotifyInsertText( text.Text ); + } // IRtfElementVisitor.VisitText + + // ---------------------------------------------------------------------- + // members + private readonly RtfFontTableBuilder fontTableBuilder; + private readonly RtfColorTableBuilder colorTableBuilder; + private readonly RtfDocumentInfoBuilder documentInfoBuilder; + private readonly RtfUserPropertyBuilder userPropertyBuilder; + private readonly RtfImageBuilder imageBuilder; + + } // class RtfInterpreter + +} // namespace Itenso.Rtf.Interpreter +// -- EOF ------------------------------------------------------------------- diff --git a/RtfConverter/Interpreter/Interpreter2005.csproj b/RtfConverter/Interpreter/Interpreter2005.csproj new file mode 100644 index 0000000..29b144e --- /dev/null +++ b/RtfConverter/Interpreter/Interpreter2005.csproj @@ -0,0 +1,133 @@ + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {2A49B537-AFDB-4541-8683-468F2A0BE0AE} + Library + Properties + Itenso.Rtf.Interpreter + Itenso.Rtf.Interpreter + + + true + full + false + ..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {6FA3F1A8-4E10-459C-A8DC-C40A90D627B0} + Parser2005 + + + {0F203536-FF4F-4783-992D-1DE210C3C485} + Sys2005 + + + + + \ No newline at end of file diff --git a/RtfConverter/Parser/Parser2005.csproj b/RtfConverter/Parser/Parser2005.csproj new file mode 100644 index 0000000..ce1af43 --- /dev/null +++ b/RtfConverter/Parser/Parser2005.csproj @@ -0,0 +1,79 @@ + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {6FA3F1A8-4E10-459C-A8DC-C40A90D627B0} + Library + Properties + Itenso.Rtf.Parser + Itenso.Rtf.Parser + + + true + full + false + ..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {0F203536-FF4F-4783-992D-1DE210C3C485} + Sys2005 + + + + + \ No newline at end of file diff --git a/RtfConverter/bin/Debug/Itenso.Rtf.Interpreter.dll b/RtfConverter/bin/Debug/Itenso.Rtf.Interpreter.dll new file mode 100644 index 0000000000000000000000000000000000000000..e77226adbc0578fa05c4035ed36309db770f423d GIT binary patch literal 90112 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�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 O1jZ5=OJFPkrT#xBTw_N7 literal 0 HcmV?d00001 diff --git a/RtfConverter/bin/Debug/Itenso.Rtf.Parser.dll b/RtfConverter/bin/Debug/Itenso.Rtf.Parser.dll new file mode 100644 index 0000000000000000000000000000000000000000..03e7f7009e5cfa378a3c9a609a2dddedd2fbf95c GIT binary patch literal 49152 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 PdtlrH;~x0`f(QODUgFAj literal 0 HcmV?d00001 diff --git a/iTechSharp/AssemblyInfo.cs b/iTechSharp/AssemblyInfo.cs new file mode 100644 index 0000000..b275404 --- /dev/null +++ b/iTechSharp/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("iTextSharp")] +[assembly: AssemblyDescription("A free PDF library ported from Java iText.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("Copyright (C) 1999-2008 by Bruno Lowagie and Paulo Soares. All Rights Reserved.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("4.1.2")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("..\\..\\itextsharp.snk")] +[assembly: AssemblyKeyName("")] diff --git a/iTechSharp/System/Drawing/Dimension.cs b/iTechSharp/System/Drawing/Dimension.cs new file mode 100644 index 0000000..5526d6f --- /dev/null +++ b/iTechSharp/System/Drawing/Dimension.cs @@ -0,0 +1,158 @@ +using System; + +namespace System.Drawing { + ///

    + /// The Dimension class encapsulates the width and + /// height of a component (in int precision) in a single object. + /// + /// + /// The class is + /// associated with certain properties of components. Several methods + /// defined by the Component class and the + /// LayoutManager interface return a Dimension object. + ///

    + /// Normally the values of width + /// and height are non-negative ints. + /// The constructors that allow you to create a dimension do + /// not prevent you from setting a negative value for these properties. + /// If the value of width or height is + /// negative, the behavior of some methods defined by other objects is + /// undefined. + /// + public class Dimension : Dimension2D { + + ///

    + /// The width dimension. Negative values can be used. + /// + public int width; + + /// + /// The height dimension. Negative values can be used. + /// + public int height; + + /// + /// Creates an instance of Dimension with a width + /// of zero and a height of zero. + /// + public Dimension() : this(0, 0) {} + + /// + /// Creates an instance of Dimension whose width + /// and height are the same as for the specified dimension. + /// + /// + /// the specified dimension for the + /// width and + /// height values. + /// + public Dimension(Dimension d) : this(d.width, d.height) {} + + /// + /// Constructs a Dimension and initializes it to the specified width and + /// specified height. + /// + /// the specified width dimension + /// the specified height dimension + public Dimension(int width, int height) { + this.width = width; + this.height = height; + } + + /// + /// Returns the width of this dimension in double precision. + /// + /// the width + public override double Width { + get { + return width; + } + } + + /// + /// Returns the height of this dimension in double precision. + /// + /// the height + public override double Height { + get { + return height; + } + } + + /// + /// Set the size of this Dimension object to the specified width + /// and height in double precision. + /// + /// the new width for the Dimension object + /// the new height for the Dimension object + public override void SetSize(double width, double height) { + width = (int) Math.Ceiling(width); + height = (int) Math.Ceiling(height); + } + + /// + /// Get/set the size of this Dimension object. + /// + /// the size + public new Dimension Size { + get { + return new Dimension(width, height); + } + + set { + SetSize(value.width, value.height); + } + } + + /// + /// Set the size of this Dimension object + /// to the specified width and height. + /// + /// the new width for this Dimension object. + /// the new height for this Dimension object. + public void SetSize(int width, int height) { + this.width = width; + this.height = height; + } + + /// + /// Checks whether two dimension objects have equal values. + /// + /// + /// + public override bool Equals(Object obj) { + if (obj is Dimension) { + Dimension d = (Dimension)obj; + return (width == d.width) && (height == d.height); + } + return false; + } + + /// + /// Returns the hash code for this Dimension. + /// + /// a hash code + public override int GetHashCode() { + int sum = width + height; + return sum * (sum + 1)/2 + width; + } + + /// + /// Returns a string representation of the values of this + /// Dimension object's height and + /// width fields. + /// + /// + /// This method is intended to be used only + /// for debugging purposes, and the content and format of the returned + /// string may vary between implementations. The returned string may be + /// empty but may not be null. + /// + /// a string representation of this Dimension + /// object. + /// + public override string ToString() { + return this.GetType().Name + "[width=" + width + ",height=" + height + "]"; + } + } +} diff --git a/iTechSharp/System/Drawing/Dimension2D.cs b/iTechSharp/System/Drawing/Dimension2D.cs new file mode 100644 index 0000000..b0c710a --- /dev/null +++ b/iTechSharp/System/Drawing/Dimension2D.cs @@ -0,0 +1,69 @@ +using System; + +namespace System.Drawing { + /// + /// The Dimension2D class is to encapsulate a width + /// and a height dimension. + /// + /// + /// This class is only the abstract baseclass for all objects that + /// store a 2D dimension. + /// The actual storage representation of the sizes is left to + /// the subclass. + /// + public abstract class Dimension2D : ICloneable { + /// + /// This is an abstract class that cannot be instantiated directly. + /// Type-specific implementation subclasses are available for + /// instantiation and provide a number of formats for storing + /// the information necessary to satisfy the various accessor + /// methods below. + /// + /// + protected Dimension2D() { + } + + /// + /// Returns the width of this Dimension in double + /// precision. + /// + /// the width + public abstract double Width {get;} + + /// + /// Returns the height of this Dimension in double + /// precision. + /// + /// the height + public abstract double Height {get;} + + /// + /// Sets the size of this Dimension object to the + /// specified width and height. + /// + /// the new width for the Dimension + /// object + /// the new height for the Dimension + /// object + public abstract void SetSize(double width, double height); + + /// + /// Sets the size of this Dimension2D object to + /// match the specified size. + /// + /// the size + public Dimension2D Size { + set { + SetSize(value.Width, value.Height); + } + } + + /// + /// Creates a new object of the same class as this object. + /// + /// a clone of this instance + public Object Clone() { + throw new Exception("not implemented"); + } + } +} diff --git a/iTechSharp/System/util/ListIterator.cs b/iTechSharp/System/util/ListIterator.cs new file mode 100644 index 0000000..8596274 --- /dev/null +++ b/iTechSharp/System/util/ListIterator.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections; + +namespace System.util { + /// + /// Summary description for ListIterator. + /// + public class ListIterator { + ArrayList col; + int cursor = 0; + int lastRet = -1; + + public ListIterator(ArrayList col) { + this.col = col; + } + + public bool HasNext() { + return cursor != col.Count; + } + + public object Next() { + Object next = col[cursor]; + lastRet = cursor++; + return next; + } + + public object Previous() { + int i = cursor - 1; + Object previous = col[i]; + lastRet = cursor = i; + return previous; + } + + public void Remove() { + if (lastRet == -1) + throw new InvalidOperationException(); + col.RemoveAt(lastRet); + if (lastRet < cursor) + cursor--; + lastRet = -1; + } + } +} diff --git a/iTechSharp/System/util/Properties.cs b/iTechSharp/System/util/Properties.cs new file mode 100644 index 0000000..47b10a8 --- /dev/null +++ b/iTechSharp/System/util/Properties.cs @@ -0,0 +1,209 @@ +using System; +using System.Text; +using System.IO; +using System.Collections; + +namespace System.util +{ + /// + /// Summary description for Properties. + /// + public class Properties + { + private Hashtable _col; + private const string whiteSpaceChars = " \t\r\n\f"; + private const string keyValueSeparators = "=: \t\r\n\f"; + private const string strictKeyValueSeparators = "=:"; + + public Properties() + { + _col = new Hashtable(); + } + + public string Remove(string key) { + string retval = (string)_col[key]; + _col.Remove(key); + return retval; + } + + public IEnumerator GetEnumerator() { + return _col.GetEnumerator(); + } + + public bool ContainsKey(string key) { + return _col.ContainsKey(key); + } + + public virtual void Add(string key, string value) { + _col[key] = value; + } + + public void AddAll(Properties col) { + foreach (string itm in col.Keys) { + _col[itm] = col[itm]; + } + } + + public int Count { + get { + return _col.Count; + } + } + + public virtual string this[string key] { + get { + return (string)_col[key]; + } + + set { + _col[key] = value; + } + } + + public ICollection Keys { + get { + return _col.Keys; + } + } + + public void Clear() { + _col.Clear(); + } + + public void Load(Stream inStream) { + StreamReader inp = new StreamReader(inStream, Encoding.GetEncoding(1252)); + while (true) { + // Get next line + String line = inp.ReadLine(); + if (line == null) + return; + + if (line.Length > 0) { + + // Find start of key + int len = line.Length; + int keyStart; + for (keyStart=0; keyStart= 0) && (line[index--] == '\\')) + slashCount++; + return (slashCount % 2 == 1); + } + } +} diff --git a/iTechSharp/System/util/StringTokenizer.cs b/iTechSharp/System/util/StringTokenizer.cs new file mode 100644 index 0000000..6257e31 --- /dev/null +++ b/iTechSharp/System/util/StringTokenizer.cs @@ -0,0 +1,130 @@ +using System; +/* + * $Id: StringTokenizer.cs,v 1.4 2006/06/16 10:52:26 psoares33 Exp $ + * + * Copyright 2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License isp distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code isp 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code isp Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code isp Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library isp free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library isp distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace System.util { + + // a replacement for the StringTokenizer java class + // it's more or less the same as the one in the GNU classpath + public class StringTokenizer { + private int pos; + private String str; + private int len; + private String delim; + private bool retDelims; + + public StringTokenizer(String str) : this(str, " \t\n\r\f", false) { + } + + public StringTokenizer(String str, String delim) : this(str, delim, false) { + } + + public StringTokenizer(String str, String delim, bool retDelims) { + len = str.Length; + this.str = str; + this.delim = delim; + this.retDelims = retDelims; + this.pos = 0; + } + + public bool HasMoreTokens() { + if (! retDelims) { + while (pos < len && delim.IndexOf(str[pos]) >= 0) + pos++; + } + return pos < len; + } + + public String NextToken(String delim) { + this.delim = delim; + return NextToken(); + } + + public String NextToken() { + if (pos < len && delim.IndexOf(str[pos]) >= 0) { + if (retDelims) + return str.Substring(pos++, 1); + while (++pos < len && delim.IndexOf(str[pos]) >= 0); + } + if (pos < len) { + int start = pos; + while (++pos < len && delim.IndexOf(str[pos]) < 0); + + return str.Substring(start, pos - start); + } + throw new IndexOutOfRangeException(); + } + + public int CountTokens() { + int count = 0; + int delimiterCount = 0; + bool tokenFound = false; + int tmpPos = pos; + + while (tmpPos < len) { + if (delim.IndexOf(str[tmpPos++]) >= 0) { + if (tokenFound) { + count++; + tokenFound = false; + } + delimiterCount++; + } + else { + tokenFound = true; + while (tmpPos < len + && delim.IndexOf(str[tmpPos]) < 0) + ++tmpPos; + } + } + if (tokenFound) + count++; + return retDelims ? count + delimiterCount : count; + } + } +} \ No newline at end of file diff --git a/iTechSharp/System/util/Util.cs b/iTechSharp/System/util/Util.cs new file mode 100644 index 0000000..2080d87 --- /dev/null +++ b/iTechSharp/System/util/Util.cs @@ -0,0 +1,27 @@ +using System; +using System.Globalization; + +namespace System.util +{ + /// + /// Summary description for Util. + /// + public class Util + { + public static int USR(int op1, int op2) { + if (op2 < 1) { + return op1; + } else { + return unchecked((int)((uint)op1 >> op2)); + } + } + + public static bool EqualsIgnoreCase(string s1, string s2) { + return CultureInfo.InvariantCulture.CompareInfo.Compare(s1, s2, CompareOptions.IgnoreCase) == 0; + } + + public static int CompareToIgnoreCase(string s1, string s2) { + return CultureInfo.InvariantCulture.CompareInfo.Compare(s1, s2, CompareOptions.IgnoreCase); + } + } +} diff --git a/iTechSharp/System/util/collections/Algorithm.cs b/iTechSharp/System/util/collections/Algorithm.cs new file mode 100644 index 0000000..fe4e74a --- /dev/null +++ b/iTechSharp/System/util/collections/Algorithm.cs @@ -0,0 +1,49 @@ +using System; + +namespace System.util.collections +{ + /// + /// Very basic algorithms tool class. + /// + public class k_Algorithm + { + public static k_Iterator Copy(k_Iterator ak_SrcFirst, k_Iterator ak_BehindSrcLast, k_Iterator ak_DstFirst) + { + k_Iterator lk_Src = ak_SrcFirst.Clone(), lk_Dst = ak_DstFirst.Clone(); + while (lk_Src != ak_BehindSrcLast) + { + lk_Dst.Current = lk_Src.Current; + lk_Src.Next(); lk_Dst.Next(); + } + return lk_Dst; + } + + public static k_Iterator CopyBackward(k_Iterator ak_SrcFirst, k_Iterator ak_BehindSrcLast, k_Iterator ak_BehindDstLast) + { + k_Iterator lk_Src = ak_BehindSrcLast.Clone(), lk_Dst = ak_BehindDstLast.Clone(); + while (lk_Src != ak_SrcFirst) + { + lk_Src.Prev(); lk_Dst.Prev(); + lk_Dst.Current = lk_Src.Current; + } + return lk_Dst; + } + + public static void Fill(k_Iterator ak_DstFirst, k_Iterator ak_BehindDstLast, object ak_Value) + { + for (k_Iterator lk_Iter = ak_DstFirst.Clone(); lk_Iter != ak_BehindDstLast; lk_Iter.Next()) + lk_Iter.Current = ak_Value; + } + + public static k_Iterator Find(k_Iterator ak_First, k_Iterator ak_Last, object ak_Value) + { + k_Iterator lk_Iter = ak_First.Clone(); + for (; lk_Iter != ak_Last; lk_Iter.Next()) + { + if (object.Equals(lk_Iter.Current, ak_Value)) + break; + } + return lk_Iter; + } + } +} diff --git a/iTechSharp/System/util/collections/Container.cs b/iTechSharp/System/util/collections/Container.cs new file mode 100644 index 0000000..b3913ca --- /dev/null +++ b/iTechSharp/System/util/collections/Container.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// Base interface for all containers + /// + public interface IContainer : ICollection, ICloneable + { + k_Iterator Begin { get; } + k_Iterator End { get; } + + bool IsEmpty { get; } + + k_Iterator Find(object ak_Value); + + k_Iterator Erase(k_Iterator ak_Where); + k_Iterator Erase(k_Iterator ak_First, k_Iterator ak_Last); + } + + /// + /// Interface for non-associative sequential containers (k_Vector, k_Deque, k_List) + /// + public interface ISequence : IContainer, IList + { + object Front { get; set; } + object Back { get; set; } + + void PushFront(object ak_Value); + void PopFront(); + + void PushBack(object ak_Value); + void PopBack(); + + void Assign(k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd); + void Assign(object ak_Value, int ai_Count); + + void Insert(k_Iterator ak_Where, object ak_Value); + void Insert(k_Iterator ak_Where, k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd); + } + + /// + /// Interface for IDictionary derived containers which provide key to value mapping (k_HashTable) + /// + public interface IMap : IContainer, IDictionary + { + k_Iterator FindKey(object ak_Key); + + void Add(DictionaryEntry ar_Item); + void Insert(k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd); + } + + /// + /// Interface for sorted mapping containers (k_SkipList, k_Tree) + /// + public interface ISortedMap : IMap + { + IComparer Comparer { get; } + + k_Iterator LowerBound(object ak_Key); + k_Iterator UpperBound(object ak_Key); + } +} diff --git a/iTechSharp/System/util/collections/Deque.cs b/iTechSharp/System/util/collections/Deque.cs new file mode 100644 index 0000000..53a2c4b --- /dev/null +++ b/iTechSharp/System/util/collections/Deque.cs @@ -0,0 +1,470 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// Circular buffer of arrays + /// + public class k_Deque : ISequence + { + #region k_BlockIterator Implementation + + private class k_BlockIterator : k_Iterator + { + private readonly k_Deque mk_Deque; + private int mi_Index; + private int mi_BlockIndex; + private int mi_BlockOffset; + + public k_BlockIterator(k_Deque ak_Deque, int ai_Index) + { + mk_Deque = ak_Deque; + mi_Index = ai_Index; + mi_BlockIndex = mk_Deque.CalcBlockAndPos(mi_Index, out mi_BlockOffset); + } + + public override void Move(int ai_Count) + { + int li_Index = mi_Index + ai_Count; + + if (li_Index > mk_Deque.Count) + throw new InvalidOperationException("Tried to move beyond end element."); + else if (li_Index < 0) + throw new InvalidOperationException("Tried to move before first element."); + + mi_Index = li_Index; + mi_BlockOffset += ai_Count; + + if (mi_BlockOffset >= k_Deque.mi_BlockSize || mi_BlockOffset < 0) + mi_BlockIndex = mk_Deque.CalcBlockAndPos(mi_Index, out mi_BlockOffset); + } + + public override int Distance(k_Iterator ak_Iter) + { + return mi_Index - ((k_BlockIterator)ak_Iter).mi_Index; + } + + public override object Collection + { + get { return mk_Deque; } + } + + public override object Current + { + get + { + if (mi_Index < 0 || mi_Index >= mk_Deque.mi_Count) + throw new k_InvalidPositionException(); + return mk_Deque.mk_Blocks[mi_BlockIndex][mi_BlockOffset]; + } + set + { + if (mi_Index < 0 || mi_Index >= mk_Deque.mi_Count) + throw new k_InvalidPositionException(); + mk_Deque.mk_Blocks[mi_BlockIndex][mi_BlockOffset] = value; + } + } + + public override bool Equals(object ak_Obj) + { + k_BlockIterator lk_Iter = ak_Obj as k_BlockIterator; + if (lk_Iter == null) + return false; + + return (mi_Index == lk_Iter.mi_Index) && object.ReferenceEquals(this.Collection, lk_Iter.Collection); + } + + public override int GetHashCode() + { + return mk_Deque.GetHashCode() ^ mi_Index; + } + + public override k_Iterator Clone() + { + return new k_BlockIterator(mk_Deque, mi_Index); + } + + internal int Index + { + get { return mi_Index; } + } + } + + private class k_PinnedBlockIterator : k_BlockIterator + { + public k_PinnedBlockIterator(k_Deque ak_Deque, int ai_Index) + : base(ak_Deque, ai_Index) + { + } + + public override void Move(int ai_Count) + { + throw new k_IteratorPinnedException(); + } + } + + #endregion + + private const int mi_BlockSize = 16; + private object[][] mk_Blocks; + + private int mi_Offset; + private int mi_Count; + + public k_Deque() + : this(mi_BlockSize) + { + } + + public k_Deque(int ai_Capacity) + { + if (ai_Capacity < 0) + throw new ArgumentException("Capacity must be positive.", "ai_Capacity"); + mk_Blocks = new object[(ai_Capacity+mi_BlockSize-1)/mi_BlockSize][]; + for (int i=0; i= mk_Blocks.Length) + li_Block -= mk_Blocks.Length; + mk_Blocks[li_Block][li_Pos%mi_BlockSize] = ak_Value; + ++mi_Count; + } + + public void PopBack() + { + Erase(this.End-1); + } + + public void Assign(k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + Clear(); + Insert(this.End, ak_SrcBegin, ak_SrcEnd); + } + + public void Assign(object ak_Value, int ai_Count) + { + Clear(); + for (int i = 0; i < ai_Count; ++i) + Insert(this.End, ak_Value); + } + + public void Insert(k_Iterator ak_Where, object ak_Value) + { + if (ak_Where == this.Begin) + PushFront(ak_Value); + else if (ak_Where == this.End) + PushBack(ak_Value); + else + { + int li_Index = ((k_BlockIterator)ak_Where).Index; + if (mk_Blocks.Length * mi_BlockSize - mi_Count < mi_BlockSize) + AllocateBlock(mi_BlockSize); + + ++mi_Count; + if (li_Index < mi_Count/2) + { + if (mi_Offset == 0) + mi_Offset = mk_Blocks.Length * mi_BlockSize; + --mi_Offset; + k_Iterator lk_Dest = k_Algorithm.Copy(this.Begin+1, this.Begin+li_Index+1, this.Begin); + lk_Dest.Current = ak_Value; + } + else + { + // count has been incremented - there is a free element at the end + k_Iterator lk_Dest = this.Begin + li_Index; + k_Algorithm.CopyBackward(lk_Dest, this.End - 1, this.End); + lk_Dest.Current = ak_Value; + } + } + } + + public void Insert(k_Iterator ak_Where, k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + int li_FirstIndex = ((k_BlockIterator)ak_Where).Index; + int li_Count = ak_SrcEnd - ak_SrcBegin; + if (mk_Blocks.Length * mi_BlockSize <= mi_Count + li_Count + mi_BlockSize) + AllocateBlock(li_Count); + + mi_Count += li_Count; + + k_Iterator lk_Dest; + if (li_FirstIndex < li_Count/2) + { + if (mi_Offset == 0) + mi_Offset = mk_Blocks.Length * mi_BlockSize; + mi_Offset -= li_Count; + lk_Dest = k_Algorithm.Copy(this.Begin+li_Count, this.Begin+li_FirstIndex+li_Count, this.Begin); + } + else + { + // count has been incremented - there are li_Count free elements at the end + lk_Dest = this.Begin + li_FirstIndex; + k_Algorithm.CopyBackward(lk_Dest, this.End - li_Count, this.End); + } + + k_Algorithm.Copy(ak_SrcBegin, ak_SrcEnd, lk_Dest); + } + + #region IList Members + + public int Add(object ak_Value) + { + PushBack(ak_Value); + return mi_Count; + } + + public void Clear() + { + for (int i=0; i= mi_Count || ai_Index < 0) + throw new ArgumentOutOfRangeException("Position out of boundary"); + + int li_Pos, li_Block = CalcBlockAndPos(ai_Index, out li_Pos); + return mk_Blocks[li_Block][li_Pos]; + } + set + { + if (ai_Index >= mi_Count || ai_Index < 0) + throw new ArgumentOutOfRangeException("Position out of boundary"); + + int li_Pos, li_Block = CalcBlockAndPos(ai_Index, out li_Pos); + mk_Blocks[li_Block][li_Pos] = value; + } + } + + #endregion + + #region ICollection Members + + public void CopyTo(Array ak_Array, int ai_Index) + { + for (k_Iterator lk_Iter = this.Begin.Clone(); lk_Iter != this.End; lk_Iter.Next()) + ak_Array.SetValue(lk_Iter.Current, ai_Index++); + } + + public int Count + { + get { return mi_Count; } + } + + public bool IsSynchronized + { + get { return false; } + } + + public object SyncRoot + { + get { return this; } + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return new k_IteratorEnumerator(this.Begin, this.End); + } + + #endregion + + #region ICloneable Members + + public object Clone() + { + k_Deque lk_Clone = new k_Deque(this.Count); + lk_Clone.Insert(lk_Clone.End, this.Begin, this.End); + return lk_Clone; + } + + #endregion + + private void AllocateBlock(int ai_MinElements) + { + // number of new blocks - grow by half block count (150%) + int li_Increment = mk_Blocks.Length / 2; + if (ai_MinElements > li_Increment*mi_BlockSize) + li_Increment = (ai_MinElements + mi_BlockSize - 1)/mi_BlockSize; + + object[][] lk_NewBlocks = new object[mk_Blocks.Length + li_Increment][]; + + // first move all blocks after offset to front + int li_StartBlock = mi_Offset / mi_BlockSize; + int li_BackCount = mk_Blocks.Length - li_StartBlock; + Array.Copy(mk_Blocks, li_StartBlock, lk_NewBlocks, 0, li_BackCount); + + int li_TotalOld = li_BackCount; + + // second move all blocks before offset to end + int li_FrontCount = (mi_Offset + mi_Count + mi_BlockSize - 1) / mi_BlockSize - mk_Blocks.Length; + if (li_FrontCount > 0) + { + Array.Copy(mk_Blocks, 0, lk_NewBlocks, li_BackCount, li_FrontCount); + li_TotalOld += li_FrontCount; + } + + // actually create new empty blocks + for (int i=li_TotalOld; i < li_TotalOld+li_Increment; ++i) + lk_NewBlocks[i] = new object[mi_BlockSize]; + + mk_Blocks = lk_NewBlocks; + mi_Offset %= mi_BlockSize; + } + + private int CalcBlockAndPos(int ai_Index, out int ai_Pos) + { + ai_Pos = mi_Offset + ai_Index; + int li_BlockIndex = ai_Pos / mi_BlockSize; + if (li_BlockIndex >= mk_Blocks.Length) + li_BlockIndex -= mk_Blocks.Length; + ai_Pos %= mi_BlockSize; + return li_BlockIndex; + } + } +} diff --git a/iTechSharp/System/util/collections/HashTable.cs b/iTechSharp/System/util/collections/HashTable.cs new file mode 100644 index 0000000..f16a1a2 --- /dev/null +++ b/iTechSharp/System/util/collections/HashTable.cs @@ -0,0 +1,658 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// A HashTable with iterators + /// + public class k_HashTable : IMap + { + #region static helper functions + + private readonly static int[] mk_Primes = + { + 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919, + 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591, + 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, + 156437, 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, + 968897, 1162687, 1395263, 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, + 4999559, 5999471, 7199369 + }; + + private static bool IsPrime(int ai_Number) + { + if ((ai_Number & 1) == 0) + return (ai_Number == 2); + + int li_Max = (int)Math.Sqrt(ai_Number); + for (int li_Div=3; li_Div < li_Max; li_Div+=2) + { + if ((ai_Number % li_Div) == 0) + return false; + } + return true; + } + + private static int FindPrimeGreater(int ai_Min) + { + if (ai_Min < 0) + throw new ArgumentException("k_HashTable capacity overflow."); + + // do binary search lookup in primes array + int li_Pos = Array.BinarySearch(mk_Primes, ai_Min); + if (li_Pos >= 0) + return mk_Primes[li_Pos]; + + li_Pos = ~li_Pos; + if (li_Pos < mk_Primes.Length) + return mk_Primes[li_Pos]; + + // ai_Min is greater than highest number in mk_Primes + for (int i = (ai_Min|1); i <= Int32.MaxValue; i+=2) + { + if (IsPrime(i)) + return i; + } + return ai_Min; + } + + #endregion + + #region Bucket Structure + + private struct r_Bucket + { + public object mk_Key; + public object mk_Value; + public int mi_HashCode; // MSB (sign bit) indicates a collision. + } + + #endregion + + #region k_BucketIterator Implementation + + private class k_BucketIterator : k_Iterator + { + private readonly k_HashTable mk_Table; + private int mi_Index; + + public k_BucketIterator(k_HashTable ak_Table, int ai_Index) + { + mk_Table = ak_Table; + mi_Index = -1; + if (ai_Index >= 0) + mi_Index = FindNext(ai_Index-1); + } + + public override object Current + { + get + { + if (mi_Index < 0 || mk_Table.mk_Buckets[mi_Index].mk_Key == null) + throw new k_InvalidPositionException(); + + r_Bucket lr_Bucket = mk_Table.mk_Buckets[mi_Index]; + return new DictionaryEntry(lr_Bucket.mk_Key, lr_Bucket.mk_Value); + } + set + { + if (mi_Index < 0 || mk_Table.mk_Buckets[mi_Index].mk_Key == null) + throw new k_InvalidPositionException(); + + DictionaryEntry lr_Entry = (DictionaryEntry)value; + r_Bucket lr_Bucket = mk_Table.mk_Buckets[mi_Index]; + if (mk_Table.mk_Comparer.Compare(lr_Entry.Key, lr_Bucket.mk_Key) != 0) + throw new ArgumentException("Key values must not be changed."); + mk_Table.mk_Buckets[mi_Index].mk_Value = lr_Entry.Value; + } + } + + public override void Move(int ai_Count) + { + int li_NewIndex = mi_Index; + + if (ai_Count > 0) + { + while (ai_Count-- > 0) + { + if (li_NewIndex < 0) + throw new InvalidOperationException("Tried to moved beyond end element."); + + li_NewIndex = FindNext(li_NewIndex); + } + } + else + { + while (ai_Count++ < 0) + { + if (li_NewIndex < 0) + li_NewIndex = FindPrev(mk_Table.mk_Buckets.Length); + else + li_NewIndex = FindPrev(li_NewIndex); + + if (li_NewIndex < 0) + throw new InvalidOperationException("Tried to move before first element."); + } + } + + mi_Index = li_NewIndex; + } + + public override int Distance(k_Iterator ak_Iter) + { + k_BucketIterator lk_Iter = ak_Iter as k_BucketIterator; + if (lk_Iter == null || !object.ReferenceEquals(lk_Iter.Collection, this.Collection)) + throw new ArgumentException("Cannot determine distance of iterators belonging to different collections."); + + k_Iterator lk_End = mk_Table.End; + + int li_IndexDiff; + if (this != lk_End && ak_Iter != lk_End) + li_IndexDiff = mi_Index - lk_Iter.mi_Index; + else + li_IndexDiff = (this == lk_End) ? 1 : -1; // 1 is also fine when both are End + + if (li_IndexDiff < 0) + { + int li_Diff = 0; + k_Iterator lk_Bck = this.Clone(); + for (; lk_Bck != ak_Iter && lk_Bck != lk_End; lk_Bck.Next()) + --li_Diff; + + if (lk_Bck == ak_Iter) + return li_Diff; + } + else + { + int li_Diff = 0; + k_Iterator lk_Fwd = ak_Iter.Clone(); + for (; lk_Fwd != this && lk_Fwd != lk_End; lk_Fwd.Next()) + ++li_Diff; + + if (lk_Fwd == this) + return li_Diff; + } + + throw new Exception("Inconsistent state. Concurrency?"); + } + + public override object Collection + { + get { return mk_Table; } + } + + public override bool Equals(object ak_Obj) + { + k_BucketIterator lk_Iter = ak_Obj as k_BucketIterator; + if (lk_Iter == null) + return false; + + return (mi_Index == lk_Iter.mi_Index && object.ReferenceEquals(mk_Table, lk_Iter.mk_Table)); + } + + public override int GetHashCode() + { + return mk_Table.GetHashCode() ^ mi_Index; + } + + public override k_Iterator Clone() + { + return new k_BucketIterator(mk_Table, mi_Index); + } + + private int FindPrev(int ai_Index) + { + --ai_Index; + r_Bucket[] lk_Buckets = mk_Table.mk_Buckets; + while (ai_Index >= 0 && lk_Buckets[ai_Index].mk_Key == null) + --ai_Index; + if (ai_Index < -1) + return -1; + return ai_Index; + } + + private int FindNext(int ai_Index) + { + ++ai_Index; + r_Bucket[] lk_Buckets = mk_Table.mk_Buckets; + while (ai_Index < lk_Buckets.Length && lk_Buckets[ai_Index].mk_Key == null) + ++ai_Index; + + if (ai_Index >= lk_Buckets.Length) + return -1; + return ai_Index; + } + + internal int Index + { + get { return mi_Index; } + } + } + + private class k_PinnedBucketIterator : k_BucketIterator + { + public k_PinnedBucketIterator(k_HashTable ak_Table, int ai_Index) + : base(ak_Table, ai_Index) + { + } + + public override void Move(int ai_Count) + { + throw new k_IteratorPinnedException(); + } + } + + #endregion + + private IHashCodeProvider mk_HashProvider; + private IComparer mk_Comparer; + private double md_LoadFactor; + private int mi_GrowSize; + private r_Bucket[] mk_Buckets; + private int mi_Count; + private readonly k_Iterator mk_End; + + public k_HashTable() + : this(0, 0.72) + { + } + + public k_HashTable(int ai_Capacity, double ad_LoadFactor) + : this(ai_Capacity, ad_LoadFactor, null, null) + { + } + + public k_HashTable(int ai_Capacity, double ad_LoadFactor, IHashCodeProvider ak_HashProvider, IComparer ak_Comparer) + { + if (ad_LoadFactor <= .0 || ad_LoadFactor > 1.0) + throw new ArgumentException("Load factor must be greater than .0 and smaller or equal to 1.0", "ad_LoadFactor"); + md_LoadFactor = ad_LoadFactor; + + double ld_Size = ai_Capacity/ad_LoadFactor; + if (ld_Size > int.MaxValue) + throw new ArgumentException("k_HashTable overflow"); + + int li_TableSize = FindPrimeGreater((int)ld_Size); + mk_Buckets = new r_Bucket[li_TableSize]; + mi_GrowSize = (md_LoadFactor < 1.0) ? (int)(md_LoadFactor * li_TableSize) : li_TableSize-1; + + mk_HashProvider = ak_HashProvider; + mk_Comparer = ak_Comparer; + + mk_End = new k_PinnedBucketIterator(this, -1); + } + + // IContainer Members + public k_Iterator Begin + { + get + { + if (mi_Count == 0) + return mk_End; + return new k_PinnedBucketIterator(this, 0); + } + } + + public k_Iterator End + { + get { return mk_End; } + } + + public bool IsEmpty + { + get { return (mi_Count == 0); } + } + + public k_Iterator Find(object ak_Value) + { + DictionaryEntry lr_Item = (DictionaryEntry)ak_Value; + int li_Index = FindBucket(lr_Item.Key); + if (li_Index < 0 || !object.Equals(mk_Buckets[li_Index].mk_Value, lr_Item.Value)) + return this.End; + return new k_BucketIterator(this, li_Index); + } + + public k_Iterator Erase(k_Iterator ak_Where) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this collection."); + k_Iterator lk_Successor = ak_Where + 1; + EmptyBucket(((k_BucketIterator)ak_Where).Index); + return lk_Successor; + } + + public k_Iterator Erase(k_Iterator ak_First, k_Iterator ak_Last) + { + if (ak_First == this.Begin && ak_Last == this.End) + { + Clear(); + return ak_Last.Clone(); + } + + k_Iterator lk_Current = ak_First; + while (lk_Current != ak_Last) + lk_Current = Erase(lk_Current); + return lk_Current; + } + + // IMap Members + public k_Iterator FindKey(object ak_Key) + { + return new k_BucketIterator(this, FindBucket(ak_Key)); + } + + public void Add(DictionaryEntry ar_Item) + { + Add(ar_Item.Key, ar_Item.Value); + } + + public void Insert(k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + for (k_Iterator lk_Iter = ak_SrcBegin.Clone(); lk_Iter != ak_SrcEnd; lk_Iter.Next()) + Add((DictionaryEntry)lk_Iter.Current); + } + + #region IDictionary Members + + public void Add(object ak_Key, object ak_Value) + { + SetValue(ak_Key, ak_Value, true); + } + + public void Clear() + { + if (mi_Count == 0) + return; + + for (int i=0; i < mk_Buckets.Length; ++i) + mk_Buckets[i] = new r_Bucket(); + + mi_Count = 0; + } + + public bool Contains(object ak_Key) + { + return (FindBucket(ak_Key) >= 0); + } + + public void Remove(object ak_Key) + { + EmptyBucket(FindBucket(ak_Key)); + } + + public IDictionaryEnumerator GetEnumerator() + { + return new k_IteratorDictEnumerator(this.Begin, this.End); + } + + public bool IsReadOnly + { + get { return false; } + + } + public bool IsFixedSize + { + get { return false; } + } + + public object this[object ak_Key] + { + get + { + int li_Index = FindBucket(ak_Key); + if (li_Index < 0) + return null; + + return mk_Buckets[li_Index].mk_Value; + } + set + { + SetValue(ak_Key, value, false); + } + } + + public ICollection Keys + { + get + { + int i = 0; + object[] lk_Keys = new object[mi_Count]; + foreach (DictionaryEntry lr_Entry in this) + lk_Keys[i++] = lr_Entry.Key; + return lk_Keys; + } + } + + public ICollection Values + { + get + { + int i=0; + object[] lk_Values = new object[mi_Count]; + foreach (DictionaryEntry lr_Entry in this) + lk_Values[i++] = lr_Entry.Value; + return lk_Values; + } + } + + #endregion + + #region ICollection Members + + public void CopyTo(Array ak_Array, int ai_Index) + { + foreach (DictionaryEntry lr_Entry in this) + ak_Array.SetValue(lr_Entry, ai_Index++); + } + + public int Count + { + get { return mi_Count; } + } + + public bool IsSynchronized + { + get { return false; } + } + + public object SyncRoot + { + get { return this; } + } + + #endregion + + #region IEnumerable Members + + IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return new k_IteratorEnumerator(this.Begin, this.End); + } + + #endregion + + #region ICloneable Members + + public object Clone() + { + k_HashTable lk_Clone = new k_HashTable(this.Count, md_LoadFactor, mk_HashProvider, mk_Comparer); + + int i = mk_Buckets.Length; + while (i-- > 0) + { + object lk_Key = mk_Buckets[i].mk_Key; + if (lk_Key != null) + lk_Clone[lk_Key] = mk_Buckets[i].mk_Value; + } + return lk_Clone; + } + + #endregion + + private void EmptyBucket(int ai_Index) + { + if (ai_Index < 0 || ai_Index >= mk_Buckets.Length) + return; + + if (mk_Buckets[ai_Index].mk_Key == null) + throw new InvalidOperationException("Key was removed earlier."); + + mk_Buckets[ai_Index].mi_HashCode &= unchecked((int)0x80000000); + mk_Buckets[ai_Index].mk_Key = null; + mk_Buckets[ai_Index].mk_Value = null; + --mi_Count; + } + + private int FindBucket(object ak_Key) + { + if (ak_Key == null) + throw new ArgumentException("Key must not be null.", "ak_Key"); + + uint lui_BucketCount = (uint)mk_Buckets.Length; + + uint lui_Increment; + uint lui_HashCode = ComputeHashAndStep(ak_Key, out lui_Increment); + + uint lui_Walker = lui_HashCode % lui_BucketCount; + r_Bucket lr_Bucket; + do + { + int li_Index = (int)lui_Walker; + lr_Bucket = mk_Buckets[li_Index]; + if (lr_Bucket.mk_Key == null && lr_Bucket.mi_HashCode >= 0) + break; // stop on empty non-duplicate + + if ((lr_Bucket.mi_HashCode & 0x7fffffff) == lui_HashCode + && EqualsHelper(lr_Bucket.mk_Key, ak_Key)) + return li_Index; + + lui_Walker += lui_Increment; + lui_Walker %= lui_BucketCount; + } + while (lr_Bucket.mi_HashCode < 0 && lui_Walker != lui_HashCode); + + return -1; // not found + } + + private void SetValue(object ak_Key, object ak_Value, bool ab_Add) + { + if (mi_Count >= mi_GrowSize) + ExpandBucketsArray(); + + uint lui_BucketCount = (uint)mk_Buckets.Length; + + uint lui_Increment; + uint lui_HashCode = ComputeHashAndStep(ak_Key, out lui_Increment); + + r_Bucket lr_Bucket; + int li_Free = -1; + uint lui_Walker = lui_HashCode % lui_BucketCount; + do + { + int li_Index = (int)lui_Walker; + lr_Bucket = mk_Buckets[li_Index]; + if (li_Free < 0 && lr_Bucket.mk_Key == null && lr_Bucket.mi_HashCode < 0) + li_Free = li_Index; + + if (lr_Bucket.mk_Key == null && (lr_Bucket.mi_HashCode & unchecked(0x80000000)) == 0) + { + if (li_Free >= 0) + li_Index = li_Free; + mk_Buckets[li_Index].mk_Key = ak_Key; + mk_Buckets[li_Index].mk_Value = ak_Value; + mk_Buckets[li_Index].mi_HashCode |= (int)lui_HashCode; + ++mi_Count; + return; + } + + if ((lr_Bucket.mi_HashCode & 0x7fffffff) == lui_HashCode + && EqualsHelper(lr_Bucket.mk_Key, ak_Key)) + { + if (ab_Add) + throw new ArgumentException("duplicate key"); + mk_Buckets[li_Index].mk_Value = ak_Value; + return; + } + + // mark all as dupes as long as we have not found a free bucket + if (li_Free == -1) + mk_Buckets[li_Index].mi_HashCode |= unchecked((int)0x80000000); + + lui_Walker += lui_Increment; + lui_Walker %= lui_BucketCount; + } + while (lui_Walker != lui_HashCode); + + if (li_Free == -1) + throw new InvalidOperationException("Corrupted hash table. Insert failed."); + + mk_Buckets[li_Free].mk_Key = ak_Key; + mk_Buckets[li_Free].mk_Value = ak_Value; + mk_Buckets[li_Free].mi_HashCode |= (int)lui_HashCode; + ++mi_Count; + } + + private static void InternalExpandInsert(r_Bucket[] ak_Buckets, r_Bucket ar_Bucket) + { + ar_Bucket.mi_HashCode &= 0x7fffffff; + uint lui_BucketCount = (uint)ak_Buckets.Length; + uint lui_Increment = (uint)(1 + ((((uint)ar_Bucket.mi_HashCode >> 5) + 1) % (lui_BucketCount - 1))); + + uint lui_Walker = (uint)ar_Bucket.mi_HashCode % lui_BucketCount; + for (;;) + { + int li_Index = (int)lui_Walker; + if (ak_Buckets[li_Index].mk_Key == null) + { + ak_Buckets[li_Index] = ar_Bucket; + return; + } + + // since current bucket is occupied mark it as duplicate + ak_Buckets[li_Index].mi_HashCode |= unchecked((int)0x80000000); + + lui_Walker += lui_Increment; + lui_Walker %= lui_BucketCount; + } + } + + private void ExpandBucketsArray() + { + int li_NewSize = FindPrimeGreater(mk_Buckets.Length * 2); + + r_Bucket[] lk_Buckets = new r_Bucket[li_NewSize]; + foreach (r_Bucket lr_Bucket in mk_Buckets) + { + if (lr_Bucket.mk_Key == null) + continue; + InternalExpandInsert(lk_Buckets, lr_Bucket); + } + + mk_Buckets = lk_Buckets; + mi_GrowSize = (md_LoadFactor < 1.0) ? (int)(md_LoadFactor * li_NewSize) : li_NewSize-1; + } + + private uint ComputeHashAndStep(object ak_Key, out uint aui_Increment) + { + // mask the sign bit (our collision indicator) + uint lui_HashCode = (uint)GetHashHelper(ak_Key) & 0x7fffffff; + // calc increment value relatively prime to mk_Buckets.Length + aui_Increment = (uint)(1 + (((lui_HashCode >> 5) + 1) % ((uint)mk_Buckets.Length - 1))); + return lui_HashCode; + } + + private int GetHashHelper(object ak_Key) + { + if (mk_HashProvider != null) + return mk_HashProvider.GetHashCode(ak_Key); + return ak_Key.GetHashCode(); + } + + private bool EqualsHelper(object ak_ObjA, object ak_ObjB) + { + if (mk_Comparer != null) + return (mk_Comparer.Compare(ak_ObjA, ak_ObjB) == 0); + return Object.Equals(ak_ObjA, ak_ObjB); + } + } +} diff --git a/iTechSharp/System/util/collections/Iterator.cs b/iTechSharp/System/util/collections/Iterator.cs new file mode 100644 index 0000000..aa2e7f1 --- /dev/null +++ b/iTechSharp/System/util/collections/Iterator.cs @@ -0,0 +1,323 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + public abstract class k_Iterator : IComparable, ICloneable + { + public static k_Iterator operator ++(k_Iterator ak_Iter) + { + return ak_Iter + 1; + } + + public static k_Iterator operator --(k_Iterator ak_Iter) + { + return ak_Iter - 1; + } + + public static k_Iterator operator +(k_Iterator ak_Iter, int ai_Distance) + { + k_Iterator lk_Clone = ak_Iter.Clone(); + lk_Clone.Move(ai_Distance); + return lk_Clone; + } + + public static k_Iterator operator -(k_Iterator ak_Iter, int ai_Distance) + { + k_Iterator lk_Clone = ak_Iter.Clone(); + lk_Clone.Move(-ai_Distance); + return lk_Clone; + } + + public static int operator -(k_Iterator ak_Left, k_Iterator ak_Right) + { + return ak_Left.Distance(ak_Right); + } + + public static bool operator ==(k_Iterator ak_Left, k_Iterator ak_Right) + { + return object.Equals(ak_Left, ak_Right); + } + + public static bool operator !=(k_Iterator ak_Left, k_Iterator ak_Right) + { + return !object.Equals(ak_Left, ak_Right); + } + + public override bool Equals(object ak_Obj) + { + return base.Equals(ak_Obj); // implemented to avoid warning + } + + public override int GetHashCode() + { + return base.GetHashCode(); // implemented to avoid warning + } + + public int CompareTo(object ak_Obj) + { + k_Iterator lk_Iter = ak_Obj as k_Iterator; + if (lk_Iter == null || !object.ReferenceEquals(lk_Iter.Collection, this.Collection)) + throw new ArgumentException("Cannot compare iterators of different origin."); + + return Distance(lk_Iter); + } + + object ICloneable.Clone() + { + return this.Clone(); + } + + public void Next() + { + Move(1); + } + + public void Prev() + { + Move(-1); + } + + public abstract object Current { get; set; } + public abstract object Collection { get; } + public abstract k_Iterator Clone(); + + public abstract void Move(int ai_Count); + public abstract int Distance(k_Iterator ak_Iter); + } + + public class k_IteratorEnumerator : IEnumerator + { + protected k_Iterator mk_Current; + protected k_Iterator mk_Begin, mk_End; + protected bool mb_Fresh; + + public k_IteratorEnumerator(k_Iterator ak_Begin, k_Iterator ak_End) + { + mk_Begin = ak_Begin; + mk_End = ak_End; + mb_Fresh = true; + } + + #region IEnumerator Members + + public bool MoveNext() + { + if (mb_Fresh) + { + mk_Current = mk_Begin.Clone(); + mb_Fresh = false; + } + else if (mk_Current != mk_End) + mk_Current.Next(); + + return (mk_Current != mk_End); + } + + public void Reset() + { + mb_Fresh = true; + mk_Current = null; + } + + public object Current + { + get + { + if (mb_Fresh || mk_Current == mk_End) + throw new InvalidOperationException("The enumerator is positioned before the first element of the collection or after the last element."); + return mk_Current.Current; + } + } + + #endregion + } + + public class k_IteratorDictEnumerator : k_IteratorEnumerator, IDictionaryEnumerator + { + public k_IteratorDictEnumerator(k_Iterator ak_Begin, k_Iterator ak_End) + : base(ak_Begin, ak_End) + { + } + + #region IDictionaryEnumerator Members + + public object Key + { + get { return this.Entry.Key; } + } + + public object Value + { + get { return this.Entry.Value; } + } + + public DictionaryEntry Entry + { + get { return (DictionaryEntry)this.Current; } + } + + #endregion + } + + public class k_IListIterator : k_Iterator + { + private readonly IList mk_List; + private int mi_Index; + + public static k_IListIterator CreateBegin(IList ak_List) + { + return new k_PinnedIListIterator(ak_List, 0); + } + + public static k_IListIterator CreateEnd(IList ak_List) + { + return new k_PinnedIListIterator(ak_List, ak_List.Count); + } + + public k_IListIterator(IList ak_List, int ai_Index) + { + mk_List = ak_List; + mi_Index = ai_Index; + } + + public override void Move(int ai_Count) + { + int li_Index = mi_Index + ai_Count; + + if (li_Index < 0) + throw new InvalidOperationException("Tried to move before first element."); + else if (li_Index > mk_List.Count) + throw new InvalidOperationException("Tried to moved beyond end element."); + + mi_Index = li_Index; + } + + public override int Distance(k_Iterator ak_Iter) + { + return mi_Index - ((k_IListIterator)ak_Iter).mi_Index; + } + + public override object Collection + { + get { return mk_List; } + } + + public override object Current + { + get + { + if (mi_Index < 0 || mi_Index >= mk_List.Count) + throw new k_InvalidPositionException(); + return mk_List[mi_Index]; + } + set + { + if (mi_Index < 0 || mi_Index >= mk_List.Count) + throw new k_InvalidPositionException(); + mk_List[mi_Index] = value; + } + } + + public override bool Equals(object ak_Obj) + { + k_IListIterator lk_Iter = ak_Obj as k_IListIterator; + if (lk_Iter == null) + return false; + return (mi_Index == lk_Iter.mi_Index) && object.ReferenceEquals(this.Collection, lk_Iter.Collection); + } + + public override int GetHashCode() + { + return mk_List.GetHashCode() ^ mi_Index; + } + + public override k_Iterator Clone() + { + return new k_IListIterator(mk_List, mi_Index); + } + + internal int Index + { + get { return mi_Index; } + } + } + + internal class k_PinnedIListIterator : k_IListIterator + { + public k_PinnedIListIterator(IList ak_List, int ai_Index) + : base(ak_List, ai_Index) + { + } + + public override void Move(int ai_Count) + { + throw new k_IteratorPinnedException(); + } + } + + public class k_CollectionOnIterators : ICollection + { + private k_Iterator mk_Begin, mk_End; + private int mi_Count; + + public k_CollectionOnIterators(k_Iterator ak_Begin, k_Iterator ak_End) + { + mk_Begin = ak_Begin; + mk_End = ak_End; + mi_Count = mk_End - mk_Begin; + } + + #region ICollection Members + + public int Count + { + get { return mi_Count; } + } + + public bool IsSynchronized + { + get { return false; } + } + + public object SyncRoot + { + get { return mk_Begin.Collection; } + } + + public void CopyTo(Array ak_Array, int ai_Index) + { + foreach (object lk_Obj in this) + ak_Array.SetValue(lk_Obj, ai_Index++); + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return new k_IteratorEnumerator(mk_Begin, mk_End); + } + + #endregion + } + + [Serializable] + public class k_IteratorPinnedException : InvalidOperationException + { + public k_IteratorPinnedException() + : base("Cannot move pinned iterator. Use Clone() to create a movable copy.") + { + } + } + + [Serializable] + public class k_InvalidPositionException : InvalidOperationException + { + public k_InvalidPositionException() + : base("Iterator positioned on End or invalid element.") + { + } + } +} diff --git a/iTechSharp/System/util/collections/List.cs b/iTechSharp/System/util/collections/List.cs new file mode 100644 index 0000000..53b15ee --- /dev/null +++ b/iTechSharp/System/util/collections/List.cs @@ -0,0 +1,537 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// A doubly linked list + /// + public class k_List : ISequence + { + #region k_Node Implementation + + private class k_Node + { + private object mk_Value; + public k_Node mk_Prev, mk_Next; + + public k_Node(object ak_Value) + { + mk_Value = ak_Value; + } + + public object Value + { + get { return mk_Value; } + set { mk_Value = value; } + } + } + + #endregion + + #region k_NodeIterator Implementation + + private class k_NodeIterator : k_Iterator, ICloneable + { + private readonly k_List mk_List; + private k_Node mk_Current; + + public k_NodeIterator(k_List ak_List, k_Node ak_Node) + { + mk_List = ak_List; + mk_Current = ak_Node; + } + + public override object Current + { + get + { + if (mk_Current == null) + throw new k_InvalidPositionException(); + return mk_Current.Value; + } + set + { + if (mk_Current == null) + throw new k_InvalidPositionException(); + mk_Current.Value = value; + } + } + + public override object Collection + { + get { return mk_List; } + } + + public override void Move(int ai_Count) + { + k_Node lk_NewPos = mk_Current; + + int li_Count = ai_Count; + if (li_Count > 0) + { + while (li_Count-- > 0) + { + if (lk_NewPos == null) + throw new InvalidOperationException("Tried to moved beyond end element."); + + lk_NewPos = lk_NewPos.mk_Next; + } + } + else + { + while (li_Count++ < 0) + { + if (lk_NewPos == null) + lk_NewPos = mk_List.mk_Tail; + else + lk_NewPos = lk_NewPos.mk_Prev; + + if (lk_NewPos == null) + throw new InvalidOperationException("Tried to move before first element."); + } + } + +#if (DEBUG) + if (ai_Count != 0 && object.ReferenceEquals(mk_Current, lk_NewPos)) + throw new IndexOutOfRangeException("Iterator is positioned on invalid node."); +#endif + + mk_Current = lk_NewPos; + } + + public override int Distance(k_Iterator ak_Iter) + { + k_NodeIterator lk_Iter = (k_NodeIterator)ak_Iter; + + if (!this.IsValid || !lk_Iter.IsValid) + throw new ArgumentException("Iterator is invalid."); + + int li_Diff = 0; + k_Iterator lk_End = mk_List.End; + k_Iterator lk_Fwd = lk_Iter.Clone(); + for (; lk_Fwd != this && lk_Fwd != lk_End; lk_Fwd.Next()) + ++li_Diff; + + if (lk_Fwd == this) + return li_Diff; + + li_Diff = 0; + k_Iterator lk_Bck = this.Clone(); + for (; lk_Bck != lk_Iter && lk_Bck != lk_End; lk_Bck.Next()) + --li_Diff; + + if (lk_Bck == lk_Iter) + return li_Diff; + + throw new Exception("Inconsistent state. Concurrency?"); + } + + public override bool Equals(object ak_Obj) + { + k_NodeIterator lk_Iter = ak_Obj as k_NodeIterator; + if (lk_Iter == null) + return false; + return object.ReferenceEquals(mk_Current, lk_Iter.mk_Current); + } + + public override int GetHashCode() + { + if (mk_Current == null) + return mk_List.GetHashCode(); + return mk_Current.GetHashCode(); + } + + public override k_Iterator Clone() + { + return new k_NodeIterator(mk_List, mk_Current); + } + + internal k_Node Node + { + get { return mk_Current; } + } + + internal bool IsValid + { + get { return (mk_Current == null || (!object.ReferenceEquals(mk_Current.mk_Next, mk_Current) && !object.ReferenceEquals(mk_Current.mk_Prev, mk_Current))); } + } + } + + private class k_PinnedNodeIterator : k_NodeIterator + { + public k_PinnedNodeIterator(k_List ak_List, k_Node ak_Node) + : base(ak_List, ak_Node) + { + } + + public override void Move(int ai_Count) + { + throw new k_IteratorPinnedException(); + } + } + + #endregion + + private int mi_Count; + private k_Node mk_Head, mk_Tail; + private k_Iterator mk_Begin, mk_End; + + public k_List() + { + mk_End = new k_PinnedNodeIterator(this, null); + mk_Begin = mk_End; + } + + // IContainer Members + public k_Iterator Begin + { + get + { + if (mi_Count == 0) + return mk_End; + if (mk_Begin == null) + mk_Begin = new k_PinnedNodeIterator(this, mk_Head); + return mk_Begin; + } + } + + public k_Iterator End + { + get { return mk_End; } + } + + public bool IsEmpty + { + get { return (mi_Count == 0); } + } + + public k_Iterator Find(object ak_Value) + { + return k_Algorithm.Find(this.Begin, this.End, ak_Value); + } + + public k_Iterator Erase(k_Iterator ak_Where) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this list."); + if (ak_Where == this.End) + return this.End; + return Erase(ak_Where, ak_Where + 1); + } + + public k_Iterator Erase(k_Iterator ak_First, k_Iterator ak_Last) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_First.Collection) && object.ReferenceEquals(this, ak_Last.Collection), "Iterators do not belong to this collection."); + int li_Distance = ak_Last - ak_First; + if (li_Distance == 0) + return ak_Last; + + k_Node lk_First = ((k_NodeIterator)ak_First).Node; + k_Node lk_Prev = lk_First.mk_Prev; + k_Node lk_Next = (ak_Last != this.End) ? ((k_NodeIterator)ak_Last).Node : null; + + if (lk_Prev != null) + lk_Prev.mk_Next = lk_Next; + else + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(mk_Head, lk_First), "Inconsistent list state"); + mk_Head = lk_Next; + mk_Begin = null; + } + + if (lk_Next != null) + lk_Next.mk_Prev = lk_Prev; + else + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(mk_Tail, ((k_NodeIterator)(ak_Last-1)).Node), "Inconsistent list state"); + mk_Tail = lk_Prev; + } + + mi_Count -= li_Distance; + +#if (DEBUG) + // create invalid nodes linking to itself + k_Node lk_Node = lk_First; + while (lk_Node != null && lk_Node != lk_Next) + { + k_Node lk_Tmp = lk_Node.mk_Next; + lk_Node.mk_Next = lk_Node; + lk_Node.mk_Prev = lk_Node; + + lk_Node = lk_Tmp; + } +#endif + + return ak_Last; + } + + // ISequence Members + public object Front + { + get + { + if (this.IsEmpty) + throw new InvalidOperationException("Empty list"); + return mk_Head.Value; + } + set + { + if (this.IsEmpty) + throw new InvalidOperationException("Empty list"); + mk_Head.Value = value; + } + } + + public object Back + { + get + { + if (this.IsEmpty) + throw new InvalidOperationException("Empty list"); + return mk_Tail.Value; + } + set + { + if (this.IsEmpty) + throw new InvalidOperationException("Empty list"); + mk_Tail.Value = value; + } + } + + public void PushFront(object ak_Value) + { + Insert(this.Begin, ak_Value); + } + + public void PopFront() + { + Erase(this.Begin); + } + + public void PushBack(object ak_Value) + { + Insert(this.End, ak_Value); + } + + public void PopBack() + { + Erase(this.End-1); + } + + public void Assign(k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + Clear(); + Insert(this.End, ak_SrcBegin, ak_SrcEnd); + } + + public void Assign(object ak_Value, int ai_Count) + { + Clear(); + Insert(this.End, ak_Value, ai_Count); + } + + public void Insert(k_Iterator ak_Where, object ak_Value) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this collection."); + + k_Node lk_New = new k_Node(ak_Value); + PasteNodeRange((k_NodeIterator)ak_Where, lk_New, lk_New); + ++mi_Count; + } + + public void Insert(k_Iterator ak_Where, k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this collection."); + + k_Node lk_Start = new k_Node(null), lk_End = lk_Start; + + int li_Count = 0; + for (k_Iterator lk_Iter = ak_SrcBegin.Clone(); lk_Iter != ak_SrcEnd; lk_Iter.Next(), ++li_Count) + { + k_Node lk_New = new k_Node(lk_Iter.Current); + lk_End.mk_Next = lk_New; + lk_New.mk_Prev = lk_End; + lk_End = lk_New; + } + + if (li_Count > 0) + { + PasteNodeRange((k_NodeIterator)ak_Where, lk_Start.mk_Next, lk_End); + mi_Count += li_Count; + } + } + + public void Insert(k_Iterator ak_Where, object ak_Value, int ai_Count) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this collection."); + + k_Node lk_Start = new k_Node(null), lk_End = lk_Start; + + for (int i=0; i 0) + { + PasteNodeRange((k_NodeIterator)ak_Where, lk_Start.mk_Next, lk_End); + mi_Count += ai_Count; + } + } + + #region IList Members + + public int Add(object ak_Value) + { + Insert(this.End, ak_Value); + return mi_Count; + } + + public void Clear() + { + mk_Head = mk_Tail = null; + mk_Begin = mk_End; + mi_Count = 0; + } + + public bool Contains(object ak_Value) + { + return (this.Find(ak_Value) != this.End); + } + + public int IndexOf(object ak_Value) + { + int li_Index = 0; + foreach (object lk_Val in this) + { + if (object.Equals(lk_Val, ak_Value)) + return li_Index; + ++li_Index; + } + return -1; + } + + void IList.Insert(int ai_Index, object ak_Value) + { + this.Insert(this.Begin + ai_Index, ak_Value); + } + + void IList.Remove(object ak_Value) + { + k_NodeIterator lk_Found = (k_NodeIterator)this.Find(ak_Value); + if (lk_Found != this.End) + Erase(lk_Found); + } + + public void RemoveAt(int ai_Index) + { + Erase(this.Begin + ai_Index); + } + + public bool IsFixedSize + { + get { return false; } + } + + bool IList.IsReadOnly + { + get { return false; } + } + + public object this[int index] + { + get + { + k_Iterator lk_Iter = this.Begin + index; + return lk_Iter.Current; + } + set + { + k_Iterator lk_Iter = this.Begin + index; + lk_Iter.Current = value; + } + } + + #endregion + + #region ICollection Members + + public void CopyTo(Array ak_Array, int ai_Index) + { + foreach (object lk_Obj in this) + ak_Array.SetValue(lk_Obj, ai_Index++); + } + + public int Count + { + get { return mi_Count; } + } + + public bool IsSynchronized + { + get { return false; } + } + + public object SyncRoot + { + get { return this; } + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return new k_IteratorEnumerator(this.Begin, this.End); + } + + #endregion + + #region ICloneable Members + + public object Clone() + { + k_List lk_Clone = new k_List(); + for (k_Iterator lk_Iter = this.Begin.Clone(); lk_Iter != this.End; lk_Iter.Next()) + lk_Clone.Add(lk_Iter.Current); + return lk_Clone; + } + + #endregion + + private void PasteNodeRange(k_NodeIterator ak_Where, k_Node ak_First, k_Node ak_Last) + { + if (ak_Where != this.End) + { + k_Node lk_Next = ak_Where.Node; + k_Node lk_Prev = lk_Next.mk_Prev; + + ak_Last.mk_Next = lk_Next; + ak_First.mk_Prev = lk_Prev; + if (lk_Next != null) + lk_Next.mk_Prev = ak_Last; + if (lk_Prev != null) + lk_Prev.mk_Next = ak_First; + } + else + { + if (mk_Tail != null) + { + mk_Tail.mk_Next = ak_First; + ak_First.mk_Prev = mk_Tail; + } + mk_Tail = ak_Last; + } + + if (ak_Where == this.Begin) + { + mk_Head = ak_First; + mk_Begin = null; // recalc on next get + } + } + } +} diff --git a/iTechSharp/System/util/collections/Queue.cs b/iTechSharp/System/util/collections/Queue.cs new file mode 100644 index 0000000..f80d116 --- /dev/null +++ b/iTechSharp/System/util/collections/Queue.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// k_Queue is a first-in, first-out (FIFO) data structure. + /// It hides functionality of the underlying container (e.g. k_List, k_Deque) + /// and provides a a basic queue class. + /// + public class k_Queue : ICollection + { + private ISequence mk_Container; + + public k_Queue() + : this(typeof(k_Deque)) + { + } + + public k_Queue(Type ak_ContainerType) + { + mk_Container = Activator.CreateInstance(ak_ContainerType) as ISequence; + if (mk_Container == null) + throw new ArgumentException("Container type must implement ISequence.", "ak_ContainerType"); + } + + public k_Iterator Begin + { + get { return mk_Container.Begin; } + } + + public k_Iterator End + { + get { return mk_Container.End; } + } + + public object Front + { + get { return mk_Container.Front; } + } + + public object Back + { + get { return mk_Container.Back; } + } + + public bool IsEmpty + { + get { return mk_Container.IsEmpty; } + } + + public k_Iterator Erase(k_Iterator ak_Where) + { + return mk_Container.Erase(ak_Where); + } + + public void Push(object ak_Value) + { + mk_Container.PushBack(ak_Value); + } + + public object Pop() + { + object lk_Obj = mk_Container.Front; + mk_Container.PopFront(); + return lk_Obj; + } + + public IContainer UnderlyingContainer + { + get { return mk_Container; } + } + + #region ICollection Members + + public void CopyTo(Array ak_Array, int ai_Index) + { + foreach (object lk_Obj in this) + ak_Array.SetValue(lk_Obj, ai_Index++); + } + + public int Count + { + get { return mk_Container.Count; } + } + + public bool IsSynchronized + { + get { return false; } + } + + public object SyncRoot + { + get { return this; } + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return new k_IteratorEnumerator(mk_Container.Begin, mk_Container.End); + } + + #endregion + } +} diff --git a/iTechSharp/System/util/collections/SkipList.cs b/iTechSharp/System/util/collections/SkipList.cs new file mode 100644 index 0000000..a04784c --- /dev/null +++ b/iTechSharp/System/util/collections/SkipList.cs @@ -0,0 +1,699 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// A Skip List + /// + public class k_SkipList : ISortedMap + { + #region k_Node Implementation + + private class k_Node + { + private object mk_Key; + private object mk_Value; + + private k_Node[] mk_Next; + + public k_Node(object ak_Key, object ak_Value, int ai_Height) + { + mk_Next = new k_Node[ai_Height]; + mk_Key = ak_Key; + mk_Value = ak_Value; + } + + public object Key + { + get { return mk_Key; } + } + + public object Value + { + get { return mk_Value; } + set { mk_Value = Value; } + } + + public DictionaryEntry Item + { + get { return new DictionaryEntry(mk_Key, mk_Value); } + } + + public k_Node[] Next + { + get { return mk_Next; } + } + + public int Height + { + get { return mk_Next.Length; } + } + } + + #endregion + + #region k_NodeIterator Implementation + + private class k_NodeIterator : k_Iterator + { + private readonly k_SkipList mk_List; + private k_Node mk_Current; + + public k_NodeIterator(k_SkipList ak_List, k_Node ak_Node) + { + mk_List = ak_List; + mk_Current = ak_Node; + } + + public override object Current + { + get + { + if (mk_Current == null) + throw new k_InvalidPositionException(); + return mk_Current.Item; + } + set + { + DictionaryEntry lr_Entry = (DictionaryEntry)value; + if (mk_List.mk_Comparer.Compare(lr_Entry.Key, mk_Current.Key) != 0) + throw new ArgumentException("Key values must not be changed."); + mk_Current.Value = lr_Entry.Value; + } + } + + public override object Collection + { + get { return mk_List; } + } + + public override void Move(int ai_Count) + { + k_Node lk_NewPos = mk_Current; + + if (ai_Count > 0) + { + while (ai_Count-- > 0) + { + if (lk_NewPos == null) + throw new InvalidOperationException("Tried to moved beyond end element."); + + lk_NewPos = mk_List.Next(lk_NewPos); + } + } + else + { + while (ai_Count++ < 0) + { + if (lk_NewPos == null) + lk_NewPos = mk_List.RightMost(); + else + lk_NewPos = mk_List.Previous(lk_NewPos); + + if (lk_NewPos == null) + throw new InvalidOperationException("Tried to move before first element."); + } + } + + mk_Current = lk_NewPos; + } + + public override int Distance(k_Iterator ak_Iter) + { + k_NodeIterator lk_Iter = (k_NodeIterator)ak_Iter; + k_Iterator lk_End = mk_List.End; + + int li_KeyDiff; + if (this == lk_End || ak_Iter == lk_End) + li_KeyDiff = (this == lk_End && this != ak_Iter) ? 1 : 0; + else + li_KeyDiff = mk_List.mk_Comparer.Compare(mk_Current.Key, lk_Iter.mk_Current.Key); + + if (li_KeyDiff <= 0) + { + int li_Diff = 0; + k_Iterator lk_Bck = this.Clone(); + for (; lk_Bck != lk_Iter && lk_Bck != lk_End; lk_Bck.Next()) + --li_Diff; + + if (lk_Bck == lk_Iter) + return li_Diff; + } + + if (li_KeyDiff >= 0) + { + int li_Diff = 0; + k_Iterator lk_Fwd = lk_Iter.Clone(); + for (; lk_Fwd != this && lk_Fwd != lk_End; lk_Fwd.Next()) + ++li_Diff; + + if (lk_Fwd == this) + return li_Diff; + } + + throw new Exception("Inconsistent state. Concurrency?"); + } + + public override bool Equals(object ak_Obj) + { + k_NodeIterator lk_Iter = ak_Obj as k_NodeIterator; + if (lk_Iter == null) + return false; + return object.ReferenceEquals(mk_Current, lk_Iter.mk_Current); + } + + public override int GetHashCode() + { + if (mk_Current == null) + return mk_List.GetHashCode(); + return mk_Current.GetHashCode(); + } + + public override k_Iterator Clone() + { + return new k_NodeIterator(mk_List, mk_Current); + } + + internal k_Node Node + { + get { return mk_Current; } + } + } + + private class k_PinnedNodeIterator : k_NodeIterator + { + public k_PinnedNodeIterator(k_SkipList ak_List, k_Node ak_Node) + : base(ak_List, ak_Node) + { + } + + public override void Move(int ai_Count) + { + throw new k_IteratorPinnedException(); + } + } + + #endregion + + private static Random mk_Rand = new Random(); + + private IComparer mk_Comparer; + private double md_Prob; + private int mi_MaxLevel; + private int mi_HighestNode; + private k_Node mk_Head; + private int mi_Count; + private k_Iterator mk_End; + + public k_SkipList() + : this(System.Collections.Comparer.Default) + { + } + + public k_SkipList(IComparer ak_Comparer) + : this(ak_Comparer, 1.0/Math.E, 16) + { + } + + public k_SkipList(IComparer ak_Comparer, double ad_Prob, int ai_MaxLevel) + { + if (ad_Prob >= 1.0 || ad_Prob <= 0) + throw new ArgumentException("Invalid probability. Must be (0-1).", "ad_Prob"); + md_Prob = ad_Prob; + mi_MaxLevel = ai_MaxLevel; + mk_Comparer = ak_Comparer; + mk_Head = new k_Node(null, null, ai_MaxLevel); + mk_End = new k_PinnedNodeIterator(this, null); + } + + // IContainer Members + public k_Iterator Begin + { + get + { + if (mi_Count == 0) + return this.End; + return new k_NodeIterator(this, this.LeftMost()); + } + } + + public k_Iterator End + { + get { return mk_End; } + } + + public bool IsEmpty + { + get { return (mi_Count == 0); } + } + + public k_Iterator Find(object ak_Value) + { + DictionaryEntry lr_Item = (DictionaryEntry)ak_Value; + k_NodeIterator lk_Found = (k_NodeIterator)LowerBound(lr_Item.Key); + if (lk_Found != this.End + && mk_Comparer.Compare(lr_Item.Key, lk_Found.Node.Key) == 0 && mk_Comparer.Compare(lr_Item.Value, lk_Found.Node.Value) == 0) + return lk_Found; + return this.End; + } + + public k_Iterator Erase(k_Iterator ak_Where) + { + return Erase(ak_Where, ak_Where+1); + } + + public k_Iterator Erase(k_Iterator ak_First, k_Iterator ak_Last) + { + if (ak_First == ak_Last) + return ak_Last.Clone(); + + int li_Count = ak_Last - ak_First; + + k_Node lk_First = ((k_NodeIterator)ak_First).Node; + k_Node lk_Last = (ak_Last != this.End) ? ((k_NodeIterator)ak_Last).Node : null; + k_Node lk_Node = new k_Node(null, null, mi_HighestNode); + + k_Node lk_Current = mk_Head; + for (int li_Level = mi_HighestNode-1; li_Level >= 0; --li_Level) + { + while (lk_Current.Next[li_Level] != null) + { + if (ComparePos(lk_Current.Next[li_Level], lk_First) >= 0) + break; + lk_Current = lk_Current.Next[li_Level]; + } + lk_Node.Next[li_Level] = lk_Current; + } + + if (lk_Last == null) + { + for (int i=0; i= 0) + break; + lk_Current = lk_Current.Next[i]; + } + lk_Left.Next[i] = lk_Current; + } + } + + mi_Count -= li_Count; + + while (mi_HighestNode > 0 && mk_Head.Next[mi_HighestNode-1] == null) + --mi_HighestNode; + + return ak_Last; + } + + // IMap Members + public k_Iterator FindKey(object ak_Key) + { + k_NodeIterator lk_Found = (k_NodeIterator)LowerBound(ak_Key); + if (lk_Found != this.End && mk_Comparer.Compare(ak_Key, lk_Found.Node.Key) == 0) + return lk_Found; + return this.End; + } + + public void Add(DictionaryEntry ar_Entry) + { + Add(ar_Entry.Key, ar_Entry.Value); + } + + public void Insert(k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + for (k_Iterator lk_Iter = ak_SrcBegin.Clone(); lk_Iter != ak_SrcEnd; lk_Iter.Next()) + Add((DictionaryEntry)lk_Iter.Current); + } + + // ISortedMap Members + public IComparer Comparer + { + get { return mk_Comparer; } + } + + /// + /// Returns an iterator to the first element in a list with a key value + /// that is equal to or greater than that of a specified key. + /// + /// + /// The argument key value to be compared with the sort key of an element + /// from the list being searched. + /// + /// + /// Location of an element in a list that with a key that is equal to + /// or greater than the argument key, or this.End if no match is found for the key. + /// + public k_Iterator LowerBound(object ak_Key) + { + k_Node lk_Found = null; + k_Node lk_Current = mk_Head; + for (int li_Level = mi_HighestNode-1; li_Level >= 0; --li_Level) + { + k_Node lk_Next = lk_Current.Next[li_Level]; + while (lk_Next != null) + { + int li_Diff = mk_Comparer.Compare(lk_Next.Key, ak_Key); + if (li_Diff >= 0) + { + lk_Found = lk_Next; + break; + } + + lk_Current = lk_Next; + lk_Next = lk_Next.Next[li_Level]; + } + } + + return new k_NodeIterator(this, lk_Found); + } + + /// + /// Returns an iterator to the first element in a list with a key value + /// that is greater than that of a specified key. + /// + /// + /// The argument key value to be compared with the sort key of an element + /// from the list being searched. + /// + /// + /// Location of an element in a list that with a key that is greater + /// than the argument key, or this.End if no match is found for the key. + /// + public k_Iterator UpperBound(object ak_Key) + { + k_Node lk_Found = null; + k_Node lk_Current = mk_Head; + for (int li_Level = mi_HighestNode-1; li_Level >= 0; --li_Level) + { + k_Node lk_Next = lk_Current.Next[li_Level]; + while (lk_Next != null) + { + int li_Diff = mk_Comparer.Compare(lk_Next.Key, ak_Key); + if (li_Diff > 0) + { + lk_Found = lk_Next; + break; + } + + lk_Current = lk_Next; + lk_Next = lk_Next.Next[li_Level]; + } + } + + return new k_NodeIterator(this, lk_Found); + } + + #region IDictionary Members + + public void Add(object ak_Key, object ak_Value) + { + k_Node lk_Node = new k_Node(ak_Key, ak_Value, CalcNewNodeHeight()); + if (lk_Node.Height > mi_HighestNode) + mi_HighestNode = lk_Node.Height; + + FindInsertPos(lk_Node); + for (int i=0; i= 0; --li_Level) + { + while (lk_Current.Next[li_Level] != null) + { + int li_Diff = mk_Comparer.Compare(lk_Current.Next[li_Level].Key, ak_Node.Key); + if (li_Diff > 0) + break; + if (li_Diff == 0) + { + k_Node lk_Next = lk_Current; + while (lk_Next != null && !object.ReferenceEquals(lk_Next.Next[0], ak_Node)) + { + if (mk_Comparer.Compare(lk_Next.Key, ak_Node.Key) > 0) + lk_Next = null; + else + lk_Next = lk_Next.Next[0]; + } + if (lk_Next == null) + break; + + return lk_Next; // found previous node during right-scan of nodes with equal key value + } + lk_Current = lk_Current.Next[li_Level]; + } + } + if (object.ReferenceEquals(mk_Head, lk_Current)) + return null; + return lk_Current; + } + + private k_Node Next(k_Node ak_Node) + { + return ak_Node.Next[0]; + } + + /// + /// Return leftmost node in list. + /// + /// Found node + private k_Node LeftMost() + { + return mk_Head.Next[0]; + } + + /// + /// Return rightmost node in list. + /// + /// Found node + private k_Node RightMost() + { + k_Node lk_Current = mk_Head.Next[mi_HighestNode-1]; + for (int li_Level = mi_HighestNode-1; li_Level >= 0; --li_Level) + { + while (lk_Current.Next[li_Level] != null) + lk_Current = lk_Current.Next[li_Level]; + } + return lk_Current; + } + + private void FindInsertPos(k_Node ak_Node) + { + k_Node lk_Current = mk_Head; + for (int li_Level = mi_HighestNode-1; li_Level >= 0; --li_Level) + { + while (lk_Current.Next[li_Level] != null && mk_Comparer.Compare(lk_Current.Next[li_Level].Key, ak_Node.Key) < 0) + lk_Current = lk_Current.Next[li_Level]; + + if (li_Level < ak_Node.Height) + ak_Node.Next[li_Level] = lk_Current; + } + } + + private int CalcNewNodeHeight() + { + double ld_Rnd = mk_Rand.NextDouble(); + + int li_Level = 1; + for (double ld_Pow = md_Prob; li_Level < mi_MaxLevel; ++li_Level, ld_Pow*=md_Prob) + { + if (ld_Pow < ld_Rnd) + break; + } + + return li_Level; + } + + private int ComparePos(k_Node ak_Left, k_Node ak_Right) + { + if (object.ReferenceEquals(ak_Left, ak_Right)) + return 0; + + int li_Diff = mk_Comparer.Compare(ak_Left.Key, ak_Right.Key); + if (li_Diff != 0) + return li_Diff; + + k_Node lk_Current = ak_Left; + for (;;) + { + if (lk_Current == null || mk_Comparer.Compare(lk_Current.Key, ak_Right.Key) > 0) + return 1; + else if (object.ReferenceEquals(lk_Current, ak_Right)) + return -1; + + lk_Current = lk_Current.Next[0]; + } + } + + private k_Node CloneR(k_Node ak_Node, k_Node ak_NextHigher) + { + k_Node lk_New = new k_Node(ak_Node.Key, ak_Node.Value, ak_Node.Height); + + for (int i=ak_Node.Height-1; i>=0; --i) + { + // simply copy two links with equal target next to each other + if (i < ak_Node.Height-1 && object.ReferenceEquals(ak_Node.Next[i], ak_Node.Next[i+1])) + { + lk_New.Next[i] = lk_New.Next[i+1]; + continue; + } + + k_Node lk_Next = ak_Node.Next[i]; + if (lk_Next != null && lk_Next.Height-1 <= i) + { + k_Node lk_Higher = (i < ak_Node.Height-1) ? ak_Node.Next[i+1] : ak_NextHigher; + lk_New.Next[i] = CloneR(lk_Next, lk_Higher); + } + else + lk_New.Next[i] = ak_NextHigher; + } + return lk_New; + } + } +} diff --git a/iTechSharp/System/util/collections/Stack.cs b/iTechSharp/System/util/collections/Stack.cs new file mode 100644 index 0000000..b378166 --- /dev/null +++ b/iTechSharp/System/util/collections/Stack.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// A push-down stack using an underlying k_Vector. + /// Last in first out (LIFO). + /// + public class k_Stack : ICollection + { + private ISequence mk_Items; // stack container + private int mi_MaxSize; + + public k_Stack() + { + mk_Items = new k_Vector(); + mi_MaxSize = int.MaxValue; + } + + public k_Stack(int ai_Capacity, bool ab_FixedSize) + { + mk_Items = new k_Vector(ai_Capacity); + mi_MaxSize = (ab_FixedSize) ? ai_Capacity : int.MaxValue; + } + + public object Top + { + get { return mk_Items.Back; } + set { mk_Items.Back = value; } + } + + public object this[int ai_Index] + { + get { return (mk_Items.Begin+ai_Index).Current; } + set { (mk_Items.Begin+ai_Index).Current = value; } + } + + public void Push(object ak_Value) + { + if (mk_Items.Count >= mi_MaxSize) + throw new StackOverflowException("Stack overflow"); + + mk_Items.PushBack(ak_Value); + } + + public object Pop() + { + if (mk_Items.Count == 0) + throw new StackOverflowException("Stack underflow"); + + object lk_Obj = mk_Items.Back; + mk_Items.PopBack(); + return lk_Obj; + } + + public bool IsEmpty + { + get { return mk_Items.IsEmpty; } + } + + public void Clear() + { + mk_Items.Clear(); + } + + #region ICollection Members + + public void CopyTo(Array ak_Array, int ai_Index) + { + for (k_Iterator lk_Iter = mk_Items.Begin.Clone(); lk_Iter != mk_Items.End; lk_Iter.Next()) + ak_Array.SetValue(lk_Iter.Current, ai_Index++); + } + + public int Count + { + get { return mk_Items.Count; } + } + + public bool IsSynchronized + { + get { return false; } + } + + public object SyncRoot + { + get { return this; } + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return new k_IteratorEnumerator(mk_Items.Begin, mk_Items.End); + } + + #endregion + } +} diff --git a/iTechSharp/System/util/collections/Tree.cs b/iTechSharp/System/util/collections/Tree.cs new file mode 100644 index 0000000..0d43e82 --- /dev/null +++ b/iTechSharp/System/util/collections/Tree.cs @@ -0,0 +1,830 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// k_Tree is a red-black balanced search tree (BST) implementation. + /// Complexity of find, insert and erase operations is near O(lg n). + /// + public class k_Tree : ISortedMap + { + #region k_Node Implementation + + private class k_Node + { + private object mk_Key; + private object mk_Value; + private bool mb_Red; + public k_Node mk_Left, mk_Right, mk_Parent; // public to simplify fixup & clone (passing by ref) + + public k_Node(object ak_Key, object ak_Value, k_Node ak_Parent) + { + mk_Key = ak_Key; + mk_Value = ak_Value; + mk_Parent = ak_Parent; + mb_Red = true; + } + + public object Key + { + get { return mk_Key; } + } + + public object Value + { + get { return mk_Value; } + set { mk_Value = value; } + } + + public DictionaryEntry Item + { + get { return new DictionaryEntry(mk_Key, mk_Value); } + } + + public bool Red + { + get { return mb_Red; } + set { mb_Red = value; } + } + + public static void SwapItems(k_Node ak_A, k_Node ak_B) + { + object lk_Tmp = ak_A.mk_Key; + ak_A.mk_Key = ak_B.mk_Key; + ak_B.mk_Key = lk_Tmp; + + lk_Tmp = ak_A.mk_Value; + ak_A.mk_Value = ak_B.mk_Value; + ak_B.mk_Value = lk_Tmp; + } + } + + #endregion + + #region k_NodeIterator Implementation + + private class k_NodeIterator : k_Iterator + { + private readonly k_Tree mk_Tree; + private k_Node mk_Current; + + public k_NodeIterator(k_Tree ak_Tree, k_Node ak_Node) + { + mk_Tree = ak_Tree; + mk_Current = ak_Node; + } + + public override object Current + { + get + { + if (mk_Current == null) + throw new k_InvalidPositionException(); + return mk_Current.Item; + } + set + { + DictionaryEntry lr_Entry = (DictionaryEntry)value; + if (mk_Tree.mk_Comparer.Compare(lr_Entry.Key, mk_Current.Key) != 0) + throw new ArgumentException("Key values must not be changed."); + mk_Current.Value = lr_Entry.Value; + } + } + + public override object Collection + { + get { return mk_Tree; } + } + + public override void Move(int ai_Count) + { + k_Node lk_NewPos = mk_Current; + + if (ai_Count > 0) + { + while (ai_Count-- > 0) + { + if (lk_NewPos == null) + throw new InvalidOperationException("Tried to moved beyond end element."); + + lk_NewPos = k_Tree.Next(lk_NewPos); + } + } + else + { + while (ai_Count++ < 0) + { + if (lk_NewPos == null) + lk_NewPos = mk_Tree.mk_Right; + else + lk_NewPos = k_Tree.Previous(lk_NewPos); + + if (lk_NewPos == null) + throw new InvalidOperationException("Tried to move before first element."); + } + } + + mk_Current = lk_NewPos; + } + + public override int Distance(k_Iterator ak_Iter) + { + k_NodeIterator lk_Iter = ak_Iter as k_NodeIterator; + if (lk_Iter == null || !object.ReferenceEquals(lk_Iter.Collection, this.Collection)) + throw new ArgumentException("Cannot determine distance of iterators belonging to different collections."); + + k_Iterator lk_End = mk_Tree.End; + + int li_KeyDiff; + if (this == lk_End || ak_Iter == lk_End) + li_KeyDiff = (this == lk_End && this != ak_Iter) ? 1 : 0; + else + li_KeyDiff = mk_Tree.mk_Comparer.Compare(mk_Current.Key, lk_Iter.mk_Current.Key); + + if (li_KeyDiff <= 0) + { + int li_Diff = 0; + k_Iterator lk_Bck = this.Clone(); + for (; lk_Bck != ak_Iter && lk_Bck != lk_End; lk_Bck.Next()) + --li_Diff; + + if (lk_Bck == ak_Iter) + return li_Diff; + } + + if (li_KeyDiff >= 0) + { + int li_Diff = 0; + k_Iterator lk_Fwd = ak_Iter.Clone(); + for (; lk_Fwd != this && lk_Fwd != lk_End; lk_Fwd.Next()) + ++li_Diff; + + if (lk_Fwd == this) + return li_Diff; + } + + throw new Exception("Inconsistent state. Concurrency?"); + } + + public override bool Equals(object ak_Obj) + { + k_NodeIterator lk_Iter = ak_Obj as k_NodeIterator; + if (lk_Iter == null) + return false; + return object.ReferenceEquals(mk_Current, lk_Iter.mk_Current); + } + + public override int GetHashCode() + { + if (mk_Current == null) + return mk_Tree.GetHashCode(); + return mk_Current.GetHashCode(); + } + + public override k_Iterator Clone() + { + return new k_NodeIterator(mk_Tree, mk_Current); + } + + internal k_Node Node + { + get { return mk_Current; } + } + } + + private class k_PinnedNodeIterator : k_NodeIterator + { + public k_PinnedNodeIterator(k_Tree ak_Tree, k_Node ak_Node) + : base(ak_Tree, ak_Node) + { + } + + public override void Move(int ai_Count) + { + throw new k_IteratorPinnedException(); + } + } + + #endregion + + private k_Node mk_Head, mk_Left, mk_Right; + private k_Iterator mk_End; + private int mi_Count; + private IComparer mk_Comparer; + private bool mb_AllowDuplicateKeys; + + public k_Tree() + : this(false) + { + } + + public k_Tree(bool ab_AllowDuplicateKeys) + : this(ab_AllowDuplicateKeys, System.Collections.Comparer.Default) + { + } + + public k_Tree(bool ab_AllowDuplicateKeys, IComparer ak_Comparer) + { + mb_AllowDuplicateKeys = ab_AllowDuplicateKeys; + mk_Comparer = ak_Comparer; + mk_End = new k_PinnedNodeIterator(this, null); + } + + // IContainer Members + public k_Iterator Begin + { + get + { + if (mi_Count == 0) + return this.End; + return new k_NodeIterator(this, mk_Left); + } + } + + public k_Iterator End + { + get { return mk_End; } + } + + public bool IsEmpty + { + get { return (mi_Count == 0); } + } + + public k_Iterator Find(object ak_Value) + { + DictionaryEntry lr_Item = (DictionaryEntry)ak_Value; + k_Node lk_Found = FindInternal(mk_Head, lr_Item.Key); + if (lk_Found != null && mk_Comparer.Compare(lk_Found.Value, lr_Item.Value) == 0) + return new k_NodeIterator(this, lk_Found); + return this.End; + } + + public k_Iterator Erase(k_Iterator ak_Where) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this tree."); + k_Iterator lk_Successor = ak_Where + 1; + RemoveNode(((k_NodeIterator)ak_Where).Node); + return lk_Successor; + } + + public k_Iterator Erase(k_Iterator ak_First, k_Iterator ak_Last) + { + if (ak_First == this.Begin && ak_Last == this.End) + { + Clear(); + return ak_Last.Clone(); + } + + k_Iterator lk_Current = ak_First; + while (lk_Current != ak_Last) + lk_Current = Erase(lk_Current); + return lk_Current; + } + + // IMap Members + public void Add(DictionaryEntry ar_Item) + { + Add(ar_Item.Key, ar_Item.Value); + } + + public k_Iterator FindKey(object ak_Key) + { + return new k_NodeIterator(this, FindInternal(mk_Head, ak_Key)); + } + + public void Insert(k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + for (k_Iterator lk_Iter = ak_SrcBegin.Clone(); lk_Iter != ak_SrcEnd; lk_Iter.Next()) + Add((DictionaryEntry)lk_Iter.Current); + } + + // ISortedMap Members + public IComparer Comparer + { + get { return mk_Comparer; } + } + + public k_Iterator LowerBound(object ak_Key) + { + k_Node lk_Node = mk_Head; + k_Node lk_Found = null; + while (lk_Node != null) + { + if (mk_Comparer.Compare(lk_Node.Key, ak_Key) < 0) + lk_Node = lk_Node.mk_Right; + else + { + lk_Found = lk_Node; + lk_Node = lk_Node.mk_Left; + } + } + return new k_NodeIterator(this, lk_Found); + } + + public k_Iterator UpperBound(object ak_Key) + { + k_Node lk_Node = mk_Head; + k_Node lk_Found = null; + while (lk_Node != null) + { + if (mk_Comparer.Compare(lk_Node.Key, ak_Key) > 0) + { + lk_Found = lk_Node; + lk_Node = lk_Node.mk_Left; + } + else + lk_Node = lk_Node.mk_Right; + } + return new k_NodeIterator(this, lk_Found); + } + + #region IDictionary Members + + public void Add(object ak_Key, object ak_Value) + { + Insert(ref mk_Head, null, ak_Key, ak_Value, false); + mk_Head.Red = false; + ++mi_Count; + } + + public void Clear() + { + mi_Count = 0; + mk_Head = null; + mk_Left = null; + mk_Right = null; + } + + public bool Contains(object ak_Key) + { + return (FindInternal(mk_Head, ak_Key) != null); + } + + public IDictionaryEnumerator GetEnumerator() + { + return new k_IteratorDictEnumerator(this.Begin, this.End); + } + + public void Remove(object ak_Key) + { + RemoveNode(FindInternal(mk_Head, ak_Key)); + } + + public bool IsFixedSize + { + get { return false; } + } + + public bool IsReadOnly + { + get { return false; } + } + + public object this[object ak_Key] + { + get + { + k_Node lk_Node = FindInternal(mk_Head, ak_Key); + if (lk_Node == null) + return null; + return lk_Node.Value; + } + set + { + k_Node lk_Node = FindInternal(mk_Head, ak_Key); + if (lk_Node == null) + Add(new DictionaryEntry(ak_Key, value)); + else + lk_Node.Value = value; + } + } + + public ICollection Keys + { + get + { + int i=0; + object[] lk_Keys = new object[mi_Count]; + foreach (DictionaryEntry lr_Entry in this) + lk_Keys[i++] = lr_Entry.Key; + return lk_Keys; + } + } + + public ICollection Values + { + get + { + int i=0; + object[] lk_Values = new object[mi_Count]; + foreach (DictionaryEntry lr_Entry in this) + lk_Values[i++] = lr_Entry.Value; + return lk_Values; + } + } + + #endregion + + #region ICollection Members + + public void CopyTo(Array ak_Array, int ai_Index) + { + foreach (DictionaryEntry lr_Entry in this) + ak_Array.SetValue(lr_Entry, ai_Index++); + } + + public int Count + { + get { return mi_Count; } + } + + public bool IsSynchronized + { + get { return false; } + } + + public object SyncRoot + { + get { return this; } + } + + #endregion + + #region IEnumerable Members + + IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return new k_IteratorEnumerator(this.Begin, this.End); + } + + #endregion + + #region ICloneable Members + + public object Clone() + { + k_Tree lk_Clone = new k_Tree(mb_AllowDuplicateKeys, mk_Comparer); + lk_Clone.mi_Count = mi_Count; + CloneRecursive(mk_Head, null, ref lk_Clone.mk_Head); + lk_Clone.mk_Left = k_Tree.LeftMost(lk_Clone.mk_Head); + lk_Clone.mk_Right = k_Tree.RightMost(lk_Clone.mk_Head); + + return lk_Clone; + } + + #endregion + + private void CloneRecursive(k_Node ak_Node, k_Node ak_Parent, ref k_Node ak_Link) + { + if (ak_Node == null) + return; + + ak_Link = new k_Node(ak_Node.Key, ak_Node.Value, ak_Parent); + ak_Link.Red = ak_Node.Red; + + CloneRecursive(ak_Node.mk_Left, ak_Link, ref ak_Link.mk_Left); + CloneRecursive(ak_Node.mk_Right, ak_Link, ref ak_Link.mk_Right); + } + + private bool IsRed(k_Node ak_Node) + { + return (ak_Node != null && ak_Node.Red); + } + + private k_Node FindInternal(k_Node ak_Node, object ak_Key) + { + while (ak_Node != null) + { + int li_Diff = mk_Comparer.Compare(ak_Key, ak_Node.Key); + if (li_Diff == 0) + return ak_Node; + ak_Node = (li_Diff < 0) ? ak_Node.mk_Left : ak_Node.mk_Right; + } + return null; + } + + /// + /// Return leftmost node in subtree. + /// + /// Node where to start search + /// Found node + private static k_Node LeftMost(k_Node ak_Node) + { + if (ak_Node == null) + return null; + while (ak_Node.mk_Left != null) + ak_Node = ak_Node.mk_Left; + return ak_Node; + } + + /// + /// Return rightmost node in subtree. + /// + /// Node where to start search + /// Found node + private static k_Node RightMost(k_Node ak_Node) + { + if (ak_Node == null) + return null; + while (ak_Node.mk_Right != null) + ak_Node = ak_Node.mk_Right; + return ak_Node; + } + + private static k_Node Previous(k_Node ak_Node) // the next smaller + { + if (ak_Node.mk_Left != null) + return RightMost(ak_Node.mk_Left); + + k_Node lk_Parent = ak_Node.mk_Parent; + while (lk_Parent != null && lk_Parent.mk_Left == ak_Node) + { + ak_Node = lk_Parent; + lk_Parent = lk_Parent.mk_Parent; + } + return lk_Parent; + } + + private static k_Node Next(k_Node ak_Node) + { + if (ak_Node.mk_Right != null) + return LeftMost(ak_Node.mk_Right); + + k_Node lk_Parent = ak_Node.mk_Parent; + while (lk_Parent != null && lk_Parent.mk_Right == ak_Node) + { + ak_Node = lk_Parent; + lk_Parent = lk_Parent.mk_Parent; + } + return lk_Parent; + } + + private void RemoveNode(k_Node ak_Node) + { + if (ak_Node == null) + return; + if (ak_Node == mk_Head) + UnlinkNode(ref mk_Head); + else if (ak_Node == ak_Node.mk_Parent.mk_Right) + UnlinkNode(ref ak_Node.mk_Parent.mk_Right); + else + UnlinkNode(ref ak_Node.mk_Parent.mk_Left); + } + + private void UnlinkNode(ref k_Node ak_Node) + { + bool lb_Red = ak_Node.Red; + k_Node lk_Erased = ak_Node; + + k_Node lk_PatchNode = null; + if (ak_Node.mk_Right == null) + lk_PatchNode = ak_Node.mk_Left; + else if (ak_Node.mk_Left == null) + lk_PatchNode = ak_Node.mk_Right; + else + lk_PatchNode = ak_Node; + + k_Node lk_PatchParent = null, lk_FixNode = null; + if (lk_PatchNode == null) + { + lk_PatchParent = ak_Node.mk_Parent; + ak_Node = null; + } + else if (lk_PatchNode != ak_Node) + { + lk_PatchNode.mk_Parent = ak_Node.mk_Parent; + ak_Node = lk_PatchNode; + lk_PatchParent = lk_PatchNode.mk_Parent; + } + else + { + // two subtrees + lk_PatchNode = RightMost(ak_Node.mk_Left); + if (lk_PatchNode.mk_Parent.mk_Right == lk_PatchNode) + lk_PatchNode.mk_Parent.mk_Right = lk_PatchNode.mk_Left; + else + lk_PatchNode.mk_Parent.mk_Left = lk_PatchNode.mk_Left; + + lb_Red = lk_PatchNode.Red; + if (lk_PatchNode.mk_Left != null) + lk_PatchNode.mk_Left.mk_Parent = lk_PatchNode.mk_Parent; + + lk_PatchParent = lk_PatchNode.mk_Parent; + lk_FixNode = lk_PatchNode.mk_Left; + + k_Node.SwapItems(ak_Node, lk_PatchNode); + + // ensure that mk_Left and/or mk_Right are corrected after unlink + lk_Erased = lk_PatchNode; + } + + if (!lb_Red && lk_PatchParent != null) + { + // erased node was black link - rebalance the tree + while (!IsRed(lk_FixNode) && lk_FixNode != mk_Head) + { + if (lk_PatchParent.mk_Left != null || lk_PatchParent.mk_Right != null) + { + if (lk_PatchParent.mk_Left == lk_FixNode) + { + // fixup right subtree + k_Node lk_Node = lk_PatchParent.mk_Right; + + if (IsRed(lk_Node)) + { + lk_Node.Red = false; + lk_PatchParent.Red = true; + RotateLeft(lk_PatchParent); + lk_Node = lk_PatchParent.mk_Right; + } + + if (lk_Node != null) + { + if (!IsRed(lk_Node.mk_Left) && !IsRed(lk_Node.mk_Right)) + lk_Node.Red = true; + else + { + if (!IsRed(lk_Node.mk_Right)) + { + lk_Node.Red = true; + lk_Node.mk_Left.Red = false; + RotateRight(lk_Node); + lk_Node = lk_PatchParent.mk_Right; + } + + lk_Node.Red = lk_PatchParent.Red; + lk_PatchParent.Red = false; + lk_Node.mk_Right.Red = false; + RotateLeft(lk_PatchParent); + break; + } + } + } + else + { + // fixup leftsubtree + k_Node lk_Node = lk_PatchParent.mk_Left; + + if (IsRed(lk_Node)) + { + lk_Node.Red = false; + lk_PatchParent.Red = true; + RotateRight(lk_PatchParent); + lk_Node = lk_PatchParent.mk_Left; + } + + if (lk_Node != null) + { + if (!IsRed(lk_Node.mk_Left) && !IsRed(lk_Node.mk_Right)) + lk_Node.Red = true; + else + { + if (!IsRed(lk_Node.mk_Left)) + { + lk_Node.Red = true; + lk_Node.mk_Right.Red = false; + RotateLeft(lk_Node); + lk_Node = lk_PatchParent.mk_Left; + } + + lk_Node.Red = lk_PatchParent.Red; + lk_PatchParent.Red = false; + lk_Node.mk_Left.Red = false; + RotateRight(lk_PatchParent); + break; + } + } + } + } + lk_FixNode = lk_PatchParent; + lk_PatchParent = lk_PatchParent.mk_Parent; + } + + if (lk_FixNode != null) + lk_FixNode.Red = false; + } + + --mi_Count; + + if (object.ReferenceEquals(lk_Erased, mk_Right)) + mk_Right = k_Tree.RightMost(mk_Head); + if (object.ReferenceEquals(lk_Erased, mk_Left)) + mk_Left = k_Tree.LeftMost(mk_Head); + } + + private void Insert(ref k_Node ak_Node, k_Node ak_Parent, object ak_Key, object ak_Value, bool ab_RightMove) + { + if (ak_Node == null) + { + ak_Node = new k_Node(ak_Key, ak_Value, ak_Parent); + if (object.ReferenceEquals(ak_Parent, mk_Right) && (ak_Parent == null || ab_RightMove)) + mk_Right = ak_Node; + if (object.ReferenceEquals(ak_Parent, mk_Left) && (ak_Parent == null || !ab_RightMove)) + mk_Left = ak_Node; + return; + } + + if (IsRed(ak_Node.mk_Left) && IsRed(ak_Node.mk_Right)) + { + ak_Node.Red = true; + ak_Node.mk_Left.Red = false; + ak_Node.mk_Right.Red = false; + } + + int li_Diff = mk_Comparer.Compare(ak_Key, ak_Node.Key); + if (!mb_AllowDuplicateKeys && li_Diff == 0) + throw new ArgumentException("An element with the same key already exists in the tree."); + + if (li_Diff < 0) + { + Insert(ref ak_Node.mk_Left, ak_Node, ak_Key, ak_Value, false); + if (IsRed(ak_Node) && IsRed(ak_Node.mk_Left) && ab_RightMove) + ak_Node = RotateRight(ak_Node); + if (IsRed(ak_Node.mk_Left) && IsRed(ak_Node.mk_Left.mk_Left)) + { + ak_Node = RotateRight(ak_Node); + ak_Node.Red = false; + ak_Node.mk_Right.Red = true; + } + } + else + { + Insert(ref ak_Node.mk_Right, ak_Node, ak_Key, ak_Value, true); + if (IsRed(ak_Node) && IsRed(ak_Node.mk_Right) && !ab_RightMove) + ak_Node = RotateLeft(ak_Node); + if (IsRed(ak_Node.mk_Right) && IsRed(ak_Node.mk_Right.mk_Right)) + { + ak_Node = RotateLeft(ak_Node); + ak_Node.Red = false; + ak_Node.mk_Left.Red = true; + } + } + } + + /* + A right rotation: ak_Node.Left takes old position of ak_Node. + Makes the old root the right subtree of the new root. + + 5 2 + 2 7 -> 1 5 + 1 3 6 8 3 7 + 6 8 + */ + private k_Node RotateRight(k_Node ak_Node) + { + k_Node lk_Tmp = ak_Node.mk_Left; + + lk_Tmp.mk_Parent = ak_Node.mk_Parent; + ak_Node.mk_Parent = lk_Tmp; + + ak_Node.mk_Left = lk_Tmp.mk_Right; + if (ak_Node.mk_Left != null) + ak_Node.mk_Left.mk_Parent = ak_Node; + lk_Tmp.mk_Right = ak_Node; + + // correct parent + if (lk_Tmp.mk_Parent == null) + mk_Head = lk_Tmp; + else if (lk_Tmp.mk_Parent.mk_Right == ak_Node) + lk_Tmp.mk_Parent.mk_Right = lk_Tmp; + else + lk_Tmp.mk_Parent.mk_Left = lk_Tmp; + + return lk_Tmp; + } + + /* + A left rotation: ak_Node.Right takes old position of ak_Node. + Makes the old root the left subtree of the new root. + + 5 7 + 2 7 -> 5 8 + 1 3 6 8 2 6 + 1 3 + */ + private k_Node RotateLeft(k_Node ak_Node) + { + k_Node lk_Tmp = ak_Node.mk_Right; + + lk_Tmp.mk_Parent = ak_Node.mk_Parent; + ak_Node.mk_Parent = lk_Tmp; + + ak_Node.mk_Right = lk_Tmp.mk_Left; + if (ak_Node.mk_Right != null) + ak_Node.mk_Right.mk_Parent = ak_Node; + lk_Tmp.mk_Left = ak_Node; + + // correct parent + if (lk_Tmp.mk_Parent == null) + mk_Head = lk_Tmp; + else if (lk_Tmp.mk_Parent.mk_Right == ak_Node) + lk_Tmp.mk_Parent.mk_Right = lk_Tmp; + else + lk_Tmp.mk_Parent.mk_Left = lk_Tmp; + + return lk_Tmp; + } + } +} diff --git a/iTechSharp/System/util/collections/Vector.cs b/iTechSharp/System/util/collections/Vector.cs new file mode 100644 index 0000000..0ab80d6 --- /dev/null +++ b/iTechSharp/System/util/collections/Vector.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections; + +namespace System.util.collections +{ + /// + /// One dimensional array of variable size + /// + public class k_Vector : ArrayList, ISequence + { + public k_Vector() + : base() + { + } + + public k_Vector(int ai_Capacity) + : base(ai_Capacity) + { + } + + public k_Vector(ICollection ak_Collection) + : base(ak_Collection) + { + } + + // IContainer Members + public k_Iterator Begin + { + get { return k_IListIterator.CreateBegin(this); } + } + + public k_Iterator End + { + get { return k_IListIterator.CreateEnd(this); } + } + + public bool IsEmpty + { + get { return (this.Count == 0); } + } + + public k_Iterator Find(object ak_Value) + { + int li_Index = this.IndexOf(ak_Value); + if (li_Index < 0) + return this.End; + return new k_IListIterator(this, li_Index); + } + + public k_Iterator Erase(k_Iterator ak_Where) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this collection."); + int li_Index = ((k_IListIterator)ak_Where).Index; + if (li_Index < this.Count) + base.RemoveAt(li_Index); + return new k_IListIterator(this, li_Index); + } + + public k_Iterator Erase(k_Iterator ak_First, k_Iterator ak_Last) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_First.Collection) && object.ReferenceEquals(this, ak_Last.Collection), "Iterators do not belong to this collection."); + int li_FirstIndex = ((k_IListIterator)ak_First).Index; + int li_Count = ak_Last - ak_First; + + base.RemoveRange(li_FirstIndex, li_Count); + + return new k_IListIterator(this, li_FirstIndex); + } + + // ISequence Members + public object Front + { + get { return this.Begin.Current; } + set { this.Begin.Current = value; } + } + + public object Back + { + get { return (this.End-1).Current; } + set { (this.End-1).Current = value; } + } + + public void PushFront(object ak_Value) + { + Insert(this.Begin, ak_Value); + } + + public void PopFront() + { + Erase(this.Begin); + } + + public void PushBack(object ak_Value) + { + Insert(this.End, ak_Value); + } + + public void PopBack() + { + Erase(this.End-1); + } + + public void Assign(k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + Clear(); + Insert(this.End, ak_SrcBegin, ak_SrcEnd); + } + + public void Assign(object ak_Value, int ai_Count) + { + Clear(); + Insert(this.End, ak_Value, ai_Count); + } + + public void Insert(k_Iterator ak_Where, object ak_Value) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this collection."); + this.Insert(((k_IListIterator)ak_Where).Index, ak_Value); + } + + public void Insert(k_Iterator ak_Where, k_Iterator ak_SrcBegin, k_Iterator ak_SrcEnd) + { + //System.Diagnostics.Debug.Assert(object.ReferenceEquals(this, ak_Where.Collection), "Iterator does not belong to this collection."); + InsertRange(((k_IListIterator)ak_Where).Index, new k_CollectionOnIterators(ak_SrcBegin, ak_SrcEnd)); + } + + public void Insert(k_Iterator ak_Where, object ak_Value, int ai_Count) + { + int li_Pos = ((k_IListIterator)ak_Where).Index; + for (int i=0; i>16)&0xffff; + int k; + + while(len > 0) { + k=len=16){ + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + s1+=buf[index++]&0xff; s2+=s1; + k-=16; + } + if(k!=0){ + do{ + s1+=buf[index++]&0xff; s2+=s1; + } + while(--k!=0); + } + s1%=BASE; + s2%=BASE; + } + return (s2<<16)|s1; + } + + } +} \ No newline at end of file diff --git a/iTechSharp/System/util/zlib/Deflate.cs b/iTechSharp/System/util/zlib/Deflate.cs new file mode 100644 index 0000000..09353a8 --- /dev/null +++ b/iTechSharp/System/util/zlib/Deflate.cs @@ -0,0 +1,1639 @@ +using System; +/* + * $Id: Deflate.cs,v 1.1 2006/06/16 10:56:20 psoares33 Exp $ + * +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +namespace System.util.zlib { + + public sealed class Deflate{ + + private const int MAX_MEM_LEVEL=9; + + private const int Z_DEFAULT_COMPRESSION=-1; + + private const int MAX_WBITS=15; // 32K LZ77 window + private const int DEF_MEM_LEVEL=8; + + internal class Config{ + internal int good_length; // reduce lazy search above this match length + internal int max_lazy; // do not perform lazy search above this match length + internal int nice_length; // quit search above this match length + internal int max_chain; + internal int func; + internal Config(int good_length, int max_lazy, + int nice_length, int max_chain, int func){ + this.good_length=good_length; + this.max_lazy=max_lazy; + this.nice_length=nice_length; + this.max_chain=max_chain; + this.func=func; + } + } + + private const int STORED=0; + private const int FAST=1; + private const int SLOW=2; + private static Config[] config_table; + static Deflate(){ + config_table=new Config[10]; + // good lazy nice chain + config_table[0]=new Config(0, 0, 0, 0, STORED); + config_table[1]=new Config(4, 4, 8, 4, FAST); + config_table[2]=new Config(4, 5, 16, 8, FAST); + config_table[3]=new Config(4, 6, 32, 32, FAST); + + config_table[4]=new Config(4, 4, 16, 16, SLOW); + config_table[5]=new Config(8, 16, 32, 32, SLOW); + config_table[6]=new Config(8, 16, 128, 128, SLOW); + config_table[7]=new Config(8, 32, 128, 256, SLOW); + config_table[8]=new Config(32, 128, 258, 1024, SLOW); + config_table[9]=new Config(32, 258, 258, 4096, SLOW); + } + + private static String[] z_errmsg = { + "need dictionary", // Z_NEED_DICT 2 + "stream end", // Z_STREAM_END 1 + "", // Z_OK 0 + "file error", // Z_ERRNO (-1) + "stream error", // Z_STREAM_ERROR (-2) + "data error", // Z_DATA_ERROR (-3) + "insufficient memory", // Z_MEM_ERROR (-4) + "buffer error", // Z_BUF_ERROR (-5) + "incompatible version",// Z_VERSION_ERROR (-6) + "" + }; + + // block not completed, need more input or more output + private const int NeedMore=0; + + // block flush performed + private const int BlockDone=1; + + // finish started, need only more output at next deflate + private const int FinishStarted=2; + + // finish done, accept no more input or output + private const int FinishDone=3; + + // preset dictionary flag in zlib header + private const int PRESET_DICT=0x20; + + private const int Z_FILTERED=1; + private const int Z_HUFFMAN_ONLY=2; + private const int Z_DEFAULT_STRATEGY=0; + + private const int Z_NO_FLUSH=0; + private const int Z_PARTIAL_FLUSH=1; + private const int Z_SYNC_FLUSH=2; + private const int Z_FULL_FLUSH=3; + private const int Z_FINISH=4; + + private const int Z_OK=0; + private const int Z_STREAM_END=1; + private const int Z_NEED_DICT=2; + private const int Z_ERRNO=-1; + private const int Z_STREAM_ERROR=-2; + private const int Z_DATA_ERROR=-3; + private const int Z_MEM_ERROR=-4; + private const int Z_BUF_ERROR=-5; + private const int Z_VERSION_ERROR=-6; + + private const int INIT_STATE=42; + private const int BUSY_STATE=113; + private const int FINISH_STATE=666; + + // The deflate compression method + private const int Z_DEFLATED=8; + + private const int STORED_BLOCK=0; + private const int STATIC_TREES=1; + private const int DYN_TREES=2; + + // The three kinds of block type + private const int Z_BINARY=0; + private const int Z_ASCII=1; + private const int Z_UNKNOWN=2; + + private const int Buf_size=8*2; + + // repeat previous bit length 3-6 times (2 bits of repeat count) + private const int REP_3_6=16; + + // repeat a zero length 3-10 times (3 bits of repeat count) + private const int REPZ_3_10=17; + + // repeat a zero length 11-138 times (7 bits of repeat count) + private const int REPZ_11_138=18; + + private const int MIN_MATCH=3; + private const int MAX_MATCH=258; + private const int MIN_LOOKAHEAD=(MAX_MATCH+MIN_MATCH+1); + + private const int MAX_BITS=15; + private const int D_CODES=30; + private const int BL_CODES=19; + private const int LENGTH_CODES=29; + private const int LITERALS=256; + private const int L_CODES=(LITERALS+1+LENGTH_CODES); + private const int HEAP_SIZE=(2*L_CODES+1); + + private const int END_BLOCK=256; + + internal ZStream strm; // pointer back to this zlib stream + internal int status; // as the name implies + internal byte[] pending_buf; // output still pending + internal int pending_buf_size; // size of pending_buf + internal int pending_out; // next pending byte to output to the stream + internal int pending; // nb of bytes in the pending buffer + internal int noheader; // suppress zlib header and adler32 + internal byte data_type; // UNKNOWN, BINARY or ASCII + internal byte method; // STORED (for zip only) or DEFLATED + internal int last_flush; // value of flush param for previous deflate call + + internal int w_size; // LZ77 window size (32K by default) + internal int w_bits; // log2(w_size) (8..16) + internal int w_mask; // w_size - 1 + + internal byte[] window; + // Sliding window. Input bytes are read into the second half of the window, + // and move to the first half later to keep a dictionary of at least wSize + // bytes. With this organization, matches are limited to a distance of + // wSize-MAX_MATCH bytes, but this ensures that IO is always + // performed with a length multiple of the block size. Also, it limits + // the window size to 64K, which is quite useful on MSDOS. + // To do: use the user input buffer as sliding window. + + internal int window_size; + // Actual size of window: 2*wSize, except when the user input buffer + // is directly used as sliding window. + + internal short[] prev; + // Link to older string with same hash index. To limit the size of this + // array to 64K, this link is maintained only for the last 32K strings. + // An index in this array is thus a window index modulo 32K. + + internal short[] head; // Heads of the hash chains or NIL. + + internal int ins_h; // hash index of string to be inserted + internal int hash_size; // number of elements in hash table + internal int hash_bits; // log2(hash_size) + internal int hash_mask; // hash_size-1 + + // Number of bits by which ins_h must be shifted at each input + // step. It must be such that after MIN_MATCH steps, the oldest + // byte no longer takes part in the hash key, that is: + // hash_shift * MIN_MATCH >= hash_bits + internal int hash_shift; + + // Window position at the beginning of the current output block. Gets + // negative when the window is moved backwards. + + internal int block_start; + + internal int match_length; // length of best match + internal int prev_match; // previous match + internal int match_available; // set if previous match exists + internal int strstart; // start of string to insert + internal int match_start; // start of matching string + internal int lookahead; // number of valid bytes ahead in window + + // Length of the best match at previous step. Matches not greater than this + // are discarded. This is used in the lazy match evaluation. + internal int prev_length; + + // To speed up deflation, hash chains are never searched beyond this + // length. A higher limit improves compression ratio but degrades the speed. + internal int max_chain_length; + + // Attempt to find a better match only when the current match is strictly + // smaller than this value. This mechanism is used only for compression + // levels >= 4. + internal int max_lazy_match; + + // Insert new strings in the hash table only if the match length is not + // greater than this length. This saves time but degrades compression. + // max_insert_length is used only for compression levels <= 3. + + internal int level; // compression level (1..9) + internal int strategy; // favor or force Huffman coding + + // Use a faster search when the previous match is longer than this + internal int good_match; + + // Stop searching when current match exceeds this + internal int nice_match; + + internal short[] dyn_ltree; // literal and length tree + internal short[] dyn_dtree; // distance tree + internal short[] bl_tree; // Huffman tree for bit lengths + + internal Tree l_desc=new Tree(); // desc for literal tree + internal Tree d_desc=new Tree(); // desc for distance tree + internal Tree bl_desc=new Tree(); // desc for bit length tree + + // number of codes at each bit length for an optimal tree + internal short[] bl_count=new short[MAX_BITS+1]; + + // heap used to build the Huffman trees + internal int[] heap=new int[2*L_CODES+1]; + + internal int heap_len; // number of elements in the heap + internal int heap_max; // element of largest frequency + // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + // The same heap array is used to build all trees. + + // Depth of each subtree used as tie breaker for trees of equal frequency + internal byte[] depth=new byte[2*L_CODES+1]; + + internal int l_buf; // index for literals or lengths */ + + // Size of match buffer for literals/lengths. There are 4 reasons for + // limiting lit_bufsize to 64K: + // - frequencies can be kept in 16 bit counters + // - if compression is not successful for the first block, all input + // data is still in the window so we can still emit a stored block even + // when input comes from standard input. (This can also be done for + // all blocks if lit_bufsize is not greater than 32K.) + // - if compression is not successful for a file smaller than 64K, we can + // even emit a stored file instead of a stored block (saving 5 bytes). + // This is applicable only for zip (not gzip or zlib). + // - creating new Huffman trees less frequently may not provide fast + // adaptation to changes in the input data statistics. (Take for + // example a binary file with poorly compressible code followed by + // a highly compressible string table.) Smaller buffer sizes give + // fast adaptation but have of course the overhead of transmitting + // trees more frequently. + // - I can't count above 4 + internal int lit_bufsize; + + internal int last_lit; // running index in l_buf + + // Buffer for distances. To simplify the code, d_buf and l_buf have + // the same number of elements. To use different lengths, an extra flag + // array would be necessary. + + internal int d_buf; // index of pendig_buf + + internal int opt_len; // bit length of current block with optimal trees + internal int static_len; // bit length of current block with static trees + internal int matches; // number of string matches in current block + internal int last_eob_len; // bit length of EOB code for last block + + // Output buffer. bits are inserted starting at the bottom (least + // significant bits). + internal uint bi_buf; + + // Number of valid bits in bi_buf. All bits above the last valid bit + // are always zero. + internal int bi_valid; + + internal Deflate(){ + dyn_ltree=new short[HEAP_SIZE*2]; + dyn_dtree=new short[(2*D_CODES+1)*2]; // distance tree + bl_tree=new short[(2*BL_CODES+1)*2]; // Huffman tree for bit lengths + } + + internal void lm_init() { + window_size=2*w_size; + + head[hash_size-1]=0; + for(int i=0; i= 3; max_blindex--) { + if (bl_tree[Tree.bl_order[max_blindex]*2+1] != 0) break; + } + // Update opt_len to include the bit length tree and counts + opt_len += 3*(max_blindex+1) + 5+5+4; + + return max_blindex; + } + + + // Send the header for a block using dynamic Huffman trees: the counts, the + // lengths of the bit length codes, the literal tree and the distance tree. + // IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + internal void send_all_trees(int lcodes, int dcodes, int blcodes){ + int rank; // index in bl_order + + send_bits(lcodes-257, 5); // not +255 as stated in appnote.txt + send_bits(dcodes-1, 5); + send_bits(blcodes-4, 4); // not -3 as stated in appnote.txt + for (rank = 0; rank < blcodes; rank++) { + send_bits(bl_tree[Tree.bl_order[rank]*2+1], 3); + } + send_tree(dyn_ltree, lcodes-1); // literal tree + send_tree(dyn_dtree, dcodes-1); // distance tree + } + + // Send a literal or distance tree in compressed form, using the codes in + // bl_tree. + internal void send_tree (short[] tree,// the tree to be sent + int max_code // and its largest code of non zero frequency + ){ + int n; // iterates over all tree elements + int prevlen = -1; // last emitted length + int curlen; // length of current code + int nextlen = tree[0*2+1]; // length of next code + int count = 0; // repeat count of the current code + int max_count = 7; // max repeat count + int min_count = 4; // min repeat count + + if (nextlen == 0){ max_count = 138; min_count = 3; } + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[(n+1)*2+1]; + if(++count < max_count && curlen == nextlen) { + continue; + } + else if(count < min_count) { + do { send_code(curlen, bl_tree); } while (--count != 0); + } + else if(curlen != 0){ + if(curlen != prevlen){ + send_code(curlen, bl_tree); count--; + } + send_code(REP_3_6, bl_tree); + send_bits(count-3, 2); + } + else if(count <= 10){ + send_code(REPZ_3_10, bl_tree); + send_bits(count-3, 3); + } + else{ + send_code(REPZ_11_138, bl_tree); + send_bits(count-11, 7); + } + count = 0; prevlen = curlen; + if(nextlen == 0){ + max_count = 138; min_count = 3; + } + else if(curlen == nextlen){ + max_count = 6; min_count = 3; + } + else{ + max_count = 7; min_count = 4; + } + } + } + + // Output a byte on the stream. + // IN assertion: there is enough room in pending_buf. + internal void put_byte(byte[] p, int start, int len){ + System.Array.Copy(p, start, pending_buf, pending, len); + pending+=len; + } + + internal void put_byte(byte c){ + pending_buf[pending++]=c; + } + internal void put_short(int w) { + pending_buf[pending++]=(byte)(w/*&0xff*/); + pending_buf[pending++]=(byte)(w>>8); + } + internal void putShortMSB(int b){ + pending_buf[pending++]=(byte)(b>>8); + pending_buf[pending++]=(byte)(b/*&0xff*/); + } + + internal void send_code(int c, short[] tree){ + int c2=c*2; + send_bits((tree[c2]&0xffff), (tree[c2+1]&0xffff)); + } + + internal void send_bits(int val, int length){ + if (bi_valid > Buf_size - length) { + bi_buf |= (uint)(val << bi_valid); + pending_buf[pending++]=(byte)(bi_buf/*&0xff*/); + pending_buf[pending++]=(byte)(bi_buf>>8); + bi_buf = ((uint)val) >> (Buf_size - bi_valid); + bi_valid += length - Buf_size; + } else { + bi_buf |= (uint)(val << bi_valid); + bi_valid += length; + } +// int len = length; +// if (bi_valid > (int)Buf_size - len) { +// int val = value; +// // bi_buf |= (val << bi_valid); +// bi_buf = (short)((ushort)bi_buf | (ushort)((val << bi_valid)&0xffff)); +// put_short(bi_buf); +// bi_buf = (short)(((uint)val) >> (Buf_size - bi_valid)); +// bi_valid += len - Buf_size; +// } else { +// // bi_buf |= (value) << bi_valid; +// bi_buf = (short)((ushort)bi_buf | (ushort)(((value) << bi_valid)&0xffff)); +// bi_valid += len; +// } + } + + // Send one empty static block to give enough lookahead for inflate. + // This takes 10 bits, of which 7 may remain in the bit buffer. + // The current inflate code requires 9 bits of lookahead. If the + // last two codes for the previous block (real code plus EOB) were coded + // on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + // the last real code. In this case we send two empty static blocks instead + // of one. (There are no problems if the previous block is stored or fixed.) + // To simplify the code, we assume the worst case of last real code encoded + // on one bit only. + internal void _tr_align(){ + send_bits(STATIC_TREES<<1, 3); + send_code(END_BLOCK, StaticTree.static_ltree); + + bi_flush(); + + // Of the 10 bits for the empty block, we have already sent + // (10 - bi_valid) bits. The lookahead for the last real code (before + // the EOB of the previous block) was thus at least one plus the length + // of the EOB plus what we have just sent of the empty static block. + if (1 + last_eob_len + 10 - bi_valid < 9) { + send_bits(STATIC_TREES<<1, 3); + send_code(END_BLOCK, StaticTree.static_ltree); + bi_flush(); + } + last_eob_len = 7; + } + + + // Save the match info and tally the frequency counts. Return true if + // the current block must be flushed. + internal bool _tr_tally (int dist, // distance of matched string + int lc // match length-MIN_MATCH or unmatched char (if dist==0) + ){ + + pending_buf[d_buf+last_lit*2] = (byte)(dist>>8); + pending_buf[d_buf+last_lit*2+1] = (byte)dist; + + pending_buf[l_buf+last_lit] = (byte)lc; last_lit++; + + if (dist == 0) { + // lc is the unmatched char + dyn_ltree[lc*2]++; + } + else { + matches++; + // Here, lc is the match length - MIN_MATCH + dist--; // dist = match distance - 1 + dyn_ltree[(Tree._length_code[lc]+LITERALS+1)*2]++; + dyn_dtree[Tree.d_code(dist)*2]++; + } + + if ((last_lit & 0x1fff) == 0 && level > 2) { + // Compute an upper bound for the compressed length + int out_length = last_lit*8; + int in_length = strstart - block_start; + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (int)((int)dyn_dtree[dcode*2] * + (5L+Tree.extra_dbits[dcode])); + } + out_length >>= 3; + if ((matches < (last_lit/2)) && out_length < in_length/2) return true; + } + + return (last_lit == lit_bufsize-1); + // We avoid equality with lit_bufsize because of wraparound at 64K + // on 16 bit machines and because stored blocks are restricted to + // 64K-1 bytes. + } + + // Send the block data compressed using the given Huffman trees + internal void compress_block(short[] ltree, short[] dtree){ + int dist; // distance of matched string + int lc; // match length or unmatched char (if dist == 0) + int lx = 0; // running index in l_buf + int code; // the code to send + int extra; // number of extra bits to send + + if (last_lit != 0){ + do{ + dist=((pending_buf[d_buf+lx*2]<<8)&0xff00)| + (pending_buf[d_buf+lx*2+1]&0xff); + lc=(pending_buf[l_buf+lx])&0xff; lx++; + + if(dist == 0){ + send_code(lc, ltree); // send a literal byte + } + else{ + // Here, lc is the match length - MIN_MATCH + code = Tree._length_code[lc]; + + send_code(code+LITERALS+1, ltree); // send the length code + extra = Tree.extra_lbits[code]; + if(extra != 0){ + lc -= Tree.base_length[code]; + send_bits(lc, extra); // send the extra length bits + } + dist--; // dist is now the match distance - 1 + code = Tree.d_code(dist); + + send_code(code, dtree); // send the distance code + extra = Tree.extra_dbits[code]; + if (extra != 0) { + dist -= Tree.base_dist[code]; + send_bits(dist, extra); // send the extra distance bits + } + } // literal or match pair ? + + // Check that the overlay between pending_buf and d_buf+l_buf is ok: + } + while (lx < last_lit); + } + + send_code(END_BLOCK, ltree); + last_eob_len = ltree[END_BLOCK*2+1]; + } + + // Set the data type to ASCII or BINARY, using a crude approximation: + // binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + // IN assertion: the fields freq of dyn_ltree are set and the total of all + // frequencies does not exceed 64K (to fit in an int on 16 bit machines). + internal void set_data_type(){ + int n = 0; + int ascii_freq = 0; + int bin_freq = 0; + while(n<7){ bin_freq += dyn_ltree[n*2]; n++;} + while(n<128){ ascii_freq += dyn_ltree[n*2]; n++;} + while(n (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); + } + + // Flush the bit buffer, keeping at most 7 bits in it. + internal void bi_flush(){ + if (bi_valid == 16) { + pending_buf[pending++]=(byte)(bi_buf/*&0xff*/); + pending_buf[pending++]=(byte)(bi_buf>>8); + bi_buf=0; + bi_valid=0; + } + else if (bi_valid >= 8) { + pending_buf[pending++]=(byte)(bi_buf); + bi_buf>>=8; + bi_buf &= 0x00ff; + bi_valid-=8; + } + } + + // Flush the bit buffer and align the output on a byte boundary + internal void bi_windup(){ + if (bi_valid > 8) { + pending_buf[pending++]=(byte)(bi_buf); + pending_buf[pending++]=(byte)(bi_buf>>8); + } else if (bi_valid > 0) { + pending_buf[pending++]=(byte)(bi_buf); + } + bi_buf = 0; + bi_valid = 0; + } + + // Copy a stored block, storing first the length and its + // one's complement if requested. + internal void copy_block(int buf, // the input data + int len, // its length + bool header // true if block header must be written + ){ + //int index=0; + bi_windup(); // align on byte boundary + last_eob_len = 8; // enough lookahead for inflate + + if (header) { + put_short((short)len); + put_short((short)~len); + } + + // while(len--!=0) { + // put_byte(window[buf+index]); + // index++; + // } + put_byte(window, buf, len); + } + + internal void flush_block_only(bool eof){ + _tr_flush_block(block_start>=0 ? block_start : -1, + strstart-block_start, + eof); + block_start=strstart; + strm.flush_pending(); + } + + // Copy without compression as much as possible from the input stream, return + // the current block state. + // This function does not insert new strings in the dictionary since + // uncompressible data is probably not useful. This function is used + // only for the level=0 compression option. + // NOTE: this function should be optimized to avoid extra copying from + // window to pending_buf. + internal int deflate_stored(int flush){ + // Stored blocks are limited to 0xffff bytes, pending_buf is limited + // to pending_buf_size, and each stored block has a 5 byte header: + + int max_block_size = 0xffff; + int max_start; + + if(max_block_size > pending_buf_size - 5) { + max_block_size = pending_buf_size - 5; + } + + // Copy as much as possible from input to output: + while(true){ + // Fill the window as much as possible: + if(lookahead<=1){ + fill_window(); + if(lookahead==0 && flush==Z_NO_FLUSH) return NeedMore; + if(lookahead==0) break; // flush the current block + } + + strstart+=lookahead; + lookahead=0; + + // Emit a stored block if pending_buf will be full: + max_start=block_start+max_block_size; + if(strstart==0|| strstart>=max_start) { + // strstart == 0 is possible when wraparound on 16-bit machine + lookahead = (int)(strstart-max_start); + strstart = (int)max_start; + + flush_block_only(false); + if(strm.avail_out==0) return NeedMore; + + } + + // Flush if we may have to slide, otherwise block_start may become + // negative and the data will be gone: + if(strstart-block_start >= w_size-MIN_LOOKAHEAD) { + flush_block_only(false); + if(strm.avail_out==0) return NeedMore; + } + } + + flush_block_only(flush == Z_FINISH); + if(strm.avail_out==0) + return (flush == Z_FINISH) ? FinishStarted : NeedMore; + + return flush == Z_FINISH ? FinishDone : BlockDone; + } + + // Send a stored block + internal void _tr_stored_block(int buf, // input block + int stored_len, // length of input block + bool eof // true if this is the last block for a file + ){ + send_bits((STORED_BLOCK<<1)+(eof?1:0), 3); // send block type + copy_block(buf, stored_len, true); // with header + } + + // Determine the best encoding for the current block: dynamic trees, static + // trees or store, and output the encoded block to the zip file. + internal void _tr_flush_block(int buf, // input block, or NULL if too old + int stored_len, // length of input block + bool eof // true if this is the last block for a file + ) { + int opt_lenb, static_lenb;// opt_len and static_len in bytes + int max_blindex = 0; // index of last bit length code of non zero freq + + // Build the Huffman trees unless a stored block is forced + if(level > 0) { + // Check if the file is ascii or binary + if(data_type == Z_UNKNOWN) set_data_type(); + + // Construct the literal and distance trees + l_desc.build_tree(this); + + d_desc.build_tree(this); + + // At this point, opt_len and static_len are the total bit lengths of + // the compressed block data, excluding the tree representations. + + // Build the bit length tree for the above two trees, and get the index + // in bl_order of the last bit length code to send. + max_blindex=build_bl_tree(); + + // Determine the best encoding. Compute first the block length in bytes + opt_lenb=(opt_len+3+7)>>3; + static_lenb=(static_len+3+7)>>3; + + if(static_lenb<=opt_lenb) opt_lenb=static_lenb; + } + else { + opt_lenb=static_lenb=stored_len+5; // force a stored block + } + + if(stored_len+4<=opt_lenb && buf != -1){ + // 4: two words for the lengths + // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + // Otherwise we can't have processed more than WSIZE input bytes since + // the last block flush, because compression would have been + // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + // transform a block into a stored block. + _tr_stored_block(buf, stored_len, eof); + } + else if(static_lenb == opt_lenb){ + send_bits((STATIC_TREES<<1)+(eof?1:0), 3); + compress_block(StaticTree.static_ltree, StaticTree.static_dtree); + } + else{ + send_bits((DYN_TREES<<1)+(eof?1:0), 3); + send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1); + compress_block(dyn_ltree, dyn_dtree); + } + + // The above check is made mod 2^32, for files larger than 512 MB + // and uLong implemented on 32 bits. + + init_block(); + + if(eof){ + bi_windup(); + } + } + + // Fill the window when the lookahead becomes insufficient. + // Updates strstart and lookahead. + // + // IN assertion: lookahead < MIN_LOOKAHEAD + // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + // At least one byte has been read, or avail_in == 0; reads are + // performed for at least two bytes (required for the zip translate_eol + // option -- not supported here). + internal void fill_window(){ + int n, m; + int p; + int more; // Amount of free space at the end of the window. + + do{ + more = (window_size-lookahead-strstart); + + // Deal with !@#$% 64K limit: + if(more==0 && strstart==0 && lookahead==0){ + more = w_size; + } + else if(more==-1) { + // Very unlikely, but possible on 16 bit machine if strstart == 0 + // and lookahead == 1 (input done one byte at time) + more--; + + // If the window is almost full and there is insufficient lookahead, + // move the upper half to the lower one to make room in the upper half. + } + else if(strstart >= w_size+ w_size-MIN_LOOKAHEAD) { + System.Array.Copy(window, w_size, window, 0, w_size); + match_start-=w_size; + strstart-=w_size; // we now have strstart >= MAX_DIST + block_start-=w_size; + + // Slide the hash table (could be avoided with 32 bit values + // at the expense of memory usage). We slide even when level == 0 + // to keep the hash table consistent if we switch back to level > 0 + // later. (Using level 0 permanently is not an optimal usage of + // zlib, so we don't care about this pathological case.) + + n = hash_size; + p=n; + do { + m = (head[--p]&0xffff); + head[p]=(short)(m>=w_size ? (m-w_size) : 0); + } + while (--n != 0); + + n = w_size; + p = n; + do { + m = (prev[--p]&0xffff); + prev[p] = (short)(m >= w_size ? (m-w_size) : 0); + // If n is not on any hash chain, prev[n] is garbage but + // its value will never be used. + } + while (--n!=0); + more += w_size; + } + + if (strm.avail_in == 0) return; + + // If there was no sliding: + // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + // more == window_size - lookahead - strstart + // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + // => more >= window_size - 2*WSIZE + 2 + // In the BIG_MEM or MMAP case (not yet supported), + // window_size == input_size + MIN_LOOKAHEAD && + // strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + // Otherwise, window_size == 2*WSIZE so more >= 2. + // If there was sliding, more >= WSIZE. So in all cases, more >= 2. + + n = strm.read_buf(window, strstart + lookahead, more); + lookahead += n; + + // Initialize the hash value now that we have some input: + if(lookahead >= MIN_MATCH) { + ins_h = window[strstart]&0xff; + ins_h=(((ins_h)<= MIN_MATCH){ + ins_h=(((ins_h)<=MIN_MATCH){ + // check_match(strstart, match_start, match_length); + + bflush=_tr_tally(strstart-match_start, match_length-MIN_MATCH); + + lookahead -= match_length; + + // Insert new strings in the hash table only if the match length + // is not too large. This saves time but degrades compression. + if(match_length <= max_lazy_match && + lookahead >= MIN_MATCH) { + match_length--; // string at strstart already in hash table + do{ + strstart++; + + ins_h=((ins_h<= MIN_MATCH) { + ins_h=(((ins_h)< 4096))) { + + // If prev_match is also MIN_MATCH, match_start is garbage + // but we will ignore the current match anyway. + match_length = MIN_MATCH-1; + } + } + + // If there was a match at the previous step and the current + // match is not better, output the previous match: + if(prev_length >= MIN_MATCH && match_length <= prev_length) { + int max_insert = strstart + lookahead - MIN_MATCH; + // Do not insert strings in hash table beyond this. + + // check_match(strstart-1, prev_match, prev_length); + + bflush=_tr_tally(strstart-1-prev_match, prev_length - MIN_MATCH); + + // Insert in hash table all strings up to the end of the match. + // strstart-1 and strstart are already inserted. If there is not + // enough lookahead, the last two strings are not inserted in + // the hash table. + lookahead -= prev_length-1; + prev_length -= 2; + do{ + if(++strstart <= max_insert) { + ins_h=(((ins_h)<(w_size-MIN_LOOKAHEAD) ? + strstart-(w_size-MIN_LOOKAHEAD) : 0; + int nice_match=this.nice_match; + + // Stop when cur_match becomes <= limit. To simplify the code, + // we prevent matches with the string of window index 0. + + int wmask = w_mask; + + int strend = strstart + MAX_MATCH; + byte scan_end1 = window[scan+best_len-1]; + byte scan_end = window[scan+best_len]; + + // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + // It is easy to get rid of this optimization if necessary. + + // Do not waste too much time if we already have a good match: + if (prev_length >= good_match) { + chain_length >>= 2; + } + + // Do not look for matches beyond the end of the input. This is necessary + // to make deflate deterministic. + if (nice_match > lookahead) nice_match = lookahead; + + do { + match = cur_match; + + // Skip to next match if the match length cannot increase + // or if the match length is less than 2: + if (window[match+best_len] != scan_end || + window[match+best_len-1] != scan_end1 || + window[match] != window[scan] || + window[++match] != window[scan+1]) continue; + + // The check at best_len-1 can be removed because it will be made + // again later. (This heuristic is not always a win.) + // It is not necessary to compare scan[2] and match[2] since they + // are always equal when the other bytes match, given that + // the hash keys are equal and that HASH_BITS >= 8. + scan += 2; match++; + + // We check for insufficient lookahead only every 8th comparison; + // the 256th check will be made at strstart+258. + do { + } while (window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + window[++scan] == window[++match] && + scan < strend); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + + if(len>best_len) { + match_start = cur_match; + best_len = len; + if (len >= nice_match) break; + scan_end1 = window[scan+best_len-1]; + scan_end = window[scan+best_len]; + } + + } while ((cur_match = (prev[cur_match & wmask]&0xffff)) > limit + && --chain_length != 0); + + if (best_len <= lookahead) return best_len; + return lookahead; + } + + internal int deflateInit(ZStream strm, int level, int bits){ + return deflateInit2(strm, level, Z_DEFLATED, bits, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY); + } + internal int deflateInit(ZStream strm, int level){ + return deflateInit(strm, level, MAX_WBITS); + } + internal int deflateInit2(ZStream strm, int level, int method, int windowBits, + int memLevel, int strategy){ + int noheader = 0; + // byte[] my_version=ZLIB_VERSION; + + // + // if (version == null || version[0] != my_version[0] + // || stream_size != sizeof(z_stream)) { + // return Z_VERSION_ERROR; + // } + + strm.msg = null; + + if (level == Z_DEFAULT_COMPRESSION) level = 6; + + if (windowBits < 0) { // undocumented feature: suppress zlib header + noheader = 1; + windowBits = -windowBits; + } + + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || + method != Z_DEFLATED || + windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + + strm.dstate = (Deflate)this; + + this.noheader = noheader; + w_bits = windowBits; + w_size = 1 << w_bits; + w_mask = w_size - 1; + + hash_bits = memLevel + 7; + hash_size = 1 << hash_bits; + hash_mask = hash_size - 1; + hash_shift = ((hash_bits+MIN_MATCH-1)/MIN_MATCH); + + window = new byte[w_size*2]; + prev = new short[w_size]; + head = new short[hash_size]; + + lit_bufsize = 1 << (memLevel + 6); // 16K elements by default + + // We overlay pending_buf and d_buf+l_buf. This works since the average + // output size for (length,distance) codes is <= 24 bits. + pending_buf = new byte[lit_bufsize*4]; + pending_buf_size = lit_bufsize*4; + + d_buf = lit_bufsize/2; + l_buf = (1+2)*lit_bufsize; + + this.level = level; + + //System.out.println("level="+level); + + this.strategy = strategy; + this.method = (byte)method; + + return deflateReset(strm); + } + + internal int deflateReset(ZStream strm){ + strm.total_in = strm.total_out = 0; + strm.msg = null; // + strm.data_type = Z_UNKNOWN; + + pending = 0; + pending_out = 0; + + if(noheader < 0) { + noheader = 0; // was set to -1 by deflate(..., Z_FINISH); + } + status = (noheader!=0) ? BUSY_STATE : INIT_STATE; + strm.adler=strm._adler.adler32(0, null, 0, 0); + + last_flush = Z_NO_FLUSH; + + tr_init(); + lm_init(); + return Z_OK; + } + + internal int deflateEnd(){ + if(status!=INIT_STATE && status!=BUSY_STATE && status!=FINISH_STATE){ + return Z_STREAM_ERROR; + } + // Deallocate in reverse order of allocations: + pending_buf=null; + head=null; + prev=null; + window=null; + // free + // dstate=null; + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; + } + + internal int deflateParams(ZStream strm, int _level, int _strategy){ + int err=Z_OK; + + if(_level == Z_DEFAULT_COMPRESSION){ + _level = 6; + } + if(_level < 0 || _level > 9 || + _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + + if(config_table[level].func!=config_table[_level].func && + strm.total_in != 0) { + // Flush the last buffer: + err = strm.deflate(Z_PARTIAL_FLUSH); + } + + if(level != _level) { + level = _level; + max_lazy_match = config_table[level].max_lazy; + good_match = config_table[level].good_length; + nice_match = config_table[level].nice_length; + max_chain_length = config_table[level].max_chain; + } + strategy = _strategy; + return err; + } + + internal int deflateSetDictionary (ZStream strm, byte[] dictionary, int dictLength){ + int length = dictLength; + int index=0; + + if(dictionary == null || status != INIT_STATE) + return Z_STREAM_ERROR; + + strm.adler=strm._adler.adler32(strm.adler, dictionary, 0, dictLength); + + if(length < MIN_MATCH) return Z_OK; + if(length > w_size-MIN_LOOKAHEAD){ + length = w_size-MIN_LOOKAHEAD; + index=dictLength-length; // use the tail of the dictionary + } + System.Array.Copy(dictionary, index, window, 0, length); + strstart = length; + block_start = length; + + // Insert all strings in the hash table (except for the last two bytes). + // s->lookahead stays null, so s->ins_h will be recomputed at the next + // call of fill_window. + + ins_h = window[0]&0xff; + ins_h=(((ins_h)<Z_FINISH || flush<0){ + return Z_STREAM_ERROR; + } + + if(strm.next_out == null || + (strm.next_in == null && strm.avail_in != 0) || + (status == FINISH_STATE && flush != Z_FINISH)) { + strm.msg=z_errmsg[Z_NEED_DICT-(Z_STREAM_ERROR)]; + return Z_STREAM_ERROR; + } + if(strm.avail_out == 0){ + strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)]; + return Z_BUF_ERROR; + } + + this.strm = strm; // just in case + old_flush = last_flush; + last_flush = flush; + + // Write the zlib header + if(status == INIT_STATE) { + int header = (Z_DEFLATED+((w_bits-8)<<4))<<8; + int level_flags=((level-1)&0xff)>>1; + + if(level_flags>3) level_flags=3; + header |= (level_flags<<6); + if(strstart!=0) header |= PRESET_DICT; + header+=31-(header % 31); + + status=BUSY_STATE; + putShortMSB(header); + + + // Save the adler32 of the preset dictionary: + if(strstart!=0){ + putShortMSB((int)(strm.adler>>16)); + putShortMSB((int)(strm.adler&0xffff)); + } + strm.adler=strm._adler.adler32(0, null, 0, 0); + } + + // Flush as much pending output as possible + if(pending != 0) { + strm.flush_pending(); + if(strm.avail_out == 0) { + //System.out.println(" avail_out==0"); + // Since avail_out is 0, deflate will be called again with + // more output space, but possibly with both pending and + // avail_in equal to zero. There won't be anything to do, + // but this is not an error situation so make sure we + // return OK instead of BUF_ERROR at next call of deflate: + last_flush = -1; + return Z_OK; + } + + // Make sure there is something to do and avoid duplicate consecutive + // flushes. For repeated and useless calls with Z_FINISH, we keep + // returning Z_STREAM_END instead of Z_BUFF_ERROR. + } + else if(strm.avail_in==0 && flush <= old_flush && + flush != Z_FINISH) { + strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)]; + return Z_BUF_ERROR; + } + + // User must not provide more input after the first FINISH: + if(status == FINISH_STATE && strm.avail_in != 0) { + strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)]; + return Z_BUF_ERROR; + } + + // Start a new block or continue the current one. + if(strm.avail_in!=0 || lookahead!=0 || + (flush != Z_NO_FLUSH && status != FINISH_STATE)) { + int bstate=-1; + switch(config_table[level].func){ + case STORED: + bstate = deflate_stored(flush); + break; + case FAST: + bstate = deflate_fast(flush); + break; + case SLOW: + bstate = deflate_slow(flush); + break; + default: + break; + } + + if (bstate==FinishStarted || bstate==FinishDone) { + status = FINISH_STATE; + } + if (bstate==NeedMore || bstate==FinishStarted) { + if(strm.avail_out == 0) { + last_flush = -1; // avoid BUF_ERROR next call, see above + } + return Z_OK; + // If flush != Z_NO_FLUSH && avail_out == 0, the next call + // of deflate should use the same flush parameter to make sure + // that the flush is complete. So we don't have to output an + // empty block here, this will be done at next call. This also + // ensures that for a very small output buffer, we emit at most + // one empty block. + } + + if (bstate==BlockDone) { + if(flush == Z_PARTIAL_FLUSH) { + _tr_align(); + } + else { // FULL_FLUSH or SYNC_FLUSH + _tr_stored_block(0, 0, false); + // For a full flush, this empty block will be recognized + // as a special marker by inflate_sync(). + if(flush == Z_FULL_FLUSH) { + //state.head[s.hash_size-1]=0; + for(int i=0; i>16)); + putShortMSB((int)(strm.adler&0xffff)); + strm.flush_pending(); + + // If avail_out is zero, the application will call deflate again + // to flush the rest. + noheader = -1; // write the trailer only once! + return pending != 0 ? Z_OK : Z_STREAM_END; + } + } +} \ No newline at end of file diff --git a/iTechSharp/System/util/zlib/InfBlocks.cs b/iTechSharp/System/util/zlib/InfBlocks.cs new file mode 100644 index 0000000..d6a1599 --- /dev/null +++ b/iTechSharp/System/util/zlib/InfBlocks.cs @@ -0,0 +1,618 @@ +using System; +/* + * $Id: InfBlocks.cs,v 1.1 2006/06/16 10:56:20 psoares33 Exp $ + * +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +namespace System.util.zlib { + + internal sealed class InfBlocks{ + private const int MANY=1440; + + // And'ing with mask[n] masks the lower n bits + static private int[] inflate_mask = { + 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, + 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, + 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, + 0x00007fff, 0x0000ffff + }; + + // Table for deflate from PKZIP's appnote.txt. + static int[] border = { // Order of the bit length code lengths + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + }; + + private const int Z_OK=0; + private const int Z_STREAM_END=1; + private const int Z_NEED_DICT=2; + private const int Z_ERRNO=-1; + private const int Z_STREAM_ERROR=-2; + private const int Z_DATA_ERROR=-3; + private const int Z_MEM_ERROR=-4; + private const int Z_BUF_ERROR=-5; + private const int Z_VERSION_ERROR=-6; + + private const int TYPE=0; // get type bits (3, including end bit) + private const int LENS=1; // get lengths for stored + private const int STORED=2;// processing stored block + private const int TABLE=3; // get table lengths + private const int BTREE=4; // get bit lengths tree for a dynamic block + private const int DTREE=5; // get length, distance trees for a dynamic block + private const int CODES=6; // processing fixed or dynamic block + private const int DRY=7; // output remaining window bytes + private const int DONE=8; // finished last block, done + private const int BAD=9; // ot a data error--stuck here + + internal int mode; // current inflate_block mode + + internal int left; // if STORED, bytes left to copy + + internal int table; // table lengths (14 bits) + internal int index; // index into blens (or border) + internal int[] blens; // bit lengths of codes + internal int[] bb=new int[1]; // bit length tree depth + internal int[] tb=new int[1]; // bit length decoding tree + + internal InfCodes codes=new InfCodes(); // if CODES, current state + + int last; // true if this block is the last block + + // mode independent information + internal int bitk; // bits in bit buffer + internal int bitb; // bit buffer + internal int[] hufts; // single malloc for tree space + internal byte[] window; // sliding window + internal int end; // one byte after sliding window + internal int read; // window read pointer + internal int write; // window write pointer + internal Object checkfn; // check function + internal long check; // check on output + + internal InfTree inftree=new InfTree(); + + internal InfBlocks(ZStream z, Object checkfn, int w){ + hufts=new int[MANY*3]; + window=new byte[w]; + end=w; + this.checkfn = checkfn; + mode = TYPE; + reset(z, null); + } + + internal void reset(ZStream z, long[] c){ + if(c!=null) c[0]=check; + if(mode==BTREE || mode==DTREE){ + } + if(mode==CODES){ + codes.free(z); + } + mode=TYPE; + bitk=0; + bitb=0; + read=write=0; + + if(checkfn != null) + z.adler=check=z._adler.adler32(0L, null, 0, 0); + } + + internal int proc(ZStream z, int r){ + int t; // temporary storage + int b; // bit buffer + int k; // bits in bit buffer + int p; // input data pointer + int n; // bytes available there + int q; // output window write pointer + int m; { // bytes to end of window or read pointer + + // copy input/output information to locals (UPDATE macro restores) + p=z.next_in_index;n=z.avail_in;b=bitb;k=bitk;} { + q=write;m=(int)(q> 1){ + case 0: { // stored + b>>=(3);k-=(3);} + t = k & 7; { // go to byte boundary + + b>>=(t);k-=(t);} + mode = LENS; // get length of stored block + break; + case 1: { // fixed + int[] bl=new int[1]; + int[] bd=new int[1]; + int[][] tl=new int[1][]; + int[][] td=new int[1][]; + + InfTree.inflate_trees_fixed(bl, bd, tl, td, z); + codes.init(bl[0], bd[0], tl[0], 0, td[0], 0, z); + } { + + b>>=(3);k-=(3);} + + mode = CODES; + break; + case 2: { // dynamic + + b>>=(3);k-=(3);} + + mode = TABLE; + break; + case 3: { // illegal + + b>>=(3);k-=(3);} + mode = BAD; + z.msg = "invalid block type"; + r = Z_DATA_ERROR; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + break; + case LENS: + + while(k<(32)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + }; + n--; + b|=(z.next_in[p++]&0xff)<> 16) & 0xffff) != (b & 0xffff)){ + mode = BAD; + z.msg = "invalid stored block lengths"; + r = Z_DATA_ERROR; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + left = (b & 0xffff); + b = k = 0; // dump bits + mode = left!=0 ? STORED : (last!=0 ? DRY : TYPE); + break; + case STORED: + if (n == 0){ + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + + if(m==0){ + if(q==end&&read!=0){ + q=0; m=(int)(qn) t = n; + if(t>m) t = m; + System.Array.Copy(z.next_in, p, window, q, t); + p += t; n -= t; + q += t; m -= t; + if ((left -= t) != 0) + break; + mode = last!=0 ? DRY : TYPE; + break; + case TABLE: + + while(k<(14)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + }; + n--; + b|=(z.next_in[p++]&0xff)< 29 || ((t >> 5) & 0x1f) > 29) { + mode = BAD; + z.msg = "too many length or distance symbols"; + r = Z_DATA_ERROR; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if(blens==null || blens.Length>=(14);k-=(14);} + + index = 0; + mode = BTREE; + goto case BTREE; + case BTREE: + while (index < 4 + (table >> 10)){ + while(k<(3)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + }; + n--; + b|=(z.next_in[p++]&0xff)<>=(3);k-=(3);} + } + + while(index < 19){ + blens[border[index++]] = 0; + } + + bb[0] = 7; + t = inftree.inflate_trees_bits(blens, bb, tb, hufts, z); + if (t != Z_OK){ + r = t; + if (r == Z_DATA_ERROR){ + blens=null; + mode = BAD; + } + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + + index = 0; + mode = DTREE; + goto case DTREE; + case DTREE: + while (true){ + t = table; + if(!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))){ + break; + } + + int i, j, c; + + t = bb[0]; + + while(k<(t)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + }; + n--; + b|=(z.next_in[p++]&0xff)<>=(t);k-=(t); + blens[index++] = c; + } + else { // c == 16..18 + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + + while(k<(t+i)){ + if(n!=0){ + r=Z_OK; + } + else{ + bitb=b; bitk=k; + z.avail_in=n; + z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + }; + n--; + b|=(z.next_in[p++]&0xff)<>=(t);k-=(t); + + j += (b & inflate_mask[i]); + + b>>=(i);k-=(i); + + i = index; + t = table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)){ + blens=null; + mode = BAD; + z.msg = "invalid bit length repeat"; + r = Z_DATA_ERROR; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + + c = c == 16 ? blens[i-1] : 0; + do{ + blens[i++] = c; + } + while (--j!=0); + index = i; + } + } + + tb[0]=-1; { + int[] bl=new int[1]; + int[] bd=new int[1]; + int[] tl=new int[1]; + int[] td=new int[1]; + bl[0] = 9; // must be <= 9 for lookahead assumptions + bd[0] = 6; // must be <= 9 for lookahead assumptions + + t = table; + t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), + 1 + ((t >> 5) & 0x1f), + blens, bl, bd, tl, td, hufts, z); + + if (t != Z_OK){ + if (t == Z_DATA_ERROR){ + blens=null; + mode = BAD; + } + r = t; + + bitb=b; bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + return inflate_flush(z,r); + } + codes.init(bl[0], bd[0], hufts, tl[0], hufts, td[0], z); + } + mode = CODES; + goto case CODES; + case CODES: + bitb=b; bitk=k; + z.avail_in=n; z.total_in+=p-z.next_in_index;z.next_in_index=p; + write=q; + + if ((r = codes.proc(this, z, r)) != Z_STREAM_END){ + return inflate_flush(z, r); + } + r = Z_OK; + codes.free(z); + + p=z.next_in_index; n=z.avail_in;b=bitb;k=bitk; + q=write;m=(int)(q z.avail_out) n = z.avail_out; + if (n!=0 && r == Z_BUF_ERROR) r = Z_OK; + + // update counters + z.avail_out -= n; + z.total_out += n; + + // update check information + if(checkfn != null) + z.adler=check=z._adler.adler32(check, window, q, n); + + // copy as far as end of window + System.Array.Copy(window, q, z.next_out, p, n); + p += n; + q += n; + + // see if more to copy at beginning of window + if (q == end){ + // wrap pointers + q = 0; + if (write == end) + write = 0; + + // compute bytes to copy + n = write - q; + if (n > z.avail_out) n = z.avail_out; + if (n!=0 && r == Z_BUF_ERROR) r = Z_OK; + + // update counters + z.avail_out -= n; + z.total_out += n; + + // update check information + if(checkfn != null) + z.adler=check=z._adler.adler32(check, window, q, n); + + // copy + System.Array.Copy(window, q, z.next_out, p, n); + p += n; + q += n; + } + + // update pointers + z.next_out_index = p; + read = q; + + // done + return r; + } + } +} \ No newline at end of file diff --git a/iTechSharp/System/util/zlib/InfCodes.cs b/iTechSharp/System/util/zlib/InfCodes.cs new file mode 100644 index 0000000..a70e4b0 --- /dev/null +++ b/iTechSharp/System/util/zlib/InfCodes.cs @@ -0,0 +1,611 @@ +using System; +/* + * $Id: InfCodes.cs,v 1.1 2006/06/16 10:56:20 psoares33 Exp $ + * +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +namespace System.util.zlib { + + internal sealed class InfCodes{ + + static private int[] inflate_mask = { + 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, + 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, + 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, + 0x00007fff, 0x0000ffff + }; + + private const int Z_OK=0; + private const int Z_STREAM_END=1; + private const int Z_NEED_DICT=2; + private const int Z_ERRNO=-1; + private const int Z_STREAM_ERROR=-2; + private const int Z_DATA_ERROR=-3; + private const int Z_MEM_ERROR=-4; + private const int Z_BUF_ERROR=-5; + private const int Z_VERSION_ERROR=-6; + + // waiting for "i:"=input, + // "o:"=output, + // "x:"=nothing + private const int START=0; // x: set up for LEN + private const int LEN=1; // i: get length/literal/eob next + private const int LENEXT=2; // i: getting length extra (have base) + private const int DIST=3; // i: get distance next + private const int DISTEXT=4;// i: getting distance extra + private const int COPY=5; // o: copying bytes in window, waiting for space + private const int LIT=6; // o: got literal, waiting for output space + private const int WASH=7; // o: got eob, possibly still output waiting + private const int END=8; // x: got eob and all data flushed + private const int BADCODE=9;// x: got error + + int mode; // current inflate_codes mode + + // mode dependent information + int len; + + int[] tree; // pointer into tree + int tree_index=0; + int need; // bits needed + + int lit; + + // if EXT or COPY, where and how much + int get; // bits to get for extra + int dist; // distance back to copy from + + byte lbits; // ltree bits decoded per branch + byte dbits; // dtree bits decoder per branch + int[] ltree; // literal/length/eob tree + int ltree_index; // literal/length/eob tree + int[] dtree; // distance tree + int dtree_index; // distance tree + + internal InfCodes(){ + } + internal void init(int bl, int bd, + int[] tl, int tl_index, + int[] td, int td_index, ZStream z){ + mode=START; + lbits=(byte)bl; + dbits=(byte)bd; + ltree=tl; + ltree_index=tl_index; + dtree = td; + dtree_index=td_index; + tree=null; + } + + internal int proc(InfBlocks s, ZStream z, int r){ + int j; // temporary storage + int tindex; // temporary pointer + int e; // extra bits or operation + int b=0; // bit buffer + int k=0; // bits in bit buffer + int p=0; // input data pointer + int n; // bytes available there + int q; // output window write pointer + int m; // bytes to end of window or read pointer + int f; // pointer to copy strings from + + // copy input/output information to locals (UPDATE macro restores) + p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk; + q=s.write;m=q= 258 && n >= 10){ + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + r = inflate_fast(lbits, dbits, + ltree, ltree_index, + dtree, dtree_index, + s, z); + + p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk; + q=s.write;m=q>=(tree[tindex+1]); + k-=(tree[tindex+1]); + + e=tree[tindex]; + + if(e == 0){ // literal + lit = tree[tindex+2]; + mode = LIT; + break; + } + if((e & 16)!=0 ){ // length + get = e & 15; + len = tree[tindex+2]; + mode = LENEXT; + break; + } + if ((e & 64) == 0){ // next table + need = e; + tree_index = tindex/3+tree[tindex+2]; + break; + } + if ((e & 32)!=0){ // end of block + mode = WASH; + break; + } + mode = BADCODE; // invalid code + z.msg = "invalid literal/length code"; + r = Z_DATA_ERROR; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(z,r); + + case LENEXT: // i: getting length extra (have base) + j = get; + + while(k<(j)){ + if(n!=0)r=Z_OK; + else{ + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(z,r); + } + n--; b|=(z.next_in[p++]&0xff)<>=j; + k-=j; + + need = dbits; + tree = dtree; + tree_index=dtree_index; + mode = DIST; + goto case DIST; + case DIST: // i: get distance next + j = need; + + while(k<(j)){ + if(n!=0)r=Z_OK; + else{ + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(z,r); + } + n--; b|=(z.next_in[p++]&0xff)<>=tree[tindex+1]; + k-=tree[tindex+1]; + + e = (tree[tindex]); + if((e & 16)!=0){ // distance + get = e & 15; + dist = tree[tindex+2]; + mode = DISTEXT; + break; + } + if ((e & 64) == 0){ // next table + need = e; + tree_index = tindex/3 + tree[tindex+2]; + break; + } + mode = BADCODE; // invalid code + z.msg = "invalid distance code"; + r = Z_DATA_ERROR; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(z,r); + + case DISTEXT: // i: getting distance extra + j = get; + + while(k<(j)){ + if(n!=0)r=Z_OK; + else{ + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + return s.inflate_flush(z,r); + } + n--; b|=(z.next_in[p++]&0xff)<>=j; + k-=j; + + mode = COPY; + goto case COPY; + case COPY: // o: copying bytes in window, waiting for space + f = q - dist; + while(f < 0){ // modulo window size-"while" instead + f += s.end; // of "if" handles invalid distances + } + while (len!=0){ + + if(m==0){ + if(q==s.end&&s.read!=0){q=0;m=q 7){ // return unused byte, if any + k -= 8; + n++; + p--; // can always return one + } + + s.write=q; r=s.inflate_flush(z,r); + q=s.write;m=q= 258 && n >= 10 + // get literal/length code + while(k<(20)){ // max bits for literal/length code + n--; + b|=(z.next_in[p++]&0xff)<>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); + + s.window[q++] = (byte)tp[tp_index_t_3+2]; + m--; + continue; + } + do { + + b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); + + if((e&16)!=0){ + e &= 15; + c = tp[tp_index_t_3+2] + ((int)b & inflate_mask[e]); + + b>>=e; k-=e; + + // decode distance base of block to copy + while(k<(15)){ // max bits for distance code + n--; + b|=(z.next_in[p++]&0xff)<>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); + + if((e&16)!=0){ + // get extra bits to add to distance base + e &= 15; + while(k<(e)){ // get extra bits (up to 13) + n--; + b|=(z.next_in[p++]&0xff)<>=(e); k-=(e); + + // do the copy + m -= c; + if (q >= d){ // offset before dest + // just copy + r=q-d; + if(q-r>0 && 2>(q-r)){ + s.window[q++]=s.window[r++]; // minimum count is three, + s.window[q++]=s.window[r++]; // so unroll loop a little + c-=2; + } + else{ + System.Array.Copy(s.window, r, s.window, q, 2); + q+=2; r+=2; c-=2; + } + } + else{ // else offset after destination + r=q-d; + do{ + r+=s.end; // force pointer in window + }while(r<0); // covers invalid distances + e=s.end-r; + if(c>e){ // if source crosses, + c-=e; // wrapped copy + if(q-r>0 && e>(q-r)){ + do{s.window[q++] = s.window[r++];} + while(--e!=0); + } + else{ + System.Array.Copy(s.window, r, s.window, q, e); + q+=e; r+=e; e=0; + } + r = 0; // copy rest from start of window + } + + } + + // copy all or what's left + if(q-r>0 && c>(q-r)){ + do{s.window[q++] = s.window[r++];} + while(--c!=0); + } + else{ + System.Array.Copy(s.window, r, s.window, q, c); + q+=c; r+=c; c=0; + } + break; + } + else if((e&64)==0){ + t+=tp[tp_index_t_3+2]; + t+=(b&inflate_mask[e]); + tp_index_t_3=(tp_index+t)*3; + e=tp[tp_index_t_3]; + } + else{ + z.msg = "invalid distance code"; + + c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + + return Z_DATA_ERROR; + } + } + while(true); + break; + } + + if((e&64)==0){ + t+=tp[tp_index_t_3+2]; + t+=(b&inflate_mask[e]); + tp_index_t_3=(tp_index+t)*3; + if((e=tp[tp_index_t_3])==0){ + + b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); + + s.window[q++]=(byte)tp[tp_index_t_3+2]; + m--; + break; + } + } + else if((e&32)!=0){ + + c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + + return Z_STREAM_END; + } + else{ + z.msg="invalid literal/length code"; + + c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + + return Z_DATA_ERROR; + } + } + while(true); + } + while(m>=258 && n>= 10); + + // not enough input or output--restore pointers and return + c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3; + + s.bitb=b;s.bitk=k; + z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; + s.write=q; + + return Z_OK; + } + } +} \ No newline at end of file diff --git a/iTechSharp/System/util/zlib/InfTree.cs b/iTechSharp/System/util/zlib/InfTree.cs new file mode 100644 index 0000000..d7450d4 --- /dev/null +++ b/iTechSharp/System/util/zlib/InfTree.cs @@ -0,0 +1,523 @@ +using System; +/* + * $Id: InfTree.cs,v 1.1 2006/06/16 10:56:20 psoares33 Exp $ + * +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +namespace System.util.zlib { + + internal sealed class InfTree{ + + private const int MANY=1440; + + private const int Z_OK=0; + private const int Z_STREAM_END=1; + private const int Z_NEED_DICT=2; + private const int Z_ERRNO=-1; + private const int Z_STREAM_ERROR=-2; + private const int Z_DATA_ERROR=-3; + private const int Z_MEM_ERROR=-4; + private const int Z_BUF_ERROR=-5; + private const int Z_VERSION_ERROR=-6; + + private const int fixed_bl = 9; + private const int fixed_bd = 5; + + static int[] fixed_tl = { + 96,7,256, 0,8,80, 0,8,16, 84,8,115, + 82,7,31, 0,8,112, 0,8,48, 0,9,192, + 80,7,10, 0,8,96, 0,8,32, 0,9,160, + 0,8,0, 0,8,128, 0,8,64, 0,9,224, + 80,7,6, 0,8,88, 0,8,24, 0,9,144, + 83,7,59, 0,8,120, 0,8,56, 0,9,208, + 81,7,17, 0,8,104, 0,8,40, 0,9,176, + 0,8,8, 0,8,136, 0,8,72, 0,9,240, + 80,7,4, 0,8,84, 0,8,20, 85,8,227, + 83,7,43, 0,8,116, 0,8,52, 0,9,200, + 81,7,13, 0,8,100, 0,8,36, 0,9,168, + 0,8,4, 0,8,132, 0,8,68, 0,9,232, + 80,7,8, 0,8,92, 0,8,28, 0,9,152, + 84,7,83, 0,8,124, 0,8,60, 0,9,216, + 82,7,23, 0,8,108, 0,8,44, 0,9,184, + 0,8,12, 0,8,140, 0,8,76, 0,9,248, + 80,7,3, 0,8,82, 0,8,18, 85,8,163, + 83,7,35, 0,8,114, 0,8,50, 0,9,196, + 81,7,11, 0,8,98, 0,8,34, 0,9,164, + 0,8,2, 0,8,130, 0,8,66, 0,9,228, + 80,7,7, 0,8,90, 0,8,26, 0,9,148, + 84,7,67, 0,8,122, 0,8,58, 0,9,212, + 82,7,19, 0,8,106, 0,8,42, 0,9,180, + 0,8,10, 0,8,138, 0,8,74, 0,9,244, + 80,7,5, 0,8,86, 0,8,22, 192,8,0, + 83,7,51, 0,8,118, 0,8,54, 0,9,204, + 81,7,15, 0,8,102, 0,8,38, 0,9,172, + 0,8,6, 0,8,134, 0,8,70, 0,9,236, + 80,7,9, 0,8,94, 0,8,30, 0,9,156, + 84,7,99, 0,8,126, 0,8,62, 0,9,220, + 82,7,27, 0,8,110, 0,8,46, 0,9,188, + 0,8,14, 0,8,142, 0,8,78, 0,9,252, + 96,7,256, 0,8,81, 0,8,17, 85,8,131, + 82,7,31, 0,8,113, 0,8,49, 0,9,194, + 80,7,10, 0,8,97, 0,8,33, 0,9,162, + 0,8,1, 0,8,129, 0,8,65, 0,9,226, + 80,7,6, 0,8,89, 0,8,25, 0,9,146, + 83,7,59, 0,8,121, 0,8,57, 0,9,210, + 81,7,17, 0,8,105, 0,8,41, 0,9,178, + 0,8,9, 0,8,137, 0,8,73, 0,9,242, + 80,7,4, 0,8,85, 0,8,21, 80,8,258, + 83,7,43, 0,8,117, 0,8,53, 0,9,202, + 81,7,13, 0,8,101, 0,8,37, 0,9,170, + 0,8,5, 0,8,133, 0,8,69, 0,9,234, + 80,7,8, 0,8,93, 0,8,29, 0,9,154, + 84,7,83, 0,8,125, 0,8,61, 0,9,218, + 82,7,23, 0,8,109, 0,8,45, 0,9,186, + 0,8,13, 0,8,141, 0,8,77, 0,9,250, + 80,7,3, 0,8,83, 0,8,19, 85,8,195, + 83,7,35, 0,8,115, 0,8,51, 0,9,198, + 81,7,11, 0,8,99, 0,8,35, 0,9,166, + 0,8,3, 0,8,131, 0,8,67, 0,9,230, + 80,7,7, 0,8,91, 0,8,27, 0,9,150, + 84,7,67, 0,8,123, 0,8,59, 0,9,214, + 82,7,19, 0,8,107, 0,8,43, 0,9,182, + 0,8,11, 0,8,139, 0,8,75, 0,9,246, + 80,7,5, 0,8,87, 0,8,23, 192,8,0, + 83,7,51, 0,8,119, 0,8,55, 0,9,206, + 81,7,15, 0,8,103, 0,8,39, 0,9,174, + 0,8,7, 0,8,135, 0,8,71, 0,9,238, + 80,7,9, 0,8,95, 0,8,31, 0,9,158, + 84,7,99, 0,8,127, 0,8,63, 0,9,222, + 82,7,27, 0,8,111, 0,8,47, 0,9,190, + 0,8,15, 0,8,143, 0,8,79, 0,9,254, + 96,7,256, 0,8,80, 0,8,16, 84,8,115, + 82,7,31, 0,8,112, 0,8,48, 0,9,193, + + 80,7,10, 0,8,96, 0,8,32, 0,9,161, + 0,8,0, 0,8,128, 0,8,64, 0,9,225, + 80,7,6, 0,8,88, 0,8,24, 0,9,145, + 83,7,59, 0,8,120, 0,8,56, 0,9,209, + 81,7,17, 0,8,104, 0,8,40, 0,9,177, + 0,8,8, 0,8,136, 0,8,72, 0,9,241, + 80,7,4, 0,8,84, 0,8,20, 85,8,227, + 83,7,43, 0,8,116, 0,8,52, 0,9,201, + 81,7,13, 0,8,100, 0,8,36, 0,9,169, + 0,8,4, 0,8,132, 0,8,68, 0,9,233, + 80,7,8, 0,8,92, 0,8,28, 0,9,153, + 84,7,83, 0,8,124, 0,8,60, 0,9,217, + 82,7,23, 0,8,108, 0,8,44, 0,9,185, + 0,8,12, 0,8,140, 0,8,76, 0,9,249, + 80,7,3, 0,8,82, 0,8,18, 85,8,163, + 83,7,35, 0,8,114, 0,8,50, 0,9,197, + 81,7,11, 0,8,98, 0,8,34, 0,9,165, + 0,8,2, 0,8,130, 0,8,66, 0,9,229, + 80,7,7, 0,8,90, 0,8,26, 0,9,149, + 84,7,67, 0,8,122, 0,8,58, 0,9,213, + 82,7,19, 0,8,106, 0,8,42, 0,9,181, + 0,8,10, 0,8,138, 0,8,74, 0,9,245, + 80,7,5, 0,8,86, 0,8,22, 192,8,0, + 83,7,51, 0,8,118, 0,8,54, 0,9,205, + 81,7,15, 0,8,102, 0,8,38, 0,9,173, + 0,8,6, 0,8,134, 0,8,70, 0,9,237, + 80,7,9, 0,8,94, 0,8,30, 0,9,157, + 84,7,99, 0,8,126, 0,8,62, 0,9,221, + 82,7,27, 0,8,110, 0,8,46, 0,9,189, + 0,8,14, 0,8,142, 0,8,78, 0,9,253, + 96,7,256, 0,8,81, 0,8,17, 85,8,131, + 82,7,31, 0,8,113, 0,8,49, 0,9,195, + 80,7,10, 0,8,97, 0,8,33, 0,9,163, + 0,8,1, 0,8,129, 0,8,65, 0,9,227, + 80,7,6, 0,8,89, 0,8,25, 0,9,147, + 83,7,59, 0,8,121, 0,8,57, 0,9,211, + 81,7,17, 0,8,105, 0,8,41, 0,9,179, + 0,8,9, 0,8,137, 0,8,73, 0,9,243, + 80,7,4, 0,8,85, 0,8,21, 80,8,258, + 83,7,43, 0,8,117, 0,8,53, 0,9,203, + 81,7,13, 0,8,101, 0,8,37, 0,9,171, + 0,8,5, 0,8,133, 0,8,69, 0,9,235, + 80,7,8, 0,8,93, 0,8,29, 0,9,155, + 84,7,83, 0,8,125, 0,8,61, 0,9,219, + 82,7,23, 0,8,109, 0,8,45, 0,9,187, + 0,8,13, 0,8,141, 0,8,77, 0,9,251, + 80,7,3, 0,8,83, 0,8,19, 85,8,195, + 83,7,35, 0,8,115, 0,8,51, 0,9,199, + 81,7,11, 0,8,99, 0,8,35, 0,9,167, + 0,8,3, 0,8,131, 0,8,67, 0,9,231, + 80,7,7, 0,8,91, 0,8,27, 0,9,151, + 84,7,67, 0,8,123, 0,8,59, 0,9,215, + 82,7,19, 0,8,107, 0,8,43, 0,9,183, + 0,8,11, 0,8,139, 0,8,75, 0,9,247, + 80,7,5, 0,8,87, 0,8,23, 192,8,0, + 83,7,51, 0,8,119, 0,8,55, 0,9,207, + 81,7,15, 0,8,103, 0,8,39, 0,9,175, + 0,8,7, 0,8,135, 0,8,71, 0,9,239, + 80,7,9, 0,8,95, 0,8,31, 0,9,159, + 84,7,99, 0,8,127, 0,8,63, 0,9,223, + 82,7,27, 0,8,111, 0,8,47, 0,9,191, + 0,8,15, 0,8,143, 0,8,79, 0,9,255 + }; + static int[] fixed_td = { + 80,5,1, 87,5,257, 83,5,17, 91,5,4097, + 81,5,5, 89,5,1025, 85,5,65, 93,5,16385, + 80,5,3, 88,5,513, 84,5,33, 92,5,8193, + 82,5,9, 90,5,2049, 86,5,129, 192,5,24577, + 80,5,2, 87,5,385, 83,5,25, 91,5,6145, + 81,5,7, 89,5,1537, 85,5,97, 93,5,24577, + 80,5,4, 88,5,769, 84,5,49, 92,5,12289, + 82,5,13, 90,5,3073, 86,5,193, 192,5,24577 + }; + + // Tables for deflate from PKZIP's appnote.txt. + static int[] cplens = { // Copy lengths for literal codes 257..285 + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 + }; + + // see note #13 above about 258 + static int[] cplext = { // Extra bits for literal codes 257..285 + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112 // 112==invalid + }; + + static int[] cpdist = { // Copy offsets for distance codes 0..29 + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577 + }; + + static int[] cpdext = { // Extra bits for distance codes + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + // If BMAX needs to be larger than 16, then h and x[] should be uLong. + const int BMAX=15; // maximum bit length of any code + + int[] hn = null; // hufts used in space + int[] v = null; // work area for huft_build + int[] c = null; // bit length count table + int[] r = null; // table entry for structure assignment + int[] u = null; // table stack + int[] x = null; // bit offsets, then code stack + + private int huft_build(int[] b, // code lengths in bits (all assumed <= BMAX) + int bindex, + int n, // number of codes (assumed <= 288) + int s, // number of simple-valued codes (0..s-1) + int[] d, // list of base values for non-simple codes + int[] e, // list of extra bits for non-simple codes + int[] t, // result: starting table + int[] m, // maximum lookup bits, returns actual + int[] hp,// space for trees + int[] hn,// hufts used in space + int[] v // working area: values in order of bit length + ){ + // Given a list of code lengths and a maximum table size, make a set of + // tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + // if the given code set is incomplete (the tables are still built in this + // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + // lengths), or Z_MEM_ERROR if not enough memory. + + int a; // counter for codes of length k + int f; // i repeats in table every f entries + int g; // maximum code length + int h; // table level + int i; // counter, current code + int j; // counter + int k; // number of bits in current code + int l; // bits per table (returned in m) + int mask; // (1 << w) - 1, to avoid cc -O bug on HP + int p; // pointer into c[], b[], or v[] + int q; // points to current table + int w; // bits before this table == (l * h) + int xp; // pointer into x + int y; // number of dummy codes added + int z; // number of entries in current table + + // Generate counts for each bit length + + p = 0; i = n; + do { + c[b[bindex+p]]++; p++; i--; // assume all entries <= BMAX + }while(i!=0); + + if(c[0] == n){ // null input--all zero length codes + t[0] = -1; + m[0] = 0; + return Z_OK; + } + + // Find minimum and maximum length, bound *m by those + l = m[0]; + for (j = 1; j <= BMAX; j++) + if(c[j]!=0) break; + k = j; // minimum code length + if(l < j){ + l = j; + } + for (i = BMAX; i!=0; i--){ + if(c[i]!=0) break; + } + g = i; // maximum code length + if(l > i){ + l = i; + } + m[0] = l; + + // Adjust last length count to fill out codes, if needed + for (y = 1 << j; j < i; j++, y <<= 1){ + if ((y -= c[j]) < 0){ + return Z_DATA_ERROR; + } + } + if ((y -= c[i]) < 0){ + return Z_DATA_ERROR; + } + c[i] += y; + + // Generate starting offsets into the value table for each length + x[1] = j = 0; + p = 1; xp = 2; + while (--i!=0) { // note that i == g from above + x[xp] = (j += c[p]); + xp++; + p++; + } + + // Make a table of values in order of bit lengths + i = 0; p = 0; + do { + if ((j = b[bindex+p]) != 0){ + v[x[j]++] = i; + } + p++; + } + while (++i < n); + n = x[g]; // set n to length of v + + // Generate the Huffman codes and for each, make the table entries + x[0] = i = 0; // first Huffman code is zero + p = 0; // grab values in bit order + h = -1; // no tables yet--level -1 + w = -l; // bits decoded == (l * h) + u[0] = 0; // just to keep compilers happy + q = 0; // ditto + z = 0; // ditto + + // go through the bit lengths (k already is bits in shortest code) + for (; k <= g; k++){ + a = c[k]; + while (a--!=0){ + // here i is the Huffman code of length k bits for value *p + // make tables up to required level + while (k > w + l){ + h++; + w += l; // previous table always l bits + // compute minimum size table less than or equal to l bits + z = g - w; + z = (z > l) ? l : z; // table size upper limit + if((f=1<<(j=k-w))>a+1){ // try a k-w bit table + // too few codes for k-w bit table + f -= a + 1; // deduct codes from patterns left + xp = k; + if(j < z){ + while (++j < z){ // try smaller tables up to z bits + if((f <<= 1) <= c[++xp]) + break; // enough codes to use up j bits + f -= c[xp]; // else deduct codes from patterns + } + } + } + z = 1 << j; // table entries for j-bit table + + // allocate new table + if (hn[0] + z > MANY){ // (note: doesn't matter for fixed) + return Z_DATA_ERROR; // overflow of MANY + } + u[h] = q = /*hp+*/ hn[0]; // DEBUG + hn[0] += z; + + // connect to last table, if there is one + if(h!=0){ + x[h]=i; // save pattern for backing up + r[0]=(byte)j; // bits in this table + r[1]=(byte)l; // bits to dump before this table + j=i>>(w - l); + r[2] = (int)(q - u[h-1] - j); // offset to this table + System.Array.Copy(r, 0, hp, (u[h-1]+j)*3, 3); // connect to last table + } + else{ + t[0] = q; // first table is returned result + } + } + + // set up table entry in r + r[1] = (byte)(k - w); + if (p >= n){ + r[0] = 128 + 64; // out of values--invalid code + } + else if (v[p] < s){ + r[0] = (byte)(v[p] < 256 ? 0 : 32 + 64); // 256 is end-of-block + r[2] = v[p++]; // simple code is just the value + } + else{ + r[0]=(byte)(e[v[p]-s]+16+64); // non-simple--look up in lists + r[2]=d[v[p++] - s]; + } + + // fill code-like entries with r + f=1<<(k-w); + for (j=i>>w;j>= 1){ + i ^= j; + } + i ^= j; + + // backup over finished tables + mask = (1 << w) - 1; // needed on HP, cc -O bug + while ((i & mask) != x[h]){ + h--; // don't need to update q + w -= l; + mask = (1 << w) - 1; + } + } + } + // Return Z_BUF_ERROR if we were given an incomplete table + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; + } + + internal int inflate_trees_bits(int[] c, // 19 code lengths + int[] bb, // bits tree desired/actual depth + int[] tb, // bits tree result + int[] hp, // space for trees + ZStream z // for messages + ){ + int result; + initWorkArea(19); + hn[0]=0; + result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v); + + if(result == Z_DATA_ERROR){ + z.msg = "oversubscribed dynamic bit lengths tree"; + } + else if(result == Z_BUF_ERROR || bb[0] == 0){ + z.msg = "incomplete dynamic bit lengths tree"; + result = Z_DATA_ERROR; + } + return result; + } + + internal int inflate_trees_dynamic(int nl, // number of literal/length codes + int nd, // number of distance codes + int[] c, // that many (total) code lengths + int[] bl, // literal desired/actual bit depth + int[] bd, // distance desired/actual bit depth + int[] tl, // literal/length tree result + int[] td, // distance tree result + int[] hp, // space for trees + ZStream z // for messages + ){ + int result; + + // build literal/length tree + initWorkArea(288); + hn[0]=0; + result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v); + if (result != Z_OK || bl[0] == 0){ + if(result == Z_DATA_ERROR){ + z.msg = "oversubscribed literal/length tree"; + } + else if (result != Z_MEM_ERROR){ + z.msg = "incomplete literal/length tree"; + result = Z_DATA_ERROR; + } + return result; + } + + // build distance tree + initWorkArea(288); + result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v); + + if (result != Z_OK || (bd[0] == 0 && nl > 257)){ + if (result == Z_DATA_ERROR){ + z.msg = "oversubscribed distance tree"; + } + else if (result == Z_BUF_ERROR) { + z.msg = "incomplete distance tree"; + result = Z_DATA_ERROR; + } + else if (result != Z_MEM_ERROR){ + z.msg = "empty distance tree with lengths"; + result = Z_DATA_ERROR; + } + return result; + } + + return Z_OK; + } + + internal static int inflate_trees_fixed(int[] bl, //literal desired/actual bit depth + int[] bd, //distance desired/actual bit depth + int[][] tl,//literal/length tree result + int[][] td,//distance tree result + ZStream z //for memory allocation + ){ + bl[0]=fixed_bl; + bd[0]=fixed_bd; + tl[0]=fixed_tl; + td[0]=fixed_td; + return Z_OK; + } + + private void initWorkArea(int vsize){ + if(hn==null){ + hn=new int[1]; + v=new int[vsize]; + c=new int[BMAX+1]; + r=new int[3]; + u=new int[BMAX]; + x=new int[BMAX+1]; + } + if(v.Lengthstate); + return Z_OK; + } + + internal int inflateInit(ZStream z, int w){ + z.msg = null; + blocks = null; + + // handle undocumented nowrap option (no zlib header or check) + nowrap = 0; + if(w < 0){ + w = - w; + nowrap = 1; + } + + // set window size + if(w<8 ||w>15){ + inflateEnd(z); + return Z_STREAM_ERROR; + } + wbits=w; + + z.istate.blocks=new InfBlocks(z, + z.istate.nowrap!=0 ? null : this, + 1<>4)+8>z.istate.wbits){ + z.istate.mode = BAD; + z.msg="invalid window size"; + z.istate.marker = 5; // can't try inflateSync + break; + } + z.istate.mode=FLAG; + goto case FLAG; + case FLAG: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + b = (z.next_in[z.next_in_index++])&0xff; + + if((((z.istate.method << 8)+b) % 31)!=0){ + z.istate.mode = BAD; + z.msg = "incorrect header check"; + z.istate.marker = 5; // can't try inflateSync + break; + } + + if((b&PRESET_DICT)==0){ + z.istate.mode = BLOCKS; + break; + } + z.istate.mode = DICT4; + goto case DICT4; + case DICT4: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L; + z.istate.mode=DICT3; + goto case DICT3; + case DICT3: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L; + z.istate.mode=DICT2; + goto case DICT2; + case DICT2: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L; + z.istate.mode=DICT1; + goto case DICT1; + case DICT1: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need += (z.next_in[z.next_in_index++]&0xffL); + z.adler = z.istate.need; + z.istate.mode = DICT0; + return Z_NEED_DICT; + case DICT0: + z.istate.mode = BAD; + z.msg = "need dictionary"; + z.istate.marker = 0; // can try inflateSync + return Z_STREAM_ERROR; + case BLOCKS: + + r = z.istate.blocks.proc(z, r); + if(r == Z_DATA_ERROR){ + z.istate.mode = BAD; + z.istate.marker = 0; // can try inflateSync + break; + } + if(r == Z_OK){ + r = f; + } + if(r != Z_STREAM_END){ + return r; + } + r = f; + z.istate.blocks.reset(z, z.istate.was); + if(z.istate.nowrap!=0){ + z.istate.mode=DONE; + break; + } + z.istate.mode=CHECK4; + goto case CHECK4; + case CHECK4: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L; + z.istate.mode=CHECK3; + goto case CHECK3; + case CHECK3: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L; + z.istate.mode = CHECK2; + goto case CHECK2; + case CHECK2: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L; + z.istate.mode = CHECK1; + goto case CHECK1; + case CHECK1: + + if(z.avail_in==0)return r;r=f; + + z.avail_in--; z.total_in++; + z.istate.need+=(z.next_in[z.next_in_index++]&0xffL); + + if(((int)(z.istate.was[0])) != ((int)(z.istate.need))){ + z.istate.mode = BAD; + z.msg = "incorrect data check"; + z.istate.marker = 5; // can't try inflateSync + break; + } + + z.istate.mode = DONE; + goto case DONE; + case DONE: + return Z_STREAM_END; + case BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } + } + } + + + internal int inflateSetDictionary(ZStream z, byte[] dictionary, int dictLength){ + int index=0; + int length = dictLength; + if(z==null || z.istate == null|| z.istate.mode != DICT0) + return Z_STREAM_ERROR; + + if(z._adler.adler32(1L, dictionary, 0, dictLength)!=z.adler){ + return Z_DATA_ERROR; + } + + z.adler = z._adler.adler32(0, null, 0, 0); + + if(length >= (1<>7)]); + } + + internal short[] dyn_tree; // the dynamic tree + internal int max_code; // largest code with non zero frequency + internal StaticTree stat_desc; // the corresponding static tree + + // Compute the optimal bit lengths for a tree and update the total bit length + // for the current block. + // IN assertion: the fields freq and dad are set, heap[heap_max] and + // above are the tree nodes sorted by increasing frequency. + // OUT assertions: the field len is set to the optimal bit length, the + // array bl_count contains the frequencies for each bit length. + // The length opt_len is updated; static_len is also updated if stree is + // not null. + internal void gen_bitlen(Deflate s){ + short[] tree = dyn_tree; + short[] stree = stat_desc.static_tree; + int[] extra = stat_desc.extra_bits; + int based = stat_desc.extra_base; + int max_length = stat_desc.max_length; + int h; // heap index + int n, m; // iterate over the tree elements + int bits; // bit length + int xbits; // extra bits + short f; // frequency + int overflow = 0; // number of elements with bit length too large + + for (bits = 0; bits <= MAX_BITS; bits++) s.bl_count[bits] = 0; + + // In a first pass, compute the optimal bit lengths (which may + // overflow in the case of the bit length tree). + tree[s.heap[s.heap_max]*2+1] = 0; // root of the heap + + for(h=s.heap_max+1; h max_length){ bits = max_length; overflow++; } + tree[n*2+1] = (short)bits; + // We overwrite tree[n*2+1] which is no longer needed + + if (n > max_code) continue; // not a leaf node + + s.bl_count[bits]++; + xbits = 0; + if (n >= based) xbits = extra[n-based]; + f = tree[n*2]; + s.opt_len += f * (bits + xbits); + if (stree!=null) s.static_len += f * (stree[n*2+1] + xbits); + } + if (overflow == 0) return; + + // This happens for example on obj2 and pic of the Calgary corpus + // Find the first bit length which could increase: + do { + bits = max_length-1; + while(s.bl_count[bits]==0) bits--; + s.bl_count[bits]--; // move one leaf down the tree + s.bl_count[bits+1]+=2; // move one overflow item as its brother + s.bl_count[max_length]--; + // The brother of the overflow item also moves one step up, + // but this does not affect bl_count[max_length] + overflow -= 2; + } + while (overflow > 0); + + for (bits = max_length; bits != 0; bits--) { + n = s.bl_count[bits]; + while (n != 0) { + m = s.heap[--h]; + if (m > max_code) continue; + if (tree[m*2+1] != bits) { + s.opt_len += (int)(((long)bits - (long)tree[m*2+1])*(long)tree[m*2]); + tree[m*2+1] = (short)bits; + } + n--; + } + } + } + + // Construct one Huffman tree and assigns the code bit strings and lengths. + // Update the total bit length for the current block. + // IN assertion: the field freq is set for all tree elements. + // OUT assertions: the fields len and code are set to the optimal bit length + // and corresponding code. The length opt_len is updated; static_len is + // also updated if stree is not null. The field max_code is set. + internal void build_tree(Deflate s){ + short[] tree=dyn_tree; + short[] stree=stat_desc.static_tree; + int elems=stat_desc.elems; + int n, m; // iterate over heap elements + int max_code=-1; // largest code with non zero frequency + int node; // new node being created + + // Construct the initial heap, with least frequent element in + // heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + // heap[0] is not used. + s.heap_len = 0; + s.heap_max = HEAP_SIZE; + + for(n=0; n=1; n--) + s.pqdownheap(tree, n); + + // Construct the Huffman tree by repeatedly combining the least two + // frequent nodes. + + node=elems; // next internal node of the tree + do{ + // n = node of least frequency + n=s.heap[1]; + s.heap[1]=s.heap[s.heap_len--]; + s.pqdownheap(tree, 1); + m=s.heap[1]; // m = node of next least frequency + + s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency + s.heap[--s.heap_max] = m; + + // Create a new node father of n and m + tree[node*2] = (short)(tree[n*2] + tree[m*2]); + s.depth[node] = (byte)(System.Math.Max(s.depth[n],s.depth[m])+1); + tree[n*2+1] = tree[m*2+1] = (short)node; + + // and insert the new node in the heap + s.heap[1] = node++; + s.pqdownheap(tree, 1); + } + while(s.heap_len>=2); + + s.heap[--s.heap_max] = s.heap[1]; + + // At this point, the fields freq and dad are set. We can now + // generate the bit lengths. + + gen_bitlen(s); + + // The field len is now set, we can generate the bit codes + gen_codes(tree, max_code, s.bl_count); + } + + // Generate the codes for a given tree and bit counts (which need not be + // optimal). + // IN assertion: the array bl_count contains the bit length statistics for + // the given tree and the field len is set for all tree elements. + // OUT assertion: the field code is set for all tree elements of non + // zero code length. + internal static void gen_codes(short[] tree, // the tree to decorate + int max_code, // largest code with non zero frequency + short[] bl_count // number of codes at each bit length + ){ + short[] next_code=new short[MAX_BITS+1]; // next code value for each bit length + short code = 0; // running code value + int bits; // bit index + int n; // code index + + // The distribution counts are first used to generate the code values + // without bit reversal. + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (short)((code + bl_count[bits-1]) << 1); + } + + // Check that the bit counts in bl_count are consistent. The last code + // must be all ones. + //Assert (code + bl_count[MAX_BITS]-1 == (1<>=1; + res<<=1; + } + while(--len>0); + return res>>1; + } + } +} \ No newline at end of file diff --git a/iTechSharp/System/util/zlib/ZDeflaterOutputStream.cs b/iTechSharp/System/util/zlib/ZDeflaterOutputStream.cs new file mode 100644 index 0000000..dc5e75a --- /dev/null +++ b/iTechSharp/System/util/zlib/ZDeflaterOutputStream.cs @@ -0,0 +1,196 @@ +using System; +using System.IO; +/* + * $Id: ZDeflaterOutputStream.cs,v 1.3 2007/06/22 14:14:13 psoares33 Exp $ + * + * Copyright 2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License isp distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code isp 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code isp Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code isp Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library isp free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library isp distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace System.util.zlib { + /// + /// Summary description for DeflaterOutputStream. + /// + public class ZDeflaterOutputStream : Stream { + protected ZStream z=new ZStream(); + protected int flushLevel=JZlib.Z_NO_FLUSH; + private const int BUFSIZE = 4192; + protected byte[] buf=new byte[BUFSIZE]; + private byte[] buf1=new byte[1]; + + protected Stream outp; + + public ZDeflaterOutputStream(Stream outp) : this(outp, 6, false) { + } + + public ZDeflaterOutputStream(Stream outp, int level) : this(outp, level, false) { + } + + public ZDeflaterOutputStream(Stream outp, int level, bool nowrap) { + this.outp=outp; + z.deflateInit(level, nowrap); + } + + + public override bool CanRead { + get { + // TODO: Add DeflaterOutputStream.CanRead getter implementation + return false; + } + } + + public override bool CanSeek { + get { + // TODO: Add DeflaterOutputStream.CanSeek getter implementation + return false; + } + } + + public override bool CanWrite { + get { + // TODO: Add DeflaterOutputStream.CanWrite getter implementation + return true; + } + } + + public override long Length { + get { + // TODO: Add DeflaterOutputStream.Length getter implementation + return 0; + } + } + + public override long Position { + get { + // TODO: Add DeflaterOutputStream.Position getter implementation + return 0; + } + set { + // TODO: Add DeflaterOutputStream.Position setter implementation + } + } + + public override void Write(byte[] b, int off, int len) { + if(len==0) + return; + int err; + z.next_in=b; + z.next_in_index=off; + z.avail_in=len; + do{ + z.next_out=buf; + z.next_out_index=0; + z.avail_out=BUFSIZE; + err=z.deflate(flushLevel); + if(err!=JZlib.Z_OK) + throw new IOException("deflating: "+z.msg); + if (z.avail_out < BUFSIZE) + outp.Write(buf, 0, BUFSIZE-z.avail_out); + } + while(z.avail_in>0 || z.avail_out==0); + } + + public override long Seek(long offset, SeekOrigin origin) { + // TODO: Add DeflaterOutputStream.Seek implementation + return 0; + } + + public override void SetLength(long value) { + // TODO: Add DeflaterOutputStream.SetLength implementation + + } + + public override int Read(byte[] buffer, int offset, int count) { + // TODO: Add DeflaterOutputStream.Read implementation + return 0; + } + + public override void Flush() { + outp.Flush(); + } + + public override void WriteByte(byte b) { + buf1[0]=(byte)b; + Write(buf1, 0, 1); + } + + public void Finish() { + int err; + do{ + z.next_out=buf; + z.next_out_index=0; + z.avail_out=BUFSIZE; + err=z.deflate(JZlib.Z_FINISH); + if(err!=JZlib.Z_STREAM_END && err != JZlib.Z_OK) + throw new IOException("deflating: "+z.msg); + if(BUFSIZE-z.avail_out>0){ + outp.Write(buf, 0, BUFSIZE-z.avail_out); + } + } + while(z.avail_in>0 || z.avail_out==0); + Flush(); + } + + public void End() { + if(z==null) + return; + z.deflateEnd(); + z.free(); + z=null; + } + + public override void Close() { + try{ + try{Finish();} + catch (IOException) {} + } + finally{ + End(); + outp.Close(); + outp=null; + } + } + } +} diff --git a/iTechSharp/System/util/zlib/ZInflaterInputStream.cs b/iTechSharp/System/util/zlib/ZInflaterInputStream.cs new file mode 100644 index 0000000..c8ed40c --- /dev/null +++ b/iTechSharp/System/util/zlib/ZInflaterInputStream.cs @@ -0,0 +1,174 @@ +using System; +using System.IO; +/* + * $Id: ZInflaterInputStream.cs,v 1.4 2007/06/22 14:14:16 psoares33 Exp $ + * + * Copyright 2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License isp distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code isp 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code isp Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code isp Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library isp free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library isp distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace System.util.zlib { + /// + /// Summary description for DeflaterOutputStream. + /// + public class ZInflaterInputStream : Stream { + protected ZStream z=new ZStream(); + protected int flushLevel=JZlib.Z_NO_FLUSH; + private const int BUFSIZE = 4192; + protected byte[] buf=new byte[BUFSIZE]; + private byte[] buf1=new byte[1]; + + protected Stream inp=null; + private bool nomoreinput=false; + + public ZInflaterInputStream(Stream inp) : this(inp, false) { + } + + public ZInflaterInputStream(Stream inp, bool nowrap) { + this.inp=inp; + z.inflateInit(nowrap); + z.next_in=buf; + z.next_in_index=0; + z.avail_in=0; + } + + public override bool CanRead { + get { + // TODO: Add DeflaterOutputStream.CanRead getter implementation + return true; + } + } + + public override bool CanSeek { + get { + // TODO: Add DeflaterOutputStream.CanSeek getter implementation + return false; + } + } + + public override bool CanWrite { + get { + // TODO: Add DeflaterOutputStream.CanWrite getter implementation + return false; + } + } + + public override long Length { + get { + // TODO: Add DeflaterOutputStream.Length getter implementation + return 0; + } + } + + public override long Position { + get { + // TODO: Add DeflaterOutputStream.Position getter implementation + return 0; + } + set { + // TODO: Add DeflaterOutputStream.Position setter implementation + } + } + + public override void Write(byte[] b, int off, int len) { + } + + public override long Seek(long offset, SeekOrigin origin) { + // TODO: Add DeflaterOutputStream.Seek implementation + return 0; + } + + public override void SetLength(long value) { + // TODO: Add DeflaterOutputStream.SetLength implementation + + } + + public override int Read(byte[] b, int off, int len) { + if(len==0) + return(0); + int err; + z.next_out=b; + z.next_out_index=off; + z.avail_out=len; + do { + if((z.avail_in==0)&&(!nomoreinput)) { // if buffer is empty and more input is avaiable, refill it + z.next_in_index=0; + z.avail_in=inp.Read(buf, 0, BUFSIZE);//(BUFSIZEnext_out buffer and copying into it. + // (See also read_buf()). + internal void flush_pending(){ + int len=dstate.pending; + + if(len>avail_out) len=avail_out; + if(len==0) return; + + if(dstate.pending_buf.Length<=dstate.pending_out || + next_out.Length<=next_out_index || + dstate.pending_buf.Length<(dstate.pending_out+len) || + next_out.Length<(next_out_index+len)){ + // System.out.println(dstate.pending_buf.length+", "+dstate.pending_out+ + // ", "+next_out.length+", "+next_out_index+", "+len); + // System.out.println("avail_out="+avail_out); + } + + System.Array.Copy(dstate.pending_buf, dstate.pending_out, + next_out, next_out_index, len); + + next_out_index+=len; + dstate.pending_out+=len; + total_out+=len; + avail_out-=len; + dstate.pending-=len; + if(dstate.pending==0){ + dstate.pending_out=0; + } + } + + // Read a new buffer from the current input stream, update the adler32 + // and total number of bytes read. All deflate() input goes through + // this function so some applications may wish to modify it to avoid + // allocating a large strm->next_in buffer and copying from it. + // (See also flush_pending()). + internal int read_buf(byte[] buf, int start, int size) { + int len=avail_in; + + if(len>size) len=size; + if(len==0) return 0; + + avail_in-=len; + + if(dstate.noheader==0) { + adler=_adler.adler32(adler, next_in, next_in_index, len); + } + System.Array.Copy(next_in, next_in_index, buf, start, len); + next_in_index += len; + total_in += len; + return len; + } + + public void free(){ + next_in=null; + next_out=null; + msg=null; + _adler=null; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/Anchor.cs b/iTechSharp/iTextSharp/text/Anchor.cs new file mode 100644 index 0000000..3b7849c --- /dev/null +++ b/iTechSharp/iTextSharp/text/Anchor.cs @@ -0,0 +1,284 @@ +using System; +using System.Collections; +using System.util; + +using iTextSharp.text.html; +using iTextSharp.text.factories; + +/* + * $Id: Anchor.cs,v 1.9 2008/05/13 11:25:08 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iTextSharp, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text +{ + /// + /// An Anchor can be a reference or a destination of a reference. + /// + /// + /// An Anchor is a special kind of . + /// It is constructed in the same way. + /// + /// + /// + public class Anchor : Phrase + { + + // membervariables + + /// + /// This is the name of the Anchor. + /// + protected string name = null; + + /// + /// This is the reference of the Anchor. + /// + protected string reference = null; + + // constructors + + /// + /// Constructs an Anchor without specifying a leading. + /// + /// + /// Has nine overloads. + /// + public Anchor() : base(16) {} + + /// + /// Constructs an Anchor with a certain leading. + /// + /// the leading + public Anchor(float leading) : base(leading) {} + + /// + /// Constructs an Anchor with a certain Chunk. + /// + /// a Chunk + public Anchor(Chunk chunk) : base(chunk) {} + + /// + /// Constructs an Anchor with a certain string. + /// + /// a string + public Anchor(string str) : base(str) {} + + /// + /// Constructs an Anchor with a certain string + /// and a certain Font. + /// + /// a string + /// a Font + public Anchor(string str, Font font) : base(str, font) {} + + /// + /// Constructs an Anchor with a certain Chunk + /// and a certain leading. + /// + /// the leading + /// a Chunk + public Anchor(float leading, Chunk chunk) : base(leading, chunk) {} + + /// + /// Constructs an Anchor with a certain leading + /// and a certain string. + /// + /// the leading + /// a string + public Anchor(float leading, string str) : base(leading, str) {} + + /// + /// Constructs an Anchor with a certain leading, + /// a certain string and a certain Font. + /// + /// the leading + /// a string + /// a Font + public Anchor(float leading, string str, Font font) : base(leading, str, font) {} + + /** + * Constructs an Anchor with a certain Phrase. + * + * @param phrase a Phrase + */ + public Anchor(Phrase phrase) : base(phrase) { + if (phrase is Anchor) { + Anchor a = (Anchor) phrase; + Name = a.name; + Reference = a.reference; + } + } + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// + /// + /// an IElementListener + /// true if the element was processed successfully + public override bool Process(IElementListener listener) + { + try + { + bool localDestination = (reference != null && reference.StartsWith("#")); + bool notGotoOK = true; + foreach (Chunk chunk in this.Chunks) + { + if (name != null && notGotoOK && !chunk.IsEmpty()) + { + chunk.SetLocalDestination(name); + notGotoOK = false; + } + if (localDestination) + { + chunk.SetLocalGoto(reference.Substring(1)); + } + else if (reference != null) + chunk.SetAnchor(reference); + listener.Add(chunk); + } + return true; + } + catch (DocumentException) + { + return false; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public override ArrayList Chunks + { + get + { + ArrayList tmp = new ArrayList(); + bool localDestination = (reference != null && reference.StartsWith("#")); + bool notGotoOK = true; + foreach (Chunk chunk in this) + { + if (name != null && notGotoOK && !chunk.IsEmpty()) + { + chunk.SetLocalDestination(name); + notGotoOK = false; + } + if (localDestination) + { + chunk.SetLocalGoto(reference.Substring(1)); + } + else if (reference != null) + { + chunk.SetAnchor(reference); + } + + tmp.Add(chunk); + } + return tmp; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public override int Type + { + get + { + return Element.ANCHOR; + } + } + + // methods + + /// + /// Name of this Anchor. + /// + public string Name { + get { + return this.name; + } + + set { + this.name = value; + } + } + + // methods to retrieve information + + /// + /// reference of this Anchor. + /// + public string Reference { + get { + return reference; + } + + set { + this.reference = value; + } + } + + /// + /// reference of this Anchor. + /// + /// an Uri + public Uri Url { + get { + try { + return new Uri(reference); + } + catch { + return null; + } + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/Annotation.cs b/iTechSharp/iTextSharp/text/Annotation.cs new file mode 100644 index 0000000..dd61c44 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Annotation.cs @@ -0,0 +1,525 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text.factories; + +/* + * $Id: Annotation.cs,v 1.12 2008/05/13 11:25:08 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text +{ + /// + /// An Annotation is a little note that can be added to a page + /// on a document. + /// + /// + /// + public class Annotation : IElement + { + + // membervariables + + /// This is a possible annotation type. + public const int TEXT = 0; + /// This is a possible annotation type. + public const int URL_NET = 1; + /// This is a possible annotation type. + public const int URL_AS_STRING = 2; + /// This is a possible annotation type. + public const int FILE_DEST = 3; + /// This is a possible annotation type. + public const int FILE_PAGE = 4; + /// This is a possible annotation type. + public const int NAMED_DEST = 5; + /// This is a possible annotation type. + public const int LAUNCH = 6; + /// This is a possible annotation type. + public const int SCREEN = 7; + + /// This is a possible attribute. + public const string TITLE = "title"; + /// This is a possible attribute. + public const string CONTENT = "content"; + /// This is a possible attribute. + public const string URL = "url"; + /// This is a possible attribute. + public const string FILE = "file"; + /// This is a possible attribute. + public const string DESTINATION = "destination"; + /// This is a possible attribute. + public const string PAGE = "page"; + /// This is a possible attribute. + public const string NAMED = "named"; + /// This is a possible attribute. + public const string APPLICATION = "application"; + /// This is a possible attribute. + public const string PARAMETERS = "parameters"; + /// This is a possible attribute. + public const string OPERATION = "operation"; + /// This is a possible attribute. + public const string DEFAULTDIR = "defaultdir"; + /// This is a possible attribute. + public const string LLX = "llx"; + /// This is a possible attribute. + public const string LLY = "lly"; + /// This is a possible attribute. + public const string URX = "urx"; + /// This is a possible attribute. + public const string URY = "ury"; + /// This is a possible attribute. + public const string MIMETYPE = "mime"; + + /// This is the type of annotation. + protected int annotationtype; + + /// This is the title of the Annotation. + protected Hashtable annotationAttributes = new Hashtable(); + + /// This is the lower left x-value + private float llx = float.NaN; + /// This is the lower left y-value + private float lly = float.NaN; + /// This is the upper right x-value + private float urx = float.NaN; + /// This is the upper right y-value + private float ury = float.NaN; + + // constructors + + /// + /// Constructs an Annotation with a certain title and some text. + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + private Annotation(float llx, float lly, float urx, float ury) + { + this.llx = llx; + this.lly = lly; + this.urx = urx; + this.ury = ury; + } + + public Annotation(Annotation an) { + annotationtype = an.annotationtype; + annotationAttributes = an.annotationAttributes; + llx = an.llx; + lly = an.lly; + urx = an.urx; + ury = an.ury; + } + + /// + /// Constructs an Annotation with a certain title and some text. + /// + /// the title of the annotation + /// the content of the annotation + public Annotation(string title, string text) + { + annotationtype = TEXT; + annotationAttributes[TITLE] = title; + annotationAttributes[CONTENT] = text; + } + + /// + /// Constructs an Annotation with a certain title and some text. + /// + /// the title of the annotation + /// the content of the annotation + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + public Annotation(string title, string text, float llx, float lly, float urx, float ury) : this(llx, lly, urx, ury) + { + annotationtype = TEXT; + annotationAttributes[TITLE] = title; + annotationAttributes[CONTENT] = text; + } + + /// + /// Constructs an Annotation. + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + /// the external reference + public Annotation(float llx, float lly, float urx, float ury, Uri url) : this(llx, lly, urx, ury) + { + annotationtype = URL_NET; + annotationAttributes[URL] = url; + } + + /// + /// Constructs an Annotation. + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + /// the external reference + public Annotation(float llx, float lly, float urx, float ury, string url) : this(llx, lly, urx, ury) + { + annotationtype = URL_AS_STRING; + annotationAttributes[FILE] = url; + } + + /// + /// Constructs an Annotation. + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + /// an external PDF file + /// the destination in this file + public Annotation(float llx, float lly, float urx, float ury, string file, string dest) : this(llx, lly, urx, ury) + { + annotationtype = FILE_DEST; + annotationAttributes[FILE] = file; + annotationAttributes[DESTINATION] = dest; + } + + /// + /// Creates a Screen anotation to embed media clips + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + /// path to the media clip file + /// mime type of the media + /// if true play on display of the page + public Annotation(float llx, float lly, float urx, float ury, + string moviePath, string mimeType, bool showOnDisplay) : this(llx, lly, urx, ury) + { + annotationtype = SCREEN; + annotationAttributes[FILE] = moviePath; + annotationAttributes[MIMETYPE] = mimeType; + annotationAttributes[PARAMETERS] = new bool[] {false /* embedded */, showOnDisplay }; + } + + /// + /// Constructs an Annotation. + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + /// an external PDF file + /// a page number in this file + public Annotation(float llx, float lly, float urx, float ury, string file, int page) : this(llx, lly, urx, ury) + { + annotationtype = FILE_PAGE; + annotationAttributes[FILE] = file; + annotationAttributes[PAGE] = page; + } + + /// + /// Constructs an Annotation. + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + /// a named destination in this file + /// + /// Has nine overloads. + /// + public Annotation(float llx, float lly, float urx, float ury, int named) : this(llx, lly, urx, ury) + { + annotationtype = NAMED_DEST; + annotationAttributes[NAMED] = named; + } + + /// + /// Constructs an Annotation. + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + /// an external application + /// parameters to pass to this application + /// the operation to pass to this application + /// the default directory to run this application in + public Annotation(float llx, float lly, float urx, float ury, string application, string parameters, string operation, string defaultdir) : this(llx, lly, urx, ury) + { + annotationtype = LAUNCH; + annotationAttributes[APPLICATION] = application; + annotationAttributes[PARAMETERS] = parameters; + annotationAttributes[OPERATION] = operation; + annotationAttributes[DEFAULTDIR] = defaultdir; + } + + // implementation of the Element-methods + + /// + /// Gets the type of the text element + /// + public int Type + { + get + { + return Element.ANNOTATION; + } + } + + // methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// IElementListener. + /// + /// an IElementListener + /// true if the element was process successfully + public bool Process(IElementListener listener) + { + try + { + return listener.Add(this); + } + catch (DocumentException) + { + return false; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public ArrayList Chunks + { + get + { + return new ArrayList(); + } + } + + // methods + + /// + /// Sets the dimensions of this annotation. + /// + /// the lower left x-value + /// the lower left y-value + /// the upper right x-value + /// the upper right y-value + public void SetDimensions (float llx, float lly, float urx, float ury) + { + this.llx = llx; + this.lly = lly; + this.urx = urx; + this.ury = ury; + } + + // methods to retrieve information + + /// + /// Returns the lower left x-value. + /// + /// a value + public float GetLlx() + { + return llx; + } + + /// + /// Returns the lower left y-value. + /// + /// a value + public float GetLly() + { + return lly; + } + + /// + /// Returns the uppper right x-value. + /// + /// a value + public float GetUrx() + { + return urx; + } + + /// + /// Returns the uppper right y-value. + /// + /// a value + public float GetUry() + { + return ury; + } + + /// + /// Returns the lower left x-value. + /// + /// the default value + /// a value + public float GetLlx(float def) + { + if (float.IsNaN(llx)) + return def; + return llx; + } + + /// + /// Returns the lower left y-value. + /// + /// the default value + /// a value + public float GetLly(float def) + { + if (float.IsNaN(lly)) + return def; + return lly; + } + + /// + /// Returns the upper right x-value. + /// + /// the default value + /// a value + public float GetUrx(float def) + { + if (float.IsNaN(urx)) + return def; + return urx; + } + + /// + /// Returns the upper right y-value. + /// + /// the default value + /// a value + public float GetUry(float def) + { + if (float.IsNaN(ury)) + return def; + return ury; + } + + /// + /// Returns the type of this Annotation. + /// + /// a type + public int AnnotationType + { + get + { + return annotationtype; + } + } + + /// + /// Returns the title of this Annotation. + /// + /// a name + public string Title + { + get + { + string s = (string)annotationAttributes[TITLE]; + if (s == null) + s = ""; + return s; + } + } + + /// + /// Gets the content of this Annotation. + /// + /// a reference + public string Content + { + get + { + string s = (string)annotationAttributes[CONTENT]; + if (s == null) s = ""; + return s; + } + } + + /// + /// Gets the content of this Annotation. + /// + /// a reference + public Hashtable Attributes + { + get + { + return annotationAttributes; + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return true; + } + + public override string ToString() { + return base.ToString(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/BadElementException.cs b/iTechSharp/iTextSharp/text/BadElementException.cs new file mode 100644 index 0000000..0c5c03d --- /dev/null +++ b/iTechSharp/iTextSharp/text/BadElementException.cs @@ -0,0 +1,66 @@ +using System; + +/* + * $Id: BadElementException.cs,v 1.3 2008/05/13 11:25:08 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text +{ + /// + /// Signals an attempt to create an Element that hasn't got the right form. + /// + /// + /// + public class BadElementException : DocumentException + { + public BadElementException() : base() {} + + public BadElementException(string message) : base(message) {} + } +} diff --git a/iTechSharp/iTextSharp/text/Cell.cs b/iTechSharp/iTextSharp/text/Cell.cs new file mode 100644 index 0000000..64cd0e3 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Cell.cs @@ -0,0 +1,873 @@ +using System; +using System.Collections; +using System.util; + +using iTextSharp.text.html; +using iTextSharp.text.pdf; +using iTextSharp.text.factories; + +/* + * $Id: Cell.cs,v 1.17 2008/05/13 11:25:08 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A Cell is a Rectangle containing other Elements. + /// + /// + /// A Cell is a Rectangle containing other + /// Elements. + ///

    + /// A Cell must be added to a Table. + /// The Table will place the Cell in + /// a Row. + /// + /// + /// + /// Table table = new Table(3); + /// table.SetBorderWidth(1); + /// table.SetBorderColor(new Color(0, 0, 255)); + /// table.SetCellpadding(5); + /// table.SetCellspacing(5); + /// Cell cell = new Cell("header"); + /// cell.SetHeader(true); + /// cell.SetColspan(3); + /// table.AddCell(cell); + /// cell = new Cell("example cell with colspan 1 and rowspan 2"); + /// cell.SetRowspan(2); + /// cell.SetBorderColor(new Color(255, 0, 0)); + /// table.AddCell(cell); + /// table.AddCell("1.1"); + /// table.AddCell("2.1"); + /// table.AddCell("1.2"); + /// table.AddCell("2.2"); + /// + /// + /// + /// + /// + /// + public class Cell : Rectangle, ITextElementArray { + + // static membervariable + + public static Cell DummyCell { + get { + Cell cell = new Cell(true); + cell.Colspan = 3; + cell.Border = NO_BORDER; + return cell; + } + } + + // membervariables + + ///

    This is the ArrayList of Elements. + protected ArrayList arrayList = null; + + /// This is the horizontal Element. + protected int horizontalAlignment = Element.ALIGN_UNDEFINED; + + /// This is the vertical Element. + protected int verticalAlignment = Element.ALIGN_UNDEFINED; + + /// This is the vertical Element. + protected float width; + protected bool percentage = false; + + /// This is the colspan. + protected int colspan = 1; + + /// This is the rowspan. + protected int rowspan = 1; + + /// This is the leading. + float leading = float.NaN; + + /// Is this Cell a header? + protected bool header; + + /// + /// Indicates that the largest ascender height should be used to determine the + /// height of the first line. Note that this only has an effect when rendered + /// to PDF. Setting this to true can help with vertical alignment problems. + /// + protected bool useAscender = false; + + /// + /// Indicates that the largest descender height should be added to the height of + /// the last line (so characters like y don't dip into the border). Note that + /// this only has an effect when rendered to PDF. + /// + protected bool useDescender = false; + + /// + /// Adjusts the cell contents to compensate for border widths. Note that + /// this only has an effect when rendered to PDF. + /// + protected bool useBorderPadding; + + /// Will the element have to be wrapped? + protected bool noWrap; + + // constructors + + /** + * Constructs an empty Cell. + */ + /// + /// Constructs an empty Cell. + /// + /// + /// Has five overloads. + /// + public Cell() : base(0, 0, 0, 0) { + // creates a Rectangle with BY DEFAULT a border of 0.5 + + this.Border = UNDEFINED; + this.BorderWidth = 0.5F; + + // initializes the arraylist and adds an element + arrayList = new ArrayList(); + } + + /// + /// Constructs an empty Cell (for internal use only). + /// + /// a dummy value + public Cell(bool dummy) : this() { + arrayList.Add(new Paragraph(0)); + } + + /// + /// Constructs a Cell with a certain content. + /// + /// + /// The string will be converted into a Paragraph. + /// + /// a string + public Cell(string content) : this() { + AddElement(new Paragraph(content)); + } + + /// + /// Constructs a Cell with a certain Element. + /// + /// + /// if the element is a ListItem, Row or + /// Cell, an exception will be thrown. + /// + /// the element + public Cell(IElement element) : this() { + if (element is Phrase) { + Leading = ((Phrase)element).Leading; + } + AddElement(element); + } + + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// IElementListener. + /// + /// an IElementListener + /// true if the element was processed successfully + public override bool Process(IElementListener listener) { + try { + return listener.Add(this); + } + catch (DocumentException) { + return false; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public override int Type { + get { + return Element.CELL; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public override ArrayList Chunks { + get { + ArrayList tmp = new ArrayList(); + foreach (IElement ele in arrayList) { + tmp.AddRange(ele.Chunks); + } + return tmp; + } + } + + // methods to set the membervariables + + /** + * Adds an element to this Cell. + *

    + * Remark: you can't add ListItems, Rows, Cells, + * JPEGs, GIFs or PNGs to a Cell. + * + * @param element The Element to add + * @throws BadElementException if the method was called with a ListItem, Row or Cell + */ + ///

    + /// Adds an element to this Cell. + /// + /// + /// You can't add ListItems, Rows, Cells, + /// JPEGs, GIFs or PNGs to a Cell. + /// + /// the Element to add + public void AddElement(IElement element) { + if (IsTable()) { + Table table = (Table) arrayList[0]; + Cell tmp = new Cell(element); + tmp.Border = NO_BORDER; + tmp.Colspan = table.Columns; + table.AddCell(tmp); + return; + } + switch (element.Type) { + case Element.LISTITEM: + case Element.ROW: + case Element.CELL: + throw new BadElementException("You can't add listitems, rows or cells to a cell."); + case Element.JPEG: + case Element.IMGRAW: + case Element.IMGTEMPLATE: + arrayList.Add(element); + break; + case Element.LIST: + if (float.IsNaN(this.Leading)) { + leading = ((List) element).TotalLeading; + } + if (((List) element).IsEmpty()) return; + arrayList.Add(element); + return; + case Element.ANCHOR: + case Element.PARAGRAPH: + case Element.PHRASE: + if (float.IsNaN(leading)) { + leading = ((Phrase) element).Leading; + } + if (((Phrase) element).IsEmpty()) return; + arrayList.Add(element); + return; + case Element.CHUNK: + if (((Chunk) element).IsEmpty()) return; + arrayList.Add(element); + return; + case Element.TABLE: + Table table = new Table(3); + float[] widths = new float[3]; + widths[1] = ((Table)element).Width; + + switch (((Table)element).Alignment) { + case Element.ALIGN_LEFT: + widths[0] = 0f; + widths[2] = 100f - widths[1]; + break; + case Element.ALIGN_CENTER: + widths[0] = (100f - widths[1]) / 2f; + widths[2] = widths[0]; + break; + case Element.ALIGN_RIGHT: + widths[0] = 100f - widths[1]; + widths[2] = 0f; + break; + } + table.Widths = widths; + Cell tmp; + if (arrayList.Count == 0) { + table.AddCell(Cell.DummyCell); + } + else { + tmp = new Cell(); + tmp.Border = NO_BORDER; + tmp.Colspan = 3; + foreach (IElement ele in arrayList) { + tmp.Add(ele); + } + table.AddCell(tmp); + } + tmp = new Cell(); + tmp.Border = NO_BORDER; + table.AddCell(tmp); + table.InsertTable((Table)element); + tmp = new Cell(); + tmp.Border = NO_BORDER; + table.AddCell(tmp); + table.AddCell(Cell.DummyCell); + Clear(); + arrayList.Add(table); + return; + default: + arrayList.Add(element); + break; + } + } + + /// + /// Add an Object to this cell. + /// + /// the object to add + /// always true + public bool Add(Object o) { + try { + this.AddElement((IElement) o); + return true; + } + catch (BadElementException bee) { + throw new Exception(bee.Message); + } + catch { + throw new Exception("You can only add objects that implement the Element interface."); + } + } + + /// + /// Sets the alignment of this cell. + /// + /// the new alignment as a string + public void SetHorizontalAlignment(string alignment) { + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_CENTER)) { + this.HorizontalAlignment = Element.ALIGN_CENTER; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_RIGHT)) { + this.HorizontalAlignment = Element.ALIGN_RIGHT; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_JUSTIFIED)) { + this.HorizontalAlignment = Element.ALIGN_JUSTIFIED; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_JUSTIFIED_ALL)) { + this.HorizontalAlignment = Element.ALIGN_JUSTIFIED_ALL; + return; + } + this.HorizontalAlignment = Element.ALIGN_LEFT; + } + + /// + /// Sets the alignment of this paragraph. + /// + /// the new alignment as a string + public void SetVerticalAlignment(string alignment) { + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_MIDDLE)) { + this.VerticalAlignment = Element.ALIGN_MIDDLE; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_BOTTOM)) { + this.VerticalAlignment = Element.ALIGN_BOTTOM; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_BASELINE)) { + this.VerticalAlignment = Element.ALIGN_BASELINE; + return; + } + this.VerticalAlignment = Element.ALIGN_TOP; + } + + /// + /// Sets the width. + /// + /// the new value + public override float Width { + set { + width = value; + } + get { + return width; + } + } + + /** + * Sets the width. + * It can be an absolute value "100" or a percentage "20%" + * + * @param value the new value + */ + public void SetWidth(String value) { + if (value.EndsWith("%")) { + value = value.Substring(0, value.Length - 1); + percentage = true; + } + width = int.Parse(value); + } + + /** + * Gets the width as a String. + * + * @return a value + */ + public String GetWidthAsString() { + String w = width.ToString(System.Globalization.CultureInfo.InvariantCulture); + if (w.EndsWith(".0")) w = w.Substring(0, w.Length - 2); + if (percentage) w += "%"; + return w; + } + + // methods to retrieve information + + /// + /// Gets the number of Elements in the Cell. + /// + /// a size + public int Size { + get { + return arrayList.Count; + } + } + + /// + /// Checks if the Cell is empty. + /// + /// false if there are non-empty Elements in the Cell. + public bool IsEmpty() { + switch (this.Size) { + case 0: + return true; + case 1: + IElement element = (IElement)arrayList[0]; + switch (element.Type) { + case Element.CHUNK: + return ((Chunk) element).IsEmpty(); + case Element.ANCHOR: + case Element.PHRASE: + case Element.PARAGRAPH: + return ((Phrase) element).IsEmpty(); + case Element.LIST: + return ((List) element).IsEmpty(); + } + return false; + default: + return false; + } + } + + /// + /// Makes sure there is at least 1 object in the Cell. + /// Otherwise it might not be shown in the table. + /// + internal void Fill() { + if (this.Size == 0) arrayList.Add(new Paragraph(0)); + } + + /// + /// Checks if the Cell is empty. + /// + /// false if there are non-empty Elements in the Cell. + public bool IsTable() { + return (this.Size == 1) && (((IElement)arrayList[0]).Type == Element.TABLE); + } + + /// + /// Gets Elements. + /// + /// an ArrayList + public ArrayList Elements { + get { + return arrayList; + } + } + + /// + /// Gets/Sets the horizontal Element. + /// + /// a value + public int HorizontalAlignment { + get { + return horizontalAlignment; + } + + set { + horizontalAlignment = value; + } + } + + /// + /// Gets/sets the vertical Element. + /// + /// a value + public int VerticalAlignment { + get { + return verticalAlignment; + } + + set { + verticalAlignment = value; + } + } + + /** + * Gets the colspan. + * + * @return a value + */ + /// + /// Gets/sets the colspan. + /// + /// a value + public int Colspan { + get { + return colspan; + } + + set { + colspan = value; + } + } + + /// + /// Gets/sets the rowspan. + /// + /// a value + public int Rowspan { + get { + return rowspan; + } + + set { + rowspan = value; + } + } + + /// + /// Gets/sets the leading. + /// + /// a value + public float Leading { + get { + if (float.IsNaN(leading)) { + return 16; + } + return leading; + } + + set { + leading = value; + } + } + + /// + /// Gets/sets header + /// + /// a value + public bool Header { + get { + return header; + } + + set { + header = value; + } + } + + /** + * Get nowrap. + * + * @return a value + */ + /// + /// Get/set nowrap. + /// + /// a value + public bool NoWrap { + get { + return (maxLines == 1); + } + + set { + maxLines = 1; + } + } + + /// + /// Clears all the Elements of this Cell. + /// + public void Clear() { + arrayList.Clear(); + } + + /// + /// This property throws an Exception. + /// + /// none + public override float Top { + get { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + + set { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + } + + /// + /// This property throws an Exception. + /// + /// none + public override float Bottom { + get { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + + set { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + } + + /// + /// This property throws an Exception. + /// + /// none + public override float Left { + get { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + + set { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + } + + /// + /// This property throws an Exception. + /// + /// none + public override float Right { + get { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + + set { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + } + + /// + /// This method throws an Exception. + /// + /// new value + /// none + public float GetTop(int margin) { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + + /// + /// This method throws an Exception. + /// + /// new value + /// none + public float GetBottom(int margin) { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + + /// + /// This method throws an Exception. + /// + /// new value + /// none + public float GetLeft(int margin) { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + + /// + /// This method throws an Exception. + /// + /// new value + /// none + public float GetRight(int margin) { + throw new Exception("Dimensions of a Cell can't be calculated. See the FAQ."); + } + + /// + /// Checks if a given tag corresponds with this object. + /// + /// the given tag + /// true if the tag corresponds + public static bool IsTag(string tag) { + return ElementTags.CELL.Equals(tag); + } + + + ///Does this Cell force a group change? + protected bool groupChange = true; + + /// + /// Does this Cell force a group change? + /// + public bool GroupChange { + get { + return groupChange; + } + + set { + groupChange = value; + } + } + + /// + /// get/set maxLines value + /// + public int MaxLines { + get { + return maxLines; + } + + set { + maxLines = value; + } + } + + /// + /// Maximum number of lines allowed in the cell. + /// The default value of this property is not to limit the maximum number of lines + /// (contributed by dperezcar@fcc.es) + /// + protected int maxLines = int.MaxValue; + + /// + /// get/set showTruncation value + /// + public string ShowTruncation { + get { + return showTruncation; + } + + set { + showTruncation = value; + } + } + + /// + /// If a truncation happens due to the {@link #maxLines} property, then this text will + /// be added to indicate a truncation has happened. + /// Default value is null, and means avoiding marking the truncation. + /// A useful value of this property could be e.g. "..." + /// (contributed by dperezcar@fcc.es) + /// + private string showTruncation; + + /// + /// get/set useAscender value + /// + public bool UseAscender { + get { + return useAscender; + } + + set { + useAscender = value; + } + } + + /// + /// get/set useDescender value + /// + public bool UseDescender { + get { + return useDescender; + } + + set { + useDescender = value; + } + } + + /// + /// get/set useBorderPadding value + /// + public bool UseBorderPadding { + get { + return useBorderPadding; + } + + set { + useBorderPadding = value; + } + } + /** + * Creates a PdfPCell based on this Cell object. + * @return a PdfPCell + * @throws BadElementException + */ + public PdfPCell CreatePdfPCell() { + if (rowspan > 1) throw new BadElementException("PdfPCells can't have a rowspan > 1"); + if (IsTable()) return new PdfPCell(((Table)arrayList[0]).CreatePdfPTable()); + PdfPCell cell = new PdfPCell(); + cell.VerticalAlignment = verticalAlignment; + cell.HorizontalAlignment = horizontalAlignment; + cell.Colspan = colspan; + cell.UseBorderPadding = useBorderPadding; + cell.UseDescender = useDescender; + cell.SetLeading(Leading, 0); + cell.CloneNonPositionParameters(this); + cell.NoWrap = noWrap; + foreach (IElement i in Elements) { + if (i.Type == Element.PHRASE || i.Type == Element.PARAGRAPH) { + Paragraph p = new Paragraph((Phrase)i); + p.Alignment = horizontalAlignment; + cell.AddElement(p); + } + else + cell.AddElement(i); + } + return cell; + } + } +} diff --git a/iTechSharp/iTextSharp/text/Chapter.cs b/iTechSharp/iTextSharp/text/Chapter.cs new file mode 100644 index 0000000..9a9f874 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Chapter.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text.factories; + +/* + * $Id: Chapter.cs,v 1.10 2008/05/13 11:25:08 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + * + */ + +namespace iTextSharp.text +{ + /// + /// A Chapter is a special Section. + /// + /// + /// A chapter number has to be created using a Paragraph as title + /// and an int as chapter number. The chapter number is shown be + /// default. If you don't want to see the chapter number, you have to set the + /// numberdepth to 0. + /// + /// + /// + /// Paragraph title2 = new Paragraph("This is Chapter 2", FontFactory.GetFont(FontFactory.HELVETICA, 18, Font.BOLDITALIC, new Color(0, 0, 255))); + /// Chapter chapter2 = new Chapter(title2, 2); + /// chapter2.SetNumberDepth(0); + /// Paragraph someText = new Paragraph("This is some text"); + /// chapter2.Add(someText); + /// Paragraph title21 = new Paragraph("This is Section 1 in Chapter 2", FontFactory.GetFont(FontFactory.HELVETICA, 16, Font.BOLD, new Color(255, 0, 0))); + /// Section section1 = chapter2.AddSection(title21); + /// Paragraph someSectionText = new Paragraph("This is some silly paragraph in a chapter and/or section. It contains some text to test the functionality of Chapters and Section."); + /// section1.Add(someSectionText); + /// + /// + public class Chapter : Section + { + + // constructors + + /** + * Constructs a new Chapter. + * @param number the Chapter number + */ + + public Chapter(int number) : base (null, 1) { + numbers = new ArrayList(); + numbers.Add(number); + triggerNewPage = true; + } + + /// + /// Constructs a new Chapter. + /// + /// the Chapter title (as a Paragraph) + /// the Chapter number + /// + /// Has three overloads. + /// + public Chapter(Paragraph title, int number) : base(title, 1) + { + numbers = new ArrayList(); + numbers.Add(number); + triggerNewPage = true; + } + + /// + /// Constructs a new Chapter. + /// + /// the Chapter title (as a string) + /// the Chapter number + /// + /// Has three overloads. + /// + public Chapter(string title, int number) : this(new Paragraph(title), number) {} + + // implementation of the Element-methods + + /// + /// Gets the type of the text element. + /// + /// a type + public override int Type { + get { + return Element.CHAPTER; + } + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public override bool IsNestable() { + return false; + } + } +} diff --git a/iTechSharp/iTextSharp/text/ChapterAutoNumber.cs b/iTechSharp/iTextSharp/text/ChapterAutoNumber.cs new file mode 100644 index 0000000..e3ad8a6 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ChapterAutoNumber.cs @@ -0,0 +1,101 @@ +using System; + +/* + * Copyright 2005 by Michael Niedermair. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + + /** + * Chapter with auto numbering. + * + * @author Michael Niedermair + */ + public class ChapterAutoNumber : Chapter { + + /** + * Create a new object. + * + * @param para the Chapter title (as a Paragraph) + */ + public ChapterAutoNumber(Paragraph para) : base(para, 0) { + } + + /** + * Create a new objet. + * + * @param title the Chapter title (as a String) + */ + public ChapterAutoNumber(String title) : base(title, 0) { + } + + /** + * Create a new section for this chapter and ad it. + * + * @param title the Section title (as a String) + * @return Returns the new section. + */ + public override Section AddSection(String title) { + if (AddedCompletely) { + throw new InvalidOperationException("This LargeElement has already been added to the Document."); + } + return AddSection(title, 2); + } + + /** + * Create a new section for this chapter and add it. + * + * @param title the Section title (as a Paragraph) + * @return Returns the new section. + */ + public override Section AddSection(Paragraph title) { + if (AddedCompletely) { + throw new InvalidOperationException("This LargeElement has already been added to the Document."); + } + return AddSection(title, 2); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/Chunk.cs b/iTechSharp/iTextSharp/text/Chunk.cs new file mode 100644 index 0000000..ee7377b --- /dev/null +++ b/iTechSharp/iTextSharp/text/Chunk.cs @@ -0,0 +1,733 @@ +using System; +using System.Text; +using System.Collections; +using System.util; + +using iTextSharp.text.pdf; +using iTextSharp.text.html; +using iTextSharp.text.factories; +using iTextSharp.text.pdf.draw; + +/* + * $Id: Chunk.cs,v 1.20 2008/05/13 11:25:09 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// This is the smallest significant part of text that can be added to a document. + /// + /// + /// Most elements can be divided in one or more Chunks. + /// A chunk is a string with a certain Font. + /// all other layoutparameters should be defined in the object to which + /// this chunk of text is added. + /// + /// + /// + /// Chunk chunk = new Chunk("Hello world", FontFactory.GetFont(FontFactory.COURIER, 20, Font.ITALIC, new Color(255, 0, 0))); + /// document.Add(chunk); + /// + /// + public class Chunk : IElement { + + // public static membervariables + + /** The character stand in for an image or a separator. */ + public const string OBJECT_REPLACEMENT_CHARACTER = "\ufffc"; + + /// This is a Chunk containing a newline. + public static readonly Chunk NEWLINE = new Chunk("\n"); + + /** This is a Chunk containing a newpage. */ + public static readonly Chunk NEXTPAGE = new Chunk(""); + static Chunk() { + NEXTPAGE.SetNewPage(); + } + + + // member variables + + /// This is the content of this chunk of text. + protected StringBuilder content = null; + + /// This is the Font of this chunk of text. + protected Font font = null; + + /// Contains some of the attributes for this Chunk. + protected Hashtable attributes = null; + + // constructors + + /// + /// Empty constructor. + /// + /// + /// Has six overloads. + /// + public Chunk() { + this.content = new StringBuilder(); + this.font = new Font(); + } + + /** + * A Chunk copy constructor. + * @param ck the Chunk to be copied + */ + public Chunk(Chunk ck) { + if (ck.content != null) { + content = new StringBuilder(ck.content.ToString()); + } + if (ck.font != null) { + font = new Font(ck.font); + } + } + + /// + /// Constructs a chunk of text with a certain content and a certain Font. + /// + /// the content + /// the font + public Chunk(string content, Font font) { + this.content = new StringBuilder(content); + this.font = font; + } + + /// + /// Constructs a chunk of text with a certain content, without specifying a Font. + /// + /// the content + public Chunk(string content) : this(content, new Font()) {} + + /** + * Constructs a chunk of text with a char and a certain Font. + * + * @param c the content + * @param font the font + */ + public Chunk(char c, Font font) { + this.content = new StringBuilder(); + this.content.Append(c); + this.font = font; + } + + /** + * Constructs a chunk of text with a char, without specifying a Font. + * + * @param c the content + */ + public Chunk(char c) : this(c, new Font()) { + } + + /// + /// Constructs a chunk containing an Image. + /// + /// the image + /// the image offset in the x direction + /// the image offset in the y direction + public Chunk(Image image, float offsetX, float offsetY) : this(OBJECT_REPLACEMENT_CHARACTER, new Font()) { + Image copyImage = Image.GetInstance(image); + copyImage.SetAbsolutePosition(float.NaN, float.NaN); + SetAttribute(IMAGE, new Object[]{copyImage, offsetX, offsetY, false}); + } + + /** + * Key for drawInterface of the Separator. + * @since 2.1.2 + */ + public const String SEPARATOR = "SEPARATOR"; + + /** + * Creates a separator Chunk. + * Note that separator chunks can't be used in combination with tab chunks! + * @param separator the drawInterface to use to draw the separator. + * @since 2.1.2 + */ + public Chunk(IDrawInterface separator) : this(separator, false) { + } + + /** + * Creates a separator Chunk. + * Note that separator chunks can't be used in combination with tab chunks! + * @param separator the drawInterface to use to draw the separator. + * @param vertical true if this is a vertical separator + * @since 2.1.2 + */ + public Chunk(IDrawInterface separator, bool vertical) : this(OBJECT_REPLACEMENT_CHARACTER, new Font()) { + SetAttribute(SEPARATOR, new Object[] {separator, vertical}); + } + + /** + * Key for drawInterface of the tab. + * @since 2.1.2 + */ + public const String TAB = "TAB"; + + /** + * Creates a tab Chunk. + * Note that separator chunks can't be used in combination with tab chunks! + * @param separator the drawInterface to use to draw the tab. + * @param tabPosition an X coordinate that will be used as start position for the next Chunk. + * @since 2.1.2 + */ + public Chunk(IDrawInterface separator, float tabPosition) : this(separator, tabPosition, false) { + } + + /** + * Creates a tab Chunk. + * Note that separator chunks can't be used in combination with tab chunks! + * @param separator the drawInterface to use to draw the tab. + * @param tabPosition an X coordinate that will be used as start position for the next Chunk. + * @param newline if true, a newline will be added if the tabPosition has already been reached. + * @since 2.1.2 + */ + public Chunk(IDrawInterface separator, float tabPosition, bool newline) : this(OBJECT_REPLACEMENT_CHARACTER, new Font()) { + if (tabPosition < 0) { + throw new ArgumentException("A tab position may not be lower than 0; yours is " + tabPosition); + } + SetAttribute(TAB, new Object[] {separator, tabPosition, newline, 0}); + } + + /// + /// Constructs a chunk containing an Image. + /// + /// the image + /// the image offset in the x direction + /// the image offset in the y direction + /// true if the leading has to be adapted to the image + public Chunk(Image image, float offsetX, float offsetY, bool changeLeading) : this(OBJECT_REPLACEMENT_CHARACTER, new Font()) { + SetAttribute(IMAGE, new Object[]{image, offsetX, offsetY, changeLeading}); + } + + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// IElementListener. + /// + /// an IElementListener + /// true if the element was processed successfully + public bool Process(IElementListener listener) { + try { + return listener.Add(this); + } + catch (DocumentException) { + return false; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public int Type { + get { + return Element.CHUNK; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public ArrayList Chunks { + get { + ArrayList tmp = new ArrayList(); + tmp.Add(this); + return tmp; + } + } + + // methods + + /// + /// appends some text to this Chunk. + /// + /// a string + /// a StringBuilder + public StringBuilder Append(string str) { + return content.Append(str); + } + + // methods to retrieve information + + /// + /// Get/set the font of this Chunk. + /// + /// a Font + public virtual Font Font { + get { + return font; + } + + set { + this.font = value; + } + } + + + /// + /// Returns the content of this Chunk. + /// + /// a string + public virtual string Content { + get { + return content.ToString(); + } + } + + public override string ToString() { + return content.ToString(); + } + + + /// + /// Checks is this Chunk is empty. + /// + /// false if the Chunk contains other characters than space. + public virtual bool IsEmpty() { + return (content.ToString().Trim().Length == 0) && (content.ToString().IndexOf("\n") == -1) && (attributes == null); + } + + /** + * Gets the width of the Chunk in points. + * @return a width in points + */ + public float GetWidthPoint() { + if (GetImage() != null) { + return GetImage().ScaledWidth; + } + return font.GetCalculatedBaseFont(true).GetWidthPoint(Content, font.CalculatedSize) * HorizontalScaling; + } + + /// + /// Checks the attributes of this Chunk. + /// + /// false if there aren't any. + public bool HasAttributes() { + return attributes != null; + } + + /// + /// Gets the attributes for this Chunk. + /// + /// + /// It may be null. + /// + /// a Hashtable + public Hashtable Attributes { + get { + return attributes; + } + set { + attributes = value; + } + } + + /// + /// Sets an arbitrary attribute. + /// + /// the key for the attribute + /// the value of the attribute + /// this Chunk + private Chunk SetAttribute(string name, Object obj) { + if (attributes == null) + attributes = new Hashtable(); + attributes[name] = obj; + return this; + } + + /** Key for text horizontal scaling. */ + public const string HSCALE = "HSCALE"; + + /** + * Sets the text horizontal scaling. A value of 1 is normal and a value of 0.5f + * shrinks the text to half it's width. + * @param scale the horizontal scaling factor + * @return this Chunk + */ + public Chunk SetHorizontalScaling(float scale) { + return SetAttribute(HSCALE, scale); + } + + /** + * Gets the horizontal scaling. + * @return a percentage in float + */ + public float HorizontalScaling { + get { + if (attributes == null) return 1f; + Object f = attributes[HSCALE]; + if (f == null) return 1f; + return (float)f; + } + } + + /// Key for underline. + public const string UNDERLINE = "UNDERLINE"; + + /** + * Sets an horizontal line that can be an underline or a strikethrough. + * Actually, the line can be anywhere vertically and has always the + * Chunk width. Multiple call to this method will + * produce multiple lines. + * @param thickness the absolute thickness of the line + * @param yPosition the absolute y position relative to the baseline + * @return this Chunk + */ + public Chunk SetUnderline(float thickness, float yPosition) { + return SetUnderline(null, thickness, 0f, yPosition, 0f, PdfContentByte.LINE_CAP_BUTT); + } + + /** + * Sets an horizontal line that can be an underline or a strikethrough. + * Actually, the line can be anywhere vertically and has always the + * Chunk width. Multiple call to this method will + * produce multiple lines. + * @param color the color of the line or null to follow + * the text color + * @param thickness the absolute thickness of the line + * @param thicknessMul the thickness multiplication factor with the font size + * @param yPosition the absolute y position relative to the baseline + * @param yPositionMul the position multiplication factor with the font size + * @param cap the end line cap. Allowed values are + * PdfContentByte.LINE_CAP_BUTT, PdfContentByte.LINE_CAP_ROUND and + * PdfContentByte.LINE_CAP_PROJECTING_SQUARE + * @return this Chunk + */ + public Chunk SetUnderline(Color color, float thickness, float thicknessMul, float yPosition, float yPositionMul, int cap) { + if (attributes == null) + attributes = new Hashtable(); + Object[] obj = {color, new float[]{thickness, thicknessMul, yPosition, yPositionMul, (float)cap}}; + Object[][] unders = Utilities.AddToArray((Object[][])attributes[UNDERLINE], obj); + return SetAttribute(UNDERLINE, unders); + } + + /// Key for sub/basescript. + public const string SUBSUPSCRIPT = "SUBSUPSCRIPT"; + + /// + /// Sets the text displacement relative to the baseline. Positive values rise the text, + /// negative values lower the text. + /// + /// + /// It can be used to implement sub/basescript. + /// + /// the displacement in points + /// this Chunk + public Chunk SetTextRise(float rise) { + return SetAttribute(SUBSUPSCRIPT, rise); + } + + public float GetTextRise() { + if (attributes != null && attributes.ContainsKey(SUBSUPSCRIPT)) { + return (float)attributes[SUBSUPSCRIPT]; + } + return 0.0f; + } + + /// Key for text skewing. + public const string SKEW = "SKEW"; + + /** + * Skews the text to simulate italic and other effects. + * Try alpha=0 and beta=12. + * @param alpha the first angle in degrees + * @param beta the second angle in degrees + * @return this Chunk + */ + public Chunk SetSkew(float alpha, float beta) { + alpha = (float)Math.Tan(alpha * Math.PI / 180); + beta = (float)Math.Tan(beta * Math.PI / 180); + return SetAttribute(SKEW, new float[]{alpha, beta}); + } + + /// Key for background. + public const string BACKGROUND = "BACKGROUND"; + + /// + /// Sets the color of the background Chunk. + /// + /// the color of the background + /// this Chunk + public Chunk SetBackground(Color color) { + return SetBackground(color, 0, 0, 0, 0); + } + + /** Sets the color and the size of the background Chunk. + * @param color the color of the background + * @param extraLeft increase the size of the rectangle in the left + * @param extraBottom increase the size of the rectangle in the bottom + * @param extraRight increase the size of the rectangle in the right + * @param extraTop increase the size of the rectangle in the top + * @return this Chunk + */ + public Chunk SetBackground(Color color, float extraLeft, float extraBottom, float extraRight, float extraTop) { + return SetAttribute(BACKGROUND, new Object[]{color, new float[]{extraLeft, extraBottom, extraRight, extraTop}}); + } + + /// Key for text rendering mode. + public const string TEXTRENDERMODE = "TEXTRENDERMODE"; + + /** Sets the text rendering mode. It can outline text, simulate bold and make + * text invisible. + * @param mode the text rendering mode. It can be PdfContentByte.TEXT_RENDER_MODE_FILL, + * PdfContentByte.TEXT_RENDER_MODE_STROKE, PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE + * and PdfContentByte.TEXT_RENDER_MODE_INVISIBLE. + * @param strokeWidth the stroke line width for the modes PdfContentByte.TEXT_RENDER_MODE_STROKE and + * PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE. + * @param strokeColor the stroke color or null to follow the text color + * @return this Chunk + */ + public Chunk SetTextRenderMode(int mode, float strokeWidth, Color strokeColor) { + return SetAttribute(TEXTRENDERMODE, new Object[]{mode, strokeWidth, strokeColor}); + } + + /// Key for split character. + public const string SPLITCHARACTER = "SPLITCHARACTER"; + + /// + /// Sets the split characters. + /// + /// the SplitCharacter interface + /// this Chunk + public Chunk SetSplitCharacter(ISplitCharacter splitCharacter) { + return SetAttribute(SPLITCHARACTER, splitCharacter); + } + + /// Key for hyphenation. + public const string HYPHENATION = "HYPHENATION"; + + /// + /// sets the hyphenation engine to this Chunk. + /// + /// the hyphenation engine + /// this Chunk + public Chunk SetHyphenation(IHyphenationEvent hyphenation) { + return SetAttribute(HYPHENATION, hyphenation); + } + + /// Key for remote goto. + public const string REMOTEGOTO = "REMOTEGOTO"; + + /// + /// Sets a goto for a remote destination for this Chunk. + /// + /// the file name of the destination document + /// the name of the destination to go to + /// this Chunk + public Chunk SetRemoteGoto(string filename, string name) { + return SetAttribute(REMOTEGOTO, new Object[]{filename, name}); + } + + /// + /// Sets a goto for a remote destination for this Chunk. + /// + /// the file name of the destination document + /// the page of the destination to go to. First page is 1 + /// this Chunk + public Chunk SetRemoteGoto(string filename, int page) { + return SetAttribute(REMOTEGOTO, new Object[]{filename, page}); + } + + /// Key for local goto. + public const string LOCALGOTO = "LOCALGOTO"; + + /// + /// Sets a local goto for this Chunk. + /// + /// + /// There must be a local destination matching the name. + /// + /// the name of the destination to go to + /// this Chunk + public Chunk SetLocalGoto(string name) { + return SetAttribute(LOCALGOTO, name); + } + + /// Key for local destination. + public const string LOCALDESTINATION = "LOCALDESTINATION"; + + /// + /// Sets a local destination for this Chunk. + /// + /// the name for this destination + /// this Chunk + public Chunk SetLocalDestination(string name) { + return SetAttribute(LOCALDESTINATION, name); + } + + /// Key for generic tag. + public const string GENERICTAG = "GENERICTAG"; + + /// + /// Sets the generic tag Chunk. + /// + /// + /// The text for this tag can be retrieved with PdfPageEvent. + /// + /// the text for the tag + /// this Chunk + public Chunk SetGenericTag(string text) { + return SetAttribute(GENERICTAG, text); + } + + /// Key for image. + public const string IMAGE = "IMAGE"; + + /// + /// Returns the image. + /// + /// an Image + public Image GetImage() { + if (attributes == null) return null; + Object[] obj = (Object[])attributes[Chunk.IMAGE]; + if (obj == null) + return null; + else { + return (Image)obj[0]; + } + } + + /// + /// Checks if a given tag corresponds with this object. + /// + /// the given tag + /// true if the tag corresponds + public static bool IsTag(string tag) { + return ElementTags.CHUNK.Equals(tag); + } + + /// Key for Action. + public const string ACTION = "ACTION"; + + /// + /// Sets an action for this Chunk. + /// + /// the action + /// this Chunk + public Chunk SetAction(PdfAction action) { + return SetAttribute(ACTION, action); + } + + /// + /// Sets an anchor for this Chunk. + /// + /// the Uri to link to + /// this Chunk + public Chunk SetAnchor(Uri url) { + return SetAttribute(ACTION, new PdfAction(url)); + } + + /// + /// Sets an anchor for this Chunk. + /// + /// the url to link to + /// this Chunk + public Chunk SetAnchor(string url) { + return SetAttribute(ACTION, new PdfAction(url)); + } + + /// Key for newpage. + public const string NEWPAGE = "NEWPAGE"; + + /// + /// Sets a new page tag. + /// + /// this Chunk + public Chunk SetNewPage() { + return SetAttribute(NEWPAGE, null); + } + + /// Key for annotation. + public const string PDFANNOTATION = "PDFANNOTATION"; + + /// + /// Sets a generic annotation to this Chunk. + /// + /// the annotation + /// this Chunk + public Chunk SetAnnotation(PdfAnnotation annotation) { + return SetAttribute(PDFANNOTATION, annotation); + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return true; + } + + /** + * Returns the hyphenation (if present). + * @param hyphenation a HyphenationEvent instance + * @since 2.1.2 + */ + public IHyphenationEvent GetHyphenation() { + if (attributes == null) return null; + return (IHyphenationEvent) attributes[Chunk.HYPHENATION]; + } + + // keys used in PdfChunk + + /// Key for color. + public const string COLOR = "COLOR"; + + /// Key for encoding. + public const string ENCODING = "ENCODING"; + } +} diff --git a/iTechSharp/iTextSharp/text/Color.cs b/iTechSharp/iTextSharp/text/Color.cs new file mode 100644 index 0000000..0f593e6 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Color.cs @@ -0,0 +1,150 @@ +using System; + +namespace iTextSharp.text { + /// + /// Base class for Color, serves as wrapper class for + /// to allow extension. + /// + public class Color { + public static readonly Color WHITE = new Color(255, 255, 255); + public static readonly Color LIGHT_GRAY = new Color(192, 192, 192); + public static readonly Color GRAY = new Color(128, 128, 128); + public static readonly Color DARK_GRAY = new Color(64, 64, 64); + public static readonly Color BLACK = new Color(0, 0, 0); + public static readonly Color RED = new Color(255, 0, 0); + public static readonly Color PINK = new Color(255, 175, 175); + public static readonly Color ORANGE = new Color(255, 200, 0); + public static readonly Color YELLOW = new Color(255, 255, 0); + public static readonly Color GREEN = new Color(0, 255, 0); + public static readonly Color MAGENTA = new Color(255, 0, 255); + public static readonly Color CYAN = new Color(0, 255, 255); + public static readonly Color BLUE = new Color(0, 0, 255); + private const double FACTOR = 0.7; + System.Drawing.Color color; + + /// + /// Constuctor for Color object. + /// + /// The red component value for the new Color structure. Valid values are 0 through 255. + /// The green component value for the new Color structure. Valid values are 0 through 255. + /// The blue component value for the new Color structure. Valid values are 0 through 255. + public Color(int red, int green, int blue) { + color = System.Drawing.Color.FromArgb(red, green, blue); + } + + /// + /// Constuctor for Color object. + /// + /// The red component value for the new Color structure. Valid values are 0 through 255. + /// The green component value for the new Color structure. Valid values are 0 through 255. + /// The blue component value for the new Color structure. Valid values are 0 through 255. + /// The transparency component value for the new Color structure. Valid values are 0 through 255. + public Color(int red, int green, int blue, int alpha) { + color = System.Drawing.Color.FromArgb(alpha, red, green, blue); + } + + /// + /// Constructor for Color object + /// + /// The red component value for the new Color structure. Valid values are 0 through 1. + /// The green component value for the new Color structure. Valid values are 0 through 1. + /// The blue component value for the new Color structure. Valid values are 0 through 1. + public Color(float red, float green, float blue) { + color = System.Drawing.Color.FromArgb((int)(red * 255 + .5), (int)(green * 255 + .5), (int)(blue * 255 + .5)); + } + + /// + /// Constructor for Color object + /// + /// The red component value for the new Color structure. Valid values are 0 through 1. + /// The green component value for the new Color structure. Valid values are 0 through 1. + /// The blue component value for the new Color structure. Valid values are 0 through 1. + /// The transparency component value for the new Color structure. Valid values are 0 through 1. + public Color(float red, float green, float blue, float alpha) { + color = System.Drawing.Color.FromArgb((int)(alpha * 255 + .5), (int)(red * 255 + .5), (int)(green * 255 + .5), (int)(blue * 255 + .5)); + } + + public Color(int argb) { + color = System.Drawing.Color.FromArgb(argb); + } + + /// + /// Constructor for Color object + /// + /// a Color object + /// + /// Has three overloads. + /// + public Color(System.Drawing.Color color) { + this.color = color; + } + + /// + /// Gets the red component value of this structure. + /// + /// The red component value of this structure. + public int R { + get { + return color.R; + } + } + + /// + /// Gets the green component value of this structure. + /// + /// The green component value of this structure. + public int G { + get { + return color.G; + } + } + + /// + /// Gets the blue component value of this structure. + /// + /// The blue component value of this structure. + public int B { + get { + return color.B; + } + } + + public Color Brighter() { + int r = color.R; + int g = color.G; + int b = color.B; + + int i = (int)(1.0/(1.0-FACTOR)); + if ( r == 0 && g == 0 && b == 0) { + return new Color(i, i, i); + } + if ( r > 0 && r < i ) r = i; + if ( g > 0 && g < i ) g = i; + if ( b > 0 && b < i ) b = i; + + return new Color(Math.Min((int)(r/FACTOR), 255), + Math.Min((int)(g/FACTOR), 255), + Math.Min((int)(b/FACTOR), 255)); + } + + public Color Darker() { + return new Color(Math.Max((int)(color.R * FACTOR), 0), + Math.Max((int)(color.G * FACTOR), 0), + Math.Max((int)(color.B * FACTOR), 0)); + } + + public override bool Equals(object obj) { + if (!(obj is Color)) + return false; + return color.Equals(((Color)obj).color); + } + + public override int GetHashCode() { + return color.GetHashCode(); + } + + public int ToArgb() { + return color.ToArgb(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/DocWriter.cs b/iTechSharp/iTextSharp/text/DocWriter.cs new file mode 100644 index 0000000..9e2b53f --- /dev/null +++ b/iTechSharp/iTextSharp/text/DocWriter.cs @@ -0,0 +1,416 @@ +using System; +using System.IO; +using System.Collections; +using System.util; +using iTextSharp.text.pdf; +/* + * $Id: DocWriter.cs,v 1.7 2008/05/13 11:25:09 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// An abstract Writer class for documents. + /// + /// + /// DocWriter is the abstract class of several writers such + /// as PdfWriter and HtmlWriter. + /// A DocWriter can be added as a DocListener + /// to a certain Document by getting an instance (see method + /// GetInstance() in the specific writer-classes). + /// Every Element added to the original Document + /// will be written to the stream of the listening + /// DocWriter. + /// + /// + /// + public abstract class DocWriter : IDocListener { + + /// This is some byte that is often used. + public const byte NEWLINE = (byte)'\n'; + + /// This is some byte that is often used. + public const byte TAB = (byte)'\t'; + + /// This is some byte that is often used. + public const byte LT = (byte)'<'; + + /// This is some byte that is often used. + public const byte SPACE = (byte)' '; + + /// This is some byte that is often used. + public const byte EQUALS = (byte)'='; + + /// This is some byte that is often used. + public const byte QUOTE = (byte)'\"'; + + /// This is some byte that is often used. + public const byte GT = (byte)'>'; + + /// This is some byte that is often used. + public const byte FORWARD = (byte)'/'; + + // membervariables + + /// The pageSize. + protected Rectangle pageSize; + + /// This is the document that has to be written. + protected Document document; + + /// The stream of this writer. + protected OutputStreamCounter os; + + /// Is the writer open for writing? + protected bool open = false; + + /// Do we have to pause all writing actions? + protected bool pause = false; + + /** Closes the stream on document close */ + protected bool closeStream = true; + + // constructor + + protected DocWriter() { + } + /// + /// Constructs a DocWriter. + /// + /// The Document that has to be written + /// The Stream the writer has to write to. + protected DocWriter(Document document, Stream os) + { + this.document = document; + this.os = new OutputStreamCounter(os); + } + + // implementation of the DocListener methods + + /// + /// Signals that an Element was added to the Document. + /// + /// + /// This method should be overriden in the specific DocWriter classes + /// derived from this abstract class. + /// + /// + /// false + public virtual bool Add(IElement element) { + return false; + } + + /// + /// Signals that the Document was opened. + /// + public virtual void Open() { + open = true; + } + + /// + /// Sets the pagesize. + /// + /// the new pagesize + /// a boolean + public virtual bool SetPageSize(Rectangle pageSize) { + this.pageSize = pageSize; + return true; + } + + /// + /// Sets the margins. + /// + /// + /// This does nothing. Has to be overridden if needed. + /// + /// the margin on the left + /// the margin on the right + /// the margin on the top + /// the margin on the bottom + /// + public virtual bool SetMargins(float marginLeft, float marginRight, float marginTop, float marginBottom) { + return false; + } + + /// + /// Signals that an new page has to be started. + /// + /// + /// This does nothing. Has to be overridden if needed. + /// + /// true if the page was added, false if not. + public virtual bool NewPage() { + if (!open) { + return false; + } + return true; + } + + /// + /// Changes the header of this document. + /// + /// + /// This method should be overriden in the specific DocWriter classes + /// derived from this abstract class if they actually support the use of + /// headers. + /// + /// the new header + public virtual HeaderFooter Header { + set {} + } + + /// + /// Resets the header of this document. + /// + /// + /// This method should be overriden in the specific DocWriter classes + /// derived from this abstract class if they actually support the use of + /// headers. + /// + public virtual void ResetHeader() { + } + + /// + /// Changes the footer of this document. + /// + /// + /// This method should be overriden in the specific DocWriter classes + /// derived from this abstract class if they actually support the use of + /// footers. + /// + /// the new footer + public virtual HeaderFooter Footer { + set {} + } + + /// + /// Resets the footer of this document. + /// + /// + /// This method should be overriden in the specific DocWriter classes + /// derived from this abstract class if they actually support the use of + /// footers. + /// + public virtual void ResetFooter() { + } + + /// + /// Sets the page number to 0. + /// + /// + /// This method should be overriden in the specific DocWriter classes + /// derived from this abstract class if they actually support the use of + /// pagenumbers. + /// + public virtual void ResetPageCount() { + } + + /// + /// Sets the page number. + /// + /// + /// This method should be overriden in the specific DocWriter classes + /// derived from this abstract class if they actually support the use of + /// pagenumbers. + /// + public virtual int PageCount { + set {} + } + + /// + /// Signals that the Document was closed and that no other + /// Elements will be added. + /// + public virtual void Close() { + open = false; + os.Flush(); + if (closeStream) + os.Close(); + } + + // methods + + /// + /// Converts a string into a Byte array + /// according to the ISO-8859-1 codepage. + /// + /// the text to be converted + /// the conversion result + public static byte[] GetISOBytes(string text) { + if (text == null) + return null; + int len = text.Length; + byte[] b = new byte[len]; + for (int k = 0; k < len; ++k) + b[k] = (byte)text[k]; + return b; + } + + /// + /// Let the writer know that all writing has to be paused. + /// + public virtual void Pause() { + pause = true; + } + + /** + * Checks if writing is paused. + * + * @return true if writing temporarely has to be paused, false otherwise. + */ + + public bool IsPaused() { + return pause; + } + + /// + /// Let the writer know that writing may be resumed. + /// + public virtual void Resume() { + pause = false; + } + + /// + /// Flushes the Stream. + /// + public virtual void Flush() { + os.Flush(); + } + + /// + /// Writes a string to the stream. + /// + /// the string to write + protected void Write(string str) { + byte[] tmp = GetISOBytes(str); + os.Write(tmp, 0, tmp.Length); + } + + /// + /// Writes a number of tabs. + /// + /// the number of tabs to add + protected void AddTabs(int indent) { + os.WriteByte(NEWLINE); + for (int i = 0; i < indent; i++) { + os.WriteByte(TAB); + } + } + + /// + /// Writes a key-value pair to the stream. + /// + /// the name of an attribute + /// the value of an attribute + protected void Write(string key, string value) { + os.WriteByte(SPACE); + Write(key); + os.WriteByte(EQUALS); + os.WriteByte(QUOTE); + Write(value); + os.WriteByte(QUOTE); + } + + /// + /// Writes a starttag to the stream. + /// + /// the name of the tag + protected void WriteStart(string tag) { + os.WriteByte(LT); + Write(tag); + } + + /// + /// Writes an endtag to the stream. + /// + /// the name of the tag + protected void WriteEnd(string tag) { + os.WriteByte(LT); + os.WriteByte(FORWARD); + Write(tag); + os.WriteByte(GT); + } + + /// + /// Writes an endtag to the stream. + /// + protected void WriteEnd() { + os.WriteByte(SPACE); + os.WriteByte(FORWARD); + os.WriteByte(GT); + } + + /// + /// Writes the markup attributes of the specified MarkupAttributes + /// object to the stream. + /// + /// the MarkupAttributes to write. + /// + protected bool WriteMarkupAttributes(Properties markup) { + if (markup == null) return false; + foreach (String name in markup.Keys) { + Write(name, markup[name]); + } + markup.Clear(); + return true; + } + + public virtual bool CloseStream { + get { + return closeStream; + } + set { + closeStream = value; + } + } + + public virtual bool SetMarginMirroring(bool marginMirroring) { + return false; + } + } +} diff --git a/iTechSharp/iTextSharp/text/Document.cs b/iTechSharp/iTextSharp/text/Document.cs new file mode 100644 index 0000000..41ed30f --- /dev/null +++ b/iTechSharp/iTextSharp/text/Document.cs @@ -0,0 +1,684 @@ +using System; +using System.Collections; + +/* + * $Id: Document.cs,v 1.45 2008/05/25 13:08:44 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + + /// + /// A generic Document class. + /// + /// + /// All kinds of Text-elements can be added to a HTMLDocument. + /// The Document signals all the listeners when an element + /// has been added.

    + ///

      + ///
    1. Once a document is created you can add some meta information. + ///
    2. You can also set the headers/footers. + ///
    3. You have to open the document before you can write content. + ///
    4. You can only write content (no more meta-formation!) once a document is opened. + ///
    5. When you change the header/footer on a certain page, this will be effective starting on the next page. + ///
    6. Ater closing the document, every listener (as well as its OutputStream) is closed too. + ///
    + ///
    + /// + /// + /// // creation of the document with a certain size and certain margins + /// Document document = new Document(PageSize.A4, 50, 50, 50, 50); + /// try { + /// // creation of the different writers + /// HtmlWriter.GetInstance(document, System.out); + /// PdfWriter.GetInstance(document, new FileOutputStream("text.pdf")); + /// // we add some meta information to the document + /// document.AddAuthor("Bruno Lowagie"); + /// document.AddSubject("This is the result of a Test."); + /// + /// // we define a header and a footer + /// HeaderFooter header = new HeaderFooter(new Phrase("This is a header."), false); + /// HeaderFooter footer = new HeaderFooter(new Phrase("This is page "), new Phrase(".")); + /// footer.SetAlignment(Element.ALIGN_CENTER); + /// document.SetHeader(header); + /// document.SetFooter(footer); + /// // we open the document for writing + /// document.Open(); + /// document.Add(new Paragraph("Hello world")); + /// } + /// catch (DocumentException de) { + /// Console.Error.WriteLine(de.Message); + /// } + /// document.Close(); + /// + /// + public class Document : IDocListener { + + // membervariables + + /// This constant may only be changed by Paulo Soares and/or Bruno Lowagie. + private const string ITEXT_VERSION = "iTextSharp 4.1.2 (based on iText 2.1.2u)"; + + /// Allows the pdf documents to be produced without compression for debugging purposes. + public static bool Compress = true; + + /// Scales the WMF font size. The default value is 0.86. + public static float WmfFontCorrection = 0.86f; + + /// The IDocListener. + private ArrayList listeners = new ArrayList(); + + /// Is the document open or not? + protected bool open; + + /// Has the document allready been closed? + protected bool close; + + // membervariables concerning the layout + + /// The size of the page. + protected Rectangle pageSize; + + /// margin in x direction starting from the left + protected float marginLeft = 0; + + /// margin in x direction starting from the right + protected float marginRight = 0; + + /// margin in y direction starting from the top + protected float marginTop = 0; + + /// margin in y direction starting from the bottom + protected float marginBottom = 0; + + protected bool marginMirroring = false; + /// Content of JavaScript onLoad function + protected string javaScript_onLoad = null; + + /// Content of JavaScript onUnLoad function + protected string javaScript_onUnLoad = null; + + /// Style class in HTML body tag + protected string htmlStyleClass = null; + + // headers, footers + + /// Current pagenumber + protected int pageN = 0; + + /// This is the textual part of a Page; it can contain a header + protected HeaderFooter header = null; + + /// This is the textual part of the footer + protected HeaderFooter footer = null; + + // constructor + + /// + /// Constructs a new Document-object. + /// + /// + /// Has three overloads. + /// + public Document() : this(iTextSharp.text.PageSize.A4) {} + + /// + /// Constructs a new Document-object. + /// + /// the pageSize + public Document(Rectangle pageSize) : this(pageSize, 36, 36, 36, 36) {} + + /// + /// Constructs a new Document-object. + /// + /// the pageSize + /// the margin on the left + /// the margin on the right + /// the margin on the top + /// the margin on the bottom + public Document(Rectangle pageSize, float marginLeft, float marginRight, float marginTop, float marginBottom) { + this.pageSize = pageSize; + this.marginLeft = marginLeft; + this.marginRight = marginRight; + this.marginTop = marginTop; + this.marginBottom = marginBottom; + } + + // listener methods + + /// + /// Adds a IDocListener to the Document. + /// + /// the new IDocListener + public void AddDocListener(IDocListener listener) { + listeners.Add(listener); + } + + /// + /// Removes a IDocListener from the Document. + /// + /// the IDocListener that has to be removed. + public void RemoveIDocListener(IDocListener listener) { + listeners.Remove(listener); + } + + // methods implementing the IDocListener interface + + /// + /// Adds an Element to the Document. + /// + /// the Element to add + /// true if the element was added, false if not + public virtual bool Add(IElement element) { + if (close) { + throw new DocumentException("The document has been closed. You can't add any Elements."); + } + if (!open && element.IsContent()) { + throw new DocumentException("The document is not open yet; you can only add Meta information."); + } + bool success = false; + foreach (IDocListener listener in listeners) { + success |= listener.Add(element); + } + if (element is ILargeElement) { + ILargeElement e = (ILargeElement)element; + if (!e.ElementComplete) + e.FlushContent(); + } + return success; + } + + /// + /// Opens the document. + /// + /// + /// Once the document is opened, you can't write any Header- or Meta-information + /// anymore. You have to open the document before you can begin to add content + /// to the body of the document. + /// + public virtual void Open() { + if (! close) { + open = true; + } + foreach (IDocListener listener in listeners) { + listener.SetPageSize(pageSize); + listener.SetMargins(marginLeft, marginRight, marginTop, marginBottom); + listener.Open(); + } + } + + /// + /// Sets the pagesize. + /// + /// the new pagesize + /// a bool + public virtual bool SetPageSize(Rectangle pageSize) { + this.pageSize = pageSize; + foreach (IDocListener listener in listeners) { + listener.SetPageSize(pageSize); + } + return true; + } + + /// + /// Sets the margins. + /// + /// the margin on the left + /// the margin on the right + /// the margin on the top + /// the margin on the bottom + /// + public virtual bool SetMargins(float marginLeft,float marginRight,float marginTop,float marginBottom) { + this.marginLeft = marginLeft; + this.marginRight = marginRight; + this.marginTop = marginTop; + this.marginBottom = marginBottom; + foreach (IDocListener listener in listeners) { + listener.SetMargins(marginLeft, marginRight, marginTop, marginBottom); + } + return true; + } + + /// + /// Signals that an new page has to be started. + /// + /// true if the page was added, false if not. + public virtual bool NewPage() { + if (!open || close) { + return false; + } + foreach (IDocListener listener in listeners) { + listener.NewPage(); + } + return true; + } + + /// + /// Changes the header of this document. + /// + /// a HeaderFooter + public virtual HeaderFooter Header { + set { + this.header = value; + foreach (IDocListener listener in listeners) { + listener.Header = value; + } + } + } + + /// + /// Resets the header of this document. + /// + public virtual void ResetHeader() { + this.header = null; + foreach (IDocListener listener in listeners) { + listener.ResetHeader(); + } + } + + /// + /// Changes the footer of this document. + /// + /// a HeaderFooter + public virtual HeaderFooter Footer { + set { + this.footer = value; + foreach (IDocListener listener in listeners) { + listener.Footer = value; + } + } + } + + /// + /// Resets the footer of this document. + /// + public virtual void ResetFooter() { + this.footer = null; + foreach (IDocListener listener in listeners) { + listener.ResetFooter(); + } + } + + /// + /// Sets the page number to 0. + /// + public virtual void ResetPageCount() { + pageN = 0; + foreach (IDocListener listener in listeners) { + listener.ResetPageCount(); + } + } + + /// + /// Sets the page number. + /// + /// an int + public virtual int PageCount { + set { + this.pageN = value; + foreach (IDocListener listener in listeners) { + listener.PageCount = value; + } + } + } + + /// + /// Returns the current page number. + /// + /// an int + public int PageNumber { + get { + return this.pageN; + } + } + + /// + /// Closes the document. + /// + /// + /// Once all the content has been written in the body, you have to close + /// the body. After that nothing can be written to the body anymore. + /// + public virtual void Close() { + if (!close) { + open = false; + close = true; + } + foreach (IDocListener listener in listeners) { + listener.Close(); + } + } + + // methods concerning the header or some meta information + + /// + /// Adds a user defined header to the document. + /// + /// the name of the header + /// the content of the header + /// true if successful, false otherwise + public bool AddHeader(string name, string content) { + return Add(new Header(name, content)); + } + + /// + /// Adds the title to a Document. + /// + /// the title + /// true if successful, false otherwise + public bool AddTitle(string title) { + return Add(new Meta(Element.TITLE, title)); + } + + /// + /// Adds the subject to a Document. + /// + /// the subject + /// true if successful, false otherwise + public bool AddSubject(string subject) { + return Add(new Meta(Element.SUBJECT, subject)); + } + + /// + /// Adds the keywords to a Document. + /// + /// keywords to add + /// true if successful, false otherwise + public bool AddKeywords(string keywords) { + return Add(new Meta(Element.KEYWORDS, keywords)); + } + + /// + /// Adds the author to a Document. + /// + /// the name of the author + /// true if successful, false otherwise + public bool AddAuthor(string author) { + return Add(new Meta(Element.AUTHOR, author)); + } + + /// + /// Adds the creator to a Document. + /// + /// the name of the creator + /// true if successful, false otherwise + public bool AddCreator(string creator) { + return Add(new Meta(Element.CREATOR, creator)); + } + + /// + /// Adds the producer to a Document. + /// + /// true if successful, false otherwise + public bool AddProducer() { + return Add(new Meta(Element.PRODUCER, "iText# by lowagie.com")); + } + + /// + /// Adds the current date and time to a Document. + /// + /// true if successful, false otherwise + public bool AddCreationDate() { + return Add(new Meta(Element.CREATIONDATE, DateTime.Now.ToString("ddd MMM dd HH:mm:ss zzz yyyy"))); + } + + // methods to get the layout of the document. + + /// + /// Returns the left margin. + /// + /// the left margin + public float LeftMargin { + get { + return marginLeft; + } + } + + /// + /// Return the right margin. + /// + /// the right margin + public float RightMargin { + get { + return marginRight; + } + } + + /// + /// Returns the top margin. + /// + /// the top margin + public float TopMargin { + get { + return marginTop; + } + } + + /// + /// Returns the bottom margin. + /// + /// the bottom margin + public float BottomMargin { + get { + return marginBottom; + } + } + + /// + /// Returns the lower left x-coordinate. + /// + /// the lower left x-coordinate + public float Left { + get { + return pageSize.GetLeft(marginLeft); + } + } + + /// + /// Returns the upper right x-coordinate. + /// + /// the upper right x-coordinate. + public float Right { + get { + return pageSize.GetRight(marginRight); + } + } + + /// + /// Returns the upper right y-coordinate. + /// + /// the upper right y-coordinate. + public float Top { + get { + return pageSize.GetTop(marginTop); + } + } + + /// + /// Returns the lower left y-coordinate. + /// + /// the lower left y-coordinate. + public float Bottom { + get { + return pageSize.GetBottom(marginBottom); + } + } + + /// + /// Returns the lower left x-coordinate considering a given margin. + /// + /// a margin + /// the lower left x-coordinate + public float GetLeft(float margin) { + return pageSize.GetLeft(marginLeft + margin); + } + + /// + /// Returns the upper right x-coordinate, considering a given margin. + /// + /// a margin + /// the upper right x-coordinate + public float GetRight(float margin) { + return pageSize.GetRight(marginRight + margin); + } + + /// + /// Returns the upper right y-coordinate, considering a given margin. + /// + /// a margin + /// the upper right y-coordinate + public float GetTop(float margin) { + return pageSize.GetTop(marginTop + margin); + } + + /// + /// Returns the lower left y-coordinate, considering a given margin. + /// + /// a margin + /// the lower left y-coordinate + public float GetBottom(float margin) { + return pageSize.GetBottom(marginBottom + margin); + } + + /// + /// Gets the pagesize. + /// + /// the page size + public Rectangle PageSize { + get { + return this.pageSize; + } + } + + /// + /// Checks if the document is open. + /// + /// true if the document is open + public bool IsOpen() { + return open; + } + + /// + /// Gets the iText version. + /// + /// iText version + public static string Version { + get { + return ITEXT_VERSION; + } + } + + /// + /// Gets the JavaScript onLoad command. + /// + /// the JavaScript onLoad command. + public string JavaScript_onLoad { + get { + return this.javaScript_onLoad; + } + + set { + this.javaScript_onLoad = value; + } + } + + /// + /// Gets the JavaScript onUnLoad command. + /// + /// the JavaScript onUnLoad command + public string JavaScript_onUnLoad { + get { + return this.javaScript_onUnLoad; + } + + set { + this.javaScript_onUnLoad = value; + } + } + + /// + /// Gets the style class of the HTML body tag + /// + /// the style class of the HTML body tag + public string HtmlStyleClass { + get { + return this.htmlStyleClass; + } + + set { + this.htmlStyleClass = value; + } + } + + /** + * Set the margin mirroring. It will mirror margins for odd/even pages. + *

    + * Note: it will not work with {@link Table}. + * + * @param marginMirroring + * true to mirror the margins + * @return always true + */ + public virtual bool SetMarginMirroring(bool marginMirroring) { + this.marginMirroring = marginMirroring; + foreach (IDocListener listener in listeners) { + listener.SetMarginMirroring(marginMirroring); + } + return true; + } + + /** + * Gets the margin mirroring flag. + * + * @return the margin mirroring flag + */ + public bool IsMarginMirroring() { + return marginMirroring; + } + } +} diff --git a/iTechSharp/iTextSharp/text/DocumentException.cs b/iTechSharp/iTextSharp/text/DocumentException.cs new file mode 100644 index 0000000..1c2b689 --- /dev/null +++ b/iTechSharp/iTextSharp/text/DocumentException.cs @@ -0,0 +1,77 @@ +using System; + +/* + * $Id: DocumentException.cs,v 1.3 2008/05/13 11:25:09 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + * + */ + +namespace iTextSharp.text { + ///

    + /// Signals that an error has occurred in a Document. + /// + /// + /// + /// + /// + public class DocumentException : Exception { + /// + /// Constructs a new DocumentException + /// + /// + /// Has two overloads. + /// + public DocumentException() : base() {} + + /// + /// Construct a new DocumentException + /// + /// error message + public DocumentException(string message) : base(message) {} + } +} diff --git a/iTechSharp/iTextSharp/text/Element.cs b/iTechSharp/iTextSharp/text/Element.cs new file mode 100644 index 0000000..cf4824f --- /dev/null +++ b/iTechSharp/iTextSharp/text/Element.cs @@ -0,0 +1,285 @@ +using System; + +/* + * $Id: Element.cs,v 1.7 2008/05/13 11:25:09 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text +{ + + /// + /// Interface for a text element. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public class Element + { + + // static membervariables (meta information) + + /// This is a possible type of Element. + public const int HEADER = 0; + + /// This is a possible type of Element. + public const int TITLE = 1; + + /// This is a possible type of Element. + public const int SUBJECT = 2; + + /// This is a possible type of Element. + public const int KEYWORDS = 3; + + /// This is a possible type of Element. + public const int AUTHOR = 4; + + /// This is a possible type of Element. + public const int PRODUCER = 5; + + /// This is a possible type of Element. + public const int CREATIONDATE = 6; + + /// This is a possible type of Element. + public const int CREATOR = 7; + + // static membervariables (content) + + /// This is a possible type of Element. + public const int CHUNK = 10; + + /// This is a possible type of Element. + public const int PHRASE = 11; + + /// This is a possible type of Element. + public const int PARAGRAPH = 12; + + /// This is a possible type of Element + public const int SECTION = 13; + + /// This is a possible type of Element + public const int LIST = 14; + + /// This is a possible type of Element + public const int LISTITEM = 15; + + /// This is a possible type of Element + public const int CHAPTER = 16; + + /// This is a possible type of Element + public const int ANCHOR = 17; + + // static membervariables (tables) + + /// This is a possible type of Element. + public const int CELL = 20; + + /// This is a possible type of Element. + public const int ROW = 21; + + /// This is a possible type of Element. + public const int TABLE = 22; + + /// This is a possible type of Element. + public const int PTABLE = 23; + + // static membervariables (annotations) + + /// This is a possible type of Element. + public const int ANNOTATION = 29; + + // static membervariables (geometric figures) + + /// This is a possible type of Element. + public const int RECTANGLE = 30; + + /// This is a possible type of Element. + public const int JPEG = 32; + + /** This is a possible type of Element. */ + public const int JPEG2000 = 33; + + /// This is a possible type of Element. + public const int IMGRAW = 34; + + /// This is a possible type of Element. + public const int IMGTEMPLATE = 35; + + /// This is a possible type of Element. + public const int MULTI_COLUMN_TEXT = 40; + + /** This is a possible type of Element. */ + public const int MARKED = 50; + + /** This is a possible type of Element. + * @since 2.1.2 + */ + public const int YMARK = 55; + + // static membervariables (alignment) + + /// + /// A possible value for paragraph Element. This + /// specifies that the text is aligned to the left + /// indent and extra whitespace should be placed on + /// the right. + /// + public const int ALIGN_UNDEFINED = -1; + + /// + /// A possible value for paragraph Element. This + /// specifies that the text is aligned to the left + /// indent and extra whitespace should be placed on + /// the right. + /// + public const int ALIGN_LEFT = 0; + + /// + /// A possible value for paragraph Element. This + /// specifies that the text is aligned to the center + /// and extra whitespace should be placed equally on + /// the left and right. + /// + public const int ALIGN_CENTER = 1; + + /// + /// A possible value for paragraph Element. This + /// specifies that the text is aligned to the right + /// indent and extra whitespace should be placed on + /// the left. + /// + public const int ALIGN_RIGHT = 2; + + /// + /// A possible value for paragraph Element. This + /// specifies that extra whitespace should be spread + /// out through the rows of the paragraph with the + /// text lined up with the left and right indent + /// except on the last line which should be aligned + /// to the left. + /// + public const int ALIGN_JUSTIFIED = 3; + + /// + /// A possible value for vertical Element. + /// + public const int ALIGN_TOP = 4; + + /// + /// A possible value for vertical Element. + /// + public const int ALIGN_MIDDLE = 5; + + /// + /// A possible value for vertical Element. + /// + public const int ALIGN_BOTTOM = 6; + + /// + /// A possible value for vertical Element. + /// + public const int ALIGN_BASELINE = 7; + + /// + /// Does the same as ALIGN_JUSTIFIED but the last line is also spread out. + /// + public const int ALIGN_JUSTIFIED_ALL = 8; + + // static member variables for CCITT compression + + /// + /// Pure two-dimensional encoding (Group 4) + /// + public const int CCITTG4 = 0x100; + /// + /// Pure one-dimensional encoding (Group 3, 1-D) + /// + public const int CCITTG3_1D = 0x101; + /// + /// Mixed one- and two-dimensional encoding (Group 3, 2-D) + /// + public const int CCITTG3_2D = 0x102; + /// + /// A flag indicating whether 1-bits are to be interpreted as black pixels + /// and 0-bits as white pixels, + /// + public const int CCITT_BLACKIS1 = 1; + /// + /// A flag indicating whether the filter expects extra 0-bits before each + /// encoded line so that the line begins on a byte boundary. + /// + public const int CCITT_ENCODEDBYTEALIGN = 2; + /// + /// A flag indicating whether end-of-line bit patterns are required to be + /// present in the encoding. + /// + public const int CCITT_ENDOFLINE = 4; + /// + /// A flag indicating whether the filter expects the encoded data to be + /// terminated by an end-of-block pattern, overriding the Rows + /// parameter. The use of this flag will set the key /EndOfBlock to false. + /// + public const int CCITT_ENDOFBLOCK = 8; + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/ElementTags.cs b/iTechSharp/iTextSharp/text/ElementTags.cs new file mode 100644 index 0000000..29388ef --- /dev/null +++ b/iTechSharp/iTextSharp/text/ElementTags.cs @@ -0,0 +1,521 @@ +using System; +using System.util; + +/* + * $Id: ElementTags.cs,v 1.8 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright (c) 2001, 2002 Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text +{ + /// + /// A class that contains all the possible tagnames and their attributes. + /// + public class ElementTags + { + + /// the root tag. + public const string ITEXT = "itext"; + + /// attribute of the root and annotation tag (also a special tag within a chapter or section) + public const string TITLE = "title"; + + /// attribute of the root tag + public const string SUBJECT = "subject"; + + /// attribute of the root tag + public const string KEYWORDS = "keywords"; + + /// attribute of the root tag + public const string AUTHOR = "author"; + + /// attribute of the root tag + public const string CREATIONDATE = "creationdate"; + + /// attribute of the root tag + public const string PRODUCER = "producer"; + + // Chapters and Sections + + /// the chapter tag + public const string CHAPTER = "chapter"; + + /// the section tag + public const string SECTION = "section"; + + /// attribute of section/chapter tag + public const string NUMBERDEPTH = "numberdepth"; + + /// attribute of section/chapter tag + public const string DEPTH = "depth"; + + /// attribute of section/chapter tag + public const string NUMBER = "number"; + + /// attribute of section/chapter tag + public const string INDENT = "indent"; + + /// attribute of chapter/section/paragraph/table/cell tag + public const string LEFT = "left"; + + /// attribute of chapter/section/paragraph/table/cell tag + public const string RIGHT = "right"; + + // Phrases, Anchors, Lists and Paragraphs + + /// the phrase tag + public const string PHRASE = "phrase"; + + /// the anchor tag + public const string ANCHOR = "anchor"; + + /// the list tag + public const string LIST = "list"; + + /// the listitem tag + public const string LISTITEM = "listitem"; + + /// the paragraph tag + public const string PARAGRAPH = "paragraph"; + + /// attribute of phrase/paragraph/cell tag + public const string LEADING = "leading"; + + /// attribute of paragraph/image/table tag + public const string ALIGN = "align"; + + /// attribute of paragraph + public const string KEEPTOGETHER = "keeptogether"; + + /// attribute of anchor tag + public const string NAME = "name"; + + /// attribute of anchor tag + public const string REFERENCE = "reference"; + + /// attribute of list tag + public const string LISTSYMBOL = "listsymbol"; + + /// attribute of list tag + public const string NUMBERED = "numbered"; + + /// attribute of the list tag + public const string LETTERED = "lettered"; + + /// attribute of list tag + public const string FIRST = "first"; + + /// attribute of list tag + public const string SYMBOLINDENT = "symbolindent"; + + /// attribute of list tag + public const string INDENTATIONLEFT = "indentationleft"; + + /// attribute of list tag + public const string INDENTATIONRIGHT = "indentationright"; + + // Chunks + + /// the chunk tag + public const string IGNORE = "ignore"; + + /// the chunk tag + public const string ENTITY = "entity"; + + /// the chunk tag + public const string ID = "id"; + + /// the chunk tag + public const string CHUNK = "chunk"; + + /// attribute of the chunk tag + public const string ENCODING = "encoding"; + + /// attribute of the chunk tag + public const string EMBEDDED = "embedded"; + + /// attribute of the chunk/table/cell tag + public const string COLOR = "color"; + + /// attribute of the chunk/table/cell tag + public const string RED = "red"; + + /// attribute of the chunk/table/cell tag + public const string GREEN = "green"; + + /// attribute of the chunk/table/cell tag + public const string BLUE = "blue"; + + /// attribute of the chunk tag + public static readonly string SUBSUPSCRIPT = Chunk.SUBSUPSCRIPT.ToLower(System.Globalization.CultureInfo.InvariantCulture); + + /// attribute of the chunk tag + public static readonly string LOCALGOTO = Chunk.LOCALGOTO.ToLower(System.Globalization.CultureInfo.InvariantCulture); + + /// attribute of the chunk tag + public static readonly string REMOTEGOTO = Chunk.REMOTEGOTO.ToLower(System.Globalization.CultureInfo.InvariantCulture); + + /// attribute of the chunk tag + public static readonly string LOCALDESTINATION = Chunk.LOCALDESTINATION.ToLower(System.Globalization.CultureInfo.InvariantCulture); + + /// attribute of the chunk tag + public static readonly string GENERICTAG = Chunk.GENERICTAG.ToLower(System.Globalization.CultureInfo.InvariantCulture); + + // tables/cells + + /// the table tag + public const string TABLE = "table"; + + /// the cell tag + public const string ROW = "row"; + + /// the cell tag + public const string CELL = "cell"; + + /// attribute of the table tag + public const string COLUMNS = "columns"; + + /// attribute of the table tag + public const string LASTHEADERROW = "lastHeaderRow"; + + /// attribute of the table tag + public const string CELLPADDING = "cellpadding"; + + /// attribute of the table tag + public const string CELLSPACING = "cellspacing"; + + /// attribute of the table tag + public const string OFFSET = "offset"; + + /// attribute of the table tag + public const string WIDTHS = "widths"; + + /// attribute of the table tag + public const string TABLEFITSPAGE = "tablefitspage"; + + /// attribute of the table tag + public const string CELLSFITPAGE = "cellsfitpage"; + + /// attribute of the table tag + public const string CONVERT2PDFP = "convert2pdfp"; + + /// attribute of the cell tag + public const string HORIZONTALALIGN = "horizontalalign"; + + /// attribute of the cell tag + public const string VERTICALALIGN = "verticalalign"; + + /// attribute of the cell tag + public const string COLSPAN = "colspan"; + + /// attribute of the cell tag + public const string ROWSPAN = "rowspan"; + + /// attribute of the cell tag + public const string HEADER = "header"; + + /// attribute of the cell tag + public const string FOOTER = "footer"; + + /// attribute of the cell tag + public const string NOWRAP = "nowrap"; + + /// attribute of the table/cell tag + public const string BORDERWIDTH = "borderwidth"; + + /// attribute of the table/cell tag + public const string TOP = "top"; + + /// attribute of the table/cell tag + public const string BOTTOM = "bottom"; + + /// attribute of the table/cell tag + public const string WIDTH = "width"; + + /// attribute of the table/cell tag + public const string BORDERCOLOR = "bordercolor"; + + /// attribute of the table/cell tag + public const string BACKGROUNDCOLOR = "backgroundcolor"; + + /// attribute of the table/cell tag + public const string BGRED = "bgred"; + + /// attribute of the table/cell tag + public const string BGGREEN = "bggreen"; + + /// attribute of the table/cell tag + public const string BGBLUE = "bgblue"; + + /// attribute of the table/cell tag + public const string GRAYFILL = "grayfill"; + + // Misc + + /// the image tag + public const string IMAGE = "image"; + + /// the image tag + public const string BOOKMARKOPEN = "bookmarkopen"; + + /// attribute of the image and annotation tag + public const string URL = "url"; + + /// attribute of the image tag + public const string UNDERLYING = "underlying"; + + /// attribute of the image tag + public const string TEXTWRAP = "textwrap"; + + /// attribute of the image tag + public const string ALT = "alt"; + + /// attribute of the image tag + public const string ABSOLUTEX = "absolutex"; + + /// attribute of the image tag + public const string ABSOLUTEY = "absolutey"; + + /// attribute of the image tag + public const string PLAINWIDTH = "plainwidth"; + + /// attribute of the image tag + public const string PLAINHEIGHT = "plainheight"; + + /// attribute of the image tag + public const string SCALEDWIDTH = "scaledwidth"; + + /// attribute of the image tag + public const string SCALEDHEIGHT = "scaledheight"; + + /// attribute of the image tag + public const string ROTATION = "rotation"; + + /// the newpage tag + public const string NEWPAGE = "newpage"; + + /// the newpage tag + public const string NEWLINE = "newline"; + + /// the annotation tag + public const string ANNOTATION = "annotation"; + + /// attribute of the annotation tag + public const string FILE = "file"; + + /// attribute of the annotation tag + public const string DESTINATION = "destination"; + + /// attribute of the annotation tag + public const string PAGE = "page"; + + /// attribute of the annotation tag + public const string NAMED = "named"; + + /// attribute of the annotation tag + public const string APPLICATION = "application"; + + /// attribute of the annotation tag + public const string PARAMETERS = "parameters"; + + /// attribute of the annotation tag + public const string OPERATION = "operation"; + + /// attribute of the annotation tag + public const string DEFAULTDIR = "defaultdir"; + + /// attribute of the annotation tag + public const string LLX = "llx"; + + /// attribute of the annotation tag + public const string LLY = "lly"; + + /// attribute of the annotation tag + public const string URX = "urx"; + + /// attribute of the annotation tag + public const string URY = "ury"; + + /// attribute of the annotation tag + public const string CONTENT = "content"; + + // alignment attribute values + + /// the possible value of an alignment attribute + public const string ALIGN_LEFT = "Left"; + + /// the possible value of an alignment attribute + public const string ALIGN_CENTER = "Center"; + + /// the possible value of an alignment attribute + public const string ALIGN_RIGHT = "Right"; + + /// the possible value of an alignment attribute + public const string ALIGN_JUSTIFIED = "Justify"; + + /// the possible value of an alignment attribute + public const string ALIGN_JUSTIFIED_ALL = "JustifyAll"; + + /// the possible value of an alignment attribute + public const string ALIGN_TOP = "Top"; + + /// the possible value of an alignment attribute + public const string ALIGN_MIDDLE = "Middle"; + + /// the possible value of an alignment attribute + public const string ALIGN_BOTTOM = "Bottom"; + + /// the possible value of an alignment attribute + public const string ALIGN_BASELINE = "Baseline"; + + /// the possible value of an alignment attribute + public const string DEFAULT = "Default"; + + /// the possible value of an alignment attribute + public const string UNKNOWN = "unknown"; + + /// the possible value of an alignment attribute + public const string FONT = "font"; + + /// the possible value of an alignment attribute + public const string SIZE = "size"; + + /// the possible value of an alignment attribute + public const string STYLE = "fontstyle"; + + /// the possible value of a tag + public const string HORIZONTALRULE = "horizontalrule"; + /** the possible value of a tag */ + public const string PAGE_SIZE = "pagesize"; + + /** the possible value of a tag */ + public const string ORIENTATION = "orientation"; + + /** a possible list attribute */ + public const String ALIGN_INDENTATION_ITEMS = "alignindent"; + + /** a possible list attribute */ + public const String AUTO_INDENT_ITEMS = "autoindent"; + + /** a possible list attribute */ + public const String LOWERCASE = "lowercase"; + + // methods + + /// + /// Translates the alignment value to a String value. + /// + /// the alignment value + /// the translated value + public static string GetAlignment(int alignment) + { + switch (alignment) + { + case Element.ALIGN_LEFT: + return ALIGN_LEFT; + case Element.ALIGN_CENTER: + return ALIGN_CENTER; + case Element.ALIGN_RIGHT: + return ALIGN_RIGHT; + case Element.ALIGN_JUSTIFIED: + case Element.ALIGN_JUSTIFIED_ALL: + return ALIGN_JUSTIFIED; + case Element.ALIGN_TOP: + return ALIGN_TOP; + case Element.ALIGN_MIDDLE: + return ALIGN_MIDDLE; + case Element.ALIGN_BOTTOM: + return ALIGN_BOTTOM; + case Element.ALIGN_BASELINE: + return ALIGN_BASELINE; + default: + return DEFAULT; + } + } + + /** + * Translates a String value to an alignment value. + * (written by Norman Richards, integrated into iText by Bruno) + * @param a String (one of the ALIGN_ constants of this class) + * @param an alignment value (one of the ALIGN_ constants of the Element interface) + */ + public static int AlignmentValue(String alignment) { + if (alignment == null) return Element.ALIGN_UNDEFINED; + if (Util.EqualsIgnoreCase(ALIGN_CENTER, alignment)) { + return Element.ALIGN_CENTER; + } + if (Util.EqualsIgnoreCase(ALIGN_LEFT, alignment)) { + return Element.ALIGN_LEFT; + } + if (Util.EqualsIgnoreCase(ALIGN_RIGHT, alignment)) { + return Element.ALIGN_RIGHT; + } + if (Util.EqualsIgnoreCase(ALIGN_JUSTIFIED, alignment)) { + return Element.ALIGN_JUSTIFIED; + } + if (Util.EqualsIgnoreCase(ALIGN_JUSTIFIED_ALL, alignment)) { + return Element.ALIGN_JUSTIFIED_ALL; + } + if (Util.EqualsIgnoreCase(ALIGN_TOP, alignment)) { + return Element.ALIGN_TOP; + } + if (Util.EqualsIgnoreCase(ALIGN_MIDDLE, alignment)) { + return Element.ALIGN_MIDDLE; + } + if (Util.EqualsIgnoreCase(ALIGN_BOTTOM, alignment)) { + return Element.ALIGN_BOTTOM; + } + if (Util.EqualsIgnoreCase(ALIGN_BASELINE, alignment)) { + return Element.ALIGN_BASELINE; + } + + return Element.ALIGN_UNDEFINED; + } + + } +} diff --git a/iTechSharp/iTextSharp/text/Font.cs b/iTechSharp/iTextSharp/text/Font.cs new file mode 100644 index 0000000..ee2a1ca --- /dev/null +++ b/iTechSharp/iTextSharp/text/Font.cs @@ -0,0 +1,698 @@ +using System; +using System.util; + +using iTextSharp.text.pdf; +using iTextSharp.text.html; + +/* + * $Id: Font.cs,v 1.11 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// Contains all the specifications of a font: fontfamily, size, style and color. + /// + /// + /// + /// Paragraph p = new Paragraph("This is a paragraph", + /// new Font(Font.HELVETICA, 18, Font.BOLDITALIC, new Color(0, 0, 255))); + /// + /// + public class Font : IComparable { + + // static membervariables for the different families + + /// a possible value of a font family. + public const int COURIER = 0; + + /// a possible value of a font family. + public const int HELVETICA = 1; + + /// a possible value of a font family. + public const int TIMES_ROMAN = 2; + + /// a possible value of a font family. + public const int SYMBOL = 3; + + /// a possible value of a font family. + public const int ZAPFDINGBATS = 4; + + // static membervariables for the different styles + + /// this is a possible style. + public const int NORMAL = 0; + + /// this is a possible style. + public const int BOLD = 1; + + /// this is a possible style. + public const int ITALIC = 2; + + /// this is a possible style. + public const int UNDERLINE = 4; + + /// this is a possible style. + public const int STRIKETHRU = 8; + + /// this is a possible style. + public const int BOLDITALIC = BOLD | ITALIC; + + // static membervariables + + /// the value of an undefined attribute. + public const int UNDEFINED = -1; + + /// the value of the default size. + public const int DEFAULTSIZE = 12; + + // membervariables + + /// the value of the fontfamily. + private int family = UNDEFINED; + + /// the value of the fontsize. + private float size = UNDEFINED; + + /// the value of the style. + private int style = UNDEFINED; + + /// the value of the color. + private Color color; + + /// the external font + private BaseFont baseFont = null; + + // constructors + + /** + * Copy constructor of a Font + * @param other the font that has to be copied + */ + public Font(Font other) { + this.color = other.color; + this.family = other.family; + this.size = other.size; + this.style = other.style; + this.baseFont = other.baseFont; + } + + /// + /// Constructs a Font. + /// + /// the family to which this font belongs + /// the size of this font + /// the style of this font + /// the Color of this font. + public Font(int family, float size, int style, Color color) { + this.family = family; + this.size = size; + this.style = style; + this.color = color; + } + + /// + /// Constructs a Font. + /// + /// the external font + /// the size of this font + /// the style of this font + /// the Color of this font. + public Font(BaseFont bf, float size, int style, Color color) { + this.baseFont = bf; + this.size = size; + this.style = style; + this.color = color; + } + + /// + /// Constructs a Font. + /// + /// the external font + /// the size of this font + /// the style of this font + public Font(BaseFont bf, float size, int style) : this(bf, size, style, null) {} + + /// + /// Constructs a Font. + /// + /// the external font + /// the size of this font + public Font(BaseFont bf, float size) : this(bf, size, UNDEFINED, null) {} + + /// + /// Constructs a Font. + /// + /// the external font + public Font(BaseFont bf) : this(bf, UNDEFINED, UNDEFINED, null) {} + + /// + /// Constructs a Font. + /// + /// the family to which this font belongs + /// the size of this font + /// the style of this font + public Font(int family, float size, int style) : this(family, size, style, null) {} + + /// + /// Constructs a Font. + /// + /// the family to which this font belongs + /// the size of this font + public Font(int family, float size) : this(family, size, UNDEFINED, null) {} + + /// + /// Constructs a Font. + /// + /// the family to which this font belongs + public Font(int family) : this(family, UNDEFINED, UNDEFINED, null) {} + + /// + /// Constructs a Font. + /// + /// + /// Has nine overloads. + /// + public Font() : this(UNDEFINED, UNDEFINED, UNDEFINED, null) {} + + // implementation of the Comparable interface + + /// + /// Compares this Font with another + /// + /// the other Font + /// a value + public virtual int CompareTo(Object obj) { + if (obj == null) { + return -1; + } + Font font; + try { + font = (Font) obj; + if (baseFont != null && !baseFont.Equals(font.BaseFont)) { + return -2; + } + if (this.family != font.Family) { + return 1; + } + if (this.size != font.Size) { + return 2; + } + if (this.style != font.Style) { + return 3; + } + if (this.color == null) { + if (font.Color == null) { + return 0; + } + return 4; + } + if (font.Color == null) { + return 4; + } + if (((Color)this.color).Equals(font.Color)) { + return 0; + } + return 4; + } + catch { + return -3; + } + } + + // FAMILY + + /// + /// Gets the family of this font. + /// + /// the value of the family + public int Family { + get { + return family; + } + } + + /// + /// Gets the familyname as a string. + /// + /// the familyname + public virtual string Familyname { + get { + string tmp = "unknown"; + switch (this.Family) { + case Font.COURIER: + return FontFactory.COURIER; + case Font.HELVETICA: + return FontFactory.HELVETICA; + case Font.TIMES_ROMAN: + return FontFactory.TIMES_ROMAN; + case Font.SYMBOL: + return FontFactory.SYMBOL; + case Font.ZAPFDINGBATS: + return FontFactory.ZAPFDINGBATS; + default: + if (baseFont != null) { + string[][] names = baseFont.FamilyFontName; + for (int i = 0; i < names.Length; i++) { + if ("0".Equals(names[i][2])) { + return names[i][3]; + } + if ("1033".Equals(names[i][2])) { + tmp = names[i][3]; + } + if ("".Equals(names[i][2])) { + tmp = names[i][3]; + } + } + } + break; + } + return tmp; + } + } + + /// + /// Sets the family using a String ("Courier", + /// "Helvetica", "Times New Roman", "Symbol" or "ZapfDingbats"). + /// + /// A String representing a certain font-family. + public virtual void SetFamily(String family) { + this.family = GetFamilyIndex(family); + } + + /// + /// Translates a string-value of a certain family + /// into the index that is used for this family in this class. + /// + /// A string representing a certain font-family + /// the corresponding index + public static int GetFamilyIndex(string family) { + if (Util.EqualsIgnoreCase(family, FontFactory.COURIER)) { + return COURIER; + } + if (Util.EqualsIgnoreCase(family, FontFactory.HELVETICA)) { + return HELVETICA; + } + if (Util.EqualsIgnoreCase(family, FontFactory.TIMES_ROMAN)) { + return TIMES_ROMAN; + } + if (Util.EqualsIgnoreCase(family, FontFactory.SYMBOL)) { + return SYMBOL; + } + if (Util.EqualsIgnoreCase(family, FontFactory.ZAPFDINGBATS)) { + return ZAPFDINGBATS; + } + return UNDEFINED; + } + + // SIZE + + /// + /// Get/set the size of this font. + /// + /// the size of this font + public virtual float Size { + get { + return size; + } + set { + this.size = value; + } + } + + /** Gets the size that can be used with the calculated BaseFont. + * @return the size that can be used with the calculated BaseFont + */ + public float CalculatedSize { + get { + float s = this.size; + if (s == UNDEFINED) { + s = DEFAULTSIZE; + } + return s; + } + } + + /** + * Gets the leading that can be used with this font. + * + * @param linespacing + * a certain linespacing + * @return the height of a line + */ + public float GetCalculatedLeading(float linespacing) { + return linespacing * CalculatedSize; + } + + // STYLE + + /// + /// Gets the style of this font. + /// + /// the style of this font + public int Style { + get { + return style; + } + } + + /** Gets the style that can be used with the calculated BaseFont. + * @return the style that can be used with the calculated BaseFont + */ + public int CalculatedStyle { + get { + int style = this.style; + if (style == UNDEFINED) { + style = NORMAL; + } + if (baseFont != null) + return style; + if (family == SYMBOL || family == ZAPFDINGBATS) + return style; + else + return style & (~BOLDITALIC); + } + } + + /// + /// checks if this font is Bold. + /// + /// a boolean + public bool IsBold() { + if (style == UNDEFINED) { + return false; + } + return (style & BOLD) == BOLD; + } + + /// + /// checks if this font is Bold. + /// + /// a boolean + public bool IsItalic() { + if (style == UNDEFINED) { + return false; + } + return (style & ITALIC) == ITALIC; + } + + /// + /// checks if this font is underlined. + /// + /// a boolean + public bool IsUnderlined() { + if (style == UNDEFINED) { + return false; + } + return (style & UNDERLINE) == UNDERLINE; + } + + /// + /// checks if the style of this font is STRIKETHRU. + /// + /// a boolean + public bool IsStrikethru() { + if (style == UNDEFINED) { + return false; + } + return (style & STRIKETHRU) == STRIKETHRU; + } + + /// + /// Sets the style using a String containing one of + /// more of the following values: normal, bold, italic, underline, strike. + /// + /// A String representing a certain style. + public virtual void SetStyle(String style) { + if (this.style == UNDEFINED) this.style = NORMAL; + this.style |= GetStyleValue(style); + } + + /** + * Sets the style. + * @param style the style. + */ + + public virtual void SetStyle(int style) { + if (this.style == UNDEFINED) this.style = NORMAL; + this.style |= style; + } + + /// + /// Translates a string-value of a certain style + /// into the index value is used for this style in this class. + /// + /// a string + /// the corresponding value + public static int GetStyleValue(string style) { + int s = 0; + if (style.IndexOf(Markup.CSS_VALUE_NORMAL) != -1) { + s |= NORMAL; + } + if (style.IndexOf(Markup.CSS_VALUE_BOLD) != -1) { + s |= BOLD; + } + if (style.IndexOf(Markup.CSS_VALUE_ITALIC) != -1) { + s |= ITALIC; + } + if (style.IndexOf(Markup.CSS_VALUE_OBLIQUE) != -1) { + s |= ITALIC; + } + if (style.IndexOf(Markup.CSS_VALUE_UNDERLINE) != -1) { + s |= UNDERLINE; + } + if (style.IndexOf(Markup.CSS_VALUE_LINETHROUGH) != -1) { + s |= STRIKETHRU; + } + return s; + } + + + // COLOR + + /// + /// Get/set the color of this font. + /// + /// the color of this font + public virtual Color Color { + get { + return color; + } + set { + this.color = value; + } + } + + /// + /// Sets the color. + /// + /// the red-value of the new color + /// the green-value of the new color + /// the blue-value of the new color + public virtual void SetColor(int red, int green, int blue) { + this.color = new Color(red, green, blue); + } + + // BASEFONT + + /// + /// Gets the BaseFont inside this object. + /// + /// the BaseFont + public BaseFont BaseFont { + get { + return baseFont; + } + } + + /** Gets the BaseFont this class represents. + * For the built-in fonts a BaseFont is calculated. + * @param specialEncoding true to use the special encoding for Symbol and ZapfDingbats, + * false to always use Cp1252 + * @return the BaseFont this class represents + */ + public BaseFont GetCalculatedBaseFont(bool specialEncoding) { + if (baseFont != null) + return baseFont; + int style = this.style; + if (style == UNDEFINED) { + style = NORMAL; + } + String fontName = BaseFont.HELVETICA; + String encoding = BaseFont.WINANSI; + BaseFont cfont = null; + switch (family) { + case COURIER: + switch (style & BOLDITALIC) { + case BOLD: + fontName = BaseFont.COURIER_BOLD; + break; + case ITALIC: + fontName = BaseFont.COURIER_OBLIQUE; + break; + case BOLDITALIC: + fontName = BaseFont.COURIER_BOLDOBLIQUE; + break; + default: + //case NORMAL: + fontName = BaseFont.COURIER; + break; + } + break; + case TIMES_ROMAN: + switch (style & BOLDITALIC) { + case BOLD: + fontName = BaseFont.TIMES_BOLD; + break; + case ITALIC: + fontName = BaseFont.TIMES_ITALIC; + break; + case BOLDITALIC: + fontName = BaseFont.TIMES_BOLDITALIC; + break; + default: + //case NORMAL: + fontName = BaseFont.TIMES_ROMAN; + break; + } + break; + case SYMBOL: + fontName = BaseFont.SYMBOL; + if (specialEncoding) + encoding = BaseFont.SYMBOL; + break; + case ZAPFDINGBATS: + fontName = BaseFont.ZAPFDINGBATS; + if (specialEncoding) + encoding = BaseFont.ZAPFDINGBATS; + break; + default: + //case Font.HELVETICA: + switch (style & BOLDITALIC) { + case BOLD: + fontName = BaseFont.HELVETICA_BOLD; + break; + case ITALIC: + fontName = BaseFont.HELVETICA_OBLIQUE; + break; + case BOLDITALIC: + fontName = BaseFont.HELVETICA_BOLDOBLIQUE; + break; + default: + //case NORMAL: + fontName = BaseFont.HELVETICA; + break; + } + break; + } + cfont = BaseFont.CreateFont(fontName, encoding, false); + return cfont; + } + + // Helper methods + + /// + /// Checks if the properties of this font are undefined or null. + ///

    + /// If so, the standard should be used. + ///

    + /// a boolean + public virtual bool IsStandardFont() { + return (family == UNDEFINED + && size == UNDEFINED + && style == UNDEFINED + && color == null + && baseFont == null); + } + + /// + /// Replaces the attributes that are equal to null with + /// the attributes of a given font. + /// + /// the font of a bigger element class + /// a Font + public virtual Font Difference(Font font) { + if (font == null) return this; + // size + float dSize = font.size; + if (dSize == UNDEFINED) { + dSize = this.size; + } + // style + int dStyle = UNDEFINED; + int style1 = this.Style; + int style2 = font.Style; + if (style1 != UNDEFINED || style2 != UNDEFINED) { + if (style1 == UNDEFINED) style1 = 0; + if (style2 == UNDEFINED) style2 = 0; + dStyle = style1 | style2; + } + // color + object dColor = (Color)font.Color; + if (dColor == null) { + dColor = this.Color; + } + // family + if (font.baseFont != null) { + return new Font(font.BaseFont, dSize, dStyle, (Color)dColor); + } + if (font.Family != UNDEFINED) { + return new Font(font.Family, dSize, dStyle, (Color)dColor); + } + if (this.baseFont != null) { + if (dStyle == style1) { + return new Font(this.BaseFont, dSize, dStyle, (Color)dColor); + } + else { + return FontFactory.GetFont(this.Familyname, dSize, dStyle, (Color)dColor); + } + } + return new Font(this.Family, dSize, dStyle, (Color)dColor); + } + } +} diff --git a/iTechSharp/iTextSharp/text/FontFactory.cs b/iTechSharp/iTextSharp/text/FontFactory.cs new file mode 100644 index 0000000..a90d249 --- /dev/null +++ b/iTechSharp/iTextSharp/text/FontFactory.cs @@ -0,0 +1,426 @@ +using System; +using System.IO; +using System.Collections; +using System.util; +using System.Globalization; + +using iTextSharp.text.html; +using iTextSharp.text.pdf; +using iTextSharp.text; + +/* + * $Id: FontFactory.cs,v 1.16 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text { + /// + /// If you are using True Type fonts, you can declare the paths of the different ttf- and ttc-files + /// to this static class first and then create fonts in your code using one of the static getFont-method + /// without having to enter a path as parameter. + /// + public sealed class FontFactory { + + /// This is a possible value of a base 14 type 1 font + public const string COURIER = BaseFont.COURIER; + + /// This is a possible value of a base 14 type 1 font + public const string COURIER_BOLD = BaseFont.COURIER_BOLD; + + /// This is a possible value of a base 14 type 1 font + public const string COURIER_OBLIQUE = BaseFont.COURIER_OBLIQUE; + + /// This is a possible value of a base 14 type 1 font + public const string COURIER_BOLDOBLIQUE = BaseFont.COURIER_BOLDOBLIQUE; + + /// This is a possible value of a base 14 type 1 font + public const string HELVETICA = BaseFont.HELVETICA; + + /// This is a possible value of a base 14 type 1 font + public const string HELVETICA_BOLD = BaseFont.HELVETICA_BOLD; + + /// This is a possible value of a base 14 type 1 font + public const string HELVETICA_OBLIQUE = BaseFont.HELVETICA_OBLIQUE; + + /// This is a possible value of a base 14 type 1 font + public const string HELVETICA_BOLDOBLIQUE = BaseFont.HELVETICA_BOLDOBLIQUE; + + /// This is a possible value of a base 14 type 1 font + public const string SYMBOL = BaseFont.SYMBOL; + + /// This is a possible value of a base 14 type 1 font + public const string TIMES = "Times"; + + /// This is a possible value of a base 14 type 1 font + public const string TIMES_ROMAN = BaseFont.TIMES_ROMAN; + + /// This is a possible value of a base 14 type 1 font + public const string TIMES_BOLD = BaseFont.TIMES_BOLD; + + /// This is a possible value of a base 14 type 1 font + public const string TIMES_ITALIC = BaseFont.TIMES_ITALIC; + + /// This is a possible value of a base 14 type 1 font + public const string TIMES_BOLDITALIC = BaseFont.TIMES_BOLDITALIC; + + /// This is a possible value of a base 14 type 1 font + public const string ZAPFDINGBATS = BaseFont.ZAPFDINGBATS; + + private static FontFactoryImp fontImp = new FontFactoryImp(); + + /// This is the default encoding to use. + private static string defaultEncoding = BaseFont.WINANSI; + + /// This is the default value of the embedded variable. + private static bool defaultEmbedding = BaseFont.NOT_EMBEDDED; + + /// Creates new FontFactory + private FontFactory() { + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// the size of this font + /// the style of this font + /// the Color of this font + /// a Font object + public static Font GetFont(string fontname, string encoding, bool embedded, float size, int style, Color color) { + return fontImp.GetFont(fontname, encoding, embedded, size, style, color); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// the size of this font + /// the style of this font + /// the Color of this font + /// true if the font comes from the cache or is added to the cache if new, false if the font is always created new + /// a Font object + public static Font GetFont(string fontname, string encoding, bool embedded, float size, int style, Color color, bool cached) { + return fontImp.GetFont(fontname, encoding, embedded, size, style, color, cached); + } + + /// + /// Constructs a Font-object. + /// + /// the attributes of a Font object + /// a Font object + public static Font GetFont(Properties attributes) { + fontImp.DefaultEmbedding = defaultEmbedding; + fontImp.DefaultEncoding = defaultEncoding; + return fontImp.GetFont(attributes); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// the size of this font + /// the style of this font + /// a Font object + public static Font GetFont(string fontname, string encoding, bool embedded, float size, int style) { + return GetFont(fontname, encoding, embedded, size, style, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// the size of this font + /// + public static Font GetFont(string fontname, string encoding, bool embedded, float size) { + return GetFont(fontname, encoding, embedded, size, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// a Font object + public static Font GetFont(string fontname, string encoding, bool embedded) { + return GetFont(fontname, encoding, embedded, Font.UNDEFINED, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// the size of this font + /// the style of this font + /// the Color of this font + /// a Font object + public static Font GetFont(string fontname, string encoding, float size, int style, Color color) { + return GetFont(fontname, encoding, defaultEmbedding, size, style, color); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// the size of this font + /// the style of this font + /// a Font object + public static Font GetFont(string fontname, string encoding, float size, int style) { + return GetFont(fontname, encoding, defaultEmbedding, size, style, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// the size of this font + /// a Font object + public static Font GetFont(string fontname, string encoding, float size) { + return GetFont(fontname, encoding, defaultEmbedding, size, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// a Font object + public static Font GetFont(string fontname, string encoding) { + return GetFont(fontname, encoding, defaultEmbedding, Font.UNDEFINED, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the size of this font + /// the style of this font + /// the Color of this font + /// a Font object + public static Font GetFont(string fontname, float size, int style, Color color) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, size, style, color); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the size of this font + /// the Color of this font + /// a Font object + public static Font GetFont(string fontname, float size, Color color) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, size, Font.UNDEFINED, color); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the size of this font + /// the style of this font + /// a Font object + public static Font GetFont(string fontname, float size, int style) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, size, style, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the size of this font + /// a Font object + public static Font GetFont(string fontname, float size) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, size, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// a Font object + public static Font GetFont(string fontname) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, Font.UNDEFINED, Font.UNDEFINED, null); + } + + /** + * Register a font by giving explicitly the font family and name. + * @param familyName the font family + * @param fullName the font name + * @param path the font path + */ + public void RegisterFamily(String familyName, String fullName, String path) { + fontImp.RegisterFamily(familyName, fullName, path); + } + + public static void Register(Properties attributes) { + string path; + string alias = null; + + path = attributes.Remove("path"); + alias = attributes.Remove("alias"); + + fontImp.Register(path, alias); + } + + /// + /// Register a ttf- or a ttc-file. + /// + /// the path to a ttf- or ttc-file + public static void Register(string path) { + Register(path, null); + } + + /// + /// Register a ttf- or a ttc-file and use an alias for the font contained in the ttf-file. + /// + /// the path to a ttf- or ttc-file + /// the alias you want to use for the font + public static void Register(string path, string alias) { + fontImp.Register(path, alias); + } + + /** Register all the fonts in a directory. + * @param dir the directory + * @return the number of fonts registered + */ + public static int RegisterDirectory(String dir) { + return fontImp.RegisterDirectory(dir); + } + + /** + * Register all the fonts in a directory and possibly its subdirectories. + * @param dir the directory + * @param scanSubdirectories recursively scan subdirectories if true + * @return the number of fonts registered + * @since 2.1.2 + */ + public static int RegisterDirectory(String dir, bool scanSubdirectories) { + return fontImp.RegisterDirectory(dir, scanSubdirectories); + } + + /** Register fonts in some probable directories. It usually works in Windows, + * Linux and Solaris. + * @return the number of fonts registered + */ + public static int RegisterDirectories() { + return fontImp.RegisterDirectories(); + } + + /// + /// Gets a set of registered fontnames. + /// + /// a set of registered fontnames + public static ICollection RegisteredFonts { + get { + return fontImp.RegisteredFonts; + } + } + + /// + /// Gets a set of registered font families. + /// + /// a set of registered font families + public static ICollection RegisteredFamilies { + get { + return fontImp.RegisteredFamilies; + } + } + + /// + /// Checks whether the given font is contained within the object + /// + /// the name of the font + /// true if font is contained within the object + public static bool Contains(string fontname) { + return fontImp.IsRegistered(fontname); + } + + /// + /// Checks if a certain font is registered. + /// + /// the name of the font that has to be checked + /// true if the font is found + public static bool IsRegistered(string fontname) { + return fontImp.IsRegistered(fontname); + } + + public static string DefaultEncoding { + get { + return defaultEncoding; + } + } + + public static bool DefaultEmbedding { + get { + return defaultEmbedding; + } + } + + + public static FontFactoryImp FontImp { + get { + return fontImp; + } + set { + if (value == null) + throw new ArgumentNullException("FontFactoryImp cannot be null."); + fontImp = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/FontFactoryImp.cs b/iTechSharp/iTextSharp/text/FontFactoryImp.cs new file mode 100644 index 0000000..2159137 --- /dev/null +++ b/iTechSharp/iTextSharp/text/FontFactoryImp.cs @@ -0,0 +1,677 @@ +using System; +using System.IO; +using System.Collections; +using System.util; +using System.Globalization; + +using iTextSharp.text.html; +using iTextSharp.text.pdf; +using iTextSharp.text; + +/* + * $Id: FontFactoryImp.cs,v 1.13 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text { + /// + /// If you are using True Type fonts, you can declare the paths of the different ttf- and ttc-files + /// to this class first and then create fonts in your code using one of the getFont method + /// without having to enter a path as parameter. + /// + public class FontFactoryImp { + + /// This is a map of postscriptfontnames of True Type fonts and the path of their ttf- or ttc-file. + private Properties trueTypeFonts = new Properties(); + + private static String[] TTFamilyOrder = { + "3", "1", "1033", + "3", "0", "1033", + "1", "0", "0", + "0", "3", "0" + }; + + /// This is a map of fontfamilies. + private Hashtable fontFamilies = new Hashtable(); + + /// This is the default encoding to use. + private string defaultEncoding = BaseFont.WINANSI; + + /// This is the default value of the embedded variable. + private bool defaultEmbedding = BaseFont.NOT_EMBEDDED; + + /// Creates new FontFactory + public FontFactoryImp() { + trueTypeFonts.Add(FontFactory.COURIER.ToLower(CultureInfo.InvariantCulture), FontFactory.COURIER); + trueTypeFonts.Add(FontFactory.COURIER_BOLD.ToLower(CultureInfo.InvariantCulture), FontFactory.COURIER_BOLD); + trueTypeFonts.Add(FontFactory.COURIER_OBLIQUE.ToLower(CultureInfo.InvariantCulture), FontFactory.COURIER_OBLIQUE); + trueTypeFonts.Add(FontFactory.COURIER_BOLDOBLIQUE.ToLower(CultureInfo.InvariantCulture), FontFactory.COURIER_BOLDOBLIQUE); + trueTypeFonts.Add(FontFactory.HELVETICA.ToLower(CultureInfo.InvariantCulture), FontFactory.HELVETICA); + trueTypeFonts.Add(FontFactory.HELVETICA_BOLD.ToLower(CultureInfo.InvariantCulture), FontFactory.HELVETICA_BOLD); + trueTypeFonts.Add(FontFactory.HELVETICA_OBLIQUE.ToLower(CultureInfo.InvariantCulture), FontFactory.HELVETICA_OBLIQUE); + trueTypeFonts.Add(FontFactory.HELVETICA_BOLDOBLIQUE.ToLower(CultureInfo.InvariantCulture), FontFactory.HELVETICA_BOLDOBLIQUE); + trueTypeFonts.Add(FontFactory.SYMBOL.ToLower(CultureInfo.InvariantCulture), FontFactory.SYMBOL); + trueTypeFonts.Add(FontFactory.TIMES_ROMAN.ToLower(CultureInfo.InvariantCulture), FontFactory.TIMES_ROMAN); + trueTypeFonts.Add(FontFactory.TIMES_BOLD.ToLower(CultureInfo.InvariantCulture), FontFactory.TIMES_BOLD); + trueTypeFonts.Add(FontFactory.TIMES_ITALIC.ToLower(CultureInfo.InvariantCulture), FontFactory.TIMES_ITALIC); + trueTypeFonts.Add(FontFactory.TIMES_BOLDITALIC.ToLower(CultureInfo.InvariantCulture), FontFactory.TIMES_BOLDITALIC); + trueTypeFonts.Add(FontFactory.ZAPFDINGBATS.ToLower(CultureInfo.InvariantCulture), FontFactory.ZAPFDINGBATS); + + ArrayList tmp; + tmp = new ArrayList(); + tmp.Add(FontFactory.COURIER); + tmp.Add(FontFactory.COURIER_BOLD); + tmp.Add(FontFactory.COURIER_OBLIQUE); + tmp.Add(FontFactory.COURIER_BOLDOBLIQUE); + fontFamilies[FontFactory.COURIER.ToLower(CultureInfo.InvariantCulture)] = tmp; + tmp = new ArrayList(); + tmp.Add(FontFactory.HELVETICA); + tmp.Add(FontFactory.HELVETICA_BOLD); + tmp.Add(FontFactory.HELVETICA_OBLIQUE); + tmp.Add(FontFactory.HELVETICA_BOLDOBLIQUE); + fontFamilies[FontFactory.HELVETICA.ToLower(CultureInfo.InvariantCulture)] = tmp; + tmp = new ArrayList(); + tmp.Add(FontFactory.SYMBOL); + fontFamilies[FontFactory.SYMBOL.ToLower(CultureInfo.InvariantCulture)] = tmp; + tmp = new ArrayList(); + tmp.Add(FontFactory.TIMES_ROMAN); + tmp.Add(FontFactory.TIMES_BOLD); + tmp.Add(FontFactory.TIMES_ITALIC); + tmp.Add(FontFactory.TIMES_BOLDITALIC); + fontFamilies[FontFactory.TIMES.ToLower(CultureInfo.InvariantCulture)] = tmp; + fontFamilies[FontFactory.TIMES_ROMAN.ToLower(CultureInfo.InvariantCulture)] = tmp; + tmp = new ArrayList(); + tmp.Add(FontFactory.ZAPFDINGBATS); + fontFamilies[FontFactory.ZAPFDINGBATS.ToLower(CultureInfo.InvariantCulture)] = tmp; + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// the size of this font + /// the style of this font + /// the Color of this font + /// a Font object + public virtual Font GetFont(string fontname, string encoding, bool embedded, float size, int style, Color color) { + return GetFont(fontname, encoding, embedded, size, style, color, true); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// the size of this font + /// the style of this font + /// the Color of this font + /// true if the font comes from the cache or is added to the cache if new, false if the font is always created new + /// a Font object + public virtual Font GetFont(string fontname, string encoding, bool embedded, float size, int style, Color color, bool cached) { + if (fontname == null) return new Font(Font.UNDEFINED, size, style, color); + string lowercasefontname = fontname.ToLower(CultureInfo.InvariantCulture); + ArrayList tmp = (ArrayList) fontFamilies[lowercasefontname]; + if (tmp != null) { + // some bugs were fixed here by Daniel Marczisovszky + int fs = Font.NORMAL; + bool found = false; + int s = style == Font.UNDEFINED ? Font.NORMAL : style; + foreach (string f in tmp) { + string lcf = f.ToLower(CultureInfo.InvariantCulture); + fs = Font.NORMAL; + if (lcf.ToLower(CultureInfo.InvariantCulture).IndexOf("bold") != -1) fs |= Font.BOLD; + if (lcf.ToLower(CultureInfo.InvariantCulture).IndexOf("italic") != -1 || lcf.ToLower(CultureInfo.InvariantCulture).IndexOf("oblique") != -1) fs |= Font.ITALIC; + if ((s & Font.BOLDITALIC) == fs) { + fontname = f; + found = true; + break; + } + } + if (style != Font.UNDEFINED && found) { + style &= ~fs; + } + } + BaseFont basefont = null; + try { + try { + // the font is a type 1 font or CJK font + basefont = BaseFont.CreateFont(fontname, encoding, embedded, cached, null, null, true); + } + catch (DocumentException) { + } + if (basefont == null) { + // the font is a true type font or an unknown font + fontname = trueTypeFonts[fontname.ToLower(CultureInfo.InvariantCulture)]; + // the font is not registered as truetype font + if (fontname == null) return new Font(Font.UNDEFINED, size, style, color); + // the font is registered as truetype font + basefont = BaseFont.CreateFont(fontname, encoding, embedded, cached, null, null); + } + } + catch (DocumentException de) { + // this shouldn't happen + throw de; + } + catch (System.IO.IOException) { + // the font is registered as a true type font, but the path was wrong + return new Font(Font.UNDEFINED, size, style, color); + } + catch { + // null was entered as fontname and/or encoding + return new Font(Font.UNDEFINED, size, style, color); + } + return new Font(basefont, size, style, color); + } + + /// + /// Constructs a Font-object. + /// + /// the attributes of a Font object + /// a Font object + public virtual Font GetFont(Properties attributes) { + string fontname = null; + string encoding = defaultEncoding; + bool embedded = defaultEmbedding; + float size = Font.UNDEFINED; + int style = Font.NORMAL; + Color color = null; + string value = attributes[Markup.HTML_ATTR_STYLE]; + if (value != null && value.Length > 0) { + Properties styleAttributes = Markup.ParseAttributes(value); + if (styleAttributes.Count == 0) { + attributes.Add(Markup.HTML_ATTR_STYLE, value); + } + else { + fontname = styleAttributes[Markup.CSS_KEY_FONTFAMILY]; + if (fontname != null) { + string tmp; + while (fontname.IndexOf(',') != -1) { + tmp = fontname.Substring(0, fontname.IndexOf(',')); + if (IsRegistered(tmp)) { + fontname = tmp; + } + else { + fontname = fontname.Substring(fontname.IndexOf(',') + 1); + } + } + } + if ((value = styleAttributes[Markup.CSS_KEY_FONTSIZE]) != null) { + size = Markup.ParseLength(value); + } + if ((value = styleAttributes[Markup.CSS_KEY_FONTWEIGHT]) != null) { + style |= Font.GetStyleValue(value); + } + if ((value = styleAttributes[Markup.CSS_KEY_FONTSTYLE]) != null) { + style |= Font.GetStyleValue(value); + } + if ((value = styleAttributes[Markup.CSS_KEY_COLOR]) != null) { + color = Markup.DecodeColor(value); + } + attributes.AddAll(styleAttributes); + } + } + if ((value = attributes[ElementTags.ENCODING]) != null) { + encoding = value; + } + if ("true".Equals(attributes[ElementTags.EMBEDDED])) { + embedded = true; + } + if ((value = attributes[ElementTags.FONT]) != null) { + fontname = value; + } + if ((value = attributes[ElementTags.SIZE]) != null) { + size = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + if ((value = attributes[Markup.HTML_ATTR_STYLE]) != null) { + style |= Font.GetStyleValue(value); + } + if ((value = attributes[ElementTags.STYLE]) != null) { + style |= Font.GetStyleValue(value); + } + string r = attributes[ElementTags.RED]; + string g = attributes[ElementTags.GREEN]; + string b = attributes[ElementTags.BLUE]; + if (r != null || g != null || b != null) { + int red = 0; + int green = 0; + int blue = 0; + if (r != null) red = int.Parse(r); + if (g != null) green = int.Parse(g); + if (b != null) blue = int.Parse(b); + color = new Color(red, green, blue); + } + else if ((value = attributes[ElementTags.COLOR]) != null) { + color = Markup.DecodeColor(value); + } + if (fontname == null) { + return GetFont(null, encoding, embedded, size, style, color); + } + return GetFont(fontname, encoding, embedded, size, style, color); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// the size of this font + /// the style of this font + /// a Font object + public Font GetFont(string fontname, string encoding, bool embedded, float size, int style) { + return GetFont(fontname, encoding, embedded, size, style, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// the size of this font + /// + public virtual Font GetFont(string fontname, string encoding, bool embedded, float size) { + return GetFont(fontname, encoding, embedded, size, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// true if the font is to be embedded in the PDF + /// a Font object + public virtual Font GetFont(string fontname, string encoding, bool embedded) { + return GetFont(fontname, encoding, embedded, Font.UNDEFINED, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// the size of this font + /// the style of this font + /// the Color of this font + /// a Font object + public virtual Font GetFont(string fontname, string encoding, float size, int style, Color color) { + return GetFont(fontname, encoding, defaultEmbedding, size, style, color); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// the size of this font + /// the style of this font + /// a Font object + public virtual Font GetFont(string fontname, string encoding, float size, int style) { + return GetFont(fontname, encoding, defaultEmbedding, size, style, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// the size of this font + /// a Font object + public virtual Font GetFont(string fontname, string encoding, float size) { + return GetFont(fontname, encoding, defaultEmbedding, size, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the encoding of the font + /// a Font object + public virtual Font GetFont(string fontname, string encoding) { + return GetFont(fontname, encoding, defaultEmbedding, Font.UNDEFINED, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the size of this font + /// the style of this font + /// the Color of this font + /// a Font object + public virtual Font GetFont(string fontname, float size, int style, Color color) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, size, style, color); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the size of this font + /// the Color of this font + /// a Font object + public virtual Font GetFont(string fontname, float size, Color color) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, size, Font.UNDEFINED, color); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the size of this font + /// the style of this font + /// a Font object + public virtual Font GetFont(string fontname, float size, int style) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, size, style, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// the size of this font + /// a Font object + public virtual Font GetFont(string fontname, float size) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, size, Font.UNDEFINED, null); + } + + /// + /// Constructs a Font-object. + /// + /// the name of the font + /// a Font object + public virtual Font GetFont(string fontname) { + return GetFont(fontname, defaultEncoding, defaultEmbedding, Font.UNDEFINED, Font.UNDEFINED, null); + } + + public virtual void Register(Properties attributes) { + string path; + string alias = null; + + path = attributes.Remove("path"); + alias = attributes.Remove("alias"); + + Register(path, alias); + } + + /** + * Register a font by giving explicitly the font family and name. + * @param familyName the font family + * @param fullName the font name + * @param path the font path + */ + public void RegisterFamily(String familyName, String fullName, String path) { + if (path != null) + trueTypeFonts.Add(fullName, path); + ArrayList tmp = (ArrayList) fontFamilies[familyName]; + if (tmp == null) { + tmp = new ArrayList(); + tmp.Add(fullName); + fontFamilies[familyName] = tmp; + } + else { + int fullNameLength = fullName.Length; + bool inserted = false; + for (int j = 0; j < tmp.Count; ++j) { + if (((String)tmp[j]).Length >= fullNameLength) { + tmp.Insert(j, fullName); + inserted = true; + break; + } + } + if (!inserted) + tmp.Add(fullName); + } + } + + /// + /// Register a ttf- or a ttc-file. + /// + /// the path to a ttf- or ttc-file + public virtual void Register(string path) { + Register(path, null); + } + + /// + /// Register a ttf- or a ttc-file and use an alias for the font contained in the ttf-file. + /// + /// the path to a ttf- or ttc-file + /// the alias you want to use for the font + public virtual void Register(string path, string alias) { + try { + if (path.ToLower(CultureInfo.InvariantCulture).EndsWith(".ttf") || path.ToLower(CultureInfo.InvariantCulture).EndsWith(".otf") || path.ToLower(CultureInfo.InvariantCulture).IndexOf(".ttc,") > 0) { + Object[] allNames = BaseFont.GetAllFontNames(path, BaseFont.WINANSI, null); + trueTypeFonts.Add(((string)allNames[0]).ToLower(CultureInfo.InvariantCulture), path); + if (alias != null) { + trueTypeFonts.Add(alias.ToLower(CultureInfo.InvariantCulture), path); + } + // register all the font names with all the locales + string[][] names = (string[][])allNames[2]; //full name + for (int i = 0; i < names.Length; i++) { + trueTypeFonts.Add(names[i][3].ToLower(CultureInfo.InvariantCulture), path); + } + string fullName = null; + string familyName = null; + names = (string[][])allNames[1]; //family name + for (int k = 0; k < TTFamilyOrder.Length; k += 3) { + for (int i = 0; i < names.Length; i++) { + if (TTFamilyOrder[k].Equals(names[i][0]) && TTFamilyOrder[k + 1].Equals(names[i][1]) && TTFamilyOrder[k + 2].Equals(names[i][2])) { + familyName = names[i][3].ToLower(CultureInfo.InvariantCulture); + k = TTFamilyOrder.Length; + break; + } + } + } + if (familyName != null) { + String lastName = ""; + names = (string[][])allNames[2]; //full name + for (int i = 0; i < names.Length; i++) { + for (int k = 0; k < TTFamilyOrder.Length; k += 3) { + if (TTFamilyOrder[k].Equals(names[i][0]) && TTFamilyOrder[k + 1].Equals(names[i][1]) && TTFamilyOrder[k + 2].Equals(names[i][2])) { + fullName = names[i][3]; + if (fullName.Equals(lastName)) + continue; + lastName = fullName; + RegisterFamily(familyName, fullName, null); + break; + } + } + } + } + } + else if (path.ToLower(CultureInfo.InvariantCulture).EndsWith(".ttc")) { + string[] names = BaseFont.EnumerateTTCNames(path); + for (int i = 0; i < names.Length; i++) { + Register(path + "," + i); + } + } + else if (path.ToLower(CultureInfo.InvariantCulture).EndsWith(".afm") || path.ToLower(CultureInfo.InvariantCulture).EndsWith(".pfm")) { + BaseFont bf = BaseFont.CreateFont(path, BaseFont.CP1252, false); + String fullName = (bf.FullFontName[0][3]).ToLower(CultureInfo.InvariantCulture); + String familyName = (bf.FamilyFontName[0][3]).ToLower(CultureInfo.InvariantCulture); + String psName = bf.PostscriptFontName.ToLower(CultureInfo.InvariantCulture); + RegisterFamily(familyName, fullName, null); + trueTypeFonts.Add(psName, path); + trueTypeFonts.Add(fullName, path); + } + } + catch (DocumentException de) { + // this shouldn't happen + throw de; + } + catch (System.IO.IOException ioe) { + throw ioe; + } + } + + /** Register all the fonts in a directory. + * @param dir the directory + * @return the number of fonts registered + */ + public virtual int RegisterDirectory(String dir) { + return RegisterDirectory(dir, false); + } + + /** + * Register all the fonts in a directory and possibly its subdirectories. + * @param dir the directory + * @param scanSubdirectories recursively scan subdirectories if true + * @return the number of fonts registered + * @since 2.1.2 + */ + public int RegisterDirectory(String dir, bool scanSubdirectories) { + int count = 0; + try { + if (!Directory.Exists(dir)) + return 0; + string[] files = Directory.GetFiles(dir); + if (files == null) + return 0; + for (int k = 0; k < files.Length; ++k) { + try { + if (Directory.Exists(files[k])) { + if (scanSubdirectories) { + count += RegisterDirectory(Path.GetFullPath(files[k]), true); + } + } else { + String name = Path.GetFullPath(files[k]); + String suffix = name.Length < 4 ? null : name.Substring(name.Length - 4).ToLower(CultureInfo.InvariantCulture); + if (".afm".Equals(suffix) || ".pfm".Equals(suffix)) { + /* Only register Type 1 fonts with matching .pfb files */ + string pfb = name.Substring(0, name.Length - 4) + ".pfb"; + if (File.Exists(pfb)) { + Register(name, null); + ++count; + } + } else if (".ttf".Equals(suffix) || ".otf".Equals(suffix) || ".ttc".Equals(suffix)) { + Register(name, null); + ++count; + } + } + } + catch { + //empty on purpose + } + } + } + catch { + //empty on purpose + } + return count; + } + + /** Register fonts in some probable directories. It usually works in Windows, + * Linux and Solaris. + * @return the number of fonts registered + */ + public virtual int RegisterDirectories() { + int count = 0; + count += RegisterDirectory("c:/windows/fonts"); + count += RegisterDirectory("c:/winnt/fonts"); + count += RegisterDirectory("d:/windows/fonts"); + count += RegisterDirectory("d:/winnt/fonts"); + count += RegisterDirectory("/usr/share/X11/fonts", true); + count += RegisterDirectory("/usr/X/lib/X11/fonts", true); + count += RegisterDirectory("/usr/openwin/lib/X11/fonts", true); + count += RegisterDirectory("/usr/share/fonts", true); + count += RegisterDirectory("/usr/X11R6/lib/X11/fonts", true); + count += RegisterDirectory("/Library/Fonts"); + count += RegisterDirectory("/System/Library/Fonts"); + return count; + } + + /// + /// Gets a set of registered fontnames. + /// + /// a set of registered fontnames + public virtual ICollection RegisteredFonts { + get { + return trueTypeFonts.Keys; + } + } + + /// + /// Gets a set of registered font families. + /// + /// a set of registered font families + public virtual ICollection RegisteredFamilies { + get { + return fontFamilies.Keys; + } + } + + /// + /// Checks if a certain font is registered. + /// + /// the name of the font that has to be checked + /// true if the font is found + public virtual bool IsRegistered(string fontname) { + return trueTypeFonts.ContainsKey(fontname.ToLower(CultureInfo.InvariantCulture)); + } + + public virtual string DefaultEncoding { + get { + return defaultEncoding; + } + set { + defaultEncoding = value; + } + } + + public virtual bool DefaultEmbedding { + get { + return defaultEmbedding; + } + set { + defaultEmbedding = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/GreekList.cs b/iTechSharp/iTextSharp/text/GreekList.cs new file mode 100644 index 0000000..dcb6965 --- /dev/null +++ b/iTechSharp/iTextSharp/text/GreekList.cs @@ -0,0 +1,124 @@ +using System; +using iTextSharp.text.factories; +/* + * Copyright 2003 by Michael Niedermair. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text +{ + /** + * + * A special-version of LIST whitch use greek-letters. + * + * @see com.lowagie.text.List + */ + public class GreekList : List { + /** + * Initialization + * + * @param symbolIndent indent + */ + public GreekList() : base(true) { + SetGreekFont(); + } + + /** + * Initialisierung + * + * @param symbolIndent indent + */ + public GreekList(int symbolIndent) : base(true, symbolIndent) { + SetGreekFont(); + } + + /** + * Initialisierung + * @param greeklower greek-char in lowercase + * @param symbolIndent indent + */ + public GreekList(bool greeklower, int symbolIndent) : base(true, symbolIndent) { + lowercase = greeklower; + SetGreekFont(); + } + + /** + * change the font to SYMBOL + */ + protected void SetGreekFont() { + float fontsize = symbol.Font.Size; + symbol.Font = FontFactory.GetFont(FontFactory.SYMBOL, fontsize, Font.NORMAL); + } + + /** + * Adds an Object to the List. + * + * @param o the object to add. + * @return true if adding the object succeeded + */ + public override bool Add(Object o) { + if (o is ListItem) { + ListItem item = (ListItem) o; + Chunk chunk = new Chunk(preSymbol, symbol.Font); + chunk.Append(GreekAlphabetFactory.GetString(first + list.Count, lowercase)); + chunk.Append(postSymbol); + item.ListSymbol = chunk; + item.SetIndentationLeft(symbolIndent, autoindent); + item.IndentationRight = 0; + list.Add(item); + return true; + } else if (o is List) { + List nested = (List) o; + nested.IndentationLeft = nested.IndentationLeft + symbolIndent; + first--; + list.Add(nested); + return true; + } else if (o is string) { + return this.Add(new ListItem((string)o)); + } + return false; + } + } +} diff --git a/iTechSharp/iTextSharp/text/Header.cs b/iTechSharp/iTextSharp/text/Header.cs new file mode 100644 index 0000000..e8a37eb --- /dev/null +++ b/iTechSharp/iTextSharp/text/Header.cs @@ -0,0 +1,94 @@ +using System; +using System.Text; + +/* + * $Id: Header.cs,v 1.4 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// This is an Element that contains + /// some userdefined meta information about the document. + /// + /// + /// + /// Header header = new Header("inspired by", "William Shakespeare"); + /// + /// + public class Header : Meta { + + // membervariables + + /// This is the content of this chunk of text. + private StringBuilder name; + + // constructors + + /// + /// Constructs a Header. + /// + /// the name of the meta-information + /// the content + public Header(string name, string content) : base(Element.HEADER, content) { + this.name = new StringBuilder(name); + } + + // methods to retrieve information + + /// + /// Returns the name of the meta information. + /// + /// a string + public override string Name { + get { + return name.ToString(); + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/HeaderFooter.cs b/iTechSharp/iTextSharp/text/HeaderFooter.cs new file mode 100644 index 0000000..8dfecd0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/HeaderFooter.cs @@ -0,0 +1,234 @@ +using System; +using System.util; +using System.Collections; + +/* + * $Id: HeaderFooter.cs,v 1.6 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A HeaderFooter-object is a Rectangle with text + /// that can be put above and/or below every page. + /// + /// + /// + /// HeaderFooter header = new HeaderFooter(new Phrase("This is a header."), false); + /// HeaderFooter footer = new HeaderFooter(new Phrase("This is page "), new Phrase(".")); + /// document.SetHeader(header); + /// document.SetFooter(footer); + /// + /// + public class HeaderFooter : Rectangle { + + // membervariables + + /// Does the page contain a pagenumber? + private bool numbered; + + /// This is the Phrase that comes before the pagenumber. + private Phrase before = null; + + /// This is number of the page. + private int pageN; + + /// This is the Phrase that comes after the pagenumber. + private Phrase after = null; + + /// This is alignment of the header/footer. + private int alignment; + + // constructors + + /// + /// Constructs a HeaderFooter-object. + /// + /// the Phrase before the pagenumber + /// the Phrase after the pagenumber + public HeaderFooter(Phrase before, Phrase after) : base(0, 0, 0, 0) { + this.Border = TOP_BORDER + BOTTOM_BORDER; + this.BorderWidth = 1; + + numbered = true; + this.before = before; + this.after = after; + } + + /// + /// Constructs a Header-object with a pagenumber at the end. + /// + /// the Phrase before the pagenumber + /// true if the page has to be numbered + public HeaderFooter(Phrase before, bool numbered) : base(0, 0, 0, 0) { + this.Border = TOP_BORDER + BOTTOM_BORDER; + this.BorderWidth = 1; + + this.numbered = numbered; + this.before = before; + } + + public HeaderFooter(Properties attributes) : base(0, 0, 0, 0) { + string value; + + if ((value = attributes.Remove(ElementTags.NUMBERED)) != null) { + this.numbered = bool.Parse(value); + } + if ((value = attributes.Remove(ElementTags.ALIGN)) != null) { + this.SetAlignment(value); + } + if ((value = attributes.Remove("border")) != null) { + this.Border = int.Parse(value); + } else { + this.Border = TOP_BORDER + BOTTOM_BORDER; + } + } + + // methods + + /// + /// Checks if the HeaderFooter contains a page number. + /// + /// true if the page has to be numbered + public bool IsNumbered() { + return numbered; + } + + /// + /// Get/set the part that comes before the pageNumber. + /// + /// a Phrase + public Phrase Before { + get { + return before; + } + + set { + this.before = value; + } + } + + /// + /// Get/set the part that comes after the pageNumber. + /// + /// a Phrase + public Phrase After { + get { + return after; + } + + set { + this.after = value; + } + } + + /// + /// Sets the page number. + /// + /// the new page number + public int PageNumber { + set { + this.pageN = value; + } + } + + /// + /// Sets the Element. + /// + /// the new alignment + public int Alignment{ + set { + this.alignment = value; + } + get { + return this.alignment; + } + } + + /// + /// Sets the alignment of this HeaderFooter. + /// + /// the new alignment as a string + public void SetAlignment(string alignment) { + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_CENTER)) { + this.alignment = Element.ALIGN_CENTER; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_RIGHT)) { + this.alignment = Element.ALIGN_RIGHT; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_JUSTIFIED)) { + this.alignment = Element.ALIGN_JUSTIFIED; + return; + } + this.alignment = Element.ALIGN_LEFT; + } + + // methods to retrieve the membervariables + + /// + /// Gets the Paragraph that can be used as header or footer. + /// + /// a Paragraph + public Paragraph Paragraph { + get { + Paragraph paragraph = new Paragraph(before.Leading); + paragraph.Add(before); + if (numbered) { + paragraph.AddSpecial(new Chunk(pageN.ToString(), before.Font)); + } + if (after != null) { + paragraph.AddSpecial(after); + } + paragraph.Alignment = alignment; + return paragraph; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/IDocListener.cs b/iTechSharp/iTextSharp/text/IDocListener.cs new file mode 100644 index 0000000..9cdad26 --- /dev/null +++ b/iTechSharp/iTextSharp/text/IDocListener.cs @@ -0,0 +1,149 @@ +using System; + +/* + * $Id: IDocListener.cs,v 1.5 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright (c) 1999, 2000, 2001, 2002 Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A class that implements DocListener will perform some + /// actions when some actions are performed on a Document. + /// + /// + /// + /// + public interface IDocListener : IElementListener { + + // methods + + /// + /// Signals that the Document has been opened and that + /// Elements can be added. + /// + void Open(); + + /// + /// Signals that the Document was closed and that no other + /// Elements will be added. + /// + /// + /// The output stream of every writer implementing IDocListener will be closed. + /// + void Close(); + + /// + /// Signals that an new page has to be started. + /// + /// true if the page was added, false if not. + bool NewPage(); + + /// + /// Sets the pagesize. + /// + /// the new pagesize + /// a boolean + bool SetPageSize(Rectangle pageSize); + + /// + /// Sets the margins. + /// + /// the margin on the left + /// the margin on the right + /// the margin on the top + /// the margin on the bottom + /// + bool SetMargins(float marginLeft, float marginRight, float marginTop, float marginBottom); + + /** + * Parameter that allows you to do margin mirroring (odd/even pages) + * @param marginMirroring + * @return true if succesfull + */ + bool SetMarginMirroring(bool marginMirroring); + + /// + /// Sets the page number. + /// + /// the new page number + int PageCount { + set; + } + + /// + /// Sets the page number to 0. + /// + void ResetPageCount(); + + /// + /// Changes the header of this document. + /// + /// a Header + HeaderFooter Header { + set; + } + + /// + /// Resets the header of this document. + /// + void ResetHeader(); + + /// + /// Changes the footer of this document. + /// + /// a Footer + HeaderFooter Footer { + set; + } + + /// + /// Resets the footer of this document. + /// + void ResetFooter(); + } +} diff --git a/iTechSharp/iTextSharp/text/IElement.cs b/iTechSharp/iTextSharp/text/IElement.cs new file mode 100644 index 0000000..36f86cf --- /dev/null +++ b/iTechSharp/iTextSharp/text/IElement.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections; + +/* + * $Id: IElement.cs,v 1.4 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text { + /// + /// Interface for a text element. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public interface IElement { + + // methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// IElementListener. + /// + /// an IElementListener + /// true if the element was processed successfully + bool Process(IElementListener listener); + + /// + /// Gets the type of the text element. + /// + /// a type + int Type { + get; + } + + /** + * Checks if this element is a content object. + * If not, it's a metadata object. + * @since iText 2.0.8 + * @return true if this is a 'content' element; false if this is a 'medadata' element + */ + + bool IsContent(); + + /** + * Checks if this element is nestable. + * @since iText 2.0.8 + * @return true if this element can be nested inside other elements. + */ + + bool IsNestable(); + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + ArrayList Chunks { + get; + } + + /// + /// Gets the content of the text element. + /// + /// the content of the text element + string ToString(); + } +} diff --git a/iTechSharp/iTextSharp/text/IElementListener.cs b/iTechSharp/iTextSharp/text/IElementListener.cs new file mode 100644 index 0000000..bbba509 --- /dev/null +++ b/iTechSharp/iTextSharp/text/IElementListener.cs @@ -0,0 +1,16 @@ +using System; + +namespace iTextSharp.text { + /// + /// A class that implements ElementListener will perform some + /// actions when an Element is added. + /// + public interface IElementListener { + /// + /// Signals that an Element was added to the Document. + /// + /// Element added + /// true if the element was added, false if not. + bool Add(IElement element); + } +} diff --git a/iTechSharp/iTextSharp/text/ILargeElement.cs b/iTechSharp/iTextSharp/text/ILargeElement.cs new file mode 100644 index 0000000..03e300e --- /dev/null +++ b/iTechSharp/iTextSharp/text/ILargeElement.cs @@ -0,0 +1,84 @@ +using System; +/* + * $Id: ILargeElement.cs,v 1.2 2008/05/13 11:25:10 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + + /** + * Interface implemented by Element objects that can potentially consume + * a lot of memory. Objects implementing the LargeElement interface can + * be added to a Document more than once. If you have invoked setCompleted(false), + * they will be added partially and the content that was added will be + * removed until you've invoked setCompleted(true); + * @since iText 2.0.8 + */ + + public interface ILargeElement : IElement { + + /** + * If you invoke setCompleted(false), you indicate that the content + * of the object isn't complete yet; it can be added to the document + * partially, but more will follow. If you invoke setCompleted(true), + * you indicate that you won't add any more data to the object. + * @since iText 2.0.8 + * @param complete false if you'll be adding more data after + * adding the object to the document. + */ + bool ElementComplete { + get; + set; + } + + /** + * Flushes the content that has been added. + */ + void FlushContent(); + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/IRtfElementInterface.cs b/iTechSharp/iTextSharp/text/IRtfElementInterface.cs new file mode 100644 index 0000000..0c2d792 --- /dev/null +++ b/iTechSharp/iTextSharp/text/IRtfElementInterface.cs @@ -0,0 +1,60 @@ +/* + * $Id: IRtfElementInterface.cs,v 1.2 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 2008 by Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + + /** + * The RTF jar depends on the iText jar, but the iText jar may not + * depend on the RTF jar. This interface offers a temporary solution + * until we find a more elegant way to solve this. + */ + public interface IRtfElementInterface { + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/ISplitCharacter.cs b/iTechSharp/iTextSharp/text/ISplitCharacter.cs new file mode 100644 index 0000000..191b1c1 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ISplitCharacter.cs @@ -0,0 +1,94 @@ +using System; +using iTextSharp.text.pdf; +/* + * $Id: ISplitCharacter.cs,v 1.3 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text { + /// + /// Interface for customizing the split character. + /// + public interface ISplitCharacter { + /** + * Returns true if the character can split a line. The splitting implementation + * is free to look ahead or look behind characters to make a decision. + *

    + * The default implementation is: + *

    + *

    +        * public boolean IsSplitCharacter(int start, int current, int end, char[] cc, PdfChunk[] ck) {
    +        *    char c;
    +        *    if (ck == null)
    +        *        c = cc[current];
    +        *    else
    +        *        c = ck[Math.Min(current, ck.length - 1)].GetUnicodeEquivalent(cc[current]);
    +        *    if (c <= ' ' || c == '-') {
    +        *        return true;
    +        *    }
    +        *    if (c < 0x2e80)
    +        *        return false;
    +        *    return ((c >= 0x2e80 && c < 0xd7a0)
    +        *    || (c >= 0xf900 && c < 0xfb00)
    +        *    || (c >= 0xfe30 && c < 0xfe50)
    +        *    || (c >= 0xff61 && c < 0xffa0));
    +        * }
    +        * 
    + * @param start the lower limit of cc inclusive + * @param current the pointer to the character in cc + * @param end the upper limit of cc exclusive + * @param cc an array of characters at least end sized + * @param ck an array of PdfChunk. The main use is to be able to call + * {@link PdfChunk#getUnicodeEquivalent(char)}. It may be null + * or shorter than end. If null no convertion takes place. + * If shorter than end the last element is used + * @return true if the Character(s) can split a line + */ + + bool IsSplitCharacter(int start, int current, int end, char[] cc, PdfChunk[] ck); + } +} diff --git a/iTechSharp/iTextSharp/text/ITextElementArray.cs b/iTechSharp/iTextSharp/text/ITextElementArray.cs new file mode 100644 index 0000000..8df3bf4 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ITextElementArray.cs @@ -0,0 +1,22 @@ +using System; + +namespace iTextSharp.text { + /// + /// Interface for a text element to which other objects can be added. + /// + /// + /// + /// + /// + /// + /// + /// + public interface ITextElementArray : IElement { + /// + /// Adds an object to the TextElementArray. + /// + /// an object that has to be added + /// true if the addition succeeded; false otherwise + bool Add(Object o); + } +} diff --git a/iTechSharp/iTextSharp/text/Image.cs b/iTechSharp/iTextSharp/text/Image.cs new file mode 100644 index 0000000..a73249a --- /dev/null +++ b/iTechSharp/iTextSharp/text/Image.cs @@ -0,0 +1,1483 @@ +using System; +using System.IO; +using System.Net; +using System.Text; +using System.Runtime.CompilerServices; +using System.Collections; +using System.util; +using System.Reflection; + +using iTextSharp.text.pdf; +using iTextSharp.text.factories; +using iTextSharp.text.pdf.codec; + +/* + * $Id: Image.cs,v 1.28 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// An Image is the representation of a graphic element (JPEG, PNG or GIF) + /// that has to be inserted into the document + /// + /// + /// + public abstract class Image : Rectangle { + + // static membervariables (concerning the presence of borders) + + /// this is a kind of image Element. + public const int DEFAULT = 0; + + /// this is a kind of image Element. + public const int RIGHT_ALIGN = 2; + + /// this is a kind of image Element. + public const int LEFT_ALIGN = 0; + + /// this is a kind of image Element. + public const int MIDDLE_ALIGN = 1; + + /// this is a kind of image Element. + public const int TEXTWRAP = 4; + + /// this is a kind of image Element. + public const int UNDERLYING = 8; + + /// This represents a coordinate in the transformation matrix. + public const int AX = 0; + + /// This represents a coordinate in the transformation matrix. + public const int AY = 1; + + /// This represents a coordinate in the transformation matrix. + public const int BX = 2; + + /// This represents a coordinate in the transformation matrix. + public const int BY = 3; + + /// This represents a coordinate in the transformation matrix. + public const int CX = 4; + + /// This represents a coordinate in the transformation matrix. + public const int CY = 5; + + /// This represents a coordinate in the transformation matrix. + public const int DX = 6; + + /// This represents a coordinate in the transformation matrix. + public const int DY = 7; + + /** type of image */ + public const int ORIGINAL_NONE = 0; + + /** type of image */ + public const int ORIGINAL_JPEG = 1; + + /** type of image */ + public const int ORIGINAL_PNG = 2; + + /** type of image */ + public const int ORIGINAL_GIF = 3; + + /** type of image */ + public const int ORIGINAL_BMP = 4; + + /** type of image */ + public const int ORIGINAL_TIFF = 5; + + /** type of image */ + public const int ORIGINAL_WMF = 6; + + /** type of image */ + public const int ORIGINAL_JPEG2000 = 8; + + /** Image color inversion */ + protected bool invert = false; + + /// The imagetype. + protected int type; + + /// The URL of the image. + protected Uri url; + + /// The raw data of the image. + protected byte[] rawData; + + /// The template to be treated as an image. + protected PdfTemplate[] template = new PdfTemplate[1]; + + /// The alignment of the Image. + protected int alignment; + + /// Text that can be shown instead of the image. + protected string alt; + + /// This is the absolute X-position of the image. + protected float absoluteX = float.NaN; + + /// This is the absolute Y-position of the image. + protected float absoluteY = float.NaN; + + /// This is the width of the image without rotation. + protected float plainWidth; + + /// This is the width of the image without rotation. + protected float plainHeight; + + /// This is the scaled width of the image taking rotation into account. + protected float scaledWidth; + + /// This is the original height of the image taking rotation into account. + protected float scaledHeight; + + /// This is the rotation of the image. + protected float rotationRadians; + + /// this is the colorspace of a jpeg-image. + protected int colorspace = -1; + + /// this is the bits per component of the raw image. It also flags a CCITT image. + protected int bpc = 1; + + /// this is the transparency information of the raw image + protected int[] transparency; + + // for the moment these variables are only used for Images in class Table + // code contributed by Pelikan Stephan + /** the indentation to the left. */ + protected float indentationLeft = 0; + + /** the indentation to the right. */ + protected float indentationRight = 0; + // serial stamping + + protected long mySerialId = GetSerialId(); + + static object serialId = 0L; + + /// Holds value of property dpiX. + protected int dpiX = 0; + + /// Holds value of property dpiY. + protected int dpiY = 0; + + protected bool mask = false; + + protected Image imageMask; + + /// Holds value of property interpolation. + protected bool interpolation; + + /// if the annotation is not null the image will be clickable. + protected Annotation annotation = null; + + /// ICC Profile attached + protected ICC_Profile profile = null; + + /** Holds value of property deflated. */ + protected bool deflated = false; + + private PdfDictionary additional = null; + + /** Holds value of property smask. */ + private bool smask; + + /** Holds value of property XYRatio. */ + private float xyRatio = 0; + + /** Holds value of property originalType. */ + protected int originalType = ORIGINAL_NONE; + + /** Holds value of property originalData. */ + protected byte[] originalData; + + /** The spacing before the image. */ + protected float spacingBefore; + + /** The spacing after the image. */ + protected float spacingAfter; + + /** + * Holds value of property widthPercentage. + */ + private float widthPercentage = 100; + + protected IPdfOCG layer; + + /** + * Holds value of property initialRotation. + */ + private float initialRotation; + + private PdfIndirectReference directReference; + + // constructors + + /// + /// Constructs an Image-object, using an url. + /// + /// the URL where the image can be found. + public Image(Uri url) : base(0, 0) { + this.url = url; + this.alignment = DEFAULT; + rotationRadians = 0; + } + + /// + /// Constructs an Image object duplicate. + /// + /// another Image object. + public Image(Image image) : base(image) { + this.type = image.type; + this.url = image.url; + this.alignment = image.alignment; + this.alt = image.alt; + this.absoluteX = image.absoluteX; + this.absoluteY = image.absoluteY; + this.plainWidth = image.plainWidth; + this.plainHeight = image.plainHeight; + this.scaledWidth = image.scaledWidth; + this.scaledHeight = image.scaledHeight; + this.rotationRadians = image.rotationRadians; + this.indentationLeft = image.indentationLeft; + this.indentationRight = image.indentationRight; + this.colorspace = image.colorspace; + this.rawData = image.rawData; + this.template = image.template; + this.bpc = image.bpc; + this.transparency = image.transparency; + this.mySerialId = image.mySerialId; + this.invert = image.invert; + this.dpiX = image.dpiX; + this.dpiY = image.dpiY; + this.mask = image.mask; + this.imageMask = image.imageMask; + this.interpolation = image.interpolation; + this.annotation = image.annotation; + this.profile = image.profile; + this.deflated = image.deflated; + this.additional = image.additional; + this.smask = image.smask; + this.XYRatio = image.XYRatio; + this.originalData = image.originalData; + this.originalType = image.originalType; + this.spacingAfter = image.spacingAfter; + this.spacingBefore = image.spacingBefore; + this.widthPercentage = image.widthPercentage; + this.layer = image.layer; + this.initialRotation = image.initialRotation; + this.directReference = image.directReference; + } + + /// + /// Gets an instance of an Image. + /// + /// an Image + /// an object of type Gif, Jpeg or Png + public static Image GetInstance(Image image) { + if (image == null) + return null; + return (Image)image.GetType().GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[] {typeof(Image)}, null).Invoke(new object[] {image}); + } + + /// + /// Gets an instance of an Image. + /// + /// an URL + /// an object of type Gif, Jpeg or Png + public static Image GetInstance(Uri url) { + Stream istr = null; + try { + WebRequest w = WebRequest.Create(url); + istr = w.GetResponse().GetResponseStream(); + int c1 = istr.ReadByte(); + int c2 = istr.ReadByte(); + int c3 = istr.ReadByte(); + int c4 = istr.ReadByte(); + istr.Close(); + + istr = null; + if (c1 == 'G' && c2 == 'I' && c3 == 'F') { + GifImage gif = new GifImage(url); + Image img = gif.GetImage(1); + return img; + } + if (c1 == 0xFF && c2 == 0xD8) { + return new Jpeg(url); + } + if (c1 == 0x00 && c2 == 0x00 && c3 == 0x00 && c4 == 0x0c) { + return new Jpeg2000(url); + } + if (c1 == 0xff && c2 == 0x4f && c3 == 0xff && c4 == 0x51) { + return new Jpeg2000(url); + } + if (c1 == PngImage.PNGID[0] && c2 == PngImage.PNGID[1] + && c3 == PngImage.PNGID[2] && c4 == PngImage.PNGID[3]) { + Image img = PngImage.GetImage(url); + return img; + } + if (c1 == 0xD7 && c2 == 0xCD) { + Image img = new ImgWMF(url); + return img; + } + if (c1 == 'B' && c2 == 'M') { + Image img = BmpImage.GetImage(url); + return img; + } + if ((c1 == 'M' && c2 == 'M' && c3 == 0 && c4 == 42) + || (c1 == 'I' && c2 == 'I' && c3 == 42 && c4 == 0)) { + RandomAccessFileOrArray ra = null; + try { + if (url.IsFile) { + String file = url.LocalPath; + ra = new RandomAccessFileOrArray(file); + } else + ra = new RandomAccessFileOrArray(url); + Image img = TiffImage.GetTiffImage(ra, 1); + img.url = url; + return img; + } finally { + if (ra != null) + ra.Close(); + } + + } + throw new IOException(url.ToString() + + " is not a recognized imageformat."); + } finally { + if (istr != null) { + istr.Close(); + } + } + } + + public static Image GetInstance(Stream s) { + byte[] a = RandomAccessFileOrArray.InputStreamToArray(s); + s.Close(); + return GetInstance(a); + } + + /// + /// Gets an instance of an Image. + /// + /// a byte array + /// an object of type Gif, Jpeg or Png + public static Image GetInstance(byte[] imgb) { + int c1 = imgb[0]; + int c2 = imgb[1]; + int c3 = imgb[2]; + int c4 = imgb[3]; + + if (c1 == 'G' && c2 == 'I' && c3 == 'F') { + GifImage gif = new GifImage(imgb); + return gif.GetImage(1); + } + if (c1 == 0xFF && c2 == 0xD8) { + return new Jpeg(imgb); + } + if (c1 == 0x00 && c2 == 0x00 && c3 == 0x00 && c4 == 0x0c) { + return new Jpeg2000(imgb); + } + if (c1 == 0xff && c2 == 0x4f && c3 == 0xff && c4 == 0x51) { + return new Jpeg2000(imgb); + } + if (c1 == PngImage.PNGID[0] && c2 == PngImage.PNGID[1] + && c3 == PngImage.PNGID[2] && c4 == PngImage.PNGID[3]) { + return PngImage.GetImage(imgb); + } + if (c1 == 0xD7 && c2 == 0xCD) { + return new ImgWMF(imgb); + } + if (c1 == 'B' && c2 == 'M') { + return BmpImage.GetImage(imgb); + } + if ((c1 == 'M' && c2 == 'M' && c3 == 0 && c4 == 42) + || (c1 == 'I' && c2 == 'I' && c3 == 42 && c4 == 0)) { + RandomAccessFileOrArray ra = null; + try { + ra = new RandomAccessFileOrArray(imgb); + Image img = TiffImage.GetTiffImage(ra, 1); + if (img.OriginalData == null) + img.OriginalData = imgb; + + return img; + } finally { + if (ra != null) + ra.Close(); + } + + } + throw new IOException("The byte array is not a recognized imageformat."); + } + /// + /// Converts a .NET image to a Native(PNG, JPG, GIF, WMF) image + /// + /// + /// + /// + public static Image GetInstance(System.Drawing.Image image, System.Drawing.Imaging.ImageFormat format) { + MemoryStream ms = new MemoryStream(); + image.Save(ms, format); + return GetInstance(ms.ToArray()); + } + + /// + /// Gets an instance of an Image from a System.Drwaing.Image. + /// + /// the System.Drawing.Image to convert + /// + /// if different from null the transparency + /// pixels are replaced by this color + /// + /// if true the image is treated as black and white + /// an object of type ImgRaw + public static Image GetInstance(System.Drawing.Image image, Color color, bool forceBW) { + System.Drawing.Bitmap bm = (System.Drawing.Bitmap)image; + int w = bm.Width; + int h = bm.Height; + int pxv = 0; + if (forceBW) { + int byteWidth = (w / 8) + ((w & 7) != 0 ? 1 : 0); + byte[] pixelsByte = new byte[byteWidth * h]; + + int index = 0; + int size = h * w; + int transColor = 1; + if (color != null) { + transColor = (color.R + color.G + color.B < 384) ? 0 : 1; + } + int[] transparency = null; + int cbyte = 0x80; + int wMarker = 0; + int currByte = 0; + if (color != null) { + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i++) { + int alpha = bm.GetPixel(i, j).A; + if (alpha < 250) { + if (transColor == 1) + currByte |= cbyte; + } + else { + if ((bm.GetPixel(i, j).ToArgb() & 0x888) != 0) + currByte |= cbyte; + } + cbyte >>= 1; + if (cbyte == 0 || wMarker + 1 >= w) { + pixelsByte[index++] = (byte)currByte; + cbyte = 0x80; + currByte = 0; + } + ++wMarker; + if (wMarker >= w) + wMarker = 0; + } + } + } + else { + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i++) { + if (transparency == null) { + int alpha = bm.GetPixel(i, j).A; + if (alpha == 0) { + transparency = new int[2]; + transparency[0] = transparency[1] = ((bm.GetPixel(i, j).ToArgb() & 0x888) != 0) ? 1 : 0; + } + } + if ((bm.GetPixel(i, j).ToArgb() & 0x888) != 0) + currByte |= cbyte; + cbyte >>= 1; + if (cbyte == 0 || wMarker + 1 >= w) { + pixelsByte[index++] = (byte)currByte; + cbyte = 0x80; + currByte = 0; + } + ++wMarker; + if (wMarker >= w) + wMarker = 0; + } + } + } + return Image.GetInstance(w, h, 1, 1, pixelsByte, transparency); + } + else { + byte[] pixelsByte = new byte[w * h * 3]; + byte[] smask = null; + + int index = 0; + int size = h * w; + int red = 255; + int green = 255; + int blue = 255; + if (color != null) { + red = color.R; + green = color.G; + blue = color.B; + } + int[] transparency = null; + if (color != null) { + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i++) { + int alpha = (bm.GetPixel(i, j).ToArgb() >> 24) & 0xff; + if (alpha < 250) { + pixelsByte[index++] = (byte) red; + pixelsByte[index++] = (byte) green; + pixelsByte[index++] = (byte) blue; + } + else { + pxv = bm.GetPixel(i, j).ToArgb(); + pixelsByte[index++] = (byte) ((pxv >> 16) & 0xff); + pixelsByte[index++] = (byte) ((pxv >> 8) & 0xff); + pixelsByte[index++] = (byte) ((pxv) & 0xff); + } + } + } + } + else { + int transparentPixel = 0; + smask = new byte[w * h]; + bool shades = false; + int smaskPtr = 0; + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i++) { + pxv = bm.GetPixel(i, j).ToArgb(); + byte alpha = smask[smaskPtr++] = (byte) ((pxv >> 24) & 0xff); + /* bugfix by Chris Nokleberg */ + if (!shades) { + if (alpha != 0 && alpha != 255) { + shades = true; + } else if (transparency == null) { + if (alpha == 0) { + transparentPixel = pxv & 0xffffff; + transparency = new int[6]; + transparency[0] = transparency[1] = (transparentPixel >> 16) & 0xff; + transparency[2] = transparency[3] = (transparentPixel >> 8) & 0xff; + transparency[4] = transparency[5] = transparentPixel & 0xff; + } + } else if ((pxv & 0xffffff) != transparentPixel) { + shades = true; + } + } + pixelsByte[index++] = (byte) ((pxv >> 16) & 0xff); + pixelsByte[index++] = (byte) ((pxv >> 8) & 0xff); + pixelsByte[index++] = (byte) (pxv & 0xff); + } + } + if (shades) + transparency = null; + else + smask = null; + } + Image img = Image.GetInstance(w, h, 3, 8, pixelsByte, transparency); + if (smask != null) { + Image sm = Image.GetInstance(w, h, 1, 8, smask); + sm.MakeMask(); + img.ImageMask = sm; + } + return img; + } + } + + /// + /// Gets an instance of an Image from a System.Drawing.Image. + /// + /// the System.Drawing.Image to convert + /// + /// if different from null the transparency + /// pixels are replaced by this color + /// + /// an object of type ImgRaw + public static Image GetInstance(System.Drawing.Image image, Color color) { + return Image.GetInstance(image, color, false); + } + + /// + /// Gets an instance of an Image. + /// + /// a filename + /// an object of type Gif, Jpeg or Png + public static Image GetInstance(string filename) { + return GetInstance(Utilities.ToURL(filename)); + } + + /// + /// Gets an instance of an Image in raw mode. + /// + /// the width of the image in pixels + /// the height of the image in pixels + /// 1,3 or 4 for GrayScale, RGB and CMYK + /// bits per component + /// the image data + /// an object of type ImgRaw + public static Image GetInstance(int width, int height, int components, int bpc, byte[] data) { + return Image.GetInstance(width, height, components, bpc, data, null); + } + + /** + * Reuses an existing image. + * @param ref the reference to the image dictionary + * @throws BadElementException on error + * @return the image + */ + public static Image GetInstance(PRIndirectReference iref) { + PdfDictionary dic = (PdfDictionary)PdfReader.GetPdfObjectRelease(iref); + int width = ((PdfNumber)PdfReader.GetPdfObjectRelease(dic.Get(PdfName.WIDTH))).IntValue; + int height = ((PdfNumber)PdfReader.GetPdfObjectRelease(dic.Get(PdfName.HEIGHT))).IntValue; + Image imask = null; + PdfObject obj = dic.Get(PdfName.SMASK); + if (obj != null && obj.IsIndirect()) { + imask = GetInstance((PRIndirectReference)obj); + } + else { + obj = dic.Get(PdfName.MASK); + if (obj != null && obj.IsIndirect()) { + PdfObject obj2 = PdfReader.GetPdfObjectRelease(obj); + if (obj2 is PdfDictionary) + imask = GetInstance((PRIndirectReference)obj); + } + } + Image img = new ImgRaw(width, height, 1, 1, null); + img.imageMask = imask; + img.directReference = iref; + return img; + } + + /// + /// Gets an instance of an Image in raw mode. + /// + /// + /// + public static Image GetInstance(PdfTemplate template) { + return new ImgTemplate(template); + } + + /// + /// Gets an instance of an Image in raw mode. + /// + /// the width of the image in pixels + /// the height of the image in pixels + /// + /// + /// + /// + /// + public static Image GetInstance(int width, int height, bool reverseBits, int typeCCITT, int parameters, byte[] data) { + return Image.GetInstance(width, height, reverseBits, typeCCITT, parameters, data, null); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static Image GetInstance(int width, int height, bool reverseBits, int typeCCITT, int parameters, byte[] data, int[] transparency) { + if (transparency != null && transparency.Length != 2) + throw new BadElementException("Transparency length must be equal to 2 with CCITT images"); + Image img = new ImgCCITT(width, height, reverseBits, typeCCITT, parameters, data); + img.transparency = transparency; + return img; + } + + /// + /// Gets an instance of an Image in raw mode. + /// + /// the width of the image in pixels + /// the height of the image in pixels + /// 1,3 or 4 for GrayScale, RGB and CMYK + /// bits per component + /// the image data + /// + /// transparency information in the Mask format of the + /// image dictionary + /// + /// an object of type ImgRaw + public static Image GetInstance(int width, int height, int components, int bpc, byte[] data, int[] transparency) { + if (transparency != null && transparency.Length != components * 2) + throw new BadElementException("Transparency length must be equal to (componentes * 2)"); + if (components == 1 && bpc == 1) { + byte[] g4 = CCITTG4Encoder.Compress(data, width, height); + return Image.GetInstance(width, height, false, Element.CCITTG4, Element.CCITT_BLACKIS1, g4, transparency); + } + Image img = new ImgRaw(width, height, components, bpc, data); + img.transparency = transparency; + return img; + } + + // methods to set information + + /// + /// Sets the absolute position of the Image. + /// + /// + /// + public void SetAbsolutePosition(float absoluteX, float absoluteY) { + this.absoluteX = absoluteX; + this.absoluteY = absoluteY; + } + + /// + /// Scale the image to an absolute width and an absolute height. + /// + /// the new width + /// the new height + public void ScaleAbsolute(float newWidth, float newHeight) { + plainWidth = newWidth; + plainHeight = newHeight; + float[] matrix = this.Matrix; + scaledWidth = matrix[DX] - matrix[CX]; + scaledHeight = matrix[DY] - matrix[CY]; + WidthPercentage = 0; + } + + /// + /// Scale the image to an absolute width. + /// + /// the new width + public void ScaleAbsoluteWidth(float newWidth) { + plainWidth = newWidth; + float[] matrix = this.Matrix; + scaledWidth = matrix[DX] - matrix[CX]; + scaledHeight = matrix[DY] - matrix[CY]; + WidthPercentage = 0; + } + + /// + /// Scale the image to an absolute height. + /// + /// the new height + public void ScaleAbsoluteHeight(float newHeight) { + plainHeight = newHeight; + float[] matrix = Matrix; + scaledWidth = matrix[DX] - matrix[CX]; + scaledHeight = matrix[DY] - matrix[CY]; + WidthPercentage = 0; + } + + /// + /// Scale the image to a certain percentage. + /// + /// the scaling percentage + public void ScalePercent(float percent) { + ScalePercent(percent, percent); + } + + /// + /// Scale the width and height of an image to a certain percentage. + /// + /// the scaling percentage of the width + /// the scaling percentage of the height + public void ScalePercent(float percentX, float percentY) { + plainWidth = (this.Width * percentX) / 100f; + plainHeight = (this.Height * percentY) / 100f; + float[] matrix = Matrix; + scaledWidth = matrix[DX] - matrix[CX]; + scaledHeight = matrix[DY] - matrix[CY]; + WidthPercentage = 0; + } + + /// + /// Scales the image so that it fits a certain width and height. + /// + /// the width to fit + /// the height to fit + public void ScaleToFit(float fitWidth, float fitHeight) { + ScalePercent(100); + float percentX = (fitWidth * 100) / this.ScaledWidth; + float percentY = (fitHeight * 100) / this.ScaledHeight; + ScalePercent(percentX < percentY ? percentX : percentY); + WidthPercentage = 0; + } + + /** + * Gets the current image rotation in radians. + * @return the current image rotation in radians + */ + public float GetImageRotation() { + float rot = (float) ((rotationRadians - initialRotation) % (2.0 * Math.PI)); + if (rot < 0) { + rot += (float)(2.0 * Math.PI); + } + return rot; + } + + /// + /// Sets the rotation of the image in radians. + /// + /// rotation in radians + public new float Rotation { + set { + double d=Math.PI; //__IDS__ + rotationRadians = (float) ((value + initialRotation) % (2.0 * d)); //__IDS__ + if (rotationRadians < 0) { + rotationRadians += (float)(2.0 * d); //__IDS__ + } + float[] matrix = Matrix; + scaledWidth = matrix[DX] - matrix[CX]; + scaledHeight = matrix[DY] - matrix[CY]; + } + } + + /// + /// Sets the rotation of the image in degrees. + /// + /// rotation in degrees + public float RotationDegrees { + set { + Rotation = (value / 180 * (float)Math.PI); //__IDS__ + } + } + + /// + /// Get/set the annotation. + /// + /// the Annotation + public Annotation Annotation { + get { + return annotation; + } + + set { + this.annotation = value; + } + } + + // methods to retrieve information + + /// + /// Gets the bpc for the image. + /// + /// + /// this only makes sense for Images of the type RawImage. + /// + /// a bpc value + public int Bpc { + get { + return bpc; + } + } + + /// + /// Gets the raw data for the image. + /// + /// + /// this only makes sense for Images of the type RawImage. + /// + /// the raw data + public byte[] RawData { + get { + return rawData; + } + } + + /// + /// Get/set the template to be used as an image. + /// + /// + /// this only makes sense for Images of the type ImgTemplate. + /// + /// the template + public PdfTemplate TemplateData { + get { + return template[0]; + } + + set { + this.template[0] = value; + } + } + + /// + /// Checks if the Images has to be added at an absolute position. + /// + /// a bool + public bool HasAbsolutePosition() { + return !float.IsNaN(absoluteY); + } + + /// + /// Checks if the Images has to be added at an absolute X position. + /// + /// a bool + public bool HasAbsoluteX() { + return !float.IsNaN(absoluteX); + } + + /// + /// Returns the absolute X position. + /// + /// a position + public float AbsoluteX { + get { + return absoluteX; + } + } + + /// + /// Returns the absolute Y position. + /// + /// a position + public float AbsoluteY { + get { + return absoluteY; + } + } + + /// + /// Returns the type. + /// + /// a type + public override int Type { + get { + return type; + } + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public override bool IsNestable() { + return true; + } + + /// + /// Returns true if the image is a Jpeg-object. + /// + /// a bool + public bool IsJpeg() { + return type == Element.JPEG; + } + + /// + /// Returns true if the image is a ImgRaw-object. + /// + /// a bool + public bool IsImgRaw() { + return type == Element.IMGRAW; + } + + /// + /// Returns true if the image is an ImgTemplate-object. + /// + /// a bool + public bool IsImgTemplate() { + return type == Element.IMGTEMPLATE; + } + + /// + /// Gets the string-representation of the reference to the image. + /// + /// a string + public Uri Url { + get { + return url; + } + set { + url = value; + } + } + + /// + /// Get/set the alignment for the image. + /// + /// a value + public int Alignment { + get { + return alignment; + } + + set { + this.alignment = value; + } + } + + /// + /// Get/set the alternative text for the image. + /// + /// a string + public string Alt { + get { + return alt; + } + + set { + this.alt = value; + } + } + + /// + /// Gets the scaled width of the image. + /// + /// a value + public float ScaledWidth { + get { + return scaledWidth; + } + } + + /// + /// Gets the scaled height of the image. + /// + /// a value + public float ScaledHeight { + get { + return scaledHeight; + } + } + + /// + /// Gets the colorspace for the image. + /// + /// + /// this only makes sense for Images of the type Jpeg. + /// + /// a colorspace value + public int Colorspace { + get { + return colorspace; + } + } + + /// + /// Returns the transformation matrix of the image. + /// + /// an array [AX, AY, BX, BY, CX, CY, DX, DY] + public float[] Matrix { + get { + float[] matrix = new float[8]; + float cosX = (float)Math.Cos(rotationRadians); + float sinX = (float)Math.Sin(rotationRadians); + matrix[AX] = plainWidth * cosX; + matrix[AY] = plainWidth * sinX; + matrix[BX] = (- plainHeight) * sinX; + matrix[BY] = plainHeight * cosX; + if (rotationRadians < Math.PI / 2f) { + matrix[CX] = matrix[BX]; + matrix[CY] = 0; + matrix[DX] = matrix[AX]; + matrix[DY] = matrix[AY] + matrix[BY]; + } + else if (rotationRadians < Math.PI) { + matrix[CX] = matrix[AX] + matrix[BX]; + matrix[CY] = matrix[BY]; + matrix[DX] = 0; + matrix[DY] = matrix[AY]; + } + else if (rotationRadians < Math.PI * 1.5f) { + matrix[CX] = matrix[AX]; + matrix[CY] = matrix[AY] + matrix[BY]; + matrix[DX] = matrix[BX]; + matrix[DY] = 0; + } + else { + matrix[CX] = 0; + matrix[CY] = matrix[AY]; + matrix[DX] = matrix[AX] + matrix[BX]; + matrix[DY] = matrix[BY]; + } + return matrix; + } + } + + /// + /// Returns the transparency. + /// + /// the transparency + public int[] Transparency { + get { + return transparency; + } + set { + transparency = value; + } + } + + /// + /// Gets the plain width of the image. + /// + /// a value + public float PlainWidth { + get { + return plainWidth; + } + } + + /// + /// Gets the plain height of the image. + /// + /// a value + public float PlainHeight { + get { + return plainHeight; + } + } + + /// + /// generates new serial id + /// + static protected long GetSerialId() { + lock (serialId) { + serialId = (long)serialId + 1L; + return (long)serialId; + } + } + + /// + /// returns serial id for this object + /// + public long MySerialId { + get { + return mySerialId; + } + } + + /// + /// Gets the dots-per-inch in the X direction. Returns 0 if not available. + /// + /// the dots-per-inch in the X direction + public int DpiX { + get { + return dpiX; + } + } + + /// + /// Gets the dots-per-inch in the Y direction. Returns 0 if not available. + /// + /// the dots-per-inch in the Y direction + public int DpiY { + get { + return dpiY; + } + } + + /** + * Sets the dots per inch value + * + * @param dpiX + * dpi for x coordinates + * @param dpiY + * dpi for y coordinates + */ + public void SetDpi(int dpiX, int dpiY) { + this.dpiX = dpiX; + this.dpiY = dpiY; + } + + /// + /// Returns true if this Image has the + /// requisites to be a mask. + /// + /// true if this Image can be a mask + public bool IsMaskCandidate() { + if (type == Element.IMGRAW) { + if (bpc > 0xff) + return true; + } + return colorspace == 1; + } + + /// + /// Make this Image a mask. + /// + public void MakeMask() { + if (!IsMaskCandidate()) + throw new DocumentException("This image can not be an image mask."); + mask = true; + } + + /// + /// Get/set the explicit masking. + /// + /// the explicit masking + public Image ImageMask { + get { + return imageMask; + } + + set { + if (this.mask) + throw new DocumentException("An image mask cannot contain another image mask."); + if (!value.mask) + throw new DocumentException("The image mask is not a mask. Did you do MakeMask()?"); + imageMask = value; + smask = (value.bpc > 1 && value.bpc <= 8); + } + } + + /// + /// Returns true if this Image is a mask. + /// + /// true if this Image is a mask + public bool IsMask() { + return mask; + } + + /// + /// Inverts the meaning of the bits of a mask. + /// + /// true to invert the meaning of the bits of a mask + public bool Inverted { + set { + this.invert = value; + } + get { + return this.invert; + } + } + + /// + /// Sets the image interpolation. Image interpolation attempts to + /// produce a smooth transition between adjacent sample values. + /// + /// New value of property interpolation. + public bool Interpolation { + set { + this.interpolation = value; + } + get { + return this.interpolation; + } + } + + /** Tags this image with an ICC profile. + * @param profile the profile + */ + public ICC_Profile TagICC { + get { + return profile; + } + set { + this.profile = value; + } + } + + /** Checks is the image has an ICC profile. + * @return the ICC profile or null + */ + public bool HasICCProfile() { + return (this.profile != null); + } + + public bool Deflated { + get { + return deflated; + } + set { + deflated = value; + } + } + + public PdfDictionary Additional { + get { + return additional; + } + set { + additional = value; + } + } + + public bool Smask { + get { + return smask; + } + set { + smask = value; + } + } + + public float XYRatio { + get { + return xyRatio; + } + set { + xyRatio = value; + } + } + + public float IndentationLeft { + get { + return indentationLeft; + } + set { + indentationLeft = value; + } + } + + public float IndentationRight { + get { + return indentationRight; + } + set { + indentationRight = value; + } + } + + public int OriginalType { + get { + return originalType; + } + set { + originalType = value; + } + } + + public byte[] OriginalData { + get { + return originalData; + } + set { + originalData = value; + } + } + + public float SpacingBefore { + get { + return spacingBefore; + } + set { + spacingBefore = value; + } + } + + public float SpacingAfter { + get { + return spacingAfter; + } + set { + spacingAfter = value; + } + } + + public float WidthPercentage { + get { + return widthPercentage; + } + set { + widthPercentage = value; + } + } + + public IPdfOCG Layer { + get { + return layer; + } + set { + layer = value; + } + } + + private PdfObject SimplifyColorspace(PdfObject obj) { + if (obj == null || !obj.IsArray()) + return obj; + PdfObject first = (PdfObject)(((PdfArray)obj).ArrayList[0]); + if (PdfName.CALGRAY.Equals(first)) + return PdfName.DEVICEGRAY; + else if (PdfName.CALRGB.Equals(first)) + return PdfName.DEVICERGB; + else + return obj; + } + + /** + * Replaces CalRGB and CalGray colorspaces with DeviceRGB and DeviceGray. + */ + public void SimplifyColorspace() { + if (additional == null) + return; + PdfObject value = additional.Get(PdfName.COLORSPACE); + if (value == null || !value.IsArray()) + return; + PdfObject cs = SimplifyColorspace(value); + if (cs.IsName()) + value = cs; + else { + PdfObject first = (PdfObject)(((PdfArray)value).ArrayList[0]); + if (PdfName.INDEXED.Equals(first)) { + ArrayList array = ((PdfArray)value).ArrayList; + if (array.Count >= 2 && ((PdfObject)array[1]).IsArray()) { + array[1] = SimplifyColorspace((PdfObject)array[1]); + } + } + } + additional.Put(PdfName.COLORSPACE, value); + } + + /** + * Some image formats, like TIFF may present the images rotated that have + * to be compensated. + */ + public float InitialRotation { + get { + return initialRotation; + } + set { + float old_rot = rotationRadians - this.initialRotation; + this.initialRotation = value; + Rotation = old_rot; + } + } + + public PdfIndirectReference DirectReference { + set { + directReference = value; + } + get { + return directReference; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/ImgCCITT.cs b/iTechSharp/iTextSharp/text/ImgCCITT.cs new file mode 100644 index 0000000..f8b7950 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ImgCCITT.cs @@ -0,0 +1,107 @@ +using System; +using iTextSharp.text.pdf.codec; + +/* + * $Id: ImgCCITT.cs,v 1.6 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 2000, 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /** + * CCITT Image data that has to be inserted into the document + * + * @see Element + * @see Image + * + * @author Paulo Soares + */ + /// + /// CCITT Image data that has to be inserted into the document + /// + /// + /// + public class ImgCCITT : Image { + public ImgCCITT(Image image) : base(image) {} + + /// + /// Creats an Image in CCITT mode. + /// + /// the exact width of the image + /// the exact height of the image + /// + /// reverses the bits in data. + /// Bit 0 is swapped with bit 7 and so on + /// + /// + /// the type of compression in data. It can be + /// CCITTG4, CCITTG31D, CCITTG32D + /// + /// + /// parameters associated with this stream. Possible values are + /// CCITT_BLACKIS1, CCITT_ENCODEDBYTEALIGN, CCITT_ENDOFLINE and CCITT_ENDOFBLOCK or a + /// combination of them + /// + /// the image data + public ImgCCITT(int width, int height, bool reverseBits, int typeCCITT, int parameters, byte[] data) : base((Uri)null) { + if (typeCCITT != Element.CCITTG4 && typeCCITT != Element.CCITTG3_1D && typeCCITT != Element.CCITTG3_2D) + throw new BadElementException("The CCITT compression type must be CCITTG4, CCITTG3_1D or CCITTG3_2D"); + if (reverseBits) + TIFFFaxDecoder.ReverseBits(data); + type = Element.IMGRAW; + scaledHeight = height; + this.Top = scaledHeight; + scaledWidth = width; + this.Right = scaledWidth; + colorspace = parameters; + bpc = typeCCITT; + rawData = data; + plainWidth = this.Width; + plainHeight = this.Height; + } + } +} diff --git a/iTechSharp/iTextSharp/text/ImgRaw.cs b/iTechSharp/iTextSharp/text/ImgRaw.cs new file mode 100644 index 0000000..2b97c96 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ImgRaw.cs @@ -0,0 +1,88 @@ +using System; + +/* + * $Id: ImgRaw.cs,v 1.5 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 2000, 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// Raw Image data that has to be inserted into the document + /// + /// + /// + public class ImgRaw : Image { + + public ImgRaw(Image image) : base(image) {} + + /// + /// Creats an Image in raw mode. + /// + /// the exact width of the image + /// the exact height of the image + /// 1,3 or 4 for GrayScale, RGB and CMYK + /// bits per component. Must be 1,2,4 or 8 + /// data the image data + public ImgRaw(int width, int height, int components, int bpc, byte[] data) : base((Uri)null) { + type = Element.IMGRAW; + scaledHeight = height; + this.Top = scaledHeight; + scaledWidth = width; + this.Right = scaledWidth; + if (components != 1 && components != 3 && components != 4) + throw new BadElementException("Components must be 1, 3, or 4."); + if (bpc != 1 && bpc != 2 && bpc != 4 && bpc != 8) + throw new BadElementException("Bits-per-component must be 1, 2, 4, or 8."); + colorspace = components; + this.bpc = bpc; + rawData = data; + plainWidth = this.Width; + plainHeight = this.Height; + } + } +} diff --git a/iTechSharp/iTextSharp/text/ImgTemplate.cs b/iTechSharp/iTextSharp/text/ImgTemplate.cs new file mode 100644 index 0000000..4b60f04 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ImgTemplate.cs @@ -0,0 +1,88 @@ +using System; + +using iTextSharp.text.pdf; + +/* + * $Id: ImgTemplate.cs,v 1.5 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 2000, 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// PdfTemplate that has to be inserted into the document + /// + /// + /// + public class ImgTemplate : Image { + + /// + /// Creats an Image from a PdfTemplate. + /// + /// the Image + public ImgTemplate(Image image) : base(image) {} + + /// + /// Creats an Image from a PdfTemplate. + /// + /// the PdfTemplate + public ImgTemplate(PdfTemplate template) : base((Uri)null) { + if (template == null) + throw new BadElementException("The template can not be null."); + if (template.Type == PdfTemplate.TYPE_PATTERN) + throw new BadElementException("A pattern can not be used as a template to create an image."); + type = Element.IMGTEMPLATE; + scaledHeight = template.Height; + this.Top = scaledHeight; + scaledWidth = template.Width; + this.Right = scaledWidth; + TemplateData = template; + plainWidth = this.Width; + plainHeight = this.Height; + } + } +} diff --git a/iTechSharp/iTextSharp/text/ImgWMF.cs b/iTechSharp/iTextSharp/text/ImgWMF.cs new file mode 100644 index 0000000..6199fa0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ImgWMF.cs @@ -0,0 +1,176 @@ +using System; +using System.IO; +using System.Net; + +using iTextSharp.text.pdf; +using iTextSharp.text.pdf.codec.wmf; + +/* + * $Id: ImgWMF.cs,v 1.7 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /** + * An ImgWMF is the representation of a windows metafile + * that has to be inserted into the document + * + * @see Element + * @see Image + * @see Gif + * @see Png + */ + /// + /// An ImgWMF is the representation of a windows metafile + /// that has to be inserted into the document + /// + public class ImgWMF : Image { + + // Constructors + /// + /// Constructs an ImgWMF-object + /// + /// a Image + public ImgWMF(Image image) : base(image) {} + + /// + /// Constructs an ImgWMF-object, using an url. + /// + /// the URL where the image can be found + public ImgWMF(Uri url) : base(url) { + ProcessParameters(); + } + + /// + /// Constructs an ImgWMF-object, using a filename. + /// + /// a string-representation of the file that contains the image. + public ImgWMF(string filename) : this(Utilities.ToURL(filename)) {} + + /// + /// Constructs an ImgWMF-object from memory. + /// + /// the memory image + public ImgWMF(byte[] img) : base((Uri)null) { + rawData = img; + originalData = img; + ProcessParameters(); + } + + /// + /// This method checks if the image is a valid WMF and processes some parameters. + /// + private void ProcessParameters() { + type = Element.IMGTEMPLATE; + originalType = ORIGINAL_WMF; + Stream istr = null; + try { + string errorID; + if (rawData == null){ + WebRequest w = WebRequest.Create(url); + istr = w.GetResponse().GetResponseStream(); + errorID = url.ToString(); + } + else{ + istr = new MemoryStream(rawData); + errorID = "Byte array"; + } + InputMeta im = new InputMeta(istr); + if (im.ReadInt() != unchecked((int)0x9AC6CDD7)) { + throw new BadElementException(errorID + " is not a valid placeable windows metafile."); + } + im.ReadWord(); + int left = im.ReadShort(); + int top = im.ReadShort(); + int right = im.ReadShort(); + int bottom = im.ReadShort(); + int inch = im.ReadWord(); + dpiX = 72; + dpiY = 72; + scaledHeight = (float)(bottom - top) / inch * 72f; + this.Top =scaledHeight; + scaledWidth = (float)(right - left) / inch * 72f; + this.Right = scaledWidth; + } + finally { + if (istr != null) { + istr.Close(); + } + plainWidth = this.Width; + plainHeight = this.Height; + } + } + + /// + /// Reads the WMF into a template. + /// + /// the template to read to + public void ReadWMF(PdfTemplate template) { + TemplateData = template; + template.Width = this.Width; + template.Height = this.Height; + Stream istr = null; + try { + if (rawData == null){ + WebRequest w = WebRequest.Create(url); + istr = w.GetResponse().GetResponseStream(); + } + else{ + istr = new MemoryStream(rawData); + } + MetaDo meta = new MetaDo(istr, template); + meta.ReadAll(); + } + finally { + if (istr != null) { + istr.Close(); + } + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/Jpeg.cs b/iTechSharp/iTextSharp/text/Jpeg.cs new file mode 100644 index 0000000..f0f524d --- /dev/null +++ b/iTechSharp/iTextSharp/text/Jpeg.cs @@ -0,0 +1,335 @@ +using System; +using System.IO; +using System.Net; +using System.util; +using iTextSharp.text.pdf; + +/* + * $Id: Jpeg.cs,v 1.11 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// An Jpeg is the representation of a graphic element (JPEG) + /// that has to be inserted into the document + /// + /// + /// + /// + /// + public class Jpeg : Image { + + // public static membervariables + + /// This is a type of marker. + public const int NOT_A_MARKER = -1; + + /// This is a type of marker. + public const int VALID_MARKER = 0; + + /// Acceptable Jpeg markers. + public static int[] VALID_MARKERS = {0xC0, 0xC1, 0xC2}; + + /// This is a type of marker. + public const int UNSUPPORTED_MARKER = 1; + + /// Unsupported Jpeg markers. + public static int[] UNSUPPORTED_MARKERS = {0xC3, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCD, 0xCE, 0xCF}; + + /// This is a type of marker. + public const int NOPARAM_MARKER = 2; + + /// Jpeg markers without additional parameters. + public static int[] NOPARAM_MARKERS = {0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0x01}; + + public const int M_APP0 = 0xE0; + public const int M_APP2 = 0xE2; + public const int M_APPE = 0xEE; + + public static byte[] JFIF_ID = {0x4A, 0x46, 0x49, 0x46, 0x00}; + + private byte[][] icc; + + // Constructors + + /// + /// Construct a Jpeg-object, using a Image + /// + /// a Image + public Jpeg(Image image) : base(image) {} + + /// + /// Constructs a Jpeg-object, using an Uri. + /// + /// + /// Deprecated, use Image.GetInstance(...) to create an Image + /// + /// the Uri where the image can be found + public Jpeg(Uri Uri) : base(Uri) { + ProcessParameters(); + } + + /// + /// Constructs a Jpeg-object from memory. + /// + /// the memory image + public Jpeg(byte[] img) : base((Uri)null) { + rawData = img; + originalData = img; + ProcessParameters(); + } + + /// + /// Constructs a Jpeg-object from memory. + /// + /// the memory image. + /// the width you want the image to have + /// the height you want the image to have + public Jpeg(byte[] img, float width, float height) : this(img) { + scaledWidth = width; + scaledHeight = height; + } + + // private static methods + + /// + /// Reads a short from the Stream. + /// + /// the Stream + /// an int + private static int GetShort(Stream istr) { + return (istr.ReadByte() << 8) + istr.ReadByte(); + } + + /// + /// Reads an inverted short from the Stream. + /// + /// the Stream + /// an int + private static int GetShortInverted(Stream istr) { + return (istr.ReadByte() + istr.ReadByte() << 8); + } + + /// + /// Returns a type of marker. + /// + /// an int + /// a type: VALID_MARKER, UNSUPPORTED_MARKER or NOPARAM_MARKER + private static int MarkerType(int marker) { + for (int i = 0; i < VALID_MARKERS.Length; i++) { + if (marker == VALID_MARKERS[i]) { + return VALID_MARKER; + } + } + for (int i = 0; i < NOPARAM_MARKERS.Length; i++) { + if (marker == NOPARAM_MARKERS[i]) { + return NOPARAM_MARKER; + } + } + for (int i = 0; i < UNSUPPORTED_MARKERS.Length; i++) { + if (marker == UNSUPPORTED_MARKERS[i]) { + return UNSUPPORTED_MARKER; + } + } + return NOT_A_MARKER; + } + + // private methods + + /// + /// This method checks if the image is a valid JPEG and processes some parameters. + /// + private void ProcessParameters() { + type = Element.JPEG; + originalType = ORIGINAL_JPEG; + Stream istr = null; + try { + string errorID; + if (rawData == null){ + WebRequest w = WebRequest.Create(url); + istr = w.GetResponse().GetResponseStream(); + errorID = url.ToString(); + } + else{ + istr = new MemoryStream(rawData); + errorID = "Byte array"; + } + if (istr.ReadByte() != 0xFF || istr.ReadByte() != 0xD8) { + throw new BadElementException(errorID + " is not a valid JPEG-file."); + } + bool firstPass = true; + int len; + while (true) { + int v = istr.ReadByte(); + if (v < 0) + throw new IOException("Premature EOF while reading JPG."); + if (v == 0xFF) { + int marker = istr.ReadByte(); + if (firstPass && marker == M_APP0) { + firstPass = false; + len = GetShort(istr); + if (len < 16) { + Utilities.Skip(istr, len - 2); + continue; + } + byte[] bcomp = new byte[JFIF_ID.Length]; + int r = istr.Read(bcomp, 0, bcomp.Length); + if (r != bcomp.Length) + throw new BadElementException(errorID + " corrupted JFIF marker."); + bool found = true; + for (int k = 0; k < bcomp.Length; ++k) { + if (bcomp[k] != JFIF_ID[k]) { + found = false; + break; + } + } + if (!found) { + Utilities.Skip(istr, len - 2 - bcomp.Length); + continue; + } + Utilities.Skip(istr, 2); + int units = istr.ReadByte(); + int dx = GetShort(istr); + int dy = GetShort(istr); + if (units == 1) { + dpiX = dx; + dpiY = dy; + } + else if (units == 2) { + dpiX = (int)((float)dx * 2.54f + 0.5f); + dpiY = (int)((float)dy * 2.54f + 0.5f); + } + Utilities.Skip(istr, len - 2 - bcomp.Length - 7); + continue; + } + if (marker == M_APPE) { + len = GetShort(istr) - 2; + byte[] byteappe = new byte[len]; + for (int k = 0; k < len; ++k) { + byteappe[k] = (byte)istr.ReadByte(); + } + if (byteappe.Length >= 12) { + string appe = System.Text.ASCIIEncoding.ASCII.GetString(byteappe,0,5); + if (Util.EqualsIgnoreCase(appe, "adobe")) { + invert = true; + } + } + continue; + } + if (marker == M_APP2) { + len = GetShort(istr) - 2; + byte[] byteapp2 = new byte[len]; + for (int k = 0; k < len; ++k) { + byteapp2[k] = (byte)istr.ReadByte(); + } + if (byteapp2.Length >= 14) { + String app2 = System.Text.ASCIIEncoding.ASCII.GetString(byteapp2, 0, 11); + if (app2.Equals("ICC_PROFILE")) { + int order = byteapp2[12] & 0xff; + int count = byteapp2[13] & 0xff; + if (icc == null) + icc = new byte[count][]; + icc[order - 1] = byteapp2; + } + } + continue; + } + firstPass = false; + int markertype = MarkerType(marker); + if (markertype == VALID_MARKER) { + Utilities.Skip(istr, 2); + if (istr.ReadByte() != 0x08) { + throw new BadElementException(errorID + " must have 8 bits per component."); + } + scaledHeight = GetShort(istr); + Top = scaledHeight; + scaledWidth = GetShort(istr); + Right = scaledWidth; + colorspace = istr.ReadByte(); + bpc = 8; + break; + } + else if (markertype == UNSUPPORTED_MARKER) { + throw new BadElementException(errorID + ": unsupported JPEG marker: " + marker); + } + else if (markertype != NOPARAM_MARKER) { + Utilities.Skip(istr, GetShort(istr) - 2); + } + } + } + } + finally { + if (istr != null) { + istr.Close(); + } + } + plainWidth = this.Width; + plainHeight = this.Height; + if (icc != null) { + int total = 0; + for (int k = 0; k < icc.Length; ++k) { + if (icc[k] == null) { + icc = null; + return; + } + total += icc[k].Length - 14; + } + byte[] ficc = new byte[total]; + total = 0; + for (int k = 0; k < icc.Length; ++k) { + System.Array.Copy(icc[k], 14, ficc, total, icc[k].Length - 14); + total += icc[k].Length - 14; + } + ICC_Profile icc_prof = ICC_Profile.GetInstance(ficc); + TagICC = icc_prof; + icc = null; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/Jpeg2000.cs b/iTechSharp/iTextSharp/text/Jpeg2000.cs new file mode 100644 index 0000000..029f9e4 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Jpeg2000.cs @@ -0,0 +1,239 @@ +using System; +using System.IO; +using System.Net; +using System.util; +using iTextSharp.text.pdf; +/* + * $Id: Jpeg2000.cs,v 1.5 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + + /** + * An Jpeg2000 is the representation of a graphic element (JPEG) + * that has to be inserted into the document + * + * @see Element + * @see Image + */ + + public class Jpeg2000 : Image { + + // public static final membervariables + + public const int JP2_JP = 0x6a502020; + public const int JP2_IHDR = 0x69686472; + public const int JPIP_JPIP = 0x6a706970; + + public const int JP2_FTYP = 0x66747970; + public const int JP2_JP2H = 0x6a703268; + public const int JP2_COLR = 0x636f6c72; + public const int JP2_JP2C = 0x6a703263; + public const int JP2_URL = 0x75726c20; + public const int JP2_DBTL = 0x6474626c; + public const int JP2_BPCC = 0x62706363; + public const int JP2_JP2 = 0x6a703220; + + private Stream inp; + private int boxLength; + private int boxType; + + // Constructors + + public Jpeg2000(Image image) : base(image) { + } + + /** + * Constructs a Jpeg2000-object, using an url. + * + * @param url the URL where the image can be found + * @throws BadElementException + * @throws IOException + */ + public Jpeg2000(Uri url) : base(url) { + ProcessParameters(); + } + + /** + * Constructs a Jpeg2000-object from memory. + * + * @param img the memory image + * @throws BadElementException + * @throws IOException + */ + + public Jpeg2000(byte[] img) : base((Uri)null) { + rawData = img; + originalData = img; + ProcessParameters(); + } + + /** + * Constructs a Jpeg2000-object from memory. + * + * @param img the memory image. + * @param width the width you want the image to have + * @param height the height you want the image to have + * @throws BadElementException + * @throws IOException + */ + + public Jpeg2000(byte[] img, float width, float height) : this(img) { + scaledWidth = width; + scaledHeight = height; + } + + private int Cio_read(int n) { + int v = 0; + for (int i = n - 1; i >= 0; i--) { + v += inp.ReadByte() << (i << 3); + } + return v; + } + + public void Jp2_read_boxhdr() { + boxLength = Cio_read(4); + boxType = Cio_read(4); + if (boxLength == 1) { + if (Cio_read(4) != 0) { + throw new IOException("Cannot handle box sizes higher than 2^32"); + } + boxLength = Cio_read(4); + if (boxLength == 0) + throw new IOException("Unsupported box size == 0"); + } + else if (boxLength == 0) { + throw new IOException("Unsupported box size == 0"); + } + } + + /** + * This method checks if the image is a valid JPEG and processes some parameters. + * @throws BadElementException + * @throws IOException + */ + private void ProcessParameters() { + type = JPEG2000; + originalType = ORIGINAL_JPEG2000; + inp = null; + try { + string errorID; + if (rawData == null){ + WebRequest w = WebRequest.Create(url); + inp = w.GetResponse().GetResponseStream(); + errorID = url.ToString(); + } + else{ + inp = new MemoryStream(rawData); + errorID = "Byte array"; + } + boxLength = Cio_read(4); + if (boxLength == 0x0000000c) { + boxType = Cio_read(4); + if (JP2_JP != boxType) { + throw new IOException("Expected JP Marker"); + } + if (0x0d0a870a != Cio_read(4)) { + throw new IOException("Error with JP Marker"); + } + + Jp2_read_boxhdr(); + if (JP2_FTYP != boxType) { + throw new IOException("Expected FTYP Marker"); + } + Utilities.Skip(inp, boxLength - 8); + Jp2_read_boxhdr(); + do { + if (JP2_JP2H != boxType) { + if (boxType == JP2_JP2C) { + throw new IOException("Expected JP2H Marker"); + } + Utilities.Skip(inp, boxLength - 8); + Jp2_read_boxhdr(); + } + } while (JP2_JP2H != boxType); + Jp2_read_boxhdr(); + if (JP2_IHDR != boxType) { + throw new IOException("Expected IHDR Marker"); + } + scaledHeight = Cio_read(4); + Top = scaledHeight; + scaledWidth = Cio_read(4); + Right = scaledWidth; + bpc = -1; + } + else if ((uint)boxLength == 0xff4fff51) { + Utilities.Skip(inp, 4); + int x1 = Cio_read(4); + int y1 = Cio_read(4); + int x0 = Cio_read(4); + int y0 = Cio_read(4); + Utilities.Skip(inp, 16); + colorspace = Cio_read(2); + bpc = 8; + scaledHeight = y1 - y0; + Top = scaledHeight; + scaledWidth = x1 - x0; + Right = scaledWidth; + } + else { + throw new IOException("Not a valid Jpeg2000 file"); + } + } + finally { + if (inp != null) { + try{inp.Close();}catch{} + inp = null; + } + } + plainWidth = this.Width; + plainHeight = this.Height; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/List.cs b/iTechSharp/iTextSharp/text/List.cs new file mode 100644 index 0000000..192cee2 --- /dev/null +++ b/iTechSharp/iTextSharp/text/List.cs @@ -0,0 +1,555 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text.factories; + +/* + * $Id: List.cs,v 1.20 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A List contains several ListItems. + /// + /// + /// Example 1: + /// + /// List list = new List(true, 20); + /// list.Add(new ListItem("First line")); + /// list.Add(new ListItem("The second line is longer to see what happens once the end of the line is reached. Will it start on a new line?")); + /// list.Add(new ListItem("Third line")); + /// + /// + /// The result of this code looks like this: + ///
      + ///
    1. + /// First line + ///
    2. + ///
    3. + /// The second line is longer to see what happens once the end of the line is reached. Will it start on a new line? + ///
    4. + ///
    5. + /// Third line + ///
    6. + ///
    + /// + /// Example 2: + /// + /// List overview = new List(false, 10); + /// overview.Add(new ListItem("This is an item")); + /// overview.Add("This is another item"); + /// + /// + /// The result of this code looks like this: + ///
      + ///
    • + /// This is an item + ///
    • + ///
    • + /// This is another item + ///
    • + ///
    + ///
    + /// + /// + public class List : ITextElementArray { + + // membervariables + /** a possible value for the numbered parameter */ + public const bool ORDERED = true; + /** a possible value for the numbered parameter */ + public const bool UNORDERED = false; + /** a possible value for the lettered parameter */ + public const bool NUMERICAL = false; + /** a possible value for the lettered parameter */ + public const bool ALPHABETICAL = true; + /** a possible value for the lettered parameter */ + public const bool UPPERCASE = false; + /** a possible value for the lettered parameter */ + public const bool LOWERCASE = true; + + /// This is the ArrayList containing the different ListItems. + protected ArrayList list = new ArrayList(); + + /** Indicates if the list has to be numbered. */ + protected bool numbered = false; + /** Indicates if the listsymbols are numerical or alphabetical. */ + protected bool lettered = false; + /** Indicates if the listsymbols are lowercase or uppercase. */ + protected bool lowercase = false; + /** Indicates if the indentation has to be set automatically. */ + protected bool autoindent = false; + /** Indicates if the indentation of all the items has to be aligned. */ + protected bool alignindent = false; + + /// This variable indicates the first number of a numbered list. + protected int first = 1; + + /// This is the listsymbol of a list that is not numbered. + protected Chunk symbol = new Chunk("-"); + /** + * In case you are using numbered/lettered lists, this String is added before the number/letter. + * @since iText 2.1.1 + */ + protected String preSymbol = ""; + /** + * In case you are using numbered/lettered lists, this String is added after the number/letter. + * @since iText 2.1.1 + */ + protected String postSymbol = ". "; + + /// The indentation of this list on the left side. + protected float indentationLeft = 0; + + /// The indentation of this list on the right side. + protected float indentationRight = 0; + + /// The indentation of the listitems. + protected float symbolIndent = 0; + + // constructors + + /** + * Constructs a List. + */ + public List() : this(false, false) { + } + + /** + * Constructs a List with a specific symbol indentation. + * @param symbolIndent the symbol indentation + * @since iText 2.0.8 + */ + public List(float symbolIndent) { + this.symbolIndent = symbolIndent; + } + + /** + * Constructs a List. + * + * @param numbered a bool + */ + public List(bool numbered) : this(numbered, false) { + } + + /** + * Constructs a List. + * + * @param numbered a bool + * @param lettered has the list to be 'numbered' with letters + */ + public List(bool numbered, bool lettered) { + this.numbered = numbered; + this.lettered = lettered; + this.autoindent = true; + this.alignindent = true; + } + + + /// + /// Constructs a List. + /// + /// + /// the parameter symbolIndent is important for instance when + /// generating PDF-documents; it indicates the indentation of the listsymbol. + /// + /// a bool + /// the indentation that has to be used for the listsymbol + public List(bool numbered, float symbolIndent) : this(numbered, false, symbolIndent) { + } + + /// + /// Constructs a List. + /// + /// a bool + /// a bool + /// the indentation that has to be used for the listsymbol + public List(bool numbered, bool lettered, float symbolIndent ) { + this.numbered = numbered; + this.lettered = lettered; + this.symbolIndent = symbolIndent; + } + + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// IElementListener. + /// + /// an IElementListener + /// true if the element was processed successfully + public bool Process(IElementListener listener) { + try { + foreach (IElement ele in list) { + listener.Add(ele); + } + return true; + } + catch (DocumentException) { + return false; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public int Type { + get { + return Element.LIST; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public ArrayList Chunks { + get { + ArrayList tmp = new ArrayList(); + foreach (IElement ele in list) { + tmp.AddRange(ele.Chunks); + } + return tmp; + } + } + + // methods to set the membervariables + + /// + /// Adds an Object to the List. + /// + /// the object to add + /// true is successful + public virtual bool Add(Object o) { + if (o is ListItem) { + ListItem item = (ListItem) o; + if (numbered || lettered) { + Chunk chunk = new Chunk(preSymbol, symbol.Font); + int index = first + list.Count; + if (lettered) + chunk.Append(RomanAlphabetFactory.GetString(index, lowercase)); + else + chunk.Append(index.ToString()); + chunk.Append(postSymbol); + item.ListSymbol = chunk; + } + else { + item.ListSymbol = symbol; + } + item.SetIndentationLeft(symbolIndent, autoindent); + item.IndentationRight = 0; + list.Add(item); + return true; + } + else if (o is List) { + List nested = (List) o; + nested.IndentationLeft = nested.IndentationLeft + symbolIndent; + first--; + list.Add(nested); + return true; + } + else if (o is string) { + return this.Add(new ListItem((string) o)); + } + return false; + } + + // extra methods + + /** Makes sure all the items in the list have the same indentation. */ + public void NormalizeIndentation() { + float max = 0; + foreach (IElement o in list) { + if (o is ListItem) { + max = Math.Max(max, ((ListItem)o).IndentationLeft); + } + } + foreach (IElement o in list) { + if (o is ListItem) { + ((ListItem)o).IndentationLeft = max; + } + } + } + + //setters/getters + + public bool Numbered { + set { + numbered = value; + } + get { + return numbered; + } + } + + public bool Lettered { + set { + lettered = value; + } + get { + return lettered; + } + } + + public bool Lowercase { + set { + lowercase = value; + } + get { + return lowercase; + } + } + + public bool Autoindent { + set { + autoindent = value; + } + get { + return autoindent; + } + } + + public bool Alignindent { + set { + alignindent = value; + } + get { + return alignindent; + } + } + + /// + /// Get/set the first number + /// + /// an int + public int First { + get { + return first; + } + + set { + this.first = value; + } + } + + /// + /// Sets the symbol + /// + /// a Chunk + public Chunk ListSymbol { + set { + this.symbol = value; + } + } + + /// + /// Sets the listsymbol. + /// + /// + /// This is a shortcut for SetListSymbol(Chunk symbol). + /// + /// a string + public void SetListSymbol(string symbol) { + this.symbol = new Chunk(symbol); + } + + /// + /// Get/set the indentation of this paragraph on the left side. + /// + /// the indentation + public float IndentationLeft { + get { + return indentationLeft; + } + + set { + this.indentationLeft = value; + } + } + + /// + /// Get/set the indentation of this paragraph on the right side. + /// + /// the indentation + public float IndentationRight { + get { + return indentationRight; + } + + set { + this.indentationRight = value; + } + } + + /// + /// Gets the symbol indentation. + /// + /// the symbol indentation + public float SymbolIndent { + set { + symbolIndent = value; + } + get { + return symbolIndent; + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return true; + } + + // methods to retrieve information + + /// + /// Gets all the items in the list. + /// + /// an ArrayList containing ListItems + public ArrayList Items { + get { + return list; + } + } + + /// + /// Gets the size of the list. + /// + /// a size + public int Size { + get { + return list.Count; + } + } + + /** + * Returns true if the list is empty. + * + * @return true if the list is empty + */ + public virtual bool IsEmpty() { + return list.Count == 0; + } + + /// + /// Gets the leading of the first listitem. + /// + /// a leading + public float TotalLeading { + get { + if (list.Count < 1) { + return -1; + } + ListItem item = (ListItem)list[0]; + return item.TotalLeading; + } + } + + /// + /// Get/set the symbol indentation. + /// + /// a Chunk + public Chunk Symbol { + get { + return symbol; + } + set { + this.symbol = value; + } + } + + /** + * Returns the String that is after a number or letter in the list symbol. + * @return the String that is after a number or letter in the list symbol + * @since iText 2.1.1 + */ + public String getPostSymbol() { + return postSymbol; + } + + /** + * Sets the String that has to be added after a number or letter in the list symbol. + * @since iText 2.1.1 + * @param postSymbol the String that has to be added after a number or letter in the list symbol. + */ + public String PostSymbol { + set { + postSymbol = value; + } + get { + return postSymbol; + } + } + + /** + * Sets the String that has to be added before a number or letter in the list symbol. + * @since iText 2.1.1 + * @param preSymbol the String that has to be added before a number or letter in the list symbol. + */ + public String PreSymbol { + set { + preSymbol = value; + } + get { + return preSymbol; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/ListItem.cs b/iTechSharp/iTextSharp/text/ListItem.cs new file mode 100644 index 0000000..6df1365 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ListItem.cs @@ -0,0 +1,239 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text.factories; +/* + * $Id: ListItem.cs,v 1.11 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A ListItem is a Paragraph + /// that can be added to a List. + /// + /// + /// Example 1: + /// + /// List list = new List(true, 20); + /// list.Add(new ListItem("First line")); + /// list.Add(new ListItem("The second line is longer to see what happens once the end of the line is reached. Will it start on a new line?")); + /// list.Add(new ListItem("Third line")); + /// + /// + /// The result of this code looks like this: + ///
      + ///
    1. + /// First line + ///
    2. + ///
    3. + /// The second line is longer to see what happens once the end of the line is reached. Will it start on a new line? + ///
    4. + ///
    5. + /// Third line + ///
    6. + ///
    + /// + /// Example 2: + /// + /// List overview = new List(false, 10); + /// overview.Add(new ListItem("This is an item")); + /// overview.Add("This is another item"); + /// + /// + /// The result of this code looks like this: + ///
      + ///
    • + /// This is an item + ///
    • + ///
    • + /// This is another item + ///
    • + ///
    + ///
    + /// + /// + /// + public class ListItem : Paragraph { + + // membervariables + + /// this is the symbol that wil proceed the listitem. + private Chunk symbol; + + // constructors + + /// + /// Constructs a ListItem. + /// + public ListItem() : base() {} + + /// + /// Constructs a ListItem with a certain leading. + /// + /// the leading + public ListItem(float leading) : base(leading) {} + + /// + /// Constructs a ListItem with a certain Chunk. + /// + /// a Chunk + public ListItem(Chunk chunk) : base(chunk) {} + + /// + /// Constructs a ListItem with a certain string. + /// + /// a string + public ListItem(string str) : base(str) {} + + /// + /// Constructs a ListItem with a certain string + /// and a certain Font. + /// + /// a string + /// a string + public ListItem(string str, Font font) : base(str, font) {} + + /// + /// Constructs a ListItem with a certain Chunk + /// and a certain leading. + /// + /// the leading + /// a Chunk + public ListItem(float leading, Chunk chunk) : base(leading, chunk) {} + + /// + /// Constructs a ListItem with a certain string + /// and a certain leading. + /// + /// the leading + /// a string + public ListItem(float leading, string str) : base(leading, str) {} + + /** + * Constructs a ListItem with a certain leading, string + * and Font. + * + * @param leading the leading + * @param string a string + * @param font a Font + */ + /// + /// Constructs a ListItem with a certain leading, string + /// and Font. + /// + /// the leading + /// a string + /// a Font + public ListItem(float leading, string str, Font font) : base(leading, str, font) {} + + /// + /// Constructs a ListItem with a certain Phrase. + /// + /// a Phrase + public ListItem(Phrase phrase) : base(phrase) {} + + // implementation of the Element-methods + + /// + /// Gets the type of the text element. + /// + /// a type + public override int Type { + get { + return Element.LISTITEM; + } + } + + // methods + + // methods to retrieve information + + /// + /// Get/set the listsymbol. + /// + /// a Chunk + public Chunk ListSymbol { + get { + return symbol; + } + + set { + if (this.symbol == null) { + this.symbol = value; + if (this.symbol.Font.IsStandardFont()) { + this.symbol.Font = font; + } + } + } + } + + /// + /// Checks if a given tag corresponds with this object. + /// + /// the given tag + /// true if the tag corresponds + public new static bool IsTag(string tag) { + return ElementTags.LISTITEM.Equals(tag); + } + + /** + * Sets the indentation of this paragraph on the left side. + * + * @param indentation the new indentation + */ + public void SetIndentationLeft(float indentation, bool autoindent) { + if (autoindent) { + IndentationLeft = ListSymbol.GetWidthPoint(); + } + else { + IndentationLeft = indentation; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/MarkedObject.cs b/iTechSharp/iTextSharp/text/MarkedObject.cs new file mode 100644 index 0000000..f4885bd --- /dev/null +++ b/iTechSharp/iTextSharp/text/MarkedObject.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections; +using System.util; +/* + * $Id: MarkedObject.cs,v 1.4 2008/05/13 11:25:11 psoares33 Exp $ + * + * + * Copyright 2007 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2007 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2007 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + + /** + * Wrapper that allows to add properties to 'basic building block' objects. + * Before iText 1.5 every 'basic building block' implemented the MarkupAttributes interface. + * By setting attributes, you could add markup to the corresponding XML and/or HTML tag. + * This functionality was hardly used by anyone, so it was removed, and replaced by + * the MarkedObject functionality. + */ + + public class MarkedObject : IElement { + + /** The element that is wrapped in a MarkedObject. */ + protected internal IElement element; + + /** Contains extra markupAttributes */ + protected internal Properties markupAttributes = new Properties(); + + /** + * This constructor is for internal use only. + */ + protected MarkedObject() { + element = null; + } + + /** + * Creates a MarkedObject. + */ + public MarkedObject(IElement element) { + this.element = element; + } + + /** + * Gets all the chunks in this element. + * + * @return an ArrayList + */ + public virtual ArrayList Chunks { + get { + return element.Chunks; + } + } + + /** + * Processes the element by adding it (or the different parts) to an + * ElementListener. + * + * @param listener an ElementListener + * @return true if the element was processed successfully + */ + public virtual bool Process(IElementListener listener) { + try { + return listener.Add(element); + } + catch (DocumentException) { + return false; + } + } + + /** + * Gets the type of the text element. + * + * @return a type + */ + public virtual int Type { + get { + return Element.MARKED; + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return true; + } + + /** + * @return the markupAttributes + */ + public virtual Properties MarkupAttributes { + get { + return markupAttributes; + } + } + + public virtual void SetMarkupAttribute(String key, String value) { + markupAttributes.Add(key, value); + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/MarkedSection.cs b/iTechSharp/iTextSharp/text/MarkedSection.cs new file mode 100644 index 0000000..9acff78 --- /dev/null +++ b/iTechSharp/iTextSharp/text/MarkedSection.cs @@ -0,0 +1,297 @@ +using System; +using System.Collections; +using System.Text; +using System.util; +/* + * $Id: MarkedSection.cs,v 1.7 2008/05/13 11:25:12 psoares33 Exp $ + * + * + * Copyright 2007 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2007 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2007 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + + /** + * Wrapper that allows to add properties to a Chapter/Section object. + * Before iText 1.5 every 'basic building block' implemented the MarkupAttributes interface. + * By setting attributes, you could add markup to the corresponding XML and/or HTML tag. + * This functionality was hardly used by anyone, so it was removed, and replaced by + * the MarkedObject functionality. + */ + + public class MarkedSection : MarkedObject { + + /** This is the title of this section. */ + protected MarkedObject title = null; + + /** + * Creates a MarkedObject with a Section or Chapter object. + * @param section the marked section + */ + public MarkedSection(Section section) : base() { + if (section.Title != null) { + title = new MarkedObject(section.Title); + section.Title = null; + } + this.element = section; + } + + /** + * Adds a Paragraph, List or Table + * to this Section. + * + * @param index index at which the specified element is to be inserted + * @param o an object of type Paragraph, List or Table= + * @throws ClassCastException if the object is not a Paragraph, List or Table + */ + + public void Add(int index, Object o) { + ((Section)element).Add(index, o); + } + + /** + * Adds a Paragraph, List, Table or another Section + * to this Section. + * + * @param o an object of type Paragraph, List, Table or another Section + * @return a bool + * @throws ClassCastException if the object is not a Paragraph, List, Table or Section + */ + + public bool Add(Object o) { + return ((Section)element).Add(o); + } + + /** + * Processes the element by adding it (or the different parts) to an + * ElementListener. + * + * @param listener an ElementListener + * @return true if the element was processed successfully + */ + public override bool Process(IElementListener listener) { + try { + foreach (IElement element in ((Section)this.element)) { + listener.Add(element); + } + return true; + } + catch (DocumentException) { + return false; + } + } + + /** + * Adds a collection of Elements + * to this Section. + * + * @param collection a collection of Paragraphs, Lists and/or Tables + * @return true if the action succeeded, false if not. + * @throws ClassCastException if one of the objects isn't a Paragraph, List, Table + */ + + public bool AddAll(ICollection collection) { + return ((Section)element).AddAll(collection); + } + + /** + * Creates a Section, adds it to this Section and returns it. + * + * @param indentation the indentation of the new section + * @param numberDepth the numberDepth of the section + * @return a new Section object + */ + + public MarkedSection AddSection(float indentation, int numberDepth) { + MarkedSection section = ((Section)element).AddMarkedSection(); + section.Indentation = indentation; + section.NumberDepth = numberDepth; + return section; + } + + /** + * Creates a Section, adds it to this Section and returns it. + * + * @param indentation the indentation of the new section + * @return a new Section object + */ + + public MarkedSection AddSection(float indentation) { + MarkedSection section = ((Section)element).AddMarkedSection(); + section.Indentation = indentation; + return section; + } + + /** + * Creates a Section, add it to this Section and returns it. + * + * @param numberDepth the numberDepth of the section + * @return a new Section object + */ + public MarkedSection AddSection(int numberDepth) { + MarkedSection section = ((Section)element).AddMarkedSection(); + section.NumberDepth = numberDepth; + return section; + } + + /** + * Creates a Section, adds it to this Section and returns it. + * + * @return a new Section object + */ + public MarkedSection AddSection() { + return ((Section)element).AddMarkedSection(); + } + + // public methods + + /** + * Sets the title of this section. + * + * @param title the new title + */ + public MarkedObject Title { + set { + if (value.element is Paragraph) + this.title = value; + } + get { + Paragraph result = Section.ConstructTitle((Paragraph)title.element, ((Section)element).numbers, ((Section)element).NumberDepth, ((Section)element).NumberStyle); + MarkedObject mo = new MarkedObject(result); + mo.markupAttributes = title.MarkupAttributes; + return mo; + } + } + + /** + * Sets the depth of the sectionnumbers that will be shown preceding the title. + *

    + * If the numberdepth is 0, the sections will not be numbered. If the numberdepth + * is 1, the section will be numbered with their own number. If the numberdepth is + * higher (for instance x > 1), the numbers of x - 1 parents will be shown. + * + * @param numberDepth the new numberDepth + */ + public int NumberDepth { + set { + ((Section)element).NumberDepth = value; + } + } + + /** + * Sets the indentation of this Section on the left side. + * + * @param indentation the indentation + */ + public float IndentationLeft { + set { + ((Section)element).IndentationLeft = value; + } + } + + /** + * Sets the indentation of this Section on the right side. + * + * @param indentation the indentation + */ + + public float IndentationRight { + set { + ((Section)element).IndentationRight = value; + } + } + + /** + * Sets the indentation of the content of this Section. + * + * @param indentation the indentation + */ + public float Indentation { + set { + ((Section)element).Indentation = value; + } + } + + /** Setter for property bookmarkOpen. + * @param bookmarkOpen false if the bookmark children are not + * visible. + */ + public bool BookmarkOpen { + set { + ((Section)element).BookmarkOpen = value; + } + } + + /** + * Setter for property triggerNewPage. + * @param triggerNewPage true if a new page has to be triggered. + */ + public bool TriggerNewPage { + set { + ((Section)element).TriggerNewPage = value; + } + } + + /** + * Sets the bookmark title. The bookmark title is the same as the section title but + * can be changed with this method. + * @param bookmarkTitle the bookmark title + */ + public String BookmarkTitle { + set { + ((Section)element).BookmarkTitle = value; + } + } + + /** + * Adds a new page to the section. + * @since 2.1.1 + */ + public void NewPage() { + ((Section)element).NewPage(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/Meta.cs b/iTechSharp/iTextSharp/text/Meta.cs new file mode 100644 index 0000000..130bd75 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Meta.cs @@ -0,0 +1,234 @@ +using System; +using System.Text; +using System.Collections; +using System.util; + +/* + * $Id: Meta.cs,v 1.6 2008/05/13 11:25:12 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + ///

    + /// This is an Element that contains + /// some meta information about the document. + /// + /// + /// An object of type Meta can not be constructed by the user. + /// Userdefined meta information should be placed in a Header-object. + /// Meta is reserved for: Subject, Keywords, Author, Title, Producer + /// and Creationdate information. + /// + /// + /// + public class Meta : IElement { + + // membervariables + + /// This is the type of Meta-information this object contains. + private int type; + + /// This is the content of the Meta-information. + private StringBuilder content; + + // constructors + + /// + /// Constructs a Meta. + /// + /// the type of meta-information + /// the content + public Meta(int type, string content) { + this.type = type; + this.content = new StringBuilder(content); + } + + /// + /// Constructs a Meta. + /// + /// the tagname of the meta-information + /// the content + public Meta(string tag, string content) { + this.type = Meta.GetType(tag); + this.content = new StringBuilder(content); + } + + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to a + /// IElementListener. + /// + /// the IElementListener + /// true if the element was processed successfully + public bool Process(IElementListener listener) { + try { + return listener.Add(this); + } + catch (DocumentException) { + return false; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public int Type { + get { + return type; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public ArrayList Chunks { + get { + return new ArrayList(); + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return false; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return false; + } + + // methods + + /// + /// appends some text to this Meta. + /// + /// a string + /// a StringBuilder + public StringBuilder Append(string str) { + return content.Append(str); + } + + // methods to retrieve information + + /// + /// Returns the content of the meta information. + /// + /// a string + public string Content { + get { + return content.ToString(); + } + } + + /// + /// Returns the name of the meta information. + /// + /// a string + public virtual string Name { + get { + switch (type) { + case Element.SUBJECT: + return ElementTags.SUBJECT; + case Element.KEYWORDS: + return ElementTags.KEYWORDS; + case Element.AUTHOR: + return ElementTags.AUTHOR; + case Element.TITLE: + return ElementTags.TITLE; + case Element.PRODUCER: + return ElementTags.PRODUCER; + case Element.CREATIONDATE: + return ElementTags.CREATIONDATE; + default: + return ElementTags.UNKNOWN; + } + } + } + + /// + /// Returns the name of the meta information. + /// + /// name to match + /// a string + public static int GetType(string tag) { + if (ElementTags.SUBJECT.Equals(tag)) { + return Element.SUBJECT; + } + if (ElementTags.KEYWORDS.Equals(tag)) { + return Element.KEYWORDS; + } + if (ElementTags.AUTHOR.Equals(tag)) { + return Element.AUTHOR; + } + if (ElementTags.TITLE.Equals(tag)) { + return Element.TITLE; + } + if (ElementTags.PRODUCER.Equals(tag)) { + return Element.PRODUCER; + } + if (ElementTags.CREATIONDATE.Equals(tag)) { + return Element.CREATIONDATE; + } + return Element.HEADER; + } + + + public override string ToString() { + return base.ToString(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/PageSize.cs b/iTechSharp/iTextSharp/text/PageSize.cs new file mode 100644 index 0000000..749287f --- /dev/null +++ b/iTechSharp/iTextSharp/text/PageSize.cs @@ -0,0 +1,244 @@ +using System; + +/* + * $Id: PageSize.cs,v 1.9 2008/05/13 11:25:12 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// The PageSize-object contains a number of read only rectangles representing the most common paper sizes. + /// + /// + public class PageSize { + + // membervariables + + /** This is the letter format */ + public static readonly Rectangle LETTER = new RectangleReadOnly(612,792); + + /** This is the note format */ + public static readonly Rectangle NOTE = new RectangleReadOnly(540,720); + + /** This is the legal format */ + public static readonly Rectangle LEGAL = new RectangleReadOnly(612,1008); + + /** This is the tabloid format */ + public static readonly Rectangle TABLOID = new RectangleReadOnly(792,1224); + + /** This is the executive format */ + public static readonly Rectangle EXECUTIVE = new RectangleReadOnly(522,756); + + /** This is the postcard format */ + public static readonly Rectangle POSTCARD = new RectangleReadOnly(283,416); + + /** This is the a0 format */ + public static readonly Rectangle A0 = new RectangleReadOnly(2384,3370); + + /** This is the a1 format */ + public static readonly Rectangle A1 = new RectangleReadOnly(1684,2384); + + /** This is the a2 format */ + public static readonly Rectangle A2 = new RectangleReadOnly(1191,1684); + + /** This is the a3 format */ + public static readonly Rectangle A3 = new RectangleReadOnly(842,1191); + + /** This is the a4 format */ + public static readonly Rectangle A4 = new RectangleReadOnly(595,842); + + /** This is the a5 format */ + public static readonly Rectangle A5 = new RectangleReadOnly(420,595); + + /** This is the a6 format */ + public static readonly Rectangle A6 = new RectangleReadOnly(297,420); + + /** This is the a7 format */ + public static readonly Rectangle A7 = new RectangleReadOnly(210,297); + + /** This is the a8 format */ + public static readonly Rectangle A8 = new RectangleReadOnly(148,210); + + /** This is the a9 format */ + public static readonly Rectangle A9 = new RectangleReadOnly(105,148); + + /** This is the a10 format */ + public static readonly Rectangle A10 = new RectangleReadOnly(73,105); + + /** This is the b0 format */ + public static readonly Rectangle B0 = new RectangleReadOnly(2834,4008); + + /** This is the b1 format */ + public static readonly Rectangle B1 = new RectangleReadOnly(2004,2834); + + /** This is the b2 format */ + public static readonly Rectangle B2 = new RectangleReadOnly(1417,2004); + + /** This is the b3 format */ + public static readonly Rectangle B3 = new RectangleReadOnly(1000,1417); + + /** This is the b4 format */ + public static readonly Rectangle B4 = new RectangleReadOnly(708,1000); + + /** This is the b5 format */ + public static readonly Rectangle B5 = new RectangleReadOnly(498,708); + + /** This is the b6 format */ + public static readonly Rectangle B6 = new RectangleReadOnly(354,498); + + /** This is the b7 format */ + public static readonly Rectangle B7 = new RectangleReadOnly(249,354); + + /** This is the b8 format */ + public static readonly Rectangle B8 = new RectangleReadOnly(175,249); + + /** This is the b9 format */ + public static readonly Rectangle B9 = new RectangleReadOnly(124,175); + + /** This is the b10 format */ + public static readonly Rectangle B10 = new RectangleReadOnly(87,124); + + /** This is the archE format */ + public static readonly Rectangle ARCH_E = new RectangleReadOnly(2592,3456); + + /** This is the archD format */ + public static readonly Rectangle ARCH_D = new RectangleReadOnly(1728,2592); + + /** This is the archC format */ + public static readonly Rectangle ARCH_C = new RectangleReadOnly(1296,1728); + + /** This is the archB format */ + public static readonly Rectangle ARCH_B = new RectangleReadOnly(864,1296); + + /** This is the archA format */ + public static readonly Rectangle ARCH_A = new RectangleReadOnly(648,864); + + /** This is the American Foolscap format */ + public static readonly Rectangle FLSA = new RectangleReadOnly(612,936); + + /** This is the European Foolscap format */ + public static readonly Rectangle FLSE = new RectangleReadOnly(648,936); + + /** This is the halfletter format */ + public static readonly Rectangle HALFLETTER = new RectangleReadOnly(396,612); + + /** This is the 11x17 format */ + public static readonly Rectangle _11X17 = new RectangleReadOnly(792,1224); + + /** This is the ISO 7810 ID-1 format (85.60 x 53.98 mm or 3.370 x 2.125 inch) */ + public static readonly Rectangle ID_1 = new RectangleReadOnly(242.65f,153); + + /** This is the ISO 7810 ID-2 format (A7 rotated) */ + public static readonly Rectangle ID_2 = new RectangleReadOnly(297,210); + + /** This is the ISO 7810 ID-3 format (B7 rotated) */ + public static readonly Rectangle ID_3 = new RectangleReadOnly(354,249); + + /** This is the ledger format */ + public static readonly Rectangle LEDGER = new RectangleReadOnly(1224,792); + + /** This is the Crown Quarto format */ + public static readonly Rectangle CROWN_QUARTO = new RectangleReadOnly(535,697); + + /** This is the Large Crown Quarto format */ + public static readonly Rectangle LARGE_CROWN_QUARTO = new RectangleReadOnly(569,731); + + /** This is the Demy Quarto format. */ + public static readonly Rectangle DEMY_QUARTO = new RectangleReadOnly(620,782); + + /** This is the Royal Quarto format. */ + public static readonly Rectangle ROYAL_QUARTO = new RectangleReadOnly(671,884); + + /** This is the Crown Octavo format */ + public static readonly Rectangle CROWN_OCTAVO = new RectangleReadOnly(348,527); + + /** This is the Large Crown Octavo format */ + public static readonly Rectangle LARGE_CROWN_OCTAVO = new RectangleReadOnly(365,561); + + /** This is the Demy Octavo format */ + public static readonly Rectangle DEMY_OCTAVO = new RectangleReadOnly(391,612); + + /** This is the Royal Octavo format. */ + public static readonly Rectangle ROYAL_OCTAVO = new RectangleReadOnly(442,663); + + /** This is the small paperback format. */ + public static readonly Rectangle SMALL_PAPERBACK = new RectangleReadOnly(314,504); + + /** This is the Pengiun small paperback format. */ + public static readonly Rectangle PENGUIN_SMALL_PAPERBACK = new RectangleReadOnly(314,513); + + /** This is the Penguin large paparback format. */ + public static readonly Rectangle PENGUIN_LARGE_PAPERBACK = new RectangleReadOnly(365,561); + + /** + * This method returns a Rectangle based on a String. + * Possible values are the the names of a constant in this class + * (for instance "A4", "LETTER",...) or a value like "595 842" + */ + public static Rectangle GetRectangle(String name) { + name = name.Trim().ToUpper(System.Globalization.CultureInfo.InvariantCulture); + int pos = name.IndexOf(' '); + if (pos == -1) { + try { + return (Rectangle)typeof(PageSize).GetField(name).GetValue(null); + } catch (Exception) { + throw new ArgumentException("Can't find page size " + name); + } + } + else { + try { + String width = name.Substring(0, pos); + String height = name.Substring(pos + 1); + return new Rectangle(float.Parse(width, System.Globalization.NumberFormatInfo.InvariantInfo), float.Parse(height, System.Globalization.NumberFormatInfo.InvariantInfo)); + } catch(Exception e) { + throw new ArgumentException(name + " is not a valid page size format: " + e.Message); + } + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/Paragraph.cs b/iTechSharp/iTextSharp/text/Paragraph.cs new file mode 100644 index 0000000..77047f9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Paragraph.cs @@ -0,0 +1,408 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text.factories; + +/* + * $Id: Paragraph.cs,v 1.13 2008/05/13 11:25:12 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A Paragraph is a series of Chunks and/or Phrases. + /// + /// + /// A Paragraph has the same qualities of a Phrase, but also + /// some additional layout-parameters: + ///
      + ///
    • the indentation + ///
    • the alignment of the text + ///
    + ///
    + /// + /// + /// Paragraph p = new Paragraph("This is a paragraph", + /// FontFactory.GetFont(FontFactory.HELVETICA, 18, Font.BOLDITALIC, new Color(0, 0, 255))); + /// + /// + /// + /// + /// + public class Paragraph : Phrase { + + // membervariables + + /// The alignment of the text. + protected int alignment = Element.ALIGN_UNDEFINED; + + /** The text leading that is multiplied by the biggest font size in the line. */ + protected float multipliedLeading = 0; + + /// The indentation of this paragraph on the left side. + protected float indentationLeft; + + /// The indentation of this paragraph on the right side. + protected float indentationRight; + + /** + * Holds value of property firstLineIndent. + */ + private float firstLineIndent = 0; + + /** The spacing before the paragraph. */ + protected float spacingBefore; + + /** The spacing after the paragraph. */ + protected float spacingAfter; + + + /** + * Holds value of property extraParagraphSpace. + */ + private float extraParagraphSpace = 0; + + /// Does the paragraph has to be kept together on 1 page. + protected bool keeptogether = false; + + // constructors + + /// + /// Constructs a Paragraph. + /// + public Paragraph() : base() {} + + /// + /// Constructs a Paragraph with a certain leading. + /// + /// the leading + public Paragraph(float leading) : base(leading) {} + + /// + /// Constructs a Paragraph with a certain Chunk. + /// + /// a Chunk + public Paragraph(Chunk chunk) : base(chunk) {} + + /// + /// Constructs a Paragraph with a certain Chunk + /// and a certain leading. + /// + /// the leading + /// a Chunk + public Paragraph(float leading, Chunk chunk) : base(leading, chunk) {} + + /// + /// Constructs a Paragraph with a certain string. + /// + /// a string + public Paragraph(string str) : base(str) {} + + /// + /// Constructs a Paragraph with a certain string + /// and a certain Font. + /// + /// a string + /// a Font + public Paragraph(string str, Font font) : base(str, font) {} + + /// + /// Constructs a Paragraph with a certain string + /// and a certain leading. + /// + /// the leading + /// a string + public Paragraph(float leading, string str) : base(leading, str) {} + + /// + /// Constructs a Paragraph with a certain leading, string + /// and Font. + /// + /// the leading + /// a string + /// a Font + public Paragraph(float leading, string str, Font font) : base(leading, str, font) {} + + /// + /// Constructs a Paragraph with a certain Phrase. + /// + /// a Phrase + public Paragraph(Phrase phrase) : base(phrase) { + if (phrase is Paragraph) { + Paragraph p = (Paragraph)phrase; + Alignment = p.Alignment; + ExtraParagraphSpace = p.ExtraParagraphSpace; + FirstLineIndent = p.FirstLineIndent; + IndentationLeft = p.IndentationLeft; + IndentationRight = p.IndentationRight; + SpacingAfter = p.SpacingAfter; + SpacingBefore = p.SpacingBefore; + } + } + + // implementation of the Element-methods + + /// + /// Gets the type of the text element. + /// + /// a type + public override int Type { + get { + return Element.PARAGRAPH; + } + } + + // methods + + /// + /// Adds an Object to the Paragraph. + /// + /// the object to add + /// a bool + public override bool Add(Object o) { + if (o is List) { + List list = (List) o; + list.IndentationLeft = list.IndentationLeft + indentationLeft; + list.IndentationRight = indentationRight; + base.Add(list); + return true; + } + else if (o is Image) { + base.AddSpecial((Image) o); + return true; + } + else if (o is Paragraph) { + base.Add(o); + base.Add(Chunk.NEWLINE); + return true; + } + base.Add(o); + return true; + } + + // setting the membervariables + + /// + /// Sets the alignment of this paragraph. + /// + /// the new alignment as a string + public void SetAlignment(string alignment) { + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_CENTER)) { + this.alignment = Element.ALIGN_CENTER; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_RIGHT)) { + this.alignment = Element.ALIGN_RIGHT; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_JUSTIFIED)) { + this.alignment = Element.ALIGN_JUSTIFIED; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_JUSTIFIED_ALL)) { + this.alignment = Element.ALIGN_JUSTIFIED_ALL; + return; + } + this.alignment = Element.ALIGN_LEFT; + } + + public override float Leading { + set { + this.leading = value; + this.multipliedLeading = 0; + } + } + + /** + * Sets the leading fixed and variable. The resultant leading will be + * fixedLeading+multipliedLeading*maxFontSize where maxFontSize is the + * size of the bigest font in the line. + * @param fixedLeading the fixed leading + * @param multipliedLeading the variable leading + */ + public void SetLeading(float fixedLeading, float multipliedLeading) { + this.leading = fixedLeading; + this.multipliedLeading = multipliedLeading; + } + + /** + * Sets the variable leading. The resultant leading will be + * multipliedLeading*maxFontSize where maxFontSize is the + * size of the bigest font in the line. + * @param multipliedLeading the variable leading + */ + public float MultipliedLeading { + get { + return this.multipliedLeading; + } + set { + this.leading = 0; + this.multipliedLeading = value; + } + } + + + /// + /// Get/set the alignment of this paragraph. + /// + /// a integer + public int Alignment{ + get { + return alignment; + } + set { + this.alignment = value; + } + } + + /// + /// Get/set the indentation of this paragraph on the left side. + /// + /// a float + public float IndentationLeft { + get { + return indentationLeft; + } + + set { + this.indentationLeft = value; + } + } + + /// + /// Get/set the indentation of this paragraph on the right side. + /// + /// a float + public float IndentationRight { + get { + return indentationRight; + } + + set { + this.indentationRight = value; + } + } + + /// + /// Checks if a given tag corresponds with this object. + /// + /// the given tag + /// true if the tag corresponds + public new static bool IsTag(string tag) { + return ElementTags.PARAGRAPH.Equals(tag); + } + + public float SpacingBefore { + get { + return spacingBefore; + } + set { + spacingBefore = value; + } + } + + public float SpacingAfter { + get { + return spacingAfter; + } + set { + spacingAfter = value; + } + } + + /// + /// Set/get if this paragraph has to be kept together on one page. + /// + /// a bool + public bool KeepTogether { + get { + return keeptogether; + } + set { + this.keeptogether = value; + } + } + + /** + * Gets the total leading. + * This method is based on the assumption that the + * font of the Paragraph is the font of all the elements + * that make part of the paragraph. This isn't necessarily + * true. + * @return the total leading (fixed and multiplied) + */ + public float TotalLeading { + get { + float m = font == null ? + Font.DEFAULTSIZE * multipliedLeading : font.GetCalculatedLeading(multipliedLeading); + if (m > 0 && !HasLeading()) { + return m; + } + return Leading + m; + } + } + + public float FirstLineIndent { + get { + return this.firstLineIndent; + } + set { + this.firstLineIndent = value; + } + } + + public float ExtraParagraphSpace { + get { + return this.extraParagraphSpace; + } + set { + this.extraParagraphSpace = value; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/Phrase.cs b/iTechSharp/iTextSharp/text/Phrase.cs new file mode 100644 index 0000000..b4124e9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Phrase.cs @@ -0,0 +1,509 @@ +using System; +using System.Text; +using System.Collections; +using System.util; +using iTextSharp.text.html; +using iTextSharp.text.pdf; +using iTextSharp.text.factories; + +namespace iTextSharp.text { + /// + /// A Phrase is a series of Chunks. + /// + /// + /// A Phrase has a main Font, but some chunks + /// within the phrase can have a Font that differs from the + /// main Font. All the Chunks in a Phrase + /// have the same leading. + /// + /// + /// + /// // When no parameters are passed, the default leading = 16 + /// Phrase phrase0 = new Phrase(); + /// Phrase phrase1 = new Phrase("this is a phrase"); + /// // In this example the leading is passed as a parameter + /// Phrase phrase2 = new Phrase(16, "this is a phrase with leading 16"); + /// // When a Font is passed (explicitely or embedded in a chunk), the default leading = 1.5 * size of the font + /// Phrase phrase3 = new Phrase("this is a phrase with a red, normal font Courier, size 12", FontFactory.GetFont(FontFactory.COURIER, 12, Font.NORMAL, new Color(255, 0, 0))); + /// Phrase phrase4 = new Phrase(new Chunk("this is a phrase")); + /// Phrase phrase5 = new Phrase(18, new Chunk("this is a phrase", FontFactory.GetFont(FontFactory.HELVETICA, 16, Font.BOLD, new Color(255, 0, 0))); + /// + /// + public class Phrase : ArrayList, ITextElementArray { + + // membervariables + + /// This is the leading of this phrase. + protected Single leading = Single.NaN; + + /// This is the font of this phrase. + protected Font font; + + /** Null, unless the Phrase has to be hyphenated. + * @since 2.1.2 + */ + protected IHyphenationEvent hyphenation = null; + + // constructors + + /// + /// Constructs a Phrase without specifying a leading. + /// + /// + /// Has nine overloads. + /// + public Phrase() : this(16) {} + + /** + * Copy constructor for Phrase. + */ + public Phrase(Phrase phrase) : base() { + this.AddAll(phrase); + leading = phrase.Leading; + font = phrase.Font; + hyphenation = phrase.hyphenation; + } + + /// + /// Constructs a Phrase with a certain leading. + /// + /// the leading + public Phrase(float leading) { + this.leading = leading; + font = new Font(); + } + + /// + /// Constructs a Phrase with a certain Chunk. + /// + /// a Chunk + public Phrase(Chunk chunk) { + base.Add(chunk); + font = chunk.Font; + hyphenation = chunk.GetHyphenation(); + } + + /// + /// Constructs a Phrase with a certain Chunk and a certain leading. + /// + /// the leading + /// a Chunk + public Phrase(float leading, Chunk chunk) { + this.leading = leading; + base.Add(chunk); + font = chunk.Font; + hyphenation = chunk.GetHyphenation(); + } + + /// + /// Constructs a Phrase with a certain string. + /// + /// a string + public Phrase(string str) : this(float.NaN, str, new Font()) {} + + /// + /// Constructs a Phrase with a certain string and a certain Font. + /// + /// a string + /// a Font + public Phrase(string str, Font font) : this(float.NaN, str, font) { + } + + /// + /// Constructs a Phrase with a certain leading and a certain string. + /// + /// the leading + /// a string + public Phrase(float leading, string str) : this(leading, str, new Font()) {} + + public Phrase(float leading, string str, Font font) { + this.leading = leading; + this.font = font; + /* bugfix by August Detlefsen */ + if (str != null && str.Length != 0) { + base.Add(new Chunk(str, font)); + } + } + + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// . + /// + /// an IElementListener + /// true if the element was processed successfully + public virtual bool Process(IElementListener listener) { + try { + foreach (IElement ele in this) { + listener.Add(ele); + } + return true; + } + catch (DocumentException) { + return false; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public virtual int Type { + get { + return Element.PHRASE; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public virtual ArrayList Chunks { + get { + ArrayList tmp = new ArrayList(); + foreach (IElement ele in this) { + tmp.AddRange(ele.Chunks); + } + return tmp; + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return true; + } + + // overriding some of the ArrayList-methods + + /// + /// Adds a Chunk, an Anchor or another Phrase + /// to this Phrase. + /// + /// index at which the specified element is to be inserted + /// an object of type Chunk, Anchor, or Phrase + public virtual void Add(int index, Object o) { + if (o == null) return; + try { + IElement element = (IElement) o; + if (element.Type == Element.CHUNK) { + Chunk chunk = (Chunk)element; + if (!font.IsStandardFont()) { + chunk.Font = font.Difference(chunk.Font); + } + if (hyphenation != null) { + chunk.SetHyphenation(hyphenation); + } + base.Insert(index, chunk); + } + else if (element.Type == Element.PHRASE || + element.Type == Element.ANCHOR || + element.Type == Element.ANNOTATION || + element.Type == Element.TABLE || // line added by David Freels + element.Type == Element.YMARK || + element.Type == Element.MARKED) { + base.Insert(index, element); + } + else { + throw new Exception(element.Type.ToString()); + } + } + catch (Exception cce) { + throw new Exception("Insertion of illegal Element: " + cce.Message); + } + } + + /// + /// Adds a Chunk, Anchor or another Phrase + /// to this Phrase. + /// + /// an object of type Chunk, Anchor or Phrase + /// a bool + public virtual new bool Add(Object o) { + if (o == null) return false; + if (o is string) { + base.Add(new Chunk((string) o, font)); + return true; + } + if (o is IRtfElementInterface) { + base.Add(o); + return true; + } + try { + IElement element = (IElement) o; + switch (element.Type) { + case Element.CHUNK: + return AddChunk((Chunk) o); + case Element.PHRASE: + case Element.PARAGRAPH: + Phrase phrase = (Phrase) o; + bool success = true; + foreach (IElement e in phrase) { + if (e is Chunk) { + success &= AddChunk((Chunk)e); + } + else { + success &= this.Add(e); + } + } + return success; + case Element.MARKED: + case Element.ANCHOR: + case Element.ANNOTATION: + case Element.TABLE: // case added by David Freels + case Element.PTABLE: // case added by Karen Vardanyan + // This will only work for PDF!!! Not for RTF/HTML + case Element.LIST: + case Element.YMARK: + base.Add(o); + return true; + default: + throw new Exception(element.Type.ToString()); + } + } + catch (Exception cce) { + throw new Exception("Insertion of illegal Element: " + cce.Message); + } + } + + /// + /// Adds a collection of Chunks + /// to this Phrase. + /// + /// a collection of Chunks, Anchors and Phrases. + /// true if the action succeeded, false if not. + public bool AddAll(ICollection collection) { + foreach (object itm in collection) { + this.Add(itm); + } + return true; + } + + /// + /// Adds a Chunk. + /// + /// + /// This method is a hack to solve a problem I had with phrases that were split between chunks + /// in the wrong place. + /// + /// a Chunk + /// a bool + protected bool AddChunk(Chunk chunk) { + Font f = chunk.Font; + String c = chunk.Content; + if (font != null && !font.IsStandardFont()) { + f = font.Difference(chunk.Font); + } + if (Count > 0 && !chunk.HasAttributes()) { + try { + Chunk previous = (Chunk) this[Count - 1]; + if (!previous.HasAttributes() + && (f == null + || f.CompareTo(previous.Font) == 0) + && previous.Font.CompareTo(f) == 0 + && !"".Equals(previous.Content.Trim()) + && !"".Equals(c.Trim())) { + previous.Append(c); + return true; + } + } + catch { + } + } + Chunk newChunk = new Chunk(c, f); + newChunk.Attributes = chunk.Attributes; + if (newChunk.GetHyphenation() == null) { + newChunk.SetHyphenation(hyphenation); + } + base.Add(newChunk); + return true; + } + + /// + /// Adds a Object to the Paragraph. + /// + /// the object to add. + public void AddSpecial(Object obj) { + base.Add(obj); + } + + // methods + + // methods to retrieve information + + /// + /// Checks is this Phrase contains no or 1 empty Chunk. + /// + /// + /// false if the Phrase + /// contains more than one or more non-emptyChunks. + /// + public bool IsEmpty() { + switch (Count) { + case 0: + return true; + case 1: + IElement element = (IElement) this[0]; + if (element.Type == Element.CHUNK && ((Chunk) element).IsEmpty()) { + return true; + } + return false; + default: + return false; + } + } + + public bool HasLeading() { + if (float.IsNaN(leading)) { + return false; + } + return true; + } + + /// + /// Gets/sets the leading of this phrase. + /// + /// the linespacing + public virtual float Leading { + get { + if (float.IsNaN(leading) && font != null) { + return font.GetCalculatedLeading(1.5f); + } + return leading; + } + + set { + this.leading = value; + } + } + + /// + /// Gets the font of the first Chunk that appears in this Phrase. + /// + /// a Font + public Font Font { + get { + return font; + } + set { + font = value; + } + } + + /** + * Returns the content as a String object. + * This method differs from toString because toString will return an ArrayList with the toString value of the Chunks in this Phrase. + */ + public String Content { + get { + StringBuilder buf = new StringBuilder(); + foreach (object obj in Chunks) + buf.Append(obj.ToString()); + return buf.ToString(); + } + } + /// + /// Checks if a given tag corresponds with this object. + /// + /// the given tag + /// true if the tag corresponds + public static bool IsTag(string tag) { + return ElementTags.PHRASE.Equals(tag); + } + + public override string ToString() { + return base.ToString(); + } + + /** + * Setter/getter for the hyphenation. + * @param hyphenation a HyphenationEvent instance + * @since 2.1.2 + */ + public IHyphenationEvent Hyphenation { + set { + hyphenation = value; + } + get { + return hyphenation; + } + } + + + // kept for historical reasons; people should use FontSelector + // eligable for deprecation, but the methods are mentioned in the book p277. + + /** + * Constructs a Phrase that can be used in the static GetInstance() method. + * @param dummy a dummy parameter + */ + private Phrase(bool dummy) { + } + + /** + * Gets a special kind of Phrase that changes some characters into corresponding symbols. + * @param string + * @return a newly constructed Phrase + */ + public static Phrase GetInstance(String str) { + return GetInstance(16, str, new Font()); + } + + /** + * Gets a special kind of Phrase that changes some characters into corresponding symbols. + * @param leading + * @param string + * @return a newly constructed Phrase + */ + public static Phrase GetInstance(int leading, String str) { + return GetInstance(leading, str, new Font()); + } + + /** + * Gets a special kind of Phrase that changes some characters into corresponding symbols. + * @param leading + * @param string + * @param font + * @return a newly constructed Phrase + */ + public static Phrase GetInstance(int leading, String str, Font font) { + Phrase p = new Phrase(true); + p.Leading = leading; + p.font = font; + if (font.Family != Font.SYMBOL && font.Family != Font.ZAPFDINGBATS && font.BaseFont == null) { + int index; + while ((index = SpecialSymbol.Index(str)) > -1) { + if (index > 0) { + String firstPart = str.Substring(0, index); + ((ArrayList)p).Add(new Chunk(firstPart, font)); + str = str.Substring(index); + } + Font symbol = new Font(Font.SYMBOL, font.Size, font.Style, font.Color); + StringBuilder buf = new StringBuilder(); + buf.Append(SpecialSymbol.GetCorrespondingSymbol(str[0])); + str = str.Substring(1); + while (SpecialSymbol.Index(str) == 0) { + buf.Append(SpecialSymbol.GetCorrespondingSymbol(str[0])); + str = str.Substring(1); + } + ((ArrayList)p).Add(new Chunk(buf.ToString(), symbol)); + } + } + if (str != null && str.Length != 0) { + ((ArrayList)p).Add(new Chunk(str, font)); + } + return p; + } + } +} diff --git a/iTechSharp/iTextSharp/text/Rectangle.cs b/iTechSharp/iTextSharp/text/Rectangle.cs new file mode 100644 index 0000000..2663eef --- /dev/null +++ b/iTechSharp/iTextSharp/text/Rectangle.cs @@ -0,0 +1,733 @@ +using System; +using System.Collections; +using System.Text; +using System.util; +using iTextSharp.text.pdf; + +/* + * $Id: Rectangle.cs,v 1.18 2008/05/13 11:25:12 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A Rectangle is the representation of a geometric figure. + /// + /// + /// + /// + /// + public class Rectangle : Element, IElement { + + // static membervariables (concerning the presence of borders) + + /// This is the value that will be used as undefined. + public const int UNDEFINED = -1; + + /// This represents one side of the border of the Rectangle. + public const int TOP_BORDER = 1; + + /// This represents one side of the border of the Rectangle. + public const int BOTTOM_BORDER = 2; + + /// This represents one side of the border of the Rectangle. + public const int LEFT_BORDER = 4; + + /// This represents one side of the border of the Rectangle. + public const int RIGHT_BORDER = 8; + + /// This represents a rectangle without borders. + public const int NO_BORDER = 0; + + /// This represents a type of border. + public const int BOX = TOP_BORDER + BOTTOM_BORDER + LEFT_BORDER + RIGHT_BORDER; + + // membervariables + + /// the lower left x-coordinate. + protected float llx; + + /// the lower left y-coordinate. + protected float lly; + + /// the upper right x-coordinate. + protected float urx; + + /// the upper right y-coordinate. + protected float ury; + + /// This represents the status of the 4 sides of the rectangle. + protected int border = UNDEFINED; + + /// This is the width of the border around this rectangle. + protected float borderWidth = UNDEFINED; + + /// This is the color of the border of this rectangle. + protected Color borderColor = null; + + /** The color of the left border of this rectangle. */ + protected Color borderColorLeft = null; + + /** The color of the right border of this rectangle. */ + protected Color borderColorRight = null; + + /** The color of the top border of this rectangle. */ + protected Color borderColorTop = null; + + /** The color of the bottom border of this rectangle. */ + protected Color borderColorBottom = null; + + /** The width of the left border of this rectangle. */ + protected float borderWidthLeft = UNDEFINED; + + /** The width of the right border of this rectangle. */ + protected float borderWidthRight = UNDEFINED; + + /** The width of the top border of this rectangle. */ + protected float borderWidthTop = UNDEFINED; + + /** The width of the bottom border of this rectangle. */ + protected float borderWidthBottom = UNDEFINED; + + /** Whether variable width borders are used. */ + protected bool useVariableBorders = false; + + /// This is the color of the background of this rectangle. + protected Color backgroundColor = null; + + /// This is the rotation value of this rectangle. + protected int rotation = 0; + + // constructors + + /// + /// Constructs a Rectangle-object. + /// + /// lower left x + /// lower left y + /// upper right x + /// upper right y + public Rectangle(float llx, float lly, float urx, float ury) { + this.llx = llx; + this.lly = lly; + this.urx = urx; + this.ury = ury; + } + + /// + /// Constructs a Rectangle-object starting from the origin (0, 0). + /// + /// upper right x + /// upper right y + public Rectangle(float urx, float ury) : this(0, 0, urx, ury) {} + + /// + /// Constructs a Rectangle-object. + /// + /// another Rectangle + public Rectangle(Rectangle rect) : this(rect.llx, rect.lly, rect.urx, rect.ury) { + CloneNonPositionParameters(rect); + } + + /** + * Copies all of the parameters from a Rectangle object + * except the position. + * + * @param rect + * Rectangle to copy from + */ + + public virtual void CloneNonPositionParameters(Rectangle rect) { + this.rotation = rect.rotation; + this.border = rect.border; + this.borderWidth = rect.borderWidth; + this.borderColor = rect.borderColor; + this.backgroundColor = rect.backgroundColor; + this.borderColorLeft = rect.borderColorLeft; + this.borderColorRight = rect.borderColorRight; + this.borderColorTop = rect.borderColorTop; + this.borderColorBottom = rect.borderColorBottom; + this.borderWidthLeft = rect.borderWidthLeft; + this.borderWidthRight = rect.borderWidthRight; + this.borderWidthTop = rect.borderWidthTop; + this.borderWidthBottom = rect.borderWidthBottom; + this.useVariableBorders = rect.useVariableBorders; + } + + /** + * Copies all of the parameters from a Rectangle object + * except the position. + * + * @param rect + * Rectangle to copy from + */ + + public virtual void SoftCloneNonPositionParameters(Rectangle rect) { + if (rect.rotation != 0) + this.rotation = rect.rotation; + if (rect.border != UNDEFINED) + this.border = rect.border; + if (rect.borderWidth != UNDEFINED) + this.borderWidth = rect.borderWidth; + if (rect.borderColor != null) + this.borderColor = rect.borderColor; + if (rect.backgroundColor != null) + this.backgroundColor = rect.backgroundColor; + if (rect.borderColorLeft != null) + this.borderColorLeft = rect.borderColorLeft; + if (rect.borderColorRight != null) + this.borderColorRight = rect.borderColorRight; + if (rect.borderColorTop != null) + this.borderColorTop = rect.borderColorTop; + if (rect.borderColorBottom != null) + this.borderColorBottom = rect.borderColorBottom; + if (rect.borderWidthLeft != UNDEFINED) + this.borderWidthLeft = rect.borderWidthLeft; + if (rect.borderWidthRight != UNDEFINED) + this.borderWidthRight = rect.borderWidthRight; + if (rect.borderWidthTop != UNDEFINED) + this.borderWidthTop = rect.borderWidthTop; + if (rect.borderWidthBottom != UNDEFINED) + this.borderWidthBottom = rect.borderWidthBottom; + if (useVariableBorders) + this.useVariableBorders = rect.useVariableBorders; + } + + // implementation of the Element interface + + /// + /// Processes the element by adding it (or the different parts) to an + /// IElementListener. + /// + /// an IElementListener + /// true if the element was processed successfully + public virtual bool Process(IElementListener listener) { + try { + return listener.Add(this); + } + catch (DocumentException) { + return false; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public virtual int Type { + get { + return Element.RECTANGLE; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public virtual ArrayList Chunks { + get { + return new ArrayList(); + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public virtual bool IsNestable() { + return false; + } + + // methods + + /** + * Switches lowerleft with upperright + */ + public virtual void Normalize() { + if (llx > urx) { + float a = llx; + llx = urx; + urx = a; + } + if (lly > ury) { + float a = lly; + lly = ury; + ury = a; + } + } + + /// + /// Gets a Rectangle that is altered to fit on the page. + /// + /// the top position + /// the bottom position + /// a Rectangle + public Rectangle GetRectangle(float top, float bottom) { + Rectangle tmp = new Rectangle(this); + if (this.Top > top) { + tmp.Top = top; + tmp.Border = border - (border & TOP_BORDER); + } + if (Bottom < bottom) { + tmp.Bottom = bottom; + tmp.Border = border - (border & BOTTOM_BORDER); + } + return tmp; + } + + /// + /// Swaps the values of urx and ury and of lly and llx in order to rotate the rectangle. + /// + /// a Rectangle + public Rectangle Rotate() { + Rectangle rect = new Rectangle(lly, llx, ury, urx); + rect.rotation = rotation + 90; + rect.rotation %= 360; + return rect; + } + + // methods to set the membervariables + + /// + /// Get/set the upper right y-coordinate. + /// + /// a float + public virtual float Top { + get { + return ury; + } + + set { + ury = value; + } + } + + /** + * Enables the border on the specified side. + * + * @param side + * the side to enable. One of LEFT, RIGHT, TOP, BOTTOM + * + */ + public virtual void EnableBorderSide(int side) { + if (border == UNDEFINED) { + border = 0; + } + border |= side; + } + + /** + * Disables the border on the specified side. + * + * @param side + * the side to disable. One of LEFT, RIGHT, TOP, BOTTOM + * + */ + public virtual void DisableBorderSide(int side) { + if (border == UNDEFINED) { + border = 0; + } + border &= ~side; + } + + + /// + /// Get/set the border + /// + /// a int + public virtual int Border { + get { + return this.border; + } + + set { + border = value; + } + } + + /// + /// Get/set the grayscale of the rectangle. + /// + /// a float + public virtual float GrayFill { + get { + if (backgroundColor is GrayColor) + return ((GrayColor)backgroundColor).Gray; + else + return 0; + } + set { + backgroundColor = new GrayColor(value); } + } + + // methods to get the membervariables + + /// + /// Get/set the lower left x-coordinate. + /// + /// a float + public virtual float Left { + get { + return llx; + } + + set { + llx = value; + } + } + + /// + /// Get/set the upper right x-coordinate. + /// + /// a float + public virtual float Right { + get { + return urx; + } + + set { + urx = value; + } + } + + /// + /// Get/set the lower left y-coordinate. + /// + /// a float + public virtual float Bottom { + get { + return lly; + } + set { + lly = value; + } + } + + public virtual Color BorderColorBottom { + get { + if (borderColorBottom == null) return borderColor; + return borderColorBottom; + } + set { + borderColorBottom = value; + } + } + + public virtual Color BorderColorTop { + get { + if (borderColorTop == null) return borderColor; + return borderColorTop; + } + set { + borderColorTop = value; + } + } + + public virtual Color BorderColorLeft { + get { + if (borderColorLeft == null) return borderColor; + return borderColorLeft; + } + set { + borderColorLeft = value; + } + } + + public virtual Color BorderColorRight { + get { + if (borderColorRight == null) return borderColor; + return borderColorRight; + } + set { + borderColorRight = value; + } + } + + /// + /// Returns the lower left x-coordinate, considering a given margin. + /// + /// a margin + /// the lower left x-coordinate + public virtual float GetLeft(float margin) { + return llx + margin; + } + + /// + /// Returns the upper right x-coordinate, considering a given margin. + /// + /// a margin + /// the upper right x-coordinate + public virtual float GetRight(float margin) { + return urx - margin; + } + + /// + /// Returns the upper right y-coordinate, considering a given margin. + /// + /// a margin + /// the upper right y-coordinate + public virtual float GetTop(float margin) { + return ury - margin; + } + + /// + /// Returns the lower left y-coordinate, considering a given margin. + /// + /// a margin + /// the lower left y-coordinate + public virtual float GetBottom(float margin) { + return lly + margin; + } + + /// + /// Returns the width of the rectangle. + /// + /// a width + public virtual float Width { + get { + return urx - llx; + } + set { + throw new InvalidOperationException("The width cannot be set."); + } + } + + /// + /// Returns the height of the rectangle. + /// + /// a height + public float Height { + get { + return ury - lly; + } + } + + /// + /// Indicates if the table has borders. + /// + /// a bool + public bool HasBorders() { + return (border > 0) + && ((borderWidth > 0) || (borderWidthLeft > 0) + || (borderWidthRight > 0) || (borderWidthTop > 0) || (borderWidthBottom > 0)); + } + + /// + /// Indicates if the table has a some type of border. + /// + /// the type of border + /// a bool + public bool HasBorder(int type) { + return border != UNDEFINED && (border & type) == type; + } + + /// + /// Get/set the borderwidth. + /// + /// a float + public virtual float BorderWidth { + get { + return borderWidth; + } + + set { + borderWidth = value; + } + } + + /** + * Gets the color of the border. + * + * @return a value + */ + /// + /// Get/set the color of the border. + /// + /// a Color + public virtual Color BorderColor { + get { + return borderColor; + } + + set { + borderColor = value; + } + } + + /** + * Gets the backgroundcolor. + * + * @return a value + */ + /// + /// Get/set the backgroundcolor. + /// + /// a Color + public virtual Color BackgroundColor { + get { + return backgroundColor; + } + + set { + backgroundColor = value; + } + } + + /// + /// Returns the rotation + /// + /// a int + public int Rotation { + get { + return rotation; + } + } + + public virtual float BorderWidthLeft { + get { + return GetVariableBorderWidth(borderWidthLeft, LEFT_BORDER); + } + set { + borderWidthLeft = value; + UpdateBorderBasedOnWidth(value, LEFT_BORDER); + } + } + + public virtual float BorderWidthRight { + get { + return GetVariableBorderWidth(borderWidthRight, RIGHT_BORDER); + } + set { + borderWidthRight = value; + UpdateBorderBasedOnWidth(value, RIGHT_BORDER); + } + } + + public virtual float BorderWidthTop { + get { + return GetVariableBorderWidth(borderWidthTop, TOP_BORDER); + } + set { + borderWidthTop = value; + UpdateBorderBasedOnWidth(value, TOP_BORDER); + } + } + + public virtual float BorderWidthBottom { + get { + return GetVariableBorderWidth(borderWidthBottom, BOTTOM_BORDER); + } + set { + borderWidthBottom = value; + UpdateBorderBasedOnWidth(value, BOTTOM_BORDER); + } + } + + /** + * Updates the border flag for a side based on the specified width. A width + * of 0 will disable the border on that side. Any other width enables it. + * + * @param width + * width of border + * @param side + * border side constant + */ + + private void UpdateBorderBasedOnWidth(float width, int side) { + useVariableBorders = true; + if (width > 0) { + EnableBorderSide(side); + } else { + DisableBorderSide(side); + } + } + + private float GetVariableBorderWidth(float variableWidthValue, int side) { + if ((border & side) != 0) { + return variableWidthValue != UNDEFINED ? variableWidthValue + : borderWidth; + } else { + return 0; + } + } + + /** + * Sets a parameter indicating if the rectangle has variable borders + * + * @param useVariableBorders + * indication if the rectangle has variable borders + */ + public virtual bool UseVariableBorders{ + get { + return useVariableBorders; + } + set { + useVariableBorders = value; + } + } + + public override String ToString() { + StringBuilder buf = new StringBuilder("Rectangle: "); + buf.Append(Width); + buf.Append('x'); + buf.Append(Height); + buf.Append(" (rot: "); + buf.Append(rotation); + buf.Append(" degrees)"); + return buf.ToString(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/RectangleReadOnly.cs b/iTechSharp/iTextSharp/text/RectangleReadOnly.cs new file mode 100644 index 0000000..b1e532d --- /dev/null +++ b/iTechSharp/iTextSharp/text/RectangleReadOnly.cs @@ -0,0 +1,329 @@ +using System; +using System.Collections; +using System.Text; +using System.util; +using iTextSharp.text.pdf; + +/* + * $Id: RectangleReadOnly.cs,v 1.2 2008/05/13 11:25:12 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A RectangleReadOnly is the representation of a geometric figure. + /// It's the same as a Rectangle but immutable. + /// + /// + /// + /// + /// + public class RectangleReadOnly : Rectangle { + + // constructors + + /// + /// Constructs a RectangleReadOnly-object. + /// + /// lower left x + /// lower left y + /// upper right x + /// upper right y + public RectangleReadOnly(float llx, float lly, float urx, float ury) : base(llx, lly, urx, ury) { + } + + /// + /// Constructs a RectangleReadOnly-object starting from the origin (0, 0). + /// + /// upper right x + /// upper right y + public RectangleReadOnly(float urx, float ury) : base(0, 0, urx, ury) {} + + /// + /// Constructs a RectangleReadOnly-object. + /// + /// another Rectangle + public RectangleReadOnly(Rectangle rect) : base(rect.Left, rect.Bottom, rect.Right, rect.Top) { + base.CloneNonPositionParameters(rect); + } + + /** + * Copies all of the parameters from a Rectangle object + * except the position. + * + * @param rect + * Rectangle to copy from + */ + public override void CloneNonPositionParameters(Rectangle rect) { + ThrowReadOnlyError(); + } + + private void ThrowReadOnlyError() { + throw new InvalidOperationException("RectangleReadOnly: this Rectangle is read only."); + } + + /** + * Copies all of the parameters from a Rectangle object + * except the position. + * + * @param rect + * Rectangle to copy from + */ + + public override void SoftCloneNonPositionParameters(Rectangle rect) { + ThrowReadOnlyError(); + } + + // methods + + /** + * Switches lowerleft with upperright + */ + public override void Normalize() { + ThrowReadOnlyError(); + } + + // methods to set the membervariables + + /// + /// Get/set the upper right y-coordinate. + /// + /// a float + public override float Top { + set { + ThrowReadOnlyError(); + } + } + + /** + * Enables the border on the specified side. + * + * @param side + * the side to enable. One of LEFT, RIGHT, TOP, BOTTOM + * + */ + public override void EnableBorderSide(int side) { + ThrowReadOnlyError(); + } + + /** + * Disables the border on the specified side. + * + * @param side + * the side to disable. One of LEFT, RIGHT, TOP, BOTTOM + * + */ + public override void DisableBorderSide(int side) { + ThrowReadOnlyError(); + } + + + /// + /// Get/set the border + /// + /// a int + public override int Border { + set { + ThrowReadOnlyError(); + } + } + + /// + /// Get/set the grayscale of the rectangle. + /// + /// a float + public override float GrayFill { + set { + ThrowReadOnlyError(); + } + } + + // methods to get the membervariables + + /// + /// Get/set the lower left x-coordinate. + /// + /// a float + public override float Left { + set { + ThrowReadOnlyError(); + } + } + + /// + /// Get/set the upper right x-coordinate. + /// + /// a float + public override float Right { + set { + ThrowReadOnlyError(); + } + } + + /// + /// Get/set the lower left y-coordinate. + /// + /// a float + public override float Bottom { + set { + ThrowReadOnlyError(); + } + } + + public override Color BorderColorBottom { + set { + ThrowReadOnlyError(); + } + } + + public override Color BorderColorTop { + set { + ThrowReadOnlyError(); + } + } + + public override Color BorderColorLeft { + set { + ThrowReadOnlyError(); + } + } + + public override Color BorderColorRight { + set { + ThrowReadOnlyError(); + } + } + + /// + /// Get/set the borderwidth. + /// + /// a float + public override float BorderWidth { + set { + ThrowReadOnlyError(); + } + } + + /** + * Gets the color of the border. + * + * @return a value + */ + /// + /// Get/set the color of the border. + /// + /// a Color + public override Color BorderColor { + set { + ThrowReadOnlyError(); + } + } + + /** + * Gets the backgroundcolor. + * + * @return a value + */ + /// + /// Get/set the backgroundcolor. + /// + /// a Color + public override Color BackgroundColor { + set { + ThrowReadOnlyError(); + } + } + + public override float BorderWidthLeft { + set { + ThrowReadOnlyError(); + } + } + + public override float BorderWidthRight { + set { + ThrowReadOnlyError(); + } + } + + public override float BorderWidthTop { + set { + ThrowReadOnlyError(); + } + } + + public override float BorderWidthBottom { + set { + ThrowReadOnlyError(); + } + } + + /** + * Sets a parameter indicating if the rectangle has variable borders + * + * @param useVariableBorders + * indication if the rectangle has variable borders + */ + public override bool UseVariableBorders{ + set { + ThrowReadOnlyError(); + } + } + + public override String ToString() { + StringBuilder buf = new StringBuilder("RectangleReadOnly: "); + buf.Append(Width); + buf.Append('x'); + buf.Append(Height); + buf.Append(" (rot: "); + buf.Append(rotation); + buf.Append(" degrees)"); + return buf.ToString(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/RomanList.cs b/iTechSharp/iTextSharp/text/RomanList.cs new file mode 100644 index 0000000..0cd1bdb --- /dev/null +++ b/iTechSharp/iTextSharp/text/RomanList.cs @@ -0,0 +1,116 @@ +using System; +using System.Text; +using iTextSharp.text.factories; + +/* + * Copyright 2003 by Michael Niedermair. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text { + +/** + * + * A special-version of LIST which use roman-letters. + * + * @see com.lowagie.text.List + * @version 2003-06-22 + * @author Michael Niedermair + */ + + public class RomanList : List { + + /** + * Initialization + */ + public RomanList() : base(true) { + } + + /** + * Initialization + * + * @param symbolIndent indent + */ + public RomanList(int symbolIndent) : base(true, symbolIndent){ + } + + /** + * Initialization + * @param romanlower roman-char in lowercase + * @param symbolIndent indent + */ + public RomanList(bool romanlower, int symbolIndent) : base(true, symbolIndent) { + this.lowercase = romanlower; + } + + /** + * Adds an Object to the List. + * + * @param o the object to add. + * @return true if adding the object succeeded + */ + public override bool Add(Object o) { + if (o is ListItem) { + ListItem item = (ListItem) o; + Chunk chunk = new Chunk(preSymbol, symbol.Font); + chunk.Append(RomanNumberFactory.GetString(first + list.Count, lowercase)); + chunk.Append(postSymbol); + item.ListSymbol = chunk; + item.SetIndentationLeft(symbolIndent, autoindent); + item.IndentationRight = 0; + list.Add(item); + return true; + } else if (o is List) { + List nested = (List) o; + nested.IndentationLeft = nested.IndentationLeft + symbolIndent; + first--; + list.Add(nested); + return true; + } else if (o is string) { + return this.Add(new ListItem((string) o)); + } + return false; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/Row.cs b/iTechSharp/iTextSharp/text/Row.cs new file mode 100644 index 0000000..256542c --- /dev/null +++ b/iTechSharp/iTextSharp/text/Row.cs @@ -0,0 +1,376 @@ +using System; +using System.Collections; +using System.util; + +/* + * $Id: Row.cs,v 1.10 2008/05/13 11:25:12 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A Row is part of a Table + /// and contains some Cells. + /// + /// + /// All Rows are constructed by a Table-object. + /// You don't have to construct any Row yourself. + /// In fact you can't construct a Row outside the package. + ///

    + /// Since a Cell can span several rows and/or columns + /// a row can contain reserved space without any content. + /// + /// + /// + /// + public class Row : IElement { + + // membervariables + + ///

    id of a null element in a Row + public static int NULL = 0; + + /// id of the Cell element in a Row + public static int CELL = 1; + + /// id of the Table element in a Row + public static int TABLE = 2; + + /// This is the number of columns in the Row. + protected int columns; + + /// This is a valid position the Row. + protected int currentColumn; + + /// This is the array that keeps track of reserved cells. + protected bool[] reserved; + + /// This is the array of Objects (Cell or Table). + protected Object[] cells; + + /// This is the horizontal alignment. + protected int horizontalAlignment; + + // constructors + + /// + /// Constructs a Row with a certain number of columns. + /// + /// a number of columns + internal Row(int columns) { + this.columns = columns; + reserved = new bool[columns]; + cells = new Object[columns]; + currentColumn = 0; + } + + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to a + /// IElementListener. + /// + /// an IElementListener + /// true if the element was processed successfully + public bool Process(IElementListener listener) { + try { + return listener.Add(this); + } + catch (DocumentException) { + return false; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public int Type { + get { + return Element.ROW; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public ArrayList Chunks { + get { + return new ArrayList(); + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return false; + } + + /// + /// Deletes a certain column has been deleted. + /// + /// the number of the column to delete + internal void DeleteColumn(int column) { + if ((column >= columns) || (column < 0)) { + throw new Exception("getCell at illegal index : " + column); + } + columns--; + bool[] newReserved = new bool[columns]; + Object[] newCells = new Cell[columns]; + + for (int i = 0; i < column; i++) { + newReserved[i] = reserved[i]; + newCells[i] = cells[i]; + if (newCells[i] != null && (i + ((Cell) newCells[i]).Colspan > column)) { + ((Cell) newCells[i]).Colspan = ((Cell) cells[i]).Colspan - 1; + } + } + for (int i = column; i < columns; i++) { + newReserved[i] = reserved[i + 1]; + newCells[i] = cells[i + 1]; + } + if (cells[column] != null && ((Cell) cells[column]).Colspan > 1) { + newCells[column] = cells[column]; + ((Cell) newCells[column]).Colspan = ((Cell) newCells[column]).Colspan - 1; + } + reserved = newReserved; + cells = newCells; + } + + // methods + + /// + /// Adds a Cell to the Row. + /// + /// the element to add (currently only Cells and Tables supported) + /// + /// the column position the Cell was added, + /// or -1 if the element couldn't be added. + /// + internal int AddElement(Object element) { + return AddElement(element, currentColumn); + } + + /// + /// Adds an element to the Row at the position given. + /// + /// the element to add. (currently only Cells and Tables supported + /// the position where to add the cell + /// + /// the column position the Cell was added, + /// or -1 if the Cell couldn't be added. + /// + internal int AddElement(Object element, int column) { + if (element == null) throw new Exception("addCell - null argument"); + if ((column < 0) || (column > columns)) throw new Exception("addCell - illegal column argument"); + if ( !((GetObjectID(element) == CELL) || (GetObjectID(element) == TABLE)) ) throw new ArgumentException("addCell - only Cells or Tables allowed"); + + int lColspan = ((element is Cell) ? ((Cell)element).Colspan : 1); + + if (!Reserve(column, lColspan)) { + return -1; + } + + cells[column] = element; + currentColumn += lColspan - 1; + + return column; + } + + /// + /// Puts Cell to the Row at the position given, doesn't reserve colspan. + /// + /// the cell to add. + /// the position where to add the cell. + internal void SetElement(Object aElement, int column) { + if (reserved[column]) throw new ArgumentException("setElement - position already taken"); + + cells[column] = aElement; + if (aElement != null) { + reserved[column] = true; + } + } + + /// + /// Reserves a Cell in the Row. + /// + /// the column that has to be reserved. + /// true if the column was reserved, false if not. + internal bool Reserve(int column) { + return Reserve(column, 1); + } + + + /// + /// Reserves a Cell in the Row. + /// + /// the column that has to be reserved. + /// the number of columns + /// true if the column was reserved, false if not. + internal bool Reserve(int column, int size) { + if ((column < 0) || ((column + size) > columns)) throw new Exception("reserve - incorrect column/size"); + + for (int i=column; i < column + size; i++) { + if (reserved[i]) { + // undo reserve + for (int j=i; j >= column; j--) { + reserved[j] = false; + } + return false; + } + reserved[i] = true; + } + return true; + } + + // methods to retrieve information + + /// + /// Returns true/false when this position in the Row has been reserved, either filled or through a colspan of an Element. + /// + /// the column. + /// true if the column was reserved, false if not. + internal bool IsReserved(int column) { + return reserved[column]; + } + + /// + /// Returns the type-id of the element in a Row. + /// + /// the column of which you'd like to know the type + /// the element id + int GetElementID(int column) { + if (cells[column] == null) return NULL; + else if (cells[column] is Cell) return CELL; + else if (cells[column] is Table) return TABLE; + + return -1; + } + + + /// + /// Returns the type-id of an Object. + /// + /// + /// the object of which you'd like to know the type-id, -1 if invalid + int GetObjectID(Object element) { + if (element == null) return NULL; + else if (element is Cell) return CELL; + else if (element is Table) return TABLE; + + return -1; + } + + + /// + /// Gets a Cell or Table from a certain column. + /// + /// the column the Cell/Table is in. + /// + /// the Cell,Table or Object if the column was + /// reserved or null if empty. + /// + public Object GetCell(int column) { + if ((column < 0) || (column > columns)) { + throw new Exception("getCell at illegal index :" + column + " max is " + columns); + } + return cells[column]; + } + + /// + /// Checks if the row is empty. + /// + /// true if none of the columns is reserved. + public bool IsEmpty() { + for (int i = 0; i < columns; i++) { + if (cells[i] != null) { + return false; + } + } + return true; + } + + /// + /// Gets the number of columns. + /// + /// a value + public int Columns { + get { + return columns; + } + } + + /// + /// Gets the horizontal Element. + /// + /// a value + public int HorizontalAlignment { + get { + return horizontalAlignment; + } + set { + horizontalAlignment = value; + } + } + + public override string ToString() { + return base.ToString(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/Section.cs b/iTechSharp/iTextSharp/text/Section.cs new file mode 100644 index 0000000..10844e5 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Section.cs @@ -0,0 +1,756 @@ +using System; +using System.Text; +using System.Collections; +using System.util; +using iTextSharp.text.factories; + +/* + * $Id: Section.cs,v 1.17 2008/05/13 11:25:13 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text { + /// + /// A Section is a part of a Document containing + /// other Sections, Paragraphs, List + /// and/or Tables. + /// + /// + /// You can not construct a Section yourself. + /// You will have to ask an instance of Section to the + /// Chapter or Section to which you want to + /// add the new Section. + /// + /// + /// + /// Paragraph title2 = new Paragraph("This is Chapter 2", FontFactory.GetFont(FontFactory.HELVETICA, 18, Font.BOLDITALIC, new Color(0, 0, 255))); + /// Chapter chapter2 = new Chapter(title2, 2); + /// Paragraph someText = new Paragraph("This is some text"); + /// chapter2.Add(someText); + /// Paragraph title21 = new Paragraph("This is Section 1 in Chapter 2", FontFactory.GetFont(FontFactory.HELVETICA, 16, Font.BOLD, new Color(255, 0, 0))); + /// Section section1 = chapter2.AddSection(title21); + /// Paragraph someSectionText = new Paragraph("This is some silly paragraph in a chapter and/or section. It contains some text to test the functionality of Chapters and Section."); + /// section1.Add(someSectionText); + /// Paragraph title211 = new Paragraph("This is SubSection 1 in Section 1 in Chapter 2", FontFactory.GetFont(FontFactory.HELVETICA, 14, Font.BOLD, new Color(255, 0, 0))); + /// Section section11 = section1.AddSection(40, title211, 2); + /// section11.Add(someSectionText);strong> + /// + /// + public class Section : ArrayList, ITextElementArray, ILargeElement { + + // constant + /** + * A possible number style. The default number style: "1.2.3." + * @since iText 2.0.8 + */ + public const int NUMBERSTYLE_DOTTED = 0; + /** + * A possible number style. For instance: "1.2.3" + * @since iText 2.0.8 + */ + public const int NUMBERSTYLE_DOTTED_WITHOUT_FINAL_DOT = 1; + + // membervariables + + /// This is the title of this section. + protected Paragraph title; + + /// This is the number of sectionnumbers that has to be shown before the section title. + protected int numberDepth; + + /** + * The style for sectionnumbers. + * @since iText 2.0.8 + */ + protected int numberStyle = NUMBERSTYLE_DOTTED; + + /// The indentation of this section on the left side. + protected float indentationLeft; + + /// The indentation of this section on the right side. + protected float indentationRight; + + /// The additional indentation of the content of this section. + protected float indentation; + + /// This is the number of subsections. + protected int subsections = 0; + + /// This is the complete list of sectionnumbers of this section and the parents of this section. + protected internal ArrayList numbers = null; + + /** + * Indicates if the Section will be complete once added to the document. + * @since iText 2.0.8 + */ + protected bool complete = true; + + /** + * Indicates if the Section was added completely to the document. + * @since iText 2.0.8 + */ + protected bool addedCompletely = false; + + /** + * Indicates if this is the first time the section was added. + * @since iText 2.0.8 + */ + protected bool notAddedYet = true; + + /// false if the bookmark children are not visible + protected bool bookmarkOpen = true; + + /** true if the section has to trigger a new page */ + protected bool triggerNewPage = false; + + /** The bookmark title if different from the content title */ + protected string bookmarkTitle; + + // constructors + + /// + /// Constructs a new Section. + /// + /// + /// Has 2 overloads. + /// + protected internal Section() { + title = new Paragraph(); + numberDepth = 1; + } + + /// + /// Constructs a new Section. + /// + /// a Paragraph + /// the numberDepth + protected internal Section(Paragraph title, int numberDepth) { + this.numberDepth = numberDepth; + this.title = title; + } + + // private methods + + /// + /// Sets the number of this section. + /// + /// the number of this section + /// an ArrayList, containing the numbers of the Parent + private void SetNumbers(int number, ArrayList numbers) { + this.numbers = new ArrayList(); + this.numbers.Add(number); + this.numbers.AddRange(numbers); + } + + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// IElementListener. + /// + /// the IElementListener + /// true if the element was processed successfully + public bool Process(IElementListener listener) { + try { + foreach (IElement ele in this) { + listener.Add(ele); + } + return true; + } + catch (DocumentException) { + return false; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public virtual int Type { + get { + return Element.SECTION; + } + } + + /// + /// Gets all the chunks in this element. + /// + /// an ArrayList + public ArrayList Chunks { + get { + ArrayList tmp = new ArrayList(); + foreach (IElement ele in this) { + tmp.AddRange(ele.Chunks); + } + return tmp; + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public virtual bool IsNestable() { + return false; + } + + // overriding some of the ArrayList-methods + + /// + /// Adds a Paragraph, List or Table + /// to this Section. + /// + /// index at which the specified element is to be inserted + /// an object of type Paragraph, List or Table + public void Add(int index, Object o) { + if (AddedCompletely) { + throw new InvalidOperationException("This LargeElement has already been added to the Document."); + } + try { + IElement element = (IElement) o; + if (element.IsNestable()) { + base.Insert(index, element); + } + else { + throw new Exception(element.Type.ToString()); + } + } + catch (Exception cce) { + throw new Exception("Insertion of illegal Element: " + cce.Message); + } + } + + /// + /// Adds a Paragraph, List, Table or another Section + /// to this Section. + /// + /// an object of type Paragraph, List, Table or another Section + /// a bool + public new bool Add(Object o) { + try { + IElement element = (IElement) o; + if (element.Type == Element.SECTION) { + Section section = (Section) o; + section.SetNumbers(++subsections, numbers); + base.Add(section); + return true; + } + else if (o is MarkedSection && ((MarkedObject)o).element.Type == Element.SECTION) { + MarkedSection mo = (MarkedSection)o; + Section section = (Section)(mo.element); + section.SetNumbers(++subsections, numbers); + base.Add(mo); + return true; + } + else if (element.IsNestable()) { + base.Add(o); + return true; + } + else { + throw new Exception(element.Type.ToString()); + } + } + catch (Exception cce) { + throw new Exception("Insertion of illegal Element: " + cce.Message); + } + } + + /// + /// Adds a collection of Elements + /// to this Section. + /// + /// a collection of Paragraphs, Lists and/or Tables + /// true if the action succeeded, false if not. + public bool AddAll(ICollection collection) { + foreach (object itm in collection) { + this.Add(itm); + } + return true; + } + + // methods that return a Section + + /// + /// Creates a Section, adds it to this Section and returns it. + /// + /// the indentation of the new section + /// the title of the new section + /// the numberDepth of the section + /// the newly added Section + public virtual Section AddSection(float indentation, Paragraph title, int numberDepth) { + if (AddedCompletely) { + throw new InvalidOperationException("This LargeElement has already been added to the Document."); + } + Section section = new Section(title, numberDepth); + section.Indentation = indentation; + Add(section); + return section; + } + + /// + /// Creates a Section, adds it to this Section and returns it. + /// + /// the indentation of the new section + /// the title of the new section + /// the newly added Section + public virtual Section AddSection(float indentation, Paragraph title) { + return AddSection(indentation, title, numberDepth + 1); + } + + /// + /// Creates a Section, add it to this Section and returns it. + /// + /// the title of the new section + /// the numberDepth of the section + /// the newly added Section + public virtual Section AddSection(Paragraph title, int numberDepth) { + return AddSection(0, title, numberDepth); + } + + /** + * Adds a marked section. For use in class MarkedSection only! + */ + public MarkedSection AddMarkedSection() { + MarkedSection section = new MarkedSection(new Section(null, numberDepth + 1)); + Add(section); + return section; + } + + /// + /// Creates a Section, adds it to this Section and returns it. + /// + /// the title of the new section + /// the newly added Section + public virtual Section AddSection(Paragraph title) { + return AddSection(0, title, numberDepth + 1); + } + + /** + * Adds a Section to this Section and returns it. + * + * @param indentation the indentation of the new section + * @param title the title of the new section + * @param numberDepth the numberDepth of the section + */ + /// + /// Adds a Section to this Section and returns it. + /// + /// the indentation of the new section + /// the title of the new section + /// the numberDepth of the section + /// the newly added Section + public virtual Section AddSection(float indentation, string title, int numberDepth) { + return AddSection(indentation, new Paragraph(title), numberDepth); + } + + /** + * Adds a Section to this Section and returns it. + * + * @param title the title of the new section + * @param numberDepth the numberDepth of the section + */ + /// + /// Adds a Section to this Section and returns it. + /// + /// the title of the new section + /// the numberDepth of the section + /// the newly added Section + public virtual Section AddSection(string title, int numberDepth) { + return AddSection(new Paragraph(title), numberDepth); + } + + /// + /// Adds a Section to this Section and returns it. + /// + /// the indentation of the new section + /// the title of the new section + /// the newly added Section + public virtual Section AddSection(float indentation, string title) { + return AddSection(indentation, new Paragraph(title)); + } + + /// + /// Adds a Section to this Section and returns it. + /// + /// the title of the new section + /// the newly added Section + public virtual Section AddSection(string title) { + return AddSection(new Paragraph(title)); + } + + // public methods + + /// + /// Alters the attributes of this Section. + /// + /// the attributes + public void Set(Properties attributes) { + string value; + if ((value = attributes.Remove(ElementTags.NUMBERDEPTH)) != null) { + NumberDepth = int.Parse(value); + } + if ((value = attributes.Remove(ElementTags.INDENT)) != null) { + Indentation = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + if ((value = attributes.Remove(ElementTags.INDENTATIONLEFT)) != null) { + IndentationLeft = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + if ((value = attributes.Remove(ElementTags.INDENTATIONRIGHT)) != null) { + IndentationRight = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + } + + /// + /// Get/set the title of this section + /// + /// a Paragraph + public Paragraph Title { + get { + return ConstructTitle(title, numbers, numberDepth, numberStyle); + } + + set { + this.title = value; + } + } + + /** + * Sets the style for numbering sections. + * Possible values are NUMBERSTYLE_DOTTED: 1.2.3. (the default) + * or NUMBERSTYLE_DOTTED_WITHOUT_FINAL_DOT: 1.2.3 + * @since iText 2.0.8 + */ + public int NumberStyle { + set { + numberStyle = value; + } + get { + return numberStyle; + } + } + + /** + * Constructs a Paragraph that will be used as title for a Section or Chapter. + * @param title the title of the section + * @param numbers a list of sectionnumbers + * @param numberDepth how many numbers have to be shown + * @param numberStyle the numbering style + * @return a Paragraph object + * @since iText 2.0.8 + */ + public static Paragraph ConstructTitle(Paragraph title, ArrayList numbers, int numberDepth, int numberStyle) { + if (title == null) { + return null; + } + int depth = Math.Min(numbers.Count, numberDepth); + if (depth < 1) { + return title; + } + StringBuilder buf = new StringBuilder(" "); + for (int i = 0; i < depth; i++) { + buf.Insert(0, "."); + buf.Insert(0, (int)numbers[i]); + } + if (numberStyle == NUMBERSTYLE_DOTTED_WITHOUT_FINAL_DOT) { + buf.Remove(buf.Length - 2, 1); + } + Paragraph result = new Paragraph(title); + result.Insert(0, new Chunk(buf.ToString(), title.Font)); + return result; + } + + // methods to retrieve information + + /// + /// Checks if this object is a Chapter. + /// + /// + /// true if it is a Chapter, + /// false if it is a Section + /// + public bool IsChapter() { + return Type == Element.CHAPTER; + } + + /// + /// Checks if this object is a Section. + /// + /// + /// true if it is a Section, + /// false if it is a Chapter. + /// + public bool IsSection() { + return Type == Element.SECTION; + } + + /// + /// Get/set the numberdepth of this Section. + /// + /// a int + public int NumberDepth { + get { + return numberDepth; + } + + set { + this.numberDepth = value; + } + } + + /// + /// Get/set the indentation of this Section on the left side. + /// + /// the indentation + public float IndentationLeft { + get { + return indentationLeft; + } + + set { + indentationLeft = value; + } + } + + /// + /// Get/set the indentation of this Section on the right side. + /// + /// the indentation + public float IndentationRight { + get { + return indentationRight; + } + + set { + indentationRight = value; + } + } + + /// + /// Get/set the indentation of the content of this Section. + /// + /// the indentation + public float Indentation { + get { + return indentation; + } + + set { + indentation = value; + } + } + + /// + /// Returns the depth of this section. + /// + /// the depth + public int Depth { + get { + return numbers.Count; + } + } + + /// + /// Checks if a given tag corresponds with a title tag for this object. + /// + /// the given tag + /// true if the tag corresponds + public static bool IsTitle(string tag) { + return ElementTags.TITLE.Equals(tag); + } + + /// + /// Checks if a given tag corresponds with this object. + /// + /// the given tag + /// true if the tag corresponds + public static bool IsTag(string tag) { + return ElementTags.SECTION.Equals(tag); + } + + /// + /// Get/set the bookmark + /// + /// a bool + public bool BookmarkOpen { + get { + return bookmarkOpen; + } + + set { + this.bookmarkOpen = value; + } + } + + /** + * Gets the bookmark title. + * @return the bookmark title + */ + public Paragraph GetBookmarkTitle() { + if (bookmarkTitle == null) + return Title; + else + return new Paragraph(bookmarkTitle); + } + + /** + * Sets the bookmark title. The bookmark title is the same as the section title but + * can be changed with this method. + * @param bookmarkTitle the bookmark title + */ + public String BookmarkTitle { + set { + this.bookmarkTitle = value; + } + } + + public override string ToString() { + return base.ToString(); + } + + public virtual bool TriggerNewPage { + get { + return triggerNewPage && notAddedYet; + } + set { + triggerNewPage = value; + } + } + + /** + * Changes the Chapter number. + */ + public void SetChapterNumber(int number) { + numbers[numbers.Count - 1] = number; + foreach (Object s in this) { + if (s is Section) { + ((Section)s).SetChapterNumber(number); + } + } + } + + /** + * Indicates if this is the first time the section is added. + * @since iText2.0.8 + * @return true if the section wasn't added yet + */ + public bool NotAddedYet { + get { + return notAddedYet; + } + set { + notAddedYet = value; + } + } + + /** + * @see com.lowagie.text.LargeElement#isAddedCompletely() + * @since iText 2.0.8 + */ + protected bool AddedCompletely { + get { + return addedCompletely; + } + set { + addedCompletely = value; + } + } + + /** + * @since iText 2.0.8 + * @see com.lowagie.text.LargeElement#flushContent() + */ + public void FlushContent() { + NotAddedYet = false; + title = null; + for (int k = 0; k < Count; ++k) { + IElement element = (IElement)this[k]; + if (element is Section) { + Section s = (Section)element; + if (!s.ElementComplete && Count == 1) { + s.FlushContent(); + return; + } + else { + s.AddedCompletely = true; + } + } + this.RemoveAt(k); + --k; + } + } + + /** + * @since iText 2.0.8 + * @see com.lowagie.text.LargeElement#isComplete() + */ + public bool ElementComplete { + get { + return complete; + } + set { + complete = value; + } + } + + /** + * Adds a new page to the section. + * @since 2.1.1 + */ + public void NewPage() { + this.Add(Chunk.NEXTPAGE); + } + } +} diff --git a/iTechSharp/iTextSharp/text/SimpleCell.cs b/iTechSharp/iTextSharp/text/SimpleCell.cs new file mode 100644 index 0000000..2849b13 --- /dev/null +++ b/iTechSharp/iTextSharp/text/SimpleCell.cs @@ -0,0 +1,453 @@ +using System; +using System.Collections; +using iTextSharp.text.pdf; + +namespace iTextSharp.text +{ + /// + /// Summary description for SimpleCell. + /// + public class SimpleCell : Rectangle, IPdfPCellEvent, ITextElementArray { + + /** the CellAttributes object represents a row. */ + public new const bool ROW = true; + /** the CellAttributes object represents a cell. */ + public new const bool CELL = false; + /** the content of the Cell. */ + private ArrayList content = new ArrayList(); + /** the width of the Cell. */ + private float width = 0f; + /** the widthpercentage of the Cell. */ + private float widthpercentage = 0f; + /** an extra spacing variable */ + private float spacing_left = float.NaN; + /** an extra spacing variable */ + private float spacing_right = float.NaN; + /** an extra spacing variable */ + private float spacing_top = float.NaN; + /** an extra spacing variable */ + private float spacing_bottom = float.NaN; + /** an extra padding variable */ + private float padding_left = float.NaN; + /** an extra padding variable */ + private float padding_right = float.NaN; + /** an extra padding variable */ + private float padding_top = float.NaN; + /** an extra padding variable */ + private float padding_bottom = float.NaN; + /** the colspan of a Cell */ + private int colspan = 1; + /** horizontal alignment inside the Cell. */ + private int horizontalAlignment = Element.ALIGN_UNDEFINED; + /** vertical alignment inside the Cell. */ + private int verticalAlignment = Element.ALIGN_UNDEFINED; + /** indicates if these are the attributes of a single Cell (false) or a group of Cells (true). */ + private bool cellgroup = false; + /** Indicates that the largest ascender height should be used to determine the + * height of the first line. Note that this only has an effect when rendered + * to PDF. Setting this to true can help with vertical alignment problems. */ + protected bool useAscender = false; + /** Indicates that the largest descender height should be added to the height of + * the last line (so characters like y don't dip into the border). Note that + * this only has an effect when rendered to PDF. */ + protected bool useDescender = false; + /** + * Adjusts the cell contents to compensate for border widths. Note that + * this only has an effect when rendered to PDF. + */ + protected bool useBorderPadding; + + /** + * A CellAttributes object is always constructed without any dimensions. + * Dimensions are defined after creation. + * @param row only true if the CellAttributes object represents a row. + */ + public SimpleCell(bool row) : base (0f, 0f, 0f, 0f) { + cellgroup = row; + Border = BOX; + } + + /** + * Adds content to this object. + * @param element + * @throws BadElementException + */ + public void AddElement(IElement element) { + if (cellgroup) { + if (element is SimpleCell) { + if (((SimpleCell)element).Cellgroup) { + throw new BadElementException("You can't add one row to another row."); + } + content.Add(element); + return; + } + else { + throw new BadElementException("You can only add cells to rows, no objects of type " + element.GetType().ToString()); + } + } + if (element.Type == Element.PARAGRAPH + || element.Type == Element.PHRASE + || element.Type == Element.ANCHOR + || element.Type == Element.CHUNK + || element.Type == Element.LIST + || element.Type == Element.MARKED + || element.Type == Element.JPEG + || element.Type == Element.JPEG2000 + || element.Type == Element.IMGRAW + || element.Type == Element.IMGTEMPLATE) { + content.Add(element); + } + else { + throw new BadElementException("You can't add an element of type " + element.GetType().ToString() + " to a SimpleCell."); + } + } + + /** + * Creates a Cell with these attributes. + * @param rowAttributes + * @return a cell based on these attributes. + * @throws BadElementException + */ + public Cell CreateCell(SimpleCell rowAttributes) { + Cell cell = new Cell(); + cell.CloneNonPositionParameters(rowAttributes); + cell.SoftCloneNonPositionParameters(this); + cell.Colspan = colspan; + cell.HorizontalAlignment = horizontalAlignment; + cell.VerticalAlignment = verticalAlignment; + cell.UseAscender = useAscender; + cell.UseBorderPadding = useBorderPadding; + cell.UseDescender = useDescender; + foreach (IElement element in content) { + cell.AddElement(element); + } + return cell; + } + + /** + * Creates a PdfPCell with these attributes. + * @param rowAttributes + * @return a PdfPCell based on these attributes. + */ + public PdfPCell CreatePdfPCell(SimpleCell rowAttributes) { + PdfPCell cell = new PdfPCell(); + cell.Border = NO_BORDER; + SimpleCell tmp = new SimpleCell(CELL); + tmp.Spacing_left = spacing_left; + tmp.Spacing_right = spacing_right; + tmp.Spacing_top = spacing_top; + tmp.Spacing_bottom = spacing_bottom; + tmp.CloneNonPositionParameters(rowAttributes); + tmp.SoftCloneNonPositionParameters(this); + cell.CellEvent = tmp; + cell.HorizontalAlignment = rowAttributes.horizontalAlignment; + cell.VerticalAlignment = rowAttributes.verticalAlignment; + cell.UseAscender = rowAttributes.useAscender; + cell.UseBorderPadding = rowAttributes.useBorderPadding; + cell.UseDescender = rowAttributes.useDescender; + cell.Colspan = colspan; + if (horizontalAlignment != Element.ALIGN_UNDEFINED) + cell.HorizontalAlignment = horizontalAlignment; + if (verticalAlignment != Element.ALIGN_UNDEFINED) + cell.VerticalAlignment = verticalAlignment; + if (useAscender) + cell.UseAscender = useAscender; + if (useBorderPadding) + cell.UseBorderPadding = useBorderPadding; + if (useDescender) + cell.UseDescender = useDescender; + float p; + float sp_left = spacing_left; + if (float.IsNaN(sp_left)) sp_left = 0f; + float sp_right = spacing_right; + if (float.IsNaN(sp_right)) sp_right = 0f; + float sp_top = spacing_top; + if (float.IsNaN(sp_top)) sp_top = 0f; + float sp_bottom = spacing_bottom; + if (float.IsNaN(sp_bottom)) sp_bottom = 0f; + p = padding_left; + if (float.IsNaN(p)) p = 0f; + cell.PaddingLeft = p + sp_left; + p = padding_right; + if (float.IsNaN(p)) p = 0f; + cell.PaddingRight = p + sp_right; + p = padding_top; + if (float.IsNaN(p)) p = 0f; + cell.PaddingTop = p + sp_top; + p = padding_bottom; + if (float.IsNaN(p)) p = 0f; + cell.PaddingBottom = p + sp_bottom; + foreach (IElement element in content) { + cell.AddElement(element); + } + return cell; + } + + /** + * @param rectangle + * @param spacing + * @return a rectangle + */ + public static SimpleCell GetDimensionlessInstance(Rectangle rectangle, float spacing) { + SimpleCell cell = new SimpleCell(CELL); + cell.CloneNonPositionParameters(rectangle); + cell.Spacing = spacing * 2; + return cell; + } + + /** + * @see com.lowagie.text.pdf.PdfPCellEvent#cellLayout(com.lowagie.text.pdf.PdfPCell, com.lowagie.text.Rectangle, com.lowagie.text.pdf.PdfContentByte[]) + */ + public void CellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) { + float sp_left = spacing_left; + if (float.IsNaN(sp_left)) sp_left = 0f; + float sp_right = spacing_right; + if (float.IsNaN(sp_right)) sp_right = 0f; + float sp_top = spacing_top; + if (float.IsNaN(sp_top)) sp_top = 0f; + float sp_bottom = spacing_bottom; + if (float.IsNaN(sp_bottom)) sp_bottom = 0f; + Rectangle rect = new Rectangle(position.GetLeft(sp_left), position.GetBottom(sp_bottom), position.GetRight(sp_right), position.GetTop(sp_top)); + rect.CloneNonPositionParameters(this); + canvases[PdfPTable.BACKGROUNDCANVAS].Rectangle(rect); + rect.BackgroundColor = null; + canvases[PdfPTable.LINECANVAS].Rectangle(rect); + } + + /** Sets the padding parameters if they are undefined. + * @param padding*/ + public float Padding { + set { + if (float.IsNaN(padding_right)) { + Padding_right = value; + } + if (float.IsNaN(padding_left)) { + Padding_left = value; + } + if (float.IsNaN(padding_bottom)) { + Padding_bottom = value; + } + if (float.IsNaN(padding_top)) { + Padding_top = value; + } + } + } + + /** + * @return Returns the colspan. + */ + public int Colspan { + get { + return colspan; + } + set { + if (value > 0) this.colspan = value; + } + } + + /** + * @param padding_bottom The padding_bottom to set. + */ + public float Padding_bottom { + get { + return padding_bottom; + } + set { + padding_bottom = value; + } + } + + public float Padding_left { + get { + return padding_left; + } + set { + padding_left = value; + } + } + + public float Padding_right { + get { + return padding_right; + } + set { + padding_right = value; + } + } + + public float Padding_top { + get { + return padding_top; + } + set { + padding_top = value; + } + } + + /** + * @return Returns the spacing. + */ + public float Spacing { + set { + this.spacing_left = value; + this.spacing_right = value; + this.spacing_top = value; + this.spacing_bottom = value; + } + + } + + public float Spacing_top { + get { + return spacing_top; + } + set { + spacing_top = value; + } + } + + public float Spacing_bottom { + get { + return spacing_bottom; + } + set { + spacing_bottom = value; + } + } + + public float Spacing_left { + get { + return spacing_left; + } + set { + spacing_left = value; + } + } + + public float Spacing_right { + get { + return spacing_right; + } + set { + spacing_right = value; + } + } + + /** + * @return Returns the cellgroup. + */ + public bool Cellgroup { + get { + return cellgroup; + } + set { + cellgroup = value; + } + } + + /** + * @return Returns the horizontal alignment. + */ + public int HorizontalAlignment { + get { + return horizontalAlignment; + } + set { + horizontalAlignment = value; + } + } + + public int VerticalAlignment { + get { + return verticalAlignment; + } + set { + verticalAlignment = value; + } + } + /** + * @return Returns the width. + */ + public new float Width { + get { + return width; + } + set { + width = value; + } + } + + /** + * @return Returns the widthpercentage. + */ + public float Widthpercentage { + get { + return widthpercentage; + } + set { + widthpercentage = value; + } + } + + /** + * @return Returns the useAscender. + */ + public bool UseAscender { + get { + return useAscender; + } + set { + useAscender = value; + } + } + + public bool UseDescender { + get { + return useDescender; + } + set { + useDescender = value; + } + } + /** + * @return Returns the useBorderPadding. + */ + public bool UseBorderPadding { + get { + return useBorderPadding; + } + set { + useBorderPadding = value; + } + } + + /** + * @return Returns the content. + */ + internal ArrayList Content { + get { + return content; + } + } + + /** + * @see com.lowagie.text.TextElementArray#add(java.lang.Object) + */ + public bool Add(Object o) { + try { + AddElement((IElement)o); + return true; + } + catch (InvalidCastException) { + return false; + } + } + + public override int Type { + get { + return Element.CELL; + } + } + + } +} diff --git a/iTechSharp/iTextSharp/text/SimpleTable.cs b/iTechSharp/iTextSharp/text/SimpleTable.cs new file mode 100644 index 0000000..0416a8e --- /dev/null +++ b/iTechSharp/iTextSharp/text/SimpleTable.cs @@ -0,0 +1,302 @@ +using System; +using System.Collections; +using iTextSharp.text.pdf; + +namespace iTextSharp.text +{ + /// + /// Summary description for SimpleTable. + /// + public class SimpleTable : Rectangle, IPdfPTableEvent, ITextElementArray { + + /** the content of a Table. */ + private ArrayList content = new ArrayList(); + /** the width of the Table. */ + private float width = 0f; + /** the widthpercentage of the Table. */ + private float widthpercentage = 0f; + /** the spacing of the Cells. */ + private float cellspacing; + /** the padding of the Cells. */ + private float cellpadding; + /** the alignment of the table. */ + private int alignment; + + /** + * A RectangleCell is always constructed without any dimensions. + * Dimensions are defined after creation. + */ + public SimpleTable() : base(0f, 0f, 0f, 0f) { + Border = BOX; + BorderWidth = 2f; + } + + /** + * Adds content to this object. + * @param element + * @throws BadElementException + */ + public void AddElement(SimpleCell element) { + if (!element.Cellgroup) { + throw new BadElementException("You can't add cells to a table directly, add them to a row first."); + } + content.Add(element); + } + + /** + * Creates a Table object based on this TableAttributes object. + * @return a com.lowagie.text.Table object + * @throws BadElementException + */ + public Table CreateTable() { + if (content.Count == 0) throw new BadElementException("Trying to create a table without rows."); + SimpleCell rowx = (SimpleCell)content[0]; + int columns = 0; + foreach (SimpleCell cell in rowx.Content) { + columns += cell.Colspan; + } + float[] widths = new float[columns]; + float[] widthpercentages = new float[columns]; + Table table = new Table(columns); + table.Alignment = alignment; + table.Spacing = cellspacing; + table.Padding = cellpadding; + table.CloneNonPositionParameters(this); + int pos; + foreach (SimpleCell row in content) { + pos = 0; + foreach (SimpleCell cell in row.Content) { + table.AddCell(cell.CreateCell(row)); + if (cell.Colspan == 1) { + if (cell.Width > 0) widths[pos] = cell.Width; + if (cell.Widthpercentage > 0) widthpercentages[pos] = cell.Widthpercentage; + } + pos += cell.Colspan; + } + } + float sumWidths = 0f; + for (int i = 0; i < columns; i++) { + if (widths[i] == 0) { + sumWidths = 0; + break; + } + sumWidths += widths[i]; + } + if (sumWidths > 0) { + table.Width = sumWidths; + table.Locked = true; + table.Widths = widths; + } + else { + for (int i = 0; i < columns; i++) { + if (widthpercentages[i] == 0) { + sumWidths = 0; + break; + } + sumWidths += widthpercentages[i]; + } + if (sumWidths > 0) { + table.Widths = widthpercentages; + } + } + if (width > 0) { + table.Width = width; + table.Locked = true; + } + else if (widthpercentage > 0) { + table.Width = widthpercentage; + } + return table; + } + + /** + * Creates a PdfPTable object based on this TableAttributes object. + * @return a com.lowagie.text.pdf.PdfPTable object + * @throws DocumentException + */ + public PdfPTable CreatePdfPTable() { + if (content.Count == 0) throw new BadElementException("Trying to create a table without rows."); + SimpleCell rowx = (SimpleCell)content[0]; + int columns = 0; + foreach (SimpleCell cell in rowx.Content) { + columns += cell.Colspan; + } + float[] widths = new float[columns]; + float[] widthpercentages = new float[columns]; + PdfPTable table = new PdfPTable(columns); + table.TableEvent = this; + table.HorizontalAlignment = alignment; + int pos; + foreach (SimpleCell row in content) { + pos = 0; + foreach (SimpleCell cell in row.Content) { + if (float.IsNaN(cell.Spacing_left)) { + cell.Spacing_left = cellspacing / 2f; + } + if (float.IsNaN(cell.Spacing_right)) { + cell.Spacing_right = cellspacing / 2f; + } + if (float.IsNaN(cell.Spacing_top)) { + cell.Spacing_top = cellspacing / 2f; + } + if (float.IsNaN(cell.Spacing_bottom)) { + cell.Spacing_bottom = cellspacing / 2f; + } + cell.Padding = cellpadding; + table.AddCell(cell.CreatePdfPCell(row)); + if (cell.Colspan == 1) { + if (cell.Width > 0) widths[pos] = cell.Width; + if (cell.Widthpercentage > 0) widthpercentages[pos] = cell.Widthpercentage; + } + pos += cell.Colspan; + } + } + float sumWidths = 0f; + for (int i = 0; i < columns; i++) { + if (widths[i] == 0) { + sumWidths = 0; + break; + } + sumWidths += widths[i]; + } + if (sumWidths > 0) { + table.TotalWidth = sumWidths; + table.SetWidths(widths); + } + else { + for (int i = 0; i < columns; i++) { + if (widthpercentages[i] == 0) { + sumWidths = 0; + break; + } + sumWidths += widthpercentages[i]; + } + if (sumWidths > 0) { + table.SetWidths(widthpercentages); + } + } + if (width > 0) { + table.TotalWidth = width; + } + if (widthpercentage > 0) { + table.WidthPercentage = widthpercentage; + } + return table; + } + + /** + * @param rectangle + * @param spacing + * @return a rectangle + */ + public static SimpleTable GetDimensionlessInstance(Rectangle rectangle, float spacing) { + SimpleTable ev = new SimpleTable(); + ev.CloneNonPositionParameters(rectangle); + ev.Cellspacing = spacing; + return ev; + } + + /** + * @see com.lowagie.text.pdf.PdfPTableEvent#tableLayout(com.lowagie.text.pdf.PdfPTable, float[][], float[], int, int, com.lowagie.text.pdf.PdfContentByte[]) + */ + public void TableLayout(PdfPTable table, float[][] widths, float[] heights, int headerRows, int rowStart, PdfContentByte[] canvases) { + float[] width = widths[0]; + Rectangle rect = new Rectangle(width[0], heights[heights.Length - 1], width[width.Length - 1], heights[0]); + rect.CloneNonPositionParameters(this); + int bd = rect.Border; + rect.Border = Rectangle.NO_BORDER; + canvases[PdfPTable.BACKGROUNDCANVAS].Rectangle(rect); + rect.Border = bd; + rect.BackgroundColor = null; + canvases[PdfPTable.LINECANVAS].Rectangle(rect); + } + + /** + * @return Returns the cellpadding. + */ + public float Cellpadding { + get { + return cellpadding; + } + set { + cellpadding = value; + } + } + + /** + * @return Returns the cellspacing. + */ + public float Cellspacing { + get { + return cellspacing; + } + set { + cellspacing = value; + } + } + + /** + * @return Returns the alignment. + */ + public int Alignment { + get { + return alignment; + } + set { + alignment = value; + } + } + + /** + * @return Returns the width. + */ + public override float Width { + get { + return width; + } + set { + width = value; + } + } + /** + * @return Returns the widthpercentage. + */ + public float Widthpercentage { + get { + return widthpercentage; + } + set { + widthpercentage = value; + } + } + /** + * @see com.lowagie.text.Element#type() + */ + public override int Type { + get { + return Element.TABLE; + } + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public override bool IsNestable() { + return true; + } + + /** + * @see com.lowagie.text.TextElementArray#add(java.lang.Object) + */ + public bool Add(Object o) { + try { + AddElement((SimpleCell)o); + return true; + } + catch (InvalidCastException) { + return false; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/SpecialSymbol.cs b/iTechSharp/iTextSharp/text/SpecialSymbol.cs new file mode 100644 index 0000000..d706298 --- /dev/null +++ b/iTechSharp/iTextSharp/text/SpecialSymbol.cs @@ -0,0 +1,202 @@ +using System; + +/* + * $Id: SpecialSymbol.cs,v 1.4 2008/05/13 11:25:13 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text +{ + public class SpecialSymbol { + + /** + * Returns the first occurrence of a special symbol in a String. + * + * @param string a String + * @return an index of -1 if no special symbol was found + */ + + public static int Index(string str) { + int length = str.Length; + for (int i = 0; i < length; i++) { + if (GetCorrespondingSymbol(str[i]) != ' ') { + return i; + } + } + return -1; + } + + /** + * Gets a chunk with a symbol character. + * @param c a character that has to be changed into a symbol + * @param font Font if there is no SYMBOL character corresponding with c + * @return a SYMBOL version of a character + */ + + public static Chunk Get(char c, Font font) { + char greek = SpecialSymbol.GetCorrespondingSymbol(c); + if (greek == ' ') { + return new Chunk(c.ToString(), font); + } + Font symbol = new Font(Font.SYMBOL, font.Size, font.Style, font.Color); + return new Chunk(greek.ToString(), symbol); + } + + /** + * Looks for the corresponding symbol in the font Symbol. + * + * @param c the original ASCII-char + * @return the corresponding symbol in font Symbol + */ + + public static char GetCorrespondingSymbol(char c) { + switch (c) { + case (char)913: + return 'A'; // ALFA + case (char)914: + return 'B'; // BETA + case (char)915: + return 'G'; // GAMMA + case (char)916: + return 'D'; // DELTA + case (char)917: + return 'E'; // EPSILON + case (char)918: + return 'Z'; // ZETA + case (char)919: + return 'H'; // ETA + case (char)920: + return 'Q'; // THETA + case (char)921: + return 'I'; // IOTA + case (char)922: + return 'K'; // KAPPA + case (char)923: + return 'L'; // LAMBDA + case (char)924: + return 'M'; // MU + case (char)925: + return 'N'; // NU + case (char)926: + return 'X'; // XI + case (char)927: + return 'O'; // OMICRON + case (char)928: + return 'P'; // PI + case (char)929: + return 'R'; // RHO + case (char)931: + return 'S'; // SIGMA + case (char)932: + return 'T'; // TAU + case (char)933: + return 'U'; // UPSILON + case (char)934: + return 'J'; // PHI + case (char)935: + return 'C'; // CHI + case (char)936: + return 'Y'; // PSI + case (char)937: + return 'W'; // OMEGA + case (char)945: + return 'a'; // alfa + case (char)946: + return 'b'; // beta + case (char)947: + return 'g'; // gamma + case (char)948: + return 'd'; // delta + case (char)949: + return 'e'; // epsilon + case (char)950: + return 'z'; // zeta + case (char)951: + return 'h'; // eta + case (char)952: + return 'q'; // theta + case (char)953: + return 'i'; // iota + case (char)954: + return 'k'; // kappa + case (char)955: + return 'l'; // lambda + case (char)956: + return 'm'; // mu + case (char)957: + return 'n'; // nu + case (char)958: + return 'x'; // xi + case (char)959: + return 'o'; // omicron + case (char)960: + return 'p'; // pi + case (char)961: + return 'r'; // rho + case (char)962: + return 'V'; // sigma + case (char)963: + return 's'; // sigma + case (char)964: + return 't'; // tau + case (char)965: + return 'u'; // upsilon + case (char)966: + return 'j'; // phi + case (char)967: + return 'c'; // chi + case (char)968: + return 'y'; // psi + case (char)969: + return 'w'; // omega + default: + return ' '; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/Table.cs b/iTechSharp/iTextSharp/text/Table.cs new file mode 100644 index 0000000..4699bca --- /dev/null +++ b/iTechSharp/iTextSharp/text/Table.cs @@ -0,0 +1,1577 @@ +using System; +using System.Collections; +using System.util; + +using iTextSharp.text.html; +using iTextSharp.text.pdf; + +/* + * $Id: Table.cs,v 1.23 2008/05/13 11:25:13 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + * + * Some methods in this class were contributed by Geert Poels, Kris Jespers and + * Steve Ogryzek. Check the CVS repository. + */ + +namespace iTextSharp.text { + /// + /// A Table is a Rectangle that contains Cells, + /// ordered in some kind of matrix. + /// + /// + /// Tables that span multiple pages are cut into different parts automatically. + /// If you want a table header to be repeated on every page, you may not forget to + /// mark the end of the header section by using the method EndHeaders(). + ///

    + /// The matrix of a table is not necessarily an m x n-matrix. It can contain holes + /// or cells that are bigger than the unit. Believe me or not, but it took some serious + /// thinking to make this as userfriendly as possible. I hope you wil find the result + /// quite simple (I love simple solutions, especially for complex problems). + /// + /// + /// + /// // Remark: You MUST know the number of columns when constructing a Table. + /// // The number of rows is not important. + /// Table table = new Table(3); + /// table.SetBorderWidth(1); + /// table.SetBorderColor(new Color(0, 0, 255)); + /// table.SetPadding(5); + /// table.SetSpacing(5); + /// Cell cell = new Cell("header"); + /// cell.SetHeader(true); + /// cell.SetColspan(3); + /// table.AddCell(cell); + /// table.EndHeaders(); + /// cell = new Cell("example cell with colspan 1 and rowspan 2"); + /// cell.SetRowspan(2); + /// cell.SetBorderColor(new Color(255, 0, 0)); + /// table.AddCell(cell); + /// table.AddCell("1.1"); + /// table.AddCell("2.1"); + /// table.AddCell("1.2"); + /// table.AddCell("2.2"); + /// table.AddCell("cell test1"); + /// cell = new Cell("big cell"); + /// cell.SetRowspan(2); + /// cell.SetColspan(2); + /// table.AddCell(cell); + /// table.AddCell("cell test2"); + /// + /// + /// The result of this code is a table: + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + ///
    + /// header + ///
    + /// example cell with colspan 1 and rowspan 2 + /// + /// 1.1 + /// + /// 2.1 + ///
    + /// 1.2 + /// + /// 2.2 + ///
    + /// cell test1 + /// + /// big cell + ///
    + /// cell test2 + ///
    + ///
    + /// + /// + /// + /// + public class Table : Rectangle, ILargeElement { + + // membervariables + + // these variables contain the data of the table + + ///

    This is the number of columns in the Table. + private int columns; + + // this is the current Position in the table + private System.Drawing.Point curPosition = new System.Drawing.Point(0, 0); + + /// This is the list of Rows. + private ArrayList rows = new ArrayList(); + + // these variables contain the layout of the table + + /// This Empty Cell contains the DEFAULT layout of each Cell added with the method AddCell(string content). + private Cell defaultCell = new Cell(true); + + /// This is the number of the last row of the table headers. + private int lastHeaderRow = -1; + + /// This is the horizontal Element. + private int alignment = Element.ALIGN_CENTER; + + /// This is cellpadding. + private float cellpadding; + + /// This is cellspacing. + private float cellspacing; + + /// This is the width of the table (in percent of the available space). + private float width = 80; + + /** Is the width a percentage (false) or an absolute width (true)? */ + private bool locked = false; + + /// This is an array containing the widths (in percentages) of every column. + private float[] widths; + + /// bool to track if a table was inserted (to avoid unnecessary computations afterwards) + private bool mTableInserted = false; + + /// + /// Boolean to automatically fill empty cells before a table is rendered + /// (takes CPU so may be set to false in case of certainty) + /// + protected internal bool autoFillEmptyCells = false; + + /// If true this table may not be split over two pages. + bool tableFitsPage = false; + + /// If true cells may not be split over two pages. + bool cellsFitPage = false; + + /// This is the offset of the table. + float offset = float.NaN; + + /** if you want to generate tables the old way, set this value to false. */ + protected bool convert2pdfptable = false; + + /** + * Indicates if this is the first time the section was added. + * @since iText 2.0.8 + */ + protected bool notAddedYet = true; + + /** + * Indicates if the PdfPTable is complete once added to the document. + * @since iText 2.0.8 + */ + protected bool complete = true; + + // constructors + + /// + /// Constructs a Table with a certain number of columns. + /// + /// The number of columns in the table + /// + /// Has three overloads + /// + public Table(int columns) : this(columns, 1) {} + + /// + /// Constructs a Table with a certain number of columns + /// and a certain number of Rows. + /// + /// The number of columns in the table + /// The number of rows + /// + /// Has three overloads + /// + public Table(int columns, int rows) : base(0, 0, 0, 0) { + Border = BOX; + BorderWidth = 1; + defaultCell.Border = BOX; + + // a table should have at least 1 column + if (columns <= 0) { + throw new BadElementException("A table should have at least 1 column."); + } + this.columns = columns; + + // a certain number of rows are created + for (int i = 0; i < rows; i++) { + this.rows.Add(new Row(columns)); + } + curPosition = new System.Drawing.Point(0, 0); + + // the DEFAULT widths are calculated + widths = new float[columns]; + float width = 100f / columns; + for (int i = 0; i < columns; i++) { + widths[i] = width; + } + } + + // implementation of the Element-methods + + /// + /// Processes the element by adding it (or the different parts) to an + /// IElementListener. + /// + /// an IElementListener + /// true if the element was processed successfully + public override bool Process(IElementListener listener) { + try { + return listener.Add(this); + } + catch (DocumentException) { + return false; + } + } + + /** + * Sets the default layout of the Table to + * the provided Cell + * @param value a cell with all the defaults + */ + public Cell DefaultLayout { + set { + defaultCell = value; + } + get { + return defaultCell; + } + } + + /** + * Sets the default layout of the Table to + * the provided Cell + * @param value a cell with all the defaults + */ + public Cell DefaultCell { + set { + defaultCell = value; + } + get { + return defaultCell; + } + } + + /// + /// Enables/disables automatic insertion of empty cells before table is rendered. (default = false) + /// + /// + /// As some people may want to create a table, fill only a couple of the cells and don't bother with + /// investigating which empty ones need to be added, this default behaviour may be very welcome. + /// Disabling is recommended to increase speed. (empty cells should be added through extra code then) + /// + /// enable/disable autofill + public bool AutoFillEmptyCells { + set { + autoFillEmptyCells = value; + } + } + + /// + /// Allows you to control when a page break occurs. + /// + /// + /// When a table doesn't fit a page, it is split in two parts. + /// If you want to avoid this, you should set the tableFitsPage value to true. + /// + /// a value + public bool TableFitsPage { + set { + this.tableFitsPage = value; + if (value) CellsFitPage = true; + } + get { + return tableFitsPage; + } + } + + /// + /// Allows you to control when a page break occurs. + /// + /// + /// When a cell doesn't fit a page, it is split in two parts. + /// If you want to avoid this, you should set the cellsFitPage value to true. + /// + /// a value + public bool CellsFitPage { + set { + this.cellsFitPage = value; + } + get { + return cellsFitPage; + } + } + + /// + /// Get/set the offset of this table. + /// + /// the space between this table and the previous element. + public float Offset { + get { + return offset; + } + + set { + this.offset = value; + } + } + + /// + /// Gets the type of the text element. + /// + /// a type + public override int Type { + get { + return Element.TABLE; + } + } + + /** + * Gets all the chunks in this element. + * + * @return an ArrayList + */ + + // public ArrayList Chunks { + // get { + // return new ArrayList(); + // } + // } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public override bool IsNestable() { + return true; + } + + // methods to add content to the table + + /// + /// Adds a Cell to the Table at a certain row and column. + /// + /// The Cell to add + /// The row where the Cell will be added + /// The column where the Cell will be added + public void AddCell(Cell aCell, int row, int column) { + AddCell(aCell, new System.Drawing.Point(row,column)); + } + + /// + /// Adds a Cell to the Table at a certain location. + /// + /// The Cell to add + /// The location where the Cell will be added + public void AddCell(Cell aCell, object aLocation) { + System.Drawing.Point p; + if (aCell == null) throw new Exception("addCell - cell has null-value"); + if (aLocation == null) + throw new Exception("addCell - point has null-value"); + else + p = (System.Drawing.Point)aLocation; + + if (aCell.IsTable()) { + IEnumerator i = aCell.Elements.GetEnumerator(); + i.MoveNext(); + InsertTable((Table)i.Current, p); + } + if (p.X < 0) throw new BadElementException("row coordinate of location must be >= 0"); + if ((p.Y <= 0) && (p.Y > columns)) throw new BadElementException("column coordinate of location must be >= 0 and < nr of columns"); + if (!IsValidLocation(aCell, p)) throw new BadElementException("Adding a cell at the location (" + p.X + "," + p.Y + ") with a colspan of " + aCell.Colspan + " and a rowspan of " + aCell.Rowspan + " is illegal (beyond boundaries/overlapping)."); + if (aCell.Border == UNDEFINED) aCell.Border = defaultCell.Border; + aCell.Fill(); + PlaceCell(rows, aCell, p); + CurrentLocationToNextValidPosition = p; + } + + + /// + /// Adds a Cell to the Table. + /// + /// a Cell + public void AddCell(Cell cell) { + try { + AddCell(cell, curPosition); + } + catch (BadElementException) { + // don't add the cell + } + } + + /// + /// Adds a Cell to the Table. + /// + /// + /// This is a shortcut for AddCell(Cell cell). + /// The Phrase will be converted to a Cell. + /// + /// a Phrase + public void AddCell(Phrase content) { + AddCell(content, curPosition); + } + + /// + /// Adds a Cell to the Table. + /// + /// a Phrase + /// a System.Drawing.Point + public void AddCell(Phrase content, System.Drawing.Point location) { + Cell cell = new Cell(content); + cell.Border = defaultCell.Border; + cell.BorderWidth = defaultCell.BorderWidth; + cell.BorderColor = defaultCell.BorderColor; + cell.BackgroundColor = defaultCell.BackgroundColor; + cell.HorizontalAlignment = defaultCell.HorizontalAlignment; + cell.VerticalAlignment = defaultCell.VerticalAlignment; + cell.Colspan = defaultCell.Colspan; + cell.Rowspan = defaultCell.Rowspan; + AddCell(cell, location); + } + + /// + /// Adds a Cell to the Table. + /// + /// + /// This is a shortcut for AddCell(Cell cell). + /// The string will be converted to a Cell. + /// + /// a string + public void AddCell(string content) { + AddCell(new Phrase(content), curPosition); + } + + /// + /// Adds a Cell to the Table. + /// + /// + /// This is a shortcut for AddCell(Cell cell, System.Drawing.Point location). + /// The string will be converted to a Cell. + /// + /// a string + /// a point + public void AddCell(string content, System.Drawing.Point location) { + AddCell(new Phrase(content), location); + } + + /// + /// To put a table within the existing table at the current position + /// generateTable will of course re-arrange the widths of the columns. + /// + /// the table you want to insert + public void InsertTable(Table aTable) { + if (aTable == null) throw new Exception("insertTable - table has null-value"); + InsertTable(aTable, curPosition); + } + + /// + /// To put a table within the existing table at the given position + /// generateTable will of course re-arrange the widths of the columns. + /// + /// The Table to add + /// The row where the Cell will be added + /// The column where the Cell will be added + public void InsertTable(Table aTable, int row, int column) { + if (aTable == null) throw new Exception("insertTable - table has null-value"); + InsertTable(aTable, new System.Drawing.Point(row, column)); + } + + /// + /// To put a table within the existing table at the given position + /// generateTable will of course re-arrange the widths of the columns. + /// + /// the table you want to insert + /// a System.Drawing.Point + public void InsertTable(Table aTable, System.Drawing.Point p) { + if (aTable == null) throw new Exception("insertTable - table has null-value"); + + mTableInserted = true; + aTable.Complete(); + if (p.Y > columns) + throw new ArgumentException("insertTable -- wrong columnposition("+ p.Y + ") of location; max =" + columns); + int rowCount = p.X + 1 - rows.Count; + int i = 0; + if ( rowCount > 0 ) { //create new rows ? + for (; i < rowCount; i++) { + rows.Add(new Row(columns)); + } + } + + ((Row) rows[p.X]).SetElement(aTable,p.Y); + + CurrentLocationToNextValidPosition = p; + } + + /// + /// Will fill empty cells with valid blank Cells + /// + public void Complete() { + if (mTableInserted == true) { + MergeInsertedTables(); // integrate tables in the table + mTableInserted = false; + } + if (autoFillEmptyCells == true) { + FillEmptyMatrixCells(); + } + } + + /// + /// Changes the border in the default layout of the Cells + /// added with method AddCell(string content). + /// + /// the new border value + public int DefaultCellBorder { + set { + defaultCell.Border = value; + } + } + + /// + /// Changes the width of the borders in the default layout of the Cells + /// added with method AddCell(string content). + /// + /// the new width + public float DefaultCellBorderWidth { + set { + defaultCell.BorderWidth = value; + } + } + + /// + /// Changes the bordercolor in the default layout of the Cells + /// added with method AddCell(string content). + /// + public Color DefaultCellBorderColor { + set { + defaultCell.BorderColor = value; + } + } + + /// + /// Changes the backgroundcolor in the default layout of the Cells + /// added with method AddCell(string content). + /// + /// the new color + public Color DefaultCellBackgroundColor { + set { + defaultCell.BackgroundColor = value; + } + } + + /// + /// Changes the grayfill in the default layout of the Cells + /// added with method AddCell(string content). + /// + /// the new value + public float DefaultCellGrayFill { + set { + if (value >= 0 && value <= 1) { + defaultCell.GrayFill = value; + } + } + } + + /// + /// Changes the horizontalalignment in the default layout of the Cells + /// added with method AddCell(string content). + /// + /// the new alignment value + public int DefaultHorizontalAlignment { + set { + defaultCell.HorizontalAlignment = value; + } + } + + /// + /// Changes the verticalAlignment in the default layout of the Cells + /// added with method AddCell(string content). + /// + /// the new alignment value + public int DefaultVerticalAlignment { + set { + defaultCell.VerticalAlignment = value; + } + } + + /// + /// Changes the rowspan in the default layout of the Cells + /// added with method AddCell(string content). + /// + /// the new rowspan value + public int DefaultRowspan { + set { + defaultCell.Rowspan = value; + } + } + + /// + /// Changes the colspan in the default layout of the Cells + /// added with method AddCell(string content). + /// + /// the new colspan value + public int DefaultColspan { + set { + defaultCell.Colspan = value; + } + } + + // methods + + /// + /// Sets the unset cell properties to be the table defaults. + /// + /// The cell to set to table defaults as necessary. + private void AssumeTableDefaults(Cell aCell) { + + if (aCell.Border == Rectangle.UNDEFINED) { + aCell.Border = defaultCell.Border; + } + if (aCell.BorderWidth == Rectangle.UNDEFINED) { + aCell.BorderWidth = defaultCell.BorderWidth; + } + if (aCell.BorderColor == null) { + aCell.BorderColor = defaultCell.BorderColor; + } + if (aCell.BackgroundColor == null) { + aCell.BackgroundColor = defaultCell.BackgroundColor; + } + if (aCell.HorizontalAlignment == Element.ALIGN_UNDEFINED) { + aCell.HorizontalAlignment = defaultCell.HorizontalAlignment; + } + if (aCell.VerticalAlignment == Element.ALIGN_UNDEFINED) { + aCell.VerticalAlignment = defaultCell.VerticalAlignment; + } + } + + /// + /// Deletes a column in this table. + /// + /// the number of the column that has to be deleted + public void DeleteColumn(int column) { + float[] newWidths = new float[--columns]; + System.Array.Copy(widths, 0, newWidths, 0, column); + System.Array.Copy(widths, column + 1, newWidths, column, columns - column); + Widths = newWidths; + System.Array.Copy(widths, 0, newWidths, 0, columns); + widths = newWidths; + Row row; + int size = rows.Count; + for (int i = 0; i < size; i++) { + row = (Row) rows[i]; + row.DeleteColumn(column); + rows[i] = row; + } + if (column == columns) { + curPosition.X++; + curPosition.Y = 0; + } + } + + /// + /// Deletes a row. + /// + /// the number of the row to delete + /// true if the row was deleted; false if not + public bool DeleteRow(int row) { + if (row < 0 || row >= rows.Count) { + return false; + } + rows.RemoveAt(row); + curPosition.X--; + return true; + } + + /** + * Deletes all rows in this table. + * (contributed by dperezcar@fcc.es) + */ + + public void DeleteAllRows() { + rows.Clear(); + rows.Add(new Row(columns)); + curPosition.X = 0; + curPosition.Y = 0; + lastHeaderRow = -1; + } + + /// + /// Deletes the last row in this table. + /// + /// true if the row was deleted; false if not + public bool DeleteLastRow() { + return DeleteRow(rows.Count - 1); + } + + /// + /// Marks the last row of the table headers. + /// + /// the number of the last row of the table headers + public int EndHeaders() { + /* patch sep 8 2001 Francesco De Milato */ + lastHeaderRow = curPosition.X - 1; + return lastHeaderRow; + } + + // methods to set the membervariables + + /// + /// Sets the horizontal Element. + /// + /// the new value + public int LastHeaderRow { + set { + lastHeaderRow = value; + } + get { + return lastHeaderRow; + } + } + + /// + /// Sets the alignment of this paragraph. + /// + /// the new alignment as a string + public void SetAlignment(string alignment) { + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_LEFT)) { + this.alignment = Element.ALIGN_LEFT; + return; + } + if (Util.EqualsIgnoreCase(alignment, ElementTags.ALIGN_RIGHT)) { + this.alignment = Element.ALIGN_RIGHT; + return; + } + this.alignment = Element.ALIGN_CENTER; + } + + /// + /// Sets the cellpadding. + /// + /// the new value + public float Padding { + set { + cellpadding = value; + } + } + + /// + /// Sets the cellspacing. + /// + /// the new value + public float Spacing { + set { + cellspacing = value; + } + } + + /// + /// Sets the widths of the different columns (percentages). + /// + /// + /// You can give up relative values of borderwidths. + /// The sum of these values will be considered 100%. + /// The values will be recalculated as percentages of this sum. + /// + /// + ///
    +        /// float[] widths = {2, 1, 1};
    +        /// table.SetWidths(widths)
    +        /// 
    + /// + /// The widths will be: a width of 50% for the first column, + /// 25% for the second and third column. + ///
    + /// an array with values + public float[] Widths { + set { + if (value.Length != columns) { + throw new BadElementException("Wrong number of columns."); + } + + // The sum of all values is 100% + float hundredPercent = 0; + for (int i = 0; i < columns; i++) { + hundredPercent += value[i]; + } + + // The different percentages are calculated + float width; + this.widths[columns - 1] = 100; + for (int i = 0; i < columns - 1; i++) { + width = (100.0f * value[i]) / hundredPercent; + this.widths[i] = width; + this.widths[columns - 1] -= width; + } + } + } + + /// + /// Sets the widths of the different columns (percentages). + /// + /// + /// You can give up relative values of borderwidths. + /// The sum of these values will be considered 100%. + /// The values will be recalculated as percentages of this sum. + /// + /// an array with values + public void SetWidths(int[] widths) { + float[] tb = new float[widths.Length]; + for (int k = 0; k < widths.Length; ++k) + tb[k] = widths[k]; + this.Widths = tb; + } + // methods to retrieve the membervariables + + /// + /// Gets the number of columns. + /// + /// a value + public int Columns { + get { + return columns; + } + } + + /// + /// Gets the number of rows in this Table. + /// + /// the number of rows in this Table + public int Size { + get { + return rows.Count; + } + } + + /// + /// Gets the proportional widths of the columns in this Table. + /// + /// the proportional widths of the columns in this Table + public float[] ProportionalWidths { + get { + return widths; + } + } + + /// + /// Gets an Iterator of all the Rows. + /// + /// an IEnumerator + public IEnumerator GetEnumerator() { + return rows.GetEnumerator(); + } + + /// + /// Get/set the horizontal Element. + /// + /// a value + public int Alignment{ + get { + return alignment; + } + + set { + alignment = value; + } + } + + /// + /// Get/set the cellpadding. + /// + /// the cellpadding + public float Cellpadding { + get { + return cellpadding; + } + + set { + this.cellpadding = value; + } + } + + /// + /// Get/set the cellspacing. + /// + /// the cellspacing + public float Cellspacing { + get { + return cellspacing; + } + + set { + this.cellspacing = value; + } + } + + /// + /// Get/set the table width (a percentage). + /// + /// the table width (a percentage) + public override float Width { + get { + return width; + } + set { + this.width = value; + } + } + + /// + /// Gets the dimension of this table + /// + /// the dimension + public System.Drawing.Dimension Dimension { + get { + return new System.Drawing.Dimension(columns, rows.Count); + } + } + + /// + /// returns the element at the position row, column + /// (Cast to Cell or Table) + /// + /// + /// + /// an object + public object GetElement(int row, int column) { + return ((Row) rows[row]).GetCell(column); + } + + /// + /// Integrates all added tables and recalculates column widths. + /// + private void MergeInsertedTables() { + int i=0, j=0; + float [] lNewWidths = null; + int [] lDummyWidths = new int[columns]; // to keep track in how many new cols this one will be split + float[][] lDummyColumnWidths = new float[columns][]; // bugfix Tony Copping + int [] lDummyHeights = new int[rows.Count]; // to keep track in how many new rows this one will be split + ArrayList newRows = null; + bool isTable=false; + int lTotalRows = 0, lTotalColumns = 0; + int lNewMaxRows = 0, lNewMaxColumns = 0; + + Table lDummyTable = null; + + // first we'll add new columns when needed + // check one column at a time, find maximum needed nr of cols + // Search internal tables and find one with max columns + for (j=0; j < columns; j++) { + lNewMaxColumns = 1; // value to hold in how many columns the current one will be split + float [] tmpWidths = null; + for (i=0; i < rows.Count; i++) { + if (((Row) rows[i]).GetCell(j) is Table) { + isTable=true; + lDummyTable = ((Table) ((Row) rows[i]).GetCell(j)); + if ( tmpWidths == null) { + tmpWidths = lDummyTable.widths; + lNewMaxColumns=tmpWidths.Length; + } + else { + int cols = lDummyTable.Dimension.width; + float [] tmpWidthsN = new float[ cols * tmpWidths.Length]; + float tpW=0, btW=0, totW=0; + int tpI=0, btI=0, totI=0; + tpW+=tmpWidths[0]; + btW+=lDummyTable.widths[0]; + while ( tpItpW) { + tmpWidthsN[totI] = tpW-totW; + tpI++; + if (tpI lNewMaxRows ) { + lNewMaxRows = lDummyTable.Dimension.height; + } + } + } + lTotalRows += lNewMaxRows; + lDummyHeights [i] = lNewMaxRows; + } + + if ( (lTotalColumns != columns) || (lTotalRows != rows.Count) || isTable) // NO ADJUSTMENT + { + // ** WIDTH + // set correct width for new columns + // divide width over new nr of columns + // Take new max columns of internal table and work out widths for each col + lNewWidths = new float [lTotalColumns]; + int lDummy = 0; + for (int tel=0; tel < widths.Length;tel++) { + if ( lDummyWidths[tel] != 1) { + // divide + for (int tel2 = 0; tel2 < lDummyWidths[tel]; tel2++) { + lNewWidths[lDummy] = widths[tel] * lDummyColumnWidths[tel][tel2] / 100f; // bugfix Tony Copping + lDummy++; + } + } + else { + lNewWidths[lDummy] = widths[tel]; + lDummy++; + } + } + + // ** FILL OUR NEW TABLE + // generate new table + // set new widths + // copy old values + newRows = new ArrayList(lTotalRows); + for (i = 0; i < lTotalRows; i++) { + newRows.Add(new Row(lTotalColumns)); + } + int lDummyRow = 0, lDummyColumn = 0; // to remember where we are in the new, larger table + Object lDummyElement = null; + for (i=0; i < rows.Count; i++) { + lDummyColumn = 0; + lNewMaxRows = 1; + for (j=0; j < columns; j++) { + if (((Row) rows[i]).GetCell(j) is Table ) // copy values from embedded table + { + lDummyTable = (Table) ((Row) rows[i]).GetCell(j); + + // Work out where columns in table table correspond to columns in current table + int[] colMap = new int[lDummyTable.widths.Length+1]; + int cb=0, ct=0; + + for ( ; cb + /// Integrates all added tables and recalculates column widths. + /// + private void FillEmptyMatrixCells() { + for (int i=0; i < rows.Count; i++) { + for (int j=0; j < columns; j++) { + if ( ((Row) rows[i]).IsReserved(j) == false) { + AddCell(defaultCell, new System.Drawing.Point(i, j)); + } + } + } + } + + /// + /// check if Cell 'fits' the table. + /// + /// + ///
    • rowspan/colspan not beyond borders + ///
    • spanned cell don't overlap existing cells
    + ///
    + /// the cell that has to be checked + /// the location where the cell has to be placed + /// + private bool IsValidLocation(Cell aCell, System.Drawing.Point aLocation) { + // rowspan not beyond last column + if ( aLocation.X < rows.Count ) { // if false : new location is already at new, not-yet-created area so no check + if ((aLocation.Y + aCell.Colspan) > columns) { + return false; + } + + int difx = ((rows.Count - aLocation.X) > aCell.Rowspan) ? aCell.Rowspan : rows.Count - aLocation.X; + int dify = ((columns - aLocation.Y) > aCell.Colspan) ? aCell.Colspan : columns - aLocation.Y; + // no other content at cells targetted by rowspan/colspan + for (int i=aLocation.X; i < (aLocation.X + difx); i++) { + for (int j=aLocation.Y; j < (aLocation.Y + dify); j++) { + if ( ((Row) rows[i]).IsReserved(j) == true ) { + return false; + } + } + } + } + else { + if ((aLocation.Y + aCell.Colspan) > columns) { + return false; + } + } + + return true; + } + + /// + /// Inserts a Cell in a cell-array and reserves cells defined by row-/colspan. + /// + /// some rows + /// the cell that has to be inserted + /// the position where the cell has to be placed + private void PlaceCell(ArrayList someRows, Cell aCell, System.Drawing.Point aPosition) { + int i; + Row row = null; + int rowCount = aPosition.X + aCell.Rowspan - someRows.Count; + AssumeTableDefaults(aCell); + if ( (aPosition.X + aCell.Rowspan) > someRows.Count ) { //create new rows ? + for (i = 0; i < rowCount; i++) { + row = new Row(columns); + someRows.Add(row); + } + } + + // reserve cell in rows below + for (i = aPosition.X + 1; i < (aPosition.X + aCell.Rowspan); i++) { + if ( !((Row) someRows[i]).Reserve(aPosition.Y, aCell.Colspan)) { + + // should be impossible to come here :-) + throw new Exception("addCell - error in reserve"); + } + } + row = (Row) someRows[aPosition.X]; + row.AddElement(aCell, aPosition.Y); + + } + + /// + /// Gives you the posibility to add columns. + /// + /// the number of columns to add + public void AddColumns(int aColumns) { + ArrayList newRows = new ArrayList(rows.Count); + + int newColumns = columns + aColumns; + Row row; + for (int i = 0; i < rows.Count; i++) { + row = new Row(newColumns); + for (int j = 0; j < columns; j++) { + row.SetElement(((Row) rows[i]).GetCell(j) ,j); + } + for (int j = columns; j < newColumns && i < curPosition.X; j++) { + row.SetElement(null, j); + } + newRows.Add(row); + } + + // applied 1 column-fix; last column needs to have a width of 0 + float [] newWidths = new float[newColumns]; + System.Array.Copy(widths, 0, newWidths, 0, columns); + for (int j = columns; j < newColumns ; j++) { + newWidths[j] = 0; + } + columns = newColumns; + widths = newWidths; + rows = newRows; + } + + /// + /// Gets an array with the positions of the borders between every column. + /// + /// + /// This method translates the widths expressed in percentages into the + /// x-coordinate of the borders of the columns on a real document. + /// + /// this is the position of the first border at the left (cellpadding not included) + /// + /// this is the space between the first border at the left + /// and the last border at the right (cellpadding not included) + /// + /// an array with borderpositions + public float[] GetWidths(float left, float totalWidth) { + // for x columns, there are x+1 borders + float[] w = new float[columns + 1]; + float wPercentage; + if (locked) { + wPercentage = 100 * width / totalWidth; + } + else { + wPercentage = width; + } + // the border at the left is calculated + switch (alignment) { + case Element.ALIGN_LEFT: + w[0] = left; + break; + case Element.ALIGN_RIGHT: + w[0] = left + (totalWidth * (100 - wPercentage)) / 100; + break; + case Element.ALIGN_CENTER: + default: + w[0] = left + (totalWidth * (100 - wPercentage)) / 200; + break; + } + // the total available width is changed + totalWidth = (totalWidth * wPercentage) / 100; + // the inner borders are calculated + for (int i = 1; i < columns; i++) { + w[i] = w[i - 1] + (widths[i - 1] * totalWidth / 100); + } + // the border at the right is calculated + w[columns] = w[0] + totalWidth; + return w; + } + + /// + /// Sets current col/row to Valid(empty) pos after addCell/Table + /// + /// a System.Drawing.Point + private System.Drawing.Point CurrentLocationToNextValidPosition { + set { + // set latest location to next valid position + int i, j; + i = value.X; + j = value.Y; + do { + if ( (j + 1) == columns ) { // goto next row + i++; + j = 0; + } + else { + j++; + } + } + while ( + (i < rows.Count) && (j < columns) && (((Row) rows[i]).IsReserved(j) == true) + ); + curPosition = new System.Drawing.Point(i, j); + } + } + + private void ErrorDimensions() { + throw new Exception("Dimensions of a Table can't be calculated. See the FAQ."); + } + + /** + * Returns the next row 0-based index where a new cell would be added. + * (contributed by dperezcar@fcc.es) + * @return x coordinate for the next row + */ + public int NextRow { + get { + return curPosition.X; + } + } + + /** + * Returns the next column 0-based index where a new cell would be added. + * (contributed by dperezcar@fcc.es) + * @return y coordinate for the next row + */ + public int NextColumn { + get { + return curPosition.Y; + } + } + + public override float Bottom { + get { + ErrorDimensions(); + return 0; + } + set { + ErrorDimensions(); + } + } + + public override float Left { + get { + ErrorDimensions(); + return 0; + } + set { + ErrorDimensions(); + } + } + + public override float Right { + get { + ErrorDimensions(); + return 0; + } + set { + ErrorDimensions(); + } + } + + public override float Top { + get { + ErrorDimensions(); + return 0; + } + set { + ErrorDimensions(); + } + } + + public override float GetBottom(float margin) { + ErrorDimensions(); + return 0; + } + + public override float GetLeft(float margin) { + ErrorDimensions(); + return 0; + } + + public override float GetRight(float margin) { + ErrorDimensions(); + return 0; + } + + public override float GetTop(float margin) { + ErrorDimensions(); + return 0; + } + + /** + * Create a PdfPTable based on this Table object. + * @return a PdfPTable object + * @throws BadElementException + */ + public PdfPTable CreatePdfPTable() { + if (!convert2pdfptable) { + throw new BadElementException("No error, just an old style table"); + } + AutoFillEmptyCells = true; + Complete(); + PdfPTable pdfptable = new PdfPTable(widths); + pdfptable.ElementComplete = complete; + if (NotAddedYet) + pdfptable.SkipFirstHeader = true; + pdfptable.TableEvent = SimpleTable.GetDimensionlessInstance(this, cellspacing); + pdfptable.HeaderRows = lastHeaderRow + 1; + pdfptable.SplitLate = cellsFitPage; + pdfptable.KeepTogether = tableFitsPage; + if (!float.IsNaN(offset)) { + pdfptable.SpacingBefore = offset; + } + pdfptable.HorizontalAlignment = alignment; + if (locked) { + pdfptable.TotalWidth = width; + pdfptable.LockedWidth = true; + } + else { + pdfptable.WidthPercentage = width; + } + foreach (Row row in this) { + IElement cell; + PdfPCell pcell; + for (int i = 0; i < row.Columns; i++) { + if ((cell = (IElement)row.GetCell(i)) != null) { + if (cell is Table) { + pcell = new PdfPCell(((Table)cell).CreatePdfPTable()); + } + else if (cell is Cell) { + pcell = ((Cell)cell).CreatePdfPCell(); + pcell.Padding = cellpadding + cellspacing / 2f; + pcell.CellEvent = SimpleCell.GetDimensionlessInstance((Cell)cell, cellspacing); + } + else { + pcell = new PdfPCell(); + } + pdfptable.AddCell(pcell); + } + } + } + return pdfptable; + } + + /** + * If set to true, iText will try to convert the Table to a PdfPTable. + * @param convert2pdfptable true if you want iText to try to convert the Table to a PdfPTable + */ + public bool Convert2pdfptable { + get { + return convert2pdfptable; + } + set { + this.convert2pdfptable = value; + } + } + + public bool Locked { + get { + return locked; + } + set { + locked = value; + } + } + + /** + * Indicates if this is the first time the section is added. + * @since iText2.0.8 + * @return true if the section wasn't added yet + */ + public bool NotAddedYet { + get { + return notAddedYet; + } + set { + notAddedYet = value; + } + } + + /** + * @since iText 2.0.8 + * @see com.lowagie.text.LargeElement#flushContent() + */ + public void FlushContent() { + this.NotAddedYet = false; + ArrayList headerrows = new ArrayList(); + for (int i = 0; i < LastHeaderRow + 1; i++) { + headerrows.Add(rows[i]); + } + rows = headerrows; + } + + /** + * @since iText 2.0.8 + * @see com.lowagie.text.LargeElement#isComplete() + */ + public bool ElementComplete { + get { + return complete; + } + set { + complete = value; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/Utilities.cs b/iTechSharp/iTextSharp/text/Utilities.cs new file mode 100644 index 0000000..d4e1312 --- /dev/null +++ b/iTechSharp/iTextSharp/text/Utilities.cs @@ -0,0 +1,267 @@ +using System; +using System.util; +using System.Collections; +using System.Text; +using System.IO; +using iTextSharp.text.pdf; +/* + * $Id: Utilities.cs,v 1.9 2008/05/13 11:25:13 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text { + + /** + * A collection of convenience methods that were present in many different iText + * classes. + */ + + public class Utilities { + + /// + /// + /// + /// + /// + public static ICollection GetKeySet(Properties table) { + return (table == null) ? new Properties().Keys : table.Keys; + } + + /** + * Utility method to extend an array. + * @param original the original array or null + * @param item the item to be added to the array + * @return a new array with the item appended + */ + public static Object[][] AddToArray(Object[][] original, Object[] item) { + if (original == null) { + original = new Object[1][]; + original[0] = item; + return original; + } + else { + Object[][] original2 = new Object[original.Length + 1][]; + Array.Copy(original, 0, original2, 0, original.Length); + original2[original.Length] = item; + return original2; + } + } + + /** + * Checks for a true/false value of a key in a Properties object. + * @param attributes + * @param key + * @return + */ + public static bool CheckTrueOrFalse(Properties attributes, String key) { + return Util.EqualsIgnoreCase("true", attributes[key]); + } + + /// + /// This method makes a valid URL from a given filename. + /// + /// + /// + /// + /// a given filename + /// a valid URL + public static Uri ToURL(string filename) { + try { + return new Uri(filename); + } + catch { + return new Uri("file:///" + filename); + } + } + + /** + * Unescapes an URL. All the "%xx" are replaced by the 'xx' hex char value. + * @param src the url to unescape + * @return the eunescaped value + */ + public static String UnEscapeURL(String src) { + StringBuilder bf = new StringBuilder(); + char[] s = src.ToCharArray(); + for (int k = 0; k < s.Length; ++k) { + char c = s[k]; + if (c == '%') { + if (k + 2 >= s.Length) { + bf.Append(c); + continue; + } + int a0 = PRTokeniser.GetHex((int)s[k + 1]); + int a1 = PRTokeniser.GetHex((int)s[k + 2]); + if (a0 < 0 || a1 < 0) { + bf.Append(c); + continue; + } + bf.Append((char)(a0 * 16 + a1)); + k += 2; + } + else + bf.Append(c); + } + return bf.ToString(); + } + + private static byte[] skipBuffer = new byte[4096]; + + /// + /// This method is an alternative for the Stream.Skip()-method + /// that doesn't seem to work properly for big values of size. + /// + /// the stream + /// the number of bytes to skip + public static void Skip(Stream istr, int size) { + while (size > 0) { + int r = istr.Read(skipBuffer, 0, Math.Min(skipBuffer.Length, size)); + if (r <= 0) + return; + size -= r; + } + } + + /** + * Measurement conversion from millimeters to points. + * @param value a value in millimeters + * @return a value in points + * @since 2.1.2 + */ + public static float MillimetersToPoints(float value) { + return InchesToPoints(MillimetersToInches(value)); + } + + /** + * Measurement conversion from millimeters to inches. + * @param value a value in millimeters + * @return a value in inches + * @since 2.1.2 + */ + public static float MillimetersToInches(float value) { + return value / 25.4f; + } + + /** + * Measurement conversion from points to millimeters. + * @param value a value in points + * @return a value in millimeters + * @since 2.1.2 + */ + public static float PointsToMillimeters(float value) { + return InchesToMillimeters(PointsToInches(value)); + } + + /** + * Measurement conversion from points to inches. + * @param value a value in points + * @return a value in inches + * @since 2.1.2 + */ + public static float PointsToInches(float value) { + return value / 72f; + } + + /** + * Measurement conversion from inches to millimeters. + * @param value a value in inches + * @return a value in millimeters + * @since 2.1.2 + */ + public static float InchesToMillimeters(float value) { + return value * 25.4f; + } + + /** + * Measurement conversion from inches to points. + * @param value a value in inches + * @return a value in points + * @since 2.1.2 + */ + public static float InchesToPoints(float value) { + return value * 72f; + } + + public static bool IsSurrogateHigh(char c) { + return c >= '\ud800' && c <= '\udbff'; + } + + public static bool IsSurrogateLow(char c) { + return c >= '\udc00' && c <= '\udfff'; + } + + public static bool IsSurrogatePair(string text, int idx) { + if (idx < 0 || idx > text.Length - 2) + return false; + return IsSurrogateHigh(text[idx]) && IsSurrogateLow(text[idx + 1]); + } + + public static bool IsSurrogatePair(char[] text, int idx) { + if (idx < 0 || idx > text.Length - 2) + return false; + return IsSurrogateHigh(text[idx]) && IsSurrogateLow(text[idx + 1]); + } + + public static int ConvertToUtf32(char highSurrogate, char lowSurrogate) { + return (((highSurrogate - 0xd800) * 0x400) + (lowSurrogate - 0xdc00)) + 0x10000; + } + + public static int ConvertToUtf32(char[] text, int idx) { + return (((text[idx] - 0xd800) * 0x400) + (text[idx + 1] - 0xdc00)) + 0x10000; + } + + public static int ConvertToUtf32(string text, int idx) { + return (((text[idx] - 0xd800) * 0x400) + (text[idx + 1] - 0xdc00)) + 0x10000; + } + + public static string ConvertFromUtf32(int codePoint) { + if (codePoint < 0x10000) + return Char.ToString((char)codePoint); + codePoint -= 0x10000; + return new string(new char[]{(char)((codePoint / 0x400) + 0xd800), (char)((codePoint % 0x400) + 0xdc00)}); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/ZapfDingbatsList.cs b/iTechSharp/iTextSharp/text/ZapfDingbatsList.cs new file mode 100644 index 0000000..eaf22cc --- /dev/null +++ b/iTechSharp/iTextSharp/text/ZapfDingbatsList.cs @@ -0,0 +1,85 @@ +using System; + +namespace iTextSharp.text +{ + /** + * + * A special-version of LIST whitch use zapfdingbats-letters. + * + * @see com.lowagie.text.List + * @author Michael Niedermair and Bruno Lowagie + */ + public class ZapfDingbatsList : List { + /** + * char-number in zapfdingbats + */ + protected int zn; + + /** + * Creates a ZapfDingbatsList + * + * @param zn a char-number + */ + public ZapfDingbatsList(int zn) : base(true) { + this.zn = zn; + float fontsize = symbol.Font.Size; + symbol.Font = FontFactory.GetFont(FontFactory.ZAPFDINGBATS, fontsize, Font.NORMAL); + postSymbol = " "; + } + + /** + * Creates a ZapfDingbatsList + * + * @param zn a char-number + * @param symbolIndent indent + */ + public ZapfDingbatsList(int zn, int symbolIndent) : base(true, symbolIndent) { + this.zn = zn; + float fontsize = symbol.Font.Size; + symbol.Font = FontFactory.GetFont(FontFactory.ZAPFDINGBATS, fontsize, Font.NORMAL); + postSymbol = " "; + } + + /** + * set the char-number + * @param zn a char-number + */ + public int CharNumber { + set { + this.zn = value; + } + get { + return this.zn; + } + } + + /** + * Adds an Object to the List. + * + * @param o the object to add. + * @return true if adding the object succeeded + */ + public override bool Add(Object o) { + if (o is ListItem) { + ListItem item = (ListItem) o; + Chunk chunk = new Chunk(preSymbol, symbol.Font); + chunk.Append(((char)zn).ToString()); + chunk.Append(postSymbol); + item.ListSymbol = chunk; + item.SetIndentationLeft(symbolIndent, autoindent); + item.IndentationRight = 0; + list.Add(item); + return true; + } else if (o is List) { + List nested = (List) o; + nested.IndentationLeft = nested.IndentationLeft + symbolIndent; + first--; + list.Add(nested); + return true; + } else if (o is String) { + return this.Add(new ListItem((string) o)); + } + return false; + } + } +} diff --git a/iTechSharp/iTextSharp/text/ZapfDingbatsNumberList.cs b/iTechSharp/iTextSharp/text/ZapfDingbatsNumberList.cs new file mode 100644 index 0000000..5b0d108 --- /dev/null +++ b/iTechSharp/iTextSharp/text/ZapfDingbatsNumberList.cs @@ -0,0 +1,100 @@ +using System; + +namespace iTextSharp.text +{ + /** + * + * A special-version of LIST whitch use zapfdingbats-numbers (1..10). + * + * @see com.lowagie.text.List + * @version 2003-06-22 + * @author Michael Niedermair + */ + public class ZapfDingbatsNumberList : List { + + /** + * which type + */ + protected int type; + + /** + * Creates a ZapdDingbatsNumberList + * @param type the type of list + * @param symbolIndent indent + */ + public ZapfDingbatsNumberList(int type) : base(true) { + this.type = type; + float fontsize = symbol.Font.Size; + symbol.Font = FontFactory.GetFont(FontFactory.ZAPFDINGBATS, fontsize, Font.NORMAL); + postSymbol = " "; + } + + /** + * Creates a ZapdDingbatsNumberList + * @param type the type of list + * @param symbolIndent indent + */ + public ZapfDingbatsNumberList(int type, int symbolIndent) : base(true, symbolIndent) { + this.type = type; + float fontsize = symbol.Font.Size; + symbol.Font = FontFactory.GetFont(FontFactory.ZAPFDINGBATS, fontsize, Font.NORMAL); + postSymbol = " "; + } + + /** + * get the type + * + * @return char-number + */ + public int NumberType { + get { + return type; + } + set { + type = value; + } + } + + /** + * Adds an Object to the List. + * + * @param o the object to add. + * @return true if adding the object succeeded + */ + public override bool Add(Object o) { + if (o is ListItem) { + ListItem item = (ListItem) o; + Chunk chunk = new Chunk(preSymbol, symbol.Font); + switch (type ) { + case 0: + chunk.Append(((char)(first + list.Count + 171)).ToString()); + break; + case 1: + chunk.Append(((char)(first + list.Count + 181)).ToString()); + break; + case 2: + chunk.Append(((char)(first + list.Count + 191)).ToString()); + break; + default: + chunk.Append(((char)(first + list.Count + 201)).ToString()); + break; + } + chunk.Append(postSymbol); + item.ListSymbol = chunk; + item.SetIndentationLeft(symbolIndent, autoindent); + item.IndentationRight = 0; + list.Add(item); + return true; + } else if (o is List) { + List nested = (List) o; + nested.IndentationLeft = nested.IndentationLeft + symbolIndent; + first--; + list.Add(nested); + return true; + } else if (o is String) { + return this.Add(new ListItem((string) o)); + } + return false; + } + } +} diff --git a/iTechSharp/iTextSharp/text/factories/ElementFactory.cs b/iTechSharp/iTextSharp/text/factories/ElementFactory.cs new file mode 100644 index 0000000..06e52b0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/factories/ElementFactory.cs @@ -0,0 +1,533 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text; +using iTextSharp.text.html; +using iTextSharp.text.factories; +/* + * $Id: ElementFactory.cs,v 1.9 2008/05/13 11:25:14 psoares33 Exp $ + * + * + * Copyright 2007 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.factories { + + /** + * This class is able to create Element objects based on a list of properties. + */ + + public class ElementFactory { + + public static Chunk GetChunk(Properties attributes) { + Chunk chunk = new Chunk(); + + chunk.Font = FontFactory.GetFont(attributes); + String value; + + value = attributes[ElementTags.ITEXT]; + if (value != null) { + chunk.Append(value); + } + value = attributes[ElementTags.LOCALGOTO]; + if (value != null) { + chunk.SetLocalGoto(value); + } + value = attributes[ElementTags.REMOTEGOTO]; + if (value != null) { + String page = attributes[ElementTags.PAGE]; + if (page != null) { + chunk.SetRemoteGoto(value, int.Parse(page)); + } + else { + String destination = attributes[ElementTags.DESTINATION]; + if (destination != null) { + chunk.SetRemoteGoto(value, destination); + } + } + } + value = attributes[ElementTags.LOCALDESTINATION]; + if (value != null) { + chunk.SetLocalDestination(value); + } + value = attributes[ElementTags.SUBSUPSCRIPT]; + if (value != null) { + chunk.SetTextRise(float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo)); + } + value = attributes[Markup.CSS_KEY_VERTICALALIGN]; + if (value != null && value.EndsWith("%")) { + float p = float.Parse(value.Substring(0, value.Length - 1), System.Globalization.NumberFormatInfo.InvariantInfo) / 100f; + chunk.SetTextRise(p * chunk.Font.Size); + } + value = attributes[ElementTags.GENERICTAG]; + if (value != null) { + chunk.SetGenericTag(value); + } + value = attributes[ElementTags.BACKGROUNDCOLOR]; + if (value != null) { + chunk.SetBackground(Markup.DecodeColor(value)); + } + return chunk; + } + + public static Phrase GetPhrase(Properties attributes) { + Phrase phrase = new Phrase(); + phrase.Font = FontFactory.GetFont(attributes); + String value; + value = attributes[ElementTags.LEADING]; + if (value != null) { + phrase.Leading = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[Markup.CSS_KEY_LINEHEIGHT]; + if (value != null) { + phrase.Leading = Markup.ParseLength(value); + } + value = attributes[ElementTags.ITEXT]; + if (value != null) { + Chunk chunk = new Chunk(value); + if ((value = attributes[ElementTags.GENERICTAG]) != null) { + chunk.SetGenericTag(value); + } + phrase.Add(chunk); + } + return phrase; + } + + public static Anchor GetAnchor(Properties attributes) { + Anchor anchor = new Anchor(GetPhrase(attributes)); + String value; + value = attributes[ElementTags.NAME]; + if (value != null) { + anchor.Name = value; + } + value = (String)attributes.Remove(ElementTags.REFERENCE); + if (value != null) { + anchor.Reference = value; + } + return anchor; + } + + public static Paragraph GetParagraph(Properties attributes) { + Paragraph paragraph = new Paragraph(GetPhrase(attributes)); + String value; + value = attributes[ElementTags.ALIGN]; + if (value != null) { + paragraph.SetAlignment(value); + } + value = attributes[ElementTags.INDENTATIONLEFT]; + if (value != null) { + paragraph.IndentationLeft = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.INDENTATIONRIGHT]; + if (value != null) { + paragraph.IndentationRight = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + return paragraph; + } + + public static ListItem GetListItem(Properties attributes) { + ListItem item = new ListItem(GetParagraph(attributes)); + return item; + } + + public static List GetList(Properties attributes) { + List list = new List(); + + list.Numbered = Utilities.CheckTrueOrFalse(attributes, ElementTags.NUMBERED); + list.Lettered = Utilities.CheckTrueOrFalse(attributes, ElementTags.LETTERED); + list.Lowercase = Utilities.CheckTrueOrFalse(attributes, ElementTags.LOWERCASE); + list.Autoindent = Utilities.CheckTrueOrFalse(attributes, ElementTags.AUTO_INDENT_ITEMS); + list.Alignindent = Utilities.CheckTrueOrFalse(attributes, ElementTags.ALIGN_INDENTATION_ITEMS); + + String value; + + value = attributes[ElementTags.FIRST]; + if (value != null) { + char character = value[0]; + if (char.IsLetter(character) ) { + list.First = (int)character; + } + else { + list.First = int.Parse(value); + } + } + + value = attributes[ElementTags.LISTSYMBOL]; + if (value != null) { + list.ListSymbol = new Chunk(value, FontFactory.GetFont(attributes)); + } + + value = attributes[ElementTags.INDENTATIONLEFT]; + if (value != null) { + list.IndentationLeft = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + + value = attributes[ElementTags.INDENTATIONRIGHT]; + if (value != null) { + list.IndentationRight = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + + value = attributes[ElementTags.SYMBOLINDENT]; + if (value != null) { + list.SymbolIndent = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + + return list; + } + + public static Cell GetCell(Properties attributes) { + Cell cell = new Cell(); + String value; + + cell.SetHorizontalAlignment(attributes[ElementTags.HORIZONTALALIGN]); + cell.SetVerticalAlignment(attributes[ElementTags.VERTICALALIGN]); + value = attributes[ElementTags.WIDTH]; + if (value != null) { + cell.SetWidth(value); + } + value = attributes[ElementTags.COLSPAN]; + if (value != null) { + cell.Colspan = int.Parse(value); + } + value = attributes[ElementTags.ROWSPAN]; + if (value != null) { + cell.Rowspan = int.Parse(value); + } + value = attributes[ElementTags.LEADING]; + if (value != null) { + cell.Leading = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + cell.Header = Utilities.CheckTrueOrFalse(attributes, ElementTags.HEADER); + if (Utilities.CheckTrueOrFalse(attributes, ElementTags.NOWRAP)) { + cell.MaxLines = 1; + } + SetRectangleProperties(cell, attributes); + return cell; + } + + /** + * Creates an Table object based on a list of properties. + * @param attributes + * @return a Table + */ + public static Table GetTable(Properties attributes) { + String value; + Table table; + + value = attributes[ElementTags.WIDTHS]; + if (value != null) { + StringTokenizer widthTokens = new StringTokenizer(value, ";"); + ArrayList values = new ArrayList(); + while (widthTokens.HasMoreTokens()) { + values.Add(widthTokens.NextToken()); + } + table = new Table(values.Count); + float[] widths = new float[table.Columns]; + for (int i = 0; i < values.Count; i++) { + value = (String)values[i]; + widths[i] = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + table.Widths = widths; + } + else { + value = attributes[ElementTags.COLUMNS]; + try { + table = new Table(int.Parse(value)); + } + catch { + table = new Table(1); + } + } + + table.Border = Table.BOX; + table.BorderWidth = 1; + table.DefaultCell.Border = Table.BOX; + + value = attributes[ElementTags.LASTHEADERROW]; + if (value != null) { + table.LastHeaderRow = int.Parse(value); + } + value = attributes[ElementTags.ALIGN]; + if (value != null) { + table.SetAlignment(value); + } + value = attributes[ElementTags.CELLSPACING]; + if (value != null) { + table.Spacing = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.CELLPADDING]; + if (value != null) { + table.Padding = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.OFFSET]; + if (value != null) { + table.Offset = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.WIDTH]; + if (value != null) { + if (value.EndsWith("%")) + table.Width = float.Parse(value.Substring(0, value.Length - 1), System.Globalization.NumberFormatInfo.InvariantInfo); + else { + table.Width = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + table.Locked = true; + } + } + table.TableFitsPage = Utilities.CheckTrueOrFalse(attributes, ElementTags.TABLEFITSPAGE); + table.CellsFitPage = Utilities.CheckTrueOrFalse(attributes, ElementTags.CELLSFITPAGE); + table.Convert2pdfptable = Utilities.CheckTrueOrFalse(attributes, ElementTags.CONVERT2PDFP); + + SetRectangleProperties(table, attributes); + return table; + } + + /** + * Sets some Rectangle properties (for a Cell, Table,...). + */ + private static void SetRectangleProperties(Rectangle rect, Properties attributes) { + String value; + value = attributes[ElementTags.BORDERWIDTH]; + if (value != null) { + rect.BorderWidth = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + int border = 0; + if (Utilities.CheckTrueOrFalse(attributes, ElementTags.LEFT)) { + border |= Rectangle.LEFT_BORDER; + } + if (Utilities.CheckTrueOrFalse(attributes, ElementTags.RIGHT)) { + border |= Rectangle.RIGHT_BORDER; + } + if (Utilities.CheckTrueOrFalse(attributes, ElementTags.TOP)) { + border |= Rectangle.TOP_BORDER; + } + if (Utilities.CheckTrueOrFalse(attributes, ElementTags.BOTTOM)) { + border |= Rectangle.BOTTOM_BORDER; + } + rect.Border = border; + + String r = attributes[ElementTags.RED]; + String g = attributes[ElementTags.GREEN]; + String b = attributes[ElementTags.BLUE]; + if (r != null || g != null || b != null) { + int red = 0; + int green = 0; + int blue = 0; + if (r != null) red = int.Parse(r); + if (g != null) green = int.Parse(g); + if (b != null) blue = int.Parse(b); + rect.BorderColor = new Color(red, green, blue); + } + else { + rect.BorderColor = Markup.DecodeColor(attributes[ElementTags.BORDERCOLOR]); + } + r = (String)attributes.Remove(ElementTags.BGRED); + g = (String)attributes.Remove(ElementTags.BGGREEN); + b = (String)attributes.Remove(ElementTags.BGBLUE); + value = attributes[ElementTags.BACKGROUNDCOLOR]; + if (r != null || g != null || b != null) { + int red = 0; + int green = 0; + int blue = 0; + if (r != null) red = int.Parse(r); + if (g != null) green = int.Parse(g); + if (b != null) blue = int.Parse(b); + rect.BackgroundColor = new Color(red, green, blue); + } + else if (value != null) { + rect.BackgroundColor = Markup.DecodeColor(value); + } + else { + value = attributes[ElementTags.GRAYFILL]; + if (value != null) { + rect.GrayFill = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + } + } + + public static ChapterAutoNumber GetChapter(Properties attributes) { + ChapterAutoNumber chapter = new ChapterAutoNumber(""); + SetSectionParameters(chapter, attributes); + return chapter; + } + + public static Section GetSection(Section parent, Properties attributes) { + Section section = parent.AddSection(""); + SetSectionParameters(section, attributes); + return section; + } + + private static void SetSectionParameters(Section section, Properties attributes) { + String value; + value = attributes[ElementTags.NUMBERDEPTH]; + if (value != null) { + section.NumberDepth = int.Parse(value); + } + value = attributes[ElementTags.INDENT]; + if (value != null) { + section.Indentation = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.INDENTATIONLEFT]; + if (value != null) { + section.IndentationLeft = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.INDENTATIONRIGHT]; + if (value != null) { + section.IndentationRight = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + } + + /// + /// Returns an Image that has been constructed taking in account + /// the value of some attributes. + /// + /// Some attributes + /// an Image + public static Image GetImage(Properties attributes) { + String value; + + value = attributes[ElementTags.URL]; + if (value == null) + throw new ArgumentException("The URL of the image is missing."); + Image image = Image.GetInstance(value); + + value = attributes[ElementTags.ALIGN]; + int align = 0; + if (value != null) { + if (Util.EqualsIgnoreCase(ElementTags.ALIGN_LEFT, value)) + align |= Image.ALIGN_LEFT; + else if (Util.EqualsIgnoreCase(ElementTags.ALIGN_RIGHT, value)) + align |= Image.ALIGN_RIGHT; + else if (Util.EqualsIgnoreCase(ElementTags.ALIGN_MIDDLE, value)) + align |= Image.ALIGN_MIDDLE; + } + if (Util.EqualsIgnoreCase("true", attributes[ElementTags.UNDERLYING])) + align |= Image.UNDERLYING; + if (Util.EqualsIgnoreCase("true", attributes[ElementTags.TEXTWRAP])) + align |= Image.TEXTWRAP; + image.Alignment = align; + + value = attributes[ElementTags.ALT]; + if (value != null) { + image.Alt = value; + } + + String x = attributes[ElementTags.ABSOLUTEX]; + String y = attributes[ElementTags.ABSOLUTEY]; + if ((x != null) && (y != null)) { + image.SetAbsolutePosition(float.Parse(x, System.Globalization.NumberFormatInfo.InvariantInfo), + float.Parse(y, System.Globalization.NumberFormatInfo.InvariantInfo)); + } + value = attributes[ElementTags.PLAINWIDTH]; + if (value != null) { + image.ScaleAbsoluteWidth(float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo)); + } + value = attributes[ElementTags.PLAINHEIGHT]; + if (value != null) { + image.ScaleAbsoluteHeight(float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo)); + } + value = attributes[ElementTags.ROTATION]; + if (value != null) { + image.Rotation = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + return image; + } + + /** + * Creates an Annotation object based on a list of properties. + * @param attributes + * @return an Annotation + */ + public static Annotation GetAnnotation(Properties attributes) { + float llx = 0, lly = 0, urx = 0, ury = 0; + String value; + + value = attributes[ElementTags.LLX]; + if (value != null) { + llx = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.LLY]; + if (value != null) { + lly = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.URX]; + if (value != null) { + urx = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + value = attributes[ElementTags.URY]; + if (value != null) { + ury = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + + String title = attributes[ElementTags.TITLE]; + String text = attributes[ElementTags.CONTENT]; + if (title != null || text != null) { + return new Annotation(title, text, llx, lly, urx, ury); + } + value = attributes[ElementTags.URL]; + if (value != null) { + return new Annotation(llx, lly, urx, ury, value); + } + value = attributes[ElementTags.NAMED]; + if (value != null) { + return new Annotation(llx, lly, urx, ury, int.Parse(value)); + } + String file = attributes[ElementTags.FILE]; + String destination = attributes[ElementTags.DESTINATION]; + String page = (String) attributes.Remove(ElementTags.PAGE); + if (file != null) { + if (destination != null) { + return new Annotation(llx, lly, urx, ury, file, destination); + } + if (page != null) { + return new Annotation(llx, lly, urx, ury, file, int.Parse(page)); + } + } + if (title == null) + title = ""; + if (text == null) + text = ""; + return new Annotation(title, text, llx, lly, urx, ury); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/factories/GreekAlphabetFactory.cs b/iTechSharp/iTextSharp/text/factories/GreekAlphabetFactory.cs new file mode 100644 index 0000000..13b9eda --- /dev/null +++ b/iTechSharp/iTextSharp/text/factories/GreekAlphabetFactory.cs @@ -0,0 +1,122 @@ +using System; +using iTextSharp.text; +/* + * $Id: GreekAlphabetFactory.cs,v 1.2 2008/05/13 11:25:14 psoares33 Exp $ + * + * + * Copyright 2007 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.factories { + + /** + * This class can produce String combinations representing a number built with + * Greek letters (from alpha to omega, then alpha alpha, alpha beta, alpha gamma). + * We are aware of the fact that the original Greek numbering is different; + * See http://www.cogsci.indiana.edu/farg/harry/lan/grknum.htm#ancient + * but this isn't implemented yet; the main reason being the fact that we + * need a font that has the obsolete Greek characters qoppa and sampi. + */ + public class GreekAlphabetFactory { + /** + * Changes an int into a lower case Greek letter combination. + * @param index the original number + * @return the letter combination + */ + public static String GetString(int index) { + return GetString(index, true); + } + + /** + * Changes an int into a lower case Greek letter combination. + * @param index the original number + * @return the letter combination + */ + public static String GetLowerCaseString(int index) { + return GetString(index); + } + + /** + * Changes an int into a upper case Greek letter combination. + * @param index the original number + * @return the letter combination + */ + public static String GetUpperCaseString(int index) { + return GetString(index).ToUpper(System.Globalization.CultureInfo.InvariantCulture); + } + + /** + * Changes an int into a Greek letter combination. + * @param index the original number + * @return the letter combination + */ + public static String GetString(int index, bool lowercase) { + if (index < 1) return ""; + index--; + + int bytes = 1; + int start = 0; + int symbols = 24; + while (index >= symbols + start) { + bytes++; + start += symbols; + symbols *= 24; + } + + int c = index - start; + char[] value = new char[bytes]; + while (bytes > 0) { + bytes--; + value[bytes] = (char)(c % 24); + if (value[bytes] > 16) value[bytes]++; + value[bytes] += (char)(lowercase ? 945 : 913); + value[bytes] = SpecialSymbol.GetCorrespondingSymbol(value[bytes]); + c /= 24; + } + + return new String(value); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/factories/RomanAlphabetFactory.cs b/iTechSharp/iTextSharp/text/factories/RomanAlphabetFactory.cs new file mode 100644 index 0000000..f6d5f13 --- /dev/null +++ b/iTechSharp/iTextSharp/text/factories/RomanAlphabetFactory.cs @@ -0,0 +1,122 @@ +using System; +/* + * $Id: RomanAlphabetFactory.cs,v 1.2 2008/05/13 11:25:14 psoares33 Exp $ + * + * + * Copyright 2007 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.factories { + + /** + * This class can produce String combinations representing a number. + * "a" to "z" represent 1 to 26, "AA" represents 27, "AB" represents 28, + * and so on; "ZZ" is followed by "AAA". + */ + public class RomanAlphabetFactory { + + /** + * Translates a positive integer (not equal to zero) + * into a String using the letters 'a' to 'z'; + * 1 = a, 2 = b, ..., 26 = z, 27 = aa, 28 = ab,... + */ + public static String GetString(int index) { + if (index < 1) throw new FormatException("You can't translate a negative number into an alphabetical value."); + + index--; + int bytes = 1; + int start = 0; + int symbols = 26; + while (index >= symbols + start) { + bytes++; + start += symbols; + symbols *= 26; + } + + int c = index - start; + char[] value = new char[bytes]; + while (bytes > 0) { + value[--bytes] = (char)( 'a' + (c % 26)); + c /= 26; + } + + return new String(value); + } + + /** + * Translates a positive integer (not equal to zero) + * into a String using the letters 'a' to 'z'; + * 1 = a, 2 = b, ..., 26 = z, 27 = aa, 28 = ab,... + */ + public static String GetLowerCaseString(int index) { + return GetString(index); + } + + /** + * Translates a positive integer (not equal to zero) + * into a String using the letters 'A' to 'Z'; + * 1 = A, 2 = B, ..., 26 = Z, 27 = AA, 28 = AB,... + */ + public static String GetUpperCaseString(int index) { + return GetString(index).ToUpper(System.Globalization.CultureInfo.InvariantCulture); + } + + + /** + * Translates a positive integer (not equal to zero) + * into a String using the letters 'a' to 'z' + * (a = 1, b = 2, ..., z = 26, aa = 27, ab = 28,...). + */ + public static String GetString(int index, bool lowercase) { + if (lowercase) { + return GetLowerCaseString(index); + } + else { + return GetUpperCaseString(index); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/factories/RomanNumberFactory.cs b/iTechSharp/iTextSharp/text/factories/RomanNumberFactory.cs new file mode 100644 index 0000000..566caad --- /dev/null +++ b/iTechSharp/iTextSharp/text/factories/RomanNumberFactory.cs @@ -0,0 +1,180 @@ +using System; +using System.Text; +/* + * $Id: RomanNumberFactory.cs,v 1.2 2008/05/13 11:25:14 psoares33 Exp $ + * + * + * Copyright 2007 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.factories { + /** + * This class can produce String combinations representing a roman number. + */ + public class RomanNumberFactory { + /** + * Helper class for Roman Digits + */ + internal class RomanDigit { + + /** part of a roman number */ + public char digit; + + /** value of the roman digit */ + public int value; + + /** can the digit be used as a prefix */ + public bool pre; + + /** + * Constructs a roman digit + * @param digit the roman digit + * @param value the value + * @param pre can it be used as a prefix + */ + internal RomanDigit(char digit, int value, bool pre) { + this.digit = digit; + this.value = value; + this.pre = pre; + } + } + + /** + * Array with Roman digits. + */ + private static RomanDigit[] roman = { + new RomanDigit('m', 1000, false), + new RomanDigit('d', 500, false), + new RomanDigit('c', 100, true), + new RomanDigit('l', 50, false), + new RomanDigit('x', 10, true), + new RomanDigit('v', 5, false), + new RomanDigit('i', 1, true) + }; + + /** + * Changes an int into a lower case roman number. + * @param index the original number + * @return the roman number (lower case) + */ + public static String GetString(int index) { + StringBuilder buf = new StringBuilder(); + + // lower than 0 ? Add minus + if (index < 0) { + buf.Append('-'); + index = -index; + } + + // greater than 3000 + if (index > 3000) { + buf.Append('|'); + buf.Append(GetString(index / 1000)); + buf.Append('|'); + // remainder + index = index - (index / 1000) * 1000; + } + + // number between 1 and 3000 + int pos = 0; + while (true) { + // loop over the array with values for m-d-c-l-x-v-i + RomanDigit dig = roman[pos]; + // adding as many digits as we can + while (index >= dig.value) { + buf.Append(dig.digit); + index -= dig.value; + } + // we have the complete number + if (index <= 0) { + break; + } + // look for the next digit that can be used in a special way + int j = pos; + while (!roman[++j].pre); + + // does the special notation apply? + if (index + roman[j].value >= dig.value) { + buf.Append(roman[j].digit).Append(dig.digit); + index -= dig.value - roman[j].value; + } + pos++; + } + return buf.ToString(); + } + + /** + * Changes an int into a lower case roman number. + * @param index the original number + * @return the roman number (lower case) + */ + public static String GetLowerCaseString(int index) { + return GetString(index); + } + + /** + * Changes an int into an upper case roman number. + * @param index the original number + * @return the roman number (lower case) + */ + public static String GetUpperCaseString(int index) { + return GetString(index).ToUpper(System.Globalization.CultureInfo.InvariantCulture); + } + + /** + * Changes an int into a roman number. + * @param index the original number + * @return the roman number (lower case) + */ + public static String GetString(int index, bool lowercase) { + if (lowercase) { + return GetLowerCaseString(index); + } + else { + return GetUpperCaseString(index); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/HtmlEncoder.cs b/iTechSharp/iTextSharp/text/html/HtmlEncoder.cs new file mode 100644 index 0000000..c87edbb --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/HtmlEncoder.cs @@ -0,0 +1,213 @@ +using System; +using System.Text; +using System.Drawing; + +using iTextSharp.text; + +/* + * $Id: HtmlEncoder.cs,v 1.6 2008/05/13 11:25:15 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + /** + * This class converts a String to the HTML-format of a String. + *

    + * To convert the String, each character is examined: + *

      + *
    • ASCII-characters from 000 till 031 are represented as &#xxx;
      + * (with xxx = the value of the character) + *
    • ASCII-characters from 032 t/m 127 are represented by the character itself, except for: + *
        + *
      • '\n' becomes <BR>\n + *
      • " becomes &quot; + *
      • & becomes &amp; + *
      • < becomes &lt; + *
      • > becomes &gt; + *
      + *
    • ASCII-characters from 128 till 255 are represented as &#xxx;
      + * (with xxx = the value of the character) + *
    + *

    + * Example: + *

    +     *    String htmlPresentation = HtmlEncoder.Encode("Marie-Thérèse Sørensen");
    +     * 

    + * for more info: see O'Reilly; "HTML: The Definitive Guide" (page 164) + * + * @author mario.maccarini@rug.ac.be + */ + + public sealed class HtmlEncoder { + + // membervariables + + /** List with the HTML translation of all the characters. */ + private static String[] htmlCode = new String[256]; + + static HtmlEncoder() { + for (int i = 0; i < 10; i++) { + htmlCode[i] = "�" + i + ";"; + } + + for (int i = 10; i < 32; i++) { + htmlCode[i] = "�" + i + ";"; + } + + for (int i = 32; i < 128; i++) { + htmlCode[i] = ((char)i).ToString(); + } + + // Special characters + htmlCode['\t'] = "\t"; + htmlCode['\n'] = "<" + HtmlTags.NEWLINE + " />\n"; + htmlCode['\"'] = """; // double quote + htmlCode['&'] = "&"; // ampersand + htmlCode['<'] = "<"; // lower than + htmlCode['>'] = ">"; // greater than + + for (int i = 128; i < 256; i++) { + htmlCode[i] = "&#" + i + ";"; + } + } + + + // constructors + + /** + * This class will never be constructed. + *

    + * HtmlEncoder only contains static methods. + */ + + private HtmlEncoder () { } + + // methods + + /** + * Converts a String to the HTML-format of this String. + * + * @param string The String to convert + * @return a String + */ + + public static String Encode(String str) { + int n = str.Length; + char character; + StringBuilder buffer = new StringBuilder(); + // loop over all the characters of the String. + for (int i = 0; i < n; i++) { + character = str[i]; + // the Htmlcode of these characters are added to a StringBuilder one by one + if (character < 256) { + buffer.Append(htmlCode[character]); + } + else { + // Improvement posted by Joachim Eyrich + buffer.Append("&#").Append((int)character).Append(';'); + } + } + return buffer.ToString(); + } + + /** + * Converts a Color into a HTML representation of this Color. + * + * @param color the Color that has to be converted. + * @return the HTML representation of this Color + */ + + public static String Encode(Color color) { + StringBuilder buffer = new StringBuilder("#"); + if (color.R < 16) { + buffer.Append('0'); + } + buffer.Append(System.Convert.ToString(color.R, 16)); + if (color.G < 16) { + buffer.Append('0'); + } + buffer.Append(System.Convert.ToString(color.G, 16)); + if (color.B < 16) { + buffer.Append('0'); + } + buffer.Append(System.Convert.ToString(color.B, 16)); + return buffer.ToString(); + } + + /** + * Translates the alignment value. + * + * @param alignment the alignment value + * @return the translated value + */ + + public static String GetAlignment(int alignment) { + switch (alignment) { + case Element.ALIGN_LEFT: + return HtmlTags.ALIGN_LEFT; + case Element.ALIGN_CENTER: + return HtmlTags.ALIGN_CENTER; + case Element.ALIGN_RIGHT: + return HtmlTags.ALIGN_RIGHT; + case Element.ALIGN_JUSTIFIED: + case Element.ALIGN_JUSTIFIED_ALL: + return HtmlTags.ALIGN_JUSTIFIED; + case Element.ALIGN_TOP: + return HtmlTags.ALIGN_TOP; + case Element.ALIGN_MIDDLE: + return HtmlTags.ALIGN_MIDDLE; + case Element.ALIGN_BOTTOM: + return HtmlTags.ALIGN_BOTTOM; + case Element.ALIGN_BASELINE: + return HtmlTags.ALIGN_BASELINE; + default: + return ""; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/HtmlParser.cs b/iTechSharp/iTextSharp/text/html/HtmlParser.cs new file mode 100644 index 0000000..293d61c --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/HtmlParser.cs @@ -0,0 +1,239 @@ +using System; +using System.IO; +using System.Xml; +using System.Collections; + +using iTextSharp.text; +using iTextSharp.text.xml; + +/* + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + + ///

    + /// This class can be used to parse an XML file. + /// + public class HtmlParser : XmlParser{ + + /// + /// Constructs an XmlParser. + /// + public HtmlParser() { + } + + /// + /// Parses a given file. + /// + /// + /// + public override void Go(IDocListener document, XmlDocument xDoc) { + parser = new ITextmyHtmlHandler(document); + parser.Parse(xDoc); + } + + /// + /// Parses a given file. + /// + /// + /// + public override void Go(IDocListener document, String file) { + parser = new ITextmyHtmlHandler(document); + parser.Parse(file); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + public override void Go(IDocListener document, XmlTextReader reader) { + parser = new ITextmyHtmlHandler(document); + parser.Parse(reader); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public override void Go(IDocListener document, XmlDocument xDoc, XmlDocument xTagmap) { + parser = new ITextmyHtmlHandler(document, new TagMap(xTagmap)); + parser.Parse(xDoc); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + /// + public override void Go(IDocListener document, XmlTextReader reader, String tagmap) { + parser = new ITextmyHtmlHandler(document, new TagMap(tagmap)); + parser.Parse(reader); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public override void Go(IDocListener document, String file, String tagmap) { + parser = new ITextmyHtmlHandler(document, new TagMap(tagmap)); + parser.Parse(file); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public override void Go(IDocListener document, String file, Hashtable tagmap) { + parser = new ITextmyHtmlHandler(document, tagmap); + parser.Parse(file); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + /// + public override void Go(IDocListener document, XmlTextReader reader, Hashtable tagmap) { + parser = new ITextmyHtmlHandler(document, tagmap); + parser.Parse(reader); + } + + /// + /// Parses a given file. + /// + /// + /// + public new static void Parse(IDocListener document, XmlDocument xDoc) { + HtmlParser p = new HtmlParser(); + p.Go(document, xDoc); + } + + /// + /// Parses a given file. + /// + /// + /// + public new static void Parse(IDocListener document, String file) { + HtmlParser p = new HtmlParser(); + p.Go(document, file); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + public new static void Parse(IDocListener document, XmlTextReader reader) { + HtmlParser p = new HtmlParser(); + p.Go(document, reader); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public new static void Parse(IDocListener document, XmlDocument xDoc, XmlDocument xTagmap) { + HtmlParser p = new HtmlParser(); + p.Go(document, xDoc, xTagmap); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public new static void Parse(IDocListener document, String file, String tagmap) { + HtmlParser p = new HtmlParser(); + p.Go(document, file, tagmap); + } + + /// + /// Parses a given file. + /// + /// + /// + /// + public new static void Parse(IDocListener document, String file, Hashtable tagmap) { + HtmlParser p = new HtmlParser(); + p.Go(document, file, tagmap); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + /// + public new static void Parse(IDocListener document, XmlTextReader reader, String tagmap) { + HtmlParser p = new HtmlParser(); + p.Go(document, reader, tagmap); + } + + /// + /// Parses a given XmlTextReader. + /// + /// + /// + /// + public new static void Parse(IDocListener document, XmlTextReader reader, Hashtable tagmap) { + HtmlParser p = new HtmlParser(); + p.Go(document, reader, tagmap); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/HtmlPeer.cs b/iTechSharp/iTextSharp/text/html/HtmlPeer.cs new file mode 100644 index 0000000..c0bc0ac --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/HtmlPeer.cs @@ -0,0 +1,102 @@ +using System; +using System.Globalization; +using System.Collections; +using iTextSharp.text.xml; +using System.util; + +/* + * $Id: HtmlPeer.cs,v 1.4 2008/05/13 11:25:15 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + + /** + * This interface is implemented by the peer of all the iText objects. + */ + + public class HtmlPeer : XmlPeer { + + /** + * Creates a XmlPeer. + * @param name the iText name of the tag + * @param alias the Html name of the tag + */ + + public HtmlPeer(String name, String alias) : base(name, alias.ToLower(CultureInfo.InvariantCulture)) { + } + + /** + * Sets an alias for an attribute. + * + * @param name the iText tagname + * @param alias the custom tagname + */ + + public override void AddAlias(String name, String alias) { + attributeAliases.Add(alias.ToLower(CultureInfo.InvariantCulture), name); + } + + /** + * @see com.lowagie.text.xml.XmlPeer#getAttributes(org.xml.sax.Attributes) + */ + public override Properties GetAttributes(Hashtable attrs) { + Properties attributes = new Properties(); + attributes.AddAll(attributeValues); + if (defaultContent != null) { + attributes[ElementTags.ITEXT] = defaultContent; + } + if (attrs != null) { + foreach (string key in attrs.Keys) { + attributes.Add(GetName(key).ToLower(CultureInfo.InvariantCulture), (string)attrs[key]); + } + } + return attributes; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/HtmlTagMap.cs b/iTechSharp/iTextSharp/text/html/HtmlTagMap.cs new file mode 100644 index 0000000..5eb170f --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/HtmlTagMap.cs @@ -0,0 +1,289 @@ +using System; +using System.util; +using System.Collections; +using iTextSharp.text; + +/* + * $Id: HtmlTagMap.cs,v 1.4 2008/05/13 11:25:15 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + + /** + * The Tags-class maps several XHTML-tags to iText-objects. + */ + + public class HtmlTagMap : Hashtable { + + /** + * Constructs an HtmlTagMap. + */ + + public HtmlTagMap() { + HtmlPeer peer; + + peer = new HtmlPeer(ElementTags.ITEXT, HtmlTags.HTML); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.SPAN); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.CHUNK, HtmlTags.CHUNK); + peer.AddAlias(ElementTags.FONT, HtmlTags.FONT); + peer.AddAlias(ElementTags.SIZE, HtmlTags.SIZE); + peer.AddAlias(ElementTags.COLOR, HtmlTags.COLOR); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.ANCHOR, HtmlTags.ANCHOR); + peer.AddAlias(ElementTags.NAME, HtmlTags.NAME); + peer.AddAlias(ElementTags.REFERENCE, HtmlTags.REFERENCE); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PARAGRAPH, HtmlTags.PARAGRAPH); + peer.AddAlias(ElementTags.ALIGN, HtmlTags.ALIGN); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PARAGRAPH, HtmlTags.DIV); + peer.AddAlias(ElementTags.ALIGN, HtmlTags.ALIGN); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PARAGRAPH, HtmlTags.H[0]); + peer.AddValue(ElementTags.SIZE, "20"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PARAGRAPH, HtmlTags.H[1]); + peer.AddValue(ElementTags.SIZE, "18"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PARAGRAPH, HtmlTags.H[2]); + peer.AddValue(ElementTags.SIZE, "16"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PARAGRAPH, HtmlTags.H[3]); + peer.AddValue(ElementTags.SIZE, "14"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PARAGRAPH, HtmlTags.H[4]); + peer.AddValue(ElementTags.SIZE, "12"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PARAGRAPH, HtmlTags.H[5]); + peer.AddValue(ElementTags.SIZE, "10"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.LIST, HtmlTags.ORDEREDLIST); + peer.AddValue(ElementTags.NUMBERED, "true"); + peer.AddValue(ElementTags.SYMBOLINDENT, "20"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.LIST, HtmlTags.UNORDEREDLIST); + peer.AddValue(ElementTags.NUMBERED, "false"); + peer.AddValue(ElementTags.SYMBOLINDENT, "20"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.LISTITEM, HtmlTags.LISTITEM); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.I); + peer.AddValue(ElementTags.STYLE, Markup.CSS_VALUE_ITALIC); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.EM); + peer.AddValue(ElementTags.STYLE, Markup.CSS_VALUE_ITALIC); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.B); + peer.AddValue(ElementTags.STYLE, Markup.CSS_VALUE_BOLD); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.STRONG); + peer.AddValue(ElementTags.STYLE, Markup.CSS_VALUE_BOLD); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.S); + peer.AddValue(ElementTags.STYLE, Markup.CSS_VALUE_LINETHROUGH); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.CODE); + peer.AddValue(ElementTags.FONT, FontFactory.COURIER); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.VAR); + peer.AddValue(ElementTags.FONT, FontFactory.COURIER); + peer.AddValue(ElementTags.STYLE, Markup.CSS_VALUE_ITALIC); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.PHRASE, HtmlTags.U); + peer.AddValue(ElementTags.STYLE, Markup.CSS_VALUE_UNDERLINE); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.CHUNK, HtmlTags.SUP); + peer.AddValue(ElementTags.SUBSUPSCRIPT, "6.0"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.CHUNK, HtmlTags.SUB); + peer.AddValue(ElementTags.SUBSUPSCRIPT, "-6.0"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.HORIZONTALRULE, HtmlTags.HORIZONTALRULE); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.TABLE, HtmlTags.TABLE); + peer.AddAlias(ElementTags.WIDTH, HtmlTags.WIDTH); + peer.AddAlias(ElementTags.BACKGROUNDCOLOR, HtmlTags.BACKGROUNDCOLOR); + peer.AddAlias(ElementTags.BORDERCOLOR, HtmlTags.BORDERCOLOR); + peer.AddAlias(ElementTags.COLUMNS, HtmlTags.COLUMNS); + peer.AddAlias(ElementTags.CELLPADDING, HtmlTags.CELLPADDING); + peer.AddAlias(ElementTags.CELLSPACING, HtmlTags.CELLSPACING); + peer.AddAlias(ElementTags.BORDERWIDTH, HtmlTags.BORDERWIDTH); + peer.AddAlias(ElementTags.ALIGN, HtmlTags.ALIGN); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.ROW, HtmlTags.ROW); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.CELL, HtmlTags.CELL); + peer.AddAlias(ElementTags.WIDTH, HtmlTags.WIDTH); + peer.AddAlias(ElementTags.BACKGROUNDCOLOR, HtmlTags.BACKGROUNDCOLOR); + peer.AddAlias(ElementTags.BORDERCOLOR, HtmlTags.BORDERCOLOR); + peer.AddAlias(ElementTags.COLSPAN, HtmlTags.COLSPAN); + peer.AddAlias(ElementTags.ROWSPAN, HtmlTags.ROWSPAN); + peer.AddAlias(ElementTags.NOWRAP, HtmlTags.NOWRAP); + peer.AddAlias(ElementTags.HORIZONTALALIGN, HtmlTags.HORIZONTALALIGN); + peer.AddAlias(ElementTags.VERTICALALIGN, HtmlTags.VERTICALALIGN); + peer.AddValue(ElementTags.HEADER, "false"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.CELL, HtmlTags.HEADERCELL); + peer.AddAlias(ElementTags.WIDTH, HtmlTags.WIDTH); + peer.AddAlias(ElementTags.BACKGROUNDCOLOR, HtmlTags.BACKGROUNDCOLOR); + peer.AddAlias(ElementTags.BORDERCOLOR, HtmlTags.BORDERCOLOR); + peer.AddAlias(ElementTags.COLSPAN, HtmlTags.COLSPAN); + peer.AddAlias(ElementTags.ROWSPAN, HtmlTags.ROWSPAN); + peer.AddAlias(ElementTags.NOWRAP, HtmlTags.NOWRAP); + peer.AddAlias(ElementTags.HORIZONTALALIGN, HtmlTags.HORIZONTALALIGN); + peer.AddAlias(ElementTags.VERTICALALIGN, HtmlTags.VERTICALALIGN); + peer.AddValue(ElementTags.HEADER, "true"); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.IMAGE, HtmlTags.IMAGE); + peer.AddAlias(ElementTags.URL, HtmlTags.URL); + peer.AddAlias(ElementTags.ALT, HtmlTags.ALT); + peer.AddAlias(ElementTags.PLAINWIDTH, HtmlTags.PLAINWIDTH); + peer.AddAlias(ElementTags.PLAINHEIGHT, HtmlTags.PLAINHEIGHT); + this[peer.Alias] = peer; + + peer = new HtmlPeer(ElementTags.NEWLINE, HtmlTags.NEWLINE); + this[peer.Alias] = peer; + } + + /** + * Checks if this is the root tag. + * @param tag a tagvalue + * @return true if tag is HTML or html + */ + public static bool IsHtml(String tag) { + return Util.EqualsIgnoreCase(HtmlTags.HTML, tag); + } + + /** + * Checks if this is the head tag. + * @param tag a tagvalue + * @return true if tag is HEAD or head + */ + public static bool IsHead(String tag) { + return Util.EqualsIgnoreCase(HtmlTags.HEAD, tag); + } + + /** + * Checks if this is the meta tag. + * @param tag a tagvalue + * @return true if tag is META or meta + */ + public static bool IsMeta(String tag) { + return Util.EqualsIgnoreCase(HtmlTags.META, tag); + } + + /** + * Checks if this is the linl tag. + * @param tag a tagvalue + * @return true if tag is LINK or link + */ + public static bool IsLink(String tag) { + return Util.EqualsIgnoreCase(HtmlTags.LINK, tag); + } + + /** + * Checks if this is the title tag. + * @param tag a tagvalue + * @return true if tag is TITLE or title + */ + public static bool IsTitle(String tag) { + return Util.EqualsIgnoreCase(HtmlTags.TITLE, tag); + } + + /** + * Checks if this is the root tag. + * @param tag a tagvalue + * @return true if tag is BODY or body + */ + public static bool IsBody(String tag) { + return Util.EqualsIgnoreCase(HtmlTags.BODY, tag); + } + + /** + * Checks if this is a special tag. + * @param tag a tagvalue + * @return true if tag is a HTML, HEAD, META, LINK or BODY tag (case insensitive) + */ + public static bool IsSpecialTag(String tag) { + return IsHtml(tag) || IsHead(tag) || IsMeta(tag) || IsLink(tag) || IsBody(tag); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/HtmlTags.cs b/iTechSharp/iTextSharp/text/html/HtmlTags.cs new file mode 100644 index 0000000..760ba03 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/HtmlTags.cs @@ -0,0 +1,325 @@ +using System; + +/* + * $Id: HtmlTags.cs,v 1.4 2008/05/13 11:25:15 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + + /** + * A class that contains all the possible tagnames and their attributes. + */ + + public class HtmlTags { + + /** the root tag. */ + public const string HTML = "html"; + + /** the head tag */ + public const string HEAD = "head"; + + /** This is a possible HTML attribute for the HEAD tag. */ + public const string CONTENT = "content"; + + /** the meta tag */ + public const string META = "meta"; + + /** attribute of the root tag */ + public const string SUBJECT = "subject"; + + /** attribute of the root tag */ + public const string KEYWORDS = "keywords"; + + /** attribute of the root tag */ + public const string AUTHOR = "author"; + + /** the title tag. */ + public const string TITLE = "title"; + + /** the script tag. */ + public const string SCRIPT = "script"; + + /** This is a possible HTML attribute for the SCRIPT tag. */ + public const string LANGUAGE = "language"; + + /** This is a possible value for the LANGUAGE attribute. */ + public const string JAVASCRIPT = "JavaScript"; + + /** the body tag. */ + public const string BODY = "body"; + + /** This is a possible HTML attribute for the BODY tag */ + public const string JAVASCRIPT_ONLOAD = "onLoad"; + + /** This is a possible HTML attribute for the BODY tag */ + public const string JAVASCRIPT_ONUNLOAD = "onUnLoad"; + + /** This is a possible HTML attribute for the BODY tag. */ + public const string TOPMARGIN = "topmargin"; + + /** This is a possible HTML attribute for the BODY tag. */ + public const string BOTTOMMARGIN = "bottommargin"; + + /** This is a possible HTML attribute for the BODY tag. */ + public const string LEFTMARGIN = "leftmargin"; + + /** This is a possible HTML attribute for the BODY tag. */ + public const string RIGHTMARGIN = "rightmargin"; + + // Phrases, Anchors, Lists and Paragraphs + + /** the chunk tag */ + public const string CHUNK = "font"; + + /** the phrase tag */ + public const string CODE = "code"; + + /** the phrase tag */ + public const string VAR = "var"; + + /** the anchor tag */ + public const string ANCHOR = "a"; + + /** the list tag */ + public const string ORDEREDLIST = "ol"; + + /** the list tag */ + public const string UNORDEREDLIST = "ul"; + + /** the listitem tag */ + public const string LISTITEM = "li"; + + /** the paragraph tag */ + public const string PARAGRAPH = "p"; + + /** attribute of anchor tag */ + public const string NAME = "name"; + + /** attribute of anchor tag */ + public const string REFERENCE = "href"; + + /** attribute of anchor tag */ + public static string[] H = {"h1", "h2", "h3", "h4", "h5", "h6"}; + + // Chunks + + /** attribute of the chunk tag */ + public const string FONT = "face"; + + /** attribute of the chunk tag */ + public const string SIZE = "point-size"; + + /** attribute of the chunk/table/cell tag */ + public const string COLOR = "color"; + + /** some phrase tag */ + public const string EM = "em"; + + /** some phrase tag */ + public const string I = "i"; + + /** some phrase tag */ + public const string STRONG = "strong"; + + /** some phrase tag */ + public const string B = "b"; + + /** some phrase tag */ + public const string S = "s"; + + /** some phrase tag */ + public const string U = "u"; + + /** some phrase tag */ + public const string SUB = "sub"; + + /** some phrase tag */ + public const string SUP = "sup"; + + /** the possible value of a tag */ + public const string HORIZONTALRULE = "hr"; + + // tables/cells + + /** the table tag */ + public const string TABLE = "table"; + + /** the cell tag */ + public const string ROW = "tr"; + + /** the cell tag */ + public const string CELL = "td"; + + /** attribute of the cell tag */ + public const string HEADERCELL = "th"; + + /** attribute of the table tag */ + public const string COLUMNS = "cols"; + + /** attribute of the table tag */ + public const string CELLPADDING = "cellpadding"; + + /** attribute of the table tag */ + public const string CELLSPACING = "cellspacing"; + + /** attribute of the cell tag */ + public const string COLSPAN = "colspan"; + + /** attribute of the cell tag */ + public const string ROWSPAN = "rowspan"; + + /** attribute of the cell tag */ + public const string NOWRAP = "nowrap"; + + /** attribute of the table/cell tag */ + public const string BORDERWIDTH = "border"; + + /** attribute of the table/cell tag */ + public const string WIDTH = "width"; + + /** attribute of the table/cell tag */ + public const string BACKGROUNDCOLOR = "bgcolor"; + + /** attribute of the table/cell tag */ + public const string BORDERCOLOR = "bordercolor"; + + /** attribute of paragraph/image/table tag */ + public const string ALIGN = "align"; + + /** attribute of chapter/section/paragraph/table/cell tag */ + public const string LEFT = "left"; + + /** attribute of chapter/section/paragraph/table/cell tag */ + public const string RIGHT = "right"; + + /** attribute of the cell tag */ + public const string HORIZONTALALIGN = "align"; + + /** attribute of the cell tag */ + public const string VERTICALALIGN = "valign"; + + /** attribute of the table/cell tag */ + public const string TOP = "top"; + + /** attribute of the table/cell tag */ + public const string BOTTOM = "bottom"; + + // Misc + + /** the image tag */ + public const string IMAGE = "img"; + + /** attribute of the image tag */ + public const string URL = "src"; + + /** attribute of the image tag */ + public const string ALT = "alt"; + + /** attribute of the image tag */ + public const string PLAINWIDTH = "width"; + + /** attribute of the image tag */ + public const string PLAINHEIGHT = "height"; + + /** the newpage tag */ + public const string NEWLINE = "br"; + + // alignment attribute values + + /** the possible value of an alignment attribute */ + public const string ALIGN_LEFT = "Left"; + + /** the possible value of an alignment attribute */ + public const string ALIGN_CENTER = "Center"; + + /** the possible value of an alignment attribute */ + public const string ALIGN_RIGHT = "Right"; + + /** the possible value of an alignment attribute */ + public const string ALIGN_JUSTIFIED = "Justify"; + + /** the possible value of an alignment attribute */ + public const string ALIGN_TOP = "Top"; + + /** the possible value of an alignment attribute */ + public const string ALIGN_MIDDLE = "Middle"; + + /** the possible value of an alignment attribute */ + public const string ALIGN_BOTTOM = "Bottom"; + + /** the possible value of an alignment attribute */ + public const string ALIGN_BASELINE = "Baseline"; + + /** the possible value of an alignment attribute */ + public const string DEFAULT = "Default"; + + /** The DIV tag. */ + public const string DIV = "div"; + + /** The SPAN tag. */ + public const string SPAN = "span"; + /** The LINK tag. */ + public const string LINK = "link"; + + /** This is a possible HTML attribute for the LINK tag. */ + public const string TEXT_CSS = "text/css"; + + /** This is a possible HTML attribute for the LINK tag. */ + public const string REL = "rel"; + + /** This is used for inline css style information */ + public const string STYLE = "style"; + + /** This is a possible HTML attribute for the LINK tag. */ + public const string TYPE = "type"; + + /** This is a possible HTML attribute. */ + public const string STYLESHEET = "stylesheet"; + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/HtmlWriter.cs b/iTechSharp/iTextSharp/text/html/HtmlWriter.cs new file mode 100644 index 0000000..4e6f8d9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/HtmlWriter.cs @@ -0,0 +1,1041 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.Globalization; +using System.util; + +using iTextSharp.text; +using iTextSharp.text.pdf; + +/* + * $Id: HtmlWriter.cs,v 1.24 2008/05/13 11:25:15 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + /** + * A DocWriter class for HTML. + *

    + * An HtmlWriter can be added as a DocListener + * to a certain Document by getting an instance. + * Every Element added to the original Document + * will be written to the Stream of this HtmlWriter. + *

    + * Example: + *

    +     * // creation of the document with a certain size and certain margins
    +     * Document document = new Document(PageSize.A4, 50, 50, 50, 50);
    +     * try {
    +     *    // this will write HTML to the Standard Stream
    +     *    HtmlWriter.GetInstance(document, System.out);
    +     *    // this will write HTML to a file called text.html
    +     *    HtmlWriter.GetInstance(document, new FileOutputStream("text.html"));
    +     *    // this will write HTML to for instance the Stream of a HttpServletResponse-object
    +     *    HtmlWriter.GetInstance(document, response.GetOutputStream());
    +     * }
    +     * catch (DocumentException de) {
    +     *    System.err.Println(de.GetMessage());
    +     * }
    +     * // this will close the document and all the OutputStreams listening to it
    +     * document.Close();
    +     * 
    + */ + + public class HtmlWriter : DocWriter { + + // static membervariables (tags) + + /** This is a possible HTML-tag. */ + public static byte[] BEGINCOMMENT = GetISOBytes(""); + + /** This is a possible HTML-tag. */ + public const string NBSP = " "; + + // membervariables + + /** This is the current font of the HTML. */ + protected Stack currentfont = new Stack(); + + /** This is the standard font of the HTML. */ + protected Font standardfont = new Font(); + + /** This is a path for images. */ + protected String imagepath = null; + + /** Stores the page number. */ + protected int pageN = 0; + + /** This is the textual part of a header */ + protected HeaderFooter header = null; + + /** This is the textual part of the footer */ + protected HeaderFooter footer = null; + + /** Store the markup properties of a MarkedObject. */ + protected Properties markup = new Properties(); + + // constructor + + /** + * Constructs a HtmlWriter. + * + * @param doc The Document that has to be written as HTML + * @param os The Stream the writer has to write to. + */ + + protected HtmlWriter(Document doc, Stream os) : base(doc, os){ + + document.AddDocListener(this); + this.pageN = document.PageNumber; + os.WriteByte(LT); + byte[] tmp = GetISOBytes(HtmlTags.HTML); + os.Write(tmp, 0, tmp.Length); + os.WriteByte(GT); + os.WriteByte(NEWLINE); + os.WriteByte(TAB); + os.WriteByte(LT); + tmp = GetISOBytes(HtmlTags.HEAD); + os.Write(tmp, 0, tmp.Length); + os.WriteByte(GT); + } + + // get an instance of the HtmlWriter + + /** + * Gets an instance of the HtmlWriter. + * + * @param document The Document that has to be written + * @param os The Stream the writer has to write to. + * @return a new HtmlWriter + */ + + public static HtmlWriter GetInstance(Document document, Stream os) { + return new HtmlWriter(document, os); + } + + // implementation of the DocListener methods + + /** + * Signals that an new page has to be started. + * + * @return true if this action succeeded, false if not. + * @throws DocumentException when a document isn't open yet, or has been closed + */ + + public override bool NewPage() { + try { + WriteStart(HtmlTags.DIV); + Write(" "); + Write(HtmlTags.STYLE); + Write("=\""); + WriteCssProperty(Markup.CSS_KEY_PAGE_BREAK_BEFORE, Markup.CSS_VALUE_ALWAYS); + Write("\" /"); + os.WriteByte(GT); + } + catch (IOException ioe) { + throw new DocumentException(ioe.Message); + } + return true; + } + + /** + * Signals that an Element was added to the Document. + * + * @return true if the element was added, false if not. + * @throws DocumentException when a document isn't open yet, or has been closed + */ + + public override bool Add(IElement element) { + if (pause) { + return false; + } + if (open && !element.IsContent()) { + throw new DocumentException("The document is open; you can only add Elements with content."); + } + switch (element.Type) { + case Element.HEADER: + try { + Header h = (Header) element; + if (HtmlTags.STYLESHEET.Equals(h.Name)) { + WriteLink(h); + } + else if (HtmlTags.JAVASCRIPT.Equals(h.Name)) { + WriteJavaScript(h); + } + else { + WriteHeader(h); + } + } + catch (InvalidCastException) { + } + return true; + case Element.SUBJECT: + case Element.KEYWORDS: + case Element.AUTHOR: + Meta meta = (Meta) element; + WriteHeader(meta); + return true; + case Element.TITLE: + AddTabs(2); + WriteStart(HtmlTags.TITLE); + os.WriteByte(GT); + AddTabs(3); + Write(HtmlEncoder.Encode(((Meta)element).Content)); + AddTabs(2); + WriteEnd(HtmlTags.TITLE); + return true; + case Element.CREATOR: + WriteComment("Creator: " + HtmlEncoder.Encode(((Meta)element).Content)); + return true; + case Element.PRODUCER: + WriteComment("Producer: " + HtmlEncoder.Encode(((Meta)element).Content)); + return true; + case Element.CREATIONDATE: + WriteComment("Creationdate: " + HtmlEncoder.Encode(((Meta)element).Content)); + return true; + case Element.MARKED: + if (element is MarkedSection) { + MarkedSection ms = (MarkedSection)element; + AddTabs(1); + WriteStart(HtmlTags.DIV); + WriteMarkupAttributes(ms.MarkupAttributes); + os.WriteByte(GT); + MarkedObject mo = ((MarkedSection)element).Title; + if (mo != null) { + markup = mo.MarkupAttributes; + mo.Process(this); + } + ms.Process(this); + WriteEnd(HtmlTags.DIV); + return true; + } + else { + MarkedObject mo = (MarkedObject) element; + markup = mo.MarkupAttributes; + return mo.Process(this); + } + default: + Write(element, 2); + return true; + } + } + + /** + * Signals that the Document has been opened and that + * Elements can be added. + *

    + * The HEAD-section of the HTML-document is written. + */ + + public override void Open() { + base.Open(); + WriteComment(Document.Version); + WriteComment("CreationDate: " + DateTime.Now.ToString()); + AddTabs(1); + WriteEnd(HtmlTags.HEAD); + AddTabs(1); + WriteStart(HtmlTags.BODY); + if (document.LeftMargin > 0) { + Write(HtmlTags.LEFTMARGIN, document.LeftMargin.ToString()); + } + if (document.RightMargin > 0) { + Write(HtmlTags.RIGHTMARGIN, document.RightMargin.ToString()); + } + if (document.TopMargin > 0) { + Write(HtmlTags.TOPMARGIN, document.TopMargin.ToString()); + } + if (document.BottomMargin > 0) { + Write(HtmlTags.BOTTOMMARGIN, document.BottomMargin.ToString()); + } + if (pageSize.BackgroundColor != null) { + Write(HtmlTags.BACKGROUNDCOLOR, HtmlEncoder.Encode(pageSize.BackgroundColor)); + } + if (document.JavaScript_onLoad != null) { + Write(HtmlTags.JAVASCRIPT_ONLOAD, HtmlEncoder.Encode(document.JavaScript_onLoad)); + } + if (document.JavaScript_onUnLoad != null) { + Write(HtmlTags.JAVASCRIPT_ONUNLOAD, HtmlEncoder.Encode(document.JavaScript_onUnLoad)); + } + if (document.HtmlStyleClass != null) { + Write(Markup.HTML_ATTR_CSS_CLASS, document.HtmlStyleClass); + } + os.WriteByte(GT); + InitHeader(); // line added by David Freels + } + + /** + * Signals that the Document was closed and that no other + * Elements will be added. + */ + + public override void Close() { + InitFooter(); // line added by David Freels + AddTabs(1); + WriteEnd(HtmlTags.BODY); + os.WriteByte(NEWLINE); + WriteEnd(HtmlTags.HTML); + base.Close(); + } + + // some protected methods + + /** + * Adds the header to the top of the Document + */ + + protected void InitHeader() { + if (header != null) { + Add(header.Paragraph); + } + } + + /** + * Adds the header to the top of the Document + */ + + protected void InitFooter() { + if (footer != null) { + // Set the page number. HTML has no notion of a page, so it should always + // add up to 1 + footer.PageNumber = pageN + 1; + Add(footer.Paragraph); + } + } + + /** + * Writes a Metatag in the header. + * + * @param meta the element that has to be written + * @throws IOException + */ + + protected void WriteHeader(Meta meta) { + AddTabs(2); + WriteStart(HtmlTags.META); + switch (meta.Type) { + case Element.HEADER: + Write(HtmlTags.NAME, ((Header) meta).Name); + break; + case Element.SUBJECT: + Write(HtmlTags.NAME, HtmlTags.SUBJECT); + break; + case Element.KEYWORDS: + Write(HtmlTags.NAME, HtmlTags.KEYWORDS); + break; + case Element.AUTHOR: + Write(HtmlTags.NAME, HtmlTags.AUTHOR); + break; + } + Write(HtmlTags.CONTENT, HtmlEncoder.Encode(meta.Content)); + WriteEnd(); + } + + /** + * Writes a link in the header. + * + * @param header the element that has to be written + * @throws IOException + */ + + protected void WriteLink(Header header) { + AddTabs(2); + WriteStart(HtmlTags.LINK); + Write(HtmlTags.REL, header.Name); + Write(HtmlTags.TYPE, HtmlTags.TEXT_CSS); + Write(HtmlTags.REFERENCE, header.Content); + WriteEnd(); + } + + /** + * Writes a JavaScript section or, if the markup attribute HtmlTags.URL is set, a JavaScript reference in the header. + * + * @param header the element that has to be written + * @throws IOException + */ + + protected void WriteJavaScript(Header header) { + AddTabs(2); + WriteStart(HtmlTags.SCRIPT); + Write(HtmlTags.LANGUAGE, HtmlTags.JAVASCRIPT); + if (markup.Count > 0) { + /* JavaScript reference example: + * + * + */ + Write(HtmlTags.TYPE, Markup.HTML_VALUE_JAVASCRIPT); + os.WriteByte(GT); + AddTabs(2); + Write(Encoding.ASCII.GetString(BEGINCOMMENT) + "\n"); + Write(header.Content); + AddTabs(2); + Write("//" + Encoding.ASCII.GetString(ENDCOMMENT)); + AddTabs(2); + WriteEnd(HtmlTags.SCRIPT); + } + } + + /** + * Writes some comment. + *

    + * This method writes some comment. + * + * @param comment the comment that has to be written + * @throws IOException + */ + + protected void WriteComment(String comment) { + AddTabs(2); + os.Write(BEGINCOMMENT, 0, BEGINCOMMENT.Length); + Write(comment); + os.Write(ENDCOMMENT, 0, ENDCOMMENT.Length); + } + + // public methods + + /** + * Changes the standardfont. + * + * @param standardFont The font + */ + + public void SetStandardFont(Font standardFont) { + this.standardfont = standardFont; + } + + /** + * Checks if a given font is the same as the font that was last used. + * + * @param font the font of an object + * @return true if the font differs + */ + + public bool IsOtherFont(Font font) { + try { + Font cFont = (Font) currentfont.Peek(); + if (cFont.CompareTo(font) == 0) return false; + return true; + } + catch (InvalidOperationException) { + if (standardfont.CompareTo(font) == 0) return false; + return true; + } + } + + /** + * Sets the basepath for images. + *

    + * This is especially useful if you add images using a file, + * rather than an URL. In PDF there is no problem, since + * the images are added inline, but in HTML it is sometimes + * necessary to use a relative path or a special path to some + * images directory. + * + * @param imagepath the new imagepath + */ + + public void SetImagepath(String imagepath) { + this.imagepath = imagepath; + } + + /** + * Resets the imagepath. + */ + + public void ResetImagepath() { + imagepath = null; + } + + /** + * Changes the header of this document. + * + * @param header the new header + */ + + public void SetHeader(HeaderFooter header) { + this.header = header; + } + + /** + * Changes the footer of this document. + * + * @param footer the new footer + */ + + public void SetFooter(HeaderFooter footer) { + this.footer = footer; + } + + /** + * Signals that a String was added to the Document. + * + * @return true if the string was added, false if not. + * @throws DocumentException when a document isn't open yet, or has been closed + */ + + public bool Add(String str) { + if (pause) { + return false; + } + Write(str); + return true; + } + + /** + * Writes the HTML representation of an element. + * + * @param element the element + * @param indent the indentation + */ + + protected void Write(IElement element, int indent) { + Properties styleAttributes = null; + switch (element.Type) { + case Element.MARKED: { + try { + Add(element); + } catch (DocumentException) { + } + return; + } + case Element.CHUNK: { + Chunk chunk = (Chunk) element; + // if the chunk contains an image, return the image representation + Image image = chunk.GetImage(); + if (image != null) { + Write(image, indent); + return; + } + + if (chunk.IsEmpty()) return; + Hashtable attributes = chunk.Attributes; + if (attributes != null && attributes[Chunk.NEWPAGE] != null) { + return; + } + bool tag = IsOtherFont(chunk.Font) || markup.Count > 0; + if (tag) { + // start span tag + AddTabs(indent); + WriteStart(HtmlTags.SPAN); + if (IsOtherFont(chunk.Font)) { + Write(chunk.Font, null); + } + WriteMarkupAttributes(markup); + os.WriteByte(GT); + } + if (attributes != null && attributes[Chunk.SUBSUPSCRIPT] != null) { + // start sup or sub tag + if ((float)attributes[Chunk.SUBSUPSCRIPT] > 0) { + WriteStart(HtmlTags.SUP); + } + else { + WriteStart(HtmlTags.SUB); + } + os.WriteByte(GT); + } + // contents + Write(HtmlEncoder.Encode(chunk.Content)); + if (attributes != null && attributes[Chunk.SUBSUPSCRIPT] != null) { + // end sup or sub tag + os.WriteByte(LT); + os.WriteByte(FORWARD); + if ((float)attributes[Chunk.SUBSUPSCRIPT] > 0) { + Write(HtmlTags.SUP); + } + else { + Write(HtmlTags.SUB); + } + os.WriteByte(GT); + } + if (tag) { + // end tag + WriteEnd(Markup.HTML_TAG_SPAN); + } + return; + } + case Element.PHRASE: { + Phrase phrase = (Phrase) element; + styleAttributes = new Properties(); + if (phrase.HasLeading()) styleAttributes[Markup.CSS_KEY_LINEHEIGHT] = phrase.Leading.ToString() + "pt"; + + // start tag + AddTabs(indent); + WriteStart(Markup.HTML_TAG_SPAN); + WriteMarkupAttributes(markup); + Write(phrase.Font, styleAttributes); + os.WriteByte(GT); + currentfont.Push(phrase.Font); + // contents + foreach (IElement i in phrase) { + Write(i, indent + 1); + } + // end tag + AddTabs(indent); + WriteEnd(Markup.HTML_TAG_SPAN); + currentfont.Pop(); + return; + } + case Element.ANCHOR: { + Anchor anchor = (Anchor) element; + styleAttributes = new Properties(); + if (anchor.HasLeading()) styleAttributes[Markup.CSS_KEY_LINEHEIGHT] = anchor.Leading.ToString() + "pt"; + + // start tag + AddTabs(indent); + WriteStart(HtmlTags.ANCHOR); + if (anchor.Name != null) { + Write(HtmlTags.NAME, anchor.Name); + } + if (anchor.Reference != null) { + Write(HtmlTags.REFERENCE, anchor.Reference); + } + WriteMarkupAttributes(markup); + Write(anchor.Font, styleAttributes); + os.WriteByte(GT); + currentfont.Push(anchor.Font); + // contents + foreach (IElement i in anchor) { + Write(i, indent + 1); + } + // end tag + AddTabs(indent); + WriteEnd(HtmlTags.ANCHOR); + currentfont.Pop(); + return; + } + case Element.PARAGRAPH: { + Paragraph paragraph = (Paragraph) element; + styleAttributes = new Properties(); + if (paragraph.HasLeading()) styleAttributes[Markup.CSS_KEY_LINEHEIGHT] = paragraph.TotalLeading.ToString() + "pt"; + + // start tag + AddTabs(indent); + WriteStart(HtmlTags.DIV); + WriteMarkupAttributes(markup); + String alignment = HtmlEncoder.GetAlignment(paragraph.Alignment); + if (!"".Equals(alignment)) { + Write(HtmlTags.ALIGN, alignment); + } + Write(paragraph.Font, styleAttributes); + os.WriteByte(GT); + currentfont.Push(paragraph.Font); + // contents + foreach (IElement i in paragraph) { + Write(i, indent + 1); + } + // end tag + AddTabs(indent); + WriteEnd(HtmlTags.DIV); + currentfont.Pop(); + return; + } + case Element.SECTION: + case Element.CHAPTER: { + // part of the start tag + contents + WriteSection((Section) element, indent); + return; + } + case Element.LIST: { + List list = (List) element; + // start tag + AddTabs(indent); + if (list.Numbered) { + WriteStart(HtmlTags.ORDEREDLIST); + } + else { + WriteStart(HtmlTags.UNORDEREDLIST); + } + WriteMarkupAttributes(markup); + os.WriteByte(GT); + // contents + foreach (IElement i in list.Items) { + Write(i, indent + 1); + } + // end tag + AddTabs(indent); + if (list.Numbered) { + WriteEnd(HtmlTags.ORDEREDLIST); + } + else { + WriteEnd(HtmlTags.UNORDEREDLIST); + } + return; + } + case Element.LISTITEM: { + ListItem listItem = (ListItem) element; + styleAttributes = new Properties(); + if (listItem.HasLeading()) styleAttributes[Markup.CSS_KEY_LINEHEIGHT] = listItem.TotalLeading.ToString() + "pt"; + + // start tag + AddTabs(indent); + WriteStart(HtmlTags.LISTITEM); + WriteMarkupAttributes(markup); + Write(listItem.Font, styleAttributes); + os.WriteByte(GT); + currentfont.Push(listItem.Font); + // contents + foreach (IElement i in listItem) { + Write(i, indent + 1); + } + // end tag + AddTabs(indent); + WriteEnd(HtmlTags.LISTITEM); + currentfont.Pop(); + return; + } + case Element.CELL: { + Cell cell = (Cell) element; + + // start tag + AddTabs(indent); + if (cell.Header) { + WriteStart(HtmlTags.HEADERCELL); + } + else { + WriteStart(HtmlTags.CELL); + } + WriteMarkupAttributes(markup); + if (cell.BorderWidth != Rectangle.UNDEFINED) { + Write(HtmlTags.BORDERWIDTH, cell.BorderWidth.ToString()); + } + if (cell.BorderColor != null) { + Write(HtmlTags.BORDERCOLOR, HtmlEncoder.Encode(cell.BorderColor)); + } + if (cell.BackgroundColor != null) { + Write(HtmlTags.BACKGROUNDCOLOR, HtmlEncoder.Encode(cell.BackgroundColor)); + } + String alignment = HtmlEncoder.GetAlignment(cell.HorizontalAlignment); + if (!"".Equals(alignment)) { + Write(HtmlTags.HORIZONTALALIGN, alignment); + } + alignment = HtmlEncoder.GetAlignment(cell.VerticalAlignment); + if (!"".Equals(alignment)) { + Write(HtmlTags.VERTICALALIGN, alignment); + } + if (cell.GetWidthAsString() != null) { + Write(HtmlTags.WIDTH, cell.GetWidthAsString()); + } + if (cell.Colspan != 1) { + Write(HtmlTags.COLSPAN, cell.Colspan.ToString()); + } + if (cell.Rowspan != 1) { + Write(HtmlTags.ROWSPAN, cell.Rowspan.ToString()); + } + if (cell.MaxLines == 1) { + Write(HtmlTags.STYLE, "white-space: nowrap;"); + } + os.WriteByte(GT); + // contents + if (cell.IsEmpty()) { + Write(NBSP); + } else { + foreach (IElement i in cell.Elements) { + Write(i, indent + 1); + } + } + // end tag + AddTabs(indent); + if (cell.Header) { + WriteEnd(HtmlTags.HEADERCELL); + } + else { + WriteEnd(HtmlTags.CELL); + } + return; + } + case Element.ROW: { + Row row = (Row) element; + + // start tag + AddTabs(indent); + WriteStart(HtmlTags.ROW); + WriteMarkupAttributes(markup); + os.WriteByte(GT); + // contents + IElement cell; + for (int i = 0; i < row.Columns; i++) { + if ((cell = (IElement)row.GetCell(i)) != null) { + Write(cell, indent + 1); + } + } + // end tag + AddTabs(indent); + WriteEnd(HtmlTags.ROW); + return; + } + case Element.TABLE: { + Table table; + try { + table = (Table) element; + } + catch (InvalidCastException) { + table = ((SimpleTable)element).CreateTable(); + } + table.Complete(); + // start tag + AddTabs(indent); + WriteStart(HtmlTags.TABLE); + WriteMarkupAttributes(markup); + os.WriteByte(SPACE); + Write(HtmlTags.WIDTH); + os.WriteByte(EQUALS); + os.WriteByte(QUOTE); + Write(table.Width.ToString(System.Globalization.CultureInfo.InvariantCulture)); + if (!table.Locked){ + Write("%"); + } + os.WriteByte(QUOTE); + String alignment = HtmlEncoder.GetAlignment(table.Alignment); + if (!"".Equals(alignment)) { + Write(HtmlTags.ALIGN, alignment); + } + Write(HtmlTags.CELLPADDING, table.Cellpadding.ToString(System.Globalization.CultureInfo.InvariantCulture)); + Write(HtmlTags.CELLSPACING, table.Cellspacing.ToString(System.Globalization.CultureInfo.InvariantCulture)); + if (table.BorderWidth != Rectangle.UNDEFINED) { + Write(HtmlTags.BORDERWIDTH, table.BorderWidth.ToString(System.Globalization.CultureInfo.InvariantCulture)); + } + if (table.BorderColor != null) { + Write(HtmlTags.BORDERCOLOR, HtmlEncoder.Encode(table.BorderColor)); + } + if (table.BackgroundColor != null) { + Write(HtmlTags.BACKGROUNDCOLOR, HtmlEncoder.Encode(table.BackgroundColor)); + } + os.WriteByte(GT); + // contents + foreach (Row row in table) { + Write(row, indent + 1); + } + // end tag + AddTabs(indent); + WriteEnd(HtmlTags.TABLE); + return; + } + case Element.ANNOTATION: { + Annotation annotation = (Annotation) element; + WriteComment(annotation.Title + ": " + annotation.Content); + return; + } + case Element.IMGRAW: + case Element.JPEG: + case Element.JPEG2000: + case Element.IMGTEMPLATE: { + Image image = (Image) element; + if (image.Url == null) { + return; + } + + // start tag + AddTabs(indent); + WriteStart(HtmlTags.IMAGE); + String path = image.Url.ToString(); + if (imagepath != null) { + if (path.IndexOf('/') > 0) { + path = imagepath + path.Substring(path.LastIndexOf('/') + 1); + } + else { + path = imagepath + path; + } + } + Write(HtmlTags.URL, path); + if ((image.Alignment & Image.RIGHT_ALIGN) > 0) { + Write(HtmlTags.ALIGN, HtmlTags.ALIGN_RIGHT); + } + else if ((image.Alignment & Image.MIDDLE_ALIGN) > 0) { + Write(HtmlTags.ALIGN, HtmlTags.ALIGN_MIDDLE); + } + else { + Write(HtmlTags.ALIGN, HtmlTags.ALIGN_LEFT); + } + if (image.Alt != null) { + Write(HtmlTags.ALT, image.Alt); + } + Write(HtmlTags.PLAINWIDTH, image.ScaledWidth.ToString()); + Write(HtmlTags.PLAINHEIGHT, image.ScaledHeight.ToString()); + WriteMarkupAttributes(markup); + WriteEnd(); + return; + } + + default: + return; + } + } + + /** + * Writes the HTML representation of a section. + * + * @param section the section to write + * @param indent the indentation + */ + + protected void WriteSection(Section section, int indent) { + if (section.Title != null) { + int depth = section.Depth - 1; + if (depth > 5) { + depth = 5; + } + Properties styleAttributes = new Properties(); + if (section.Title.HasLeading()) styleAttributes[Markup.CSS_KEY_LINEHEIGHT] = section.Title.TotalLeading.ToString() + "pt"; + // start tag + AddTabs(indent); + WriteStart(HtmlTags.H[depth]); + Write(section.Title.Font, styleAttributes); + String alignment = HtmlEncoder.GetAlignment(section.Title.Alignment); + if (!"".Equals(alignment)) { + Write(HtmlTags.ALIGN, alignment); + } + WriteMarkupAttributes(markup); + os.WriteByte(GT); + currentfont.Push(section.Title.Font); + // contents + foreach (IElement i in section.Title) { + Write(i, indent + 1); + } + // end tag + AddTabs(indent); + WriteEnd(HtmlTags.H[depth]); + currentfont.Pop(); + } + foreach (IElement i in section) { + Write(i, indent); + } + } + + /** + * Writes the representation of a Font. + * + * @param font a Font + * @param styleAttributes the style of the font + */ + + protected void Write(Font font, Properties styleAttributes) { + if (font == null || !IsOtherFont(font) /*|| styleAttributes == null*/) return; + Write(" "); + Write(HtmlTags.STYLE); + Write("=\""); + if (styleAttributes != null) { + foreach (String key in styleAttributes.Keys) { + WriteCssProperty(key, styleAttributes[key]); + } + } + if (IsOtherFont(font)) { + WriteCssProperty(Markup.CSS_KEY_FONTFAMILY, font.Familyname); + + if (font.Size != Font.UNDEFINED) { + WriteCssProperty(Markup.CSS_KEY_FONTSIZE, font.Size.ToString() + "pt"); + } + if (font.Color != null) { + WriteCssProperty(Markup.CSS_KEY_COLOR, HtmlEncoder.Encode(font.Color)); + } + + int fontstyle = font.Style; + BaseFont bf = font.BaseFont; + if (bf != null) { + String ps = bf.PostscriptFontName.ToLower(CultureInfo.InvariantCulture); + if (ps.IndexOf("bold") >= 0) { + if (fontstyle == Font.UNDEFINED) + fontstyle = 0; + fontstyle |= Font.BOLD; + } + if (ps.IndexOf("italic") >= 0 || ps.IndexOf("oblique") >= 0) { + if (fontstyle == Font.UNDEFINED) + fontstyle = 0; + fontstyle |= Font.ITALIC; + } + } + if (fontstyle != Font.UNDEFINED && fontstyle != Font.NORMAL) { + switch (fontstyle & Font.BOLDITALIC) { + case Font.BOLD: + WriteCssProperty(Markup.CSS_KEY_FONTWEIGHT, Markup.CSS_VALUE_BOLD); + break; + case Font.ITALIC: + WriteCssProperty(Markup.CSS_KEY_FONTSTYLE, Markup.CSS_VALUE_ITALIC); + break; + case Font.BOLDITALIC: + WriteCssProperty(Markup.CSS_KEY_FONTWEIGHT, Markup.CSS_VALUE_BOLD); + WriteCssProperty(Markup.CSS_KEY_FONTSTYLE, Markup.CSS_VALUE_ITALIC); + break; + } + + // CSS only supports one decoration tag so if both are specified + // only one of the two will display + if ((fontstyle & Font.UNDERLINE) > 0) { + WriteCssProperty(Markup.CSS_KEY_TEXTDECORATION, Markup.CSS_VALUE_UNDERLINE); + } + if ((fontstyle & Font.STRIKETHRU) > 0) { + WriteCssProperty(Markup.CSS_KEY_TEXTDECORATION, Markup.CSS_VALUE_LINETHROUGH); + } + } + } + Write("\""); + } + + /** + * Writes out a CSS property. + */ + protected void WriteCssProperty(String prop, String value) { + Write(new StringBuilder(prop).Append(": ").Append(value).Append("; ").ToString()); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/ITextmyHtmlHandler.cs b/iTechSharp/iTextSharp/text/html/ITextmyHtmlHandler.cs new file mode 100644 index 0000000..2d6fa50 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/ITextmyHtmlHandler.cs @@ -0,0 +1,239 @@ +using System; +using System.Collections; +using System.Globalization; +using System.util; +using iTextSharp.text; +using iTextSharp.text.xml; +using iTextSharp.text.pdf; +using iTextSharp.text.factories; + +/* + * $Id: ITextmyHtmlHandler.cs,v 1.9 2008/05/13 11:25:15 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + + /** + * The Tags-class maps several XHTML-tags to iText-objects. + */ + + public class ITextmyHtmlHandler : ITextHandler { + + /** These are the properties of the body section. */ + private Properties bodyAttributes = new Properties(); + + /** This is the status of the table border. */ + private bool tableBorder = false; + + /** + * Constructs a new SAXiTextHandler that will translate all the events + * triggered by the parser to actions on the Document-object. + * + * @param document this is the document on which events must be triggered + */ + + public ITextmyHtmlHandler(IDocListener document) : base(document, new HtmlTagMap()) { + } + + public ITextmyHtmlHandler(IDocListener document, BaseFont bf) : base(document, new HtmlTagMap(), bf) { + } + + /** + * Constructs a new SAXiTextHandler that will translate all the events + * triggered by the parser to actions on the Document-object. + * + * @param document this is the document on which events must be triggered + * @param htmlTags a tagmap translating HTML tags to iText tags + */ + + public ITextmyHtmlHandler(IDocListener document, Hashtable htmlTags) : base(document, htmlTags) { + } + + /** + * This method gets called when a start tag is encountered. + * + * @param uri the Uniform Resource Identifier + * @param lname the local name (without prefix), or the empty string if Namespace processing is not being performed. + * @param name the name of the tag that is encountered + * @param attrs the list of attributes + */ + + public override void StartElement(String uri, String lname, String name, Hashtable attrs) { + //System.err.Println("Start: " + name); + + // super.handleStartingTags is replaced with handleStartingTags + // suggestion by Vu Ngoc Tan/Hop + name = name.ToLower(CultureInfo.InvariantCulture); + if (HtmlTagMap.IsHtml(name)) { + // we do nothing + return; + } + if (HtmlTagMap.IsHead(name)) { + // we do nothing + return; + } + if (HtmlTagMap.IsTitle(name)) { + // we do nothing + return; + } + if (HtmlTagMap.IsMeta(name)) { + // we look if we can change the body attributes + String meta = null; + String content = null; + if (attrs != null) { + foreach (String attribute in attrs.Keys) { + if (Util.EqualsIgnoreCase(attribute, HtmlTags.CONTENT)) + content = (String)attrs[attribute]; + else if (Util.EqualsIgnoreCase(attribute, HtmlTags.NAME)) + meta = (String)attrs[attribute]; + } + } + if (meta != null && content != null) { + bodyAttributes.Add(meta, content); + } + return; + } + if (HtmlTagMap.IsLink(name)) { + // we do nothing for the moment, in a later version we could extract the style sheet + return; + } + if (HtmlTagMap.IsBody(name)) { + // maybe we could extract some info about the document: color, margins,... + // but that's for a later version... + XmlPeer peer = new XmlPeer(ElementTags.ITEXT, name); + peer.AddAlias(ElementTags.TOP, HtmlTags.TOPMARGIN); + peer.AddAlias(ElementTags.BOTTOM, HtmlTags.BOTTOMMARGIN); + peer.AddAlias(ElementTags.RIGHT, HtmlTags.RIGHTMARGIN); + peer.AddAlias(ElementTags.LEFT, HtmlTags.LEFTMARGIN); + bodyAttributes.AddAll(peer.GetAttributes(attrs)); + HandleStartingTags(peer.Tag, bodyAttributes); + return; + } + if (myTags.ContainsKey(name)) { + XmlPeer peer = (XmlPeer) myTags[name]; + if (ElementTags.TABLE.Equals(peer.Tag) || ElementTags.CELL.Equals(peer.Tag)) { + Properties p = peer.GetAttributes(attrs); + String value; + if (ElementTags.TABLE.Equals(peer.Tag) && (value = p[ElementTags.BORDERWIDTH]) != null) { + if (float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo) > 0) { + tableBorder = true; + } + } + if (tableBorder) { + p.Add(ElementTags.LEFT, "true"); + p.Add(ElementTags.RIGHT, "true"); + p.Add(ElementTags.TOP, "true"); + p.Add(ElementTags.BOTTOM, "true"); + } + HandleStartingTags(peer.Tag, p); + return; + } + HandleStartingTags(peer.Tag, peer.GetAttributes(attrs)); + return; + } + Properties attributes = new Properties(); + if (attrs != null) { + foreach (String attribute in attrs.Keys) { + attributes.Add(attribute.ToLower(CultureInfo.InvariantCulture), ((String)attrs[attribute]).ToLower(CultureInfo.InvariantCulture)); + } + } + HandleStartingTags(name, attributes); + } + + /** + * This method gets called when an end tag is encountered. + * + * @param uri the Uniform Resource Identifier + * @param lname the local name (without prefix), or the empty string if Namespace processing is not being performed. + * @param name the name of the tag that ends + */ + + public override void EndElement(String uri, String lname, String name) { + //System.err.Println("End: " + name); + name = name.ToLower(CultureInfo.InvariantCulture); + if (ElementTags.PARAGRAPH.Equals(name)) { + document.Add((IElement) stack.Pop()); + return; + } + if (HtmlTagMap.IsHead(name)) { + // we do nothing + return; + } + if (HtmlTagMap.IsTitle(name)) { + if (currentChunk != null) { + bodyAttributes.Add(ElementTags.TITLE, currentChunk.Content); + } + return; + } + if (HtmlTagMap.IsMeta(name)) { + // we do nothing + return; + } + if (HtmlTagMap.IsLink(name)) { + // we do nothing + return; + } + if (HtmlTagMap.IsBody(name)) { + // we do nothing + return; + } + if (myTags.ContainsKey(name)) { + XmlPeer peer = (XmlPeer) myTags[name]; + if (ElementTags.TABLE.Equals(peer.Tag)) { + tableBorder = false; + } + base.HandleEndingTags(peer.Tag); + return; + } + // super.handleEndingTags is replaced with handleEndingTags + // suggestion by Ken Auer + HandleEndingTags(name); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/Markup.cs b/iTechSharp/iTextSharp/text/html/Markup.cs new file mode 100644 index 0000000..f2a56c4 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/Markup.cs @@ -0,0 +1,427 @@ +using System; +using System.util; +using System.IO; +using System.Text; +using System.Collections; +using System.Globalization; +using iTextSharp.text; + +/* + * $Id: Markup.cs,v 1.2 2008/05/13 11:25:16 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + ///

    + /// A class that contains all the possible tagnames and their attributes. + /// + public class Markup { + // iText specific + + /** the key for any tag */ + public const string ITEXT_TAG = "tag"; + + // HTML tags + + /** the markup for the body part of a file */ + public const string HTML_TAG_BODY = "body"; + + /** The DIV tag. */ + public const string HTML_TAG_DIV = "div"; + + /** This is a possible HTML-tag. */ + public const string HTML_TAG_LINK = "link"; + + /** The SPAN tag. */ + public const string HTML_TAG_SPAN = "span"; + + // HTML attributes + + /** the height attribute. */ + public const string HTML_ATTR_HEIGHT = "height"; + + /** the hyperlink reference attribute. */ + public const string HTML_ATTR_HREF = "href"; + + /** This is a possible HTML attribute for the LINK tag. */ + public const string HTML_ATTR_REL = "rel"; + + /** This is used for inline css style information */ + public const string HTML_ATTR_STYLE = "style"; + + /** This is a possible HTML attribute for the LINK tag. */ + public const string HTML_ATTR_TYPE = "type"; + + /** This is a possible HTML attribute. */ + public const string HTML_ATTR_STYLESHEET = "stylesheet"; + + /** the width attribute. */ + public const string HTML_ATTR_WIDTH = "width"; + + /** attribute for specifying externally defined CSS class */ + public const string HTML_ATTR_CSS_CLASS = "class"; + + /** The ID attribute. */ + public const string HTML_ATTR_CSS_ID = "id"; + + // HTML values + + /** This is a possible value for the language attribute (SCRIPT tag). */ + public const string HTML_VALUE_JAVASCRIPT = "text/javascript"; + + /** This is a possible HTML attribute for the LINK tag. */ + public const string HTML_VALUE_CSS = "text/css"; + + // CSS keys + + /** the CSS tag for background color */ + public const string CSS_KEY_BGCOLOR = "background-color"; + + /** the CSS tag for text color */ + public const string CSS_KEY_COLOR = "color"; + + /** CSS key that indicate the way something has to be displayed */ + public const string CSS_KEY_DISPLAY = "display"; + + /** the CSS tag for the font family */ + public const string CSS_KEY_FONTFAMILY = "font-family"; + + /** the CSS tag for the font size */ + public const string CSS_KEY_FONTSIZE = "font-size"; + + /** the CSS tag for the font style */ + public const string CSS_KEY_FONTSTYLE = "font-style"; + + /** the CSS tag for the font weight */ + public const string CSS_KEY_FONTWEIGHT = "font-weight"; + + /** the CSS tag for text decorations */ + public const string CSS_KEY_LINEHEIGHT = "line-height"; + + /** the CSS tag for the margin of an object */ + public const string CSS_KEY_MARGIN = "margin"; + + /** the CSS tag for the margin of an object */ + public const string CSS_KEY_MARGINLEFT = "margin-left"; + + /** the CSS tag for the margin of an object */ + public const string CSS_KEY_MARGINRIGHT = "margin-right"; + + /** the CSS tag for the margin of an object */ + public const string CSS_KEY_MARGINTOP = "margin-top"; + + /** the CSS tag for the margin of an object */ + public const string CSS_KEY_MARGINBOTTOM = "margin-bottom"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_PADDING = "padding"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_PADDINGLEFT = "padding-left"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_PADDINGRIGHT = "padding-right"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_PADDINGTOP = "padding-top"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_PADDINGBOTTOM = "padding-bottom"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_BORDERCOLOR = "border-color"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_BORDERWIDTH = "border-width"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_BORDERWIDTHLEFT = "border-left-width"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_BORDERWIDTHRIGHT = "border-right-width"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_BORDERWIDTHTOP = "border-top-width"; + + /** the CSS tag for the margin of an object */ + public const String CSS_KEY_BORDERWIDTHBOTTOM = "border-bottom-width"; + + /** the CSS tag for adding a page break when the document is printed */ + public const string CSS_KEY_PAGE_BREAK_AFTER = "page-break-after"; + + /** the CSS tag for adding a page break when the document is printed */ + public const string CSS_KEY_PAGE_BREAK_BEFORE = "page-break-before"; + + /** the CSS tag for the horizontal alignment of an object */ + public const string CSS_KEY_TEXTALIGN = "text-align"; + + /** the CSS tag for text decorations */ + public const string CSS_KEY_TEXTDECORATION = "text-decoration"; + + /** the CSS tag for text decorations */ + public const string CSS_KEY_VERTICALALIGN = "vertical-align"; + + /** the CSS tag for the visibility of objects */ + public const string CSS_KEY_VISIBILITY = "visibility"; + + // CSS values + + /** value for the CSS tag for adding a page break when the document is printed */ + public const string CSS_VALUE_ALWAYS = "always"; + + /** A possible value for the DISPLAY key */ + public const string CSS_VALUE_BLOCK = "block"; + + /** a CSS value for text font weight */ + public const string CSS_VALUE_BOLD = "bold"; + + /** the value if you want to hide objects. */ + public const string CSS_VALUE_HIDDEN = "hidden"; + + /** A possible value for the DISPLAY key */ + public const string CSS_VALUE_INLINE = "inline"; + + /** a CSS value for text font style */ + public const string CSS_VALUE_ITALIC = "italic"; + + /** a CSS value for text decoration */ + public const string CSS_VALUE_LINETHROUGH = "line-through"; + + /** A possible value for the DISPLAY key */ + public const string CSS_VALUE_LISTITEM = "list-item"; + + /** a CSS value */ + public const string CSS_VALUE_NONE = "none"; + + /** a CSS value */ + public const string CSS_VALUE_NORMAL = "normal"; + + /** a CSS value for text font style */ + public const string CSS_VALUE_OBLIQUE = "oblique"; + + /** A possible value for the DISPLAY key */ + public const string CSS_VALUE_TABLE = "table"; + + /** A possible value for the DISPLAY key */ + public const string CSS_VALUE_TABLEROW = "table-row"; + + /** A possible value for the DISPLAY key */ + public const string CSS_VALUE_TABLECELL = "table-cell"; + + /** the CSS value for a horizontal alignment of an object */ + public const string CSS_VALUE_TEXTALIGNLEFT = "left"; + + /** the CSS value for a horizontal alignment of an object */ + public const string CSS_VALUE_TEXTALIGNRIGHT = "right"; + + /** the CSS value for a horizontal alignment of an object */ + public const string CSS_VALUE_TEXTALIGNCENTER = "center"; + + /** the CSS value for a horizontal alignment of an object */ + public const string CSS_VALUE_TEXTALIGNJUSTIFY = "justify"; + + /** a CSS value for text decoration */ + public const string CSS_VALUE_UNDERLINE = "underline"; + + /// + /// Parses a length. + /// + /// a length in the form of an optional + or -, followed by a number and a unit. + /// a float + public static float ParseLength(string str) { + int pos = 0; + int length = str.Length; + bool ok = true; + while (ok && pos < length) { + switch (str[pos]) { + case '+': + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '.': + pos++; + break; + default: + ok = false; + break; + } + } + if (pos == 0) return 0f; + if (pos == length) return float.Parse(str, System.Globalization.NumberFormatInfo.InvariantInfo); + float f = float.Parse(str.Substring(0, pos), System.Globalization.NumberFormatInfo.InvariantInfo); + str = str.Substring(pos); + // inches + if (str.StartsWith("in")) { + return f * 72f; + } + // centimeters + if (str.StartsWith("cm")) { + return (f / 2.54f) * 72f; + } + // millimeters + if (str.StartsWith("mm")) { + return (f / 25.4f) * 72f; + } + // picas + if (str.StartsWith("pc")) { + return f * 12f; + } + // default: we assume the length was measured in points + return f; + } + + /// + /// Converts a Color into a HTML representation of this Color. + /// + /// the Color that has to be converted. + /// the HTML representation of this Color + public static Color DecodeColor(String s) { + if (s == null) + return null; + s = s.ToLower(CultureInfo.InvariantCulture).Trim(); + Color c = (Color)WebColors.GetRGBColor(s); + if (c != null) + return c; + try { + if (s.StartsWith("#")) { + if (s.Length == 4) + s = "#" + s.Substring(1, 1) + s.Substring(1, 1) + + s.Substring(2, 1) + s.Substring(2, 1) + + s.Substring(3, 1) + s.Substring(3, 1); + if (s.Length == 7) + return new Color(int.Parse(s.Substring(1), NumberStyles.HexNumber)); + } + else if (s.StartsWith("rgb")) { + StringTokenizer tk = new StringTokenizer(s.Substring(3), " \t\r\n\f(),"); + int[] cc = new int [3]; + for (int k = 0; k < 3; ++k) { + if (!tk.HasMoreTokens()) + return null; + String t = tk.NextToken(); + float n; + if (t.EndsWith("%")) { + n = float.Parse(t.Substring(0, t.Length - 1), System.Globalization.NumberFormatInfo.InvariantInfo); + n = n * 255f / 100f; + } + else + n = float.Parse(t, System.Globalization.NumberFormatInfo.InvariantInfo); + int ni = (int)n; + if (ni > 255) + ni = 255; + else if (ni < 0) + ni = 0; + cc[k] = ni; + } + return new Color(cc[0], cc[1], cc[2]); + } + } + catch { + } + return null; + } + + /// + /// This method parses a string with attributes and returns a Properties object. + /// + /// a string of this form: 'key1="value1"; key2="value2";... keyN="valueN" ' + /// a Properties object + public static Properties ParseAttributes(string str) { + Properties result = new Properties(); + if (str == null) return result; + StringTokenizer keyValuePairs = new StringTokenizer(str, ";"); + StringTokenizer keyValuePair; + string key; + string value; + while (keyValuePairs.HasMoreTokens()) { + keyValuePair = new StringTokenizer(keyValuePairs.NextToken(), ":"); + if (keyValuePair.HasMoreTokens()) key = keyValuePair.NextToken().Trim().Trim(); + else continue; + if (keyValuePair.HasMoreTokens()) value = keyValuePair.NextToken().Trim(); + else continue; + if (value.StartsWith("\"")) value = value.Substring(1); + if (value.EndsWith("\"")) value = value.Substring(0, value.Length - 1); + result.Add(key.ToLower(CultureInfo.InvariantCulture), value); + } + return result; + } + + /** + * Removes the comments sections of a String. + * + * @param string + * the original String + * @param startComment + * the String that marks the start of a Comment section + * @param endComment + * the String that marks the end of a Comment section. + * @return the String stripped of its comment section + */ + public static string RemoveComment(String str, String startComment, + String endComment) { + StringBuilder result = new StringBuilder(); + int pos = 0; + int end = endComment.Length; + int start = str.IndexOf(startComment, pos); + while (start > -1) { + result.Append(str.Substring(pos, start - pos)); + pos = str.IndexOf(endComment, start) + end; + start = str.IndexOf(startComment, pos); + } + result.Append(str.Substring(pos)); + return result.ToString(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/html/WebColors.cs b/iTechSharp/iTextSharp/text/html/WebColors.cs new file mode 100644 index 0000000..1e8323d --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/WebColors.cs @@ -0,0 +1,263 @@ +using System; +using System.Collections; +using System.Globalization; +using iTextSharp.text; +using System.util; +/* + * $Id: WebColors.cs,v 1.3 2008/05/13 11:25:16 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html { + + /** + * This class is a HashMap that contains the names of colors as a key and the + * corresponding Color as value. (Source: Wikipedia + * http://en.wikipedia.org/wiki/Web_colors ) + * + * @author blowagie + */ + public class WebColors : Hashtable { + + public static WebColors NAMES = new WebColors(); + static WebColors() { + NAMES["aliceblue"] = new int[] { 0xf0, 0xf8, 0xff, 0x00 }; + NAMES["antiquewhite"] = new int[] { 0xfa, 0xeb, 0xd7, 0x00 }; + NAMES["aqua"] = new int[] { 0x00, 0xff, 0xff, 0x00 }; + NAMES["aquamarine"] = new int[] { 0x7f, 0xff, 0xd4, 0x00 }; + NAMES["azure"] = new int[] { 0xf0, 0xff, 0xff, 0x00 }; + NAMES["beige"] = new int[] { 0xf5, 0xf5, 0xdc, 0x00 }; + NAMES["bisque"] = new int[] { 0xff, 0xe4, 0xc4, 0x00 }; + NAMES["black"] = new int[] { 0x00, 0x00, 0x00, 0x00 }; + NAMES["blanchedalmond"] = new int[] { 0xff, 0xeb, 0xcd, 0x00 }; + NAMES["blue"] = new int[] { 0x00, 0x00, 0xff, 0x00 }; + NAMES["blueviolet"] = new int[] { 0x8a, 0x2b, 0xe2, 0x00 }; + NAMES["brown"] = new int[] { 0xa5, 0x2a, 0x2a, 0x00 }; + NAMES["burlywood"] = new int[] { 0xde, 0xb8, 0x87, 0x00 }; + NAMES["cadetblue"] = new int[] { 0x5f, 0x9e, 0xa0, 0x00 }; + NAMES["chartreuse"] = new int[] { 0x7f, 0xff, 0x00, 0x00 }; + NAMES["chocolate"] = new int[] { 0xd2, 0x69, 0x1e, 0x00 }; + NAMES["coral"] = new int[] { 0xff, 0x7f, 0x50, 0x00 }; + NAMES["cornflowerblue"] = new int[] { 0x64, 0x95, 0xed, 0x00 }; + NAMES["cornsilk"] = new int[] { 0xff, 0xf8, 0xdc, 0x00 }; + NAMES["crimson"] = new int[] { 0xdc, 0x14, 0x3c, 0x00 }; + NAMES["cyan"] = new int[] { 0x00, 0xff, 0xff, 0x00 }; + NAMES["darkblue"] = new int[] { 0x00, 0x00, 0x8b, 0x00 }; + NAMES["darkcyan"] = new int[] { 0x00, 0x8b, 0x8b, 0x00 }; + NAMES["darkgoldenrod"] = new int[] { 0xb8, 0x86, 0x0b, 0x00 }; + NAMES["darkgray"] = new int[] { 0xa9, 0xa9, 0xa9, 0x00 }; + NAMES["darkgreen"] = new int[] { 0x00, 0x64, 0x00, 0x00 }; + NAMES["darkkhaki"] = new int[] { 0xbd, 0xb7, 0x6b, 0x00 }; + NAMES["darkmagenta"] = new int[] { 0x8b, 0x00, 0x8b, 0x00 }; + NAMES["darkolivegreen"] = new int[] { 0x55, 0x6b, 0x2f, 0x00 }; + NAMES["darkorange"] = new int[] { 0xff, 0x8c, 0x00, 0x00 }; + NAMES["darkorchid"] = new int[] { 0x99, 0x32, 0xcc, 0x00 }; + NAMES["darkred"] = new int[] { 0x8b, 0x00, 0x00, 0x00 }; + NAMES["darksalmon"] = new int[] { 0xe9, 0x96, 0x7a, 0x00 }; + NAMES["darkseagreen"] = new int[] { 0x8f, 0xbc, 0x8f, 0x00 }; + NAMES["darkslateblue"] = new int[] { 0x48, 0x3d, 0x8b, 0x00 }; + NAMES["darkslategray"] = new int[] { 0x2f, 0x4f, 0x4f, 0x00 }; + NAMES["darkturquoise"] = new int[] { 0x00, 0xce, 0xd1, 0x00 }; + NAMES["darkviolet"] = new int[] { 0x94, 0x00, 0xd3, 0x00 }; + NAMES["deeppink"] = new int[] { 0xff, 0x14, 0x93, 0x00 }; + NAMES["deepskyblue"] = new int[] { 0x00, 0xbf, 0xff, 0x00 }; + NAMES["dimgray"] = new int[] { 0x69, 0x69, 0x69, 0x00 }; + NAMES["dodgerblue"] = new int[] { 0x1e, 0x90, 0xff, 0x00 }; + NAMES["firebrick"] = new int[] { 0xb2, 0x22, 0x22, 0x00 }; + NAMES["floralwhite"] = new int[] { 0xff, 0xfa, 0xf0, 0x00 }; + NAMES["forestgreen"] = new int[] { 0x22, 0x8b, 0x22, 0x00 }; + NAMES["fuchsia"] = new int[] { 0xff, 0x00, 0xff, 0x00 }; + NAMES["gainsboro"] = new int[] { 0xdc, 0xdc, 0xdc, 0x00 }; + NAMES["ghostwhite"] = new int[] { 0xf8, 0xf8, 0xff, 0x00 }; + NAMES["gold"] = new int[] { 0xff, 0xd7, 0x00, 0x00 }; + NAMES["goldenrod"] = new int[] { 0xda, 0xa5, 0x20, 0x00 }; + NAMES["gray"] = new int[] { 0x80, 0x80, 0x80, 0x00 }; + NAMES["green"] = new int[] { 0x00, 0x80, 0x00, 0x00 }; + NAMES["greenyellow"] = new int[] { 0xad, 0xff, 0x2f, 0x00 }; + NAMES["honeydew"] = new int[] { 0xf0, 0xff, 0xf0, 0x00 }; + NAMES["hotpink"] = new int[] { 0xff, 0x69, 0xb4, 0x00 }; + NAMES["indianred"] = new int[] { 0xcd, 0x5c, 0x5c, 0x00 }; + NAMES["indigo"] = new int[] { 0x4b, 0x00, 0x82, 0x00 }; + NAMES["ivory"] = new int[] { 0xff, 0xff, 0xf0, 0x00 }; + NAMES["khaki"] = new int[] { 0xf0, 0xe6, 0x8c, 0x00 }; + NAMES["lavender"] = new int[] { 0xe6, 0xe6, 0xfa, 0x00 }; + NAMES["lavenderblush"] = new int[] { 0xff, 0xf0, 0xf5, 0x00 }; + NAMES["lawngreen"] = new int[] { 0x7c, 0xfc, 0x00, 0x00 }; + NAMES["lemonchiffon"] = new int[] { 0xff, 0xfa, 0xcd, 0x00 }; + NAMES["lightblue"] = new int[] { 0xad, 0xd8, 0xe6, 0x00 }; + NAMES["lightcoral"] = new int[] { 0xf0, 0x80, 0x80, 0x00 }; + NAMES["lightcyan"] = new int[] { 0xe0, 0xff, 0xff, 0x00 }; + NAMES["lightgoldenrodyellow"] = new int[] { 0xfa, 0xfa, 0xd2, 0x00 }; + NAMES["lightgreen"] = new int[] { 0x90, 0xee, 0x90, 0x00 }; + NAMES["lightgrey"] = new int[] { 0xd3, 0xd3, 0xd3, 0x00 }; + NAMES["lightpink"] = new int[] { 0xff, 0xb6, 0xc1, 0x00 }; + NAMES["lightsalmon"] = new int[] { 0xff, 0xa0, 0x7a, 0x00 }; + NAMES["lightseagreen"] = new int[] { 0x20, 0xb2, 0xaa, 0x00 }; + NAMES["lightskyblue"] = new int[] { 0x87, 0xce, 0xfa, 0x00 }; + NAMES["lightslategray"] = new int[] { 0x77, 0x88, 0x99, 0x00 }; + NAMES["lightsteelblue"] = new int[] { 0xb0, 0xc4, 0xde, 0x00 }; + NAMES["lightyellow"] = new int[] { 0xff, 0xff, 0xe0, 0x00 }; + NAMES["lime"] = new int[] { 0x00, 0xff, 0x00, 0x00 }; + NAMES["limegreen"] = new int[] { 0x32, 0xcd, 0x32, 0x00 }; + NAMES["linen"] = new int[] { 0xfa, 0xf0, 0xe6, 0x00 }; + NAMES["magenta"] = new int[] { 0xff, 0x00, 0xff, 0x00 }; + NAMES["maroon"] = new int[] { 0x80, 0x00, 0x00, 0x00 }; + NAMES["mediumaquamarine"] = new int[] { 0x66, 0xcd, 0xaa, 0x00 }; + NAMES["mediumblue"] = new int[] { 0x00, 0x00, 0xcd, 0x00 }; + NAMES["mediumorchid"] = new int[] { 0xba, 0x55, 0xd3, 0x00 }; + NAMES["mediumpurple"] = new int[] { 0x93, 0x70, 0xdb, 0x00 }; + NAMES["mediumseagreen"] = new int[] { 0x3c, 0xb3, 0x71, 0x00 }; + NAMES["mediumslateblue"] = new int[] { 0x7b, 0x68, 0xee, 0x00 }; + NAMES["mediumspringgreen"] = new int[] { 0x00, 0xfa, 0x9a, 0x00 }; + NAMES["mediumturquoise"] = new int[] { 0x48, 0xd1, 0xcc, 0x00 }; + NAMES["mediumvioletred"] = new int[] { 0xc7, 0x15, 0x85, 0x00 }; + NAMES["midnightblue"] = new int[] { 0x19, 0x19, 0x70, 0x00 }; + NAMES["mintcream"] = new int[] { 0xf5, 0xff, 0xfa, 0x00 }; + NAMES["mistyrose"] = new int[] { 0xff, 0xe4, 0xe1, 0x00 }; + NAMES["moccasin"] = new int[] { 0xff, 0xe4, 0xb5, 0x00 }; + NAMES["navajowhite"] = new int[] { 0xff, 0xde, 0xad, 0x00 }; + NAMES["navy"] = new int[] { 0x00, 0x00, 0x80, 0x00 }; + NAMES["oldlace"] = new int[] { 0xfd, 0xf5, 0xe6, 0x00 }; + NAMES["olive"] = new int[] { 0x80, 0x80, 0x00, 0x00 }; + NAMES["olivedrab"] = new int[] { 0x6b, 0x8e, 0x23, 0x00 }; + NAMES["orange"] = new int[] { 0xff, 0xa5, 0x00, 0x00 }; + NAMES["orangered"] = new int[] { 0xff, 0x45, 0x00, 0x00 }; + NAMES["orchid"] = new int[] { 0xda, 0x70, 0xd6, 0x00 }; + NAMES["palegoldenrod"] = new int[] { 0xee, 0xe8, 0xaa, 0x00 }; + NAMES["palegreen"] = new int[] { 0x98, 0xfb, 0x98, 0x00 }; + NAMES["paleturquoise"] = new int[] { 0xaf, 0xee, 0xee, 0x00 }; + NAMES["palevioletred"] = new int[] { 0xdb, 0x70, 0x93, 0x00 }; + NAMES["papayawhip"] = new int[] { 0xff, 0xef, 0xd5, 0x00 }; + NAMES["peachpuff"] = new int[] { 0xff, 0xda, 0xb9, 0x00 }; + NAMES["peru"] = new int[] { 0xcd, 0x85, 0x3f, 0x00 }; + NAMES["pink"] = new int[] { 0xff, 0xc0, 0xcb, 0x00 }; + NAMES["plum"] = new int[] { 0xdd, 0xa0, 0xdd, 0x00 }; + NAMES["powderblue"] = new int[] { 0xb0, 0xe0, 0xe6, 0x00 }; + NAMES["purple"] = new int[] { 0x80, 0x00, 0x80, 0x00 }; + NAMES["red"] = new int[] { 0xff, 0x00, 0x00, 0x00 }; + NAMES["rosybrown"] = new int[] { 0xbc, 0x8f, 0x8f, 0x00 }; + NAMES["royalblue"] = new int[] { 0x41, 0x69, 0xe1, 0x00 }; + NAMES["saddlebrown"] = new int[] { 0x8b, 0x45, 0x13, 0x00 }; + NAMES["salmon"] = new int[] { 0xfa, 0x80, 0x72, 0x00 }; + NAMES["sandybrown"] = new int[] { 0xf4, 0xa4, 0x60, 0x00 }; + NAMES["seagreen"] = new int[] { 0x2e, 0x8b, 0x57, 0x00 }; + NAMES["seashell"] = new int[] { 0xff, 0xf5, 0xee, 0x00 }; + NAMES["sienna"] = new int[] { 0xa0, 0x52, 0x2d, 0x00 }; + NAMES["silver"] = new int[] { 0xc0, 0xc0, 0xc0, 0x00 }; + NAMES["skyblue"] = new int[] { 0x87, 0xce, 0xeb, 0x00 }; + NAMES["slateblue"] = new int[] { 0x6a, 0x5a, 0xcd, 0x00 }; + NAMES["slategray"] = new int[] { 0x70, 0x80, 0x90, 0x00 }; + NAMES["snow"] = new int[] { 0xff, 0xfa, 0xfa, 0x00 }; + NAMES["springgreen"] = new int[] { 0x00, 0xff, 0x7f, 0x00 }; + NAMES["steelblue"] = new int[] { 0x46, 0x82, 0xb4, 0x00 }; + NAMES["tan"] = new int[] { 0xd2, 0xb4, 0x8c, 0x00 }; + NAMES["transparent"] = new int[] { 0x00, 0x00, 0x00, 0xff }; + NAMES["teal"] = new int[] { 0x00, 0x80, 0x80, 0x00 }; + NAMES["thistle"] = new int[] { 0xd8, 0xbf, 0xd8, 0x00 }; + NAMES["tomato"] = new int[] { 0xff, 0x63, 0x47, 0x00 }; + NAMES["turquoise"] = new int[] { 0x40, 0xe0, 0xd0, 0x00 }; + NAMES["violet"] = new int[] { 0xee, 0x82, 0xee, 0x00 }; + NAMES["wheat"] = new int[] { 0xf5, 0xde, 0xb3, 0x00 }; + NAMES["white"] = new int[] { 0xff, 0xff, 0xff, 0x00 }; + NAMES["whitesmoke"] = new int[] { 0xf5, 0xf5, 0xf5, 0x00 }; + NAMES["yellow"] = new int[] { 0xff, 0xff, 0x00, 0x00 }; + NAMES["yellowgreen"] = new int[] { 0x9, 0xacd, 0x32, 0x00 }; + } + + /** + * Gives you a Color based on a name. + * + * @param name + * a name such as black, violet, cornflowerblue or #RGB or #RRGGBB + * or rgb(R,G,B) + * @return the corresponding Color object + * @throws IllegalArgumentException + * if the String isn't a know representation of a color. + */ + public static Color GetRGBColor(String name) { + int[] c = { 0, 0, 0, 0 }; + if (name.StartsWith("#")) { + if (name.Length == 4) { + c[0] = int.Parse(name.Substring(1, 1), NumberStyles.HexNumber) * 16; + c[1] = int.Parse(name.Substring(2, 1), NumberStyles.HexNumber) * 16; + c[2] = int.Parse(name.Substring(3), NumberStyles.HexNumber) * 16; + return new Color(c[0], c[1], c[2], c[3]); + } + if (name.Length == 7) { + c[0] = int.Parse(name.Substring(1, 2), NumberStyles.HexNumber); + c[1] = int.Parse(name.Substring(3, 2), NumberStyles.HexNumber); + c[2] = int.Parse(name.Substring(5), NumberStyles.HexNumber); + return new Color(c[0], c[1], c[2], c[3]); + } + throw new ArgumentException( + "Unknown color format. Must be #RGB or #RRGGBB"); + } + else if (name.StartsWith("rgb(")) { + StringTokenizer tok = new StringTokenizer(name, "rgb(), \t\r\n\f"); + for (int k = 0; k < 3; ++k) { + String v = tok.NextToken(); + if (v.EndsWith("%")) + c[k] = int.Parse(v.Substring(0, v.Length - 1)) * 255 / 100; + else + c[k] = int.Parse(v); + if (c[k] < 0) + c[k] = 0; + else if (c[k] > 255) + c[k] = 255; + } + return new Color(c[0], c[1], c[2], c[3]); + } + name = name.ToLower(CultureInfo.InvariantCulture); + if (!NAMES.ContainsKey(name)) + throw new ArgumentException("Color '" + name + + "' not found."); + c = (int[]) NAMES[name]; + return new Color(c[0], c[1], c[2], c[3]); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/ChainedProperties.cs b/iTechSharp/iTextSharp/text/html/simpleparser/ChainedProperties.cs new file mode 100644 index 0000000..c9a8c05 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/ChainedProperties.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections; +/* + * Copyright 2004 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html.simpleparser { + +public class ChainedProperties { + + public static int[] fontSizes = {8, 10, 12, 14, 18, 24, 36}; + public ArrayList chain = new ArrayList(); + + /** Creates a new instance of ChainedProperties */ + public ChainedProperties() { + } + + public String this[String key] { + get { + for (int k = chain.Count - 1; k >= 0; --k) { + Object[] obj = (Object[])chain[k]; + Hashtable prop = (Hashtable)obj[1]; + String ret = (String)prop[key]; + if (ret != null) + return ret; + } + return null; + } + } + + public bool HasProperty(String key) { + for (int k = chain.Count - 1; k >= 0; --k) { + Object[] obj = (Object[])chain[k]; + Hashtable prop = (Hashtable)obj[1]; + if (prop.ContainsKey(key)) + return true; + } + return false; + } + + public void AddToChain(String key, Hashtable prop) { + // adjust the font size + String value = (String)prop["size"]; + if (value != null) { + if (value.EndsWith("px")) { + prop["size"] = value.Substring(0, value.Length - 2); + } + else { + int s = 0; + if (value.StartsWith("+") || value.StartsWith("-")) { + String old = this["basefontsize"]; + if (old == null) + old = "12"; + float f = float.Parse(old, System.Globalization.NumberFormatInfo.InvariantInfo); + int c = (int)f; + for (int k = fontSizes.Length - 1; k >= 0; --k) { + if (c >= fontSizes[k]) { + s = k; + break; + } + } + int inc = int.Parse(value.StartsWith("+") ? value.Substring(1) : value); + s += inc; + } + else { + try { + s = int.Parse(value) - 1; + } + catch { + s = 0; + } + } + if (s < 0) + s = 0; + else if (s >= fontSizes.Length) + s = fontSizes.Length - 1; + prop["size"] = fontSizes[s].ToString(); + } + } + chain.Add(new Object[]{key, prop}); + } + + public void RemoveChain(String key) { + for (int k = chain.Count - 1; k >= 0; --k) { + if (key.Equals(((Object[])chain[k])[0])) { + chain.RemoveAt(k); + return; + } + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/FactoryProperties.cs b/iTechSharp/iTextSharp/text/html/simpleparser/FactoryProperties.cs new file mode 100644 index 0000000..290876c --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/FactoryProperties.cs @@ -0,0 +1,338 @@ +using System; +using System.Collections; +using System.Globalization; +using System.util; +using iTextSharp.text; +using iTextSharp.text.pdf; +using iTextSharp.text.html; +/* + * Copyright 2004 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html.simpleparser { + + /** + * + * @author psoares + */ + public class FactoryProperties { + + private FontFactoryImp fontImp = FontFactory.FontImp; + + /** Creates a new instance of FactoryProperties */ + public FactoryProperties() { + } + + public Chunk CreateChunk(String text, ChainedProperties props) { + Font font = GetFont(props); + float size = font.Size; + size /= 2; + Chunk ck = new Chunk(text, font); + if (props.HasProperty("sub")) + ck.SetTextRise(-size); + else if (props.HasProperty("sup")) + ck.SetTextRise(size); + ck.SetHyphenation(GetHyphenation(props)); + return ck; + } + + private static void SetParagraphLeading(Paragraph p, String leading) { + if (leading == null) { + p.SetLeading(0, 1.5f); + return; + } + try { + StringTokenizer tk = new StringTokenizer(leading, " ,"); + String v = tk.NextToken(); + float v1 = float.Parse(v, System.Globalization.NumberFormatInfo.InvariantInfo); + if (!tk.HasMoreTokens()) { + p.SetLeading(v1, 0); + return; + } + v = tk.NextToken(); + float v2 = float.Parse(v, System.Globalization.NumberFormatInfo.InvariantInfo); + p.SetLeading(v1, v2); + } + catch { + p.SetLeading(0, 1.5f); + } + + } + + public static Paragraph CreateParagraph(Hashtable props) { + Paragraph p = new Paragraph(); + String value = (String)props["align"]; + if (value != null) { + if (Util.EqualsIgnoreCase(value, "center")) + p.Alignment = Element.ALIGN_CENTER; + else if (Util.EqualsIgnoreCase(value, "right")) + p.Alignment = Element.ALIGN_RIGHT; + else if (Util.EqualsIgnoreCase(value, "justify")) + p.Alignment = Element.ALIGN_JUSTIFIED; + } + SetParagraphLeading(p, (String)props["leading"]); + p.Hyphenation = GetHyphenation(props); + return p; + } + + public static void CreateParagraph(Paragraph p, ChainedProperties props) { + String value = props["align"]; + if (value != null) { + if (Util.EqualsIgnoreCase(value, "center")) + p.Alignment = Element.ALIGN_CENTER; + else if (Util.EqualsIgnoreCase(value, "right")) + p.Alignment = Element.ALIGN_RIGHT; + else if (Util.EqualsIgnoreCase(value, "justify")) + p.Alignment = Element.ALIGN_JUSTIFIED; + } + p.Hyphenation = GetHyphenation(props); + SetParagraphLeading(p, props["leading"]); + value = props["before"]; + if (value != null) { + try { + p.SpacingBefore = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + catch {} + } + value = props["after"]; + if (value != null) { + try { + p.SpacingAfter = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + catch {} + } + value = props["extraparaspace"]; + if (value != null) { + try { + p.ExtraParagraphSpace = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + } + catch {} + } + } + + public static Paragraph CreateParagraph(ChainedProperties props) { + Paragraph p = new Paragraph(); + CreateParagraph(p, props); + return p; + } + + public static ListItem CreateListItem(ChainedProperties props) { + ListItem p = new ListItem(); + CreateParagraph(p, props); + return p; + } + + public Font GetFont(ChainedProperties props) { + String face = props["face"]; + if (face != null) { + StringTokenizer tok = new StringTokenizer(face, ","); + while (tok.HasMoreTokens()) { + face = tok.NextToken().Trim(); + if (face.StartsWith("\"")) + face = face.Substring(1); + if (face.EndsWith("\"")) + face = face.Substring(0, face.Length - 1); + if (fontImp.IsRegistered(face)) + break; + } + } + int style = 0; + if (props.HasProperty("i")) + style |= Font.ITALIC; + if (props.HasProperty("b")) + style |= Font.BOLD; + if (props.HasProperty("u")) + style |= Font.UNDERLINE; + if (props.HasProperty("s")) + style |= Font.STRIKETHRU ; + + String value = props["size"]; + float size = 12; + if (value != null) + size = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + Color color = Markup.DecodeColor(props["color"]); + String encoding = props["encoding"]; + if (encoding == null) + encoding = BaseFont.WINANSI; + return fontImp.GetFont(face, encoding, true, size, style, color); + } + + /** + * Gets a HyphenationEvent based on the hyphenation entry in ChainedProperties. + * @param props ChainedProperties + * @return a HyphenationEvent + * @since 2.1.2 + */ + public static IHyphenationEvent GetHyphenation(ChainedProperties props) { + return GetHyphenation(props["hyphenation"]); + } + + /** + * Gets a HyphenationEvent based on the hyphenation entry in a HashMap. + * @param props a HashMap with properties + * @return a HyphenationEvent + * @since 2.1.2 + */ + public static IHyphenationEvent GetHyphenation(Hashtable props) { + return GetHyphenation((String)props["hyphenation"]); + } + + /** + * Gets a HyphenationEvent based on a String. + * For instance "en_UK,3,2" returns new HyphenationAuto("en", "UK", 3, 2); + * @param a String, for instance "en_UK,2,2" + * @return a HyphenationEvent + * @since 2.1.2 + */ + public static IHyphenationEvent GetHyphenation(String s) { + if (s == null || s.Length == 0) { + return null; + } + String lang = s; + String country = null; + int leftMin = 2; + int rightMin = 2; + + int pos = s.IndexOf('_'); + if (pos == -1) { + return new HyphenationAuto(lang, country, leftMin, rightMin); + } + lang = s.Substring(0, pos); + country = s.Substring(pos + 1); + pos = country.IndexOf(','); + if (pos == -1) { + return new HyphenationAuto(lang, country, leftMin, rightMin); + } + s = country.Substring(pos + 1); + country = country.Substring(0, pos); + pos = s.IndexOf(','); + if (pos == -1) { + leftMin = int.Parse(s); + } + else { + leftMin = int.Parse(s.Substring(0, pos)); + rightMin = int.Parse(s.Substring(pos + 1)); + } + return new HyphenationAuto(lang, country, leftMin, rightMin); + } + + public static void InsertStyle(Hashtable h) { + String style = (String)h["style"]; + if (style == null) + return; + Properties prop = Markup.ParseAttributes(style); + foreach (String key in prop.Keys) { + if (key.Equals(Markup.CSS_KEY_FONTFAMILY)) { + h["face"] = prop[key]; + } + else if (key.Equals(Markup.CSS_KEY_FONTSIZE)) { + h["size"] = Markup.ParseLength(prop[key]).ToString(NumberFormatInfo.InvariantInfo) + "px"; + } + else if (key.Equals(Markup.CSS_KEY_FONTSTYLE)) { + String ss = prop[key].Trim().ToLower(CultureInfo.InvariantCulture); + if (ss.Equals("italic") || ss.Equals("oblique")) + h["i"] = null; + } + else if (key.Equals(Markup.CSS_KEY_FONTWEIGHT)) { + String ss = prop[key].Trim().ToLower(CultureInfo.InvariantCulture); + if (ss.Equals("bold") || ss.Equals("700") || ss.Equals("800") || ss.Equals("900")) + h["b"] = null; + } + else if (key.Equals(Markup.CSS_KEY_FONTWEIGHT)) { + String ss = prop[key].Trim().ToLower(CultureInfo.InvariantCulture); + if (ss.Equals("underline")) + h["u"] = null; + } + else if (key.Equals(Markup.CSS_KEY_COLOR)) { + Color c = Markup.DecodeColor(prop[key]); + if (c != null) { + int hh = c.ToArgb() & 0xffffff; + String hs = "#" + hh.ToString("X06", NumberFormatInfo.InvariantInfo); + h["color"] = hs; + } + } + else if (key.Equals(Markup.CSS_KEY_LINEHEIGHT)) { + String ss = prop[key].Trim(); + float v = Markup.ParseLength(prop[key]); + if (ss.EndsWith("%")) { + v /= 100; + h["leading"] = "0," + v.ToString(NumberFormatInfo.InvariantInfo); + } + else { + h["leading"] = v.ToString(NumberFormatInfo.InvariantInfo) + ",0"; + } + } + else if (key.Equals(Markup.CSS_KEY_TEXTALIGN)) { + String ss = prop[key].Trim().ToLower(System.Globalization.CultureInfo.InvariantCulture); + h["align"] = ss; + } + } + } + + public FontFactoryImp FontImp { + get { + return fontImp; + } + set { + fontImp = value; + } + } + + public static Hashtable followTags = new Hashtable(); + + static FactoryProperties() { + followTags["i"] = "i"; + followTags["b"] = "b"; + followTags["u"] = "u"; + followTags["sub"] = "sub"; + followTags["sup"] = "sup"; + followTags["em"] = "i"; + followTags["strong"] = "b"; + followTags["s"] = "s"; + followTags["strike"] = "s"; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/HTMLWorker.cs b/iTechSharp/iTextSharp/text/html/simpleparser/HTMLWorker.cs new file mode 100644 index 0000000..3a7bd57 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/HTMLWorker.cs @@ -0,0 +1,624 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.Globalization; +using System.util; +using iTextSharp.text; +using iTextSharp.text.pdf; +using iTextSharp.text.xml.simpleparser; +/* + * Copyright 2004 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html.simpleparser { + + public class HTMLWorker : ISimpleXMLDocHandler, IDocListener { + + protected ArrayList objectList; + protected IDocListener document; + private Paragraph currentParagraph; + private ChainedProperties cprops = new ChainedProperties(); + private Stack stack = new Stack(); + private bool pendingTR = false; + private bool pendingTD = false; + private bool pendingLI = false; + private StyleSheet style = new StyleSheet(); + private bool isPRE = false; + private Stack tableState = new Stack(); + private bool skipText = false; + private Hashtable interfaceProps; + private FactoryProperties factoryProperties = new FactoryProperties(); + + /** Creates a new instance of HTMLWorker */ + public HTMLWorker(IDocListener document) { + this.document = document; + } + + public StyleSheet Style { + set { + style = value; + } + get { + return style; + } + } + + public Hashtable InterfaceProps { + set { + interfaceProps = value; + FontFactoryImp ff = null; + if (interfaceProps != null) + ff = (FontFactoryImp)interfaceProps["font_factory"]; + if (ff != null) + factoryProperties.FontImp = ff; + } + get { + return interfaceProps; + } + } + + public void Parse(TextReader reader) { + SimpleXMLParser.Parse(this, null, reader, true); + } + + public static ArrayList ParseToList(TextReader reader, StyleSheet style) { + return ParseToList(reader, style, null); + } + + public static ArrayList ParseToList(TextReader reader, StyleSheet style, Hashtable interfaceProps) { + HTMLWorker worker = new HTMLWorker(null); + if (style != null) + worker.Style = style; + worker.document = worker; + worker.InterfaceProps = interfaceProps; + worker.objectList = new ArrayList(); + worker.Parse(reader); + return worker.objectList; + } + + public virtual void EndDocument() { + foreach (IElement e in stack) + document.Add(e); + if (currentParagraph != null) + document.Add(currentParagraph); + currentParagraph = null; + } + + public virtual void StartDocument() { + Hashtable h = new Hashtable(); + style.ApplyStyle("body", h); + cprops.AddToChain("body", h); + } + + public virtual void StartElement(String tag, Hashtable h) { + if (!tagsSupported.ContainsKey(tag)) + return; + style.ApplyStyle(tag, h); + String follow = (String)FactoryProperties.followTags[tag]; + if (follow != null) { + Hashtable prop = new Hashtable(); + prop[follow] = null; + cprops.AddToChain(follow, prop); + return; + } + FactoryProperties.InsertStyle(h); + if (tag.Equals("a")) { + cprops.AddToChain(tag, h); + if (currentParagraph == null) + currentParagraph = new Paragraph(); + stack.Push(currentParagraph); + currentParagraph = new Paragraph(); + return; + } + if (tag.Equals("br")) { + if (currentParagraph == null) + currentParagraph = new Paragraph(); + currentParagraph.Add(factoryProperties.CreateChunk("\n", cprops)); + return; + } + if (tag.Equals("font") || tag.Equals("span")) { + cprops.AddToChain(tag, h); + return; + } + if (tag.Equals("img")) { + String src = (String)h["src"]; + if (src == null) + return; + cprops.AddToChain(tag, h); + Image img = null; + if (interfaceProps != null) { + IImageProvider ip = (IImageProvider)interfaceProps["img_provider"]; + if (ip != null) + img = ip.GetImage(src, h, cprops, document); + if (img == null) { + Hashtable images = (Hashtable)interfaceProps["img_static"]; + if (images != null) { + Image tim = (Image)images[src]; + if (tim != null) + img = Image.GetInstance(tim); + } else { + if (!src.StartsWith("http")) { // relative src references only + String baseurl = (String)interfaceProps["img_baseurl"]; + if (baseurl != null) { + src = baseurl + src; + img = Image.GetInstance(src); + } + } + } + } + } + if (img == null) { + if (!src.StartsWith("http")) { + String path = cprops["image_path"]; + if (path == null) + path = ""; + src = Path.Combine(path, src); + } + img = Image.GetInstance(src); + } + String align = (String)h["align"]; + String width = (String)h["width"]; + String height = (String)h["height"]; + String before = cprops["before"]; + String after = cprops["after"]; + if (before != null) + img.SpacingBefore = float.Parse(before, System.Globalization.NumberFormatInfo.InvariantInfo); + if (after != null) + img.SpacingAfter = float.Parse(after, System.Globalization.NumberFormatInfo.InvariantInfo); + float wp = LengthParse(width, (int)img.Width); + float lp = LengthParse(height, (int)img.Height); + if (wp > 0 && lp > 0) + img.ScalePercent(wp > lp ? lp : wp); + else if (wp > 0) + img.ScalePercent(wp); + else if (lp > 0) + img.ScalePercent(lp); + img.WidthPercentage = 0; + if (align != null) { + EndElement("p"); + int ralign = Image.MIDDLE_ALIGN; + if (Util.EqualsIgnoreCase(align, "left")) + ralign = Image.LEFT_ALIGN; + else if (Util.EqualsIgnoreCase(align, "right")) + ralign = Image.RIGHT_ALIGN; + img.Alignment = ralign; + IImg i = null; + bool skip = false; + if (interfaceProps != null) { + i = (IImg)interfaceProps["img_interface"]; + if (i != null) + skip = i.Process(img, h, cprops, document); + } + if (!skip) + document.Add(img); + cprops.RemoveChain(tag); + } + else { + cprops.RemoveChain(tag); + if (currentParagraph == null) + currentParagraph = FactoryProperties.CreateParagraph(cprops); + currentParagraph.Add(new Chunk(img, 0, 0)); + } + return; + } + + EndElement("p"); + if (tag.Equals("h1") || tag.Equals("h2") || tag.Equals("h3") || tag.Equals("h4") || tag.Equals("h5") || tag.Equals("h6")) { + if (!h.ContainsKey("size")) { + int v = 7 - int.Parse(tag.Substring(1)); + h["size"] = v.ToString(); + } + cprops.AddToChain(tag, h); + return; + } + if (tag.Equals("ul")) { + if (pendingLI) + EndElement("li"); + skipText = true; + cprops.AddToChain(tag, h); + List list = new List(false, 10); + list.SetListSymbol("\u2022"); + stack.Push(list); + return; + } + if (tag.Equals("ol")) { + if (pendingLI) + EndElement("li"); + skipText = true; + cprops.AddToChain(tag, h); + List list = new List(true, 10); + stack.Push(list); + return; + } + if (tag.Equals("li")) { + if (pendingLI) + EndElement("li"); + skipText = false; + pendingLI = true; + cprops.AddToChain(tag, h); + stack.Push(FactoryProperties.CreateListItem(cprops)); + return; + } + if (tag.Equals("div") || tag.Equals("body")) { + cprops.AddToChain(tag, h); + return; + } + if (tag.Equals("pre")) { + if (!h.ContainsKey("face")) { + h["face"] = "Courier"; + } + cprops.AddToChain(tag, h); + isPRE = true; + return; + } + if (tag.Equals("p")) { + cprops.AddToChain(tag, h); + currentParagraph = FactoryProperties.CreateParagraph(h); + return; + } + if (tag.Equals("tr")) { + if (pendingTR) + EndElement("tr"); + skipText = true; + pendingTR = true; + cprops.AddToChain("tr", h); + return; + } + if (tag.Equals("td") || tag.Equals("th")) { + if (pendingTD) + EndElement(tag); + skipText = false; + pendingTD = true; + cprops.AddToChain("td", h); + stack.Push(new IncCell(tag, cprops)); + return; + } + if (tag.Equals("table")) { + cprops.AddToChain("table", h); + IncTable table = new IncTable(h); + stack.Push(table); + tableState.Push(new bool[]{pendingTR, pendingTD}); + pendingTR = pendingTD = false; + skipText = true; + return; + } + } + + public virtual void EndElement(String tag) { + if (!tagsSupported.ContainsKey(tag)) + return; + String follow = (String)FactoryProperties.followTags[tag]; + if (follow != null) { + cprops.RemoveChain(follow); + return; + } + if (tag.Equals("font") || tag.Equals("span")) { + cprops.RemoveChain(tag); + return; + } + if (tag.Equals("a")) { + if (currentParagraph == null) + currentParagraph = new Paragraph(); + IALink i = null; + bool skip = false; + if (interfaceProps != null) { + i = (IALink)interfaceProps["alink_interface"]; + if (i != null) + skip = i.Process(currentParagraph, cprops); + } + if (!skip) { + String href = cprops["href"]; + if (href != null) { + ArrayList chunks = currentParagraph.Chunks; + for (int k = 0; k < chunks.Count; ++k) { + Chunk ck = (Chunk)chunks[k]; + ck.SetAnchor(href); + } + } + } + Paragraph tmp = (Paragraph)stack.Pop(); + Phrase tmp2 = new Phrase(); + tmp2.Add(currentParagraph); + tmp.Add(tmp2); + currentParagraph = tmp; + cprops.RemoveChain("a"); + return; + } + if (tag.Equals("br")) { + return; + } + if (currentParagraph != null) { + if (stack.Count == 0) + document.Add(currentParagraph); + else { + Object obj = stack.Pop(); + if (obj is ITextElementArray) { + ITextElementArray current = (ITextElementArray)obj; + current.Add(currentParagraph); + } + stack.Push(obj); + } + } + currentParagraph = null; + if (tag.Equals("ul") || tag.Equals("ol")) { + if (pendingLI) + EndElement("li"); + skipText = false; + cprops.RemoveChain(tag); + if (stack.Count == 0) + return; + Object obj = stack.Pop(); + if (!(obj is List)) { + stack.Push(obj); + return; + } + if (stack.Count == 0) + document.Add((IElement)obj); + else + ((ITextElementArray)stack.Peek()).Add(obj); + return; + } + if (tag.Equals("li")) { + pendingLI = false; + skipText = true; + cprops.RemoveChain(tag); + if (stack.Count == 0) + return; + Object obj = stack.Pop(); + if (!(obj is ListItem)) { + stack.Push(obj); + return; + } + if (stack.Count == 0) { + document.Add((IElement)obj); + return; + } + Object list = stack.Pop(); + if (!(list is List)) { + stack.Push(list); + return; + } + ListItem item = (ListItem)obj; + ((List)list).Add(item); + ArrayList cks = item.Chunks; + if (cks.Count > 0) + item.ListSymbol.Font = ((Chunk)cks[0]).Font; + stack.Push(list); + return; + } + if (tag.Equals("div") || tag.Equals("body")) { + cprops.RemoveChain(tag); + return; + } + if (tag.Equals("pre")) { + cprops.RemoveChain(tag); + isPRE = false; + return; + } + if (tag.Equals("p")) { + cprops.RemoveChain(tag); + return; + } + if (tag.Equals("h1") || tag.Equals("h2") || tag.Equals("h3") || tag.Equals("h4") || tag.Equals("h5") || tag.Equals("h6")) { + cprops.RemoveChain(tag); + return; + } + if (tag.Equals("table")) { + if (pendingTR) + EndElement("tr"); + cprops.RemoveChain("table"); + IncTable table = (IncTable) stack.Pop(); + PdfPTable tb = table.BuildTable(); + tb.SplitRows = true; + if (stack.Count == 0) + document.Add(tb); + else + ((ITextElementArray)stack.Peek()).Add(tb); + bool[] state = (bool[])tableState.Pop(); + pendingTR = state[0]; + pendingTD = state[1]; + skipText = false; + return; + } + if (tag.Equals("tr")) { + if (pendingTD) + EndElement("td"); + pendingTR = false; + cprops.RemoveChain("tr"); + ArrayList cells = new ArrayList(); + IncTable table = null; + while (true) { + Object obj = stack.Pop(); + if (obj is IncCell) { + cells.Add(((IncCell)obj).Cell); + } + if (obj is IncTable) { + table = (IncTable)obj; + break; + } + } + table.AddCols(cells); + table.EndRow(); + stack.Push(table); + skipText = true; + return; + } + if (tag.Equals("td") || tag.Equals("th")) { + pendingTD = false; + cprops.RemoveChain("td"); + skipText = true; + return; + } + } + + public virtual void Text(String str) { + if (skipText) + return; + String content = str; + if (isPRE) { + if (currentParagraph == null) + currentParagraph = FactoryProperties.CreateParagraph(cprops); + currentParagraph.Add(factoryProperties.CreateChunk(content, cprops)); + return; + } + if (content.Trim().Length == 0 && content.IndexOf(' ') < 0) { + return; + } + + StringBuilder buf = new StringBuilder(); + int len = content.Length; + char character; + bool newline = false; + for (int i = 0; i < len; i++) { + switch (character = content[i]) { + case ' ': + if (!newline) { + buf.Append(character); + } + break; + case '\n': + if (i > 0) { + newline = true; + buf.Append(' '); + } + break; + case '\r': + break; + case '\t': + break; + default: + newline = false; + buf.Append(character); + break; + } + } + if (currentParagraph == null) + currentParagraph = FactoryProperties.CreateParagraph(cprops); + currentParagraph.Add(factoryProperties.CreateChunk(buf.ToString(), cprops)); + } + + public bool Add(IElement element) { + objectList.Add(element); + return true; + } + + public void ClearTextWrap() { + } + + public void Close() { + } + + public bool NewPage() { + return true; + } + + public void Open() { + } + + public void ResetFooter() { + } + + public void ResetHeader() { + } + + public void ResetPageCount() { + } + + public bool SetMarginMirroring(bool marginMirroring) { + return true; + } + + public bool SetMargins(float marginLeft, float marginRight, float marginTop, float marginBottom) { + return true; + } + + public bool SetPageSize(Rectangle pageSize) { + return true; + } + + public const String tagsSupportedString = "ol ul li a pre font span br p div body table td th tr i b u sub sup em strong s strike" + + " h1 h2 h3 h4 h5 h6 img"; + + public static Hashtable tagsSupported = new Hashtable(); + + static HTMLWorker() { + StringTokenizer tok = new StringTokenizer(tagsSupportedString); + while (tok.HasMoreTokens()) + tagsSupported[tok.NextToken()] = null; + } + + public HeaderFooter Footer { + set { + } + } + + public HeaderFooter Header { + set { + } + } + + public int PageCount { + set { + } + } + + private static float LengthParse(String txt, int c) { + if (txt == null) + return -1; + if (txt.EndsWith("%")) { + float vf = float.Parse(txt.Substring(0, txt.Length - 1), System.Globalization.NumberFormatInfo.InvariantInfo); + return vf; + } + if (txt.EndsWith("px")) { + float vf = float.Parse(txt.Substring(0, txt.Length - 2), System.Globalization.NumberFormatInfo.InvariantInfo); + return vf; + } + int v = int.Parse(txt); + return (float)v / c * 100f; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/IALink.cs b/iTechSharp/iTextSharp/text/html/simpleparser/IALink.cs new file mode 100644 index 0000000..ee2d897 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/IALink.cs @@ -0,0 +1,54 @@ +using System; +using iTextSharp.text; +/* + * Copyright 2005 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html.simpleparser { + public interface IALink { + bool Process(Paragraph current, ChainedProperties cprops); + } +} diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/IImageProvider.cs b/iTechSharp/iTextSharp/text/html/simpleparser/IImageProvider.cs new file mode 100644 index 0000000..820933b --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/IImageProvider.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections; +using iTextSharp.text; +/* + * Copyright 2007 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html.simpleparser { + public interface IImageProvider { + Image GetImage(String src, Hashtable h, ChainedProperties cprops, IDocListener doc); + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/IImg.cs b/iTechSharp/iTextSharp/text/html/simpleparser/IImg.cs new file mode 100644 index 0000000..6eeb6f4 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/IImg.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections; +using iTextSharp.text; + +/* + * Copyright 2005 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.html.simpleparser { + public interface IImg { + bool Process(Image img, Hashtable h, ChainedProperties cprops, IDocListener doc); + } +} diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/IncCell.cs b/iTechSharp/iTextSharp/text/html/simpleparser/IncCell.cs new file mode 100644 index 0000000..acd3387 --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/IncCell.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text; +using iTextSharp.text.pdf; +using iTextSharp.text.html; +/* + * Copyright 2004 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html.simpleparser { + /** + * + * @author psoares + */ + public class IncCell : ITextElementArray { + + private ArrayList chunks = new ArrayList(); + private PdfPCell cell; + + /** Creates a new instance of IncCell */ + public IncCell(String tag, ChainedProperties props) { + cell = new PdfPCell(); + String value = props["colspan"]; + if (value != null) + cell.Colspan = int.Parse(value); + value = props["align"]; + if (tag.Equals("th")) + cell.HorizontalAlignment = Element.ALIGN_CENTER; + if (value != null) { + if (Util.EqualsIgnoreCase(value, "center")) + cell.HorizontalAlignment = Element.ALIGN_CENTER; + else if (Util.EqualsIgnoreCase(value, "right")) + cell.HorizontalAlignment = Element.ALIGN_RIGHT; + else if (Util.EqualsIgnoreCase(value, "left")) + cell.HorizontalAlignment = Element.ALIGN_LEFT; + else if (Util.EqualsIgnoreCase(value, "justify")) + cell.HorizontalAlignment = Element.ALIGN_JUSTIFIED; + } + value = props["valign"]; + cell.VerticalAlignment = Element.ALIGN_MIDDLE; + if (value != null) { + if (Util.EqualsIgnoreCase(value, "top")) + cell.VerticalAlignment = Element.ALIGN_TOP; + else if (Util.EqualsIgnoreCase(value, "bottom")) + cell.VerticalAlignment = Element.ALIGN_BOTTOM; + } + value = props["border"]; + float border = 0; + if (value != null) + border = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + cell.BorderWidth = border; + value = props["cellpadding"]; + if (value != null) + cell.Padding = float.Parse(value, System.Globalization.NumberFormatInfo.InvariantInfo); + cell.UseDescender = true; + value = props["bgcolor"]; + cell.BackgroundColor = Markup.DecodeColor(value); + } + + public bool Add(Object o) { + if (!(o is IElement)) + return false; + cell.AddElement((IElement)o); + return true; + } + + public ArrayList Chunks { + get { + return chunks; + } + } + + public bool Process(IElementListener listener) { + return true; + } + + public int Type { + get { + return Element.RECTANGLE; + } + } + + public PdfPCell Cell { + get { + return cell; + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return true; + } + + public override string ToString() { + return base.ToString(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/IncTable.cs b/iTechSharp/iTextSharp/text/html/simpleparser/IncTable.cs new file mode 100644 index 0000000..d71c9bd --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/IncTable.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.pdf; +/* + * Copyright 2004 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html.simpleparser { + + /** + * + * @author psoares + */ + public class IncTable { + private Hashtable props = new Hashtable(); + private ArrayList rows = new ArrayList(); + private ArrayList cols; + /** Creates a new instance of IncTable */ + public IncTable(Hashtable props) { + foreach (DictionaryEntry dc in props) + this.props[dc.Key] = dc.Value; + } + + public void AddCol(PdfPCell cell) { + if (cols == null) + cols = new ArrayList(); + cols.Add(cell); + } + + public void AddCols(ArrayList ncols) { + if (cols == null) + cols = new ArrayList(ncols); + else + cols.AddRange(ncols); + } + + public void EndRow() { + if (cols != null) { + cols.Reverse(); + rows.Add(cols); + cols = null; + } + } + + public ArrayList Rows { + get { + return rows; + } + } + + public PdfPTable BuildTable() { + if (rows.Count == 0) + return new PdfPTable(1); + int ncol = 0; + ArrayList c0 = (ArrayList)rows[0]; + for (int k = 0; k < c0.Count; ++k) { + ncol += ((PdfPCell)c0[k]).Colspan; + } + PdfPTable table = new PdfPTable(ncol); + String width = (String)props["width"]; + if (width == null) + table.WidthPercentage = 100; + else { + if (width.EndsWith("%")) + table.WidthPercentage = float.Parse(width.Substring(0, width.Length - 1), System.Globalization.NumberFormatInfo.InvariantInfo); + else { + table.TotalWidth = float.Parse(width, System.Globalization.NumberFormatInfo.InvariantInfo); + table.LockedWidth = true; + } + } + for (int row = 0; row < rows.Count; ++row) { + ArrayList col = (ArrayList)rows[row]; + for (int k = 0; k < col.Count; ++k) { + table.AddCell((PdfPCell)col[k]); + } + } + return table; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/html/simpleparser/StyleSheet.cs b/iTechSharp/iTextSharp/text/html/simpleparser/StyleSheet.cs new file mode 100644 index 0000000..707e53f --- /dev/null +++ b/iTechSharp/iTextSharp/text/html/simpleparser/StyleSheet.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections; +/* + * Copyright 2004 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.html.simpleparser { + + public class StyleSheet { + + public Hashtable classMap = new Hashtable(); + public Hashtable tagMap = new Hashtable(); + + /** Creates a new instance of StyleSheet */ + public StyleSheet() { + } + + public void ApplyStyle(String tag, Hashtable props) { + Hashtable map = (Hashtable)tagMap[tag.ToLower(System.Globalization.CultureInfo.InvariantCulture)]; + Hashtable temp; + if (map != null) { + temp = new Hashtable(map); + foreach (DictionaryEntry dc in props) + temp[dc.Key] = dc.Value; + foreach (DictionaryEntry dc in temp) + props[dc.Key] = dc.Value; + } + String cm = (String)props["class"]; + if (cm == null) + return; + map = (Hashtable)classMap[cm.ToLower(System.Globalization.CultureInfo.InvariantCulture)]; + if (map == null) + return; + props.Remove("class"); + temp = new Hashtable(map); + foreach (DictionaryEntry dc in props) + temp[dc.Key] = dc.Value; + foreach (DictionaryEntry dc in temp) + props[dc.Key] = dc.Value; + } + + private void ApplyMap(Hashtable map, Hashtable props) { + + } + + public void LoadStyle(String style, Hashtable props) { + classMap[style.ToLower(System.Globalization.CultureInfo.InvariantCulture)] = props; + } + + public void LoadStyle(String style, String key, String value) { + style = style.ToLower(System.Globalization.CultureInfo.InvariantCulture); + Hashtable props = (Hashtable)classMap[style]; + if (props == null) { + props = new Hashtable(); + classMap[style] = props; + } + props[key] = value; + } + + public void LoadTagStyle(String tag, Hashtable props) { + tagMap[tag.ToLower(System.Globalization.CultureInfo.InvariantCulture)] = props; + } + + public void LoadTagStyle(String tag, String key, String value) { + tag = tag.ToLower(System.Globalization.CultureInfo.InvariantCulture); + Hashtable props = (Hashtable)tagMap[tag]; + if (props == null) { + props = new Hashtable(); + tagMap[tag] = props; + } + props[key] = value; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/AcroFields.cs b/iTechSharp/iTextSharp/text/pdf/AcroFields.cs new file mode 100644 index 0000000..7508c8f --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/AcroFields.cs @@ -0,0 +1,2126 @@ +using System; +using System.Collections; +using System.IO; +using System.Xml; +using System.util; +/* + * Copyright 2003-2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** Query and change fields in existing documents either by method + * calls or by FDF merging. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class AcroFields { + + internal PdfReader reader; + internal PdfWriter writer; + internal Hashtable fields; + private int topFirst; + private Hashtable sigNames; + private bool append; + public const int DA_FONT = 0; + public const int DA_SIZE = 1; + public const int DA_COLOR = 2; + private Hashtable extensionFonts = new Hashtable(); + private XfaForm xfa; + /** + * A field type invalid or not found. + */ + public const int FIELD_TYPE_NONE = 0; + /** + * A field type. + */ + public const int FIELD_TYPE_PUSHBUTTON = 1; + /** + * A field type. + */ + public const int FIELD_TYPE_CHECKBOX = 2; + /** + * A field type. + */ + public const int FIELD_TYPE_RADIOBUTTON = 3; + /** + * A field type. + */ + public const int FIELD_TYPE_TEXT = 4; + /** + * A field type. + */ + public const int FIELD_TYPE_LIST = 5; + /** + * A field type. + */ + public const int FIELD_TYPE_COMBO = 6; + /** + * A field type. + */ + public const int FIELD_TYPE_SIGNATURE = 7; + + private bool lastWasString; + + /** Holds value of property generateAppearances. */ + private bool generateAppearances = true; + + private Hashtable localFonts = new Hashtable(); + + private float extraMarginLeft; + private float extraMarginTop; + private ArrayList substitutionFonts; + + internal AcroFields(PdfReader reader, PdfWriter writer) { + this.reader = reader; + this.writer = writer; + xfa = new XfaForm(reader); + if (writer is PdfStamperImp) { + append = ((PdfStamperImp)writer).append; + } + Fill(); + } + + internal void Fill() { + fields = new Hashtable(); + PdfDictionary top = (PdfDictionary)PdfReader.GetPdfObjectRelease(reader.Catalog.Get(PdfName.ACROFORM)); + if (top == null) + return; + PdfArray arrfds = (PdfArray)PdfReader.GetPdfObjectRelease(top.Get(PdfName.FIELDS)); + if (arrfds == null || arrfds.Size == 0) + return; + arrfds = null; + for (int k = 1; k <= reader.NumberOfPages; ++k) { + PdfDictionary page = reader.GetPageNRelease(k); + PdfArray annots = (PdfArray)PdfReader.GetPdfObjectRelease(page.Get(PdfName.ANNOTS), page); + if (annots == null) + continue; + ArrayList arr = annots.ArrayList; + for (int j = 0; j < arr.Count; ++j) { + PdfObject annoto = PdfReader.GetPdfObject((PdfObject)arr[j], annots); + if (!(annoto is PdfDictionary)) { + PdfReader.ReleaseLastXrefPartial((PdfObject)arr[j]); + continue; + } + PdfDictionary annot = (PdfDictionary)annoto; + if (!PdfName.WIDGET.Equals(annot.Get(PdfName.SUBTYPE))) { + PdfReader.ReleaseLastXrefPartial((PdfObject)arr[j]); + continue; + } + PdfDictionary widget = annot; + PdfDictionary dic = new PdfDictionary(); + dic.Merge(annot); + String name = ""; + PdfDictionary value = null; + PdfObject lastV = null; + while (annot != null) { + dic.MergeDifferent(annot); + PdfString t = (PdfString)PdfReader.GetPdfObject(annot.Get(PdfName.T)); + if (t != null) + name = t.ToUnicodeString() + "." + name; + if (lastV == null && annot.Get(PdfName.V) != null) + lastV = PdfReader.GetPdfObjectRelease(annot.Get(PdfName.V)); + if (value == null && t != null) { + value = annot; + if (annot.Get(PdfName.V) == null && lastV != null) + value.Put(PdfName.V, lastV); + } + annot = (PdfDictionary)PdfReader.GetPdfObject(annot.Get(PdfName.PARENT), annot); + } + if (name.Length > 0) + name = name.Substring(0, name.Length - 1); + Item item = (Item)fields[name]; + if (item == null) { + item = new Item(); + fields[name] = item; + } + if (value == null) + item.values.Add(widget); + else + item.values.Add(value); + item.widgets.Add(widget); + item.widget_refs.Add(arr[j]); // must be a reference + if (top != null) + dic.MergeDifferent(top); + item.merged.Add(dic); + item.page.Add(k); + item.tabOrder.Add(j); + } + } + } + + /** Gets the list of appearance names. Use it to get the names allowed + * with radio and checkbox fields. If the /Opt key exists the values will + * also be included. The name 'Off' may also be valid + * even if not returned in the list. + * @param fieldName the fully qualified field name + * @return the list of names or null if the field does not exist + */ + public String[] GetAppearanceStates(String fieldName) { + Item fd = (Item)fields[fieldName]; + if (fd == null) + return null; + Hashtable names = new Hashtable(); + PdfDictionary vals = (PdfDictionary)fd.values[0]; + PdfObject opts = PdfReader.GetPdfObject(vals.Get(PdfName.OPT)); + if (opts != null) { + if (opts.IsString()) + names[((PdfString)opts).ToUnicodeString()] = null; + else if (opts.IsArray()) { + ArrayList list = ((PdfArray)opts).ArrayList; + for (int k = 0; k < list.Count; ++k) { + PdfObject v = PdfReader.GetPdfObject((PdfObject)list[k]); + if (v != null && v.IsString()) + names[((PdfString)v).ToUnicodeString()] = null; + } + } + } + ArrayList wd = fd.widgets; + for (int k = 0; k < wd.Count; ++k) { + PdfDictionary dic = (PdfDictionary)wd[k]; + dic = (PdfDictionary)PdfReader.GetPdfObject(dic.Get(PdfName.AP)); + if (dic == null) + continue; + PdfObject ob = PdfReader.GetPdfObject(dic.Get(PdfName.N)); + if (ob == null || !ob.IsDictionary()) + continue; + dic = (PdfDictionary)ob; + foreach (PdfName pname in dic.Keys) { + String name = PdfName.DecodeName(pname.ToString()); + names[name] = null; + } + } + string[] outs = new string[names.Count]; + names.Keys.CopyTo(outs, 0); + return outs; + } + + private String[] GetListOption(String fieldName, int idx) { + Item fd = GetFieldItem(fieldName); + if (fd == null) + return null; + PdfObject obj = PdfReader.GetPdfObject(((PdfDictionary)fd.merged[0]).Get(PdfName.OPT)); + if (obj == null || !obj.IsArray()) + return null; + PdfArray ar = (PdfArray)obj; + String[] ret = new String[ar.Size]; + ArrayList a = ar.ArrayList; + for (int k = 0; k < a.Count; ++k) { + obj = PdfReader.GetPdfObject((PdfObject)a[k]); + try { + if (obj.IsArray()) { + obj = (PdfObject)((PdfArray)obj).ArrayList[idx]; + } + if (obj.IsString()) + ret[k] = ((PdfString)obj).ToUnicodeString(); + else + ret[k] = obj.ToString(); + } + catch { + ret[k] = ""; + } + } + return ret; + } + + /** + * Gets the list of export option values from fields of type list or combo. + * If the field doesn't exist or the field type is not list or combo it will return + * null. + * @param fieldName the field name + * @return the list of export option values from fields of type list or combo + */ + public String[] GetListOptionExport(String fieldName) { + return GetListOption(fieldName, 0); + } + + /** + * Gets the list of display option values from fields of type list or combo. + * If the field doesn't exist or the field type is not list or combo it will return + * null. + * @param fieldName the field name + * @return the list of export option values from fields of type list or combo + */ + public String[] GetListOptionDisplay(String fieldName) { + return GetListOption(fieldName, 1); + } + + /** + * Sets the option list for fields of type list or combo. One of exportValues + * or displayValues may be null but not both. This method will only + * set the list but will not set the value or appearance. For that, calling setField() + * is required. + *

    + * An example: + *

    + *

    +        * PdfReader pdf = new PdfReader("input.pdf");
    +        * PdfStamper stp = new PdfStamper(pdf, new FileOutputStream("output.pdf"));
    +        * AcroFields af = stp.GetAcroFields();
    +        * af.SetListOption("ComboBox", new String[]{"a", "b", "c"}, new String[]{"first", "second", "third"});
    +        * af.SetField("ComboBox", "b");
    +        * stp.Close();
    +        * 
    + * @param fieldName the field name + * @param exportValues the export values + * @param displayValues the display values + * @return true if the operation succeeded, false otherwise + */ + public bool SetListOption(String fieldName, String[] exportValues, String[] displayValues) { + if (exportValues == null && displayValues == null) + return false; + if (exportValues != null && displayValues != null && exportValues.Length != displayValues.Length) + throw new ArgumentException("The export and the display array must have the same size."); + int ftype = GetFieldType(fieldName); + if (ftype != FIELD_TYPE_COMBO && ftype != FIELD_TYPE_LIST) + return false; + Item fd = (Item)fields[fieldName]; + String[] sing = null; + if (exportValues == null && displayValues != null) + sing = displayValues; + else if (exportValues != null && displayValues == null) + sing = exportValues; + PdfArray opt = new PdfArray(); + if (sing != null) { + for (int k = 0; k < sing.Length; ++k) + opt.Add(new PdfString(sing[k], PdfObject.TEXT_UNICODE)); + } + else { + for (int k = 0; k < exportValues.Length; ++k) { + PdfArray a = new PdfArray(); + a.Add(new PdfString(exportValues[k], PdfObject.TEXT_UNICODE)); + a.Add(new PdfString(displayValues[k], PdfObject.TEXT_UNICODE)); + opt.Add(a); + } + } + ((PdfDictionary)fd.values[0]).Put(PdfName.OPT, opt); + for (int j = 0; j < fd.merged.Count; ++j) + ((PdfDictionary)fd.merged[j]).Put(PdfName.OPT, opt); + return true; + } + + /** + * Gets the field type. The type can be one of: FIELD_TYPE_PUSHBUTTON, + * FIELD_TYPE_CHECKBOX, FIELD_TYPE_RADIOBUTTON, + * FIELD_TYPE_TEXT, FIELD_TYPE_LIST, + * FIELD_TYPE_COMBO or FIELD_TYPE_SIGNATURE. + *

    + * If the field does not exist or is invalid it returns + * FIELD_TYPE_NONE. + * @param fieldName the field name + * @return the field type + */ + public int GetFieldType(String fieldName) { + Item fd = GetFieldItem(fieldName); + if (fd == null) + return FIELD_TYPE_NONE; + PdfObject type = PdfReader.GetPdfObject(((PdfDictionary)fd.merged[0]).Get(PdfName.FT)); + if (type == null) + return FIELD_TYPE_NONE; + int ff = 0; + PdfObject ffo = PdfReader.GetPdfObject(((PdfDictionary)fd.merged[0]).Get(PdfName.FF)); + if (ffo != null && ffo.Type == PdfObject.NUMBER) + ff = ((PdfNumber)ffo).IntValue; + if (PdfName.BTN.Equals(type)) { + if ((ff & PdfFormField.FF_PUSHBUTTON) != 0) + return FIELD_TYPE_PUSHBUTTON; + if ((ff & PdfFormField.FF_RADIO) != 0) + return FIELD_TYPE_RADIOBUTTON; + else + return FIELD_TYPE_CHECKBOX; + } + else if (PdfName.TX.Equals(type)) { + return FIELD_TYPE_TEXT; + } + else if (PdfName.CH.Equals(type)) { + if ((ff & PdfFormField.FF_COMBO) != 0) + return FIELD_TYPE_COMBO; + else + return FIELD_TYPE_LIST; + } + else if (PdfName.SIG.Equals(type)) { + return FIELD_TYPE_SIGNATURE; + } + return FIELD_TYPE_NONE; + } + + /** + * Export the fields as a FDF. + * @param writer the FDF writer + */ + public void ExportAsFdf(FdfWriter writer) { + foreach (DictionaryEntry entry in fields) { + Item item = (Item)entry.Value; + string name = (String)entry.Key; + PdfObject v = PdfReader.GetPdfObject(((PdfDictionary)item.merged[0]).Get(PdfName.V)); + if (v == null) + continue; + string value = GetField(name); + if (lastWasString) + writer.SetFieldAsString(name, value); + else + writer.SetFieldAsName(name, value); + } + } + + /** + * Renames a field. Only the last part of the name can be renamed. For example, + * if the original field is "ab.cd.ef" only the "ef" part can be renamed. + * @param oldName the old field name + * @param newName the new field name + * @return true if the renaming was successful, false + * otherwise + */ + public bool RenameField(String oldName, String newName) { + int idx1 = oldName.LastIndexOf('.') + 1; + int idx2 = newName.LastIndexOf('.') + 1; + if (idx1 != idx2) + return false; + if (!oldName.Substring(0, idx1).Equals(newName.Substring(0, idx2))) + return false; + if (fields.ContainsKey(newName)) + return false; + Item item = (Item)fields[oldName]; + if (item == null) + return false; + newName = newName.Substring(idx2); + PdfString ss = new PdfString(newName, PdfObject.TEXT_UNICODE); + for (int k = 0; k < item.merged.Count; ++k) { + PdfDictionary dic = (PdfDictionary)item.values[k]; + dic.Put(PdfName.T, ss); + MarkUsed(dic); + dic = (PdfDictionary)item.merged[k]; + dic.Put(PdfName.T, ss); + } + fields.Remove(oldName); + fields[newName] = item; + return true; + } + + public static Object[] SplitDAelements(String da) { + PRTokeniser tk = new PRTokeniser(PdfEncodings.ConvertToBytes(da, null)); + ArrayList stack = new ArrayList(); + Object[] ret = new Object[3]; + while (tk.NextToken()) { + if (tk.TokenType == PRTokeniser.TK_COMMENT) + continue; + if (tk.TokenType == PRTokeniser.TK_OTHER) { + String oper = tk.StringValue; + if (oper.Equals("Tf")) { + if (stack.Count >= 2) { + ret[DA_FONT] = stack[stack.Count - 2]; + ret[DA_SIZE] = float.Parse((String)stack[stack.Count - 1], System.Globalization.NumberFormatInfo.InvariantInfo); + } + } + else if (oper.Equals("g")) { + if (stack.Count >= 1) { + float gray = float.Parse((String)stack[stack.Count - 1], System.Globalization.NumberFormatInfo.InvariantInfo); + if (gray != 0) + ret[DA_COLOR] = new GrayColor(gray); + } + } + else if (oper.Equals("rg")) { + if (stack.Count >= 3) { + float red = float.Parse((String)stack[stack.Count - 3], System.Globalization.NumberFormatInfo.InvariantInfo); + float green = float.Parse((String)stack[stack.Count - 2], System.Globalization.NumberFormatInfo.InvariantInfo); + float blue = float.Parse((String)stack[stack.Count - 1], System.Globalization.NumberFormatInfo.InvariantInfo); + ret[DA_COLOR] = new Color(red, green, blue); + } + } + else if (oper.Equals("k")) { + if (stack.Count >= 4) { + float cyan = float.Parse((String)stack[stack.Count - 4], System.Globalization.NumberFormatInfo.InvariantInfo); + float magenta = float.Parse((String)stack[stack.Count - 3], System.Globalization.NumberFormatInfo.InvariantInfo); + float yellow = float.Parse((String)stack[stack.Count - 2], System.Globalization.NumberFormatInfo.InvariantInfo); + float black = float.Parse((String)stack[stack.Count - 1], System.Globalization.NumberFormatInfo.InvariantInfo); + ret[DA_COLOR] = new CMYKColor(cyan, magenta, yellow, black); + } + } + stack.Clear(); + } + else + stack.Add(tk.StringValue); + } + return ret; + } + + public void DecodeGenericDictionary(PdfDictionary merged, BaseField tx) { + int flags = 0; + // the text size and color + PdfString da = (PdfString)PdfReader.GetPdfObject(merged.Get(PdfName.DA)); + if (da != null) { + Object[] dab = SplitDAelements(da.ToUnicodeString()); + if (dab[DA_SIZE] != null) + tx.FontSize = (float)dab[DA_SIZE]; + if (dab[DA_COLOR] != null) + tx.TextColor = (Color)dab[DA_COLOR]; + if (dab[DA_FONT] != null) { + PdfDictionary font = (PdfDictionary)PdfReader.GetPdfObject(merged.Get(PdfName.DR)); + if (font != null) { + font = (PdfDictionary)PdfReader.GetPdfObject(font.Get(PdfName.FONT)); + if (font != null) { + PdfObject po = font.Get(new PdfName((String)dab[DA_FONT])); + if (po != null && po.Type == PdfObject.INDIRECT) { + PRIndirectReference por = (PRIndirectReference)po; + BaseFont bp = new DocumentFont((PRIndirectReference)po); + tx.Font = bp; + int porkey = por.Number; + BaseFont porf = (BaseFont)extensionFonts[porkey]; + if (porf == null) { + if (!extensionFonts.ContainsKey(porkey)) { + PdfDictionary fo = (PdfDictionary)PdfReader.GetPdfObject(po); + PdfDictionary fd = (PdfDictionary)PdfReader.GetPdfObject(fo.Get(PdfName.FONTDESCRIPTOR)); + if (fd != null) { + PRStream prs = (PRStream)PdfReader.GetPdfObject(fd.Get(PdfName.FONTFILE2)); + if (prs == null) + prs = (PRStream)PdfReader.GetPdfObject(fd.Get(PdfName.FONTFILE3)); + if (prs == null) { + extensionFonts[porkey] = null; + } + else { + try { + porf = BaseFont.CreateFont("font.ttf", BaseFont.IDENTITY_H, true, false, PdfReader.GetStreamBytes(prs), null); + } + catch { + } + extensionFonts[porkey] = porf; + } + } + } + } + if (tx is TextField) + ((TextField)tx).ExtensionFont = porf; + } + else { + BaseFont bf = (BaseFont)localFonts[dab[DA_FONT]]; + if (bf == null) { + String[] fn = (String[])stdFieldFontNames[dab[DA_FONT]]; + if (fn != null) { + try { + String enc = "winansi"; + if (fn.Length > 1) + enc = fn[1]; + bf = BaseFont.CreateFont(fn[0], enc, false); + tx.Font = bf; + } + catch { + // empty + } + } + } + else + tx.Font = bf; + } + } + } + } + } + //rotation, border and backgound color + PdfDictionary mk = (PdfDictionary)PdfReader.GetPdfObject(merged.Get(PdfName.MK)); + if (mk != null) { + PdfArray ar = (PdfArray)PdfReader.GetPdfObject(mk.Get(PdfName.BC)); + Color border = GetMKColor(ar); + tx.BorderColor = border; + if (border != null) + tx.BorderWidth = 1; + ar = (PdfArray)PdfReader.GetPdfObject(mk.Get(PdfName.BG)); + tx.BackgroundColor = GetMKColor(ar); + PdfNumber rotation = (PdfNumber)PdfReader.GetPdfObject(mk.Get(PdfName.R)); + if (rotation != null) + tx.Rotation = rotation.IntValue; + } + //flags + PdfNumber nfl = (PdfNumber)PdfReader.GetPdfObject(merged.Get(PdfName.F)); + flags = 0; + tx.Visibility = BaseField.VISIBLE_BUT_DOES_NOT_PRINT; + if (nfl != null) { + flags = nfl.IntValue; + if ((flags & PdfFormField.FLAGS_PRINT) != 0 && (flags & PdfFormField.FLAGS_HIDDEN) != 0) + tx.Visibility = BaseField.HIDDEN; + else if ((flags & PdfFormField.FLAGS_PRINT) != 0 && (flags & PdfFormField.FLAGS_NOVIEW) != 0) + tx.Visibility = BaseField.HIDDEN_BUT_PRINTABLE; + else if ((flags & PdfFormField.FLAGS_PRINT) != 0) + tx.Visibility = BaseField.VISIBLE; + } + //multiline + nfl = (PdfNumber)PdfReader.GetPdfObject(merged.Get(PdfName.FF)); + flags = 0; + if (nfl != null) + flags = nfl.IntValue; + tx.Options = flags; + if ((flags & PdfFormField.FF_COMB) != 0) { + PdfNumber maxLen = (PdfNumber)PdfReader.GetPdfObject(merged.Get(PdfName.MAXLEN)); + int len = 0; + if (maxLen != null) + len = maxLen.IntValue; + tx.MaxCharacterLength = len; + } + //alignment + nfl = (PdfNumber)PdfReader.GetPdfObject(merged.Get(PdfName.Q)); + if (nfl != null) { + if (nfl.IntValue == PdfFormField.Q_CENTER) + tx.Alignment = Element.ALIGN_CENTER; + else if (nfl.IntValue == PdfFormField.Q_RIGHT) + tx.Alignment = Element.ALIGN_RIGHT; + } + //border styles + PdfDictionary bs = (PdfDictionary)PdfReader.GetPdfObject(merged.Get(PdfName.BS)); + if (bs != null) { + PdfNumber w = (PdfNumber)PdfReader.GetPdfObject(bs.Get(PdfName.W)); + if (w != null) + tx.BorderWidth = w.FloatValue; + PdfName s = (PdfName)PdfReader.GetPdfObject(bs.Get(PdfName.S)); + if (PdfName.D.Equals(s)) + tx.BorderStyle = PdfBorderDictionary.STYLE_DASHED; + else if (PdfName.B.Equals(s)) + tx.BorderStyle = PdfBorderDictionary.STYLE_BEVELED; + else if (PdfName.I.Equals(s)) + tx.BorderStyle = PdfBorderDictionary.STYLE_INSET; + else if (PdfName.U.Equals(s)) + tx.BorderStyle = PdfBorderDictionary.STYLE_UNDERLINE; + } + else { + PdfArray bd = (PdfArray)PdfReader.GetPdfObject(merged.Get(PdfName.BORDER)); + if (bd != null) { + ArrayList ar = bd.ArrayList; + if (ar.Count >= 3) + tx.BorderWidth = ((PdfNumber)ar[2]).FloatValue; + if (ar.Count >= 4) + tx.BorderStyle = PdfBorderDictionary.STYLE_DASHED; + } + } + } + + internal PdfAppearance GetAppearance(PdfDictionary merged, String text, String fieldName) { + topFirst = 0; + TextField tx = null; + if (fieldCache == null || !fieldCache.ContainsKey(fieldName)) { + tx = new TextField(writer, null, null); + tx.SetExtraMargin(extraMarginLeft, extraMarginTop); + tx.BorderWidth = 0; + tx.SubstitutionFonts = substitutionFonts; + DecodeGenericDictionary(merged, tx); + //rect + PdfArray rect = (PdfArray)PdfReader.GetPdfObject(merged.Get(PdfName.RECT)); + Rectangle box = PdfReader.GetNormalizedRectangle(rect); + if (tx.Rotation == 90 || tx.Rotation == 270) + box = box.Rotate(); + tx.Box = box; + if (fieldCache != null) + fieldCache[fieldName] = tx; + } + else { + tx = (TextField)fieldCache[fieldName]; + tx.Writer = writer; + } + PdfName fieldType = (PdfName)PdfReader.GetPdfObject(merged.Get(PdfName.FT)); + if (PdfName.TX.Equals(fieldType)) { + tx.Text = text; + return tx.GetAppearance(); + } + if (!PdfName.CH.Equals(fieldType)) + throw new DocumentException("An appearance was requested without a variable text field."); + PdfArray opt = (PdfArray)PdfReader.GetPdfObject(merged.Get(PdfName.OPT)); + int flags = 0; + PdfNumber nfl = (PdfNumber)PdfReader.GetPdfObject(merged.Get(PdfName.FF)); + if (nfl != null) + flags = nfl.IntValue; + if ((flags & PdfFormField.FF_COMBO) != 0 && opt == null) { + tx.Text = text; + return tx.GetAppearance(); + } + if (opt != null) { + ArrayList op = opt.ArrayList; + String[] choices = new String[op.Count]; + String[] choicesExp = new String[op.Count]; + for (int k = 0; k < op.Count; ++k) { + PdfObject obj = (PdfObject)op[k]; + if (obj.IsString()) { + choices[k] = choicesExp[k] = ((PdfString)obj).ToUnicodeString(); + } + else { + ArrayList opar = ((PdfArray)obj).ArrayList; + choicesExp[k] = ((PdfString)opar[0]).ToUnicodeString(); + choices[k] = ((PdfString)opar[1]).ToUnicodeString(); + } + } + if ((flags & PdfFormField.FF_COMBO) != 0) { + for (int k = 0; k < choices.Length; ++k) { + if (text.Equals(choicesExp[k])) { + text = choices[k]; + break; + } + } + tx.Text = text; + return tx.GetAppearance(); + } + int idx = 0; + for (int k = 0; k < choicesExp.Length; ++k) { + if (text.Equals(choicesExp[k])) { + idx = k; + break; + } + } + tx.Choices = choices; + tx.ChoiceExports = choicesExp; + tx.ChoiceSelection = idx; + } + PdfAppearance app = tx.GetListAppearance(); + topFirst = tx.TopFirst; + return app; + } + + internal Color GetMKColor(PdfArray ar) { + if (ar == null) + return null; + ArrayList cc = ar.ArrayList; + switch (cc.Count) { + case 1: + return new GrayColor(((PdfNumber)cc[0]).FloatValue); + case 3: + return new Color(ExtendedColor.Normalize(((PdfNumber)cc[0]).FloatValue), ExtendedColor.Normalize(((PdfNumber)cc[1]).FloatValue), ExtendedColor.Normalize(((PdfNumber)cc[2]).FloatValue)); + case 4: + return new CMYKColor(((PdfNumber)cc[0]).FloatValue, ((PdfNumber)cc[1]).FloatValue, ((PdfNumber)cc[2]).FloatValue, ((PdfNumber)cc[3]).FloatValue); + default: + return null; + } + } + + /** Gets the field value. + * @param name the fully qualified field name + * @return the field value + */ + public String GetField(String name) { + if (xfa.XfaPresent) { + name = xfa.FindFieldName(name, this); + if (name == null) + return null; + name = XfaForm.Xml2Som.GetShortName(name); + return XfaForm.GetNodeText(xfa.FindDatasetsNode(name)); + } + Item item = (Item)fields[name]; + if (item == null) + return null; + lastWasString = false; + PdfObject v = PdfReader.GetPdfObject(((PdfDictionary)item.merged[0]).Get(PdfName.V)); + if (v == null) + return ""; + PdfName type = (PdfName)PdfReader.GetPdfObject(((PdfDictionary)item.merged[0]).Get(PdfName.FT)); + if (PdfName.BTN.Equals(type)) { + PdfNumber ff = (PdfNumber)PdfReader.GetPdfObject(((PdfDictionary)item.merged[0]).Get(PdfName.FF)); + int flags = 0; + if (ff != null) + flags = ff.IntValue; + if ((flags & PdfFormField.FF_PUSHBUTTON) != 0) + return ""; + String value = ""; + if (v.IsName()) + value = PdfName.DecodeName(v.ToString()); + else if (v.IsString()) + value = ((PdfString)v).ToUnicodeString(); + PdfObject opts = PdfReader.GetPdfObject(((PdfDictionary)item.values[0]).Get(PdfName.OPT)); + if (opts != null && opts.IsArray()) { + ArrayList list = ((PdfArray)opts).ArrayList; + int idx = 0; + try { + idx = int.Parse(value); + PdfString ps = (PdfString)list[idx]; + value = ps.ToUnicodeString(); + lastWasString = true; + } + catch { + } + } + return value; + } + if (v.IsString()) { + lastWasString = true; + return ((PdfString)v).ToUnicodeString(); + } + return PdfName.DecodeName(v.ToString()); + } + + /** + * Sets a field property. Valid property names are: + *

    + *

      + *
    • textfont - sets the text font. The value for this entry is a BaseFont.
      + *
    • textcolor - sets the text color. The value for this entry is a java.awt.Color.
      + *
    • textsize - sets the text size. The value for this entry is a Float. + *
    • bgcolor - sets the background color. The value for this entry is a java.awt.Color. + * If null removes the background.
      + *
    • bordercolor - sets the border color. The value for this entry is a java.awt.Color. + * If null removes the border.
      + *
    + * @param field the field name + * @param name the property name + * @param value the property value + * @param inst an array of int indexing into AcroField.Item.merged elements to process. + * Set to null to process all + * @return true if the property exists, false otherwise + */ + public bool SetFieldProperty(String field, String name, Object value, int[] inst) { + if (writer == null) + throw new Exception("This AcroFields instance is read-only."); + Item item = (Item)fields[field]; + if (item == null) + return false; + InstHit hit = new InstHit(inst); + if (Util.EqualsIgnoreCase(name, "textfont")) { + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + PdfString da = (PdfString)PdfReader.GetPdfObject(((PdfDictionary)item.merged[k]).Get(PdfName.DA)); + PdfDictionary dr = (PdfDictionary)PdfReader.GetPdfObject(((PdfDictionary)item.merged[k]).Get(PdfName.DR)); + if (da != null && dr != null) { + Object[] dao = SplitDAelements(da.ToUnicodeString()); + PdfAppearance cb = new PdfAppearance(); + if (dao[DA_FONT] != null) { + BaseFont bf = (BaseFont)value; + PdfName psn = (PdfName)PdfAppearance.stdFieldFontNames[bf.PostscriptFontName]; + if (psn == null) { + psn = new PdfName(bf.PostscriptFontName); + } + PdfDictionary fonts = (PdfDictionary)PdfReader.GetPdfObject(dr.Get(PdfName.FONT)); + if (fonts == null) { + fonts = new PdfDictionary(); + dr.Put(PdfName.FONT, fonts); + } + PdfIndirectReference fref = (PdfIndirectReference)fonts.Get(psn); + PdfDictionary top = (PdfDictionary)PdfReader.GetPdfObject(reader.Catalog.Get(PdfName.ACROFORM)); + MarkUsed(top); + dr = (PdfDictionary)PdfReader.GetPdfObject(top.Get(PdfName.DR)); + if (dr == null) { + dr = new PdfDictionary(); + top.Put(PdfName.DR, dr); + } + MarkUsed(dr); + PdfDictionary fontsTop = (PdfDictionary)PdfReader.GetPdfObject(dr.Get(PdfName.FONT)); + if (fontsTop == null) { + fontsTop = new PdfDictionary(); + dr.Put(PdfName.FONT, fontsTop); + } + MarkUsed(fontsTop); + PdfIndirectReference frefTop = (PdfIndirectReference)fontsTop.Get(psn); + if (frefTop != null) { + if (fref == null) + fonts.Put(psn, frefTop); + } + else if (fref == null) { + FontDetails fd; + if (bf.FontType == BaseFont.FONT_TYPE_DOCUMENT) { + fd = new FontDetails(null, ((DocumentFont)bf).IndirectReference, bf); + } + else { + bf.Subset = false; + fd = writer.AddSimple(bf); + localFonts[psn.ToString().Substring(1)] = bf; + } + fontsTop.Put(psn, fd.IndirectReference); + fonts.Put(psn, fd.IndirectReference); + } + ByteBuffer buf = cb.InternalBuffer; + buf.Append(psn.GetBytes()).Append(' ').Append((float)dao[DA_SIZE]).Append(" Tf "); + if (dao[DA_COLOR] != null) + cb.SetColorFill((Color)dao[DA_COLOR]); + PdfString s = new PdfString(cb.ToString()); + ((PdfDictionary)item.merged[k]).Put(PdfName.DA, s); + ((PdfDictionary)item.widgets[k]).Put(PdfName.DA, s); + MarkUsed((PdfDictionary)item.widgets[k]); + } + } + } + } + } + else if (Util.EqualsIgnoreCase(name, "textcolor")) { + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + PdfString da = (PdfString)PdfReader.GetPdfObject(((PdfDictionary)item.merged[k]).Get(PdfName.DA)); + if (da != null) { + Object[] dao = SplitDAelements(da.ToUnicodeString()); + PdfAppearance cb = new PdfAppearance(); + if (dao[DA_FONT] != null) { + ByteBuffer buf = cb.InternalBuffer; + buf.Append(new PdfName((String)dao[DA_FONT]).GetBytes()).Append(' ').Append((float)dao[DA_SIZE]).Append(" Tf "); + cb.SetColorFill((Color)value); + PdfString s = new PdfString(cb.ToString()); + ((PdfDictionary)item.merged[k]).Put(PdfName.DA, s); + ((PdfDictionary)item.widgets[k]).Put(PdfName.DA, s); + MarkUsed((PdfDictionary)item.widgets[k]); + } + } + } + } + } + else if (Util.EqualsIgnoreCase(name, "textsize")) { + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + PdfString da = (PdfString)PdfReader.GetPdfObject(((PdfDictionary)item.merged[k]).Get(PdfName.DA)); + if (da != null) { + Object[] dao = SplitDAelements(da.ToUnicodeString()); + PdfAppearance cb = new PdfAppearance(); + if (dao[DA_FONT] != null) { + ByteBuffer buf = cb.InternalBuffer; + buf.Append(new PdfName((String)dao[DA_FONT]).GetBytes()).Append(' ').Append((float)value).Append(" Tf "); + if (dao[DA_COLOR] != null) + cb.SetColorFill((Color)dao[DA_COLOR]); + PdfString s = new PdfString(cb.ToString()); + ((PdfDictionary)item.merged[k]).Put(PdfName.DA, s); + ((PdfDictionary)item.widgets[k]).Put(PdfName.DA, s); + MarkUsed((PdfDictionary)item.widgets[k]); + } + } + } + } + } + else if (Util.EqualsIgnoreCase(name, "bgcolor") || Util.EqualsIgnoreCase(name, "bordercolor")) { + PdfName dname = (Util.EqualsIgnoreCase(name, "bgcolor") ? PdfName.BG : PdfName.BC); + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + PdfObject obj = PdfReader.GetPdfObject(((PdfDictionary)item.merged[k]).Get(PdfName.MK)); + MarkUsed(obj); + PdfDictionary mk = (PdfDictionary)obj; + if (mk == null) { + if (value == null) + return true; + mk = new PdfDictionary(); + ((PdfDictionary)item.merged[k]).Put(PdfName.MK, mk); + ((PdfDictionary)item.widgets[k]).Put(PdfName.MK, mk); + MarkUsed((PdfDictionary)item.widgets[k]); + } + if (value == null) + mk.Remove(dname); + else + mk.Put(dname, PdfFormField.GetMKColor((Color)value)); + } + } + } + else + return false; + return true; + } + + /** + * Sets a field property. Valid property names are: + *

    + *

      + *
    • flags - a set of flags specifying various characteristics of the field’s widget annotation. + * The value of this entry replaces that of the F entry in the form’s corresponding annotation dictionary.
      + *
    • setflags - a set of flags to be set (turned on) in the F entry of the form’s corresponding + * widget annotation dictionary. Bits equal to 1 cause the corresponding bits in F to be set to 1.
      + *
    • clrflags - a set of flags to be cleared (turned off) in the F entry of the form’s corresponding + * widget annotation dictionary. Bits equal to 1 cause the corresponding + * bits in F to be set to 0.
      + *
    • fflags - a set of flags specifying various characteristics of the field. The value + * of this entry replaces that of the Ff entry in the form’s corresponding field dictionary.
      + *
    • setfflags - a set of flags to be set (turned on) in the Ff entry of the form’s corresponding + * field dictionary. Bits equal to 1 cause the corresponding bits in Ff to be set to 1.
      + *
    • clrfflags - a set of flags to be cleared (turned off) in the Ff entry of the form’s corresponding + * field dictionary. Bits equal to 1 cause the corresponding bits in Ff + * to be set to 0.
      + *
    + * @param field the field name + * @param name the property name + * @param value the property value + * @param inst an array of int indexing into AcroField.Item.merged elements to process. + * Set to null to process all + * @return true if the property exists, false otherwise + */ + public bool SetFieldProperty(String field, String name, int value, int[] inst) { + if (writer == null) + throw new Exception("This AcroFields instance is read-only."); + Item item = (Item)fields[field]; + if (item == null) + return false; + InstHit hit = new InstHit(inst); + if (Util.EqualsIgnoreCase(name, "flags")) { + PdfNumber num = new PdfNumber(value); + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + ((PdfDictionary)item.merged[k]).Put(PdfName.F, num); + ((PdfDictionary)item.widgets[k]).Put(PdfName.F, num); + MarkUsed((PdfDictionary)item.widgets[k]); + } + } + } + else if (Util.EqualsIgnoreCase(name, "setflags")) { + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + PdfNumber num = (PdfNumber)PdfReader.GetPdfObject(((PdfDictionary)item.widgets[k]).Get(PdfName.F)); + int val = 0; + if (num != null) + val = num.IntValue; + num = new PdfNumber(val | value); + ((PdfDictionary)item.merged[k]).Put(PdfName.F, num); + ((PdfDictionary)item.widgets[k]).Put(PdfName.F, num); + MarkUsed((PdfDictionary)item.widgets[k]); + } + } + } + else if (Util.EqualsIgnoreCase(name, "clrflags")) { + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + PdfNumber num = (PdfNumber)PdfReader.GetPdfObject(((PdfDictionary)item.widgets[k]).Get(PdfName.F)); + int val = 0; + if (num != null) + val = num.IntValue; + num = new PdfNumber(val & (~value)); + ((PdfDictionary)item.merged[k]).Put(PdfName.F, num); + ((PdfDictionary)item.widgets[k]).Put(PdfName.F, num); + MarkUsed((PdfDictionary)item.widgets[k]); + } + } + } + else if (Util.EqualsIgnoreCase(name, "fflags")) { + PdfNumber num = new PdfNumber(value); + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + ((PdfDictionary)item.merged[k]).Put(PdfName.FF, num); + ((PdfDictionary)item.values[k]).Put(PdfName.FF, num); + MarkUsed((PdfDictionary)item.values[k]); + } + } + } + else if (Util.EqualsIgnoreCase(name, "setfflags")) { + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + PdfNumber num = (PdfNumber)PdfReader.GetPdfObject(((PdfDictionary)item.values[k]).Get(PdfName.FF)); + int val = 0; + if (num != null) + val = num.IntValue; + num = new PdfNumber(val | value); + ((PdfDictionary)item.merged[k]).Put(PdfName.FF, num); + ((PdfDictionary)item.values[k]).Put(PdfName.FF, num); + MarkUsed((PdfDictionary)item.values[k]); + } + } + } + else if (Util.EqualsIgnoreCase(name, "clrfflags")) { + for (int k = 0; k < item.merged.Count; ++k) { + if (hit.IsHit(k)) { + PdfNumber num = (PdfNumber)PdfReader.GetPdfObject(((PdfDictionary)item.values[k]).Get(PdfName.FF)); + int val = 0; + if (num != null) + val = num.IntValue; + num = new PdfNumber(val & (~value)); + ((PdfDictionary)item.merged[k]).Put(PdfName.FF, num); + ((PdfDictionary)item.values[k]).Put(PdfName.FF, num); + MarkUsed((PdfDictionary)item.values[k]); + } + } + } + else + return false; + return true; + } + + /** + * Merges an XML data structure into this form. + * @param n the top node of the data structure + * @throws java.io.IOException on error + * @throws com.lowagie.text.DocumentException o error + */ + public void MergeXfaData(XmlNode n) { + XfaForm.Xml2SomDatasets data = new XfaForm.Xml2SomDatasets(n); + foreach (String name in data.Order) { + String text = XfaForm.GetNodeText((XmlNode)data.Name2Node[name]); + SetField(name, text); + } + } + + /** Sets the fields by FDF merging. + * @param fdf the FDF form + * @throws IOException on error + * @throws DocumentException on error + */ + public void SetFields(FdfReader fdf) { + Hashtable fd = fdf.Fields; + foreach (string f in fd.Keys) { + String v = fdf.GetFieldValue(f); + if (v != null) + SetField(f, v); + } + } + + /** Sets the fields by XFDF merging. + * @param xfdf the XFDF form + * @throws IOException on error + * @throws DocumentException on error + */ + + public void SetFields(XfdfReader xfdf) { + Hashtable fd = xfdf.Fields; + foreach (string f in fd.Keys) { + String v = xfdf.GetFieldValue(f); + if (v != null) + SetField(f, v); + } + } + + /** + * Regenerates the field appearance. + * This is usefull when you change a field property, but not its value, + * for instance form.SetFieldProperty("f", "bgcolor", Color.BLUE, null); + * This won't have any effect, unless you use RegenerateField("f") after changing + * the property. + * + * @param name the fully qualified field name or the partial name in the case of XFA forms + * @throws IOException on error + * @throws DocumentException on error + * @return true if the field was found and changed, + * false otherwise + */ + public bool RegenerateField(String name) { + String value = GetField(name); + return SetField(name, value, value); + } + + /** Sets the field value. + * @param name the fully qualified field name or the partial name in the case of XFA forms + * @param value the field value + * @throws IOException on error + * @throws DocumentException on error + * @return true if the field was found and changed, + * false otherwise + */ + public bool SetField(String name, String value) { + return SetField(name, value, null); + } + + /** Sets the field value and the display string. The display string + * is used to build the appearance in the cases where the value + * is modified by Acrobat with JavaScript and the algorithm is + * known. + * @param name the fully qualified field name or the partial name in the case of XFA forms + * @param value the field value + * @param display the string that is used for the appearance. If null + * the value parameter will be used + * @return true if the field was found and changed, + * false otherwise + * @throws IOException on error + * @throws DocumentException on error + */ + public bool SetField(String name, String value, String display) { + if (writer == null) + throw new DocumentException("This AcroFields instance is read-only."); + if (xfa.XfaPresent) { + name = xfa.FindFieldName(name, this); + if (name == null) + return false; + String shortName = XfaForm.Xml2Som.GetShortName(name); + XmlNode xn = xfa.FindDatasetsNode(shortName); + if (xn == null) { + xn = xfa.DatasetsSom.InsertNode(xfa.DatasetsNode, shortName); + } + xfa.SetNodeText(xn, value); + } + Item item = (Item)fields[name]; + if (item == null) + return false; + PdfName type = (PdfName)PdfReader.GetPdfObject(((PdfDictionary)item.merged[0]).Get(PdfName.FT)); + if (PdfName.TX.Equals(type)) { + PdfNumber maxLen = (PdfNumber)PdfReader.GetPdfObject(((PdfDictionary)item.merged[0]).Get(PdfName.MAXLEN)); + int len = 0; + if (maxLen != null) + len = maxLen.IntValue; + if (len > 0) + value = value.Substring(0, Math.Min(len, value.Length)); + } + if (display == null) + display = value; + if (PdfName.TX.Equals(type) || PdfName.CH.Equals(type)) { + PdfString v = new PdfString(value, PdfObject.TEXT_UNICODE); + for (int idx = 0; idx < item.values.Count; ++idx) { + PdfDictionary valueDic = (PdfDictionary)item.values[idx]; + valueDic.Put(PdfName.V, v); + valueDic.Remove(PdfName.I); + MarkUsed(valueDic); + PdfDictionary merged = (PdfDictionary)item.merged[idx]; + merged.Remove(PdfName.I); + merged.Put(PdfName.V, v); + PdfDictionary widget = (PdfDictionary)item.widgets[idx]; + if (generateAppearances) { + PdfAppearance app = GetAppearance(merged, display, name); + if (PdfName.CH.Equals(type)) { + PdfNumber n = new PdfNumber(topFirst); + widget.Put(PdfName.TI, n); + merged.Put(PdfName.TI, n); + } + PdfDictionary appDic = (PdfDictionary)PdfReader.GetPdfObject(widget.Get(PdfName.AP)); + if (appDic == null) { + appDic = new PdfDictionary(); + widget.Put(PdfName.AP, appDic); + merged.Put(PdfName.AP, appDic); + } + appDic.Put(PdfName.N, app.IndirectReference); + writer.ReleaseTemplate(app); + } + else { + widget.Remove(PdfName.AP); + merged.Remove(PdfName.AP); + } + MarkUsed(widget); + } + return true; + } + else if (PdfName.BTN.Equals(type)) { + PdfNumber ff = (PdfNumber)PdfReader.GetPdfObject(((PdfDictionary)item.merged[0]).Get(PdfName.FF)); + int flags = 0; + if (ff != null) + flags = ff.IntValue; + if ((flags & PdfFormField.FF_PUSHBUTTON) != 0) { + //we'll assume that the value is an image in base64 + Image img; + try { + img = Image.GetInstance(Convert.FromBase64String(value)); + } + catch { + return false; + } + PushbuttonField pb = GetNewPushbuttonFromField(name); + pb.Image = img; + ReplacePushbuttonField(name, pb.Field); + return true; + } + PdfName v = new PdfName(value); + ArrayList lopt = new ArrayList(); + PdfObject opts = PdfReader.GetPdfObject(((PdfDictionary)item.values[0]).Get(PdfName.OPT)); + if (opts != null && opts.IsArray()) { + ArrayList list = ((PdfArray)opts).ArrayList; + for (int k = 0; k < list.Count; ++k) { + PdfObject vv = PdfReader.GetPdfObject((PdfObject)list[k]); + if (vv != null && vv.IsString()) + lopt.Add(((PdfString)vv).ToUnicodeString()); + else + lopt.Add(null); + } + } + int vidx = lopt.IndexOf(value); + PdfName valt = null; + PdfName vt; + if (vidx >= 0) { + vt = valt = new PdfName(vidx.ToString()); + } + else + vt = v; + for (int idx = 0; idx < item.values.Count; ++idx) { + PdfDictionary merged = (PdfDictionary)item.merged[idx]; + PdfDictionary widget = (PdfDictionary)item.widgets[idx]; + MarkUsed((PdfDictionary)item.values[idx]); + if (valt != null) { + PdfString ps = new PdfString(value, PdfObject.TEXT_UNICODE); + ((PdfDictionary)item.values[idx]).Put(PdfName.V, ps); + merged.Put(PdfName.V, ps); + } + else { + ((PdfDictionary)item.values[idx]).Put(PdfName.V, v); + merged.Put(PdfName.V, v); + } + MarkUsed(widget); + if (IsInAP(widget, vt)) { + merged.Put(PdfName.AS, vt); + widget.Put(PdfName.AS, vt); + } + else { + merged.Put(PdfName.AS, PdfName.Off_); + widget.Put(PdfName.AS, PdfName.Off_); + } + } + return true; + } + return false; + } + + internal bool IsInAP(PdfDictionary dic, PdfName check) { + PdfDictionary appDic = (PdfDictionary)PdfReader.GetPdfObject(dic.Get(PdfName.AP)); + if (appDic == null) + return false; + PdfDictionary NDic = (PdfDictionary)PdfReader.GetPdfObject(appDic.Get(PdfName.N)); + return (NDic != null && NDic.Get(check) != null); + } + + /** Gets all the fields. The fields are keyed by the fully qualified field name and + * the value is an instance of AcroFields.Item. + * @return all the fields + */ + public Hashtable Fields { + get { + return fields; + } + } + + /** + * Gets the field structure. + * @param name the name of the field + * @return the field structure or null if the field + * does not exist + */ + public Item GetFieldItem(String name) { + if (xfa.XfaPresent) { + name = xfa.FindFieldName(name, this); + if (name == null) + return null; + } + return (Item)fields[name]; + } + + /** + * Gets the long XFA translated name. + * @param name the name of the field + * @return the long field name + */ + public String GetTranslatedFieldName(String name) { + if (xfa.XfaPresent) { + String namex = xfa.FindFieldName(name, this); + if (namex != null) + name = namex; + } + return name; + } + + /** + * Gets the field box positions in the document. The return is an array of float + * multiple of 5. For each of this groups the values are: [page, llx, lly, urx, + * ury]. The coordinates have the page rotation in consideration. + * @param name the field name + * @return the positions or null if field does not exist + */ + public float[] GetFieldPositions(String name) { + Item item = GetFieldItem(name); + if (item == null) + return null; + float[] ret = new float[item.page.Count * 5]; + int ptr = 0; + for (int k = 0; k < item.page.Count; ++k) { + try { + PdfDictionary wd = (PdfDictionary)item.widgets[k]; + PdfArray rect = (PdfArray)wd.Get(PdfName.RECT); + if (rect == null) + continue; + Rectangle r = PdfReader.GetNormalizedRectangle(rect); + int page = (int)item.page[k]; + int rotation = reader.GetPageRotation(page); + ret[ptr++] = page; + if (rotation != 0) { + Rectangle pageSize = reader.GetPageSize(page); + switch (rotation) { + case 270: + r = new Rectangle( + pageSize.Top - r.Bottom, + r.Left, + pageSize.Top - r.Top, + r.Right); + break; + case 180: + r = new Rectangle( + pageSize.Right - r.Left, + pageSize.Top - r.Bottom, + pageSize.Right - r.Right, + pageSize.Top - r.Top); + break; + case 90: + r = new Rectangle( + r.Bottom, + pageSize.Right - r.Left, + r.Top, + pageSize.Right - r.Right); + break; + } + r.Normalize(); + } + ret[ptr++] = r.Left; + ret[ptr++] = r.Bottom; + ret[ptr++] = r.Right; + ret[ptr++] = r.Top; + } + catch { + // empty on purpose + } + } + if (ptr < ret.Length) { + float[] ret2 = new float[ptr]; + System.Array.Copy(ret, 0, ret2, 0, ptr); + return ret2; + } + return ret; + } + + private int RemoveRefFromArray(PdfArray array, PdfObject refo) { + ArrayList ar = array.ArrayList; + if (refo == null || !refo.IsIndirect()) + return ar.Count; + PdfIndirectReference refi = (PdfIndirectReference)refo; + for (int j = 0; j < ar.Count; ++j) { + PdfObject obj = (PdfObject)ar[j]; + if (!obj.IsIndirect()) + continue; + if (((PdfIndirectReference)obj).Number == refi.Number) + ar.RemoveAt(j--); + } + return ar.Count; + } + + /** + * Removes all the fields from page. + * @param page the page to remove the fields from + * @return true if any field was removed, false otherwise + */ + public bool RemoveFieldsFromPage(int page) { + if (page < 1) + return false; + String[] names = new String[fields.Count]; + fields.Keys.CopyTo(names, 0); + bool found = false; + for (int k = 0; k < names.Length; ++k) { + bool fr = RemoveField(names[k], page); + found = (found || fr); + } + return found; + } + + /** + * Removes a field from the document. If page equals -1 all the fields with this + * name are removed from the document otherwise only the fields in + * that particular page are removed. + * @param name the field name + * @param page the page to remove the field from or -1 to remove it from all the pages + * @return true if the field exists, false otherwise + */ + public bool RemoveField(String name, int page) { + Item item = GetFieldItem(name); + if (item == null) + return false; + PdfDictionary acroForm = (PdfDictionary)PdfReader.GetPdfObject(reader.Catalog.Get(PdfName.ACROFORM), reader.Catalog); + + if (acroForm == null) + return false; + PdfArray arrayf = (PdfArray)PdfReader.GetPdfObject(acroForm.Get(PdfName.FIELDS), acroForm); + if (arrayf == null) + return false; + for (int k = 0; k < item.widget_refs.Count; ++k) { + int pageV = (int)item.page[k]; + if (page != -1 && page != pageV) + continue; + PdfIndirectReference refi = (PdfIndirectReference)item.widget_refs[k]; + PdfDictionary wd = (PdfDictionary)PdfReader.GetPdfObject(refi); + PdfDictionary pageDic = reader.GetPageN(pageV); + PdfArray annots = (PdfArray)PdfReader.GetPdfObject(pageDic.Get(PdfName.ANNOTS), pageDic); + if (annots != null) { + if (RemoveRefFromArray(annots, refi) == 0) { + pageDic.Remove(PdfName.ANNOTS); + MarkUsed(pageDic); + } + else + MarkUsed(annots); + } + PdfReader.KillIndirect(refi); + PdfIndirectReference kid = refi; + while ((refi = (PdfIndirectReference)wd.Get(PdfName.PARENT)) != null) { + wd = (PdfDictionary)PdfReader.GetPdfObject(refi); + PdfArray kids = (PdfArray)PdfReader.GetPdfObject(wd.Get(PdfName.KIDS)); + if (RemoveRefFromArray(kids, kid) != 0) + break; + kid = refi; + PdfReader.KillIndirect(refi); + } + if (refi == null) { + RemoveRefFromArray(arrayf, kid); + MarkUsed(arrayf); + } + if (page != -1) { + item.merged.RemoveAt(k); + item.page.RemoveAt(k); + item.values.RemoveAt(k); + item.widget_refs.RemoveAt(k); + item.widgets.RemoveAt(k); + --k; + } + } + if (page == -1 || item.merged.Count == 0) + fields.Remove(name); + return true; + } + + /** + * Removes a field from the document. + * @param name the field name + * @return true if the field exists, false otherwise + */ + public bool RemoveField(String name) { + return RemoveField(name, -1); + } + + /** Sets the option to generate appearances. Not generating apperances + * will speed-up form filling but the results can be + * unexpected in Acrobat. Don't use it unless your environment is well + * controlled. The default is true. + * @param generateAppearances the option to generate appearances + */ + public bool GenerateAppearances { + set { + generateAppearances = value; + PdfDictionary top = (PdfDictionary)PdfReader.GetPdfObject(reader.Catalog.Get(PdfName.ACROFORM)); + if (generateAppearances) + top.Remove(PdfName.NEEDAPPEARANCES); + else + top.Put(PdfName.NEEDAPPEARANCES, PdfBoolean.PDFTRUE); + } + get { + return generateAppearances; + } + } + + /** The field representations for retrieval and modification. */ + public class Item { + /** An array of PdfDictionary where the value tag /V + * is present. + */ + public ArrayList values = new ArrayList(); + /** An array of PdfDictionary with the widgets. + */ + public ArrayList widgets = new ArrayList(); + /** An array of PdfDictionary with the widget references. + */ + public ArrayList widget_refs = new ArrayList(); + /** An array of PdfDictionary with all the field + * and widget tags merged. + */ + public ArrayList merged = new ArrayList(); + /** An array of Integer with the page numbers where + * the widgets are displayed. + */ + public ArrayList page = new ArrayList(); + /** An array of Integer with the tab order of the field in the page. + */ + public ArrayList tabOrder = new ArrayList(); + } + + private class InstHit { + IntHashtable hits; + public InstHit(int[] inst) { + if (inst == null) + return; + hits = new IntHashtable(); + for (int k = 0; k < inst.Length; ++k) + hits[inst[k]] = 1; + } + + public bool IsHit(int n) { + if (hits == null) + return true; + return hits.ContainsKey(n); + } + } + + private void FindSignatureNames() { + if (sigNames != null) + return; + sigNames = new Hashtable(); + ArrayList sorter = new ArrayList(); + foreach (DictionaryEntry entry in fields) { + Item item = (Item)entry.Value; + PdfDictionary merged = (PdfDictionary)item.merged[0]; + if (!PdfName.SIG.Equals(merged.Get(PdfName.FT))) + continue; + PdfObject vo = PdfReader.GetPdfObject(merged.Get(PdfName.V)); + if (vo == null || vo.Type != PdfObject.DICTIONARY) + continue; + PdfDictionary v = (PdfDictionary)vo; + PdfObject contents = v.Get(PdfName.CONTENTS); + if (contents == null || contents.Type != PdfObject.STRING) + continue; + PdfObject ro = v.Get(PdfName.BYTERANGE); + if (ro == null || ro.Type != PdfObject.ARRAY) + continue; + ArrayList ra = ((PdfArray)ro).ArrayList; + if (ra.Count < 2) + continue; + int length = ((PdfNumber)ra[ra.Count - 1]).IntValue + ((PdfNumber)ra[ra.Count - 2]).IntValue; + sorter.Add(new Object[]{entry.Key, new int[]{length, 0}}); + } + sorter.Sort(new AcroFields.ISorterComparator()); + if (sorter.Count > 0) { + if (((int[])((Object[])sorter[sorter.Count - 1])[1])[0] == reader.FileLength) + totalRevisions = sorter.Count; + else + totalRevisions = sorter.Count + 1; + for (int k = 0; k < sorter.Count; ++k) { + Object[] objs = (Object[])sorter[k]; + String name = (String)objs[0]; + int[] p = (int[])objs[1]; + p[1] = k + 1; + sigNames[name] = p; + } + } + } + + /** + * Gets the field names that have signatures and are signed. + * @return the field names that have signatures and are signed + */ + public ArrayList GetSignatureNames() { + FindSignatureNames(); + return new ArrayList(sigNames.Keys); + } + + /** + * Gets the field names that have blank signatures. + * @return the field names that have blank signatures + */ + public ArrayList GetBlankSignatureNames() { + FindSignatureNames(); + ArrayList sigs = new ArrayList(); + foreach (DictionaryEntry entry in fields) { + Item item = (Item)entry.Value; + PdfDictionary merged = (PdfDictionary)item.merged[0]; + if (!PdfName.SIG.Equals(merged.Get(PdfName.FT))) + continue; + if (sigNames.ContainsKey(entry.Key)) + continue; + sigs.Add(entry.Key); + } + return sigs; + } + + /** + * Gets the signature dictionary, the one keyed by /V. + * @param name the field name + * @return the signature dictionary keyed by /V or null if the field is not + * a signature + */ + public PdfDictionary GetSignatureDictionary(String name) { + FindSignatureNames(); + name = GetTranslatedFieldName(name); + if (!sigNames.ContainsKey(name)) + return null; + Item item = (Item)fields[name]; + PdfDictionary merged = (PdfDictionary)item.merged[0]; + return (PdfDictionary)PdfReader.GetPdfObject(merged.Get(PdfName.V)); + } + + /** + * Checks is the signature covers the entire document or just part of it. + * @param name the signature field name + * @return true if the signature covers the entire document, + * false otherwise + */ + public bool SignatureCoversWholeDocument(String name) { + FindSignatureNames(); + name = GetTranslatedFieldName(name); + if (!sigNames.ContainsKey(name)) + return false; + return ((int[])sigNames[name])[0] == reader.FileLength; + } + + /** + * Verifies a signature. An example usage is: + *

    + *

    +        * KeyStore kall = PdfPKCS7.LoadCacertsKeyStore();
    +        * PdfReader reader = new PdfReader("my_signed_doc.pdf");
    +        * AcroFields af = reader.GetAcroFields();
    +        * ArrayList names = af.GetSignatureNames();
    +        * for (int k = 0; k < names.Size(); ++k) {
    +        *    String name = (String)names.Get(k);
    +        *    System.out.Println("Signature name: " + name);
    +        *    System.out.Println("Signature covers whole document: " + af.SignatureCoversWholeDocument(name));
    +        *    PdfPKCS7 pk = af.VerifySignature(name);
    +        *    Calendar cal = pk.GetSignDate();
    +        *    Certificate pkc[] = pk.GetCertificates();
    +        *    System.out.Println("Subject: " + PdfPKCS7.GetSubjectFields(pk.GetSigningCertificate()));
    +        *    System.out.Println("Document modified: " + !pk.Verify());
    +        *    Object fails[] = PdfPKCS7.VerifyCertificates(pkc, kall, null, cal);
    +        *    if (fails == null)
    +        *        System.out.Println("Certificates verified against the KeyStore");
    +        *    else
    +        *        System.out.Println("Certificate failed: " + fails[1]);
    +        * }
    +        * 
    + * @param name the signature field name + * @return a PdfPKCS7 class to continue the verification + */ + public PdfPKCS7 VerifySignature(String name) { + PdfDictionary v = GetSignatureDictionary(name); + if (v == null) + return null; + PdfName sub = (PdfName)PdfReader.GetPdfObject(v.Get(PdfName.SUBFILTER)); + PdfString contents = (PdfString)PdfReader.GetPdfObject(v.Get(PdfName.CONTENTS)); + PdfPKCS7 pk = null; + if (sub.Equals(PdfName.ADBE_X509_RSA_SHA1)) { + PdfString cert = (PdfString)PdfReader.GetPdfObject(v.Get(PdfName.CERT)); + pk = new PdfPKCS7(contents.GetOriginalBytes(), cert.GetBytes()); + } + else + pk = new PdfPKCS7(contents.GetOriginalBytes()); + UpdateByteRange(pk, v); + PdfString str = (PdfString)PdfReader.GetPdfObject(v.Get(PdfName.M)); + if (str != null) + pk.SignDate = PdfDate.Decode(str.ToString()); + PdfObject obj = PdfReader.GetPdfObject(v.Get(PdfName.NAME)); + if (obj != null) { + if (obj.IsString()) + pk.SignName = ((PdfString)obj).ToUnicodeString(); + else if(obj.IsName()) + pk.SignName = PdfName.DecodeName(obj.ToString()); + } + str = (PdfString)PdfReader.GetPdfObject(v.Get(PdfName.REASON)); + if (str != null) + pk.Reason = str.ToUnicodeString(); + str = (PdfString)PdfReader.GetPdfObject(v.Get(PdfName.LOCATION)); + if (str != null) + pk.Location = str.ToUnicodeString(); + return pk; + } + + private void UpdateByteRange(PdfPKCS7 pkcs7, PdfDictionary v) { + PdfArray b = (PdfArray)PdfReader.GetPdfObject(v.Get(PdfName.BYTERANGE)); + RandomAccessFileOrArray rf = reader.SafeFile; + try { + rf.ReOpen(); + byte[] buf = new byte[8192]; + ArrayList ar = b.ArrayList; + for (int k = 0; k < ar.Count; ++k) { + int start = ((PdfNumber)ar[k]).IntValue; + int length = ((PdfNumber)ar[++k]).IntValue; + rf.Seek(start); + while (length > 0) { + int rd = rf.Read(buf, 0, Math.Min(length, buf.Length)); + if (rd <= 0) + break; + length -= rd; + pkcs7.Update(buf, 0, rd); + } + } + } + finally { + try{rf.Close();}catch{} + } + } + + /** + * Gets the total number of revisions this document has. + * @return the total number of revisions + */ + public int TotalRevisions { + get { + FindSignatureNames(); + return this.totalRevisions; + } + } + + /** + * Gets this field revision. + * @param field the signature field name + * @return the revision or zero if it's not a signature field + */ + public int GetRevision(String field) { + FindSignatureNames(); + field = GetTranslatedFieldName(field); + if (!sigNames.ContainsKey(field)) + return 0; + return ((int[])sigNames[field])[1]; + } + + /** + * Extracts a revision from the document. + * @param field the signature field name + * @return an Stream covering the revision. Returns null if + * it's not a signature field + * @throws IOException on error + */ + public Stream ExtractRevision(String field) { + FindSignatureNames(); + field = GetTranslatedFieldName(field); + if (!sigNames.ContainsKey(field)) + return null; + int length = ((int[])sigNames[field])[0]; + RandomAccessFileOrArray raf = reader.SafeFile; + raf.ReOpen(); + raf.Seek(0); + return new RevisionStream(raf, length); + } + + /** + * Sets a cache for field appearances. Parsing the existing PDF to + * create a new TextField is time expensive. For those tasks that repeatedly + * fill the same PDF with different field values the use of the cache has dramatic + * speed advantages. An example usage: + *

    + *

    +        * String pdfFile = ...;// the pdf file used as template
    +        * ArrayList xfdfFiles = ...;// the xfdf file names
    +        * ArrayList pdfOutFiles = ...;// the output file names, one for each element in xpdfFiles
    +        * Hashtable cache = new Hashtable();// the appearances cache
    +        * PdfReader originalReader = new PdfReader(pdfFile);
    +        * for (int k = 0; k < xfdfFiles.Size(); ++k) {
    +        *    PdfReader reader = new PdfReader(originalReader);
    +        *    XfdfReader xfdf = new XfdfReader((String)xfdfFiles.Get(k));
    +        *    PdfStamper stp = new PdfStamper(reader, new FileOutputStream((String)pdfOutFiles.Get(k)));
    +        *    AcroFields af = stp.GetAcroFields();
    +        *    af.SetFieldCache(cache);
    +        *    af.SetFields(xfdf);
    +        *    stp.Close();
    +        * }
    +        * 
    + * @param fieldCache an HasMap that will carry the cached appearances + */ + public Hashtable FieldCache { + set { + fieldCache = value; + } + get { + return fieldCache; + } + } + + private void MarkUsed(PdfObject obj) { + if (!append) + return; + ((PdfStamperImp)writer).MarkUsed(obj); + } + + /** + * Sets extra margins in text fields to better mimic the Acrobat layout. + * @param extraMarginLeft the extra marging left + * @param extraMarginTop the extra margin top + */ + public void SetExtraMargin(float extraMarginLeft, float extraMarginTop) { + this.extraMarginLeft = extraMarginLeft; + this.extraMarginTop = extraMarginTop; + } + + /** + * Adds a substitution font to the list. The fonts in this list will be used if the original + * font doesn't contain the needed glyphs. + * @param font the font + */ + public void AddSubstitutionFont(BaseFont font) { + if (substitutionFonts == null) + substitutionFonts = new ArrayList(); + substitutionFonts.Add(font); + } + + private static Hashtable stdFieldFontNames = new Hashtable(); + + /** + * Holds value of property fieldCache. + */ + private Hashtable fieldCache; + + private int totalRevisions; + + static AcroFields() { + stdFieldFontNames["CoBO"] = new String[]{"Courier-BoldOblique"}; + stdFieldFontNames["CoBo"] = new String[]{"Courier-Bold"}; + stdFieldFontNames["CoOb"] = new String[]{"Courier-Oblique"}; + stdFieldFontNames["Cour"] = new String[]{"Courier"}; + stdFieldFontNames["HeBO"] = new String[]{"Helvetica-BoldOblique"}; + stdFieldFontNames["HeBo"] = new String[]{"Helvetica-Bold"}; + stdFieldFontNames["HeOb"] = new String[]{"Helvetica-Oblique"}; + stdFieldFontNames["Helv"] = new String[]{"Helvetica"}; + stdFieldFontNames["Symb"] = new String[]{"Symbol"}; + stdFieldFontNames["TiBI"] = new String[]{"Times-BoldItalic"}; + stdFieldFontNames["TiBo"] = new String[]{"Times-Bold"}; + stdFieldFontNames["TiIt"] = new String[]{"Times-Italic"}; + stdFieldFontNames["TiRo"] = new String[]{"Times-Roman"}; + stdFieldFontNames["ZaDb"] = new String[]{"ZapfDingbats"}; + stdFieldFontNames["HySm"] = new String[]{"HYSMyeongJo-Medium", "UniKS-UCS2-H"}; + stdFieldFontNames["HyGo"] = new String[]{"HYGoThic-Medium", "UniKS-UCS2-H"}; + stdFieldFontNames["KaGo"] = new String[]{"HeiseiKakuGo-W5", "UniKS-UCS2-H"}; + stdFieldFontNames["KaMi"] = new String[]{"HeiseiMin-W3", "UniJIS-UCS2-H"}; + stdFieldFontNames["MHei"] = new String[]{"MHei-Medium", "UniCNS-UCS2-H"}; + stdFieldFontNames["MSun"] = new String[]{"MSung-Light", "UniCNS-UCS2-H"}; + stdFieldFontNames["STSo"] = new String[]{"STSong-Light", "UniGB-UCS2-H"}; + } + + public class RevisionStream : Stream { + private byte[] b = new byte[1]; + private RandomAccessFileOrArray raf; + private int length; + private int rangePosition = 0; + private bool closed; + + internal RevisionStream(RandomAccessFileOrArray raf, int length) { + this.raf = raf; + this.length = length; + } + + public override int ReadByte() { + int n = Read(b, 0, 1); + if (n != 1) + return -1; + return b[0] & 0xff; + } + + public override int Read(byte[] b, int off, int len) { + if (b == null) { + throw new ArgumentNullException(); + } else if ((off < 0) || (off > b.Length) || (len < 0) || + ((off + len) > b.Length) || ((off + len) < 0)) { + throw new ArgumentOutOfRangeException(); + } else if (len == 0) { + return 0; + } + if (rangePosition >= length) { + Close(); + return -1; + } + int elen = Math.Min(len, length - rangePosition); + raf.ReadFully(b, off, elen); + rangePosition += elen; + return elen; + } + + public override void Close() { + if (!closed) { + raf.Close(); + closed = true; + } + } + + public override bool CanRead { + get { + return true; + } + } + + public override bool CanSeek { + get { + return false; + } + } + + public override bool CanWrite { + get { + return false; + } + } + + public override long Length { + get { + return 0; + } + } + + public override long Position { + get { + return 0; + } + set { + } + } + + public override void Flush() { + } + + public override long Seek(long offset, SeekOrigin origin) { + return 0; + } + + public override void SetLength(long value) { + } + + public override void Write(byte[] buffer, int offset, int count) { + } + } + + private class ISorterComparator : IComparer { + public int Compare(Object o1, Object o2) { + int n1 = ((int[])((Object[])o1)[1])[0]; + int n2 = ((int[])((Object[])o2)[1])[0]; + return n1 - n2; + } + } + + /** + * Sets a list of substitution fonts. The list is composed of BaseFont and can also be null. The fonts in this list will be used if the original + * font doesn't contain the needed glyphs. + * @param substitutionFonts the list + */ + public ArrayList SubstitutionFonts { + set { + substitutionFonts = value; + } + get { + return substitutionFonts; + } + } + + /** + * Gets the XFA form processor. + * @return the XFA form processor + */ + public XfaForm Xfa { + get { + return xfa; + } + } + + private static readonly PdfName[] buttonRemove = {PdfName.MK, PdfName.F , PdfName.FF , PdfName.Q , PdfName.BS , PdfName.BORDER}; + + /** + * Creates a new pushbutton from an existing field. If there are several pushbuttons with the same name + * only the first one is used. This pushbutton can be changed and be used to replace + * an existing one, with the same name or other name, as long is it is in the same document. To replace an existing pushbutton + * call {@link #replacePushbuttonField(String,PdfFormField)}. + * @param field the field name that should be a pushbutton + * @return a new pushbutton or null if the field is not a pushbutton + */ + public PushbuttonField GetNewPushbuttonFromField(String field) { + return GetNewPushbuttonFromField(field, 0); + } + + /** + * Creates a new pushbutton from an existing field. This pushbutton can be changed and be used to replace + * an existing one, with the same name or other name, as long is it is in the same document. To replace an existing pushbutton + * call {@link #replacePushbuttonField(String,PdfFormField,int)}. + * @param field the field name that should be a pushbutton + * @param order the field order in fields with same name + * @return a new pushbutton or null if the field is not a pushbutton + */ + public PushbuttonField GetNewPushbuttonFromField(String field, int order) { + if (GetFieldType(field) != FIELD_TYPE_PUSHBUTTON) + return null; + Item item = GetFieldItem(field); + if (order >= item.merged.Count) + return null; + int posi = order * 5; + float[] pos = GetFieldPositions(field); + Rectangle box = new Rectangle(pos[posi + 1], pos[posi + 2], pos[posi + 3], pos[posi + 4]); + PushbuttonField newButton = new PushbuttonField(writer, box, null); + PdfDictionary dic = (PdfDictionary)item.merged[order]; + DecodeGenericDictionary(dic, newButton); + PdfDictionary mk = (PdfDictionary)PdfReader.GetPdfObject(dic.Get(PdfName.MK)); + if (mk != null) { + PdfString text = (PdfString)PdfReader.GetPdfObject(mk.Get(PdfName.CA)); + if (text != null) + newButton.Text = text.ToUnicodeString(); + PdfNumber tp = (PdfNumber)PdfReader.GetPdfObject(mk.Get(PdfName.TP)); + if (tp != null) + newButton.Layout = tp.IntValue + 1; + PdfDictionary ifit = (PdfDictionary)PdfReader.GetPdfObject(mk.Get(PdfName.IF)); + if (ifit != null) { + PdfName sw = (PdfName)PdfReader.GetPdfObject(ifit.Get(PdfName.SW)); + if (sw != null) { + int scale = PushbuttonField.SCALE_ICON_ALWAYS; + if (sw.Equals(PdfName.B)) + scale = PushbuttonField.SCALE_ICON_IS_TOO_BIG; + else if (sw.Equals(PdfName.S)) + scale = PushbuttonField.SCALE_ICON_IS_TOO_SMALL; + else if (sw.Equals(PdfName.N)) + scale = PushbuttonField.SCALE_ICON_NEVER; + newButton.ScaleIcon = scale; + } + sw = (PdfName)PdfReader.GetPdfObject(ifit.Get(PdfName.S)); + if (sw != null) { + if (sw.Equals(PdfName.A)) + newButton.ProportionalIcon = false; + } + PdfArray aj = (PdfArray)PdfReader.GetPdfObject(ifit.Get(PdfName.A)); + if (aj != null && aj.Size == 2) { + float left = ((PdfNumber)PdfReader.GetPdfObject((PdfObject)aj.ArrayList[0])).FloatValue; + float bottom = ((PdfNumber)PdfReader.GetPdfObject((PdfObject)aj.ArrayList[1])).FloatValue; + newButton.IconHorizontalAdjustment = left; + newButton.IconVerticalAdjustment = bottom; + } + PdfObject fb = PdfReader.GetPdfObject(ifit.Get(PdfName.FB)); + if (fb != null && fb.ToString().Equals("true")) + newButton.IconFitToBounds = true; + } + PdfObject i = mk.Get(PdfName.I); + if (i != null && i.IsIndirect()) + newButton.IconReference = (PRIndirectReference)i; + } + return newButton; + } + + /** + * Replaces the first field with a new pushbutton. The pushbutton can be created with + * {@link #getNewPushbuttonFromField(String)} from the same document or it can be a + * generic PdfFormField of the type pushbutton. + * @param field the field name + * @param button the PdfFormField representing the pushbutton + * @return true if the field was replaced, false if the field + * was not a pushbutton + */ + public bool ReplacePushbuttonField(String field, PdfFormField button) { + return ReplacePushbuttonField(field, button, 0); + } + + /** + * Replaces the designated field with a new pushbutton. The pushbutton can be created with + * {@link #getNewPushbuttonFromField(String,int)} from the same document or it can be a + * generic PdfFormField of the type pushbutton. + * @param field the field name + * @param button the PdfFormField representing the pushbutton + * @param order the field order in fields with same name + * @return true if the field was replaced, false if the field + * was not a pushbutton + */ + public bool ReplacePushbuttonField(String field, PdfFormField button, int order) { + if (GetFieldType(field) != FIELD_TYPE_PUSHBUTTON) + return false; + Item item = GetFieldItem(field); + if (order >= item.merged.Count) + return false; + PdfDictionary merged = (PdfDictionary)item.merged[order]; + PdfDictionary values = (PdfDictionary)item.values[order]; + PdfDictionary widgets = (PdfDictionary)item.widgets[order]; + for (int k = 0; k < buttonRemove.Length; ++k) { + merged.Remove(buttonRemove[k]); + values.Remove(buttonRemove[k]); + widgets.Remove(buttonRemove[k]); + } + foreach (PdfName key in button.Keys) { + if (key.Equals(PdfName.T) || key.Equals(PdfName.RECT)) + continue; + if (key.Equals(PdfName.FF)) + values.Put(key, button.Get(key)); + else + widgets.Put(key, button.Get(key)); + merged.Put(key, button.Get(key)); + } + return true; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/ArabicLigaturizer.cs b/iTechSharp/iTextSharp/text/pdf/ArabicLigaturizer.cs new file mode 100644 index 0000000..684515e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/ArabicLigaturizer.cs @@ -0,0 +1,772 @@ +using System; +using System.Text; +/* + * Copyright 2003 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Shape arabic characters. This code was inspired by an LGPL'ed C library: + * Pango ( see http://www.pango.com/ ). Note that the code of this is the + * original work of Paulo Soares. Hence it is perfectly justifiable to distribute + * it under the MPL. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class ArabicLigaturizer { + + static bool IsVowel(char s) { + return ((s >= '\u064B') && (s <= '\u0655')) || (s == '\u0670'); + } + + static char Charshape(char s, int which) + /* which 0=isolated 1=final 2=initial 3=medial */ + { + int l, r, m; + if ((s >= '\u0621') && (s <= '\u06D3')) { + l = 0; + r = chartable.Length - 1; + while (l <= r) { + m = (l + r) / 2; + if (s == chartable[m][0]) { + return chartable[m][which + 1]; + } + else if (s < chartable[m][0]) { + r = m - 1; + } + else { + l = m + 1; + } + } + } + else if (s >= '\ufef5' && s <= '\ufefb') + return (char)(s + which); + return s; + } + + static int Shapecount(char s) { + int l, r, m; + if ((s >= '\u0621') && (s <= '\u06D3') && !IsVowel(s)) { + l = 0; + r = chartable.Length - 1; + while (l <= r) { + m = (l + r) / 2; + if (s == chartable[m][0]) { + return chartable[m].Length - 1; + } + else if (s < chartable[m][0]) { + r = m - 1; + } + else { + l = m + 1; + } + } + } + else if (s == ZWJ) { + return 4; + } + return 1; + } + + static int Ligature(char newchar, Charstruct oldchar) { + /* 0 == no ligature possible; 1 == vowel; 2 == two chars; 3 == Lam+Alef */ + int retval = 0; + + if (oldchar.basechar == 0) + return 0; + if (IsVowel(newchar)) { + retval = 1; + if ((oldchar.vowel != 0) && (newchar != SHADDA)) { + retval = 2; /* we eliminate the old vowel .. */ + } + switch (newchar) { + case SHADDA: + if (oldchar.mark1 == 0) { + oldchar.mark1 = SHADDA; + } + else { + return 0; /* no ligature possible */ + } + break; + case HAMZABELOW: + switch (oldchar.basechar) { + case ALEF: + oldchar.basechar = ALEFHAMZABELOW; + retval = 2; + break; + case LAM_ALEF: + oldchar.basechar = LAM_ALEFHAMZABELOW; + retval = 2; + break; + default: + oldchar.mark1 = HAMZABELOW; + break; + } + break; + case HAMZAABOVE: + switch (oldchar.basechar) { + case ALEF: + oldchar.basechar = ALEFHAMZA; + retval = 2; + break; + case LAM_ALEF: + oldchar.basechar = LAM_ALEFHAMZA; + retval = 2; + break; + case WAW: + oldchar.basechar = WAWHAMZA; + retval = 2; + break; + case YEH: + case ALEFMAKSURA: + case FARSIYEH: + oldchar.basechar = YEHHAMZA; + retval = 2; + break; + default: /* whatever sense this may make .. */ + oldchar.mark1 = HAMZAABOVE; + break; + } + break; + case MADDA: + switch (oldchar.basechar) { + case ALEF: + oldchar.basechar = ALEFMADDA; + retval = 2; + break; + } + break; + default: + oldchar.vowel = newchar; + break; + } + if (retval == 1) { + oldchar.lignum++; + } + return retval; + } + if (oldchar.vowel != 0) { /* if we already joined a vowel, we can't join a Hamza */ + return 0; + } + + switch (oldchar.basechar) { + case LAM: + switch (newchar) { + case ALEF: + oldchar.basechar = LAM_ALEF; + oldchar.numshapes = 2; + retval = 3; + break; + case ALEFHAMZA: + oldchar.basechar = LAM_ALEFHAMZA; + oldchar.numshapes = 2; + retval = 3; + break; + case ALEFHAMZABELOW: + oldchar.basechar = LAM_ALEFHAMZABELOW; + oldchar.numshapes = 2; + retval = 3; + break; + case ALEFMADDA: + oldchar.basechar = LAM_ALEFMADDA; + oldchar.numshapes = 2; + retval = 3; + break; + } + break; + case (char)0: + oldchar.basechar = newchar; + oldchar.numshapes = Shapecount(newchar); + retval = 1; + break; + } + return retval; + } + + static void Copycstostring(StringBuilder str, Charstruct s, int level) { + /* s is a shaped charstruct; i is the index into the string */ + if (s.basechar == 0) + return; + + str.Append(s.basechar); + s.lignum--; + if (s.mark1 != 0) { + if ((level & ar_novowel) == 0) { + str.Append(s.mark1); + s.lignum--; + } + else { + s.lignum--; + } + } + if (s.vowel != 0) { + if ((level & ar_novowel) == 0) { + str.Append(s.vowel); + s.lignum--; + } + else { /* vowel elimination */ + s.lignum--; + } + } + } + + // return len + internal static void Doublelig(StringBuilder str, int level) + /* Ok. We have presentation ligatures in our font. */ + { + int len; + int olen = len = str.Length; + int j = 0, si = 1; + char lapresult; + + while (si < olen) { + lapresult = (char)0; + if ((level & ar_composedtashkeel) != 0) { + switch (str[j]) { + case SHADDA: + switch (str[si]) { + case KASRA: + lapresult = '\uFC62'; + break; + case FATHA: + lapresult = '\uFC60'; + break; + case DAMMA: + lapresult = '\uFC61'; + break; + case '\u064C': + lapresult = '\uFC5E'; + break; + case '\u064D': + lapresult = '\uFC5F'; + break; + } + break; + case KASRA: + if (str[si] == SHADDA) + lapresult = '\uFC62'; + break; + case FATHA: + if (str[si] == SHADDA) + lapresult = '\uFC60'; + break; + case DAMMA: + if (str[si] == SHADDA) + lapresult = '\uFC61'; + break; + } + } + + if ((level & ar_lig) != 0) { + switch (str[j]) { + case '\uFEDF': /* LAM initial */ + switch (str[si]) { + case '\uFE9E': + lapresult = '\uFC3F'; + break; /* JEEM final */ + case '\uFEA0': + lapresult = '\uFCC9'; + break; /* JEEM medial */ + case '\uFEA2': + lapresult = '\uFC40'; + break; /* HAH final */ + case '\uFEA4': + lapresult = '\uFCCA'; + break; /* HAH medial */ + case '\uFEA6': + lapresult = '\uFC41'; + break; /* KHAH final */ + case '\uFEA8': + lapresult = '\uFCCB'; + break; /* KHAH medial */ + case '\uFEE2': + lapresult = '\uFC42'; + break; /* MEEM final */ + case '\uFEE4': + lapresult = '\uFCCC'; + break; /* MEEM medial */ + } + break; + case '\uFE97': /* TEH inital */ + switch (str[si]) { + case '\uFEA0': + lapresult = '\uFCA1'; + break; /* JEEM medial */ + case '\uFEA4': + lapresult = '\uFCA2'; + break; /* HAH medial */ + case '\uFEA8': + lapresult = '\uFCA3'; + break; /* KHAH medial */ + } + break; + case '\uFE91': /* BEH inital */ + switch (str[si]) { + case '\uFEA0': + lapresult = '\uFC9C'; + break; /* JEEM medial */ + case '\uFEA4': + lapresult = '\uFC9D'; + break; /* HAH medial */ + case '\uFEA8': + lapresult = '\uFC9E'; + break; /* KHAH medial */ + } + break; + case '\uFEE7': /* NOON inital */ + switch (str[si]) { + case '\uFEA0': + lapresult = '\uFCD2'; + break; /* JEEM initial */ + case '\uFEA4': + lapresult = '\uFCD3'; + break; /* HAH medial */ + case '\uFEA8': + lapresult = '\uFCD4'; + break; /* KHAH medial */ + } + break; + + case '\uFEE8': /* NOON medial */ + switch (str[si]) { + case '\uFEAE': + lapresult = '\uFC8A'; + break; /* REH final */ + case '\uFEB0': + lapresult = '\uFC8B'; + break; /* ZAIN final */ + } + break; + case '\uFEE3': /* MEEM initial */ + switch (str[si]) { + case '\uFEA0': + lapresult = '\uFCCE'; + break; /* JEEM medial */ + case '\uFEA4': + lapresult = '\uFCCF'; + break; /* HAH medial */ + case '\uFEA8': + lapresult = '\uFCD0'; + break; /* KHAH medial */ + case '\uFEE4': + lapresult = '\uFCD1'; + break; /* MEEM medial */ + } + break; + + case '\uFED3': /* FEH initial */ + switch (str[si]) { + case '\uFEF2': + lapresult = '\uFC32'; + break; /* YEH final */ + } + break; + + default: + break; + } /* end switch string[si] */ + } + if (lapresult != 0) { + str[j] = lapresult; + len--; + si++; /* jump over one character */ + /* we'll have to change this, too. */ + } + else { + j++; + str[j] = str[si]; + si++; + } + } + str.Length = len; + } + + static bool Connects_to_left(Charstruct a) { + return a.numshapes > 2; + } + + internal static void Shape(char[] text, StringBuilder str, int level) { + /* string is assumed to be empty and big enough. + * text is the original text. + * This routine does the basic arabic reshaping. + * *len the number of non-null characters. + * + * Note: We have to unshape each character first! + */ + int join; + int which; + char nextletter; + + int p = 0; /* initialize for output */ + Charstruct oldchar = new Charstruct(); + Charstruct curchar = new Charstruct(); + while (p < text.Length) { + nextletter = text[p++]; + //nextletter = unshape (nextletter); + + join = Ligature(nextletter, curchar); + if (join == 0) { /* shape curchar */ + int nc = Shapecount(nextletter); + //(*len)++; + if (nc == 1) { + which = 0; /* final or isolated */ + } + else { + which = 2; /* medial or initial */ + } + if (Connects_to_left(oldchar)) { + which++; + } + + which = which % (curchar.numshapes); + curchar.basechar = Charshape(curchar.basechar, which); + + /* get rid of oldchar */ + Copycstostring(str, oldchar, level); + oldchar = curchar; /* new values in oldchar */ + + /* init new curchar */ + curchar = new Charstruct(); + curchar.basechar = nextletter; + curchar.numshapes = nc; + curchar.lignum++; + // (*len) += unligature (&curchar, level); + } + else if (join == 1) { + } + // else + // { + // (*len) += unligature (&curchar, level); + // } + // p = g_utf8_next_char (p); + } + + /* Handle last char */ + if (Connects_to_left(oldchar)) + which = 1; + else + which = 0; + which = which % (curchar.numshapes); + curchar.basechar = Charshape(curchar.basechar, which); + + /* get rid of oldchar */ + Copycstostring(str, oldchar, level); + Copycstostring(str, curchar, level); + } + + internal static int Arabic_shape(char[] src, int srcoffset, int srclength, char[] dest, int destoffset, int destlength, int level) { + char[] str = new char[srclength]; + for (int k = srclength + srcoffset - 1; k >= srcoffset; --k) + str[k - srcoffset] = src[k]; + StringBuilder str2 = new StringBuilder(srclength); + Shape(str, str2, level); + if ((level & (ar_composedtashkeel | ar_lig)) != 0) + Doublelig(str2, level); + // string.Reverse(); + System.Array.Copy(str2.ToString().ToCharArray(), 0, dest, destoffset, str2.Length); + return str2.Length; + } + + internal static void ProcessNumbers(char[] text, int offset, int length, int options) { + int limit = offset + length; + if ((options & DIGITS_MASK) != 0) { + char digitBase = '\u0030'; // European digits + switch (options & DIGIT_TYPE_MASK) { + case DIGIT_TYPE_AN: + digitBase = '\u0660'; // Arabic-Indic digits + break; + + case DIGIT_TYPE_AN_EXTENDED: + digitBase = '\u06f0'; // Eastern Arabic-Indic digits (Persian and Urdu) + break; + + default: + break; + } + + switch (options & DIGITS_MASK) { + case DIGITS_EN2AN: { + int digitDelta = digitBase - '\u0030'; + for (int i = offset; i < limit; ++i) { + char ch = text[i]; + if (ch <= '\u0039' && ch >= '\u0030') { + text[i] += (char)digitDelta; + } + } + } + break; + + case DIGITS_AN2EN: { + char digitTop = (char)(digitBase + 9); + int digitDelta = '\u0030' - digitBase; + for (int i = offset; i < limit; ++i) { + char ch = text[i]; + if (ch <= digitTop && ch >= digitBase) { + text[i] += (char)digitDelta; + } + } + } + break; + + case DIGITS_EN2AN_INIT_LR: + ShapeToArabicDigitsWithContext(text, 0, length, digitBase, false); + break; + + case DIGITS_EN2AN_INIT_AL: + ShapeToArabicDigitsWithContext(text, 0, length, digitBase, true); + break; + + default: + break; + } + } + } + + internal static void ShapeToArabicDigitsWithContext(char[] dest, int start, int length, char digitBase, bool lastStrongWasAL) { + digitBase -= '0'; // move common adjustment out of loop + + int limit = start + length; + for (int i = start; i < limit; ++i) { + char ch = dest[i]; + switch (BidiOrder.GetDirection(ch)) { + case BidiOrder.L: + case BidiOrder.R: + lastStrongWasAL = false; + break; + case BidiOrder.AL: + lastStrongWasAL = true; + break; + case BidiOrder.EN: + if (lastStrongWasAL && ch <= '\u0039') { + dest[i] = (char)(ch + digitBase); + } + break; + default: + break; + } + } + } + + private const char ALEF = '\u0627'; + private const char ALEFHAMZA = '\u0623'; + private const char ALEFHAMZABELOW = '\u0625'; + private const char ALEFMADDA = '\u0622'; + private const char LAM = '\u0644'; + private const char HAMZA = '\u0621'; + private const char TATWEEL = '\u0640'; + private const char ZWJ = '\u200D'; + + private const char HAMZAABOVE = '\u0654'; + private const char HAMZABELOW = '\u0655'; + + private const char WAWHAMZA = '\u0624'; + private const char YEHHAMZA = '\u0626'; + private const char WAW = '\u0648'; + private const char ALEFMAKSURA = '\u0649'; + private const char YEH = '\u064A'; + private const char FARSIYEH = '\u06CC'; + + private const char SHADDA = '\u0651'; + private const char KASRA = '\u0650'; + private const char FATHA = '\u064E'; + private const char DAMMA = '\u064F'; + private const char MADDA = '\u0653'; + + private const char LAM_ALEF = '\uFEFB'; + private const char LAM_ALEFHAMZA = '\uFEF7'; + private const char LAM_ALEFHAMZABELOW = '\uFEF9'; + private const char LAM_ALEFMADDA = '\uFEF5'; + + private static char[][] chartable = { + new char[]{'\u0621', '\uFE80'}, /* HAMZA */ + new char[]{'\u0622', '\uFE81', '\uFE82'}, /* ALEF WITH MADDA ABOVE */ + new char[]{'\u0623', '\uFE83', '\uFE84'}, /* ALEF WITH HAMZA ABOVE */ + new char[]{'\u0624', '\uFE85', '\uFE86'}, /* WAW WITH HAMZA ABOVE */ + new char[]{'\u0625', '\uFE87', '\uFE88'}, /* ALEF WITH HAMZA BELOW */ + new char[]{'\u0626', '\uFE89', '\uFE8A', '\uFE8B', '\uFE8C'}, /* YEH WITH HAMZA ABOVE */ + new char[]{'\u0627', '\uFE8D', '\uFE8E'}, /* ALEF */ + new char[]{'\u0628', '\uFE8F', '\uFE90', '\uFE91', '\uFE92'}, /* BEH */ + new char[]{'\u0629', '\uFE93', '\uFE94'}, /* TEH MARBUTA */ + new char[]{'\u062A', '\uFE95', '\uFE96', '\uFE97', '\uFE98'}, /* TEH */ + new char[]{'\u062B', '\uFE99', '\uFE9A', '\uFE9B', '\uFE9C'}, /* THEH */ + new char[]{'\u062C', '\uFE9D', '\uFE9E', '\uFE9F', '\uFEA0'}, /* JEEM */ + new char[]{'\u062D', '\uFEA1', '\uFEA2', '\uFEA3', '\uFEA4'}, /* HAH */ + new char[]{'\u062E', '\uFEA5', '\uFEA6', '\uFEA7', '\uFEA8'}, /* KHAH */ + new char[]{'\u062F', '\uFEA9', '\uFEAA'}, /* DAL */ + new char[]{'\u0630', '\uFEAB', '\uFEAC'}, /* THAL */ + new char[]{'\u0631', '\uFEAD', '\uFEAE'}, /* REH */ + new char[]{'\u0632', '\uFEAF', '\uFEB0'}, /* ZAIN */ + new char[]{'\u0633', '\uFEB1', '\uFEB2', '\uFEB3', '\uFEB4'}, /* SEEN */ + new char[]{'\u0634', '\uFEB5', '\uFEB6', '\uFEB7', '\uFEB8'}, /* SHEEN */ + new char[]{'\u0635', '\uFEB9', '\uFEBA', '\uFEBB', '\uFEBC'}, /* SAD */ + new char[]{'\u0636', '\uFEBD', '\uFEBE', '\uFEBF', '\uFEC0'}, /* DAD */ + new char[]{'\u0637', '\uFEC1', '\uFEC2', '\uFEC3', '\uFEC4'}, /* TAH */ + new char[]{'\u0638', '\uFEC5', '\uFEC6', '\uFEC7', '\uFEC8'}, /* ZAH */ + new char[]{'\u0639', '\uFEC9', '\uFECA', '\uFECB', '\uFECC'}, /* AIN */ + new char[]{'\u063A', '\uFECD', '\uFECE', '\uFECF', '\uFED0'}, /* GHAIN */ + new char[]{'\u0640', '\u0640', '\u0640', '\u0640', '\u0640'}, /* TATWEEL */ + new char[]{'\u0641', '\uFED1', '\uFED2', '\uFED3', '\uFED4'}, /* FEH */ + new char[]{'\u0642', '\uFED5', '\uFED6', '\uFED7', '\uFED8'}, /* QAF */ + new char[]{'\u0643', '\uFED9', '\uFEDA', '\uFEDB', '\uFEDC'}, /* KAF */ + new char[]{'\u0644', '\uFEDD', '\uFEDE', '\uFEDF', '\uFEE0'}, /* LAM */ + new char[]{'\u0645', '\uFEE1', '\uFEE2', '\uFEE3', '\uFEE4'}, /* MEEM */ + new char[]{'\u0646', '\uFEE5', '\uFEE6', '\uFEE7', '\uFEE8'}, /* NOON */ + new char[]{'\u0647', '\uFEE9', '\uFEEA', '\uFEEB', '\uFEEC'}, /* HEH */ + new char[]{'\u0648', '\uFEED', '\uFEEE'}, /* WAW */ + new char[]{'\u0649', '\uFEEF', '\uFEF0', '\uFBE8', '\uFBE9'}, /* ALEF MAKSURA */ + new char[]{'\u064A', '\uFEF1', '\uFEF2', '\uFEF3', '\uFEF4'}, /* YEH */ + new char[]{'\u0671', '\uFB50', '\uFB51'}, /* ALEF WASLA */ + new char[]{'\u0679', '\uFB66', '\uFB67', '\uFB68', '\uFB69'}, /* TTEH */ + new char[]{'\u067A', '\uFB5E', '\uFB5F', '\uFB60', '\uFB61'}, /* TTEHEH */ + new char[]{'\u067B', '\uFB52', '\uFB53', '\uFB54', '\uFB55'}, /* BEEH */ + new char[]{'\u067E', '\uFB56', '\uFB57', '\uFB58', '\uFB59'}, /* PEH */ + new char[]{'\u067F', '\uFB62', '\uFB63', '\uFB64', '\uFB65'}, /* TEHEH */ + new char[]{'\u0680', '\uFB5A', '\uFB5B', '\uFB5C', '\uFB5D'}, /* BEHEH */ + new char[]{'\u0683', '\uFB76', '\uFB77', '\uFB78', '\uFB79'}, /* NYEH */ + new char[]{'\u0684', '\uFB72', '\uFB73', '\uFB74', '\uFB75'}, /* DYEH */ + new char[]{'\u0686', '\uFB7A', '\uFB7B', '\uFB7C', '\uFB7D'}, /* TCHEH */ + new char[]{'\u0687', '\uFB7E', '\uFB7F', '\uFB80', '\uFB81'}, /* TCHEHEH */ + new char[]{'\u0688', '\uFB88', '\uFB89'}, /* DDAL */ + new char[]{'\u068C', '\uFB84', '\uFB85'}, /* DAHAL */ + new char[]{'\u068D', '\uFB82', '\uFB83'}, /* DDAHAL */ + new char[]{'\u068E', '\uFB86', '\uFB87'}, /* DUL */ + new char[]{'\u0691', '\uFB8C', '\uFB8D'}, /* RREH */ + new char[]{'\u0698', '\uFB8A', '\uFB8B'}, /* JEH */ + new char[]{'\u06A4', '\uFB6A', '\uFB6B', '\uFB6C', '\uFB6D'}, /* VEH */ + new char[]{'\u06A6', '\uFB6E', '\uFB6F', '\uFB70', '\uFB71'}, /* PEHEH */ + new char[]{'\u06A9', '\uFB8E', '\uFB8F', '\uFB90', '\uFB91'}, /* KEHEH */ + new char[]{'\u06AD', '\uFBD3', '\uFBD4', '\uFBD5', '\uFBD6'}, /* NG */ + new char[]{'\u06AF', '\uFB92', '\uFB93', '\uFB94', '\uFB95'}, /* GAF */ + new char[]{'\u06B1', '\uFB9A', '\uFB9B', '\uFB9C', '\uFB9D'}, /* NGOEH */ + new char[]{'\u06B3', '\uFB96', '\uFB97', '\uFB98', '\uFB99'}, /* GUEH */ + new char[]{'\u06BA', '\uFB9E', '\uFB9F'}, /* NOON GHUNNA */ + new char[]{'\u06BB', '\uFBA0', '\uFBA1', '\uFBA2', '\uFBA3'}, /* RNOON */ + new char[]{'\u06BE', '\uFBAA', '\uFBAB', '\uFBAC', '\uFBAD'}, /* HEH DOACHASHMEE */ + new char[]{'\u06C0', '\uFBA4', '\uFBA5'}, /* HEH WITH YEH ABOVE */ + new char[]{'\u06C1', '\uFBA6', '\uFBA7', '\uFBA8', '\uFBA9'}, /* HEH GOAL */ + new char[]{'\u06C5', '\uFBE0', '\uFBE1'}, /* KIRGHIZ OE */ + new char[]{'\u06C6', '\uFBD9', '\uFBDA'}, /* OE */ + new char[]{'\u06C7', '\uFBD7', '\uFBD8'}, /* U */ + new char[]{'\u06C8', '\uFBDB', '\uFBDC'}, /* YU */ + new char[]{'\u06C9', '\uFBE2', '\uFBE3'}, /* KIRGHIZ YU */ + new char[]{'\u06CB', '\uFBDE', '\uFBDF'}, /* VE */ + new char[]{'\u06CC', '\uFBFC', '\uFBFD', '\uFBFE', '\uFBFF'}, /* FARSI YEH */ + new char[]{'\u06D0', '\uFBE4', '\uFBE5', '\uFBE6', '\uFBE7'}, /* E */ + new char[]{'\u06D2', '\uFBAE', '\uFBAF'}, /* YEH BARREE */ + new char[]{'\u06D3', '\uFBB0', '\uFBB1'} /* YEH BARREE WITH HAMZA ABOVE */ + }; + + public const int ar_nothing = 0x0; + public const int ar_novowel = 0x1; + public const int ar_composedtashkeel = 0x4; + public const int ar_lig = 0x8; + /** + * Digit shaping option: Replace European digits (U+0030...U+0039) by Arabic-Indic digits. + */ + public const int DIGITS_EN2AN = 0x20; + + /** + * Digit shaping option: Replace Arabic-Indic digits by European digits (U+0030...U+0039). + */ + public const int DIGITS_AN2EN = 0x40; + + /** + * Digit shaping option: + * Replace European digits (U+0030...U+0039) by Arabic-Indic digits + * if the most recent strongly directional character + * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC). + * The initial state at the start of the text is assumed to be not an Arabic, + * letter, so European digits at the start of the text will not change. + * Compare to DIGITS_ALEN2AN_INIT_AL. + */ + public const int DIGITS_EN2AN_INIT_LR = 0x60; + + /** + * Digit shaping option: + * Replace European digits (U+0030...U+0039) by Arabic-Indic digits + * if the most recent strongly directional character + * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC). + * The initial state at the start of the text is assumed to be an Arabic, + * letter, so European digits at the start of the text will change. + * Compare to DIGITS_ALEN2AN_INT_LR. + */ + public const int DIGITS_EN2AN_INIT_AL = 0x80; + + /** Not a valid option value. */ + private const int DIGITS_RESERVED = 0xa0; + + /** + * Bit mask for digit shaping options. + */ + public const int DIGITS_MASK = 0xe0; + + /** + * Digit type option: Use Arabic-Indic digits (U+0660...U+0669). + */ + public const int DIGIT_TYPE_AN = 0; + + /** + * Digit type option: Use Eastern (Extended) Arabic-Indic digits (U+06f0...U+06f9). + */ + public const int DIGIT_TYPE_AN_EXTENDED = 0x100; + + /** + * Bit mask for digit type options. + */ + public const int DIGIT_TYPE_MASK = '\u0100'; // '\u3f00'? + + private class Charstruct { + internal char basechar; + internal char mark1; /* has to be initialized to zero */ + internal char vowel; + internal int lignum; /* is a ligature with lignum aditional characters */ + internal int numshapes = 1; + }; + + + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BadPasswordException.cs b/iTechSharp/iTextSharp/text/pdf/BadPasswordException.cs new file mode 100644 index 0000000..65ead6c --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BadPasswordException.cs @@ -0,0 +1,59 @@ +using System; +using System.IO; + +/* + * $Id: BadPasswordException.cs,v 1.1 2008/01/10 15:49:39 psoares33 Exp $ + * + * Copyright 2008 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + public class BadPasswordException : IOException { + public BadPasswordException() : base("Bad user Password") { + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/BadPdfFormatException.cs b/iTechSharp/iTextSharp/text/pdf/BadPdfFormatException.cs new file mode 100644 index 0000000..db72d7c --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BadPdfFormatException.cs @@ -0,0 +1,72 @@ +using System; + +/* + * $Id: BadPdfFormatException.cs,v 1.3 2008/05/13 11:25:16 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf +{ + /** + * Signals that a bad PDF format has been used to construct a PdfObject. + * + * @see PdfException + * @see PdfBoolean + * @see PdfNumber + * @see PdfString + * @see PdfName + * @see PdfDictionary + * @see PdfFont + */ + + public class BadPdfFormatException : Exception + { + public BadPdfFormatException() : base() {} + public BadPdfFormatException(string message) : base(message) {} + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/Barcode.cs b/iTechSharp/iTextSharp/text/pdf/Barcode.cs new file mode 100644 index 0000000..22ef490 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/Barcode.cs @@ -0,0 +1,430 @@ +using System; +using iTextSharp.text; +/* + * $Id: Barcode.cs,v 1.4 2006/07/31 13:51:38 psoares33 Exp $ + * + * Copyright 2002-2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** Base class containing properties and methods commom to all + * barcode types. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public abstract class Barcode { + /** A type of barcode */ + public const int EAN13 = 1; + /** A type of barcode */ + public const int EAN8 = 2; + /** A type of barcode */ + public const int UPCA = 3; + /** A type of barcode */ + public const int UPCE = 4; + /** A type of barcode */ + public const int SUPP2 = 5; + /** A type of barcode */ + public const int SUPP5 = 6; + /** A type of barcode */ + public const int POSTNET = 7; + /** A type of barcode */ + public const int PLANET = 8; + /** A type of barcode */ + public const int CODE128 = 9; + /** A type of barcode */ + public const int CODE128_UCC = 10; + /** A type of barcode */ + public const int CODE128_RAW = 11; + /** A type of barcode */ + public const int CODABAR = 12; + + /** The minimum bar width. + */ + protected float x; + + /** The bar multiplier for wide bars or the distance between + * bars for Postnet and Planet. + */ + protected float n; + + /** The text font. null if no text. + */ + protected BaseFont font; + + /** The size of the text or the height of the shorter bar + * in Postnet. + */ + protected float size; + + /** If positive, the text distance under the bars. If zero or negative, + * the text distance above the bars. + */ + protected float baseline; + + /** The height of the bars. + */ + protected float barHeight; + + /** The text Element. Can be Element.ALIGN_LEFT, + * Element.ALIGN_CENTER or Element.ALIGN_RIGHT. + */ + protected int textAlignment; + + /** The optional checksum generation. + */ + protected bool generateChecksum; + + /** Shows the generated checksum in the the text. + */ + protected bool checksumText; + + /** Show the start and stop character '*' in the text for + * the barcode 39 or 'ABCD' for codabar. + */ + protected bool startStopText; + + /** Generates extended barcode 39. + */ + protected bool extended; + + /** The code to generate. + */ + protected string code = ""; + + /** Show the guard bars for barcode EAN. + */ + protected bool guardBars; + + /** The code type. + */ + protected int codeType; + + /** The ink spreading. */ + protected float inkSpreading = 0; + + /** Gets the minimum bar width. + * @return the minimum bar width + */ + public float X { + get { + return x; + } + + set { + this.x = value; + } + } + + /** Gets the bar multiplier for wide bars. + * @return the bar multiplier for wide bars + */ + public float N { + get { + return n; + } + + set { + this.n = value; + } + } + + /** Gets the text font. null if no text. + * @return the text font. null if no text + */ + public BaseFont Font { + get { + return font; + } + + set { + this.font = value; + } + } + + /** Gets the size of the text. + * @return the size of the text + */ + public float Size { + get { + return size; + } + + set { + this.size = value; + } + } + + /** Gets the text baseline. + * If positive, the text distance under the bars. If zero or negative, + * the text distance above the bars. + * @return the baseline. + */ + public float Baseline { + get { + return baseline; + } + + set { + this.baseline = value; + } + } + + /** Gets the height of the bars. + * @return the height of the bars + */ + public float BarHeight { + get { + return barHeight; + } + + set { + this.barHeight = value; + } + } + + /** Gets the text Element. Can be Element.ALIGN_LEFT, + * Element.ALIGN_CENTER or Element.ALIGN_RIGHT. + * @return the text alignment + */ + public int TextAlignment{ + get { + return textAlignment; + } + + set { + this.textAlignment = value; + } + } + + /** The property for the optional checksum generation. + */ + public bool GenerateChecksum { + set { + this.generateChecksum = value; + } + get { + return generateChecksum; + } + } + + /** Sets the property to show the generated checksum in the the text. + * @param checksumText new value of property checksumText + */ + public bool ChecksumText { + set { + this.checksumText = value; + } + get { + return checksumText; + } + } + + /** Gets the property to show the start and stop character '*' in the text for + * the barcode 39. + * @param startStopText new value of property startStopText + */ + public bool StartStopText { + set { + this.startStopText = value; + } + get { + return startStopText; + } + } + + /** Sets the property to generate extended barcode 39. + * @param extended new value of property extended + */ + public bool Extended { + set { + this.extended = value; + } + get { + return extended; + } + } + + /** Gets the code to generate. + * @return the code to generate + */ + public virtual string Code { + get { + return code; + } + + set { + this.code = value; + } + } + + /** Sets the property to show the guard bars for barcode EAN. + * @param guardBars new value of property guardBars + */ + public bool GuardBars { + set { + this.guardBars = value; + } + get { + return guardBars; + } + } + + /** Gets the code type. + * @return the code type + */ + public int CodeType { + get { + return codeType; + } + + set { + this.codeType = value; + } + } + + /** Gets the maximum area that the barcode and the text, if + * any, will occupy. The lower left corner is always (0, 0). + * @return the size the barcode occupies. + */ + public abstract Rectangle BarcodeSize { + get; + } + + public float InkSpreading { + set { + inkSpreading = value; + } + get { + return inkSpreading; + } + } + + /** Places the barcode in a PdfContentByte. The + * barcode is always placed at coodinates (0, 0). Use the + * translation matrix to move it elsewhere.

    + * The bars and text are written in the following colors:

    + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *

    barColor

    textColor

    Result

    null

    null

    bars and text painted with current fill color

    barColor

    null

    bars and text painted with barColor

    null

    textColor

    bars painted with current color
    text painted with textColor

    barColor

    textColor

    bars painted with barColor
    text painted with textColor

    + * @param cb the PdfContentByte where the barcode will be placed + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the dimensions the barcode occupies + */ + public abstract Rectangle PlaceBarcode(PdfContentByte cb, Color barColor, Color textColor); + + /** Creates a template with the barcode. + * @param cb the PdfContentByte to create the template. It + * serves no other use + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the template + * @see #placeBarcode(PdfContentByte cb, Color barColor, Color textColor) + */ + public PdfTemplate CreateTemplateWithBarcode(PdfContentByte cb, Color barColor, Color textColor) { + PdfTemplate tp = cb.CreateTemplate(0, 0); + Rectangle rect = PlaceBarcode(tp, barColor, textColor); + tp.BoundingBox = rect; + return tp; + } + + /** Creates an Image with the barcode. + * @param cb the PdfContentByte to create the Image. It + * serves no other use + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the Image + * @see #placeBarcode(PdfContentByte cb, Color barColor, Color textColor) + */ + public Image CreateImageWithBarcode(PdfContentByte cb, Color barColor, Color textColor) { + return Image.GetInstance(CreateTemplateWithBarcode(cb, barColor, textColor)); + } + + /** + * The alternate text to be used, if present. + */ + protected String altText; + + /** + * Sets the alternate text. If present, this text will be used instead of the + * text derived from the supplied code. + * @param altText the alternate text + */ + public String AltText { + set { + altText = value; + } + get { + return altText; + } + } + + public abstract System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background); + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/Barcode128.cs b/iTechSharp/iTextSharp/text/pdf/Barcode128.cs new file mode 100644 index 0000000..96c4807 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/Barcode128.cs @@ -0,0 +1,809 @@ +using System; +using System.Text; +using iTextSharp.text; +/* + * $Id: Barcode128.cs,v 1.6 2007/10/24 16:31:54 psoares33 Exp $ + * + * Copyright 2002-2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** Implements the code 128 and UCC/EAN-128. Other symbologies are allowed in raw mode.

    + * The code types allowed are:
    + *

      + *
    • CODE128 - plain barcode 128. + *
    • CODE128_UCC - support for UCC/EAN-128 with a full list of AI. + *
    • CODE128_RAW - raw mode. The code attribute has the actual codes from 0 + * to 105 followed by '\uffff' and the human readable text. + *
    + * The default parameters are: + *
    +     * x = 0.8f;
    +     * font = BaseFont.CreateFont("Helvetica", "winansi", false);
    +     * size = 8;
    +     * baseline = size;
    +     * barHeight = size * 3;
    +     * textint= Element.ALIGN_CENTER;
    +     * codeType = CODE128;
    +     * 
    + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class Barcode128 : Barcode { + + /** The bars to generate the code. + */ + private static readonly byte[][] BARS = + { + new byte[] {2, 1, 2, 2, 2, 2}, + new byte[] {2, 2, 2, 1, 2, 2}, + new byte[] {2, 2, 2, 2, 2, 1}, + new byte[] {1, 2, 1, 2, 2, 3}, + new byte[] {1, 2, 1, 3, 2, 2}, + new byte[] {1, 3, 1, 2, 2, 2}, + new byte[] {1, 2, 2, 2, 1, 3}, + new byte[] {1, 2, 2, 3, 1, 2}, + new byte[] {1, 3, 2, 2, 1, 2}, + new byte[] {2, 2, 1, 2, 1, 3}, + new byte[] {2, 2, 1, 3, 1, 2}, + new byte[] {2, 3, 1, 2, 1, 2}, + new byte[] {1, 1, 2, 2, 3, 2}, + new byte[] {1, 2, 2, 1, 3, 2}, + new byte[] {1, 2, 2, 2, 3, 1}, + new byte[] {1, 1, 3, 2, 2, 2}, + new byte[] {1, 2, 3, 1, 2, 2}, + new byte[] {1, 2, 3, 2, 2, 1}, + new byte[] {2, 2, 3, 2, 1, 1}, + new byte[] {2, 2, 1, 1, 3, 2}, + new byte[] {2, 2, 1, 2, 3, 1}, + new byte[] {2, 1, 3, 2, 1, 2}, + new byte[] {2, 2, 3, 1, 1, 2}, + new byte[] {3, 1, 2, 1, 3, 1}, + new byte[] {3, 1, 1, 2, 2, 2}, + new byte[] {3, 2, 1, 1, 2, 2}, + new byte[] {3, 2, 1, 2, 2, 1}, + new byte[] {3, 1, 2, 2, 1, 2}, + new byte[] {3, 2, 2, 1, 1, 2}, + new byte[] {3, 2, 2, 2, 1, 1}, + new byte[] {2, 1, 2, 1, 2, 3}, + new byte[] {2, 1, 2, 3, 2, 1}, + new byte[] {2, 3, 2, 1, 2, 1}, + new byte[] {1, 1, 1, 3, 2, 3}, + new byte[] {1, 3, 1, 1, 2, 3}, + new byte[] {1, 3, 1, 3, 2, 1}, + new byte[] {1, 1, 2, 3, 1, 3}, + new byte[] {1, 3, 2, 1, 1, 3}, + new byte[] {1, 3, 2, 3, 1, 1}, + new byte[] {2, 1, 1, 3, 1, 3}, + new byte[] {2, 3, 1, 1, 1, 3}, + new byte[] {2, 3, 1, 3, 1, 1}, + new byte[] {1, 1, 2, 1, 3, 3}, + new byte[] {1, 1, 2, 3, 3, 1}, + new byte[] {1, 3, 2, 1, 3, 1}, + new byte[] {1, 1, 3, 1, 2, 3}, + new byte[] {1, 1, 3, 3, 2, 1}, + new byte[] {1, 3, 3, 1, 2, 1}, + new byte[] {3, 1, 3, 1, 2, 1}, + new byte[] {2, 1, 1, 3, 3, 1}, + new byte[] {2, 3, 1, 1, 3, 1}, + new byte[] {2, 1, 3, 1, 1, 3}, + new byte[] {2, 1, 3, 3, 1, 1}, + new byte[] {2, 1, 3, 1, 3, 1}, + new byte[] {3, 1, 1, 1, 2, 3}, + new byte[] {3, 1, 1, 3, 2, 1}, + new byte[] {3, 3, 1, 1, 2, 1}, + new byte[] {3, 1, 2, 1, 1, 3}, + new byte[] {3, 1, 2, 3, 1, 1}, + new byte[] {3, 3, 2, 1, 1, 1}, + new byte[] {3, 1, 4, 1, 1, 1}, + new byte[] {2, 2, 1, 4, 1, 1}, + new byte[] {4, 3, 1, 1, 1, 1}, + new byte[] {1, 1, 1, 2, 2, 4}, + new byte[] {1, 1, 1, 4, 2, 2}, + new byte[] {1, 2, 1, 1, 2, 4}, + new byte[] {1, 2, 1, 4, 2, 1}, + new byte[] {1, 4, 1, 1, 2, 2}, + new byte[] {1, 4, 1, 2, 2, 1}, + new byte[] {1, 1, 2, 2, 1, 4}, + new byte[] {1, 1, 2, 4, 1, 2}, + new byte[] {1, 2, 2, 1, 1, 4}, + new byte[] {1, 2, 2, 4, 1, 1}, + new byte[] {1, 4, 2, 1, 1, 2}, + new byte[] {1, 4, 2, 2, 1, 1}, + new byte[] {2, 4, 1, 2, 1, 1}, + new byte[] {2, 2, 1, 1, 1, 4}, + new byte[] {4, 1, 3, 1, 1, 1}, + new byte[] {2, 4, 1, 1, 1, 2}, + new byte[] {1, 3, 4, 1, 1, 1}, + new byte[] {1, 1, 1, 2, 4, 2}, + new byte[] {1, 2, 1, 1, 4, 2}, + new byte[] {1, 2, 1, 2, 4, 1}, + new byte[] {1, 1, 4, 2, 1, 2}, + new byte[] {1, 2, 4, 1, 1, 2}, + new byte[] {1, 2, 4, 2, 1, 1}, + new byte[] {4, 1, 1, 2, 1, 2}, + new byte[] {4, 2, 1, 1, 1, 2}, + new byte[] {4, 2, 1, 2, 1, 1}, + new byte[] {2, 1, 2, 1, 4, 1}, + new byte[] {2, 1, 4, 1, 2, 1}, + new byte[] {4, 1, 2, 1, 2, 1}, + new byte[] {1, 1, 1, 1, 4, 3}, + new byte[] {1, 1, 1, 3, 4, 1}, + new byte[] {1, 3, 1, 1, 4, 1}, + new byte[] {1, 1, 4, 1, 1, 3}, + new byte[] {1, 1, 4, 3, 1, 1}, + new byte[] {4, 1, 1, 1, 1, 3}, + new byte[] {4, 1, 1, 3, 1, 1}, + new byte[] {1, 1, 3, 1, 4, 1}, + new byte[] {1, 1, 4, 1, 3, 1}, + new byte[] {3, 1, 1, 1, 4, 1}, + new byte[] {4, 1, 1, 1, 3, 1}, + new byte[] {2, 1, 1, 4, 1, 2}, + new byte[] {2, 1, 1, 2, 1, 4}, + new byte[] {2, 1, 1, 2, 3, 2} + }; + + /** The stop bars. + */ + private static readonly byte[] BARS_STOP = {2, 3, 3, 1, 1, 1, 2}; + /** The charset code change. + */ + public const char CODE_AB_TO_C = (char)99; + /** The charset code change. + */ + public const char CODE_AC_TO_B = (char)100; + /** The charset code change. + */ + public const char CODE_BC_TO_A = (char)101; + /** The code for UCC/EAN-128. + */ + public const char FNC1_INDEX = (char)102; + /** The start code. + */ + public const char START_A = (char)103; + /** The start code. + */ + public const char START_B = (char)104; + /** The start code. + */ + public const char START_C = (char)105; + + public const char FNC1 = '\u00ca'; + public const char DEL = '\u00c3'; + public const char FNC3 = '\u00c4'; + public const char FNC2 = '\u00c5'; + public const char SHIFT = '\u00c6'; + public const char CODE_C = '\u00c7'; + public const char CODE_A = '\u00c8'; + public const char FNC4 = '\u00c8'; + public const char STARTA = '\u00cb'; + public const char STARTB = '\u00cc'; + public const char STARTC = '\u00cd'; + + private static IntHashtable ais = new IntHashtable(); + + /** Creates new Barcode128 */ + public Barcode128() { + x = 0.8f; + font = BaseFont.CreateFont("Helvetica", "winansi", false); + size = 8; + baseline = size; + barHeight = size * 3; + textAlignment = Element.ALIGN_CENTER; + codeType = CODE128; + } + + /** + * Removes the FNC1 codes in the text. + * @param code the text to clean + * @return the cleaned text + */ + public static String RemoveFNC1(String code) { + int len = code.Length; + StringBuilder buf = new StringBuilder(len); + for (int k = 0; k < len; ++k) { + char c = code[k]; + if (c >= 32 && c <= 126) + buf.Append(c); + } + return buf.ToString(); + } + + /** + * Gets the human readable text of a sequence of AI. + * @param code the text + * @return the human readable text + */ + public static String GetHumanReadableUCCEAN(String code) { + StringBuilder buf = new StringBuilder(); + String fnc1 = FNC1.ToString(); + try { + while (true) { + if (code.StartsWith(fnc1)) { + code = code.Substring(1); + continue; + } + int n = 0; + int idlen = 0; + for (int k = 2; k < 5; ++k) { + if (code.Length < k) + break; + if ((n = ais[int.Parse(code.Substring(0, k))]) != 0) { + idlen = k; + break; + } + } + if (idlen == 0) + break; + buf.Append('(').Append(code.Substring(0, idlen)).Append(')'); + code = code.Substring(idlen); + if (n > 0) { + n -= idlen; + if (code.Length <= n) + break; + buf.Append(RemoveFNC1(code.Substring(0, n))); + code = code.Substring(n); + } + else { + int idx = code.IndexOf(FNC1); + if (idx < 0) + break; + buf.Append(code.Substring(0,idx)); + code = code.Substring(idx + 1); + } + } + } + catch { + //empty + } + buf.Append(RemoveFNC1(code)); + return buf.ToString(); + } + + /** Returns true if the next numDigits + * starting from index textIndex are numeric skipping any FNC1. + * @param text the text to check + * @param textIndex where to check from + * @param numDigits the number of digits to check + * @return the check result + */ + internal static bool IsNextDigits(string text, int textIndex, int numDigits) { + int len = text.Length; + while (textIndex < len && numDigits > 0) { + if (text[textIndex] == FNC1) { + ++textIndex; + continue; + } + int n = Math.Min(2, numDigits); + if (textIndex + n > len) + return false; + while (n-- > 0) { + char c = text[textIndex++]; + if (c < '0' || c > '9') + return false; + --numDigits; + } + } + return numDigits == 0; + } + + /** Packs the digits for charset C also considering FNC1. It assumes that all the parameters + * are valid. + * @param text the text to pack + * @param textIndex where to pack from + * @param numDigits the number of digits to pack. It is always an even number + * @return the packed digits, two digits per character + */ + internal static String GetPackedRawDigits(String text, int textIndex, int numDigits) { + String outs = ""; + int start = textIndex; + while (numDigits > 0) { + if (text[textIndex] == FNC1) { + outs += FNC1_INDEX; + ++textIndex; + continue; + } + numDigits -= 2; + int c1 = text[textIndex++] - '0'; + int c2 = text[textIndex++] - '0'; + outs += (char)(c1 * 10 + c2); + } + return (char)(textIndex - start) + outs; + } + + /** Converts the human readable text to the characters needed to + * create a barcode. Some optimization is done to get the shortest code. + * @param text the text to convert + * @param ucc true if it is an UCC/EAN-128. In this case + * the character FNC1 is added + * @return the code ready to be fed to GetBarsCode128Raw() + */ + public static string GetRawText(string text, bool ucc) { + String outs = ""; + int tLen = text.Length; + if (tLen == 0) { + outs += START_B; + if (ucc) + outs += FNC1_INDEX; + return outs; + } + int c = 0; + for (int k = 0; k < tLen; ++k) { + c = text[k]; + if (c > 127 && c != FNC1) + throw new ArgumentException("There are illegal characters for barcode 128 in '" + text + "'."); + } + c = text[0]; + char currentCode = START_B; + int index = 0; + if (IsNextDigits(text, index, 2)) { + currentCode = START_C; + outs += currentCode; + if (ucc) + outs += FNC1_INDEX; + String out2 = GetPackedRawDigits(text, index, 2); + index += (int)out2[0]; + outs += out2.Substring(1); + } + else if (c < ' ') { + currentCode = START_A; + outs += currentCode; + if (ucc) + outs += FNC1_INDEX; + outs += (char)(c + 64); + ++index; + } + else { + outs += currentCode; + if (ucc) + outs += FNC1_INDEX; + if (c == FNC1) + outs += FNC1_INDEX; + else + outs += (char)(c - ' '); + ++index; + } + while (index < tLen) { + switch (currentCode) { + case START_A: + { + if (IsNextDigits(text, index, 4)) { + currentCode = START_C; + outs += CODE_AB_TO_C; + String out2 = GetPackedRawDigits(text, index, 4); + index += (int)out2[0]; + outs += out2.Substring(1); + } + else { + c = text[index++]; + if (c == FNC1) + outs += FNC1_INDEX; + else if (c > '_') { + currentCode = START_B; + outs += CODE_AC_TO_B; + outs += (char)(c - ' '); + } + else if (c < ' ') + outs += (char)(c + 64); + else + outs += (char)(c - ' '); + } + } + break; + case START_B: + { + if (IsNextDigits(text, index, 4)) { + currentCode = START_C; + outs += CODE_AB_TO_C; + String out2 = GetPackedRawDigits(text, index, 4); + index += (int)out2[0]; + outs += out2.Substring(1); + } + else { + c = text[index++]; + if (c == FNC1) + outs += FNC1_INDEX; + else if (c < ' ') { + currentCode = START_A; + outs += CODE_BC_TO_A; + outs += (char)(c + 64); + } + else { + outs += (char)(c - ' '); + } + } + } + break; + case START_C: + { + if (IsNextDigits(text, index, 2)) { + String out2 = GetPackedRawDigits(text, index, 2); + index += (int)out2[0]; + outs += out2.Substring(1); + } + else { + c = text[index++]; + if (c == FNC1) + outs += FNC1_INDEX; + else if (c < ' ') { + currentCode = START_A; + outs += CODE_BC_TO_A; + outs += (char)(c + 64); + } + else { + currentCode = START_B; + outs += CODE_AC_TO_B; + outs += (char)(c - ' '); + } + } + } + break; + } + } + return outs; + } + + /** Generates the bars. The input has the actual barcodes, not + * the human readable text. + * @param text the barcode + * @return the bars + */ + public static byte[] GetBarsCode128Raw(string text) { + int k; + int idx = text.IndexOf('\uffff'); + if (idx >= 0) + text = text.Substring(0, idx); + int chk = text[0]; + for (k = 1; k < text.Length; ++k) + chk += k * text[k]; + chk = chk % 103; + text += (char)chk; + byte[] bars = new byte[(text.Length + 1) * 6 + 7]; + for (k = 0; k < text.Length; ++k) + Array.Copy(BARS[text[k]], 0, bars, k * 6, 6); + Array.Copy(BARS_STOP, 0, bars, k * 6, 7); + return bars; + } + + /** Gets the maximum area that the barcode and the text, if + * any, will occupy. The lower left corner is always (0, 0). + * @return the size the barcode occupies. + */ + public override Rectangle BarcodeSize { + get { + float fontX = 0; + float fontY = 0; + string fullCode; + if (font != null) { + if (baseline > 0) + fontY = baseline - font.GetFontDescriptor(BaseFont.DESCENT, size); + else + fontY = -baseline + size; + if (codeType == CODE128_RAW) { + int idx = code.IndexOf('\uffff'); + if (idx < 0) + fullCode = ""; + else + fullCode = code.Substring(idx + 1); + } + else if (codeType == CODE128_UCC) + fullCode = GetHumanReadableUCCEAN(code); + else + fullCode = RemoveFNC1(code); + fontX = font.GetWidthPoint(altText != null ? altText : fullCode, size); + } + if (codeType == CODE128_RAW) { + int idx = code.IndexOf('\uffff'); + if (idx >= 0) + fullCode = code.Substring(0, idx); + else + fullCode = code; + } + else { + fullCode = GetRawText(code, codeType == CODE128_UCC); + } + int len = fullCode.Length; + float fullWidth = (len + 2) * 11 * x + 2 * x; + fullWidth = Math.Max(fullWidth, fontX); + float fullHeight = barHeight + fontY; + return new Rectangle(fullWidth, fullHeight); + } + } + + /** Places the barcode in a PdfContentByte. The + * barcode is always placed at coodinates (0, 0). Use the + * translation matrix to move it elsewhere.

    + * The bars and text are written in the following colors:

    + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *

    barColor

    textColor

    Result

    null

    null

    bars and text painted with current fill color

    barColor

    null

    bars and text painted with barColor

    null

    textColor

    bars painted with current color
    text painted with textColor

    barColor

    textColor

    bars painted with barColor
    text painted with textColor

    + * @param cb the PdfContentByte where the barcode will be placed + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the dimensions the barcode occupies + */ + public override Rectangle PlaceBarcode(PdfContentByte cb, Color barColor, Color textColor) { + string fullCode; + if (codeType == CODE128_RAW) { + int idx = code.IndexOf('\uffff'); + if (idx < 0) + fullCode = ""; + else + fullCode = code.Substring(idx + 1); + } + else if (codeType == CODE128_UCC) + fullCode = GetHumanReadableUCCEAN(code); + else + fullCode = RemoveFNC1(code); + float fontX = 0; + if (font != null) { + fontX = font.GetWidthPoint(fullCode = altText != null ? altText : fullCode, size); + } + string bCode; + if (codeType == CODE128_RAW) { + int idx = code.IndexOf('\uffff'); + if (idx >= 0) + bCode = code.Substring(0, idx); + else + bCode = code; + } + else { + bCode = GetRawText(code, codeType == CODE128_UCC); + } + int len = bCode.Length; + float fullWidth = (len + 2) * 11 * x + 2 * x; + float barStartX = 0; + float textStartX = 0; + switch (textAlignment) { + case Element.ALIGN_LEFT: + break; + case Element.ALIGN_RIGHT: + if (fontX > fullWidth) + barStartX = fontX - fullWidth; + else + textStartX = fullWidth - fontX; + break; + default: + if (fontX > fullWidth) + barStartX = (fontX - fullWidth) / 2; + else + textStartX = (fullWidth - fontX) / 2; + break; + } + float barStartY = 0; + float textStartY = 0; + if (font != null) { + if (baseline <= 0) + textStartY = barHeight - baseline; + else { + textStartY = -font.GetFontDescriptor(BaseFont.DESCENT, size); + barStartY = textStartY + baseline; + } + } + byte[] bars = GetBarsCode128Raw(bCode); + bool print = true; + if (barColor != null) + cb.SetColorFill(barColor); + for (int k = 0; k < bars.Length; ++k) { + float w = bars[k] * x; + if (print) + cb.Rectangle(barStartX, barStartY, w - inkSpreading, barHeight); + print = !print; + barStartX += w; + } + cb.Fill(); + if (font != null) { + if (textColor != null) + cb.SetColorFill(textColor); + cb.BeginText(); + cb.SetFontAndSize(font, size); + cb.SetTextMatrix(textStartX, textStartY); + cb.ShowText(fullCode); + cb.EndText(); + } + return this.BarcodeSize; + } + + public override System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + String bCode; + if (codeType == CODE128_RAW) { + int idx = code.IndexOf('\uffff'); + if (idx >= 0) + bCode = code.Substring(0, idx); + else + bCode = code; + } + else { + bCode = GetRawText(code, codeType == CODE128_UCC); + } + int len = bCode.Length; + int fullWidth = (len + 2) * 11 + 2; + byte[] bars = GetBarsCode128Raw(bCode); + int height = (int)barHeight; + System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(fullWidth, height); + for (int h = 0; h < height; ++h) { + bool print = true; + int ptr = 0; + for (int k = 0; k < bars.Length; ++k) { + int w = bars[k]; + System.Drawing.Color c = background; + if (print) + c = foreground; + print = !print; + for (int j = 0; j < w; ++j) + bmp.SetPixel(ptr++, h, c); + } + } + return bmp; + } + + /** + * Sets the code to generate. If it's an UCC code and starts with '(' it will + * be split by the AI. This code in UCC mode is valid: + *

    + * (01)00000090311314(10)ABC123(15)060916 + * @param code the code to generate + */ + public override string Code { + set { + string code = value; + if (CodeType == Barcode128.CODE128_UCC && code.StartsWith("(")) { + int idx = 0; + String ret = ""; + while (idx >= 0) { + int end = code.IndexOf(')', idx); + if (end < 0) + throw new ArgumentException("Badly formed UCC string: " + code); + String sai = code.Substring(idx + 1, end - (idx + 1)); + if (sai.Length < 2) + throw new ArgumentException("AI too short: (" + sai + ")"); + int ai = int.Parse(sai); + int len = ais[ai]; + if (len == 0) + throw new ArgumentException("AI not found: (" + sai + ")"); + sai = ai.ToString(); + if (sai.Length == 1) + sai = "0" + sai; + idx = code.IndexOf('(', end); + int next = (idx < 0 ? code.Length : idx); + ret += sai + code.Substring(end + 1, next - (end + 1)); + if (len < 0) { + if (idx >= 0) + ret += FNC1; + } + else if (next - end - 1 + sai.Length != len) + throw new ArgumentException("Invalid AI length: (" + sai + ")"); + } + base.Code = ret; + } + else + base.Code = code; + } + } + + static Barcode128 () { + ais[0] = 20; + ais[1] = 16; + ais[2] = 16; + ais[10] = -1; + ais[11] = 9; + ais[12] = 8; + ais[13] = 8; + ais[15] = 8; + ais[17] = 8; + ais[20] = 4; + ais[21] = -1; + ais[22] = -1; + ais[23] = -1; + ais[240] = -1; + ais[241] = -1; + ais[250] = -1; + ais[251] = -1; + ais[252] = -1; + ais[30] = -1; + for (int k = 3100; k < 3700; ++k) + ais[k] = 10; + ais[37] = -1; + for (int k = 3900; k < 3940; ++k) + ais[k] = -1; + ais[400] = -1; + ais[401] = -1; + ais[402] = 20; + ais[403] = -1; + for (int k = 410; k < 416; ++k) + ais[k] = 16; + ais[420] = -1; + ais[421] = -1; + ais[422] = 6; + ais[423] = -1; + ais[424] = 6; + ais[425] = 6; + ais[426] = 6; + ais[7001] = 17; + ais[7002] = -1; + for (int k = 7030; k < 7040; ++k) + ais[k] = -1; + ais[8001] = 18; + ais[8002] = -1; + ais[8003] = -1; + ais[8004] = -1; + ais[8005] = 10; + ais[8006] = 22; + ais[8007] = -1; + ais[8008] = -1; + ais[8018] = 22; + ais[8020] = -1; + ais[8100] = 10; + ais[8101] = 14; + ais[8102] = 6; + for (int k = 90; k < 100; ++k) + ais[k] = -1; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/Barcode39.cs b/iTechSharp/iTextSharp/text/pdf/Barcode39.cs new file mode 100644 index 0000000..f93dea7 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/Barcode39.cs @@ -0,0 +1,370 @@ +using System; +using iTextSharp.text; +/* + * $Id: Barcode39.cs,v 1.6 2007/05/03 19:36:07 psoares33 Exp $ + * + * Copyright 2002-2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** Implements the code 39 and code 39 extended. The default parameters are: + *

    +     *x = 0.8f;
    +     *n = 2;
    +     *font = BaseFont.CreateFont("Helvetica", "winansi", false);
    +     *size = 8;
    +     *baseline = size;
    +     *barHeight = size * 3;
    +     *textint= Element.ALIGN_CENTER;
    +     *generateChecksum = false;
    +     *checksumText = false;
    +     *startStopText = true;
    +     *extended = false;
    +     * 
    + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class Barcode39 : Barcode { + + /** The bars to generate the code. + */ + private static readonly byte[][] BARS = + { + new byte[] {0,0,0,1,1,0,1,0,0}, + new byte[] {1,0,0,1,0,0,0,0,1}, + new byte[] {0,0,1,1,0,0,0,0,1}, + new byte[] {1,0,1,1,0,0,0,0,0}, + new byte[] {0,0,0,1,1,0,0,0,1}, + new byte[] {1,0,0,1,1,0,0,0,0}, + new byte[] {0,0,1,1,1,0,0,0,0}, + new byte[] {0,0,0,1,0,0,1,0,1}, + new byte[] {1,0,0,1,0,0,1,0,0}, + new byte[] {0,0,1,1,0,0,1,0,0}, + new byte[] {1,0,0,0,0,1,0,0,1}, + new byte[] {0,0,1,0,0,1,0,0,1}, + new byte[] {1,0,1,0,0,1,0,0,0}, + new byte[] {0,0,0,0,1,1,0,0,1}, + new byte[] {1,0,0,0,1,1,0,0,0}, + new byte[] {0,0,1,0,1,1,0,0,0}, + new byte[] {0,0,0,0,0,1,1,0,1}, + new byte[] {1,0,0,0,0,1,1,0,0}, + new byte[] {0,0,1,0,0,1,1,0,0}, + new byte[] {0,0,0,0,1,1,1,0,0}, + new byte[] {1,0,0,0,0,0,0,1,1}, + new byte[] {0,0,1,0,0,0,0,1,1}, + new byte[] {1,0,1,0,0,0,0,1,0}, + new byte[] {0,0,0,0,1,0,0,1,1}, + new byte[] {1,0,0,0,1,0,0,1,0}, + new byte[] {0,0,1,0,1,0,0,1,0}, + new byte[] {0,0,0,0,0,0,1,1,1}, + new byte[] {1,0,0,0,0,0,1,1,0}, + new byte[] {0,0,1,0,0,0,1,1,0}, + new byte[] {0,0,0,0,1,0,1,1,0}, + new byte[] {1,1,0,0,0,0,0,0,1}, + new byte[] {0,1,1,0,0,0,0,0,1}, + new byte[] {1,1,1,0,0,0,0,0,0}, + new byte[] {0,1,0,0,1,0,0,0,1}, + new byte[] {1,1,0,0,1,0,0,0,0}, + new byte[] {0,1,1,0,1,0,0,0,0}, + new byte[] {0,1,0,0,0,0,1,0,1}, + new byte[] {1,1,0,0,0,0,1,0,0}, + new byte[] {0,1,1,0,0,0,1,0,0}, + new byte[] {0,1,0,1,0,1,0,0,0}, + new byte[] {0,1,0,1,0,0,0,1,0}, + new byte[] {0,1,0,0,0,1,0,1,0}, + new byte[] {0,0,0,1,0,1,0,1,0}, + new byte[] {0,1,0,0,1,0,1,0,0} + }; + + /** The index chars to BARS. + */ + private const string CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%*"; + + /** The character combinations to make the code 39 extended. + */ + private const string EXTENDED = "%U" + + "$A$B$C$D$E$F$G$H$I$J$K$L$M$N$O$P$Q$R$S$T$U$V$W$X$Y$Z" + + "%A%B%C%D%E /A/B/C/D/E/F/G/H/I/J/K/L - ./O" + + " 0 1 2 3 4 5 6 7 8 9/Z%F%G%H%I%J%V" + + " A B C D E F G H I J K L M N O P Q R S T U V W X Y Z" + + "%K%L%M%N%O%W" + + "+A+B+C+D+E+F+G+H+I+J+K+L+M+N+O+P+Q+R+S+T+U+V+W+X+Y+Z" + + "%P%Q%R%S%T"; + + /** Creates a new Barcode39. + */ + public Barcode39() { + x = 0.8f; + n = 2; + font = BaseFont.CreateFont("Helvetica", "winansi", false); + size = 8; + baseline = size; + barHeight = size * 3; + textAlignment = Element.ALIGN_CENTER; + generateChecksum = false; + checksumText = false; + startStopText = true; + extended = false; + } + + /** Creates the bars. + * @param text the text to create the bars. This text does not include the start and + * stop characters + * @return the bars + */ + public static byte[] GetBarsCode39(string text) { + text = "*" + text + "*"; + byte[] bars = new byte[text.Length * 10 - 1]; + for (int k = 0; k < text.Length; ++k) { + int idx = CHARS.IndexOf(text[k]); + if (idx < 0) + throw new ArgumentException("The character '" + text[k] + "' is illegal in code 39."); + Array.Copy(BARS[idx], 0, bars, k * 10, 9); + } + return bars; + } + + /** Converts the extended text into a normal, escaped text, + * ready to generate bars. + * @param text the extended text + * @return the escaped text + */ + public static string GetCode39Ex(string text) { + string ret = ""; + for (int k = 0; k < text.Length; ++k) { + char c = text[k]; + if (c > 127) + throw new ArgumentException("The character '" + c + "' is illegal in code 39 extended."); + char c1 = EXTENDED[c * 2]; + char c2 = EXTENDED[c * 2 + 1]; + if (c1 != ' ') + ret += c1; + ret += c2; + } + return ret; + } + + /** Calculates the checksum. + * @param text the text + * @return the checksum + */ + internal static char GetChecksum(string text) { + int chk = 0; + for (int k = 0; k < text.Length; ++k) { + int idx = CHARS.IndexOf(text[k]); + if (idx < 0) + throw new ArgumentException("The character '" + text[k] + "' is illegal in code 39."); + chk += idx; + } + return CHARS[chk % 43]; + } + + /** Gets the maximum area that the barcode and the text, if + * any, will occupy. The lower left corner is always (0, 0). + * @return the size the barcode occupies. + */ + public override Rectangle BarcodeSize { + get { + float fontX = 0; + float fontY = 0; + string fCode = code; + if (extended) + fCode = GetCode39Ex(code); + if (font != null) { + if (baseline > 0) + fontY = baseline - font.GetFontDescriptor(BaseFont.DESCENT, size); + else + fontY = -baseline + size; + string fullCode = code; + if (generateChecksum && checksumText) + fullCode += GetChecksum(fCode); + if (startStopText) + fullCode = "*" + fullCode + "*"; + fontX = font.GetWidthPoint(altText != null ? altText : fullCode, size); + } + int len = fCode.Length + 2; + if (generateChecksum) + ++len; + float fullWidth = len * (6 * x + 3 * x * n) + (len - 1) * x; + fullWidth = Math.Max(fullWidth, fontX); + float fullHeight = barHeight + fontY; + return new Rectangle(fullWidth, fullHeight); + } + } + + /** Places the barcode in a PdfContentByte. The + * barcode is always placed at coodinates (0, 0). Use the + * translation matrix to move it elsewhere.

    + * The bars and text are written in the following colors:

    + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *

    barColor

    textColor

    Result

    null

    null

    bars and text painted with current fill color

    barColor

    null

    bars and text painted with barColor

    null

    textColor

    bars painted with current color
    text painted with textColor

    barColor

    textColor

    bars painted with barColor
    text painted with textColor

    + * @param cb the PdfContentByte where the barcode will be placed + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the dimensions the barcode occupies + */ + public override Rectangle PlaceBarcode(PdfContentByte cb, Color barColor, Color textColor) { + string fullCode = code; + float fontX = 0; + string bCode = code; + if (extended) + bCode = GetCode39Ex(code); + if (font != null) { + if (generateChecksum && checksumText) + fullCode += GetChecksum(bCode); + if (startStopText) + fullCode = "*" + fullCode + "*"; + fontX = font.GetWidthPoint(fullCode = altText != null ? altText : fullCode, size); + } + if (generateChecksum) + bCode += GetChecksum(bCode); + int len = bCode.Length + 2; + float fullWidth = len * (6 * x + 3 * x * n) + (len - 1) * x; + float barStartX = 0; + float textStartX = 0; + switch (textAlignment) { + case Element.ALIGN_LEFT: + break; + case Element.ALIGN_RIGHT: + if (fontX > fullWidth) + barStartX = fontX - fullWidth; + else + textStartX = fullWidth - fontX; + break; + default: + if (fontX > fullWidth) + barStartX = (fontX - fullWidth) / 2; + else + textStartX = (fullWidth - fontX) / 2; + break; + } + float barStartY = 0; + float textStartY = 0; + if (font != null) { + if (baseline <= 0) + textStartY = barHeight - baseline; + else { + textStartY = -font.GetFontDescriptor(BaseFont.DESCENT, size); + barStartY = textStartY + baseline; + } + } + byte[] bars = GetBarsCode39(bCode); + bool print = true; + if (barColor != null) + cb.SetColorFill(barColor); + for (int k = 0; k < bars.Length; ++k) { + float w = (bars[k] == 0 ? x : x * n); + if (print) + cb.Rectangle(barStartX, barStartY, w - inkSpreading, barHeight); + print = !print; + barStartX += w; + } + cb.Fill(); + if (font != null) { + if (textColor != null) + cb.SetColorFill(textColor); + cb.BeginText(); + cb.SetFontAndSize(font, size); + cb.SetTextMatrix(textStartX, textStartY); + cb.ShowText(fullCode); + cb.EndText(); + } + return this.BarcodeSize; + } + + public override System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + String bCode = code; + if (extended) + bCode = GetCode39Ex(code); + if (generateChecksum) + bCode += GetChecksum(bCode); + int len = bCode.Length + 2; + int nn = (int)n; + int fullWidth = len * (6 + 3 * nn) + (len - 1); + int height = (int)barHeight; + System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(fullWidth, height); + byte[] bars = GetBarsCode39(bCode); + for (int h = 0; h < height; ++h) { + bool print = true; + int ptr = 0; + for (int k = 0; k < bars.Length; ++k) { + int w = (bars[k] == 0 ? 1 : nn); + System.Drawing.Color c = background; + if (print) + c = foreground; + print = !print; + for (int j = 0; j < w; ++j) + bmp.SetPixel(ptr++, h, c); + } + } + return bmp; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BarcodeCodabar.cs b/iTechSharp/iTextSharp/text/pdf/BarcodeCodabar.cs new file mode 100644 index 0000000..d80ab49 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BarcodeCodabar.cs @@ -0,0 +1,324 @@ +using System; +using iTextSharp.text; +/* + * $Id: BarcodeCodabar.cs,v 1.7 2007/02/22 20:48:38 psoares33 Exp $ + * + * Copyright 2002-2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf +{ + /** Implements the code codabar. The default parameters are: + *

    +    *x = 0.8f;
    +    *n = 2;
    +    *font = BaseFont.CreateFont("Helvetica", "winansi", false);
    +    *size = 8;
    +    *baseline = size;
    +    *barHeight = size * 3;
    +    *textAlignment = Element.ALIGN_CENTER;
    +    *generateChecksum = false;
    +    *checksumText = false;
    +    *startStopText = false;
    +    * 
    + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class BarcodeCodabar : Barcode{ + + /** The bars to generate the code. + */ + private static readonly byte[][] BARS = new byte[][] { + new byte[]{0,0,0,0,0,1,1}, // 0 + new byte[]{0,0,0,0,1,1,0}, // 1 + new byte[]{0,0,0,1,0,0,1}, // 2 + new byte[]{1,1,0,0,0,0,0}, // 3 + new byte[]{0,0,1,0,0,1,0}, // 4 + new byte[]{1,0,0,0,0,1,0}, // 5 + new byte[]{0,1,0,0,0,0,1}, // 6 + new byte[]{0,1,0,0,1,0,0}, // 7 + new byte[]{0,1,1,0,0,0,0}, // 8 + new byte[]{1,0,0,1,0,0,0}, // 9 + new byte[]{0,0,0,1,1,0,0}, // - + new byte[]{0,0,1,1,0,0,0}, // $ + new byte[]{1,0,0,0,1,0,1}, // : + new byte[]{1,0,1,0,0,0,1}, // / + new byte[]{1,0,1,0,1,0,0}, // . + new byte[]{0,0,1,0,1,0,1}, // + + new byte[]{0,0,1,1,0,1,0}, // a + new byte[]{0,1,0,1,0,0,1}, // b + new byte[]{0,0,0,1,0,1,1}, // c + new byte[]{0,0,0,1,1,1,0} // d + }; + + /** The index chars to BARS. + */ + private const string CHARS = "0123456789-$:/.+ABCD"; + + private const int START_STOP_IDX = 16; + /** Creates a new BarcodeCodabar. + */ + public BarcodeCodabar() { + x = 0.8f; + n = 2; + font = BaseFont.CreateFont("Helvetica", "winansi", false); + size = 8; + baseline = size; + barHeight = size * 3; + textAlignment = Element.ALIGN_CENTER; + generateChecksum = false; + checksumText = false; + startStopText = false; + codeType = CODABAR; + } + + /** Creates the bars. + * @param text the text to create the bars + * @return the bars + */ + public static byte[] GetBarsCodabar(String text) { + text = text.ToUpper(System.Globalization.CultureInfo.InvariantCulture); + int len = text.Length; + if (len < 2) + throw new ArgumentException("Codabar must have at least a start and stop character."); + if (CHARS.IndexOf(text[0]) < START_STOP_IDX || CHARS.IndexOf(text[len - 1]) < START_STOP_IDX) + throw new ArgumentException("Codabar must have one of 'ABCD' as start/stop character."); + byte[] bars = new byte[text.Length * 8 - 1]; + for (int k = 0; k < len; ++k) { + int idx = CHARS.IndexOf(text[k]); + if (idx >= START_STOP_IDX && k > 0 && k < len - 1) + throw new ArgumentException("In codabar, start/stop characters are only allowed at the extremes."); + if (idx < 0) + throw new ArgumentException("The character '" + text[k] + "' is illegal in codabar."); + Array.Copy(BARS[idx], 0, bars, k * 8, 7); + } + return bars; + } + + public static String CalculateChecksum(String code) { + if (code.Length < 2) + return code; + String text = code.ToUpper(System.Globalization.CultureInfo.InvariantCulture); + int sum = 0; + int len = text.Length; + for (int k = 0; k < len; ++k) + sum += CHARS.IndexOf(text[k]); + sum = (sum + 15) / 16 * 16 - sum; + return code.Substring(0, len - 1) + CHARS[sum] + code.Substring(len - 1); + } + + /** Gets the maximum area that the barcode and the text, if + * any, will occupy. The lower left corner is always (0, 0). + * @return the size the barcode occupies. + */ + public override Rectangle BarcodeSize { + get { + float fontX = 0; + float fontY = 0; + String text = code; + if (generateChecksum && checksumText) + text = CalculateChecksum(code); + if (!startStopText) + text = text.Substring(1, text.Length - 2); + if (font != null) { + if (baseline > 0) + fontY = baseline - font.GetFontDescriptor(BaseFont.DESCENT, size); + else + fontY = -baseline + size; + fontX = font.GetWidthPoint(altText != null ? altText : text, size); + } + text = code; + if (generateChecksum) + text = CalculateChecksum(code); + byte[] bars = GetBarsCodabar(text); + int wide = 0; + for (int k = 0; k < bars.Length; ++k) { + wide += (int)bars[k]; + } + int narrow = bars.Length - wide; + float fullWidth = x * (narrow + wide * n); + fullWidth = Math.Max(fullWidth, fontX); + float fullHeight = barHeight + fontY; + return new Rectangle(fullWidth, fullHeight); + } + } + + /** Places the barcode in a PdfContentByte. The + * barcode is always placed at coodinates (0, 0). Use the + * translation matrix to move it elsewhere.

    + * The bars and text are written in the following colors:

    + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *

    barColor

    textColor

    Result

    null

    null

    bars and text painted with current fill color

    barColor

    null

    bars and text painted with barColor

    null

    textColor

    bars painted with current color
    text painted with textColor

    barColor

    textColor

    bars painted with barColor
    text painted with textColor

    + * @param cb the PdfContentByte where the barcode will be placed + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the dimensions the barcode occupies + */ + public override Rectangle PlaceBarcode(PdfContentByte cb, Color barColor, Color textColor) { + String fullCode = code; + if (generateChecksum && checksumText) + fullCode = CalculateChecksum(code); + if (!startStopText) + fullCode = fullCode.Substring(1, fullCode.Length - 2); + float fontX = 0; + if (font != null) { + fontX = font.GetWidthPoint(fullCode = altText != null ? altText : fullCode, size); + } + byte[] bars = GetBarsCodabar(generateChecksum ? CalculateChecksum(code) : code); + int wide = 0; + for (int k = 0; k < bars.Length; ++k) { + wide += (int)bars[k]; + } + int narrow = bars.Length - wide; + float fullWidth = x * (narrow + wide * n); + float barStartX = 0; + float textStartX = 0; + switch (textAlignment) { + case Element.ALIGN_LEFT: + break; + case Element.ALIGN_RIGHT: + if (fontX > fullWidth) + barStartX = fontX - fullWidth; + else + textStartX = fullWidth - fontX; + break; + default: + if (fontX > fullWidth) + barStartX = (fontX - fullWidth) / 2; + else + textStartX = (fullWidth - fontX) / 2; + break; + } + float barStartY = 0; + float textStartY = 0; + if (font != null) { + if (baseline <= 0) + textStartY = barHeight - baseline; + else { + textStartY = -font.GetFontDescriptor(BaseFont.DESCENT, size); + barStartY = textStartY + baseline; + } + } + bool print = true; + if (barColor != null) + cb.SetColorFill(barColor); + for (int k = 0; k < bars.Length; ++k) { + float w = (bars[k] == 0 ? x : x * n); + if (print) + cb.Rectangle(barStartX, barStartY, w - inkSpreading, barHeight); + print = !print; + barStartX += w; + } + cb.Fill(); + if (font != null) { + if (textColor != null) + cb.SetColorFill(textColor); + cb.BeginText(); + cb.SetFontAndSize(font, size); + cb.SetTextMatrix(textStartX, textStartY); + cb.ShowText(fullCode); + cb.EndText(); + } + return BarcodeSize; + } + + public override System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + String fullCode = code; + if (generateChecksum && checksumText) + fullCode = CalculateChecksum(code); + if (!startStopText) + fullCode = fullCode.Substring(1, fullCode.Length - 2); + byte[] bars = GetBarsCodabar(generateChecksum ? CalculateChecksum(code) : code); + int wide = 0; + for (int k = 0; k < bars.Length; ++k) { + wide += (int)bars[k]; + } + int narrow = bars.Length - wide; + int fullWidth = narrow + wide * (int)n; + int height = (int)barHeight; + System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(fullWidth, height); + for (int h = 0; h < height; ++h) { + bool print = true; + int ptr = 0; + for (int k = 0; k < bars.Length; ++k) { + int w = (bars[k] == 0 ? 1 : (int)n); + System.Drawing.Color c = background; + if (print) + c = foreground; + print = !print; + for (int j = 0; j < w; ++j) + bmp.SetPixel(ptr++, h, c); + } + } + return bmp; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BarcodeDatamatrix.cs b/iTechSharp/iTextSharp/text/pdf/BarcodeDatamatrix.cs new file mode 100644 index 0000000..48e5e1d --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BarcodeDatamatrix.cs @@ -0,0 +1,1265 @@ +using System; +using iTextSharp.text; +using iTextSharp.text.pdf.codec; +using System.Collections; +/* + * $Id: BarcodeDatamatrix.cs,v 1.3 2007/05/21 10:56:38 psoares33 Exp $ + * + * Copyright 2007 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + public class BarcodeDatamatrix { + /** + * No error. + */ + public const int DM_NO_ERROR = 0; + /** + * The text is too big for the symbology capabilities. + */ + public const int DM_ERROR_TEXT_TOO_BIG = 1; + /** + * The dimensions given for the symbol are illegal. + */ + public const int DM_ERROR_INVALID_SQUARE = 3; + /** + * An error while parsing an extension. + */ + public const int DM_ERROR_EXTENSION = 5; + + /** + * The best encodation will be used. + */ + public const int DM_AUTO = 0; + /** + * ASCII encodation. + */ + public const int DM_ASCII = 1; + /** + * C40 encodation. + */ + public const int DM_C40 = 2; + /** + * TEXT encodation. + */ + public const int DM_TEXT = 3; + /** + * Binary encodation. + */ + public const int DM_B256 = 4; + /** + * X21 encodation. + */ + public const int DM_X21 = 5; + /** + * EDIFACT encodation. + */ + public const int DM_EDIFACT = 6; + /** + * No encodation needed. The bytes provided are already encoded. + */ + public const int DM_RAW = 7; + + /** + * Allows extensions to be embedded at the start of the text. + */ + public const int DM_EXTENSION = 32; + /** + * Doesn't generate the image but returns all the other information. + */ + public const int DM_TEST = 64; + + private static readonly DmParams[] dmSizes = { + new DmParams(10, 10, 10, 10, 3, 3, 5), + new DmParams(12, 12, 12, 12, 5, 5, 7), + new DmParams(8, 18, 8, 18, 5, 5, 7), + new DmParams(14, 14, 14, 14, 8, 8, 10), + new DmParams(8, 32, 8, 16, 10, 10, 11), + new DmParams(16, 16, 16, 16, 12, 12, 12), + new DmParams(12, 26, 12, 26, 16, 16, 14), + new DmParams(18, 18, 18, 18, 18, 18, 14), + new DmParams(20, 20, 20, 20, 22, 22, 18), + new DmParams(12, 36, 12, 18, 22, 22, 18), + new DmParams(22, 22, 22, 22, 30, 30, 20), + new DmParams(16, 36, 16, 18, 32, 32, 24), + new DmParams(24, 24, 24, 24, 36, 36, 24), + new DmParams(26, 26, 26, 26, 44, 44, 28), + new DmParams(16, 48, 16, 24, 49, 49, 28), + new DmParams(32, 32, 16, 16, 62, 62, 36), + new DmParams(36, 36, 18, 18, 86, 86, 42), + new DmParams(40, 40, 20, 20, 114, 114, 48), + new DmParams(44, 44, 22, 22, 144, 144, 56), + new DmParams(48, 48, 24, 24, 174, 174, 68), + new DmParams(52, 52, 26, 26, 204, 102, 42), + new DmParams(64, 64, 16, 16, 280, 140, 56), + new DmParams(72, 72, 18, 18, 368, 92, 36), + new DmParams(80, 80, 20, 20, 456, 114, 48), + new DmParams(88, 88, 22, 22, 576, 144, 56), + new DmParams(96, 96, 24, 24, 696, 174, 68), + new DmParams(104, 104, 26, 26, 816, 136, 56), + new DmParams(120, 120, 20, 20, 1050, 175, 68), + new DmParams(132, 132, 22, 22, 1304, 163, 62), + new DmParams(144, 144, 24, 24, 1558, 156, 62)}; + + private const String x12 = "\r*> 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + private int extOut; + private short[] place; + private byte[] image; + private int height; + private int width; + private int ws; + private int options; + + /** + * Creates an instance of this class. + */ + public BarcodeDatamatrix() { + } + + private void SetBit(int x, int y, int xByte) { + image[y * xByte + x / 8] |= (byte)(128 >> (x & 7)); + } + + private void Draw(byte[] data, int dataSize, DmParams dm) { + int i, j, p, x, y, xs, ys, z; + int xByte = (dm.width + ws * 2 + 7) / 8; + for (int k = 0; k < image.Length; ++k) + image[k] = 0; + //alignment patterns + //dotted horizontal line + for (i = ws; i < dm.height + ws; i += dm.heightSection) { + for (j = ws; j < dm.width + ws; j += 2) { + SetBit(j, i, xByte); + } + } + //solid horizontal line + for (i = dm.heightSection - 1 + ws; i < dm.height + ws; i += dm.heightSection) { + for (j = ws; j < dm.width + ws; ++j) { + SetBit(j, i, xByte); + } + } + //solid vertical line + for (i = ws; i < dm.width + ws; i += dm.widthSection) { + for (j = ws; j < dm.height + ws; ++j) { + SetBit(i, j, xByte); + } + } + //dotted vertical line + for (i = dm.widthSection - 1 + ws; i < dm.width + ws; i += dm.widthSection) { + for (j = 1 + ws; j < dm.height + ws; j += 2) { + SetBit(i, j, xByte); + } + } + p = 0; + for (ys = 0; ys < dm.height; ys += dm.heightSection) { + for (y = 1; y < dm.heightSection - 1; ++y) { + for (xs = 0; xs < dm.width; xs += dm.widthSection) { + for (x = 1; x < dm.widthSection - 1; ++x) { + z = place[p++]; + if (z == 1 || (z > 1 && ((data[z/8-1] & 0xff) & (128 >> (z%8))) != 0)) + SetBit(x + xs + ws, y + ys + ws, xByte); + } + } + } + } + } + + private static void MakePadding(byte[] data, int position, int count) { + //already in ascii mode + if (count <= 0) + return; + data[position++] = (byte)129; + while (--count > 0) { + int t = 129 + (((position + 1) * 149) % 253) + 1; + if (t > 254) + t -= 254; + data[position++] = (byte)t; + } + } + + private static bool IsDigit(int c) { + return c >= '0' && c <= '9'; + } + + private static int AsciiEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength) { + int ptrIn, ptrOut, c; + ptrIn = textOffset; + ptrOut = dataOffset; + textLength += textOffset; + dataLength += dataOffset; + while (ptrIn < textLength) { + if (ptrOut >= dataLength) + return -1; + c = text[ptrIn++] & 0xff; + if (IsDigit(c) && ptrIn < textLength && IsDigit(text[ptrIn] & 0xff)) { + data[ptrOut++] = (byte)((c - '0') * 10 + (text[ptrIn++] & 0xff) - '0' + 130); + } + else if (c > 127) { + if (ptrOut + 1 >= dataLength) + return -1; + data[ptrOut++] = (byte)235; + data[ptrOut++] = (byte)(c - 128 + 1); + } + else { + data[ptrOut++] = (byte)(c + 1); + } + } + return ptrOut - dataOffset; + } + + private static int B256Encodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength) { + int k, j, prn, tv, c; + if (textLength == 0) + return 0; + if (textLength < 250 && textLength + 2 > dataLength) + return -1; + if (textLength >= 250 && textLength + 3 > dataLength) + return -1; + data[dataOffset] = (byte)231; + if (textLength < 250) { + data[dataOffset + 1] = (byte)textLength; + k = 2; + } + else { + data[dataOffset + 1] = (byte)(textLength / 250 + 249); + data[dataOffset + 2] = (byte)(textLength % 250); + k = 3; + } + System.Array.Copy(text, textOffset, data, k + dataOffset, textLength); + k += textLength + dataOffset; + for (j = dataOffset + 1; j < k; ++j) { + c = data[j] & 0xff; + prn = ((149 * (j + 1)) % 255) + 1; + tv = c + prn; + if (tv > 255) + tv -= 256; + data[j] = (byte)tv; + + } + return k - dataOffset; + } + + private static int X12Encodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength) { + int ptrIn, ptrOut, count, k, n, ci; + byte c; + if (textLength == 0) + return 0; + ptrIn = 0; + ptrOut = 0; + byte[] x = new byte[textLength]; + count = 0; + for (; ptrIn < textLength; ++ptrIn) { + int i = x12.IndexOf((char)text[ptrIn + textOffset]); + if (i >= 0) { + x[ptrIn] = (byte)i; + ++count; + } + else { + x[ptrIn] = 100; + if (count >= 6) + count -= (count / 3) * 3; + for (k = 0; k < count; ++k) + x[ptrIn - k - 1] = 100; + count = 0; + } + } + if (count >= 6) + count -= (count / 3) * 3; + for (k = 0; k < count; ++k) + x[ptrIn - k - 1] = 100; + ptrIn = 0; + c = 0; + for (; ptrIn < textLength; ++ptrIn) { + c = x[ptrIn]; + if (ptrOut >= dataLength) + break; + if (c < 40) { + if (ptrIn == 0 || (ptrIn > 0 && x[ptrIn - 1] > 40)) + data[dataOffset + ptrOut++] = (byte)238; + if (ptrOut + 2 > dataLength) + break; + n = 1600 * x[ptrIn] + 40 * x[ptrIn + 1] + x[ptrIn + 2] + 1; + data[dataOffset + ptrOut++] = (byte)(n / 256); + data[dataOffset + ptrOut++] = (byte)n; + ptrIn += 2; + } + else { + if (ptrIn > 0 && x[ptrIn - 1] < 40) + data[dataOffset + ptrOut++] = (byte)254; + ci = text[ptrIn + textOffset] & 0xff; + if (ci > 127) { + data[dataOffset + ptrOut++] = (byte)235; + ci -= 128; + } + if (ptrOut >= dataLength) + break; + data[dataOffset + ptrOut++] = (byte)(ci + 1); + } + } + c = 100; + if (textLength > 0) + c = x[textLength - 1]; + if (ptrIn != textLength || (c < 40 && ptrOut >= dataLength)) + return -1; + if (c < 40) + data[dataOffset + ptrOut++] = (byte)(254); + return ptrOut; + } + + private static int EdifactEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength) { + int ptrIn, ptrOut, edi, pedi, c; + if (textLength == 0) + return 0; + ptrIn = 0; + ptrOut = 0; + edi = 0; + pedi = 18; + bool ascii = true; + for (; ptrIn < textLength; ++ptrIn) { + c = text[ptrIn + textOffset] & 0xff; + if (((c & 0xe0) == 0x40 || (c & 0xe0) == 0x20) && c != '_') { + if (ascii) { + if (ptrOut + 1 > dataLength) + break; + data[dataOffset + ptrOut++] = (byte)240; + ascii = false; + } + c &= 0x3f; + edi |= c << pedi; + if (pedi == 0) { + if (ptrOut + 3 > dataLength) + break; + data[dataOffset + ptrOut++] = (byte)(edi >> 16); + data[dataOffset + ptrOut++] = (byte)(edi >> 8); + data[dataOffset + ptrOut++] = (byte)edi; + edi = 0; + pedi = 18; + } + else + pedi -= 6; + } + else { + if (!ascii) { + edi |= ('_' & 0x3f) << pedi; + if (ptrOut + (3 - pedi / 8) > dataLength) + break; + data[dataOffset + ptrOut++] = (byte)(edi >> 16); + if (pedi <= 12) + data[dataOffset + ptrOut++] = (byte)(edi >> 8); + if (pedi <= 6) + data[dataOffset + ptrOut++] = (byte)edi; + ascii = true; + pedi = 18; + edi = 0; + } + if (c > 127) { + if (ptrOut >= dataLength) + break; + data[dataOffset + ptrOut++] = (byte)235; + c -= 128; + } + if (ptrOut >= dataLength) + break; + data[dataOffset + ptrOut++] = (byte)(c + 1); + } + } + if (ptrIn != textLength) + return -1; + if (!ascii) { + edi |= ('_' & 0x3f) << pedi; + if (ptrOut + (3 - pedi / 8) > dataLength) + return -1; + data[dataOffset + ptrOut++] = (byte)(edi >> 16); + if (pedi <= 12) + data[dataOffset + ptrOut++] = (byte)(edi >> 8); + if (pedi <= 6) + data[dataOffset + ptrOut++] = (byte)edi; + } + return ptrOut; + } + + private static int C40OrTextEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength, bool c40) { + int ptrIn, ptrOut, encPtr, last0, last1, i, a, c; + String basic, shift2, shift3; + if (textLength == 0) + return 0; + ptrIn = 0; + ptrOut = 0; + if (c40) + data[dataOffset + ptrOut++] = (byte)230; + else + data[dataOffset + ptrOut++] = (byte)239; + shift2 = "!\"#$%&'()*+,-./:;<=>?@[\\]^_"; + if (c40) { + basic = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + shift3 = "`abcdefghijklmnopqrstuvwxyz{|}~\u007f"; + } + else { + basic = " 0123456789abcdefghijklmnopqrstuvwxyz"; + shift3 = "`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~\u007f"; + } + int[] enc = new int[textLength * 4 + 10]; + encPtr = 0; + last0 = 0; + last1 = 0; + while (ptrIn < textLength) { + if ((encPtr % 3) == 0) { + last0 = ptrIn; + last1 = encPtr; + } + c = text[textOffset + ptrIn++] & 0xff; + if (c > 127) { + c -= 128; + enc[encPtr++] = 1; + enc[encPtr++] = 30; + } + int idx = basic.IndexOf((char)c); + if (idx >= 0) { + enc[encPtr++] = idx + 3; + } + else if (c < 32) { + enc[encPtr++] = 0; + enc[encPtr++] = c; + } + else if ((idx = shift2.IndexOf((char)c)) >= 0) { + enc[encPtr++] = 1; + enc[encPtr++] = idx; + } + else if ((idx = shift3.IndexOf((char)c)) >= 0) { + enc[encPtr++] = 2; + enc[encPtr++] = idx; + } + } + if ((encPtr % 3) != 0) { + ptrIn = last0; + encPtr = last1; + } + if (encPtr / 3 * 2 > dataLength - 2) { + return -1; + } + i = 0; + for (; i < encPtr; i += 3) { + a = 1600 * enc[i] + 40 * enc[i + 1] + enc[i + 2] + 1; + data[dataOffset + ptrOut++] = (byte)(a / 256); + data[dataOffset + ptrOut++] = (byte)a; + } + data[ptrOut++] = (byte)254; + i = AsciiEncodation(text, ptrIn, textLength - ptrIn, data, ptrOut, dataLength - ptrOut); + if (i < 0) + return i; + return ptrOut + i; + } + + private static int GetEncodation(byte[] text, int textOffset, int textSize, byte[] data, int dataOffset, int dataSize, int options, bool firstMatch) { + int e, j, k; + int[] e1 = new int[6]; + if (dataSize < 0) + return -1; + e = -1; + options &= 7; + if (options == 0) { + e1[0] = AsciiEncodation(text, textOffset, textSize, data, dataOffset, dataSize); + if (firstMatch && e1[0] >= 0) + return e1[0]; + e1[1] = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, false); + if (firstMatch && e1[1] >= 0) + return e1[1]; + e1[2] = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, true); + if (firstMatch && e1[2] >= 0) + return e1[2]; + e1[3] = B256Encodation(text, textOffset, textSize, data, dataOffset, dataSize); + if (firstMatch && e1[3] >= 0) + return e1[3]; + e1[4] = X12Encodation(text, textOffset, textSize, data, dataOffset, dataSize); + if (firstMatch && e1[4] >= 0) + return e1[4]; + e1[5] = EdifactEncodation(text, textOffset, textSize, data, dataOffset, dataSize); + if (firstMatch && e1[5] >= 0) + return e1[5]; + if (e1[0] < 0 && e1[1] < 0 && e1[2] < 0 && e1[3] < 0 && e1[4] < 0 && e1[5] < 0) { + return -1; + } + j = 0; + e = 99999; + for (k = 0; k < 6; ++k) { + if (e1[k] >= 0 && e1[k] < e) { + e = e1[k]; + j = k; + } + } + if (j == 0) + e = AsciiEncodation(text, textOffset, textSize, data, dataOffset, dataSize); + else if (j == 1) + e = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, false); + else if (j == 2) + e = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, true); + else if (j == 3) + e = B256Encodation(text, textOffset, textSize, data, dataOffset, dataSize); + else if (j == 4) + e = X12Encodation(text, textOffset, textSize, data, dataOffset, dataSize); + return e; + } + switch (options) { + case DM_ASCII: + return AsciiEncodation(text, textOffset, textSize, data, dataOffset, dataSize); + case DM_C40: + return C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, true); + case DM_TEXT: + return C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, false); + case DM_B256: + return B256Encodation(text, textOffset, textSize, data, dataOffset, dataSize); + case DM_X21: + return X12Encodation(text, textOffset, textSize, data, dataOffset, dataSize); + case DM_EDIFACT: + return EdifactEncodation(text, textOffset, textSize, data, dataOffset, dataSize); + case DM_RAW: + if (textSize > dataSize) + return -1; + System.Array.Copy(text, textOffset, data, dataOffset, textSize); + return textSize; + } + return -1; + } + + private static int GetNumber(byte[] text, int ptrIn, int n) { + int v, j, c; + v = 0; + for (j = 0; j < n; ++j) { + c = text[ptrIn++] &0xff; + if (c < '0' || c > '9') + return -1; + v = v * 10 + c - '0'; + } + return v; + } + + private int ProcessExtensions(byte[] text, int textOffset, int textSize, byte[] data) { + int order, ptrIn, ptrOut, eci, fn, ft, fi, c; + if ((options & DM_EXTENSION) == 0) + return 0; + order = 0; + ptrIn = 0; + ptrOut = 0; + while (ptrIn < textSize) { + if (order > 20) + return -1; + c = text[textOffset + ptrIn++] &0xff; + ++order; + switch (c) { + case '.': + extOut = ptrIn; + return ptrOut; + case 'e': + if (ptrIn + 6 > textSize) + return -1; + eci = GetNumber(text, textOffset + ptrIn, 6); + if (eci < 0) + return -1; + ptrIn += 6; + data[ptrOut++] = (byte)241; + if (eci < 127) + data[ptrOut++] = (byte)(eci + 1); + else if (eci < 16383) { + data[ptrOut++] = (byte)((eci - 127) / 254 + 128); + data[ptrOut++] = (byte)(((eci - 127) % 254) + 1); + } + else { + data[ptrOut++] = (byte)((eci - 16383) / 64516 + 192); + data[ptrOut++] = (byte)((((eci - 16383) / 254) % 254) + 1); + data[ptrOut++] = (byte)(((eci - 16383) % 254) + 1); + } + break; + case 's': + if (order != 1) + return -1; + if (ptrIn + 9 > textSize) + return -1; + fn = GetNumber(text, textOffset + ptrIn, 2); + if (fn <= 0 || fn > 16) + return -1; + ptrIn += 2; + ft = GetNumber(text, textOffset + ptrIn, 2); + if (ft <= 1 || ft > 16) + return -1; + ptrIn += 2; + fi = GetNumber(text, textOffset + ptrIn, 5); + if (fi < 0 || fn >= 64516) + return -1; + ptrIn += 5; + data[ptrOut++] = (byte)(233); + data[ptrOut++] = (byte)(((fn - 1) << 4) | (17 - ft)); + data[ptrOut++] = (byte)(fi / 254 + 1); + data[ptrOut++] = (byte)((fi % 254) + 1); + break; + case 'p': + if (order != 1) + return -1; + data[ptrOut++] = (byte)(234); + break; + case 'm': + if (order != 1) + return -1; + if (ptrIn + 1 > textSize) + return -1; + c = text[textOffset + ptrIn++] &0xff; + if (c != '5' && c != '5') + return -1; + data[ptrOut++] = (byte)(234); + data[ptrOut++] = (byte)(c == '5' ? 236 : 237); + break; + case 'f': + if (order != 1 && (order != 2 || (text[textOffset] != 's' && text[textOffset] != 'm'))) + return -1; + data[ptrOut++] = (byte)(232); + break; + } + } + return -1; + } + + /** + * Creates a barcode. The String is interpreted with the ISO-8859-1 encoding + * @param text the text + * @return the status of the generation. It can be one of this values: + *

    + * DM_NO_ERROR - no error.
    + * DM_ERROR_TEXT_TOO_BIG - the text is too big for the symbology capabilities.
    + * DM_ERROR_INVALID_SQUARE - the dimensions given for the symbol are illegal.
    + * DM_ERROR_EXTENSION - an error was while parsing an extension. + * @throws java.io.UnsupportedEncodingException on error + */ + public int Generate(String text) { + byte[] t = System.Text.Encoding.GetEncoding(1252).GetBytes(text); + return Generate(t, 0, t.Length); + } + + /** + * Creates a barcode. + * @param text the text + * @param textOffset the offset to the start of the text + * @param textSize the text size + * @return the status of the generation. It can be one of this values: + *

    + * DM_NO_ERROR - no error.
    + * DM_ERROR_TEXT_TOO_BIG - the text is too big for the symbology capabilities.
    + * DM_ERROR_INVALID_SQUARE - the dimensions given for the symbol are illegal.
    + * DM_ERROR_EXTENSION - an error was while parsing an extension. + */ + public int Generate(byte[] text, int textOffset, int textSize) { + int extCount, e, k, full; + DmParams dm, last; + byte[] data = new byte[2500]; + extOut = 0; + extCount = ProcessExtensions(text, textOffset, textSize, data); + if (extCount < 0) { + return DM_ERROR_EXTENSION; + } + e = -1; + if (height == 0 || width == 0) { + last = dmSizes[dmSizes.Length - 1]; + e = GetEncodation(text, textOffset + extOut, textSize - extOut, data, extCount, last.dataSize - extCount, options, false); + if (e < 0) { + return DM_ERROR_TEXT_TOO_BIG; + } + e += extCount; + for (k = 0; k < dmSizes.Length; ++k) { + if (dmSizes[k].dataSize >= e) + break; + } + dm = dmSizes[k]; + height = dm.height; + width = dm.width; + } + else { + for (k = 0; k < dmSizes.Length; ++k) { + if (height == dmSizes[k].height && width == dmSizes[k].width) + break; + } + if (k == dmSizes.Length) { + return DM_ERROR_INVALID_SQUARE; + } + dm = dmSizes[k]; + e = GetEncodation(text, textOffset + extOut, textSize - extOut, data, extCount, dm.dataSize - extCount, options, true); + if (e < 0) { + return DM_ERROR_TEXT_TOO_BIG; + } + e += extCount; + } + if ((options & DM_TEST) != 0) { + return DM_NO_ERROR; + } + image = new byte[(((dm.width + 2 * ws) + 7) / 8) * (dm.height + 2 * ws)]; + MakePadding(data, e, dm.dataSize - e); + place = Placement.DoPlacement(dm.height - (dm.height / dm.heightSection * 2), dm.width - (dm.width / dm.widthSection * 2)); + full = dm.dataSize + ((dm.dataSize + 2) / dm.dataBlock) * dm.errorBlock; + ReedSolomon.GenerateECC(data, dm.dataSize, dm.dataBlock, dm.errorBlock); + Draw(data, full, dm); + return DM_NO_ERROR; + } + + /** Gets an Image with the barcode. A successful call to the method generate() + * before calling this method is required. + * @return the barcode Image + * @throws BadElementException on error + */ + public Image CreateImage() { + if (image == null) + return null; + byte[] g4 = CCITTG4Encoder.Compress(image, width + 2 * ws, height + 2 * ws); + return Image.GetInstance(width + 2 * ws, height + 2 * ws, false, Image.CCITTG4, 0, g4, null); + } + + /** + * Creates a java.awt.Image. A successful call to the method generate() + * before calling this method is required. + * @param foreground the color of the bars + * @param background the color of the background + * @return the image + */ + public virtual System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + if (image == null) + return null; + int h = height + 2 * ws; + int w = width + 2 * ws; + int stride = (w + 7) / 8; + System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(w, h); + for (int k = 0; k < h; ++k) { + int p = k * stride; + for (int j = 0; j < w; ++j) { + int b = image[p + (j / 8)] & 0xff; + b <<= j % 8; + bmp.SetPixel(j, k, (b & 0x80) == 0 ? background : foreground); + } + } + return bmp; + } + + private class DmParams { + internal DmParams(int height, int width, int heightSection, int widthSection, int dataSize, int dataBlock, int errorBlock) { + this.height = height; + this.width = width; + this.heightSection = heightSection; + this.widthSection = widthSection; + this.dataSize = dataSize; + this.dataBlock = dataBlock; + this.errorBlock = errorBlock; + } + + internal int height; + internal int width; + internal int heightSection; + internal int widthSection; + internal int dataSize; + internal int dataBlock; + internal int errorBlock; + }; + + /** + * Gets the generated image. The image is represented as a stream of bytes, each byte representing + * 8 pixels, 0 for white and 1 for black, with the high-order bit of each byte first. Each row + * is aligned at byte boundaries. The dimensions of the image are defined by height and width + * plus 2 * ws. + * @return the generated image + */ + public byte[] BitImage { + get { + return image; + } + } + + /** + * Gets/sets the height of the barcode. If the height is zero it will be calculated. This height doesn't include the whitespace border, if any. + *

    + * The allowed dimensions are (height, width):

    + * 10, 10
    + * 12, 12
    + * 8, 18
    + * 14, 14
    + * 8, 32
    + * 16, 16
    + * 12, 26
    + * 18, 18
    + * 20, 20
    + * 12, 36
    + * 22, 22
    + * 16, 36
    + * 24, 24
    + * 26, 26
    + * 16, 48
    + * 32, 32
    + * 36, 36
    + * 40, 40
    + * 44, 44
    + * 48, 48
    + * 52, 52
    + * 64, 64
    + * 72, 72
    + * 80, 80
    + * 88, 88
    + * 96, 96
    + * 104, 104
    + * 120, 120
    + * 132, 132
    + * 144, 144
    + * @param height the height of the barcode + */ + public int Height { + get { + return height; + } + set { + height = value; + } + } + + /** + * Gets/sets the width of the barcode. If the width is zero it will be calculated. This width doesn't include the whitespace border, if any. + *

    + * The allowed dimensions are (height, width):

    + * 10, 10
    + * 12, 12
    + * 8, 18
    + * 14, 14
    + * 8, 32
    + * 16, 16
    + * 12, 26
    + * 18, 18
    + * 20, 20
    + * 12, 36
    + * 22, 22
    + * 16, 36
    + * 24, 24
    + * 26, 26
    + * 16, 48
    + * 32, 32
    + * 36, 36
    + * 40, 40
    + * 44, 44
    + * 48, 48
    + * 52, 52
    + * 64, 64
    + * 72, 72
    + * 80, 80
    + * 88, 88
    + * 96, 96
    + * 104, 104
    + * 120, 120
    + * 132, 132
    + * 144, 144
    + * @param width the width of the barcode + */ + public int Width { + get { + return width; + } + set { + width = value; + } + } + + /** + * Gets/sets the whitespace border around the barcode. + * @param ws the whitespace border around the barcode + */ + public int Ws { + get { + return ws; + } + set { + ws = value; + } + } + + /** + * Gets/sets the options for the barcode generation. The options can be:

    + * One of:
    + * DM_AUTO - the best encodation will be used
    + * DM_ASCII - ASCII encodation
    + * DM_C40 - C40 encodation
    + * DM_TEXT - TEXT encodation
    + * DM_B256 - binary encodation
    + * DM_X21 - X21 encodation
    + * DM_EDIFACT - EDIFACT encodation
    + * DM_RAW - no encodation. The bytes provided are already encoded and will be added directly to the barcode, using padding if needed. It assumes that the encodation state is left at ASCII after the last byte.
    + *

    + * One of:
    + * DM_EXTENSION - allows extensions to be embedded at the start of the text:

    + * exxxxxx - ECI number xxxxxx
    + * m5 - macro 5
    + * m6 - macro 6
    + * f - FNC1
    + * saabbccccc - Structured Append, aa symbol position (1-16), bb total number of symbols (2-16), ccccc file identification (0-64515)
    + * p - Reader programming
    + * . - extension terminator

    + * Example for a structured append, symbol 2 of 6, with FNC1 and ECI 000005. The actual text is "Hello".

    + * s020600075fe000005.Hello

    + * One of:
    + * DM_TEST - doesn't generate the image but returns all the other information. + * @param options the barcode options + */ + public int Options { + get { + return options; + } + set { + options = value; + } + } + + internal class Placement { + private int nrow; + private int ncol; + private short[] array; + private static Hashtable cache = Hashtable.Synchronized(new Hashtable()); + + private Placement() { + } + + internal static short[] DoPlacement(int nrow, int ncol) { + int key = nrow * 1000 + ncol; + short[] pc = (short[])cache[key]; + if (pc != null) + return pc; + Placement p = new Placement(); + p.nrow = nrow; + p.ncol = ncol; + p.array = new short[nrow * ncol]; + p.Ecc200(); + cache[key] = p.array; + return p.array; + } + + /* "module" places "chr+bit" with appropriate wrapping within array[] */ + private void Module(int row, int col, int chr, int bit) { + if (row < 0) { row += nrow; col += 4 - ((nrow+4)%8); } + if (col < 0) { col += ncol; row += 4 - ((ncol+4)%8); } + array[row*ncol+col] = (short)(8*chr + bit); + } + /* "utah" places the 8 bits of a utah-shaped symbol character in ECC200 */ + private void Utah(int row, int col, int chr) { + Module(row-2,col-2,chr,0); + Module(row-2,col-1,chr,1); + Module(row-1,col-2,chr,2); + Module(row-1,col-1,chr,3); + Module(row-1,col,chr,4); + Module(row,col-2,chr,5); + Module(row,col-1,chr,6); + Module(row,col,chr,7); + } + /* "cornerN" places 8 bits of the four special corner cases in ECC200 */ + private void Corner1(int chr) { + Module(nrow-1,0,chr,0); + Module(nrow-1,1,chr,1); + Module(nrow-1,2,chr,2); + Module(0,ncol-2,chr,3); + Module(0,ncol-1,chr,4); + Module(1,ncol-1,chr,5); + Module(2,ncol-1,chr,6); + Module(3,ncol-1,chr,7); + } + private void Corner2(int chr){ + Module(nrow-3,0,chr,0); + Module(nrow-2,0,chr,1); + Module(nrow-1,0,chr,2); + Module(0,ncol-4,chr,3); + Module(0,ncol-3,chr,4); + Module(0,ncol-2,chr,5); + Module(0,ncol-1,chr,6); + Module(1,ncol-1,chr,7); + } + private void Corner3(int chr){ + Module(nrow-3,0,chr,0); + Module(nrow-2,0,chr,1); + Module(nrow-1,0,chr,2); + Module(0,ncol-2,chr,3); + Module(0,ncol-1,chr,4); + Module(1,ncol-1,chr,5); + Module(2,ncol-1,chr,6); + Module(3,ncol-1,chr,7); + } + private void Corner4(int chr){ + Module(nrow-1,0,chr,0); + Module(nrow-1,ncol-1,chr,1); + Module(0,ncol-3,chr,2); + Module(0,ncol-2,chr,3); + Module(0,ncol-1,chr,4); + Module(1,ncol-3,chr,5); + Module(1,ncol-2,chr,6); + Module(1,ncol-1,chr,7); + } + /* "ECC200" fills an nrow x ncol array with appropriate values for ECC200 */ + private void Ecc200(){ + int row, col, chr; + /* First, fill the array[] with invalid entries */ + for (int k = 0; k < array.Length; ++k) + array[k] = (short)0; + /* Starting in the correct location for character #1, bit 8,... */ + chr = 1; row = 4; col = 0; + do { + /* repeatedly first check for one of the special corner cases, then... */ + if ((row == nrow) && (col == 0)) Corner1(chr++); + if ((row == nrow-2) && (col == 0) && (ncol%4 != 0)) Corner2(chr++); + if ((row == nrow-2) && (col == 0) && (ncol%8 == 4)) Corner3(chr++); + if ((row == nrow+4) && (col == 2) && (ncol%8 == 0)) Corner4(chr++); + /* sweep upward diagonally, inserting successive characters,... */ + do { + if ((row < nrow) && (col >= 0) && array[row*ncol+col] == 0) + Utah(row,col,chr++); + row -= 2; col += 2; + } while ((row >= 0) && (col < ncol)); + row += 1; col += 3; + /* & then sweep downward diagonally, inserting successive characters,... */ + + do { + if ((row >= 0) && (col < ncol) && array[row*ncol+col] == 0) + Utah(row,col,chr++); + row += 2; col -= 2; + } while ((row < nrow) && (col >= 0)); + row += 3; col += 1; + /* ... until the entire array is scanned */ + } while ((row < nrow) || (col < ncol)); + /* Lastly, if the lower righthand corner is untouched, fill in fixed pattern */ + if (array[nrow*ncol-1] == 0) { + array[nrow*ncol-1] = array[nrow*ncol-ncol-2] = 1; + } + } + } + + internal class ReedSolomon { + + private static readonly int[] log = { + 0, 255, 1, 240, 2, 225, 241, 53, 3, 38, 226, 133, 242, 43, 54, 210, + 4, 195, 39, 114, 227, 106, 134, 28, 243, 140, 44, 23, 55, 118, 211, 234, + 5, 219, 196, 96, 40, 222, 115, 103, 228, 78, 107, 125, 135, 8, 29, 162, + 244, 186, 141, 180, 45, 99, 24, 49, 56, 13, 119, 153, 212, 199, 235, 91, + 6, 76, 220, 217, 197, 11, 97, 184, 41, 36, 223, 253, 116, 138, 104, 193, + 229, 86, 79, 171, 108, 165, 126, 145, 136, 34, 9, 74, 30, 32, 163, 84, + 245, 173, 187, 204, 142, 81, 181, 190, 46, 88, 100, 159, 25, 231, 50, 207, + 57, 147, 14, 67, 120, 128, 154, 248, 213, 167, 200, 63, 236, 110, 92, 176, + 7, 161, 77, 124, 221, 102, 218, 95, 198, 90, 12, 152, 98, 48, 185, 179, + 42, 209, 37, 132, 224, 52, 254, 239, 117, 233, 139, 22, 105, 27, 194, 113, + 230, 206, 87, 158, 80, 189, 172, 203, 109, 175, 166, 62, 127, 247, 146, 66, + 137, 192, 35, 252, 10, 183, 75, 216, 31, 83, 33, 73, 164, 144, 85, 170, + 246, 65, 174, 61, 188, 202, 205, 157, 143, 169, 82, 72, 182, 215, 191, 251, + 47, 178, 89, 151, 101, 94, 160, 123, 26, 112, 232, 21, 51, 238, 208, 131, + 58, 69, 148, 18, 15, 16, 68, 17, 121, 149, 129, 19, 155, 59, 249, 70, + 214, 250, 168, 71, 201, 156, 64, 60, 237, 130, 111, 20, 93, 122, 177, 150 + }; + + private static readonly int[] alog = { + 1, 2, 4, 8, 16, 32, 64, 128, 45, 90, 180, 69, 138, 57, 114, 228, + 229, 231, 227, 235, 251, 219, 155, 27, 54, 108, 216, 157, 23, 46, 92, 184, + 93, 186, 89, 178, 73, 146, 9, 18, 36, 72, 144, 13, 26, 52, 104, 208, + 141, 55, 110, 220, 149, 7, 14, 28, 56, 112, 224, 237, 247, 195, 171, 123, + 246, 193, 175, 115, 230, 225, 239, 243, 203, 187, 91, 182, 65, 130, 41, 82, + 164, 101, 202, 185, 95, 190, 81, 162, 105, 210, 137, 63, 126, 252, 213, 135, + 35, 70, 140, 53, 106, 212, 133, 39, 78, 156, 21, 42, 84, 168, 125, 250, + 217, 159, 19, 38, 76, 152, 29, 58, 116, 232, 253, 215, 131, 43, 86, 172, + 117, 234, 249, 223, 147, 11, 22, 44, 88, 176, 77, 154, 25, 50, 100, 200, + 189, 87, 174, 113, 226, 233, 255, 211, 139, 59, 118, 236, 245, 199, 163, 107, + 214, 129, 47, 94, 188, 85, 170, 121, 242, 201, 191, 83, 166, 97, 194, 169, + 127, 254, 209, 143, 51, 102, 204, 181, 71, 142, 49, 98, 196, 165, 103, 206, + 177, 79, 158, 17, 34, 68, 136, 61, 122, 244, 197, 167, 99, 198, 161, 111, + 222, 145, 15, 30, 60, 120, 240, 205, 183, 67, 134, 33, 66, 132, 37, 74, + 148, 5, 10, 20, 40, 80, 160, 109, 218, 153, 31, 62, 124, 248, 221, 151, + 3, 6, 12, 24, 48, 96, 192, 173, 119, 238, 241, 207, 179, 75, 150, 1 + }; + + private static readonly int[] poly5 = { + 228, 48, 15, 111, 62 + }; + + private static readonly int[] poly7 = { + 23, 68, 144, 134, 240, 92, 254 + }; + + private static readonly int[] poly10 = { + 28, 24, 185, 166, 223, 248, 116, 255, 110, 61 + }; + + private static readonly int[] poly11 = { + 175, 138, 205, 12, 194, 168, 39, 245, 60, 97, 120 + }; + + private static readonly int[] poly12 = { + 41, 153, 158, 91, 61, 42, 142, 213, 97, 178, 100, 242 + }; + + private static readonly int[] poly14 = { + 156, 97, 192, 252, 95, 9, 157, 119, 138, 45, 18, 186, 83, 185 + }; + + private static readonly int[] poly18 = { + 83, 195, 100, 39, 188, 75, 66, 61, 241, 213, 109, 129, 94, 254, 225, 48, + 90, 188 + }; + + private static readonly int[] poly20 = { + 15, 195, 244, 9, 233, 71, 168, 2, 188, 160, 153, 145, 253, 79, 108, 82, + 27, 174, 186, 172 + }; + + private static readonly int[] poly24 = { + 52, 190, 88, 205, 109, 39, 176, 21, 155, 197, 251, 223, 155, 21, 5, 172, + 254, 124, 12, 181, 184, 96, 50, 193 + }; + + private static readonly int[] poly28 = { + 211, 231, 43, 97, 71, 96, 103, 174, 37, 151, 170, 53, 75, 34, 249, 121, + 17, 138, 110, 213, 141, 136, 120, 151, 233, 168, 93, 255 + }; + + private static readonly int[] poly36 = { + 245, 127, 242, 218, 130, 250, 162, 181, 102, 120, 84, 179, 220, 251, 80, 182, + 229, 18, 2, 4, 68, 33, 101, 137, 95, 119, 115, 44, 175, 184, 59, 25, + 225, 98, 81, 112 + }; + + private static readonly int[] poly42 = { + 77, 193, 137, 31, 19, 38, 22, 153, 247, 105, 122, 2, 245, 133, 242, 8, + 175, 95, 100, 9, 167, 105, 214, 111, 57, 121, 21, 1, 253, 57, 54, 101, + 248, 202, 69, 50, 150, 177, 226, 5, 9, 5 + }; + + private static readonly int[] poly48 = { + 245, 132, 172, 223, 96, 32, 117, 22, 238, 133, 238, 231, 205, 188, 237, 87, + 191, 106, 16, 147, 118, 23, 37, 90, 170, 205, 131, 88, 120, 100, 66, 138, + 186, 240, 82, 44, 176, 87, 187, 147, 160, 175, 69, 213, 92, 253, 225, 19 + }; + + private static readonly int[] poly56 = { + 175, 9, 223, 238, 12, 17, 220, 208, 100, 29, 175, 170, 230, 192, 215, 235, + 150, 159, 36, 223, 38, 200, 132, 54, 228, 146, 218, 234, 117, 203, 29, 232, + 144, 238, 22, 150, 201, 117, 62, 207, 164, 13, 137, 245, 127, 67, 247, 28, + 155, 43, 203, 107, 233, 53, 143, 46 + }; + + private static readonly int[] poly62 = { + 242, 93, 169, 50, 144, 210, 39, 118, 202, 188, 201, 189, 143, 108, 196, 37, + 185, 112, 134, 230, 245, 63, 197, 190, 250, 106, 185, 221, 175, 64, 114, 71, + 161, 44, 147, 6, 27, 218, 51, 63, 87, 10, 40, 130, 188, 17, 163, 31, + 176, 170, 4, 107, 232, 7, 94, 166, 224, 124, 86, 47, 11, 204 + }; + + private static readonly int[] poly68 = { + 220, 228, 173, 89, 251, 149, 159, 56, 89, 33, 147, 244, 154, 36, 73, 127, + 213, 136, 248, 180, 234, 197, 158, 177, 68, 122, 93, 213, 15, 160, 227, 236, + 66, 139, 153, 185, 202, 167, 179, 25, 220, 232, 96, 210, 231, 136, 223, 239, + 181, 241, 59, 52, 172, 25, 49, 232, 211, 189, 64, 54, 108, 153, 132, 63, + 96, 103, 82, 186 + }; + + private static int[] GetPoly(int nc) { + switch (nc) { + case 5: + return poly5; + case 7: + return poly7; + case 10: + return poly10; + case 11: + return poly11; + case 12: + return poly12; + case 14: + return poly14; + case 18: + return poly18; + case 20: + return poly20; + case 24: + return poly24; + case 28: + return poly28; + case 36: + return poly36; + case 42: + return poly42; + case 48: + return poly48; + case 56: + return poly56; + case 62: + return poly62; + case 68: + return poly68; + } + return null; + } + + private static void ReedSolomonBlock(byte[] wd, int nd, byte[] ncout, int nc, int[] c) { + int i, j, k; + + for (i=0; i<=nc; i++) ncout[i] = 0; + for (i=0; i + *x = 0.8f; + *font = BaseFont.CreateFont("Helvetica", "winansi", false); + *size = 8; + *baseline = size; + *barHeight = size * 3; + *guardBars = true; + *codeType = EAN13; + *code = ""; + * + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class BarcodeEAN : Barcode { + + /** The bar positions that are guard bars.*/ + private static readonly int[] GUARD_EMPTY = {}; + /** The bar positions that are guard bars.*/ + private static readonly int[] GUARD_UPCA = {0, 2, 4, 6, 28, 30, 52, 54, 56, 58}; + /** The bar positions that are guard bars.*/ + private static readonly int[] GUARD_EAN13 = {0, 2, 28, 30, 56, 58}; + /** The bar positions that are guard bars.*/ + private static readonly int[] GUARD_EAN8 = {0, 2, 20, 22, 40, 42}; + /** The bar positions that are guard bars.*/ + private static readonly int[] GUARD_UPCE = {0, 2, 28, 30, 32}; + /** The x coordinates to place the text.*/ + private static readonly float[] TEXTPOS_EAN13 = {6.5f, 13.5f, 20.5f, 27.5f, 34.5f, 41.5f, 53.5f, 60.5f, 67.5f, 74.5f, 81.5f, 88.5f}; + /** The x coordinates to place the text.*/ + private static readonly float[] TEXTPOS_EAN8 = {6.5f, 13.5f, 20.5f, 27.5f, 39.5f, 46.5f, 53.5f, 60.5f}; + /** The basic bar widths.*/ + private static readonly byte[][] BARS = + { + new byte[] {3, 2, 1, 1}, // 0 + new byte[] {2, 2, 2, 1}, // 1 + new byte[] {2, 1, 2, 2}, // 2 + new byte[] {1, 4, 1, 1}, // 3 + new byte[] {1, 1, 3, 2}, // 4 + new byte[] {1, 2, 3, 1}, // 5 + new byte[] {1, 1, 1, 4}, // 6 + new byte[] {1, 3, 1, 2}, // 7 + new byte[] {1, 2, 1, 3}, // 8 + new byte[] {3, 1, 1, 2} // 9 + }; + + /** The total number of bars for EAN13.*/ + private const int TOTALBARS_EAN13 = 11 + 12 * 4; + /** The total number of bars for EAN8.*/ + private const int TOTALBARS_EAN8 = 11 + 8 * 4; + /** The total number of bars for UPCE.*/ + private const int TOTALBARS_UPCE = 9 + 6 * 4; + /** The total number of bars for supplemental 2.*/ + private const int TOTALBARS_SUPP2 = 13; + /** The total number of bars for supplemental 5.*/ + private const int TOTALBARS_SUPP5 = 31; + /** Marker for odd parity.*/ + private const byte ODD = 0; + /** Marker for even parity.*/ + private const byte EVEN = 1; + + /** Sequence of parities to be used with EAN13.*/ + private static readonly byte[][] PARITY13 = + { + new byte[] {ODD, ODD, ODD, ODD, ODD, ODD}, // 0 + new byte[] {ODD, ODD, EVEN, ODD, EVEN, EVEN}, // 1 + new byte[] {ODD, ODD, EVEN, EVEN, ODD, EVEN}, // 2 + new byte[] {ODD, ODD, EVEN, EVEN, EVEN, ODD}, // 3 + new byte[] {ODD, EVEN, ODD, ODD, EVEN, EVEN}, // 4 + new byte[] {ODD, EVEN, EVEN, ODD, ODD, EVEN}, // 5 + new byte[] {ODD, EVEN, EVEN, EVEN, ODD, ODD}, // 6 + new byte[] {ODD, EVEN, ODD, EVEN, ODD, EVEN}, // 7 + new byte[] {ODD, EVEN, ODD, EVEN, EVEN, ODD}, // 8 + new byte[] {ODD, EVEN, EVEN, ODD, EVEN, ODD} // 9 + }; + + /** Sequence of parities to be used with supplemental 2.*/ + private static readonly byte[][] PARITY2 = + { + new byte[] {ODD, ODD}, // 0 + new byte[] {ODD, EVEN}, // 1 + new byte[] {EVEN, ODD}, // 2 + new byte[] {EVEN, EVEN} // 3 + }; + + /** Sequence of parities to be used with supplemental 2.*/ + private static readonly byte[][] PARITY5 = + { + new byte[] {EVEN, EVEN, ODD, ODD, ODD}, // 0 + new byte[] {EVEN, ODD, EVEN, ODD, ODD}, // 1 + new byte[] {EVEN, ODD, ODD, EVEN, ODD}, // 2 + new byte[] {EVEN, ODD, ODD, ODD, EVEN}, // 3 + new byte[] {ODD, EVEN, EVEN, ODD, ODD}, // 4 + new byte[] {ODD, ODD, EVEN, EVEN, ODD}, // 5 + new byte[] {ODD, ODD, ODD, EVEN, EVEN}, // 6 + new byte[] {ODD, EVEN, ODD, EVEN, ODD}, // 7 + new byte[] {ODD, EVEN, ODD, ODD, EVEN}, // 8 + new byte[] {ODD, ODD, EVEN, ODD, EVEN} // 9 + }; + + /** Sequence of parities to be used with UPCE.*/ + private static readonly byte[][] PARITYE = + { + new byte[] {EVEN, EVEN, EVEN, ODD, ODD, ODD}, // 0 + new byte[] {EVEN, EVEN, ODD, EVEN, ODD, ODD}, // 1 + new byte[] {EVEN, EVEN, ODD, ODD, EVEN, ODD}, // 2 + new byte[] {EVEN, EVEN, ODD, ODD, ODD, EVEN}, // 3 + new byte[] {EVEN, ODD, EVEN, EVEN, ODD, ODD}, // 4 + new byte[] {EVEN, ODD, ODD, EVEN, EVEN, ODD}, // 5 + new byte[] {EVEN, ODD, ODD, ODD, EVEN, EVEN}, // 6 + new byte[] {EVEN, ODD, EVEN, ODD, EVEN, ODD}, // 7 + new byte[] {EVEN, ODD, EVEN, ODD, ODD, EVEN}, // 8 + new byte[] {EVEN, ODD, ODD, EVEN, ODD, EVEN} // 9 + }; + + /** Creates new BarcodeEAN */ + public BarcodeEAN() { + x = 0.8f; + font = BaseFont.CreateFont("Helvetica", "winansi", false); + size = 8; + baseline = size; + barHeight = size * 3; + guardBars = true; + codeType = EAN13; + code = ""; + } + + /** Calculates the EAN parity character. + * @param code the code + * @return the parity character + */ + public static int CalculateEANParity(string code) { + int mul = 3; + int total = 0; + for (int k = code.Length - 1; k >= 0; --k) { + int n = code[k] - '0'; + total += mul * n; + mul ^= 2; + } + return (10 - (total % 10)) % 10; + } + + /** Converts an UPCA code into an UPCE code. If the code can not + * be converted a null is returned. + * @param text the code to convert. It must have 12 numeric characters + * @return the 8 converted digits or null if the + * code could not be converted + */ + static public string ConvertUPCAtoUPCE(string text) { + if (text.Length != 12 || !(text.StartsWith("0") || text.StartsWith("1"))) + return null; + if (text.Substring(3, 3).Equals("000") || text.Substring(3, 3).Equals("100") + || text.Substring(3, 3).Equals("200")) { + if (text.Substring(6, 2).Equals("00")) + return text.Substring(0, 1) + text.Substring(1, 2) + text.Substring(8, 3) + text.Substring(3, 1) + text.Substring(11); + } + else if (text.Substring(4, 2).Equals("00")) { + if (text.Substring(6, 3).Equals("000")) + return text.Substring(0, 1) + text.Substring(1, 3) + text.Substring(9, 2) + "3" + text.Substring(11); + } + else if (text.Substring(5, 1).Equals("0")) { + if (text.Substring(6, 4).Equals("0000")) + return text.Substring(0, 1) + text.Substring(1, 4) + text.Substring(10, 1) + "4" + text.Substring(11); + } + else if (text[10] >= '5') { + if (text.Substring(6, 4).Equals("0000")) + return text.Substring(0, 1) + text.Substring(1, 5) + text.Substring(10, 1) + text.Substring(11); + } + return null; + } + + /** Creates the bars for the barcode EAN13 and UPCA. + * @param _code the text with 13 digits + * @return the barcode + */ + public static byte[] GetBarsEAN13(string _code) { + int[] code = new int[_code.Length]; + for (int k = 0; k < code.Length; ++k) + code[k] = _code[k] - '0'; + byte[] bars = new byte[TOTALBARS_EAN13]; + int pb = 0; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + byte[] sequence = PARITY13[code[0]]; + for (int k = 0; k < sequence.Length; ++k) { + int c = code[k + 1]; + byte[] stripes = BARS[c]; + if (sequence[k] == ODD) { + bars[pb++] = stripes[0]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[3]; + } + else { + bars[pb++] = stripes[3]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[0]; + } + } + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + for (int k = 7; k < 13; ++k) { + int c = code[k]; + byte[] stripes = BARS[c]; + bars[pb++] = stripes[0]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[3]; + } + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + return bars; + } + + /** Creates the bars for the barcode EAN8. + * @param _code the text with 8 digits + * @return the barcode + */ + public static byte[] GetBarsEAN8(string _code) { + int[] code = new int[_code.Length]; + for (int k = 0; k < code.Length; ++k) + code[k] = _code[k] - '0'; + byte[] bars = new byte[TOTALBARS_EAN8]; + int pb = 0; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + for (int k = 0; k < 4; ++k) { + int c = code[k]; + byte[] stripes = BARS[c]; + bars[pb++] = stripes[0]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[3]; + } + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + for (int k = 4; k < 8; ++k) { + int c = code[k]; + byte[] stripes = BARS[c]; + bars[pb++] = stripes[0]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[3]; + } + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + return bars; + } + + /** Creates the bars for the barcode UPCE. + * @param _code the text with 8 digits + * @return the barcode + */ + public static byte[] GetBarsUPCE(string _code) { + int[] code = new int[_code.Length]; + for (int k = 0; k < code.Length; ++k) + code[k] = _code[k] - '0'; + byte[] bars = new byte[TOTALBARS_UPCE]; + bool flip = (code[0] != 0); + int pb = 0; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + byte[] sequence = PARITYE[code[code.Length - 1]]; + for (int k = 1; k < code.Length - 1; ++k) { + int c = code[k]; + byte[] stripes = BARS[c]; + if (sequence[k - 1] == (flip ? EVEN : ODD)) { + bars[pb++] = stripes[0]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[3]; + } + else { + bars[pb++] = stripes[3]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[0]; + } + } + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 1; + return bars; + } + + /** Creates the bars for the barcode supplemental 2. + * @param _code the text with 2 digits + * @return the barcode + */ + public static byte[] GetBarsSupplemental2(string _code) { + int[] code = new int[2]; + for (int k = 0; k < code.Length; ++k) + code[k] = _code[k] - '0'; + byte[] bars = new byte[TOTALBARS_SUPP2]; + int pb = 0; + int parity = (code[0] * 10 + code[1]) % 4; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 2; + byte[] sequence = PARITY2[parity]; + for (int k = 0; k < sequence.Length; ++k) { + if (k == 1) { + bars[pb++] = 1; + bars[pb++] = 1; + } + int c = code[k]; + byte[] stripes = BARS[c]; + if (sequence[k] == ODD) { + bars[pb++] = stripes[0]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[3]; + } + else { + bars[pb++] = stripes[3]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[0]; + } + } + return bars; + } + + /** Creates the bars for the barcode supplemental 5. + * @param _code the text with 5 digits + * @return the barcode + */ + public static byte[] GetBarsSupplemental5(string _code) { + int[] code = new int[5]; + for (int k = 0; k < code.Length; ++k) + code[k] = _code[k] - '0'; + byte[] bars = new byte[TOTALBARS_SUPP5]; + int pb = 0; + int parity = (((code[0] + code[2] + code[4]) * 3) + ((code[1] + code[3]) * 9)) % 10; + bars[pb++] = 1; + bars[pb++] = 1; + bars[pb++] = 2; + byte[] sequence = PARITY5[parity]; + for (int k = 0; k < sequence.Length; ++k) { + if (k != 0) { + bars[pb++] = 1; + bars[pb++] = 1; + } + int c = code[k]; + byte[] stripes = BARS[c]; + if (sequence[k] == ODD) { + bars[pb++] = stripes[0]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[3]; + } + else { + bars[pb++] = stripes[3]; + bars[pb++] = stripes[2]; + bars[pb++] = stripes[1]; + bars[pb++] = stripes[0]; + } + } + return bars; + } + + /** Gets the maximum area that the barcode and the text, if + * any, will occupy. The lower left corner is always (0, 0). + * @return the size the barcode occupies. + */ + public override Rectangle BarcodeSize { + get { + float width = 0; + float height = barHeight; + if (font != null) { + if (baseline <= 0) + height += -baseline + size; + else + height += baseline - font.GetFontDescriptor(BaseFont.DESCENT, size); + } + switch (codeType) { + case BarcodeEAN.EAN13: + width = x * (11 + 12 * 7); + if (font != null) { + width += font.GetWidthPoint(code[0], size); + } + break; + case EAN8: + width = x * (11 + 8 * 7); + break; + case UPCA: + width = x * (11 + 12 * 7); + if (font != null) { + width += font.GetWidthPoint(code[0], size) + font.GetWidthPoint(code[11], size); + } + break; + case UPCE: + width = x * (9 + 6 * 7); + if (font != null) { + width += font.GetWidthPoint(code[0], size) + font.GetWidthPoint(code[7], size); + } + break; + case SUPP2: + width = x * (6 + 2 * 7); + break; + case SUPP5: + width = x * (4 + 5 * 7 + 4 * 2); + break; + default: + throw new ArgumentException("Invalid code type."); + } + return new Rectangle(width, height); + } + } + + /** Places the barcode in a PdfContentByte. The + * barcode is always placed at coodinates (0, 0). Use the + * translation matrix to move it elsewhere.

    + * The bars and text are written in the following colors:

    + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *

    barColor

    textColor

    Result

    null

    null

    bars and text painted with current fill color

    barColor

    null

    bars and text painted with barColor

    null

    textColor

    bars painted with current color
    text painted with textColor

    barColor

    textColor

    bars painted with barColor
    text painted with textColor

    + * @param cb the PdfContentByte where the barcode will be placed + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the dimensions the barcode occupies + */ + public override Rectangle PlaceBarcode(PdfContentByte cb, Color barColor, Color textColor) { + Rectangle rect = this.BarcodeSize; + float barStartX = 0; + float barStartY = 0; + float textStartY = 0; + if (font != null) { + if (baseline <= 0) + textStartY = barHeight - baseline; + else { + textStartY = -font.GetFontDescriptor(BaseFont.DESCENT, size); + barStartY = textStartY + baseline; + } + } + switch (codeType) { + case EAN13: + case UPCA: + case UPCE: + if (font != null) + barStartX += font.GetWidthPoint(code[0], size); + break; + } + byte[] bars = null; + int[] guard = GUARD_EMPTY; + switch (codeType) { + case EAN13: + bars = GetBarsEAN13(code); + guard = GUARD_EAN13; + break; + case EAN8: + bars = GetBarsEAN8(code); + guard = GUARD_EAN8; + break; + case UPCA: + bars = GetBarsEAN13("0" + code); + guard = GUARD_UPCA; + break; + case UPCE: + bars = GetBarsUPCE(code); + guard = GUARD_UPCE; + break; + case SUPP2: + bars = GetBarsSupplemental2(code); + break; + case SUPP5: + bars = GetBarsSupplemental5(code); + break; + } + float keepBarX = barStartX; + bool print = true; + float gd = 0; + if (font != null && baseline > 0 && guardBars) { + gd = baseline / 2; + } + if (barColor != null) + cb.SetColorFill(barColor); + for (int k = 0; k < bars.Length; ++k) { + float w = bars[k] * x; + if (print) { + if (Array.BinarySearch(guard, k) >= 0) + cb.Rectangle(barStartX, barStartY - gd, w - inkSpreading, barHeight + gd); + else + cb.Rectangle(barStartX, barStartY, w - inkSpreading, barHeight); + } + print = !print; + barStartX += w; + } + cb.Fill(); + if (font != null) { + if (textColor != null) + cb.SetColorFill(textColor); + cb.BeginText(); + cb.SetFontAndSize(font, size); + switch (codeType) { + case EAN13: + cb.SetTextMatrix(0, textStartY); + cb.ShowText(code.Substring(0, 1)); + for (int k = 1; k < 13; ++k) { + string c = code.Substring(k, 1); + float len = font.GetWidthPoint(c, size); + float pX = keepBarX + TEXTPOS_EAN13[k - 1] * x - len / 2; + cb.SetTextMatrix(pX, textStartY); + cb.ShowText(c); + } + break; + case EAN8: + for (int k = 0; k < 8; ++k) { + string c = code.Substring(k, 1); + float len = font.GetWidthPoint(c, size); + float pX = TEXTPOS_EAN8[k] * x - len / 2; + cb.SetTextMatrix(pX, textStartY); + cb.ShowText(c); + } + break; + case UPCA: + cb.SetTextMatrix(0, textStartY); + cb.ShowText(code.Substring(0, 1)); + for (int k = 1; k < 11; ++k) { + string c = code.Substring(k, 1); + float len = font.GetWidthPoint(c, size); + float pX = keepBarX + TEXTPOS_EAN13[k] * x - len / 2; + cb.SetTextMatrix(pX, textStartY); + cb.ShowText(c); + } + cb.SetTextMatrix(keepBarX + x * (11 + 12 * 7), textStartY); + cb.ShowText(code.Substring(11, 1)); + break; + case UPCE: + cb.SetTextMatrix(0, textStartY); + cb.ShowText(code.Substring(0, 1)); + for (int k = 1; k < 7; ++k) { + string c = code.Substring(k, 1); + float len = font.GetWidthPoint(c, size); + float pX = keepBarX + TEXTPOS_EAN13[k - 1] * x - len / 2; + cb.SetTextMatrix(pX, textStartY); + cb.ShowText(c); + } + cb.SetTextMatrix(keepBarX + x * (9 + 6 * 7), textStartY); + cb.ShowText(code.Substring(7, 1)); + break; + case SUPP2: + case SUPP5: + for (int k = 0; k < code.Length; ++k) { + string c = code.Substring(k, 1); + float len = font.GetWidthPoint(c, size); + float pX = (7.5f + (9 * k)) * x - len / 2; + cb.SetTextMatrix(pX, textStartY); + cb.ShowText(c); + } + break; + } + cb.EndText(); + } + return rect; + } + + public override System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + int width = 0; + byte[] bars = null; + switch (codeType) { + case EAN13: + bars = GetBarsEAN13(code); + width = 11 + 12 * 7; + break; + case EAN8: + bars = GetBarsEAN8(code); + width = 11 + 8 * 7; + break; + case UPCA: + bars = GetBarsEAN13("0" + code); + width = 11 + 12 * 7; + break; + case UPCE: + bars = GetBarsUPCE(code); + width = 9 + 6 * 7; + break; + case SUPP2: + bars = GetBarsSupplemental2(code); + width = 6 + 2 * 7; + break; + case SUPP5: + bars = GetBarsSupplemental5(code); + width = 4 + 5 * 7 + 4 * 2; + break; + default: + throw new InvalidOperationException("Invalid code type."); + } + int height = (int)barHeight; + System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(width, height); + for (int h = 0; h < height; ++h) { + bool print = true; + int ptr = 0; + for (int k = 0; k < bars.Length; ++k) { + int w = bars[k]; + System.Drawing.Color c = background; + if (print) + c = foreground; + print = !print; + for (int j = 0; j < w; ++j) + bmp.SetPixel(ptr++, h, c); + } + } + return bmp; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BarcodeEANSUPP.cs b/iTechSharp/iTextSharp/text/pdf/BarcodeEANSUPP.cs new file mode 100644 index 0000000..0f15fb0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BarcodeEANSUPP.cs @@ -0,0 +1,150 @@ +using System; +using iTextSharp.text; + +/* + * Copyright 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** This class takes 2 barcodes, an EAN/UPC and a supplemental + * and creates a single barcode with both combined in the + * expected layout. The UPC/EAN should have a positive text + * baseline and the supplemental a negative one (in the supplemental + * the text is on the top of the barcode.

    + * The default parameters are: + *

    +     *n = 8; // horizontal distance between the two barcodes
    +     * 
    + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class BarcodeEANSUPP : Barcode { + + /** The barcode with the EAN/UPC. + */ + protected Barcode ean; + /** The barcode with the supplemental. + */ + protected Barcode supp; + + /** Creates new combined barcode. + * @param ean the EAN/UPC barcode + * @param supp the supplemental barcode + */ + public BarcodeEANSUPP(Barcode ean, Barcode supp) { + n = 8; // horizontal distance between the two barcodes + this.ean = ean; + this.supp = supp; + } + + /** Gets the maximum area that the barcode and the text, if + * any, will occupy. The lower left corner is always (0, 0). + * @return the size the barcode occupies. + */ + public override Rectangle BarcodeSize { + get { + Rectangle rect = ean.BarcodeSize; + rect.Right = rect.Width + supp.BarcodeSize.Width + n; + return rect; + } + } + + /** Places the barcode in a PdfContentByte. The + * barcode is always placed at coodinates (0, 0). Use the + * translation matrix to move it elsewhere.

    + * The bars and text are written in the following colors:

    + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *

    barColor

    textColor

    Result

    null

    null

    bars and text painted with current fill color

    barColor

    null

    bars and text painted with barColor

    null

    textColor

    bars painted with current color
    text painted with textColor

    barColor

    textColor

    bars painted with barColor
    text painted with textColor

    + * @param cb the PdfContentByte where the barcode will be placed + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the dimensions the barcode occupies + */ + public override Rectangle PlaceBarcode(PdfContentByte cb, Color barColor, Color textColor) { + if (supp.Font != null) + supp.BarHeight = ean.BarHeight + supp.Baseline - supp.Font.GetFontDescriptor(BaseFont.CAPHEIGHT, supp.Size); + else + supp.BarHeight = ean.BarHeight; + Rectangle eanR = ean.BarcodeSize; + cb.SaveState(); + ean.PlaceBarcode(cb, barColor, textColor); + cb.RestoreState(); + cb.SaveState(); + cb.ConcatCTM(1, 0, 0, 1, eanR.Width + n, eanR.Height - ean.BarHeight); + supp.PlaceBarcode(cb, barColor, textColor); + cb.RestoreState(); + return this.BarcodeSize; + } + + public override System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + throw new InvalidOperationException("The two barcodes must be composed externally."); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BarcodeInter25.cs b/iTechSharp/iTextSharp/text/pdf/BarcodeInter25.cs new file mode 100644 index 0000000..cc1479b --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BarcodeInter25.cs @@ -0,0 +1,317 @@ +using System; +using System.Text; +using iTextSharp.text; + +/* + * $Id: BarcodeInter25.cs,v 1.5 2006/09/17 15:58:51 psoares33 Exp $ + * + * Copyright 2002-2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** Implements the code interleaved 2 of 5. The text can include + * non numeric characters that are printed but do not generate bars. + * The default parameters are: + *

    +     *x = 0.8f;
    +     *n = 2;
    +     *font = BaseFont.CreateFont("Helvetica", "winansi", false);
    +     *size = 8;
    +     *baseline = size;
    +     *barHeight = size * 3;
    +     *textint= Element.ALIGN_CENTER;
    +     *generateChecksum = false;
    +     *checksumText = false;
    +     * 
    + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class BarcodeInter25 : Barcode { + + /** The bars to generate the code. + */ + private static readonly byte[][] BARS = { + new byte[] {0,0,1,1,0}, + new byte[] {1,0,0,0,1}, + new byte[] {0,1,0,0,1}, + new byte[] {1,1,0,0,0}, + new byte[] {0,0,1,0,1}, + new byte[] {1,0,1,0,0}, + new byte[] {0,1,1,0,0}, + new byte[] {0,0,0,1,1}, + new byte[] {1,0,0,1,0}, + new byte[] {0,1,0,1,0} + }; + + /** Creates new BarcodeInter25 */ + public BarcodeInter25() { + x = 0.8f; + n = 2; + font = BaseFont.CreateFont("Helvetica", "winansi", false); + size = 8; + baseline = size; + barHeight = size * 3; + textAlignment = Element.ALIGN_CENTER; + generateChecksum = false; + checksumText = false; + } + + /** Deletes all the non numeric characters from text. + * @param text the text + * @return a string with only numeric characters + */ + public static string KeepNumbers(string text) { + StringBuilder sb = new StringBuilder(); + for (int k = 0; k < text.Length; ++k) { + char c = text[k]; + if (c >= '0' && c <= '9') + sb.Append(c); + } + return sb.ToString(); + } + + /** Calculates the checksum. + * @param text the numeric text + * @return the checksum + */ + public static char GetChecksum(string text) { + int mul = 3; + int total = 0; + for (int k = text.Length - 1; k >= 0; --k) { + int n = text[k] - '0'; + total += mul * n; + mul ^= 2; + } + return (char)(((10 - (total % 10)) % 10) + '0'); + } + + /** Creates the bars for the barcode. + * @param text the text. It can contain non numeric characters + * @return the barcode + */ + public static byte[] GetBarsInter25(string text) { + text = KeepNumbers(text); + if ((text.Length & 1) != 0) + throw new ArgumentException("The text length must be even."); + byte[] bars = new byte[text.Length * 5 + 7]; + int pb = 0; + bars[pb++] = 0; + bars[pb++] = 0; + bars[pb++] = 0; + bars[pb++] = 0; + int len = text.Length / 2; + for (int k = 0; k < len; ++k) { + int c1 = text[k * 2] - '0'; + int c2 = text[k * 2 + 1] - '0'; + byte[] b1 = BARS[c1]; + byte[] b2 = BARS[c2]; + for (int j = 0; j < 5; ++j) { + bars[pb++] = b1[j]; + bars[pb++] = b2[j]; + } + } + bars[pb++] = 1; + bars[pb++] = 0; + bars[pb++] = 0; + return bars; + } + + /** Gets the maximum area that the barcode and the text, if + * any, will occupy. The lower left corner is always (0, 0). + * @return the size the barcode occupies. + */ + public override Rectangle BarcodeSize { + get { + float fontX = 0; + float fontY = 0; + if (font != null) { + if (baseline > 0) + fontY = baseline - font.GetFontDescriptor(BaseFont.DESCENT, size); + else + fontY = -baseline + size; + string fullCode = code; + if (generateChecksum && checksumText) + fullCode += GetChecksum(fullCode); + fontX = font.GetWidthPoint(altText != null ? altText : fullCode, size); + } + string fCode = KeepNumbers(code); + int len = fCode.Length; + if (generateChecksum) + ++len; + float fullWidth = len * (3 * x + 2 * x * n) + (6 + n ) * x; + fullWidth = Math.Max(fullWidth, fontX); + float fullHeight = barHeight + fontY; + return new Rectangle(fullWidth, fullHeight); + } + } + + /** Places the barcode in a PdfContentByte. The + * barcode is always placed at coodinates (0, 0). Use the + * translation matrix to move it elsewhere.

    + * The bars and text are written in the following colors:

    + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *

    barColor

    textColor

    Result

    null

    null

    bars and text painted with current fill color

    barColor

    null

    bars and text painted with barColor

    null

    textColor

    bars painted with current color
    text painted with textColor

    barColor

    textColor

    bars painted with barColor
    text painted with textColor

    + * @param cb the PdfContentByte where the barcode will be placed + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the dimensions the barcode occupies + */ + public override Rectangle PlaceBarcode(PdfContentByte cb, Color barColor, Color textColor) { + string fullCode = code; + float fontX = 0; + if (font != null) { + if (generateChecksum && checksumText) + fullCode += GetChecksum(fullCode); + fontX = font.GetWidthPoint(fullCode = altText != null ? altText : fullCode, size); + } + string bCode = KeepNumbers(code); + if (generateChecksum) + bCode += GetChecksum(bCode); + int len = bCode.Length; + float fullWidth = len * (3 * x + 2 * x * n) + (6 + n ) * x; + float barStartX = 0; + float textStartX = 0; + switch (textAlignment) { + case Element.ALIGN_LEFT: + break; + case Element.ALIGN_RIGHT: + if (fontX > fullWidth) + barStartX = fontX - fullWidth; + else + textStartX = fullWidth - fontX; + break; + default: + if (fontX > fullWidth) + barStartX = (fontX - fullWidth) / 2; + else + textStartX = (fullWidth - fontX) / 2; + break; + } + float barStartY = 0; + float textStartY = 0; + if (font != null) { + if (baseline <= 0) + textStartY = barHeight - baseline; + else { + textStartY = -font.GetFontDescriptor(BaseFont.DESCENT, size); + barStartY = textStartY + baseline; + } + } + byte[] bars = GetBarsInter25(bCode); + bool print = true; + if (barColor != null) + cb.SetColorFill(barColor); + for (int k = 0; k < bars.Length; ++k) { + float w = (bars[k] == 0 ? x : x * n); + if (print) + cb.Rectangle(barStartX, barStartY, w - inkSpreading, barHeight); + print = !print; + barStartX += w; + } + cb.Fill(); + if (font != null) { + if (textColor != null) + cb.SetColorFill(textColor); + cb.BeginText(); + cb.SetFontAndSize(font, size); + cb.SetTextMatrix(textStartX, textStartY); + cb.ShowText(fullCode); + cb.EndText(); + } + return this.BarcodeSize; + } + + public override System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + String bCode = KeepNumbers(code); + if (generateChecksum) + bCode += GetChecksum(bCode); + int len = bCode.Length; + int nn = (int)n; + int fullWidth = len * (3 + 2 * nn) + (6 + nn ); + byte[] bars = GetBarsInter25(bCode); + int height = (int)barHeight; + System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(fullWidth, height); + for (int h = 0; h < height; ++h) { + bool print = true; + int ptr = 0; + for (int k = 0; k < bars.Length; ++k) { + int w = (bars[k] == 0 ? 1 : nn); + System.Drawing.Color c = background; + if (print) + c = foreground; + print = !print; + for (int j = 0; j < w; ++j) + bmp.SetPixel(ptr++, h, c); + } + } + return bmp; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BarcodePDF417.cs b/iTechSharp/iTextSharp/text/pdf/BarcodePDF417.cs new file mode 100644 index 0000000..94cf499 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BarcodePDF417.cs @@ -0,0 +1,1551 @@ +using System; +using iTextSharp.text; +using iTextSharp.text.pdf.codec; +using System.Collections; +using System.Text; + +namespace iTextSharp.text.pdf { + /** Generates the 2D barcode PDF417. Supports dimensioning auto-sizing, fixed + * and variable sizes, automatic and manual error levels, raw codeword input, + * codeword size optimization and bitmap inversion. The output can + * be a CCITT G4 Image or a raw bitmap. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class BarcodePDF417 { + + /** Auto-size is made based on aspectRatio and yHeight. */ + public const int PDF417_USE_ASPECT_RATIO = 0; + /** The size of the barcode will be at least codeColumns*codeRows. */ + public const int PDF417_FIXED_RECTANGLE = 1; + /** The size will be at least codeColumns + * with a variable number of codeRows. + */ + public const int PDF417_FIXED_COLUMNS = 2; + /** The size will be at least codeRows + * with a variable number of codeColumns. + */ + public const int PDF417_FIXED_ROWS = 4; + /** The error level correction is set automatically according + * to ISO 15438 recomendations. + */ + public const int PDF417_AUTO_ERROR_LEVEL = 0; + /** The error level correction is set by the user. It can be 0 to 8. */ + public const int PDF417_USE_ERROR_LEVEL = 16; + /** + * One single binary segment is used + */ + public const int PDF417_FORCE_BINARY = 32; + /** No text interpretation is done and the content of codewords + * is used directly. + */ + public const int PDF417_USE_RAW_CODEWORDS = 64; + /** Inverts the output bits of the raw bitmap that is normally + * bit one for black. It has only effect for the raw bitmap. + */ + public const int PDF417_INVERT_BITMAP = 128; + /** Use Macro PDF417 Encoding + * @see #setMacroFileId(String) + * @see #setMacroSegmentId(int) + * @see #setMacroSegmentCount(int) + */ + public const int PDF417_USE_MACRO = 256; + + + private int macroSegmentCount=0; + private int macroSegmentId=-1; + private String macroFileId; + private int macroIndex; + + protected int bitPtr; + protected int cwPtr; + protected SegmentList segmentList; + + /** Creates a new BarcodePDF417 with the default settings. */ + public BarcodePDF417() { + SetDefaultParameters(); + } + + /** + * Sets the segment id for macro PDF417 encoding + * @param id the id (starting at 0) + * @see #setMacroSegmentCount(int) + */ + public int MacroSegmentId { + set { + this.macroSegmentId = value; + } + } + + /** + * Sets the segment count for macro PDF417 encoding + * @param cnt the number of macro segments + * @see #setMacroSegmentId(int) + */ + public int MacroSegmentCount { + set { + this.macroSegmentCount = value; + } + } + + /** + * Sets the File ID for macro PDF417 encoding + * @param id the file id + */ + public String MacroFileId { + set { + this.macroFileId = value; + } + } + + protected bool CheckSegmentType(Segment segment, char type) { + if (segment == null) + return false; + return segment.type == type; + } + + protected int GetSegmentLength(Segment segment) { + if (segment == null) + return 0; + return segment.end - segment.start; + } + + /** Set the default settings that correspond to PDF417_USE_ASPECT_RATIO + * and PDF417_AUTO_ERROR_LEVEL. + */ + public void SetDefaultParameters() { + options = 0; + outBits = null; + text = new byte[0]; + yHeight = 3; + aspectRatio = 0.5f; + } + + protected void OutCodeword17(int codeword) { + int bytePtr = bitPtr / 8; + int bit = bitPtr - bytePtr * 8; + outBits[bytePtr++] |= (byte)(codeword >> (9 + bit)); + outBits[bytePtr++] |= (byte)(codeword >> (1 + bit)); + codeword <<= 8; + outBits[bytePtr] |= (byte)(codeword >> (1 + bit)); + bitPtr += 17; + } + + protected void OutCodeword18(int codeword) { + int bytePtr = bitPtr / 8; + int bit = bitPtr - bytePtr * 8; + outBits[bytePtr++] |= (byte)(codeword >> (10 + bit)); + outBits[bytePtr++] |= (byte)(codeword >> (2 + bit)); + codeword <<= 8; + outBits[bytePtr] |= (byte)(codeword >> (2 + bit)); + if (bit == 7) + outBits[++bytePtr] |= 0x80; + bitPtr += 18; + } + + protected void OutCodeword(int codeword) { + OutCodeword17(codeword); + } + + protected void OutStopPattern() { + OutCodeword18(STOP_PATTERN); + } + + protected void OutStartPattern() { + OutCodeword17(START_PATTERN); + } + + protected void OutPaintCode() { + int codePtr = 0; + bitColumns = START_CODE_SIZE * (codeColumns + 3) + STOP_SIZE; + int lenBits = ((bitColumns - 1) / 8 + 1) * codeRows; + outBits = new byte[lenBits]; + for (int row = 0; row < codeRows; ++row) { + bitPtr = ((bitColumns - 1) / 8 + 1) * 8 * row; + int rowMod = row % 3; + int[] cluster = CLUSTERS[rowMod]; + OutStartPattern(); + int edge = 0; + switch (rowMod) { + case 0: + edge = 30 * (row / 3) + ((codeRows - 1) / 3); + break; + case 1: + edge = 30 * (row / 3) + errorLevel * 3 + ((codeRows - 1) % 3); + break; + default: + edge = 30 * (row / 3) + codeColumns - 1; + break; + } + OutCodeword(cluster[edge]); + + for (int column = 0; column < codeColumns; ++column) { + OutCodeword(cluster[codewords[codePtr++]]); + } + + switch (rowMod) { + case 0: + edge = 30 * (row / 3) + codeColumns - 1; + break; + case 1: + edge = 30 * (row / 3) + ((codeRows - 1) / 3); + break; + default: + edge = 30 * (row / 3) + errorLevel * 3 + ((codeRows - 1) % 3); + break; + } + OutCodeword(cluster[edge]); + OutStopPattern(); + } + if ((options & PDF417_INVERT_BITMAP) != 0) { + for (int k = 0; k < outBits.Length; ++k) + outBits[k] ^= 0xff; + } + } + + protected void CalculateErrorCorrection(int dest) { + if (errorLevel < 0 || errorLevel > 8) + errorLevel = 0; + int[] A = ERROR_LEVEL[errorLevel]; + int Alength = 2 << errorLevel; + for (int k = 0; k < Alength; ++k) + codewords[dest + k] = 0; + int lastE = Alength - 1; + for (int k = 0; k < lenCodewords; ++k) { + int t1 = codewords[k] + codewords[dest]; + for (int e = 0; e <= lastE; ++e) { + int t2 = (t1 * A[lastE - e]) % MOD; + int t3 = MOD - t2; + codewords[dest + e] = ((e == lastE ? 0 : codewords[dest + e + 1]) + t3) % MOD; + } + } + for (int k = 0; k < Alength; ++k) + codewords[dest + k] = (MOD - codewords[dest + k]) % MOD; + } + + private static int GetTextTypeAndValue(byte[] input, int maxLength, int idx) { + if (idx >= maxLength) + return 0; + char c = (char)(input[idx] & 0xff); + if (c >= 'A' && c <= 'Z') + return (ALPHA + c - 'A'); + if (c >= 'a' && c <= 'z') + return (LOWER + c - 'a'); + if (c == ' ') + return (ALPHA + LOWER + MIXED + SPACE); + int ms = MIXED_SET.IndexOf(c); + int ps = PUNCTUATION_SET.IndexOf(c); + if (ms < 0 && ps < 0) + return (ISBYTE + c); + if (ms == ps) + return (MIXED + PUNCTUATION + ms); + if (ms >= 0) + return (MIXED + ms); + return (PUNCTUATION + ps); + } + + protected int GetTextTypeAndValue(int maxLength, int idx) { + return GetTextTypeAndValue(text, maxLength,idx); + } + + private void TextCompaction(byte[] input, int start, int length) { + int[] dest = new int[ABSOLUTE_MAX_TEXT_SIZE * 2]; + int mode = ALPHA; + int ptr = 0; + int fullBytes = 0; + int v = 0; + int k; + int size; + length += start; + for (k = start; k < length; ++k) { + v = GetTextTypeAndValue(input, length, k); + if ((v & mode) != 0) { + dest[ptr++] = v & 0xff; + continue; + } + if ((v & ISBYTE) != 0) { + if ((ptr & 1) != 0) { + //add a padding word + dest[ptr++] = PAL; + mode = (mode & PUNCTUATION) != 0 ? ALPHA : mode; + } + dest[ptr++] = BYTESHIFT; + dest[ptr++] = v & 0xff; + fullBytes += 2; + continue; + } + switch (mode) { + case ALPHA: + if ((v & LOWER) != 0) { + dest[ptr++] = LL; + dest[ptr++] = v & 0xff; + mode = LOWER; + } + else if ((v & MIXED) != 0) { + dest[ptr++] = ML; + dest[ptr++] = v & 0xff; + mode = MIXED; + } + else if ((GetTextTypeAndValue(input, length, k + 1) & GetTextTypeAndValue(input, length, k + 2) & PUNCTUATION) != 0) { + dest[ptr++] = ML; + dest[ptr++] = PL; + dest[ptr++] = v & 0xff; + mode = PUNCTUATION; + } + else { + dest[ptr++] = PS; + dest[ptr++] = v & 0xff; + } + break; + case LOWER: + if ((v & ALPHA) != 0) { + if ((GetTextTypeAndValue(length, k + 1) & GetTextTypeAndValue(length, k + 2) & ALPHA) != 0) { + dest[ptr++] = ML; + dest[ptr++] = AL; + mode = ALPHA; + } + else { + dest[ptr++] = AS; + } + dest[ptr++] = v & 0xff; + } + else if ((v & MIXED) != 0) { + dest[ptr++] = ML; + dest[ptr++] = v & 0xff; + mode = MIXED; + } + else if ((GetTextTypeAndValue(input, length, k + 1) & GetTextTypeAndValue(input, length, k + 2) & PUNCTUATION) != 0) { + dest[ptr++] = ML; + dest[ptr++] = PL; + dest[ptr++] = v & 0xff; + mode = PUNCTUATION; + } + else { + dest[ptr++] = PS; + dest[ptr++] = v & 0xff; + } + break; + case MIXED: + if ((v & LOWER) != 0) { + dest[ptr++] = LL; + dest[ptr++] = v & 0xff; + mode = LOWER; + } + else if ((v & ALPHA) != 0) { + dest[ptr++] = AL; + dest[ptr++] = v & 0xff; + mode = ALPHA; + } + else if ((GetTextTypeAndValue(input, length, k + 1) & GetTextTypeAndValue(input, length, k + 2) & PUNCTUATION) != 0) { + dest[ptr++] = PL; + dest[ptr++] = v & 0xff; + mode = PUNCTUATION; + } + else { + dest[ptr++] = PS; + dest[ptr++] = v & 0xff; + } + break; + case PUNCTUATION: + dest[ptr++] = PAL; + mode = ALPHA; + --k; + break; + } + } + if ((ptr & 1) != 0) + dest[ptr++] = PS; + size = (ptr + fullBytes) / 2; + if (size + cwPtr > MAX_DATA_CODEWORDS) { + throw new ArgumentOutOfRangeException("The text is too big."); + } + length = ptr; + ptr = 0; + while (ptr < length) { + v = dest[ptr++]; + if (v >= 30) { + codewords[cwPtr++] = v; + codewords[cwPtr++] = dest[ptr++]; + } + else + codewords[cwPtr++] = v * 30 + dest[ptr++]; + } + } + + protected void TextCompaction(int start, int length) { + TextCompaction(text, start, length); + } + + protected void BasicNumberCompaction(int start, int length) { + BasicNumberCompaction(text, start, length); + } + + private void BasicNumberCompaction(byte[] input, int start, int length) { + int ret = cwPtr; + int retLast = length / 3; + int ni, k; + cwPtr += retLast + 1; + for (k = 0; k <= retLast; ++k) + codewords[ret + k] = 0; + codewords[ret + retLast] = 1; + length += start; + for (ni = start; ni < length; ++ni) { + // multiply by 10 + for (k = retLast; k >= 0; --k) + codewords[ret + k] *= 10; + // add the digit + codewords[ret + retLast] += input[ni] - '0'; + // propagate carry + for (k = retLast; k > 0; --k) { + codewords[ret + k - 1] += codewords[ret + k] / 900; + codewords[ret + k] %= 900; + } + } + } + + private void NumberCompaction(byte[] input, int start, int length) { + int full = (length / 44) * 15; + int size = length % 44; + int k; + if (size == 0) + size = full; + else + size = full + size / 3 + 1; + if (size + cwPtr > MAX_DATA_CODEWORDS) { + throw new ArgumentOutOfRangeException("The text is too big."); + } + length += start; + for (k = start; k < length; k += 44) { + size = length - k < 44 ? length - k : 44; + BasicNumberCompaction(input, k, size); + } + } + + protected void NumberCompaction(int start, int length) { + NumberCompaction(text, start, length); + } + + protected void ByteCompaction6(int start) { + int length = 6; + int ret = cwPtr; + int retLast = 4; + int ni, k; + cwPtr += retLast + 1; + for (k = 0; k <= retLast ; ++k) + codewords[ret + k] = 0; + length += start; + for (ni = start; ni < length; ++ni) { + // multiply by 256 + for (k = retLast; k >= 0; --k) + codewords[ret + k] *= 256; + // add the digit + codewords[ret + retLast] += (int)text[ni] & 0xff; + // propagate carry + for (k = retLast; k > 0; --k) { + codewords[ret + k - 1] += codewords[ret + k] / 900; + codewords[ret + k] %= 900; + } + } + } + + internal void ByteCompaction(int start, int length) { + int k, j; + int size = (length / 6) * 5 + (length % 6); + if (size + cwPtr > MAX_DATA_CODEWORDS) { + throw new ArgumentOutOfRangeException("The text is too big."); + } + length += start; + for (k = start; k < length; k += 6) { + size = length - k < 44 ? length - k : 6; + if (size < 6) { + for (j = 0; j < size; ++j) + codewords[cwPtr++] = (int)text[k + j] & 0xff; + } + else { + ByteCompaction6(k); + } + } + } + + internal void BreakString() { + int textLength = text.Length; + int lastP = 0; + int startN = 0; + int nd = 0; + char c = (char)0; + int k, j; + bool lastTxt, txt; + Segment v; + Segment vp; + Segment vn; + + if ((options & PDF417_FORCE_BINARY) != 0) { + segmentList.Add('B', 0, textLength); + return; + } + for (k = 0; k < textLength; ++k) { + c = (char)(text[k] & 0xff); + if (c >= '0' && c <= '9') { + if (nd == 0) + startN = k; + ++nd; + continue; + } + if (nd >= 13) { + if (lastP != startN) { + c = (char)(text[lastP] & 0xff); + lastTxt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t'; + for (j = lastP; j < startN; ++j) { + c = (char)(text[j] & 0xff); + txt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t'; + if (txt != lastTxt) { + segmentList.Add(lastTxt ? 'T' : 'B', lastP, j); + lastP = j; + lastTxt = txt; + } + } + segmentList.Add(lastTxt ? 'T' : 'B', lastP, startN); + } + segmentList.Add('N', startN, k); + lastP = k; + } + nd = 0; + } + if (nd < 13) + startN = textLength; + if (lastP != startN) { + c = (char)(text[lastP] & 0xff); + lastTxt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t'; + for (j = lastP; j < startN; ++j) { + c = (char)(text[j] & 0xff); + txt = (c >= ' ' && c < 127) || c == '\r' || c == '\n' || c == '\t'; + if (txt != lastTxt) { + segmentList.Add(lastTxt ? 'T' : 'B', lastP, j); + lastP = j; + lastTxt = txt; + } + } + segmentList.Add(lastTxt ? 'T' : 'B', lastP, startN); + } + if (nd >= 13) + segmentList.Add('N', startN, textLength); + //optimize + //merge short binary + for (k = 0; k < segmentList.Size; ++k) { + v = segmentList.Get(k); + vp = segmentList.Get(k - 1); + vn = segmentList.Get(k + 1); + if (CheckSegmentType(v, 'B') && GetSegmentLength(v) == 1) { + if (CheckSegmentType(vp, 'T') && CheckSegmentType(vn, 'T') + && GetSegmentLength(vp) + GetSegmentLength(vn) >= 3) { + vp.end = vn.end; + segmentList.Remove(k); + segmentList.Remove(k); + k = -1; + continue; + } + } + } + //merge text sections + for (k = 0; k < segmentList.Size; ++k) { + v = segmentList.Get(k); + vp = segmentList.Get(k - 1); + vn = segmentList.Get(k + 1); + if (CheckSegmentType(v, 'T') && GetSegmentLength(v) >= 5) { + bool redo = false; + if ((CheckSegmentType(vp, 'B') && GetSegmentLength(vp) == 1) || CheckSegmentType(vp, 'T')) { + redo = true; + v.start = vp.start; + segmentList.Remove(k - 1); + --k; + } + if ((CheckSegmentType(vn, 'B') && GetSegmentLength(vn) == 1) || CheckSegmentType(vn, 'T')) { + redo = true; + v.end = vn.end; + segmentList.Remove(k + 1); + } + if (redo) { + k = -1; + continue; + } + } + } + //merge binary sections + for (k = 0; k < segmentList.Size; ++k) { + v = segmentList.Get(k); + vp = segmentList.Get(k - 1); + vn = segmentList.Get(k + 1); + if (CheckSegmentType(v, 'B')) { + bool redo = false; + if ((CheckSegmentType(vp, 'T') && GetSegmentLength(vp) < 5) || CheckSegmentType(vp, 'B')) { + redo = true; + v.start = vp.start; + segmentList.Remove(k - 1); + --k; + } + if ((CheckSegmentType(vn, 'T') && GetSegmentLength(vn) < 5) || CheckSegmentType(vn, 'B')) { + redo = true; + v.end = vn.end; + segmentList.Remove(k + 1); + } + if (redo) { + k = -1; + continue; + } + } + } + // check if all numbers + if (segmentList.Size == 1 && (v = segmentList.Get(0)).type == 'T' && GetSegmentLength(v) >= 8) { + for (k = v.start; k < v.end; ++k) { + c = (char)(text[k] & 0xff); + if (c < '0' || c > '9') + break; + } + if (k == v.end) + v.type = 'N'; + } + } + + protected void Assemble() { + int k; + if (segmentList.Size == 0) + return; + cwPtr = 1; + for (k = 0; k < segmentList.Size; ++k) { + Segment v = segmentList.Get(k); + switch (v.type) { + case 'T': + if (k != 0) + codewords[cwPtr++] = TEXT_MODE; + TextCompaction(v.start, GetSegmentLength(v)); + break; + case 'N': + codewords[cwPtr++] = NUMERIC_MODE; + NumberCompaction(v.start, GetSegmentLength(v)); + break; + case 'B': + codewords[cwPtr++] = (GetSegmentLength(v) % 6) != 0 ? BYTE_MODE : BYTE_MODE_6; + ByteCompaction(v.start, GetSegmentLength(v)); + break; + } + } + if ((options & PDF417_USE_MACRO) != 0) { + MacroCodes(); + } + + } + + private void MacroCodes() { + if (macroSegmentId < 0) { + throw new InvalidOperationException("macroSegmentId must be >=0"); + } + if (macroSegmentId >= macroSegmentCount) { + throw new InvalidOperationException("macroSegmentId must be < macroSemgentCount"); + } + if (macroSegmentCount < 1) { + throw new InvalidOperationException("macroSemgentCount must be > 0"); + } + + macroIndex = cwPtr; + codewords[cwPtr++] = MACRO_SEGMENT_ID; + Append(macroSegmentId, 5); + + if (macroFileId != null) { + Append(macroFileId); + } + + if (macroSegmentId >= macroSegmentCount-1) { + codewords[cwPtr++] = MACRO_LAST_SEGMENT; + } + + } + + private void Append(int inp, int len) { + StringBuilder sb = new StringBuilder(len+1); + sb.Append(inp); + for(int i = sb.Length; i < len; i++) { + sb.Insert(0, "0"); + } + + byte[] bytes = PdfEncodings.ConvertToBytes(sb.ToString(), "cp437"); + NumberCompaction(bytes, 0, bytes.Length); + } + + private void Append(String s) { + byte[] bytes = PdfEncodings.ConvertToBytes(s, "cp437"); + TextCompaction(bytes, 0, bytes.Length); + } + + protected static int MaxPossibleErrorLevel(int remain) { + int level = 8; + int size = 512; + while (level > 0) { + if (remain >= size) + return level; + --level; + size >>= 1; + } + return 0; + } + + protected void DumpList() { + if (segmentList.Size == 0) + return; + for (int k = 0; k < segmentList.Size; ++k) { + Segment v = segmentList.Get(k); + int len = GetSegmentLength(v); + char[] c = new char[len]; + for (int j = 0; j < len; ++j) { + c[j] = (char)(text[v.start + j] & 0xff); + if (c[j] == '\r') + c[j] = '\n'; + } + Console.WriteLine("" + v.type + new String(c)); + } + } + + protected int GetMaxSquare() { + if (codeColumns > 21) { + codeColumns = 29; + codeRows = 32; + } + else { + codeColumns = 16; + codeRows = 58; + } + return MAX_DATA_CODEWORDS + 2; + } + + /** Paints the barcode. If no exception was thrown a valid barcode is available. */ + public void PaintCode() { + int maxErr, lenErr, tot, pad; + if ((options & PDF417_USE_RAW_CODEWORDS) != 0) { + if (lenCodewords > MAX_DATA_CODEWORDS || lenCodewords < 1 || lenCodewords != codewords[0]) { + throw new ArgumentException("Invalid codeword size."); + } + } + else { + if (text == null) + throw new ArgumentNullException("Text cannot be null."); + if (text.Length > ABSOLUTE_MAX_TEXT_SIZE) { + throw new ArgumentOutOfRangeException("The text is too big."); + } + segmentList = new SegmentList(); + BreakString(); + //dumpList(); + Assemble(); + segmentList = null; + codewords[0] = lenCodewords = cwPtr; + } + maxErr = MaxPossibleErrorLevel(MAX_DATA_CODEWORDS + 2 - lenCodewords); + if ((options & PDF417_USE_ERROR_LEVEL) == 0) { + if (lenCodewords < 41) + errorLevel = 2; + else if (lenCodewords < 161) + errorLevel = 3; + else if (lenCodewords < 321) + errorLevel = 4; + else + errorLevel = 5; + } + if (errorLevel < 0) + errorLevel = 0; + else if (errorLevel > maxErr) + errorLevel = maxErr; + if (codeColumns < 1) + codeColumns = 1; + else if (codeColumns > 30) + codeColumns = 30; + if (codeRows < 3) + codeRows = 3; + else if (codeRows > 90) + codeRows = 90; + lenErr = 2 << errorLevel; + bool fixedColumn = (options & PDF417_FIXED_ROWS) == 0; + bool skipRowColAdjust = false; + tot = lenCodewords + lenErr; + if ((options & PDF417_FIXED_RECTANGLE) != 0) { + tot = codeColumns * codeRows; + if (tot > MAX_DATA_CODEWORDS + 2) { + tot = GetMaxSquare(); + } + if (tot < lenCodewords + lenErr) + tot = lenCodewords + lenErr; + else + skipRowColAdjust = true; + } + else if ((options & (PDF417_FIXED_COLUMNS | PDF417_FIXED_ROWS)) == 0) { + double c, b; + fixedColumn = true; + if (aspectRatio < 0.001) + aspectRatio = 0.001f; + else if (aspectRatio > 1000) + aspectRatio = 1000; + b = 73 * aspectRatio - 4; + c = (-b + Math.Sqrt(b * b + 4 * 17 * aspectRatio * (lenCodewords + lenErr) * yHeight)) / (2 * 17 * aspectRatio); + codeColumns = (int)(c + 0.5); + if (codeColumns < 1) + codeColumns = 1; + else if (codeColumns > 30) + codeColumns = 30; + } + if (!skipRowColAdjust) { + if (fixedColumn) { + codeRows = (tot - 1) / codeColumns + 1; + if (codeRows < 3) + codeRows = 3; + else if (codeRows > 90) { + codeRows = 90; + codeColumns = (tot - 1) / 90 + 1; + } + } + else { + codeColumns = (tot - 1) / codeRows + 1; + if (codeColumns > 30) { + codeColumns = 30; + codeRows = (tot - 1) / 30 + 1; + } + } + tot = codeRows * codeColumns; + } + if (tot > MAX_DATA_CODEWORDS + 2) { + tot = GetMaxSquare(); + } + errorLevel = MaxPossibleErrorLevel(tot - lenCodewords); + lenErr = 2 << errorLevel; + pad = tot - lenErr - lenCodewords; + if ((options & PDF417_USE_MACRO) != 0) { + // the padding comes before the control block + System.Array.Copy(codewords, macroIndex, codewords, macroIndex + pad, pad); + cwPtr = lenCodewords + pad; + while (pad-- != 0) + codewords[macroIndex++] = TEXT_MODE; + } + else { + cwPtr = lenCodewords; + while (pad-- != 0) + codewords[cwPtr++] = TEXT_MODE; + } + codewords[0] = lenCodewords = cwPtr; + CalculateErrorCorrection(lenCodewords); + lenCodewords = tot; + OutPaintCode(); + } + + /** Gets an Image with the barcode. The image will have to be + * scaled in the Y direction by yHeightfor the barcode + * to have the right printing aspect. + * @return the barcode Image + * @throws BadElementException on error + */ + public Image GetImage() { + PaintCode(); + byte[] g4 = CCITTG4Encoder.Compress(outBits, bitColumns, codeRows); + return Image.GetInstance(bitColumns, codeRows, false, Element.CCITTG4, (options & PDF417_INVERT_BITMAP) == 0 ? 0 : Element.CCITT_BLACKIS1, g4, null); + } + + public virtual System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + PaintCode(); + int h = (int)yHeight; + int stride = (bitColumns + 7) / 8; + System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(bitColumns, codeRows * h); + int y = 0; + for (int k = 0; k < codeRows; ++k) { + for (int hh = 0; hh < h; ++hh) { + int p = k * stride; + for (int j = 0; j < bitColumns; ++j) { + int b = outBits[p + (j / 8)] & 0xff; + b <<= j % 8; + bmp.SetPixel(j, y, (b & 0x80) == 0 ? background : foreground); + } + ++y; + } + } + return bmp; + } + + /** Gets the raw image bits of the barcode. The image will have to + * be scaled in the Y direction by yHeight. + * @return The raw barcode image + */ + public byte[] OutBits { + get { + return this.outBits; + } + } + + /** Gets the number of X pixels of outBits. + * @return the number of X pixels of outBits + */ + public int BitColumns { + get { + return this.bitColumns; + } + } + + /** Gets the number of Y pixels of outBits. + * It is also the number of rows in the barcode. + * @return the number of Y pixels of outBits + */ + /** Sets the number of barcode rows. This number may be changed + * to keep the barcode valid. + * @param codeRows the number of barcode rows + */ + public int CodeRows { + set { + this.codeRows = value; + } + get { + return codeRows; + } + } + + /** Sets the number of barcode data columns. + * This number may be changed to keep the barcode valid. + * @param codeColumns the number of barcode data columns + */ + public int CodeColumns { + set { + this.codeColumns = value; + } + get { + return codeColumns; + } + } + + /** Gets the codeword array. This array is always 928 elements long. + * It can be writen to if the option PDF417_USE_RAW_CODEWORDS + * is set. + * @return the codeword array + */ + public int[] Codewords { + get { + return this.codewords; + } + } + + /** Sets the length of the codewords. + * @param lenCodewords the length of the codewords + */ + public int LenCodewords { + set { + this.lenCodewords = value; + } + get { + return lenCodewords; + } + } + + /** Gets the error level correction used for the barcode. It may different + * from the previously set value. + * @return the error level correction used for the barcode + */ + /** Sets the error level correction for the barcode. + * @param errorLevel the error level correction for the barcode + */ + public int ErrorLevel { + set { + this.errorLevel = value; + } + get { + return errorLevel; + } + } + + /** Sets the bytes that form the barcode. This bytes should + * be interpreted in the codepage Cp437. + * @param text the bytes that form the barcode + */ + public byte[] Text { + set { + this.text = value; + } + get { + return text; + } + } + + /** Sets the text that will form the barcode. This text is converted + * to bytes using the encoding Cp437. + * @param s the text that will form the barcode + * @throws UnsupportedEncodingException if the encoding Cp437 is not supported + */ + public void SetText(String s) { + this.text = PdfEncodings.ConvertToBytes(s, "cp437"); + } + + /** Sets the options to generate the barcode. This can be all + * the PDF417_* constants. + * @param options the options to generate the barcode + */ + public int Options { + set { + this.options = value; + } + get { + return options; + } + } + + /** Sets the barcode aspect ratio. A ratio or 0.5 will make the + * barcode width twice as large as the height. + * @param aspectRatio the barcode aspect ratio + */ + public float AspectRatio { + set { + this.aspectRatio = value; + } + get { + return aspectRatio; + } + } + + /** Sets the Y pixel height relative to X. It is usually 3. + * @param yHeight the Y pixel height relative to X + */ + public float YHeight { + set { + this.yHeight = value; + } + get { + return yHeight; + } + } + + protected const int START_PATTERN = 0x1fea8; + protected const int STOP_PATTERN = 0x3fa29; + protected const int START_CODE_SIZE = 17; + protected const int STOP_SIZE = 18; + protected const int MOD = 929; + protected const int ALPHA = 0x10000; + protected const int LOWER = 0x20000; + protected const int MIXED = 0x40000; + protected const int PUNCTUATION = 0x80000; + protected const int ISBYTE = 0x100000; + protected const int BYTESHIFT = 913; + protected const int PL = 25; + protected const int LL = 27; + protected const int AS = 27; + protected const int ML = 28; + protected const int AL = 28; + protected const int PS = 29; + protected const int PAL = 29; + protected const int SPACE = 26; + protected const int TEXT_MODE = 900; + protected const int BYTE_MODE_6 = 924; + protected const int BYTE_MODE = 901; + protected const int NUMERIC_MODE = 902; + protected const int ABSOLUTE_MAX_TEXT_SIZE = 5420; + protected const int MAX_DATA_CODEWORDS = 926; + protected const int MACRO_SEGMENT_ID=928; + protected const int MACRO_LAST_SEGMENT=922; + + private const string MIXED_SET = "0123456789&\r\t,:#-.$/+%*=^"; + private const string PUNCTUATION_SET = ";<>@[\\]_`~!\r\t,:\n-.$/\"|*()?{}'"; + + private static readonly int[][] CLUSTERS = new int[][] + {new int[]{ + 0x1d5c0, 0x1eaf0, 0x1f57c, 0x1d4e0, 0x1ea78, 0x1f53e, 0x1a8c0, 0x1d470, + 0x1a860, 0x15040, 0x1a830, 0x15020, 0x1adc0, 0x1d6f0, 0x1eb7c, 0x1ace0, + 0x1d678, 0x1eb3e, 0x158c0, 0x1ac70, 0x15860, 0x15dc0, 0x1aef0, 0x1d77c, + 0x15ce0, 0x1ae78, 0x1d73e, 0x15c70, 0x1ae3c, 0x15ef0, 0x1af7c, 0x15e78, + 0x1af3e, 0x15f7c, 0x1f5fa, 0x1d2e0, 0x1e978, 0x1f4be, 0x1a4c0, 0x1d270, + 0x1e93c, 0x1a460, 0x1d238, 0x14840, 0x1a430, 0x1d21c, 0x14820, 0x1a418, + 0x14810, 0x1a6e0, 0x1d378, 0x1e9be, 0x14cc0, 0x1a670, 0x1d33c, 0x14c60, + 0x1a638, 0x1d31e, 0x14c30, 0x1a61c, 0x14ee0, 0x1a778, 0x1d3be, 0x14e70, + 0x1a73c, 0x14e38, 0x1a71e, 0x14f78, 0x1a7be, 0x14f3c, 0x14f1e, 0x1a2c0, + 0x1d170, 0x1e8bc, 0x1a260, 0x1d138, 0x1e89e, 0x14440, 0x1a230, 0x1d11c, + 0x14420, 0x1a218, 0x14410, 0x14408, 0x146c0, 0x1a370, 0x1d1bc, 0x14660, + 0x1a338, 0x1d19e, 0x14630, 0x1a31c, 0x14618, 0x1460c, 0x14770, 0x1a3bc, + 0x14738, 0x1a39e, 0x1471c, 0x147bc, 0x1a160, 0x1d0b8, 0x1e85e, 0x14240, + 0x1a130, 0x1d09c, 0x14220, 0x1a118, 0x1d08e, 0x14210, 0x1a10c, 0x14208, + 0x1a106, 0x14360, 0x1a1b8, 0x1d0de, 0x14330, 0x1a19c, 0x14318, 0x1a18e, + 0x1430c, 0x14306, 0x1a1de, 0x1438e, 0x14140, 0x1a0b0, 0x1d05c, 0x14120, + 0x1a098, 0x1d04e, 0x14110, 0x1a08c, 0x14108, 0x1a086, 0x14104, 0x141b0, + 0x14198, 0x1418c, 0x140a0, 0x1d02e, 0x1a04c, 0x1a046, 0x14082, 0x1cae0, + 0x1e578, 0x1f2be, 0x194c0, 0x1ca70, 0x1e53c, 0x19460, 0x1ca38, 0x1e51e, + 0x12840, 0x19430, 0x12820, 0x196e0, 0x1cb78, 0x1e5be, 0x12cc0, 0x19670, + 0x1cb3c, 0x12c60, 0x19638, 0x12c30, 0x12c18, 0x12ee0, 0x19778, 0x1cbbe, + 0x12e70, 0x1973c, 0x12e38, 0x12e1c, 0x12f78, 0x197be, 0x12f3c, 0x12fbe, + 0x1dac0, 0x1ed70, 0x1f6bc, 0x1da60, 0x1ed38, 0x1f69e, 0x1b440, 0x1da30, + 0x1ed1c, 0x1b420, 0x1da18, 0x1ed0e, 0x1b410, 0x1da0c, 0x192c0, 0x1c970, + 0x1e4bc, 0x1b6c0, 0x19260, 0x1c938, 0x1e49e, 0x1b660, 0x1db38, 0x1ed9e, + 0x16c40, 0x12420, 0x19218, 0x1c90e, 0x16c20, 0x1b618, 0x16c10, 0x126c0, + 0x19370, 0x1c9bc, 0x16ec0, 0x12660, 0x19338, 0x1c99e, 0x16e60, 0x1b738, + 0x1db9e, 0x16e30, 0x12618, 0x16e18, 0x12770, 0x193bc, 0x16f70, 0x12738, + 0x1939e, 0x16f38, 0x1b79e, 0x16f1c, 0x127bc, 0x16fbc, 0x1279e, 0x16f9e, + 0x1d960, 0x1ecb8, 0x1f65e, 0x1b240, 0x1d930, 0x1ec9c, 0x1b220, 0x1d918, + 0x1ec8e, 0x1b210, 0x1d90c, 0x1b208, 0x1b204, 0x19160, 0x1c8b8, 0x1e45e, + 0x1b360, 0x19130, 0x1c89c, 0x16640, 0x12220, 0x1d99c, 0x1c88e, 0x16620, + 0x12210, 0x1910c, 0x16610, 0x1b30c, 0x19106, 0x12204, 0x12360, 0x191b8, + 0x1c8de, 0x16760, 0x12330, 0x1919c, 0x16730, 0x1b39c, 0x1918e, 0x16718, + 0x1230c, 0x12306, 0x123b8, 0x191de, 0x167b8, 0x1239c, 0x1679c, 0x1238e, + 0x1678e, 0x167de, 0x1b140, 0x1d8b0, 0x1ec5c, 0x1b120, 0x1d898, 0x1ec4e, + 0x1b110, 0x1d88c, 0x1b108, 0x1d886, 0x1b104, 0x1b102, 0x12140, 0x190b0, + 0x1c85c, 0x16340, 0x12120, 0x19098, 0x1c84e, 0x16320, 0x1b198, 0x1d8ce, + 0x16310, 0x12108, 0x19086, 0x16308, 0x1b186, 0x16304, 0x121b0, 0x190dc, + 0x163b0, 0x12198, 0x190ce, 0x16398, 0x1b1ce, 0x1638c, 0x12186, 0x16386, + 0x163dc, 0x163ce, 0x1b0a0, 0x1d858, 0x1ec2e, 0x1b090, 0x1d84c, 0x1b088, + 0x1d846, 0x1b084, 0x1b082, 0x120a0, 0x19058, 0x1c82e, 0x161a0, 0x12090, + 0x1904c, 0x16190, 0x1b0cc, 0x19046, 0x16188, 0x12084, 0x16184, 0x12082, + 0x120d8, 0x161d8, 0x161cc, 0x161c6, 0x1d82c, 0x1d826, 0x1b042, 0x1902c, + 0x12048, 0x160c8, 0x160c4, 0x160c2, 0x18ac0, 0x1c570, 0x1e2bc, 0x18a60, + 0x1c538, 0x11440, 0x18a30, 0x1c51c, 0x11420, 0x18a18, 0x11410, 0x11408, + 0x116c0, 0x18b70, 0x1c5bc, 0x11660, 0x18b38, 0x1c59e, 0x11630, 0x18b1c, + 0x11618, 0x1160c, 0x11770, 0x18bbc, 0x11738, 0x18b9e, 0x1171c, 0x117bc, + 0x1179e, 0x1cd60, 0x1e6b8, 0x1f35e, 0x19a40, 0x1cd30, 0x1e69c, 0x19a20, + 0x1cd18, 0x1e68e, 0x19a10, 0x1cd0c, 0x19a08, 0x1cd06, 0x18960, 0x1c4b8, + 0x1e25e, 0x19b60, 0x18930, 0x1c49c, 0x13640, 0x11220, 0x1cd9c, 0x1c48e, + 0x13620, 0x19b18, 0x1890c, 0x13610, 0x11208, 0x13608, 0x11360, 0x189b8, + 0x1c4de, 0x13760, 0x11330, 0x1cdde, 0x13730, 0x19b9c, 0x1898e, 0x13718, + 0x1130c, 0x1370c, 0x113b8, 0x189de, 0x137b8, 0x1139c, 0x1379c, 0x1138e, + 0x113de, 0x137de, 0x1dd40, 0x1eeb0, 0x1f75c, 0x1dd20, 0x1ee98, 0x1f74e, + 0x1dd10, 0x1ee8c, 0x1dd08, 0x1ee86, 0x1dd04, 0x19940, 0x1ccb0, 0x1e65c, + 0x1bb40, 0x19920, 0x1eedc, 0x1e64e, 0x1bb20, 0x1dd98, 0x1eece, 0x1bb10, + 0x19908, 0x1cc86, 0x1bb08, 0x1dd86, 0x19902, 0x11140, 0x188b0, 0x1c45c, + 0x13340, 0x11120, 0x18898, 0x1c44e, 0x17740, 0x13320, 0x19998, 0x1ccce, + 0x17720, 0x1bb98, 0x1ddce, 0x18886, 0x17710, 0x13308, 0x19986, 0x17708, + 0x11102, 0x111b0, 0x188dc, 0x133b0, 0x11198, 0x188ce, 0x177b0, 0x13398, + 0x199ce, 0x17798, 0x1bbce, 0x11186, 0x13386, 0x111dc, 0x133dc, 0x111ce, + 0x177dc, 0x133ce, 0x1dca0, 0x1ee58, 0x1f72e, 0x1dc90, 0x1ee4c, 0x1dc88, + 0x1ee46, 0x1dc84, 0x1dc82, 0x198a0, 0x1cc58, 0x1e62e, 0x1b9a0, 0x19890, + 0x1ee6e, 0x1b990, 0x1dccc, 0x1cc46, 0x1b988, 0x19884, 0x1b984, 0x19882, + 0x1b982, 0x110a0, 0x18858, 0x1c42e, 0x131a0, 0x11090, 0x1884c, 0x173a0, + 0x13190, 0x198cc, 0x18846, 0x17390, 0x1b9cc, 0x11084, 0x17388, 0x13184, + 0x11082, 0x13182, 0x110d8, 0x1886e, 0x131d8, 0x110cc, 0x173d8, 0x131cc, + 0x110c6, 0x173cc, 0x131c6, 0x110ee, 0x173ee, 0x1dc50, 0x1ee2c, 0x1dc48, + 0x1ee26, 0x1dc44, 0x1dc42, 0x19850, 0x1cc2c, 0x1b8d0, 0x19848, 0x1cc26, + 0x1b8c8, 0x1dc66, 0x1b8c4, 0x19842, 0x1b8c2, 0x11050, 0x1882c, 0x130d0, + 0x11048, 0x18826, 0x171d0, 0x130c8, 0x19866, 0x171c8, 0x1b8e6, 0x11042, + 0x171c4, 0x130c2, 0x171c2, 0x130ec, 0x171ec, 0x171e6, 0x1ee16, 0x1dc22, + 0x1cc16, 0x19824, 0x19822, 0x11028, 0x13068, 0x170e8, 0x11022, 0x13062, + 0x18560, 0x10a40, 0x18530, 0x10a20, 0x18518, 0x1c28e, 0x10a10, 0x1850c, + 0x10a08, 0x18506, 0x10b60, 0x185b8, 0x1c2de, 0x10b30, 0x1859c, 0x10b18, + 0x1858e, 0x10b0c, 0x10b06, 0x10bb8, 0x185de, 0x10b9c, 0x10b8e, 0x10bde, + 0x18d40, 0x1c6b0, 0x1e35c, 0x18d20, 0x1c698, 0x18d10, 0x1c68c, 0x18d08, + 0x1c686, 0x18d04, 0x10940, 0x184b0, 0x1c25c, 0x11b40, 0x10920, 0x1c6dc, + 0x1c24e, 0x11b20, 0x18d98, 0x1c6ce, 0x11b10, 0x10908, 0x18486, 0x11b08, + 0x18d86, 0x10902, 0x109b0, 0x184dc, 0x11bb0, 0x10998, 0x184ce, 0x11b98, + 0x18dce, 0x11b8c, 0x10986, 0x109dc, 0x11bdc, 0x109ce, 0x11bce, 0x1cea0, + 0x1e758, 0x1f3ae, 0x1ce90, 0x1e74c, 0x1ce88, 0x1e746, 0x1ce84, 0x1ce82, + 0x18ca0, 0x1c658, 0x19da0, 0x18c90, 0x1c64c, 0x19d90, 0x1cecc, 0x1c646, + 0x19d88, 0x18c84, 0x19d84, 0x18c82, 0x19d82, 0x108a0, 0x18458, 0x119a0, + 0x10890, 0x1c66e, 0x13ba0, 0x11990, 0x18ccc, 0x18446, 0x13b90, 0x19dcc, + 0x10884, 0x13b88, 0x11984, 0x10882, 0x11982, 0x108d8, 0x1846e, 0x119d8, + 0x108cc, 0x13bd8, 0x119cc, 0x108c6, 0x13bcc, 0x119c6, 0x108ee, 0x119ee, + 0x13bee, 0x1ef50, 0x1f7ac, 0x1ef48, 0x1f7a6, 0x1ef44, 0x1ef42, 0x1ce50, + 0x1e72c, 0x1ded0, 0x1ef6c, 0x1e726, 0x1dec8, 0x1ef66, 0x1dec4, 0x1ce42, + 0x1dec2, 0x18c50, 0x1c62c, 0x19cd0, 0x18c48, 0x1c626, 0x1bdd0, 0x19cc8, + 0x1ce66, 0x1bdc8, 0x1dee6, 0x18c42, 0x1bdc4, 0x19cc2, 0x1bdc2, 0x10850, + 0x1842c, 0x118d0, 0x10848, 0x18426, 0x139d0, 0x118c8, 0x18c66, 0x17bd0, + 0x139c8, 0x19ce6, 0x10842, 0x17bc8, 0x1bde6, 0x118c2, 0x17bc4, 0x1086c, + 0x118ec, 0x10866, 0x139ec, 0x118e6, 0x17bec, 0x139e6, 0x17be6, 0x1ef28, + 0x1f796, 0x1ef24, 0x1ef22, 0x1ce28, 0x1e716, 0x1de68, 0x1ef36, 0x1de64, + 0x1ce22, 0x1de62, 0x18c28, 0x1c616, 0x19c68, 0x18c24, 0x1bce8, 0x19c64, + 0x18c22, 0x1bce4, 0x19c62, 0x1bce2, 0x10828, 0x18416, 0x11868, 0x18c36, + 0x138e8, 0x11864, 0x10822, 0x179e8, 0x138e4, 0x11862, 0x179e4, 0x138e2, + 0x179e2, 0x11876, 0x179f6, 0x1ef12, 0x1de34, 0x1de32, 0x19c34, 0x1bc74, + 0x1bc72, 0x11834, 0x13874, 0x178f4, 0x178f2, 0x10540, 0x10520, 0x18298, + 0x10510, 0x10508, 0x10504, 0x105b0, 0x10598, 0x1058c, 0x10586, 0x105dc, + 0x105ce, 0x186a0, 0x18690, 0x1c34c, 0x18688, 0x1c346, 0x18684, 0x18682, + 0x104a0, 0x18258, 0x10da0, 0x186d8, 0x1824c, 0x10d90, 0x186cc, 0x10d88, + 0x186c6, 0x10d84, 0x10482, 0x10d82, 0x104d8, 0x1826e, 0x10dd8, 0x186ee, + 0x10dcc, 0x104c6, 0x10dc6, 0x104ee, 0x10dee, 0x1c750, 0x1c748, 0x1c744, + 0x1c742, 0x18650, 0x18ed0, 0x1c76c, 0x1c326, 0x18ec8, 0x1c766, 0x18ec4, + 0x18642, 0x18ec2, 0x10450, 0x10cd0, 0x10448, 0x18226, 0x11dd0, 0x10cc8, + 0x10444, 0x11dc8, 0x10cc4, 0x10442, 0x11dc4, 0x10cc2, 0x1046c, 0x10cec, + 0x10466, 0x11dec, 0x10ce6, 0x11de6, 0x1e7a8, 0x1e7a4, 0x1e7a2, 0x1c728, + 0x1cf68, 0x1e7b6, 0x1cf64, 0x1c722, 0x1cf62, 0x18628, 0x1c316, 0x18e68, + 0x1c736, 0x19ee8, 0x18e64, 0x18622, 0x19ee4, 0x18e62, 0x19ee2, 0x10428, + 0x18216, 0x10c68, 0x18636, 0x11ce8, 0x10c64, 0x10422, 0x13de8, 0x11ce4, + 0x10c62, 0x13de4, 0x11ce2, 0x10436, 0x10c76, 0x11cf6, 0x13df6, 0x1f7d4, + 0x1f7d2, 0x1e794, 0x1efb4, 0x1e792, 0x1efb2, 0x1c714, 0x1cf34, 0x1c712, + 0x1df74, 0x1cf32, 0x1df72, 0x18614, 0x18e34, 0x18612, 0x19e74, 0x18e32, + 0x1bef4 + }, new int[]{ + 0x1f560, 0x1fab8, 0x1ea40, 0x1f530, 0x1fa9c, 0x1ea20, 0x1f518, 0x1fa8e, + 0x1ea10, 0x1f50c, 0x1ea08, 0x1f506, 0x1ea04, 0x1eb60, 0x1f5b8, 0x1fade, + 0x1d640, 0x1eb30, 0x1f59c, 0x1d620, 0x1eb18, 0x1f58e, 0x1d610, 0x1eb0c, + 0x1d608, 0x1eb06, 0x1d604, 0x1d760, 0x1ebb8, 0x1f5de, 0x1ae40, 0x1d730, + 0x1eb9c, 0x1ae20, 0x1d718, 0x1eb8e, 0x1ae10, 0x1d70c, 0x1ae08, 0x1d706, + 0x1ae04, 0x1af60, 0x1d7b8, 0x1ebde, 0x15e40, 0x1af30, 0x1d79c, 0x15e20, + 0x1af18, 0x1d78e, 0x15e10, 0x1af0c, 0x15e08, 0x1af06, 0x15f60, 0x1afb8, + 0x1d7de, 0x15f30, 0x1af9c, 0x15f18, 0x1af8e, 0x15f0c, 0x15fb8, 0x1afde, + 0x15f9c, 0x15f8e, 0x1e940, 0x1f4b0, 0x1fa5c, 0x1e920, 0x1f498, 0x1fa4e, + 0x1e910, 0x1f48c, 0x1e908, 0x1f486, 0x1e904, 0x1e902, 0x1d340, 0x1e9b0, + 0x1f4dc, 0x1d320, 0x1e998, 0x1f4ce, 0x1d310, 0x1e98c, 0x1d308, 0x1e986, + 0x1d304, 0x1d302, 0x1a740, 0x1d3b0, 0x1e9dc, 0x1a720, 0x1d398, 0x1e9ce, + 0x1a710, 0x1d38c, 0x1a708, 0x1d386, 0x1a704, 0x1a702, 0x14f40, 0x1a7b0, + 0x1d3dc, 0x14f20, 0x1a798, 0x1d3ce, 0x14f10, 0x1a78c, 0x14f08, 0x1a786, + 0x14f04, 0x14fb0, 0x1a7dc, 0x14f98, 0x1a7ce, 0x14f8c, 0x14f86, 0x14fdc, + 0x14fce, 0x1e8a0, 0x1f458, 0x1fa2e, 0x1e890, 0x1f44c, 0x1e888, 0x1f446, + 0x1e884, 0x1e882, 0x1d1a0, 0x1e8d8, 0x1f46e, 0x1d190, 0x1e8cc, 0x1d188, + 0x1e8c6, 0x1d184, 0x1d182, 0x1a3a0, 0x1d1d8, 0x1e8ee, 0x1a390, 0x1d1cc, + 0x1a388, 0x1d1c6, 0x1a384, 0x1a382, 0x147a0, 0x1a3d8, 0x1d1ee, 0x14790, + 0x1a3cc, 0x14788, 0x1a3c6, 0x14784, 0x14782, 0x147d8, 0x1a3ee, 0x147cc, + 0x147c6, 0x147ee, 0x1e850, 0x1f42c, 0x1e848, 0x1f426, 0x1e844, 0x1e842, + 0x1d0d0, 0x1e86c, 0x1d0c8, 0x1e866, 0x1d0c4, 0x1d0c2, 0x1a1d0, 0x1d0ec, + 0x1a1c8, 0x1d0e6, 0x1a1c4, 0x1a1c2, 0x143d0, 0x1a1ec, 0x143c8, 0x1a1e6, + 0x143c4, 0x143c2, 0x143ec, 0x143e6, 0x1e828, 0x1f416, 0x1e824, 0x1e822, + 0x1d068, 0x1e836, 0x1d064, 0x1d062, 0x1a0e8, 0x1d076, 0x1a0e4, 0x1a0e2, + 0x141e8, 0x1a0f6, 0x141e4, 0x141e2, 0x1e814, 0x1e812, 0x1d034, 0x1d032, + 0x1a074, 0x1a072, 0x1e540, 0x1f2b0, 0x1f95c, 0x1e520, 0x1f298, 0x1f94e, + 0x1e510, 0x1f28c, 0x1e508, 0x1f286, 0x1e504, 0x1e502, 0x1cb40, 0x1e5b0, + 0x1f2dc, 0x1cb20, 0x1e598, 0x1f2ce, 0x1cb10, 0x1e58c, 0x1cb08, 0x1e586, + 0x1cb04, 0x1cb02, 0x19740, 0x1cbb0, 0x1e5dc, 0x19720, 0x1cb98, 0x1e5ce, + 0x19710, 0x1cb8c, 0x19708, 0x1cb86, 0x19704, 0x19702, 0x12f40, 0x197b0, + 0x1cbdc, 0x12f20, 0x19798, 0x1cbce, 0x12f10, 0x1978c, 0x12f08, 0x19786, + 0x12f04, 0x12fb0, 0x197dc, 0x12f98, 0x197ce, 0x12f8c, 0x12f86, 0x12fdc, + 0x12fce, 0x1f6a0, 0x1fb58, 0x16bf0, 0x1f690, 0x1fb4c, 0x169f8, 0x1f688, + 0x1fb46, 0x168fc, 0x1f684, 0x1f682, 0x1e4a0, 0x1f258, 0x1f92e, 0x1eda0, + 0x1e490, 0x1fb6e, 0x1ed90, 0x1f6cc, 0x1f246, 0x1ed88, 0x1e484, 0x1ed84, + 0x1e482, 0x1ed82, 0x1c9a0, 0x1e4d8, 0x1f26e, 0x1dba0, 0x1c990, 0x1e4cc, + 0x1db90, 0x1edcc, 0x1e4c6, 0x1db88, 0x1c984, 0x1db84, 0x1c982, 0x1db82, + 0x193a0, 0x1c9d8, 0x1e4ee, 0x1b7a0, 0x19390, 0x1c9cc, 0x1b790, 0x1dbcc, + 0x1c9c6, 0x1b788, 0x19384, 0x1b784, 0x19382, 0x1b782, 0x127a0, 0x193d8, + 0x1c9ee, 0x16fa0, 0x12790, 0x193cc, 0x16f90, 0x1b7cc, 0x193c6, 0x16f88, + 0x12784, 0x16f84, 0x12782, 0x127d8, 0x193ee, 0x16fd8, 0x127cc, 0x16fcc, + 0x127c6, 0x16fc6, 0x127ee, 0x1f650, 0x1fb2c, 0x165f8, 0x1f648, 0x1fb26, + 0x164fc, 0x1f644, 0x1647e, 0x1f642, 0x1e450, 0x1f22c, 0x1ecd0, 0x1e448, + 0x1f226, 0x1ecc8, 0x1f666, 0x1ecc4, 0x1e442, 0x1ecc2, 0x1c8d0, 0x1e46c, + 0x1d9d0, 0x1c8c8, 0x1e466, 0x1d9c8, 0x1ece6, 0x1d9c4, 0x1c8c2, 0x1d9c2, + 0x191d0, 0x1c8ec, 0x1b3d0, 0x191c8, 0x1c8e6, 0x1b3c8, 0x1d9e6, 0x1b3c4, + 0x191c2, 0x1b3c2, 0x123d0, 0x191ec, 0x167d0, 0x123c8, 0x191e6, 0x167c8, + 0x1b3e6, 0x167c4, 0x123c2, 0x167c2, 0x123ec, 0x167ec, 0x123e6, 0x167e6, + 0x1f628, 0x1fb16, 0x162fc, 0x1f624, 0x1627e, 0x1f622, 0x1e428, 0x1f216, + 0x1ec68, 0x1f636, 0x1ec64, 0x1e422, 0x1ec62, 0x1c868, 0x1e436, 0x1d8e8, + 0x1c864, 0x1d8e4, 0x1c862, 0x1d8e2, 0x190e8, 0x1c876, 0x1b1e8, 0x1d8f6, + 0x1b1e4, 0x190e2, 0x1b1e2, 0x121e8, 0x190f6, 0x163e8, 0x121e4, 0x163e4, + 0x121e2, 0x163e2, 0x121f6, 0x163f6, 0x1f614, 0x1617e, 0x1f612, 0x1e414, + 0x1ec34, 0x1e412, 0x1ec32, 0x1c834, 0x1d874, 0x1c832, 0x1d872, 0x19074, + 0x1b0f4, 0x19072, 0x1b0f2, 0x120f4, 0x161f4, 0x120f2, 0x161f2, 0x1f60a, + 0x1e40a, 0x1ec1a, 0x1c81a, 0x1d83a, 0x1903a, 0x1b07a, 0x1e2a0, 0x1f158, + 0x1f8ae, 0x1e290, 0x1f14c, 0x1e288, 0x1f146, 0x1e284, 0x1e282, 0x1c5a0, + 0x1e2d8, 0x1f16e, 0x1c590, 0x1e2cc, 0x1c588, 0x1e2c6, 0x1c584, 0x1c582, + 0x18ba0, 0x1c5d8, 0x1e2ee, 0x18b90, 0x1c5cc, 0x18b88, 0x1c5c6, 0x18b84, + 0x18b82, 0x117a0, 0x18bd8, 0x1c5ee, 0x11790, 0x18bcc, 0x11788, 0x18bc6, + 0x11784, 0x11782, 0x117d8, 0x18bee, 0x117cc, 0x117c6, 0x117ee, 0x1f350, + 0x1f9ac, 0x135f8, 0x1f348, 0x1f9a6, 0x134fc, 0x1f344, 0x1347e, 0x1f342, + 0x1e250, 0x1f12c, 0x1e6d0, 0x1e248, 0x1f126, 0x1e6c8, 0x1f366, 0x1e6c4, + 0x1e242, 0x1e6c2, 0x1c4d0, 0x1e26c, 0x1cdd0, 0x1c4c8, 0x1e266, 0x1cdc8, + 0x1e6e6, 0x1cdc4, 0x1c4c2, 0x1cdc2, 0x189d0, 0x1c4ec, 0x19bd0, 0x189c8, + 0x1c4e6, 0x19bc8, 0x1cde6, 0x19bc4, 0x189c2, 0x19bc2, 0x113d0, 0x189ec, + 0x137d0, 0x113c8, 0x189e6, 0x137c8, 0x19be6, 0x137c4, 0x113c2, 0x137c2, + 0x113ec, 0x137ec, 0x113e6, 0x137e6, 0x1fba8, 0x175f0, 0x1bafc, 0x1fba4, + 0x174f8, 0x1ba7e, 0x1fba2, 0x1747c, 0x1743e, 0x1f328, 0x1f996, 0x132fc, + 0x1f768, 0x1fbb6, 0x176fc, 0x1327e, 0x1f764, 0x1f322, 0x1767e, 0x1f762, + 0x1e228, 0x1f116, 0x1e668, 0x1e224, 0x1eee8, 0x1f776, 0x1e222, 0x1eee4, + 0x1e662, 0x1eee2, 0x1c468, 0x1e236, 0x1cce8, 0x1c464, 0x1dde8, 0x1cce4, + 0x1c462, 0x1dde4, 0x1cce2, 0x1dde2, 0x188e8, 0x1c476, 0x199e8, 0x188e4, + 0x1bbe8, 0x199e4, 0x188e2, 0x1bbe4, 0x199e2, 0x1bbe2, 0x111e8, 0x188f6, + 0x133e8, 0x111e4, 0x177e8, 0x133e4, 0x111e2, 0x177e4, 0x133e2, 0x177e2, + 0x111f6, 0x133f6, 0x1fb94, 0x172f8, 0x1b97e, 0x1fb92, 0x1727c, 0x1723e, + 0x1f314, 0x1317e, 0x1f734, 0x1f312, 0x1737e, 0x1f732, 0x1e214, 0x1e634, + 0x1e212, 0x1ee74, 0x1e632, 0x1ee72, 0x1c434, 0x1cc74, 0x1c432, 0x1dcf4, + 0x1cc72, 0x1dcf2, 0x18874, 0x198f4, 0x18872, 0x1b9f4, 0x198f2, 0x1b9f2, + 0x110f4, 0x131f4, 0x110f2, 0x173f4, 0x131f2, 0x173f2, 0x1fb8a, 0x1717c, + 0x1713e, 0x1f30a, 0x1f71a, 0x1e20a, 0x1e61a, 0x1ee3a, 0x1c41a, 0x1cc3a, + 0x1dc7a, 0x1883a, 0x1987a, 0x1b8fa, 0x1107a, 0x130fa, 0x171fa, 0x170be, + 0x1e150, 0x1f0ac, 0x1e148, 0x1f0a6, 0x1e144, 0x1e142, 0x1c2d0, 0x1e16c, + 0x1c2c8, 0x1e166, 0x1c2c4, 0x1c2c2, 0x185d0, 0x1c2ec, 0x185c8, 0x1c2e6, + 0x185c4, 0x185c2, 0x10bd0, 0x185ec, 0x10bc8, 0x185e6, 0x10bc4, 0x10bc2, + 0x10bec, 0x10be6, 0x1f1a8, 0x1f8d6, 0x11afc, 0x1f1a4, 0x11a7e, 0x1f1a2, + 0x1e128, 0x1f096, 0x1e368, 0x1e124, 0x1e364, 0x1e122, 0x1e362, 0x1c268, + 0x1e136, 0x1c6e8, 0x1c264, 0x1c6e4, 0x1c262, 0x1c6e2, 0x184e8, 0x1c276, + 0x18de8, 0x184e4, 0x18de4, 0x184e2, 0x18de2, 0x109e8, 0x184f6, 0x11be8, + 0x109e4, 0x11be4, 0x109e2, 0x11be2, 0x109f6, 0x11bf6, 0x1f9d4, 0x13af8, + 0x19d7e, 0x1f9d2, 0x13a7c, 0x13a3e, 0x1f194, 0x1197e, 0x1f3b4, 0x1f192, + 0x13b7e, 0x1f3b2, 0x1e114, 0x1e334, 0x1e112, 0x1e774, 0x1e332, 0x1e772, + 0x1c234, 0x1c674, 0x1c232, 0x1cef4, 0x1c672, 0x1cef2, 0x18474, 0x18cf4, + 0x18472, 0x19df4, 0x18cf2, 0x19df2, 0x108f4, 0x119f4, 0x108f2, 0x13bf4, + 0x119f2, 0x13bf2, 0x17af0, 0x1bd7c, 0x17a78, 0x1bd3e, 0x17a3c, 0x17a1e, + 0x1f9ca, 0x1397c, 0x1fbda, 0x17b7c, 0x1393e, 0x17b3e, 0x1f18a, 0x1f39a, + 0x1f7ba, 0x1e10a, 0x1e31a, 0x1e73a, 0x1ef7a, 0x1c21a, 0x1c63a, 0x1ce7a, + 0x1defa, 0x1843a, 0x18c7a, 0x19cfa, 0x1bdfa, 0x1087a, 0x118fa, 0x139fa, + 0x17978, 0x1bcbe, 0x1793c, 0x1791e, 0x138be, 0x179be, 0x178bc, 0x1789e, + 0x1785e, 0x1e0a8, 0x1e0a4, 0x1e0a2, 0x1c168, 0x1e0b6, 0x1c164, 0x1c162, + 0x182e8, 0x1c176, 0x182e4, 0x182e2, 0x105e8, 0x182f6, 0x105e4, 0x105e2, + 0x105f6, 0x1f0d4, 0x10d7e, 0x1f0d2, 0x1e094, 0x1e1b4, 0x1e092, 0x1e1b2, + 0x1c134, 0x1c374, 0x1c132, 0x1c372, 0x18274, 0x186f4, 0x18272, 0x186f2, + 0x104f4, 0x10df4, 0x104f2, 0x10df2, 0x1f8ea, 0x11d7c, 0x11d3e, 0x1f0ca, + 0x1f1da, 0x1e08a, 0x1e19a, 0x1e3ba, 0x1c11a, 0x1c33a, 0x1c77a, 0x1823a, + 0x1867a, 0x18efa, 0x1047a, 0x10cfa, 0x11dfa, 0x13d78, 0x19ebe, 0x13d3c, + 0x13d1e, 0x11cbe, 0x13dbe, 0x17d70, 0x1bebc, 0x17d38, 0x1be9e, 0x17d1c, + 0x17d0e, 0x13cbc, 0x17dbc, 0x13c9e, 0x17d9e, 0x17cb8, 0x1be5e, 0x17c9c, + 0x17c8e, 0x13c5e, 0x17cde, 0x17c5c, 0x17c4e, 0x17c2e, 0x1c0b4, 0x1c0b2, + 0x18174, 0x18172, 0x102f4, 0x102f2, 0x1e0da, 0x1c09a, 0x1c1ba, 0x1813a, + 0x1837a, 0x1027a, 0x106fa, 0x10ebe, 0x11ebc, 0x11e9e, 0x13eb8, 0x19f5e, + 0x13e9c, 0x13e8e, 0x11e5e, 0x13ede, 0x17eb0, 0x1bf5c, 0x17e98, 0x1bf4e, + 0x17e8c, 0x17e86, 0x13e5c, 0x17edc, 0x13e4e, 0x17ece, 0x17e58, 0x1bf2e, + 0x17e4c, 0x17e46, 0x13e2e, 0x17e6e, 0x17e2c, 0x17e26, 0x10f5e, 0x11f5c, + 0x11f4e, 0x13f58, 0x19fae, 0x13f4c, 0x13f46, 0x11f2e, 0x13f6e, 0x13f2c, + 0x13f26 + }, new int[]{ + 0x1abe0, 0x1d5f8, 0x153c0, 0x1a9f0, 0x1d4fc, 0x151e0, 0x1a8f8, 0x1d47e, + 0x150f0, 0x1a87c, 0x15078, 0x1fad0, 0x15be0, 0x1adf8, 0x1fac8, 0x159f0, + 0x1acfc, 0x1fac4, 0x158f8, 0x1ac7e, 0x1fac2, 0x1587c, 0x1f5d0, 0x1faec, + 0x15df8, 0x1f5c8, 0x1fae6, 0x15cfc, 0x1f5c4, 0x15c7e, 0x1f5c2, 0x1ebd0, + 0x1f5ec, 0x1ebc8, 0x1f5e6, 0x1ebc4, 0x1ebc2, 0x1d7d0, 0x1ebec, 0x1d7c8, + 0x1ebe6, 0x1d7c4, 0x1d7c2, 0x1afd0, 0x1d7ec, 0x1afc8, 0x1d7e6, 0x1afc4, + 0x14bc0, 0x1a5f0, 0x1d2fc, 0x149e0, 0x1a4f8, 0x1d27e, 0x148f0, 0x1a47c, + 0x14878, 0x1a43e, 0x1483c, 0x1fa68, 0x14df0, 0x1a6fc, 0x1fa64, 0x14cf8, + 0x1a67e, 0x1fa62, 0x14c7c, 0x14c3e, 0x1f4e8, 0x1fa76, 0x14efc, 0x1f4e4, + 0x14e7e, 0x1f4e2, 0x1e9e8, 0x1f4f6, 0x1e9e4, 0x1e9e2, 0x1d3e8, 0x1e9f6, + 0x1d3e4, 0x1d3e2, 0x1a7e8, 0x1d3f6, 0x1a7e4, 0x1a7e2, 0x145e0, 0x1a2f8, + 0x1d17e, 0x144f0, 0x1a27c, 0x14478, 0x1a23e, 0x1443c, 0x1441e, 0x1fa34, + 0x146f8, 0x1a37e, 0x1fa32, 0x1467c, 0x1463e, 0x1f474, 0x1477e, 0x1f472, + 0x1e8f4, 0x1e8f2, 0x1d1f4, 0x1d1f2, 0x1a3f4, 0x1a3f2, 0x142f0, 0x1a17c, + 0x14278, 0x1a13e, 0x1423c, 0x1421e, 0x1fa1a, 0x1437c, 0x1433e, 0x1f43a, + 0x1e87a, 0x1d0fa, 0x14178, 0x1a0be, 0x1413c, 0x1411e, 0x141be, 0x140bc, + 0x1409e, 0x12bc0, 0x195f0, 0x1cafc, 0x129e0, 0x194f8, 0x1ca7e, 0x128f0, + 0x1947c, 0x12878, 0x1943e, 0x1283c, 0x1f968, 0x12df0, 0x196fc, 0x1f964, + 0x12cf8, 0x1967e, 0x1f962, 0x12c7c, 0x12c3e, 0x1f2e8, 0x1f976, 0x12efc, + 0x1f2e4, 0x12e7e, 0x1f2e2, 0x1e5e8, 0x1f2f6, 0x1e5e4, 0x1e5e2, 0x1cbe8, + 0x1e5f6, 0x1cbe4, 0x1cbe2, 0x197e8, 0x1cbf6, 0x197e4, 0x197e2, 0x1b5e0, + 0x1daf8, 0x1ed7e, 0x169c0, 0x1b4f0, 0x1da7c, 0x168e0, 0x1b478, 0x1da3e, + 0x16870, 0x1b43c, 0x16838, 0x1b41e, 0x1681c, 0x125e0, 0x192f8, 0x1c97e, + 0x16de0, 0x124f0, 0x1927c, 0x16cf0, 0x1b67c, 0x1923e, 0x16c78, 0x1243c, + 0x16c3c, 0x1241e, 0x16c1e, 0x1f934, 0x126f8, 0x1937e, 0x1fb74, 0x1f932, + 0x16ef8, 0x1267c, 0x1fb72, 0x16e7c, 0x1263e, 0x16e3e, 0x1f274, 0x1277e, + 0x1f6f4, 0x1f272, 0x16f7e, 0x1f6f2, 0x1e4f4, 0x1edf4, 0x1e4f2, 0x1edf2, + 0x1c9f4, 0x1dbf4, 0x1c9f2, 0x1dbf2, 0x193f4, 0x193f2, 0x165c0, 0x1b2f0, + 0x1d97c, 0x164e0, 0x1b278, 0x1d93e, 0x16470, 0x1b23c, 0x16438, 0x1b21e, + 0x1641c, 0x1640e, 0x122f0, 0x1917c, 0x166f0, 0x12278, 0x1913e, 0x16678, + 0x1b33e, 0x1663c, 0x1221e, 0x1661e, 0x1f91a, 0x1237c, 0x1fb3a, 0x1677c, + 0x1233e, 0x1673e, 0x1f23a, 0x1f67a, 0x1e47a, 0x1ecfa, 0x1c8fa, 0x1d9fa, + 0x191fa, 0x162e0, 0x1b178, 0x1d8be, 0x16270, 0x1b13c, 0x16238, 0x1b11e, + 0x1621c, 0x1620e, 0x12178, 0x190be, 0x16378, 0x1213c, 0x1633c, 0x1211e, + 0x1631e, 0x121be, 0x163be, 0x16170, 0x1b0bc, 0x16138, 0x1b09e, 0x1611c, + 0x1610e, 0x120bc, 0x161bc, 0x1209e, 0x1619e, 0x160b8, 0x1b05e, 0x1609c, + 0x1608e, 0x1205e, 0x160de, 0x1605c, 0x1604e, 0x115e0, 0x18af8, 0x1c57e, + 0x114f0, 0x18a7c, 0x11478, 0x18a3e, 0x1143c, 0x1141e, 0x1f8b4, 0x116f8, + 0x18b7e, 0x1f8b2, 0x1167c, 0x1163e, 0x1f174, 0x1177e, 0x1f172, 0x1e2f4, + 0x1e2f2, 0x1c5f4, 0x1c5f2, 0x18bf4, 0x18bf2, 0x135c0, 0x19af0, 0x1cd7c, + 0x134e0, 0x19a78, 0x1cd3e, 0x13470, 0x19a3c, 0x13438, 0x19a1e, 0x1341c, + 0x1340e, 0x112f0, 0x1897c, 0x136f0, 0x11278, 0x1893e, 0x13678, 0x19b3e, + 0x1363c, 0x1121e, 0x1361e, 0x1f89a, 0x1137c, 0x1f9ba, 0x1377c, 0x1133e, + 0x1373e, 0x1f13a, 0x1f37a, 0x1e27a, 0x1e6fa, 0x1c4fa, 0x1cdfa, 0x189fa, + 0x1bae0, 0x1dd78, 0x1eebe, 0x174c0, 0x1ba70, 0x1dd3c, 0x17460, 0x1ba38, + 0x1dd1e, 0x17430, 0x1ba1c, 0x17418, 0x1ba0e, 0x1740c, 0x132e0, 0x19978, + 0x1ccbe, 0x176e0, 0x13270, 0x1993c, 0x17670, 0x1bb3c, 0x1991e, 0x17638, + 0x1321c, 0x1761c, 0x1320e, 0x1760e, 0x11178, 0x188be, 0x13378, 0x1113c, + 0x17778, 0x1333c, 0x1111e, 0x1773c, 0x1331e, 0x1771e, 0x111be, 0x133be, + 0x177be, 0x172c0, 0x1b970, 0x1dcbc, 0x17260, 0x1b938, 0x1dc9e, 0x17230, + 0x1b91c, 0x17218, 0x1b90e, 0x1720c, 0x17206, 0x13170, 0x198bc, 0x17370, + 0x13138, 0x1989e, 0x17338, 0x1b99e, 0x1731c, 0x1310e, 0x1730e, 0x110bc, + 0x131bc, 0x1109e, 0x173bc, 0x1319e, 0x1739e, 0x17160, 0x1b8b8, 0x1dc5e, + 0x17130, 0x1b89c, 0x17118, 0x1b88e, 0x1710c, 0x17106, 0x130b8, 0x1985e, + 0x171b8, 0x1309c, 0x1719c, 0x1308e, 0x1718e, 0x1105e, 0x130de, 0x171de, + 0x170b0, 0x1b85c, 0x17098, 0x1b84e, 0x1708c, 0x17086, 0x1305c, 0x170dc, + 0x1304e, 0x170ce, 0x17058, 0x1b82e, 0x1704c, 0x17046, 0x1302e, 0x1706e, + 0x1702c, 0x17026, 0x10af0, 0x1857c, 0x10a78, 0x1853e, 0x10a3c, 0x10a1e, + 0x10b7c, 0x10b3e, 0x1f0ba, 0x1e17a, 0x1c2fa, 0x185fa, 0x11ae0, 0x18d78, + 0x1c6be, 0x11a70, 0x18d3c, 0x11a38, 0x18d1e, 0x11a1c, 0x11a0e, 0x10978, + 0x184be, 0x11b78, 0x1093c, 0x11b3c, 0x1091e, 0x11b1e, 0x109be, 0x11bbe, + 0x13ac0, 0x19d70, 0x1cebc, 0x13a60, 0x19d38, 0x1ce9e, 0x13a30, 0x19d1c, + 0x13a18, 0x19d0e, 0x13a0c, 0x13a06, 0x11970, 0x18cbc, 0x13b70, 0x11938, + 0x18c9e, 0x13b38, 0x1191c, 0x13b1c, 0x1190e, 0x13b0e, 0x108bc, 0x119bc, + 0x1089e, 0x13bbc, 0x1199e, 0x13b9e, 0x1bd60, 0x1deb8, 0x1ef5e, 0x17a40, + 0x1bd30, 0x1de9c, 0x17a20, 0x1bd18, 0x1de8e, 0x17a10, 0x1bd0c, 0x17a08, + 0x1bd06, 0x17a04, 0x13960, 0x19cb8, 0x1ce5e, 0x17b60, 0x13930, 0x19c9c, + 0x17b30, 0x1bd9c, 0x19c8e, 0x17b18, 0x1390c, 0x17b0c, 0x13906, 0x17b06, + 0x118b8, 0x18c5e, 0x139b8, 0x1189c, 0x17bb8, 0x1399c, 0x1188e, 0x17b9c, + 0x1398e, 0x17b8e, 0x1085e, 0x118de, 0x139de, 0x17bde, 0x17940, 0x1bcb0, + 0x1de5c, 0x17920, 0x1bc98, 0x1de4e, 0x17910, 0x1bc8c, 0x17908, 0x1bc86, + 0x17904, 0x17902, 0x138b0, 0x19c5c, 0x179b0, 0x13898, 0x19c4e, 0x17998, + 0x1bcce, 0x1798c, 0x13886, 0x17986, 0x1185c, 0x138dc, 0x1184e, 0x179dc, + 0x138ce, 0x179ce, 0x178a0, 0x1bc58, 0x1de2e, 0x17890, 0x1bc4c, 0x17888, + 0x1bc46, 0x17884, 0x17882, 0x13858, 0x19c2e, 0x178d8, 0x1384c, 0x178cc, + 0x13846, 0x178c6, 0x1182e, 0x1386e, 0x178ee, 0x17850, 0x1bc2c, 0x17848, + 0x1bc26, 0x17844, 0x17842, 0x1382c, 0x1786c, 0x13826, 0x17866, 0x17828, + 0x1bc16, 0x17824, 0x17822, 0x13816, 0x17836, 0x10578, 0x182be, 0x1053c, + 0x1051e, 0x105be, 0x10d70, 0x186bc, 0x10d38, 0x1869e, 0x10d1c, 0x10d0e, + 0x104bc, 0x10dbc, 0x1049e, 0x10d9e, 0x11d60, 0x18eb8, 0x1c75e, 0x11d30, + 0x18e9c, 0x11d18, 0x18e8e, 0x11d0c, 0x11d06, 0x10cb8, 0x1865e, 0x11db8, + 0x10c9c, 0x11d9c, 0x10c8e, 0x11d8e, 0x1045e, 0x10cde, 0x11dde, 0x13d40, + 0x19eb0, 0x1cf5c, 0x13d20, 0x19e98, 0x1cf4e, 0x13d10, 0x19e8c, 0x13d08, + 0x19e86, 0x13d04, 0x13d02, 0x11cb0, 0x18e5c, 0x13db0, 0x11c98, 0x18e4e, + 0x13d98, 0x19ece, 0x13d8c, 0x11c86, 0x13d86, 0x10c5c, 0x11cdc, 0x10c4e, + 0x13ddc, 0x11cce, 0x13dce, 0x1bea0, 0x1df58, 0x1efae, 0x1be90, 0x1df4c, + 0x1be88, 0x1df46, 0x1be84, 0x1be82, 0x13ca0, 0x19e58, 0x1cf2e, 0x17da0, + 0x13c90, 0x19e4c, 0x17d90, 0x1becc, 0x19e46, 0x17d88, 0x13c84, 0x17d84, + 0x13c82, 0x17d82, 0x11c58, 0x18e2e, 0x13cd8, 0x11c4c, 0x17dd8, 0x13ccc, + 0x11c46, 0x17dcc, 0x13cc6, 0x17dc6, 0x10c2e, 0x11c6e, 0x13cee, 0x17dee, + 0x1be50, 0x1df2c, 0x1be48, 0x1df26, 0x1be44, 0x1be42, 0x13c50, 0x19e2c, + 0x17cd0, 0x13c48, 0x19e26, 0x17cc8, 0x1be66, 0x17cc4, 0x13c42, 0x17cc2, + 0x11c2c, 0x13c6c, 0x11c26, 0x17cec, 0x13c66, 0x17ce6, 0x1be28, 0x1df16, + 0x1be24, 0x1be22, 0x13c28, 0x19e16, 0x17c68, 0x13c24, 0x17c64, 0x13c22, + 0x17c62, 0x11c16, 0x13c36, 0x17c76, 0x1be14, 0x1be12, 0x13c14, 0x17c34, + 0x13c12, 0x17c32, 0x102bc, 0x1029e, 0x106b8, 0x1835e, 0x1069c, 0x1068e, + 0x1025e, 0x106de, 0x10eb0, 0x1875c, 0x10e98, 0x1874e, 0x10e8c, 0x10e86, + 0x1065c, 0x10edc, 0x1064e, 0x10ece, 0x11ea0, 0x18f58, 0x1c7ae, 0x11e90, + 0x18f4c, 0x11e88, 0x18f46, 0x11e84, 0x11e82, 0x10e58, 0x1872e, 0x11ed8, + 0x18f6e, 0x11ecc, 0x10e46, 0x11ec6, 0x1062e, 0x10e6e, 0x11eee, 0x19f50, + 0x1cfac, 0x19f48, 0x1cfa6, 0x19f44, 0x19f42, 0x11e50, 0x18f2c, 0x13ed0, + 0x19f6c, 0x18f26, 0x13ec8, 0x11e44, 0x13ec4, 0x11e42, 0x13ec2, 0x10e2c, + 0x11e6c, 0x10e26, 0x13eec, 0x11e66, 0x13ee6, 0x1dfa8, 0x1efd6, 0x1dfa4, + 0x1dfa2, 0x19f28, 0x1cf96, 0x1bf68, 0x19f24, 0x1bf64, 0x19f22, 0x1bf62, + 0x11e28, 0x18f16, 0x13e68, 0x11e24, 0x17ee8, 0x13e64, 0x11e22, 0x17ee4, + 0x13e62, 0x17ee2, 0x10e16, 0x11e36, 0x13e76, 0x17ef6, 0x1df94, 0x1df92, + 0x19f14, 0x1bf34, 0x19f12, 0x1bf32, 0x11e14, 0x13e34, 0x11e12, 0x17e74, + 0x13e32, 0x17e72, 0x1df8a, 0x19f0a, 0x1bf1a, 0x11e0a, 0x13e1a, 0x17e3a, + 0x1035c, 0x1034e, 0x10758, 0x183ae, 0x1074c, 0x10746, 0x1032e, 0x1076e, + 0x10f50, 0x187ac, 0x10f48, 0x187a6, 0x10f44, 0x10f42, 0x1072c, 0x10f6c, + 0x10726, 0x10f66, 0x18fa8, 0x1c7d6, 0x18fa4, 0x18fa2, 0x10f28, 0x18796, + 0x11f68, 0x18fb6, 0x11f64, 0x10f22, 0x11f62, 0x10716, 0x10f36, 0x11f76, + 0x1cfd4, 0x1cfd2, 0x18f94, 0x19fb4, 0x18f92, 0x19fb2, 0x10f14, 0x11f34, + 0x10f12, 0x13f74, 0x11f32, 0x13f72, 0x1cfca, 0x18f8a, 0x19f9a, 0x10f0a, + 0x11f1a, 0x13f3a, 0x103ac, 0x103a6, 0x107a8, 0x183d6, 0x107a4, 0x107a2, + 0x10396, 0x107b6, 0x187d4, 0x187d2, 0x10794, 0x10fb4, 0x10792, 0x10fb2, + 0x1c7ea + }}; + + private static readonly int[][] ERROR_LEVEL = new int[][] + {new int[]{ + 27, 917 + }, new int[]{ + 522, 568, 723, 809 + }, new int[]{ + 237, 308, 436, 284, 646, 653, 428, 379 + }, new int[]{ + 274, 562, 232, 755, 599, 524, 801, 132, 295, 116, 442, 428, 295, 42, 176, 65 + }, new int[]{ + 361, 575, 922, 525, 176, 586, 640, 321, 536, 742, 677, 742, 687, 284, 193, 517, + 273, 494, 263, 147, 593, 800, 571, 320, 803, 133, 231, 390, 685, 330, 63, 410 + }, new int[]{ + 539, 422, 6, 93, 862, 771, 453, 106, 610, 287, 107, 505, 733, 877, 381, 612, + 723, 476, 462, 172, 430, 609, 858, 822, 543, 376, 511, 400, 672, 762, 283, 184, + 440, 35, 519, 31, 460, 594, 225, 535, 517, 352, 605, 158, 651, 201, 488, 502, + 648, 733, 717, 83, 404, 97, 280, 771, 840, 629, 4, 381, 843, 623, 264, 543 + }, new int[]{ + 521, 310, 864, 547, 858, 580, 296, 379, 53, 779, 897, 444, 400, 925, 749, 415, + 822, 93, 217, 208, 928, 244, 583, 620, 246, 148, 447, 631, 292, 908, 490, 704, + 516, 258, 457, 907, 594, 723, 674, 292, 272, 96, 684, 432, 686, 606, 860, 569, + 193, 219, 129, 186, 236, 287, 192, 775, 278, 173, 40, 379, 712, 463, 646, 776, + 171, 491, 297, 763, 156, 732, 95, 270, 447, 90, 507, 48, 228, 821, 808, 898, + 784, 663, 627, 378, 382, 262, 380, 602, 754, 336, 89, 614, 87, 432, 670, 616, + 157, 374, 242, 726, 600, 269, 375, 898, 845, 454, 354, 130, 814, 587, 804, 34, + 211, 330, 539, 297, 827, 865, 37, 517, 834, 315, 550, 86, 801, 4, 108, 539 + }, new int[]{ + 524, 894, 75, 766, 882, 857, 74, 204, 82, 586, 708, 250, 905, 786, 138, 720, + 858, 194, 311, 913, 275, 190, 375, 850, 438, 733, 194, 280, 201, 280, 828, 757, + 710, 814, 919, 89, 68, 569, 11, 204, 796, 605, 540, 913, 801, 700, 799, 137, + 439, 418, 592, 668, 353, 859, 370, 694, 325, 240, 216, 257, 284, 549, 209, 884, + 315, 70, 329, 793, 490, 274, 877, 162, 749, 812, 684, 461, 334, 376, 849, 521, + 307, 291, 803, 712, 19, 358, 399, 908, 103, 511, 51, 8, 517, 225, 289, 470, + 637, 731, 66, 255, 917, 269, 463, 830, 730, 433, 848, 585, 136, 538, 906, 90, + 2, 290, 743, 199, 655, 903, 329, 49, 802, 580, 355, 588, 188, 462, 10, 134, + 628, 320, 479, 130, 739, 71, 263, 318, 374, 601, 192, 605, 142, 673, 687, 234, + 722, 384, 177, 752, 607, 640, 455, 193, 689, 707, 805, 641, 48, 60, 732, 621, + 895, 544, 261, 852, 655, 309, 697, 755, 756, 60, 231, 773, 434, 421, 726, 528, + 503, 118, 49, 795, 32, 144, 500, 238, 836, 394, 280, 566, 319, 9, 647, 550, + 73, 914, 342, 126, 32, 681, 331, 792, 620, 60, 609, 441, 180, 791, 893, 754, + 605, 383, 228, 749, 760, 213, 54, 297, 134, 54, 834, 299, 922, 191, 910, 532, + 609, 829, 189, 20, 167, 29, 872, 449, 83, 402, 41, 656, 505, 579, 481, 173, + 404, 251, 688, 95, 497, 555, 642, 543, 307, 159, 924, 558, 648, 55, 497, 10 + }, new int[]{ + 352, 77, 373, 504, 35, 599, 428, 207, 409, 574, 118, 498, 285, 380, 350, 492, + 197, 265, 920, 155, 914, 299, 229, 643, 294, 871, 306, 88, 87, 193, 352, 781, + 846, 75, 327, 520, 435, 543, 203, 666, 249, 346, 781, 621, 640, 268, 794, 534, + 539, 781, 408, 390, 644, 102, 476, 499, 290, 632, 545, 37, 858, 916, 552, 41, + 542, 289, 122, 272, 383, 800, 485, 98, 752, 472, 761, 107, 784, 860, 658, 741, + 290, 204, 681, 407, 855, 85, 99, 62, 482, 180, 20, 297, 451, 593, 913, 142, + 808, 684, 287, 536, 561, 76, 653, 899, 729, 567, 744, 390, 513, 192, 516, 258, + 240, 518, 794, 395, 768, 848, 51, 610, 384, 168, 190, 826, 328, 596, 786, 303, + 570, 381, 415, 641, 156, 237, 151, 429, 531, 207, 676, 710, 89, 168, 304, 402, + 40, 708, 575, 162, 864, 229, 65, 861, 841, 512, 164, 477, 221, 92, 358, 785, + 288, 357, 850, 836, 827, 736, 707, 94, 8, 494, 114, 521, 2, 499, 851, 543, + 152, 729, 771, 95, 248, 361, 578, 323, 856, 797, 289, 51, 684, 466, 533, 820, + 669, 45, 902, 452, 167, 342, 244, 173, 35, 463, 651, 51, 699, 591, 452, 578, + 37, 124, 298, 332, 552, 43, 427, 119, 662, 777, 475, 850, 764, 364, 578, 911, + 283, 711, 472, 420, 245, 288, 594, 394, 511, 327, 589, 777, 699, 688, 43, 408, + 842, 383, 721, 521, 560, 644, 714, 559, 62, 145, 873, 663, 713, 159, 672, 729, + 624, 59, 193, 417, 158, 209, 563, 564, 343, 693, 109, 608, 563, 365, 181, 772, + 677, 310, 248, 353, 708, 410, 579, 870, 617, 841, 632, 860, 289, 536, 35, 777, + 618, 586, 424, 833, 77, 597, 346, 269, 757, 632, 695, 751, 331, 247, 184, 45, + 787, 680, 18, 66, 407, 369, 54, 492, 228, 613, 830, 922, 437, 519, 644, 905, + 789, 420, 305, 441, 207, 300, 892, 827, 141, 537, 381, 662, 513, 56, 252, 341, + 242, 797, 838, 837, 720, 224, 307, 631, 61, 87, 560, 310, 756, 665, 397, 808, + 851, 309, 473, 795, 378, 31, 647, 915, 459, 806, 590, 731, 425, 216, 548, 249, + 321, 881, 699, 535, 673, 782, 210, 815, 905, 303, 843, 922, 281, 73, 469, 791, + 660, 162, 498, 308, 155, 422, 907, 817, 187, 62, 16, 425, 535, 336, 286, 437, + 375, 273, 610, 296, 183, 923, 116, 667, 751, 353, 62, 366, 691, 379, 687, 842, + 37, 357, 720, 742, 330, 5, 39, 923, 311, 424, 242, 749, 321, 54, 669, 316, + 342, 299, 534, 105, 667, 488, 640, 672, 576, 540, 316, 486, 721, 610, 46, 656, + 447, 171, 616, 464, 190, 531, 297, 321, 762, 752, 533, 175, 134, 14, 381, 433, + 717, 45, 111, 20, 596, 284, 736, 138, 646, 411, 877, 669, 141, 919, 45, 780, + 407, 164, 332, 899, 165, 726, 600, 325, 498, 655, 357, 752, 768, 223, 849, 647, + 63, 310, 863, 251, 366, 304, 282, 738, 675, 410, 389, 244, 31, 121, 303, 263 + }}; + + /** Holds value of property outBits. */ + private byte[] outBits; + + /** Holds value of property bitColumns. */ + private int bitColumns; + + /** Holds value of property codeRows. */ + private int codeRows; + + /** Holds value of property codeColumns. */ + private int codeColumns; + + /** Holds value of property codewords. */ + private int[] codewords = new int[MAX_DATA_CODEWORDS + 2]; + + /** Holds value of property lenCodewords. */ + private int lenCodewords; + + /** Holds value of property errorLevel. */ + private int errorLevel; + + /** Holds value of property text. */ + private byte[] text; + + /** Holds value of property options. */ + private int options; + + /** Holds value of property aspectRatio. */ + private float aspectRatio; + + /** Holds value of property yHeight. */ + private float yHeight; + + protected class Segment { + public char type; + public int start; + public int end; + + public Segment(char type, int start, int end) { + this.type = type; + this.start = start; + this.end = end; + } + } + + protected class SegmentList { + protected ArrayList list = new ArrayList(); + + public void Add(char type, int start, int end) { + list.Add(new Segment(type, start, end)); + } + + public Segment Get(int idx) { + if (idx < 0 || idx >= list.Count) + return null; + return (Segment)list[idx]; + } + + public void Remove(int idx) { + if (idx < 0 || idx >= list.Count) + return; + list.RemoveAt(idx); + } + + public int Size { + get { + return list.Count; + } + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BarcodePostnet.cs b/iTechSharp/iTextSharp/text/pdf/BarcodePostnet.cs new file mode 100644 index 0000000..0aa745f --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BarcodePostnet.cs @@ -0,0 +1,219 @@ +using System; +using iTextSharp.text; + +/* + * Copyright 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** Implements the Postnet and Planet barcodes. The default parameters are: + *

    +     *n = 72f / 22f; // distance between bars
    +     *x = 0.02f * 72f; // bar width
    +     *barHeight = 0.125f * 72f; // height of the tall bars
    +     *size = 0.05f * 72f; // height of the short bars
    +     *codeType = POSTNET; // type of code
    +     * 
    + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class BarcodePostnet : Barcode{ + + /** The bars for each character. + */ + private static readonly byte[][] BARS = { + new byte[] {1,1,0,0,0}, + new byte[] {0,0,0,1,1}, + new byte[] {0,0,1,0,1}, + new byte[] {0,0,1,1,0}, + new byte[] {0,1,0,0,1}, + new byte[] {0,1,0,1,0}, + new byte[] {0,1,1,0,0}, + new byte[] {1,0,0,0,1}, + new byte[] {1,0,0,1,0}, + new byte[] {1,0,1,0,0} + }; + + /** Creates new BarcodePostnet */ + public BarcodePostnet() { + n = 72f / 22f; // distance between bars + x = 0.02f * 72f; // bar width + barHeight = 0.125f * 72f; // height of the tall bars + size = 0.05f * 72f; // height of the short bars + codeType = POSTNET; // type of code + } + + /** Creates the bars for Postnet. + * @param text the code to be created without checksum + * @return the bars + */ + public static byte[] GetBarsPostnet(string text) { + int total = 0; + for (int k = text.Length - 1; k >= 0; --k) { + int n = text[k] - '0'; + total += n; + } + text += (char)(((10 - (total % 10)) % 10) + '0'); + byte[] bars = new byte[text.Length * 5 + 2]; + bars[0] = 1; + bars[bars.Length - 1] = 1; + for (int k = 0; k < text.Length; ++k) { + int c = text[k] - '0'; + Array.Copy(BARS[c], 0, bars, k * 5 + 1, 5); + } + return bars; + } + + /** Gets the maximum area that the barcode and the text, if + * any, will occupy. The lower left corner is always (0, 0). + * @return the size the barcode occupies. + */ + public override Rectangle BarcodeSize { + get { + float width = ((code.Length + 1) * 5 + 1) * n + x; + return new Rectangle(width, barHeight); + } + } + + /** Places the barcode in a PdfContentByte. The + * barcode is always placed at coodinates (0, 0). Use the + * translation matrix to move it elsewhere.

    + * The bars and text are written in the following colors:

    + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *

    barColor

    textColor

    Result

    null

    null

    bars and text painted with current fill color

    barColor

    null

    bars and text painted with barColor

    null

    textColor

    bars painted with current color
    text painted with textColor

    barColor

    textColor

    bars painted with barColor
    text painted with textColor

    + * @param cb the PdfContentByte where the barcode will be placed + * @param barColor the color of the bars. It can be null + * @param textColor the color of the text. It can be null + * @return the dimensions the barcode occupies + */ + public override Rectangle PlaceBarcode(PdfContentByte cb, Color barColor, Color textColor) { + if (barColor != null) + cb.SetColorFill(barColor); + byte[] bars = GetBarsPostnet(code); + byte flip = 1; + if (codeType == PLANET) { + flip = 0; + bars[0] = 0; + bars[bars.Length - 1] = 0; + } + float startX = 0; + for (int k = 0; k < bars.Length; ++k) { + cb.Rectangle(startX, 0, x - inkSpreading, bars[k] == flip ? barHeight : size); + startX += n; + } + cb.Fill(); + return this.BarcodeSize; + } + + public override System.Drawing.Image CreateDrawingImage(System.Drawing.Color foreground, System.Drawing.Color background) { + int barWidth = (int)x; + if (barWidth <= 0) + barWidth = 1; + int barDistance = (int)n; + if (barDistance <= barWidth) + barDistance = barWidth + 1; + int barShort = (int)size; + if (barShort <= 0) + barShort = 1; + int barTall = (int)barHeight; + if (barTall <= barShort) + barTall = barShort + 1; + byte[] bars = GetBarsPostnet(code); + int width = bars.Length * barDistance; + byte flip = 1; + if (codeType == PLANET) { + flip = 0; + bars[0] = 0; + bars[bars.Length - 1] = 0; + } + System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(width, barTall); + int seg1 = barTall - barShort; + for (int i = 0; i < seg1; ++i) { + int idx = 0; + for (int k = 0; k < bars.Length; ++k) { + bool dot = (bars[k] == flip); + for (int j = 0; j < barDistance; ++j) { + bmp.SetPixel(idx++, i, (dot && j < barWidth) ? foreground : background); + } + } + } + for (int i = seg1; i < barTall; ++i) { + int idx = 0; + for (int k = 0; k < bars.Length; ++k) { + for (int j = 0; j < barDistance; ++j) { + bmp.SetPixel(idx++, i, (j < barWidth) ? foreground : background); + } + } + } + return bmp; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BaseField.cs b/iTechSharp/iTextSharp/text/pdf/BaseField.cs new file mode 100644 index 0000000..9d73757 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BaseField.cs @@ -0,0 +1,630 @@ +using System; +using System.Collections; +using System.Text; +/* + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf +{ + public abstract class BaseField { + + /** A thin border with 1 point width. */ + public const float BORDER_WIDTH_THIN = 1; + /** A medium border with 2 point width. */ + public const float BORDER_WIDTH_MEDIUM = 2; + /** A thick border with 3 point width. */ + public const float BORDER_WIDTH_THICK = 3; + /** The field is visible. */ + public const int VISIBLE = 0; + /** The field is hidden. */ + public const int HIDDEN = 1; + /** The field is visible but does not print. */ + public const int VISIBLE_BUT_DOES_NOT_PRINT = 2; + /** The field is hidden but is printable. */ + public const int HIDDEN_BUT_PRINTABLE = 3; + /** The user may not change the value of the field. */ + public const int READ_ONLY = PdfFormField.FF_READ_ONLY; + /** The field must have a value at the time it is exported by a submit-form + * action. + */ + public const int REQUIRED = PdfFormField.FF_REQUIRED; + /** The field may contain multiple lines of text. + * This flag is only meaningful with text fields. + */ + public const int MULTILINE = PdfFormField.FF_MULTILINE; + /** The field will not scroll (horizontally for single-line + * fields, vertically for multiple-line fields) to accommodate more text + * than will fit within its annotation rectangle. Once the field is full, no + * further text will be accepted. + */ + public const int DO_NOT_SCROLL = PdfFormField.FF_DONOTSCROLL; + /** The field is intended for entering a secure password that should + * not be echoed visibly to the screen. + */ + public const int PASSWORD = PdfFormField.FF_PASSWORD; + /** The text entered in the field represents the pathname of + * a file whose contents are to be submitted as the value of the field. + */ + public const int FILE_SELECTION = PdfFormField.FF_FILESELECT; + /** The text entered in the field will not be spell-checked. + * This flag is meaningful only in text fields and in combo + * fields with the EDIT flag set. + */ + public const int DO_NOT_SPELL_CHECK = PdfFormField.FF_DONOTSPELLCHECK; + /** If set the combo box includes an editable text box as well as a drop list; if + * clear, it includes only a drop list. + * This flag is only meaningful with combo fields. + */ + public const int EDIT = PdfFormField.FF_EDIT; + + /** + * combo box flag. + */ + public const int COMB = PdfFormField.FF_COMB; + + protected float borderWidth = BORDER_WIDTH_THIN; + protected int borderStyle = PdfBorderDictionary.STYLE_SOLID; + protected Color borderColor; + protected Color backgroundColor; + protected Color textColor; + protected BaseFont font; + protected float fontSize = 0; + protected int alignment = Element.ALIGN_LEFT; + protected PdfWriter writer; + protected String text; + protected Rectangle box; + + /** Holds value of property rotation. */ + protected int rotation = 0; + + /** Holds value of property visibility. */ + protected int visibility; + + /** Holds value of property fieldName. */ + protected String fieldName; + + /** Holds value of property options. */ + protected int options; + + /** Holds value of property maxCharacterLength. */ + protected int maxCharacterLength; + + private static Hashtable fieldKeys = new Hashtable(); + + static BaseField() { + foreach (DictionaryEntry entry in PdfCopyFieldsImp.fieldKeys) + fieldKeys[entry.Key] = entry.Value; + fieldKeys[PdfName.T] = 1; + } + /** Creates a new TextField. + * @param writer the document PdfWriter + * @param box the field location and dimensions + * @param fieldName the field name. If null only the widget keys + * will be included in the field allowing it to be used as a kid field. + */ + public BaseField(PdfWriter writer, Rectangle box, String fieldName) { + this.writer = writer; + Box = box; + this.fieldName = fieldName; + } + + protected BaseFont RealFont { + get { + if (font == null) + return BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.WINANSI, false); + else + return font; + } + } + + protected PdfAppearance GetBorderAppearance() { + PdfAppearance app = PdfAppearance.CreateAppearance(writer, box.Width, box.Height); + switch (rotation) { + case 90: + app.SetMatrix(0, 1, -1, 0, box.Height, 0); + break; + case 180: + app.SetMatrix(-1, 0, 0, -1, box.Width, box.Height); + break; + case 270: + app.SetMatrix(0, -1, 1, 0, 0, box.Width); + break; + } + app.SaveState(); + // background + if (backgroundColor != null) { + app.SetColorFill(backgroundColor); + app.Rectangle(0, 0, box.Width, box.Height); + app.Fill(); + } + // border + if (borderStyle == PdfBorderDictionary.STYLE_UNDERLINE) { + if (borderWidth != 0 && borderColor != null) { + app.SetColorStroke(borderColor); + app.SetLineWidth(borderWidth); + app.MoveTo(0, borderWidth / 2); + app.LineTo(box.Width, borderWidth / 2); + app.Stroke(); + } + } + else if (borderStyle == PdfBorderDictionary.STYLE_BEVELED) { + if (borderWidth != 0 && borderColor != null) { + app.SetColorStroke(borderColor); + app.SetLineWidth(borderWidth); + app.Rectangle(borderWidth / 2, borderWidth / 2, box.Width - borderWidth, box.Height - borderWidth); + app.Stroke(); + } + // beveled + Color actual = backgroundColor; + if (actual == null) + actual = Color.WHITE; + app.SetGrayFill(1); + DrawTopFrame(app); + app.SetColorFill(actual.Darker()); + DrawBottomFrame(app); + } + else if (borderStyle == PdfBorderDictionary.STYLE_INSET) { + if (borderWidth != 0 && borderColor != null) { + app.SetColorStroke(borderColor); + app.SetLineWidth(borderWidth); + app.Rectangle(borderWidth / 2, borderWidth / 2, box.Width - borderWidth, box.Height - borderWidth); + app.Stroke(); + } + // inset + app.SetGrayFill(0.5f); + DrawTopFrame(app); + app.SetGrayFill(0.75f); + DrawBottomFrame(app); + } + else { + if (borderWidth != 0 && borderColor != null) { + if (borderStyle == PdfBorderDictionary.STYLE_DASHED) + app.SetLineDash(3, 0); + app.SetColorStroke(borderColor); + app.SetLineWidth(borderWidth); + app.Rectangle(borderWidth / 2, borderWidth / 2, box.Width - borderWidth, box.Height - borderWidth); + app.Stroke(); + if ((options & COMB) != 0 && maxCharacterLength > 1) { + float step = box.Width / maxCharacterLength; + float yb = borderWidth / 2; + float yt = box.Height - borderWidth / 2; + for (int k = 1; k < maxCharacterLength; ++k) { + float x = step * k; + app.MoveTo(x, yb); + app.LineTo(x, yt); + } + app.Stroke(); + } + } + } + app.RestoreState(); + return app; + } + + protected static ArrayList GetHardBreaks(String text) { + ArrayList arr = new ArrayList(); + char[] cs = text.ToCharArray(); + int len = cs.Length; + StringBuilder buf = new StringBuilder(); + for (int k = 0; k < len; ++k) { + char c = cs[k]; + if (c == '\r') { + if (k + 1 < len && cs[k + 1] == '\n') + ++k; + arr.Add(buf.ToString()); + buf = new StringBuilder(); + } + else if (c == '\n') { + arr.Add(buf.ToString()); + buf = new StringBuilder(); + } + else + buf.Append(c); + } + arr.Add(buf.ToString()); + return arr; + } + + protected static void TrimRight(StringBuilder buf) { + int len = buf.Length; + while (true) { + if (len == 0) + return; + if (buf[--len] != ' ') + return; + buf.Length = len; + } + } + + protected static ArrayList BreakLines(ArrayList breaks, BaseFont font, float fontSize, float width) { + ArrayList lines = new ArrayList(); + StringBuilder buf = new StringBuilder(); + for (int ck = 0; ck < breaks.Count; ++ck) { + buf.Length = 0; + float w = 0; + char[] cs = ((String)breaks[ck]).ToCharArray(); + int len = cs.Length; + // 0 inline first, 1 inline, 2 spaces + int state = 0; + int lastspace = -1; + char c = (char)0; + int refk = 0; + for (int k = 0; k < len; ++k) { + c = cs[k]; + switch (state) { + case 0: + w += font.GetWidthPoint(c, fontSize); + buf.Append(c); + if (w > width) { + w = 0; + if (buf.Length > 1) { + --k; + buf.Length = buf.Length - 1; + } + lines.Add(buf.ToString()); + buf.Length = 0; + refk = k; + if (c == ' ') + state = 2; + else + state = 1; + } + else { + if (c != ' ') + state = 1; + } + break; + case 1: + w += font.GetWidthPoint(c, fontSize); + buf.Append(c); + if (c == ' ') + lastspace = k; + if (w > width) { + w = 0; + if (lastspace >= 0) { + k = lastspace; + buf.Length = lastspace - refk; + TrimRight(buf); + lines.Add(buf.ToString()); + buf.Length = 0; + refk = k; + lastspace = -1; + state = 2; + } + else { + if (buf.Length > 1) { + --k; + buf.Length = buf.Length - 1; + } + lines.Add(buf.ToString()); + buf.Length = 0; + refk = k; + if (c == ' ') + state = 2; + } + } + break; + case 2: + if (c != ' ') { + w = 0; + --k; + state = 1; + } + break; + } + } + TrimRight(buf); + lines.Add(buf.ToString()); + } + return lines; + } + + private void DrawTopFrame(PdfAppearance app) { + app.MoveTo(borderWidth, borderWidth); + app.LineTo(borderWidth, box.Height - borderWidth); + app.LineTo(box.Width - borderWidth, box.Height - borderWidth); + app.LineTo(box.Width - 2 * borderWidth, box.Height - 2 * borderWidth); + app.LineTo(2 * borderWidth, box.Height - 2 * borderWidth); + app.LineTo(2 * borderWidth, 2 * borderWidth); + app.LineTo(borderWidth, borderWidth); + app.Fill(); + } + + private void DrawBottomFrame(PdfAppearance app) { + app.MoveTo(borderWidth, borderWidth); + app.LineTo(box.Width - borderWidth, borderWidth); + app.LineTo(box.Width - borderWidth, box.Height - borderWidth); + app.LineTo(box.Width - 2 * borderWidth, box.Height - 2 * borderWidth); + app.LineTo(box.Width - 2 * borderWidth, 2 * borderWidth); + app.LineTo(2 * borderWidth, 2 * borderWidth); + app.LineTo(borderWidth, borderWidth); + app.Fill(); + } + + /** Sets the border width in points. To eliminate the border + * set the border color to null. + * @param borderWidth the border width in points + */ + public float BorderWidth { + set { + this.borderWidth = value; + } + get { + return borderWidth; + } + } + + /** Sets the border style. The styles are found in PdfBorderDictionary + * and can be STYLE_SOLID, STYLE_DASHED, + * STYLE_BEVELED, STYLE_INSET and + * STYLE_UNDERLINE. + * @param borderStyle the border style + */ + public int BorderStyle { + set { + this.borderStyle = value; + } + get { + return borderStyle; + } + } + + /** Sets the border color. Set to null to remove + * the border. + * @param borderColor the border color + */ + public Color BorderColor { + set { + this.borderColor = value; + } + get { + return borderColor; + } + } + + /** Sets the background color. Set to null for + * transparent background. + * @param backgroundColor the background color + */ + public Color BackgroundColor { + set { + this.backgroundColor = value; + } + get { + return backgroundColor; + } + } + + /** Sets the text color. If null the color used + * will be black. + * @param textColor the text color + */ + public Color TextColor { + set { + this.textColor = value; + } + get { + return textColor; + } + } + + /** Sets the text font. If null then Helvetica + * will be used. + * @param font the text font + */ + public BaseFont Font { + set { + this.font = value; + } + get { + return font; + } + } + + /** Sets the font size. If 0 then auto-sizing will be used but + * only for text fields. + * @param fontSize the font size + */ + public float FontSize { + set { + this.fontSize = value; + } + get { + return fontSize; + } + } + + /** Sets the text horizontal alignment. It can be Element.ALIGN_LEFT, + * Element.ALIGN_CENTER and Element.ALIGN_RIGHT. + * @param alignment the text horizontal alignment + */ + public int Alignment { + set { + this.alignment = value; + } + get { + return alignment; + } + } + + /** Sets the text for text fields. + * @param text the text + */ + public string Text { + set { + this.text = value; + } + get { + return text; + } + } + + /** Sets the field dimension and position. + * @param box the field dimension and position + */ + public Rectangle Box { + set { + if (value == null) + box = null; + else { + box = new Rectangle(value); + box.Normalize(); + } + } + get { + return box; + } + } + + /** Sets the field rotation. This value should be the same as + * the page rotation where the field will be shown. + * @param rotation the field rotation + */ + public int Rotation { + set { + if (value % 90 != 0) + throw new ArgumentException("Rotation must be a multiple of 90."); + rotation = (value % 360); + if (rotation < 0) + rotation += 360; + } + get { + return rotation; + } + } + + /** Convenience method to set the field rotation the same as the + * page rotation. + * @param page the page + */ + public void SetRotationFromPage(Rectangle page) { + Rotation = page.Rotation; + } + + /** Sets the field visibility flag. This flags can be one of + * VISIBLE, HIDDEN, VISIBLE_BUT_DOES_NOT_PRINT + * and HIDDEN_BUT_PRINTABLE. + * @param visibility field visibility flag + */ + public int Visibility { + set { + this.visibility = value; + } + get { + return visibility; + } + } + + /** Sets the field name. + * @param fieldName the field name. If null only the widget keys + * will be included in the field allowing it to be used as a kid field. + */ + public string FieldName { + set { + this.fieldName = value; + } + get { + return fieldName; + } + } + + /** Sets the option flags. The option flags can be a combination by oring of + * READ_ONLY, REQUIRED, + * MULTILINE, DO_NOT_SCROLL, + * PASSWORD, FILE_SELECTION, + * DO_NOT_SPELL_CHECK and EDIT. + * @param options the option flags + */ + public int Options { + set { + this.options = value; + } + get { + return options; + } + } + + /** Sets the maximum length of the field’s text, in characters. + * It is only meaningful for text fields. + * @param maxCharacterLength the maximum length of the field’s text, in characters + */ + public int MaxCharacterLength { + set { + this.maxCharacterLength = value; + } + get { + return maxCharacterLength; + } + } + + public PdfWriter Writer { + get { + return writer; + } + set { + writer = value; + } + } + + /** + * Moves the field keys from from to to. The moved keys + * are removed from from. + * @param from the source + * @param to the destination. It may be null + */ + public static void MoveFields(PdfDictionary from, PdfDictionary to) { + PdfName[] keys = new PdfName[from.Size]; + foreach (PdfName key in keys) { + if (fieldKeys.ContainsKey(key)) { + if (to != null) + to.Put(key, from.Get(key)); + from.Remove(key); + } + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/BaseFont.cs b/iTechSharp/iTextSharp/text/pdf/BaseFont.cs new file mode 100644 index 0000000..c2b27ca --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BaseFont.cs @@ -0,0 +1,1433 @@ +using System; +using System.Globalization; +using System.Reflection; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Collections; +using System.util; +using iTextSharp.text.xml.simpleparser; + +/* + * $Id: BaseFont.cs,v 1.17 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2000-2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + ///

    + /// Summary description for BaseFont. + /// + public abstract class BaseFont { + /** This is a possible value of a base 14 type 1 font */ + public const string COURIER = "Courier"; + + /** This is a possible value of a base 14 type 1 font */ + public const string COURIER_BOLD = "Courier-Bold"; + + /** This is a possible value of a base 14 type 1 font */ + public const string COURIER_OBLIQUE = "Courier-Oblique"; + + /** This is a possible value of a base 14 type 1 font */ + public const string COURIER_BOLDOBLIQUE = "Courier-BoldOblique"; + + /** This is a possible value of a base 14 type 1 font */ + public const string HELVETICA = "Helvetica"; + + /** This is a possible value of a base 14 type 1 font */ + public const string HELVETICA_BOLD = "Helvetica-Bold"; + + /** This is a possible value of a base 14 type 1 font */ + public const string HELVETICA_OBLIQUE = "Helvetica-Oblique"; + + /** This is a possible value of a base 14 type 1 font */ + public const string HELVETICA_BOLDOBLIQUE = "Helvetica-BoldOblique"; + + /** This is a possible value of a base 14 type 1 font */ + public const string SYMBOL = "Symbol"; + + /** This is a possible value of a base 14 type 1 font */ + public const string TIMES_ROMAN = "Times-Roman"; + + /** This is a possible value of a base 14 type 1 font */ + public const string TIMES_BOLD = "Times-Bold"; + + /** This is a possible value of a base 14 type 1 font */ + public const string TIMES_ITALIC = "Times-Italic"; + + /** This is a possible value of a base 14 type 1 font */ + public const string TIMES_BOLDITALIC = "Times-BoldItalic"; + + /** This is a possible value of a base 14 type 1 font */ + public const string ZAPFDINGBATS = "ZapfDingbats"; + + /** The maximum height above the baseline reached by glyphs in this + * font, excluding the height of glyphs for accented characters. + */ + public const int ASCENT = 1; + /** The y coordinate of the top of flat capital letters, measured from + * the baseline. + */ + public const int CAPHEIGHT = 2; + /** The maximum depth below the baseline reached by glyphs in this + * font. The value is a negative number. + */ + public const int DESCENT = 3; + /** The angle, expressed in degrees counterclockwise from the vertical, + * of the dominant vertical strokes of the font. The value is + * negative for fonts that slope to the right, as almost all italic fonts do. + */ + public const int ITALICANGLE = 4; + /** The lower left x glyph coordinate. + */ + public const int BBOXLLX = 5; + /** The lower left y glyph coordinate. + */ + public const int BBOXLLY = 6; + /** The upper right x glyph coordinate. + */ + public const int BBOXURX = 7; + /** The upper right y glyph coordinate. + */ + public const int BBOXURY = 8; + /** java.awt.Font property */ + public const int AWT_ASCENT = 9; + /** java.awt.Font property */ + public const int AWT_DESCENT = 10; + /** java.awt.Font property */ + public const int AWT_LEADING = 11; + /** java.awt.Font property */ + public const int AWT_MAXADVANCE = 12; + /** + * The undeline position. Usually a negative value. + */ + public const int UNDERLINE_POSITION = 13; + /** + * The underline thickness. + */ + public const int UNDERLINE_THICKNESS = 14; + /** + * The strikethrough position. + */ + public const int STRIKETHROUGH_POSITION = 15; + /** + * The strikethrough thickness. + */ + public const int STRIKETHROUGH_THICKNESS = 16; + /** + * The recommended vertical size for subscripts for this font. + */ + public const int SUBSCRIPT_SIZE = 17; + /** + * The recommended vertical offset from the baseline for subscripts for this font. Usually a negative value. + */ + public const int SUBSCRIPT_OFFSET = 18; + /** + * The recommended vertical size for superscripts for this font. + */ + public const int SUPERSCRIPT_SIZE = 19; + /** + * The recommended vertical offset from the baseline for superscripts for this font. + */ + public const int SUPERSCRIPT_OFFSET = 20; + + /** The font is Type 1. + */ + public const int FONT_TYPE_T1 = 0; + /** The font is True Type with a standard encoding. + */ + public const int FONT_TYPE_TT = 1; + /** The font is CJK. + */ + public const int FONT_TYPE_CJK = 2; + /** The font is True Type with a Unicode encoding. + */ + public const int FONT_TYPE_TTUNI = 3; + /** A font already inside the document. + */ + public const int FONT_TYPE_DOCUMENT = 4; + /** A Type3 font. + */ + public const int FONT_TYPE_T3 = 5; + + /** The Unicode encoding with horizontal writing. + */ + public const string IDENTITY_H = "Identity-H"; + /** The Unicode encoding with vertical writing. + */ + public const string IDENTITY_V = "Identity-V"; + + /** A possible encoding. */ + public const string CP1250 = "Cp1250"; + + /** A possible encoding. */ + public const string CP1252 = "Cp1252"; + + /** A possible encoding. */ + public const string CP1257 = "Cp1257"; + + /** A possible encoding. */ + public const string WINANSI = "Cp1252"; + + /** A possible encoding. */ + public const string MACROMAN = "MacRoman"; + + public static readonly int[] CHAR_RANGE_LATIN = {0, 0x17f, 0x2000, 0x206f, 0x20a0, 0x20cf, 0xfb00, 0xfb06}; + public static readonly int[] CHAR_RANGE_ARABIC = {0, 0x7f, 0x0600, 0x067f, 0x20a0, 0x20cf, 0xfb50, 0xfbff, 0xfe70, 0xfeff}; + public static readonly int[] CHAR_RANGE_HEBREW = {0, 0x7f, 0x0590, 0x05ff, 0x20a0, 0x20cf, 0xfb1d, 0xfb4f}; + public static readonly int[] CHAR_RANGE_CYRILLIC = {0, 0x7f, 0x0400, 0x052f, 0x2000, 0x206f, 0x20a0, 0x20cf}; + + /** if the font has to be embedded */ + public const bool EMBEDDED = true; + + /** if the font doesn't have to be embedded */ + public const bool NOT_EMBEDDED = false; + /** if the font has to be cached */ + public const bool CACHED = true; + /** if the font doesn't have to be cached */ + public const bool NOT_CACHED = false; + + /** The path to the font resources. */ + public const string RESOURCE_PATH = "iTextSharp.text.pdf.fonts."; + /** The fake CID code that represents a newline. */ + public const char CID_NEWLINE = '\u7fff'; + + protected ArrayList subsetRanges; + + /** The font type. + */ + internal int fontType; + /** a not defined character in a custom PDF encoding */ + public const string notdef = ".notdef"; + + /** table of characters widths for this encoding */ + protected int[] widths = new int[256]; + + /** encoding names */ + protected string[] differences = new string[256]; + /** same as differences but with the unicode codes */ + protected char[] unicodeDifferences = new char[256]; + protected int[][] charBBoxes = new int[256][]; + /** encoding used with this font */ + protected string encoding; + + /** true if the font is to be embedded in the PDF */ + protected bool embedded; + + /** + * true if the font must use it's built in encoding. In that case the + * encoding is only used to map a char to the position inside + * the font, not to the expected char name. + */ + protected bool fontSpecific = true; + + /** cache for the fonts already used. */ + protected static Hashtable fontCache = new Hashtable(); + + /** list of the 14 built in fonts. */ + protected static Hashtable BuiltinFonts14 = new Hashtable(); + + /** Forces the output of the width array. Only matters for the 14 + * built-in fonts. + */ + protected bool forceWidthsOutput = false; + + /** Converts char directly to byte + * by casting. + */ + protected bool directTextToByte = false; + + /** Indicates if all the glyphs and widths for that particular + * encoding should be included in the document. + */ + protected bool subset = true; + + protected bool fastWinansi = false; + + /** + * Custom encodings use this map to key the Unicode character + * to the single byte code. + */ + protected IntHashtable specialMap; + + protected static internal ArrayList resourceSearch = ArrayList.Synchronized(new ArrayList()); + + private static Random random = new Random(); + + static BaseFont() { + BuiltinFonts14.Add(COURIER, PdfName.COURIER); + BuiltinFonts14.Add(COURIER_BOLD, PdfName.COURIER_BOLD); + BuiltinFonts14.Add(COURIER_BOLDOBLIQUE, PdfName.COURIER_BOLDOBLIQUE); + BuiltinFonts14.Add(COURIER_OBLIQUE, PdfName.COURIER_OBLIQUE); + BuiltinFonts14.Add(HELVETICA, PdfName.HELVETICA); + BuiltinFonts14.Add(HELVETICA_BOLD, PdfName.HELVETICA_BOLD); + BuiltinFonts14.Add(HELVETICA_BOLDOBLIQUE, PdfName.HELVETICA_BOLDOBLIQUE); + BuiltinFonts14.Add(HELVETICA_OBLIQUE, PdfName.HELVETICA_OBLIQUE); + BuiltinFonts14.Add(SYMBOL, PdfName.SYMBOL); + BuiltinFonts14.Add(TIMES_ROMAN, PdfName.TIMES_ROMAN); + BuiltinFonts14.Add(TIMES_BOLD, PdfName.TIMES_BOLD); + BuiltinFonts14.Add(TIMES_BOLDITALIC, PdfName.TIMES_BOLDITALIC); + BuiltinFonts14.Add(TIMES_ITALIC, PdfName.TIMES_ITALIC); + BuiltinFonts14.Add(ZAPFDINGBATS, PdfName.ZAPFDINGBATS); + } + + /** Generates the PDF stream with the Type1 and Truetype fonts returning + * a PdfStream. + */ + internal class StreamFont : PdfStream { + + /** Generates the PDF stream with the Type1 and Truetype fonts returning + * a PdfStream. + * @param contents the content of the stream + * @param lengths an array of int that describes the several lengths of each part of the font + */ + internal StreamFont(byte[] contents, int[] lengths) { + bytes = contents; + Put(PdfName.LENGTH, new PdfNumber(bytes.Length)); + for (int k = 0; k < lengths.Length; ++k) { + Put(new PdfName("Length" + (k + 1)), new PdfNumber(lengths[k])); + } + FlateCompress(); + } + + internal StreamFont(byte[] contents, string subType) { + bytes = contents; + Put(PdfName.LENGTH, new PdfNumber(bytes.Length)); + if (subType != null) + Put(PdfName.SUBTYPE, new PdfName(subType)); + FlateCompress(); + } + } + + /** + *Creates new BaseFont + */ + protected BaseFont() { + } + + /** + * Creates a new font. This will always be the default Helvetica font (not embedded). + * This method is introduced because Helvetica is used in many examples. + * @return a BaseFont object (Helvetica, Winansi, not embedded) + * @throws IOException This shouldn't occur ever + * @throws DocumentException This shouldn't occur ever + * @since 2.1.1 + */ + public static BaseFont CreateFont() { + return CreateFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED); + } + /** + * Creates a new font. This font can be one of the 14 built in types, + * a Type1 font referred to by an AFM or PFM file, a TrueType font (simple or collection) or a CJK font from the + * Adobe Asian Font Pack. TrueType fonts and CJK fonts can have an optional style modifier + * appended to the name. These modifiers are: Bold, Italic and BoldItalic. An + * example would be "STSong-Light,Bold". Note that this modifiers do not work if + * the font is embedded. Fonts in TrueType collections are addressed by index such as "msgothic.ttc,1". + * This would get the second font (indexes start at 0), in this case "MS PGothic". + *

    + * The fonts are cached and if they already exist they are extracted from the cache, + * not parsed again. + *

    + * Besides the common encodings described by name, custom encodings + * can also be made. These encodings will only work for the single byte fonts + * Type1 and TrueType. The encoding string starts with a '#' + * followed by "simple" or "full". If "simple" there is a decimal for the first character position and then a list + * of hex values representing the Unicode codes that compose that encoding.
    + * The "simple" encoding is recommended for TrueType fonts + * as the "full" encoding risks not matching the character with the right glyph + * if not done with care.
    + * The "full" encoding is specially aimed at Type1 fonts where the glyphs have to be + * described by non standard names like the Tex math fonts. Each group of three elements + * compose a code position: the one byte code order in decimal or as 'x' (x cannot be the space), the name and the Unicode character + * used to access the glyph. The space must be assigned to character position 32 otherwise + * text justification will not work. + *

    + * Example for a "simple" encoding that includes the Unicode + * character space, A, B and ecyrillic: + *

    +        * "# simple 32 0020 0041 0042 0454"
    +        * 
    + *

    + * Example for a "full" encoding for a Type1 Tex font: + *

    +        * "# full 'A' nottriangeqlleft 0041 'B' dividemultiply 0042 32 space 0020"
    +        * 
    + *

    + * This method calls:
    + *

    +        * createFont(name, encoding, embedded, true, null, null);
    +        * 
    + * @param name the name of the font or it's location on file + * @param encoding the encoding to be applied to this font + * @param embedded true if the font is to be embedded in the PDF + * @return returns a new font. This font may come from the cache + * @throws DocumentException the font is invalid + * @throws IOException the font file could not be read + */ + public static BaseFont CreateFont(string name, string encoding, bool embedded) { + return CreateFont(name, encoding, embedded, true, null, null); + } + + /** Creates a new font. This font can be one of the 14 built in types, + * a Type1 font referred to by an AFM or PFM file, a TrueType font (simple or collection) or a CJK font from the + * Adobe Asian Font Pack. TrueType fonts and CJK fonts can have an optional style modifier + * appended to the name. These modifiers are: Bold, Italic and BoldItalic. An + * example would be "STSong-Light,Bold". Note that this modifiers do not work if + * the font is embedded. Fonts in TrueType collections are addressed by index such as "msgothic.ttc,1". + * This would get the second font (indexes start at 0), in this case "MS PGothic". + *

    + * The fonts may or may not be cached depending on the flag cached. + * If the byte arrays are present the font will be + * read from them instead of the name. A name is still required to identify + * the font type. + *

    + * Besides the common encodings described by name, custom encodings + * can also be made. These encodings will only work for the single byte fonts + * Type1 and TrueType. The encoding string starts with a '#' + * followed by "simple" or "full". If "simple" there is a decimal for the first character position and then a list + * of hex values representing the Unicode codes that compose that encoding.
    + * The "simple" encoding is recommended for TrueType fonts + * as the "full" encoding risks not matching the character with the right glyph + * if not done with care.
    + * The "full" encoding is specially aimed at Type1 fonts where the glyphs have to be + * described by non standard names like the Tex math fonts. Each group of three elements + * compose a code position: the one byte code order in decimal or as 'x' (x cannot be the space), the name and the Unicode character + * used to access the glyph. The space must be assigned to character position 32 otherwise + * text justification will not work. + *

    + * Example for a "simple" encoding that includes the Unicode + * character space, A, B and ecyrillic: + *

    +        * "# simple 32 0020 0041 0042 0454"
    +        * 
    + *

    + * Example for a "full" encoding for a Type1 Tex font: + *

    +        * "# full 'A' nottriangeqlleft 0041 'B' dividemultiply 0042 32 space 0020"
    +        * 
    + * @param name the name of the font or it's location on file + * @param encoding the encoding to be applied to this font + * @param embedded true if the font is to be embedded in the PDF + * @param cached true if the font comes from the cache or is added to + * the cache if new, false if the font is always created new + * @param ttfAfm the true type font or the afm in a byte array + * @param pfb the pfb in a byte array + * @return returns a new font. This font may come from the cache but only if cached + * is true, otherwise it will always be created new + * @throws DocumentException the font is invalid + * @throws IOException the font file could not be read + */ + public static BaseFont CreateFont(string name, string encoding, bool embedded, bool cached, byte[] ttfAfm, byte[] pfb) { + return CreateFont(name, encoding, embedded, cached, ttfAfm, pfb, false); + } + + /** Creates a new font. This font can be one of the 14 built in types, + * a Type1 font referred to by an AFM or PFM file, a TrueType font (simple or collection) or a CJK font from the + * Adobe Asian Font Pack. TrueType fonts and CJK fonts can have an optional style modifier + * appended to the name. These modifiers are: Bold, Italic and BoldItalic. An + * example would be "STSong-Light,Bold". Note that this modifiers do not work if + * the font is embedded. Fonts in TrueType collections are addressed by index such as "msgothic.ttc,1". + * This would get the second font (indexes start at 0), in this case "MS PGothic". + *

    + * The fonts may or may not be cached depending on the flag cached. + * If the byte arrays are present the font will be + * read from them instead of the name. A name is still required to identify + * the font type. + *

    + * Besides the common encodings described by name, custom encodings + * can also be made. These encodings will only work for the single byte fonts + * Type1 and TrueType. The encoding string starts with a '#' + * followed by "simple" or "full". If "simple" there is a decimal for the first character position and then a list + * of hex values representing the Unicode codes that compose that encoding.
    + * The "simple" encoding is recommended for TrueType fonts + * as the "full" encoding risks not matching the character with the right glyph + * if not done with care.
    + * The "full" encoding is specially aimed at Type1 fonts where the glyphs have to be + * described by non standard names like the Tex math fonts. Each group of three elements + * compose a code position: the one byte code order in decimal or as 'x' (x cannot be the space), the name and the Unicode character + * used to access the glyph. The space must be assigned to character position 32 otherwise + * text justification will not work. + *

    + * Example for a "simple" encoding that includes the Unicode + * character space, A, B and ecyrillic: + *

    +        * "# simple 32 0020 0041 0042 0454"
    +        * 
    + *

    + * Example for a "full" encoding for a Type1 Tex font: + *

    +        * "# full 'A' nottriangeqlleft 0041 'B' dividemultiply 0042 32 space 0020"
    +        * 
    + * @param name the name of the font or it's location on file + * @param encoding the encoding to be applied to this font + * @param embedded true if the font is to be embedded in the PDF + * @param cached true if the font comes from the cache or is added to + * the cache if new, false if the font is always created new + * @param ttfAfm the true type font or the afm in a byte array + * @param pfb the pfb in a byte array + * @param noThrow if true will not throw an exception if the font is not recognized and will return null, if false will throw + * an exception if the font is not recognized. Note that even if true an exception may be thrown in some circumstances. + * This parameter is useful for FontFactory that may have to check many invalid font names before finding the right one + * @return returns a new font. This font may come from the cache but only if cached + * is true, otherwise it will always be created new + * @throws DocumentException the font is invalid + * @throws IOException the font file could not be read + */ + public static BaseFont CreateFont(string name, string encoding, bool embedded, bool cached, byte[] ttfAfm, byte[] pfb, bool noThrow) { + string nameBase = GetBaseName(name); + encoding = NormalizeEncoding(encoding); + bool isBuiltinFonts14 = BuiltinFonts14.ContainsKey(name); + bool isCJKFont = isBuiltinFonts14 ? false : CJKFont.IsCJKFont(nameBase, encoding); + if (isBuiltinFonts14 || isCJKFont) + embedded = false; + else if (encoding.Equals(IDENTITY_H) || encoding.Equals(IDENTITY_V)) + embedded = true; + BaseFont fontFound = null; + BaseFont fontBuilt = null; + string key = name + "\n" + encoding + "\n" + embedded; + if (cached) { + lock (fontCache) { + fontFound = (BaseFont)fontCache[key]; + } + if (fontFound != null) + return fontFound; + } + if (isBuiltinFonts14 || name.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".afm") || name.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".pfm")) { + fontBuilt = new Type1Font(name, encoding, embedded, ttfAfm, pfb); + fontBuilt.fastWinansi = encoding.Equals(CP1252); + } + else if (nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".ttf") || nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".otf") || nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf(".ttc,") > 0) { + if (encoding.Equals(IDENTITY_H) || encoding.Equals(IDENTITY_V)) + fontBuilt = new TrueTypeFontUnicode(name, encoding, embedded, ttfAfm); + else { + fontBuilt = new TrueTypeFont(name, encoding, embedded, ttfAfm); + fontBuilt.fastWinansi = encoding.Equals(CP1252); + } + } + else if (isCJKFont) + fontBuilt = new CJKFont(name, encoding, embedded); + else if (noThrow) + return null; + else + throw new DocumentException("Font '" + name + "' with '" + encoding + "' is not recognized."); + if (cached) { + lock (fontCache) { + fontFound = (BaseFont)fontCache[key]; + if (fontFound != null) + return fontFound; + fontCache.Add(key, fontBuilt); + } + } + return fontBuilt; + } + + /** + * Creates a font based on an existing document font. The created font font may not + * behave as expected, depending on the encoding or subset. + * @param fontRef the reference to the document font + * @return the font + */ + public static BaseFont CreateFont(PRIndirectReference fontRef) { + return new DocumentFont(fontRef); + } + + /** + * Gets the name without the modifiers Bold, Italic or BoldItalic. + * @param name the full name of the font + * @return the name without the modifiers Bold, Italic or BoldItalic + */ + protected static string GetBaseName(string name) { + if (name.EndsWith(",Bold")) + return name.Substring(0, name.Length - 5); + else if (name.EndsWith(",Italic")) + return name.Substring(0, name.Length - 7); + else if (name.EndsWith(",BoldItalic")) + return name.Substring(0, name.Length - 11); + else + return name; + } + + /** + * Normalize the encoding names. "winansi" is changed to "Cp1252" and + * "macroman" is changed to "MacRoman". + * @param enc the encoding to be normalized + * @return the normalized encoding + */ + protected static string NormalizeEncoding(string enc) { + if (enc.Equals("winansi") || enc.Equals("")) + return CP1252; + else if (enc.Equals("macroman")) + return MACROMAN; + int n = IanaEncodings.GetEncodingNumber(enc); + if (n == 1252) + return CP1252; + if (n == 10000) + return MACROMAN; + return enc; + } + + /** + * Creates the widths and the differences arrays + * @throws UnsupportedEncodingException the encoding is not supported + */ + protected void CreateEncoding() { + if (encoding.StartsWith("#")) { + specialMap = new IntHashtable(); + StringTokenizer tok = new StringTokenizer(encoding.Substring(1), " ,\t\n\r\f"); + if (tok.NextToken().Equals("full")) { + while (tok.HasMoreTokens()) { + String order = tok.NextToken(); + String name = tok.NextToken(); + char uni = (char)int.Parse(tok.NextToken(), NumberStyles.HexNumber); + int orderK; + if (order.StartsWith("'")) + orderK = (int)order[1]; + else + orderK = int.Parse(order); + orderK %= 256; + specialMap[(int)uni] = orderK; + differences[orderK] = name; + unicodeDifferences[orderK] = uni; + widths[orderK] = GetRawWidth((int)uni, name); + charBBoxes[orderK] = GetRawCharBBox((int)uni, name); + } + } + else { + int k = 0; + if (tok.HasMoreTokens()) + k = int.Parse(tok.NextToken()); + while (tok.HasMoreTokens() && k < 256) { + String hex = tok.NextToken(); + int uni = int.Parse(hex, NumberStyles.HexNumber) % 0x10000; + String name = GlyphList.UnicodeToName(uni); + if (name != null) { + specialMap[uni] = k; + differences[k] = name; + unicodeDifferences[k] = (char)uni; + widths[k] = GetRawWidth(uni, name); + charBBoxes[k] = GetRawCharBBox(uni, name); + ++k; + } + } + } + for (int k = 0; k < 256; ++k) { + if (differences[k] == null) { + differences[k] = notdef; + } + } + } + else if (fontSpecific) { + for (int k = 0; k < 256; ++k) { + widths[k] = GetRawWidth(k, null); + charBBoxes[k] = GetRawCharBBox(k, null); + } + } + else { + string s; + string name; + char c; + byte[] b = new byte[1]; + for (int k = 0; k < 256; ++k) { + b[0] = (byte)k; + s = PdfEncodings.ConvertToString(b, encoding); + if (s.Length > 0) { + c = s[0]; + } + else { + c = '?'; + } + name = GlyphList.UnicodeToName((int)c); + if (name == null) + name = notdef; + differences[k] = name; + this.UnicodeDifferences[k] = c; + widths[k] = GetRawWidth((int)c, name); + charBBoxes[k] = GetRawCharBBox((int)c, name); + } + } + } + + /** + * Gets the width from the font according to the Unicode char c + * or the name. If the name is null it's a symbolic font. + * @param c the unicode char + * @param name the glyph name + * @return the width of the char + */ + internal abstract int GetRawWidth(int c, string name); + + /** + * Gets the kerning between two Unicode chars. + * @param char1 the first char + * @param char2 the second char + * @return the kerning to be applied + */ + public abstract int GetKerning(int char1, int char2); + + /** + * Sets the kerning between two Unicode chars. + * @param char1 the first char + * @param char2 the second char + * @param kern the kerning to apply in normalized 1000 units + * @return true if the kerning was applied, false otherwise + */ + public abstract bool SetKerning(int char1, int char2, int kern); + + /** + * Gets the width of a char in normalized 1000 units. + * @param char1 the unicode char to get the width of + * @return the width in normalized 1000 units + */ + public virtual int GetWidth(int char1) { + if (fastWinansi) { + if (char1 < 128 || (char1 >= 160 && char1 <= 255)) + return widths[char1]; + else + return widths[PdfEncodings.winansi[char1]]; + } + else { + int total = 0; + byte[] mbytes = ConvertToBytes((char)char1); + for (int k = 0; k < mbytes.Length; ++k) + total += widths[0xff & mbytes[k]]; + return total; + } + } + + /** + * Gets the width of a string in normalized 1000 units. + * @param text the string to get the witdth of + * @return the width in normalized 1000 units + */ + public virtual int GetWidth(string text) { + int total = 0; + if (fastWinansi) { + int len = text.Length; + for (int k = 0; k < len; ++k) { + char char1 = text[k]; + if (char1 < 128 || (char1 >= 160 && char1 <= 255)) + total += widths[char1]; + else + total += widths[PdfEncodings.winansi[char1]]; + } + return total; + } + else { + byte[] mbytes = ConvertToBytes(text); + for (int k = 0; k < mbytes.Length; ++k) + total += widths[0xff & mbytes[k]]; + } + return total; + } + + /** + * Gets the descent of a String in normalized 1000 units. The descent will always be + * less than or equal to zero even if all the characters have an higher descent. + * @param text the String to get the descent of + * @return the dexcent in normalized 1000 units + */ + public int GetDescent(String text) { + int min = 0; + char[] chars = text.ToCharArray(); + for (int k = 0; k < chars.Length; ++k) { + int[] bbox = GetCharBBox(chars[k]); + if (bbox != null && bbox[1] < min) + min = bbox[1]; + } + return min; + } + + /** + * Gets the ascent of a String in normalized 1000 units. The ascent will always be + * greater than or equal to zero even if all the characters have a lower ascent. + * @param text the String to get the ascent of + * @return the ascent in normalized 1000 units + */ + public int GetAscent(String text) { + int max = 0; + char[] chars = text.ToCharArray(); + for (int k = 0; k < chars.Length; ++k) { + int[] bbox = GetCharBBox(chars[k]); + if (bbox != null && bbox[3] > max) + max = bbox[3]; + } + return max; + } + + /** + * Gets the descent of a String in points. The descent will always be + * less than or equal to zero even if all the characters have an higher descent. + * @param text the String to get the descent of + * @param fontSize the size of the font + * @return the dexcent in points + */ + public float GetDescentPoint(String text, float fontSize) + { + return (float)GetDescent(text) * 0.001f * fontSize; + } + + /** + * Gets the ascent of a String in points. The ascent will always be + * greater than or equal to zero even if all the characters have a lower ascent. + * @param text the String to get the ascent of + * @param fontSize the size of the font + * @return the ascent in points + */ + public float GetAscentPoint(String text, float fontSize) + { + return (float)GetAscent(text) * 0.001f * fontSize; + } + + /** + * Gets the width of a String in points taking kerning + * into account. + * @param text the String to get the witdth of + * @param fontSize the font size + * @return the width in points + */ + public float GetWidthPointKerned(String text, float fontSize) { + float size = (float)GetWidth(text) * 0.001f * fontSize; + if (!HasKernPairs()) + return size; + int len = text.Length - 1; + int kern = 0; + char[] c = text.ToCharArray(); + for (int k = 0; k < len; ++k) { + kern += GetKerning(c[k], c[k + 1]); + } + return size + kern * 0.001f * fontSize; + } + + /** + * Gets the width of a string in points. + * @param text the string to get the witdth of + * @param fontSize the font size + * @return the width in points + */ + public float GetWidthPoint(string text, float fontSize) { + return (float)GetWidth(text) * 0.001f * fontSize; + } + + /** + * Gets the width of a char in points. + * @param char1 the char to get the witdth of + * @param fontSize the font size + * @return the width in points + */ + public float GetWidthPoint(int char1, float fontSize) { + return GetWidth(char1) * 0.001f * fontSize; + } + + /** + * Converts a string to a byte array according + * to the font's encoding. + * @param text the string to be converted + * @return an array of byte representing the conversion according to the font's encoding + */ + internal virtual byte[] ConvertToBytes(string text) { + if (directTextToByte) + return PdfEncodings.ConvertToBytes(text, null); + if (specialMap != null) { + byte[] b = new byte[text.Length]; + int ptr = 0; + int length = text.Length; + for (int k = 0; k < length; ++k) { + char c = text[k]; + if (specialMap.ContainsKey((int)c)) + b[ptr++] = (byte)specialMap[(int)c]; + } + if (ptr < length) { + byte[] b2 = new byte[ptr]; + System.Array.Copy(b, 0, b2, 0, ptr); + return b2; + } + else + return b; + } + return PdfEncodings.ConvertToBytes(text, encoding); + } + + /** + * Converts a char to a byte array according + * to the font's encoding. + * @param text the String to be converted + * @return an array of byte representing the conversion according to the font's encoding + */ + internal virtual byte[] ConvertToBytes(int char1) { + if (directTextToByte) + return PdfEncodings.ConvertToBytes((char)char1, null); + if (specialMap != null) { + if (specialMap.ContainsKey(char1)) + return new byte[]{(byte)specialMap[(int)char1]}; + else + return new byte[0]; + } + return PdfEncodings.ConvertToBytes((char)char1, encoding); + } + + /** Outputs to the writer the font dictionaries and streams. + * @param writer the writer for this document + * @param ref the font indirect reference + * @param params several parameters that depend on the font type + * @throws IOException on error + * @throws DocumentException error in generating the object + */ + internal abstract void WriteFont(PdfWriter writer, PdfIndirectReference piRef, Object[] oParams); + + /** Gets the encoding used to convert string into byte[]. + * @return the encoding name + */ + public string Encoding { + get { + return encoding; + } + } + + /** Gets the font parameter identified by key. Valid values + * for key are ASCENT, CAPHEIGHT, DESCENT, + * ITALICANGLE, BBOXLLX, BBOXLLY, BBOXURX + * and BBOXURY. + * @param key the parameter to be extracted + * @param fontSize the font size in points + * @return the parameter in points + */ + public abstract float GetFontDescriptor(int key, float fontSize); + + /** Gets the font type. The font types can be: FONT_TYPE_T1, + * FONT_TYPE_TT, FONT_TYPE_CJK and FONT_TYPE_TTUNI. + * @return the font type + */ + public int FontType { + get { + return fontType; + } + + set { + fontType = value; + } + } + + /** Gets the embedded flag. + * @return true if the font is embedded. + */ + public bool IsEmbedded() { + return embedded; + } + + /** Gets the symbolic flag of the font. + * @return true if the font is symbolic + */ + public bool IsFontSpecific() { + return fontSpecific; + } + + /** Creates a unique subset prefix to be added to the font name when the font is embedded and subset. + * @return the subset prefix + */ + internal static string CreateSubsetPrefix() { + char[] s = new char[7]; + lock (random) { + for (int k = 0; k < 6; ++k) + s[k] = (char)(random.Next('A', 'Z' + 1)); + } + s[6] = '+'; + return new String(s); + } + + /** Gets the Unicode character corresponding to the byte output to the pdf stream. + * @param index the byte index + * @return the Unicode character + */ + internal char GetUnicodeDifferences(int index) { + return unicodeDifferences[index]; + } + + /** Gets the postscript font name. + * @return the postscript font name + */ + public abstract string PostscriptFontName { + get; + set; + } + + /** Gets the full name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
    + * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @return the full name of the font + */ + public abstract string[][] FullFontName { + get; + } + + /** Gets all the entries of the names-table. If it is a True Type font + * each array element will have {Name ID, Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
    + * For the other fonts the array has a single element with {"4", "", "", "", + * font name}. + * @return the full name of the font + */ + public abstract string[][] AllNameEntries{ + get; + } + + /** Gets the full name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
    + * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @param name the name of the font + * @param encoding the encoding of the font + * @param ttfAfm the true type font or the afm in a byte array + * @throws DocumentException on error + * @throws IOException on error + * @return the full name of the font + */ + public static string[][] GetFullFontName(string name, string encoding, byte[] ttfAfm) { + string nameBase = GetBaseName(name); + BaseFont fontBuilt = null; + if (nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".ttf") || nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".otf") || nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf(".ttc,") > 0) + fontBuilt = new TrueTypeFont(name, CP1252, false, ttfAfm, true); + else + fontBuilt = CreateFont(name, encoding, false, false, ttfAfm, null); + return fontBuilt.FullFontName; + } + + /** Gets all the names from the font. Only the required tables are read. + * @param name the name of the font + * @param encoding the encoding of the font + * @param ttfAfm the true type font or the afm in a byte array + * @throws DocumentException on error + * @throws IOException on error + * @return an array of Object[] built with {getPostscriptFontName(), GetFamilyFontName(), GetFullFontName()} + */ + public static Object[] GetAllFontNames(String name, String encoding, byte[] ttfAfm) { + String nameBase = GetBaseName(name); + BaseFont fontBuilt = null; + if (nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".ttf") || nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".otf") || nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf(".ttc,") > 0) + fontBuilt = new TrueTypeFont(name, CP1252, false, ttfAfm, true); + else + fontBuilt = CreateFont(name, encoding, false, false, ttfAfm, null); + return new Object[]{fontBuilt.PostscriptFontName, fontBuilt.FamilyFontName, fontBuilt.FullFontName}; + } + + /** Gets all the entries of the namestable from the font. Only the required tables are read. + * @param name the name of the font + * @param encoding the encoding of the font + * @param ttfAfm the true type font or the afm in a byte array + * @throws DocumentException on error + * @throws IOException on error + * @return an array of Object[] built with {getPostscriptFontName(), getFamilyFontName(), getFullFontName()} + */ + public static String[][] GetAllNameEntries(String name, String encoding, byte[] ttfAfm) { + String nameBase = GetBaseName(name); + BaseFont fontBuilt = null; + if (nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".ttf") || nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).EndsWith(".otf") || nameBase.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf(".ttc,") > 0) + fontBuilt = new TrueTypeFont(name, CP1252, false, ttfAfm, true); + else + fontBuilt = CreateFont(name, encoding, false, false, ttfAfm, null); + return fontBuilt.AllNameEntries; + } + + /** Gets the family name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
    + * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @return the family name of the font + */ + public abstract string[][] FamilyFontName { + get; + } + + /** Gets the code pages supported by the font. This has only meaning + * with True Type fonts. + * @return the code pages supported by the font + */ + public virtual string[] CodePagesSupported { + get { + return new string[0]; + } + } + + /** Enumerates the postscript font names present inside a + * True Type Collection. + * @param ttcFile the file name of the font + * @throws DocumentException on error + * @throws IOException on error + * @return the postscript font names + */ + public static string[] EnumerateTTCNames(string ttcFile) { + return new EnumerateTTC(ttcFile).Names; + } + + /** Enumerates the postscript font names present inside a + * True Type Collection. + * @param ttcArray the font as a byte array + * @throws DocumentException on error + * @throws IOException on error + * @return the postscript font names + */ + public static string[] EnumerateTTCNames(byte[] ttcArray) { + return new EnumerateTTC(ttcArray).Names; + } + + /** Gets the font width array. + * @return the font width array + */ + public int[] Widths { + get { + return widths; + } + } + + /** Gets the array with the names of the characters. + * @return the array with the names of the characters + */ + public string[] Differences { + get { + return differences; + } + } + + /** Gets the array with the unicode characters. + * @return the array with the unicode characters + */ + public char[] UnicodeDifferences { + get { + return unicodeDifferences; + } + } + + /** Set to true to force the generation of the + * widths array. + * @param forceWidthsOutput true to force the generation of the + * widths array + */ + public bool ForceWidthsOutput { + set { + this.forceWidthsOutput = value; + } + get { + return forceWidthsOutput; + } + } + + /** Sets the conversion of char directly to byte + * by casting. This is a low level feature to put the bytes directly in + * the content stream without passing through string.GetBytes(). + * @param directTextToByte New value of property directTextToByte. + */ + public bool DirectTextToByte { + set { + this.directTextToByte = value; + } + get { + return directTextToByte; + } + } + + /** Indicates if all the glyphs and widths for that particular + * encoding should be included in the document. When set to true + * only the glyphs used will be included in the font. When set to false + * and {@link #addSubsetRange(int[])} was not called the full font will be included + * otherwise just the characters ranges will be included. + * @param subset new value of property subset + */ + public bool Subset { + set { + this.subset = value; + } + get { + return subset; + } + } + + public static void AddToResourceSearch (object obj) { + if (obj is Assembly) { + resourceSearch.Add(obj); + } + else if (obj is string) { + string f = (string)obj; + if (Directory.Exists(f) || File.Exists(f)) + resourceSearch.Add(obj); + } + } + + /** Gets the font resources. + * @param key the name of the resource + * @return the Stream to get the resource or + * null if not found + */ + public static Stream GetResourceStream(string key) { + Stream istr = null; + // Try to use resource loader to load the properties file. + try { + Assembly assm = Assembly.GetExecutingAssembly(); + istr = assm.GetManifestResourceStream(key); + } + catch { + } + if (istr != null) + return istr; + for (int k = 0; k < resourceSearch.Count; ++k) { + object obj = resourceSearch[k]; + try { + if (obj is Assembly) { + istr = ((Assembly)obj).GetManifestResourceStream(key); + if (istr != null) + return istr; + } + else if (obj is string) { + string dir = (string)obj; + try { + istr = Assembly.LoadFrom(dir).GetManifestResourceStream(key); + } + catch { + } + if (istr != null) + return istr; + string modkey = key.Replace('.', '/'); + string fullPath = Path.Combine(dir, modkey); + if (File.Exists(fullPath)) { + return new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read); + } + int idx = modkey.LastIndexOf('/'); + if (idx >= 0) { + modkey = modkey.Substring(0, idx) + "." + modkey.Substring(idx + 1); + fullPath = Path.Combine(dir, modkey); + if (File.Exists(fullPath)) + return new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read); + } + } + } + catch { + } + } + + return istr; + } + + /** Gets the Unicode equivalent to a CID. + * The (inexistent) CID is translated as '\n'. + * It has only meaning with CJK fonts with Identity encoding. + * @param c the CID code + * @return the Unicode equivalent + */ + public virtual int GetUnicodeEquivalent(int c) { + return c; + } + + /** Gets the CID code given an Unicode. + * It has only meaning with CJK fonts. + * @param c the Unicode + * @return the CID equivalent + */ + public virtual int GetCidCode(int c) { + return c; + } + + /** Checks if the font has any kerning pairs. + * @return true if the font has any kerning pairs + */ + public abstract bool HasKernPairs(); + + /** + * Checks if a character exists in this font. + * @param c the character to check + * @return true if the character has a glyph, + * false otherwise + */ + public virtual bool CharExists(int c) { + byte[] b = ConvertToBytes(c); + return b.Length > 0; + } + + /** + * Sets the character advance. + * @param c the character + * @param advance the character advance normalized to 1000 units + * @return true if the advance was set, + * false otherwise + */ + public virtual bool SetCharAdvance(int c, int advance) { + byte[] b = ConvertToBytes(c); + if (b.Length == 0) + return false; + widths[0xff & b[0]] = advance; + return true; + } + + private static void AddFont(PRIndirectReference fontRef, IntHashtable hits, ArrayList fonts) { + PdfObject obj = PdfReader.GetPdfObject(fontRef); + if (obj == null || !obj.IsDictionary()) + return; + PdfDictionary font = (PdfDictionary)obj; + PdfName subtype = (PdfName)PdfReader.GetPdfObject(font.Get(PdfName.SUBTYPE)); + if (!PdfName.TYPE1.Equals(subtype) && !PdfName.TRUETYPE.Equals(subtype)) + return; + PdfName name = (PdfName)PdfReader.GetPdfObject(font.Get(PdfName.BASEFONT)); + fonts.Add(new Object[]{PdfName.DecodeName(name.ToString()), fontRef}); + hits[fontRef.Number] = 1; + } + + private static void RecourseFonts(PdfDictionary page, IntHashtable hits, ArrayList fonts, int level) { + ++level; + if (level > 50) // in case we have an endless loop + return; + PdfDictionary resources = (PdfDictionary)PdfReader.GetPdfObject(page.Get(PdfName.RESOURCES)); + if (resources == null) + return; + PdfDictionary font = (PdfDictionary)PdfReader.GetPdfObject(resources.Get(PdfName.FONT)); + if (font != null) { + foreach (PdfName key in font.Keys) { + PdfObject ft = font.Get(key); + if (ft == null || !ft.IsIndirect()) + continue; + int hit = ((PRIndirectReference)ft).Number; + if (hits.ContainsKey(hit)) + continue; + AddFont((PRIndirectReference)ft, hits, fonts); + } + } + PdfDictionary xobj = (PdfDictionary)PdfReader.GetPdfObject(resources.Get(PdfName.XOBJECT)); + if (xobj != null) { + foreach (PdfName key in xobj.Keys) { + RecourseFonts((PdfDictionary)PdfReader.GetPdfObject(xobj.Get(key)), hits, fonts, level); + } + } + } + + /** + * Gets a list of all document fonts. Each element of the ArrayList + * contains a Object[]{String,PRIndirectReference} with the font name + * and the indirect reference to it. + * @param reader the document where the fonts are to be listed from + * @return the list of fonts and references + */ + public static ArrayList GetDocumentFonts(PdfReader reader) { + IntHashtable hits = new IntHashtable(); + ArrayList fonts = new ArrayList(); + int npages = reader.NumberOfPages; + for (int k = 1; k <= npages; ++k) + RecourseFonts(reader.GetPageN(k), hits, fonts, 1); + return fonts; + } + + /** + * Gets a list of the document fonts in a particular page. Each element of the ArrayList + * contains a Object[]{String,PRIndirectReference} with the font name + * and the indirect reference to it. + * @param reader the document where the fonts are to be listed from + * @param page the page to list the fonts from + * @return the list of fonts and references + */ + public static ArrayList GetDocumentFonts(PdfReader reader, int page) { + IntHashtable hits = new IntHashtable(); + ArrayList fonts = new ArrayList(); + RecourseFonts(reader.GetPageN(page), hits, fonts, 1); + return fonts; + } + + /** + * Gets the smallest box enclosing the character contours. It will return + * null if the font has not the information or the character has no + * contours, as in the case of the space, for example. Characters with no contours may + * also return [0,0,0,0]. + * @param c the character to get the contour bounding box from + * @return an array of four floats with the bounding box in the format [llx,lly,urx,ury] or + * null + */ + public virtual int[] GetCharBBox(int c) { + byte[] b = ConvertToBytes(c); + if (b.Length == 0) + return null; + else + return charBBoxes[b[0] & 0xff]; + } + + protected abstract int[] GetRawCharBBox(int c, String name); + + /** + * iText expects Arabic Diactrics (tashkeel) to have zero advance but some fonts, + * most notably those that come with Windows, like times.ttf, have non-zero + * advance for those characters. This method makes those character to have zero + * width advance and work correctly in the iText Arabic shaping and reordering + * context. + */ + public void CorrectArabicAdvance() { + for (char c = '\u064b'; c <= '\u0658'; ++c) + SetCharAdvance(c, 0); + SetCharAdvance('\u0670', 0); + for (char c = '\u06d6'; c <= '\u06dc'; ++c) + SetCharAdvance(c, 0); + for (char c = '\u06df'; c <= '\u06e4'; ++c) + SetCharAdvance(c, 0); + for (char c = '\u06e7'; c <= '\u06e8'; ++c) + SetCharAdvance(c, 0); + for (char c = '\u06ea'; c <= '\u06ed'; ++c) + SetCharAdvance(c, 0); + } + + /** + * Adds a character range when subsetting. The range is an int array + * where the first element is the start range inclusive and the second element is the + * end range inclusive. Several ranges are allowed in the same array. + * @param range the character range + */ + public void AddSubsetRange(int[] range) { + if (subsetRanges == null) + subsetRanges = new ArrayList(); + subsetRanges.Add(range); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/BidiLine.cs b/iTechSharp/iTextSharp/text/pdf/BidiLine.cs new file mode 100644 index 0000000..239e921 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BidiLine.cs @@ -0,0 +1,946 @@ +using System; +using System.Collections; +using System.Text; + +/* + * + * Copyright 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Does all the line bidirectional processing with PdfChunk assembly. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class BidiLine { + private const int pieceSizeStart = 256; + + protected int runDirection; + protected int pieceSize = pieceSizeStart; + protected char[] text = new char[pieceSizeStart]; + protected PdfChunk[] detailChunks = new PdfChunk[pieceSizeStart]; + protected int totalTextLength = 0; + + protected byte[] orderLevels = new byte[pieceSizeStart]; + protected int[] indexChars = new int[pieceSizeStart]; + + protected ArrayList chunks = new ArrayList(); + protected int indexChunk = 0; + protected int indexChunkChar = 0; + protected int currentChar = 0; + + protected int storedRunDirection; + protected char[] storedText = new char[0]; + protected PdfChunk[] storedDetailChunks = new PdfChunk[0]; + protected int storedTotalTextLength = 0; + + protected byte[] storedOrderLevels = new byte[0]; + protected int[] storedIndexChars = new int[0]; + + protected int storedIndexChunk = 0; + protected int storedIndexChunkChar = 0; + protected int storedCurrentChar = 0; + + protected bool shortStore; + protected static IntHashtable mirrorChars = new IntHashtable(); + protected int arabicOptions; + + /** Creates new BidiLine */ + public BidiLine() { + } + + public BidiLine(BidiLine org) { + runDirection = org.runDirection; + pieceSize = org.pieceSize; + text = (char[])org.text.Clone(); + detailChunks = (PdfChunk[])org.detailChunks.Clone(); + totalTextLength = org.totalTextLength; + + orderLevels = (byte[])org.orderLevels.Clone(); + indexChars = (int[])org.indexChars.Clone(); + + chunks = new ArrayList(org.chunks); + indexChunk = org.indexChunk; + indexChunkChar = org.indexChunkChar; + currentChar = org.currentChar; + + storedRunDirection = org.storedRunDirection; + storedText = (char[])org.storedText.Clone(); + storedDetailChunks = (PdfChunk[])org.storedDetailChunks.Clone(); + storedTotalTextLength = org.storedTotalTextLength; + + storedOrderLevels = (byte[])org.storedOrderLevels.Clone(); + storedIndexChars = (int[])org.storedIndexChars.Clone(); + + storedIndexChunk = org.storedIndexChunk; + storedIndexChunkChar = org.storedIndexChunkChar; + storedCurrentChar = org.storedCurrentChar; + + shortStore = org.shortStore; + arabicOptions = org.arabicOptions; + } + + public bool IsEmpty() { + return (currentChar >= totalTextLength && indexChunk >= chunks.Count); + } + + public void ClearChunks() { + chunks.Clear(); + totalTextLength = 0; + currentChar = 0; + } + + public bool GetParagraph(int runDirection) { + this.runDirection = runDirection; + currentChar = 0; + totalTextLength = 0; + bool hasText = false; + char c; + char uniC; + BaseFont bf; + for (; indexChunk < chunks.Count; ++indexChunk) { + PdfChunk ck = (PdfChunk)chunks[indexChunk]; + bf = ck.Font.Font; + string s = ck.ToString(); + int len = s.Length; + for (; indexChunkChar < len; ++indexChunkChar) { + c = s[indexChunkChar]; + uniC = (char)bf.GetUnicodeEquivalent(c); + if (uniC == '\r' || uniC == '\n') { + // next condition is never true for CID + if (uniC == '\r' && indexChunkChar + 1 < len && s[indexChunkChar + 1] == '\n') + ++indexChunkChar; + ++indexChunkChar; + if (indexChunkChar >= len) { + indexChunkChar = 0; + ++indexChunk; + } + hasText = true; + if (totalTextLength == 0) + detailChunks[0] = ck; + break; + } + AddPiece(c, ck); + } + if (hasText) + break; + indexChunkChar = 0; + } + if (totalTextLength == 0) + return hasText; + + // remove trailing WS + totalTextLength = TrimRight(0, totalTextLength - 1) + 1; + if (totalTextLength == 0) + return true; + + if (runDirection == PdfWriter.RUN_DIRECTION_LTR || runDirection == PdfWriter.RUN_DIRECTION_RTL) { + if (orderLevels.Length < totalTextLength) { + orderLevels = new byte[pieceSize]; + indexChars = new int[pieceSize]; + } + + ArabicLigaturizer.ProcessNumbers(text, 0, totalTextLength, arabicOptions); + BidiOrder order = new BidiOrder(text, 0, totalTextLength, (sbyte)(runDirection == PdfWriter.RUN_DIRECTION_RTL ? 1 : 0)); + byte[] od = order.GetLevels(); + for (int k = 0; k < totalTextLength; ++k) { + orderLevels[k] = od[k]; + indexChars[k] = k; + } + DoArabicShapping(); + MirrorGlyphs(); + } + totalTextLength = TrimRightEx(0, totalTextLength - 1) + 1; + return true; + } + + public void AddChunk(PdfChunk chunk) { + chunks.Add(chunk); + } + + public void AddChunks(ArrayList chunks) { + this.chunks.AddRange(chunks); + } + + public void AddPiece(char c, PdfChunk chunk) { + if (totalTextLength >= pieceSize) { + char[] tempText = text; + PdfChunk[] tempDetailChunks = detailChunks; + pieceSize *= 2; + text = new char[pieceSize]; + detailChunks = new PdfChunk[pieceSize]; + Array.Copy(tempText, 0, text, 0, totalTextLength); + Array.Copy(tempDetailChunks, 0, detailChunks, 0, totalTextLength); + } + text[totalTextLength] = c; + detailChunks[totalTextLength++] = chunk; + } + + public void Save() { + if (indexChunk > 0) { + if (indexChunk >= chunks.Count) + chunks.Clear(); + else { + for (--indexChunk; indexChunk >= 0; --indexChunk) + chunks.RemoveAt(indexChunk); + } + indexChunk = 0; + } + storedRunDirection = runDirection; + storedTotalTextLength = totalTextLength; + storedIndexChunk = indexChunk; + storedIndexChunkChar = indexChunkChar; + storedCurrentChar = currentChar; + shortStore = (currentChar < totalTextLength); + if (!shortStore) { + // long save + if (storedText.Length < totalTextLength) { + storedText = new char[totalTextLength]; + storedDetailChunks = new PdfChunk[totalTextLength]; + } + Array.Copy(text, 0, storedText, 0, totalTextLength); + Array.Copy(detailChunks, 0, storedDetailChunks, 0, totalTextLength); + } + if (runDirection == PdfWriter.RUN_DIRECTION_LTR || runDirection == PdfWriter.RUN_DIRECTION_RTL) { + if (storedOrderLevels.Length < totalTextLength) { + storedOrderLevels = new byte[totalTextLength]; + storedIndexChars = new int[totalTextLength]; + } + Array.Copy(orderLevels, currentChar, storedOrderLevels, currentChar, totalTextLength - currentChar); + Array.Copy(indexChars, currentChar, storedIndexChars, currentChar, totalTextLength - currentChar); + } + } + + public void Restore() { + runDirection = storedRunDirection; + totalTextLength = storedTotalTextLength; + indexChunk = storedIndexChunk; + indexChunkChar = storedIndexChunkChar; + currentChar = storedCurrentChar; + if (!shortStore) { + // long restore + Array.Copy(storedText, 0, text, 0, totalTextLength); + Array.Copy(storedDetailChunks, 0, detailChunks, 0, totalTextLength); + } + if (runDirection == PdfWriter.RUN_DIRECTION_LTR || runDirection == PdfWriter.RUN_DIRECTION_RTL) { + Array.Copy(storedOrderLevels, currentChar, orderLevels, currentChar, totalTextLength - currentChar); + Array.Copy(storedIndexChars, currentChar, indexChars, currentChar, totalTextLength - currentChar); + } + } + + public void MirrorGlyphs() { + for (int k = 0; k < totalTextLength; ++k) { + if ((orderLevels[k] & 1) == 1) { + int mirror = mirrorChars[text[k]]; + if (mirror != 0) + text[k] = (char)mirror; + } + } + } + + public void DoArabicShapping() { + int src = 0; + int dest = 0; + for (;;) { + while (src < totalTextLength) { + char c = text[src]; + if (c >= 0x0600 && c <= 0x06ff) + break; + if (src != dest) { + text[dest] = text[src]; + detailChunks[dest] = detailChunks[src]; + orderLevels[dest] = orderLevels[src]; + } + ++src; + ++dest; + } + if (src >= totalTextLength) { + totalTextLength = dest; + return; + } + int startArabicIdx = src; + ++src; + while (src < totalTextLength) { + char c = text[src]; + if (c < 0x0600 || c > 0x06ff) + break; + ++src; + } + int arabicWordSize = src - startArabicIdx; + int size = ArabicLigaturizer.Arabic_shape(text, startArabicIdx, arabicWordSize, text, dest, arabicWordSize, arabicOptions); + if (startArabicIdx != dest) { + for (int k = 0; k < size; ++k) { + detailChunks[dest] = detailChunks[startArabicIdx]; + orderLevels[dest++] = orderLevels[startArabicIdx++]; + } + } + else + dest += size; + } + } + + public PdfLine ProcessLine(float leftX, float width, int alignment, int runDirection, int arabicOptions) { + this.arabicOptions = arabicOptions; + Save(); + bool isRTL = (runDirection == PdfWriter.RUN_DIRECTION_RTL); + if (currentChar >= totalTextLength) { + bool hasText = GetParagraph(runDirection); + if (!hasText) + return null; + if (totalTextLength == 0) { + ArrayList ar = new ArrayList(); + PdfChunk ckx = new PdfChunk("", detailChunks[0]); + ar.Add(ckx); + return new PdfLine(0, 0, 0, alignment, true, ar, isRTL); + } + } + float originalWidth = width; + int lastSplit = -1; + if (currentChar != 0) + currentChar = TrimLeftEx(currentChar, totalTextLength - 1); + int oldCurrentChar = currentChar; + int uniC = 0; + PdfChunk ck = null; + float charWidth = 0; + PdfChunk lastValidChunk = null; + bool splitChar = false; + bool surrogate = false; + for (; currentChar < totalTextLength; ++currentChar) { + ck = detailChunks[currentChar]; + surrogate = Utilities.IsSurrogatePair(text, currentChar); + if (surrogate) + uniC = ck.GetUnicodeEquivalent(Utilities.ConvertToUtf32(text, currentChar)); + else + uniC = ck.GetUnicodeEquivalent(text[currentChar]); + if (PdfChunk.NoPrint(uniC)) + continue; + if (surrogate) + charWidth = ck.GetCharWidth(uniC); + else + charWidth = ck.GetCharWidth(text[currentChar]); + splitChar = ck.IsExtSplitCharacter(oldCurrentChar, currentChar, totalTextLength, text, detailChunks); + if (splitChar && Char.IsWhiteSpace((char)uniC)) + lastSplit = currentChar; + if (width - charWidth < 0) + break; + if (splitChar) + lastSplit = currentChar; + width -= charWidth; + lastValidChunk = ck; + if (surrogate) + ++currentChar; + if (ck.IsTab()) { + Object[] tab = (Object[])ck.GetAttribute(Chunk.TAB); + float tabPosition = (float)tab[1]; + bool newLine = (bool)tab[2]; + if (newLine && tabPosition < originalWidth - width) { + return new PdfLine(0, originalWidth, width, alignment, true, CreateArrayOfPdfChunks(oldCurrentChar, currentChar - 1), isRTL); + } + detailChunks[currentChar].AdjustLeft(leftX); + width = originalWidth - tabPosition; + } + } + if (lastValidChunk == null) { + // not even a single char fit; must output the first char + ++currentChar; + if (surrogate) + ++currentChar; + return new PdfLine(0, originalWidth, 0, alignment, false, CreateArrayOfPdfChunks(currentChar - 1, currentChar - 1), isRTL); + } + if (currentChar >= totalTextLength) { + // there was more line than text + return new PdfLine(0, originalWidth, width, alignment, true, CreateArrayOfPdfChunks(oldCurrentChar, totalTextLength - 1), isRTL); + } + int newCurrentChar = TrimRightEx(oldCurrentChar, currentChar - 1); + if (newCurrentChar < oldCurrentChar) { + // only WS + return new PdfLine(0, originalWidth, width, alignment, false, CreateArrayOfPdfChunks(oldCurrentChar, currentChar - 1), isRTL); + } + if (newCurrentChar == currentChar - 1) { // middle of word + IHyphenationEvent he = (IHyphenationEvent)lastValidChunk.GetAttribute(Chunk.HYPHENATION); + if (he != null) { + int[] word = GetWord(oldCurrentChar, newCurrentChar); + if (word != null) { + float testWidth = width + GetWidth(word[0], currentChar - 1); + String pre = he.GetHyphenatedWordPre(new String(text, word[0], word[1] - word[0]), lastValidChunk.Font.Font, lastValidChunk.Font.Size, testWidth); + String post = he.HyphenatedWordPost; + if (pre.Length > 0) { + PdfChunk extra = new PdfChunk(pre, lastValidChunk); + currentChar = word[1] - post.Length; + return new PdfLine(0, originalWidth, testWidth - lastValidChunk.Font.Width(pre), alignment, false, CreateArrayOfPdfChunks(oldCurrentChar, word[0] - 1, extra), isRTL); + } + } + } + } + if (lastSplit == -1 || lastSplit >= newCurrentChar) { + // no split point or split point ahead of end + return new PdfLine(0, originalWidth, width + GetWidth(newCurrentChar + 1, currentChar - 1), alignment, false, CreateArrayOfPdfChunks(oldCurrentChar, newCurrentChar), isRTL); + } + // standard split + currentChar = lastSplit + 1; + newCurrentChar = TrimRightEx(oldCurrentChar, lastSplit); + if (newCurrentChar < oldCurrentChar) { + // only WS again + newCurrentChar = currentChar - 1; + } + return new PdfLine(0, originalWidth, originalWidth - GetWidth(oldCurrentChar, newCurrentChar), alignment, false, CreateArrayOfPdfChunks(oldCurrentChar, newCurrentChar), isRTL); + } + + /** Gets the width of a range of characters. + * @param startIdx the first index to calculate + * @param lastIdx the last inclusive index to calculate + * @return the sum of all widths + */ + public float GetWidth(int startIdx, int lastIdx) { + char c = (char)0; + PdfChunk ck = null; + float width = 0; + for (; startIdx <= lastIdx; ++startIdx) { + bool surrogate = Utilities.IsSurrogatePair(text, startIdx); + if (surrogate) { + width += detailChunks[startIdx].GetCharWidth(Utilities.ConvertToUtf32(text, startIdx)); + ++startIdx; + } + else { + c = text[startIdx]; + ck = detailChunks[startIdx]; + if (PdfChunk.NoPrint(ck.GetUnicodeEquivalent(c))) + continue; + width += detailChunks[startIdx].GetCharWidth(c); + } + } + return width; + } + + public ArrayList CreateArrayOfPdfChunks(int startIdx, int endIdx) { + return CreateArrayOfPdfChunks(startIdx, endIdx, null); + } + + public ArrayList CreateArrayOfPdfChunks(int startIdx, int endIdx, PdfChunk extraPdfChunk) { + bool bidi = (runDirection == PdfWriter.RUN_DIRECTION_LTR || runDirection == PdfWriter.RUN_DIRECTION_RTL); + if (bidi) + Reorder(startIdx, endIdx); + ArrayList ar = new ArrayList(); + PdfChunk refCk = detailChunks[startIdx]; + PdfChunk ck = null; + StringBuilder buf = new StringBuilder(); + char c; + int idx = 0; + for (; startIdx <= endIdx; ++startIdx) { + idx = bidi ? indexChars[startIdx] : startIdx; + c = text[idx]; + ck = detailChunks[idx]; + if (PdfChunk.NoPrint(ck.GetUnicodeEquivalent(c))) + continue; + if (ck.IsImage() || ck.IsSeparator() || ck.IsTab()) { + if (buf.Length > 0) { + ar.Add(new PdfChunk(buf.ToString(), refCk)); + buf = new StringBuilder(); + } + ar.Add(ck); + } + else if (ck == refCk) { + buf.Append(c); + } + else { + if (buf.Length > 0) { + ar.Add(new PdfChunk(buf.ToString(), refCk)); + buf = new StringBuilder(); + } + if (!ck.IsImage() && !ck.IsSeparator() && !ck.IsTab()) + buf.Append(c); + refCk = ck; + } + } + if (buf.Length > 0) { + ar.Add(new PdfChunk(buf.ToString(), refCk)); + } + if (extraPdfChunk != null) + ar.Add(extraPdfChunk); + return ar; + } + + public int[] GetWord(int startIdx, int idx) { + int last = idx; + int first = idx; + // forward + for (; last < totalTextLength; ++last) { + if (!char.IsLetter(text[last])) + break; + } + if (last == idx) + return null; + // backward + for (; first >= startIdx; --first) { + if (!char.IsLetter(text[first])) + break; + } + ++first; + return new int[]{first, last}; + } + + public int TrimRight(int startIdx, int endIdx) { + int idx = endIdx; + char c; + for (; idx >= startIdx; --idx) { + c = (char)detailChunks[idx].GetUnicodeEquivalent(text[idx]); + if (!IsWS(c)) + break; + } + return idx; + } + + public int TrimLeft(int startIdx, int endIdx) { + int idx = startIdx; + char c; + for (; idx <= endIdx; ++idx) { + c = (char)detailChunks[idx].GetUnicodeEquivalent(text[idx]); + if (!IsWS(c)) + break; + } + return idx; + } + + public int TrimRightEx(int startIdx, int endIdx) { + int idx = endIdx; + char c = (char)0; + for (; idx >= startIdx; --idx) { + c = (char)detailChunks[idx].GetUnicodeEquivalent(text[idx]); + if (!IsWS(c) && !PdfChunk.NoPrint(c)) + break; + } + return idx; + } + + public int TrimLeftEx(int startIdx, int endIdx) { + int idx = startIdx; + char c = (char)0; + for (; idx <= endIdx; ++idx) { + c = (char)detailChunks[idx].GetUnicodeEquivalent(text[idx]); + if (!IsWS(c) && !PdfChunk.NoPrint(c)) + break; + } + return idx; + } + + public void Reorder(int start, int end) { + byte maxLevel = orderLevels[start]; + byte minLevel = maxLevel; + byte onlyOddLevels = maxLevel; + byte onlyEvenLevels = maxLevel; + for (int k = start + 1; k <= end; ++k) { + byte b = orderLevels[k]; + if (b > maxLevel) + maxLevel = b; + else if (b < minLevel) + minLevel = b; + onlyOddLevels &= b; + onlyEvenLevels |= b; + } + if ((onlyEvenLevels & 1) == 0) // nothing to do + return; + if ((onlyOddLevels & 1) == 1) { // single inversion + Flip(start, end + 1); + return; + } + minLevel |= 1; + for (; maxLevel >= minLevel; --maxLevel) { + int pstart = start; + for (;;) { + for (;pstart <= end; ++pstart) { + if (orderLevels[pstart] >= maxLevel) + break; + } + if (pstart > end) + break; + int pend = pstart + 1; + for (; pend <= end; ++pend) { + if (orderLevels[pend] < maxLevel) + break; + } + Flip(pstart, pend); + pstart = pend + 1; + } + } + } + + public void Flip(int start, int end) { + int mid = (start + end) / 2; + --end; + for (; start < mid; ++start, --end) { + int temp = indexChars[start]; + indexChars[start] = indexChars[end]; + indexChars[end] = temp; + } + } + + public static bool IsWS(char c) { + return (c <= ' '); + } + + static BidiLine() { + mirrorChars[0x0028] = 0x0029; // LEFT PARENTHESIS + mirrorChars[0x0029] = 0x0028; // RIGHT PARENTHESIS + mirrorChars[0x003C] = 0x003E; // LESS-THAN SIGN + mirrorChars[0x003E] = 0x003C; // GREATER-THAN SIGN + mirrorChars[0x005B] = 0x005D; // LEFT SQUARE BRACKET + mirrorChars[0x005D] = 0x005B; // RIGHT SQUARE BRACKET + mirrorChars[0x007B] = 0x007D; // LEFT CURLY BRACKET + mirrorChars[0x007D] = 0x007B; // RIGHT CURLY BRACKET + mirrorChars[0x00AB] = 0x00BB; // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + mirrorChars[0x00BB] = 0x00AB; // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + mirrorChars[0x2039] = 0x203A; // SINGLE LEFT-POINTING ANGLE QUOTATION MARK + mirrorChars[0x203A] = 0x2039; // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + mirrorChars[0x2045] = 0x2046; // LEFT SQUARE BRACKET WITH QUILL + mirrorChars[0x2046] = 0x2045; // RIGHT SQUARE BRACKET WITH QUILL + mirrorChars[0x207D] = 0x207E; // SUPERSCRIPT LEFT PARENTHESIS + mirrorChars[0x207E] = 0x207D; // SUPERSCRIPT RIGHT PARENTHESIS + mirrorChars[0x208D] = 0x208E; // SUBSCRIPT LEFT PARENTHESIS + mirrorChars[0x208E] = 0x208D; // SUBSCRIPT RIGHT PARENTHESIS + mirrorChars[0x2208] = 0x220B; // ELEMENT OF + mirrorChars[0x2209] = 0x220C; // NOT AN ELEMENT OF + mirrorChars[0x220A] = 0x220D; // SMALL ELEMENT OF + mirrorChars[0x220B] = 0x2208; // CONTAINS AS MEMBER + mirrorChars[0x220C] = 0x2209; // DOES NOT CONTAIN AS MEMBER + mirrorChars[0x220D] = 0x220A; // SMALL CONTAINS AS MEMBER + mirrorChars[0x2215] = 0x29F5; // DIVISION SLASH + mirrorChars[0x223C] = 0x223D; // TILDE OPERATOR + mirrorChars[0x223D] = 0x223C; // REVERSED TILDE + mirrorChars[0x2243] = 0x22CD; // ASYMPTOTICALLY EQUAL TO + mirrorChars[0x2252] = 0x2253; // APPROXIMATELY EQUAL TO OR THE IMAGE OF + mirrorChars[0x2253] = 0x2252; // IMAGE OF OR APPROXIMATELY EQUAL TO + mirrorChars[0x2254] = 0x2255; // COLON EQUALS + mirrorChars[0x2255] = 0x2254; // EQUALS COLON + mirrorChars[0x2264] = 0x2265; // LESS-THAN OR EQUAL TO + mirrorChars[0x2265] = 0x2264; // GREATER-THAN OR EQUAL TO + mirrorChars[0x2266] = 0x2267; // LESS-THAN OVER EQUAL TO + mirrorChars[0x2267] = 0x2266; // GREATER-THAN OVER EQUAL TO + mirrorChars[0x2268] = 0x2269; // [BEST FIT] LESS-THAN BUT NOT EQUAL TO + mirrorChars[0x2269] = 0x2268; // [BEST FIT] GREATER-THAN BUT NOT EQUAL TO + mirrorChars[0x226A] = 0x226B; // MUCH LESS-THAN + mirrorChars[0x226B] = 0x226A; // MUCH GREATER-THAN + mirrorChars[0x226E] = 0x226F; // [BEST FIT] NOT LESS-THAN + mirrorChars[0x226F] = 0x226E; // [BEST FIT] NOT GREATER-THAN + mirrorChars[0x2270] = 0x2271; // [BEST FIT] NEITHER LESS-THAN NOR EQUAL TO + mirrorChars[0x2271] = 0x2270; // [BEST FIT] NEITHER GREATER-THAN NOR EQUAL TO + mirrorChars[0x2272] = 0x2273; // [BEST FIT] LESS-THAN OR EQUIVALENT TO + mirrorChars[0x2273] = 0x2272; // [BEST FIT] GREATER-THAN OR EQUIVALENT TO + mirrorChars[0x2274] = 0x2275; // [BEST FIT] NEITHER LESS-THAN NOR EQUIVALENT TO + mirrorChars[0x2275] = 0x2274; // [BEST FIT] NEITHER GREATER-THAN NOR EQUIVALENT TO + mirrorChars[0x2276] = 0x2277; // LESS-THAN OR GREATER-THAN + mirrorChars[0x2277] = 0x2276; // GREATER-THAN OR LESS-THAN + mirrorChars[0x2278] = 0x2279; // NEITHER LESS-THAN NOR GREATER-THAN + mirrorChars[0x2279] = 0x2278; // NEITHER GREATER-THAN NOR LESS-THAN + mirrorChars[0x227A] = 0x227B; // PRECEDES + mirrorChars[0x227B] = 0x227A; // SUCCEEDS + mirrorChars[0x227C] = 0x227D; // PRECEDES OR EQUAL TO + mirrorChars[0x227D] = 0x227C; // SUCCEEDS OR EQUAL TO + mirrorChars[0x227E] = 0x227F; // [BEST FIT] PRECEDES OR EQUIVALENT TO + mirrorChars[0x227F] = 0x227E; // [BEST FIT] SUCCEEDS OR EQUIVALENT TO + mirrorChars[0x2280] = 0x2281; // [BEST FIT] DOES NOT PRECEDE + mirrorChars[0x2281] = 0x2280; // [BEST FIT] DOES NOT SUCCEED + mirrorChars[0x2282] = 0x2283; // SUBSET OF + mirrorChars[0x2283] = 0x2282; // SUPERSET OF + mirrorChars[0x2284] = 0x2285; // [BEST FIT] NOT A SUBSET OF + mirrorChars[0x2285] = 0x2284; // [BEST FIT] NOT A SUPERSET OF + mirrorChars[0x2286] = 0x2287; // SUBSET OF OR EQUAL TO + mirrorChars[0x2287] = 0x2286; // SUPERSET OF OR EQUAL TO + mirrorChars[0x2288] = 0x2289; // [BEST FIT] NEITHER A SUBSET OF NOR EQUAL TO + mirrorChars[0x2289] = 0x2288; // [BEST FIT] NEITHER A SUPERSET OF NOR EQUAL TO + mirrorChars[0x228A] = 0x228B; // [BEST FIT] SUBSET OF WITH NOT EQUAL TO + mirrorChars[0x228B] = 0x228A; // [BEST FIT] SUPERSET OF WITH NOT EQUAL TO + mirrorChars[0x228F] = 0x2290; // SQUARE IMAGE OF + mirrorChars[0x2290] = 0x228F; // SQUARE ORIGINAL OF + mirrorChars[0x2291] = 0x2292; // SQUARE IMAGE OF OR EQUAL TO + mirrorChars[0x2292] = 0x2291; // SQUARE ORIGINAL OF OR EQUAL TO + mirrorChars[0x2298] = 0x29B8; // CIRCLED DIVISION SLASH + mirrorChars[0x22A2] = 0x22A3; // RIGHT TACK + mirrorChars[0x22A3] = 0x22A2; // LEFT TACK + mirrorChars[0x22A6] = 0x2ADE; // ASSERTION + mirrorChars[0x22A8] = 0x2AE4; // TRUE + mirrorChars[0x22A9] = 0x2AE3; // FORCES + mirrorChars[0x22AB] = 0x2AE5; // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE + mirrorChars[0x22B0] = 0x22B1; // PRECEDES UNDER RELATION + mirrorChars[0x22B1] = 0x22B0; // SUCCEEDS UNDER RELATION + mirrorChars[0x22B2] = 0x22B3; // NORMAL SUBGROUP OF + mirrorChars[0x22B3] = 0x22B2; // CONTAINS AS NORMAL SUBGROUP + mirrorChars[0x22B4] = 0x22B5; // NORMAL SUBGROUP OF OR EQUAL TO + mirrorChars[0x22B5] = 0x22B4; // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO + mirrorChars[0x22B6] = 0x22B7; // ORIGINAL OF + mirrorChars[0x22B7] = 0x22B6; // IMAGE OF + mirrorChars[0x22C9] = 0x22CA; // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT + mirrorChars[0x22CA] = 0x22C9; // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT + mirrorChars[0x22CB] = 0x22CC; // LEFT SEMIDIRECT PRODUCT + mirrorChars[0x22CC] = 0x22CB; // RIGHT SEMIDIRECT PRODUCT + mirrorChars[0x22CD] = 0x2243; // REVERSED TILDE EQUALS + mirrorChars[0x22D0] = 0x22D1; // DOUBLE SUBSET + mirrorChars[0x22D1] = 0x22D0; // DOUBLE SUPERSET + mirrorChars[0x22D6] = 0x22D7; // LESS-THAN WITH DOT + mirrorChars[0x22D7] = 0x22D6; // GREATER-THAN WITH DOT + mirrorChars[0x22D8] = 0x22D9; // VERY MUCH LESS-THAN + mirrorChars[0x22D9] = 0x22D8; // VERY MUCH GREATER-THAN + mirrorChars[0x22DA] = 0x22DB; // LESS-THAN EQUAL TO OR GREATER-THAN + mirrorChars[0x22DB] = 0x22DA; // GREATER-THAN EQUAL TO OR LESS-THAN + mirrorChars[0x22DC] = 0x22DD; // EQUAL TO OR LESS-THAN + mirrorChars[0x22DD] = 0x22DC; // EQUAL TO OR GREATER-THAN + mirrorChars[0x22DE] = 0x22DF; // EQUAL TO OR PRECEDES + mirrorChars[0x22DF] = 0x22DE; // EQUAL TO OR SUCCEEDS + mirrorChars[0x22E0] = 0x22E1; // [BEST FIT] DOES NOT PRECEDE OR EQUAL + mirrorChars[0x22E1] = 0x22E0; // [BEST FIT] DOES NOT SUCCEED OR EQUAL + mirrorChars[0x22E2] = 0x22E3; // [BEST FIT] NOT SQUARE IMAGE OF OR EQUAL TO + mirrorChars[0x22E3] = 0x22E2; // [BEST FIT] NOT SQUARE ORIGINAL OF OR EQUAL TO + mirrorChars[0x22E4] = 0x22E5; // [BEST FIT] SQUARE IMAGE OF OR NOT EQUAL TO + mirrorChars[0x22E5] = 0x22E4; // [BEST FIT] SQUARE ORIGINAL OF OR NOT EQUAL TO + mirrorChars[0x22E6] = 0x22E7; // [BEST FIT] LESS-THAN BUT NOT EQUIVALENT TO + mirrorChars[0x22E7] = 0x22E6; // [BEST FIT] GREATER-THAN BUT NOT EQUIVALENT TO + mirrorChars[0x22E8] = 0x22E9; // [BEST FIT] PRECEDES BUT NOT EQUIVALENT TO + mirrorChars[0x22E9] = 0x22E8; // [BEST FIT] SUCCEEDS BUT NOT EQUIVALENT TO + mirrorChars[0x22EA] = 0x22EB; // [BEST FIT] NOT NORMAL SUBGROUP OF + mirrorChars[0x22EB] = 0x22EA; // [BEST FIT] DOES NOT CONTAIN AS NORMAL SUBGROUP + mirrorChars[0x22EC] = 0x22ED; // [BEST FIT] NOT NORMAL SUBGROUP OF OR EQUAL TO + mirrorChars[0x22ED] = 0x22EC; // [BEST FIT] DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL + mirrorChars[0x22F0] = 0x22F1; // UP RIGHT DIAGONAL ELLIPSIS + mirrorChars[0x22F1] = 0x22F0; // DOWN RIGHT DIAGONAL ELLIPSIS + mirrorChars[0x22F2] = 0x22FA; // ELEMENT OF WITH LONG HORIZONTAL STROKE + mirrorChars[0x22F3] = 0x22FB; // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + mirrorChars[0x22F4] = 0x22FC; // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + mirrorChars[0x22F6] = 0x22FD; // ELEMENT OF WITH OVERBAR + mirrorChars[0x22F7] = 0x22FE; // SMALL ELEMENT OF WITH OVERBAR + mirrorChars[0x22FA] = 0x22F2; // CONTAINS WITH LONG HORIZONTAL STROKE + mirrorChars[0x22FB] = 0x22F3; // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + mirrorChars[0x22FC] = 0x22F4; // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + mirrorChars[0x22FD] = 0x22F6; // CONTAINS WITH OVERBAR + mirrorChars[0x22FE] = 0x22F7; // SMALL CONTAINS WITH OVERBAR + mirrorChars[0x2308] = 0x2309; // LEFT CEILING + mirrorChars[0x2309] = 0x2308; // RIGHT CEILING + mirrorChars[0x230A] = 0x230B; // LEFT FLOOR + mirrorChars[0x230B] = 0x230A; // RIGHT FLOOR + mirrorChars[0x2329] = 0x232A; // LEFT-POINTING ANGLE BRACKET + mirrorChars[0x232A] = 0x2329; // RIGHT-POINTING ANGLE BRACKET + mirrorChars[0x2768] = 0x2769; // MEDIUM LEFT PARENTHESIS ORNAMENT + mirrorChars[0x2769] = 0x2768; // MEDIUM RIGHT PARENTHESIS ORNAMENT + mirrorChars[0x276A] = 0x276B; // MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT + mirrorChars[0x276B] = 0x276A; // MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT + mirrorChars[0x276C] = 0x276D; // MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT + mirrorChars[0x276D] = 0x276C; // MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT + mirrorChars[0x276E] = 0x276F; // HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT + mirrorChars[0x276F] = 0x276E; // HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT + mirrorChars[0x2770] = 0x2771; // HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT + mirrorChars[0x2771] = 0x2770; // HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT + mirrorChars[0x2772] = 0x2773; // LIGHT LEFT TORTOISE SHELL BRACKET + mirrorChars[0x2773] = 0x2772; // LIGHT RIGHT TORTOISE SHELL BRACKET + mirrorChars[0x2774] = 0x2775; // MEDIUM LEFT CURLY BRACKET ORNAMENT + mirrorChars[0x2775] = 0x2774; // MEDIUM RIGHT CURLY BRACKET ORNAMENT + mirrorChars[0x27D5] = 0x27D6; // LEFT OUTER JOIN + mirrorChars[0x27D6] = 0x27D5; // RIGHT OUTER JOIN + mirrorChars[0x27DD] = 0x27DE; // LONG RIGHT TACK + mirrorChars[0x27DE] = 0x27DD; // LONG LEFT TACK + mirrorChars[0x27E2] = 0x27E3; // WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK + mirrorChars[0x27E3] = 0x27E2; // WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK + mirrorChars[0x27E4] = 0x27E5; // WHITE SQUARE WITH LEFTWARDS TICK + mirrorChars[0x27E5] = 0x27E4; // WHITE SQUARE WITH RIGHTWARDS TICK + mirrorChars[0x27E6] = 0x27E7; // MATHEMATICAL LEFT WHITE SQUARE BRACKET + mirrorChars[0x27E7] = 0x27E6; // MATHEMATICAL RIGHT WHITE SQUARE BRACKET + mirrorChars[0x27E8] = 0x27E9; // MATHEMATICAL LEFT ANGLE BRACKET + mirrorChars[0x27E9] = 0x27E8; // MATHEMATICAL RIGHT ANGLE BRACKET + mirrorChars[0x27EA] = 0x27EB; // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET + mirrorChars[0x27EB] = 0x27EA; // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET + mirrorChars[0x2983] = 0x2984; // LEFT WHITE CURLY BRACKET + mirrorChars[0x2984] = 0x2983; // RIGHT WHITE CURLY BRACKET + mirrorChars[0x2985] = 0x2986; // LEFT WHITE PARENTHESIS + mirrorChars[0x2986] = 0x2985; // RIGHT WHITE PARENTHESIS + mirrorChars[0x2987] = 0x2988; // Z NOTATION LEFT IMAGE BRACKET + mirrorChars[0x2988] = 0x2987; // Z NOTATION RIGHT IMAGE BRACKET + mirrorChars[0x2989] = 0x298A; // Z NOTATION LEFT BINDING BRACKET + mirrorChars[0x298A] = 0x2989; // Z NOTATION RIGHT BINDING BRACKET + mirrorChars[0x298B] = 0x298C; // LEFT SQUARE BRACKET WITH UNDERBAR + mirrorChars[0x298C] = 0x298B; // RIGHT SQUARE BRACKET WITH UNDERBAR + mirrorChars[0x298D] = 0x2990; // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER + mirrorChars[0x298E] = 0x298F; // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER + mirrorChars[0x298F] = 0x298E; // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER + mirrorChars[0x2990] = 0x298D; // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER + mirrorChars[0x2991] = 0x2992; // LEFT ANGLE BRACKET WITH DOT + mirrorChars[0x2992] = 0x2991; // RIGHT ANGLE BRACKET WITH DOT + mirrorChars[0x2993] = 0x2994; // LEFT ARC LESS-THAN BRACKET + mirrorChars[0x2994] = 0x2993; // RIGHT ARC GREATER-THAN BRACKET + mirrorChars[0x2995] = 0x2996; // DOUBLE LEFT ARC GREATER-THAN BRACKET + mirrorChars[0x2996] = 0x2995; // DOUBLE RIGHT ARC LESS-THAN BRACKET + mirrorChars[0x2997] = 0x2998; // LEFT BLACK TORTOISE SHELL BRACKET + mirrorChars[0x2998] = 0x2997; // RIGHT BLACK TORTOISE SHELL BRACKET + mirrorChars[0x29B8] = 0x2298; // CIRCLED REVERSE SOLIDUS + mirrorChars[0x29C0] = 0x29C1; // CIRCLED LESS-THAN + mirrorChars[0x29C1] = 0x29C0; // CIRCLED GREATER-THAN + mirrorChars[0x29C4] = 0x29C5; // SQUARED RISING DIAGONAL SLASH + mirrorChars[0x29C5] = 0x29C4; // SQUARED FALLING DIAGONAL SLASH + mirrorChars[0x29CF] = 0x29D0; // LEFT TRIANGLE BESIDE VERTICAL BAR + mirrorChars[0x29D0] = 0x29CF; // VERTICAL BAR BESIDE RIGHT TRIANGLE + mirrorChars[0x29D1] = 0x29D2; // BOWTIE WITH LEFT HALF BLACK + mirrorChars[0x29D2] = 0x29D1; // BOWTIE WITH RIGHT HALF BLACK + mirrorChars[0x29D4] = 0x29D5; // TIMES WITH LEFT HALF BLACK + mirrorChars[0x29D5] = 0x29D4; // TIMES WITH RIGHT HALF BLACK + mirrorChars[0x29D8] = 0x29D9; // LEFT WIGGLY FENCE + mirrorChars[0x29D9] = 0x29D8; // RIGHT WIGGLY FENCE + mirrorChars[0x29DA] = 0x29DB; // LEFT DOUBLE WIGGLY FENCE + mirrorChars[0x29DB] = 0x29DA; // RIGHT DOUBLE WIGGLY FENCE + mirrorChars[0x29F5] = 0x2215; // REVERSE SOLIDUS OPERATOR + mirrorChars[0x29F8] = 0x29F9; // BIG SOLIDUS + mirrorChars[0x29F9] = 0x29F8; // BIG REVERSE SOLIDUS + mirrorChars[0x29FC] = 0x29FD; // LEFT-POINTING CURVED ANGLE BRACKET + mirrorChars[0x29FD] = 0x29FC; // RIGHT-POINTING CURVED ANGLE BRACKET + mirrorChars[0x2A2B] = 0x2A2C; // MINUS SIGN WITH FALLING DOTS + mirrorChars[0x2A2C] = 0x2A2B; // MINUS SIGN WITH RISING DOTS + mirrorChars[0x2A2D] = 0x2A2C; // PLUS SIGN IN LEFT HALF CIRCLE + mirrorChars[0x2A2E] = 0x2A2D; // PLUS SIGN IN RIGHT HALF CIRCLE + mirrorChars[0x2A34] = 0x2A35; // MULTIPLICATION SIGN IN LEFT HALF CIRCLE + mirrorChars[0x2A35] = 0x2A34; // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE + mirrorChars[0x2A3C] = 0x2A3D; // INTERIOR PRODUCT + mirrorChars[0x2A3D] = 0x2A3C; // RIGHTHAND INTERIOR PRODUCT + mirrorChars[0x2A64] = 0x2A65; // Z NOTATION DOMAIN ANTIRESTRICTION + mirrorChars[0x2A65] = 0x2A64; // Z NOTATION RANGE ANTIRESTRICTION + mirrorChars[0x2A79] = 0x2A7A; // LESS-THAN WITH CIRCLE INSIDE + mirrorChars[0x2A7A] = 0x2A79; // GREATER-THAN WITH CIRCLE INSIDE + mirrorChars[0x2A7D] = 0x2A7E; // LESS-THAN OR SLANTED EQUAL TO + mirrorChars[0x2A7E] = 0x2A7D; // GREATER-THAN OR SLANTED EQUAL TO + mirrorChars[0x2A7F] = 0x2A80; // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE + mirrorChars[0x2A80] = 0x2A7F; // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE + mirrorChars[0x2A81] = 0x2A82; // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE + mirrorChars[0x2A82] = 0x2A81; // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE + mirrorChars[0x2A83] = 0x2A84; // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT + mirrorChars[0x2A84] = 0x2A83; // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT + mirrorChars[0x2A8B] = 0x2A8C; // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN + mirrorChars[0x2A8C] = 0x2A8B; // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN + mirrorChars[0x2A91] = 0x2A92; // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL + mirrorChars[0x2A92] = 0x2A91; // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL + mirrorChars[0x2A93] = 0x2A94; // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL + mirrorChars[0x2A94] = 0x2A93; // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL + mirrorChars[0x2A95] = 0x2A96; // SLANTED EQUAL TO OR LESS-THAN + mirrorChars[0x2A96] = 0x2A95; // SLANTED EQUAL TO OR GREATER-THAN + mirrorChars[0x2A97] = 0x2A98; // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE + mirrorChars[0x2A98] = 0x2A97; // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE + mirrorChars[0x2A99] = 0x2A9A; // DOUBLE-LINE EQUAL TO OR LESS-THAN + mirrorChars[0x2A9A] = 0x2A99; // DOUBLE-LINE EQUAL TO OR GREATER-THAN + mirrorChars[0x2A9B] = 0x2A9C; // DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN + mirrorChars[0x2A9C] = 0x2A9B; // DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN + mirrorChars[0x2AA1] = 0x2AA2; // DOUBLE NESTED LESS-THAN + mirrorChars[0x2AA2] = 0x2AA1; // DOUBLE NESTED GREATER-THAN + mirrorChars[0x2AA6] = 0x2AA7; // LESS-THAN CLOSED BY CURVE + mirrorChars[0x2AA7] = 0x2AA6; // GREATER-THAN CLOSED BY CURVE + mirrorChars[0x2AA8] = 0x2AA9; // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL + mirrorChars[0x2AA9] = 0x2AA8; // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL + mirrorChars[0x2AAA] = 0x2AAB; // SMALLER THAN + mirrorChars[0x2AAB] = 0x2AAA; // LARGER THAN + mirrorChars[0x2AAC] = 0x2AAD; // SMALLER THAN OR EQUAL TO + mirrorChars[0x2AAD] = 0x2AAC; // LARGER THAN OR EQUAL TO + mirrorChars[0x2AAF] = 0x2AB0; // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN + mirrorChars[0x2AB0] = 0x2AAF; // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN + mirrorChars[0x2AB3] = 0x2AB4; // PRECEDES ABOVE EQUALS SIGN + mirrorChars[0x2AB4] = 0x2AB3; // SUCCEEDS ABOVE EQUALS SIGN + mirrorChars[0x2ABB] = 0x2ABC; // DOUBLE PRECEDES + mirrorChars[0x2ABC] = 0x2ABB; // DOUBLE SUCCEEDS + mirrorChars[0x2ABD] = 0x2ABE; // SUBSET WITH DOT + mirrorChars[0x2ABE] = 0x2ABD; // SUPERSET WITH DOT + mirrorChars[0x2ABF] = 0x2AC0; // SUBSET WITH PLUS SIGN BELOW + mirrorChars[0x2AC0] = 0x2ABF; // SUPERSET WITH PLUS SIGN BELOW + mirrorChars[0x2AC1] = 0x2AC2; // SUBSET WITH MULTIPLICATION SIGN BELOW + mirrorChars[0x2AC2] = 0x2AC1; // SUPERSET WITH MULTIPLICATION SIGN BELOW + mirrorChars[0x2AC3] = 0x2AC4; // SUBSET OF OR EQUAL TO WITH DOT ABOVE + mirrorChars[0x2AC4] = 0x2AC3; // SUPERSET OF OR EQUAL TO WITH DOT ABOVE + mirrorChars[0x2AC5] = 0x2AC6; // SUBSET OF ABOVE EQUALS SIGN + mirrorChars[0x2AC6] = 0x2AC5; // SUPERSET OF ABOVE EQUALS SIGN + mirrorChars[0x2ACD] = 0x2ACE; // SQUARE LEFT OPEN BOX OPERATOR + mirrorChars[0x2ACE] = 0x2ACD; // SQUARE RIGHT OPEN BOX OPERATOR + mirrorChars[0x2ACF] = 0x2AD0; // CLOSED SUBSET + mirrorChars[0x2AD0] = 0x2ACF; // CLOSED SUPERSET + mirrorChars[0x2AD1] = 0x2AD2; // CLOSED SUBSET OR EQUAL TO + mirrorChars[0x2AD2] = 0x2AD1; // CLOSED SUPERSET OR EQUAL TO + mirrorChars[0x2AD3] = 0x2AD4; // SUBSET ABOVE SUPERSET + mirrorChars[0x2AD4] = 0x2AD3; // SUPERSET ABOVE SUBSET + mirrorChars[0x2AD5] = 0x2AD6; // SUBSET ABOVE SUBSET + mirrorChars[0x2AD6] = 0x2AD5; // SUPERSET ABOVE SUPERSET + mirrorChars[0x2ADE] = 0x22A6; // SHORT LEFT TACK + mirrorChars[0x2AE3] = 0x22A9; // DOUBLE VERTICAL BAR LEFT TURNSTILE + mirrorChars[0x2AE4] = 0x22A8; // VERTICAL BAR DOUBLE LEFT TURNSTILE + mirrorChars[0x2AE5] = 0x22AB; // DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE + mirrorChars[0x2AEC] = 0x2AED; // DOUBLE STROKE NOT SIGN + mirrorChars[0x2AED] = 0x2AEC; // REVERSED DOUBLE STROKE NOT SIGN + mirrorChars[0x2AF7] = 0x2AF8; // TRIPLE NESTED LESS-THAN + mirrorChars[0x2AF8] = 0x2AF7; // TRIPLE NESTED GREATER-THAN + mirrorChars[0x2AF9] = 0x2AFA; // DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO + mirrorChars[0x2AFA] = 0x2AF9; // DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO + mirrorChars[0x3008] = 0x3009; // LEFT ANGLE BRACKET + mirrorChars[0x3009] = 0x3008; // RIGHT ANGLE BRACKET + mirrorChars[0x300A] = 0x300B; // LEFT DOUBLE ANGLE BRACKET + mirrorChars[0x300B] = 0x300A; // RIGHT DOUBLE ANGLE BRACKET + mirrorChars[0x300C] = 0x300D; // [BEST FIT] LEFT CORNER BRACKET + mirrorChars[0x300D] = 0x300C; // [BEST FIT] RIGHT CORNER BRACKET + mirrorChars[0x300E] = 0x300F; // [BEST FIT] LEFT WHITE CORNER BRACKET + mirrorChars[0x300F] = 0x300E; // [BEST FIT] RIGHT WHITE CORNER BRACKET + mirrorChars[0x3010] = 0x3011; // LEFT BLACK LENTICULAR BRACKET + mirrorChars[0x3011] = 0x3010; // RIGHT BLACK LENTICULAR BRACKET + mirrorChars[0x3014] = 0x3015; // LEFT TORTOISE SHELL BRACKET + mirrorChars[0x3015] = 0x3014; // RIGHT TORTOISE SHELL BRACKET + mirrorChars[0x3016] = 0x3017; // LEFT WHITE LENTICULAR BRACKET + mirrorChars[0x3017] = 0x3016; // RIGHT WHITE LENTICULAR BRACKET + mirrorChars[0x3018] = 0x3019; // LEFT WHITE TORTOISE SHELL BRACKET + mirrorChars[0x3019] = 0x3018; // RIGHT WHITE TORTOISE SHELL BRACKET + mirrorChars[0x301A] = 0x301B; // LEFT WHITE SQUARE BRACKET + mirrorChars[0x301B] = 0x301A; // RIGHT WHITE SQUARE BRACKET + mirrorChars[0xFF08] = 0xFF09; // FULLWIDTH LEFT PARENTHESIS + mirrorChars[0xFF09] = 0xFF08; // FULLWIDTH RIGHT PARENTHESIS + mirrorChars[0xFF1C] = 0xFF1E; // FULLWIDTH LESS-THAN SIGN + mirrorChars[0xFF1E] = 0xFF1C; // FULLWIDTH GREATER-THAN SIGN + mirrorChars[0xFF3B] = 0xFF3D; // FULLWIDTH LEFT SQUARE BRACKET + mirrorChars[0xFF3D] = 0xFF3B; // FULLWIDTH RIGHT SQUARE BRACKET + mirrorChars[0xFF5B] = 0xFF5D; // FULLWIDTH LEFT CURLY BRACKET + mirrorChars[0xFF5D] = 0xFF5B; // FULLWIDTH RIGHT CURLY BRACKET + mirrorChars[0xFF5F] = 0xFF60; // FULLWIDTH LEFT WHITE PARENTHESIS + mirrorChars[0xFF60] = 0xFF5F; // FULLWIDTH RIGHT WHITE PARENTHESIS + mirrorChars[0xFF62] = 0xFF63; // [BEST FIT] HALFWIDTH LEFT CORNER BRACKET + mirrorChars[0xFF63] = 0xFF62; // [BEST FIT] HALFWIDTH RIGHT CORNER BRACKET + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/BidiOrder.cs b/iTechSharp/iTextSharp/text/pdf/BidiOrder.cs new file mode 100644 index 0000000..08f4be6 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/BidiOrder.cs @@ -0,0 +1,1296 @@ +using System; +/* + * Copyright 2003 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +/* + * (C) Copyright IBM Corp. 1999, All Rights Reserved + * + * version 1.1 + */ + +/* + * As stated in the Javadoc comments below, materials from Unicode.org + * are used in this class. The following license applies to these materials: + * http://www.unicode.org/copyright.html#Exhibit1 + * + * EXHIBIT 1 + * UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE + * + * Unicode Data Files include all data files under the directories + * http://www.unicode.org/Public/, http://www.unicode.org/reports/, + * and http://www.unicode.org/cldr/data/ . + * Unicode Software includes any source code published in the Unicode Standard + * or under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, + * and http://www.unicode.org/cldr/data/. + * + * NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, + * INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES ("DATA FILES"), + * AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, + * ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT + * DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + * + * COPYRIGHT AND PERMISSION NOTICE + * Copyright © 1991-2007 Unicode, Inc. All rights reserved. Distributed under + * the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of the Unicode data files and any associated documentation (the "Data Files") + * or Unicode software and any associated documentation (the "Software") to deal + * in the Data Files or Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, and/or sell copies + * of the Data Files or Software, and to permit persons to whom the Data Files + * or Software are furnished to do so, provided that (a) the above copyright + * notice(s) and this permission notice appear with all copies of the Data Files + * or Software, (b) both the above copyright notice(s) and this permission notice + * appear in associated documentation, and (c) there is clear notice in each + * modified Data File or in the Software as well as in the documentation associated + * with the Data File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE + * LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not + * be used in advertising or otherwise to promote the sale, use or other dealings + * in these Data Files or Software without prior written authorization of the + * copyright holder. + */ + +/** + * Reference implementation of the Unicode 3.0 Bidi algorithm. + * + *

    + * This implementation is not optimized for performance. It is intended + * as a reference implementation that closely follows the specification + * of the Bidirectional Algorithm in The Unicode Standard version 3.0. + *

    + * Input:
    + * There are two levels of input to the algorithm, since clients may prefer + * to supply some information from out-of-band sources rather than relying on + * the default behavior. + *

      + *
    1. unicode type array + *
    2. unicode type array, with externally supplied base line direction + *
    + *

    Output:
    + * Output is separated into several stages as well, to better enable clients + * to evaluate various aspects of implementation conformance. + *

      + *
    1. levels array over entire paragraph + *
    2. reordering array over entire paragraph + *
    3. levels array over line + *
    4. reordering array over line + *
    + * Note that for conformance, algorithms are only required to generate correct + * reordering and character directionality (odd or even levels) over a line. + * Generating identical level arrays over a line is not required. Bidi + * explicit format codes (LRE, RLE, LRO, RLO, PDF) and BN can be assigned + * arbitrary levels and positions as long as the other text matches. + *

    + * As the algorithm is defined to operate on a single paragraph at a time, + * this implementation is written to handle single paragraphs. Thus + * rule P1 is presumed by this implementation-- the data provided to the + * implementation is assumed to be a single paragraph, and either contains no + * 'B' codes, or a single 'B' code at the end of the input. 'B' is allowed + * as input to illustrate how the algorithm assigns it a level. + *

    + * Also note that rules L3 and L4 depend on the rendering engine that uses + * the result of the bidi algorithm. This implementation assumes that the + * rendering engine expects combining marks in visual order (e.g. to the + * left of their base character in RTL runs) and that it adjust the glyphs + * used to render mirrored characters that are in RTL runs so that they + * render appropriately. + * + * @author Doug Felt + */ + +namespace iTextSharp.text.pdf { + public sealed class BidiOrder { + private sbyte[] initialTypes; + private sbyte[] embeddings; // generated from processing format codes + private sbyte paragraphEmbeddingLevel = -1; // undefined + + private int textLength; // for convenience + private sbyte[] resultTypes; // for paragraph, not lines + private sbyte[] resultLevels; // for paragraph, not lines + + // The bidi types + + /** Left-to-right*/ + public const sbyte L = 0; + + /** Left-to-Right Embedding */ + public const sbyte LRE = 1; + + /** Left-to-Right Override */ + public const sbyte LRO = 2; + + /** Right-to-Left */ + public const sbyte R = 3; + + /** Right-to-Left Arabic */ + public const sbyte AL = 4; + + /** Right-to-Left Embedding */ + public const sbyte RLE = 5; + + /** Right-to-Left Override */ + public const sbyte RLO = 6; + + /** Pop Directional Format */ + public const sbyte PDF = 7; + + /** European Number */ + public const sbyte EN = 8; + + /** European Number Separator */ + public const sbyte ES = 9; + + /** European Number Terminator */ + public const sbyte ET = 10; + + /** Arabic Number */ + public const sbyte AN = 11; + + /** Common Number Separator */ + public const sbyte CS = 12; + + /** Non-Spacing Mark */ + public const sbyte NSM = 13; + + /** Boundary Neutral */ + public const sbyte BN = 14; + + /** Paragraph Separator */ + public const sbyte B = 15; + + /** Segment Separator */ + public const sbyte S = 16; + + /** Whitespace */ + public const sbyte WS = 17; + + /** Other Neutrals */ + public const sbyte ON = 18; + + /** Minimum bidi type value. */ + public const sbyte TYPE_MIN = 0; + + /** Maximum bidi type value. */ + public const sbyte TYPE_MAX = 18; + + // + // Input + // + + /** + * Initialize using an array of direction types. Types range from TYPE_MIN to TYPE_MAX inclusive + * and represent the direction codes of the characters in the text. + * + * @param types the types array + */ + public BidiOrder(sbyte[] types) { + ValidateTypes(types); + + this.initialTypes = (sbyte[])types.Clone(); // client type array remains unchanged + + RunAlgorithm(); + } + + /** + * Initialize using an array of direction types and an externally supplied paragraph embedding level. + * The embedding level may be -1, 0, or 1. -1 means to apply the default algorithm (rules P2 and P3), + * 0 is for LTR paragraphs, and 1 is for RTL paragraphs. + * + * @param types the types array + * @param paragraphEmbeddingLevel the externally supplied paragraph embedding level. + */ + public BidiOrder(sbyte[] types, sbyte paragraphEmbeddingLevel) { + ValidateTypes(types); + ValidateParagraphEmbeddingLevel(paragraphEmbeddingLevel); + + this.initialTypes = (sbyte[])types.Clone(); // client type array remains unchanged + this.paragraphEmbeddingLevel = paragraphEmbeddingLevel; + + RunAlgorithm(); + } + + public BidiOrder(char[] text, int offset, int length, sbyte paragraphEmbeddingLevel) { + initialTypes = new sbyte[length]; + for (int k = 0; k < length; ++k) { + initialTypes[k] = rtypes[text[offset + k]]; + } + ValidateParagraphEmbeddingLevel(paragraphEmbeddingLevel); + + this.paragraphEmbeddingLevel = paragraphEmbeddingLevel; + + RunAlgorithm(); + } + + public static sbyte GetDirection(char c) { + return rtypes[c]; + } + + /** + * The algorithm. + * Does not include line-based processing (Rules L1, L2). + * These are applied later in the line-based phase of the algorithm. + */ + private void RunAlgorithm() { + textLength = initialTypes.Length; + + // Initialize output types. + // Result types initialized to input types. + resultTypes = (sbyte[])initialTypes.Clone(); + + + // 1) determining the paragraph level + // Rule P1 is the requirement for entering this algorithm. + // Rules P2, P3. + // If no externally supplied paragraph embedding level, use default. + if (paragraphEmbeddingLevel == -1) { + DetermineParagraphEmbeddingLevel(); + } + + // Initialize result levels to paragraph embedding level. + resultLevels = new sbyte[textLength]; + SetLevels(0, textLength, paragraphEmbeddingLevel); + + // 2) Explicit levels and directions + // Rules X1-X8. + DetermineExplicitEmbeddingLevels(); + + // Rule X9. + textLength = RemoveExplicitCodes(); + + // Rule X10. + // Run remainder of algorithm one level run at a time + sbyte prevLevel = paragraphEmbeddingLevel; + int start = 0; + while (start < textLength) { + sbyte level = resultLevels[start]; + sbyte prevType = TypeForLevel(Math.Max(prevLevel, level)); + + int limit = start + 1; + while (limit < textLength && resultLevels[limit] == level) { + ++limit; + } + + sbyte succLevel = limit < textLength ? resultLevels[limit] : paragraphEmbeddingLevel; + sbyte succType = TypeForLevel(Math.Max(succLevel, level)); + + // 3) resolving weak types + // Rules W1-W7. + ResolveWeakTypes(start, limit, level, prevType, succType); + + // 4) resolving neutral types + // Rules N1-N3. + ResolveNeutralTypes(start, limit, level, prevType, succType); + + // 5) resolving implicit embedding levels + // Rules I1, I2. + ResolveImplicitLevels(start, limit, level, prevType, succType); + + prevLevel = level; + start = limit; + } + + // Reinsert explicit codes and assign appropriate levels to 'hide' them. + // This is for convenience, so the resulting level array maps 1-1 + // with the initial array. + // See the implementation suggestions section of TR#9 for guidelines on + // how to implement the algorithm without removing and reinserting the codes. + textLength = ReinsertExplicitCodes(textLength); + } + + /** + * 1) determining the paragraph level. + *

    + * Rules P2, P3. + *

    + * At the end of this function, the member variable paragraphEmbeddingLevel is set to either 0 or 1. + */ + private void DetermineParagraphEmbeddingLevel() { + sbyte strongType = -1; // unknown + + // Rule P2. + for (int i = 0; i < textLength; ++i) { + sbyte t = resultTypes[i]; + if (t == L || t == AL || t == R) { + strongType = t; + break; + } + } + + // Rule P3. + if (strongType == -1) { // none found + // default embedding level when no strong types found is 0. + paragraphEmbeddingLevel = 0; + } else if (strongType == L) { + paragraphEmbeddingLevel = 0; + } else { // AL, R + paragraphEmbeddingLevel = 1; + } + } + + /** + * Process embedding format codes. + *

    + * Calls processEmbeddings to generate an embedding array from the explicit format codes. The + * embedding overrides in the array are then applied to the result types, and the result levels are + * initialized. + * @see #processEmbeddings + */ + private void DetermineExplicitEmbeddingLevels() { + embeddings = ProcessEmbeddings(resultTypes, paragraphEmbeddingLevel); + + for (int i = 0; i < textLength; ++i) { + sbyte level = embeddings[i]; + if ((level & 0x80) != 0) { + level &= 0x7f; + resultTypes[i] = TypeForLevel(level); + } + resultLevels[i] = level; + } + } + + /** + * Rules X9. + * Remove explicit codes so that they may be ignored during the remainder + * of the main portion of the algorithm. The length of the resulting text + * is returned. + * @return the length of the data excluding explicit codes and BN. + */ + private int RemoveExplicitCodes() { + int w = 0; + for (int i = 0; i < textLength; ++i) { + sbyte t = initialTypes[i]; + if (!(t == LRE || t == RLE || t == LRO || t == RLO || t == PDF || t == BN)) { + embeddings[w] = embeddings[i]; + resultTypes[w] = resultTypes[i]; + resultLevels[w] = resultLevels[i]; + w++; + } + } + return w; // new textLength while explicit levels are removed + } + + /** + * Reinsert levels information for explicit codes. + * This is for ease of relating the level information + * to the original input data. Note that the levels + * assigned to these codes are arbitrary, they're + * chosen so as to avoid breaking level runs. + * @param textLength the length of the data after compression + * @return the length of the data (original length of + * types array supplied to constructor) + */ + private int ReinsertExplicitCodes(int textLength) { + for (int i = initialTypes.Length; --i >= 0;) { + sbyte t = initialTypes[i]; + if (t == LRE || t == RLE || t == LRO || t == RLO || t == PDF || t == BN) { + embeddings[i] = 0; + resultTypes[i] = t; + resultLevels[i] = -1; + } else { + --textLength; + embeddings[i] = embeddings[textLength]; + resultTypes[i] = resultTypes[textLength]; + resultLevels[i] = resultLevels[textLength]; + } + } + + // now propagate forward the levels information (could have + // propagated backward, the main thing is not to introduce a level + // break where one doesn't already exist). + + if (resultLevels[0] == -1) { + resultLevels[0] = paragraphEmbeddingLevel; + } + for (int i = 1; i < initialTypes.Length; ++i) { + if (resultLevels[i] == -1) { + resultLevels[i] = resultLevels[i-1]; + } + } + + // Embedding information is for informational purposes only + // so need not be adjusted. + + return initialTypes.Length; + } + + /** + * 2) determining explicit levels + * Rules X1 - X8 + * + * The interaction of these rules makes handling them a bit complex. + * This examines resultTypes but does not modify it. It returns embedding and + * override information in the result array. The low 7 bits are the level, the high + * bit is set if the level is an override, and clear if it is an embedding. + */ + private static sbyte[] ProcessEmbeddings(sbyte[] resultTypes, sbyte paragraphEmbeddingLevel) { + int EXPLICIT_LEVEL_LIMIT = 62; + + int textLength = resultTypes.Length; + sbyte[] embeddings = new sbyte[textLength]; + + // This stack will store the embedding levels and override status in a single sbyte + // as described above. + sbyte[] embeddingValueStack = new sbyte[EXPLICIT_LEVEL_LIMIT]; + int stackCounter = 0; + + // An LRE or LRO at level 60 is invalid, since the new level 62 is invalid. But + // an RLE at level 60 is valid, since the new level 61 is valid. The current wording + // of the rules requires that the RLE remain valid even if a previous LRE is invalid. + // This keeps track of ignored LRE or LRO codes at level 60, so that the matching PDFs + // will not try to pop the stack. + int overflowAlmostCounter = 0; + + // This keeps track of ignored pushes at level 61 or higher, so that matching PDFs will + // not try to pop the stack. + int overflowCounter = 0; + + // Rule X1. + + // Keep the level separate from the value (level | override status flag) for ease of access. + sbyte currentEmbeddingLevel = paragraphEmbeddingLevel; + sbyte currentEmbeddingValue = paragraphEmbeddingLevel; + + // Loop through types, handling all remaining rules + for (int i = 0; i < textLength; ++i) { + + embeddings[i] = currentEmbeddingValue; + + sbyte t = resultTypes[i]; + + // Rules X2, X3, X4, X5 + switch (t) { + case RLE: + case LRE: + case RLO: + case LRO: + // Only need to compute new level if current level is valid + if (overflowCounter == 0) { + sbyte newLevel; + if (t == RLE || t == RLO) { + newLevel = (sbyte)((currentEmbeddingLevel + 1) | 1); // least greater odd + } else { // t == LRE || t == LRO + newLevel = (sbyte)((currentEmbeddingLevel + 2) & ~1); // least greater even + } + + // If the new level is valid, push old embedding level and override status + // No check for valid stack counter, since the level check suffices. + if (newLevel < EXPLICIT_LEVEL_LIMIT) { + embeddingValueStack[stackCounter] = currentEmbeddingValue; + stackCounter++; + + currentEmbeddingLevel = newLevel; + if (t == LRO || t == RLO) { // override + currentEmbeddingValue = (sbyte)((byte)newLevel | 0x80); + } else { + currentEmbeddingValue = newLevel; + } + + // Adjust level of format mark (for expositional purposes only, this gets + // removed later). + embeddings[i] = currentEmbeddingValue; + break; + } + + // Otherwise new level is invalid, but a valid level can still be achieved if this + // level is 60 and we encounter an RLE or RLO further on. So record that we + // 'almost' overflowed. + if (currentEmbeddingLevel == 60) { + overflowAlmostCounter++; + break; + } + } + + // Otherwise old or new level is invalid. + overflowCounter++; + break; + + case PDF: + // The only case where this did not actually overflow but may have almost overflowed + // is when there was an RLE or RLO on level 60, which would result in level 61. So we + // only test the almost overflow condition in that case. + // + // Also note that there may be a PDF without any pushes at all. + + if (overflowCounter > 0) { + --overflowCounter; + } else if (overflowAlmostCounter > 0 && currentEmbeddingLevel != 61) { + --overflowAlmostCounter; + } else if (stackCounter > 0) { + --stackCounter; + currentEmbeddingValue = embeddingValueStack[stackCounter]; + currentEmbeddingLevel = (sbyte)(currentEmbeddingValue & 0x7f); + } + break; + + case B: + // Rule X8. + + // These values are reset for clarity, in this implementation B can only + // occur as the last code in the array. + stackCounter = 0; + overflowCounter = 0; + overflowAlmostCounter = 0; + currentEmbeddingLevel = paragraphEmbeddingLevel; + currentEmbeddingValue = paragraphEmbeddingLevel; + + embeddings[i] = paragraphEmbeddingLevel; + break; + + default: + break; + } + } + + return embeddings; + } + + + /** + * 3) resolving weak types + * Rules W1-W7. + * + * Note that some weak types (EN, AN) remain after this processing is complete. + */ + private void ResolveWeakTypes(int start, int limit, sbyte level, sbyte sor, sbyte eor) { + + // Rule W1. + // Changes all NSMs. + sbyte preceedingCharacterType = sor; + for (int i = start; i < limit; ++i) { + sbyte t = resultTypes[i]; + if (t == NSM) { + resultTypes[i] = preceedingCharacterType; + } else { + preceedingCharacterType = t; + } + } + + // Rule W2. + // EN does not change at the start of the run, because sor != AL. + for (int i = start; i < limit; ++i) { + if (resultTypes[i] == EN) { + for (int j = i - 1; j >= start; --j) { + sbyte t = resultTypes[j]; + if (t == L || t == R || t == AL) { + if (t == AL) { + resultTypes[i] = AN; + } + break; + } + } + } + } + + // Rule W3. + for (int i = start; i < limit; ++i) { + if (resultTypes[i] == AL) { + resultTypes[i] = R; + } + } + + // Rule W4. + // Since there must be values on both sides for this rule to have an + // effect, the scan skips the first and last value. + // + // Although the scan proceeds left to right, and changes the type values + // in a way that would appear to affect the computations later in the scan, + // there is actually no problem. A change in the current value can only + // affect the value to its immediate right, and only affect it if it is + // ES or CS. But the current value can only change if the value to its + // right is not ES or CS. Thus either the current value will not change, + // or its change will have no effect on the remainder of the analysis. + + for (int i = start + 1; i < limit - 1; ++i) { + if (resultTypes[i] == ES || resultTypes[i] == CS) { + sbyte prevSepType = resultTypes[i-1]; + sbyte succSepType = resultTypes[i+1]; + if (prevSepType == EN && succSepType == EN) { + resultTypes[i] = EN; + } else if (resultTypes[i] == CS && prevSepType == AN && succSepType == AN) { + resultTypes[i] = AN; + } + } + } + + // Rule W5. + for (int i = start; i < limit; ++i) { + if (resultTypes[i] == ET) { + // locate end of sequence + int runstart = i; + int runlimit = FindRunLimit(runstart, limit, new sbyte[] { ET }); + + // check values at ends of sequence + sbyte t = runstart == start ? sor : resultTypes[runstart - 1]; + + if (t != EN) { + t = runlimit == limit ? eor : resultTypes[runlimit]; + } + + if (t == EN) { + SetTypes(runstart, runlimit, EN); + } + + // continue at end of sequence + i = runlimit; + } + } + + // Rule W6. + for (int i = start; i < limit; ++i) { + sbyte t = resultTypes[i]; + if (t == ES || t == ET || t == CS) { + resultTypes[i] = ON; + } + } + + // Rule W7. + for (int i = start; i < limit; ++i) { + if (resultTypes[i] == EN) { + // set default if we reach start of run + sbyte prevStrongType = sor; + for (int j = i - 1; j >= start; --j) { + sbyte t = resultTypes[j]; + if (t == L || t == R) { // AL's have been removed + prevStrongType = t; + break; + } + } + if (prevStrongType == L) { + resultTypes[i] = L; + } + } + } + } + + /** + * 6) resolving neutral types + * Rules N1-N2. + */ + private void ResolveNeutralTypes(int start, int limit, sbyte level, sbyte sor, sbyte eor) { + + for (int i = start; i < limit; ++i) { + sbyte t = resultTypes[i]; + if (t == WS || t == ON || t == B || t == S) { + // find bounds of run of neutrals + int runstart = i; + int runlimit = FindRunLimit(runstart, limit, new sbyte[] {B, S, WS, ON}); + + // determine effective types at ends of run + sbyte leadingType; + sbyte trailingType; + + if (runstart == start) { + leadingType = sor; + } else { + leadingType = resultTypes[runstart - 1]; + if (leadingType == L || leadingType == R) { + // found the strong type + } else if (leadingType == AN) { + leadingType = R; + } else if (leadingType == EN) { + // Since EN's with previous strong L types have been changed + // to L in W7, the leadingType must be R. + leadingType = R; + } + } + + if (runlimit == limit) { + trailingType = eor; + } else { + trailingType = resultTypes[runlimit]; + if (trailingType == L || trailingType == R) { + // found the strong type + } else if (trailingType == AN) { + trailingType = R; + } else if (trailingType == EN) { + trailingType = R; + } + } + + sbyte resolvedType; + if (leadingType == trailingType) { + // Rule N1. + resolvedType = leadingType; + } else { + // Rule N2. + // Notice the embedding level of the run is used, not + // the paragraph embedding level. + resolvedType = TypeForLevel(level); + } + + SetTypes(runstart, runlimit, resolvedType); + + // skip over run of (former) neutrals + i = runlimit; + } + } + } + + /** + * 7) resolving implicit embedding levels + * Rules I1, I2. + */ + private void ResolveImplicitLevels(int start, int limit, sbyte level, sbyte sor, sbyte eor) { + if ((level & 1) == 0) { // even level + for (int i = start; i < limit; ++i) { + sbyte t = resultTypes[i]; + // Rule I1. + if (t == L ) { + // no change + } else if (t == R) { + resultLevels[i] += 1; + } else { // t == AN || t == EN + resultLevels[i] += 2; + } + } + } else { // odd level + for (int i = start; i < limit; ++i) { + sbyte t = resultTypes[i]; + // Rule I2. + if (t == R) { + // no change + } else { // t == L || t == AN || t == EN + resultLevels[i] += 1; + } + } + } + } + + // + // Output + // + + public byte[] GetLevels() { + return GetLevels(new int[]{textLength}); + } + + /** + * Return levels array breaking lines at offsets in linebreaks.
    + * Rule L1. + *

    + * The returned levels array contains the resolved level for each + * bidi code passed to the constructor. + *

    + * The linebreaks array must include at least one value. + * The values must be in strictly increasing order (no duplicates) + * between 1 and the length of the text, inclusive. The last value + * must be the length of the text. + * + * @param linebreaks the offsets at which to break the paragraph + * @return the resolved levels of the text + */ + public byte[] GetLevels(int[] linebreaks) { + + // Note that since the previous processing has removed all + // P, S, and WS values from resultTypes, the values referred to + // in these rules are the initial types, before any processing + // has been applied (including processing of overrides). + // + // This example implementation has reinserted explicit format codes + // and BN, in order that the levels array correspond to the + // initial text. Their final placement is not normative. + // These codes are treated like WS in this implementation, + // so they don't interrupt sequences of WS. + + ValidateLineBreaks(linebreaks, textLength); + + byte[] result = new byte[resultLevels.Length]; + for (int k = 0; k < resultLevels.Length; ++k) + result[k] = (byte)resultLevels[k]; + + // don't worry about linebreaks since if there is a break within + // a series of WS values preceeding S, the linebreak itself + // causes the reset. + for (int i = 0; i < result.Length; ++i) { + sbyte t = initialTypes[i]; + if (t == B || t == S) { + // Rule L1, clauses one and two. + result[i] = (byte)paragraphEmbeddingLevel; + + // Rule L1, clause three. + for (int j = i - 1; j >= 0; --j) { + if (IsWhitespace(initialTypes[j])) { // including format codes + result[j] = (byte)paragraphEmbeddingLevel; + } else { + break; + } + } + } + } + + // Rule L1, clause four. + int start = 0; + for (int i = 0; i < linebreaks.Length; ++i) { + int limit = linebreaks[i]; + for (int j = limit - 1; j >= start; --j) { + if (IsWhitespace(initialTypes[j])) { // including format codes + result[j] = (byte)paragraphEmbeddingLevel; + } else { + break; + } + } + + start = limit; + } + + return result; + } + + /** + * Return reordering array breaking lines at offsets in linebreaks. + *

    + * The reordering array maps from a visual index to a logical index. + * Lines are concatenated from left to right. So for example, the + * fifth character from the left on the third line is + *

     GetReordering(linebreaks)[linebreaks[1] + 4]
    + * (linebreaks[1] is the position after the last character of the + * second line, which is also the index of the first character on the + * third line, and adding four gets the fifth character from the left). + *

    + * The linebreaks array must include at least one value. + * The values must be in strictly increasing order (no duplicates) + * between 1 and the length of the text, inclusive. The last value + * must be the length of the text. + * + * @param linebreaks the offsets at which to break the paragraph. + */ +/* public int[] GetReordering(int[] linebreaks) { + ValidateLineBreaks(linebreaks, textLength); + + sbyte[] levels = GetLevels(linebreaks); + + return ComputeMultilineReordering(levels, linebreaks); + }*/ + + /** + * Return multiline reordering array for a given level array. + * Reordering does not occur across a line break. + */ + private static int[] ComputeMultilineReordering(sbyte[] levels, int[] linebreaks) { + int[] result = new int[levels.Length]; + + int start = 0; + for (int i = 0; i < linebreaks.Length; ++i) { + int limit = linebreaks[i]; + + sbyte[] templevels = new sbyte[limit - start]; + Array.Copy(levels, start, templevels, 0, templevels.Length); + + int[] temporder = ComputeReordering(templevels); + for (int j = 0; j < temporder.Length; ++j) { + result[start + j] = temporder[j] + start; + } + + start = limit; + } + + return result; + } + + /** + * Return reordering array for a given level array. This reorders a single line. + * The reordering is a visual to logical map. For example, + * the leftmost char is string.CharAt(order[0]). + * Rule L2. + */ + private static int[] ComputeReordering(sbyte[] levels) { + int lineLength = levels.Length; + + int[] result = new int[lineLength]; + + // initialize order + for (int i = 0; i < lineLength; ++i) { + result[i] = i; + } + + // locate highest level found on line. + // Note the rules say text, but no reordering across line bounds is performed, + // so this is sufficient. + sbyte highestLevel = 0; + sbyte lowestOddLevel = 63; + for (int i = 0; i < lineLength; ++i) { + sbyte level = levels[i]; + if (level > highestLevel) { + highestLevel = level; + } + if (((level & 1) != 0) && level < lowestOddLevel) { + lowestOddLevel = level; + } + } + + for (int level = highestLevel; level >= lowestOddLevel; --level) { + for (int i = 0; i < lineLength; ++i) { + if (levels[i] >= level) { + // find range of text at or above this level + int start = i; + int limit = i + 1; + while (limit < lineLength && levels[limit] >= level) { + ++limit; + } + + // reverse run + for (int j = start, k = limit - 1; j < k; ++j, --k) { + int temp = result[j]; + result[j] = result[k]; + result[k] = temp; + } + + // skip to end of level run + i = limit; + } + } + } + + return result; + } + + /** + * Return the base level of the paragraph. + */ + public sbyte GetBaseLevel() { + return paragraphEmbeddingLevel; + } + + // --- internal utilities ------------------------------------------------- + + /** + * Return true if the type is considered a whitespace type for the line break rules. + */ + private static bool IsWhitespace(sbyte biditype) { + switch (biditype) { + case LRE: + case RLE: + case LRO: + case RLO: + case PDF: + case BN: + case WS: + return true; + default: + return false; + } + } + + /** + * Return the strong type (L or R) corresponding to the level. + */ + private static sbyte TypeForLevel(int level) { + return ((level & 0x1) == 0) ? L : R; + } + + /** + * Return the limit of the run starting at index that includes only resultTypes in validSet. + * This checks the value at index, and will return index if that value is not in validSet. + */ + private int FindRunLimit(int index, int limit, sbyte[] validSet) { + --index; + loop: + while (++index < limit) { + sbyte t = resultTypes[index]; + for (int i = 0; i < validSet.Length; ++i) { + if (t == validSet[i]) { + goto loop; + } + } + // didn't find a match in validSet + return index; + } + return limit; + } + + /** + * Return the start of the run including index that includes only resultTypes in validSet. + * This assumes the value at index is valid, and does not check it. + */ + private int FindRunStart(int index, sbyte[] validSet) { + loop: + while (--index >= 0) { + sbyte t = resultTypes[index]; + for (int i = 0; i < validSet.Length; ++i) { + if (t == validSet[i]) { + goto loop; + } + } + return index + 1; + } + return 0; + } + + /** + * Set resultTypes from start up to (but not including) limit to newType. + */ + private void SetTypes(int start, int limit, sbyte newType) { + for (int i = start; i < limit; ++i) { + resultTypes[i] = newType; + } + } + + /** + * Set resultLevels from start up to (but not including) limit to newLevel. + */ + private void SetLevels(int start, int limit, sbyte newLevel) { + for (int i = start; i < limit; ++i) { + resultLevels[i] = newLevel; + } + } + + // --- input validation --------------------------------------------------- + + /** + * Throw exception if type array is invalid. + */ + private static void ValidateTypes(sbyte[] types) { + if (types == null) { + throw new ArgumentException("types is null"); + } + for (int i = 0; i < types.Length; ++i) { + if (types[i] < TYPE_MIN || types[i] > TYPE_MAX) { + throw new ArgumentException("illegal type value at " + i + ": " + types[i]); + } + } + for (int i = 0; i < types.Length - 1; ++i) { + if (types[i] == B) { + throw new ArgumentException("B type before end of paragraph at index: " + i); + } + } + } + + /** + * Throw exception if paragraph embedding level is invalid. Special allowance for -1 so that + * default processing can still be performed when using this API. + */ + private static void ValidateParagraphEmbeddingLevel(sbyte paragraphEmbeddingLevel) { + if (paragraphEmbeddingLevel != -1 && + paragraphEmbeddingLevel != 0 && + paragraphEmbeddingLevel != 1) { + throw new ArgumentException("illegal paragraph embedding level: " + paragraphEmbeddingLevel); + } + } + + /** + * Throw exception if line breaks array is invalid. + */ + private static void ValidateLineBreaks(int[] linebreaks, int textLength) { + int prev = 0; + for (int i = 0; i < linebreaks.Length; ++i) { + int next = linebreaks[i]; + if (next <= prev) { + throw new ArgumentException("bad linebreak: " + next + " at index: " + i); + } + prev = next; + } + if (prev != textLength) { + throw new ArgumentException("last linebreak must be at " + textLength); + } + } + + private static sbyte[] rtypes = new sbyte[0x10000]; + + private static char[] baseTypes = { + (char)0, (char)8, (char)BN, (char)9, (char)9, (char)S, (char)10, (char)10, (char)B, (char)11, (char)11, (char)S, (char)12, (char)12, (char)WS, (char)13, (char)13, (char)B, + (char)14, (char)27, (char)BN, (char)28, (char)30, (char)B, (char)31, (char)31, (char)S, (char)32, (char)32, (char)WS, (char)33, (char)34, (char)ON, (char)35, (char)37, (char)ET, + (char)38, (char)42, (char)ON, (char)43, (char)43, (char)ET, (char)44, (char)44, (char)CS, (char)45, (char)45, (char)ET, (char)46, (char)46, (char)CS, (char)47, (char)47, (char)ES, + (char)48, (char)57, (char)EN, (char)58, (char)58, (char)CS, (char)59, (char)64, (char)ON, (char)65, (char)90, (char)L, (char)91, (char)96, (char)ON, (char)97, (char)122, (char)L, + (char)123, (char)126, (char)ON, (char)127, (char)132, (char)BN, (char)133, (char)133, (char)B, (char)134, (char)159, (char)BN, (char)160, (char)160, (char)CS, + (char)161, (char)161, (char)ON, (char)162, (char)165, (char)ET, (char)166, (char)169, (char)ON, (char)170, (char)170, (char)L, (char)171, (char)175, (char)ON, + (char)176, (char)177, (char)ET, (char)178, (char)179, (char)EN, (char)180, (char)180, (char)ON, (char)181, (char)181, (char)L, (char)182, (char)184, (char)ON, + (char)185, (char)185, (char)EN, (char)186, (char)186, (char)L, (char)187, (char)191, (char)ON, (char)192, (char)214, (char)L, (char)215, (char)215, (char)ON, + (char)216, (char)246, (char)L, (char)247, (char)247, (char)ON, (char)248, (char)696, (char)L, (char)697, (char)698, (char)ON, (char)699, (char)705, (char)L, + (char)706, (char)719, (char)ON, (char)720, (char)721, (char)L, (char)722, (char)735, (char)ON, (char)736, (char)740, (char)L, (char)741, (char)749, (char)ON, + (char)750, (char)750, (char)L, (char)751, (char)767, (char)ON, (char)768, (char)855, (char)NSM, (char)856, (char)860, (char)L, (char)861, (char)879, (char)NSM, + (char)880, (char)883, (char)L, (char)884, (char)885, (char)ON, (char)886, (char)893, (char)L, (char)894, (char)894, (char)ON, (char)895, (char)899, (char)L, + (char)900, (char)901, (char)ON, (char)902, (char)902, (char)L, (char)903, (char)903, (char)ON, (char)904, (char)1013, (char)L, (char)1014, (char)1014, (char)ON, + (char)1015, (char)1154, (char)L, (char)1155, (char)1158, (char)NSM, (char)1159, (char)1159, (char)L, (char)1160, (char)1161, (char)NSM, + (char)1162, (char)1417, (char)L, (char)1418, (char)1418, (char)ON, (char)1419, (char)1424, (char)L, (char)1425, (char)1441, (char)NSM, + (char)1442, (char)1442, (char)L, (char)1443, (char)1465, (char)NSM, (char)1466, (char)1466, (char)L, (char)1467, (char)1469, (char)NSM, + (char)1470, (char)1470, (char)R, (char)1471, (char)1471, (char)NSM, (char)1472, (char)1472, (char)R, (char)1473, (char)1474, (char)NSM, + (char)1475, (char)1475, (char)R, (char)1476, (char)1476, (char)NSM, (char)1477, (char)1487, (char)L, (char)1488, (char)1514, (char)R, + (char)1515, (char)1519, (char)L, (char)1520, (char)1524, (char)R, (char)1525, (char)1535, (char)L, (char)1536, (char)1539, (char)AL, + (char)1540, (char)1547, (char)L, (char)1548, (char)1548, (char)CS, (char)1549, (char)1549, (char)AL, (char)1550, (char)1551, (char)ON, + (char)1552, (char)1557, (char)NSM, (char)1558, (char)1562, (char)L, (char)1563, (char)1563, (char)AL, (char)1564, (char)1566, (char)L, + (char)1567, (char)1567, (char)AL, (char)1568, (char)1568, (char)L, (char)1569, (char)1594, (char)AL, (char)1595, (char)1599, (char)L, + (char)1600, (char)1610, (char)AL, (char)1611, (char)1624, (char)NSM, (char)1625, (char)1631, (char)L, (char)1632, (char)1641, (char)AN, + (char)1642, (char)1642, (char)ET, (char)1643, (char)1644, (char)AN, (char)1645, (char)1647, (char)AL, (char)1648, (char)1648, (char)NSM, + (char)1649, (char)1749, (char)AL, (char)1750, (char)1756, (char)NSM, (char)1757, (char)1757, (char)AL, (char)1758, (char)1764, (char)NSM, + (char)1765, (char)1766, (char)AL, (char)1767, (char)1768, (char)NSM, (char)1769, (char)1769, (char)ON, (char)1770, (char)1773, (char)NSM, + (char)1774, (char)1775, (char)AL, (char)1776, (char)1785, (char)EN, (char)1786, (char)1805, (char)AL, (char)1806, (char)1806, (char)L, + (char)1807, (char)1807, (char)BN, (char)1808, (char)1808, (char)AL, (char)1809, (char)1809, (char)NSM, (char)1810, (char)1839, (char)AL, + (char)1840, (char)1866, (char)NSM, (char)1867, (char)1868, (char)L, (char)1869, (char)1871, (char)AL, (char)1872, (char)1919, (char)L, + (char)1920, (char)1957, (char)AL, (char)1958, (char)1968, (char)NSM, (char)1969, (char)1969, (char)AL, (char)1970, (char)2304, (char)L, + (char)2305, (char)2306, (char)NSM, (char)2307, (char)2363, (char)L, (char)2364, (char)2364, (char)NSM, (char)2365, (char)2368, (char)L, + (char)2369, (char)2376, (char)NSM, (char)2377, (char)2380, (char)L, (char)2381, (char)2381, (char)NSM, (char)2382, (char)2384, (char)L, + (char)2385, (char)2388, (char)NSM, (char)2389, (char)2401, (char)L, (char)2402, (char)2403, (char)NSM, (char)2404, (char)2432, (char)L, + (char)2433, (char)2433, (char)NSM, (char)2434, (char)2491, (char)L, (char)2492, (char)2492, (char)NSM, (char)2493, (char)2496, (char)L, + (char)2497, (char)2500, (char)NSM, (char)2501, (char)2508, (char)L, (char)2509, (char)2509, (char)NSM, (char)2510, (char)2529, (char)L, + (char)2530, (char)2531, (char)NSM, (char)2532, (char)2545, (char)L, (char)2546, (char)2547, (char)ET, (char)2548, (char)2560, (char)L, + (char)2561, (char)2562, (char)NSM, (char)2563, (char)2619, (char)L, (char)2620, (char)2620, (char)NSM, (char)2621, (char)2624, (char)L, + (char)2625, (char)2626, (char)NSM, (char)2627, (char)2630, (char)L, (char)2631, (char)2632, (char)NSM, (char)2633, (char)2634, (char)L, + (char)2635, (char)2637, (char)NSM, (char)2638, (char)2671, (char)L, (char)2672, (char)2673, (char)NSM, (char)2674, (char)2688, (char)L, + (char)2689, (char)2690, (char)NSM, (char)2691, (char)2747, (char)L, (char)2748, (char)2748, (char)NSM, (char)2749, (char)2752, (char)L, + (char)2753, (char)2757, (char)NSM, (char)2758, (char)2758, (char)L, (char)2759, (char)2760, (char)NSM, (char)2761, (char)2764, (char)L, + (char)2765, (char)2765, (char)NSM, (char)2766, (char)2785, (char)L, (char)2786, (char)2787, (char)NSM, (char)2788, (char)2800, (char)L, + (char)2801, (char)2801, (char)ET, (char)2802, (char)2816, (char)L, (char)2817, (char)2817, (char)NSM, (char)2818, (char)2875, (char)L, + (char)2876, (char)2876, (char)NSM, (char)2877, (char)2878, (char)L, (char)2879, (char)2879, (char)NSM, (char)2880, (char)2880, (char)L, + (char)2881, (char)2883, (char)NSM, (char)2884, (char)2892, (char)L, (char)2893, (char)2893, (char)NSM, (char)2894, (char)2901, (char)L, + (char)2902, (char)2902, (char)NSM, (char)2903, (char)2945, (char)L, (char)2946, (char)2946, (char)NSM, (char)2947, (char)3007, (char)L, + (char)3008, (char)3008, (char)NSM, (char)3009, (char)3020, (char)L, (char)3021, (char)3021, (char)NSM, (char)3022, (char)3058, (char)L, + (char)3059, (char)3064, (char)ON, (char)3065, (char)3065, (char)ET, (char)3066, (char)3066, (char)ON, (char)3067, (char)3133, (char)L, + (char)3134, (char)3136, (char)NSM, (char)3137, (char)3141, (char)L, (char)3142, (char)3144, (char)NSM, (char)3145, (char)3145, (char)L, + (char)3146, (char)3149, (char)NSM, (char)3150, (char)3156, (char)L, (char)3157, (char)3158, (char)NSM, (char)3159, (char)3259, (char)L, + (char)3260, (char)3260, (char)NSM, (char)3261, (char)3275, (char)L, (char)3276, (char)3277, (char)NSM, (char)3278, (char)3392, (char)L, + (char)3393, (char)3395, (char)NSM, (char)3396, (char)3404, (char)L, (char)3405, (char)3405, (char)NSM, (char)3406, (char)3529, (char)L, + (char)3530, (char)3530, (char)NSM, (char)3531, (char)3537, (char)L, (char)3538, (char)3540, (char)NSM, (char)3541, (char)3541, (char)L, + (char)3542, (char)3542, (char)NSM, (char)3543, (char)3632, (char)L, (char)3633, (char)3633, (char)NSM, (char)3634, (char)3635, (char)L, + (char)3636, (char)3642, (char)NSM, (char)3643, (char)3646, (char)L, (char)3647, (char)3647, (char)ET, (char)3648, (char)3654, (char)L, + (char)3655, (char)3662, (char)NSM, (char)3663, (char)3760, (char)L, (char)3761, (char)3761, (char)NSM, (char)3762, (char)3763, (char)L, + (char)3764, (char)3769, (char)NSM, (char)3770, (char)3770, (char)L, (char)3771, (char)3772, (char)NSM, (char)3773, (char)3783, (char)L, + (char)3784, (char)3789, (char)NSM, (char)3790, (char)3863, (char)L, (char)3864, (char)3865, (char)NSM, (char)3866, (char)3892, (char)L, + (char)3893, (char)3893, (char)NSM, (char)3894, (char)3894, (char)L, (char)3895, (char)3895, (char)NSM, (char)3896, (char)3896, (char)L, + (char)3897, (char)3897, (char)NSM, (char)3898, (char)3901, (char)ON, (char)3902, (char)3952, (char)L, (char)3953, (char)3966, (char)NSM, + (char)3967, (char)3967, (char)L, (char)3968, (char)3972, (char)NSM, (char)3973, (char)3973, (char)L, (char)3974, (char)3975, (char)NSM, + (char)3976, (char)3983, (char)L, (char)3984, (char)3991, (char)NSM, (char)3992, (char)3992, (char)L, (char)3993, (char)4028, (char)NSM, + (char)4029, (char)4037, (char)L, (char)4038, (char)4038, (char)NSM, (char)4039, (char)4140, (char)L, (char)4141, (char)4144, (char)NSM, + (char)4145, (char)4145, (char)L, (char)4146, (char)4146, (char)NSM, (char)4147, (char)4149, (char)L, (char)4150, (char)4151, (char)NSM, + (char)4152, (char)4152, (char)L, (char)4153, (char)4153, (char)NSM, (char)4154, (char)4183, (char)L, (char)4184, (char)4185, (char)NSM, + (char)4186, (char)5759, (char)L, (char)5760, (char)5760, (char)WS, (char)5761, (char)5786, (char)L, (char)5787, (char)5788, (char)ON, + (char)5789, (char)5905, (char)L, (char)5906, (char)5908, (char)NSM, (char)5909, (char)5937, (char)L, (char)5938, (char)5940, (char)NSM, + (char)5941, (char)5969, (char)L, (char)5970, (char)5971, (char)NSM, (char)5972, (char)6001, (char)L, (char)6002, (char)6003, (char)NSM, + (char)6004, (char)6070, (char)L, (char)6071, (char)6077, (char)NSM, (char)6078, (char)6085, (char)L, (char)6086, (char)6086, (char)NSM, + (char)6087, (char)6088, (char)L, (char)6089, (char)6099, (char)NSM, (char)6100, (char)6106, (char)L, (char)6107, (char)6107, (char)ET, + (char)6108, (char)6108, (char)L, (char)6109, (char)6109, (char)NSM, (char)6110, (char)6127, (char)L, (char)6128, (char)6137, (char)ON, + (char)6138, (char)6143, (char)L, (char)6144, (char)6154, (char)ON, (char)6155, (char)6157, (char)NSM, (char)6158, (char)6158, (char)WS, + (char)6159, (char)6312, (char)L, (char)6313, (char)6313, (char)NSM, (char)6314, (char)6431, (char)L, (char)6432, (char)6434, (char)NSM, + (char)6435, (char)6438, (char)L, (char)6439, (char)6443, (char)NSM, (char)6444, (char)6449, (char)L, (char)6450, (char)6450, (char)NSM, + (char)6451, (char)6456, (char)L, (char)6457, (char)6459, (char)NSM, (char)6460, (char)6463, (char)L, (char)6464, (char)6464, (char)ON, + (char)6465, (char)6467, (char)L, (char)6468, (char)6469, (char)ON, (char)6470, (char)6623, (char)L, (char)6624, (char)6655, (char)ON, + (char)6656, (char)8124, (char)L, (char)8125, (char)8125, (char)ON, (char)8126, (char)8126, (char)L, (char)8127, (char)8129, (char)ON, + (char)8130, (char)8140, (char)L, (char)8141, (char)8143, (char)ON, (char)8144, (char)8156, (char)L, (char)8157, (char)8159, (char)ON, + (char)8160, (char)8172, (char)L, (char)8173, (char)8175, (char)ON, (char)8176, (char)8188, (char)L, (char)8189, (char)8190, (char)ON, + (char)8191, (char)8191, (char)L, (char)8192, (char)8202, (char)WS, (char)8203, (char)8205, (char)BN, (char)8206, (char)8206, (char)L, + (char)8207, (char)8207, (char)R, (char)8208, (char)8231, (char)ON, (char)8232, (char)8232, (char)WS, (char)8233, (char)8233, (char)B, + (char)8234, (char)8234, (char)LRE, (char)8235, (char)8235, (char)RLE, (char)8236, (char)8236, (char)PDF, (char)8237, (char)8237, (char)LRO, + (char)8238, (char)8238, (char)RLO, (char)8239, (char)8239, (char)WS, (char)8240, (char)8244, (char)ET, (char)8245, (char)8276, (char)ON, + (char)8277, (char)8278, (char)L, (char)8279, (char)8279, (char)ON, (char)8280, (char)8286, (char)L, (char)8287, (char)8287, (char)WS, + (char)8288, (char)8291, (char)BN, (char)8292, (char)8297, (char)L, (char)8298, (char)8303, (char)BN, (char)8304, (char)8304, (char)EN, + (char)8305, (char)8307, (char)L, (char)8308, (char)8313, (char)EN, (char)8314, (char)8315, (char)ET, (char)8316, (char)8318, (char)ON, + (char)8319, (char)8319, (char)L, (char)8320, (char)8329, (char)EN, (char)8330, (char)8331, (char)ET, (char)8332, (char)8334, (char)ON, + (char)8335, (char)8351, (char)L, (char)8352, (char)8369, (char)ET, (char)8370, (char)8399, (char)L, (char)8400, (char)8426, (char)NSM, + (char)8427, (char)8447, (char)L, (char)8448, (char)8449, (char)ON, (char)8450, (char)8450, (char)L, (char)8451, (char)8454, (char)ON, + (char)8455, (char)8455, (char)L, (char)8456, (char)8457, (char)ON, (char)8458, (char)8467, (char)L, (char)8468, (char)8468, (char)ON, + (char)8469, (char)8469, (char)L, (char)8470, (char)8472, (char)ON, (char)8473, (char)8477, (char)L, (char)8478, (char)8483, (char)ON, + (char)8484, (char)8484, (char)L, (char)8485, (char)8485, (char)ON, (char)8486, (char)8486, (char)L, (char)8487, (char)8487, (char)ON, + (char)8488, (char)8488, (char)L, (char)8489, (char)8489, (char)ON, (char)8490, (char)8493, (char)L, (char)8494, (char)8494, (char)ET, + (char)8495, (char)8497, (char)L, (char)8498, (char)8498, (char)ON, (char)8499, (char)8505, (char)L, (char)8506, (char)8507, (char)ON, + (char)8508, (char)8511, (char)L, (char)8512, (char)8516, (char)ON, (char)8517, (char)8521, (char)L, (char)8522, (char)8523, (char)ON, + (char)8524, (char)8530, (char)L, (char)8531, (char)8543, (char)ON, (char)8544, (char)8591, (char)L, (char)8592, (char)8721, (char)ON, + (char)8722, (char)8723, (char)ET, (char)8724, (char)9013, (char)ON, (char)9014, (char)9082, (char)L, (char)9083, (char)9108, (char)ON, + (char)9109, (char)9109, (char)L, (char)9110, (char)9168, (char)ON, (char)9169, (char)9215, (char)L, (char)9216, (char)9254, (char)ON, + (char)9255, (char)9279, (char)L, (char)9280, (char)9290, (char)ON, (char)9291, (char)9311, (char)L, (char)9312, (char)9371, (char)EN, + (char)9372, (char)9449, (char)L, (char)9450, (char)9450, (char)EN, (char)9451, (char)9751, (char)ON, (char)9752, (char)9752, (char)L, + (char)9753, (char)9853, (char)ON, (char)9854, (char)9855, (char)L, (char)9856, (char)9873, (char)ON, (char)9874, (char)9887, (char)L, + (char)9888, (char)9889, (char)ON, (char)9890, (char)9984, (char)L, (char)9985, (char)9988, (char)ON, (char)9989, (char)9989, (char)L, + (char)9990, (char)9993, (char)ON, (char)9994, (char)9995, (char)L, (char)9996, (char)10023, (char)ON, (char)10024, (char)10024, (char)L, + (char)10025, (char)10059, (char)ON, (char)10060, (char)10060, (char)L, (char)10061, (char)10061, (char)ON, (char)10062, (char)10062, (char)L, + (char)10063, (char)10066, (char)ON, (char)10067, (char)10069, (char)L, (char)10070, (char)10070, (char)ON, (char)10071, (char)10071, (char)L, + (char)10072, (char)10078, (char)ON, (char)10079, (char)10080, (char)L, (char)10081, (char)10132, (char)ON, (char)10133, (char)10135, (char)L, + (char)10136, (char)10159, (char)ON, (char)10160, (char)10160, (char)L, (char)10161, (char)10174, (char)ON, (char)10175, (char)10191, (char)L, + (char)10192, (char)10219, (char)ON, (char)10220, (char)10223, (char)L, (char)10224, (char)11021, (char)ON, (char)11022, (char)11903, (char)L, + (char)11904, (char)11929, (char)ON, (char)11930, (char)11930, (char)L, (char)11931, (char)12019, (char)ON, (char)12020, (char)12031, (char)L, + (char)12032, (char)12245, (char)ON, (char)12246, (char)12271, (char)L, (char)12272, (char)12283, (char)ON, (char)12284, (char)12287, (char)L, + (char)12288, (char)12288, (char)WS, (char)12289, (char)12292, (char)ON, (char)12293, (char)12295, (char)L, (char)12296, (char)12320, (char)ON, + (char)12321, (char)12329, (char)L, (char)12330, (char)12335, (char)NSM, (char)12336, (char)12336, (char)ON, (char)12337, (char)12341, (char)L, + (char)12342, (char)12343, (char)ON, (char)12344, (char)12348, (char)L, (char)12349, (char)12351, (char)ON, (char)12352, (char)12440, (char)L, + (char)12441, (char)12442, (char)NSM, (char)12443, (char)12444, (char)ON, (char)12445, (char)12447, (char)L, (char)12448, (char)12448, (char)ON, + (char)12449, (char)12538, (char)L, (char)12539, (char)12539, (char)ON, (char)12540, (char)12828, (char)L, (char)12829, (char)12830, (char)ON, + (char)12831, (char)12879, (char)L, (char)12880, (char)12895, (char)ON, (char)12896, (char)12923, (char)L, (char)12924, (char)12925, (char)ON, + (char)12926, (char)12976, (char)L, (char)12977, (char)12991, (char)ON, (char)12992, (char)13003, (char)L, (char)13004, (char)13007, (char)ON, + (char)13008, (char)13174, (char)L, (char)13175, (char)13178, (char)ON, (char)13179, (char)13277, (char)L, (char)13278, (char)13279, (char)ON, + (char)13280, (char)13310, (char)L, (char)13311, (char)13311, (char)ON, (char)13312, (char)19903, (char)L, (char)19904, (char)19967, (char)ON, + (char)19968, (char)42127, (char)L, (char)42128, (char)42182, (char)ON, (char)42183, (char)64284, (char)L, (char)64285, (char)64285, (char)R, + (char)64286, (char)64286, (char)NSM, (char)64287, (char)64296, (char)R, (char)64297, (char)64297, (char)ET, (char)64298, (char)64310, (char)R, + (char)64311, (char)64311, (char)L, (char)64312, (char)64316, (char)R, (char)64317, (char)64317, (char)L, (char)64318, (char)64318, (char)R, + (char)64319, (char)64319, (char)L, (char)64320, (char)64321, (char)R, (char)64322, (char)64322, (char)L, (char)64323, (char)64324, (char)R, + (char)64325, (char)64325, (char)L, (char)64326, (char)64335, (char)R, (char)64336, (char)64433, (char)AL, (char)64434, (char)64466, (char)L, + (char)64467, (char)64829, (char)AL, (char)64830, (char)64831, (char)ON, (char)64832, (char)64847, (char)L, (char)64848, (char)64911, (char)AL, + (char)64912, (char)64913, (char)L, (char)64914, (char)64967, (char)AL, (char)64968, (char)65007, (char)L, (char)65008, (char)65020, (char)AL, + (char)65021, (char)65021, (char)ON, (char)65022, (char)65023, (char)L, (char)65024, (char)65039, (char)NSM, (char)65040, (char)65055, (char)L, + (char)65056, (char)65059, (char)NSM, (char)65060, (char)65071, (char)L, (char)65072, (char)65103, (char)ON, (char)65104, (char)65104, (char)CS, + (char)65105, (char)65105, (char)ON, (char)65106, (char)65106, (char)CS, (char)65107, (char)65107, (char)L, (char)65108, (char)65108, (char)ON, + (char)65109, (char)65109, (char)CS, (char)65110, (char)65118, (char)ON, (char)65119, (char)65119, (char)ET, (char)65120, (char)65121, (char)ON, + (char)65122, (char)65123, (char)ET, (char)65124, (char)65126, (char)ON, (char)65127, (char)65127, (char)L, (char)65128, (char)65128, (char)ON, + (char)65129, (char)65130, (char)ET, (char)65131, (char)65131, (char)ON, (char)65132, (char)65135, (char)L, (char)65136, (char)65140, (char)AL, + (char)65141, (char)65141, (char)L, (char)65142, (char)65276, (char)AL, (char)65277, (char)65278, (char)L, (char)65279, (char)65279, (char)BN, + (char)65280, (char)65280, (char)L, (char)65281, (char)65282, (char)ON, (char)65283, (char)65285, (char)ET, (char)65286, (char)65290, (char)ON, + (char)65291, (char)65291, (char)ET, (char)65292, (char)65292, (char)CS, (char)65293, (char)65293, (char)ET, (char)65294, (char)65294, (char)CS, + (char)65295, (char)65295, (char)ES, (char)65296, (char)65305, (char)EN, (char)65306, (char)65306, (char)CS, (char)65307, (char)65312, (char)ON, + (char)65313, (char)65338, (char)L, (char)65339, (char)65344, (char)ON, (char)65345, (char)65370, (char)L, (char)65371, (char)65381, (char)ON, + (char)65382, (char)65503, (char)L, (char)65504, (char)65505, (char)ET, (char)65506, (char)65508, (char)ON, (char)65509, (char)65510, (char)ET, + (char)65511, (char)65511, (char)L, (char)65512, (char)65518, (char)ON, (char)65519, (char)65528, (char)L, (char)65529, (char)65531, (char)BN, + (char)65532, (char)65533, (char)ON, (char)65534, (char)65535, (char)L}; + + static BidiOrder() { + for (int k = 0; k < baseTypes.Length; ++k) { + int start = baseTypes[k]; + int end = baseTypes[++k]; + sbyte b = (sbyte)baseTypes[++k]; + while (start <= end) + rtypes[start++] = b; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/ByteBuffer.cs b/iTechSharp/iTextSharp/text/pdf/ByteBuffer.cs new file mode 100644 index 0000000..8c7d617 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/ByteBuffer.cs @@ -0,0 +1,673 @@ +using System; +using System.IO; +using System.Text; +using System.Globalization; + +/* + * $Id: ByteBuffer.cs,v 1.7 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2000, 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Acts like a StringBuilder but works with byte arrays. + * floating point is converted to a format suitable to the PDF. + * @author Paulo Soares (psoares@consiste.pt) + */ + + public class ByteBuffer : Stream { + /** The count of bytes in the buffer. */ + protected int count; + + /** The buffer where the bytes are stored. */ + protected byte[] buf; + + private static int byteCacheSize = 0; + + private static byte[][] byteCache = new byte[byteCacheSize][]; + public const byte ZERO = (byte)'0'; + private static char[] chars = new char[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + private static byte[] bytes = new byte[] {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102}; + /** + * If true always output floating point numbers with 6 decimal digits. + * If false uses the faster, although less precise, representation. + */ + public static bool HIGH_PRECISION = false; + + /** Creates new ByteBuffer with capacity 128 */ + public ByteBuffer() : this(128) {} + + /** + * Creates a byte buffer with a certain capacity. + * @param size the initial capacity + */ + public ByteBuffer(int size) { + if (size < 1) + size = 128; + buf = new byte[size]; + } + + /** + * Sets the cache size. + *

    + * This can only be used to increment the size. + * If the size that is passed through is smaller than the current size, nothing happens. + * + * @param size the size of the cache + */ + + public static void SetCacheSize(int size) { + if (size > 3276700) size = 3276700; + if (size <= byteCacheSize) return; + byte[][] tmpCache = new byte[size][]; + System.Array.Copy(byteCache, 0, tmpCache, 0, byteCacheSize); + byteCache = tmpCache; + byteCacheSize = size; + } + + /** + * You can fill the cache in advance if you want to. + * + * @param decimals + */ + + public static void FillCache(int decimals) { + int step = 1; + switch (decimals) { + case 0: + step = 100; + break; + case 1: + step = 10; + break; + } + for (int i = 1; i < byteCacheSize; i += step) { + if (byteCache[i] != null) continue; + byteCache[i] = ConvertToBytes(i); + } + } + + /** + * Converts an double (multiplied by 100 and cast to an int) into an array of bytes. + * + * @param i the int + * @return a bytearray + */ + + private static byte[] ConvertToBytes(int i) { + int size = (int)Math.Floor(Math.Log(i) / Math.Log(10)); + if (i % 100 != 0) { + size += 2; + } + if (i % 10 != 0) { + size++; + } + if (i < 100) { + size++; + if (i < 10) { + size++; + } + } + size--; + byte[] cache = new byte[size]; + size --; + if (i < 100) { + cache[0] = (byte)'0'; + } + if (i % 10 != 0) { + cache[size--] = bytes[i % 10]; + } + if (i % 100 != 0) { + cache[size--] = bytes[(i / 10) % 10]; + cache[size--] = (byte)'.'; + } + size = (int)Math.Floor(Math.Log(i) / Math.Log(10)) - 1; + int add = 0; + while (add < size) { + cache[add] = bytes[(i / (int)Math.Pow(10, size - add + 1)) % 10]; + add++; + } + return cache; + } + + /** + * Appends an int. The size of the array will grow by one. + * @param b the int to be appended + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append_i(int b) { + int newcount = count + 1; + if (newcount > buf.Length) { + byte[] newbuf = new byte[Math.Max(buf.Length << 1, newcount)]; + Array.Copy(buf, 0, newbuf, 0, count); + buf = newbuf; + } + buf[count] = (byte)b; + count = newcount; + return this; + } + + /** + * Appends the subarray of the byte array. The buffer will grow by + * len bytes. + * @param b the array to be appended + * @param off the offset to the start of the array + * @param len the length of bytes to Append + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append(byte[] b, int off, int len) { + if ((off < 0) || (off > b.Length) || (len < 0) || + ((off + len) > b.Length) || ((off + len) < 0) || len == 0) + return this; + int newcount = count + len; + if (newcount > buf.Length) { + byte[] newbuf = new byte[Math.Max(buf.Length << 1, newcount)]; + Array.Copy(buf, 0, newbuf, 0, count); + buf = newbuf; + } + Array.Copy(b, off, buf, count, len); + count = newcount; + return this; + } + + /** + * Appends an array of bytes. + * @param b the array to be appended + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append(byte[] b) { + return Append(b, 0, b.Length); + } + + /** + * Appends a string to the buffer. The string is + * converted according to the encoding ISO-8859-1. + * @param str the string to be appended + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append(string str) { + if (str != null) + return Append(DocWriter.GetISOBytes(str)); + return this; + } + + /** + * Appends a char to the buffer. The char is + * converted according to the encoding ISO-8859-1. + * @param c the char to be appended + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append(char c) { + return Append_i(c); + } + + /** + * Appends another ByteBuffer to this buffer. + * @param buf the ByteBuffer to be appended + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append(ByteBuffer buf) { + return Append(buf.buf, 0, buf.count); + } + + /** + * Appends the string representation of an int. + * @param i the int to be appended + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append(int i) { + return Append((double)i); + } + + public ByteBuffer Append(byte b) { + return Append_i(b); + } + + public ByteBuffer AppendHex(byte b) { + Append(bytes[(b >> 4) & 0x0f]); + return Append(bytes[b & 0x0f]); + } + + /** + * Appends a string representation of a float according + * to the Pdf conventions. + * @param i the float to be appended + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append(float i) { + return Append((double)i); + } + + /** + * Appends a string representation of a double according + * to the Pdf conventions. + * @param d the double to be appended + * @return a reference to this ByteBuffer object + */ + public ByteBuffer Append(double d) { + Append(FormatDouble(d, this)); + return this; + } + + /** + * Outputs a double into a format suitable for the PDF. + * @param d a double + * @return the string representation of the double + */ + public static string FormatDouble(double d) { + return FormatDouble(d, null); + } + + /** + * Outputs a double into a format suitable for the PDF. + * @param d a double + * @param buf a ByteBuffer + * @return the String representation of the double if + * buf is null. If buf is not null, + * then the double is appended directly to the buffer and this methods returns null. + */ + public static string FormatDouble(double d, ByteBuffer buf) { + if (HIGH_PRECISION) { + String sform = d.ToString("0.######", CultureInfo.InvariantCulture); + if (buf == null) + return sform; + else { + buf.Append(sform); + return null; + } + } + bool negative = false; + if (Math.Abs(d) < 0.000015) { + if (buf != null) { + buf.Append(ZERO); + return null; + } else { + return "0"; + } + } + if (d < 0) { + negative = true; + d = -d; + } + if (d < 1.0) { + d += 0.000005; + if (d >= 1) { + if (negative) { + if (buf != null) { + buf.Append((byte)'-'); + buf.Append((byte)'1'); + return null; + } else { + return "-1"; + } + } else { + if (buf != null) { + buf.Append((byte)'1'); + return null; + } else { + return "1"; + } + } + } + if (buf != null) { + int v = (int) (d * 100000); + + if (negative) buf.Append((byte)'-'); + buf.Append((byte)'0'); + buf.Append((byte)'.'); + + buf.Append( (byte)(v / 10000 + ZERO) ); + if (v % 10000 != 0) { + buf.Append( (byte)((v / 1000) % 10 + ZERO) ); + if (v % 1000 != 0) { + buf.Append( (byte)((v / 100) % 10 + ZERO) ); + if (v % 100 != 0) { + buf.Append((byte)((v / 10) % 10 + ZERO) ); + if (v % 10 != 0) { + buf.Append((byte)((v) % 10 + ZERO) ); + } + } + } + } + return null; + } else { + int x = 100000; + int v = (int) (d * x); + + StringBuilder res = new StringBuilder(); + if (negative) res.Append('-'); + res.Append("0."); + + while ( v < x/10 ) { + res.Append('0'); + x /= 10; + } + res.Append(v); + int cut = res.Length - 1; + while (res[cut] == '0') { + --cut; + } + res.Length = cut + 1; + return res.ToString(); + } + } else if (d <= 32767) { + d += 0.005; + int v = (int) (d * 100); + + if (v < byteCacheSize && byteCache[v] != null) { + if (buf != null) { + if (negative) buf.Append((byte)'-'); + buf.Append(byteCache[v]); + return null; + } else { + string tmp = PdfEncodings.ConvertToString(byteCache[v], null); + if (negative) tmp = "-" + tmp; + return tmp; + } + } + if (buf != null) { + if (v < byteCacheSize) { + //create the cachebyte[] + byte[] cache; + int size = 0; + if (v >= 1000000) { + //the original number is >=10000, we need 5 more bytes + size += 5; + } else if (v >= 100000) { + //the original number is >=1000, we need 4 more bytes + size += 4; + } else if (v >= 10000) { + //the original number is >=100, we need 3 more bytes + size += 3; + } else if (v >= 1000) { + //the original number is >=10, we need 2 more bytes + size += 2; + } else if (v >= 100) { + //the original number is >=1, we need 1 more bytes + size += 1; + } + + //now we must check if we have a decimal number + if (v % 100 != 0) { + //yes, do not forget the "." + size += 2; + } + if (v % 10 != 0) { + size++; + } + cache = new byte[size]; + int add = 0; + if (v >= 1000000) { + cache[add++] = bytes[(v / 1000000)]; + } + if (v >= 100000) { + cache[add++] = bytes[(v / 100000) % 10]; + } + if (v >= 10000) { + cache[add++] = bytes[(v / 10000) % 10]; + } + if (v >= 1000) { + cache[add++] = bytes[(v / 1000) % 10]; + } + if (v >= 100) { + cache[add++] = bytes[(v / 100) % 10]; + } + + if (v % 100 != 0) { + cache[add++] = (byte)'.'; + cache[add++] = bytes[(v / 10) % 10]; + if (v % 10 != 0) { + cache[add++] = bytes[v % 10]; + } + } + byteCache[v] = cache; + } + + if (negative) buf.Append((byte)'-'); + if (v >= 1000000) { + buf.Append( bytes[(v / 1000000)] ); + } + if (v >= 100000) { + buf.Append( bytes[(v / 100000) % 10] ); + } + if (v >= 10000) { + buf.Append( bytes[(v / 10000) % 10] ); + } + if (v >= 1000) { + buf.Append( bytes[(v / 1000) % 10] ); + } + if (v >= 100) { + buf.Append( bytes[(v / 100) % 10] ); + } + + if (v % 100 != 0) { + buf.Append((byte)'.'); + buf.Append( bytes[(v / 10) % 10] ); + if (v % 10 != 0) { + buf.Append( bytes[v % 10] ); + } + } + return null; + } else { + StringBuilder res = new StringBuilder(); + if (negative) res.Append('-'); + if (v >= 1000000) { + res.Append( chars[(v / 1000000)] ); + } + if (v >= 100000) { + res.Append( chars[(v / 100000) % 10] ); + } + if (v >= 10000) { + res.Append( chars[(v / 10000) % 10] ); + } + if (v >= 1000) { + res.Append( chars[(v / 1000) % 10] ); + } + if (v >= 100) { + res.Append( chars[(v / 100) % 10] ); + } + + if (v % 100 != 0) { + res.Append('.'); + res.Append( chars[(v / 10) % 10] ); + if (v % 10 != 0) { + res.Append( chars[v % 10] ); + } + } + return res.ToString(); + } + } else { + StringBuilder res = new StringBuilder(); + if (negative) res.Append('-'); + d += 0.5; + long v = (long) d; + return res.Append(v).ToString(); + } + } + + /** + * Sets the size to zero. + */ + public void Reset() { + count = 0; + } + + /** + * Creates a newly allocated byte array. Its size is the current + * size of this output stream and the valid contents of the buffer + * have been copied into it. + * + * @return the current contents of this output stream, as a byte array. + */ + public byte[] ToByteArray() { + byte[] newbuf = new byte[count]; + Array.Copy(buf, 0, newbuf, 0, count); + return newbuf; + } + + /** + * Returns the current size of the buffer. + * + * @return the value of the count field, which is the number of valid bytes in this byte buffer. + */ + public int Size { + get { + return count; + } + set { + if (value > count || value < 0) + throw new ArgumentOutOfRangeException("The new size must be positive and <= of the current size"); + count = value; + } + } + + /** + * Converts the buffer's contents into a string, translating bytes into + * characters according to the platform's default character encoding. + * + * @return string translated from the buffer's contents. + */ + public override string ToString() { + char[] tmp = this.ConvertToChar(buf); + return new String(tmp, 0, count); + } + + /** + * Converts the buffer's contents into a string, translating bytes into + * characters according to the specified character encoding. + * + * @param enc a character-encoding name. + * @return string translated from the buffer's contents. + * @throws UnsupportedEncodingException + * If the named encoding is not supported. + */ +// public string ToString(System.Text.Encoding enc) { +// return new String(ref buf, 0, count, enc); +// } + + /** + * Writes the complete contents of this byte buffer output to + * the specified output stream argument, as if by calling the output + * stream's write method using out.Write(buf, 0, count). + * + * @param out the output stream to which to write the data. + * @exception IOException if an I/O error occurs. + */ + public void WriteTo(Stream str) { + str.Write(buf, 0, count); + } + + private char[] ConvertToChar(byte[] buf) { + char[] retVal = new char[count + 1]; + for (int i = 0; i <= count; i++) { + retVal[i] = (char)buf[i]; + } + return retVal; + } + + public byte[] Buffer { + get { + return buf; + } + } + + public override bool CanRead { + get { + return false; + } + } + + public override bool CanSeek { + get { + return false; + } + } + + public override bool CanWrite { + get { + return true; + } + } + + public override long Length { + get { + return count; + } + } + + public override long Position { + get { + return count; + } + set { + } + } + + public override void Flush() { + } + + public override int Read(byte[] buffer, int offset, int count) { + return 0; + } + + public override long Seek(long offset, SeekOrigin origin) { + return 0; + } + + public override void SetLength(long value) { + } + + public override void Write(byte[] buffer, int offset, int count) { + Append(buffer, offset, count); + } + + public override void WriteByte(byte value) { + Append(value); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/CFFFont.cs b/iTechSharp/iTextSharp/text/pdf/CFFFont.cs new file mode 100644 index 0000000..4062617 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/CFFFont.cs @@ -0,0 +1,1111 @@ +using System; +using System.Text; +using System.Collections; +/* + * + * Copyright 2003 Sivan Toledo + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + */ + +namespace iTextSharp.text.pdf { + public class CFFFont { + + internal static String[] operatorNames = { + "version", "Notice", "FullName", "FamilyName", + "Weight", "FontBBox", "BlueValues", "OtherBlues", + "FamilyBlues", "FamilyOtherBlues", "StdHW", "StdVW", + "UNKNOWN_12", "UniqueID", "XUID", "charset", + "Encoding", "CharStrings", "Private", "Subrs", + "defaultWidthX", "nominalWidthX", "UNKNOWN_22", "UNKNOWN_23", + "UNKNOWN_24", "UNKNOWN_25", "UNKNOWN_26", "UNKNOWN_27", + "UNKNOWN_28", "UNKNOWN_29", "UNKNOWN_30", "UNKNOWN_31", + "Copyright", "isFixedPitch", "ItalicAngle", "UnderlinePosition", + "UnderlineThickness", "PaintType", "CharstringType", "FontMatrix", + "StrokeWidth", "BlueScale", "BlueShift", "BlueFuzz", + "StemSnapH", "StemSnapV", "ForceBold", "UNKNOWN_12_15", + "UNKNOWN_12_16", "LanguageGroup", "ExpansionFactor", "initialRandomSeed", + "SyntheticBase", "PostScript", "BaseFontName", "BaseFontBlend", + "UNKNOWN_12_24", "UNKNOWN_12_25", "UNKNOWN_12_26", "UNKNOWN_12_27", + "UNKNOWN_12_28", "UNKNOWN_12_29", "ROS", "CIDFontVersion", + "CIDFontRevision", "CIDFontType", "CIDCount", "UIDBase", + "FDArray", "FDSelect", "FontName" + }; + + internal static String[] standardStrings = { + // Automatically generated from Appendix A of the CFF specification; do + // not edit. Size should be 391. + ".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", + "percent", "ampersand", "quoteright", "parenleft", "parenright", + "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", + "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", + "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", + "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", + "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", + "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c", + "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", + "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", + "asciitilde", "exclamdown", "cent", "sterling", "fraction", "yen", + "florin", "section", "currency", "quotesingle", "quotedblleft", + "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", "endash", + "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet", + "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", + "ellipsis", "perthousand", "questiondown", "grave", "acute", "circumflex", + "tilde", "macron", "breve", "dotaccent", "dieresis", "ring", "cedilla", + "hungarumlaut", "ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash", + "Oslash", "OE", "ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe", + "germandbls", "onesuperior", "logicalnot", "mu", "trademark", "Eth", + "onehalf", "plusminus", "Thorn", "onequarter", "divide", "brokenbar", + "degree", "thorn", "threequarters", "twosuperior", "registered", "minus", + "eth", "multiply", "threesuperior", "copyright", "Aacute", "Acircumflex", + "Adieresis", "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute", + "Ecircumflex", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", + "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", "Ograve", + "Otilde", "Scaron", "Uacute", "Ucircumflex", "Udieresis", "Ugrave", + "Yacute", "Ydieresis", "Zcaron", "aacute", "acircumflex", "adieresis", + "agrave", "aring", "atilde", "ccedilla", "eacute", "ecircumflex", + "edieresis", "egrave", "iacute", "icircumflex", "idieresis", "igrave", + "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde", + "scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", + "ydieresis", "zcaron", "exclamsmall", "Hungarumlautsmall", + "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", + "parenleftsuperior", "parenrightsuperior", "twodotenleader", + "onedotenleader", "zerooldstyle", "oneoldstyle", "twooldstyle", + "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", + "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior", + "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", + "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", + "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", + "ssuperior", "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", + "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", + "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", + "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", + "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", + "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", + "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", "centoldstyle", + "Lslashsmall", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", + "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash", + "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", + "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths", + "seveneighths", "onethird", "twothirds", "zerosuperior", "foursuperior", + "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", + "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", + "threeinferior", "fourinferior", "fiveinferior", "sixinferior", + "seveninferior", "eightinferior", "nineinferior", "centinferior", + "dollarinferior", "periodinferior", "commainferior", "Agravesmall", + "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", + "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", + "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", + "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", + "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", + "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", + "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", + "Ydieresissmall", "001.000", "001.001", "001.002", "001.003", "Black", + "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold" + }; + + //private String[] strings; + public String GetString(char sid) { + if (sid < standardStrings.Length) return standardStrings[sid]; + if (sid >= standardStrings.Length+(stringOffsets.Length-1)) return null; + int j = sid - standardStrings.Length; + int p = GetPosition(); + Seek(stringOffsets[j]); + StringBuilder s = new StringBuilder(); + for (int k=stringOffsets[j]; k count in the index header. 1->offset size in index header + + 2+1 + //offset array size * offset size + + (count+1)*indexOffSize + //???zero <-> one base + - 1 + // read object offset relative to object array base + + GetOffset(indexOffSize); + } + //nextIndexOffset = offsets[count]; + return offsets; + } + + protected String key; + protected Object[] args = new Object[48]; + protected int arg_count = 0; + + protected void GetDictItem() { + for (int i=0; i= 32 && b0 <= 246) { + sbyte item = (sbyte) ((int)b0-139); + args[arg_count] = (int)item; + arg_count++; + //System.err.Println(item+" "); + continue; + } + if (b0 >= 247 && b0 <= 250) { + char b1 = GetCard8(); + short item = (short) (((int)b0-247)*256+(int)b1+108); + args[arg_count] = (int)item; + arg_count++; + //System.err.Println(item+" "); + continue; + } + if (b0 >= 251 && b0 <= 254) { + char b1 = GetCard8(); + short item = (short) (-((int)b0-251)*256-(int)b1-108); + args[arg_count] = (int)item; + arg_count++; + //System.err.Println(item+" "); + continue; + } + if (b0 == 30) { + String item = ""; + bool done = false; + char buffer = (char)0; + byte avail = 0; + int nibble = 0; + while (!done) { + // get a nibble + if (avail==0) { buffer = GetCard8(); avail=2; } + if (avail==1) { nibble = (buffer / 16); avail--; } + if (avail==2) { nibble = (buffer % 16); avail--; } + switch (nibble) { + case 0xa: item += "." ; break; + case 0xb: item += "E" ; break; + case 0xc: item += "E-"; break; + case 0xe: item += "-" ; break; + case 0xf: done=true ; break; + default: + if (nibble >= 0 && nibble <= 9) + item += nibble.ToString(); + else { + item += ""; + done = true; + } + break; + } + } + args[arg_count] = item; + arg_count++; + //System.err.Println(" real=["+item+"]"); + continue; + } + if (b0 <= 21) { + gotKey=true; + if (b0 != 12) key = operatorNames[b0]; + else key = operatorNames[32 + GetCard8()]; + //for (int i=0; i> 24) & 0xff); + i++; + goto case 3; + case 3: + buffer[myOffset+i] = (byte) ((value >> 16) & 0xff); + i++; + goto case 2; + case 2: + buffer[myOffset+i] = (byte) ((value >> 8) & 0xff); + i++; + goto case 1; + case 1: + buffer[myOffset+i] = (byte) ((value >> 0) & 0xff); + i++; + break; + } + /* + int mask = 0xff; + for (int i=size-1; i>=0; i--) { + buffer[myOffset+i] = (byte) (value & mask); + mask <<= 8; + } + */ + } + } + + protected internal class IndexBaseItem : Item { + public IndexBaseItem() {} + } + + protected internal class IndexMarkerItem : Item { + private OffsetItem offItem; + private IndexBaseItem indexBase; + public IndexMarkerItem(OffsetItem offItem, IndexBaseItem indexBase) { + this.offItem = offItem; + this.indexBase = indexBase; + } + public override void Xref() { + //System.err.Println("index marker item, base="+indexBase.myOffset+" my="+this.myOffset); + offItem.Set(this.myOffset-indexBase.myOffset+1); + } + } + /** + * + * @author orly manor + * + * TODO To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ + protected internal class SubrMarkerItem : Item { + private OffsetItem offItem; + private IndexBaseItem indexBase; + public SubrMarkerItem(OffsetItem offItem, IndexBaseItem indexBase) { + this.offItem = offItem; + this.indexBase = indexBase; + } + public override void Xref() { + //System.err.Println("index marker item, base="+indexBase.myOffset+" my="+this.myOffset); + offItem.Set(this.myOffset-indexBase.myOffset); + } + } + + + /** an unknown offset in a dictionary for the list. + * We will fix up the offset later; for now, assume it's large. + */ + protected internal class DictOffsetItem : OffsetItem { + public int size; + public DictOffsetItem() {this.size=5; } + + public override void Increment(int[] currentOffset) { + base.Increment(currentOffset); + currentOffset[0] += size; + } + // this is incomplete! + public override void Emit(byte[] buffer) { + if (size==5) { + buffer[myOffset] = 29; + buffer[myOffset+1] = (byte) ((value >> 24) & 0xff); + buffer[myOffset+2] = (byte) ((value >> 16) & 0xff); + buffer[myOffset+3] = (byte) ((value >> 8) & 0xff); + buffer[myOffset+4] = (byte) ((value >> 0) & 0xff); + } + } + } + + /** Card24 item. + */ + + protected internal class UInt24Item : Item { + public int value; + public UInt24Item(int value) {this.value=value;} + + public override void Increment(int[] currentOffset) { + base.Increment(currentOffset); + currentOffset[0] += 3; + } + // this is incomplete! + public override void Emit(byte[] buffer) { + buffer[myOffset+0] = (byte) ((value >> 16) & 0xff); + buffer[myOffset+1] = (byte) ((value >> 8) & 0xff); + buffer[myOffset+2] = (byte) ((value >> 0) & 0xff); + } + } + + /** Card32 item. + */ + + protected internal class UInt32Item : Item { + public int value; + public UInt32Item(int value) {this.value=value;} + + public override void Increment(int[] currentOffset) { + base.Increment(currentOffset); + currentOffset[0] += 4; + } + // this is incomplete! + public override void Emit(byte[] buffer) { + buffer[myOffset+0] = (byte) ((value >> 24) & 0xff); + buffer[myOffset+1] = (byte) ((value >> 16) & 0xff); + buffer[myOffset+2] = (byte) ((value >> 8) & 0xff); + buffer[myOffset+3] = (byte) ((value >> 0) & 0xff); + } + } + + /** A SID or Card16 item. + */ + + protected internal class UInt16Item : Item { + public char value; + public UInt16Item(char value) {this.value=value;} + + public override void Increment(int[] currentOffset) { + base.Increment(currentOffset); + currentOffset[0] += 2; + } + // this is incomplete! + public override void Emit(byte[] buffer) { + buffer[myOffset+0] = (byte) ((value >> 8) & 0xff); + buffer[myOffset+1] = (byte) ((value >> 0) & 0xff); + } + } + + /** A Card8 item. + */ + + protected internal class UInt8Item : Item { + public char value; + public UInt8Item(char value) {this.value=value;} + + public override void Increment(int[] currentOffset) { + base.Increment(currentOffset); + currentOffset[0] += 1; + } + // this is incomplete! + public override void Emit(byte[] buffer) { + buffer[myOffset+0] = (byte) ((value >> 0) & 0xff); + } + } + + protected internal class StringItem : Item { + public String s; + public StringItem(String s) {this.s=s;} + + public override void Increment(int[] currentOffset) { + base.Increment(currentOffset); + currentOffset[0] += s.Length; + } + public override void Emit(byte[] buffer) { + for (int i=0; i> 24) & 0xff); + buffer[myOffset+2] = (byte) ((value >> 16) & 0xff); + buffer[myOffset+3] = (byte) ((value >> 8) & 0xff); + buffer[myOffset+4] = (byte) ((value >> 0) & 0xff); + } + } + } + + /** An offset-marker item for the list. + * It is used to mark an offset and to set the offset list item. + */ + + protected internal class MarkerItem : Item { + OffsetItem p; + public MarkerItem(OffsetItem pointerToMarker) {p=pointerToMarker;} + public override void Xref() { + p.Set(this.myOffset); + } + } + + /** a utility that creates a range item for an entire index + * + * @param indexOffset where the index is + * @return a range item representing the entire index + */ + + protected virtual RangeItem GetEntireIndexRange(int indexOffset) { + Seek(indexOffset); + int count = GetCard16(); + if (count==0) { + return new RangeItem(buf,indexOffset,2); + } else { + int indexOffSize = GetCard8(); + Seek(indexOffset+2+1+count*indexOffSize); + int size = GetOffset(indexOffSize)-1; + return new RangeItem(buf,indexOffset, + 2+1+(count+1)*indexOffSize+size); + } + } + + + /** get a single CID font. The PDF architecture (1.4) + * supports 16-bit strings only with CID CFF fonts, not + * in Type-1 CFF fonts, so we convert the font to CID if + * it is in the Type-1 format. + * Two other tasks that we need to do are to select + * only a single font from the CFF package (this again is + * a PDF restriction) and to subset the CharStrings glyph + * description. + */ + + + public byte[] GetCID(String fontName) + //throws java.io.FileNotFoundException + { + int j; + for (j=0; j 127) + fdFontName = fdFontName.Substring(0,127); + String extraStrings = "Adobe"+"Identity"+fdFontName; + + int origStringsLen = stringOffsets[stringOffsets.Length-1] + - stringOffsets[0]; + int stringsBaseOffset = stringOffsets[0]-1; + + byte stringsIndexOffSize; + if (origStringsLen+extraStrings.Length <= 0xff) stringsIndexOffSize = 1; + else if (origStringsLen+extraStrings.Length <= 0xffff) stringsIndexOffSize = 2; + else if (origStringsLen+extraStrings.Length <= 0xffffff) stringsIndexOffSize = 3; + else stringsIndexOffSize = 4; + + l.Add(new UInt16Item((char)((stringOffsets.Length-1)+3))); // count + l.Add(new UInt8Item((char)stringsIndexOffSize)); // offSize + for (int i=0; i= 0) { + //System.err.Println("has subrs="+fonts[j].privateSubrs+" ,len="+fonts[j].privateLength); + l.Add(GetEntireIndexRange(fonts[j].privateSubrs)); + } + } + + // copy the charstring index + + l.Add(new MarkerItem(charstringsRef)); + l.Add(GetEntireIndexRange(fonts[j].charstringsOffset)); + + // now create the new CFF font + + int[] currentOffset = new int[1]; + currentOffset[0] = 0; + + foreach (Item item in l) { + item.Increment(currentOffset); + } + + foreach (Item item in l) { + item.Xref(); + } + + int size = currentOffset[0]; + byte[] b = new byte[size]; + + foreach (Item item in l) { + item.Emit(b); + } + + return b; + } + + + public bool IsCID(String fontName) { + int j; + for (j=0; j"); + } + + // string index + + //strings = new String[stringOffsets.length-1]; + /* + System.err.Println("std strings = "+standardStrings.length); + System.err.Println("fnt strings = "+(stringOffsets.length-1)); + for (char j=0; j"); + } + */ + + // top dict + + for (int j=0; j= 0) { + //System.err.Println("PRIVATE::"); + Seek(fonts[j].privateOffset); + while (GetPosition() < fonts[j].privateOffset+fonts[j].privateLength) { + GetDictItem(); + if (key=="Subrs") + //Add the private offset to the lsubrs since the offset is + // relative to the begining of the PrivateDict + fonts[j].privateSubrs = (int)args[0]+fonts[j].privateOffset; + } + } + + // fdarray index + if (fonts[j].fdarrayOffset >= 0) { + int[] fdarrayOffsets = GetIndex(fonts[j].fdarrayOffset); + + fonts[j].fdprivateOffsets = new int[fdarrayOffsets.Length-1]; + fonts[j].fdprivateLengths = new int[fdarrayOffsets.Length-1]; + + //System.err.Println("FD Font::"); + + for (int k=0; k + * @author Oren Manor & Ygal Blum + */ + public class CFFFontSubset : CFFFont { + + /** + * The Strings in this array represent Type1/Type2 operator names + */ + internal static String[] SubrsFunctions = { + "RESERVED_0","hstem","RESERVED_2","vstem","vmoveto","rlineto","hlineto","vlineto", + "rrcurveto","RESERVED_9","callsubr","return","escape","RESERVED_13", + "endchar","RESERVED_15","RESERVED_16","RESERVED_17","hstemhm","hintmask", + "cntrmask","rmoveto","hmoveto","vstemhm","rcurveline","rlinecurve","vvcurveto", + "hhcurveto","shortint","callgsubr","vhcurveto","hvcurveto" + }; + /** + * The Strings in this array represent Type1/Type2 escape operator names + */ + internal static String[] SubrsEscapeFuncs = { + "RESERVED_0","RESERVED_1","RESERVED_2","and","or","not","RESERVED_6", + "RESERVED_7","RESERVED_8","abs","add","sub","div","RESERVED_13","neg", + "eq","RESERVED_16","RESERVED_17","drop","RESERVED_19","put","get","ifelse", + "random","mul","RESERVED_25","sqrt","dup","exch","index","roll","RESERVED_31", + "RESERVED_32","RESERVED_33","hflex","flex","hflex1","flex1","RESERVED_REST" + }; + + /** + * A HashMap containing the glyphs used in the text after being converted + * to glyph number by the CMap + */ + internal Hashtable GlyphsUsed; + /** + * The GlyphsUsed keys as an ArrayList + */ + internal ArrayList glyphsInList; + /** + * A HashMap for keeping the FDArrays being used by the font + */ + internal Hashtable FDArrayUsed = new Hashtable(); + /** + * A HashMaps array for keeping the subroutines used in each FontDict + */ + internal Hashtable[] hSubrsUsed; + /** + * The SubroutinesUsed HashMaps as ArrayLists + */ + internal ArrayList[] lSubrsUsed; + /** + * A HashMap for keeping the Global subroutines used in the font + */ + internal Hashtable hGSubrsUsed = new Hashtable(); + /** + * The Global SubroutinesUsed HashMaps as ArrayLists + */ + internal ArrayList lGSubrsUsed = new ArrayList(); + /** + * A HashMap for keeping the subroutines used in a non-cid font + */ + internal Hashtable hSubrsUsedNonCID = new Hashtable(); + /** + * The SubroutinesUsed HashMap as ArrayList + */ + internal ArrayList lSubrsUsedNonCID = new ArrayList(); + /** + * An array of the new Indexs for the local Subr. One index for each FontDict + */ + internal byte[][] NewLSubrsIndex; + /** + * The new subroutines index for a non-cid font + */ + internal byte[] NewSubrsIndexNonCID; + /** + * The new global subroutines index of the font + */ + internal byte[] NewGSubrsIndex; + /** + * The new CharString of the font + */ + internal byte[] NewCharStringsIndex; + + /** + * The bias for the global subroutines + */ + internal int GBias = 0; + + /** + * The linked list for generating the new font stream + */ + internal ArrayList OutputList; + + /** + * Number of arguments to the stem operators in a subroutine calculated recursivly + */ + internal int NumOfHints=0; + + + /** + * C'tor for CFFFontSubset + * @param rf - The font file + * @param GlyphsUsed - a HashMap that contains the glyph used in the subset + */ + public CFFFontSubset(RandomAccessFileOrArray rf,Hashtable GlyphsUsed) : base(rf) { + // Use CFFFont c'tor in order to parse the font file. + this.GlyphsUsed = GlyphsUsed; + //Put the glyphs into a list + glyphsInList = new ArrayList(GlyphsUsed.Keys); + + + for (int i=0;i=0) + { + // Proces the FDSelect + ReadFDSelect(i); + // Build the FDArrayUsed hashmap + BuildFDArrayUsed(i); + } + if (fonts[i].isCID) + // Build the FD Array used Hash Map + ReadFDArray(i); + // compute the charset length + fonts[i].CharsetLength = CountCharset(fonts[i].charsetOffset,fonts[i].nglyphs); + } + } + + /** + * Calculates the length of the charset according to its format + * @param Offset The Charset Offset + * @param NumofGlyphs Number of glyphs in the font + * @return the length of the Charset + */ + internal int CountCharset(int Offset,int NumofGlyphs){ + int format; + int Length=0; + Seek(Offset); + // Read the format + format = GetCard8(); + // Calc according to format + switch (format){ + case 0: + Length = 1+2*NumofGlyphs; + break; + case 1: + Length = 1+3*CountRange(NumofGlyphs,1); + break; + case 2: + Length = 1+4*CountRange(NumofGlyphs,2); + break; + default: + break; + } + return Length; + } + + /** + * Function calculates the number of ranges in the Charset + * @param NumofGlyphs The number of glyphs in the font + * @param Type The format of the Charset + * @return The number of ranges in the Charset data structure + */ + int CountRange(int NumofGlyphs,int Type){ + int num=0; + char Sid; + int i=1,nLeft; + while (i= 0) + GBias = CalcBias(gsubrIndexOffset,j); + + // Prepare the new CharStrings Index + BuildNewCharString(j); + // Prepare the new Global and Local Subrs Indices + BuildNewLGSubrs(j); + // Build the new file + byte[] Ret = BuildNewFile(j); + return Ret; + } + finally { + try { + buf.Close(); + } + catch { + // empty on purpose + } + } + } + + /** + * Function calcs bias according to the CharString type and the count + * of the subrs + * @param Offset The offset to the relevent subrs index + * @param Font the font + * @return The calculated Bias + */ + protected int CalcBias(int Offset,int Font) + { + Seek(Offset); + int nSubrs = GetCard16(); + // If type==1 -> bias=0 + if (fonts[Font].CharstringType == 1) + return 0; + // else calc according to the count + else if (nSubrs < 1240) + return 107; + else if (nSubrs < 33900) + return 1131; + else + return 32768; + } + + /** + *Function uses BuildNewIndex to create the new index of the subset charstrings + * @param FontIndex the font + * @throws IOException + */ + protected void BuildNewCharString(int FontIndex) + { + NewCharStringsIndex = BuildNewIndex(fonts[FontIndex].charstringsOffsets,GlyphsUsed); + } + + /** + * Function builds the new local & global subsrs indices. IF CID then All of + * the FD Array lsubrs will be subsetted. + * @param Font the font + * @throws IOException + */ + protected void BuildNewLGSubrs(int Font) + { + // If the font is CID then the lsubrs are divided into FontDicts. + // for each FD array the lsubrs will be subsetted. + if (fonts[Font].isCID) + { + // Init the hasmap-array and the arraylist-array to hold the subrs used + // in each private dict. + hSubrsUsed = new Hashtable[fonts[Font].fdprivateOffsets.Length]; + lSubrsUsed = new ArrayList[fonts[Font].fdprivateOffsets.Length]; + // A [][] which will store the byte array for each new FD Array lsubs index + NewLSubrsIndex = new byte[fonts[Font].fdprivateOffsets.Length][]; + // An array to hold the offset for each Lsubr index + fonts[Font].PrivateSubrsOffset = new int[fonts[Font].fdprivateOffsets.Length]; + // A [][] which will store the offset array for each lsubr index + fonts[Font].PrivateSubrsOffsetsArray = new int[fonts[Font].fdprivateOffsets.Length][]; + + // Put the FDarrayUsed into a list + ArrayList FDInList = new ArrayList(FDArrayUsed.Keys); + // For each FD array which is used subset the lsubr + for (int j=0;j=0) + { + //Scans the Charsting data storing the used Local and Global subroutines + // by the glyphs. Scans the Subrs recursivley. + BuildSubrUsed(Font,FD,fonts[Font].PrivateSubrsOffset[FD],fonts[Font].PrivateSubrsOffsetsArray[FD],hSubrsUsed[FD],lSubrsUsed[FD]); + // Builds the New Local Subrs index + NewLSubrsIndex[FD] = BuildNewIndex(fonts[Font].PrivateSubrsOffsetsArray[FD],hSubrsUsed[FD]); + } + } + } + // If the font is not CID && the Private Subr exists then subset: + else if (fonts[Font].privateSubrs>=0) + { + // Build the subrs offsets; + fonts[Font].SubrsOffsets = GetIndex(fonts[Font].privateSubrs); + //Scans the Charsting data storing the used Local and Global subroutines + // by the glyphs. Scans the Subrs recursivley. + BuildSubrUsed(Font,-1,fonts[Font].privateSubrs,fonts[Font].SubrsOffsets,hSubrsUsedNonCID,lSubrsUsedNonCID); + } + // For all fonts susbset the Global Subroutines + // Scan the Global Subr Hashmap recursivly on the Gsubrs + BuildGSubrsUsed(Font); + if (fonts[Font].privateSubrs>=0) + // Builds the New Local Subrs index + NewSubrsIndexNonCID = BuildNewIndex(fonts[Font].SubrsOffsets,hSubrsUsedNonCID); + //Builds the New Global Subrs index + NewGSubrsIndex = BuildNewIndex(gsubrOffsets,hGSubrsUsed); + } + + /** + * The function finds for the FD array processed the local subr offset and its + * offset array. + * @param Font the font + * @param FD The FDARRAY processed + */ + protected void BuildFDSubrsOffsets(int Font,int FD) + { + // Initiate to -1 to indicate lsubr operator present + fonts[Font].PrivateSubrsOffset[FD] = -1; + // Goto begining of objects + Seek(fonts[Font].fdprivateOffsets[FD]); + // While in the same object: + while (GetPosition() < fonts[Font].fdprivateOffsets[FD]+fonts[Font].fdprivateLengths[FD]) + { + GetDictItem(); + // If the dictItem is the "Subrs" then find and store offset, + if (key=="Subrs") + fonts[Font].PrivateSubrsOffset[FD] = (int)args[0]+fonts[Font].fdprivateOffsets[FD]; + } + //Read the lsub index if the lsubr was found + if (fonts[Font].PrivateSubrsOffset[FD] >= 0) + fonts[Font].PrivateSubrsOffsetsArray[FD] = GetIndex(fonts[Font].PrivateSubrsOffset[FD]); + } + + /** + * Function uses ReadAsubr on the glyph used to build the LSubr & Gsubr HashMap. + * The HashMap (of the lsub only) is then scaned recursivly for Lsubr & Gsubrs + * calls. + * @param Font the font + * @param FD FD array processed. 0 indicates function was called by non CID font + * @param SubrOffset the offset to the subr index to calc the bias + * @param SubrsOffsets the offset array of the subr index + * @param hSubr HashMap of the subrs used + * @param lSubr ArrayList of the subrs used + */ + protected void BuildSubrUsed(int Font,int FD,int SubrOffset,int[] SubrsOffsets,Hashtable hSubr,ArrayList lSubr) + { + + // Calc the Bias for the subr index + int LBias = CalcBias(SubrOffset,Font); + + // For each glyph used find its GID, start & end pos + for (int i=0;i= 0) + { + EmptyStack(); + NumOfHints=0; + // Using FDSELECT find the FD Array the glyph belongs to. + int GlyphFD = fonts[Font].FDSelect[glyph]; + // If the Glyph is part of the FD being processed + if (GlyphFD == FD) + // Find the Subrs called by the glyph and insert to hash: + ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets); + } + else + // If the font is not CID + //Find the Subrs called by the glyph and insert to hash: + ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets); + } + // For all Lsubrs used, check recusrivly for Lsubr & Gsubr used + for (int i=0;i=0) + { + // Read and process the subr + int Start = SubrsOffsets[Subr]; + int End = SubrsOffsets[Subr+1]; + ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets); + } + } + } + + /** + * Function scans the Glsubr used ArrayList to find recursive calls + * to Gsubrs and adds to Hashmap & ArrayList + * @param Font the font + */ + protected void BuildGSubrsUsed(int Font) + { + int LBias = 0; + int SizeOfNonCIDSubrsUsed = 0; + if (fonts[Font].privateSubrs>=0) + { + LBias = CalcBias(fonts[Font].privateSubrs,Font); + SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.Count; + } + + // For each global subr used + for (int i=0;i=0) + { + // Read the subr and process + int Start = gsubrOffsets[Subr]; + int End = gsubrOffsets[Subr+1]; + + if (fonts[Font].isCID) + ReadASubr(Start,End,GBias,0,hGSubrsUsed,lGSubrsUsed,null); + else + { + ReadASubr(Start,End,GBias,LBias,hSubrsUsedNonCID,lSubrsUsedNonCID,fonts[Font].SubrsOffsets); + if (SizeOfNonCIDSubrsUsed < lSubrsUsedNonCID.Count) + { + for (int j=SizeOfNonCIDSubrsUsed;j=0) + { + // Read the subr and process + int LStart = fonts[Font].SubrsOffsets[LSubr]; + int LEnd = fonts[Font].SubrsOffsets[LSubr+1]; + ReadASubr(LStart,LEnd,GBias,LBias,hSubrsUsedNonCID,lSubrsUsedNonCID,fonts[Font].SubrsOffsets); + } + } + SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.Count; + } + } + } + } + } + + /** + * The function reads a subrs (glyph info) between begin and end. + * Adds calls to a Lsubr to the hSubr and lSubrs. + * Adds calls to a Gsubr to the hGSubr and lGSubrs. + * @param begin the start point of the subr + * @param end the end point of the subr + * @param GBias the bias of the Global Subrs + * @param LBias the bias of the Local Subrs + * @param hSubr the HashMap for the lSubrs + * @param lSubr the ArrayList for the lSubrs + */ + protected void ReadASubr(int begin,int end,int GBias,int LBias,Hashtable hSubr,ArrayList lSubr,int[] LSubrsOffsets) + { + // Clear the stack for the subrs + EmptyStack(); + NumOfHints = 0; + // Goto begining of the subr + Seek(begin); + while (GetPosition() < end) + { + // Read the next command + ReadCommand(); + int pos = GetPosition(); + Object TopElement=null; + if (arg_count > 0) + TopElement = args[arg_count-1]; + int NumOfArgs = arg_count; + // Check the modification needed on the Argument Stack according to key; + HandelStack(); + // a call to a Lsubr + if (key=="callsubr") + { + // Verify that arguments are passed + if (NumOfArgs > 0) + { + // Calc the index of the Subrs + int Subr = (int)TopElement + LBias; + // If the subr isn't in the HashMap -> Put in + if (!hSubr.ContainsKey(Subr)) + { + hSubr[Subr] = null; + lSubr.Add(Subr); + } + CalcHints(LSubrsOffsets[Subr],LSubrsOffsets[Subr+1],LBias,GBias,LSubrsOffsets); + Seek(pos); + } + } + // a call to a Gsubr + else if (key=="callgsubr") + { + // Verify that arguments are passed + if (NumOfArgs > 0) + { + // Calc the index of the Subrs + int Subr = (int)TopElement + GBias; + // If the subr isn't in the HashMap -> Put in + if (!hGSubrsUsed.ContainsKey(Subr)) + { + hGSubrsUsed[Subr] = null; + lGSubrsUsed.Add(Subr); + } + CalcHints(gsubrOffsets[Subr],gsubrOffsets[Subr+1],LBias,GBias,LSubrsOffsets); + Seek(pos); + } + } + // A call to "stem" + else if (key == "hstem" || key == "vstem" || key == "hstemhm" || key == "vstemhm") + // Increment the NumOfHints by the number couples of of arguments + NumOfHints += NumOfArgs/2; + // A call to "mask" + else if (key == "hintmask" || key == "cntrmask") + { + // Compute the size of the mask + int SizeOfMask = NumOfHints/8; + if (NumOfHints%8 != 0 || SizeOfMask == 0) + SizeOfMask++; + // Continue the pointer in SizeOfMask steps + for (int i=0;i flush the stack + */ + protected int StackOpp() + { + if (key == "ifelse") + return -3; + if (key == "roll" || key == "put") + return -2; + if (key == "callsubr" || key == "callgsubr" || key == "add" || key == "sub" || + key == "div" || key == "mul" || key == "drop" || key == "and" || + key == "or" || key == "eq") + return -1; + if (key == "abs" || key == "neg" || key == "sqrt" || key == "exch" || + key == "index" || key == "get" || key == "not" || key == "return") + return 0; + if (key == "random" || key == "dup") + return 1; + return 2; + } + + /** + * Empty the Type2 Stack + * + */ + protected void EmptyStack() + { + // Null the arguments + for (int i=0; i0) + { + args[arg_count-1]=null; + arg_count--; + } + } + + /** + * Add an item to the stack + * + */ + protected void PushStack() + { + arg_count++; + } + + /** + * The function reads the next command after the file pointer is set + */ + protected void ReadCommand() + { + key = null; + bool gotKey = false; + // Until a key is found + while (!gotKey) { + // Read the first Char + char b0 = GetCard8(); + // decode according to the type1/type2 format + if (b0 == 28) // the two next bytes represent a short int; + { + int first = GetCard8(); + int second = GetCard8(); + args[arg_count] = first<<8 | second; + arg_count++; + continue; + } + if (b0 >= 32 && b0 <= 246) // The byte read is the byte; + { + args[arg_count] = (int)b0 - 139; + arg_count++; + continue; + } + if (b0 >= 247 && b0 <= 250) // The byte read and the next byte constetute a short int + { + int w = GetCard8(); + args[arg_count] = ((int)b0-247)*256 + w + 108; + arg_count++; + continue; + } + if (b0 >= 251 && b0 <= 254)// Same as above except negative + { + int w = GetCard8(); + args[arg_count] = -((int)b0-251)*256 - w - 108; + arg_count++; + continue; + } + if (b0 == 255)// The next for bytes represent a double. + { + int first = GetCard8(); + int second = GetCard8(); + int third = GetCard8(); + int fourth = GetCard8(); + args[arg_count] = first<<24 | second<<16 | third<<8 | fourth; + arg_count++; + continue; + } + if (b0<=31 && b0 != 28) // An operator was found.. Set Key. + { + gotKey=true; + // 12 is an escape command therefor the next byte is a part + // of this command + if (b0 == 12) + { + int b1 = GetCard8(); + if (b1>SubrsEscapeFuncs.Length-1) + b1 = SubrsEscapeFuncs.Length-1; + key = SubrsEscapeFuncs[b1]; + } + else + key = SubrsFunctions[b0]; + continue; + } + } + } + + /** + * The function reads the subroutine and returns the number of the hint in it. + * If a call to another subroutine is found the function calls recursively. + * @param begin the start point of the subr + * @param end the end point of the subr + * @param LBias the bias of the Local Subrs + * @param GBias the bias of the Global Subrs + * @param LSubrsOffsets The Offsets array of the subroutines + * @return The number of hints in the subroutine read. + */ + protected int CalcHints(int begin,int end,int LBias,int GBias,int[] LSubrsOffsets) + { + // Goto begining of the subr + Seek(begin); + while (GetPosition() < end) + { + // Read the next command + ReadCommand(); + int pos = GetPosition(); + Object TopElement = null; + if (arg_count>0) + TopElement = args[arg_count-1]; + int NumOfArgs = arg_count; + //Check the modification needed on the Argument Stack according to key; + HandelStack(); + // a call to a Lsubr + if (key=="callsubr") + { + if (NumOfArgs>0) + { + int Subr = (int)TopElement + LBias; + CalcHints(LSubrsOffsets[Subr],LSubrsOffsets[Subr+1],LBias,GBias,LSubrsOffsets); + Seek(pos); + } + } + // a call to a Gsubr + else if (key=="callgsubr") + { + if (NumOfArgs>0) + { + int Subr = (int)TopElement + GBias; + CalcHints(gsubrOffsets[Subr],gsubrOffsets[Subr+1],LBias,GBias,LSubrsOffsets); + Seek(pos); + } + } + // A call to "stem" + else if (key == "hstem" || key == "vstem" || key == "hstemhm" || key == "vstemhm") + // Increment the NumOfHints by the number couples of of arguments + NumOfHints += NumOfArgs/2; + // A call to "mask" + else if (key == "hintmask" || key == "cntrmask") + { + // Compute the size of the mask + int SizeOfMask = NumOfHints/8; + if (NumOfHints%8 != 0 || SizeOfMask == 0) + SizeOfMask++; + // Continue the pointer in SizeOfMask steps + for (int i=0;i> 8) & 0xff); + NewIndex[Place++] = (byte) ((Count >> 0) & 0xff); + // Write the offsize field + NewIndex[Place++] = Offsize; + // Write the offset array according to the offsize + for (int i=0;i> 24) & 0xff); + goto case 3; + case 3: + NewIndex[Place++] = (byte) ((Num >> 16) & 0xff); + goto case 2; + case 2: + NewIndex[Place++] = (byte) ((Num >> 8) & 0xff); + goto case 1; + case 1: + NewIndex[Place++] = (byte) ((Num >> 0) & 0xff); + break; + } + } + // Write the new object array one by one + for (int i=0;i=0) + OutputList.Add(new RangeItem(buf,fonts[Font].fdselectOffset,fonts[Font].FDSelectLength)); + // Else create a new one + else + CreateFDSelect(fdselectRef,fonts[Font].nglyphs); + + // Copy the Charset + // Mark the beginning and copy entirly + OutputList.Add(new MarkerItem(charsetRef)); + OutputList.Add(new RangeItem(buf,fonts[Font].charsetOffset,fonts[Font].CharsetLength)); + + // Copy the FDArray + // If an FDArray exists + if (fonts[Font].fdarrayOffset>=0) + { + // Mark the beginning + OutputList.Add(new MarkerItem(fdarrayRef)); + // Build a new FDArray with its private dicts and their LSubrs + Reconstruct(Font); + } + else + // Else create a new one + CreateFDArray(fdarrayRef,privateRef,Font); + + } + // If the font is not CID + else + { + // create FDSelect + CreateFDSelect(fdselectRef,fonts[Font].nglyphs); + // recreate a new charset + CreateCharset(charsetRef,fonts[Font].nglyphs); + // create a font dict index (fdarray) + CreateFDArray(fdarrayRef,privateRef,Font); + } + + // if a private dict exists insert its subsetted version + if (fonts[Font].privateOffset>=0) + { + // Mark the beginning of the private dict + IndexBaseItem PrivateBase = new IndexBaseItem(); + OutputList.Add(PrivateBase); + OutputList.Add(new MarkerItem(privateRef)); + + OffsetItem Subr = new DictOffsetItem(); + // Build and copy the new private dict + CreateNonCIDPrivate(Font,Subr); + // Copy the new LSubrs index + CreateNonCIDSubrs(Font,PrivateBase,Subr); + } + + // copy the charstring index + OutputList.Add(new MarkerItem(charstringsRef)); + + // Add the subsetted charstring + OutputList.Add(new RangeItem(new RandomAccessFileOrArray(NewCharStringsIndex),0,NewCharStringsIndex.Length)); + + // now create the new CFF font + int[] currentOffset = new int[1]; + currentOffset[0] = 0; + // Count and save the offset for each item + foreach (Item item in OutputList) { + item.Increment(currentOffset); + } + // Compute the Xref for each of the offset items + foreach (Item item in OutputList) { + item.Xref(); + } + + int size = currentOffset[0]; + byte[] b = new byte[size]; + + // Emit all the items into the new byte array + foreach (Item item in OutputList) { + item.Emit(b); + } + // Return the new stream + return b; + } + + /** + * Function Copies the header from the original fileto the output list + */ + protected void CopyHeader() + { + Seek(0); + int major = GetCard8(); + int minor = GetCard8(); + int hdrSize = GetCard8(); + int offSize = GetCard8(); + nextIndexOffset = hdrSize; + OutputList.Add(new RangeItem(buf,0,hdrSize)); + } + + /** + * Function Build the header of an index + * @param Count the count field of the index + * @param Offsize the offsize field of the index + * @param First the first offset of the index + */ + protected void BuildIndexHeader(int Count,int Offsize,int First) + { + // Add the count field + OutputList.Add(new UInt16Item((char)Count)); // count + // Add the offsize field + OutputList.Add(new UInt8Item((char)Offsize)); // offSize + // Add the first offset according to the offsize + switch (Offsize){ + case 1: + OutputList.Add(new UInt8Item((char)First)); // first offset + break; + case 2: + OutputList.Add(new UInt16Item((char)First)); // first offset + break; + case 3: + OutputList.Add(new UInt24Item((char)First)); // first offset + break; + case 4: + OutputList.Add(new UInt32Item((char)First)); // first offset + break; + default: + break; + } + } + + /** + * Function adds the keys into the TopDict + * @param fdarrayRef OffsetItem for the FDArray + * @param fdselectRef OffsetItem for the FDSelect + * @param charsetRef OffsetItem for the CharSet + * @param charstringsRef OffsetItem for the CharString + */ + protected void CreateKeys(OffsetItem fdarrayRef,OffsetItem fdselectRef,OffsetItem charsetRef,OffsetItem charstringsRef) + { + // create an FDArray key + OutputList.Add(fdarrayRef); + OutputList.Add(new UInt8Item((char)12)); + OutputList.Add(new UInt8Item((char)36)); + // create an FDSelect key + OutputList.Add(fdselectRef); + OutputList.Add(new UInt8Item((char)12)); + OutputList.Add(new UInt8Item((char)37)); + // create an charset key + OutputList.Add(charsetRef); + OutputList.Add(new UInt8Item((char)15)); + // create a CharStrings key + OutputList.Add(charstringsRef); + OutputList.Add(new UInt8Item((char)17)); + } + + /** + * Function takes the original string item and adds the new strings + * to accomodate the CID rules + * @param Font the font + */ + protected void CreateNewStringIndex(int Font) + { + String fdFontName = fonts[Font].name+"-OneRange"; + if (fdFontName.Length > 127) + fdFontName = fdFontName.Substring(0,127); + String extraStrings = "Adobe"+"Identity"+fdFontName; + + int origStringsLen = stringOffsets[stringOffsets.Length-1] + - stringOffsets[0]; + int stringsBaseOffset = stringOffsets[0]-1; + + byte stringsIndexOffSize; + if (origStringsLen+extraStrings.Length <= 0xff) stringsIndexOffSize = 1; + else if (origStringsLen+extraStrings.Length <= 0xffff) stringsIndexOffSize = 2; + else if (origStringsLen+extraStrings.Length <= 0xffffff) stringsIndexOffSize = 3; + else stringsIndexOffSize = 4; + + OutputList.Add(new UInt16Item((char)((stringOffsets.Length-1)+3))); // count + OutputList.Add(new UInt8Item((char)stringsIndexOffSize)); // offSize + for (int i=0; i= 0) + { + OutputList.Add(new SubrMarkerItem(fdSubrs[i],fdPrivateBase[i])); + OutputList.Add(new RangeItem(new RandomAccessFileOrArray(NewLSubrsIndex[i]),0,NewLSubrsIndex[i].Length)); + } + } + } + + /** + * Calculates how many byte it took to write the offset for the subrs in a specific + * private dict. + * @param Offset The Offset for the private dict + * @param Size The size of the private dict + * @return The size of the offset of the subrs in the private dict + */ + internal int CalcSubrOffsetSize(int Offset,int Size) + { + // Set the size to 0 + int OffsetSize = 0; + // Go to the beginning of the private dict + Seek(Offset); + // Go until the end of the private dict + while (GetPosition() < Offset+Size) + { + int p1 = GetPosition(); + GetDictItem(); + int p2 = GetPosition(); + // When reached to the subrs offset + if (key=="Subrs") { + // The Offsize (minus the subrs key) + OffsetSize = p2-p1-1; + } + // All other keys are ignored + } + // return the size + return OffsetSize; + } + + /** + * Function computes the size of an index + * @param indexOffset The offset for the computed index + * @return The size of the index + */ + protected int CountEntireIndexRange(int indexOffset) + { + // Go to the beginning of the index + Seek(indexOffset); + // Read the count field + int count = GetCard16(); + // If count==0 -> size=2 + if (count==0) + return 2; + else + { + // Read the offsize field + int indexOffSize = GetCard8(); + // Go to the last element of the offset array + Seek(indexOffset+2+1+count*indexOffSize); + // The size of the object array is the value of the last element-1 + int size = GetOffset(indexOffSize)-1; + // Return the size of the entire index + return 2+1+(count+1)*indexOffSize+size; + } + } + + /** + * The function creates a private dict for a font that was not CID + * All the keys are copied as is except for the subrs key + * @param Font the font + * @param Subr The OffsetItem for the subrs of the private + */ + internal void CreateNonCIDPrivate(int Font,OffsetItem Subr) + { + // Go to the beginning of the private dict and read untill the end + Seek(fonts[Font].privateOffset); + while (GetPosition() < fonts[Font].privateOffset+fonts[Font].privateLength) + { + int p1 = GetPosition(); + GetDictItem(); + int p2 = GetPosition(); + // If the dictItem is the "Subrs" then, + // use marker for offset and write operator number + if (key=="Subrs") { + OutputList.Add(Subr); + OutputList.Add(new UInt8Item((char)19)); // Subrs + } + // Else copy the entire range + else + OutputList.Add(new RangeItem(buf,p1,p2-p1)); + } + } + + /** + * the function marks the beginning of the subrs index and adds the subsetted subrs + * index to the output list. + * @param Font the font + * @param PrivateBase IndexBaseItem for the private that's referencing to the subrs + * @param Subrs OffsetItem for the subrs + * @throws IOException + */ + internal void CreateNonCIDSubrs(int Font,IndexBaseItem PrivateBase,OffsetItem Subrs) + { + // Mark the beginning of the Subrs index + OutputList.Add(new SubrMarkerItem(Subrs,PrivateBase)); + // Put the subsetted new subrs index + OutputList.Add(new RangeItem(new RandomAccessFileOrArray(NewSubrsIndexNonCID),0,NewSubrsIndexNonCID.Length)); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/CJKFont.cs b/iTechSharp/iTextSharp/text/pdf/CJKFont.cs new file mode 100644 index 0000000..1e978a2 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/CJKFont.cs @@ -0,0 +1,646 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.util; + +/* + * $Id: CJKFont.cs,v 1.9 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2000, 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + +/** + * Creates a CJK font compatible with the fonts in the Adobe Asian font Pack. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + +internal class CJKFont : BaseFont { + /** The encoding used in the PDF document for CJK fonts + */ + internal const string CJK_ENCODING = "UNICODEBIGUNMARKED"; + private const int FIRST = 0; + private const int BRACKET = 1; + private const int SERIAL = 2; + private const int V1Y = 880; + + internal static Properties cjkFonts = new Properties(); + internal static Properties cjkEncodings = new Properties(); + internal static Hashtable allCMaps = Hashtable.Synchronized(new Hashtable()); + internal static Hashtable allFonts = Hashtable.Synchronized(new Hashtable()); + private static bool propertiesLoaded = false; + + /** The font name */ + private string fontName; + /** The style modifier */ + private string style = ""; + /** The CMap name associated with this font */ + private string CMap; + + private bool cidDirect = false; + + private char[] translationMap; + private IntHashtable vMetrics; + private IntHashtable hMetrics; + private Hashtable fontDesc; + private bool vertical = false; + + private static void LoadProperties() { + if (propertiesLoaded) + return; + lock (allFonts) { + if (propertiesLoaded) + return; + try { + Stream isp = GetResourceStream(RESOURCE_PATH + "cjkfonts.properties"); + cjkFonts.Load(isp); + isp.Close(); + isp = GetResourceStream(RESOURCE_PATH + "cjkencodings.properties"); + cjkEncodings.Load(isp); + isp.Close(); + } + catch { + cjkFonts = new Properties(); + cjkEncodings = new Properties(); + } + propertiesLoaded = true; + } + } + + /** Creates a CJK font. + * @param fontName the name of the font + * @param enc the encoding of the font + * @param emb always false. CJK font and not embedded + * @throws DocumentException on error + * @throws IOException on error + */ + internal CJKFont(string fontName, string enc, bool emb) { + LoadProperties(); + this.FontType = FONT_TYPE_CJK; + string nameBase = GetBaseName(fontName); + if (!IsCJKFont(nameBase, enc)) + throw new DocumentException("Font '" + fontName + "' with '" + enc + "' encoding is not a CJK font."); + if (nameBase.Length < fontName.Length) { + style = fontName.Substring(nameBase.Length); + fontName = nameBase; + } + this.fontName = fontName; + encoding = CJK_ENCODING; + vertical = enc.EndsWith("V"); + CMap = enc; + if (enc.StartsWith("Identity-")) { + cidDirect = true; + string s = cjkFonts[fontName]; + s = s.Substring(0, s.IndexOf('_')); + char[] c = (char[])allCMaps[s]; + if (c == null) { + c = ReadCMap(s); + if (c == null) + throw new DocumentException("The cmap " + s + " does not exist as a resource."); + c[CID_NEWLINE] = '\n'; + allCMaps.Add(s, c); + } + translationMap = c; + } + else { + char[] c = (char[])allCMaps[enc]; + if (c == null) { + string s = cjkEncodings[enc]; + if (s == null) + throw new DocumentException("The resource cjkencodings.properties does not contain the encoding " + enc); + StringTokenizer tk = new StringTokenizer(s); + string nt = tk.NextToken(); + c = (char[])allCMaps[nt]; + if (c == null) { + c = ReadCMap(nt); + allCMaps.Add(nt, c); + } + if (tk.HasMoreTokens()) { + string nt2 = tk.NextToken(); + char[] m2 = ReadCMap(nt2); + for (int k = 0; k < 0x10000; ++k) { + if (m2[k] == 0) + m2[k] = c[k]; + } + allCMaps.Add(enc, m2); + c = m2; + } + } + translationMap = c; + } + fontDesc = (Hashtable)allFonts[fontName]; + if (fontDesc == null) { + fontDesc = ReadFontProperties(fontName); + allFonts.Add(fontName, fontDesc); + } + hMetrics = (IntHashtable)fontDesc["W"]; + vMetrics = (IntHashtable)fontDesc["W2"]; + } + + /** Checks if its a valid CJK font. + * @param fontName the font name + * @param enc the encoding + * @return true if it is CJK font + */ + public static bool IsCJKFont(string fontName, string enc) { + LoadProperties(); + string encodings = cjkFonts[fontName]; + return (encodings != null && (enc.Equals("Identity-H") || enc.Equals("Identity-V") || encodings.IndexOf("_" + enc + "_") >= 0)); + } + + /** + * Gets the width of a char in normalized 1000 units. + * @param char1 the unicode char to get the width of + * @return the width in normalized 1000 units + */ + public override int GetWidth(int char1) { + int c = (int)char1; + if (!cidDirect) + c = translationMap[c]; + int v; + if (vertical) + v = vMetrics[c]; + else + v = hMetrics[c]; + if (v > 0) + return v; + else + return 1000; + } + + public override int GetWidth(string text) { + int total = 0; + for (int k = 0; k < text.Length; ++k) { + int c = text[k]; + if (!cidDirect) + c = translationMap[c]; + int v; + if (vertical) + v = vMetrics[c]; + else + v = hMetrics[c]; + if (v > 0) + total += v; + else + total += 1000; + } + return total; + } + + internal override int GetRawWidth(int c, string name) { + return 0; + } + public override int GetKerning(int char1, int char2) { + return 0; + } + + private PdfDictionary GetFontDescriptor() { + PdfDictionary dic = new PdfDictionary(PdfName.FONTDESCRIPTOR); + dic.Put(PdfName.ASCENT, new PdfLiteral((String)fontDesc["Ascent"])); + dic.Put(PdfName.CAPHEIGHT, new PdfLiteral((String)fontDesc["CapHeight"])); + dic.Put(PdfName.DESCENT, new PdfLiteral((String)fontDesc["Descent"])); + dic.Put(PdfName.FLAGS, new PdfLiteral((String)fontDesc["Flags"])); + dic.Put(PdfName.FONTBBOX, new PdfLiteral((String)fontDesc["FontBBox"])); + dic.Put(PdfName.FONTNAME, new PdfName(fontName + style)); + dic.Put(PdfName.ITALICANGLE, new PdfLiteral((String)fontDesc["ItalicAngle"])); + dic.Put(PdfName.STEMV, new PdfLiteral((String)fontDesc["StemV"])); + PdfDictionary pdic = new PdfDictionary(); + pdic.Put(PdfName.PANOSE, new PdfString((String)fontDesc["Panose"], null)); + dic.Put(PdfName.STYLE, pdic); + return dic; + } + + private PdfDictionary GetCIDFont(PdfIndirectReference fontDescriptor, IntHashtable cjkTag) { + PdfDictionary dic = new PdfDictionary(PdfName.FONT); + dic.Put(PdfName.SUBTYPE, PdfName.CIDFONTTYPE0); + dic.Put(PdfName.BASEFONT, new PdfName(fontName + style)); + dic.Put(PdfName.FONTDESCRIPTOR, fontDescriptor); + int[] keys = cjkTag.ToOrderedKeys(); + string w = ConvertToHCIDMetrics(keys, hMetrics); + if (w != null) + dic.Put(PdfName.W, new PdfLiteral(w)); + if (vertical) { + w = ConvertToVCIDMetrics(keys, vMetrics, hMetrics); + if (w != null) + dic.Put(PdfName.W2, new PdfLiteral(w)); + } + else + dic.Put(PdfName.DW, new PdfNumber(1000)); + PdfDictionary cdic = new PdfDictionary(); + cdic.Put(PdfName.REGISTRY, new PdfString((string)fontDesc["Registry"], null)); + cdic.Put(PdfName.ORDERING, new PdfString((string)fontDesc["Ordering"], null)); + cdic.Put(PdfName.SUPPLEMENT, new PdfLiteral((string)fontDesc["Supplement"])); + dic.Put(PdfName.CIDSYSTEMINFO, cdic); + return dic; + } + + private PdfDictionary GetFontBaseType(PdfIndirectReference CIDFont) { + PdfDictionary dic = new PdfDictionary(PdfName.FONT); + dic.Put(PdfName.SUBTYPE, PdfName.TYPE0); + string name = fontName; + if (style.Length > 0) + name += "-" + style.Substring(1); + name += "-" + CMap; + dic.Put(PdfName.BASEFONT, new PdfName(name)); + dic.Put(PdfName.ENCODING, new PdfName(CMap)); + dic.Put(PdfName.DESCENDANTFONTS, new PdfArray(CIDFont)); + return dic; + } + + internal override void WriteFont(PdfWriter writer, PdfIndirectReference piref, Object[] parms) { + IntHashtable cjkTag = (IntHashtable)parms[0]; + PdfIndirectReference ind_font = null; + PdfObject pobj = null; + PdfIndirectObject obj = null; + pobj = GetFontDescriptor(); + if (pobj != null){ + obj = writer.AddToBody(pobj); + ind_font = obj.IndirectReference; + } + pobj = GetCIDFont(ind_font, cjkTag); + if (pobj != null){ + obj = writer.AddToBody(pobj); + ind_font = obj.IndirectReference; + } + pobj = GetFontBaseType(ind_font); + writer.AddToBody(pobj, piref); + } + + private float GetDescNumber(string name) { + return int.Parse((string)fontDesc[name]); + } + + private float GetBBox(int idx) { + string s = (string)fontDesc["FontBBox"]; + StringTokenizer tk = new StringTokenizer(s, " []\r\n\t\f"); + string ret = tk.NextToken(); + for (int k = 0; k < idx; ++k) + ret = tk.NextToken(); + return int.Parse(ret); + } + + /** Gets the font parameter identified by key. Valid values + * for key are ASCENT, CAPHEIGHT, DESCENT + * and ITALICANGLE. + * @param key the parameter to be extracted + * @param fontSize the font size in points + * @return the parameter in points + */ + public override float GetFontDescriptor(int key, float fontSize) { + switch (key) { + case AWT_ASCENT: + case ASCENT: + return GetDescNumber("Ascent") * fontSize / 1000; + case CAPHEIGHT: + return GetDescNumber("CapHeight") * fontSize / 1000; + case AWT_DESCENT: + case DESCENT: + return GetDescNumber("Descent") * fontSize / 1000; + case ITALICANGLE: + return GetDescNumber("ItalicAngle"); + case BBOXLLX: + return fontSize * GetBBox(0) / 1000; + case BBOXLLY: + return fontSize * GetBBox(1) / 1000; + case BBOXURX: + return fontSize * GetBBox(2) / 1000; + case BBOXURY: + return fontSize * GetBBox(3) / 1000; + case AWT_LEADING: + return 0; + case AWT_MAXADVANCE: + return fontSize * (GetBBox(2) - GetBBox(0)) / 1000; + } + return 0; + } + + public override string PostscriptFontName { + get { + return fontName; + } + set { + fontName = value; + } + } + + /** Gets the full name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
    + * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @return the full name of the font + */ + public override string[][] FullFontName { + get { + return new string[][]{new string[] {"", "", "", fontName}}; + } + } + + /** Gets all the entries of the names-table. If it is a True Type font + * each array element will have {Name ID, Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
    + * For the other fonts the array has a single element with {"4", "", "", "", + * font name}. + * @return the full name of the font + */ + public override string[][] AllNameEntries { + get { + return new string[][]{new string[]{"4", "", "", "", fontName}}; + } + } + + /** Gets the family name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
    + * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @return the family name of the font + */ + public override string[][] FamilyFontName { + get { + return this.FullFontName; + } + } + + internal static char[] ReadCMap(string name) { + Stream istr = null; + try { + name = name + ".cmap"; + istr = GetResourceStream(RESOURCE_PATH + name); + char[] c = new char[0x10000]; + for (int k = 0; k < 0x10000; ++k) + c[k] = (char)((istr.ReadByte() << 8) + istr.ReadByte()); + return c; + } + catch { + // empty on purpose + } + finally { + try{istr.Close();}catch{} + } + + return null; + } + + internal static IntHashtable CreateMetric(string s) { + IntHashtable h = new IntHashtable(); + StringTokenizer tk = new StringTokenizer(s); + while (tk.HasMoreTokens()) { + int n1 = int.Parse(tk.NextToken()); + h[n1] = int.Parse(tk.NextToken()); + } + return h; + } + + internal static string ConvertToHCIDMetrics(int[] keys, IntHashtable h) { + if (keys.Length == 0) + return null; + int lastCid = 0; + int lastValue = 0; + int start; + for (start = 0; start < keys.Length; ++start) { + lastCid = keys[start]; + lastValue = h[lastCid]; + if (lastValue != 0) { + ++start; + break; + } + } + if (lastValue == 0) + return null; + StringBuilder buf = new StringBuilder(); + buf.Append('['); + buf.Append(lastCid); + int state = FIRST; + for (int k = start; k < keys.Length; ++k) { + int cid = keys[k]; + int value = h[cid]; + if (value == 0) + continue; + switch (state) { + case FIRST: { + if (cid == lastCid + 1 && value == lastValue) { + state = SERIAL; + } + else if (cid == lastCid + 1) { + state = BRACKET; + buf.Append('[').Append(lastValue); + } + else { + buf.Append('[').Append(lastValue).Append(']').Append(cid); + } + break; + } + case BRACKET: { + if (cid == lastCid + 1 && value == lastValue) { + state = SERIAL; + buf.Append(']').Append(lastCid); + } + else if (cid == lastCid + 1) { + buf.Append(' ').Append(lastValue); + } + else { + state = FIRST; + buf.Append(' ').Append(lastValue).Append(']').Append(cid); + } + break; + } + case SERIAL: { + if (cid != lastCid + 1 || value != lastValue) { + buf.Append(' ').Append(lastCid).Append(' ').Append(lastValue).Append(' ').Append(cid); + state = FIRST; + } + break; + } + } + lastValue = value; + lastCid = cid; + } + switch (state) { + case FIRST: { + buf.Append('[').Append(lastValue).Append("]]"); + break; + } + case BRACKET: { + buf.Append(' ').Append(lastValue).Append("]]"); + break; + } + case SERIAL: { + buf.Append(' ').Append(lastCid).Append(' ').Append(lastValue).Append(']'); + break; + } + } + return buf.ToString(); + } + + internal static string ConvertToVCIDMetrics(int[] keys, IntHashtable v, IntHashtable h) { + if (keys.Length == 0) + return null; + int lastCid = 0; + int lastValue = 0; + int lastHValue = 0; + int start; + for (start = 0; start < keys.Length; ++start) { + lastCid = keys[start]; + lastValue = v[lastCid]; + if (lastValue != 0) { + ++start; + break; + } + else + lastHValue = h[lastCid]; + } + if (lastValue == 0) + return null; + if (lastHValue == 0) + lastHValue = 1000; + StringBuilder buf = new StringBuilder(); + buf.Append('['); + buf.Append(lastCid); + int state = FIRST; + for (int k = start; k < keys.Length; ++k) { + int cid = keys[k]; + int value = v[cid]; + if (value == 0) + continue; + int hValue = h[lastCid]; + if (hValue == 0) + hValue = 1000; + switch (state) { + case FIRST: { + if (cid == lastCid + 1 && value == lastValue && hValue == lastHValue) { + state = SERIAL; + } + else { + buf.Append(' ').Append(lastCid).Append(' ').Append(-lastValue).Append(' ').Append(lastHValue / 2).Append(' ').Append(V1Y).Append(' ').Append(cid); + } + break; + } + case SERIAL: { + if (cid != lastCid + 1 || value != lastValue || hValue != lastHValue) { + buf.Append(' ').Append(lastCid).Append(' ').Append(-lastValue).Append(' ').Append(lastHValue / 2).Append(' ').Append(V1Y).Append(' ').Append(cid); + state = FIRST; + } + break; + } + } + lastValue = value; + lastCid = cid; + lastHValue = hValue; + } + buf.Append(' ').Append(lastCid).Append(' ').Append(-lastValue).Append(' ').Append(lastHValue / 2).Append(' ').Append(V1Y).Append(" ]"); + return buf.ToString(); + } + + internal static Hashtable ReadFontProperties(String name) { + try { + name += ".properties"; + Stream isp = GetResourceStream(RESOURCE_PATH + name); + Properties p = new Properties(); + p.Load(isp); + isp.Close(); + IntHashtable W = CreateMetric(p["W"]); + p.Remove("W"); + IntHashtable W2 = CreateMetric(p["W2"]); + p.Remove("W2"); + Hashtable map = new Hashtable(); + foreach (string key in p.Keys) { + map[key] = p[key]; + } + map["W"] = W; + map["W2"] = W2; + return map; + } + catch { + // empty on purpose + } + return null; + } + + public override int GetUnicodeEquivalent(int c) { + if (cidDirect) + return translationMap[c]; + return c; + } + + public override int GetCidCode(int c) { + if (cidDirect) + return c; + return translationMap[c]; + } + + public override bool HasKernPairs() { + return false; + } + + public override bool CharExists(int c) { + return translationMap[c] != 0; + } + + public override bool SetCharAdvance(int c, int advance) { + return false; + } + + public override bool SetKerning(int char1, int char2, int kern) { + return false; + } + + public override int[] GetCharBBox(int c) { + return null; + } + + protected override int[] GetRawCharBBox(int c, String name) { + return null; + } +} +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/CMYKColor.cs b/iTechSharp/iTextSharp/text/pdf/CMYKColor.cs new file mode 100644 index 0000000..ba718d2 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/CMYKColor.cs @@ -0,0 +1,112 @@ +using System; + +/* + * $Id: CMYKColor.cs,v 1.4 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class CMYKColor : ExtendedColor { + + float ccyan; + float cmagenta; + float cyellow; + float cblack; + + public CMYKColor(int intCyan, int intMagenta, int intYellow, int intBlack) : + this((float)intCyan / 255f, (float)intMagenta / 255f, (float)intYellow / 255f, (float)intBlack / 255f) {} + + public CMYKColor(float floatCyan, float floatMagenta, float floatYellow, float floatBlack) : + base(TYPE_CMYK, 1f - floatCyan - floatBlack, 1f - floatMagenta - floatBlack, 1f - floatYellow - floatBlack) { + ccyan = Normalize(floatCyan); + cmagenta = Normalize(floatMagenta); + cyellow = Normalize(floatYellow); + cblack = Normalize(floatBlack); + } + + public float Cyan { + get { + return ccyan; + } + } + + public float Magenta { + get { + return cmagenta; + } + } + + public float Yellow { + get { + return cyellow; + } + } + + public float Black { + get { + return cblack; + } + } + + public override bool Equals(Object obj) { + if (!(obj is CMYKColor)) + return false; + CMYKColor c2 = (CMYKColor)obj; + return (ccyan == c2.ccyan && cmagenta == c2.cmagenta && cyellow == c2.cyellow && cblack == c2.cblack); + } + + public override int GetHashCode() { + return ccyan.GetHashCode() ^ cmagenta.GetHashCode() ^ cyellow.GetHashCode() ^ cblack.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/CodeFile1.cs b/iTechSharp/iTextSharp/text/pdf/CodeFile1.cs new file mode 100644 index 0000000..e69de29 diff --git a/iTechSharp/iTextSharp/text/pdf/ColorDetails.cs b/iTechSharp/iTextSharp/text/pdf/ColorDetails.cs new file mode 100644 index 0000000..86d0636 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/ColorDetails.cs @@ -0,0 +1,107 @@ +using System; + +/* + * $Id: ColorDetails.cs,v 1.3 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Each spotcolor in the document will have an instance of this class + * + * @author Phillip Pan (phillip@formstar.com) + */ + public class ColorDetails { + + /** The indirect reference to this color + */ + PdfIndirectReference indirectReference; + /** The color name that appears in the document body stream + */ + PdfName colorName; + /** The color + */ + PdfSpotColor spotcolor; + + /** Each spot color used in a document has an instance of this class. + * @param colorName the color name + * @param indirectReference the indirect reference to the font + * @param scolor the PDfSpotColor + */ + internal ColorDetails(PdfName colorName, PdfIndirectReference indirectReference, PdfSpotColor scolor) { + this.colorName = colorName; + this.indirectReference = indirectReference; + this.spotcolor = scolor; + } + + /** Gets the indirect reference to this color. + * @return the indirect reference to this color + */ + internal PdfIndirectReference IndirectReference { + get { + return indirectReference; + } + } + + /** Gets the color name as it appears in the document body. + * @return the color name + */ + internal PdfName ColorName { + get { + return colorName; + } + } + + /** Gets the SpotColor object. + * @return the PdfSpotColor + */ + internal PdfObject GetSpotColor(PdfWriter writer) { + return spotcolor.GetSpotObject(writer); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/ColumnText.cs b/iTechSharp/iTextSharp/text/pdf/ColumnText.cs new file mode 100644 index 0000000..6e72376 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/ColumnText.cs @@ -0,0 +1,1534 @@ +using System; +using System.Collections; +using System.util.collections; +using iTextSharp.text.pdf.draw; + +/* + * Copyright 2001-2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + +/** + * Formats text in a columnwise form. The text is bound + * on the left and on the right by a sequence of lines. This allows the column + * to have any shape, not only rectangular. + *

    + * Several parameters can be set like the first paragraph line indent and + * extra space between paragraphs. + *

    + * A call to the method go will return one of the following + * situations: the column ended or the text ended. + *

    + * I the column ended, a new column definition can be loaded with the method + * setColumns and the method go can be called again. + *

    + * If the text ended, more text can be loaded with addText + * and the method go can be called again.
    + * The only limitation is that one or more complete paragraphs must be loaded + * each time. + *

    + * Full bidirectional reordering is supported. If the run direction is + * PdfWriter.RUN_DIRECTION_RTL the meaning of the horizontal + * alignments and margins is mirrored. + * @author Paulo Soares (psoares@consiste.pt) + */ + +public class ColumnText { + /** Eliminate the arabic vowels */ + public int AR_NOVOWEL = ArabicLigaturizer.ar_novowel; + /** Compose the tashkeel in the ligatures. */ + public const int AR_COMPOSEDTASHKEEL = ArabicLigaturizer.ar_composedtashkeel; + /** Do some extra double ligatures. */ + public const int AR_LIG = ArabicLigaturizer.ar_lig; + /** + * Digit shaping option: Replace European digits (U+0030...U+0039) by Arabic-Indic digits. + */ + public const int DIGITS_EN2AN = ArabicLigaturizer.DIGITS_EN2AN; + + /** + * Digit shaping option: Replace Arabic-Indic digits by European digits (U+0030...U+0039). + */ + public const int DIGITS_AN2EN = ArabicLigaturizer.DIGITS_AN2EN; + + /** + * Digit shaping option: + * Replace European digits (U+0030...U+0039) by Arabic-Indic digits + * if the most recent strongly directional character + * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC). + * The initial state at the start of the text is assumed to be not an Arabic, + * letter, so European digits at the start of the text will not change. + * Compare to DIGITS_ALEN2AN_INIT_AL. + */ + public const int DIGITS_EN2AN_INIT_LR = ArabicLigaturizer.DIGITS_EN2AN_INIT_LR; + + /** + * Digit shaping option: + * Replace European digits (U+0030...U+0039) by Arabic-Indic digits + * if the most recent strongly directional character + * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC). + * The initial state at the start of the text is assumed to be an Arabic, + * letter, so European digits at the start of the text will change. + * Compare to DIGITS_ALEN2AN_INT_LR. + */ + public const int DIGITS_EN2AN_INIT_AL = ArabicLigaturizer.DIGITS_EN2AN_INIT_AL; + + /** + * Digit type option: Use Arabic-Indic digits (U+0660...U+0669). + */ + public const int DIGIT_TYPE_AN = ArabicLigaturizer.DIGIT_TYPE_AN; + + /** + * Digit type option: Use Eastern (Extended) Arabic-Indic digits (U+06f0...U+06f9). + */ + public const int DIGIT_TYPE_AN_EXTENDED = ArabicLigaturizer.DIGIT_TYPE_AN_EXTENDED; + + protected int runDirection = PdfWriter.RUN_DIRECTION_DEFAULT; + public static float GLOBAL_SPACE_CHAR_RATIO = 0; + + /** Signals that there is no more text available. */ + public const int NO_MORE_TEXT = 1; + + /** Signals that there is no more column. */ + public const int NO_MORE_COLUMN = 2; + + /** The column is valid. */ + protected const int LINE_STATUS_OK = 0; + + /** The line is out the column limits. */ + protected const int LINE_STATUS_OFFLIMITS = 1; + + /** The line cannot fit this column position. */ + protected const int LINE_STATUS_NOLINE = 2; + + /** Upper bound of the column. */ + protected float maxY; + + /** Lower bound of the column. */ + protected float minY; + + protected float leftX; + + protected float rightX; + + /** The column Element. Default is left Element. */ + protected int alignment = Element.ALIGN_LEFT; + + /** The left column bound. */ + protected ArrayList leftWall; + + /** The right column bound. */ + protected ArrayList rightWall; + + /** The chunks that form the text. */ +// protected ArrayList chunks = new ArrayList(); + protected BidiLine bidiLine; + + /** The current y line location. Text will be written at this line minus the leading. */ + protected float yLine; + + /** The leading for the current line. */ + protected float currentLeading = 16; + + /** The fixed text leading. */ + protected float fixedLeading = 16; + + /** The text leading that is multiplied by the biggest font size in the line. */ + protected float multipliedLeading = 0; + + /** The PdfContent where the text will be written to. */ + protected PdfContentByte canvas; + + protected PdfContentByte[] canvases; + + /** The line status when trying to fit a line to a column. */ + protected int lineStatus; + + /** The first paragraph line indent. */ + protected float indent = 0; + + /** The following paragraph lines indent. */ + protected float followingIndent = 0; + + /** The right paragraph lines indent. */ + protected float rightIndent = 0; + + /** The extra space between paragraphs. */ + protected float extraParagraphSpace = 0; + + /** The width of the line when the column is defined as a simple rectangle. */ + protected float rectangularWidth = -1; + + protected bool rectangularMode = false; + + /** Holds value of property spaceCharRatio. */ + private float spaceCharRatio = GLOBAL_SPACE_CHAR_RATIO; + + private bool lastWasNewline = true; + + /** Holds value of property linesWritten. */ + private int linesWritten; + + private float firstLineY; + + private bool firstLineYDone = false; + + /** Holds value of property arabicOptions. */ + private int arabicOptions = 0; + + protected float descender; + + protected bool composite = false; + + protected ColumnText compositeColumn; + + protected internal ArrayList compositeElements; + + protected int listIdx = 0; + + private bool splittedRow; + + protected Phrase waitPhrase; + + /** if true, first line height is adjusted so that the max ascender touches the top */ + private bool useAscender = false; + + /** + * Creates a ColumnText. + * @param text the place where the text will be written to. Can + * be a template. + */ + public ColumnText(PdfContentByte canvas) { + this.canvas = canvas; + } + + /** Creates an independent duplicated of the instance org. + * @param org the original ColumnText + * @return the duplicated + */ + public static ColumnText Duplicate(ColumnText org) { + ColumnText ct = new ColumnText(null); + ct.SetACopy(org); + return ct; + } + + /** Makes this instance an independent copy of org. + * @param org the original ColumnText + * @return itself + */ + public ColumnText SetACopy(ColumnText org) { + SetSimpleVars(org); + if (org.bidiLine != null) + bidiLine = new BidiLine(org.bidiLine); + return this; + } + + protected internal void SetSimpleVars(ColumnText org) { + maxY = org.maxY; + minY = org.minY; + alignment = org.alignment; + leftWall = null; + if (org.leftWall != null) + leftWall = new ArrayList(org.leftWall); + rightWall = null; + if (org.rightWall != null) + rightWall = new ArrayList(org.rightWall); + yLine = org.yLine; + currentLeading = org.currentLeading; + fixedLeading = org.fixedLeading; + multipliedLeading = org.multipliedLeading; + canvas = org.canvas; + canvases = org.canvases; + lineStatus = org.lineStatus; + indent = org.indent; + followingIndent = org.followingIndent; + rightIndent = org.rightIndent; + extraParagraphSpace = org.extraParagraphSpace; + rectangularWidth = org.rectangularWidth; + rectangularMode = org.rectangularMode; + spaceCharRatio = org.spaceCharRatio; + lastWasNewline = org.lastWasNewline; + linesWritten = org.linesWritten; + arabicOptions = org.arabicOptions; + runDirection = org.runDirection; + descender = org.descender; + composite = org.composite; + splittedRow = org.splittedRow; + if (org.composite) { + compositeElements = new ArrayList(org.compositeElements); + if (splittedRow) { + PdfPTable table = (PdfPTable)compositeElements[0]; + compositeElements[0] = new PdfPTable(table); + } + if (org.compositeColumn != null) + compositeColumn = Duplicate(org.compositeColumn); + } + listIdx = org.listIdx; + firstLineY = org.firstLineY; + leftX = org.leftX; + rightX = org.rightX; + firstLineYDone = org.firstLineYDone; + waitPhrase = org.waitPhrase; + useAscender = org.useAscender; + filledWidth = org.filledWidth; + adjustFirstLine = org.adjustFirstLine; + } + + private void AddWaitingPhrase() { + if (bidiLine == null && waitPhrase != null) { + bidiLine = new BidiLine(); + foreach (Chunk ck in waitPhrase.Chunks) { + bidiLine.AddChunk(new PdfChunk(ck, null)); + } + waitPhrase = null; + } + } + + /** + * Adds a Phrase to the current text array. + * @param phrase the text + */ + public void AddText(Phrase phrase) { + if (phrase == null || composite) + return; + AddWaitingPhrase(); + if (bidiLine == null) { + waitPhrase = phrase; + return; + } + foreach (Chunk c in phrase.Chunks) { + bidiLine.AddChunk(new PdfChunk(c, null)); + } + } + + /** + * Replaces the current text array with this Phrase. + * Anything added previously with AddElement() is lost. + * @param phrase the text + */ + public void SetText(Phrase phrase) { + bidiLine = null; + composite = false; + compositeColumn = null; + compositeElements = null; + listIdx = 0; + splittedRow = false; + waitPhrase = phrase; + } + + /** + * Adds a Chunk to the current text array. + * Will not have any effect if AddElement() was called before. + * @param chunk the text + */ + public void AddText(Chunk chunk) { + if (chunk == null || composite) + return; + AddText(new Phrase(chunk)); + } + + /** + * Adds an element. Elements supported are Paragraph, + * List, PdfPTable, Image and + * Graphic. + *

    + * It removes all the text placed with addText(). + * @param element the Element + */ + public void AddElement(IElement element) { + if (element == null) + return; + if (element is Image) { + Image img = (Image)element; + PdfPTable t = new PdfPTable(1); + float w = img.WidthPercentage; + if (w == 0) { + t.TotalWidth = img.ScaledWidth; + t.LockedWidth = true; + } + else + t.WidthPercentage = w; + t.SpacingAfter = img.SpacingAfter; + t.SpacingBefore = img.SpacingBefore; + switch (img.Alignment) { + case Image.LEFT_ALIGN: + t.HorizontalAlignment = Element.ALIGN_LEFT; + break; + case Image.RIGHT_ALIGN: + t.HorizontalAlignment = Element.ALIGN_RIGHT; + break; + default: + t.HorizontalAlignment = Element.ALIGN_CENTER; + break; + } + PdfPCell c = new PdfPCell(img, true); + c.Padding = 0; + c.Border = img.Border; + c.BorderColor = img.BorderColor; + c.BorderWidth = img.BorderWidth; + c.BackgroundColor = img.BackgroundColor; + t.AddCell(c); + element = t; + } + if (element.Type == Element.CHUNK) { + element = new Paragraph((Chunk)element); + } + else if (element.Type == Element.PHRASE) { + element = new Paragraph((Phrase)element); + } + if (element is SimpleTable) { + try { + element = ((SimpleTable)element).CreatePdfPTable(); + } catch (DocumentException) { + throw new ArgumentException("Element not allowed."); + } + } + else if (element.Type != Element.PARAGRAPH && element.Type != Element.LIST && element.Type != Element.PTABLE && element.Type != Element.YMARK) + throw new ArgumentException("Element not allowed."); + if (!composite) { + composite = true; + compositeElements = new ArrayList(); + bidiLine = null; + waitPhrase = null; + } + compositeElements.Add(element); + } + + /** + * Converts a sequence of lines representing one of the column bounds into + * an internal format. + *

    + * Each array element will contain a float[4] representing + * the line x = ax + b. + * @param cLine the column array + * @return the converted array + */ + protected ArrayList ConvertColumn(float[] cLine) { + if (cLine.Length < 4) + throw new Exception("No valid column line found."); + ArrayList cc = new ArrayList(); + for (int k = 0; k < cLine.Length - 2; k += 2) { + float x1 = cLine[k]; + float y1 = cLine[k + 1]; + float x2 = cLine[k + 2]; + float y2 = cLine[k + 3]; + if (y1 == y2) + continue; + // x = ay + b + float a = (x1 - x2) / (y1 - y2); + float b = x1 - a * y1; + float[] r = new float[4]; + r[0] = Math.Min(y1, y2); + r[1] = Math.Max(y1, y2); + r[2] = a; + r[3] = b; + cc.Add(r); + maxY = Math.Max(maxY, r[1]); + minY = Math.Min(minY, r[0]); + } + if (cc.Count == 0) + throw new Exception("No valid column line found."); + return cc; + } + + /** + * Finds the intersection between the yLine and the column. It will + * set the lineStatus apropriatly. + * @param wall the column to intersect + * @return the x coordinate of the intersection + */ + protected float FindLimitsPoint(ArrayList wall) { + lineStatus = LINE_STATUS_OK; + if (yLine < minY || yLine > maxY) { + lineStatus = LINE_STATUS_OFFLIMITS; + return 0; + } + for (int k = 0; k < wall.Count; ++k) { + float[] r = (float[])wall[k]; + if (yLine < r[0] || yLine > r[1]) + continue; + return r[2] * yLine + r[3]; + } + lineStatus = LINE_STATUS_NOLINE; + return 0; + } + + /** + * Finds the intersection between the yLine and the two + * column bounds. It will set the lineStatus apropriatly. + * @return a float[2]with the x coordinates of the intersection + */ + protected float[] FindLimitsOneLine() { + float x1 = FindLimitsPoint(leftWall); + if (lineStatus == LINE_STATUS_OFFLIMITS || lineStatus == LINE_STATUS_NOLINE) + return null; + float x2 = FindLimitsPoint(rightWall); + if (lineStatus == LINE_STATUS_NOLINE) + return null; + return new float[]{x1, x2}; + } + + /** + * Finds the intersection between the yLine, + * the yLine-leadingand the two + * column bounds. It will set the lineStatus apropriatly. + * @return a float[4]with the x coordinates of the intersection + */ + protected float[] FindLimitsTwoLines() { + bool repeat = false; + for (;;) { + if (repeat && currentLeading == 0) + return null; + repeat = true; + float[] x1 = FindLimitsOneLine(); + if (lineStatus == LINE_STATUS_OFFLIMITS) + return null; + yLine -= currentLeading; + if (lineStatus == LINE_STATUS_NOLINE) { + continue; + } + float[] x2 = FindLimitsOneLine(); + if (lineStatus == LINE_STATUS_OFFLIMITS) + return null; + if (lineStatus == LINE_STATUS_NOLINE) { + yLine -= currentLeading; + continue; + } + if (x1[0] >= x2[1] || x2[0] >= x1[1]) + continue; + return new float[]{x1[0], x1[1], x2[0], x2[1]}; + } + } + + /** + * Sets the columns bounds. Each column bound is described by a + * float[] with the line points [x1,y1,x2,y2,...]. + * The array must have at least 4 elements. + * @param leftLine the left column bound + * @param rightLine the right column bound + */ + public void SetColumns(float[] leftLine, float[] rightLine) { + maxY = -10e20f; + minY = 10e20f; + rightWall = ConvertColumn(rightLine); + leftWall = ConvertColumn(leftLine); + rectangularWidth = -1; + rectangularMode = false; + } + + /** + * Simplified method for rectangular columns. + * @param phrase a Phrase + * @param llx the lower left x corner + * @param lly the lower left y corner + * @param urx the upper right x corner + * @param ury the upper right y corner + * @param leading the leading + * @param alignment the column alignment + */ + public void SetSimpleColumn(Phrase phrase, float llx, float lly, float urx, float ury, float leading, int alignment) { + AddText(phrase); + SetSimpleColumn(llx, lly, urx, ury, leading, alignment); + } + + /** + * Simplified method for rectangular columns. + * @param llx the lower left x corner + * @param lly the lower left y corner + * @param urx the upper right x corner + * @param ury the upper right y corner + * @param leading the leading + * @param alignment the column alignment + */ + public void SetSimpleColumn(float llx, float lly, float urx, float ury, float leading, int alignment) { + Leading = leading; + this.alignment = alignment; + SetSimpleColumn(llx, lly, urx, ury); + } + + /** + * Simplified method for rectangular columns. + * @param llx + * @param lly + * @param urx + * @param ury + */ + public void SetSimpleColumn(float llx, float lly, float urx, float ury) { + leftX = Math.Min(llx, urx); + maxY = Math.Max(lly, ury); + minY = Math.Min(lly, ury); + rightX = Math.Max(llx, urx); + yLine = maxY; + rectangularWidth = rightX - leftX; + if (rectangularWidth < 0) + rectangularWidth = 0; + rectangularMode = true; + } + + /** + * Sets the leading fixed and variable. The resultant leading will be + * fixedLeading+multipliedLeading*maxFontSize where maxFontSize is the + * size of the bigest font in the line. + * @param fixedLeading the fixed leading + * @param multipliedLeading the variable leading + */ + public void SetLeading(float fixedLeading, float multipliedLeading) { + this.fixedLeading = fixedLeading; + this.multipliedLeading = multipliedLeading; + } + + /** + * Gets the fixed leading + * @return the leading + */ + public float Leading { + get { + return fixedLeading; + } + + set { + this.fixedLeading = value; + this.multipliedLeading = 0; + } + } + + /** + * Gets the variable leading + * @return the leading + */ + public float MultipliedLeading { + get { + return multipliedLeading; + } + } + + /** + * Gets the yLine. + * @return the yLine + */ + public float YLine { + get { + return yLine; + } + + set { + this.yLine = value; + } + } + + /** + * Gets the Element. + * @return the alignment + */ + public int Alignment{ + get { + return alignment; + } + + set { + this.alignment = value; + } + } + + /** + * Gets the first paragraph line indent. + * @return the indent + */ + public float Indent { + get { + return indent; + } + + set { + this.indent = value; + lastWasNewline = true; + } + } + + /** + * Gets the following paragraph lines indent. + * @return the indent + */ + public float FollowingIndent { + get { + return followingIndent; + } + + set { + this.followingIndent = value; + lastWasNewline = true; + } + } + + /** + * Gets the right paragraph lines indent. + * @return the indent + */ + public float RightIndent { + get { + return rightIndent; + } + + set { + this.rightIndent = value; + lastWasNewline = true; + } + } + + /** + * Outputs the lines to the document. It is equivalent to go(false). + * @return returns the result of the operation. It can be NO_MORE_TEXT + * and/or NO_MORE_COLUMN + * @throws DocumentException on error + */ + public int Go() { + return Go(false); + } + + /** + * Outputs the lines to the document. The output can be simulated. + * @param simulate true to simulate the writting to the document + * @return returns the result of the operation. It can be NO_MORE_TEXT + * and/or NO_MORE_COLUMN + * @throws DocumentException on error + */ + public int Go(bool simulate) { + if (composite) + return GoComposite(simulate); + AddWaitingPhrase(); + if (bidiLine == null) + return NO_MORE_TEXT; + descender = 0; + linesWritten = 0; + bool dirty = false; + float ratio = spaceCharRatio; + Object[] currentValues = new Object[2]; + PdfFont currentFont = null; + float lastBaseFactor = 0F; + currentValues[1] = lastBaseFactor; + PdfDocument pdf = null; + PdfContentByte graphics = null; + PdfContentByte text = null; + firstLineY = float.NaN; + int localRunDirection = PdfWriter.RUN_DIRECTION_NO_BIDI; + if (runDirection != PdfWriter.RUN_DIRECTION_DEFAULT) + localRunDirection = runDirection; + if (canvas != null) { + graphics = canvas; + pdf = canvas.PdfDocument; + text = canvas.Duplicate; + } + else if (!simulate) + throw new Exception("ColumnText.go with simulate==false and text==null."); + if (!simulate) { + if (ratio == GLOBAL_SPACE_CHAR_RATIO) + ratio = text.PdfWriter.SpaceCharRatio; + else if (ratio < 0.001f) + ratio = 0.001f; + } + float firstIndent = 0; + + int status = 0; + if (rectangularMode) { + for (;;) { + firstIndent = (lastWasNewline ? indent : followingIndent); + if (rectangularWidth <= firstIndent + rightIndent) { + status = NO_MORE_COLUMN; + if (bidiLine.IsEmpty()) + status |= NO_MORE_TEXT; + break; + } + if (bidiLine.IsEmpty()) { + status = NO_MORE_TEXT; + break; + } + PdfLine line = bidiLine.ProcessLine(leftX, rectangularWidth - firstIndent - rightIndent, alignment, localRunDirection, arabicOptions); + if (line == null) { + status = NO_MORE_TEXT; + break; + } + float maxSize = line.MaxSizeSimple; + if (UseAscender && float.IsNaN(firstLineY)) { + currentLeading = line.Ascender; + } + else { + currentLeading = fixedLeading + maxSize * multipliedLeading; + } + if (yLine > maxY || yLine - currentLeading < minY ) { + status = NO_MORE_COLUMN; + bidiLine.Restore(); + break; + } + yLine -= currentLeading; + if (!simulate && !dirty) { + text.BeginText(); + dirty = true; + } + if (float.IsNaN(firstLineY)) { + firstLineY = yLine; + } + UpdateFilledWidth(rectangularWidth - line.WidthLeft); + if (!simulate) { + currentValues[0] = currentFont; + text.SetTextMatrix(leftX + (line.RTL ? rightIndent : firstIndent) + line.IndentLeft, yLine); + pdf.WriteLineToContent(line, text, graphics, currentValues, ratio); + currentFont = (PdfFont)currentValues[0]; + } + lastWasNewline = line.NewlineSplit; + yLine -= line.NewlineSplit ? extraParagraphSpace : 0; + ++linesWritten; + descender = line.Descender; + } + } + else { + currentLeading = fixedLeading; + for (;;) { + firstIndent = (lastWasNewline ? indent : followingIndent); + float yTemp = yLine; + float[] xx = FindLimitsTwoLines(); + if (xx == null) { + status = NO_MORE_COLUMN; + if (bidiLine.IsEmpty()) + status |= NO_MORE_TEXT; + yLine = yTemp; + break; + } + if (bidiLine.IsEmpty()) { + status = NO_MORE_TEXT; + yLine = yTemp; + break; + } + float x1 = Math.Max(xx[0], xx[2]); + float x2 = Math.Min(xx[1], xx[3]); + if (x2 - x1 <= firstIndent + rightIndent) + continue; + if (!simulate && !dirty) { + text.BeginText(); + dirty = true; + } + PdfLine line = bidiLine.ProcessLine(x1, x2 - x1 - firstIndent - rightIndent, alignment, localRunDirection, arabicOptions); + if (line == null) { + status = NO_MORE_TEXT; + yLine = yTemp; + break; + } + if (!simulate) { + currentValues[0] = currentFont; + text.SetTextMatrix(x1 + (line.RTL ? rightIndent : firstIndent) + line.IndentLeft, yLine); + pdf.WriteLineToContent(line, text, graphics, currentValues, ratio); + currentFont = (PdfFont)currentValues[0]; + } + lastWasNewline = line.NewlineSplit; + yLine -= line.NewlineSplit ? extraParagraphSpace : 0; + ++linesWritten; + descender = line.Descender; + } + } + if (dirty) { + text.EndText(); + canvas.Add(text); + } + return status; + } + + /** + * Sets the extra space between paragraphs. + * @return the extra space between paragraphs + */ + public float ExtraParagraphSpace { + get { + return extraParagraphSpace; + } + + set { + this.extraParagraphSpace = value; + } + } + + /** + * Clears the chunk array. A call to go() will always return + * NO_MORE_TEXT. + */ + public void ClearChunks() { + if (bidiLine != null) + bidiLine.ClearChunks(); + } + + /** Gets the space/character extra spacing ratio for + * fully justified text. + * @return the space/character extra spacing ratio + */ + public float SpaceCharRatio { + get { + return spaceCharRatio; + } + + set { + this.spaceCharRatio = value; + } + } + + /** Gets the run direction. + * @return the run direction + */ + public int RunDirection { + get { + return runDirection; + } + + set { + if (value < PdfWriter.RUN_DIRECTION_DEFAULT || value > PdfWriter.RUN_DIRECTION_RTL) + throw new Exception("Invalid run direction: " + value); + this.runDirection = value; + } + } + + /** Gets the number of lines written. + * @return the number of lines written + */ + public int LinesWritten { + get { + return this.linesWritten; + } + } + + /** Sets the arabic shaping options. The option can be AR_NOVOWEL, + * AR_COMPOSEDTASHKEEL and AR_LIG. + * @param arabicOptions the arabic shaping options + */ + public int ArabicOptions { + set { + this.arabicOptions = value; + } + get { + return arabicOptions; + } + } + + /** Gets the biggest descender value of the last line written. + * @return the biggest descender value of the last line written + */ + public float Descender { + get { + return descender; + } + } + + /** Gets the width that the line will occupy after writing. + * Only the width of the first line is returned. + * @param phrase the Phrase containing the line + * @param runDirection the run direction + * @param arabicOptions the options for the arabic shaping + * @return the width of the line + */ + public static float GetWidth(Phrase phrase, int runDirection, int arabicOptions) { + ColumnText ct = new ColumnText(null); + ct.AddText(phrase); + ct.AddWaitingPhrase(); + PdfLine line = ct.bidiLine.ProcessLine(0, 20000, Element.ALIGN_LEFT, runDirection, arabicOptions); + if (line == null) + return 0; + else + return 20000 - line.WidthLeft; + } + + /** Gets the width that the line will occupy after writing. + * Only the width of the first line is returned. + * @param phrase the Phrase containing the line + * @return the width of the line + */ + public static float GetWidth(Phrase phrase) { + return GetWidth(phrase, PdfWriter.RUN_DIRECTION_NO_BIDI, 0); + } + + /** Shows a line of text. Only the first line is written. + * @param canvas where the text is to be written to + * @param alignment the alignment. It is not influenced by the run direction + * @param phrase the Phrase with the text + * @param x the x reference position + * @param y the y reference position + * @param rotation the rotation to be applied in degrees counterclockwise + * @param runDirection the run direction + * @param arabicOptions the options for the arabic shaping + */ + public static void ShowTextAligned(PdfContentByte canvas, int alignment, Phrase phrase, float x, float y, float rotation, int runDirection, int arabicOptions) { + if (alignment != Element.ALIGN_LEFT && alignment != Element.ALIGN_CENTER + && alignment != Element.ALIGN_RIGHT) + alignment = Element.ALIGN_LEFT; + canvas.SaveState(); + ColumnText ct = new ColumnText(canvas); + if (rotation == 0) { + if (alignment == Element.ALIGN_LEFT) + ct.SetSimpleColumn(phrase, x, y - 1, 20000 + x, y + 2, 2, alignment); + else if (alignment == Element.ALIGN_RIGHT) + ct.SetSimpleColumn(phrase, x-20000, y-1, x, y+2, 2, alignment); + else + ct.SetSimpleColumn(phrase, x-20000, y-1, x+20000, y+2, 2, alignment); + } + else { + double alpha = rotation * Math.PI / 180.0; + float cos = (float)Math.Cos(alpha); + float sin = (float)Math.Sin(alpha); + canvas.ConcatCTM(cos, sin, -sin, cos, x, y); + if (alignment == Element.ALIGN_LEFT) + ct.SetSimpleColumn(phrase, 0, -1, 20000, 2, 2, alignment); + else if (alignment == Element.ALIGN_RIGHT) + ct.SetSimpleColumn(phrase, -20000, -1, 0, 2, 2, alignment); + else + ct.SetSimpleColumn(phrase, -20000, -1, 20000, 2, 2, alignment); + } + if (runDirection == PdfWriter.RUN_DIRECTION_RTL) { + if (alignment == Element.ALIGN_LEFT) + alignment = Element.ALIGN_RIGHT; + else if (alignment == Element.ALIGN_RIGHT) + alignment = Element.ALIGN_LEFT; + } + ct.Alignment = alignment; + ct.ArabicOptions = arabicOptions; + ct.RunDirection = runDirection; + ct.Go(); + canvas.RestoreState(); + } + + /** Shows a line of text. Only the first line is written. + * @param canvas where the text is to be written to + * @param alignment the alignment + * @param phrase the Phrase with the text + * @param x the x reference position + * @param y the y reference position + * @param rotation the rotation to be applied in degrees counterclockwise + */ + public static void ShowTextAligned(PdfContentByte canvas, int alignment, Phrase phrase, float x, float y, float rotation) { + ShowTextAligned(canvas, alignment, phrase, x, y, rotation, PdfWriter.RUN_DIRECTION_NO_BIDI, 0); + } + + protected int GoComposite(bool simulate) { + if (!rectangularMode) + throw new DocumentException("Irregular columns are not supported in composite mode."); + linesWritten = 0; + descender = 0; + bool firstPass = adjustFirstLine; + main_loop: + while (true) { + if (compositeElements.Count == 0) + return NO_MORE_TEXT; + IElement element = (IElement)compositeElements[0]; + if (element.Type == Element.PARAGRAPH) { + Paragraph para = (Paragraph)element; + int status = 0; + for (int keep = 0; keep < 2; ++keep) { + float lastY = yLine; + bool createHere = false; + if (compositeColumn == null) { + compositeColumn = new ColumnText(canvas); + compositeColumn.UseAscender = (firstPass ? useAscender : false); + compositeColumn.Alignment = para.Alignment; + compositeColumn.Indent = para.IndentationLeft + para.FirstLineIndent; + compositeColumn.ExtraParagraphSpace = para.ExtraParagraphSpace; + compositeColumn.FollowingIndent = para.IndentationLeft; + compositeColumn.RightIndent = para.IndentationRight; + compositeColumn.SetLeading(para.Leading, para.MultipliedLeading); + compositeColumn.RunDirection = runDirection; + compositeColumn.ArabicOptions = arabicOptions; + compositeColumn.SpaceCharRatio = spaceCharRatio; + compositeColumn.AddText(para); + if (!firstPass) { + yLine -= para.SpacingBefore; + } + createHere = true; + } + compositeColumn.leftX = leftX; + compositeColumn.rightX = rightX; + compositeColumn.yLine = yLine; + compositeColumn.rectangularWidth = rectangularWidth; + compositeColumn.rectangularMode = rectangularMode; + compositeColumn.minY = minY; + compositeColumn.maxY = maxY; + bool keepCandidate = (para.KeepTogether && createHere && !firstPass); + status = compositeColumn.Go(simulate || (keepCandidate && keep == 0)); + UpdateFilledWidth(compositeColumn.filledWidth); + if ((status & NO_MORE_TEXT) == 0 && keepCandidate) { + compositeColumn = null; + yLine = lastY; + return NO_MORE_COLUMN; + } + if (simulate || !keepCandidate) + break; + if (keep == 0) { + compositeColumn = null; + yLine = lastY; + } + } + firstPass = false; + yLine = compositeColumn.yLine; + linesWritten += compositeColumn.linesWritten; + descender = compositeColumn.descender; + if ((status & NO_MORE_TEXT) != 0) { + compositeColumn = null; + compositeElements.RemoveAt(0); + yLine -= para.SpacingAfter; + } + if ((status & NO_MORE_COLUMN) != 0) { + return NO_MORE_COLUMN; + } + } + else if (element.Type == Element.LIST) { + List list = (List)element; + ArrayList items = list.Items; + ListItem item = null; + float listIndentation = list.IndentationLeft; + int count = 0; + Stack stack = new Stack(); + for (int k = 0; k < items.Count; ++k) { + Object obj = items[k]; + if (obj is ListItem) { + if (count == listIdx) { + item = (ListItem)obj; + break; + } + else ++count; + } + else if (obj is List) { + stack.Push(new Object[]{list, k, listIndentation}); + list = (List)obj; + items = list.Items; + listIndentation += list.IndentationLeft; + k = -1; + continue; + } + if (k == items.Count - 1) { + if (stack.Count > 0) { + Object[] objs = (Object[])stack.Pop(); + list = (List)objs[0]; + items = list.Items; + k = (int)objs[1]; + listIndentation = (float)objs[2]; + } + } + } + int status = 0; + for (int keep = 0; keep < 2; ++keep) { + float lastY = yLine; + bool createHere = false; + if (compositeColumn == null) { + if (item == null) { + listIdx = 0; + compositeElements.RemoveAt(0); + goto main_loop; + } + compositeColumn = new ColumnText(canvas); + + compositeColumn.UseAscender = (firstPass ? useAscender : false); + compositeColumn.Alignment = item.Alignment; + compositeColumn.Indent = item.IndentationLeft + listIndentation + item.FirstLineIndent; + compositeColumn.ExtraParagraphSpace = item.ExtraParagraphSpace; + compositeColumn.FollowingIndent = compositeColumn.Indent; + compositeColumn.RightIndent = item.IndentationRight + list.IndentationRight; + compositeColumn.SetLeading(item.Leading, item.MultipliedLeading); + compositeColumn.RunDirection = runDirection; + compositeColumn.ArabicOptions = arabicOptions; + compositeColumn.SpaceCharRatio = spaceCharRatio; + compositeColumn.AddText(item); + if (!firstPass) { + yLine -= item.SpacingBefore; + } + createHere = true; + } + compositeColumn.leftX = leftX; + compositeColumn.rightX = rightX; + compositeColumn.yLine = yLine; + compositeColumn.rectangularWidth = rectangularWidth; + compositeColumn.rectangularMode = rectangularMode; + compositeColumn.minY = minY; + compositeColumn.maxY = maxY; + bool keepCandidate = (item.KeepTogether && createHere && !firstPass); + status = compositeColumn.Go(simulate || (keepCandidate && keep == 0)); + UpdateFilledWidth(compositeColumn.filledWidth); + if ((status & NO_MORE_TEXT) == 0 && keepCandidate) { + compositeColumn = null; + yLine = lastY; + return NO_MORE_COLUMN; + } + if (simulate || !keepCandidate) + break; + if (keep == 0) { + compositeColumn = null; + yLine = lastY; + } + } + firstPass = false; + yLine = compositeColumn.yLine; + linesWritten += compositeColumn.linesWritten; + descender = compositeColumn.descender; + if (!float.IsNaN(compositeColumn.firstLineY) && !compositeColumn.firstLineYDone) { + if (!simulate) + ShowTextAligned(canvas, Element.ALIGN_LEFT, new Phrase(item.ListSymbol), compositeColumn.leftX + listIndentation, compositeColumn.firstLineY, 0); + compositeColumn.firstLineYDone = true; + } + if ((status & NO_MORE_TEXT) != 0) { + compositeColumn = null; + ++listIdx; + yLine -= item.SpacingAfter; + } + if ((status & NO_MORE_COLUMN) != 0) { + return NO_MORE_COLUMN; + } + } + else if (element.Type == Element.PTABLE) { + // don't write anything in the current column if there's no more space available + if (yLine < minY || yLine > maxY) + return NO_MORE_COLUMN; + + // get the PdfPTable element + PdfPTable table = (PdfPTable)element; + + // we ignore tables without a body + if (table.Size <= table.HeaderRows) { + compositeElements.RemoveAt(0); + continue; + } + + // offsets + float yTemp = yLine; + if (!firstPass && listIdx == 0) { + yTemp -= table.SpacingBefore; + } + float yLineWrite = yTemp; + + // don't write anything in the current column if there's no more space available + if (yTemp < minY || yTemp > maxY) { + return NO_MORE_COLUMN; + } + + // coordinates + currentLeading = 0; + float x1 = leftX; + float tableWidth; + if (table.LockedWidth) { + tableWidth = table.TotalWidth; + UpdateFilledWidth(tableWidth); + } + else { + tableWidth = rectangularWidth * table.WidthPercentage / 100f; + table.TotalWidth = tableWidth; + } + + // how many header rows are real header rows; how many are footer rows? + int headerRows = table.HeaderRows; + int footerRows = table.FooterRows; + if (footerRows > headerRows) + footerRows = headerRows; + int realHeaderRows = headerRows - footerRows; + float headerHeight = table.HeaderHeight; + float footerHeight = table.FooterHeight; + + // make sure the header and footer fit on the page + bool skipHeader = (!firstPass && table.SkipFirstHeader && listIdx <= headerRows); + if (!skipHeader) { + yTemp -= headerHeight; + if (yTemp < minY || yTemp > maxY) { + if (firstPass) { + compositeElements.RemoveAt(0); + continue; + } + return NO_MORE_COLUMN; + } + } + + // how many real rows (not header or footer rows) fit on a page? + int k; + if (listIdx < headerRows) { + listIdx = headerRows; + } + if (!table.ElementComplete) { + yTemp -= footerHeight; + } + for (k = listIdx; k < table.Size; ++k) { + float rowHeight = table.GetRowHeight(k); + if (yTemp - rowHeight < minY) + break; + yTemp -= rowHeight; + } + if (!table.ElementComplete) { + yTemp += footerHeight; + } + // either k is the first row that doesn't fit on the page (break); + if (k < table.Size) { + if (table.SplitRows && (!table.SplitLate || (k == listIdx && firstPass))) { + if (!splittedRow) { + splittedRow = true; + table = new PdfPTable(table); + compositeElements[0] = table; + ArrayList rows = table.Rows; + for (int i = headerRows; i < listIdx; ++i) + rows[i] = null; + } + float h = yTemp - minY; + PdfPRow newRow = table.GetRow(k).SplitRow(h); + if (newRow == null) { + if (k == listIdx) { + return NO_MORE_COLUMN; + } + } + else { + yTemp = minY; + table.Rows.Insert(++k, newRow); + } + } + else if (!table.SplitRows && k == listIdx && firstPass) { + compositeElements.RemoveAt(0); + splittedRow = false; + continue; + } + else if (k == listIdx && !firstPass && (!table.SplitRows || table.SplitLate) && (table.FooterRows == 0 || table.ElementComplete)) { + return NO_MORE_COLUMN; + } + } + // or k is the number of rows in the table (for loop was done). + firstPass = false; + // we draw the table (for real now) + if (!simulate) { + // set the alignment + switch (table.HorizontalAlignment) { + case Element.ALIGN_LEFT: + break; + case Element.ALIGN_RIGHT: + x1 += rectangularWidth - tableWidth; + break; + default: + x1 += (rectangularWidth - tableWidth) / 2f; + break; + } + // copy the rows that fit on the page in a new table nt + PdfPTable nt = PdfPTable.ShallowCopy(table); + ArrayList rows = table.Rows; + ArrayList sub = nt.Rows; + + // first we add the real header rows (if necessary) + if (!skipHeader) { + for (int j = 0; j < realHeaderRows; ++j) { + PdfPRow headerRow = (PdfPRow)rows[j]; + sub.Add(headerRow); + } + } + else { + nt.HeaderRows = footerRows; + } + // then we add the real content + for (int j = listIdx; j < k; ++j) { + sub.Add(rows[j]); + } + // if k < table.size(), we must indicate that the new table is complete; + // otherwise no footers will be added (because iText thinks the table continues on the same page) + if (k < table.Size) { + nt.ElementComplete = true; + } + // we add the footer rows if necessary (not for incomplete tables) + for (int j = 0; j < footerRows && nt.ElementComplete; ++j) { + sub.Add(rows[j + realHeaderRows]); + } + + // we need a correction if the last row needs to be extended + float rowHeight = 0; + if (table.ExtendLastRow) { + PdfPRow last = (PdfPRow)sub[sub.Count - 1 - footerRows]; + rowHeight = last.MaxHeights; + last.MaxHeights = yTemp - minY + rowHeight; + yTemp = minY; + } + + // now we render the rows of the new table + if (canvases != null) + nt.WriteSelectedRows(0, -1, x1, yLineWrite, canvases); + else + nt.WriteSelectedRows(0, -1, x1, yLineWrite, canvas); + if (table.ExtendLastRow) { + PdfPRow last = (PdfPRow)sub[sub.Count - 1 - footerRows]; + last.MaxHeights = rowHeight; + } + } + else if (table.ExtendLastRow && minY > PdfPRow.BOTTOM_LIMIT) { + yTemp = minY; + } + yLine = yTemp; + if (!(skipHeader || table.ElementComplete)) { + yLine += footerHeight; + } + if (k >= table.Size) { + yLine -= table.SpacingAfter; + compositeElements.RemoveAt(0); + splittedRow = false; + listIdx = 0; + } + else { + if (splittedRow) { + ArrayList rows = table.Rows; + for (int i = listIdx; i < k; ++i) + rows[i] = null; + } + listIdx = k; + return NO_MORE_COLUMN; + } + } + else if (element.Type == Element.YMARK) { + if (!simulate) { + IDrawInterface zh = (IDrawInterface)element; + zh.Draw(canvas, leftX, minY, rightX, maxY, yLine); + } + compositeElements.RemoveAt(0); + } + else + compositeElements.RemoveAt(0); + } + } + + /** + * Sets the canvas. + * @param canvas + */ + public PdfContentByte Canvas { + set { + canvas = value; + canvases = null; + if (compositeColumn != null) + compositeColumn.Canvas = value; + } + get { + return canvas; + } + } + + /** + * Sets the canvases. + * @param canvas + */ + public PdfContentByte[] Canvases { + set { + canvases = value; + canvas = canvases[PdfPTable.TEXTCANVAS]; + if (compositeColumn != null) + compositeColumn.Canvases = canvases; + } + get { + return canvases; + } + } + + /** + * Checks if the element has a height of 0. + * @return true or false + * @since 2.1.2 + */ + public bool ZeroHeightElement() { + return composite && compositeElements.Count != 0 && ((IElement)compositeElements[0]).Type == Element.YMARK; + } + + /** + * Enables/Disables adjustment of first line height based on max ascender. + * @param use enable adjustment if true + */ + public bool UseAscender { + set { + useAscender = value; + } + get { + return useAscender; + } + } + + /** + * Checks the status variable and looks if there's still some text. + */ + public static bool HasMoreText(int status) { + return (status & ColumnText.NO_MORE_TEXT) == 0; + } + /** + * Holds value of property filledWidth. + */ + private float filledWidth; + + /** + * Sets the real width used by the largest line. Only used to set it + * to zero to start another measurement. + * @param filledWidth the real width used by the largest line + */ + public float FilledWidth { + set { + filledWidth = value; + } + get { + return filledWidth; + } + } + + /** + * Replaces the filledWidth if greater than the existing one. + * @param w the new filledWidth if greater than the existing one + */ + public void UpdateFilledWidth(float w) { + if (w > filledWidth) + filledWidth = w; + } + + private bool adjustFirstLine = true; + + /** + * Sets the first line adjustment. Some objects have properties, like spacing before, that + * behave differently if the object is the first to be written after go() or not. The first line adjustment is + * true by default but can be changed if several objects are to be placed one + * after the other in the same column calling go() several times. + * @param adjustFirstLine true to adjust the first line, false otherwise + */ + public bool AdjustFirstLine { + set { + adjustFirstLine = value; + } + get { + return adjustFirstLine; + } + } +} +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/DefaultSplitCharacter.cs b/iTechSharp/iTextSharp/text/pdf/DefaultSplitCharacter.cs new file mode 100644 index 0000000..d2d8645 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/DefaultSplitCharacter.cs @@ -0,0 +1,109 @@ +using System; +using iTextSharp.text; + +/* + * $Id: DefaultSplitCharacter.cs,v 1.1 2008/05/22 22:11:09 psoares33 Exp $ + * + * Copyright 2008 Bruno Lowagie and Xavier Le Vourch + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * The default class that is used to determine whether or not a character + * is a split character. You can subclass this class to define your own + * split characters. + * @since 2.1.2 + */ + public class DefaultSplitCharacter : ISplitCharacter { + + /** + * An instance of the default SplitCharacter. + */ + public static readonly ISplitCharacter DEFAULT = new DefaultSplitCharacter(); + + /** + * Checks if a character can be used to split a PdfString. + *

    + * for the moment every character less than or equal to SPACE, the character '-' + * and some specific unicode ranges are 'splitCharacters'. + * + * @param start start position in the array + * @param current current position in the array + * @param end end position in the array + * @param cc the character array that has to be checked + * @param ck chunk array + * @return true if the character can be used to split a string, false otherwise + */ + public bool IsSplitCharacter(int start, int current, int end, char[] cc, PdfChunk[] ck) { + char c = GetCurrentCharacter(current, cc, ck); + if (c <= ' ' || c == '-' || c == '\u2010') { + return true; + } + if (c < 0x2002) + return false; + return ((c >= 0x2002 && c <= 0x200b) + || (c >= 0x2e80 && c < 0xd7a0) + || (c >= 0xf900 && c < 0xfb00) + || (c >= 0xfe30 && c < 0xfe50) + || (c >= 0xff61 && c < 0xffa0)); + } + + /** + * Returns the current character + * @param current current position in the array + * @param cc the character array that has to be checked + * @param ck chunk array + * @return the current character + */ + protected char GetCurrentCharacter(int current, char[] cc, PdfChunk[] ck) { + if (ck == null) { + return (char)cc[current]; + } + return (char)ck[Math.Min(current, ck.Length - 1)].GetUnicodeEquivalent(cc[current]); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/DocumentFont.cs b/iTechSharp/iTextSharp/text/pdf/DocumentFont.cs new file mode 100644 index 0000000..d2dd905 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/DocumentFont.cs @@ -0,0 +1,633 @@ +using System; +using System.Collections; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + public class DocumentFont : BaseFont { + + // code, [glyph, width] + private Hashtable metrics = new Hashtable(); + private String fontName; + private PRIndirectReference refFont; + private PdfDictionary font; + private IntHashtable uni2byte = new IntHashtable(); + private IntHashtable byte2uni = new IntHashtable(); + private float Ascender = 800; + private float CapHeight = 700; + private float Descender = -200; + private float ItalicAngle = 0; + private float llx = -50; + private float lly = -200; + private float urx = 100; + private float ury = 900; + private bool isType0 = false; + + private BaseFont cjkMirror; + + private static String[] cjkNames = {"HeiseiMin-W3", "HeiseiKakuGo-W5", "STSong-Light", "MHei-Medium", + "MSung-Light", "HYGoThic-Medium", "HYSMyeongJo-Medium", "MSungStd-Light", "STSongStd-Light", + "HYSMyeongJoStd-Medium", "KozMinPro-Regular"}; + + private static String[] cjkEncs = {"UniJIS-UCS2-H", "UniJIS-UCS2-H", "UniGB-UCS2-H", "UniCNS-UCS2-H", + "UniCNS-UCS2-H", "UniKS-UCS2-H", "UniKS-UCS2-H", "UniCNS-UCS2-H", "UniGB-UCS2-H", + "UniKS-UCS2-H", "UniJIS-UCS2-H"}; + + private static String[] cjkNames2 = {"MSungStd-Light", "STSongStd-Light", "HYSMyeongJoStd-Medium", "KozMinPro-Regular"}; + + private static String[] cjkEncs2 = {"UniCNS-UCS2-H", "UniGB-UCS2-H", "UniKS-UCS2-H", "UniJIS-UCS2-H", + "UniCNS-UTF16-H", "UniGB-UTF16-H", "UniKS-UTF16-H", "UniJIS-UTF16-H"}; + + private static int[] stdEnc = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 32,33,34,35,36,37,38,8217,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, + 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, + 8216,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,161,162,163,8260,165,402,167,164,39,8220,171,8249,8250,64257,64258, + 0,8211,8224,8225,183,0,182,8226,8218,8222,8221,187,8230,8240,0,191, + 0,96,180,710,732,175,728,729,168,0,730,184,0,733,731,711, + 8212,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,198,0,170,0,0,0,0,321,216,338,186,0,0,0,0, + 0,230,0,0,0,305,0,0,322,248,339,223,0,0,0,0}; + + /** Creates a new instance of DocumentFont */ + internal DocumentFont(PRIndirectReference refFont) { + encoding = ""; + fontSpecific = false; + this.refFont = refFont; + fontType = FONT_TYPE_DOCUMENT; + font = (PdfDictionary)PdfReader.GetPdfObject(refFont); + fontName = PdfName.DecodeName(((PdfName)PdfReader.GetPdfObject(font.Get(PdfName.BASEFONT))).ToString()); + PdfName subType = (PdfName)PdfReader.GetPdfObject(font.Get(PdfName.SUBTYPE)); + if (PdfName.TYPE1.Equals(subType) || PdfName.TRUETYPE.Equals(subType)) + DoType1TT(); + else { + for (int k = 0; k < cjkNames.Length; ++k) { + if (fontName.StartsWith(cjkNames[k])) { + fontName = cjkNames[k]; + cjkMirror = BaseFont.CreateFont(fontName, cjkEncs[k], false); + return; + } + } + String enc = PdfName.DecodeName(((PdfName)PdfReader.GetPdfObject(font.Get(PdfName.ENCODING))).ToString()); + for (int k = 0; k < cjkEncs2.Length; ++k) { + if (enc.StartsWith(cjkEncs2[k])) { + if (k > 3) + k -= 4; + cjkMirror = BaseFont.CreateFont(cjkNames2[k], cjkEncs2[k], false); + return; + } + } + if (PdfName.TYPE0.Equals(subType) && enc.Equals("Identity-H")) { + ProcessType0(font); + isType0 = true; + } + } + } + + private void ProcessType0(PdfDictionary font) { + byte[] touni = PdfReader.GetStreamBytes((PRStream)PdfReader.GetPdfObjectRelease(font.Get(PdfName.TOUNICODE))); + PdfArray df = (PdfArray)PdfReader.GetPdfObjectRelease(font.Get(PdfName.DESCENDANTFONTS)); + PdfDictionary cidft = (PdfDictionary)PdfReader.GetPdfObjectRelease((PdfObject)df.ArrayList[0]); + PdfNumber dwo = (PdfNumber)PdfReader.GetPdfObjectRelease(cidft.Get(PdfName.DW)); + int dw = 1000; + if (dwo != null) + dw = dwo.IntValue; + IntHashtable widths = ReadWidths((PdfArray)PdfReader.GetPdfObjectRelease(cidft.Get(PdfName.W))); + PdfDictionary fontDesc = (PdfDictionary)PdfReader.GetPdfObjectRelease(cidft.Get(PdfName.FONTDESCRIPTOR)); + FillFontDesc(fontDesc); + FillMetrics(touni, widths, dw); + } + + private IntHashtable ReadWidths(PdfArray ws) { + IntHashtable hh = new IntHashtable(); + if (ws == null) + return hh; + ArrayList ar = ws.ArrayList; + for (int k = 0; k < ar.Count; ++k) { + int c1 = ((PdfNumber)PdfReader.GetPdfObjectRelease((PdfObject)ar[k])).IntValue; + PdfObject obj = PdfReader.GetPdfObjectRelease((PdfObject)ar[++k]); + if (obj.IsArray()) { + ArrayList ar2 = ((PdfArray)obj).ArrayList; + for (int j = 0; j < ar2.Count; ++j) { + int c2 = ((PdfNumber)PdfReader.GetPdfObjectRelease((PdfObject)ar2[j])).IntValue; + hh[c1++] = c2; + } + } + else { + int c2 = ((PdfNumber)obj).IntValue; + int w = ((PdfNumber)PdfReader.GetPdfObjectRelease((PdfObject)ar[++k])).IntValue; + for (; c1 <= c2; ++c1) + hh[c1] = w; + } + } + return hh; + } + + private String DecodeString(PdfString ps) { + if (ps.IsHexWriting()) + return PdfEncodings.ConvertToString(ps.GetBytes(), "UnicodeBigUnmarked"); + else + return ps.ToUnicodeString(); + } + + private void FillMetrics(byte[] touni, IntHashtable widths, int dw) { + PdfContentParser ps = new PdfContentParser(new PRTokeniser(touni)); + PdfObject ob = null; + PdfObject last = null; + while ((ob = ps.ReadPRObject()) != null) { + if (ob.Type == PdfContentParser.COMMAND_TYPE) { + if (ob.ToString().Equals("beginbfchar")) { + int n = ((PdfNumber)last).IntValue; + for (int k = 0; k < n; ++k) { + String cid = DecodeString((PdfString)ps.ReadPRObject()); + String uni = DecodeString((PdfString)ps.ReadPRObject()); + if (uni.Length == 1) { + int cidc = (int)cid[0]; + int unic = (int)uni[uni.Length - 1]; + int w = dw; + if (widths.ContainsKey(cidc)) + w = widths[cidc]; + metrics[unic] = new int[]{cidc, w}; + } + } + } + else if (ob.ToString().Equals("beginbfrange")) { + int n = ((PdfNumber)last).IntValue; + for (int k = 0; k < n; ++k) { + String cid1 = DecodeString((PdfString)ps.ReadPRObject()); + String cid2 = DecodeString((PdfString)ps.ReadPRObject()); + int cid1c = (int)cid1[0]; + int cid2c = (int)cid2[0]; + PdfObject ob2 = ps.ReadPRObject(); + if (ob2.IsString()) { + String uni = DecodeString((PdfString)ob2); + if (uni.Length == 1) { + int unic = (int)uni[uni.Length - 1]; + for (; cid1c <= cid2c; cid1c++, unic++) { + int w = dw; + if (widths.ContainsKey(cid1c)) + w = widths[cid1c]; + metrics[unic] = new int[]{cid1c, w}; + } + } + } + else { + ArrayList ar = ((PdfArray)ob2).ArrayList; + for (int j = 0; j < ar.Count; ++j, ++cid1c) { + String uni = DecodeString((PdfString)ar[j]); + if (uni.Length == 1) { + int unic = (int)uni[uni.Length - 1]; + int w = dw; + if (widths.ContainsKey(cid1c)) + w = widths[cid1c]; + metrics[unic] = new int[]{cid1c, w}; + } + } + } + } + } + } + else + last = ob; + } + } + + private void DoType1TT() { + PdfObject enc = PdfReader.GetPdfObject(font.Get(PdfName.ENCODING)); + if (enc == null) + FillEncoding(null); + else { + if (enc.IsName()) + FillEncoding((PdfName)enc); + else { + PdfDictionary encDic = (PdfDictionary)enc; + enc = PdfReader.GetPdfObject(encDic.Get(PdfName.BASEENCODING)); + if (enc == null) + FillEncoding(null); + else + FillEncoding((PdfName)enc); + PdfArray diffs = (PdfArray)PdfReader.GetPdfObject(encDic.Get(PdfName.DIFFERENCES)); + if (diffs != null) { + ArrayList dif = diffs.ArrayList; + int currentNumber = 0; + for (int k = 0; k < dif.Count; ++k) { + PdfObject obj = (PdfObject)dif[k]; + if (obj.IsNumber()) + currentNumber = ((PdfNumber)obj).IntValue; + else { + int[] c = GlyphList.NameToUnicode(PdfName.DecodeName(((PdfName)obj).ToString())); + if (c != null && c.Length > 0) { + if (byte2uni.ContainsKey(currentNumber)) { + uni2byte.Remove(byte2uni[currentNumber]); + } + uni2byte[c[0]] = currentNumber; + byte2uni[currentNumber] = c[0]; + } + ++currentNumber; + } + } + } + } + } + PdfArray newWidths = (PdfArray)PdfReader.GetPdfObject(font.Get(PdfName.WIDTHS)); + PdfNumber first = (PdfNumber)PdfReader.GetPdfObject(font.Get(PdfName.FIRSTCHAR)); + PdfNumber last = (PdfNumber)PdfReader.GetPdfObject(font.Get(PdfName.LASTCHAR)); + if (BuiltinFonts14.ContainsKey(fontName)) { + BaseFont bf; + bf = BaseFont.CreateFont(fontName, WINANSI, false); + int[] e = uni2byte.ToOrderedKeys(); + for (int k = 0; k < e.Length; ++k) { + int n = uni2byte[e[k]]; + widths[n] = bf.GetRawWidth(n, GlyphList.UnicodeToName(e[k])); + } + Ascender = bf.GetFontDescriptor(ASCENT, 1000); + CapHeight = bf.GetFontDescriptor(CAPHEIGHT, 1000); + Descender = bf.GetFontDescriptor(DESCENT, 1000); + ItalicAngle = bf.GetFontDescriptor(ITALICANGLE, 1000); + llx = bf.GetFontDescriptor(BBOXLLX, 1000); + lly = bf.GetFontDescriptor(BBOXLLY, 1000); + urx = bf.GetFontDescriptor(BBOXURX, 1000); + ury = bf.GetFontDescriptor(BBOXURY, 1000); + } + if (first != null && last != null && newWidths != null) { + int f = first.IntValue; + ArrayList ar = newWidths.ArrayList; + for (int k = 0; k < ar.Count; ++k) { + widths[f + k] = ((PdfNumber)ar[k]).IntValue; + } + } + FillFontDesc((PdfDictionary)PdfReader.GetPdfObject(font.Get(PdfName.FONTDESCRIPTOR))); + } + + private void FillFontDesc(PdfDictionary fontDesc) { + if (fontDesc == null) + return; + PdfNumber v = (PdfNumber)PdfReader.GetPdfObject(fontDesc.Get(PdfName.ASCENT)); + if (v != null) + Ascender = v.FloatValue; + v = (PdfNumber)PdfReader.GetPdfObject(fontDesc.Get(PdfName.CAPHEIGHT)); + if (v != null) + CapHeight = v.FloatValue; + v = (PdfNumber)PdfReader.GetPdfObject(fontDesc.Get(PdfName.DESCENT)); + if (v != null) + Descender = v.FloatValue; + v = (PdfNumber)PdfReader.GetPdfObject(fontDesc.Get(PdfName.ITALICANGLE)); + if (v != null) + ItalicAngle = v.FloatValue; + PdfArray bbox = (PdfArray)PdfReader.GetPdfObject(fontDesc.Get(PdfName.FONTBBOX)); + if (bbox != null) { + ArrayList ar = bbox.ArrayList; + llx = ((PdfNumber)ar[0]).FloatValue; + lly = ((PdfNumber)ar[1]).FloatValue; + urx = ((PdfNumber)ar[2]).FloatValue; + ury = ((PdfNumber)ar[3]).FloatValue; + if (llx > urx) { + float t = llx; + llx = urx; + urx = t; + } + if (lly > ury) { + float t = lly; + lly = ury; + ury = t; + } + } + } + + private void FillEncoding(PdfName encoding) { + if (PdfName.MAC_ROMAN_ENCODING.Equals(encoding) || PdfName.WIN_ANSI_ENCODING.Equals(encoding)) { + byte[] b = new byte[256]; + for (int k = 0; k < 256; ++k) + b[k] = (byte)k; + String enc = WINANSI; + if (PdfName.MAC_ROMAN_ENCODING.Equals(encoding)) + enc = MACROMAN; + String cv = PdfEncodings.ConvertToString(b, enc); + char[] arr = cv.ToCharArray(); + for (int k = 0; k < 256; ++k) { + uni2byte[arr[k]] = k; + byte2uni[k] = arr[k]; + } + } + else { + for (int k = 0; k < 256; ++k) { + uni2byte[stdEnc[k]] = k; + byte2uni[k] = stdEnc[k]; + } + } + } + + /** Gets the family name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
    + * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @return the family name of the font + * + */ + public override string[][] FamilyFontName { + get { + return FullFontName; + } + } + + /** Gets the font parameter identified by key. Valid values + * for key are ASCENT, CAPHEIGHT, DESCENT, + * ITALICANGLE, BBOXLLX, BBOXLLY, BBOXURX + * and BBOXURY. + * @param key the parameter to be extracted + * @param fontSize the font size in points + * @return the parameter in points + * + */ + public override float GetFontDescriptor(int key, float fontSize) { + if (cjkMirror != null) + return cjkMirror.GetFontDescriptor(key, fontSize); + switch (key) { + case AWT_ASCENT: + case ASCENT: + return Ascender * fontSize / 1000; + case CAPHEIGHT: + return CapHeight * fontSize / 1000; + case AWT_DESCENT: + case DESCENT: + return Descender * fontSize / 1000; + case ITALICANGLE: + return ItalicAngle; + case BBOXLLX: + return llx * fontSize / 1000; + case BBOXLLY: + return lly * fontSize / 1000; + case BBOXURX: + return urx * fontSize / 1000; + case BBOXURY: + return ury * fontSize / 1000; + case AWT_LEADING: + return 0; + case AWT_MAXADVANCE: + return (urx - llx) * fontSize / 1000; + } + return 0; + } + + /** Gets the full name of the font. If it is a True Type font + * each array element will have {Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
    + * For the other fonts the array has a single element with {"", "", "", + * font name}. + * @return the full name of the font + * + */ + public override string[][] FullFontName { + get { + return new string[][]{new string[]{"", "", "", fontName}}; + } + } + + /** Gets all the entries of the names-table. If it is a True Type font + * each array element will have {Name ID, Platform ID, Platform Encoding ID, + * Language ID, font name}. The interpretation of this values can be + * found in the Open Type specification, chapter 2, in the 'name' table.
    + * For the other fonts the array has a single element with {"4", "", "", "", + * font name}. + * @return the full name of the font + */ + public override string[][] AllNameEntries { + get { + return new string[][]{new string[]{"4", "", "", "", fontName}}; + } + } + + /** Gets the kerning between two Unicode chars. + * @param char1 the first char + * @param char2 the second char + * @return the kerning to be applied + * + */ + public override int GetKerning(int char1, int char2) { + return 0; + } + + /** Gets the postscript font name. + * @return the postscript font name + * + */ + public override string PostscriptFontName { + get { + return fontName; + } + set { + } + } + + /** Gets the width from the font according to the Unicode char c + * or the name. If the name is null it's a symbolic font. + * @param c the unicode char + * @param name the glyph name + * @return the width of the char + * + */ + internal override int GetRawWidth(int c, String name) { + return 0; + } + + /** Checks if the font has any kerning pairs. + * @return true if the font has any kerning pairs + * + */ + public override bool HasKernPairs() { + return false; + } + + /** Outputs to the writer the font dictionaries and streams. + * @param writer the writer for this document + * @param ref the font indirect reference + * @param params several parameters that depend on the font type + * @throws IOException on error + * @throws DocumentException error in generating the object + * + */ + internal override void WriteFont(PdfWriter writer, PdfIndirectReference refi, Object[] param) { + } + + /** + * Gets the width of a char in normalized 1000 units. + * @param char1 the unicode char to get the width of + * @return the width in normalized 1000 units + */ + public override int GetWidth(int char1) { + if (cjkMirror != null) + return cjkMirror.GetWidth(char1); + else if (isType0) { + int[] ws = (int[])metrics[(int)char1]; + if (ws != null) + return ws[1]; + else + return 0; + } + else + return base.GetWidth(char1); + } + + public override int GetWidth(String text) { + if (cjkMirror != null) + return cjkMirror.GetWidth(text); + else if (isType0) { + char[] chars = text.ToCharArray(); + int len = chars.Length; + int total = 0; + for (int k = 0; k < len; ++k) { + int[] ws = (int[])metrics[(int)chars[k]]; + if (ws != null) + total += ws[1]; + } + return total; + } + else + return base.GetWidth(text); + } + + internal override byte[] ConvertToBytes(String text) { + if (cjkMirror != null) + return PdfEncodings.ConvertToBytes(text, CJKFont.CJK_ENCODING); + else if (isType0) { + char[] chars = text.ToCharArray(); + int len = chars.Length; + byte[] b = new byte[len * 2]; + int bptr = 0; + for (int k = 0; k < len; ++k) { + int[] ws = (int[])metrics[(int)chars[k]]; + if (ws != null) { + int g = ws[0]; + b[bptr++] = (byte)(g / 256); + b[bptr++] = (byte)(g); + } + } + if (bptr == b.Length) + return b; + else { + byte[] nb = new byte[bptr]; + System.Array.Copy(b, 0, nb, 0, bptr); + return nb; + } + } + else { + char[] cc = text.ToCharArray(); + byte[] b = new byte[cc.Length]; + int ptr = 0; + for (int k = 0; k < cc.Length; ++k) { + if (uni2byte.ContainsKey(cc[k])) + b[ptr++] = (byte)uni2byte[cc[k]]; + } + if (ptr == b.Length) + return b; + else { + byte[] b2 = new byte[ptr]; + System.Array.Copy(b, 0, b2, 0, ptr); + return b2; + } + } + } + + internal override byte[] ConvertToBytes(int char1) { + if (cjkMirror != null) + return PdfEncodings.ConvertToBytes((char)char1, CJKFont.CJK_ENCODING); + else if (isType0) { + int[] ws = (int[])metrics[(int)char1]; + if (ws != null) { + int g = ws[0]; + return new byte[]{(byte)(g / 256), (byte)(g)}; + } + else + return new byte[0]; + } + else { + if (uni2byte.ContainsKey(char1)) + return new byte[]{(byte)uni2byte[char1]}; + else + return new byte[0]; + } + } + + internal PdfIndirectReference IndirectReference { + get { + return refFont; + } + } + + public override bool CharExists(int c) { + if (cjkMirror != null) + return cjkMirror.CharExists(c); + else if (isType0) { + return metrics.ContainsKey((int)c); + } + else + return base.CharExists(c); + } + + public override bool SetKerning(int char1, int char2, int kern) { + return false; + } + + public override int[] GetCharBBox(int c) { + return null; + } + + protected override int[] GetRawCharBBox(int c, String name) { + return null; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/EnumerateTTC.cs b/iTechSharp/iTextSharp/text/pdf/EnumerateTTC.cs new file mode 100644 index 0000000..88398fe --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/EnumerateTTC.cs @@ -0,0 +1,123 @@ +using System; +using System.IO; +using System.Collections; + +using iTextSharp.text; + +/* + * $Id: EnumerateTTC.cs,v 1.3 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Enumerates all the fonts inside a True Type Collection. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + internal class EnumerateTTC : TrueTypeFont { + + protected String[] names; + + internal EnumerateTTC(String ttcFile) { + fileName = ttcFile; + rf = new RandomAccessFileOrArray(ttcFile); + FindNames(); + } + + internal EnumerateTTC(byte[] ttcArray) { + fileName = "Byte array TTC"; + rf = new RandomAccessFileOrArray(ttcArray); + FindNames(); + } + + internal void FindNames() { + tables = new Hashtable(); + + try { + String mainTag = ReadStandardString(4); + if (!mainTag.Equals("ttcf")) + throw new DocumentException(fileName + " is not a valid TTC file."); + rf.SkipBytes(4); + int dirCount = rf.ReadInt(); + names = new String[dirCount]; + int dirPos = rf.FilePointer; + for (int dirIdx = 0; dirIdx < dirCount; ++dirIdx) { + tables.Clear(); + rf.Seek(dirPos); + rf.SkipBytes(dirIdx * 4); + directoryOffset = rf.ReadInt(); + rf.Seek(directoryOffset); + if (rf.ReadInt() != 0x00010000) + throw new DocumentException(fileName + " is not a valid TTF file."); + int num_tables = rf.ReadUnsignedShort(); + rf.SkipBytes(6); + for (int k = 0; k < num_tables; ++k) { + String tag = ReadStandardString(4); + rf.SkipBytes(4); + int[] table_location = new int[2]; + table_location[0] = rf.ReadInt(); + table_location[1] = rf.ReadInt(); + tables[tag] = table_location; + } + names[dirIdx] = this.BaseFont; + } + } + finally { + if (rf != null) + rf.Close(); + } + } + + internal String[] Names { + get { + return names; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/ExtendedColor.cs b/iTechSharp/iTextSharp/text/pdf/ExtendedColor.cs new file mode 100644 index 0000000..b12e3c9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/ExtendedColor.cs @@ -0,0 +1,101 @@ +using System; + +using iTextSharp.text; + +/* + * $Id: ExtendedColor.cs,v 1.4 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * + * @author Paulo Soares (psoares@consiste.pt) + */ + //public class ExtendedColor : Color { + public abstract class ExtendedColor : Color { + + internal const int TYPE_RGB = 0; + internal const int TYPE_GRAY = 1; + internal const int TYPE_CMYK = 2; + internal const int TYPE_SEPARATION = 3; + internal const int TYPE_PATTERN = 4; + internal const int TYPE_SHADING = 5; + + protected int type; + + public ExtendedColor(int type) : base(0, 0, 0) { + this.type = type; + } + + public ExtendedColor(int type, float red, float green, float blue) : base(Normalize(red), Normalize(green), Normalize(blue)) { + this.type = type; + } + + public int Type { + get { + return type; + } + } + + public static int GetType(object color) { + if (color is ExtendedColor) + return ((ExtendedColor)color).Type; + return TYPE_RGB; + } + + internal static float Normalize(float value) { + if (value < 0) + return 0; + if (value > 1) + return 1; + return (float)value; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/FdfReader.cs b/iTechSharp/iTextSharp/text/pdf/FdfReader.cs new file mode 100644 index 0000000..cb7e23b --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/FdfReader.cs @@ -0,0 +1,218 @@ +using System; +using System.Text; +using System.Collections; +using System.Net; +using System.IO; + +/* + * Copyright 2003 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** Reads an FDF form and makes the fields available + * @author Paulo Soares (psoares@consiste.pt) + */ + public class FdfReader : PdfReader { + + internal Hashtable fields; + internal String fileSpec; + internal PdfName encoding; + + /** Reads an FDF form. + * @param filename the file name of the form + * @throws IOException on error + */ + public FdfReader(String filename) : base(filename) { + } + + /** Reads an FDF form. + * @param pdfIn the byte array with the form + * @throws IOException on error + */ + public FdfReader(byte[] pdfIn) : base(pdfIn) { + } + + /** Reads an FDF form. + * @param url the URL of the document + * @throws IOException on error + */ + public FdfReader(Uri url) : base(url) { + } + + /** Reads an FDF form. + * @param is the InputStream containing the document. The stream is read to the + * end but is not closed + * @throws IOException on error + */ + public FdfReader(Stream isp) : base(isp) { + } + + protected internal override void ReadPdf() { + fields = new Hashtable(); + try { + tokens.CheckFdfHeader(); + RebuildXref(); + ReadDocObj(); + } + finally { + try { + tokens.Close(); + } + catch { + // empty on purpose + } + } + ReadFields(); + } + + protected virtual void KidNode(PdfDictionary merged, String name) { + PdfArray kids = (PdfArray)GetPdfObject(merged.Get(PdfName.KIDS)); + if (kids == null || kids.ArrayList.Count == 0) { + if (name.Length > 0) + name = name.Substring(1); + fields[name] = merged; + } + else { + merged.Remove(PdfName.KIDS); + ArrayList ar = kids.ArrayList; + for (int k = 0; k < ar.Count; ++k) { + PdfDictionary dic = new PdfDictionary(); + dic.Merge(merged); + PdfDictionary newDic = (PdfDictionary)GetPdfObject((PdfObject)ar[k]); + PdfString t = (PdfString)GetPdfObject(newDic.Get(PdfName.T)); + String newName = name; + if (t != null) + newName += "." + t.ToUnicodeString(); + dic.Merge(newDic); + dic.Remove(PdfName.T); + KidNode(dic, newName); + } + } + } + + protected virtual void ReadFields() { + catalog = (PdfDictionary)GetPdfObject(trailer.Get(PdfName.ROOT)); + PdfDictionary fdf = (PdfDictionary)GetPdfObject(catalog.Get(PdfName.FDF)); + if (fdf == null) + return; + PdfString fs = (PdfString)GetPdfObject(fdf.Get(PdfName.F)); + if (fs != null) + fileSpec = fs.ToUnicodeString(); + PdfArray fld = (PdfArray)GetPdfObject(fdf.Get(PdfName.FIELDS)); + if (fld == null) + return; + encoding = (PdfName)GetPdfObject(fdf.Get(PdfName.ENCODING)); + PdfDictionary merged = new PdfDictionary(); + merged.Put(PdfName.KIDS, fld); + KidNode(merged, ""); + } + + /** Gets all the fields. The map is keyed by the fully qualified + * field name and the value is a merged PdfDictionary + * with the field content. + * @return all the fields + */ + public Hashtable Fields { + get { + return fields; + } + } + + /** Gets the field dictionary. + * @param name the fully qualified field name + * @return the field dictionary + */ + public PdfDictionary GetField(String name) { + return (PdfDictionary)fields[name]; + } + + /** Gets the field value or null if the field does not + * exist or has no value defined. + * @param name the fully qualified field name + * @return the field value or null + */ + public String GetFieldValue(String name) { + PdfDictionary field = (PdfDictionary)fields[name]; + if (field == null) + return null; + PdfObject v = GetPdfObject(field.Get(PdfName.V)); + if (v == null) + return null; + if (v.IsName()) + return PdfName.DecodeName(((PdfName)v).ToString()); + else if (v.IsString()) { + PdfString vs = (PdfString)v; + if (encoding == null || vs.Encoding != null) + return vs.ToUnicodeString(); + byte[] b = vs.GetBytes(); + if (b.Length >= 2 && b[0] == (byte)254 && b[1] == (byte)255) + return vs.ToUnicodeString(); + try { + if (encoding.Equals(PdfName.SHIFT_JIS)) + return Encoding.GetEncoding(932).GetString(b); + else if (encoding.Equals(PdfName.UHC)) + return Encoding.GetEncoding(949).GetString(b); + else if (encoding.Equals(PdfName.GBK)) + return Encoding.GetEncoding(936).GetString(b); + else if (encoding.Equals(PdfName.BIGFIVE)) + return Encoding.GetEncoding(950).GetString(b); + } + catch { + } + return vs.ToUnicodeString(); + } + return null; + } + + /** Gets the PDF file specification contained in the FDF. + * @return the PDF file specification contained in the FDF + */ + public String FileSpec { + get { + return fileSpec; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/FdfWriter.cs b/iTechSharp/iTextSharp/text/pdf/FdfWriter.cs new file mode 100644 index 0000000..864a217 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/FdfWriter.cs @@ -0,0 +1,324 @@ +using System; +using System.util; +using System.IO; +using System.Collections; + +/* + * Copyright 2003 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** Writes an FDF form. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class FdfWriter { + private static readonly byte[] HEADER_FDF = DocWriter.GetISOBytes("%FDF-1.2\n%\u00e2\u00e3\u00cf\u00d3\n"); + Hashtable fields = new Hashtable(); + + /** The PDF file associated with the FDF. */ + private String file; + + /** Creates a new FdfWriter. */ + public FdfWriter() { + } + + /** Writes the content to a stream. + * @param os the stream + * @throws DocumentException on error + * @throws IOException on error + */ + public void WriteTo(Stream os) { + Wrt wrt = new Wrt(os, this); + wrt.WriteTo(); + } + + internal bool SetField(String field, PdfObject value) { + Hashtable map = fields; + StringTokenizer tk = new StringTokenizer(field, "."); + if (!tk.HasMoreTokens()) + return false; + while (true) { + String s = tk.NextToken(); + Object obj = map[s]; + if (tk.HasMoreTokens()) { + if (obj == null) { + obj = new Hashtable(); + map[s] = obj; + map = (Hashtable)obj; + continue; + } + else if (obj is Hashtable) + map = (Hashtable)obj; + else + return false; + } + else { + if (!(obj is Hashtable)) { + map[s] = value; + return true; + } + else + return false; + } + } + } + + internal void IterateFields(Hashtable values, Hashtable map, String name) { + foreach (DictionaryEntry entry in map) { + String s = (String)entry.Key; + Object obj = entry.Value; + if (obj is Hashtable) + IterateFields(values, (Hashtable)obj, name + "." + s); + else + values[(name + "." + s).Substring(1)] = obj; + } + } + + /** Removes the field value. + * @param field the field name + * @return true if the field was found and removed, + * false otherwise + */ + public bool RemoveField(String field) { + Hashtable map = fields; + StringTokenizer tk = new StringTokenizer(field, "."); + if (!tk.HasMoreTokens()) + return false; + ArrayList hist = new ArrayList(); + while (true) { + String s = tk.NextToken(); + Object obj = map[s]; + if (obj == null) + return false; + hist.Add(map); + hist.Add(s); + if (tk.HasMoreTokens()) { + if (obj is Hashtable) + map = (Hashtable)obj; + else + return false; + } + else { + if (obj is Hashtable) + return false; + else + break; + } + } + for (int k = hist.Count - 2; k >= 0; k -= 2) { + map = (Hashtable)hist[k]; + String s = (String)hist[k + 1]; + map.Remove(s); + if (map.Count > 0) + break; + } + return true; + } + + /** Gets all the fields. The map is keyed by the fully qualified + * field name and the values are PdfObject. + * @return a map with all the fields + */ + public Hashtable GetFields() { + Hashtable values = new Hashtable(); + IterateFields(values, fields, ""); + return values; + } + + /** Gets the field value. + * @param field the field name + * @return the field value or null if not found + */ + public String GetField(String field) { + Hashtable map = fields; + StringTokenizer tk = new StringTokenizer(field, "."); + if (!tk.HasMoreTokens()) + return null; + while (true) { + String s = tk.NextToken(); + Object obj = map[s]; + if (obj == null) + return null; + if (tk.HasMoreTokens()) { + if (obj is Hashtable) + map = (Hashtable)obj; + else + return null; + } + else { + if (obj is Hashtable) + return null; + else { + if (((PdfObject)obj).IsString()) + return ((PdfString)obj).ToUnicodeString(); + else + return PdfName.DecodeName(obj.ToString()); + } + } + } + } + + /** Sets the field value as a name. + * @param field the fully qualified field name + * @param value the value + * @return true if the value was inserted, + * false if the name is incompatible with + * an existing field + */ + public bool SetFieldAsName(String field, String value) { + return SetField(field, new PdfName(value)); + } + + /** Sets the field value as a string. + * @param field the fully qualified field name + * @param value the value + * @return true if the value was inserted, + * false if the name is incompatible with + * an existing field + */ + public bool SetFieldAsString(String field, String value) { + return SetField(field, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + + /** Sets all the fields from this FdfReader + * @param fdf the FdfReader + */ + public void SetFields(FdfReader fdf) { + Hashtable map = fdf.Fields; + foreach (DictionaryEntry entry in map) { + String key = (String)entry.Key; + PdfDictionary dic = (PdfDictionary)entry.Value; + PdfObject v = dic.Get(PdfName.V); + if (v != null) { + SetField(key, v); + } + } + } + + /** Sets all the fields from this PdfReader + * @param pdf the PdfReader + */ + public void SetFields(PdfReader pdf) { + SetFields(pdf.AcroFields); + } + + /** Sets all the fields from this AcroFields + * @param acro the AcroFields + */ + public void SetFields(AcroFields af) { + foreach (DictionaryEntry entry in af.Fields) { + String fn = (String)entry.Key; + AcroFields.Item item = (AcroFields.Item)entry.Value; + PdfDictionary dic = (PdfDictionary)item.merged[0]; + PdfObject v = PdfReader.GetPdfObjectRelease(dic.Get(PdfName.V)); + if (v == null) + continue; + PdfObject ft = PdfReader.GetPdfObjectRelease(dic.Get(PdfName.FT)); + if (ft == null || PdfName.SIG.Equals(ft)) + continue; + SetField(fn, v); + } + } + + /** Gets the PDF file name associated with the FDF. + * @return the PDF file name associated with the FDF + */ + public String File { + get { + return this.file; + } + set { + file = value; + } + } + + internal class Wrt : PdfWriter { + private FdfWriter fdf; + + internal Wrt(Stream os, FdfWriter fdf) : base(new PdfDocument(), os) { + this.fdf = fdf; + this.os.Write(HEADER_FDF, 0, HEADER_FDF.Length); + body = new PdfBody(this); + } + + internal void WriteTo() { + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.FIELDS, Calculate(fdf.fields)); + if (fdf.file != null) + dic.Put(PdfName.F, new PdfString(fdf.file, PdfObject.TEXT_UNICODE)); + PdfDictionary fd = new PdfDictionary(); + fd.Put(PdfName.FDF, dic); + PdfIndirectReference refi = AddToBody(fd).IndirectReference; + byte[] b = GetISOBytes("trailer\n"); + os.Write(b, 0, b.Length); + PdfDictionary trailer = new PdfDictionary(); + trailer.Put(PdfName.ROOT, refi); + trailer.ToPdf(null, os); + b = GetISOBytes("\n%%EOF\n"); + os.Write(b, 0, b.Length); + os.Close(); + } + + + internal PdfArray Calculate(Hashtable map) { + PdfArray ar = new PdfArray(); + foreach (DictionaryEntry entry in map) { + String key = (String)entry.Key; + Object v = entry.Value; + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.T, new PdfString(key, PdfObject.TEXT_UNICODE)); + if (v is Hashtable) { + dic.Put(PdfName.KIDS, Calculate((Hashtable)v)); + } + else { + dic.Put(PdfName.V, (PdfObject)v); + } + ar.Add(dic); + } + return ar; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/FontDetails.cs b/iTechSharp/iTextSharp/text/pdf/FontDetails.cs new file mode 100644 index 0000000..8e56bb1 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/FontDetails.cs @@ -0,0 +1,278 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text; + +/* + * $Id: FontDetails.cs,v 1.7 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Each font in the document will have an instance of this class + * where the characters used will be represented. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + internal class FontDetails { + + /** The indirect reference to this font + */ + PdfIndirectReference indirectReference; + /** The font name that appears in the document body stream + */ + PdfName fontName; + /** The font + */ + BaseFont baseFont; + /** The font if its an instance of TrueTypeFontUnicode + */ + TrueTypeFontUnicode ttu; + + CJKFont cjkFont; + /** The array used with single byte encodings + */ + byte[] shortTag; + /** The map used with double byte encodings. The key is Int(glyph) and the + * value is int[]{glyph, width, Unicode code} + */ + Hashtable longTag; + + IntHashtable cjkTag; + /** The font type + */ + int fontType; + /** true if the font is symbolic + */ + bool symbolic; + /** Indicates if all the glyphs and widths for that particular + * encoding should be included in the document. + */ + protected bool subset = true; + /** Each font used in a document has an instance of this class. + * This class stores the characters used in the document and other + * specifics unique to the current working document. + * @param fontName the font name + * @param indirectReference the indirect reference to the font + * @param baseFont the BaseFont + */ + internal FontDetails(PdfName fontName, PdfIndirectReference indirectReference, BaseFont baseFont) { + this.fontName = fontName; + this.indirectReference = indirectReference; + this.baseFont = baseFont; + fontType = baseFont.FontType; + switch (fontType) { + case BaseFont.FONT_TYPE_T1: + case BaseFont.FONT_TYPE_TT: + shortTag = new byte[256]; + break; + case BaseFont.FONT_TYPE_CJK: + cjkTag = new IntHashtable(); + cjkFont = (CJKFont)baseFont; + break; + case BaseFont.FONT_TYPE_TTUNI: + longTag = new Hashtable(); + ttu = (TrueTypeFontUnicode)baseFont; + symbolic = baseFont.IsFontSpecific(); + break; + } + } + + /** Gets the indirect reference to this font. + * @return the indirect reference to this font + */ + internal PdfIndirectReference IndirectReference { + get { + return indirectReference; + } + } + + /** Gets the font name as it appears in the document body. + * @return the font name + */ + internal PdfName FontName { + get { + return fontName; + } + } + + /** Gets the BaseFont of this font. + * @return the BaseFont of this font + */ + internal BaseFont BaseFont { + get { + return baseFont; + } + } + + /** Converts the text into bytes to be placed in the document. + * The conversion is done according to the font and the encoding and the characters + * used are stored. + * @param text the text to convert + * @return the conversion + */ + internal byte[] ConvertToBytes(string text) { + byte[] b = null; + switch (fontType) { + case BaseFont.FONT_TYPE_T3: + return baseFont.ConvertToBytes(text); + case BaseFont.FONT_TYPE_T1: + case BaseFont.FONT_TYPE_TT: { + b = baseFont.ConvertToBytes(text); + int len = b.Length; + for (int k = 0; k < len; ++k) + shortTag[((int)b[k]) & 0xff] = 1; + break; + } + case BaseFont.FONT_TYPE_CJK: { + int len = text.Length; + for (int k = 0; k < len; ++k) + cjkTag[cjkFont.GetCidCode(text[k])] = 0; + b = baseFont.ConvertToBytes(text); + break; + } + case BaseFont.FONT_TYPE_DOCUMENT: { + b = baseFont.ConvertToBytes(text); + break; + } + case BaseFont.FONT_TYPE_TTUNI: { + int len = text.Length; + int[] metrics = null; + char[] glyph = new char[len]; + int i = 0; + if (symbolic) { + b = PdfEncodings.ConvertToBytes(text, "symboltt"); + len = b.Length; + for (int k = 0; k < len; ++k) { + metrics = ttu.GetMetricsTT(b[k] & 0xff); + if (metrics == null) + continue; + longTag[metrics[0]] = new int[]{metrics[0], metrics[1], ttu.GetUnicodeDifferences(b[k] & 0xff)}; + glyph[i++] = (char)metrics[0]; + } + } + else { + for (int k = 0; k < len; ++k) { + int val; + if (Utilities.IsSurrogatePair(text, k)) { + val = Utilities.ConvertToUtf32(text, k); + k++; + } + else { + val = (int)text[k]; + } + metrics = ttu.GetMetricsTT(val); + if (metrics == null) + continue; + int m0 = metrics[0]; + int gl = m0; + if (!longTag.ContainsKey(gl)) + longTag[gl] = new int[]{m0, metrics[1], val}; + glyph[i++] = (char)m0; + } + } + string s = new String(glyph, 0, i); + b = PdfEncodings.ConvertToBytes(s, CJKFont.CJK_ENCODING); + break; + } + } + return b; + } + + /** Writes the font definition to the document. + * @param writer the PdfWriter of this document + */ + internal void WriteFont(PdfWriter writer) { + switch (fontType) { + case BaseFont.FONT_TYPE_T3: + baseFont.WriteFont(writer, indirectReference, null); + break; + case BaseFont.FONT_TYPE_T1: + case BaseFont.FONT_TYPE_TT: { + int firstChar; + int lastChar; + for (firstChar = 0; firstChar < 256; ++firstChar) { + if (shortTag[firstChar] != 0) + break; + } + for (lastChar = 255; lastChar >= firstChar; --lastChar) { + if (shortTag[lastChar] != 0) + break; + } + if (firstChar > 255) { + firstChar = 255; + lastChar = 255; + } + baseFont.WriteFont(writer, indirectReference, new Object[]{firstChar, lastChar, shortTag, subset}); + break; + } + case BaseFont.FONT_TYPE_CJK: + baseFont.WriteFont(writer, indirectReference, new Object[]{cjkTag}); + break; + case BaseFont.FONT_TYPE_TTUNI: + baseFont.WriteFont(writer, indirectReference, new Object[]{longTag, subset}); + break; + } + } + + /** Indicates if all the glyphs and widths for that particular + * encoding should be included in the document. Set to false + * to include all. + * @param subset new value of property subset + */ + public bool Subset { + set { + this.subset = value; + } + get { + return subset; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/FontSelector.cs b/iTechSharp/iTextSharp/text/pdf/FontSelector.cs new file mode 100644 index 0000000..41cb9f3 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/FontSelector.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections; +using System.Text; +using iTextSharp.text; +/* + * Copyright 2003 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** Selects the appropriate fonts that contain the glyphs needed to + * render text correctly. The fonts are checked in order until the + * character is found. + *

    + * The built in fonts "Symbol" and "ZapfDingbats", if used, have a special encoding + * to allow the characters to be referred by Unicode. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class FontSelector { + + protected ArrayList fonts = new ArrayList(); + + /** + * Adds a Font to be searched for valid characters. + * @param font the Font + */ + public void AddFont(Font font) { + if (font.BaseFont != null) { + fonts.Add(font); + return; + } + BaseFont bf = font.GetCalculatedBaseFont(true); + Font f2 = new Font(bf, font.Size, font.CalculatedStyle, font.Color); + fonts.Add(f2); + } + + /** + * Process the text so that it will render with a combination of fonts + * if needed. + * @param text the text + * @return a Phrase with one or more chunks + */ + public Phrase Process(String text) { + int fsize = fonts.Count; + if (fsize == 0) + throw new ArgumentException("No font is defined."); + char[] cc = text.ToCharArray(); + int len = cc.Length; + StringBuilder sb = new StringBuilder(); + Font font = null; + int lastidx = -1; + Phrase ret = new Phrase(); + for (int k = 0; k < len; ++k) { + char c = cc[k]; + if (c == '\n' || c == '\r') { + sb.Append(c); + continue; + } + if (Utilities.IsSurrogatePair(cc, k)) { + int u = Utilities.ConvertToUtf32(cc, k); + for (int f = 0; f < fsize; ++f) { + font = (Font)fonts[f]; + if (font.BaseFont.CharExists(u)) { + if (lastidx != f) { + if (sb.Length > 0 && lastidx != -1) { + Chunk ck = new Chunk(sb.ToString(), (Font)fonts[lastidx]); + ret.Add(ck); + sb.Length = 0; + } + lastidx = f; + } + sb.Append(c); + sb.Append(cc[++k]); + break; + } + } + } + else { + for (int f = 0; f < fsize; ++f) { + font = (Font)fonts[f]; + if (font.BaseFont.CharExists(c)) { + if (lastidx != f) { + if (sb.Length > 0 && lastidx != -1) { + Chunk ck = new Chunk(sb.ToString(), (Font)fonts[lastidx]); + ret.Add(ck); + sb.Length = 0; + } + lastidx = f; + } + sb.Append(c); + break; + } + } + } + } + if (sb.Length > 0) { + Chunk ck = new Chunk(sb.ToString(), (Font)fonts[lastidx == -1 ? 0 : lastidx]); + ret.Add(ck); + } + return ret; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/GlyphList.cs b/iTechSharp/iTextSharp/text/pdf/GlyphList.cs new file mode 100644 index 0000000..9ba1c7a --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/GlyphList.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections; +using System.IO; +using System.Globalization; +using System.util; + +/* + * $Id: GlyphList.cs,v 1.7 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + public class GlyphList { + private static Hashtable unicode2names = new Hashtable(); + private static Hashtable names2unicode = new Hashtable(); + + static GlyphList() { + Stream istr = null; + try { + istr = BaseFont.GetResourceStream(BaseFont.RESOURCE_PATH + "glyphlist.txt"); + if (istr == null) { + String msg = "glyphlist.txt not found as resource."; + throw new Exception(msg); + } + byte[] buf = new byte[1024]; + MemoryStream outp = new MemoryStream(); + while (true) { + int size = istr.Read(buf, 0, buf.Length); + if (size == 0) + break; + outp.Write(buf, 0, size); + } + istr.Close(); + istr = null; + String s = PdfEncodings.ConvertToString(outp.ToArray(), null); + StringTokenizer tk = new StringTokenizer(s, "\r\n"); + while (tk.HasMoreTokens()) { + String line = tk.NextToken(); + if (line.StartsWith("#")) + continue; + StringTokenizer t2 = new StringTokenizer(line, " ;\r\n\t\f"); + String name = null; + String hex = null; + if (!t2.HasMoreTokens()) + continue; + name = t2.NextToken(); + if (!t2.HasMoreTokens()) + continue; + hex = t2.NextToken(); + int num = int.Parse(hex, NumberStyles.HexNumber); + unicode2names[num] = name; + names2unicode[name] = new int[]{num}; + } + } + catch (Exception e) { + Console.Error.WriteLine("glyphlist.txt loading error: " + e.Message); + } + finally { + if (istr != null) { + try { + istr.Close(); + } + catch { + // empty on purpose + } + } + } + } + + public static int[] NameToUnicode(string name) { + return (int[])names2unicode[name]; + } + + public static string UnicodeToName(int num) { + return (string)unicode2names[num]; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/GrayColor.cs b/iTechSharp/iTextSharp/text/pdf/GrayColor.cs new file mode 100644 index 0000000..ea3c9c8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/GrayColor.cs @@ -0,0 +1,86 @@ +using System; + +/* + * $Id: GrayColor.cs,v 1.5 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class GrayColor : ExtendedColor { + + private float cgray; + + public static readonly GrayColor GRAYBLACK = new GrayColor(0f); + public static readonly GrayColor GRAYWHITE = new GrayColor(1f); + + public GrayColor(int intGray) : this((float)intGray / 255f) {} + + public GrayColor(float floatGray) : base(TYPE_GRAY, floatGray, floatGray, floatGray) { + cgray = Normalize(floatGray); + } + + public float Gray { + get { + return cgray; + } + } + + public override bool Equals(Object obj) { + return (obj is GrayColor) && ((GrayColor)obj).cgray == this.cgray; + } + + public override int GetHashCode() { + return cgray.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/HyphenationAuto.cs b/iTechSharp/iTextSharp/text/pdf/HyphenationAuto.cs new file mode 100644 index 0000000..1d665c3 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/HyphenationAuto.cs @@ -0,0 +1,130 @@ +using System; + +using iTextSharp.text.pdf.hyphenation; + +/* + * Copyright 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Hyphenates words automatically accordingly to the language and country. + * The hyphenator engine was taken from FOP and uses the TEX patterns. If a language + * is not provided and a TEX pattern for it exists, it can be easily adapted. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class HyphenationAuto : IHyphenationEvent { + + /** The hyphenator engine. + */ + protected Hyphenator hyphenator; + /** The second part of the hyphenated word. + */ + protected string post; + + /** Creates a new hyphenation instance usable in Chunk. + * @param lang the language ("en" for english, for example) + * @param country the country ("GB" for Great-Britain or "none" for no country, for example) + * @param leftMin the minimun number of letters before the hyphen + * @param rightMin the minimun number of letters after the hyphen + */ + public HyphenationAuto(string lang, string country, int leftMin, int rightMin) { + hyphenator = new Hyphenator(lang, country, leftMin, rightMin); + } + + /** Gets the hyphen symbol. + * @return the hyphen symbol + */ + public string HyphenSymbol { + get { + return "-"; + } + } + + /** Hyphenates a word and returns the first part of it. To get + * the second part of the hyphenated word call getHyphenatedWordPost(). + * @param word the word to hyphenate + * @param font the font used by this word + * @param fontSize the font size used by this word + * @param remainingWidth the width available to fit this word in + * @return the first part of the hyphenated word including + * the hyphen symbol, if any + */ + public string GetHyphenatedWordPre(string word, BaseFont font, float fontSize, float remainingWidth) { + post = word; + string hyphen = this.HyphenSymbol; + float hyphenWidth = font.GetWidthPoint(hyphen, fontSize); + if (hyphenWidth > remainingWidth) + return ""; + Hyphenation hyphenation = hyphenator.Hyphenate(word); + if (hyphenation == null) { + return ""; + } + int len = hyphenation.Length; + int k; + for (k = 0; k < len; ++k) { + if (font.GetWidthPoint(hyphenation.GetPreHyphenText(k), fontSize) + hyphenWidth > remainingWidth) + break; + } + --k; + if (k < 0) + return ""; + post = hyphenation.GetPostHyphenText(k); + return hyphenation.GetPreHyphenText(k) + hyphen; + } + + /** Gets the second part of the hyphenated word. Must be called + * after getHyphenatedWordPre(). + * @return the second part of the hyphenated word + */ + public string HyphenatedWordPost { + get { + return post; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/ICC_Profile.cs b/iTechSharp/iTextSharp/text/pdf/ICC_Profile.cs new file mode 100644 index 0000000..d2337e8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/ICC_Profile.cs @@ -0,0 +1,108 @@ +using System; +using System.Text; +using System.Collections; +using System.IO; + +namespace iTextSharp.text.pdf +{ + ///

    + /// Summary description for ICC_Profile. + /// + public class ICC_Profile + { + protected byte[] data; + protected int numComponents; + private static Hashtable cstags = new Hashtable(); + + protected ICC_Profile() { + } + + public static ICC_Profile GetInstance(byte[] data) { + if (data.Length < 128 | data[36] != 0x61 || data[37] != 0x63 + || data[38] != 0x73 || data[39] != 0x70) + throw new ArgumentException("Invalid ICC profile"); + ICC_Profile icc = new ICC_Profile(); + icc.data = data; + object cs = cstags[Encoding.ASCII.GetString(data, 16, 4)]; + icc.numComponents = (cs == null ? 0 : (int)cs); + return icc; + } + + public static ICC_Profile GetInstance(Stream file) { + byte[] head = new byte[128]; + int remain = head.Length; + int ptr = 0; + while (remain > 0) { + int n = file.Read(head, ptr, remain); + if (n <= 0) + throw new ArgumentException("Invalid ICC profile"); + remain -= n; + ptr += n; + } + if (head[36] != 0x61 || head[37] != 0x63 + || head[38] != 0x73 || head[39] != 0x70) + throw new ArgumentException("Invalid ICC profile"); + remain = ((head[0] & 0xff) << 24) | ((head[1] & 0xff) << 16) + | ((head[2] & 0xff) << 8) | (head[3] & 0xff); + byte[] icc = new byte[remain]; + System.Array.Copy(head, 0, icc, 0, head.Length); + remain -= head.Length; + ptr = head.Length; + while (remain > 0) { + int n = file.Read(icc, ptr, remain); + if (n <= 0) + throw new ArgumentException("Invalid ICC profile"); + remain -= n; + ptr += n; + } + return GetInstance(icc); + } + + public static ICC_Profile GetInstance(String fname) { + FileStream fs = new FileStream(fname, FileMode.Open, FileAccess.Read, FileShare.Read); + ICC_Profile icc = GetInstance(fs); + fs.Close(); + return icc; + } + + public byte[] Data { + get { + return data; + } + } + + public int NumComponents { + get { + return numComponents; + } + } + + static ICC_Profile() { + cstags["XYZ "] = 3; + cstags["Lab "] = 3; + cstags["Luv "] = 3; + cstags["YCbr"] = 3; + cstags["Yxy "] = 3; + cstags["RGB "] = 3; + cstags["GRAY"] = 1; + cstags["HSV "] = 3; + cstags["HLS "] = 3; + cstags["CMYK"] = 4; + cstags["CMY "] = 3; + cstags["2CLR"] = 2; + cstags["3CLR"] = 3; + cstags["4CLR"] = 4; + cstags["5CLR"] = 5; + cstags["6CLR"] = 6; + cstags["7CLR"] = 7; + cstags["8CLR"] = 8; + cstags["9CLR"] = 9; + cstags["ACLR"] = 10; + cstags["BCLR"] = 11; + cstags["CCLR"] = 12; + cstags["DCLR"] = 13; + cstags["ECLR"] = 14; + cstags["FCLR"] = 15; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/IExtraEncoding.cs b/iTechSharp/iTextSharp/text/pdf/IExtraEncoding.cs new file mode 100644 index 0000000..4c7d34b --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/IExtraEncoding.cs @@ -0,0 +1,84 @@ +using System; +/* + * Copyright 2003 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Classes implementing this interface can create custom encodings or + * replace existing ones. It is used in the context of PdfEncoding. + * @author Paulo Soares (psoares@consiste.pt) + */ + public interface IExtraEncoding { + + /** + * Converts an Unicode string to a byte array according to some encoding. + * @param text the Unicode string + * @param encoding the requested encoding. It's mainly of use if the same class + * supports more than one encoding. + * @return the conversion or null if no conversion is supported + */ + byte[] CharToByte(String text, String encoding); + + /** + * Converts an Unicode char to a byte array according to some encoding. + * @param char1 the Unicode char + * @param encoding the requested encoding. It's mainly of use if the same class + * supports more than one encoding. + * @return the conversion or null if no conversion is supported + */ + byte[] CharToByte(char char1, String encoding); + + /** + * Converts a byte array to an Unicode string according to some encoding. + * @param b the input byte array + * @param encoding the requested encoding. It's mainly of use if the same class + * supports more than one encoding. + * @return the conversion or null if no conversion is supported + */ + String ByteToChar(byte[] b, String encoding); + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/IHyphenationEvent.cs b/iTechSharp/iTextSharp/text/pdf/IHyphenationEvent.cs new file mode 100644 index 0000000..5369ab8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/IHyphenationEvent.cs @@ -0,0 +1,83 @@ +using System; + +/* + * Copyright 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** Called by Chunk to hyphenate a word. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public interface IHyphenationEvent { + + /** Gets the hyphen symbol. + * @return the hyphen symbol + */ + string HyphenSymbol { + get; + } + + /** Hyphenates a word and returns the first part of it. To get + * the second part of the hyphenated word call getHyphenatedWordPost(). + * @param word the word to hyphenate + * @param font the font used by this word + * @param fontSize the font size used by this word + * @param remainingWidth the width available to fit this word in + * @return the first part of the hyphenated word including + * the hyphen symbol, if any + */ + string GetHyphenatedWordPre(string word, BaseFont font, float fontSize, float remainingWidth); + + /** Gets the second part of the hyphenated word. Must be called + * after getHyphenatedWordPre(). + * @return the second part of the hyphenated word + */ + string HyphenatedWordPost { + get; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/IPdfOCG.cs b/iTechSharp/iTextSharp/text/pdf/IPdfOCG.cs new file mode 100644 index 0000000..1a6d4bf --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/IPdfOCG.cs @@ -0,0 +1,73 @@ +using System; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * The interface common to all layer types. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public interface IPdfOCG { + + /** + * Gets the PdfIndirectReference that represents this layer. + * @return the PdfIndirectReference that represents this layer + */ + PdfIndirectReference Ref { + get; + } + + /** + * Gets the object representing the layer. + * @return the object representing the layer + */ + PdfObject PdfObject { + get; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/IPdfPCellEvent.cs b/iTechSharp/iTextSharp/text/pdf/IPdfPCellEvent.cs new file mode 100644 index 0000000..bf4e680 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/IPdfPCellEvent.cs @@ -0,0 +1,29 @@ +using System; + +namespace iTextSharp.text.pdf +{ + /// + /// Summary description for IPdfPCellEvent. + /// + public interface IPdfPCellEvent { + /** This method is called at the end of the cell rendering. The text or graphics are added to + * one of the 4 PdfContentByte contained in + * canvases.
    + * The indexes to canvases are:

    + *

      + *
    • PdfPTable.BASECANVAS - the original PdfContentByte. Anything placed here + * will be under the cell. + *
    • PdfPTable.BACKGROUNDCANVAS - the layer where the background goes to. + *
    • PdfPTable.LINECANVAS - the layer where the lines go to. + *
    • PdfPTable.TEXTCANVAS - the layer where the text go to. Anything placed here + * will be over the cell. + *
    + * The layers are placed in sequence on top of each other. + *

    + * @param cell the cell + * @param position the coordinates of the cell + * @param canvases an array of PdfContentByte + */ + void CellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases); + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/IPdfPTableEvent.cs b/iTechSharp/iTextSharp/text/pdf/IPdfPTableEvent.cs new file mode 100644 index 0000000..0762633 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/IPdfPTableEvent.cs @@ -0,0 +1,96 @@ +using System; + +/* + * $Id: IPdfPTableEvent.cs,v 1.3 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** An interface that can be used to retrieve the position of cells in PdfPTable. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public interface IPdfPTableEvent { + + /** This method is called at the end of the table rendering. The text or graphics are added to + * one of the 4 PdfContentByte contained in + * canvases.
    + * The indexes to canvases are:

    + *

      + *
    • PdfPTable.BASECANVAS - the original PdfContentByte. Anything placed here + * will be under the table. + *
    • PdfPTable.BACKGROUNDCANVAS - the layer where the background goes to. + *
    • PdfPTable.LINECANVAS - the layer where the lines go to. + *
    • PdfPTable.TEXTCANVAS - the layer where the text go to. Anything placed here + * will be over the table. + *
    + * The layers are placed in sequence on top of each other. + *

    + * The widths and heights have the coordinates of the cells.
    + * The size of the widths array is the number of rows. + * Each sub-array in widths corresponds to the x column border positions where + * the first element is the x coordinate of the left table border and the last + * element is the x coordinate of the right table border. + * If colspan is not used all the sub-arrays in widths + * are the same.
    + * For the heights the first element is the y coordinate of the top table border and the last + * element is the y coordinate of the bottom table border. + * @param table the PdfPTable in use + * @param widths an array of arrays with the cells' x positions. It has the length of the number + * of rows + * @param heights an array with the cells' y positions. It has a length of the number + * of rows + 1 + * @param headerRows the number of rows defined for the header. + * @param rowStart the first row number after the header + * @param canvases an array of PdfContentByte + */ + void TableLayout(PdfPTable table, float[][] widths, float[] heights, int headerRows, int rowStart, PdfContentByte[] canvases); + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/IPdfPageEvent.cs b/iTechSharp/iTextSharp/text/pdf/IPdfPageEvent.cs new file mode 100644 index 0000000..b441107 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/IPdfPageEvent.cs @@ -0,0 +1,189 @@ +using System; + +using iTextSharp.text; + +/* + * $Id: IPdfPageEvent.cs,v 1.3 2008/05/13 11:25:17 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Allows a class to catch several document events. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + + public interface IPdfPageEvent { + + /** + * Called when the document is opened. + * + * @param writer the PdfWriter for this document + * @param document the document + */ + void OnOpenDocument(PdfWriter writer, Document document); + + /** + * Called when a page is initialized. + *

    + * Note that if even if a page is not written this method is still + * called. It is preferable to use onEndPage to avoid + * infinite loops. + * + * @param writer the PdfWriter for this document + * @param document the document + */ + void OnStartPage(PdfWriter writer, Document document); + + /** + * Called when a page is finished, just before being written to the document. + * + * @param writer the PdfWriter for this document + * @param document the document + */ + void OnEndPage(PdfWriter writer, Document document); + + /** + * Called when the document is closed. + *

    + * Note that this method is called with the page number equal + * to the last page plus one. + * + * @param writer the PdfWriter for this document + * @param document the document + */ + void OnCloseDocument(PdfWriter writer, Document document); + + /** + * Called when a Paragraph is written. + *

    + * paragraphPosition will hold the height at which the + * paragraph will be written to. This is useful to insert bookmarks with + * more control. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position the paragraph will be written to + */ + void OnParagraph(PdfWriter writer, Document document, float paragraphPosition); + + /** + * Called when a Paragraph is written. + *

    + * paragraphPosition will hold the height of the end of the paragraph. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position of the end of the paragraph + */ + void OnParagraphEnd(PdfWriter writer,Document document,float paragraphPosition); + + /** + * Called when a Chapter is written. + *

    + * position will hold the height at which the + * chapter will be written to. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position the chapter will be written to + * @param title the title of the Chapter + */ + void OnChapter(PdfWriter writer,Document document,float paragraphPosition, Paragraph title); + + /** + * Called when the end of a Chapter is reached. + *

    + * position will hold the height of the end of the chapter. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position the chapter will be written to + */ + void OnChapterEnd(PdfWriter writer,Document document,float paragraphPosition); + + /** + * Called when a Section is written. + *

    + * position will hold the height at which the + * section will be written to. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position the chapter will be written to + * @param title the title of the Chapter + */ + void OnSection(PdfWriter writer,Document document,float paragraphPosition, int depth, Paragraph title); + + /** + * Called when the end of a Section is reached. + *

    + * position will hold the height of the section end. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position the chapter will be written to + */ + void OnSectionEnd(PdfWriter writer,Document document,float paragraphPosition); + + /** + * Called when a Chunk with a generic tag is written. + *

    + * It is usefull to pinpoint the Chunk location to generate + * bookmarks, for example. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param rect the Rectangle containing the Chunk + * @param text the text of the tag + */ + void OnGenericTag(PdfWriter writer, Document document, Rectangle rect, string text); + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/IntHashtable.cs b/iTechSharp/iTextSharp/text/pdf/IntHashtable.cs new file mode 100644 index 0000000..57aae9e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/IntHashtable.cs @@ -0,0 +1,312 @@ +using System; + +// IntHashtable - a Hashtable that uses ints as the keys +// +// This is 90% based on JavaSoft's java.util.Hashtable. +// +// Visit the ACME Labs Java page for up-to-date versions of this and other +// fine Java utilities: http://www.acme.com/java/ + +namespace iTextSharp.text.pdf { + + /// A Hashtable that uses ints as the keys. + //

    + // Use just like java.util.Hashtable, except that the keys must be ints. + // This is much faster than creating a new int for each access. + //

    + // Fetch the software.
    + // Fetch the entire Acme package. + //

    + // @see java.util.Hashtable + + public class IntHashtable { + /// The hash table data. + private IntHashtableEntry[] table; + + /// The total number of entries in the hash table. + private int count; + + /// Rehashes the table when count exceeds this threshold. + private int threshold; + + /// The load factor for the hashtable. + private float loadFactor; + + /// Constructs a new, empty hashtable with the specified initial + // capacity and the specified load factor. + // @param initialCapacity the initial number of buckets + // @param loadFactor a number between 0.0 and 1.0, it defines + // the threshold for rehashing the hashtable into + // a bigger one. + // @exception IllegalArgumentException If the initial capacity + // is less than or equal to zero. + // @exception IllegalArgumentException If the load factor is + // less than or equal to zero. + public IntHashtable( int initialCapacity, float loadFactor ) { + if ( initialCapacity <= 0 || loadFactor <= 0.0 ) + throw new ArgumentException(); + this.loadFactor = loadFactor; + table = new IntHashtableEntry[initialCapacity]; + threshold = (int) ( initialCapacity * loadFactor ); + } + + /// Constructs a new, empty hashtable with the specified initial + // capacity. + // @param initialCapacity the initial number of buckets + public IntHashtable( int initialCapacity ) : this( initialCapacity, 0.75f ) {} + + /// Constructs a new, empty hashtable. A default capacity and load factor + // is used. Note that the hashtable will automatically grow when it gets + // full. + public IntHashtable() : this( 101, 0.75f ) {} + + /// Returns the number of elements contained in the hashtable. + public int Size { + get { + return count; + } + } + + /// Returns true if the hashtable contains no elements. + public bool IsEmpty() { + return count == 0; + } + + /// Returns true if the specified object is an element of the hashtable. + // This operation is more expensive than the ContainsKey() method. + // @param value the value that we are looking for + // @exception NullPointerException If the value being searched + // for is equal to null. + // @see IntHashtable#containsKey + public bool Contains( int value ) { + IntHashtableEntry[] tab = table; + for ( int i = tab.Length ; i-- > 0 ; ) { + for ( IntHashtableEntry e = tab[i] ; e != null ; e = e.next ) { + if ( e.value == value ) + return true; + } + } + return false; + } + + /// Returns true if the collection contains an element for the key. + // @param key the key that we are looking for + // @see IntHashtable#contains + public bool ContainsKey( int key ) { + IntHashtableEntry[] tab = table; + int hash = key; + int index = ( hash & 0x7FFFFFFF ) % tab.Length; + for ( IntHashtableEntry e = tab[index] ; e != null ; e = e.next ) { + if ( e.hash == hash && e.key == key ) + return true; + } + return false; + } + + /// Gets the object associated with the specified key in the + // hashtable. + // @param key the specified key + // @returns the element for the key or null if the key + // is not defined in the hash table. + // @see IntHashtable#put + public int this[int key] { + get { + IntHashtableEntry[] tab = table; + int hash = key; + int index = ( hash & 0x7FFFFFFF ) % tab.Length; + for ( IntHashtableEntry e = tab[index] ; e != null ; e = e.next ) { + if ( e.hash == hash && e.key == key ) + return e.value; + } + return 0; + } + + set { + // Makes sure the key is not already in the hashtable. + IntHashtableEntry[] tab = table; + int hash = key; + int index = ( hash & 0x7FFFFFFF ) % tab.Length; + for ( IntHashtableEntry e = tab[index] ; e != null ; e = e.next ) { + if ( e.hash == hash && e.key == key ) { + e.value = value; + return; + } + } + + if ( count >= threshold ) { + // Rehash the table if the threshold is exceeded. + Rehash(); + this[key] = value; + return; + } + + // Creates the new entry. + IntHashtableEntry en = new IntHashtableEntry(); + en.hash = hash; + en.key = key; + en.value = value; + en.next = tab[index]; + tab[index] = en; + ++count; + } + } + + /// Rehashes the content of the table into a bigger table. + // This method is called automatically when the hashtable's + // size exceeds the threshold. + protected void Rehash() { + int oldCapacity = table.Length; + IntHashtableEntry[] oldTable = table; + + int newCapacity = oldCapacity * 2 + 1; + IntHashtableEntry[] newTable = new IntHashtableEntry[newCapacity]; + + threshold = (int) ( newCapacity * loadFactor ); + table = newTable; + + for ( int i = oldCapacity ; i-- > 0 ; ) { + for ( IntHashtableEntry old = oldTable[i] ; old != null ; ) { + IntHashtableEntry e = old; + old = old.next; + + int index = ( e.hash & 0x7FFFFFFF ) % newCapacity; + e.next = newTable[index]; + newTable[index] = e; + } + } + } + + /// Removes the element corresponding to the key. Does nothing if the + // key is not present. + // @param key the key that needs to be removed + // @return the value of key, or null if the key was not found. + public int Remove( int key ) { + IntHashtableEntry[] tab = table; + int hash = key; + int index = ( hash & 0x7FFFFFFF ) % tab.Length; + for ( IntHashtableEntry e = tab[index], prev = null ; e != null ; prev = e, e = e.next ) { + if ( e.hash == hash && e.key == key ) { + if ( prev != null ) + prev.next = e.next; + else + tab[index] = e.next; + --count; + return e.value; + } + } + return 0; + } + + /// Clears the hash table so that it has no more elements in it. + public void Clear() { + IntHashtableEntry[] tab = table; + for ( int index = tab.Length; --index >= 0; ) + tab[index] = null; + count = 0; + } + + public IntHashtable Clone() { + IntHashtable t = new IntHashtable(); + t.count = count; + t.loadFactor = loadFactor; + t.threshold = threshold; + t.table = new IntHashtableEntry[table.Length]; + for (int i = table.Length ; i-- > 0 ; ) { + t.table[i] = (table[i] != null) + ? (IntHashtableEntry)table[i].Clone() : null; + } + return t; + } + + public int[] ToOrderedKeys() { + int[] res = GetKeys(); + Array.Sort(res); + return res; + } + + public int[] GetKeys() { + int[] res = new int[count]; + int ptr = 0; + int index = table.Length; + IntHashtableEntry entry = null; + while (true) { + if (entry == null) + while ((index-- > 0) && ((entry = table[index]) == null)); + if (entry == null) + break; + IntHashtableEntry e = entry; + entry = e.next; + res[ptr++] = e.key; + } + return res; + } + + public class IntHashtableEntry { + internal int hash; + internal int key; + internal int value; + internal IntHashtableEntry next; + + public int Key { + get { + return key; + } + } + + public int Value { + get { + return value; + } + } + + protected internal IntHashtableEntry Clone() { + IntHashtableEntry entry = new IntHashtableEntry(); + entry.hash = hash; + entry.key = key; + entry.value = value; + entry.next = (next != null) ? next.Clone() : null; + return entry; + } + } + + public IntHashtableIterator GetEntryIterator() { + return new IntHashtableIterator(table); + } + + public class IntHashtableIterator { + // boolean keys; + int index; + IntHashtableEntry[] table; + IntHashtableEntry entry; + + internal IntHashtableIterator(IntHashtableEntry[] table) { + this.table = table; + this.index = table.Length; + } + + public bool HasNext() { + if (entry != null) { + return true; + } + while (index-- > 0) { + if ((entry = table[index]) != null) { + return true; + } + } + return false; + } + + public IntHashtableEntry Next() { + if (entry == null) { + while ((index-- > 0) && ((entry = table[index]) == null)); + } + if (entry != null) { + IntHashtableEntry e = entry; + entry = e.next; + return e; + } + throw new InvalidOperationException("IntHashtableIterator"); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/LZWDecoder.cs b/iTechSharp/iTextSharp/text/pdf/LZWDecoder.cs new file mode 100644 index 0000000..cad5aff --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/LZWDecoder.cs @@ -0,0 +1,240 @@ +using System; +using System.IO; +using System.Collections; + +/* + * Copyright 2002-2008 by Paulo Soares. + * + * This code was originally released in 2001 by SUN (see class + * com.sun.media.imageioimpl.plugins.tiff.TIFFLZWDecompressor.java) + * using the BSD license in a specific wording. In a mail dating from + * January 23, 2008, Brian Burkhalter (@sun.com) gave us permission + * to use the code under the following version of the BSD license: + * + * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL + * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF + * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR + * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for + * use in the design, construction, operation or maintenance of any + * nuclear facility. + */ +namespace iTextSharp.text.pdf { + /** + * A class for performing LZW decoding. + * + * + */ + public class LZWDecoder { + + byte[][] stringTable; + byte[] data = null; + Stream uncompData; + int tableIndex, bitsToGet = 9; + int bytePointer; + int nextData = 0; + int nextBits = 0; + + internal int[] andTable = { + 511, + 1023, + 2047, + 4095 + }; + + public LZWDecoder() { + } + + /** + * Method to decode LZW compressed data. + * + * @param data The compressed data. + * @param uncompData Array to return the uncompressed data in. + */ + public void Decode(byte[] data, Stream uncompData) { + + if (data[0] == (byte)0x00 && data[1] == (byte)0x01) { + throw new Exception("LZW flavour not supported."); + } + + InitializeStringTable(); + + this.data = data; + this.uncompData = uncompData; + + // Initialize pointers + bytePointer = 0; + + nextData = 0; + nextBits = 0; + + int code, oldCode = 0; + byte[] str; + + while ((code = this.NextCode) != 257) { + + if (code == 256) { + + InitializeStringTable(); + code = NextCode; + + if (code == 257) { + break; + } + + WriteString(stringTable[code]); + oldCode = code; + + } else { + + if (code < tableIndex) { + + str = stringTable[code]; + + WriteString(str); + AddStringToTable(stringTable[oldCode], str[0]); + oldCode = code; + + } else { + + str = stringTable[oldCode]; + str = ComposeString(str, str[0]); + WriteString(str); + AddStringToTable(str); + oldCode = code; + } + } + } + } + + + /** + * Initialize the string table. + */ + public void InitializeStringTable() { + + stringTable = new byte[8192][]; + + for (int i=0; i<256; i++) { + stringTable[i] = new byte[1]; + stringTable[i][0] = (byte)i; + } + + tableIndex = 258; + bitsToGet = 9; + } + + /** + * Write out the string just uncompressed. + */ + public void WriteString(byte[] str) { + uncompData.Write(str, 0, str.Length); + } + + /** + * Add a new string to the string table. + */ + public void AddStringToTable(byte[] oldstring, byte newstring) { + int length = oldstring.Length; + byte[] str = new byte[length + 1]; + Array.Copy(oldstring, 0, str, 0, length); + str[length] = newstring; + + // Add this new string to the table + stringTable[tableIndex++] = str; + + if (tableIndex == 511) { + bitsToGet = 10; + } else if (tableIndex == 1023) { + bitsToGet = 11; + } else if (tableIndex == 2047) { + bitsToGet = 12; + } + } + + /** + * Add a new string to the string table. + */ + public void AddStringToTable(byte[] str) { + + // Add this new string to the table + stringTable[tableIndex++] = str; + + if (tableIndex == 511) { + bitsToGet = 10; + } else if (tableIndex == 1023) { + bitsToGet = 11; + } else if (tableIndex == 2047) { + bitsToGet = 12; + } + } + + /** + * Append newstring to the end of oldstring. + */ + public byte[] ComposeString(byte[] oldstring, byte newstring) { + int length = oldstring.Length; + byte[] str = new byte[length + 1]; + Array.Copy(oldstring, 0, str, 0, length); + str[length] = newstring; + + return str; + } + + // Returns the next 9, 10, 11 or 12 bits + public int NextCode { + get { + // Attempt to get the next code. The exception is caught to make + // this robust to cases wherein the EndOfInformation code has been + // omitted from a strip. Examples of such cases have been observed + // in practice. + try { + nextData = (nextData << 8) | (data[bytePointer++] & 0xff); + nextBits += 8; + + if (nextBits < bitsToGet) { + nextData = (nextData << 8) | (data[bytePointer++] & 0xff); + nextBits += 8; + } + + int code = + (nextData >> (nextBits - bitsToGet)) & andTable[bitsToGet-9]; + nextBits -= bitsToGet; + + return code; + } catch { + // Strip not terminated as expected: return EndOfInformation code. + return 257; + } + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/MultiColumnText.cs b/iTechSharp/iTextSharp/text/pdf/MultiColumnText.cs new file mode 100644 index 0000000..3551982 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/MultiColumnText.cs @@ -0,0 +1,605 @@ +using System; +using System.Collections; +using iTextSharp.text; +/* + * $Id: MultiColumnText.cs,v 1.13 2008/05/13 11:25:18 psoares33 Exp $ + * + * + * Copyright 2004 Steve Appling + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Formats content into one or more columns bounded by a + * rectangle. The columns may be simple rectangles or + * more complicated shapes. Add all of the columns before + * adding content. Column continuation is supported. A MultiColumnText object may be added to + * a document using Document.add. + * @author Steve Appling + */ + public class MultiColumnText : IElement { + + /** special constant for automatic calculation of height */ + public const float AUTOMATIC = -1f; + + /** + * total desiredHeight of columns. If AUTOMATIC, this means fill pages until done. + * This may be larger than one page + */ + private float desiredHeight; + + /** + * total height of element written out so far + */ + private float totalHeight; + + /** + * true if all the text could not be written out due to height restriction + */ + private bool overflow; + + /** + * Top of the columns - y position on starting page. + * If AUTOMATIC, it means current y position when added to document + */ + private float top; + + /** + * used to store the y position of the bottom of the page + */ + private float pageBottom; + + /** + * ColumnText object used to do all the real work. This same object is used for all columns + */ + private ColumnText columnText; + + /** + * Array of ColumnDef objects used to define the columns + */ + private ArrayList columnDefs; + + /** + * true if all columns are simple (rectangular) + */ + private bool simple = true; + + private int currentColumn = 0; + + private float nextY = AUTOMATIC; + + private bool columnsRightToLeft = false; + + private PdfDocument document; + /** + * Default constructor. Sets height to AUTOMATIC. + * Columns will repeat on each page as necessary to accomodate content length. + */ + public MultiColumnText() : this(AUTOMATIC) { + } + + /** + * Construct a MultiColumnText container of the specified height. + * If height is AUTOMATIC, fill complete pages until done. + * If a specific height is used, it may span one or more pages. + * + * @param height + */ + public MultiColumnText(float height) { + columnDefs = new ArrayList(); + desiredHeight = height; + top = AUTOMATIC; + // canvas will be set later + columnText = new ColumnText(null); + totalHeight = 0f; + } + + /** + * Construct a MultiColumnText container of the specified height + * starting at the specified Y position. + * + * @param height + * @param top + */ + public MultiColumnText(float top, float height) { + columnDefs = new ArrayList(); + desiredHeight = height; + this.top = top; + nextY = top; + // canvas will be set later + columnText = new ColumnText(null); + totalHeight = 0f; + } + + /** + * Indicates that all of the text did not fit in the + * specified height. Note that isOverflow will return + * false before the MultiColumnText object has been + * added to the document. It will always be false if + * the height is AUTOMATIC. + * + * @return true if there is still space left in the column + */ + public bool IsOverflow() { + return overflow; + } + + /** + * Copy the parameters from the specified ColumnText to use + * when rendering. Parameters like setArabicOptions + * must be set in this way. + * + * @param sourceColumn + */ + public void UseColumnParams(ColumnText sourceColumn) { + // note that canvas will be overwritten later + columnText.SetSimpleVars(sourceColumn); + } + + /** + * Add a new column. The parameters are limits for each column + * wall in the format of a sequence of points (x1,y1,x2,y2,...). + * + * @param left limits for left column + * @param right limits for right column + */ + public void AddColumn(float[] left, float[] right) { + ColumnDef nextDef = new ColumnDef(left, right, this); + simple = nextDef.IsSimple(); + columnDefs.Add(nextDef); + } + + /** + * Add a simple rectangular column with specified left + * and right x position boundaries. + * + * @param left left boundary + * @param right right boundary + */ + public void AddSimpleColumn(float left, float right) { + ColumnDef newCol = new ColumnDef(left, right, this); + columnDefs.Add(newCol); + } + + /** + * Add the specified number of evenly spaced rectangular columns. + * Columns will be seperated by the specified gutterWidth. + * + * @param left left boundary of first column + * @param right right boundary of last column + * @param gutterWidth width of gutter spacing between columns + * @param numColumns number of columns to add + */ + public void AddRegularColumns(float left, float right, float gutterWidth, int numColumns) { + float currX = left; + float width = right - left; + float colWidth = (width - (gutterWidth * (numColumns - 1))) / numColumns; + for (int i = 0; i < numColumns; i++) { + AddSimpleColumn(currX, currX + colWidth); + currX += colWidth + gutterWidth; + } + } + + /** + * Add an element to be rendered in a column. + * Note that you can only add a Phrase + * or a Chunk if the columns are + * not all simple. This is an underlying restriction in + * {@link com.lowagie.text.pdf.ColumnText} + * + * @param element element to add + * @throws DocumentException if element can't be added + */ + public void AddElement(IElement element) { + if (simple) { + columnText.AddElement(element); + } else if (element is Phrase) { + columnText.AddText((Phrase) element); + } else if (element is Chunk) { + columnText.AddText((Chunk) element); + } else { + throw new DocumentException("Can't add " + element.GetType().ToString() + " to MultiColumnText with complex columns"); + } + } + + + /** + * Write out the columns. After writing, use + * {@link #isOverflow()} to see if all text was written. + * @param canvas PdfContentByte to write with + * @param document document to write to (only used to get page limit info) + * @param documentY starting y position to begin writing at + * @return the current height (y position) after writing the columns + * @throws DocumentException on error + */ + public float Write(PdfContentByte canvas, PdfDocument document, float documentY) { + this.document = document; + columnText.Canvas = canvas; + if (columnDefs.Count == 0) { + throw new DocumentException("MultiColumnText has no columns"); + } + overflow = false; + pageBottom = document.Bottom; + float currentHeight = 0; + bool done = false; + while (!done) { + if (top == AUTOMATIC) { + top = document.GetVerticalPosition(true); + } + else if (nextY == AUTOMATIC) { + nextY = document.GetVerticalPosition(true); // RS - 07/07/2005 - - Get current doc writing position for top of columns on new page. + } + + ColumnDef currentDef = (ColumnDef) columnDefs[CurrentColumn]; + columnText.YLine = top; + + float[] left = currentDef.ResolvePositions(Rectangle.LEFT_BORDER); + float[] right = currentDef.ResolvePositions(Rectangle.RIGHT_BORDER); + if (document.IsMarginMirroring() && document.PageNumber % 2 == 0){ + float delta = document.RightMargin - document.Left; + left = (float[])left.Clone(); + right = (float[])right.Clone(); + for (int i = 0; i < left.Length; i += 2) { + left[i] -= delta; + } + for (int i = 0; i < right.Length; i += 2) { + right[i] -= delta; + } + } + currentHeight = Math.Max(currentHeight, GetHeight(left, right)); + + if (currentDef.IsSimple()) { + columnText.SetSimpleColumn(left[2], left[3], right[0], right[1]); + } else { + columnText.SetColumns(left, right); + } + + int result = columnText.Go(); + if ((result & ColumnText.NO_MORE_TEXT) != 0) { + done = true; + top = columnText.YLine; + } else if (ShiftCurrentColumn()) { + top = nextY; + } else { // check if we are done because of height + totalHeight += currentHeight; + + if ((desiredHeight != AUTOMATIC) && (totalHeight >= desiredHeight)) { + overflow = true; + break; + } else { // need to start new page and reset the columns + documentY = nextY; + NewPage(); + currentHeight = 0; + } + } + } + if (desiredHeight == AUTOMATIC && columnDefs.Count == 1) { + currentHeight = documentY - columnText.YLine; + } + return currentHeight; + } + + private void NewPage() { + ResetCurrentColumn(); + if (desiredHeight == AUTOMATIC) { + top = nextY = AUTOMATIC; + } + else { + top = nextY; + } + totalHeight = 0; + if (document != null) { + document.NewPage(); + } + } + + /** + * Figure out the height of a column from the border extents + * + * @param left left border + * @param right right border + * @return height + */ + private float GetHeight(float[] left, float[] right) { + float max = float.MinValue; + float min = float.MaxValue; + for (int i = 0; i < left.Length; i += 2) { + min = Math.Min(min, left[i + 1]); + max = Math.Max(max, left[i + 1]); + } + for (int i = 0; i < right.Length; i += 2) { + min = Math.Min(min, right[i + 1]); + max = Math.Max(max, right[i + 1]); + } + return max - min; + } + + + /** + * Processes the element by adding it to an + * ElementListener. + * + * @param listener an ElementListener + * @return true if the element was processed successfully + */ + public bool Process(IElementListener listener) { + try { + return listener.Add(this); + } catch (DocumentException) { + return false; + } + } + + /** + * Gets the type of the text element. + * + * @return a type + */ + + public int Type { + get { + return Element.MULTI_COLUMN_TEXT; + } + } + + /** + * Returns null - not used + * + * @return null + */ + + public ArrayList Chunks { + get { + return null; + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return false; + } + + /** + * Calculates the appropriate y position for the bottom + * of the columns on this page. + * + * @return the y position of the bottom of the columns + */ + private float GetColumnBottom() { + if (desiredHeight == AUTOMATIC) { + return pageBottom; + } else { + return Math.Max(top - (desiredHeight - totalHeight), pageBottom); + } + } + + /** + * Moves the text insertion point to the beginning of the next column, issuing a page break if + * needed. + * @throws DocumentException on error + */ + public void NextColumn() { + currentColumn = (currentColumn + 1) % columnDefs.Count; + top = nextY; + if (currentColumn == 0) { + NewPage(); + } + } + + /** + * Gets the current column. + * @return the current column + */ + public int CurrentColumn { + get { + if (columnsRightToLeft) { + return (columnDefs.Count - currentColumn - 1); + } + return currentColumn; + } + } + + /** + * Resets the current column. + */ + public void ResetCurrentColumn() { + currentColumn = 0; + } + + /** + * Shifts the current column. + * @return true if the currentcolumn has changed + */ + public bool ShiftCurrentColumn() { + if (currentColumn + 1 < columnDefs.Count) { + currentColumn++; + return true; + } + return false; + } + + /** + * Sets the direction of the columns. + * @param direction true = right2left; false = left2right + */ + public void SetColumnsRightToLeft(bool direction) { + columnsRightToLeft = direction; + } + + /** Sets the ratio between the extra word spacing and the extra character spacing + * when the text is fully justified. + * Extra word spacing will grow spaceCharRatio times more than extra character spacing. + * If the ratio is PdfWriter.NO_SPACE_CHAR_RATIO then the extra character spacing + * will be zero. + * @param spaceCharRatio the ratio between the extra word spacing and the extra character spacing + */ + public float SpaceCharRatio { + set { + columnText.SpaceCharRatio = value; + } + } + + /** Sets the run direction. + * @param runDirection the run direction + */ + public int RunDirection { + set { + columnText.RunDirection = value; + } + } + + /** Sets the arabic shaping options. The option can be AR_NOVOWEL, + * AR_COMPOSEDTASHKEEL and AR_LIG. + * @param arabicOptions the arabic shaping options + */ + public int ArabicOptions { + set { + columnText.ArabicOptions = value; + } + } + + /** Sets the default alignment + * @param alignment the default alignment + */ + public int Alignment { + set { + columnText.Alignment = value; + } + } + + public override string ToString() { + return base.ToString(); + } + + /** + * Inner class used to define a column + */ + internal class ColumnDef { + private float[] left; + private float[] right; + private MultiColumnText mc; + + internal ColumnDef(float[] newLeft, float[] newRight, MultiColumnText mc) { + this.mc = mc; + left = newLeft; + right = newRight; + } + + internal ColumnDef(float leftPosition, float rightPosition, MultiColumnText mc) { + this.mc = mc; + left = new float[4]; + left[0] = leftPosition; // x1 + left[1] = mc.top; // y1 + left[2] = leftPosition; // x2 + if (mc.desiredHeight == AUTOMATIC || mc.top == AUTOMATIC) { + left[3] = AUTOMATIC; + } else { + left[3] = mc.top - mc.desiredHeight; + } + + right = new float[4]; + right[0] = rightPosition; // x1 + right[1] = mc.top; // y1 + right[2] = rightPosition; // x2 + if (mc.desiredHeight == AUTOMATIC || mc.top == AUTOMATIC) { + right[3] = AUTOMATIC; + } else { + right[3] = mc.top - mc.desiredHeight; + } + } + + /** + * Resolves the positions for the specified side of the column + * into real numbers once the top of the column is known. + * + * @param side either Rectangle.LEFT_BORDER + * or Rectangle.RIGHT_BORDER + * @return the array of floats for the side + */ + internal float[] ResolvePositions(int side) { + if (side == Rectangle.LEFT_BORDER) { + return ResolvePositions(left); + } else { + return ResolvePositions(right); + } + } + + internal float[] ResolvePositions(float[] positions) { + if (!IsSimple()) { + return positions; + } + if (mc.top == AUTOMATIC) { + // this is bad - must be programmer error + throw new Exception("resolvePositions called with top=AUTOMATIC (-1). " + + "Top position must be set befure lines can be resolved"); + } + positions[1] = mc.top; + positions[3] = mc.GetColumnBottom(); + return positions; + } + + /** + * Checks if column definition is a simple rectangle + * @return true if it is a simple column + */ + internal bool IsSimple() { + return (left.Length == 4 && right.Length == 4) && (left[0] == left[2] && right[0] == right[2]); + } + + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/OutputStreamCounter.cs b/iTechSharp/iTextSharp/text/pdf/OutputStreamCounter.cs new file mode 100644 index 0000000..0058116 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/OutputStreamCounter.cs @@ -0,0 +1,81 @@ +using System; +using System.IO; + +namespace iTextSharp.text.pdf { + public class OutputStreamCounter : Stream { + protected Stream outc; + protected int counter = 0; + + public OutputStreamCounter(Stream _outc) { + outc = _outc; + } + + public int Counter { + get { + return counter; + } + } + + public void ResetCounter() { + counter = 0; + } + + public override bool CanRead { + get { + return false; + } + } + + public override bool CanSeek { + get { + return false; + } + } + + public override bool CanWrite { + get { + return true; + } + } + + public override long Length { + get { + throw new NotSupportedException(); + } + } + + public override long Position { + get { + throw new NotSupportedException(); + } + set { + throw new NotSupportedException(); + } + } + + public override void Flush() { + outc.Flush(); + } + + public override int Read(byte[] buffer, int offset, int count) { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) { + throw new NotSupportedException(); + } + + public override void SetLength(long value) { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) { + counter += count; + outc.Write(buffer, offset, count); + } + + public override void Close() { + outc.Close (); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/OutputStreamEncryption.cs b/iTechSharp/iTextSharp/text/pdf/OutputStreamEncryption.cs new file mode 100644 index 0000000..a6295c9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/OutputStreamEncryption.cs @@ -0,0 +1,170 @@ +using System; +using System.IO; +using iTextSharp.text.pdf.crypto; +/* + * $Id: OutputStreamEncryption.cs,v 1.3 2007/04/29 13:57:07 psoares33 Exp $ + * + * Copyright 2006 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + public class OutputStreamEncryption : Stream { + protected Stream outc; + protected ARCFOUREncryption arcfour; + protected AESCipher cipher; + private byte[] buf = new byte[1]; + private const int AES_128 = 4; + private bool aes; + private bool finished; + + public OutputStreamEncryption(Stream outc, byte[] key, int off, int len, int revision) { + this.outc = outc; + aes = revision == AES_128; + if (aes) { + byte[] iv = IVGenerator.GetIV(); + byte[] nkey = new byte[len]; + System.Array.Copy(key, off, nkey, 0, len); + cipher = new AESCipher(true, nkey, iv); + Write(iv, 0, iv.Length); + } + else { + arcfour = new ARCFOUREncryption(); + arcfour.PrepareARCFOURKey(key, off, len); + } + } + + public OutputStreamEncryption(Stream outc, byte[] key, int revision) : this(outc, key, 0, key.Length, revision) { + } + + public override bool CanRead { + get { + return false; + } + } + + public override bool CanSeek { + get { + return false; + } + } + + public override bool CanWrite { + get { + return true; + } + } + + public override long Length { + get { + throw new NotSupportedException(); + } + } + + public override long Position { + get { + throw new NotSupportedException(); + } + set { + throw new NotSupportedException(); + } + } + + public override void Flush() { + outc.Flush(); + } + + public override int Read(byte[] buffer, int offset, int count) { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) { + throw new NotSupportedException(); + } + + public override void SetLength(long value) { + throw new NotSupportedException(); + } + + public override void Write(byte[] b, int off, int len) { + if (aes) { + byte[] b2 = cipher.Update(b, off, len); + if (b2 == null || b2.Length == 0) + return; + outc.Write(b2, 0, b2.Length); + } + else { + byte[] b2 = new byte[Math.Min(len, 4192)]; + while (len > 0) { + int sz = Math.Min(len, b2.Length); + arcfour.EncryptARCFOUR(b, off, sz, b2, 0); + outc.Write(b2, 0, sz); + len -= sz; + off += sz; + } + } + } + + public override void Close() { + Finish(); + outc.Close(); + } + + public override void WriteByte(byte value) { + buf[0] = value; + Write(buf, 0, 1); + } + + public void Finish() { + if (!finished) { + finished = true; + if (aes) { + byte[] b = cipher.DoFinal(); + outc.Write(b, 0, b.Length); + } + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PRAcroForm.cs b/iTechSharp/iTextSharp/text/pdf/PRAcroForm.cs new file mode 100644 index 0000000..f3c66f3 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PRAcroForm.cs @@ -0,0 +1,225 @@ +using System; +using System.Collections; +/* + * $Id: PRAcroForm.cs,v 1.5 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * This class written by Mark Thompson, Copyright (C) 2002 by Mark Thompson. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * This class captures an AcroForm on input. Basically, it extends Dictionary + * by indexing the fields of an AcroForm + * @author Mark Thompson + */ + + public class PRAcroForm : PdfDictionary { + + /** + * This class holds the information for a single field + */ + public class FieldInformation { + internal String name; + internal PdfDictionary info; + internal PRIndirectReference refi; + + internal FieldInformation(String name, PdfDictionary info, PRIndirectReference refi) { + this.name = name; this.info = info; this.refi = refi; + } + public String Name { + get { + return name; + } + } + public PdfDictionary Info { + get { + return info; + } + } + public PRIndirectReference Ref { + get { + return refi; + } + } + } + + internal ArrayList fields; + internal ArrayList stack; + internal Hashtable fieldByName; + internal PdfReader reader; + + /** + * Constructor + * @param reader reader of the input file + */ + public PRAcroForm(PdfReader reader) { + this.reader = reader; + fields = new ArrayList(); + fieldByName = new Hashtable(); + stack = new ArrayList(); + } + /** + * Number of fields found + * @return size + */ + public new int Size { + get { + return fields.Count; + } + } + + public ArrayList Fields { + get { + return fields; + } + } + + public FieldInformation GetField(String name) { + return (FieldInformation)fieldByName[name]; + } + + /** + * Given the title (/T) of a reference, return the associated reference + * @param name a string containing the path + * @return a reference to the field, or null + */ + public PRIndirectReference GetRefByName(String name) { + FieldInformation fi = (FieldInformation)fieldByName[name]; + if (fi == null) return null; + return fi.Ref; + } + /** + * Read, and comprehend the acroform + * @param root the docment root + */ + public void ReadAcroForm(PdfDictionary root) { + if (root == null) + return; + hashMap = root.hashMap; + PushAttrib(root); + PdfArray fieldlist = (PdfArray)PdfReader.GetPdfObjectRelease(root.Get(PdfName.FIELDS)); + IterateFields(fieldlist, null, null); + } + + /** + * After reading, we index all of the fields. Recursive. + * @param fieldlist An array of fields + * @param fieldDict the last field dictionary we encountered (recursively) + * @param title the pathname of the field, up to this point or null + */ + protected void IterateFields(PdfArray fieldlist, PRIndirectReference fieldDict, String title) { + foreach (PRIndirectReference refi in fieldlist.ArrayList) { + PdfDictionary dict = (PdfDictionary) PdfReader.GetPdfObjectRelease(refi); + + // if we are not a field dictionary, pass our parent's values + PRIndirectReference myFieldDict = fieldDict; + String myTitle = title; + PdfString tField = (PdfString)dict.Get(PdfName.T); + bool isFieldDict = tField != null; + + if (isFieldDict) { + myFieldDict = refi; + if (title == null) myTitle = tField.ToString(); + else myTitle = title + '.' + tField.ToString(); + } + + PdfArray kids = (PdfArray)dict.Get(PdfName.KIDS); + if (kids != null) { + PushAttrib(dict); + IterateFields(kids, myFieldDict, myTitle); + stack.RemoveAt(stack.Count - 1); // pop + } + else { // leaf node + if (myFieldDict != null) { + PdfDictionary mergedDict = (PdfDictionary)stack[stack.Count - 1]; + if (isFieldDict) + mergedDict = MergeAttrib(mergedDict, dict); + + mergedDict.Put(PdfName.T, new PdfString(myTitle)); + FieldInformation fi = new FieldInformation(myTitle, mergedDict, myFieldDict); + fields.Add(fi); + fieldByName[myTitle] = fi; + } + } + } + } + /** + * merge field attributes from two dictionaries + * @param parent one dictionary + * @param child the other dictionary + * @return a merged dictionary + */ + protected PdfDictionary MergeAttrib(PdfDictionary parent, PdfDictionary child) { + PdfDictionary targ = new PdfDictionary(); + if (parent != null) targ.Merge(parent); + + foreach (PdfName key in child.Keys) { + if (key.Equals(PdfName.DR) || key.Equals(PdfName.DA) || + key.Equals(PdfName.Q) || key.Equals(PdfName.FF) || + key.Equals(PdfName.DV) || key.Equals(PdfName.V) + || key.Equals(PdfName.FT) + || key.Equals(PdfName.F)) { + targ.Put(key,child.Get(key)); + } + } + return targ; + } + /** + * stack a level of dictionary. Merge in a dictionary from this level + */ + protected void PushAttrib(PdfDictionary dict) { + PdfDictionary dic = null; + if (stack.Count != 0) { + dic = (PdfDictionary)stack[stack.Count - 1]; + } + dic = MergeAttrib(dic, dict); + stack.Add(dic); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PRIndirectReference.cs b/iTechSharp/iTextSharp/text/pdf/PRIndirectReference.cs new file mode 100644 index 0000000..3800c9e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PRIndirectReference.cs @@ -0,0 +1,107 @@ +using System; +using System.Text; +using System.IO; + +/* + * $Id: PRIndirectReference.cs,v 1.3 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + public class PRIndirectReference : PdfIndirectReference { + + protected PdfReader reader; + // membervariables + + // constructors + + /** + * Constructs a PdfIndirectReference. + * + * @param reader a PdfReader + * @param number the object number. + * @param generation the generation number. + */ + + internal PRIndirectReference(PdfReader reader, int number, int generation) { + type = INDIRECT; + this.number = number; + this.generation = generation; + this.reader = reader; + } + + /** + * Constructs a PdfIndirectReference. + * + * @param reader a PdfReader + * @param number the object number. + */ + + internal PRIndirectReference(PdfReader reader, int number) : this(reader, number, 0) {} + + // methods + + public override void ToPdf(PdfWriter writer, Stream os) { + int n = writer.GetNewObjectNumber(reader, number, generation); + byte[] b = PdfEncodings.ConvertToBytes(new StringBuilder().Append(n).Append(" 0 R").ToString(), null); + os.Write(b, 0, b.Length); + } + + public PdfReader Reader { + get { + return reader; + } + } + + public void SetNumber(int number, int generation) { + this.number = number; + this.generation = generation; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PRStream.cs b/iTechSharp/iTextSharp/text/pdf/PRStream.cs new file mode 100644 index 0000000..d381d03 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PRStream.cs @@ -0,0 +1,205 @@ +using System; +using System.IO; + +using System.util.zlib; + +/* + * $Id: PRStream.cs,v 1.6 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + +public class PRStream : PdfStream { + + protected PdfReader reader; + protected int offset; + protected int length; + + //added by ujihara for decryption + protected int objNum = 0; + protected int objGen = 0; + + public PRStream(PRStream stream, PdfDictionary newDic) { + reader = stream.reader; + offset = stream.offset; + length = stream.Length; + compressed = stream.compressed; + streamBytes = stream.streamBytes; + bytes = stream.bytes; + objNum = stream.objNum; + objGen = stream.objGen; + if (newDic != null) + Merge(newDic); + else + Merge(stream); + } + + public PRStream(PRStream stream, PdfDictionary newDic, PdfReader reader) : this(stream, newDic) { + this.reader = reader; + } + + public PRStream(PdfReader reader, int offset) { + this.reader = reader; + this.offset = offset; + } + + public PRStream(PdfReader reader, byte[] conts) { + this.reader = reader; + this.offset = -1; + if (Document.Compress) { + MemoryStream stream = new MemoryStream(); + ZDeflaterOutputStream zip = new ZDeflaterOutputStream(stream); + zip.Write(conts, 0, conts.Length); + zip.Close(); + bytes = stream.ToArray(); + Put(PdfName.FILTER, PdfName.FLATEDECODE); + } + else + bytes = conts; + Length = bytes.Length; + } + + /** + * Sets the data associated with the stream, either compressed or + * uncompressed. Note that the data will never be compressed if + * Document.compress is set to false. + * + * @param data raw data, decrypted and uncompressed. + * @param compress true if you want the stream to be compresssed. + * @since iText 2.1.1 + */ + public void SetData(byte[] data, bool compress) { + Remove(PdfName.FILTER); + this.offset = -1; + if (Document.Compress && compress) { + MemoryStream stream = new MemoryStream(); + ZDeflaterOutputStream zip = new ZDeflaterOutputStream(stream); + zip.Write(data, 0, data.Length); + zip.Close(); + bytes = stream.ToArray(); + Put(PdfName.FILTER, PdfName.FLATEDECODE); + } + else + bytes = data; + Length = bytes.Length; + } + + /**Sets the data associated with the stream + * @param data raw data, decrypted and uncompressed. + */ + public void SetData(byte[] data) { + SetData(data, true); + } + + public new int Length { + set { + length = value; + Put(PdfName.LENGTH, new PdfNumber(length)); + } + get { + return length; + } + } + + public int Offset { + get { + return offset; + } + } + + public PdfReader Reader { + get { + return reader; + } + } + + public new byte[] GetBytes() { + return bytes; + } + + public int ObjNum { + get { + return objNum; + } + set { + objNum = value; + } + } + + public int ObjGen { + get { + return objGen; + } + set { + objGen = value; + } + } + + public override void ToPdf(PdfWriter writer, Stream os) { + byte[] b = PdfReader.GetStreamBytesRaw(this); + PdfEncryption crypto = null; + if (writer != null) + crypto = writer.Encryption; + PdfObject objLen = Get(PdfName.LENGTH); + int nn = b.Length; + if (crypto != null) + nn = crypto.CalculateStreamSize(nn); + Put(PdfName.LENGTH, new PdfNumber(nn)); + SuperToPdf(writer, os); + Put(PdfName.LENGTH, objLen); + os.Write(STARTSTREAM, 0, STARTSTREAM.Length); + if (length > 0) { + if (crypto != null) + b = crypto.EncryptByteArray(b); + os.Write(b, 0, b.Length); + } + os.Write(ENDSTREAM, 0, ENDSTREAM.Length); + } +} +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PRTokeniser.cs b/iTechSharp/iTextSharp/text/pdf/PRTokeniser.cs new file mode 100644 index 0000000..d8c7235 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PRTokeniser.cs @@ -0,0 +1,565 @@ +using System; +using System.IO; +using System.Text; + +/* + * Copyright 2001, 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PRTokeniser { + + public const int TK_NUMBER = 1; + public const int TK_STRING = 2; + public const int TK_NAME = 3; + public const int TK_COMMENT = 4; + public const int TK_START_ARRAY = 5; + public const int TK_END_ARRAY = 6; + public const int TK_START_DIC = 7; + public const int TK_END_DIC = 8; + public const int TK_REF = 9; + public const int TK_OTHER = 10; + + internal const string EMPTY = ""; + + + protected RandomAccessFileOrArray file; + protected int type; + protected string stringValue; + protected int reference; + protected int generation; + protected bool hexString; + + public PRTokeniser(string filename) { + file = new RandomAccessFileOrArray(filename); + } + + public PRTokeniser(byte[] pdfIn) { + file = new RandomAccessFileOrArray(pdfIn); + } + + public PRTokeniser(RandomAccessFileOrArray file) { + this.file = file; + } + + public void Seek(int pos) { + file.Seek(pos); + } + + public int FilePointer { + get { + return file.FilePointer; + } + } + + public void Close() { + file.Close(); + } + + public int Length { + get { + return file.Length; + } + } + + public int Read() { + return file.Read(); + } + + public RandomAccessFileOrArray SafeFile { + get { + return new RandomAccessFileOrArray(file); + } + } + + public RandomAccessFileOrArray File { + get { + return file; + } + } + + public string ReadString(int size) { + StringBuilder buf = new StringBuilder(); + int ch; + while ((size--) > 0) { + ch = file.Read(); + if (ch == -1) + break; + buf.Append((char)ch); + } + return buf.ToString(); + } + + public static bool IsWhitespace(int ch) { + return (ch == 0 || ch == 9 || ch == 10 || ch == 12 || ch == 13 || ch == 32); + } + + public static bool IsDelimiter(int ch) { + return (ch == '(' || ch == ')' || ch == '<' || ch == '>' || ch == '[' || ch == ']' || ch == '/' || ch == '%'); + } + + public int TokenType { + get { + return type; + } + } + + public string StringValue { + get { + return stringValue; + } + } + + public int Reference { + get { + return reference; + } + } + + public int Generation { + get { + return generation; + } + } + + public void BackOnePosition(int ch) { + if (ch != -1) + file.PushBack((byte)ch); + } + + public void ThrowError(string error) { + throw new IOException(error + " at file pointer " + file.FilePointer); + } + + public char CheckPdfHeader() { + file.StartOffset = 0; + String str = ReadString(1024); + int idx = str.IndexOf("%PDF-"); + if (idx < 0) + throw new IOException("PDF header signature not found."); + file.StartOffset = idx; + return str[idx + 7]; + } + + public void CheckFdfHeader() { + file.StartOffset = 0; + String str = ReadString(1024); + int idx = str.IndexOf("%FDF-1.2"); + if (idx < 0) + throw new IOException("FDF header signature not found."); + file.StartOffset = idx; + } + + public int Startxref { + get { + int size = Math.Min(1024, file.Length); + int pos = file.Length - size; + file.Seek(pos); + string str = ReadString(1024); + int idx = str.LastIndexOf("startxref"); + if (idx < 0) + throw new IOException("PDF startxref not found."); + return pos + idx; + } + } + + public static int GetHex(int v) { + if (v >= '0' && v <= '9') + return v - '0'; + if (v >= 'A' && v <= 'F') + return v - 'A' + 10; + if (v >= 'a' && v <= 'f') + return v - 'a' + 10; + return -1; + } + + public void NextValidToken() { + int level = 0; + string n1 = null; + string n2 = null; + int ptr = 0; + while (NextToken()) { + if (type == TK_COMMENT) + continue; + switch (level) { + case 0: { + if (type != TK_NUMBER) + return; + ptr = file.FilePointer; + n1 = stringValue; + ++level; + break; + } + case 1: { + if (type != TK_NUMBER) { + file.Seek(ptr); + type = TK_NUMBER; + stringValue = n1; + return; + } + n2 = stringValue; + ++level; + break; + } + default: { + if (type != TK_OTHER || !stringValue.Equals("R")) { + file.Seek(ptr); + type = TK_NUMBER; + stringValue = n1; + return; + } + type = TK_REF; + reference = int.Parse(n1); + generation = int.Parse(n2); + return; + } + } + } + ThrowError("Unexpected end of file"); + } + + public bool NextToken() { + StringBuilder outBuf = null; + stringValue = EMPTY; + int ch = 0; + do { + ch = file.Read(); + } while (ch != -1 && IsWhitespace(ch)); + if (ch == -1) + return false; + switch (ch) { + case '[': + type = TK_START_ARRAY; + break; + case ']': + type = TK_END_ARRAY; + break; + case '/': { + outBuf = new StringBuilder(); + type = TK_NAME; + while (true) { + ch = file.Read(); + if (ch == -1 || IsDelimiter(ch) || IsWhitespace(ch)) + break; + if (ch == '#') { + ch = (GetHex(file.Read()) << 4) + GetHex(file.Read()); + } + outBuf.Append((char)ch); + } + BackOnePosition(ch); + break; + } + case '>': + ch = file.Read(); + if (ch != '>') + ThrowError("'>' not expected"); + type = TK_END_DIC; + break; + case '<': { + int v1 = file.Read(); + if (v1 == '<') { + type = TK_START_DIC; + break; + } + outBuf = new StringBuilder(); + type = TK_STRING; + hexString = true; + int v2 = 0; + while (true) { + while (IsWhitespace(v1)) + v1 = file.Read(); + if (v1 == '>') + break; + v1 = GetHex(v1); + if (v1 < 0) + break; + v2 = file.Read(); + while (IsWhitespace(v2)) + v2 = file.Read(); + if (v2 == '>') { + ch = v1 << 4; + outBuf.Append((char)ch); + break; + } + v2 = GetHex(v2); + if (v2 < 0) + break; + ch = (v1 << 4) + v2; + outBuf.Append((char)ch); + v1 = file.Read(); + } + if (v1 < 0 || v2 < 0) + ThrowError("Error reading string"); + break; + } + case '%': + type = TK_COMMENT; + do { + ch = file.Read(); + } while (ch != -1 && ch != '\r' && ch != '\n'); + break; + case '(': { + outBuf = new StringBuilder(); + type = TK_STRING; + hexString = false; + int nesting = 0; + while (true) { + ch = file.Read(); + if (ch == -1) + break; + if (ch == '(') { + ++nesting; + } + else if (ch == ')') { + --nesting; + } + else if (ch == '\\') { + bool lineBreak = false; + ch = file.Read(); + switch (ch) { + case 'n': + ch = '\n'; + break; + case 'r': + ch = '\r'; + break; + case 't': + ch = '\t'; + break; + case 'b': + ch = '\b'; + break; + case 'f': + ch = '\f'; + break; + case '(': + case ')': + case '\\': + break; + case '\r': + lineBreak = true; + ch = file.Read(); + if (ch != '\n') + BackOnePosition(ch); + break; + case '\n': + lineBreak = true; + break; + default: { + if (ch < '0' || ch > '7') { + break; + } + int octal = ch - '0'; + ch = file.Read(); + if (ch < '0' || ch > '7') { + BackOnePosition(ch); + ch = octal; + break; + } + octal = (octal << 3) + ch - '0'; + ch = file.Read(); + if (ch < '0' || ch > '7') { + BackOnePosition(ch); + ch = octal; + break; + } + octal = (octal << 3) + ch - '0'; + ch = octal & 0xff; + break; + } + } + if (lineBreak) + continue; + if (ch < 0) + break; + } + else if (ch == '\r') { + ch = file.Read(); + if (ch < 0) + break; + if (ch != '\n') { + BackOnePosition(ch); + ch = '\n'; + } + } + if (nesting == -1) + break; + outBuf.Append((char)ch); + } + if (ch == -1) + ThrowError("Error reading string"); + break; + } + default: { + outBuf = new StringBuilder(); + if (ch == '-' || ch == '+' || ch == '.' || (ch >= '0' && ch <= '9')) { + type = TK_NUMBER; + do { + outBuf.Append((char)ch); + ch = file.Read(); + } while (ch != -1 && ((ch >= '0' && ch <= '9') || ch == '.')); + } + else { + type = TK_OTHER; + do { + outBuf.Append((char)ch); + ch = file.Read(); + } while (ch != -1 && !IsDelimiter(ch) && !IsWhitespace(ch)); + } + BackOnePosition(ch); + break; + } + } + if (outBuf != null) + stringValue = outBuf.ToString(); + return true; + } + + public int IntValue { + get { + return int.Parse(stringValue); + } + } + + public bool ReadLineSegment(byte[] input) { + int c = -1; + bool eol = false; + int ptr = 0; + int len = input.Length; + // ssteward, pdftk-1.10, 040922: + // skip initial whitespace; added this because PdfReader.RebuildXref() + // assumes that line provided by readLineSegment does not have init. whitespace; + if ( ptr < len ) { + while ( IsWhitespace( (c = Read()) ) ); + } + while ( !eol && ptr < len ) { + switch (c) { + case -1: + case '\n': + eol = true; + break; + case '\r': + eol = true; + int cur = FilePointer; + if ((Read()) != '\n') { + Seek(cur); + } + break; + default: + input[ptr++] = (byte)c; + break; + } + + // break loop? do it before we Read() again + if ( eol || len <= ptr ) { + break; + } + else { + c = Read(); + } + } + if (ptr >= len) { + eol = false; + while (!eol) { + switch (c = Read()) { + case -1: + case '\n': + eol = true; + break; + case '\r': + eol = true; + int cur = FilePointer; + if ((Read()) != '\n') { + Seek(cur); + } + break; + } + } + } + + if ((c == -1) && (ptr == 0)) { + return false; + } + if (ptr + 2 <= len) { + input[ptr++] = (byte)' '; + input[ptr] = (byte)'X'; + } + return true; + } + + public static int[] CheckObjectStart(byte[] line) { + try { + PRTokeniser tk = new PRTokeniser(line); + int num = 0; + int gen = 0; + if (!tk.NextToken() || tk.TokenType != TK_NUMBER) + return null; + num = tk.IntValue; + if (!tk.NextToken() || tk.TokenType != TK_NUMBER) + return null; + gen = tk.IntValue; + if (!tk.NextToken()) + return null; + if (!tk.StringValue.Equals("obj")) + return null; + return new int[]{num, gen}; + } + catch { + } + return null; + } + + public bool IsHexString() { + return this.hexString; + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PageResources.cs b/iTechSharp/iTextSharp/text/pdf/PageResources.cs new file mode 100644 index 0000000..81d44a8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PageResources.cs @@ -0,0 +1,194 @@ +using System; +using System.Collections; + +/* + * $Id: PageResources.cs,v 1.6 2006/09/24 15:48:24 psoares33 Exp $ + * + * Copyright 2003-2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + public class PageResources { + + protected PdfDictionary fontDictionary = new PdfDictionary(); + protected PdfDictionary xObjectDictionary = new PdfDictionary(); + protected PdfDictionary colorDictionary = new PdfDictionary(); + protected PdfDictionary patternDictionary = new PdfDictionary(); + protected PdfDictionary shadingDictionary = new PdfDictionary(); + protected PdfDictionary extGStateDictionary = new PdfDictionary(); + protected PdfDictionary propertyDictionary = new PdfDictionary(); + protected Hashtable forbiddenNames; + protected PdfDictionary originalResources; + protected int[] namePtr = {0}; + protected Hashtable usedNames; + + internal PageResources() { + } + + internal void SetOriginalResources(PdfDictionary resources, int[] newNamePtr) { + if (newNamePtr != null) + namePtr = newNamePtr; + forbiddenNames = new Hashtable(); + usedNames = new Hashtable(); + if (resources == null) + return; + originalResources = new PdfDictionary(); + originalResources.Merge(resources); + foreach (PdfName key in resources.Keys) { + PdfObject sub = PdfReader.GetPdfObject(resources.Get(key)); + if (sub != null && sub.IsDictionary()) { + PdfDictionary dic = (PdfDictionary)sub; + foreach (PdfName name in dic.Keys) { + forbiddenNames[name] = null; + } + PdfDictionary dic2 = new PdfDictionary(); + dic2.Merge(dic); + originalResources.Put(key, dic2); + } + } + } + + internal PdfName TranslateName(PdfName name) { + PdfName translated = name; + if (forbiddenNames != null) { + translated = (PdfName)usedNames[name]; + if (translated == null) { + while (true) { + translated = new PdfName("Xi" + (namePtr[0]++)); + if (!forbiddenNames.ContainsKey(translated)) + break; + } + usedNames[name] = translated; + } + } + return translated; + } + + internal PdfName AddFont(PdfName name, PdfIndirectReference reference) { + name = TranslateName(name); + fontDictionary.Put(name, reference); + return name; + } + + internal PdfName AddXObject(PdfName name, PdfIndirectReference reference) { + name = TranslateName(name); + xObjectDictionary.Put(name, reference); + return name; + } + + internal PdfName AddColor(PdfName name, PdfIndirectReference reference) { + name = TranslateName(name); + colorDictionary.Put(name, reference); + return name; + } + + internal void AddDefaultColor(PdfName name, PdfObject obj) { + if (obj == null || obj.IsNull()) + colorDictionary.Remove(name); + else + colorDictionary.Put(name, obj); + } + + internal void AddDefaultColor(PdfDictionary dic) { + colorDictionary.Merge(dic); + } + + internal void AddDefaultColorDiff(PdfDictionary dic) { + colorDictionary.MergeDifferent(dic); + } + + internal PdfName AddShading(PdfName name, PdfIndirectReference reference) { + name = TranslateName(name); + shadingDictionary.Put(name, reference); + return name; + } + + internal PdfName AddPattern(PdfName name, PdfIndirectReference reference) { + name = TranslateName(name); + patternDictionary.Put(name, reference); + return name; + } + + internal PdfName AddExtGState(PdfName name, PdfIndirectReference reference) { + name = TranslateName(name); + extGStateDictionary.Put(name, reference); + return name; + } + + internal PdfName AddProperty(PdfName name, PdfIndirectReference reference) { + name = TranslateName(name); + propertyDictionary.Put(name, reference); + return name; + } + + internal PdfDictionary Resources { + get { + PdfResources resources = new PdfResources(); + if (originalResources != null) + resources.Merge(originalResources); + resources.Put(PdfName.PROCSET, new PdfLiteral("[/PDF /Text /ImageB /ImageC /ImageI]")); + resources.Add(PdfName.FONT, fontDictionary); + resources.Add(PdfName.XOBJECT, xObjectDictionary); + resources.Add(PdfName.COLORSPACE, colorDictionary); + resources.Add(PdfName.PATTERN, patternDictionary); + resources.Add(PdfName.SHADING, shadingDictionary); + resources.Add(PdfName.EXTGSTATE, extGStateDictionary); + resources.Add(PdfName.PROPERTIES, propertyDictionary); + return resources; + } + } + + internal bool HasResources() { + return (fontDictionary.Size > 0 + || xObjectDictionary.Size > 0 + || colorDictionary.Size > 0 + || patternDictionary.Size > 0 + || shadingDictionary.Size > 0 + || extGStateDictionary.Size > 0 + || propertyDictionary.Size > 0); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PatternColor.cs b/iTechSharp/iTextSharp/text/pdf/PatternColor.cs new file mode 100644 index 0000000..b2d693a --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PatternColor.cs @@ -0,0 +1,82 @@ +using System; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Represents a pattern. Can be used in high-level constructs (Paragraph, Cell, etc.). + */ + public class PatternColor : ExtendedColor { + /** The actual pattern. + */ + PdfPatternPainter painter; + + /** Creates a color representing a pattern. + * @param painter the actual pattern + */ + public PatternColor(PdfPatternPainter painter) : base(TYPE_PATTERN, .5f, .5f, .5f) { + this.painter = painter; + } + + /** Gets the pattern. + * @return the pattern + */ + public PdfPatternPainter Painter { + get { + return this.painter; + } + } + + public override bool Equals(Object obj) { + return this == obj; + } + + public override int GetHashCode() { + return painter.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfAcroForm.cs b/iTechSharp/iTextSharp/text/pdf/PdfAcroForm.cs new file mode 100644 index 0000000..a82f2d3 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfAcroForm.cs @@ -0,0 +1,490 @@ +using System; +using System.Text; +using System.Collections; +using System.util; + +/* + * $Id: PdfAcroForm.cs,v 1.9 2008/05/13 11:25:18 psoares33 Exp $ + * + * + * Copyright 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + +/** + * Each PDF document can contain maximum 1 AcroForm. + */ + +public class PdfAcroForm : PdfDictionary { + + private PdfWriter writer; + + + /** This is a map containing FieldTemplates. */ + private Hashtable fieldTemplates = new Hashtable(); + + /** This is an array containing DocumentFields. */ + private PdfArray documentFields = new PdfArray(); + + /** This is an array containing the calculationorder of the fields. */ + private PdfArray calculationOrder = new PdfArray(); + + /** Contains the signature flags. */ + private int sigFlags = 0; + + /** Creates new PdfAcroForm */ + public PdfAcroForm(PdfWriter writer) : base() { + this.writer = writer; + } + + public bool NeedAppearances { + set { + Put(PdfName.NEEDAPPEARANCES, value ? PdfBoolean.PDFTRUE : PdfBoolean.PDFFALSE); + } + } + + + /** + * Adds fieldTemplates. + */ + + public void AddFieldTemplates(Hashtable ft) { + foreach (object key in ft.Keys) { + fieldTemplates[key] = ft[key]; + } + } + + /** + * Adds documentFields. + */ + + public void AddDocumentField(PdfIndirectReference piref) { + documentFields.Add(piref); + } + + /** + * Closes the AcroForm. + */ + + public bool IsValid() { + if (documentFields.Size == 0) return false; + Put(PdfName.FIELDS, documentFields); + if (sigFlags != 0) + Put(PdfName.SIGFLAGS, new PdfNumber(sigFlags)); + if (calculationOrder.Size > 0) + Put(PdfName.CO, calculationOrder); + if (fieldTemplates.Count == 0) return true; + PdfDictionary dic = new PdfDictionary(); + foreach (PdfTemplate template in fieldTemplates.Keys) { + PdfFormField.MergeResources(dic, (PdfDictionary)template.Resources); + } + Put(PdfName.DR, dic); + Put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g ")); + PdfDictionary fonts = (PdfDictionary)dic.Get(PdfName.FONT); + if (fonts != null) { + writer.EliminateFontSubset(fonts); + } + return true; + } + + /** + * Adds an object to the calculationOrder. + */ + + public void AddCalculationOrder(PdfFormField formField) { + calculationOrder.Add(formField.IndirectReference); + } + + /** + * Sets the signature flags. + */ + + public int SigFlags { + set { + sigFlags |= value; + } + } + + /** + * Adds a formfield to the AcroForm. + */ + + public void AddFormField(PdfFormField formField) { + writer.AddAnnotation(formField); + } + + public PdfFormField AddHtmlPostButton(string name, string caption, string value, string url, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfAction action = PdfAction.CreateSubmitForm(url, null, PdfAction.SUBMIT_HTML_FORMAT); + PdfFormField button = new PdfFormField(writer, llx, lly, urx, ury, action); + SetButtonParams(button, PdfFormField.FF_PUSHBUTTON, name, value); + DrawButton(button, caption, font, fontSize, llx, lly, urx, ury); + AddFormField(button); + return button; + } + + public PdfFormField AddResetButton(string name, string caption, string value, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfAction action = PdfAction.CreateResetForm(null, 0); + PdfFormField button = new PdfFormField(writer, llx, lly, urx, ury, action); + SetButtonParams(button, PdfFormField.FF_PUSHBUTTON, name, value); + DrawButton(button, caption, font, fontSize, llx, lly, urx, ury); + AddFormField(button); + return button; + } + + public PdfFormField AddMap(string name, string value, string url, PdfContentByte appearance, float llx, float lly, float urx, float ury) { + PdfAction action = PdfAction.CreateSubmitForm(url, null, PdfAction.SUBMIT_HTML_FORMAT | PdfAction.SUBMIT_COORDINATES); + PdfFormField button = new PdfFormField(writer, llx, lly, urx, ury, action); + SetButtonParams(button, PdfFormField.FF_PUSHBUTTON, name, null); + PdfAppearance pa = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + pa.Add(appearance); + button.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, pa); + AddFormField(button); + return button; + } + + public void SetButtonParams(PdfFormField button, int characteristics, string name, string value) { + button.Button = characteristics; + button.Flags = PdfAnnotation.FLAGS_PRINT; + button.SetPage(); + button.FieldName = name; + if (value != null) button.ValueAsString = value; + } + + public void DrawButton(PdfFormField button, string caption, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfAppearance pa = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + pa.DrawButton(0f, 0f, urx - llx, ury - lly, caption, font, fontSize); + button.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, pa); + } + + public PdfFormField AddHiddenField(string name, string value) { + PdfFormField hidden = PdfFormField.CreateEmpty(writer); + hidden.FieldName = name; + hidden.ValueAsName = value; + AddFormField(hidden); + return hidden; + } + + public PdfFormField AddSingleLineTextField(string name, string text, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfFormField field = PdfFormField.CreateTextField(writer, PdfFormField.SINGLELINE, PdfFormField.PLAINTEXT, 0); + SetTextFieldParams(field, text, name, llx, lly, urx, ury); + DrawSingleLineOfText(field, text, font, fontSize, llx, lly, urx, ury); + AddFormField(field); + return field; + } + + public PdfFormField AddMultiLineTextField(string name, string text, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfFormField field = PdfFormField.CreateTextField(writer, PdfFormField.MULTILINE, PdfFormField.PLAINTEXT, 0); + SetTextFieldParams(field, text, name, llx, lly, urx, ury); + DrawMultiLineOfText(field, text, font, fontSize, llx, lly, urx, ury); + AddFormField(field); + return field; + } + + public PdfFormField AddSingleLinePasswordField(string name, string text, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfFormField field = PdfFormField.CreateTextField(writer, PdfFormField.SINGLELINE, PdfFormField.PASSWORD, 0); + SetTextFieldParams(field, text, name, llx, lly, urx, ury); + DrawSingleLineOfText(field, text, font, fontSize, llx, lly, urx, ury); + AddFormField(field); + return field; + } + + public void SetTextFieldParams(PdfFormField field, string text, string name, float llx, float lly, float urx, float ury) { + field.SetWidget(new Rectangle(llx, lly, urx, ury), PdfAnnotation.HIGHLIGHT_INVERT); + field.ValueAsString = text; + field.DefaultValueAsString = text; + field.FieldName = name; + field.Flags = PdfAnnotation.FLAGS_PRINT; + field.SetPage(); + } + + public void DrawSingleLineOfText(PdfFormField field, string text, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfAppearance tp = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + PdfAppearance tp2 = (PdfAppearance)tp.Duplicate; + tp2.SetFontAndSize(font, fontSize); + tp2.ResetRGBColorFill(); + field.DefaultAppearanceString = tp2; + tp.DrawTextField(0f, 0f, urx - llx, ury - lly); + tp.BeginVariableText(); + tp.SaveState(); + tp.Rectangle(3f, 3f, urx - llx - 6f, ury - lly - 6f); + tp.Clip(); + tp.NewPath(); + tp.BeginText(); + tp.SetFontAndSize(font, fontSize); + tp.ResetRGBColorFill(); + tp.SetTextMatrix(4, (ury - lly) / 2 - (fontSize * 0.3f)); + tp.ShowText(text); + tp.EndText(); + tp.RestoreState(); + tp.EndVariableText(); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, tp); + } + + public void DrawMultiLineOfText(PdfFormField field, string text, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfAppearance tp = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + PdfAppearance tp2 = (PdfAppearance)tp.Duplicate; + tp2.SetFontAndSize(font, fontSize); + tp2.ResetRGBColorFill(); + field.DefaultAppearanceString = tp2; + tp.DrawTextField(0f, 0f, urx - llx, ury - lly); + tp.BeginVariableText(); + tp.SaveState(); + tp.Rectangle(3f, 3f, urx - llx - 6f, ury - lly - 6f); + tp.Clip(); + tp.NewPath(); + tp.BeginText(); + tp.SetFontAndSize(font, fontSize); + tp.ResetRGBColorFill(); + tp.SetTextMatrix(4, 5); + System.util.StringTokenizer tokenizer = new System.util.StringTokenizer(text, "\n"); + float yPos = ury - lly; + while (tokenizer.HasMoreTokens()) { + yPos -= fontSize * 1.2f; + tp.ShowTextAligned(PdfContentByte.ALIGN_LEFT, tokenizer.NextToken(), 3, yPos, 0); + } + tp.EndText(); + tp.RestoreState(); + tp.EndVariableText(); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, tp); + } + + public PdfFormField AddCheckBox(string name, string value, bool status, float llx, float lly, float urx, float ury) { + PdfFormField field = PdfFormField.CreateCheckBox(writer); + SetCheckBoxParams(field, name, value, status, llx, lly, urx, ury); + DrawCheckBoxAppearences(field, value, llx, lly, urx, ury); + AddFormField(field); + return field; + } + + public void SetCheckBoxParams(PdfFormField field, string name, string value, bool status, float llx, float lly, float urx, float ury) { + field.SetWidget(new Rectangle(llx, lly, urx, ury), PdfAnnotation.HIGHLIGHT_TOGGLE); + field.FieldName = name; + if (status) { + field.ValueAsName = value; + field.AppearanceState = value; + } + else { + field.ValueAsName = "Off"; + field.AppearanceState = "Off"; + } + field.Flags = PdfAnnotation.FLAGS_PRINT; + field.SetPage(); + field.BorderStyle = new PdfBorderDictionary(1, PdfBorderDictionary.STYLE_SOLID); + } + + public void DrawCheckBoxAppearences(PdfFormField field, string value, float llx, float lly, float urx, float ury) { + BaseFont font = BaseFont.CreateFont(BaseFont.ZAPFDINGBATS, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED); + float size = (ury - lly); + PdfAppearance tpOn = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + PdfAppearance tp2 = (PdfAppearance)tpOn.Duplicate; + tp2.SetFontAndSize(font, size); + tp2.ResetRGBColorFill(); + field.DefaultAppearanceString = tp2; + tpOn.DrawTextField(0f, 0f, urx - llx, ury - lly); + tpOn.SaveState(); + tpOn.ResetRGBColorFill(); + tpOn.BeginText(); + tpOn.SetFontAndSize(font, size); + tpOn.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "4", (urx - llx) / 2, (ury - lly) / 2 - (size * 0.3f), 0); + tpOn.EndText(); + tpOn.RestoreState(); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, value, tpOn); + PdfAppearance tpOff = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + tpOff.DrawTextField(0f, 0f, urx - llx, ury - lly); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, "Off", tpOff); + } + + public PdfFormField GetRadioGroup(string name, string defaultValue, bool noToggleToOff) { + PdfFormField radio = PdfFormField.CreateRadioButton(writer, noToggleToOff); + radio.FieldName = name; + radio.ValueAsName = defaultValue; + return radio; + } + + public void AddRadioGroup(PdfFormField radiogroup) { + AddFormField(radiogroup); + } + + public PdfFormField AddRadioButton(PdfFormField radiogroup, string value, float llx, float lly, float urx, float ury) { + PdfFormField radio = PdfFormField.CreateEmpty(writer); + radio.SetWidget(new Rectangle(llx, lly, urx, ury), PdfAnnotation.HIGHLIGHT_TOGGLE); + string name = ((PdfName)radiogroup.Get(PdfName.V)).ToString().Substring(1); + if (name.Equals(value)) { + radio.AppearanceState = value; + } + else { + radio.AppearanceState = "Off"; + } + DrawRadioAppearences(radio, value, llx, lly, urx, ury); + radiogroup.AddKid(radio); + return radio; + } + + public void DrawRadioAppearences(PdfFormField field, string value, float llx, float lly, float urx, float ury) { + PdfAppearance tpOn = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + tpOn.DrawRadioField(0f, 0f, urx - llx, ury - lly, true); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, value, tpOn); + PdfAppearance tpOff = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + tpOff.DrawRadioField(0f, 0f, urx - llx, ury - lly, false); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, "Off", tpOff); + } + + public PdfFormField AddSelectList(string name, string[] options, string defaultValue, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfFormField choice = PdfFormField.CreateList(writer, options, 0); + SetChoiceParams(choice, name, defaultValue, llx, lly, urx, ury); + StringBuilder text = new StringBuilder(); + for (int i = 0; i < options.Length; i++) { + text.Append(options[i]).Append('\n'); + } + DrawMultiLineOfText(choice, text.ToString(), font, fontSize, llx, lly, urx, ury); + AddFormField(choice); + return choice; + } + + public PdfFormField AddSelectList(string name, string[,] options, string defaultValue, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfFormField choice = PdfFormField.CreateList(writer, options, 0); + SetChoiceParams(choice, name, defaultValue, llx, lly, urx, ury); + StringBuilder text = new StringBuilder(); + for (int i = 0; i < options.GetLength(0); i++) { + text.Append(options[i, 1]).Append('\n'); + } + DrawMultiLineOfText(choice, text.ToString(), font, fontSize, llx, lly, urx, ury); + AddFormField(choice); + return choice; + } + + public PdfFormField AddComboBox(string name, string[] options, string defaultValue, bool editable, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfFormField choice = PdfFormField.CreateCombo(writer, editable, options, 0); + SetChoiceParams(choice, name, defaultValue, llx, lly, urx, ury); + if (defaultValue == null) { + defaultValue = options[0]; + } + DrawSingleLineOfText(choice, defaultValue, font, fontSize, llx, lly, urx, ury); + AddFormField(choice); + return choice; + } + + public PdfFormField AddComboBox(string name, string[,] options, string defaultValue, bool editable, BaseFont font, float fontSize, float llx, float lly, float urx, float ury) { + PdfFormField choice = PdfFormField.CreateCombo(writer, editable, options, 0); + SetChoiceParams(choice, name, defaultValue, llx, lly, urx, ury); + string value = null; + for (int i = 0; i < options.GetLength(0); i++) { + if (options[i, 0].Equals(defaultValue)) { + value = options[i, 1]; + break; + } + } + if (value == null) { + value = options[0, 1]; + } + DrawSingleLineOfText(choice, value, font, fontSize, llx, lly, urx, ury); + AddFormField(choice); + return choice; + } + + public void SetChoiceParams(PdfFormField field, string name, string defaultValue, float llx, float lly, float urx, float ury) { + field.SetWidget(new Rectangle(llx, lly, urx, ury), PdfAnnotation.HIGHLIGHT_INVERT); + if (defaultValue != null) { + field.ValueAsString = defaultValue; + field.DefaultValueAsString = defaultValue; + } + field.FieldName = name; + field.Flags = PdfAnnotation.FLAGS_PRINT; + field.SetPage(); + field.BorderStyle = new PdfBorderDictionary(2, PdfBorderDictionary.STYLE_SOLID); + } + + public PdfFormField AddSignature(String name, float llx, float lly, float urx, float ury) { + PdfFormField signature = PdfFormField.CreateSignature(writer); + SetSignatureParams(signature, name, llx, lly, urx, ury); + DrawSignatureAppearences(signature, llx, lly, urx, ury); + AddFormField(signature); + return signature; + } + + /** + * @param field + * @param name + * @param llx + * @param lly + * @param urx + * @param ury + */ + public void SetSignatureParams(PdfFormField field, String name, float llx, float lly, float urx, float ury) { + field.SetWidget(new Rectangle(llx, lly, urx, ury), PdfAnnotation.HIGHLIGHT_INVERT); + field.FieldName = name; + field.Flags = PdfAnnotation.FLAGS_PRINT; + field.SetPage(); + field.MKBorderColor = Color.BLACK; + field.MKBackgroundColor = Color.WHITE; + } + + /** + * @param field + * @param llx + * @param lly + * @param urx + * @param ury + */ + public void DrawSignatureAppearences(PdfFormField field, float llx, float lly, float urx, float ury) { + PdfAppearance tp = PdfAppearance.CreateAppearance(writer, urx - llx, ury - lly); + tp.SetGrayFill(1.0f); + tp.Rectangle(0, 0, urx - llx, ury - lly); + tp.Fill(); + tp.SetGrayStroke(0); + tp.SetLineWidth(1); + tp.Rectangle(0.5f, 0.5f, urx - llx - 0.5f, ury - lly - 0.5f); + tp.ClosePathStroke(); + tp.SaveState(); + tp.Rectangle(1, 1, urx - llx - 2, ury - lly - 2); + tp.Clip(); + tp.NewPath(); + tp.RestoreState(); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, tp); + } +} +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfAction.cs b/iTechSharp/iTextSharp/text/pdf/PdfAction.cs new file mode 100644 index 0000000..cc606de --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfAction.cs @@ -0,0 +1,521 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text.pdf.collection; + +/* + * $Id: PdfAction.cs,v 1.6 2008/05/13 11:25:18 psoares33 Exp $ + * + * + * Copyright 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** + * A PdfAction defines an action that can be triggered from a PDF file. + * + * @see PdfDictionary + */ + + public class PdfAction : PdfDictionary { + + /** A named action to go to the first page. + */ + public const int FIRSTPAGE = 1; + /** A named action to go to the previous page. + */ + public const int PREVPAGE = 2; + /** A named action to go to the next page. + */ + public const int NEXTPAGE = 3; + /** A named action to go to the last page. + */ + public const int LASTPAGE = 4; + + /** A named action to open a print dialog. + */ + public const int PRINTDIALOG = 5; + + // constructors + public const int SUBMIT_EXCLUDE = 1; + public const int SUBMIT_INCLUDE_NO_VALUE_FIELDS = 2; + public const int SUBMIT_HTML_FORMAT = 4; + public const int SUBMIT_HTML_GET = 8; + public const int SUBMIT_COORDINATES = 16; + /** a possible submitvalue */ + public const int SUBMIT_XFDF = 32; + /** a possible submitvalue */ + public const int SUBMIT_INCLUDE_APPEND_SAVES = 64; + /** a possible submitvalue */ + public const int SUBMIT_INCLUDE_ANNOTATIONS = 128; + /** a possible submitvalue */ + public const int SUBMIT_PDF = 256; + /** a possible submitvalue */ + public const int SUBMIT_CANONICAL_FORMAT = 512; + /** a possible submitvalue */ + public const int SUBMIT_EXCL_NON_USER_ANNOTS = 1024; + /** a possible submitvalue */ + public const int SUBMIT_EXCL_F_KEY = 2048; + /** a possible submitvalue */ + public const int SUBMIT_EMBED_FORM = 8196; + /** a possible submitvalue */ + public const int RESET_EXCLUDE = 1; + + /** Create an empty action. + */ + public PdfAction() { + } + + /** + * Constructs a new PdfAction of Subtype URI. + * + * @param url the Url to go to + */ + + public PdfAction(Uri url) : this(url.AbsoluteUri) {} + + public PdfAction(Uri url, bool isMap) : this(url.AbsoluteUri, isMap) {} + + /** + * Constructs a new PdfAction of Subtype URI. + * + * @param url the url to go to + */ + + public PdfAction(string url) : this(url, false) {} + + public PdfAction(string url, bool isMap) { + Put(PdfName.S, PdfName.URI); + Put(PdfName.URI, new PdfString(url)); + if (isMap) + Put(PdfName.ISMAP, PdfBoolean.PDFTRUE); + } + + /** + * Constructs a new PdfAction of Subtype GoTo. + * @param destination the destination to go to + */ + + internal PdfAction(PdfIndirectReference destination) { + Put(PdfName.S, PdfName.GOTO); + Put(PdfName.D, destination); + } + + /** + * Constructs a new PdfAction of Subtype GoToR. + * @param filename the file name to go to + * @param name the named destination to go to + */ + + public PdfAction(string filename, string name) { + Put(PdfName.S, PdfName.GOTOR); + Put(PdfName.F, new PdfString(filename)); + Put(PdfName.D, new PdfString(name)); + } + + /** + * Constructs a new PdfAction of Subtype GoToR. + * @param filename the file name to go to + * @param page the page destination to go to + */ + + public PdfAction(string filename, int page) { + Put(PdfName.S, PdfName.GOTOR); + Put(PdfName.F, new PdfString(filename)); + Put(PdfName.D, new PdfLiteral("[" + (page - 1) + " /FitH 10000]")); + } + + /** Implements name actions. The action can be FIRSTPAGE, LASTPAGE, + * NEXTPAGE and PREVPAGE. + * @param named the named action + */ + public PdfAction(int named) { + Put(PdfName.S, PdfName.NAMED); + switch (named) { + case FIRSTPAGE: + Put(PdfName.N, PdfName.FIRSTPAGE); + break; + case LASTPAGE: + Put(PdfName.N, PdfName.LASTPAGE); + break; + case NEXTPAGE: + Put(PdfName.N, PdfName.NEXTPAGE); + break; + case PREVPAGE: + Put(PdfName.N, PdfName.PREVPAGE); + break; + case PRINTDIALOG: + Put(PdfName.S, PdfName.JAVASCRIPT); + Put(PdfName.JS, new PdfString("this.print(true);\r")); + break; + default: + throw new ArgumentException("Invalid named action."); + } + } + + /** Launchs an application or a document. + * @param application the application to be launched or the document to be opened or printed. + * @param parameters (Windows-specific) A parameter string to be passed to the application. + * It can be null. + * @param operation (Windows-specific) the operation to perform: "open" - Open a document, + * "print" - Print a document. + * It can be null. + * @param defaultDir (Windows-specific) the default directory in standard DOS syntax. + * It can be null. + */ + public PdfAction(string application, string parameters, string operation, string defaultDir) { + Put(PdfName.S, PdfName.LAUNCH); + if (parameters == null && operation == null && defaultDir == null) + Put(PdfName.F, new PdfString(application)); + else { + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.F, new PdfString(application)); + if (parameters != null) + dic.Put(PdfName.P, new PdfString(parameters)); + if (operation != null) + dic.Put(PdfName.O, new PdfString(operation)); + if (defaultDir != null) + dic.Put(PdfName.D, new PdfString(defaultDir)); + Put(PdfName.WIN, dic); + } + } + + /** Launchs an application or a document. + * @param application the application to be launched or the document to be opened or printed. + * @param parameters (Windows-specific) A parameter string to be passed to the application. + * It can be null. + * @param operation (Windows-specific) the operation to perform: "open" - Open a document, + * "print" - Print a document. + * It can be null. + * @param defaultDir (Windows-specific) the default directory in standard DOS syntax. + * It can be null. + * @return a Launch action + */ + public static PdfAction CreateLaunch(String application, String parameters, String operation, String defaultDir) { + return new PdfAction(application, parameters, operation, defaultDir); + } + + /**Creates a Rendition action + * @param file + * @param fs + * @param mimeType + * @param ref + * @return a Media Clip action + * @throws IOException + */ + public static PdfAction Rendition(String file, PdfFileSpecification fs, String mimeType, PdfIndirectReference refi) { + PdfAction js = new PdfAction(); + js.Put(PdfName.S, PdfName.RENDITION); + js.Put(PdfName.R, new PdfRendition(file, fs, mimeType)); + js.Put(new PdfName("OP"), new PdfNumber(0)); + js.Put(new PdfName("AN"), refi); + return js; + } + + /** Creates a JavaScript action. If the JavaScript is smaller than + * 50 characters it will be placed as a string, otherwise it will + * be placed as a compressed stream. + * @param code the JavaScript code + * @param writer the writer for this action + * @param unicode select JavaScript unicode. Note that the internal + * Acrobat JavaScript engine does not support unicode, + * so this may or may not work for you + * @return the JavaScript action + */ + public static PdfAction JavaScript(string code, PdfWriter writer, bool unicode) { + PdfAction js = new PdfAction(); + js.Put(PdfName.S, PdfName.JAVASCRIPT); + if (unicode && code.Length < 50) { + js.Put(PdfName.JS, new PdfString(code, PdfObject.TEXT_UNICODE)); + } + else if (!unicode && code.Length < 100) { + js.Put(PdfName.JS, new PdfString(code)); + } + else { + byte[] b = PdfEncodings.ConvertToBytes(code, unicode ? PdfObject.TEXT_UNICODE : PdfObject.TEXT_PDFDOCENCODING); + PdfStream stream = new PdfStream(b); + stream.FlateCompress(); + js.Put(PdfName.JS, writer.AddToBody(stream).IndirectReference); + } + return js; + } + + /** Creates a JavaScript action. If the JavaScript is smaller than + * 50 characters it will be place as a string, otherwise it will + * be placed as a compressed stream. + * @param code the JavaScript code + * @param writer the writer for this action + * @return the JavaScript action + */ + public static PdfAction JavaScript(string code, PdfWriter writer) { + return JavaScript(code, writer, false); + } + + internal static PdfAction CreateHide(PdfObject obj, bool hide) { + PdfAction action = new PdfAction(); + action.Put(PdfName.S, PdfName.HIDE); + action.Put(PdfName.T, obj); + if (!hide) + action.Put(PdfName.H, PdfBoolean.PDFFALSE); + return action; + } + + public static PdfAction CreateHide(PdfAnnotation annot, bool hide) { + return CreateHide(annot.IndirectReference, hide); + } + + public static PdfAction CreateHide(string name, bool hide) { + return CreateHide(new PdfString(name), hide); + } + + internal static PdfArray BuildArray(Object[] names) { + PdfArray array = new PdfArray(); + for (int k = 0; k < names.Length; ++k) { + Object obj = names[k]; + if (obj is string) + array.Add(new PdfString((string)obj)); + else if (obj is PdfAnnotation) + array.Add(((PdfAnnotation)obj).IndirectReference); + else + throw new ArgumentException("The array must contain string or PdfAnnotation."); + } + return array; + } + + public static PdfAction CreateHide(Object[] names, bool hide) { + return CreateHide(BuildArray(names), hide); + } + + public static PdfAction CreateSubmitForm(string file, Object[] names, int flags) { + PdfAction action = new PdfAction(); + action.Put(PdfName.S, PdfName.SUBMITFORM); + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.F, new PdfString(file)); + dic.Put(PdfName.FS, PdfName.URL); + action.Put(PdfName.F, dic); + if (names != null) + action.Put(PdfName.FIELDS, BuildArray(names)); + action.Put(PdfName.FLAGS, new PdfNumber(flags)); + return action; + } + + public static PdfAction CreateResetForm(Object[] names, int flags) { + PdfAction action = new PdfAction(); + action.Put(PdfName.S, PdfName.RESETFORM); + if (names != null) + action.Put(PdfName.FIELDS, BuildArray(names)); + action.Put(PdfName.FLAGS, new PdfNumber(flags)); + return action; + } + + public static PdfAction CreateImportData(string file) { + PdfAction action = new PdfAction(); + action.Put(PdfName.S, PdfName.IMPORTDATA); + action.Put(PdfName.F, new PdfString(file)); + return action; + } + + /** Add a chained action. + * @param na the next action + */ + public void Next(PdfAction na) { + PdfObject nextAction = Get(PdfName.NEXT); + if (nextAction == null) + Put(PdfName.NEXT, na); + else if (nextAction.IsDictionary()) { + PdfArray array = new PdfArray(nextAction); + array.Add(na); + Put(PdfName.NEXT, array); + } + else { + ((PdfArray)nextAction).Add(na); + } + } + + /** Creates a GoTo action to an internal page. + * @param page the page to go. First page is 1 + * @param dest the destination for the page + * @param writer the writer for this action + * @return a GoTo action + */ + public static PdfAction GotoLocalPage(int page, PdfDestination dest, PdfWriter writer) { + PdfIndirectReference piref = writer.GetPageReference(page); + dest.AddPage(piref); + PdfAction action = new PdfAction(); + action.Put(PdfName.S, PdfName.GOTO); + action.Put(PdfName.D, dest); + return action; + } + + /** + * Creates a GoTo action to a named destination. + * @param dest the named destination + * @param isName if true sets the destination as a name, if false sets it as a String + * @return a GoToR action + */ + public static PdfAction GotoLocalPage(String dest, bool isName) { + PdfAction action = new PdfAction(); + action.Put(PdfName.S, PdfName.GOTO); + if (isName) + action.Put(PdfName.D, new PdfName(dest)); + else + action.Put(PdfName.D, new PdfString(dest, null)); + return action; + } + + /** + * Creates a GoToR action to a named destination. + * @param filename the file name to go to + * @param dest the destination name + * @param isName if true sets the destination as a name, if false sets it as a String + * @param newWindow open the document in a new window if true, if false the current document is replaced by the new document. + * @return a GoToR action + */ + public static PdfAction GotoRemotePage(String filename, String dest, bool isName, bool newWindow) { + PdfAction action = new PdfAction(); + action.Put(PdfName.F, new PdfString(filename)); + action.Put(PdfName.S, PdfName.GOTOR); + if (isName) + action.Put(PdfName.D, new PdfName(dest)); + else + action.Put(PdfName.D, new PdfString(dest, null)); + if (newWindow) + action.Put(PdfName.NEWWINDOW, PdfBoolean.PDFTRUE); + return action; + } + + /** + * Creates a GoToE action to an embedded file. + * @param filename the root document of the target (null if the target is in the same document) + * @param dest the named destination + * @param isName if true sets the destination as a name, if false sets it as a String + * @return a GoToE action + */ + public static PdfAction GotoEmbedded(String filename, PdfTargetDictionary target, String dest, bool isName, bool newWindow) { + if (isName) + return GotoEmbedded(filename, target, new PdfName(dest), newWindow); + else + return GotoEmbedded(filename, target, new PdfString(dest, null), newWindow); + } + + /** + * Creates a GoToE action to an embedded file. + * @param filename the root document of the target (null if the target is in the same document) + * @param target a path to the target document of this action + * @param dest the destination inside the target document, can be of type PdfDestination, PdfName, or PdfString + * @param newWindow if true, the destination document should be opened in a new window + * @return a GoToE action + */ + public static PdfAction GotoEmbedded(String filename, PdfTargetDictionary target, PdfObject dest, bool newWindow) { + PdfAction action = new PdfAction(); + action.Put(PdfName.S, PdfName.GOTOE); + action.Put(PdfName.T, target); + action.Put(PdfName.D, dest); + action.Put(PdfName.NEWWINDOW, new PdfBoolean(newWindow)); + if (filename != null) { + action.Put(PdfName.F, new PdfString(filename)); + } + return action; + } + + /** + * A set-OCG-state action (PDF 1.5) sets the state of one or more optional content + * groups. + * @param state an array consisting of any number of sequences beginning with a PdfName + * or String (ON, OFF, or Toggle) followed by one or more optional content group dictionaries + * PdfLayer or a PdfIndirectReference to a PdfLayer.
    + * The array elements are processed from left to right; each name is applied + * to the subsequent groups until the next name is encountered: + *

      + *
    • ON sets the state of subsequent groups to ON
    • + *
    • OFF sets the state of subsequent groups to OFF
    • + *
    • Toggle reverses the state of subsequent groups
    • + *
    + * @param preserveRB if true, indicates that radio-button state relationships between optional + * content groups (as specified by the RBGroups entry in the current configuration + * dictionary) should be preserved when the states in the + * state array are applied. That is, if a group is set to ON (either by ON or Toggle) during + * processing of the state array, any other groups belong to the same radio-button + * group are turned OFF. If a group is set to OFF, there is no effect on other groups.
    + * If false, radio-button state relationships, if any, are ignored + * @return the action + */ + public static PdfAction SetOCGstate(ArrayList state, bool preserveRB) { + PdfAction action = new PdfAction(); + action.Put(PdfName.S, PdfName.SETOCGSTATE); + PdfArray a = new PdfArray(); + for (int k = 0; k < state.Count; ++k) { + Object o = state[k]; + if (o == null) + continue; + if (o is PdfIndirectReference) + a.Add((PdfIndirectReference)o); + else if (o is PdfLayer) + a.Add(((PdfLayer)o).Ref); + else if (o is PdfName) + a.Add((PdfName)o); + else if (o is String) { + PdfName name = null; + String s = (String)o; + if (Util.EqualsIgnoreCase(s, "on")) + name = PdfName.ON; + else if (Util.EqualsIgnoreCase(s, "off")) + name = PdfName.OFF; + else if (Util.EqualsIgnoreCase(s, "toggle")) + name = PdfName.TOGGLE; + else + throw new ArgumentException("A string '" + s + " was passed in state. Only 'ON', 'OFF' and 'Toggle' are allowed."); + a.Add(name); + } + else + throw new ArgumentException("Invalid type was passed in state: " + o.GetType().ToString()); + } + action.Put(PdfName.STATE, a); + if (!preserveRB) + action.Put(PdfName.PRESERVERB, PdfBoolean.PDFFALSE); + return action; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfAnnotation.cs b/iTechSharp/iTextSharp/text/pdf/PdfAnnotation.cs new file mode 100644 index 0000000..05593f5 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfAnnotation.cs @@ -0,0 +1,824 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text; +/* + * $Id: PdfAnnotation.cs,v 1.12 2008/05/24 18:41:23 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * A PdfAnnotation is a note that is associated with a page. + * + * @see PdfDictionary + */ + public class PdfAnnotation : PdfDictionary { + + public static readonly PdfName HIGHLIGHT_NONE = PdfName.N; + public static readonly PdfName HIGHLIGHT_INVERT = PdfName.I; + public static readonly PdfName HIGHLIGHT_OUTLINE = PdfName.O; + public static readonly PdfName HIGHLIGHT_PUSH = PdfName.P; + public static readonly PdfName HIGHLIGHT_TOGGLE = PdfName.T; + public const int FLAGS_INVISIBLE = 1; + public const int FLAGS_HIDDEN = 2; + public const int FLAGS_PRINT = 4; + public const int FLAGS_NOZOOM = 8; + public const int FLAGS_NOROTATE = 16; + public const int FLAGS_NOVIEW = 32; + public const int FLAGS_READONLY = 64; + public const int FLAGS_LOCKED = 128; + public const int FLAGS_TOGGLENOVIEW = 256; + public static readonly PdfName APPEARANCE_NORMAL = PdfName.N; + public static readonly PdfName APPEARANCE_ROLLOVER = PdfName.R; + public static readonly PdfName APPEARANCE_DOWN = PdfName.D; + public static readonly PdfName AA_ENTER = PdfName.E; + public static readonly PdfName AA_EXIT = PdfName.X; + public static readonly PdfName AA_DOWN = PdfName.D; + public static readonly PdfName AA_UP = PdfName.U; + public static readonly PdfName AA_FOCUS = PdfName.FO; + public static readonly PdfName AA_BLUR = PdfName.BL; + public static readonly PdfName AA_JS_KEY = PdfName.K; + public static readonly PdfName AA_JS_FORMAT = PdfName.F; + public static readonly PdfName AA_JS_CHANGE = PdfName.V; + public static readonly PdfName AA_JS_OTHER_CHANGE = PdfName.C; + public const int MARKUP_HIGHLIGHT = 0; + public const int MARKUP_UNDERLINE = 1; + public const int MARKUP_STRIKEOUT = 2; + /** attributevalue */ + public const int MARKUP_SQUIGGLY = 3; + protected internal PdfWriter writer; + protected internal PdfIndirectReference reference; + protected internal Hashtable templates; + protected internal bool form = false; + protected internal bool annotation = true; + + /** Holds value of property used. */ + protected internal bool used = false; + + /** Holds value of property placeInPage. */ + private int placeInPage = -1; + + // constructors + public PdfAnnotation(PdfWriter writer, Rectangle rect) { + this.writer = writer; + if (rect != null) + Put(PdfName.RECT, new PdfRectangle(rect)); + } + + /** + * Constructs a new PdfAnnotation of subtype text. + */ + + public PdfAnnotation(PdfWriter writer, float llx, float lly, float urx, float ury, PdfString title, PdfString content) { + this.writer = writer; + Put(PdfName.SUBTYPE, PdfName.TEXT); + Put(PdfName.T, title); + Put(PdfName.RECT, new PdfRectangle(llx, lly, urx, ury)); + Put(PdfName.CONTENTS, content); + } + + /** + * Constructs a new PdfAnnotation of subtype link (Action). + */ + + public PdfAnnotation(PdfWriter writer, float llx, float lly, float urx, float ury, PdfAction action) { + this.writer = writer; + Put(PdfName.SUBTYPE, PdfName.LINK); + Put(PdfName.RECT, new PdfRectangle(llx, lly, urx, ury)); + Put(PdfName.A, action); + Put(PdfName.BORDER, new PdfBorderArray(0, 0, 0)); + Put(PdfName.C, new PdfColor(0x00, 0x00, 0xFF)); + } + + /** + * Creates a screen PdfAnnotation + * @param writer + * @param rect + * @param clipTitle + * @param fs + * @param mimeType + * @param playOnDisplay + * @return a screen PdfAnnotation + * @throws IOException + */ + public static PdfAnnotation CreateScreen(PdfWriter writer, Rectangle rect, String clipTitle, PdfFileSpecification fs, + String mimeType, bool playOnDisplay) { + PdfAnnotation ann = new PdfAnnotation(writer, rect); + ann.Put(PdfName.SUBTYPE, PdfName.SCREEN); + ann.Put (PdfName.F, new PdfNumber(FLAGS_PRINT)); + ann.Put(PdfName.TYPE, PdfName.ANNOT); + ann.SetPage(); + PdfIndirectReference refi = ann.IndirectReference; + PdfAction action = PdfAction.Rendition(clipTitle,fs,mimeType, refi); + PdfIndirectReference actionRef = writer.AddToBody(action).IndirectReference; + // for play on display add trigger event + if (playOnDisplay) + { + PdfDictionary aa = new PdfDictionary(); + aa.Put(new PdfName("PV"), actionRef); + ann.Put(PdfName.AA, aa); + } + ann.Put(PdfName.A, actionRef); + return ann; + } + + public PdfIndirectReference IndirectReference { + get { + if (reference == null) { + reference = writer.PdfIndirectReference; + } + return reference; + } + } + + public static PdfAnnotation CreateText(PdfWriter writer, Rectangle rect, string title, string contents, bool open, string icon) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + annot.Put(PdfName.SUBTYPE, PdfName.TEXT); + if (title != null) + annot.Put(PdfName.T, new PdfString(title, PdfObject.TEXT_UNICODE)); + if (contents != null) + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + if (open) + annot.Put(PdfName.OPEN, PdfBoolean.PDFTRUE); + if (icon != null) { + annot.Put(PdfName.NAME, new PdfName(icon)); + } + return annot; + } + + protected static PdfAnnotation CreateLink(PdfWriter writer, Rectangle rect, PdfName highlight) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + annot.Put(PdfName.SUBTYPE, PdfName.LINK); + if (!highlight.Equals(HIGHLIGHT_INVERT)) + annot.Put(PdfName.H, highlight); + return annot; + } + + public static PdfAnnotation CreateLink(PdfWriter writer, Rectangle rect, PdfName highlight, PdfAction action) { + PdfAnnotation annot = CreateLink(writer, rect, highlight); + annot.PutEx(PdfName.A, action); + return annot; + } + + public static PdfAnnotation CreateLink(PdfWriter writer, Rectangle rect, PdfName highlight, string namedDestination) { + PdfAnnotation annot = CreateLink(writer, rect, highlight); + annot.Put(PdfName.DEST, new PdfString(namedDestination)); + return annot; + } + + public static PdfAnnotation CreateLink(PdfWriter writer, Rectangle rect, PdfName highlight, int page, PdfDestination dest) { + PdfAnnotation annot = CreateLink(writer, rect, highlight); + PdfIndirectReference piref = writer.GetPageReference(page); + dest.AddPage(piref); + annot.Put(PdfName.DEST, dest); + return annot; + } + + public static PdfAnnotation CreateFreeText(PdfWriter writer, Rectangle rect, string contents, PdfContentByte defaultAppearance) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + annot.Put(PdfName.SUBTYPE, PdfName.FREETEXT); + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + annot.DefaultAppearanceString = defaultAppearance; + return annot; + } + + public static PdfAnnotation CreateLine(PdfWriter writer, Rectangle rect, string contents, float x1, float y1, float x2, float y2) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + annot.Put(PdfName.SUBTYPE, PdfName.LINE); + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + PdfArray array = new PdfArray(new PdfNumber(x1)); + array.Add(new PdfNumber(y1)); + array.Add(new PdfNumber(x2)); + array.Add(new PdfNumber(y2)); + annot.Put(PdfName.L, array); + return annot; + } + + public static PdfAnnotation CreateSquareCircle(PdfWriter writer, Rectangle rect, string contents, bool square) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + if (square) + annot.Put(PdfName.SUBTYPE, PdfName.SQUARE); + else + annot.Put(PdfName.SUBTYPE, PdfName.CIRCLE); + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + return annot; + } + + public static PdfAnnotation CreateMarkup(PdfWriter writer, Rectangle rect, string contents, int type, float[] quadPoints) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + PdfName name = PdfName.HIGHLIGHT; + switch (type) { + case MARKUP_UNDERLINE: + name = PdfName.UNDERLINE; + break; + case MARKUP_STRIKEOUT: + name = PdfName.STRIKEOUT; + break; + case MARKUP_SQUIGGLY: + name = PdfName.SQUIGGLY; + break; + } + annot.Put(PdfName.SUBTYPE, name); + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + PdfArray array = new PdfArray(); + for (int k = 0; k < quadPoints.Length; ++k) + array.Add(new PdfNumber(quadPoints[k])); + annot.Put(PdfName.QUADPOINTS, array); + return annot; + } + + public static PdfAnnotation CreateStamp(PdfWriter writer, Rectangle rect, string contents, string name) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + annot.Put(PdfName.SUBTYPE, PdfName.STAMP); + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + annot.Put(PdfName.NAME, new PdfName(name)); + return annot; + } + + public static PdfAnnotation CreateInk(PdfWriter writer, Rectangle rect, string contents, float[][] inkList) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + annot.Put(PdfName.SUBTYPE, PdfName.INK); + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + PdfArray outer = new PdfArray(); + for (int k = 0; k < inkList.Length; ++k) { + PdfArray inner = new PdfArray(); + float[] deep = inkList[k]; + for (int j = 0; j < deep.Length; ++j) + inner.Add(new PdfNumber(deep[j])); + outer.Add(inner); + } + annot.Put(PdfName.INKLIST, outer); + return annot; + } + + /** Creates a file attachment annotation. + * @param writer the PdfWriter + * @param rect the dimensions in the page of the annotation + * @param contents the file description + * @param fileStore an array with the file. If it's null + * the file will be read from the disk + * @param file the path to the file. It will only be used if + * fileStore is not null + * @param fileDisplay the actual file name stored in the pdf + * @throws IOException on error + * @return the annotation + */ + public static PdfAnnotation CreateFileAttachment(PdfWriter writer, Rectangle rect, String contents, byte[] fileStore, String file, String fileDisplay) { + return CreateFileAttachment(writer, rect, contents, PdfFileSpecification.FileEmbedded(writer, file, fileDisplay, fileStore)); + } + + /** Creates a file attachment annotation + * @param writer + * @param rect + * @param contents + * @param fs + * @return the annotation + * @throws IOException + */ + public static PdfAnnotation CreateFileAttachment(PdfWriter writer, Rectangle rect, String contents, PdfFileSpecification fs) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + annot.Put(PdfName.SUBTYPE, PdfName.FILEATTACHMENT); + if (contents != null) + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + annot.Put(PdfName.FS, fs.Reference); + return annot; + } + + public static PdfAnnotation CreatePopup(PdfWriter writer, Rectangle rect, string contents, bool open) { + PdfAnnotation annot = new PdfAnnotation(writer, rect); + annot.Put(PdfName.SUBTYPE, PdfName.POPUP); + if (contents != null) + annot.Put(PdfName.CONTENTS, new PdfString(contents, PdfObject.TEXT_UNICODE)); + if (open) + annot.Put(PdfName.OPEN, PdfBoolean.PDFTRUE); + return annot; + } + + public PdfContentByte DefaultAppearanceString { + set { + byte[] b = value.InternalBuffer.ToByteArray(); + int len = b.Length; + for (int k = 0; k < len; ++k) { + if (b[k] == '\n') + b[k] = 32; + } + Put(PdfName.DA, new PdfString(b)); + } + } + + public int Flags { + set { + if (value == 0) + Remove(PdfName.F); + else + Put(PdfName.F, new PdfNumber(value)); + } + } + + public PdfBorderArray Border { + set { + Put(PdfName.BORDER, value); + } + } + + public PdfBorderDictionary BorderStyle { + set { + Put(PdfName.BS, value); + } + } + + /** + * Sets the annotation's highlighting mode. The values can be + * HIGHLIGHT_NONE, HIGHLIGHT_INVERT, + * HIGHLIGHT_OUTLINE and HIGHLIGHT_PUSH; + * @param highlight the annotation's highlighting mode + */ + public void SetHighlighting(PdfName highlight) { + if (highlight.Equals(HIGHLIGHT_INVERT)) + Remove(PdfName.H); + else + Put(PdfName.H, highlight); + } + + public void SetAppearance(PdfName ap, PdfTemplate template) { + PdfDictionary dic = (PdfDictionary)Get(PdfName.AP); + if (dic == null) + dic = new PdfDictionary(); + dic.Put(ap, template.IndirectReference); + Put(PdfName.AP, dic); + if (!form) + return; + if (templates == null) + templates = new Hashtable(); + templates[template] = null; + } + + public void SetAppearance(PdfName ap, string state, PdfTemplate template) { + PdfDictionary dicAp = (PdfDictionary)Get(PdfName.AP); + if (dicAp == null) + dicAp = new PdfDictionary(); + + PdfDictionary dic; + PdfObject obj = dicAp.Get(ap); + if (obj != null && obj.IsDictionary()) + dic = (PdfDictionary)obj; + else + dic = new PdfDictionary(); + dic.Put(new PdfName(state), template.IndirectReference); + dicAp.Put(ap, dic); + Put(PdfName.AP, dicAp); + if (!form) + return; + if (templates == null) + templates = new Hashtable(); + templates[template] = null; + } + + public string AppearanceState { + set { + if (value == null) { + Remove(PdfName.AS); + return; + } + Put(PdfName.AS, new PdfName(value)); + } + } + + public Color Color { + set { + Put(PdfName.C, new PdfColor(value)); + } + } + + public string Title { + set { + if (value == null) { + Remove(PdfName.T); + return; + } + Put(PdfName.T, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public PdfAnnotation Popup { + set { + Put(PdfName.POPUP, value.IndirectReference); + value.Put(PdfName.PARENT, this.IndirectReference); + } + } + + public PdfAction Action { + set { + Put(PdfName.A, value); + } + } + + public void SetAdditionalActions(PdfName key, PdfAction action) { + PdfDictionary dic; + PdfObject obj = Get(PdfName.AA); + if (obj != null && obj.IsDictionary()) + dic = (PdfDictionary)obj; + else + dic = new PdfDictionary(); + dic.Put(key, action); + Put(PdfName.AA, dic); + } + + internal virtual bool IsUsed() { + return used; + } + + public virtual void SetUsed() { + used = true; + } + + public Hashtable Templates { + get { + return templates; + } + } + + /** Getter for property form. + * @return Value of property form. + */ + public bool IsForm() { + return form; + } + + /** Getter for property annotation. + * @return Value of property annotation. + */ + public bool IsAnnotation() { + return annotation; + } + + public int Page { + set { + Put(PdfName.P, writer.GetPageReference(value)); + } + } + + public void SetPage() { + Put(PdfName.P, writer.CurrentPage); + } + + /** Getter for property placeInPage. + * @return Value of property placeInPage. + */ + public int PlaceInPage { + get { + return placeInPage; + } + + set { + this.placeInPage = value; + } + } + + public static PdfAnnotation ShallowDuplicate(PdfAnnotation annot) { + PdfAnnotation dup; + if (annot.IsForm()) { + dup = new PdfFormField(annot.writer); + PdfFormField dupField = (PdfFormField)dup; + PdfFormField srcField = (PdfFormField)annot; + dupField.parent = srcField.parent; + dupField.kids = srcField.kids; + } + else + dup = new PdfAnnotation(annot.writer, null); + dup.Merge(annot); + dup.form = annot.form; + dup.annotation = annot.annotation; + dup.templates = annot.templates; + return dup; + } + + public int Rotate { + set { + Put(PdfName.ROTATE, new PdfNumber(value)); + } + } + + internal PdfDictionary MK { + get { + PdfDictionary mk = (PdfDictionary)Get(PdfName.MK); + if (mk == null) { + mk = new PdfDictionary(); + Put(PdfName.MK, mk); + } + return mk; + } + } + + public int MKRotation { + set { + MK.Put(PdfName.R, new PdfNumber(value)); + } + } + + public static PdfArray GetMKColor(Color color) { + PdfArray array = new PdfArray(); + int type = ExtendedColor.GetType(color); + switch (type) { + case ExtendedColor.TYPE_GRAY: { + array.Add(new PdfNumber(((GrayColor)color).Gray)); + break; + } + case ExtendedColor.TYPE_CMYK: { + CMYKColor cmyk = (CMYKColor)color; + array.Add(new PdfNumber(cmyk.Cyan)); + array.Add(new PdfNumber(cmyk.Magenta)); + array.Add(new PdfNumber(cmyk.Yellow)); + array.Add(new PdfNumber(cmyk.Black)); + break; + } + case ExtendedColor.TYPE_SEPARATION: + case ExtendedColor.TYPE_PATTERN: + case ExtendedColor.TYPE_SHADING: + throw new Exception("Separations, patterns and shadings are not allowed in MK dictionary."); + default: + array.Add(new PdfNumber(color.R / 255f)); + array.Add(new PdfNumber(color.G / 255f)); + array.Add(new PdfNumber(color.B / 255f)); + break; + } + return array; + } + + public Color MKBorderColor { + set { + if (value == null) + MK.Remove(PdfName.BC); + else + MK.Put(PdfName.BC, GetMKColor(value)); + } + } + + public Color MKBackgroundColor { + set { + if (value == null) + MK.Remove(PdfName.BG); + else + MK.Put(PdfName.BG, GetMKColor(value)); + } + } + + public string MKNormalCaption { + set { + MK.Put(PdfName.CA, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public string MKRolloverCaption { + set { + MK.Put(PdfName.RC, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public string MKAlternateCaption { + set { + MK.Put(PdfName.AC, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public PdfTemplate MKNormalIcon { + set { + MK.Put(PdfName.I, value.IndirectReference); + } + } + + public PdfTemplate MKRolloverIcon { + set { + MK.Put(PdfName.RI, value.IndirectReference); + } + } + + public PdfTemplate MKAlternateIcon { + set { + MK.Put(PdfName.IX, value.IndirectReference); + } + } + + public void SetMKIconFit(PdfName scale, PdfName scalingType, float leftoverLeft, float leftoverBottom, bool fitInBounds) { + PdfDictionary dic = new PdfDictionary(); + if (!scale.Equals(PdfName.A)) + dic.Put(PdfName.SW, scale); + if (!scalingType.Equals(PdfName.P)) + dic.Put(PdfName.S, scalingType); + if (leftoverLeft != 0.5f || leftoverBottom != 0.5f) { + PdfArray array = new PdfArray(new PdfNumber(leftoverLeft)); + array.Add(new PdfNumber(leftoverBottom)); + dic.Put(PdfName.A, array); + } + if (fitInBounds) + dic.Put(PdfName.FB, PdfBoolean.PDFTRUE); + MK.Put(PdfName.IF, dic); + } + + public int MKTextPosition { + set { + MK.Put(PdfName.TP, new PdfNumber(value)); + } + } + + /** + * Sets the layer this annotation belongs to. + * @param layer the layer this annotation belongs to + */ + public IPdfOCG Layer { + set { + Put(PdfName.OC, value.Ref); + } + } + + /** + * Sets the name of the annotation. + * With this name the annotation can be identified among + * all the annotations on a page (it has to be unique). + */ + public String Name { + set { + Put(PdfName.NM, new PdfString(value)); + } + } + + /** + * This class processes links from imported pages so that they may be active. The following example code reads a group + * of files and places them all on the output PDF, four pages in a single page, keeping the links active. + *
    +        * String[] files = new String[] {"input1.pdf", "input2.pdf"};
    +        * String outputFile = "output.pdf";
    +        * int firstPage=1;
    +        * Document document = new Document();
    +        * PdfWriter writer = PdfWriter.GetInstance(document, new FileOutputStream(outputFile));
    +        * document.SetPageSize(PageSize.A4);
    +        * float W = PageSize.A4.GetWidth() / 2;
    +        * float H = PageSize.A4.GetHeight() / 2;
    +        * document.Open();
    +        * PdfContentByte cb = writer.GetDirectContent();
    +        * for (int i = 0; i < files.length; i++) {
    +        *    PdfReader currentReader = new PdfReader(files[i]);
    +        *    currentReader.ConsolidateNamedDestinations();
    +        *    for (int page = 1; page <= currentReader.GetNumberOfPages(); page++) {
    +        *        PdfImportedPage importedPage = writer.GetImportedPage(currentReader, page);
    +        *        float a = 0.5f;
    +        *        float e = (page % 2 == 0) ? W : 0;
    +        *        float f = (page % 4 == 1 || page % 4 == 2) ? H : 0;
    +        *        ArrayList links = currentReader.GetLinks(page);
    +        *        cb.AddTemplate(importedPage, a, 0, 0, a, e, f);
    +        *        for (int j = 0; j < links.Size(); j++) {
    +        *            PdfAnnotation.PdfImportedLink link = (PdfAnnotation.PdfImportedLink)links.Get(j);
    +        *            if (link.IsInternal()) {
    +        *                int dPage = link.GetDestinationPage();
    +        *                int newDestPage = (dPage-1)/4 + firstPage;
    +        *                float ee = (dPage % 2 == 0) ? W : 0;
    +        *                float ff = (dPage % 4 == 1 || dPage % 4 == 2) ? H : 0;
    +        *                link.SetDestinationPage(newDestPage);
    +        *                link.TransformDestination(a, 0, 0, a, ee, ff);
    +        *            }
    +        *            link.TransformRect(a, 0, 0, a, e, f);
    +        *            writer.AddAnnotation(link.CreateAnnotation(writer));
    +        *        }
    +        *        if (page % 4 == 0)
    +        *        document.NewPage();
    +        *    }
    +        *    if (i < files.length - 1)
    +        *    document.NewPage();
    +        *    firstPage += (currentReader.GetNumberOfPages()+3)/4;
    +        * }
    +        * document.Close();
    +        * 
    + */ + public class PdfImportedLink { + float llx, lly, urx, ury; + Hashtable parameters; + PdfArray destination = null; + int newPage=0; + + internal PdfImportedLink(PdfDictionary annotation) { + parameters = (Hashtable)annotation.hashMap.Clone(); + try { + destination = (PdfArray)parameters[PdfName.DEST]; + parameters.Remove(PdfName.DEST); + } catch (Exception) { + throw new ArgumentException("You have to consolidate the named destinations of your reader."); + } + if (destination != null) { + destination = new PdfArray(destination); + } + PdfArray rc = (PdfArray)parameters[PdfName.RECT]; + parameters.Remove(PdfName.RECT); + llx = rc.GetAsNumber(0).FloatValue; + lly = rc.GetAsNumber(1).FloatValue; + urx = rc.GetAsNumber(2).FloatValue; + ury = rc.GetAsNumber(3).FloatValue; + } + + public bool IsInternal() { + return destination != null; + } + + public int GetDestinationPage() { + if (!IsInternal()) return 0; + + // here destination is something like + // [132 0 R, /XYZ, 29.3898, 731.864502, null] + PdfIndirectReference refi = destination.GetAsIndirectObject(0); + + PRIndirectReference pr = (PRIndirectReference) refi; + PdfReader r = pr.Reader; + for (int i = 1; i <= r.NumberOfPages; i++) { + PRIndirectReference pp = r.GetPageOrigRef(i); + if (pp.Generation == pr.Generation && pp.Number == pr.Number) return i; + } + throw new ArgumentException("Page not found."); + } + + public void SetDestinationPage(int newPage) { + if (!IsInternal()) throw new ArgumentException("Cannot change destination of external link"); + this.newPage=newPage; + } + + public void TransformDestination(float a, float b, float c, float d, float e, float f) { + if (!IsInternal()) throw new ArgumentException("Cannot change destination of external link"); + if (destination.GetAsName(1).Equals(PdfName.XYZ)) { + float x = destination.GetAsNumber(2).FloatValue; + float y = destination.GetAsNumber(3).FloatValue; + float xx = x * a + y * c + e; + float yy = x * b + y * d + f; + destination.ArrayList[2] = new PdfNumber(xx); + destination.ArrayList[3] = new PdfNumber(yy); + } + } + + public void TransformRect(float a, float b, float c, float d, float e, float f) { + float x = llx * a + lly * c + e; + float y = llx * b + lly * d + f; + llx = x; + lly = y; + x = urx * a + ury * c + e; + y = urx * b + ury * d + f; + urx = x; + ury = y; + } + + public PdfAnnotation CreateAnnotation(PdfWriter writer) { + PdfAnnotation annotation = new PdfAnnotation(writer, new Rectangle(llx, lly, urx, ury)); + if (newPage != 0) { + PdfIndirectReference refi = writer.GetPageReference(newPage); + destination.ArrayList[0] = refi; + } + if (destination != null) annotation.Put(PdfName.DEST, destination); + foreach (object key in parameters.Keys) + annotation.hashMap[key] = parameters[key]; + return annotation; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfAppearance.cs b/iTechSharp/iTextSharp/text/pdf/PdfAppearance.cs new file mode 100644 index 0000000..3f780f8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfAppearance.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections; + +/* + * Copyright 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Implements the appearance stream to be used with form fields.. + */ + + public class PdfAppearance : PdfTemplate { + + public static Hashtable stdFieldFontNames = new Hashtable(); + + static PdfAppearance() { + stdFieldFontNames["Courier-BoldOblique"] = new PdfName("CoBO"); + stdFieldFontNames["Courier-Bold"] = new PdfName("CoBo"); + stdFieldFontNames["Courier-Oblique"] = new PdfName("CoOb"); + stdFieldFontNames["Courier"] = new PdfName("Cour"); + stdFieldFontNames["Helvetica-BoldOblique"] = new PdfName("HeBO"); + stdFieldFontNames["Helvetica-Bold"] = new PdfName("HeBo"); + stdFieldFontNames["Helvetica-Oblique"] = new PdfName("HeOb"); + stdFieldFontNames["Helvetica"] = PdfName.HELV; + stdFieldFontNames["Symbol"] = new PdfName("Symb"); + stdFieldFontNames["Times-BoldItalic"] = new PdfName("TiBI"); + stdFieldFontNames["Times-Bold"] = new PdfName("TiBo"); + stdFieldFontNames["Times-Italic"] = new PdfName("TiIt"); + stdFieldFontNames["Times-Roman"] = new PdfName("TiRo"); + stdFieldFontNames["ZapfDingbats"] = PdfName.ZADB; + stdFieldFontNames["HYSMyeongJo-Medium"] = new PdfName("HySm"); + stdFieldFontNames["HYGoThic-Medium"] = new PdfName("HyGo"); + stdFieldFontNames["HeiseiKakuGo-W5"] = new PdfName("KaGo"); + stdFieldFontNames["HeiseiMin-W3"] = new PdfName("KaMi"); + stdFieldFontNames["MHei-Medium"] = new PdfName("MHei"); + stdFieldFontNames["MSung-Light"] = new PdfName("MSun"); + stdFieldFontNames["STSong-Light"] = new PdfName("STSo"); + stdFieldFontNames["MSungStd-Light"] = new PdfName("MSun"); + stdFieldFontNames["STSongStd-Light"] = new PdfName("STSo"); + stdFieldFontNames["HYSMyeongJoStd-Medium"] = new PdfName("HySm"); + stdFieldFontNames["KozMinPro-Regular"] = new PdfName("KaMi"); + } + + /** + *Creates a PdfAppearance. + */ + + internal PdfAppearance() : base() { + separator = ' '; + } + + internal PdfAppearance(PdfIndirectReference iref) { + thisReference = iref; + } + /** + * Creates new PdfTemplate + * + * @param wr the PdfWriter + */ + + internal PdfAppearance(PdfWriter wr) : base(wr) { + separator = ' '; + } + + /** + * Creates a new appearance to be used with form fields. + * + * @param width the bounding box width + * @param height the bounding box height + * @return the appearance created + */ + public static PdfAppearance CreateAppearance(PdfWriter writer, float width, float height) { + return CreateAppearance(writer, width, height, null); + } + + internal static PdfAppearance CreateAppearance(PdfWriter writer, float width, float height, PdfName forcedName) { + PdfAppearance template = new PdfAppearance(writer); + template.Width = width; + template.Height = height; + writer.AddDirectTemplateSimple(template, forcedName); + return template; + } + + /** + * Set the font and the size for the subsequent text writing. + * + * @param bf the font + * @param size the font size in points + */ + public override void SetFontAndSize(BaseFont bf, float size) { + CheckWriter(); + state.size = size; + if (bf.FontType == BaseFont.FONT_TYPE_DOCUMENT) { + state.fontDetails = new FontDetails(null, ((DocumentFont)bf).IndirectReference, bf); + } + else + state.fontDetails = writer.AddSimple(bf); + PdfName psn = (PdfName)stdFieldFontNames[bf.PostscriptFontName]; + if (psn == null) { + if (bf.Subset && bf.FontType == BaseFont.FONT_TYPE_TTUNI) + psn = state.fontDetails.FontName; + else { + psn = new PdfName(bf.PostscriptFontName); + state.fontDetails.Subset = false; + } + } + PageResources prs = PageResources; + prs.AddFont(psn, state.fontDetails.IndirectReference); + content.Append(psn.GetBytes()).Append(' ').Append(size).Append(" Tf").Append_i(separator); + } + + public override PdfContentByte Duplicate { + get { + PdfAppearance tpl = new PdfAppearance(); + tpl.writer = writer; + tpl.pdf = pdf; + tpl.thisReference = thisReference; + tpl.pageResources = pageResources; + tpl.bBox = new Rectangle(bBox); + tpl.group = group; + tpl.layer = layer; + if (matrix != null) { + tpl.matrix = new PdfArray(matrix); + } + tpl.separator = separator; + return tpl; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfArray.cs b/iTechSharp/iTextSharp/text/pdf/PdfArray.cs new file mode 100644 index 0000000..ca8f0bf --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfArray.cs @@ -0,0 +1,295 @@ +using System; +using System.IO; +using System.Collections; +using System.util; + +/* + * $Id: PdfArray.cs,v 1.7 2008/05/13 11:25:18 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + +/** + * PdfArray is the PDF Array object. + *

    + * An array is a sequence of PDF objects. An array may contain a mixture of object types. + * An array is written as a left square bracket ([), followed by a sequence of objects, + * followed by a right square bracket (]).
    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.6 (page 40). + * + * @see PdfObject + */ + +public class PdfArray : PdfObject { + + // membervariables + +/** this is the actual array of PdfObjects */ + protected ArrayList arrayList; + + // constructors + +/** + * Constructs an empty PdfArray-object. + */ + + public PdfArray() : base(ARRAY) { + arrayList = new ArrayList(); + } + +/** + * Constructs an PdfArray-object, containing 1 PdfObject. + * + * @param object a PdfObject that has to be added to the array + */ + + public PdfArray(PdfObject obj) : base(ARRAY) { + arrayList = new ArrayList(); + arrayList.Add(obj); + } + + public PdfArray(float[] values) : base(ARRAY) { + arrayList = new ArrayList(); + Add(values); + } + + public PdfArray(int[] values) : base(ARRAY) { + arrayList = new ArrayList(); + Add(values); + } + +/** + * Constructs an PdfArray-object, containing all the PdfObjects in a given PdfArray. + * + * @param array a PdfArray that has to be added to the array + */ + + public PdfArray(PdfArray array) : base(ARRAY) { + arrayList = new ArrayList(array.ArrayList); + } + + // methods overriding some methods in PdfObject + +/** + * Returns the PDF representation of this PdfArray. + * + * @return an array of bytes + */ + + public override void ToPdf(PdfWriter writer, Stream os) { + os.WriteByte((byte)'['); + bool first = true; + PdfObject obj = null; + foreach (PdfObject obja in arrayList) { + obj = (obja == null) ? PdfNull.PDFNULL : obja; + type = obj.Type; + if (!first && type != PdfObject.ARRAY && type != PdfObject.DICTIONARY && type != PdfObject.NAME && type != PdfObject.STRING) + os.WriteByte((byte)' '); + first = false; + obj.ToPdf(writer, os); + } + os.WriteByte((byte)']'); + } + + // methods concerning the ArrayList-membervalue + +/** + * Returns an ArrayList containing PdfObjects. + * + * @return an ArrayList + */ + + public ArrayList ArrayList { + get { + return arrayList; + } + } + +/** + * Returns the number of entries in the array. + * + * @return the size of the ArrayList + */ + + public int Size { + get { + return arrayList.Count; + } + } + +/** + * Adds a PdfObject to the PdfArray. + * + * @param object PdfObject to add + * @return true + */ + + public virtual bool Add(PdfObject obj) { + arrayList.Add(obj); + return true; + } + + public bool Add(float[] values) { + for (int k = 0; k < values.Length; ++k) + arrayList.Add(new PdfNumber(values[k])); + return true; + } + + public bool Add(int[] values) { + for (int k = 0; k < values.Length; ++k) + arrayList.Add(new PdfNumber(values[k])); + return true; + } + +/** + * Adds a PdfObject to the PdfArray. + *

    + * The newly added object will be the first element in the ArrayList. + * + * @param object PdfObject to add + */ + + public void AddFirst(PdfObject obj) { + arrayList.Insert(0, obj); + } + +/** + * Checks if the PdfArray allready contains a certain PdfObject. + * + * @param object PdfObject to check + * @return true + */ + + public bool Contains(PdfObject obj) { + return arrayList.Contains(obj); + } + + public ListIterator GetListIterator() { + return new ListIterator(arrayList); + } + + public override string ToString() { + return arrayList.ToString(); + } + + public PdfObject GetPdfObject( int idx ) { + return (PdfObject)arrayList[idx]; + } + + public PdfObject GetDirectObject( int idx ) { + return PdfReader.GetPdfObject(GetPdfObject(idx)); + } + + // more of the same like PdfDictionary. (MAS 2/17/06) + public PdfDictionary GetAsDict(int idx) { + PdfDictionary dict = null; + PdfObject orig = GetDirectObject(idx); + if (orig != null && orig.IsDictionary()) + dict = (PdfDictionary) orig; + return dict; + } + + public PdfArray GetAsArray(int idx) { + PdfArray array = null; + PdfObject orig = GetDirectObject(idx); + if (orig != null && orig.IsArray()) + array = (PdfArray) orig; + return array; + } + + public PdfStream GetAsStream(int idx) { + PdfStream stream = null; + PdfObject orig = GetDirectObject(idx); + if (orig != null && orig.IsStream()) + stream = (PdfStream) orig; + return stream; + } + + public PdfString GetAsString(int idx) { + PdfString str = null; + PdfObject orig = GetDirectObject(idx); + if (orig != null && orig.IsString()) + str = (PdfString) orig; + return str; + } + + public PdfNumber GetAsNumber(int idx) { + PdfNumber number = null; + PdfObject orig = GetDirectObject(idx); + if (orig != null && orig.IsNumber()) + number = (PdfNumber) orig; + return number; + } + + public PdfName GetAsName(int idx) { + PdfName name = null; + PdfObject orig = GetDirectObject(idx); + if (orig != null && orig.IsName()) + name = (PdfName) orig; + return name; + } + + public PdfBoolean GetAsBoolean(int idx) { + PdfBoolean b = null; + PdfObject orig = GetDirectObject(idx); + if (orig != null && orig.IsBoolean()) + b = (PdfBoolean) orig; + return b; + } + + public PdfIndirectReference GetAsIndirectObject(int idx) { + PdfIndirectReference refi = null; + PdfObject orig = GetPdfObject(idx); // not getDirect this time. + if (orig != null && orig.IsIndirect()) + refi = (PdfIndirectReference) orig; + return refi; + } +} +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfBoolean.cs b/iTechSharp/iTextSharp/text/pdf/PdfBoolean.cs new file mode 100644 index 0000000..785308a --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfBoolean.cs @@ -0,0 +1,137 @@ +using System; + +/* + * $Id: PdfBoolean.cs,v 1.5 2008/05/13 11:25:18 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfBoolean is the bool object represented by the keywords true or false. + *

    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.2 (page 37). + * + * @see PdfObject + * @see BadPdfFormatException + */ + + public class PdfBoolean : PdfObject { + + // static membervariables (possible values of a bool object) + public static readonly PdfBoolean PDFTRUE = new PdfBoolean(true); + public static readonly PdfBoolean PDFFALSE = new PdfBoolean(false); + /** A possible value of PdfBoolean */ + public const string TRUE = "true"; + + /** A possible value of PdfBoolean */ + public const string FALSE = "false"; + + // membervariables + + /** the bool value of this object */ + private bool value; + + // constructors + + /** + * Constructs a PdfBoolean-object. + * + * @param value the value of the new PdfObject + */ + + public PdfBoolean(bool value) : base(BOOLEAN) { + if (value) { + this.Content = TRUE; + } + else { + this.Content = FALSE; + } + this.value = value; + } + + /** + * Constructs a PdfBoolean-object. + * + * @param value the value of the new PdfObject, represented as a string + * + * @throws BadPdfFormatException thrown if the value isn't 'true' or 'false' + */ + + public PdfBoolean(string value) : base(BOOLEAN, value) { + if (value.Equals(TRUE)) { + this.value = true; + } + else if (value.Equals(FALSE)) { + this.value = false; + } + else { + throw new BadPdfFormatException("The value has to be 'true' of 'false', instead of '" + value + "'."); + } + } + + // methods returning the value of this object + + /** + * Returns the primitive value of the PdfBoolean-object. + * + * @return the actual value of the object. + */ + + public bool BooleanValue { + get { + return value; + } + } + + public override string ToString() { + return value ? TRUE : FALSE; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfBorderArray.cs b/iTechSharp/iTextSharp/text/pdf/PdfBorderArray.cs new file mode 100644 index 0000000..8654d8f --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfBorderArray.cs @@ -0,0 +1,82 @@ +using System; + +/* + * $Id: PdfBorderArray.cs,v 1.3 2008/05/13 11:25:18 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfBorderArray defines the border of a PdfAnnotation. + * + * @see PdfArray + */ + + public class PdfBorderArray : PdfArray { + + // constructors + + /** + * Constructs a new PdfBorderArray. + */ + + public PdfBorderArray(float hRadius, float vRadius, float width) : this(hRadius, vRadius, width, null) {} + + /** + * Constructs a new PdfBorderArray. + */ + + public PdfBorderArray(float hRadius, float vRadius, float width, PdfDashPattern dash) : base(new PdfNumber(hRadius)) { + Add(new PdfNumber(vRadius)); + Add(new PdfNumber(width)); + if (dash != null) + Add(dash); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfBorderDictionary.cs b/iTechSharp/iTextSharp/text/pdf/PdfBorderDictionary.cs new file mode 100644 index 0000000..1604521 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfBorderDictionary.cs @@ -0,0 +1,101 @@ +using System; + +/* + * $Id: PdfBorderDictionary.cs,v 1.3 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfBorderDictionary define the appearance of a Border (Annotations). + * + * @see PdfDictionary + */ + + public class PdfBorderDictionary : PdfDictionary { + + public const int STYLE_SOLID = 0; + public const int STYLE_DASHED = 1; + public const int STYLE_BEVELED = 2; + public const int STYLE_INSET = 3; + public const int STYLE_UNDERLINE = 4; + // constructors + + /** + * Constructs a PdfBorderDictionary. + */ + + public PdfBorderDictionary(float borderWidth, int borderStyle, PdfDashPattern dashes) { + Put(PdfName.W, new PdfNumber(borderWidth)); + switch (borderStyle) { + case STYLE_SOLID: + Put(PdfName.S, PdfName.S); + break; + case STYLE_DASHED: + if (dashes != null) + Put(PdfName.D, dashes); + Put(PdfName.S, PdfName.D); + break; + case STYLE_BEVELED: + Put(PdfName.S, PdfName.B); + break; + case STYLE_INSET: + Put(PdfName.S, PdfName.I); + break; + case STYLE_UNDERLINE: + Put(PdfName.S, PdfName.U); + break; + default: + throw new ArgumentException("Invalid border style."); + } + } + + public PdfBorderDictionary(float borderWidth, int borderStyle) : this(borderWidth, borderStyle, null) {} + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfCell.cs b/iTechSharp/iTextSharp/text/pdf/PdfCell.cs new file mode 100644 index 0000000..c0633f8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfCell.cs @@ -0,0 +1,875 @@ +using System; +using System.Collections; + +using iTextSharp.text; + +/* + * $Id: PdfCell.cs,v 1.10 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfCell is the PDF translation of a Cell. + *

    + * A PdfCell is an ArrayList of PdfLines. + * + * @see iTextSharp.text.Rectangle + * @see iTextSharp.text.Cell + * @see PdfLine + * @see PdfTable + */ + + public class PdfCell : Rectangle { + + // membervariables + + /** These are the PdfLines in the Cell. */ + private ArrayList lines; + + /** These are the PdfLines in the Cell. */ + private PdfLine line; + + /** These are the Images in the Cell. */ + private ArrayList images; + + /** This is the leading of the lines. */ + private float leading; + + /** This is the number of the row the cell is in. */ + private int rownumber; + + /** This is the rowspan of the cell. */ + private int rowspan; + + /** This is the cellspacing of the cell. */ + private float cellspacing; + + /** This is the cellpadding of the cell. */ + private float cellpadding; + + /** Indicates if this cell belongs to the header of a PdfTable */ + private bool header = false; + + /** + * This is the total height of the content of the cell. Note that the actual cell + * height may be larger due to another cell on the row * + */ + private float contentHeight = 0.0f; + + /** + * Indicates that the largest ascender height should be used to + * determine the height of the first line. Setting this to true can help + * with vertical alignment problems. */ + private bool useAscender; + + /** + * Indicates that the largest descender height should be added to the height of + * the last line (so characters like y don't dip into the border). */ + private bool useDescender; + + /** + * Adjusts the cell contents to compensate for border widths. + */ + private bool useBorderPadding; + + private int verticalAlignment; + + private PdfLine firstLine; + private PdfLine lastLine; + + // constructors + + /** + * Constructs a PdfCell-object. + * + * @param cell the original Cell + * @param rownumber the number of the Row the Cell was in. + * @param left the left border of the PdfCell + * @param right the right border of the PdfCell + * @param top the top border of the PdfCell + * @param cellspacing the cellspacing of the Table + * @param cellpadding the cellpadding of the Table + */ + + public PdfCell(Cell cell, int rownumber, float left, float right, float top, float cellspacing, float cellpadding) : base(left, top, right, top) { + // copying the other Rectangle attributes from class Cell + CloneNonPositionParameters(cell); + this.cellpadding = cellpadding; + this.cellspacing = cellspacing; + this.verticalAlignment = cell.VerticalAlignment; + this.useAscender = cell.UseAscender; + this.useDescender = cell.UseDescender; + this.useBorderPadding = cell.UseBorderPadding; + + // initialisation of some parameters + PdfChunk chunk; + PdfChunk overflow; + lines = new ArrayList(); + images = new ArrayList(); + leading = cell.Leading; + int alignment = cell.HorizontalAlignment; + left += cellspacing + cellpadding; + right -= cellspacing + cellpadding; + + left += GetBorderWidthInside(LEFT_BORDER); + right -= GetBorderWidthInside(RIGHT_BORDER); + contentHeight = 0; + rowspan = cell.Rowspan; + + ArrayList allActions; + int aCounter; + // we loop over all the elements of the cell + foreach (IElement ele in cell.Elements) { + switch (ele.Type) { + case Element.JPEG: + case Element.JPEG2000: + case Element.IMGRAW: + case Element.IMGTEMPLATE: + AddImage((Image)ele, left, right, 0.4f * leading, alignment); + break; + // if the element is a list + case Element.LIST: + if (line != null && line.Size > 0) { + line.ResetAlignment(); + AddLine(line); + } + // we loop over all the listitems + AddList((List)ele, left, right, alignment); + line = new PdfLine(left, right, alignment, leading); + break; + // if the element is something else + default: + allActions = new ArrayList(); + ProcessActions(ele, null, allActions); + aCounter = 0; + + float currentLineLeading = leading; + float currentLeft = left; + float currentRight = right; + if (ele is Phrase) { + currentLineLeading = ((Phrase) ele).Leading; + } + if (ele is Paragraph) { + Paragraph p = (Paragraph) ele; + currentLeft += p.IndentationLeft; + currentRight -= p.IndentationRight; + } + if (line == null) { + line = new PdfLine(currentLeft, currentRight, alignment, currentLineLeading); + } + // we loop over the chunks + ArrayList chunks = ele.Chunks; + if (chunks.Count == 0) { + AddLine(line); // add empty line - all cells need some lines even if they are empty + line = new PdfLine(currentLeft, currentRight, alignment, currentLineLeading); + } + else { + foreach (Chunk c in chunks) { + chunk = new PdfChunk(c, (PdfAction)allActions[aCounter++]); + while ((overflow = line.Add(chunk)) != null) { + AddLine(line); + line = new PdfLine(currentLeft, currentRight, alignment, currentLineLeading); + chunk = overflow; + } + } + } + // if the element is a paragraph, section or chapter, we reset the alignment and add the line + switch (ele.Type) { + case Element.PARAGRAPH: + case Element.SECTION: + case Element.CHAPTER: + line.ResetAlignment(); + FlushCurrentLine(); + break; + } + break; + } + } + FlushCurrentLine(); + if (lines.Count > cell.MaxLines) { + while (lines.Count > cell.MaxLines) { + RemoveLine(lines.Count - 1); + } + if (cell.MaxLines > 0) { + String more = cell.ShowTruncation; + if (more != null && more.Length > 0) { + // Denote that the content has been truncated + lastLine = (PdfLine) lines[lines.Count - 1]; + if (lastLine.Size >= 0) { + PdfChunk lastChunk = lastLine.GetChunk(lastLine.Size - 1); + float moreWidth = new PdfChunk(more, lastChunk).Width; + while (lastChunk.ToString().Length > 0 && lastChunk.Width + moreWidth > right - left) { + // Remove characters to leave room for the 'more' indicator + lastChunk.Value = lastChunk.ToString().Substring(0, lastChunk.Length - 1); + } + lastChunk.Value = lastChunk.ToString() + more; + } else { + lastLine.Add(new PdfChunk(new Chunk(more), null)); + } + } + } + } + // we set some additional parameters + if (useDescender && lastLine != null) { + contentHeight -= lastLine.Descender; + } + + // adjust first line height so that it touches the top + if (lines.Count > 0) { + firstLine = (PdfLine) lines[0]; + float firstLineRealHeight = FirstLineRealHeight; + contentHeight -= firstLine.Height; + firstLine.height = firstLineRealHeight; + contentHeight += firstLineRealHeight; + } + + float newBottom = top - contentHeight - (2f * Cellpadding) - (2f * Cellspacing); + newBottom -= GetBorderWidthInside(TOP_BORDER) + GetBorderWidthInside(BOTTOM_BORDER); + Bottom = newBottom; + + this.rownumber = rownumber; + } + + private void AddList(List list, float left, float right, int alignment) { + PdfChunk chunk; + PdfChunk overflow; + ArrayList allActions = new ArrayList(); + ProcessActions(list, null, allActions); + int aCounter = 0; + foreach (IElement ele in list.Items) { + switch (ele.Type) { + case Element.LISTITEM: + ListItem item = (ListItem)ele; + line = new PdfLine(left + item.IndentationLeft, right, alignment, item.Leading); + line.ListItem = item; + foreach (Chunk c in item.Chunks) { + chunk = new PdfChunk(c, (PdfAction)(allActions[aCounter++])); + while ((overflow = line.Add(chunk)) != null) { + AddLine(line); + line = new PdfLine(left + item.IndentationLeft, right, alignment, item.Leading); + chunk = overflow; + } + line.ResetAlignment(); + AddLine(line); + line = new PdfLine(left + item.IndentationLeft, right, alignment, leading); + } + break; + case Element.LIST: + List sublist = (List)ele; + AddList(sublist, left + sublist.IndentationLeft, right, alignment); + break; + } + } + } + + // overriding of the Rectangle methods + + /** + * Returns the lower left x-coordinaat. + * + * @return the lower left x-coordinaat + */ + + public override float Left { + get { + return base.GetLeft(cellspacing); + } + } + + /** + * Returns the upper right x-coordinate. + * + * @return the upper right x-coordinate + */ + + public override float Right { + get { + return base.GetRight(cellspacing); + } + } + + /** + * Returns the upper right y-coordinate. + * + * @return the upper right y-coordinate + */ + + public override float Top { + get { + return base.GetTop(cellspacing); + } + } + + /** + * Returns the lower left y-coordinate. + * + * @return the lower left y-coordinate + */ + + public override float Bottom { + get { + return base.GetBottom(cellspacing); + } + set { + base.Bottom = value; + float firstLineRealHeight = FirstLineRealHeight; + + float totalHeight = ury - value; // can't use top (already compensates for cellspacing) + float nonContentHeight = (Cellpadding * 2f) + (Cellspacing * 2f); + nonContentHeight += GetBorderWidthInside(TOP_BORDER) + GetBorderWidthInside(BOTTOM_BORDER); + + float interiorHeight = totalHeight - nonContentHeight; + float extraHeight = 0.0f; + + switch (verticalAlignment) { + case Element.ALIGN_BOTTOM: + extraHeight = interiorHeight - contentHeight; + break; + case Element.ALIGN_MIDDLE: + extraHeight = (interiorHeight - contentHeight) / 2.0f; + break; + default: // ALIGN_TOP + extraHeight = 0f; + break; + } + + extraHeight += Cellpadding + Cellspacing; + extraHeight += GetBorderWidthInside(TOP_BORDER); + if (firstLine != null) { + firstLine.height = firstLineRealHeight + extraHeight; + } + } + } + + // methods + + private void AddLine(PdfLine line) { + lines.Add(line); + contentHeight += line.Height; + lastLine = line; + this.line = null; + } + + private PdfLine RemoveLine(int index) { + PdfLine oldLine = (PdfLine)lines[index]; + lines.RemoveAt(index); + contentHeight -= oldLine.Height; + if (index == 0) { + if (lines.Count > 0) { + firstLine = (PdfLine) lines[0]; + float firstLineRealHeight = FirstLineRealHeight; + contentHeight -= firstLine.Height; + firstLine.height = firstLineRealHeight; + contentHeight += firstLineRealHeight; + } + } + return oldLine; + } + + private void FlushCurrentLine() { + if (line != null && line.Size > 0) { + AddLine(line); + } + } + + /** + * Calculates what the height of the first line should be so that the content will be + * flush with the top. For text, this is the height of the ascender. For an image, + * it is the actual height of the image. + * @return the real height of the first line + */ + private float FirstLineRealHeight { + get { + float firstLineRealHeight = 0f; + if (firstLine != null) { + PdfChunk chunk = firstLine.GetChunk(0); + if (chunk != null) { + Image image = chunk.Image; + if (image != null) { + firstLineRealHeight = firstLine.GetChunk(0).Image.ScaledHeight; + } else { + firstLineRealHeight = useAscender ? firstLine.Ascender : leading; + } + } + } + return firstLineRealHeight; + } + } + + /** + * Gets the amount of the border for the specified side that is inside the Rectangle. + * For non-variable width borders this is only 1/2 the border width on that side. This + * always returns 0 if {@link #useBorderPadding} is false; + * @param side the side to check. One of the side constants in {@link com.lowagie.text.Rectangle} + * @return the borderwidth inside the cell + */ + private float GetBorderWidthInside(int side) { + float width = 0f; + if (useBorderPadding) { + switch (side) { + case iTextSharp.text.Rectangle.LEFT_BORDER: + width = BorderWidthLeft; + break; + + case iTextSharp.text.Rectangle.RIGHT_BORDER: + width = BorderWidthRight; + break; + + case iTextSharp.text.Rectangle.TOP_BORDER: + width = BorderWidthTop; + break; + + default: // default and BOTTOM + width = BorderWidthBottom; + break; + } + // non-variable (original style) borders overlap the rectangle (only 1/2 counts) + if (!UseVariableBorders) { + width = width / 2f; + } + } + return width; + } + + + /** + * Adds an image to this Cell. + * + * @param i the image to add + * @param left the left border + * @param right the right border + * @param extraHeight extra height to add above image + * @param alignment horizontal alignment (constant from Element class) + * @return the height of the image + */ + + private float AddImage(Image i, float left, float right, float extraHeight, int alignment) { + Image image = Image.GetInstance(i); + if (image.ScaledWidth > right - left) { + image.ScaleToFit(right - left, float.MaxValue); + } + FlushCurrentLine(); + if (line == null) { + line = new PdfLine(left, right, alignment, leading); + } + PdfLine imageLine = line; + + // left and right in chunk is relative to the start of the line + right = right - left; + left = 0f; + + if ((image.Alignment & Image.RIGHT_ALIGN) == Image.RIGHT_ALIGN) { // fix Uwe Zimmerman + left = right - image.ScaledWidth; + } else if ((image.Alignment & Image.MIDDLE_ALIGN) == Image.MIDDLE_ALIGN) { + left = left + ((right - left - image.ScaledWidth) / 2f); + } + Chunk imageChunk = new Chunk(image, left, 0); + imageLine.Add(new PdfChunk(imageChunk, null)); + AddLine(imageLine); + return imageLine.Height; + } + + /** + * Gets the lines of a cell that can be drawn between certain limits. + *

    + * Remark: all the lines that can be drawn are removed from the object! + * + * @param top the top of the part of the table that can be drawn + * @param bottom the bottom of the part of the table that can be drawn + * @return an ArrayList of PdfLines + */ + + public ArrayList GetLines(float top, float bottom) { + float lineHeight; + float currentPosition = Math.Min(this.Top, top); + this.Top = currentPosition + cellspacing; + ArrayList result = new ArrayList(); + + // if the bottom of the page is higher than the top of the cell: do nothing + if (Top < bottom) { + return result; + } + + // we loop over the lines + int size = lines.Count; + bool aboveBottom = true; + for (int i = 0; i < size && aboveBottom; i++) { + line = (PdfLine) lines[i]; + lineHeight = line.Height; + currentPosition -= lineHeight; + // if the currentPosition is higher than the bottom, we add the line to the result + if (currentPosition > (bottom + cellpadding + GetBorderWidthInside(BOTTOM_BORDER))) { // bugfix by Tom Ring and Veerendra Namineni + result.Add(line); + } + else { + aboveBottom = false; + } + } + // if the bottom of the cell is higher than the bottom of the page, the cell is written, so we can remove all lines + float difference = 0f; + if (!header) { + if (aboveBottom) { + lines = new ArrayList(); + contentHeight = 0f; + } + else { + size = result.Count; + for (int i = 0; i < size; i++) { + line = RemoveLine(0); + difference += line.Height; + } + } + } + if (difference > 0) { + foreach (Image image in images) { + image.SetAbsolutePosition(image.AbsoluteX, image.AbsoluteY - difference - leading); + } + } + return result; + } + + /** + * Gets the images of a cell that can be drawn between certain limits. + *

    + * Remark: all the lines that can be drawn are removed from the object! + * + * @param top the top of the part of the table that can be drawn + * @param bottom the bottom of the part of the table that can be drawn + * @return an ArrayList of Images + */ + + public ArrayList GetImages(float top, float bottom) { + + // if the bottom of the page is higher than the top of the cell: do nothing + if (this.Top < bottom) { + return new ArrayList(); + } + top = Math.Min(this.Top, top); + // initialisations + float height; + ArrayList result = new ArrayList(); + // we loop over the images + ArrayList remove = new ArrayList(); + foreach (Image image in images) { + height = image.AbsoluteY; + // if the currentPosition is higher than the bottom, we add the line to the result + if (top - height > (bottom + cellpadding)) { + image.SetAbsolutePosition(image.AbsoluteX, top - height); + result.Add(image); + remove.Add(image); + } + } + foreach (Image image in remove) { + images.Remove(image); + } + return result; + } + + /** + * Checks if this cell belongs to the header of a PdfTable. + * + * @return void + */ + + internal void SetHeader() { + header = true; + } + + /** + * Indicates that this cell belongs to the header of a PdfTable. + */ + + internal bool Header { + get { + return header; + } + } + + /** + * Checks if the cell may be removed. + *

    + * Headers may allways be removed, even if they are drawn only partially: + * they will be repeated on each following page anyway! + * + * @return true if all the lines are allready drawn; false otherwise. + */ + + internal bool MayBeRemoved() { + return (header || (lines.Count == 0 && images.Count == 0)); + } + + /** + * Returns the number of lines in the cell. + * + * @return a value + */ + + public int Size { + get { + return lines.Count; + } + } + + /** + * Returns the total height of all the lines in the cell. + * + * @return a value + */ + + private float RemainingLinesHeight() { + if (lines.Count == 0) return 0; + float result = 0; + int size = lines.Count; + PdfLine line; + for (int i = 0; i < size; i++) { + line = (PdfLine) lines[i]; + result += line.Height; + } + return result; + } + + /** + * Returns the height needed to draw the remaining text. + * + * @return a height + */ + + public float RemainingHeight { + get { + float result = 0f; + foreach (Image image in images) { + result += image.ScaledHeight; + } + return RemainingLinesHeight() + cellspacing + 2 * cellpadding + result; + } + } + + // methods to retrieve membervariables + + /** + * Gets the leading of a cell. + * + * @return the leading of the lines is the cell. + */ + + public float Leading { + get { + return leading; + } + } + + /** + * Gets the number of the row this cell is in.. + * + * @return a number + */ + + public int Rownumber { + get { + return rownumber; + } + } + + /** + * Gets the rowspan of a cell. + * + * @return the rowspan of the cell + */ + + public int Rowspan { + get { + return rowspan; + } + } + + /** + * Gets the cellspacing of a cell. + * + * @return a value + */ + + public float Cellspacing { + get { + return cellspacing; + } + } + + /** + * Gets the cellpadding of a cell.. + * + * @return a value + */ + + public float Cellpadding { + get { + return cellpadding; + } + } + + /** + * Processes all actions contained in the cell. + */ + + protected void ProcessActions(IElement element, PdfAction action, ArrayList allActions) { + if (element.Type == Element.ANCHOR) { + string url = ((Anchor)element).Reference; + if (url != null) { + action = new PdfAction(url); + } + } + switch (element.Type) { + case Element.PHRASE: + case Element.SECTION: + case Element.ANCHOR: + case Element.CHAPTER: + case Element.LISTITEM: + case Element.PARAGRAPH: + foreach (IElement ele in ((ArrayList)element)) { + ProcessActions(ele, action, allActions); + } + break; + case Element.CHUNK: + allActions.Add(action); + break; + case Element.LIST: + foreach (IElement ele in ((List)element).Items) { + ProcessActions(ele, action, allActions); + } + break; + default: + int n = element.Chunks.Count; + while (n-- > 0) + allActions.Add(action); + break; + } + } + + /** + * This is the number of the group the cell is in. + */ + private int groupNumber; + + /** + * Gets the number of the group this cell is in.. + * + * @return a number + */ + + public int GroupNumber { + get { + return groupNumber; + } + set { + groupNumber = value; + } + } + + /** + * Gets a Rectangle that is altered to fit on the page. + * + * @param top the top position + * @param bottom the bottom position + * @return a Rectangle + */ + + public Rectangle Rectangle(float top, float bottom) { + Rectangle tmp = new Rectangle(Left, Bottom, Right, Top); + tmp.CloneNonPositionParameters(this); + if (Top > top) { + tmp.Top = top; + tmp.Border = border - (border & TOP_BORDER); + } + if (Bottom < bottom) { + tmp.Bottom = bottom; + tmp.Border = border - (border & BOTTOM_BORDER); + } + return tmp; + } + + /** + * Gets the value of {@link #useAscender} + * @return useAscender + */ + public bool UseAscender { + get { + return useAscender; + } + set { + useAscender = value; + } + } + + /** + * Gets the value of {@link #useDescender} + * @return useDescender + */ + public bool UseDescender { + get { + return useDescender; + } + set { + useDescender = value; + } + } + + /** + * Sets the value of {@link #useBorderPadding}. + * @param use adjust layour for borders if true + */ + public bool UseBorderPadding { + set { + useBorderPadding = value; + } + get { + return useBorderPadding; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfChunk.cs b/iTechSharp/iTextSharp/text/pdf/PdfChunk.cs new file mode 100644 index 0000000..bb90e36 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfChunk.cs @@ -0,0 +1,841 @@ +using System; +using System.Collections; +using System.util; + +using iTextSharp.text; + +/* + * $Id: PdfChunk.cs,v 1.11 2008/05/22 22:11:10 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfChunk is the PDF translation of a Chunk. + *

    + * A PdfChunk is a PdfString in a certain + * PdfFont and Color. + * + * @see PdfString + * @see PdfFont + * @see iTextSharp.text.Chunk + * @see iTextSharp.text.Font + */ + + public class PdfChunk { + + + private static char[] singleSpace = {' '}; + private static PdfChunk[] thisChunk = new PdfChunk[1]; + private const float ITALIC_ANGLE = 0.21256f; + + /** The allowed attributes in variable attributes. */ + private static Hashtable keysAttributes = new Hashtable(); + + /** The allowed attributes in variable noStroke. */ + private static Hashtable keysNoStroke = new Hashtable(); + + static PdfChunk() { + keysAttributes.Add(Chunk.ACTION, null); + keysAttributes.Add(Chunk.UNDERLINE, null); + keysAttributes.Add(Chunk.REMOTEGOTO, null); + keysAttributes.Add(Chunk.LOCALGOTO, null); + keysAttributes.Add(Chunk.LOCALDESTINATION, null); + keysAttributes.Add(Chunk.GENERICTAG, null); + keysAttributes.Add(Chunk.NEWPAGE, null); + keysAttributes.Add(Chunk.IMAGE, null); + keysAttributes.Add(Chunk.BACKGROUND, null); + keysAttributes.Add(Chunk.PDFANNOTATION, null); + keysAttributes.Add(Chunk.SKEW, null); + keysAttributes.Add(Chunk.HSCALE, null); + keysAttributes.Add(Chunk.SEPARATOR, null); + keysAttributes.Add(Chunk.TAB, null); + keysNoStroke.Add(Chunk.SUBSUPSCRIPT, null); + keysNoStroke.Add(Chunk.SPLITCHARACTER, null); + keysNoStroke.Add(Chunk.HYPHENATION, null); + keysNoStroke.Add(Chunk.TEXTRENDERMODE, null); + } + + // membervariables + + /** The value of this object. */ + protected string value = PdfObject.NOTHING; + + /** The encoding. */ + protected string encoding = BaseFont.WINANSI; + + + /** The font for this PdfChunk. */ + protected PdfFont font; + + protected BaseFont baseFont; + + protected ISplitCharacter splitCharacter; + /** + * Metric attributes. + *

    + * This attributes require the mesurement of characters widths when rendering + * such as underline. + */ + protected Hashtable attributes = new Hashtable(); + + /** + * Non metric attributes. + *

    + * This attributes do not require the mesurement of characters widths when rendering + * such as Color. + */ + protected Hashtable noStroke = new Hashtable(); + + /** true if the chunk split was cause by a newline. */ + protected bool newlineSplit; + + /** The image in this PdfChunk, if it has one */ + protected Image image; + + /** The offset in the x direction for the image */ + protected float offsetX; + + /** The offset in the y direction for the image */ + protected float offsetY; + + /** Indicates if the height and offset of the Image has to be taken into account */ + protected bool changeLeading = false; + + // constructors + + /** + * Constructs a PdfChunk-object. + * + * @param string the content of the PdfChunk-object + * @param font the PdfFont + * @param attributes the metrics attributes + * @param noStroke the non metric attributes + */ + + internal PdfChunk(string str, PdfChunk other) { + thisChunk[0] = this; + value = str; + this.font = other.font; + this.attributes = other.attributes; + this.noStroke = other.noStroke; + this.baseFont = other.baseFont; + Object[] obj = (Object[])attributes[Chunk.IMAGE]; + if (obj == null) + image = null; + else { + image = (Image)obj[0]; + offsetX = (float)obj[1]; + offsetY = (float)obj[2]; + changeLeading = (bool)obj[3]; + } + encoding = font.Font.Encoding; + splitCharacter = (ISplitCharacter)noStroke[Chunk.SPLITCHARACTER]; + if (splitCharacter == null) + splitCharacter = DefaultSplitCharacter.DEFAULT; + } + + /** + * Constructs a PdfChunk-object. + * + * @param chunk the original Chunk-object + * @param action the PdfAction if the Chunk comes from an Anchor + */ + + internal PdfChunk(Chunk chunk, PdfAction action) { + thisChunk[0] = this; + value = chunk.Content; + + Font f = chunk.Font; + float size = f.Size; + if (size == iTextSharp.text.Font.UNDEFINED) + size = 12; + baseFont = f.BaseFont; + BaseFont bf = f.BaseFont; + int style = f.Style; + if (style == iTextSharp.text.Font.UNDEFINED) { + style = iTextSharp.text.Font.NORMAL; + } + if (baseFont == null) { + // translation of the font-family to a PDF font-family + baseFont = f.GetCalculatedBaseFont(false); + } + else{ + // bold simulation + if ((style & iTextSharp.text.Font.BOLD) != 0) + attributes[Chunk.TEXTRENDERMODE] = new Object[]{PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE, size / 30f, null}; + // italic simulation + if ((style & iTextSharp.text.Font.ITALIC) != 0) + attributes[Chunk.SKEW] = new float[]{0, ITALIC_ANGLE}; + } + font = new PdfFont(baseFont, size); + // other style possibilities + Hashtable attr = chunk.Attributes; + if (attr != null) { + foreach (DictionaryEntry entry in attr) { + string name = (string)entry.Key; + if (keysAttributes.ContainsKey(name)) { + attributes[name] = entry.Value; + } + else if (keysNoStroke.ContainsKey(name)) { + noStroke[name] = entry.Value; + } + } + if ("".Equals(attr[Chunk.GENERICTAG])) { + attributes[Chunk.GENERICTAG] = chunk.Content; + } + } + if (f.IsUnderlined()) { + Object[] obj = {null, new float[]{0, 1f / 15, 0, -1f / 3, 0}}; + Object[][] unders = Utilities.AddToArray((Object[][])attributes[Chunk.UNDERLINE], obj); + attributes[Chunk.UNDERLINE] = unders; + } + if (f.IsStrikethru()) { + Object[] obj = {null, new float[]{0, 1f / 15, 0, 1f / 3, 0}}; + Object[][] unders = Utilities.AddToArray((Object[][])attributes[Chunk.UNDERLINE], obj); + attributes[Chunk.UNDERLINE] = unders; + } + if (action != null) + attributes[Chunk.ACTION] = action; + // the color can't be stored in a PdfFont + noStroke[Chunk.COLOR] = f.Color; + noStroke[Chunk.ENCODING] = font.Font.Encoding; + Object[] obj2 = (Object[])attributes[Chunk.IMAGE]; + if (obj2 == null) + image = null; + else { + attributes.Remove(Chunk.HSCALE); // images are scaled in other ways + image = (Image)obj2[0]; + offsetX = ((float)obj2[1]); + offsetY = ((float)obj2[2]); + changeLeading = (bool)obj2[3]; + } + font.Image = image; + object hs = attributes[Chunk.HSCALE]; + if (hs != null) + font.HorizontalScaling = (float)hs; + encoding = font.Font.Encoding; + splitCharacter = (ISplitCharacter)noStroke[Chunk.SPLITCHARACTER]; + if (splitCharacter == null) + splitCharacter = DefaultSplitCharacter.DEFAULT; + } + + // methods + + /** Gets the Unicode equivalent to a CID. + * The (inexistent) CID is translated as '\n'. + * It has only meaning with CJK fonts with Identity encoding. + * @param c the CID code + * @return the Unicode equivalent + */ + public int GetUnicodeEquivalent(int c) { + return baseFont.GetUnicodeEquivalent(c); + } + + protected int GetWord(string text, int start) { + int len = text.Length; + while (start < len) { + if (!char.IsLetter(text[start])) + break; + ++start; + } + return start; + } + + /** + * Splits this PdfChunk if it's too long for the given width. + *

    + * Returns null if the PdfChunk wasn't truncated. + * + * @param width a given width + * @return the PdfChunk that doesn't fit into the width. + */ + + internal PdfChunk Split(float width) { + newlineSplit = false; + if (image != null) { + if (image.ScaledWidth > width) { + PdfChunk pc = new PdfChunk(Chunk.OBJECT_REPLACEMENT_CHARACTER, this); + value = ""; + attributes = new Hashtable(); + image = null; + font = PdfFont.DefaultFont; + return pc; + } + else + return null; + } + IHyphenationEvent hyphenationEvent = (IHyphenationEvent)noStroke[Chunk.HYPHENATION]; + int currentPosition = 0; + int splitPosition = -1; + float currentWidth = 0; + + // loop over all the characters of a string + // or until the totalWidth is reached + int lastSpace = -1; + float lastSpaceWidth = 0; + int length = value.Length; + char[] valueArray = value.ToCharArray(); + char character = (char)0; + BaseFont ft = font.Font; + bool surrogate = false; + if (ft.FontType == BaseFont.FONT_TYPE_CJK && ft.GetUnicodeEquivalent(' ') != ' ') { + while (currentPosition < length) { + // the width of every character is added to the currentWidth + char cidChar = valueArray[currentPosition]; + character = (char)ft.GetUnicodeEquivalent(cidChar); + // if a newLine or carriageReturn is encountered + if (character == '\n') { + newlineSplit = true; + string returnValue = value.Substring(currentPosition + 1); + value = value.Substring(0, currentPosition); + if (value.Length < 1) { + value = "\u0001"; + } + PdfChunk pc = new PdfChunk(returnValue, this); + return pc; + } + currentWidth += font.Width(cidChar); + if (character == ' ') { + lastSpace = currentPosition + 1; + lastSpaceWidth = currentWidth; + } + if (currentWidth > width) + break; + // if a split-character is encountered, the splitPosition is altered + if (splitCharacter.IsSplitCharacter(0, currentPosition, length, valueArray, thisChunk)) + splitPosition = currentPosition + 1; + currentPosition++; + } + } + else { + while (currentPosition < length) { + // the width of every character is added to the currentWidth + character = valueArray[currentPosition]; + // if a newLine or carriageReturn is encountered + if (character == '\r' || character == '\n') { + newlineSplit = true; + int inc = 1; + if (character == '\r' && currentPosition + 1 < length && valueArray[currentPosition + 1] == '\n') + inc = 2; + string returnValue = value.Substring(currentPosition + inc); + value = value.Substring(0, currentPosition); + if (value.Length < 1) { + value = " "; + } + PdfChunk pc = new PdfChunk(returnValue, this); + return pc; + } + surrogate = Utilities.IsSurrogatePair(valueArray, currentPosition); + if (surrogate) + currentWidth += font.Width(Utilities.ConvertToUtf32(valueArray[currentPosition], valueArray[currentPosition + 1])); + else + currentWidth += font.Width(character); + if (character == ' ') { + lastSpace = currentPosition + 1; + lastSpaceWidth = currentWidth; + } + if (surrogate) + currentPosition++; + if (currentWidth > width) + break; + // if a split-character is encountered, the splitPosition is altered + if (splitCharacter.IsSplitCharacter(0, currentPosition, length, valueArray, null)) + splitPosition = currentPosition + 1; + currentPosition++; + } + } + + // if all the characters fit in the total width, null is returned (there is no overflow) + if (currentPosition == length) { + return null; + } + // otherwise, the string has to be truncated + if (splitPosition < 0) { + string returnValue = value; + value = ""; + PdfChunk pc = new PdfChunk(returnValue, this); + return pc; + } + if (lastSpace > splitPosition && splitCharacter.IsSplitCharacter(0, 0, 1, singleSpace, null)) + splitPosition = lastSpace; + if (hyphenationEvent != null && lastSpace >= 0 && lastSpace < currentPosition) { + int wordIdx = GetWord(value, lastSpace); + if (wordIdx > lastSpace) { + string pre = hyphenationEvent.GetHyphenatedWordPre(value.Substring(lastSpace, wordIdx - lastSpace), font.Font, font.Size, width - lastSpaceWidth); + string post = hyphenationEvent.HyphenatedWordPost; + if (pre.Length > 0) { + string returnValue = post + value.Substring(wordIdx); + value = Trim(value.Substring(0, lastSpace) + pre); + PdfChunk pc = new PdfChunk(returnValue, this); + return pc; + } + } + } + string retVal = value.Substring(splitPosition); + value = Trim(value.Substring(0, splitPosition)); + PdfChunk tmp = new PdfChunk(retVal, this); + return tmp; + } + + /** + * Truncates this PdfChunk if it's too long for the given width. + *

    + * Returns null if the PdfChunk wasn't truncated. + * + * @param width a given width + * @return the PdfChunk that doesn't fit into the width. + */ + + internal PdfChunk Truncate(float width) { + if (image != null) { + if (image.ScaledWidth > width) { + PdfChunk pc = new PdfChunk("", this); + value = ""; + attributes.Remove(Chunk.IMAGE); + image = null; + font = PdfFont.DefaultFont; + return pc; + } + else + return null; + } + + int currentPosition = 0; + float currentWidth = 0; + + // it's no use trying to split if there isn't even enough place for a space + if (width < font.Width()) { + string returnValue = value.Substring(1); + value = value.Substring(0, 1); + PdfChunk pc = new PdfChunk(returnValue, this); + return pc; + } + + // loop over all the characters of a string + // or until the totalWidth is reached + int length = value.Length; + bool surrogate = false; + while (currentPosition < length) { + // the width of every character is added to the currentWidth + surrogate = Utilities.IsSurrogatePair(value, currentPosition); + if (surrogate) + currentWidth += font.Width(Utilities.ConvertToUtf32(value, currentPosition)); + else + currentWidth += font.Width(value[currentPosition]); + if (currentWidth > width) + break; + if (surrogate) + currentPosition++; + currentPosition++; + } + + // if all the characters fit in the total width, null is returned (there is no overflow) + if (currentPosition == length) { + return null; + } + + // otherwise, the string has to be truncated + //currentPosition -= 2; + // we have to chop off minimum 1 character from the chunk + if (currentPosition == 0) { + currentPosition = 1; + if (surrogate) + ++currentPosition; + } + string retVal = value.Substring(currentPosition); + value = value.Substring(0, currentPosition); + PdfChunk tmp = new PdfChunk(retVal, this); + return tmp; + } + + // methods to retrieve the membervariables + + /** + * Returns the font of this Chunk. + * + * @return a PdfFont + */ + + internal PdfFont Font { + get { + return font; + } + } + + /** + * Returns the color of this Chunk. + * + * @return a Color + */ + + internal Color Color { + get { + return (Color)noStroke[Chunk.COLOR]; + } + } + + /** + * Returns the width of this PdfChunk. + * + * @return a width + */ + + internal float Width { + get { + return font.Width(this.value); + } + } + + /** + * Checks if the PdfChunk split was caused by a newline. + * @return true if the PdfChunk split was caused by a newline. + */ + + public bool IsNewlineSplit() { + return newlineSplit; + } + + /** + * Gets the width of the PdfChunk taking into account the + * extra character and word spacing. + * @param charSpacing the extra character spacing + * @param wordSpacing the extra word spacing + * @return the calculated width + */ + + public float GetWidthCorrected(float charSpacing, float wordSpacing) { + if (image != null) { + return image.ScaledWidth + charSpacing; + } + int numberOfSpaces = 0; + int idx = -1; + while ((idx = value.IndexOf(' ', idx + 1)) >= 0) + ++numberOfSpaces; + return Width + (value.Length * charSpacing + numberOfSpaces * wordSpacing); + } + + /** + * Gets the text displacement relatiev to the baseline. + * @return a displacement in points + */ + public float TextRise { + get { + object f = GetAttribute(Chunk.SUBSUPSCRIPT); + if (f != null) { + return (float)f; + } + return 0.0f; + } + } + + /** + * Trims the last space. + * @return the width of the space trimmed, otherwise 0 + */ + + public float TrimLastSpace() { + BaseFont ft = font.Font; + if (ft.FontType == BaseFont.FONT_TYPE_CJK && ft.GetUnicodeEquivalent(' ') != ' ') { + if (value.Length > 1 && value.EndsWith("\u0001")) { + value = value.Substring(0, value.Length - 1); + return font.Width('\u0001'); + } + } + else { + if (value.Length > 1 && value.EndsWith(" ")) { + value = value.Substring(0, value.Length - 1); + return font.Width(' '); + } + } + return 0; + } + + public float TrimFirstSpace() + { + BaseFont ft = font.Font; + if (ft.FontType == BaseFont.FONT_TYPE_CJK && ft.GetUnicodeEquivalent(' ') != ' ') { + if (value.Length > 1 && value.StartsWith("\u0001")) { + value = value.Substring(1); + return font.Width('\u0001'); + } + } + else { + if (value.Length > 1 && value.StartsWith(" ")) { + value = value.Substring(1); + return font.Width(' '); + } + } + return 0; + } + + /** + * Gets an attribute. The search is made in attributes + * and noStroke. + * @param name the attribute key + * @return the attribute value or null if not found + */ + + internal Object GetAttribute(string name) { + if (attributes.ContainsKey(name)) + return attributes[name]; + return noStroke[name]; + } + + /** + *Checks if the attribute exists. + * @param name the attribute key + * @return true if the attribute exists + */ + + internal bool IsAttribute(string name) { + if (attributes.ContainsKey(name)) + return true; + return noStroke.ContainsKey(name); + } + + /** + * Checks if this PdfChunk needs some special metrics handling. + * @return true if this PdfChunk needs some special metrics handling. + */ + + internal bool IsStroked() { + return (attributes.Count > 0); + } + + /** + * Checks if this PdfChunk is a Separator Chunk. + * @return true if this chunk is a separator. + * @since 2.1.2 + */ + internal bool IsSeparator() { + return IsAttribute(Chunk.SEPARATOR); + } + + /** + * Checks if this PdfChunk is a horizontal Separator Chunk. + * @return true if this chunk is a horizontal separator. + * @since 2.1.2 + */ + internal bool IsHorizontalSeparator() { + if (IsAttribute(Chunk.SEPARATOR)) { + Object[] o = (Object[])GetAttribute(Chunk.SEPARATOR); + return !(bool)o[1]; + } + return false; + } + + /** + * Checks if this PdfChunk is a tab Chunk. + * @return true if this chunk is a separator. + * @since 2.1.2 + */ + internal bool IsTab() { + return IsAttribute(Chunk.TAB); + } + + /** + * Correction for the tab position based on the left starting position. + * @param newValue the new value for the left X. + * @since 2.1.2 + */ + internal void AdjustLeft(float newValue) { + Object[] o = (Object[])attributes[Chunk.TAB]; + if (o != null) { + attributes[Chunk.TAB] = new Object[]{o[0], o[1], o[2], newValue}; + } + } + + /** + * Checks if there is an image in the PdfChunk. + * @return true if an image is present + */ + + internal bool IsImage() { + return image != null; + } + + /** + * Gets the image in the PdfChunk. + * @return the image or null + */ + + internal Image Image { + get { + return image; + } + } + + /** + * Gets the image offset in the x direction + * @return the image offset in the x direction + */ + + internal float ImageOffsetX { + get { + return offsetX; + } + + set { + this.offsetX = value; + } + } + + /** + * Gets the image offset in the y direction + * @return Gets the image offset in the y direction + */ + + internal float ImageOffsetY { + get { + return offsetY; + } + + set { + this.offsetY = value; + } + } + + /** + * sets the value. + */ + + internal string Value { + set { + this.value = value; + } + } + + public override string ToString() { + return value; + } + + /** + * Tells you if this string is in Chinese, Japanese, Korean or Identity-H. + */ + + internal bool IsSpecialEncoding() { + return encoding.Equals(CJKFont.CJK_ENCODING) || encoding.Equals(BaseFont.IDENTITY_H); + } + + /** + * Gets the encoding of this string. + * + * @return a string + */ + + internal string Encoding { + get { + return encoding; + } + } + + internal int Length { + get { + return value.Length; + } + } + + internal int LengthUtf32 { + get { + if (!BaseFont.IDENTITY_H.Equals(encoding)) + return value.Length; + int total = 0; + int len = value.Length; + for (int k = 0; k < len; ++k) { + if (Utilities.IsSurrogateHigh(value[k])) + ++k; + ++total; + } + return total; + } + } + + internal bool IsExtSplitCharacter(int start, int current, int end, char[] cc, PdfChunk[] ck) { + return splitCharacter.IsSplitCharacter(start, current, end, cc, ck); + } + + /** + * Removes all the ' ' and '-'-characters on the right of a string. + *

    + * @param string the string that has to be trimmed. + * @return the trimmed string + */ + internal string Trim(string str) { + BaseFont ft = font.Font; + if (ft.FontType == BaseFont.FONT_TYPE_CJK && ft.GetUnicodeEquivalent(' ') != ' ') { + while (str.EndsWith("\u0001")) { + str = str.Substring(0, str.Length - 1); + } + } + else { + while (str.EndsWith(" ") || str.EndsWith("\t")) { + str = str.Substring(0, str.Length - 1); + } + } + return str; + } + + public bool ChangeLeading { + get { + return changeLeading; + } + } + + internal float GetCharWidth(int c) { + if (NoPrint(c)) + return 0; + return font.Width(c); + } + + public static bool NoPrint(int c) { + return ((c >= 0x200b && c <= 0x200f) || (c >= 0x202a && c <= 0x202e)); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfColor.cs b/iTechSharp/iTextSharp/text/pdf/PdfColor.cs new file mode 100644 index 0000000..4b6c831 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfColor.cs @@ -0,0 +1,80 @@ +using System; +using iTextSharp.text; + +/* + * $Id: PdfColor.cs,v 1.3 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * A PdfColor defines a Color (it's a PdfArray containing 3 values). + * + * @see PdfDictionary + */ + + internal class PdfColor : PdfArray { + + // constructors + + /** + * Constructs a new PdfColor. + * + * @param red a value between 0 and 255 + * @param green a value between 0 and 255 + * @param blue a value between 0 and 255 + */ + + internal PdfColor(int red, int green, int blue) : base(new PdfNumber((double)(red & 0xFF) / 0xFF)) { + Add(new PdfNumber((double)(green & 0xFF) / 0xFF)); + Add(new PdfNumber((double)(blue & 0xFF) / 0xFF)); + } + + internal PdfColor(Color color) : this(color.R, color.G, color.B) {} + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfContentByte.cs b/iTechSharp/iTextSharp/text/pdf/PdfContentByte.cs new file mode 100644 index 0000000..b7a817d --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfContentByte.cs @@ -0,0 +1,2898 @@ +using System; +using System.Collections; +using System.Text; +using iTextSharp.text.pdf; +using iTextSharp.text.pdf.intern; + +/* + * $Id: PdfContentByte.cs,v 1.23 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfContentByte is an object containing the user positioned + * text and graphic contents of a page. It knows how to apply the proper + * font encoding. + */ + + public class PdfContentByte { + + /** + * This class keeps the graphic state of the current page + */ + + public class GraphicState { + + /** This is the font in use */ + internal FontDetails fontDetails; + + /** This is the color in use */ + internal ColorDetails colorDetails; + + /** This is the font size in use */ + internal float size; + + /** The x position of the text line matrix. */ + protected internal float xTLM = 0; + /** The y position of the text line matrix. */ + protected internal float yTLM = 0; + /** The current text leading. */ + protected internal float leading = 0; + + /** The current horizontal scaling */ + protected internal float scale = 100; + + /** The current character spacing */ + protected internal float charSpace = 0; + + /** The current word spacing */ + protected internal float wordSpace = 0; + + internal GraphicState() { + } + + internal GraphicState(GraphicState cp) { + fontDetails = cp.fontDetails; + colorDetails = cp.colorDetails; + size = cp.size; + xTLM = cp.xTLM; + yTLM = cp.yTLM; + leading = cp.leading; + scale = cp.scale; + charSpace = cp.charSpace; + wordSpace = cp.wordSpace; + } + } + + /** The alignement is center */ + public const int ALIGN_CENTER = Element.ALIGN_CENTER; + + /** The alignement is left */ + public const int ALIGN_LEFT = Element.ALIGN_LEFT; + + /** The alignement is right */ + public const int ALIGN_RIGHT = Element.ALIGN_RIGHT; + + /** A possible line cap value */ + public const int LINE_CAP_BUTT = 0; + /** A possible line cap value */ + public const int LINE_CAP_ROUND = 1; + /** A possible line cap value */ + public const int LINE_CAP_PROJECTING_SQUARE = 2; + + /** A possible line join value */ + public const int LINE_JOIN_MITER = 0; + /** A possible line join value */ + public const int LINE_JOIN_ROUND = 1; + /** A possible line join value */ + public const int LINE_JOIN_BEVEL = 2; + + /** A possible text rendering value */ + public const int TEXT_RENDER_MODE_FILL = 0; + /** A possible text rendering value */ + public const int TEXT_RENDER_MODE_STROKE = 1; + /** A possible text rendering value */ + public const int TEXT_RENDER_MODE_FILL_STROKE = 2; + /** A possible text rendering value */ + public const int TEXT_RENDER_MODE_INVISIBLE = 3; + /** A possible text rendering value */ + public const int TEXT_RENDER_MODE_FILL_CLIP = 4; + /** A possible text rendering value */ + public const int TEXT_RENDER_MODE_STROKE_CLIP = 5; + /** A possible text rendering value */ + public const int TEXT_RENDER_MODE_FILL_STROKE_CLIP = 6; + /** A possible text rendering value */ + public const int TEXT_RENDER_MODE_CLIP = 7; + + private static float[] unitRect = {0, 0, 0, 1, 1, 0, 1, 1}; + // membervariables + + /** This is the actual content */ + protected ByteBuffer content = new ByteBuffer(); + + /** This is the writer */ + protected PdfWriter writer; + + /** This is the PdfDocument */ + protected PdfDocument pdf; + + /** This is the GraphicState in use */ + protected GraphicState state = new GraphicState(); + + /** The list were we save/restore the layer depth */ + protected ArrayList layerDepth; + + /** The list were we save/restore the state */ + protected ArrayList stateList = new ArrayList(); + + /** The separator between commands. + */ + protected int separator = '\n'; + + private static Hashtable abrev = new Hashtable(); + + static PdfContentByte() { + abrev[PdfName.BITSPERCOMPONENT] = "/BPC "; + abrev[PdfName.COLORSPACE] = "/CS "; + abrev[PdfName.DECODE] = "/D "; + abrev[PdfName.DECODEPARMS] = "/DP "; + abrev[PdfName.FILTER] = "/F "; + abrev[PdfName.HEIGHT] = "/H "; + abrev[PdfName.IMAGEMASK] = "/IM "; + abrev[PdfName.INTENT] = "/Intent "; + abrev[PdfName.INTERPOLATE] = "/I "; + abrev[PdfName.WIDTH] = "/W "; + } + + // constructors + + /** + * Constructs a new PdfContentByte-object. + * + * @param wr the writer associated to this content + */ + + public PdfContentByte(PdfWriter wr) { + if (wr != null) { + writer = wr; + pdf = writer.PdfDocument; + } + } + + // methods to get the content of this object + + /** + * Returns the string representation of this PdfContentByte-object. + * + * @return a string + */ + + public override string ToString() { + return content.ToString(); + } + + /** + * Gets the internal buffer. + * @return the internal buffer + */ + public ByteBuffer InternalBuffer { + get { + return content; + } + } + + /** Returns the PDF representation of this PdfContentByte-object. + * + * @param writer the PdfWriter + * @return a byte array with the representation + */ + + public byte[] ToPdf(PdfWriter writer) { + return content.ToByteArray(); + } + + // methods to add graphical content + + /** + * Adds the content of another PdfContent-object to this object. + * + * @param other another PdfByteContent-object + */ + + public void Add(PdfContentByte other) { + if (other.writer != null && writer != other.writer) + throw new Exception("Inconsistent writers. Are you mixing two documents?"); + content.Append(other.content); + } + + /** + * Gets the x position of the text line matrix. + * + * @return the x position of the text line matrix + */ + public float XTLM { + get { + return state.xTLM; + } + } + + /** + * Gets the y position of the text line matrix. + * + * @return the y position of the text line matrix + */ + public float YTLM { + get { + return state.yTLM; + } + } + + /** + * Gets the current character spacing. + * + * @return the current character spacing + */ + public float CharacterSpacing { + get { + return state.charSpace; + } + } + + /** + * Gets the current word spacing. + * + * @return the current word spacing + */ + public float WordSpacing { + get { + return state.wordSpace; + } + } + + /** + * Gets the current character spacing. + * + * @return the current character spacing + */ + public float HorizontalScaling { + get { + return state.scale; + } + } + + /** + * Gets the current text leading. + * + * @return the current text leading + */ + public float Leading { + get { + return state.leading; + } + } + + public void SetLeading(float v) { + state.leading = v; + content.Append(v).Append(" TL").Append_i(separator); + } + + /** + * Changes the Flatness. + *

    + * Flatness sets the maximum permitted distance in device pixels between the + * mathematically correct path and an approximation constructed from straight line segments.
    + * + * @param flatness a value + */ + + public void SetFlatness(float value) { + if (value >= 0 && value <= 100) { + content.Append(value).Append(" i").Append_i(separator); + } + } + + /** + * Changes the Line cap style. + *

    + * The line cap style specifies the shape to be used at the end of open subpaths + * when they are stroked.
    + * Allowed values are 0 (Butt end caps), 1 (Round end caps) and 2 (Projecting square end caps).
    + * + * @param style a value + */ + + public void SetLineCap(int value) { + if (value >= 0 && value <= 2) { + content.Append(value).Append(" J").Append_i(separator); + } + } + + /** + * Changes the value of the line dash pattern. + *

    + * The line dash pattern controls the pattern of dashes and gaps used to stroke paths. + * It is specified by an array and a phase. The array specifies the length + * of the alternating dashes and gaps. The phase specifies the distance into the dash + * pattern to start the dash.
    + * + * @param phase the value of the phase + */ + + public void SetLineDash(float value) { + content.Append("[] ").Append(value).Append(" d").Append_i(separator); + } + + /** + * Changes the value of the line dash pattern. + *

    + * The line dash pattern controls the pattern of dashes and gaps used to stroke paths. + * It is specified by an array and a phase. The array specifies the length + * of the alternating dashes and gaps. The phase specifies the distance into the dash + * pattern to start the dash.
    + * + * @param phase the value of the phase + * @param unitsOn the number of units that must be 'on' (equals the number of units that must be 'off'). + */ + + public void SetLineDash(float unitsOn, float phase) { + content.Append('[').Append(unitsOn).Append("] ").Append(phase).Append(" d").Append_i(separator); + } + + /** + * Changes the value of the line dash pattern. + *

    + * The line dash pattern controls the pattern of dashes and gaps used to stroke paths. + * It is specified by an array and a phase. The array specifies the length + * of the alternating dashes and gaps. The phase specifies the distance into the dash + * pattern to start the dash.
    + * + * @param phase the value of the phase + * @param unitsOn the number of units that must be 'on' + * @param unitsOff the number of units that must be 'off' + */ + + public void SetLineDash(float unitsOn, float unitsOff, float phase) { + content.Append('[').Append(unitsOn).Append(' ').Append(unitsOff).Append("] ").Append(phase).Append(" d").Append_i(separator); + } + + /** + * Changes the value of the line dash pattern. + *

    + * The line dash pattern controls the pattern of dashes and gaps used to stroke paths. + * It is specified by an array and a phase. The array specifies the length + * of the alternating dashes and gaps. The phase specifies the distance into the dash + * pattern to start the dash.
    + * + * @param array length of the alternating dashes and gaps + * @param phase the value of the phase + */ + + public void SetLineDash(float[] array, float phase) { + content.Append('['); + for (int i = 0; i < array.Length; i++) { + content.Append(array[i]); + if (i < array.Length - 1) content.Append(' '); + } + content.Append("] ").Append(phase).Append(" d").Append_i(separator); + } + + /** + * Changes the Line join style. + *

    + * The line join style specifies the shape to be used at the corners of paths + * that are stroked.
    + * Allowed values are 0 (Miter joins), 1 (Round joins) and 2 (Bevel joins).
    + * + * @param style a value + */ + + public void SetLineJoin(int value) { + if (value >= 0 && value <= 2) { + content.Append(value).Append(" j").Append_i(separator); + } + } + + /** + * Changes the line width. + *

    + * The line width specifies the thickness of the line used to stroke a path and is measured + * in used space units.
    + * + * @param w a width + */ + + public void SetLineWidth(float value) { + content.Append(value).Append(" w").Append_i(separator); + } + + /** + * Changes the Miter limit. + *

    + * When two line segments meet at a sharp angle and mitered joins have been specified as the + * line join style, it is possible for the miter to extend far beyond the thickness of the line + * stroking path. The miter limit imposes a maximum on the ratio of the miter length to the line + * witdh. When the limit is exceeded, the join is converted from a miter to a bevel.
    + * + * @param miterLimit a miter limit + */ + + public void SetMiterLimit(float value) { + if (value > 1) { + content.Append(value).Append(" M").Append_i(separator); + } + } + + /** + * Modify the current clipping path by intersecting it with the current path, using the + * nonzero winding number rule to determine which regions lie inside the clipping + * path. + */ + + public void Clip() { + content.Append('W').Append_i(separator); + } + + /** + * Modify the current clipping path by intersecting it with the current path, using the + * even-odd rule to determine which regions lie inside the clipping path. + */ + + public void EoClip() { + content.Append("W*").Append_i(separator); + } + + /** + * Changes the currentgray tint for filling paths (device dependent colors!). + *

    + * Sets the color space to DeviceGray (or the DefaultGray color space), + * and sets the gray tint to use for filling paths.

    + * + * @param gray a value between 0 (black) and 1 (white) + */ + + public virtual void SetGrayFill(float value) { + content.Append(value).Append(" g").Append_i(separator); + } + + /** + * Changes the current gray tint for filling paths to black. + */ + + public virtual void ResetGrayFill() { + content.Append("0 g").Append_i(separator); + } + + /** + * Changes the currentgray tint for stroking paths (device dependent colors!). + *

    + * Sets the color space to DeviceGray (or the DefaultGray color space), + * and sets the gray tint to use for stroking paths.

    + * + * @param gray a value between 0 (black) and 1 (white) + */ + + public virtual void SetGrayStroke(float value) { + content.Append(value).Append(" G").Append_i(separator); + } + + /** + * Changes the current gray tint for stroking paths to black. + */ + + public virtual void ResetGrayStroke() { + content.Append("0 G").Append_i(separator); + } + + /** + * Helper to validate and write the RGB color components + * @param red the intensity of red. A value between 0 and 1 + * @param green the intensity of green. A value between 0 and 1 + * @param blue the intensity of blue. A value between 0 and 1 + */ + private void HelperRGB(float red, float green, float blue) { + PdfXConformanceImp.CheckPDFXConformance(writer, PdfXConformanceImp.PDFXKEY_RGB, null); + if (red < 0) + red = 0.0f; + else if (red > 1.0f) + red = 1.0f; + if (green < 0) + green = 0.0f; + else if (green > 1.0f) + green = 1.0f; + if (blue < 0) + blue = 0.0f; + else if (blue > 1.0f) + blue = 1.0f; + content.Append(red).Append(' ').Append(green).Append(' ').Append(blue); + } + + /** + * Changes the current color for filling paths (device dependent colors!). + *

    + * Sets the color space to DeviceRGB (or the DefaultRGB color space), + * and sets the color to use for filling paths.

    + *

    + * Following the PDF manual, each operand must be a number between 0 (minimum intensity) and + * 1 (maximum intensity).

    + * + * @param red the intensity of red. A value between 0 and 1 + * @param green the intensity of green. A value between 0 and 1 + * @param blue the intensity of blue. A value between 0 and 1 + */ + + public virtual void SetRGBColorFillF(float red, float green, float blue) { + HelperRGB(red, green, blue); + content.Append(" rg").Append_i(separator); + } + + /** + * Changes the current color for filling paths to black. + */ + + public virtual void ResetRGBColorFill() { + content.Append("0 g").Append_i(separator); + } + + /** + * Changes the current color for stroking paths (device dependent colors!). + *

    + * Sets the color space to DeviceRGB (or the DefaultRGB color space), + * and sets the color to use for stroking paths.

    + *

    + * Following the PDF manual, each operand must be a number between 0 (miniumum intensity) and + * 1 (maximum intensity). + * + * @param red the intensity of red. A value between 0 and 1 + * @param green the intensity of green. A value between 0 and 1 + * @param blue the intensity of blue. A value between 0 and 1 + */ + + public virtual void SetRGBColorStrokeF(float red, float green, float blue) { + HelperRGB(red, green, blue); + content.Append(" RG").Append_i(separator); + } + + /** + * Changes the current color for stroking paths to black. + * + */ + + public virtual void ResetRGBColorStroke() { + content.Append("0 G").Append_i(separator); + } + + /** + * Helper to validate and write the CMYK color components. + * + * @param cyan the intensity of cyan. A value between 0 and 1 + * @param magenta the intensity of magenta. A value between 0 and 1 + * @param yellow the intensity of yellow. A value between 0 and 1 + * @param black the intensity of black. A value between 0 and 1 + */ + private void HelperCMYK(float cyan, float magenta, float yellow, float black) { + if (cyan < 0) + cyan = 0.0f; + else if (cyan > 1.0f) + cyan = 1.0f; + if (magenta < 0) + magenta = 0.0f; + else if (magenta > 1.0f) + magenta = 1.0f; + if (yellow < 0) + yellow = 0.0f; + else if (yellow > 1.0f) + yellow = 1.0f; + if (black < 0) + black = 0.0f; + else if (black > 1.0f) + black = 1.0f; + content.Append(cyan).Append(' ').Append(magenta).Append(' ').Append(yellow).Append(' ').Append(black); + } + + /** + * Changes the current color for filling paths (device dependent colors!). + *

    + * Sets the color space to DeviceCMYK (or the DefaultCMYK color space), + * and sets the color to use for filling paths.

    + *

    + * Following the PDF manual, each operand must be a number between 0 (no ink) and + * 1 (maximum ink).

    + * + * @param cyan the intensity of cyan. A value between 0 and 1 + * @param magenta the intensity of magenta. A value between 0 and 1 + * @param yellow the intensity of yellow. A value between 0 and 1 + * @param black the intensity of black. A value between 0 and 1 + */ + + public virtual void SetCMYKColorFillF(float cyan, float magenta, float yellow, float black) { + HelperCMYK(cyan, magenta, yellow, black); + content.Append(" k").Append_i(separator); + } + + /** + * Changes the current color for filling paths to black. + * + */ + + public virtual void ResetCMYKColorFill() { + content.Append("0 0 0 1 k").Append_i(separator); + } + + /** + * Changes the current color for stroking paths (device dependent colors!). + *

    + * Sets the color space to DeviceCMYK (or the DefaultCMYK color space), + * and sets the color to use for stroking paths.

    + *

    + * Following the PDF manual, each operand must be a number between 0 (miniumum intensity) and + * 1 (maximum intensity). + * + * @param cyan the intensity of cyan. A value between 0 and 1 + * @param magenta the intensity of magenta. A value between 0 and 1 + * @param yellow the intensity of yellow. A value between 0 and 1 + * @param black the intensity of black. A value between 0 and 1 + */ + + public virtual void SetCMYKColorStrokeF(float cyan, float magenta, float yellow, float black) { + HelperCMYK(cyan, magenta, yellow, black); + content.Append(" K").Append_i(separator); + } + + /** + * Changes the current color for stroking paths to black. + * + */ + + public virtual void ResetCMYKColorStroke() { + content.Append("0 0 0 1 K").Append_i(separator); + } + + /** + * Move the current point (x, y), omitting any connecting line segment. + * + * @param x new x-coordinate + * @param y new y-coordinate + */ + + public void MoveTo(float x, float y) { + content.Append(x).Append(' ').Append(y).Append(" m").Append_i(separator); + } + + /** + * Appends a straight line segment from the current point (x, y). The new current + * point is (x, y). + * + * @param x new x-coordinate + * @param y new y-coordinate + */ + + public void LineTo(float x, float y) { + content.Append(x).Append(' ').Append(y).Append(" l").Append_i(separator); + } + + /** + * Appends a Bêzier curve to the path, starting from the current point. + * + * @param x1 x-coordinate of the first control point + * @param y1 y-coordinate of the first control point + * @param x2 x-coordinate of the second control point + * @param y2 y-coordinate of the second control point + * @param x3 x-coordinaat of the ending point (= new current point) + * @param y3 y-coordinaat of the ending point (= new current point) + */ + + public void CurveTo(float x1, float y1, float x2, float y2, float x3, float y3) { + content.Append(x1).Append(' ').Append(y1).Append(' ').Append(x2).Append(' ').Append(y2).Append(' ').Append(x3).Append(' ').Append(y3).Append(" c").Append_i(separator); + } + + /** + * Appends a Bêzier curve to the path, starting from the current point. + * + * @param x2 x-coordinate of the second control point + * @param y2 y-coordinate of the second control point + * @param x3 x-coordinaat of the ending point (= new current point) + * @param y3 y-coordinaat of the ending point (= new current point) + */ + + public void CurveTo(float x2, float y2, float x3, float y3) { + content.Append(x2).Append(' ').Append(y2).Append(' ').Append(x3).Append(' ').Append(y3).Append(" v").Append_i(separator); + } + + /** + * Appends a Bêzier curve to the path, starting from the current point. + * + * @param x1 x-coordinate of the first control point + * @param y1 y-coordinate of the first control point + * @param x3 x-coordinaat of the ending point (= new current point) + * @param y3 y-coordinaat of the ending point (= new current point) + */ + + public void CurveFromTo(float x1, float y1, float x3, float y3) { + content.Append(x1).Append(' ').Append(y1).Append(' ').Append(x3).Append(' ').Append(y3).Append(" y").Append_i(separator); + } + + /** Draws a circle. The endpoint will (x+r, y). + * + * @param x x center of circle + * @param y y center of circle + * @param r radius of circle + */ + public void Circle(float x, float y, float r) { + float b = 0.5523f; + MoveTo(x + r, y); + CurveTo(x + r, y + r * b, x + r * b, y + r, x, y + r); + CurveTo(x - r * b, y + r, x - r, y + r * b, x - r, y); + CurveTo(x - r, y - r * b, x - r * b, y - r, x, y - r); + CurveTo(x + r * b, y - r, x + r, y - r * b, x + r, y); + } + + + + /** + * Adds a rectangle to the current path. + * + * @param x x-coordinate of the starting point + * @param y y-coordinate of the starting point + * @param w width + * @param h height + */ + + public void Rectangle(float x, float y, float w, float h) { + content.Append(x).Append(' ').Append(y).Append(' ').Append(w).Append(' ').Append(h).Append(" re").Append_i(separator); + } + + private bool CompareColors(Color c1, Color c2) { + if (c1 == null && c2 == null) + return true; + if (c1 == null || c2 == null) + return false; + if (c1 is ExtendedColor) + return c1.Equals(c2); + return c2.Equals(c1); + } + + /** + * Adds a variable width border to the current path. + * Only use if {@link com.lowagie.text.Rectangle#isUseVariableBorders() Rectangle.isUseVariableBorders} + * = true. + * @param rect a Rectangle + */ + public void VariableRectangle(Rectangle rect) { + float t = rect.Top; + float b = rect.Bottom; + float r = rect.Right; + float l = rect.Left; + float wt = rect.BorderWidthTop; + float wb = rect.BorderWidthBottom; + float wr = rect.BorderWidthRight; + float wl = rect.BorderWidthLeft; + Color ct = rect.BorderColorTop; + Color cb = rect.BorderColorBottom; + Color cr = rect.BorderColorRight; + Color cl = rect.BorderColorLeft; + SaveState(); + SetLineCap(PdfContentByte.LINE_CAP_BUTT); + SetLineJoin(PdfContentByte.LINE_JOIN_MITER); + float clw = 0; + bool cdef = false; + Color ccol = null; + bool cdefi = false; + Color cfil = null; + // draw top + if (wt > 0) { + SetLineWidth(clw = wt); + cdef = true; + if (ct == null) + ResetRGBColorStroke(); + else + SetColorStroke(ct); + ccol = ct; + MoveTo(l, t - wt / 2f); + LineTo(r, t - wt / 2f); + Stroke(); + } + + // Draw bottom + if (wb > 0) { + if (wb != clw) + SetLineWidth(clw = wb); + if (!cdef || !CompareColors(ccol, cb)) { + cdef = true; + if (cb == null) + ResetRGBColorStroke(); + else + SetColorStroke(cb); + ccol = cb; + } + MoveTo(r, b + wb / 2f); + LineTo(l, b + wb / 2f); + Stroke(); + } + + // Draw right + if (wr > 0) { + if (wr != clw) + SetLineWidth(clw = wr); + if (!cdef || !CompareColors(ccol, cr)) { + cdef = true; + if (cr == null) + ResetRGBColorStroke(); + else + SetColorStroke(cr); + ccol = cr; + } + bool bt = CompareColors(ct, cr); + bool bb = CompareColors(cb, cr); + MoveTo(r - wr / 2f, bt ? t : t - wt); + LineTo(r - wr / 2f, bb ? b : b + wb); + Stroke(); + if (!bt || !bb) { + cdefi = true; + if (cr == null) + ResetRGBColorFill(); + else + SetColorFill(cr); + cfil = cr; + if (!bt) { + MoveTo(r, t); + LineTo(r, t - wt); + LineTo(r - wr, t - wt); + Fill(); + } + if (!bb) { + MoveTo(r, b); + LineTo(r, b + wb); + LineTo(r - wr, b + wb); + Fill(); + } + } + } + + // Draw Left + if (wl > 0) { + if (wl != clw) + SetLineWidth(wl); + if (!cdef || !CompareColors(ccol, cl)) { + if (cl == null) + ResetRGBColorStroke(); + else + SetColorStroke(cl); + } + bool bt = CompareColors(ct, cl); + bool bb = CompareColors(cb, cl); + MoveTo(l + wl / 2f, bt ? t : t - wt); + LineTo(l + wl / 2f, bb ? b : b + wb); + Stroke(); + if (!bt || !bb) { + if (!cdefi || !CompareColors(cfil, cl)) { + if (cl == null) + ResetRGBColorFill(); + else + SetColorFill(cl); + } + if (!bt) { + MoveTo(l, t); + LineTo(l, t - wt); + LineTo(l + wl, t - wt); + Fill(); + } + if (!bb) { + MoveTo(l, b); + LineTo(l, b + wb); + LineTo(l + wl, b + wb); + Fill(); + } + } + } + RestoreState(); + } + + /** + * Adds a border (complete or partially) to the current path.. + * + * @param rectangle a Rectangle + */ + + public void Rectangle(Rectangle rectangle) { + // the coordinates of the border are retrieved + float x1 = rectangle.Left; + float y1 = rectangle.Bottom; + float x2 = rectangle.Right; + float y2 = rectangle.Top; + + // the backgroundcolor is set + Color background = rectangle.BackgroundColor; + if (background != null) { + SetColorFill(background); + Rectangle(x1, y1, x2 - x1, y2 - y1); + Fill(); + ResetRGBColorFill(); + } + + // if the element hasn't got any borders, nothing is added + if (! rectangle.HasBorders()) { + return; + } + + // if any of the individual border colors are set + // we draw the borders all around using the + // different colors + if (rectangle.UseVariableBorders) { + VariableRectangle(rectangle); + } + else { + // the width is set to the width of the element + if (rectangle.BorderWidth != iTextSharp.text.Rectangle.UNDEFINED) { + SetLineWidth(rectangle.BorderWidth); + } + + // the color is set to the color of the element + Color color = rectangle.BorderColor; + if (color != null) { + SetColorStroke(color); + } + + // if the box is a rectangle, it is added as a rectangle + if (rectangle.HasBorder(iTextSharp.text.Rectangle.BOX)) { + this.Rectangle(x1, y1, x2 - x1, y2 - y1); + } + // if the border isn't a rectangle, the different sides are added apart + else { + if (rectangle.HasBorder(iTextSharp.text.Rectangle.RIGHT_BORDER)) { + MoveTo(x2, y1); + LineTo(x2, y2); + } + if (rectangle.HasBorder(iTextSharp.text.Rectangle.LEFT_BORDER)) { + MoveTo(x1, y1); + LineTo(x1, y2); + } + if (rectangle.HasBorder(iTextSharp.text.Rectangle.BOTTOM_BORDER)) { + MoveTo(x1, y1); + LineTo(x2, y1); + } + if (rectangle.HasBorder(iTextSharp.text.Rectangle.TOP_BORDER)) { + MoveTo(x1, y2); + LineTo(x2, y2); + } + } + + Stroke(); + + if (color != null) { + ResetRGBColorStroke(); + } + } + } + + /** + * Closes the current subpath by appending a straight line segment from the current point + * to the starting point of the subpath. + */ + + public void ClosePath() { + content.Append('h').Append_i(separator); + } + + /** + * Ends the path without filling or stroking it. + */ + + public void NewPath() { + content.Append('n').Append_i(separator); + } + + /** + * Strokes the path. + */ + + public void Stroke() { + content.Append('S').Append_i(separator); + } + + /** + * Closes the path and strokes it. + */ + + public void ClosePathStroke() { + content.Append('s').Append_i(separator); + } + + /** + * Fills the path, using the non-zero winding number rule to determine the region to fill. + */ + + public void Fill() { + content.Append('f').Append_i(separator); + } + + /** + * Fills the path, using the even-odd rule to determine the region to fill. + */ + + public void EoFill() { + content.Append("f*").Append_i(separator); + } + + /** + * Fills the path using the non-zero winding number rule to determine the region to fill and strokes it. + */ + + public void FillStroke() { + content.Append('B').Append_i(separator); + } + + /** + * Closes the path, fills it using the non-zero winding number rule to determine the region to fill and strokes it. + */ + + public void ClosePathFillStroke() { + content.Append('b').Append_i(separator); + } + + /** + * Fills the path, using the even-odd rule to determine the region to fill and strokes it. + */ + + public void EoFillStroke() { + content.Append("B*").Append_i(separator); + } + + /** + * Closes the path, fills it using the even-odd rule to determine the region to fill and strokes it. + */ + + public void ClosePathEoFillStroke() { + content.Append("b*").Append_i(separator); + } + + /** + * Adds an Image to the page. The Image must have + * absolute positioning. + * @param image the Image object + * @throws DocumentException if the Image does not have absolute positioning + */ + public virtual void AddImage(Image image) { + AddImage(image, false); + } + + /** + * Adds an Image to the page. The Image must have + * absolute positioning. The image can be placed inline. + * @param image the Image object + * @param inlineImage true to place this image inline, false otherwise + * @throws DocumentException if the Image does not have absolute positioning + */ + public virtual void AddImage(Image image, bool inlineImage) { + if (!image.HasAbsolutePosition()) + throw new DocumentException("The image must have absolute positioning."); + float[] matrix = image.Matrix; + matrix[Image.CX] = image.AbsoluteX - matrix[Image.CX]; + matrix[Image.CY] = image.AbsoluteY - matrix[Image.CY]; + AddImage(image, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], inlineImage); + } + + /** + * Adds an Image to the page. The positioning of the Image + * is done with the transformation matrix. To position an image at (x,y) + * use AddImage(image, image_width, 0, 0, image_height, x, y). + * @param image the Image object + * @param a an element of the transformation matrix + * @param b an element of the transformation matrix + * @param c an element of the transformation matrix + * @param d an element of the transformation matrix + * @param e an element of the transformation matrix + * @param f an element of the transformation matrix + * @throws DocumentException on error + */ + public virtual void AddImage(Image image, float a, float b, float c, float d, float e, float f) { + AddImage(image, a, b, c, d, e, f, false); + } + + /** + * Adds an Image to the page. The positioning of the Image + * is done with the transformation matrix. To position an image at (x,y) + * use AddImage(image, image_width, 0, 0, image_height, x, y). The image can be placed inline. + * @param image the Image object + * @param a an element of the transformation matrix + * @param b an element of the transformation matrix + * @param c an element of the transformation matrix + * @param d an element of the transformation matrix + * @param e an element of the transformation matrix + * @param f an element of the transformation matrix + * @param inlineImage true to place this image inline, false otherwise + * @throws DocumentException on error + */ + public virtual void AddImage(Image image, float a, float b, float c, float d, float e, float f, bool inlineImage) { + if (image.Layer != null) + BeginLayer(image.Layer); + if (image.IsImgTemplate()) { + writer.AddDirectImageSimple(image); + PdfTemplate template = image.TemplateData; + float w = template.Width; + float h = template.Height; + AddTemplate(template, a / w, b / w, c / h, d / h, e, f); + } + else { + content.Append("q "); + content.Append(a).Append(' '); + content.Append(b).Append(' '); + content.Append(c).Append(' '); + content.Append(d).Append(' '); + content.Append(e).Append(' '); + content.Append(f).Append(" cm"); + if (inlineImage) { + content.Append("\nBI\n"); + PdfImage pimage = new PdfImage(image, "", null); + foreach (PdfName key in pimage.Keys) { + PdfObject value = pimage.Get(key); + String s = (String)abrev[key]; + if (s == null) + continue; + content.Append(s); + bool check = true; + if (key.Equals(PdfName.COLORSPACE) && value.IsArray()) { + ArrayList ar = ((PdfArray)value).ArrayList; + if (ar.Count == 4 + && PdfName.INDEXED.Equals(ar[0]) + && ((PdfObject)ar[1]).IsName() + && ((PdfObject)ar[2]).IsNumber() + && ((PdfObject)ar[3]).IsString() + ) { + check = false; + } + + } + if (check && key.Equals(PdfName.COLORSPACE) && !value.IsName()) { + PdfName cs = writer.GetColorspaceName(); + PageResources prs = PageResources; + prs.AddColor(cs, writer.AddToBody(value).IndirectReference); + value = cs; + } + value.ToPdf(null, content); + content.Append('\n'); + } + content.Append("ID\n"); + pimage.WriteContent(content); + content.Append("\nEI\nQ").Append_i(separator); + } + else { + PdfName name; + PageResources prs = PageResources; + Image maskImage = image.ImageMask; + if (maskImage != null) { + name = writer.AddDirectImageSimple(maskImage); + prs.AddXObject(name, writer.GetImageReference(name)); + } + name = writer.AddDirectImageSimple(image); + name = prs.AddXObject(name, writer.GetImageReference(name)); + content.Append(' ').Append(name.GetBytes()).Append(" Do Q").Append_i(separator); + } + } + if (image.HasBorders()) { + SaveState(); + float w = image.Width; + float h = image.Height; + ConcatCTM(a / w, b / w, c / h, d / h, e, f); + Rectangle(image); + RestoreState(); + } + if (image.Layer != null) + EndLayer(); + Annotation annot = image.Annotation; + if (annot == null) + return; + float[] r = new float[unitRect.Length]; + for (int k = 0; k < unitRect.Length; k += 2) { + r[k] = a * unitRect[k] + c * unitRect[k + 1] + e; + r[k + 1] = b * unitRect[k] + d * unitRect[k + 1] + f; + } + float llx = r[0]; + float lly = r[1]; + float urx = llx; + float ury = lly; + for (int k = 2; k < r.Length; k += 2) { + llx = Math.Min(llx, r[k]); + lly = Math.Min(lly, r[k + 1]); + urx = Math.Max(urx, r[k]); + ury = Math.Max(ury, r[k + 1]); + } + annot = new Annotation(annot); + annot.SetDimensions(llx, lly, urx, ury); + PdfAnnotation an = PdfAnnotationsImp.ConvertAnnotation(writer, annot, new Rectangle(llx, lly, urx, ury)); + if (an == null) + return; + AddAnnotation(an); + } + + /** + * Makes this PdfContentByte empty. + */ + public void Reset() { + content.Reset(); + stateList.Clear(); + state = new GraphicState(); + } + + /** + * Starts the writing of text. + */ + public void BeginText() { + state.xTLM = 0; + state.yTLM = 0; + content.Append("BT").Append_i(separator); + } + + /** + * Ends the writing of text and makes the current font invalid. + */ + public void EndText() { + content.Append("ET").Append_i(separator); + } + + /** + * Saves the graphic state. saveState and + * restoreState must be balanced. + */ + public void SaveState() { + content.Append('q').Append_i(separator); + stateList.Add(new GraphicState(state)); + } + + /** + * Restores the graphic state. saveState and + * restoreState must be balanced. + */ + public void RestoreState() { + content.Append('Q').Append_i(separator); + int idx = stateList.Count - 1; + if (idx < 0) + throw new Exception("Unbalanced save/restore state operators."); + state = (GraphicState)stateList[idx]; + stateList.RemoveAt(idx); + } + + /** + * Sets the character spacing parameter. + * + * @param charSpace a parameter + */ + public void SetCharacterSpacing(float value) { + state.charSpace = value; + content.Append(value).Append(" Tc").Append_i(separator); + } + + /** + * Sets the word spacing parameter. + * + * @param wordSpace a parameter + */ + public void SetWordSpacing(float value) { + state.wordSpace = value; + content.Append(value).Append(" Tw").Append_i(separator); + } + + /** + * Sets the horizontal scaling parameter. + * + * @param scale a parameter + */ + public void SetHorizontalScaling(float value) { + state.scale = value; + content.Append(value).Append(" Tz").Append_i(separator); + } + + /** + * Set the font and the size for the subsequent text writing. + * + * @param bf the font + * @param size the font size in points + */ + public virtual void SetFontAndSize(BaseFont bf, float size) { + CheckWriter(); + if (size < 0.0001f && size > -0.0001f) + throw new ArgumentException("Font size too small: " + size); + state.size = size; + state.fontDetails = writer.AddSimple(bf); + PageResources prs = PageResources; + PdfName name = state.fontDetails.FontName; + name = prs.AddFont(name, state.fontDetails.IndirectReference); + content.Append(name.GetBytes()).Append(' ').Append(size).Append(" Tf").Append_i(separator); + } + + /** + * Sets the text rendering parameter. + * + * @param rendering a parameter + */ + public void SetTextRenderingMode(int value) { + content.Append(value).Append(" Tr").Append_i(separator); + } + + /** + * Sets the text rise parameter. + *

    + * This allows to write text in subscript or basescript mode.

    + * + * @param rise a parameter + */ + public void SetTextRise(float value) { + content.Append(value).Append(" Ts").Append_i(separator); + } + + /** + * A helper to insert into the content stream the text + * converted to bytes according to the font's encoding. + * + * @param text the text to write + */ + private void ShowText2(string text) { + if (state.fontDetails == null) + throw new Exception("Font and size must be set before writing any text"); + byte[] b = state.fontDetails.ConvertToBytes(text); + EscapeString(b, content); + } + + /** + * Shows the text. + * + * @param text the text to write + */ + public void ShowText(string text) { + ShowText2(text); + content.Append("Tj").Append_i(separator); + } + + /** + * Constructs a kern array for a text in a certain font + * @param text the text + * @param font the font + * @return a PdfTextArray + */ + public static PdfTextArray GetKernArray(String text, BaseFont font) { + PdfTextArray pa = new PdfTextArray(); + StringBuilder acc = new StringBuilder(); + int len = text.Length - 1; + char[] c = text.ToCharArray(); + if (len >= 0) + acc.Append(c, 0, 1); + for (int k = 0; k < len; ++k) { + char c2 = c[k + 1]; + int kern = font.GetKerning(c[k], c2); + if (kern == 0) { + acc.Append(c2); + } + else { + pa.Add(acc.ToString()); + acc.Length = 0; + acc.Append(c, k + 1, 1); + pa.Add(-kern); + } + } + pa.Add(acc.ToString()); + return pa; + } + + /** + * Shows the text kerned. + * + * @param text the text to write + */ + public void ShowTextKerned(String text) { + if (state.fontDetails == null) + throw new ArgumentNullException("Font and size must be set before writing any text"); + BaseFont bf = state.fontDetails.BaseFont; + if (bf.HasKernPairs()) + ShowText(GetKernArray(text, bf)); + else + ShowText(text); + } + + /** + * Moves to the next line and shows text. + * + * @param text the text to write + */ + public void NewlineShowText(string text) { + state.yTLM -= state.leading; + ShowText2(text); + content.Append('\'').Append_i(separator); + } + + /** + * Moves to the next line and shows text string, using the given values of the character and word spacing parameters. + * + * @param wordSpacing a parameter + * @param charSpacing a parameter + * @param text the text to write + */ + public void NewlineShowText(float wordSpacing, float charSpacing, string text) { + state.yTLM -= state.leading; + content.Append(wordSpacing).Append(' ').Append(charSpacing); + ShowText2(text); + content.Append("\"").Append_i(separator); + + // The " operator sets charSpace and wordSpace into graphics state + // (cfr PDF reference v1.6, table 5.6) + state.charSpace = charSpacing; + state.wordSpace = wordSpacing; + } + + /** + * Changes the text matrix. + *

    + * Remark: this operation also initializes the current point position.

    + * + * @param a operand 1,1 in the matrix + * @param b operand 1,2 in the matrix + * @param c operand 2,1 in the matrix + * @param d operand 2,2 in the matrix + * @param x operand 3,1 in the matrix + * @param y operand 3,2 in the matrix + */ + public void SetTextMatrix(float a, float b, float c, float d, float x, float y) { + state.xTLM = x; + state.yTLM = y; + content.Append(a).Append(' ').Append(b).Append_i(' ') + .Append(c).Append_i(' ').Append(d).Append_i(' ') + .Append(x).Append_i(' ').Append(y).Append(" Tm").Append_i(separator); + } + + /** + * Changes the text matrix. The first four parameters are {1,0,0,1}. + *

    + * Remark: this operation also initializes the current point position.

    + * + * @param x operand 3,1 in the matrix + * @param y operand 3,2 in the matrix + */ + public void SetTextMatrix(float x, float y) { + SetTextMatrix(1, 0, 0, 1, x, y); + } + + /** + * Moves to the start of the next line, offset from the start of the current line. + * + * @param x x-coordinate of the new current point + * @param y y-coordinate of the new current point + */ + public void MoveText(float x, float y) { + state.xTLM += x; + state.yTLM += y; + content.Append(x).Append(' ').Append(y).Append(" Td").Append_i(separator); + } + + /** + * Moves to the start of the next line, offset from the start of the current line. + *

    + * As a side effect, this sets the leading parameter in the text state.

    + * + * @param x offset of the new current point + * @param y y-coordinate of the new current point + */ + public void MoveTextWithLeading(float x, float y) { + state.xTLM += x; + state.yTLM += y; + state.leading = -y; + content.Append(x).Append(' ').Append(y).Append(" TD").Append_i(separator); + } + + /** + * Moves to the start of the next line. + */ + public void NewlineText() { + state.yTLM -= state.leading; + content.Append("T*").Append_i(separator); + } + + /** + * Gets the size of this content. + * + * @return the size of the content + */ + internal int Size { + get { + return content.Size; + } + } + + /** + * Escapes a byte array according to the PDF conventions. + * + * @param b the byte array to escape + * @return an escaped byte array + */ + internal static byte[] EscapeString(byte[] b) { + ByteBuffer content = new ByteBuffer(); + EscapeString(b, content); + return content.ToByteArray(); + } + + /** + * Escapes a byte array according to the PDF conventions. + * + * @param b the byte array to escape + */ + internal static void EscapeString(byte[] b, ByteBuffer content) { + content.Append_i('('); + for (int k = 0; k < b.Length; ++k) { + byte c = b[k]; + switch ((int)c) { + case '\r': + content.Append("\\r"); + break; + case '\n': + content.Append("\\n"); + break; + case '\t': + content.Append("\\t"); + break; + case '\b': + content.Append("\\b"); + break; + case '\f': + content.Append("\\f"); + break; + case '(': + case ')': + case '\\': + content.Append_i('\\').Append_i(c); + break; + default: + content.Append_i(c); + break; + } + } + content.Append(')'); + } + + /** + * Adds a named outline to the document. + * + * @param outline the outline + * @param name the name for the local destination + */ + public void AddOutline(PdfOutline outline, string name) { + CheckWriter(); + pdf.AddOutline(outline, name); + } + /** + * Gets the root outline. + * + * @return the root outline + */ + public PdfOutline RootOutline { + get { + CheckWriter(); + return pdf.RootOutline; + } + } + + /** + * Computes the width of the given string taking in account + * the current values of "Character spacing", "Word Spacing" + * and "Horizontal Scaling". + * The additional spacing is not computed for the last character + * of the string. + * @param text the string to get width of + * @param kerned the kerning option + * @return the width + */ + + public float GetEffectiveStringWidth(String text, bool kerned) { + BaseFont bf = state.fontDetails.BaseFont; + + float w; + if (kerned) + w = bf.GetWidthPointKerned(text, state.size); + else + w = bf.GetWidthPoint(text, state.size); + + if (state.charSpace != 0.0f && text.Length > 1) { + w += state.charSpace * (text.Length -1); + } + + int ft = bf.FontType; + if (state.wordSpace != 0.0f && (ft == BaseFont.FONT_TYPE_T1 || ft == BaseFont.FONT_TYPE_TT || ft == BaseFont.FONT_TYPE_T3)) { + for (int i = 0; i < (text.Length -1); i++) { + if (text[i] == ' ') + w += state.wordSpace; + } + } + if (state.scale != 100.0) + w = (w * state.scale) / 100.0f; + + //System.out.Println("String width = " + Float.ToString(w)); + return w; + } + + /** + * Shows text right, left or center aligned with rotation. + * @param alignment the alignment can be ALIGN_CENTER, ALIGN_RIGHT or ALIGN_LEFT + * @param text the text to show + * @param x the x pivot position + * @param y the y pivot position + * @param rotation the rotation to be applied in degrees counterclockwise + */ + public void ShowTextAligned(int alignment, String text, float x, float y, float rotation) { + ShowTextAligned(alignment, text, x, y, rotation, false); + } + + private void ShowTextAligned(int alignment, String text, float x, float y, float rotation, bool kerned) { + if (state.fontDetails == null) + throw new Exception("Font and size must be set before writing any text"); + if (rotation == 0) { + switch (alignment) { + case ALIGN_CENTER: + x -= GetEffectiveStringWidth(text, kerned) / 2; + break; + case ALIGN_RIGHT: + x -= GetEffectiveStringWidth(text, kerned); + break; + } + SetTextMatrix(x, y); + if (kerned) + ShowTextKerned(text); + else + ShowText(text); + } + else { + double alpha = rotation * Math.PI / 180.0; + float cos = (float)Math.Cos(alpha); + float sin = (float)Math.Sin(alpha); + float len; + switch (alignment) { + case ALIGN_CENTER: + len = GetEffectiveStringWidth(text, kerned) / 2; + x -= len * cos; + y -= len * sin; + break; + case ALIGN_RIGHT: + len = GetEffectiveStringWidth(text, kerned); + x -= len * cos; + y -= len * sin; + break; + } + SetTextMatrix(cos, sin, -sin, cos, x, y); + if (kerned) + ShowTextKerned(text); + else + ShowText(text); + SetTextMatrix(0f, 0f); + } + } + + /** + * Shows text kerned right, left or center aligned with rotation. + * @param alignment the alignment can be ALIGN_CENTER, ALIGN_RIGHT or ALIGN_LEFT + * @param text the text to show + * @param x the x pivot position + * @param y the y pivot position + * @param rotation the rotation to be applied in degrees counterclockwise + */ + public void ShowTextAlignedKerned(int alignment, String text, float x, float y, float rotation) { + ShowTextAligned(alignment, text, x, y, rotation, true); + } + + /** + * Concatenate a matrix to the current transformation matrix. + * @param a an element of the transformation matrix + * @param b an element of the transformation matrix + * @param c an element of the transformation matrix + * @param d an element of the transformation matrix + * @param e an element of the transformation matrix + * @param f an element of the transformation matrix + **/ + public void ConcatCTM(float a, float b, float c, float d, float e, float f) { + content.Append(a).Append(' ').Append(b).Append(' ').Append(c).Append(' '); + content.Append(d).Append(' ').Append(e).Append(' ').Append(f).Append(" cm").Append_i(separator); + } + + /** + * Generates an array of bezier curves to draw an arc. + *

    + * (x1, y1) and (x2, y2) are the corners of the enclosing rectangle. + * Angles, measured in degrees, start with 0 to the right (the positive X + * axis) and increase counter-clockwise. The arc extends from startAng + * to startAng+extent. I.e. startAng=0 and extent=180 yields an openside-down + * semi-circle. + *

    + * The resulting coordinates are of the form float[]{x1,y1,x2,y2,x3,y3, x4,y4} + * such that the curve goes from (x1, y1) to (x4, y4) with (x2, y2) and + * (x3, y3) as their respective Bezier control points. + *

    + * Note: this code was taken from ReportLab (www.reportlab.com), an excelent + * PDF generator for Python. + * + * @param x1 a corner of the enclosing rectangle + * @param y1 a corner of the enclosing rectangle + * @param x2 a corner of the enclosing rectangle + * @param y2 a corner of the enclosing rectangle + * @param startAng starting angle in degrees + * @param extent angle extent in degrees + * @return a list of float[] with the bezier curves + */ + public static ArrayList BezierArc(float x1, float y1, float x2, float y2, float startAng, float extent) { + float tmp; + if (x1 > x2) { + tmp = x1; + x1 = x2; + x2 = tmp; + } + if (y2 > y1) { + tmp = y1; + y1 = y2; + y2 = tmp; + } + + float fragAngle; + int Nfrag; + if (Math.Abs(extent) <= 90f) { + fragAngle = extent; + Nfrag = 1; + } + else { + Nfrag = (int)(Math.Ceiling(Math.Abs(extent)/90f)); + fragAngle = extent / Nfrag; + } + float x_cen = (x1+x2)/2f; + float y_cen = (y1+y2)/2f; + float rx = (x2-x1)/2f; + float ry = (y2-y1)/2f; + float halfAng = (float)(fragAngle * Math.PI / 360.0); + float kappa = (float)(Math.Abs(4.0 / 3.0 * (1.0 - Math.Cos(halfAng)) / Math.Sin(halfAng))); + ArrayList pointList = new ArrayList(); + for (int i = 0; i < Nfrag; ++i) { + float theta0 = (float)((startAng + i*fragAngle) * Math.PI / 180.0); + float theta1 = (float)((startAng + (i+1)*fragAngle) * Math.PI / 180.0); + float cos0 = (float)Math.Cos(theta0); + float cos1 = (float)Math.Cos(theta1); + float sin0 = (float)Math.Sin(theta0); + float sin1 = (float)Math.Sin(theta1); + if (fragAngle > 0f) { + pointList.Add(new float[]{x_cen + rx * cos0, + y_cen - ry * sin0, + x_cen + rx * (cos0 - kappa * sin0), + y_cen - ry * (sin0 + kappa * cos0), + x_cen + rx * (cos1 + kappa * sin1), + y_cen - ry * (sin1 - kappa * cos1), + x_cen + rx * cos1, + y_cen - ry * sin1}); + } + else { + pointList.Add(new float[]{x_cen + rx * cos0, + y_cen - ry * sin0, + x_cen + rx * (cos0 + kappa * sin0), + y_cen - ry * (sin0 - kappa * cos0), + x_cen + rx * (cos1 - kappa * sin1), + y_cen - ry * (sin1 + kappa * cos1), + x_cen + rx * cos1, + y_cen - ry * sin1}); + } + } + return pointList; + } + + /** + * Draws a partial ellipse inscribed within the rectangle x1,y1,x2,y2, + * starting at startAng degrees and covering extent degrees. Angles + * start with 0 to the right (+x) and increase counter-clockwise. + * + * @param x1 a corner of the enclosing rectangle + * @param y1 a corner of the enclosing rectangle + * @param x2 a corner of the enclosing rectangle + * @param y2 a corner of the enclosing rectangle + * @param startAng starting angle in degrees + * @param extent angle extent in degrees + */ + public void Arc(float x1, float y1, float x2, float y2, float startAng, float extent) { + ArrayList ar = BezierArc(x1, y1, x2, y2, startAng, extent); + if (ar.Count == 0) + return; + float[] pt = (float [])ar[0]; + MoveTo(pt[0], pt[1]); + for (int k = 0; k < ar.Count; ++k) { + pt = (float [])ar[k]; + CurveTo(pt[2], pt[3], pt[4], pt[5], pt[6], pt[7]); + } + } + + /** + * Draws an ellipse inscribed within the rectangle x1,y1,x2,y2. + * + * @param x1 a corner of the enclosing rectangle + * @param y1 a corner of the enclosing rectangle + * @param x2 a corner of the enclosing rectangle + * @param y2 a corner of the enclosing rectangle + */ + public void Ellipse(float x1, float y1, float x2, float y2) { + Arc(x1, y1, x2, y2, 0f, 360f); + } + + /** + * Create a new colored tiling pattern. + * + * @param width the width of the pattern + * @param height the height of the pattern + * @param xstep the desired horizontal spacing between pattern cells. + * May be either positive or negative, but not zero. + * @param ystep the desired vertical spacing between pattern cells. + * May be either positive or negative, but not zero. + * @return the PdfPatternPainter where the pattern will be created + */ + public PdfPatternPainter CreatePattern(float width, float height, float xstep, float ystep) { + CheckWriter(); + if ( xstep == 0.0f || ystep == 0.0f ) + throw new Exception("XStep or YStep can not be ZERO."); + PdfPatternPainter painter = new PdfPatternPainter(writer); + painter.Width = width; + painter.Height = height; + painter.XStep = xstep; + painter.YStep = ystep; + writer.AddSimplePattern(painter); + return painter; + } + + /** + * Create a new colored tiling pattern. Variables xstep and ystep are set to the same values + * of width and height. + * @param width the width of the pattern + * @param height the height of the pattern + * @return the PdfPatternPainter where the pattern will be created + */ + public PdfPatternPainter CreatePattern(float width, float height) { + return CreatePattern(width, height, width, height); + } + + /** + * Create a new uncolored tiling pattern. + * + * @param width the width of the pattern + * @param height the height of the pattern + * @param xstep the desired horizontal spacing between pattern cells. + * May be either positive or negative, but not zero. + * @param ystep the desired vertical spacing between pattern cells. + * May be either positive or negative, but not zero. + * @param color the default color. Can be null + * @return the PdfPatternPainter where the pattern will be created + */ + public PdfPatternPainter CreatePattern(float width, float height, float xstep, float ystep, Color color) { + CheckWriter(); + if ( xstep == 0.0f || ystep == 0.0f ) + throw new Exception("XStep or YStep can not be ZERO."); + PdfPatternPainter painter = new PdfPatternPainter(writer, color); + painter.Width = width; + painter.Height = height; + painter.XStep = xstep; + painter.YStep = ystep; + writer.AddSimplePattern(painter); + return painter; + } + + /** + * Create a new uncolored tiling pattern. + * Variables xstep and ystep are set to the same values + * of width and height. + * @param width the width of the pattern + * @param height the height of the pattern + * @param color the default color. Can be null + * @return the PdfPatternPainter where the pattern will be created + */ + public PdfPatternPainter CreatePattern(float width, float height, Color color) { + return CreatePattern(width, height, width, height, color); + } + + /** + * Creates a new template. + *

    + * Creates a new template that is nothing more than a form XObject. This template can be included + * in this PdfContentByte or in another template. Templates are only written + * to the output when the document is closed permitting things like showing text in the first page + * that is only defined in the last page. + * + * @param width the bounding box width + * @param height the bounding box height + * @return the templated created + */ + public PdfTemplate CreateTemplate(float width, float height) { + return CreateTemplate(width, height, null); + } + + internal PdfTemplate CreateTemplate(float width, float height, PdfName forcedName) { + CheckWriter(); + PdfTemplate template = new PdfTemplate(writer); + template.Width = width; + template.Height = height; + writer.AddDirectTemplateSimple(template, forcedName); + return template; + } + + /** + * Creates a new appearance to be used with form fields. + * + * @param width the bounding box width + * @param height the bounding box height + * @return the appearance created + */ + public PdfAppearance CreateAppearance(float width, float height) { + return CreateAppearance(width, height, null); + } + + internal PdfAppearance CreateAppearance(float width, float height, PdfName forcedName) { + CheckWriter(); + PdfAppearance template = new PdfAppearance(writer); + template.Width = width; + template.Height = height; + writer.AddDirectTemplateSimple(template, forcedName); + return template; + } + + /** + * Adds a PostScript XObject to this content. + * + * @param psobject the object + */ + public void AddPSXObject(PdfPSXObject psobject) { + CheckWriter(); + PdfName name = writer.AddDirectTemplateSimple(psobject, null); + PageResources prs = PageResources; + name = prs.AddXObject(name, psobject.IndirectReference); + content.Append(name.GetBytes()).Append(" Do").Append_i(separator); + } + + /** + * Adds a template to this content. + * + * @param template the template + * @param a an element of the transformation matrix + * @param b an element of the transformation matrix + * @param c an element of the transformation matrix + * @param d an element of the transformation matrix + * @param e an element of the transformation matrix + * @param f an element of the transformation matrix + */ + public virtual void AddTemplate(PdfTemplate template, float a, float b, float c, float d, float e, float f) { + CheckWriter(); + CheckNoPattern(template); + PdfName name = writer.AddDirectTemplateSimple(template, null); + PageResources prs = PageResources; + name = prs.AddXObject(name, template.IndirectReference); + content.Append("q "); + content.Append(a).Append(' '); + content.Append(b).Append(' '); + content.Append(c).Append(' '); + content.Append(d).Append(' '); + content.Append(e).Append(' '); + content.Append(f).Append(" cm "); + content.Append(name.GetBytes()).Append(" Do Q").Append_i(separator); + } + + internal void AddTemplateReference(PdfIndirectReference template, PdfName name, float a, float b, float c, float d, float e, float f) { + CheckWriter(); + PageResources prs = PageResources; + name = prs.AddXObject(name, template); + content.Append("q "); + content.Append(a).Append(' '); + content.Append(b).Append(' '); + content.Append(c).Append(' '); + content.Append(d).Append(' '); + content.Append(e).Append(' '); + content.Append(f).Append(" cm "); + content.Append(name.GetBytes()).Append(" Do Q").Append_i(separator); + } + + /** + * Adds a template to this content. + * + * @param template the template + * @param x the x location of this template + * @param y the y location of this template + */ + public void AddTemplate(PdfTemplate template, float x, float y) { + AddTemplate(template, 1, 0, 0, 1, x, y); + } + + /** + * Changes the current color for filling paths (device dependent colors!). + *

    + * Sets the color space to DeviceCMYK (or the DefaultCMYK color space), + * and sets the color to use for filling paths.

    + *

    + * This method is described in the 'Portable Document Format Reference Manual version 1.3' + * section 8.5.2.1 (page 331).

    + *

    + * Following the PDF manual, each operand must be a number between 0 (no ink) and + * 1 (maximum ink). This method however accepts only ints between 0x00 and 0xFF.

    + * + * @param cyan the intensity of cyan + * @param magenta the intensity of magenta + * @param yellow the intensity of yellow + * @param black the intensity of black + */ + + public virtual void SetCMYKColorFill(int cyan, int magenta, int yellow, int black) { + content.Append((float)(cyan & 0xFF) / 0xFF); + content.Append(' '); + content.Append((float)(magenta & 0xFF) / 0xFF); + content.Append(' '); + content.Append((float)(yellow & 0xFF) / 0xFF); + content.Append(' '); + content.Append((float)(black & 0xFF) / 0xFF); + content.Append(" k").Append_i(separator); + } + /** + * Changes the current color for stroking paths (device dependent colors!). + *

    + * Sets the color space to DeviceCMYK (or the DefaultCMYK color space), + * and sets the color to use for stroking paths.

    + *

    + * This method is described in the 'Portable Document Format Reference Manual version 1.3' + * section 8.5.2.1 (page 331).

    + * Following the PDF manual, each operand must be a number between 0 (miniumum intensity) and + * 1 (maximum intensity). This method however accepts only ints between 0x00 and 0xFF. + * + * @param cyan the intensity of red + * @param magenta the intensity of green + * @param yellow the intensity of blue + * @param black the intensity of black + */ + + public virtual void SetCMYKColorStroke(int cyan, int magenta, int yellow, int black) { + content.Append((float)(cyan & 0xFF) / 0xFF); + content.Append(' '); + content.Append((float)(magenta & 0xFF) / 0xFF); + content.Append(' '); + content.Append((float)(yellow & 0xFF) / 0xFF); + content.Append(' '); + content.Append((float)(black & 0xFF) / 0xFF); + content.Append(" K").Append_i(separator); + } + + /** + * Changes the current color for filling paths (device dependent colors!). + *

    + * Sets the color space to DeviceRGB (or the DefaultRGB color space), + * and sets the color to use for filling paths.

    + *

    + * This method is described in the 'Portable Document Format Reference Manual version 1.3' + * section 8.5.2.1 (page 331).

    + *

    + * Following the PDF manual, each operand must be a number between 0 (miniumum intensity) and + * 1 (maximum intensity). This method however accepts only ints between 0x00 and 0xFF.

    + * + * @param red the intensity of red + * @param green the intensity of green + * @param blue the intensity of blue + */ + + public virtual void SetRGBColorFill(int red, int green, int blue) { + HelperRGB((float)(red & 0xFF) / 0xFF, (float)(green & 0xFF) / 0xFF, (float)(blue & 0xFF) / 0xFF); + content.Append(" rg").Append_i(separator); + } + + /** + * Changes the current color for stroking paths (device dependent colors!). + *

    + * Sets the color space to DeviceRGB (or the DefaultRGB color space), + * and sets the color to use for stroking paths.

    + *

    + * This method is described in the 'Portable Document Format Reference Manual version 1.3' + * section 8.5.2.1 (page 331).

    + * Following the PDF manual, each operand must be a number between 0 (miniumum intensity) and + * 1 (maximum intensity). This method however accepts only ints between 0x00 and 0xFF. + * + * @param red the intensity of red + * @param green the intensity of green + * @param blue the intensity of blue + */ + + public virtual void SetRGBColorStroke(int red, int green, int blue) { + HelperRGB((float)(red & 0xFF) / 0xFF, (float)(green & 0xFF) / 0xFF, (float)(blue & 0xFF) / 0xFF); + content.Append(" RG").Append_i(separator); + } + + /** Sets the stroke color. color can be an + * ExtendedColor. + * @param color the color + */ + public virtual void SetColorStroke(Color value) { + PdfXConformanceImp.CheckPDFXConformance(writer, PdfXConformanceImp.PDFXKEY_COLOR, value); + int type = ExtendedColor.GetType(value); + switch (type) { + case ExtendedColor.TYPE_GRAY: { + SetGrayStroke(((GrayColor)value).Gray); + break; + } + case ExtendedColor.TYPE_CMYK: { + CMYKColor cmyk = (CMYKColor)value; + SetCMYKColorStrokeF(cmyk.Cyan, cmyk.Magenta, cmyk.Yellow, cmyk.Black); + break; + } + case ExtendedColor.TYPE_SEPARATION: { + SpotColor spot = (SpotColor)value; + SetColorStroke(spot.PdfSpotColor, spot.Tint); + break; + } + case ExtendedColor.TYPE_PATTERN: { + PatternColor pat = (PatternColor)value; + SetPatternStroke(pat.Painter); + break; + } + case ExtendedColor.TYPE_SHADING: { + ShadingColor shading = (ShadingColor)value; + SetShadingStroke(shading.PdfShadingPattern); + break; + } + default: + SetRGBColorStroke(value.R, value.G, value.B); + break; + } + } + + /** Sets the fill color. color can be an + * ExtendedColor. + * @param color the color + */ + public virtual void SetColorFill(Color value) { + PdfXConformanceImp.CheckPDFXConformance(writer, PdfXConformanceImp.PDFXKEY_COLOR, value); + int type = ExtendedColor.GetType(value); + switch (type) { + case ExtendedColor.TYPE_GRAY: { + SetGrayFill(((GrayColor)value).Gray); + break; + } + case ExtendedColor.TYPE_CMYK: { + CMYKColor cmyk = (CMYKColor)value; + SetCMYKColorFillF(cmyk.Cyan, cmyk.Magenta, cmyk.Yellow, cmyk.Black); + break; + } + case ExtendedColor.TYPE_SEPARATION: { + SpotColor spot = (SpotColor)value; + SetColorFill(spot.PdfSpotColor, spot.Tint); + break; + } + case ExtendedColor.TYPE_PATTERN: { + PatternColor pat = (PatternColor)value; + SetPatternFill(pat.Painter); + break; + } + case ExtendedColor.TYPE_SHADING: { + ShadingColor shading = (ShadingColor)value; + SetShadingFill(shading.PdfShadingPattern); + break; + } + default: + SetRGBColorFill(value.R, value.G, value.B); + break; + } + } + + /** Sets the fill color to a spot color. + * @param sp the spot color + * @param tint the tint for the spot color. 0 is no color and 1 + * is 100% color + */ + public virtual void SetColorFill(PdfSpotColor sp, float tint) { + CheckWriter(); + state.colorDetails = writer.AddSimple(sp); + PageResources prs = PageResources; + PdfName name = state.colorDetails.ColorName; + name = prs.AddColor(name, state.colorDetails.IndirectReference); + content.Append(name.GetBytes()).Append(" cs ").Append(tint).Append(" scn").Append_i(separator); + } + + /** Sets the stroke color to a spot color. + * @param sp the spot color + * @param tint the tint for the spot color. 0 is no color and 1 + * is 100% color + */ + public virtual void SetColorStroke(PdfSpotColor sp, float tint) { + CheckWriter(); + state.colorDetails = writer.AddSimple(sp); + PageResources prs = PageResources; + PdfName name = state.colorDetails.ColorName; + name = prs.AddColor(name, state.colorDetails.IndirectReference); + content.Append(name.GetBytes()).Append(" CS ").Append(tint).Append(" SCN").Append_i(separator); + } + + /** Sets the fill color to a pattern. The pattern can be + * colored or uncolored. + * @param p the pattern + */ + public virtual void SetPatternFill(PdfPatternPainter p) { + if (p.IsStencil()) { + SetPatternFill(p, p.DefaultColor); + return; + } + CheckWriter(); + PageResources prs = PageResources; + PdfName name = writer.AddSimplePattern(p); + name = prs.AddPattern(name, p.IndirectReference); + content.Append(PdfName.PATTERN.GetBytes()).Append(" cs ").Append(name.GetBytes()).Append(" scn").Append_i(separator); + } + + /** Outputs the color values to the content. + * @param color The color + * @param tint the tint if it is a spot color, ignored otherwise + */ + internal void OutputColorNumbers(Color color, float tint) { + PdfXConformanceImp.CheckPDFXConformance(writer, PdfXConformanceImp.PDFXKEY_COLOR, color); + int type = ExtendedColor.GetType(color); + switch (type) { + case ExtendedColor.TYPE_RGB: + content.Append((float)(color.R) / 0xFF); + content.Append(' '); + content.Append((float)(color.G) / 0xFF); + content.Append(' '); + content.Append((float)(color.B) / 0xFF); + break; + case ExtendedColor.TYPE_GRAY: + content.Append(((GrayColor)color).Gray); + break; + case ExtendedColor.TYPE_CMYK: { + CMYKColor cmyk = (CMYKColor)color; + content.Append(cmyk.Cyan).Append(' ').Append(cmyk.Magenta); + content.Append(' ').Append(cmyk.Yellow).Append(' ').Append(cmyk.Black); + break; + } + case ExtendedColor.TYPE_SEPARATION: + content.Append(tint); + break; + default: + throw new Exception("Invalid color type."); + } + } + + /** Sets the fill color to an uncolored pattern. + * @param p the pattern + * @param color the color of the pattern + */ + public virtual void SetPatternFill(PdfPatternPainter p, Color color) { + if (ExtendedColor.GetType(color) == ExtendedColor.TYPE_SEPARATION) + SetPatternFill(p, color, ((SpotColor)color).Tint); + else + SetPatternFill(p, color, 0); + } + + /** Sets the fill color to an uncolored pattern. + * @param p the pattern + * @param color the color of the pattern + * @param tint the tint if the color is a spot color, ignored otherwise + */ + public virtual void SetPatternFill(PdfPatternPainter p, Color color, float tint) { + CheckWriter(); + if (!p.IsStencil()) + throw new Exception("An uncolored pattern was expected."); + PageResources prs = PageResources; + PdfName name = writer.AddSimplePattern(p); + name = prs.AddPattern(name, p.IndirectReference); + ColorDetails csDetail = writer.AddSimplePatternColorspace(color); + PdfName cName = prs.AddColor(csDetail.ColorName, csDetail.IndirectReference); + content.Append(cName.GetBytes()).Append(" cs").Append_i(separator); + OutputColorNumbers(color, tint); + content.Append(' ').Append(name.GetBytes()).Append(" scn").Append_i(separator); + } + + /** Sets the stroke color to an uncolored pattern. + * @param p the pattern + * @param color the color of the pattern + */ + public virtual void SetPatternStroke(PdfPatternPainter p, Color color) { + if (ExtendedColor.GetType(color) == ExtendedColor.TYPE_SEPARATION) + SetPatternStroke(p, color, ((SpotColor)color).Tint); + else + SetPatternStroke(p, color, 0); + } + + /** Sets the stroke color to an uncolored pattern. + * @param p the pattern + * @param color the color of the pattern + * @param tint the tint if the color is a spot color, ignored otherwise + */ + public virtual void SetPatternStroke(PdfPatternPainter p, Color color, float tint) { + CheckWriter(); + if (!p.IsStencil()) + throw new Exception("An uncolored pattern was expected."); + PageResources prs = PageResources; + PdfName name = writer.AddSimplePattern(p); + name = prs.AddPattern(name, p.IndirectReference); + ColorDetails csDetail = writer.AddSimplePatternColorspace(color); + PdfName cName = prs.AddColor(csDetail.ColorName, csDetail.IndirectReference); + content.Append(cName.GetBytes()).Append(" CS").Append_i(separator); + OutputColorNumbers(color, tint); + content.Append(' ').Append(name.GetBytes()).Append(" SCN").Append_i(separator); + } + + /** Sets the stroke color to a pattern. The pattern can be + * colored or uncolored. + * @param p the pattern + */ + public virtual void SetPatternStroke(PdfPatternPainter p) { + if (p.IsStencil()) { + SetPatternStroke(p, p.DefaultColor); + return; + } + CheckWriter(); + PageResources prs = PageResources; + PdfName name = writer.AddSimplePattern(p); + name = prs.AddPattern(name, p.IndirectReference); + content.Append(PdfName.PATTERN.GetBytes()).Append(" CS ").Append(name.GetBytes()).Append(" SCN").Append_i(separator); + } + + /** + * Paints using a shading object. + * @param shading the shading object + */ + public virtual void PaintShading(PdfShading shading) { + writer.AddSimpleShading(shading); + PageResources prs = PageResources; + PdfName name = prs.AddShading(shading.ShadingName, shading.ShadingReference); + content.Append(name.GetBytes()).Append(" sh").Append_i(separator); + ColorDetails details = shading.ColorDetails; + if (details != null) + prs.AddColor(details.ColorName, details.IndirectReference); + } + + /** + * Paints using a shading pattern. + * @param shading the shading pattern + */ + public virtual void PaintShading(PdfShadingPattern shading) { + PaintShading(shading.Shading); + } + + /** + * Sets the shading fill pattern. + * @param shading the shading pattern + */ + public virtual void SetShadingFill(PdfShadingPattern shading) { + writer.AddSimpleShadingPattern(shading); + PageResources prs = PageResources; + PdfName name = prs.AddPattern(shading.PatternName, shading.PatternReference); + content.Append(PdfName.PATTERN.GetBytes()).Append(" cs ").Append(name.GetBytes()).Append(" scn").Append_i(separator); + ColorDetails details = shading.ColorDetails; + if (details != null) + prs.AddColor(details.ColorName, details.IndirectReference); + } + + /** + * Sets the shading stroke pattern + * @param shading the shading pattern + */ + public virtual void SetShadingStroke(PdfShadingPattern shading) { + writer.AddSimpleShadingPattern(shading); + PageResources prs = PageResources; + PdfName name = prs.AddPattern(shading.PatternName, shading.PatternReference); + content.Append(PdfName.PATTERN.GetBytes()).Append(" CS ").Append(name.GetBytes()).Append(" SCN").Append_i(separator); + ColorDetails details = shading.ColorDetails; + if (details != null) + prs.AddColor(details.ColorName, details.IndirectReference); + } + + /** Check if we have a valid PdfWriter. + * + */ + protected virtual void CheckWriter() { + if (writer == null) + throw new ArgumentNullException("The writer in PdfContentByte is null."); + } + + /** + * Show an array of text. + * @param text array of text + */ + public void ShowText(PdfTextArray text) { + if (state.fontDetails == null) + throw new ArgumentNullException("Font and size must be set before writing any text"); + content.Append('['); + ArrayList arrayList = text.ArrayList; + bool lastWasNumber = false; + for (int k = 0; k < arrayList.Count; ++k) { + Object obj = arrayList[k]; + if (obj is string) { + ShowText2((string)obj); + lastWasNumber = false; + } + else { + if (lastWasNumber) + content.Append(' '); + else + lastWasNumber = true; + content.Append(((float)obj)); + } + } + content.Append("]TJ").Append_i(separator); + } + + /** + * Gets the PdfWriter in use by this object. + * @return the PdfWriter in use by this object + */ + public PdfWriter PdfWriter { + get { + return writer; + } + } + + /** + * Gets the PdfDocument in use by this object. + * @return the PdfDocument in use by this object + */ + public PdfDocument PdfDocument { + get { + return pdf; + } + } + + /** + * Implements a link to other part of the document. The jump will + * be made to a local destination with the same name, that must exist. + * @param name the name for this link + * @param llx the lower left x corner of the activation area + * @param lly the lower left y corner of the activation area + * @param urx the upper right x corner of the activation area + * @param ury the upper right y corner of the activation area + */ + public void LocalGoto(string name, float llx, float lly, float urx, float ury) { + pdf.LocalGoto(name, llx, lly, urx, ury); + } + + /** + * The local destination to where a local goto with the same + * name will jump. + * @param name the name of this local destination + * @param destination the PdfDestination with the jump coordinates + * @return true if the local destination was added, + * false if a local destination with the same name + * already exists + */ + public bool LocalDestination(string name, PdfDestination destination) { + return pdf.LocalDestination(name, destination); + } + + /** + * Gets a duplicate of this PdfContentByte. All + * the members are copied by reference but the buffer stays different. + * + * @return a copy of this PdfContentByte + */ + public virtual PdfContentByte Duplicate { + get { + return new PdfContentByte(writer); + } + } + + /** + * Implements a link to another document. + * @param filename the filename for the remote document + * @param name the name to jump to + * @param llx the lower left x corner of the activation area + * @param lly the lower left y corner of the activation area + * @param urx the upper right x corner of the activation area + * @param ury the upper right y corner of the activation area + */ + public void RemoteGoto(string filename, string name, float llx, float lly, float urx, float ury) { + RemoteGoto(filename, name, llx, lly, urx, ury); + } + + /** + * Implements a link to another document. + * @param filename the filename for the remote document + * @param page the page to jump to + * @param llx the lower left x corner of the activation area + * @param lly the lower left y corner of the activation area + * @param urx the upper right x corner of the activation area + * @param ury the upper right y corner of the activation area + */ + public void RemoteGoto(string filename, int page, float llx, float lly, float urx, float ury) { + pdf.RemoteGoto(filename, page, llx, lly, urx, ury); + } + /** + * Adds a round rectangle to the current path. + * + * @param x x-coordinate of the starting point + * @param y y-coordinate of the starting point + * @param w width + * @param h height + * @param r radius of the arc corner + */ + public void RoundRectangle(float x, float y, float w, float h, float r) { + if (w < 0) { + x += w; + w = -w; + } + if (h < 0) { + y += h; + h = -h; + } + if (r < 0) + r = -r; + float b = 0.4477f; + MoveTo(x + r, y); + LineTo(x + w - r, y); + CurveTo(x + w - r * b, y, x + w, y + r * b, x + w, y + r); + LineTo(x + w, y + h - r); + CurveTo(x + w, y + h - r * b, x + w - r * b, y + h, x + w - r, y + h); + LineTo(x + r, y + h); + CurveTo(x + r * b, y + h, x, y + h - r * b, x, y + h - r); + LineTo(x, y + r); + CurveTo(x, y + r * b, x + r * b, y, x + r, y); + } + + /** Implements an action in an area. + * @param action the PdfAction + * @param llx the lower left x corner of the activation area + * @param lly the lower left y corner of the activation area + * @param urx the upper right x corner of the activation area + * @param ury the upper right y corner of the activation area + */ + public virtual void SetAction(PdfAction action, float llx, float lly, float urx, float ury) { + pdf.SetAction(action, llx, lly, urx, ury); + } + + /** Outputs a string directly to the content. + * @param s the string + */ + public void SetLiteral(string s) { + content.Append(s); + } + + /** Outputs a char directly to the content. + * @param c the char + */ + public void SetLiteral(char c) { + content.Append(c); + } + + /** Outputs a float directly to the content. + * @param n the float + */ + public void SetLiteral(float n) { + content.Append(n); + } + + /** Throws an error if it is a pattern. + * @param t the object to check + */ + internal void CheckNoPattern(PdfTemplate t) { + if (t.Type == PdfTemplate.TYPE_PATTERN) + throw new ArgumentException("Invalid use of a pattern. A template was expected."); + } + + /** + * Draws a TextField. + */ + + public void DrawRadioField(float llx, float lly, float urx, float ury, bool on) { + if (llx > urx) { float x = llx; llx = urx; urx = x; } + if (lly > ury) { float y = lly; lly = ury; ury = y; } + // silver circle + SetLineWidth(1); + SetLineCap(1); + SetColorStroke(new Color(0xC0, 0xC0, 0xC0)); + Arc(llx + 1f, lly + 1f, urx - 1f, ury - 1f, 0f, 360f); + Stroke(); + // gray circle-segment + SetLineWidth(1); + SetLineCap(1); + SetColorStroke(new Color(0xA0, 0xA0, 0xA0)); + Arc(llx + 0.5f, lly + 0.5f, urx - 0.5f, ury - 0.5f, 45, 180); + Stroke(); + // black circle-segment + SetLineWidth(1); + SetLineCap(1); + SetColorStroke(new Color(0x00, 0x00, 0x00)); + Arc(llx + 1.5f, lly + 1.5f, urx - 1.5f, ury - 1.5f, 45, 180); + Stroke(); + if (on) { + // gray circle + SetLineWidth(1); + SetLineCap(1); + SetColorFill(new Color(0x00, 0x00, 0x00)); + Arc(llx + 4f, lly + 4f, urx - 4f, ury - 4f, 0, 360); + Fill(); + } + } + + /** + * Draws a TextField. + */ + + public void DrawTextField(float llx, float lly, float urx, float ury) { + if (llx > urx) { float x = llx; llx = urx; urx = x; } + if (lly > ury) { float y = lly; lly = ury; ury = y; } + // silver rectangle not filled + SetColorStroke(new Color(0xC0, 0xC0, 0xC0)); + SetLineWidth(1); + SetLineCap(0); + Rectangle(llx, lly, urx - llx, ury - lly); + Stroke(); + // white rectangle filled + SetLineWidth(1); + SetLineCap(0); + SetColorFill(new Color(0xFF, 0xFF, 0xFF)); + Rectangle(llx + 0.5f, lly + 0.5f, urx - llx - 1f, ury -lly - 1f); + Fill(); + // silver lines + SetColorStroke(new Color(0xC0, 0xC0, 0xC0)); + SetLineWidth(1); + SetLineCap(0); + MoveTo(llx + 1f, lly + 1.5f); + LineTo(urx - 1.5f, lly + 1.5f); + LineTo(urx - 1.5f, ury - 1f); + Stroke(); + // gray lines + SetColorStroke(new Color(0xA0, 0xA0, 0xA0)); + SetLineWidth(1); + SetLineCap(0); + MoveTo(llx + 1f, lly + 1); + LineTo(llx + 1f, ury - 1f); + LineTo(urx - 1f, ury - 1f); + Stroke(); + // black lines + SetColorStroke(new Color(0x00, 0x00, 0x00)); + SetLineWidth(1); + SetLineCap(0); + MoveTo(llx + 2f, lly + 2f); + LineTo(llx + 2f, ury - 2f); + LineTo(urx - 2f, ury - 2f); + Stroke(); + } + + /** + * Draws a button. + */ + + public void DrawButton(float llx, float lly, float urx, float ury, string text, BaseFont bf, float size) { + if (llx > urx) { float x = llx; llx = urx; urx = x; } + if (lly > ury) { float y = lly; lly = ury; ury = y; } + // black rectangle not filled + SetColorStroke(new Color(0x00, 0x00, 0x00)); + SetLineWidth(1); + SetLineCap(0); + Rectangle(llx, lly, urx - llx, ury - lly); + Stroke(); + // silver rectangle filled + SetLineWidth(1); + SetLineCap(0); + SetColorFill(new Color(0xC0, 0xC0, 0xC0)); + Rectangle(llx + 0.5f, lly + 0.5f, urx - llx - 1f, ury -lly - 1f); + Fill(); + // white lines + SetColorStroke(new Color(0xFF, 0xFF, 0xFF)); + SetLineWidth(1); + SetLineCap(0); + MoveTo(llx + 1f, lly + 1f); + LineTo(llx + 1f, ury - 1f); + LineTo(urx - 1f, ury - 1f); + Stroke(); + // dark grey lines + SetColorStroke(new Color(0xA0, 0xA0, 0xA0)); + SetLineWidth(1); + SetLineCap(0); + MoveTo(llx + 1f, lly + 1f); + LineTo(urx - 1f, lly + 1f); + LineTo(urx - 1f, ury - 1f); + Stroke(); + // text + ResetRGBColorFill(); + BeginText(); + SetFontAndSize(bf, size); + ShowTextAligned(PdfContentByte.ALIGN_CENTER, text, llx + (urx - llx) / 2, lly + (ury - lly - size) / 2, 0); + EndText(); + } + + internal virtual PageResources PageResources { + get { + return pdf.PageResources; + } + } + + /** Sets the graphic state + * @param gstate the graphic state + */ + public void SetGState(PdfGState gstate) { + PdfObject[] obj = writer.AddSimpleExtGState(gstate); + PageResources prs = PageResources; + PdfName name = prs.AddExtGState((PdfName)obj[0], (PdfIndirectReference)obj[1]); + content.Append(name.GetBytes()).Append(" gs").Append_i(separator); + } + + /** + * Begins a graphic block whose visibility is controled by the layer. + * Blocks can be nested. Each block must be terminated by an {@link #endLayer()}.

    + * Note that nested layers with {@link PdfLayer#addChild(PdfLayer)} only require a single + * call to this method and a single call to {@link #endLayer()}; all the nesting control + * is built in. + * @param layer the layer + */ + public void BeginLayer(IPdfOCG layer) { + if ((layer is PdfLayer) && ((PdfLayer)layer).Title != null) + throw new ArgumentException("A title is not a layer"); + if (layerDepth == null) + layerDepth = new ArrayList(); + if (layer is PdfLayerMembership) { + layerDepth.Add(1); + BeginLayer2(layer); + return; + } + int n = 0; + PdfLayer la = (PdfLayer)layer; + while (la != null) { + if (la.Title == null) { + BeginLayer2(la); + ++n; + } + la = la.Parent; + } + layerDepth.Add(n); + } + + private void BeginLayer2(IPdfOCG layer) { + PdfName name = (PdfName)writer.AddSimpleProperty(layer, layer.Ref)[0]; + PageResources prs = PageResources; + name = prs.AddProperty(name, layer.Ref); + content.Append("/OC ").Append(name.GetBytes()).Append(" BDC").Append_i(separator); + } + + /** + * Ends a layer controled graphic block. It will end the most recent open block. + */ + public void EndLayer() { + int n = 1; + if (layerDepth != null && layerDepth.Count > 0) { + n = (int)layerDepth[layerDepth.Count - 1]; + layerDepth.RemoveAt(layerDepth.Count - 1); + } + while (n-- > 0) + content.Append("EMC").Append_i(separator); + } + + internal virtual void AddAnnotation(PdfAnnotation annot) { + writer.AddAnnotation(annot); + } + + /** + * Sets the default colorspace. + * @param name the name of the colorspace. It can be PdfName.DEFAULTGRAY, PdfName.DEFAULTRGB + * or PdfName.DEFAULTCMYK + * @param obj the colorspace. A null or PdfNull removes any colorspace with the same name + */ + public virtual void SetDefaultColorspace(PdfName name, PdfObject obj) { + PageResources prs = PageResources; + prs.AddDefaultColor(name, obj); + } + + public void Transform(System.Drawing.Drawing2D.Matrix tx) { + float[] c = tx.Elements; + ConcatCTM(c[0], c[1], c[2], c[3], c[4], c[5]); + } + + /** + * Begins a marked content sequence. This sequence will be tagged with the structure struc. + * The same structure can be used several times to connect text that belongs to the same logical segment + * but is in a different location, like the same paragraph crossing to another page, for example. + * @param struc the tagging structure + */ + public void BeginMarkedContentSequence(PdfStructureElement struc) { + PdfObject obj = struc.Get(PdfName.K); + int mark = pdf.GetMarkPoint(); + if (obj != null) { + PdfArray ar = null; + if (obj.IsNumber()) { + ar = new PdfArray(); + ar.Add(obj); + struc.Put(PdfName.K, ar); + } + else if (obj.IsArray()) { + ar = (PdfArray)obj; + if (!((PdfObject)ar.ArrayList[0]).IsNumber()) + throw new ArgumentException("The structure has kids."); + } + else + throw new ArgumentException("Unknown object at /K " + obj.GetType().ToString()); + PdfDictionary dic = new PdfDictionary(PdfName.MCR); + dic.Put(PdfName.PG, writer.CurrentPage); + dic.Put(PdfName.MCID, new PdfNumber(mark)); + ar.Add(dic); + struc.SetPageMark(writer.PageNumber - 1, -1); + } + else { + struc.SetPageMark(writer.PageNumber - 1, mark); + struc.Put(PdfName.PG, writer.CurrentPage); + } + pdf.IncMarkPoint(); + content.Append(struc.Get(PdfName.S).GetBytes()).Append(" <> BDC").Append_i(separator); + } + + /** + * Ends a marked content sequence + */ + public void EndMarkedContentSequence() { + content.Append("EMC").Append_i(separator); + } + + /** + * Begins a marked content sequence. If property is null the mark will be of the type + * BMC otherwise it will be BDC. + * @param tag the tag + * @param property the property + * @param inline true to include the property in the content or false + * to include the property in the resource dictionary with the possibility of reusing + */ + public void BeginMarkedContentSequence(PdfName tag, PdfDictionary property, bool inline) { + if (property == null) { + content.Append(tag.GetBytes()).Append(" BMC").Append_i(separator); + return; + } + content.Append(tag.GetBytes()).Append(' '); + if (inline) + property.ToPdf(writer, content); + else { + PdfObject[] objs; + if (writer.PropertyExists(property)) + objs = writer.AddSimpleProperty(property, null); + else + objs = writer.AddSimpleProperty(property, writer.PdfIndirectReference); + PdfName name = (PdfName)objs[0]; + PageResources prs = PageResources; + name = prs.AddProperty(name, (PdfIndirectReference)objs[1]); + content.Append(name.GetBytes()); + } + content.Append(" BDC").Append_i(separator); + } + + /** + * This is just a shorthand to beginMarkedContentSequence(tag, null, false). + * @param tag the tag + */ + public void BeginMarkedContentSequence(PdfName tag) { + BeginMarkedContentSequence(tag, null, false); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfContentParser.cs b/iTechSharp/iTextSharp/text/pdf/PdfContentParser.cs new file mode 100644 index 0000000..78e4a06 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfContentParser.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections; +using System.IO; + +/* + * $Id: PdfContentParser.cs,v 1.4 2006/09/17 15:55:03 psoares33 Exp $ + * + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Parses the page or template content. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfContentParser { + + /** + * Commands have this type. + */ + public const int COMMAND_TYPE = 200; + /** + * Holds value of property tokeniser. + */ + private PRTokeniser tokeniser; + + /** + * Creates a new instance of PdfContentParser + * @param tokeniser the tokeniser with the content + */ + public PdfContentParser(PRTokeniser tokeniser) { + this.tokeniser = tokeniser; + } + + /** + * Parses a single command from the content. Each command is output as an array of arguments + * having the command itself as the last element. The returned array will be empty if the + * end of content was reached. + * @param ls an ArrayList to use. It will be cleared before using. If it's + * null will create a new ArrayList + * @return the same ArrayList given as argument or a new one + * @throws IOException on error + */ + public ArrayList Parse(ArrayList ls) { + if (ls == null) + ls = new ArrayList(); + else + ls.Clear(); + PdfObject ob = null; + while ((ob = ReadPRObject()) != null) { + ls.Add(ob); + if (ob.Type == COMMAND_TYPE) + break; + } + return ls; + } + + /** + * Gets the tokeniser. + * @return the tokeniser. + */ + public PRTokeniser GetTokeniser() { + return this.tokeniser; + } + + /** + * Sets the tokeniser. + * @param tokeniser the tokeniser + */ + public PRTokeniser Tokeniser { + set { + tokeniser = value; + } + get { + return tokeniser; + } + } + + /** + * Reads a dictionary. The tokeniser must be positioned past the "<<" token. + * @return the dictionary + * @throws IOException on error + */ + public PdfDictionary ReadDictionary() { + PdfDictionary dic = new PdfDictionary(); + while (true) { + if (!NextValidToken()) + throw new IOException("Unexpected end of file."); + if (tokeniser.TokenType == PRTokeniser.TK_END_DIC) + break; + if (tokeniser.TokenType != PRTokeniser.TK_NAME) + throw new IOException("Dictionary key is not a name."); + PdfName name = new PdfName(tokeniser.StringValue, false); + PdfObject obj = ReadPRObject(); + int type = obj.Type; + if (-type == PRTokeniser.TK_END_DIC) + throw new IOException("Unexpected '>>'"); + if (-type == PRTokeniser.TK_END_ARRAY) + throw new IOException("Unexpected ']'"); + dic.Put(name, obj); + } + return dic; + } + + /** + * Reads an array. The tokeniser must be positioned past the "[" token. + * @return an array + * @throws IOException on error + */ + public PdfArray ReadArray() { + PdfArray array = new PdfArray(); + while (true) { + PdfObject obj = ReadPRObject(); + int type = obj.Type; + if (-type == PRTokeniser.TK_END_ARRAY) + break; + if (-type == PRTokeniser.TK_END_DIC) + throw new IOException("Unexpected '>>'"); + array.Add(obj); + } + return array; + } + + /** + * Reads a pdf object. + * @return the pdf object + * @throws IOException on error + */ + public PdfObject ReadPRObject() { + if (!NextValidToken()) + return null; + int type = tokeniser.TokenType; + switch (type) { + case PRTokeniser.TK_START_DIC: { + PdfDictionary dic = ReadDictionary(); + return dic; + } + case PRTokeniser.TK_START_ARRAY: + return ReadArray(); + case PRTokeniser.TK_STRING: + PdfString str = new PdfString(tokeniser.StringValue, null).SetHexWriting(tokeniser.IsHexString()); + return str; + case PRTokeniser.TK_NAME: + return new PdfName(tokeniser.StringValue, false); + case PRTokeniser.TK_NUMBER: + return new PdfNumber(tokeniser.StringValue); + case PRTokeniser.TK_OTHER: + return new PdfLiteral(COMMAND_TYPE, tokeniser.StringValue); + default: + return new PdfLiteral(-type, tokeniser.StringValue); + } + } + + /** + * Reads the next token skipping over the comments. + * @return true if a token was read, false if the end of content was reached + * @throws IOException on error + */ + public bool NextValidToken() { + while (tokeniser.NextToken()) { + if (tokeniser.TokenType == PRTokeniser.TK_COMMENT) + continue; + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfContents.cs b/iTechSharp/iTextSharp/text/pdf/PdfContents.cs new file mode 100644 index 0000000..271f689 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfContents.cs @@ -0,0 +1,148 @@ +using System; +using System.IO; + +using iTextSharp.text; + +using System.util.zlib; + +/* + * $Id: PdfContents.cs,v 1.4 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfContents is a PdfStream containing the contents (text + graphics) of a PdfPage. + */ + + public class PdfContents : PdfStream { + + internal static byte[] SAVESTATE = DocWriter.GetISOBytes("q\n"); + internal static byte[] RESTORESTATE = DocWriter.GetISOBytes("Q\n"); + internal static byte[] ROTATE90 = DocWriter.GetISOBytes("0 1 -1 0 "); + internal static byte[] ROTATE180 = DocWriter.GetISOBytes("-1 0 0 -1 "); + internal static byte[] ROTATE270 = DocWriter.GetISOBytes("0 -1 1 0 "); + internal static byte[] ROTATEFINAL = DocWriter.GetISOBytes(" cm\n"); + // constructor + + /** + * Constructs a PdfContents-object, containing text and general graphics. + * + * @param under the direct content that is under all others + * @param content the graphics in a page + * @param text the text in a page + * @param secondContent the direct content that is over all others + * @throws BadPdfFormatException on error + */ + + internal PdfContents(PdfContentByte under, PdfContentByte content, PdfContentByte text, PdfContentByte secondContent, Rectangle page) : base() { + Stream ostr = null; + streamBytes = new MemoryStream(); + if (Document.Compress) { + compressed = true; + ostr = new ZDeflaterOutputStream(streamBytes); + } + else + ostr = streamBytes; + int rotation = page.Rotation; + byte[] tmp; + switch (rotation) { + case 90: + ostr.Write(ROTATE90, 0, ROTATE90.Length); + tmp = DocWriter.GetISOBytes(ByteBuffer.FormatDouble(page.Top)); + ostr.Write(tmp, 0, tmp.Length); + ostr.WriteByte((byte)' '); + ostr.WriteByte((byte)'0'); + ostr.Write(ROTATEFINAL, 0, ROTATEFINAL.Length); + break; + case 180: + ostr.Write(ROTATE180, 0, ROTATE180.Length); + tmp = DocWriter.GetISOBytes(ByteBuffer.FormatDouble(page.Right)); + ostr.Write(tmp, 0, tmp.Length); + ostr.WriteByte((byte)' '); + tmp = DocWriter.GetISOBytes(ByteBuffer.FormatDouble(page.Top)); + ostr.Write(tmp, 0, tmp.Length); + ostr.Write(ROTATEFINAL, 0, ROTATEFINAL.Length); + break; + case 270: + ostr.Write(ROTATE270, 0, ROTATE270.Length); + ostr.WriteByte((byte)'0'); + ostr.WriteByte((byte)' '); + tmp = DocWriter.GetISOBytes(ByteBuffer.FormatDouble(page.Right)); + ostr.Write(tmp, 0, tmp.Length); + ostr.Write(ROTATEFINAL, 0, ROTATEFINAL.Length); + break; + } + if (under.Size > 0) { + ostr.Write(SAVESTATE, 0, SAVESTATE.Length); + under.InternalBuffer.WriteTo(ostr); + ostr.Write(RESTORESTATE, 0, RESTORESTATE.Length); + } + if (content.Size > 0) { + ostr.Write(SAVESTATE, 0, SAVESTATE.Length); + content.InternalBuffer.WriteTo(ostr); + ostr.Write(RESTORESTATE, 0, RESTORESTATE.Length); + } + if (text != null) { + ostr.Write(SAVESTATE, 0, SAVESTATE.Length); + text.InternalBuffer.WriteTo(ostr); + ostr.Write(RESTORESTATE, 0, RESTORESTATE.Length); + } + if (secondContent.Size > 0) { + secondContent.InternalBuffer.WriteTo(ostr); + } + + if (ostr is ZDeflaterOutputStream) + ((ZDeflaterOutputStream)ostr).Finish(); + Put(PdfName.LENGTH, new PdfNumber(streamBytes.Length)); + if (compressed) + Put(PdfName.FILTER, PdfName.FLATEDECODE); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfCopy.cs b/iTechSharp/iTextSharp/text/pdf/PdfCopy.cs new file mode 100644 index 0000000..df1f91e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfCopy.cs @@ -0,0 +1,759 @@ +using System; +using System.Collections; +using System.IO; +using iTextSharp.text; +/* + * $Id: PdfCopy.cs,v 1.24 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * This module by Mark Thompson. Copyright (C) 2002 Mark Thompson + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Make copies of PDF documents. Documents can be edited after reading and + * before writing them out. + * @author Mark Thompson + */ + + public class PdfCopy : PdfWriter { + /** + * This class holds information about indirect references, since they are + * renumbered by iText. + */ + internal class IndirectReferences { + PdfIndirectReference theRef; + bool hasCopied; + internal IndirectReferences(PdfIndirectReference refi) { + theRef = refi; + hasCopied = false; + } + internal void SetCopied() { hasCopied = true; } + internal bool Copied { + get { + return hasCopied; + } + } + internal PdfIndirectReference Ref { + get { + return theRef; + } + } + }; + protected Hashtable indirects; + protected Hashtable indirectMap; + protected int currentObjectNum = 1; + protected PdfReader reader; + protected PdfIndirectReference acroForm; + protected int[] namePtr = {0}; + /** Holds value of property rotateContents. */ + private bool rotateContents = true; + protected internal PdfArray fieldArray; + protected internal Hashtable fieldTemplates; + + /** + * A key to allow us to hash indirect references + */ + protected class RefKey { + internal int num; + internal int gen; + internal RefKey(int num, int gen) { + this.num = num; + this.gen = gen; + } + internal RefKey(PdfIndirectReference refi) { + num = refi.Number; + gen = refi.Generation; + } + internal RefKey(PRIndirectReference refi) { + num = refi.Number; + gen = refi.Generation; + } + public override int GetHashCode() { + return (gen<<16)+num; + } + public override bool Equals(Object o) { + if (!(o is RefKey)) return false; + RefKey other = (RefKey)o; + return this.gen == other.gen && this.num == other.num; + } + public override String ToString() { + return "" + num + " " + gen; + } + } + + /** + * Constructor + * @param document + * @param os outputstream + */ + public PdfCopy(Document document, Stream os) : base(new PdfDocument(), os) { + document.AddDocListener(pdf); + pdf.AddWriter(this); + indirectMap = new Hashtable(); + } + + /** Checks if the content is automatically adjusted to compensate + * the original page rotation. + * @return the auto-rotation status + */ + /** Flags the content to be automatically adjusted to compensate + * the original page rotation. The default is true. + * @param rotateContents true to set auto-rotation, false + * otherwise + */ + public bool RotateContents { + set { + rotateContents = value; + } + get { + return rotateContents; + } + } + + /** + * Grabs a page from the input document + * @param reader the reader of the document + * @param pageNumber which page to get + * @return the page + */ + public override PdfImportedPage GetImportedPage(PdfReader reader, int pageNumber) { + if (currentPdfReaderInstance != null) { + if (currentPdfReaderInstance.Reader != reader) { + try { + currentPdfReaderInstance.Reader.Close(); + currentPdfReaderInstance.ReaderFile.Close(); + } + catch (IOException) { + // empty on purpose + } + currentPdfReaderInstance = reader.GetPdfReaderInstance(this); + } + } + else { + currentPdfReaderInstance = reader.GetPdfReaderInstance(this); + } + return currentPdfReaderInstance.GetImportedPage(pageNumber); + } + + + /** + * Translate a PRIndirectReference to a PdfIndirectReference + * In addition, translates the object numbers, and copies the + * referenced object to the output file. + * NB: PRIndirectReferences (and PRIndirectObjects) really need to know what + * file they came from, because each file has its own namespace. The translation + * we do from their namespace to ours is *at best* heuristic, and guaranteed to + * fail under some circumstances. + */ + protected virtual PdfIndirectReference CopyIndirect(PRIndirectReference inp) { + PdfIndirectReference theRef; + RefKey key = new RefKey(inp); + IndirectReferences iRef = (IndirectReferences)indirects[key] ; + if (iRef != null) { + theRef = iRef.Ref; + if (iRef.Copied) { + return theRef; + } + } + else { + theRef = body.PdfIndirectReference; + iRef = new IndirectReferences(theRef); + indirects[key] = iRef; + } + PdfObject obj = PdfReader.GetPdfObjectRelease(inp); + if (obj != null && obj.IsDictionary()) { + PdfObject type = PdfReader.GetPdfObjectRelease(((PdfDictionary)obj).Get(PdfName.TYPE)); + if (type != null && PdfName.PAGE.Equals(type)) { + return theRef; + } + } + iRef.SetCopied(); + obj = CopyObject(obj); + AddToBody(obj, theRef); + return theRef; + } + + /** + * Translate a PRDictionary to a PdfDictionary. Also translate all of the + * objects contained in it. + */ + protected PdfDictionary CopyDictionary(PdfDictionary inp) { + PdfDictionary outp = new PdfDictionary(); + PdfObject type = PdfReader.GetPdfObjectRelease(inp.Get(PdfName.TYPE)); + + foreach (PdfName key in inp.Keys) { + PdfObject value = inp.Get(key); + if (type != null && PdfName.PAGE.Equals(type)) { + if (!key.Equals(PdfName.B) && !key.Equals(PdfName.PARENT)) + outp.Put(key, CopyObject(value)); + } + else + outp.Put(key, CopyObject(value)); + } + return outp; + } + + /** + * Translate a PRStream to a PdfStream. The data part copies itself. + */ + protected PdfStream CopyStream(PRStream inp) { + PRStream outp = new PRStream(inp, null); + + foreach (PdfName key in inp.Keys) { + PdfObject value = inp.Get(key); + outp.Put(key, CopyObject(value)); + } + + return outp; + } + + + /** + * Translate a PRArray to a PdfArray. Also translate all of the objects contained + * in it + */ + protected PdfArray CopyArray(PdfArray inp) { + PdfArray outp = new PdfArray(); + + foreach (PdfObject value in inp.ArrayList) { + outp.Add(CopyObject(value)); + } + return outp; + } + + /** + * Translate a PR-object to a Pdf-object + */ + protected PdfObject CopyObject(PdfObject inp) { + if (inp == null) + return PdfNull.PDFNULL; + switch (inp.Type) { + case PdfObject.DICTIONARY: + return CopyDictionary((PdfDictionary)inp); + case PdfObject.INDIRECT: + return CopyIndirect((PRIndirectReference)inp); + case PdfObject.ARRAY: + return CopyArray((PdfArray)inp); + case PdfObject.NUMBER: + case PdfObject.NAME: + case PdfObject.STRING: + case PdfObject.NULL: + case PdfObject.BOOLEAN: + case 0: + return inp; + case PdfObject.STREAM: + return CopyStream((PRStream)inp); + // return in; + default: + if (inp.Type < 0) { + String lit = ((PdfLiteral)inp).ToString(); + if (lit.Equals("true") || lit.Equals("false")) { + return new PdfBoolean(lit); + } + return new PdfLiteral(lit); + } + return null; + } + } + + /** + * convenience method. Given an importedpage, set our "globals" + */ + protected int SetFromIPage(PdfImportedPage iPage) { + int pageNum = iPage.PageNumber; + PdfReaderInstance inst = currentPdfReaderInstance = iPage.PdfReaderInstance; + reader = inst.Reader; + SetFromReader(reader); + return pageNum; + } + + /** + * convenience method. Given a reader, set our "globals" + */ + protected void SetFromReader(PdfReader reader) { + this.reader = reader; + indirects = (Hashtable)indirectMap[reader] ; + if (indirects == null) { + indirects = new Hashtable(); + indirectMap[reader] = indirects; + PdfDictionary catalog = reader.Catalog; + PRIndirectReference refi = null; + PdfObject o = catalog.Get(PdfName.ACROFORM); + if (o == null || o.Type != PdfObject.INDIRECT) + return; + refi = (PRIndirectReference)o; + if (acroForm == null) acroForm = body.PdfIndirectReference; + indirects[new RefKey(refi)] = new IndirectReferences(acroForm); + } + } + /** + * Add an imported page to our output + * @param iPage an imported page + * @throws IOException, BadPdfFormatException + */ + public void AddPage(PdfImportedPage iPage) { + int pageNum = SetFromIPage(iPage); + + PdfDictionary thePage = reader.GetPageN(pageNum); + PRIndirectReference origRef = reader.GetPageOrigRef(pageNum); + reader.ReleasePage(pageNum); + RefKey key = new RefKey(origRef); + PdfIndirectReference pageRef; + IndirectReferences iRef = (IndirectReferences)indirects[key] ; + if (iRef != null && !iRef.Copied) { + pageReferences.Add(iRef.Ref); + iRef.SetCopied(); + } + pageRef = CurrentPage; + if (iRef == null) { + iRef = new IndirectReferences(pageRef); + indirects[key] = iRef; + } + iRef.SetCopied(); + PdfDictionary newPage = CopyDictionary(thePage); + root.AddPage(newPage); + ++currentPageNumber; + } + + /** + * Copy the acroform for an input document. Note that you can only have one, + * we make no effort to merge them. + * @param reader The reader of the input file that is being copied + * @throws IOException, BadPdfFormatException + */ + public void CopyAcroForm(PdfReader reader) { + SetFromReader(reader); + + PdfDictionary catalog = reader.Catalog; + PRIndirectReference hisRef = null; + PdfObject o = catalog.Get(PdfName.ACROFORM); + if (o != null && o.Type == PdfObject.INDIRECT) + hisRef = (PRIndirectReference)o; + if (hisRef == null) return; // bugfix by John Engla + RefKey key = new RefKey(hisRef); + PdfIndirectReference myRef; + IndirectReferences iRef = (IndirectReferences)indirects[key] ; + if (iRef != null) { + acroForm = myRef = iRef.Ref; + } + else { + acroForm = myRef = body.PdfIndirectReference; + iRef = new IndirectReferences(myRef); + indirects[key] = iRef; + } + if (! iRef.Copied) { + iRef.SetCopied(); + PdfDictionary theForm = CopyDictionary((PdfDictionary)PdfReader.GetPdfObject(hisRef)); + AddToBody(theForm, myRef); + } + } + + /* + * the getCatalog method is part of PdfWriter. + * we wrap this so that we can extend it + */ + protected override PdfDictionary GetCatalog(PdfIndirectReference rootObj) { + PdfDictionary theCat = pdf.GetCatalog(rootObj); + if (fieldArray == null) { + if (acroForm != null) theCat.Put(PdfName.ACROFORM, acroForm); + } + else + AddFieldResources(theCat); + WriteOutlines(theCat, false); + return theCat; + } + + private void AddFieldResources(PdfDictionary catalog) { + if (fieldArray == null) + return; + PdfDictionary acroForm = new PdfDictionary(); + catalog.Put(PdfName.ACROFORM, acroForm); + acroForm.Put(PdfName.FIELDS, fieldArray); + acroForm.Put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g ")); + if (fieldTemplates.Count == 0) + return; + PdfDictionary dr = new PdfDictionary(); + acroForm.Put(PdfName.DR, dr); + foreach (PdfTemplate template in fieldTemplates.Keys) { + PdfFormField.MergeResources(dr, (PdfDictionary)template.Resources); + } + if (dr.Get(PdfName.ENCODING) == null) + dr.Put(PdfName.ENCODING, PdfName.WIN_ANSI_ENCODING); + PdfDictionary fonts = (PdfDictionary)PdfReader.GetPdfObject(dr.Get(PdfName.FONT)); + if (fonts == null) { + fonts = new PdfDictionary(); + dr.Put(PdfName.FONT, fonts); + } + if (!fonts.Contains(PdfName.HELV)) { + PdfDictionary dic = new PdfDictionary(PdfName.FONT); + dic.Put(PdfName.BASEFONT, PdfName.HELVETICA); + dic.Put(PdfName.ENCODING, PdfName.WIN_ANSI_ENCODING); + dic.Put(PdfName.NAME, PdfName.HELV); + dic.Put(PdfName.SUBTYPE, PdfName.TYPE1); + fonts.Put(PdfName.HELV, AddToBody(dic).IndirectReference); + } + if (!fonts.Contains(PdfName.ZADB)) { + PdfDictionary dic = new PdfDictionary(PdfName.FONT); + dic.Put(PdfName.BASEFONT, PdfName.ZAPFDINGBATS); + dic.Put(PdfName.NAME, PdfName.ZADB); + dic.Put(PdfName.SUBTYPE, PdfName.TYPE1); + fonts.Put(PdfName.ZADB, AddToBody(dic).IndirectReference); + } + } + + /** + * Signals that the Document was closed and that no other + * Elements will be added. + *

    + * The pages-tree is built and written to the outputstream. + * A Catalog is constructed, as well as an Info-object, + * the referencetable is composed and everything is written + * to the outputstream embedded in a Trailer. + */ + + public override void Close() { + if (open) { + PdfReaderInstance ri = currentPdfReaderInstance; + pdf.Close(); + base.Close(); + if (ri != null) { + try { + ri.Reader.Close(); + ri.ReaderFile.Close(); + } + catch (IOException) { + // empty on purpose + } + } + } + } + + public override void AddAnnotation(PdfAnnotation annot) { } + internal override PdfIndirectReference Add(PdfPage page, PdfContents contents) { return null; } + + public override void FreeReader(PdfReader reader) { + indirectMap.Remove(reader); + if (currentPdfReaderInstance != null) { + if (currentPdfReaderInstance.Reader == reader) { + try { + currentPdfReaderInstance.Reader.Close(); + currentPdfReaderInstance.ReaderFile.Close(); + } + catch (IOException) { + // empty on purpose + } + currentPdfReaderInstance = null; + } + } + } + + /** + * Create a page stamp. New content and annotations, including new fields, are allowed. + * The fields added cannot have parents in another pages. This method modifies the PdfReader instance.

    + * The general usage to stamp something in a page is: + *

    + *

    +        * PdfImportedPage page = copy.getImportedPage(reader, 1);
    +        * PdfCopy.PageStamp ps = copy.createPageStamp(page);
    +        * ps.addAnnotation(PdfAnnotation.createText(copy, new Rectangle(50, 180, 70, 200), "Hello", "No Thanks", true, "Comment"));
    +        * PdfContentByte under = ps.getUnderContent();
    +        * under.addImage(img);
    +        * PdfContentByte over = ps.getOverContent();
    +        * over.beginText();
    +        * over.setFontAndSize(bf, 18);
    +        * over.setTextMatrix(30, 30);
    +        * over.showText("total page " + totalPage);
    +        * over.endText();
    +        * ps.alterContents();
    +        * copy.addPage(page);
    +        * 
    + * @param iPage an imported page + * @return the PageStamp + */ + public PageStamp CreatePageStamp(PdfImportedPage iPage) { + int pageNum = iPage.PageNumber; + PdfReader reader = iPage.PdfReaderInstance.Reader; + PdfDictionary pageN = reader.GetPageN(pageNum); + return new PageStamp(reader, pageN, this); + } + + public class PageStamp { + + PdfDictionary pageN; + PdfCopy.StampContent under; + PdfCopy.StampContent over; + PageResources pageResources; + PdfReader reader; + PdfCopy cstp; + + internal PageStamp(PdfReader reader, PdfDictionary pageN, PdfCopy cstp) { + this.pageN = pageN; + this.reader = reader; + this.cstp = cstp; + } + + public PdfContentByte GetUnderContent(){ + if (under == null) { + if (pageResources == null) { + pageResources = new PageResources(); + PdfDictionary resources = (PdfDictionary)PdfReader.GetPdfObject(pageN.Get(PdfName.RESOURCES)); + pageResources.SetOriginalResources(resources, cstp.namePtr); + } + under = new PdfCopy.StampContent(cstp, pageResources); + } + return under; + } + + public PdfContentByte GetOverContent(){ + if (over == null) { + if (pageResources == null) { + pageResources = new PageResources(); + PdfDictionary resources = (PdfDictionary)PdfReader.GetPdfObject(pageN.Get(PdfName.RESOURCES)); + pageResources.SetOriginalResources(resources, cstp.namePtr); + } + over = new PdfCopy.StampContent(cstp, pageResources); + } + return over; + } + + public void AlterContents() { + if (over == null && under == null) + return; + PdfArray ar = null; + PdfObject content = PdfReader.GetPdfObject(pageN.Get(PdfName.CONTENTS), pageN); + if (content == null) { + ar = new PdfArray(); + pageN.Put(PdfName.CONTENTS, ar); + } + else if (content.IsArray()) { + ar = (PdfArray)content; + } + else if (content.IsStream()) { + ar = new PdfArray(); + ar.Add(pageN.Get(PdfName.CONTENTS)); + pageN.Put(PdfName.CONTENTS, ar); + } + else { + ar = new PdfArray(); + pageN.Put(PdfName.CONTENTS, ar); + } + ByteBuffer out_p = new ByteBuffer(); + if (under != null) { + out_p.Append(PdfContents.SAVESTATE); + ApplyRotation(pageN, out_p); + out_p.Append(under.InternalBuffer); + out_p.Append(PdfContents.RESTORESTATE); + } + if (over != null) + out_p.Append(PdfContents.SAVESTATE); + PdfStream stream = new PdfStream(out_p.ToByteArray()); + stream.FlateCompress(); + PdfIndirectReference ref1 = cstp.AddToBody(stream).IndirectReference; + ar.AddFirst(ref1); + out_p.Reset(); + if (over != null) { + out_p.Append(' '); + out_p.Append(PdfContents.RESTORESTATE); + out_p.Append(PdfContents.SAVESTATE); + ApplyRotation(pageN, out_p); + out_p.Append(over.InternalBuffer); + out_p.Append(PdfContents.RESTORESTATE); + stream = new PdfStream(out_p.ToByteArray()); + stream.FlateCompress(); + ar.Add(cstp.AddToBody(stream).IndirectReference); + } + pageN.Put(PdfName.RESOURCES, pageResources.Resources); + } + + void ApplyRotation(PdfDictionary pageN, ByteBuffer out_p) { + if (!cstp.rotateContents) + return; + Rectangle page = reader.GetPageSizeWithRotation(pageN); + int rotation = page.Rotation; + switch (rotation) { + case 90: + out_p.Append(PdfContents.ROTATE90); + out_p.Append(page.Top); + out_p.Append(' ').Append('0').Append(PdfContents.ROTATEFINAL); + break; + case 180: + out_p.Append(PdfContents.ROTATE180); + out_p.Append(page.Right); + out_p.Append(' '); + out_p.Append(page.Top); + out_p.Append(PdfContents.ROTATEFINAL); + break; + case 270: + out_p.Append(PdfContents.ROTATE270); + out_p.Append('0').Append(' '); + out_p.Append(page.Right); + out_p.Append(PdfContents.ROTATEFINAL); + break; + } + } + + private void AddDocumentField(PdfIndirectReference refi) { + if (cstp.fieldArray == null) + cstp.fieldArray = new PdfArray(); + cstp.fieldArray.Add(refi); + } + + private void ExpandFields(PdfFormField field, ArrayList allAnnots) { + allAnnots.Add(field); + ArrayList kids = field.Kids; + if (kids != null) { + for (int k = 0; k < kids.Count; ++k) + ExpandFields((PdfFormField)kids[k], allAnnots); + } + } + + public void AddAnnotation(PdfAnnotation annot) { + ArrayList allAnnots = new ArrayList(); + if (annot.IsForm()) { + PdfFormField field = (PdfFormField)annot; + if (field.Parent != null) + return; + ExpandFields(field, allAnnots); + if (cstp.fieldTemplates == null) + cstp.fieldTemplates = new Hashtable(); + } + else + allAnnots.Add(annot); + for (int k = 0; k < allAnnots.Count; ++k) { + annot = (PdfAnnotation)allAnnots[k]; + if (annot.IsForm()) { + if (!annot.IsUsed()) { + Hashtable templates = annot.Templates; + if (templates != null) { + foreach (object tpl in templates.Keys) { + cstp.fieldTemplates[tpl] = null; + } + } + } + PdfFormField field = (PdfFormField)annot; + if (field.Parent == null) + AddDocumentField(field.IndirectReference); + } + if (annot.IsAnnotation()) { + PdfObject pdfobj = PdfReader.GetPdfObject(pageN.Get(PdfName.ANNOTS), pageN); + PdfArray annots = null; + if (pdfobj == null || !pdfobj.IsArray()) { + annots = new PdfArray(); + pageN.Put(PdfName.ANNOTS, annots); + } + else + annots = (PdfArray)pdfobj; + annots.Add(annot.IndirectReference); + if (!annot.IsUsed()) { + PdfRectangle rect = (PdfRectangle)annot.Get(PdfName.RECT); + if (rect != null && (rect.Left != 0 || rect.Right != 0 || rect.Top != 0 || rect.Bottom != 0)) { + int rotation = reader.GetPageRotation(pageN); + Rectangle pageSize = reader.GetPageSizeWithRotation(pageN); + switch (rotation) { + case 90: + annot.Put(PdfName.RECT, new PdfRectangle( + pageSize.Top - rect.Bottom, + rect.Left, + pageSize.Top - rect.Top, + rect.Right)); + break; + case 180: + annot.Put(PdfName.RECT, new PdfRectangle( + pageSize.Right - rect.Left, + pageSize.Top - rect.Bottom, + pageSize.Right - rect.Right, + pageSize.Top - rect.Top)); + break; + case 270: + annot.Put(PdfName.RECT, new PdfRectangle( + rect.Bottom, + pageSize.Right - rect.Left, + rect.Top, + pageSize.Right - rect.Right)); + break; + } + } + } + } + if (!annot.IsUsed()) { + annot.SetUsed(); + cstp.AddToBody(annot, annot.IndirectReference); + } + } + } + } + + public class StampContent : PdfContentByte { + PageResources pageResources; + + /** Creates a new instance of StampContent */ + internal StampContent(PdfWriter writer, PageResources pageResources) : base(writer) { + this.pageResources = pageResources; + } + + /** + * Gets a duplicate of this PdfContentByte. All + * the members are copied by reference but the buffer stays different. + * + * @return a copy of this PdfContentByte + */ + public override PdfContentByte Duplicate { + get { + return new PdfCopy.StampContent(writer, pageResources); + } + } + + internal override PageResources PageResources { + get { + return pageResources; + } + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfCopyFields.cs b/iTechSharp/iTextSharp/text/pdf/PdfCopyFields.cs new file mode 100644 index 0000000..0704eb7 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfCopyFields.cs @@ -0,0 +1,244 @@ +using System; +using System.Collections; +using System.IO; +using iTextSharp.text.pdf.interfaces; +using Org.BouncyCastle.X509; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Concatenates PDF documents including form fields. The rules for the form field + * concatenation are the same as in Acrobat. All the documents are kept in memory unlike + * PdfCopy. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfCopyFields : IPdfViewerPreferences, IPdfEncryptionSettings { + + private PdfCopyFieldsImp fc; + + /** + * Creates a new instance. + * @param os the output stream + * @throws DocumentException on error + * @throws IOException on error + */ + public PdfCopyFields(Stream os) { + fc = new PdfCopyFieldsImp(os); + } + + /** + * Creates a new instance. + * @param os the output stream + * @param pdfVersion the pdf version the output will have + * @throws DocumentException on error + * @throws IOException on error + */ + public PdfCopyFields(Stream os, char pdfVersion) { + fc = new PdfCopyFieldsImp(os, pdfVersion); + } + + /** + * Concatenates a PDF document. + * @param reader the PDF document + * @throws DocumentException on error + */ + public void AddDocument(PdfReader reader) { + fc.AddDocument(reader); + } + + /** + * Concatenates a PDF document selecting the pages to keep. The pages are described as a + * List of Integer. The page ordering can be changed but + * no page repetitions are allowed. + * @param reader the PDF document + * @param pagesToKeep the pages to keep + * @throws DocumentException on error + */ + public void AddDocument(PdfReader reader, ArrayList pagesToKeep) { + fc.AddDocument(reader, pagesToKeep); + } + + /** + * Concatenates a PDF document selecting the pages to keep. The pages are described as + * ranges. The page ordering can be changed but + * no page repetitions are allowed. + * @param reader the PDF document + * @param ranges the comma separated ranges as described in {@link SequenceList} + * @throws DocumentException on error + */ + public void AddDocument(PdfReader reader, String ranges) { + fc.AddDocument(reader, SequenceList.Expand(ranges, reader.NumberOfPages)); + } + + /** Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param strength128Bits true for 128 bit key length, false for 40 bit key length + * @throws DocumentException if the document is already open + */ + public void SetEncryption(byte[] userPassword, byte[] ownerPassword, int permissions, bool strength128Bits) { + fc.SetEncryption(userPassword, ownerPassword, permissions, strength128Bits ? PdfWriter.STANDARD_ENCRYPTION_128 : PdfWriter.STANDARD_ENCRYPTION_40); + } + + /** + * Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param strength true for 128 bit key length. false for 40 bit key length + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @throws DocumentException if the document is already open + */ + public void SetEncryption(bool strength, String userPassword, String ownerPassword, int permissions) { + SetEncryption(DocWriter.GetISOBytes(userPassword), DocWriter.GetISOBytes(ownerPassword), permissions, strength); + } + + /** + * Closes the output document. + */ + public void Close() { + fc.Close(); + } + + /** + * Opens the document. This is usually not needed as AddDocument() will do it + * automatically. + */ + public void Open() { + fc.OpenDoc(); + } + + /** + * Adds JavaScript to the global document + * @param js the JavaScript + */ + public void AddJavaScript(String js) { + fc.AddJavaScript(js, !PdfEncodings.IsPdfDocEncoding(js)); + } + + /** + * Sets the bookmarks. The list structure is defined in + * {@link SimpleBookmark}. + * @param outlines the bookmarks or null to remove any + */ + public ArrayList Outlines { + set { + fc.Outlines = value; + } + } + + /** Gets the underlying PdfWriter. + * @return the underlying PdfWriter + */ + public PdfWriter Writer { + get { + return fc; + } + } + + /** + * Gets the 1.5 compression status. + * @return true if the 1.5 compression is on + */ + public bool FullCompression { + get { + return fc.FullCompression; + } + } + + /** + * Sets the document's compression to the new 1.5 mode with object streams and xref + * streams. It can be set at any time but once set it can't be unset. + *

    + * If set before opening the document it will also set the pdf version to 1.5. + */ + public void SetFullCompression() { + fc.SetFullCompression(); + } + + /** + * @see com.lowagie.text.pdf.interfaces.PdfEncryptionSettings#setEncryption(byte[], byte[], int, int) + */ + public void SetEncryption(byte[] userPassword, byte[] ownerPassword, int permissions, int encryptionType) { + fc.SetEncryption(userPassword, ownerPassword, permissions, encryptionType); + } + + /** + * @see com.lowagie.text.pdf.interfaces.PdfViewerPreferences#addViewerPreference(com.lowagie.text.pdf.PdfName, com.lowagie.text.pdf.PdfObject) + */ + public void AddViewerPreference(PdfName key, PdfObject value) { + fc.AddViewerPreference(key, value); + } + + /** + * @see com.lowagie.text.pdf.interfaces.PdfViewerPreferences#setViewerPreferences(int) + */ + public int ViewerPreferences { + set { + fc.ViewerPreferences = value; + } + } + + /** + * @see com.lowagie.text.pdf.interfaces.PdfEncryptionSettings#setEncryption(java.security.cert.Certificate[], int[], int) + */ + public void SetEncryption(X509Certificate[] certs, int[] permissions, int encryptionType) { + fc.SetEncryption(certs, permissions, encryptionType); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfCopyFieldsImp.cs b/iTechSharp/iTextSharp/text/pdf/PdfCopyFieldsImp.cs new file mode 100644 index 0000000..d404fc1 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfCopyFieldsImp.cs @@ -0,0 +1,600 @@ +using System; +using System.Collections; +using System.IO; +using System.util; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * + * @author psoares + */ + internal class PdfCopyFieldsImp : PdfWriter { + + private static readonly PdfName iTextTag = new PdfName("_iTextTag_"); + private static object zero = 0; + internal ArrayList readers = new ArrayList(); + internal Hashtable readers2intrefs = new Hashtable(); + internal Hashtable pages2intrefs = new Hashtable(); + internal Hashtable visited = new Hashtable(); + internal ArrayList fields = new ArrayList(); + internal RandomAccessFileOrArray file; + internal Hashtable fieldTree = new Hashtable(); + internal ArrayList pageRefs = new ArrayList(); + internal ArrayList pageDics = new ArrayList(); + internal PdfDictionary resources = new PdfDictionary(); + internal PdfDictionary form; + bool closing = false; + internal Document nd; + private Hashtable tabOrder; + private ArrayList calculationOrder = new ArrayList(); + private ArrayList calculationOrderRefs; + + internal PdfCopyFieldsImp(Stream os) : this(os, '\0') { + } + + internal PdfCopyFieldsImp(Stream os, char pdfVersion) : base(new PdfDocument(), os) { + pdf.AddWriter(this); + if (pdfVersion != 0) + base.PdfVersion = pdfVersion; + nd = new Document(); + nd.AddDocListener(pdf); + } + + internal void AddDocument(PdfReader reader, ArrayList pagesToKeep) { + if (!readers2intrefs.ContainsKey(reader) && reader.Tampered) + throw new DocumentException("The document was reused."); + reader = new PdfReader(reader); + reader.SelectPages(pagesToKeep); + if (reader.NumberOfPages == 0) + return; + reader.Tampered = false; + AddDocument(reader); + } + + internal void AddDocument(PdfReader reader) { + if (!reader.IsOpenedWithFullPermissions) + throw new ArgumentException("PdfReader not opened with owner password"); + OpenDoc(); + if (readers2intrefs.ContainsKey(reader)) { + reader = new PdfReader(reader); + } + else { + if (reader.Tampered) + throw new DocumentException("The document was reused."); + reader.ConsolidateNamedDestinations(); + reader.Tampered = true; + } + reader.ShuffleSubsetNames(); + readers2intrefs[reader] = new IntHashtable(); + readers.Add(reader); + int len = reader.NumberOfPages; + IntHashtable refs = new IntHashtable(); + for (int p = 1; p <= len; ++p) { + refs[reader.GetPageOrigRef(p).Number] = 1; + reader.ReleasePage(p); + } + pages2intrefs[reader] = refs; + visited[reader] = new IntHashtable(); + fields.Add(reader.AcroFields); + UpdateCalculationOrder(reader); + } + + private static String GetCOName(PdfReader reader, PRIndirectReference refi) { + String name = ""; + while (refi != null) { + PdfObject obj = PdfReader.GetPdfObject(refi); + if (obj == null || obj.Type != PdfObject.DICTIONARY) + break; + PdfDictionary dic = (PdfDictionary)obj; + PdfString t = (PdfString)PdfReader.GetPdfObject(dic.Get(PdfName.T)); + if (t != null) { + name = t.ToUnicodeString()+ "." + name; + } + refi = (PRIndirectReference)dic.Get(PdfName.PARENT); + } + if (name.EndsWith(".")) + name = name.Substring(0, name.Length - 1); + return name; + } + + private void UpdateCalculationOrder(PdfReader reader) { + PdfDictionary catalog = reader.Catalog; + PdfDictionary acro = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.ACROFORM)); + if (acro == null) + return; + PdfArray co = (PdfArray)PdfReader.GetPdfObject(acro.Get(PdfName.CO)); + if (co == null || co.Size == 0) + return; + AcroFields af = reader.AcroFields; + ArrayList coa = co.ArrayList; + for (int k = 0; k < coa.Count; ++k) { + PdfObject obj = (PdfObject)coa[k]; + if (obj == null || !obj.IsIndirect()) + continue; + String name = GetCOName(reader, (PRIndirectReference)obj) ; + if (af.GetFieldItem(name) == null) + continue; + name = "." + name; + if (calculationOrder.Contains(name)) + continue; + calculationOrder.Add(name); + } + } + + internal void Propagate(PdfObject obj, PdfIndirectReference refo, bool restricted) { + if (obj == null) + return; + // if (refo != null) + // AddToBody(obj, refo); + if (obj is PdfIndirectReference) + return; + switch (obj.Type) { + case PdfObject.DICTIONARY: + case PdfObject.STREAM: { + PdfDictionary dic = (PdfDictionary)obj; + foreach (PdfName key in dic.Keys) { + if (restricted && (key.Equals(PdfName.PARENT) || key.Equals(PdfName.KIDS))) + continue; + PdfObject ob = dic.Get(key); + if (ob != null && ob.IsIndirect()) { + PRIndirectReference ind = (PRIndirectReference)ob; + if (!SetVisited(ind) && !IsPage(ind)) { + PdfIndirectReference refi = GetNewReference(ind); + Propagate(PdfReader.GetPdfObjectRelease(ind), refi, restricted); + } + } + else + Propagate(ob, null, restricted); + } + break; + } + case PdfObject.ARRAY: { + ArrayList list = ((PdfArray)obj).ArrayList; + //PdfArray arr = new PdfArray(); + foreach (PdfObject ob in list) { + if (ob != null && ob.IsIndirect()) { + PRIndirectReference ind = (PRIndirectReference)ob; + if (!IsVisited(ind) && !IsPage(ind)) { + PdfIndirectReference refi = GetNewReference(ind); + Propagate(PdfReader.GetPdfObjectRelease(ind), refi, restricted); + } + } + else + Propagate(ob, null, restricted); + } + break; + } + case PdfObject.INDIRECT: { + throw new Exception("Reference pointing to reference."); + } + } + } + + private void AdjustTabOrder(PdfArray annots, PdfIndirectReference ind, PdfNumber nn) { + int v = nn.IntValue; + ArrayList t = (ArrayList)tabOrder[annots] ; + if (t == null) { + t = new ArrayList(); + int size = annots.Size - 1; + for (int k = 0; k < size; ++k) { + t.Add(zero); + } + t.Add(v); + tabOrder[annots] = t; + annots.Add(ind); + } + else { + int size = t.Count - 1; + for (int k = size; k >= 0; --k) { + if ((int)t[k] <= v) { + t.Insert(k + 1, v); + annots.ArrayList.Insert(k + 1, ind); + size = -2; + break; + } + } + if (size != -2) { + t.Insert(0, v); + annots.ArrayList.Insert(0, ind); + } + } + } + + protected PdfArray BranchForm(Hashtable level, PdfIndirectReference parent, String fname) { + PdfArray arr = new PdfArray(); + foreach (DictionaryEntry entry in level) { + String name = (String)entry.Key; + Object obj = entry.Value; + PdfIndirectReference ind = PdfIndirectReference; + PdfDictionary dic = new PdfDictionary(); + if (parent != null) + dic.Put(PdfName.PARENT, parent); + dic.Put(PdfName.T, new PdfString(name, PdfObject.TEXT_UNICODE)); + String fname2 = fname + "." + name; + int coidx = calculationOrder.IndexOf(fname2); + if (coidx >= 0) + calculationOrderRefs[coidx] = ind; + if (obj is Hashtable) { + dic.Put(PdfName.KIDS, BranchForm((Hashtable)obj, ind, fname2)); + arr.Add(ind); + AddToBody(dic, ind); + } + else { + ArrayList list = (ArrayList)obj; + dic.MergeDifferent((PdfDictionary)list[0]); + if (list.Count == 3) { + dic.MergeDifferent((PdfDictionary)list[2]); + int page = (int)list[1]; + PdfDictionary pageDic = (PdfDictionary)pageDics[page - 1]; + PdfArray annots = (PdfArray)PdfReader.GetPdfObject(pageDic.Get(PdfName.ANNOTS)); + if (annots == null) { + annots = new PdfArray(); + pageDic.Put(PdfName.ANNOTS, annots); + } + PdfNumber nn = (PdfNumber)dic.Get(iTextTag); + dic.Remove(iTextTag); + AdjustTabOrder(annots, ind, nn); + } + else { + PdfArray kids = new PdfArray(); + for (int k = 1; k < list.Count; k += 2) { + int page = (int)list[k]; + PdfDictionary pageDic = (PdfDictionary)pageDics[page - 1]; + PdfArray annots = (PdfArray)PdfReader.GetPdfObject(pageDic.Get(PdfName.ANNOTS)); + if (annots == null) { + annots = new PdfArray(); + pageDic.Put(PdfName.ANNOTS, annots); + } + PdfDictionary widget = new PdfDictionary(); + widget.Merge((PdfDictionary)list[k + 1]); + widget.Put(PdfName.PARENT, ind); + PdfNumber nn = (PdfNumber)widget.Get(iTextTag); + widget.Remove(iTextTag); + PdfIndirectReference wref = AddToBody(widget).IndirectReference; + AdjustTabOrder(annots, wref, nn); + kids.Add(wref); + Propagate(widget, null, false); + } + dic.Put(PdfName.KIDS, kids); + } + arr.Add(ind); + AddToBody(dic, ind); + Propagate(dic, null, false); + } + } + return arr; + } + + protected void CreateAcroForms() { + if (fieldTree.Count == 0) + return; + form = new PdfDictionary(); + form.Put(PdfName.DR, resources); + Propagate(resources, null, false); + form.Put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g ")); + tabOrder = new Hashtable(); + calculationOrderRefs = new ArrayList(calculationOrder); + form.Put(PdfName.FIELDS, BranchForm(fieldTree, null, "")); + PdfArray co = new PdfArray(); + for (int k = 0; k < calculationOrderRefs.Count; ++k) { + Object obj = calculationOrderRefs[k]; + if (obj is PdfIndirectReference) + co.Add((PdfIndirectReference)obj); + } + if (co.Size > 0) + form.Put(PdfName.CO, co); + } + + public override void Close() { + if (closing) { + base.Close(); + return; + } + closing = true; + CloseIt(); + } + + protected void CloseIt() { + for (int k = 0; k < readers.Count; ++k) { + ((PdfReader)readers[k]).RemoveFields(); + } + for (int r = 0; r < readers.Count; ++r) { + PdfReader reader = (PdfReader)readers[r]; + for (int page = 1; page <= reader.NumberOfPages; ++page) { + pageRefs.Add(GetNewReference(reader.GetPageOrigRef(page))); + pageDics.Add(reader.GetPageN(page)); + } + } + MergeFields(); + CreateAcroForms(); + for (int r = 0; r < readers.Count; ++r) { + PdfReader reader = (PdfReader)readers[r]; + for (int page = 1; page <= reader.NumberOfPages; ++page) { + PdfDictionary dic = reader.GetPageN(page); + PdfIndirectReference pageRef = GetNewReference(reader.GetPageOrigRef(page)); + PdfIndirectReference parent = root.AddPageRef(pageRef); + dic.Put(PdfName.PARENT, parent); + Propagate(dic, pageRef, false); + } + } + foreach (DictionaryEntry entry in readers2intrefs) { + PdfReader reader = (PdfReader)entry.Key; + try { + file = reader.SafeFile; + file.ReOpen(); + IntHashtable t = (IntHashtable)entry.Value; + int[] keys = t.ToOrderedKeys(); + for (int k = 0; k < keys.Length; ++k) { + PRIndirectReference refi = new PRIndirectReference(reader, keys[k]); + AddToBody(PdfReader.GetPdfObjectRelease(refi), t[keys[k]]); + } + } + finally { + try { + file.Close(); + reader.Close(); + } + catch { + // empty on purpose + } + } + } + pdf.Close(); + } + + internal void AddPageOffsetToField(Hashtable fd, int pageOffset) { + if (pageOffset == 0) + return; + foreach (AcroFields.Item item in fd.Values) { + ArrayList page = item.page; + for (int k = 0; k < page.Count; ++k) + page[k] = (int)page[k] + pageOffset; + } + } + + internal void CreateWidgets(ArrayList list, AcroFields.Item item) { + for (int k = 0; k < item.merged.Count; ++k) { + list.Add(item.page[k]); + PdfDictionary merged = (PdfDictionary)item.merged[k]; + PdfObject dr = merged.Get(PdfName.DR); + if (dr != null) + PdfFormField.MergeResources(resources, (PdfDictionary)PdfReader.GetPdfObject(dr)); + PdfDictionary widget = new PdfDictionary(); + foreach (PdfName key in merged.Keys) { + if (widgetKeys.ContainsKey(key)) + widget.Put(key, merged.Get(key)); + } + widget.Put(iTextTag, new PdfNumber((int)item.tabOrder[k] + 1)); + list.Add(widget); + } + } + + internal void MergeField(String name, AcroFields.Item item) { + Hashtable map = fieldTree; + StringTokenizer tk = new StringTokenizer(name, "."); + if (!tk.HasMoreTokens()) + return; + while (true) { + String s = tk.NextToken(); + Object obj = map[s]; + if (tk.HasMoreTokens()) { + if (obj == null) { + obj = new Hashtable(); + map[s] = obj; + map = (Hashtable)obj; + continue; + } + else if (obj is Hashtable) + map = (Hashtable)obj; + else + return; + } + else { + if (obj is Hashtable) + return; + PdfDictionary merged = (PdfDictionary)item.merged[0]; + if (obj == null) { + PdfDictionary field = new PdfDictionary(); + foreach (PdfName key in merged.Keys) { + if (fieldKeys.ContainsKey(key)) + field.Put(key, merged.Get(key)); + } + ArrayList list = new ArrayList(); + list.Add(field); + CreateWidgets(list, item); + map[s] = list; + } + else { + ArrayList list = (ArrayList)obj; + PdfDictionary field = (PdfDictionary)list[0]; + PdfName type1 = (PdfName)field.Get(PdfName.FT); + PdfName type2 = (PdfName)merged.Get(PdfName.FT); + if (type1 == null || !type1.Equals(type2)) + return; + int flag1 = 0; + PdfObject f1 = field.Get(PdfName.FF); + if (f1 != null && f1.IsNumber()) + flag1 = ((PdfNumber)f1).IntValue; + int flag2 = 0; + PdfObject f2 = merged.Get(PdfName.FF); + if (f2 != null && f2.IsNumber()) + flag2 = ((PdfNumber)f2).IntValue; + if (type1.Equals(PdfName.BTN)) { + if (((flag1 ^ flag2) & PdfFormField.FF_PUSHBUTTON) != 0) + return; + if ((flag1 & PdfFormField.FF_PUSHBUTTON) == 0 && ((flag1 ^ flag2) & PdfFormField.FF_RADIO) != 0) + return; + } + else if (type1.Equals(PdfName.CH)) { + if (((flag1 ^ flag2) & PdfFormField.FF_COMBO) != 0) + return; + } + CreateWidgets(list, item); + } + return; + } + } + } + + internal void MergeWithMaster(Hashtable fd) { + foreach (DictionaryEntry entry in fd) { + String name = (String)entry.Key; + MergeField(name, (AcroFields.Item)entry.Value); + } + } + + internal void MergeFields() { + int pageOffset = 0; + for (int k = 0; k < fields.Count; ++k) { + Hashtable fd = ((AcroFields)fields[k]).Fields; + AddPageOffsetToField(fd, pageOffset); + MergeWithMaster(fd); + pageOffset += ((PdfReader)readers[k]).NumberOfPages; + } + } + + public override PdfIndirectReference GetPageReference(int page) { + return (PdfIndirectReference)pageRefs[page - 1]; + } + + protected override PdfDictionary GetCatalog(PdfIndirectReference rootObj) { + PdfDictionary cat = pdf.GetCatalog(rootObj); + if (form != null) { + PdfIndirectReference refi = AddToBody(form).IndirectReference; + cat.Put(PdfName.ACROFORM, refi); + } + WriteOutlines(cat, false); + return cat; + } + + protected PdfIndirectReference GetNewReference(PRIndirectReference refi) { + return new PdfIndirectReference(0, GetNewObjectNumber(refi.Reader, refi.Number, 0)); + } + + protected internal override int GetNewObjectNumber(PdfReader reader, int number, int generation) { + IntHashtable refs = (IntHashtable)readers2intrefs[reader]; + int n = refs[number]; + if (n == 0) { + n = IndirectReferenceNumber; + refs[number] = n; + } + return n; + } + + protected bool IsVisited(PdfReader reader, int number, int generation) { + IntHashtable refs = (IntHashtable)readers2intrefs[reader]; + return refs.ContainsKey(number); + } + + protected bool IsVisited(PRIndirectReference refi) { + IntHashtable refs = (IntHashtable)visited[refi.Reader]; + return refs.ContainsKey(refi.Number); + } + + protected bool SetVisited(PRIndirectReference refi) { + IntHashtable refs = (IntHashtable)visited[refi.Reader]; + int old = refs[refi.Number]; + refs[refi.Number] = 1; + return (old != 0); + } + + protected bool IsPage(PRIndirectReference refi) { + IntHashtable refs = (IntHashtable)pages2intrefs[refi.Reader] ; + return refs.ContainsKey(refi.Number); + } + + internal override RandomAccessFileOrArray GetReaderFile(PdfReader reader) { + return file; + } + + public void OpenDoc() { + if (!nd.IsOpen()) + nd.Open(); + } + + protected internal static Hashtable widgetKeys = new Hashtable(); + protected internal static Hashtable fieldKeys = new Hashtable(); + static PdfCopyFieldsImp() { + object one = 1; + widgetKeys[PdfName.SUBTYPE] = one; + widgetKeys[PdfName.CONTENTS] = one; + widgetKeys[PdfName.RECT] = one; + widgetKeys[PdfName.NM] = one; + widgetKeys[PdfName.M] = one; + widgetKeys[PdfName.F] = one; + widgetKeys[PdfName.BS] = one; + widgetKeys[PdfName.BORDER] = one; + widgetKeys[PdfName.AP] = one; + widgetKeys[PdfName.AS] = one; + widgetKeys[PdfName.C] = one; + widgetKeys[PdfName.A] = one; + widgetKeys[PdfName.STRUCTPARENT] = one; + widgetKeys[PdfName.OC] = one; + widgetKeys[PdfName.H] = one; + widgetKeys[PdfName.MK] = one; + widgetKeys[PdfName.DA] = one; + widgetKeys[PdfName.Q] = one; + fieldKeys[PdfName.AA] = one; + fieldKeys[PdfName.FT] = one; + fieldKeys[PdfName.TU] = one; + fieldKeys[PdfName.TM] = one; + fieldKeys[PdfName.FF] = one; + fieldKeys[PdfName.V] = one; + fieldKeys[PdfName.DV] = one; + fieldKeys[PdfName.DS] = one; + fieldKeys[PdfName.RV] = one; + fieldKeys[PdfName.OPT] = one; + fieldKeys[PdfName.MAXLEN] = one; + fieldKeys[PdfName.TI] = one; + fieldKeys[PdfName.I] = one; + fieldKeys[PdfName.LOCK] = one; + fieldKeys[PdfName.SV] = one; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfDashPattern.cs b/iTechSharp/iTextSharp/text/pdf/PdfDashPattern.cs new file mode 100644 index 0000000..386b3d6 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfDashPattern.cs @@ -0,0 +1,142 @@ +using System; +using System.IO; + +using iTextSharp.text; + +/* + * $Id: PdfDashPattern.cs,v 1.3 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfDashPattern defines a dash pattern as described in + * the PDF Reference Manual version 1.3 p 325 (section 8.4.3). + * + * @see PdfArray + */ + + public class PdfDashPattern : PdfArray { + + // membervariables + + /** This is the length of a dash. */ + private float dash = -1; + + /** This is the length of a gap. */ + private float gap = -1; + + /** This is the phase. */ + private float phase = -1; + + // constructors + + /** + * Constructs a new PdfDashPattern. + */ + + public PdfDashPattern() : base() {} + + /** + * Constructs a new PdfDashPattern. + */ + + public PdfDashPattern(float dash) : base(new PdfNumber(dash)) { + this.dash = dash; + } + + /** + * Constructs a new PdfDashPattern. + */ + + public PdfDashPattern(float dash, float gap) : base(new PdfNumber(dash)) { + Add(new PdfNumber(gap)); + this.dash = dash; + this.gap = gap; + } + + /** + * Constructs a new PdfDashPattern. + */ + + public PdfDashPattern(float dash, float gap, float phase) : base(new PdfNumber(dash)) { + Add(new PdfNumber(gap)); + this.dash = dash; + this.gap = gap; + this.phase = phase; + } + + public void Add(float n) { + Add(new PdfNumber(n)); + } + + /** + * Returns the PDF representation of this PdfArray. + * + * @return an array of bytes + */ + + public override void ToPdf(PdfWriter writer, Stream os) { + os.WriteByte((byte)'['); + + if (dash >= 0) { + new PdfNumber(dash).ToPdf(writer, os); + if (gap >= 0) { + os.WriteByte((byte)' '); + new PdfNumber(gap).ToPdf(writer, os); + } + } + os.WriteByte((byte)']'); + if (phase >=0) { + os.WriteByte((byte)' '); + new PdfNumber(phase).ToPdf(writer, os); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfDate.cs b/iTechSharp/iTextSharp/text/pdf/PdfDate.cs new file mode 100644 index 0000000..b189a51 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfDate.cs @@ -0,0 +1,215 @@ +using System; +using System.Text; +using System.Globalization; + +/* + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfDate is the PDF date object. + *

    + * PDF defines a standard date format. The PDF date format closely follows the format + * defined by the international standard ASN.1 (Abstract Syntax Notation One, defined + * in CCITT X.208 or ISO/IEC 8824). A date is a PdfString of the form: + *

    + * (D:YYYYMMDDHHmmSSOHH'mm') + *

    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 7.2 (page 183-184) + * + * @see PdfString + * @see java.util.GregorianCalendar + */ + + public class PdfDate : PdfString { + + // constructors + + /** + * Constructs a PdfDate-object. + * + * @param d the date that has to be turned into a PdfDate-object + */ + + public PdfDate(DateTime d) : base() { + //d = d.ToUniversalTime(); + + value = d.ToString("\\D\\:yyyyMMddHHmmss", DateTimeFormatInfo.InvariantInfo); + string timezone = d.ToString("zzz", DateTimeFormatInfo.InvariantInfo); + timezone = timezone.Replace(":", "'"); + value += timezone + "'"; + } + + /** + * Constructs a PdfDate-object, representing the current day and time. + */ + + public PdfDate() : this(DateTime.Now) {} + + /** + * Adds a number of leading zeros to a given string in order to get a string + * of a certain length. + * + * @param i a given number + * @param length the length of the resulting string + * @return the resulting string + */ + + private static String SetLength(int i, int length) { + return i.ToString().PadLeft(length, '0'); + } + + /** + * Gives the W3C format of the PdfDate. + * @return a formatted date + */ + public String GetW3CDate() { + return GetW3CDate(value); + } + + /** + * Gives the W3C format of the PdfDate. + * @param d the date in the format D:YYYYMMDDHHmmSSOHH'mm' + * @return a formatted date + */ + public static String GetW3CDate(String d) { + if (d.StartsWith("D:")) + d = d.Substring(2); + StringBuilder sb = new StringBuilder(); + if (d.Length < 4) + return "0000"; + sb.Append(d.Substring(0, 4)); //year + d = d.Substring(4); + if (d.Length < 2) + return sb.ToString(); + sb.Append('-').Append(d.Substring(0, 2)); //month + d = d.Substring(2); + if (d.Length < 2) + return sb.ToString(); + sb.Append('-').Append(d.Substring(0, 2)); //day + d = d.Substring(2); + if (d.Length < 2) + return sb.ToString(); + sb.Append('T').Append(d.Substring(0, 2)); //hour + d = d.Substring(2); + if (d.Length < 2) { + sb.Append(":00Z"); + return sb.ToString(); + } + sb.Append(':').Append(d.Substring(0, 2)); //minute + d = d.Substring(2); + if (d.Length < 2) { + sb.Append('Z'); + return sb.ToString(); + } + sb.Append(':').Append(d.Substring(0, 2)); //second + d = d.Substring(2); + if (d.StartsWith("-") || d.StartsWith("+")) { + String sign = d.Substring(0, 1); + d = d.Substring(1); + String h = "00"; + String m = "00"; + if (d.Length >= 2) { + h = d.Substring(0, 2); + if (d.Length > 2) { + d = d.Substring(3); + if (d.Length >= 2) + m = d.Substring(0, 2); + } + sb.Append(sign).Append(h).Append(':').Append(m); + return sb.ToString(); + } + } + sb.Append('Z'); + return sb.ToString(); + } + + public static DateTime Decode(string date) { + if (date.StartsWith("D:")) + date = date.Substring(2); + int year, month = 1, day = 1, hour = 0, minute = 0, second = 0; + int offsetHour = 0, offsetMinute = 0; + char variation = '\0'; + year = int.Parse(date.Substring(0, 4)); + if (date.Length >= 6) { + month = int.Parse(date.Substring(4, 2)); + if (date.Length >= 8) { + day = int.Parse(date.Substring(6, 2)); + if (date.Length >= 10) { + hour = int.Parse(date.Substring(8, 2)); + if (date.Length >= 12) { + minute = int.Parse(date.Substring(10, 2)); + if (date.Length >= 14) { + second = int.Parse(date.Substring(12, 2)); + } + } + } + } + } + DateTime d = new DateTime(year, month, day, hour, minute, second); + if (date.Length <= 14) + return d; + variation = date[14]; + if (variation == 'Z') + return d.ToLocalTime(); + if (date.Length >= 17) { + offsetHour = int.Parse(date.Substring(15, 2)); + if (date.Length >= 20) { + offsetMinute = int.Parse(date.Substring(18, 2)); + } + } + TimeSpan span = new TimeSpan(offsetHour, offsetMinute, 0); + if (variation == '-') + d += span; + else + d -= span; + return d.ToLocalTime(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfDestination.cs b/iTechSharp/iTextSharp/text/pdf/PdfDestination.cs new file mode 100644 index 0000000..db36a53 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfDestination.cs @@ -0,0 +1,221 @@ +using System; + +/* + * $Id: PdfDestination.cs,v 1.3 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfColor defines a Color (it's a PdfArray containing 3 values). + * + * @see PdfDictionary + */ + + public class PdfDestination : PdfArray { + + // public static member-variables + + /** This is a possible destination type */ + public const int XYZ = 0; + + /** This is a possible destination type */ + public const int FIT = 1; + + /** This is a possible destination type */ + public const int FITH = 2; + + /** This is a possible destination type */ + public const int FITV = 3; + + /** This is a possible destination type */ + public const int FITR = 4; + + /** This is a possible destination type */ + public const int FITB = 5; + + /** This is a possible destination type */ + public const int FITBH = 6; + + /** This is a possible destination type */ + public const int FITBV = 7; + + // member variables + + /** Is the indirect reference to a page already added? */ + private bool status = false; + + // constructors + + /** + * Constructs a new PdfDestination. + *

    + * If type equals FITB, the bounding box of a page + * will fit the window of the Reader. Otherwise the type will be set to + * FIT so that the entire page will fit to the window. + * + * @param type The destination type + */ + + public PdfDestination(int type) : base() { + if (type == FITB) { + Add(PdfName.FITB); + } + else { + Add(PdfName.FIT); + } + } + + /** + * Constructs a new PdfDestination. + *

    + * If type equals FITBH / FITBV, + * the width / height of the bounding box of a page will fit the window + * of the Reader. The parameter will specify the y / x coordinate of the + * top / left edge of the window. If the type equals FITH + * or FITV the width / height of the entire page will fit + * the window and the parameter will specify the y / x coordinate of the + * top / left edge. In all other cases the type will be set to FITH. + * + * @param type the destination type + * @param parameter a parameter to combined with the destination type + */ + + public PdfDestination(int type, float parameter) : base(new PdfNumber(parameter)) { + switch (type) { + default: + AddFirst(PdfName.FITH); + break; + case FITV: + AddFirst(PdfName.FITV); + break; + case FITBH: + AddFirst(PdfName.FITBH); + break; + case FITBV: + AddFirst(PdfName.FITBV); + break; + } + } + + /** Constructs a new PdfDestination. + *

    + * Display the page, with the coordinates (left, top) positioned + * at the top-left corner of the window and the contents of the page magnified + * by the factor zoom. A negative value for any of the parameters left or top, or a + * zoom value of 0 specifies that the current value of that parameter is to be retained unchanged. + * @param type must be a PdfDestination.XYZ + * @param left the left value. Negative to place a null + * @param top the top value. Negative to place a null + * @param zoom The zoom factor. A value of 0 keeps the current value + */ + + public PdfDestination(int type, float left, float top, float zoom) : base(PdfName.XYZ) { + if (left < 0) + Add(PdfNull.PDFNULL); + else + Add(new PdfNumber(left)); + if (top < 0) + Add(PdfNull.PDFNULL); + else + Add(new PdfNumber(top)); + Add(new PdfNumber(zoom)); + } + + /** Constructs a new PdfDestination. + *

    + * Display the page, with its contents magnified just enough + * to fit the rectangle specified by the coordinates left, bottom, right, and top + * entirely within the window both horizontally and vertically. If the required + * horizontal and vertical magnification factors are different, use the smaller of + * the two, centering the rectangle within the window in the other dimension. + * + * @param type must be PdfDestination.FITR + * @param left a parameter + * @param bottom a parameter + * @param right a parameter + * @param top a parameter + * @since iText0.38 + */ + + public PdfDestination(int type, float left, float bottom, float right, float top) : base(PdfName.FITR) { + Add(new PdfNumber(left)); + Add(new PdfNumber(bottom)); + Add(new PdfNumber(right)); + Add(new PdfNumber(top)); + } + + // methods + + /** + * Checks if an indirect reference to a page has been added. + * + * @return true or false + */ + + public bool HasPage() { + return status; + } + + /** Adds the indirect reference of the destination page. + * + * @param page an indirect reference + * @return true if the page reference was added + */ + + public bool AddPage(PdfIndirectReference page) { + if (!status) { + AddFirst(page); + status = true; + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfDictionary.cs b/iTechSharp/iTextSharp/text/pdf/PdfDictionary.cs new file mode 100644 index 0000000..a43b1c9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfDictionary.cs @@ -0,0 +1,375 @@ +using System; +using System.IO; +using System.Collections; + +/* + * $Id: PdfDictionary.cs,v 1.10 2008/05/13 11:25:19 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfDictionary is the Pdf dictionary object. + *

    + * A dictionary is an associative table containing pairs of objects. The first element + * of each pair is called the key and the second element is called the value. + * Unlike dictionaries in the PostScript language, a key must be a PdfName. + * A value can be any kind of PdfObject, including a dictionary. A dictionary is + * generally used to collect and tie together the attributes of a complex object, with each + * key-value pair specifying the name and value of an attribute.
    + * A dictionary is represented by two left angle brackets (<<), followed by a sequence of + * key-value pairs, followed by two right angle brackets (>>).
    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.7 (page 40-41). + *

    + * + * @see PdfObject + * @see PdfName + * @see BadPdfFormatException + */ + + public class PdfDictionary : PdfObject { + + // static membervariables (types of dictionary's) + + /** This is a possible type of dictionary */ + public static PdfName FONT = PdfName.FONT; + + /** This is a possible type of dictionary */ + public static PdfName OUTLINES = PdfName.OUTLINES; + + /** This is a possible type of dictionary */ + public static PdfName PAGE = PdfName.PAGE; + + /** This is a possible type of dictionary */ + public static PdfName PAGES = PdfName.PAGES; + + /** This is a possible type of dictionary */ + public static PdfName CATALOG = PdfName.CATALOG; + + // membervariables + + /** This is the type of this dictionary */ + private PdfName dictionaryType = null; + + /** This is the hashmap that contains all the values and keys of the dictionary */ + protected internal Hashtable hashMap; + + // constructors + + /** + * Constructs an empty PdfDictionary-object. + */ + + public PdfDictionary() : base(DICTIONARY) { + hashMap = new Hashtable(); + } + + /** + * Constructs a PdfDictionary-object of a certain type. + * + * @param type a PdfName + */ + + public PdfDictionary(PdfName type) : this() { + dictionaryType = type; + Put(PdfName.TYPE, dictionaryType); + } + + // methods overriding some methods in PdfObject + + /** + * Returns the PDF representation of this PdfDictionary. + * + * @return an array of byte + */ + public override void ToPdf(PdfWriter writer, Stream os) { + os.WriteByte((byte)'<'); + os.WriteByte((byte)'<'); + + // loop over all the object-pairs in the Hashtable + PdfObject value; + foreach (PdfName key in hashMap.Keys) { + value = (PdfObject) hashMap[key]; + key.ToPdf(writer, os); + int type = value.Type; + if (type != PdfObject.ARRAY && type != PdfObject.DICTIONARY && type != PdfObject.NAME && type != PdfObject.STRING) + os.WriteByte((byte)' '); + value.ToPdf(writer, os); + } + os.WriteByte((byte)'>'); + os.WriteByte((byte)'>'); + } + + + // methods concerning the Hashtable member value + + /** + * Adds a PdfObject and its key to the PdfDictionary. + * If the value is null or PdfNull the key is deleted. + * + * @param key key of the entry (a PdfName) + * @param value value of the entry (a PdfObject) + */ + + public void Put(PdfName key, PdfObject value) { + if (value == null || value.IsNull()) + hashMap.Remove(key); + else + hashMap[key] = value; + } + + /** + * Adds a PdfObject and its key to the PdfDictionary. + * If the value is null it does nothing. + * + * @param key key of the entry (a PdfName) + * @param value value of the entry (a PdfObject) + */ + public void PutEx(PdfName key, PdfObject value) { + if (value == null) + return; + Put(key, value); + } + + /** + * Removes a PdfObject and its key from the PdfDictionary. + * + * @param key key of the entry (a PdfName) + */ + + public void Remove(PdfName key) { + hashMap.Remove(key); + } + + /** + * Gets a PdfObject with a certain key from the PdfDictionary. + * + * @param key key of the entry (a PdfName) + * @return the previous PdfObject corresponding with the key + */ + + public PdfObject Get(PdfName key) { + return (PdfObject) hashMap[key]; + } + + // methods concerning the type of Dictionary + + /** + * Checks if a Dictionary is of the type FONT. + * + * @return true if it is, false if it isn't. + */ + + public bool IsFont() { + return FONT.Equals(dictionaryType); + } + + /** + * Checks if a Dictionary is of the type PAGE. + * + * @return true if it is, false if it isn't. + */ + + public bool IsPage() { + return PAGE.Equals(dictionaryType); + } + + /** + * Checks if a Dictionary is of the type PAGES. + * + * @return true if it is, false if it isn't. + */ + + public bool IsPages() { + return PAGES.Equals(dictionaryType); + } + + /** + * Checks if a Dictionary is of the type CATALOG. + * + * @return true if it is, false if it isn't. + */ + + public bool IsCatalog() { + return CATALOG.Equals(dictionaryType); + } + + /** + * Checks if a Dictionary is of the type OUTLINES. + * + * @return true if it is, false if it isn't. + */ + + public bool IsOutlineTree() { + return OUTLINES.Equals(dictionaryType); + } + + public void Merge(PdfDictionary other) { + foreach (object key in other.hashMap.Keys) { + hashMap[key] = other.hashMap[key]; + } + } + + public void MergeDifferent(PdfDictionary other) { + foreach (Object key in other.hashMap.Keys) { + if (!hashMap.ContainsKey(key)) { + hashMap[key] = other.hashMap[key]; + } + } + } + + public ICollection Keys { + get { + return hashMap.Keys; + } + } + + public int Size { + get { + return hashMap.Count; + } + } + + public bool Contains(PdfName key) { + return hashMap.ContainsKey(key); + } + + public virtual IDictionaryEnumerator GetEnumerator() { + return hashMap.GetEnumerator(); + } + + public override String ToString() { + if (Get(PdfName.TYPE) == null) return "Dictionary"; + return "Dictionary of type: " + Get(PdfName.TYPE); + } + + /** + * This function behaves the same as 'get', but will never return an indirect reference, + * it will always look such references up and return the actual object. + * @param key + * @return null, or a non-indirect object + */ + public PdfObject GetDirectObject(PdfName key) { + return PdfReader.GetPdfObject(Get(key)); + } + + /** + * All the getAs functions will return either null, or the specified object type + * This function will automatically look up indirect references. There's one obvious + * exception, the one that will only return an indirect reference. All direct objects + * come back as a null. + * Mark A Storer (2/17/06) + * @param key + * @return the appropriate object in its final type, or null + */ + public PdfDictionary GetAsDict(PdfName key) { + PdfDictionary dict = null; + PdfObject orig = GetDirectObject(key); + if (orig != null && orig.IsDictionary()) + dict = (PdfDictionary) orig; + return dict; + } + + public PdfArray GetAsArray(PdfName key) { + PdfArray array = null; + PdfObject orig = GetDirectObject(key); + if (orig != null && orig.IsArray()) + array = (PdfArray) orig; + return array; + } + + public PdfStream GetAsStream(PdfName key) { + PdfStream stream = null; + PdfObject orig = GetDirectObject(key); + if (orig != null && orig.IsStream()) + stream = (PdfStream) orig; + return stream; + } + + public PdfString GetAsString(PdfName key) { + PdfString str = null; + PdfObject orig = GetDirectObject(key); + if (orig != null && orig.IsString()) + str = (PdfString) orig; + return str; + } + + public PdfNumber GetAsNumber(PdfName key) { + PdfNumber number = null; + PdfObject orig = GetDirectObject(key); + if (orig != null && orig.IsNumber()) + number = (PdfNumber) orig; + return number; + } + + public PdfName GetAsName(PdfName key) { + PdfName name = null; + PdfObject orig = GetDirectObject(key); + if (orig != null && orig.IsName()) + name = (PdfName) orig; + return name; + } + + public PdfBoolean GetAsBoolean(PdfName key) { + PdfBoolean b = null; + PdfObject orig = GetDirectObject(key); + if (orig != null && orig.IsBoolean()) + b = (PdfBoolean)orig; + return b; + } + + public PdfIndirectReference GetAsIndirectObject( PdfName key ) { + PdfIndirectReference refi = null; + PdfObject orig = Get(key); // not getDirect this time. + if (orig != null && orig.IsIndirect()) + refi = (PdfIndirectReference) orig; + return refi; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfDocument.cs b/iTechSharp/iTextSharp/text/pdf/PdfDocument.cs new file mode 100644 index 0000000..434eaaa --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfDocument.cs @@ -0,0 +1,2987 @@ +using System; +using System.Collections; +using System.IO; +using System.util.collections; +using iTextSharp.text; +using iTextSharp.text.pdf.intern; +using iTextSharp.text.pdf.draw; +using iTextSharp.text.pdf.collection; +using System.util; +/* + * + * $Id: PdfDocument.cs,v 1.75 2008/05/13 11:25:19 psoares33 Exp $ + * + * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfDocument is the class that is used by PdfWriter + * to translate a Document into a PDF with different pages. + *

    + * A PdfDocument always listens to a Document + * and adds the Pdf representation of every Element that is + * added to the Document. + * + * @see com.lowagie.text.Document + * @see com.lowagie.text.DocListener + * @see PdfWriter + */ + + public class PdfDocument : Document { + + /** + * PdfInfo is the PDF InfoDictionary. + *

    + * A document's trailer may contain a reference to an Info dictionary that provides information + * about the document. This optional dictionary may contain one or more keys, whose values + * should be strings.
    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 6.10 (page 120-121) + */ + + public class PdfInfo : PdfDictionary { + + // constructors + + /** + * Construct a PdfInfo-object. + */ + + internal PdfInfo() { + AddProducer(); + AddCreationDate(); + } + + /** + * Constructs a PdfInfo-object. + * + * @param author name of the author of the document + * @param title title of the document + * @param subject subject of the document + */ + + internal PdfInfo(String author, String title, String subject) : base() { + AddTitle(title); + AddSubject(subject); + AddAuthor(author); + } + + /** + * Adds the title of the document. + * + * @param title the title of the document + */ + + internal void AddTitle(String title) { + Put(PdfName.TITLE, new PdfString(title, PdfObject.TEXT_UNICODE)); + } + + /** + * Adds the subject to the document. + * + * @param subject the subject of the document + */ + + internal void AddSubject(String subject) { + Put(PdfName.SUBJECT, new PdfString(subject, PdfObject.TEXT_UNICODE)); + } + + /** + * Adds some keywords to the document. + * + * @param keywords the keywords of the document + */ + + internal void AddKeywords(String keywords) { + Put(PdfName.KEYWORDS, new PdfString(keywords, PdfObject.TEXT_UNICODE)); + } + + /** + * Adds the name of the author to the document. + * + * @param author the name of the author + */ + + internal void AddAuthor(String author) { + Put(PdfName.AUTHOR, new PdfString(author, PdfObject.TEXT_UNICODE)); + } + + /** + * Adds the name of the creator to the document. + * + * @param creator the name of the creator + */ + + internal void AddCreator(String creator) { + Put(PdfName.CREATOR, new PdfString(creator, PdfObject.TEXT_UNICODE)); + } + + /** + * Adds the name of the producer to the document. + */ + + internal void AddProducer() { + // This line may only be changed by Bruno Lowagie or Paulo Soares + Put(PdfName.PRODUCER, new PdfString(Version)); + // Do not edit the line above! + } + + /** + * Adds the date of creation to the document. + */ + + internal void AddCreationDate() { + PdfString date = new PdfDate(); + Put(PdfName.CREATIONDATE, date); + Put(PdfName.MODDATE, date); + } + + internal void Addkey(String key, String value) { + if (key.Equals("Producer") || key.Equals("CreationDate")) + return; + Put(new PdfName(key), new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + /** + * PdfCatalog is the PDF Catalog-object. + *

    + * The Catalog is a dictionary that is the root node of the document. It contains a reference + * to the tree of pages contained in the document, a reference to the tree of objects representing + * the document's outline, a reference to the document's article threads, and the list of named + * destinations. In addition, the Catalog indicates whether the document's outline or thumbnail + * page images should be displayed automatically when the document is viewed and wether some location + * other than the first page should be shown when the document is opened.
    + * In this class however, only the reference to the tree of pages is implemented.
    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 6.2 (page 67-71) + */ + + internal class PdfCatalog : PdfDictionary { + + internal PdfWriter writer; + // constructors + + /** + * Constructs a PdfCatalog. + * + * @param pages an indirect reference to the root of the document's Pages tree. + * @param writer the writer the catalog applies to + */ + + internal PdfCatalog(PdfIndirectReference pages, PdfWriter writer) : base(CATALOG) { + this.writer = writer; + Put(PdfName.PAGES, pages); + } + + /** + * Adds the names of the named destinations to the catalog. + * @param localDestinations the local destinations + * @param documentJavaScript the javascript used in the document + * @param writer the writer the catalog applies to + */ + internal void AddNames(k_Tree localDestinations, Hashtable documentLevelJS, Hashtable documentFileAttachment, PdfWriter writer) { + if (localDestinations.Count == 0 && documentLevelJS.Count == 0 && documentFileAttachment.Count == 0) + return; + PdfDictionary names = new PdfDictionary(); + if (localDestinations.Count > 0) { + PdfArray ar = new PdfArray(); + foreach (DictionaryEntry entry in localDestinations) { + String name = (String)entry.Key; + Object[] obj = (Object[])entry.Value; + PdfIndirectReference refi = (PdfIndirectReference)obj[1]; + ar.Add(new PdfString(name, null)); + ar.Add(refi); + } + PdfDictionary dests = new PdfDictionary(); + dests.Put(PdfName.NAMES, ar); + names.Put(PdfName.DESTS, writer.AddToBody(dests).IndirectReference); + } + if (documentLevelJS.Count > 0) { + PdfDictionary tree = PdfNameTree.WriteTree(documentLevelJS, writer); + names.Put(PdfName.JAVASCRIPT, writer.AddToBody(tree).IndirectReference); + } + if (documentFileAttachment.Count > 0) { + names.Put(PdfName.EMBEDDEDFILES, writer.AddToBody(PdfNameTree.WriteTree(documentFileAttachment, writer)).IndirectReference); + } + Put(PdfName.NAMES, writer.AddToBody(names).IndirectReference); + } + + internal PdfAction OpenAction { + set { + Put(PdfName.OPENACTION, value); + } + } + + + /** Sets the document level additional actions. + * @param actions dictionary of actions + */ + internal PdfDictionary AdditionalActions { + set { + Put(PdfName.AA, writer.AddToBody(value).IndirectReference); + } + } + } + + // CONSTRUCTING A PdfDocument/PdfWriter INSTANCE + + /** + * Constructs a new PDF document. + * @throws DocumentException on error + */ + internal PdfDocument() { + AddProducer(); + AddCreationDate(); + } + + /** The PdfWriter. */ + protected internal PdfWriter writer; + + /** + * Adds a PdfWriter to the PdfDocument. + * + * @param writer the PdfWriter that writes everything + * what is added to this document to an outputstream. + * @throws DocumentException on error + */ + internal void AddWriter(PdfWriter writer) { + if (this.writer == null) { + this.writer = writer; + annotationsImp = new PdfAnnotationsImp(writer); + return; + } + throw new DocumentException("You can only add a writer to a PdfDocument once."); + } + + // LISTENER METHODS START + + // [L0] ElementListener interface + + /** This is the PdfContentByte object, containing the text. */ + protected internal PdfContentByte text; + + /** This is the PdfContentByte object, containing the borders and other Graphics. */ + protected internal PdfContentByte graphics; + + /** This represents the leading of the lines. */ + protected internal float leading = 0; + + /** + * Getter for the current leading. + * @return the current leading + * @since 2.1.2 + */ + public float Leading { + get { + return leading; + } + } + /** This is the current height of the document. */ + protected internal float currentHeight = 0; + + /** + * Signals that onParagraph is valid (to avoid that a Chapter/Section title is treated as a Paragraph). + * @since 2.1.2 + */ + protected bool isSectionTitle = false; + + /** + * Signals that the current leading has to be subtracted from a YMark object. + * @since 2.1.2 + */ + protected int leadingCount = 0; + + /** This represents the current alignment of the PDF Elements. */ + protected internal int alignment = Element.ALIGN_LEFT; + + /** The current active PdfAction when processing an Anchor. */ + protected internal PdfAction anchorAction = null; + + /** + * Signals that an Element was added to the Document. + * + * @param element the element to add + * @return true if the element was added, false if not. + * @throws DocumentException when a document isn't open yet, or has been closed + */ + public override bool Add(IElement element) { + if (writer != null && writer.IsPaused()) { + return false; + } + switch (element.Type) { + + // Information (headers) + case Element.HEADER: + info.Addkey(((Meta)element).Name, ((Meta)element).Content); + break; + case Element.TITLE: + info.AddTitle(((Meta)element).Content); + break; + case Element.SUBJECT: + info.AddSubject(((Meta)element).Content); + break; + case Element.KEYWORDS: + info.AddKeywords(((Meta)element).Content); + break; + case Element.AUTHOR: + info.AddAuthor(((Meta)element).Content); + break; + case Element.CREATOR: + info.AddCreator(((Meta)element).Content); + break; + case Element.PRODUCER: + // you can not change the name of the producer + info.AddProducer(); + break; + case Element.CREATIONDATE: + // you can not set the creation date, only reset it + info.AddCreationDate(); + break; + + // content (text) + case Element.CHUNK: { + // if there isn't a current line available, we make one + if (line == null) { + CarriageReturn(); + } + + // we cast the element to a chunk + PdfChunk chunk = new PdfChunk((Chunk) element, anchorAction); + // we try to add the chunk to the line, until we succeed + { + PdfChunk overflow; + while ((overflow = line.Add(chunk)) != null) { + CarriageReturn(); + chunk = overflow; + chunk.TrimFirstSpace(); + } + } + pageEmpty = false; + if (chunk.IsAttribute(Chunk.NEWPAGE)) { + NewPage(); + } + break; + } + case Element.ANCHOR: { + leadingCount++; + Anchor anchor = (Anchor) element; + String url = anchor.Reference; + leading = anchor.Leading; + if (url != null) { + anchorAction = new PdfAction(url); + } + + // we process the element + element.Process(this); + anchorAction = null; + leadingCount--; + break; + } + case Element.ANNOTATION: { + if (line == null) { + CarriageReturn(); + } + Annotation annot = (Annotation) element; + Rectangle rect = new Rectangle(0, 0); + if (line != null) + rect = new Rectangle(annot.GetLlx(IndentRight - line.WidthLeft), annot.GetLly(IndentTop - currentHeight), annot.GetUrx(IndentRight - line.WidthLeft + 20), annot.GetUry(IndentTop - currentHeight - 20)); + PdfAnnotation an = PdfAnnotationsImp.ConvertAnnotation(writer, annot, rect); + annotationsImp.AddPlainAnnotation(an); + pageEmpty = false; + break; + } + case Element.PHRASE: { + leadingCount++; + // we cast the element to a phrase and set the leading of the document + leading = ((Phrase) element).Leading; + // we process the element + element.Process(this); + leadingCount--; + break; + } + case Element.PARAGRAPH: { + leadingCount++; + // we cast the element to a paragraph + Paragraph paragraph = (Paragraph) element; + + AddSpacing(paragraph.SpacingBefore, leading, paragraph.Font); + + // we adjust the parameters of the document + alignment = paragraph.Alignment; + leading = paragraph.TotalLeading; + + CarriageReturn(); + // we don't want to make orphans/widows + if (currentHeight + line.Height + leading > IndentTop - IndentBottom) { + NewPage(); + } + + indentation.indentLeft += paragraph.IndentationLeft; + indentation.indentRight += paragraph.IndentationRight; + + CarriageReturn(); + + IPdfPageEvent pageEvent = writer.PageEvent; + if (pageEvent != null && !isSectionTitle) + pageEvent.OnParagraph(writer, this, IndentTop - currentHeight); + + // if a paragraph has to be kept together, we wrap it in a table object + if (paragraph.KeepTogether) { + CarriageReturn(); + PdfPTable table = new PdfPTable(1); + table.WidthPercentage = 100f; + PdfPCell cell = new PdfPCell(); + cell.AddElement(paragraph); + cell.Border = Rectangle.NO_BORDER; + cell.Padding = 0; + table.AddCell(cell); + indentation.indentLeft -= paragraph.IndentationLeft; + indentation.indentRight -= paragraph.IndentationRight; + this.Add(table); + indentation.indentLeft += paragraph.IndentationLeft; + indentation.indentRight += paragraph.IndentationRight; + } + else { + line.SetExtraIndent(paragraph.FirstLineIndent); + element.Process(this); + CarriageReturn(); + AddSpacing(paragraph.SpacingAfter, paragraph.TotalLeading, paragraph.Font); + } + + if (pageEvent != null && !isSectionTitle) + pageEvent.OnParagraphEnd(writer, this, IndentTop - currentHeight); + + alignment = Element.ALIGN_LEFT; + indentation.indentLeft -= paragraph.IndentationLeft; + indentation.indentRight -= paragraph.IndentationRight; + CarriageReturn(); + leadingCount--; + break; + } + case Element.SECTION: + case Element.CHAPTER: { + // Chapters and Sections only differ in their constructor + // so we cast both to a Section + Section section = (Section) element; + IPdfPageEvent pageEvent = writer.PageEvent; + + bool hasTitle = section.NotAddedYet && section.Title != null; + + // if the section is a chapter, we begin a new page + if (section.TriggerNewPage) { + NewPage(); + } + + if (hasTitle) { + float fith = IndentTop - currentHeight; + int rotation = pageSize.Rotation; + if (rotation == 90 || rotation == 180) + fith = pageSize.Height - fith; + PdfDestination destination = new PdfDestination(PdfDestination.FITH, fith); + while (currentOutline.Level >= section.Depth) { + currentOutline = currentOutline.Parent; + } + PdfOutline outline = new PdfOutline(currentOutline, destination, section.GetBookmarkTitle(), section.BookmarkOpen); + currentOutline = outline; + } + + // some values are set + CarriageReturn(); + indentation.sectionIndentLeft += section.IndentationLeft; + indentation.sectionIndentRight += section.IndentationRight; + if (section.NotAddedYet && pageEvent != null) + if (element.Type == Element.CHAPTER) + pageEvent.OnChapter(writer, this, IndentTop - currentHeight, section.Title); + else + pageEvent.OnSection(writer, this, IndentTop - currentHeight, section.Depth, section.Title); + + // the title of the section (if any has to be printed) + if (hasTitle) { + isSectionTitle = true; + Add(section.Title); + isSectionTitle = false; + } + indentation.sectionIndentLeft += section.Indentation; + // we process the section + element.Process(this); + // some parameters are set back to normal again + indentation.sectionIndentLeft -= (section.IndentationLeft + section.Indentation); + indentation.sectionIndentRight -= section.IndentationRight; + + if (section.ElementComplete && pageEvent != null) + if (element.Type == Element.CHAPTER) + pageEvent.OnChapterEnd(writer, this, IndentTop - currentHeight); + else + pageEvent.OnSectionEnd(writer, this, IndentTop - currentHeight); + + break; + } + case Element.LIST: { + // we cast the element to a List + List list = (List) element; + if (list.Alignindent) { + list.NormalizeIndentation(); + } + // we adjust the document + indentation.listIndentLeft += list.IndentationLeft; + indentation.indentRight += list.IndentationRight; + // we process the items in the list + element.Process(this); + // some parameters are set back to normal again + indentation.listIndentLeft -= list.IndentationLeft; + indentation.indentRight -= list.IndentationRight; + CarriageReturn(); + break; + } + case Element.LISTITEM: { + leadingCount++; + // we cast the element to a ListItem + ListItem listItem = (ListItem) element; + + AddSpacing(listItem.SpacingBefore, leading, listItem.Font); + + // we adjust the document + alignment = listItem.Alignment; + indentation.listIndentLeft += listItem.IndentationLeft; + indentation.indentRight += listItem.IndentationRight; + leading = listItem.TotalLeading; + CarriageReturn(); + // we prepare the current line to be able to show us the listsymbol + line.ListItem = listItem; + // we process the item + element.Process(this); + + AddSpacing(listItem.SpacingAfter, listItem.TotalLeading, listItem.Font); + + // if the last line is justified, it should be aligned to the left + if (line.HasToBeJustified()) { + line.ResetAlignment(); + } + // some parameters are set back to normal again + CarriageReturn(); + indentation.listIndentLeft -= listItem.IndentationLeft; + indentation.indentRight -= listItem.IndentationRight; + leadingCount--; + break; + } + case Element.RECTANGLE: { + Rectangle rectangle = (Rectangle) element; + graphics.Rectangle(rectangle); + pageEmpty = false; + break; + } + case Element.PTABLE: { + PdfPTable ptable = (PdfPTable)element; + if (ptable.Size <= ptable.HeaderRows) + break; //nothing to do + + // before every table, we add a new line and flush all lines + EnsureNewLine(); + FlushLines(); + + AddPTable(ptable); + pageEmpty = false; + NewLine(); + break; + } + case Element.MULTI_COLUMN_TEXT: { + EnsureNewLine(); + FlushLines(); + MultiColumnText multiText = (MultiColumnText) element; + float height = multiText.Write(writer.DirectContent, this, IndentTop - currentHeight); + currentHeight += height; + text.MoveText(0, -1f* height); + pageEmpty = false; + break; + } + case Element.TABLE : { + if (element is SimpleTable) { + PdfPTable ptable = ((SimpleTable)element).CreatePdfPTable(); + if (ptable.Size <= ptable.HeaderRows) + break; //nothing to do + + // before every table, we add a new line and flush all lines + EnsureNewLine(); + FlushLines(); + AddPTable(ptable); + pageEmpty = false; + break; + } else if (element is Table) { + + try { + PdfPTable ptable = ((Table)element).CreatePdfPTable(); + if (ptable.Size <= ptable.HeaderRows) + break; //nothing to do + + // before every table, we add a new line and flush all lines + EnsureNewLine(); + FlushLines(); + AddPTable(ptable); + pageEmpty = false; + break; + } + catch (BadElementException) { + // constructing the PdfTable + // Before the table, add a blank line using offset or default leading + float offset = ((Table)element).Offset; + if (float.IsNaN(offset)) + offset = leading; + CarriageReturn(); + lines.Add(new PdfLine(IndentLeft, IndentRight, alignment, offset)); + currentHeight += offset; + AddPdfTable((Table)element); + } + } else { + return false; + } + break; + } + case Element.JPEG: + case Element.JPEG2000: + case Element.IMGRAW: + case Element.IMGTEMPLATE: { + //carriageReturn(); suggestion by Marc Campforts + Add((Image) element); + break; + } + case Element.YMARK: { + IDrawInterface zh = (IDrawInterface)element; + zh.Draw(graphics, IndentLeft, IndentBottom, IndentRight, IndentTop, IndentTop - currentHeight - (leadingCount > 0 ? leading : 0)); + pageEmpty = false; + break; + } + case Element.MARKED: { + MarkedObject mo; + if (element is MarkedSection) { + mo = ((MarkedSection)element).Title; + if (mo != null) { + mo.Process(this); + } + } + mo = (MarkedObject)element; + mo.Process(this); + break; + } + default: + return false; + } + lastElementType = element.Type; + return true; + } + + // [L1] DocListener interface + + /** + * Opens the document. + *

    + * You have to open the document before you can begin to add content + * to the body of the document. + */ + public override void Open() { + if (!open) { + base.Open(); + writer.Open(); + rootOutline = new PdfOutline(writer); + currentOutline = rootOutline; + } + InitPage(); + } + + // [L2] DocListener interface + + /** + * Closes the document. + * + * Once all the content has been written in the body, you have to close + * the body. After that nothing can be written to the body anymore. + */ + public override void Close() { + if (close) { + return; + } + bool wasImage = (imageWait != null); + NewPage(); + if (imageWait != null || wasImage) NewPage(); + if (annotationsImp.HasUnusedAnnotations()) + throw new Exception("Not all annotations could be added to the document (the document doesn't have enough pages)."); + IPdfPageEvent pageEvent = writer.PageEvent; + if (pageEvent != null) + pageEvent.OnCloseDocument(writer, this); + base.Close(); + + writer.AddLocalDestinations(localDestinations); + CalculateOutlineCount(); + WriteOutlines(); + + writer.Close(); + } + + // [L3] DocListener interface + + protected internal int textEmptySize; + + // [C9] Metadata for the page + /** XMP Metadata for the page. */ + protected byte[] xmpMetadata = null; + /** + * Use this method to set the XMP Metadata. + * @param xmpMetadata The xmpMetadata to set. + */ + public byte[] XmpMetadata { + set { + xmpMetadata = value; + } + } + + /** + * Makes a new page and sends it to the PdfWriter. + * + * @return a bool + * @throws DocumentException on error + */ + public override bool NewPage() { + lastElementType = -1; + if (writer == null || (writer.DirectContent.Size == 0 && writer.DirectContentUnder.Size == 0 && (pageEmpty || writer.IsPaused()))) { + SetNewPageSizeAndMargins(); + return false; + } + if (!open || close) { + throw new Exception("The document isn't open."); + } + IPdfPageEvent pageEvent = writer.PageEvent; + if (pageEvent != null) + pageEvent.OnEndPage(writer, this); + + //Added to inform any listeners that we are moving to a new page (added by David Freels) + base.NewPage(); + + // the following 2 lines were added by Pelikan Stephan + indentation.imageIndentLeft = 0; + indentation.imageIndentRight = 0; + + // we flush the arraylist with recently written lines + FlushLines(); + // we prepare the elements of the page dictionary + + // [U1] page size and rotation + int rotation = pageSize.Rotation; + + // [C10] + if (writer.IsPdfX()) { + if (thisBoxSize.ContainsKey("art") && thisBoxSize.ContainsKey("trim")) + throw new PdfXConformanceException("Only one of ArtBox or TrimBox can exist in the page."); + if (!thisBoxSize.ContainsKey("art") && !thisBoxSize.ContainsKey("trim")) { + if (thisBoxSize.ContainsKey("crop")) + thisBoxSize["trim"] = thisBoxSize["crop"]; + else + thisBoxSize["trim"] = new PdfRectangle(pageSize, pageSize.Rotation); + } + } + + // [M1] + pageResources.AddDefaultColorDiff(writer.DefaultColorspace); + if (writer.RgbTransparencyBlending) { + PdfDictionary dcs = new PdfDictionary(); + dcs.Put(PdfName.CS, PdfName.DEVICERGB); + pageResources.AddDefaultColorDiff(dcs); + } + PdfDictionary resources = pageResources.Resources; + + // we create the page dictionary + + PdfPage page = new PdfPage(new PdfRectangle(pageSize, rotation), thisBoxSize, resources, rotation); + + // we complete the page dictionary + + // [C9] if there is XMP data to add: add it + if (xmpMetadata != null) { + PdfStream xmp = new PdfStream(xmpMetadata); + xmp.Put(PdfName.TYPE, PdfName.METADATA); + xmp.Put(PdfName.SUBTYPE, PdfName.XML); + PdfEncryption crypto = writer.Encryption; + if (crypto != null && !crypto.IsMetadataEncrypted()) { + PdfArray ar = new PdfArray(); + ar.Add(PdfName.CRYPT); + xmp.Put(PdfName.FILTER, ar); + } + page.Put(PdfName.METADATA, writer.AddToBody(xmp).IndirectReference); + } + + // [U3] page actions: transition, duration, additional actions + if (this.transition!=null) { + page.Put(PdfName.TRANS, this.transition.TransitionDictionary); + transition = null; + } + if (this.duration>0) { + page.Put(PdfName.DUR,new PdfNumber(this.duration)); + duration = 0; + } + if (pageAA != null) { + page.Put(PdfName.AA, writer.AddToBody(pageAA).IndirectReference); + pageAA = null; + } + + // [U4] we add the thumbs + if (thumb != null) { + page.Put(PdfName.THUMB, thumb); + thumb = null; + } + + // [U8] we check if the userunit is defined + if (writer.Userunit > 0f) { + page.Put(PdfName.USERUNIT, new PdfNumber(writer.Userunit)); + } + + // [C5] and [C8] we add the annotations + if (annotationsImp.HasUnusedAnnotations()) { + PdfArray array = annotationsImp.RotateAnnotations(writer, pageSize); + if (array.Size != 0) + page.Put(PdfName.ANNOTS, array); + } + + // [F12] we add tag info + if (writer.IsTagged()) + page.Put(PdfName.STRUCTPARENTS, new PdfNumber(writer.CurrentPageNumber - 1)); + + if (text.Size > textEmptySize) + text.EndText(); + else + text = null; + writer.Add(page, new PdfContents(writer.DirectContentUnder, graphics, text, writer.DirectContent, pageSize)); + // we initialize the new page + InitPage(); + return true; + } + + // [L4] DocListener interface + + /** + * Sets the pagesize. + * + * @param pageSize the new pagesize + * @return true if the page size was set + */ + public override bool SetPageSize(Rectangle pageSize) { + if (writer != null && writer.IsPaused()) { + return false; + } + nextPageSize = new Rectangle(pageSize); + return true; + } + + + /** margin in x direction starting from the left. Will be valid in the next page */ + protected float nextMarginLeft; + + /** margin in x direction starting from the right. Will be valid in the next page */ + protected float nextMarginRight; + + /** margin in y direction starting from the top. Will be valid in the next page */ + protected float nextMarginTop; + + /** margin in y direction starting from the bottom. Will be valid in the next page */ + protected float nextMarginBottom; + + /** + * Sets the margins. + * + * @param marginLeft the margin on the left + * @param marginRight the margin on the right + * @param marginTop the margin on the top + * @param marginBottom the margin on the bottom + * @return a bool + */ + public override bool SetMargins(float marginLeft, float marginRight, float marginTop, float marginBottom) { + if (writer != null && writer.IsPaused()) { + return false; + } + nextMarginLeft = marginLeft; + nextMarginRight = marginRight; + nextMarginTop = marginTop; + nextMarginBottom = marginBottom; + return true; + } + + // [L6] DocListener interface + + /** + * @see com.lowagie.text.DocListener#setMarginMirroring(bool) + */ + public override bool SetMarginMirroring(bool MarginMirroring) { + if (writer != null && writer.IsPaused()) { + return false; + } + return base.SetMarginMirroring(MarginMirroring); + } + + // [L7] DocListener interface + + /** + * Sets the page number. + * + * @param pageN the new page number + */ + public override int PageCount { + set { + if (writer != null && writer.IsPaused()) { + return; + } + base.PageCount = value; + } + } + + // [L8] DocListener interface + + /** + * Sets the page number to 0. + */ + public override void ResetPageCount() { + if (writer != null && writer.IsPaused()) { + return; + } + base.ResetPageCount(); + } + + /** + * Changes the header of this document. + * + * @param header the new header + */ + public override HeaderFooter Header { + set { + if (writer != null && writer.IsPaused()) { + return; + } + base.Header = value; + } + } + + /** + * Resets the header of this document. + */ + public override void ResetHeader() { + if (writer != null && writer.IsPaused()) { + return; + } + base.ResetHeader(); + } + + /** + * Changes the footer of this document. + * + * @param footer the new footer + */ + public override HeaderFooter Footer { + set { + if (writer != null && writer.IsPaused()) { + return; + } + base.Footer = value; + } + } + + /** + * Resets the footer of this document. + */ + public override void ResetFooter() { + if (writer != null && writer.IsPaused()) { + return; + } + base.ResetFooter(); + } + + // DOCLISTENER METHODS END + + /** Signals that OnOpenDocument should be called. */ + protected internal bool firstPageEvent = true; + + /** + * Initializes a page. + *

    + * If the footer/header is set, it is printed. + * @throws DocumentException on error + */ + + protected internal void InitPage() { + // the pagenumber is incremented + pageN++; + + // initialisation of some page objects + annotationsImp.ResetAnnotations(); + pageResources = new PageResources(); + + writer.ResetContent(); + graphics = new PdfContentByte(writer); + text = new PdfContentByte(writer); + text.Reset(); + text.BeginText(); + textEmptySize = text.Size; + + markPoint = 0; + SetNewPageSizeAndMargins(); + imageEnd = -1; + indentation.imageIndentRight = 0; + indentation.imageIndentLeft = 0; + indentation.indentBottom = 0; + indentation.indentTop = 0; + currentHeight = 0; + + // backgroundcolors, etc... + thisBoxSize = new Hashtable(boxSize); + if (pageSize.BackgroundColor != null + || pageSize.HasBorders() + || pageSize.BorderColor != null) { + Add(pageSize); + } + + float oldleading = leading; + int oldAlignment = alignment; + // if there is a footer, the footer is added + DoFooter(); + // we move to the left/top position of the page + text.MoveText(Left, Top); + DoHeader(); + pageEmpty = true; + // if there is an image waiting to be drawn, draw it + if (imageWait != null) { + Add(imageWait); + imageWait = null; + } + leading = oldleading; + alignment = oldAlignment; + CarriageReturn(); + + IPdfPageEvent pageEvent = writer.PageEvent; + if (pageEvent != null) { + if (firstPageEvent) { + pageEvent.OnOpenDocument(writer, this); + } + pageEvent.OnStartPage(writer, this); + } + firstPageEvent = false; + } + + /** The line that is currently being written. */ + protected internal PdfLine line = null; + + /** The lines that are written until now. */ + protected internal ArrayList lines = new ArrayList(); + + /** + * Adds the current line to the list of lines and also adds an empty line. + * @throws DocumentException on error + */ + + protected internal void NewLine() { + lastElementType = -1; + CarriageReturn(); + if (lines != null && lines.Count > 0) { + lines.Add(line); + currentHeight += line.Height; + } + line = new PdfLine(IndentLeft, IndentRight, alignment, leading); + } + + /** + * If the current line is not empty or null, it is added to the arraylist + * of lines and a new empty line is added. + * @throws DocumentException on error + */ + + protected internal void CarriageReturn() { + // the arraylist with lines may not be null + if (lines == null) { + lines = new ArrayList(); + } + // If the current line is not null + if (line != null) { + // we check if the end of the page is reached (bugfix by Francois Gravel) + if (currentHeight + line.Height + leading < IndentTop - IndentBottom) { + // if so nonempty lines are added and the heigt is augmented + if (line.Size > 0) { + currentHeight += line.Height; + lines.Add(line); + pageEmpty = false; + } + } + // if the end of the line is reached, we start a new page + else { + NewPage(); + } + } + if (imageEnd > -1 && currentHeight > imageEnd) { + imageEnd = -1; + indentation.imageIndentRight = 0; + indentation.imageIndentLeft = 0; + } + // a new current line is constructed + line = new PdfLine(IndentLeft, IndentRight, alignment, leading); + } + + /** + * Gets the current vertical page position. + * @param ensureNewLine Tells whether a new line shall be enforced. This may cause side effects + * for elements that do not terminate the lines they've started because those lines will get + * terminated. + * @return The current vertical page position. + */ + public float GetVerticalPosition(bool ensureNewLine) { + // ensuring that a new line has been started. + if (ensureNewLine) { + EnsureNewLine(); + } + return Top - currentHeight - indentation.indentTop; + } + + /** Holds the type of the last element, that has been added to the document. */ + protected internal int lastElementType = -1; + + /** + * Ensures that a new line has been started. + */ + protected internal void EnsureNewLine() { + if ((lastElementType == Element.PHRASE) || + (lastElementType == Element.CHUNK)) { + NewLine(); + FlushLines(); + } + } + + /** + * Writes all the lines to the text-object. + * + * @return the displacement that was caused + * @throws DocumentException on error + */ + protected internal float FlushLines() { + // checks if the ArrayList with the lines is not null + if (lines == null) { + return 0; + } + // checks if a new Line has to be made. + if (line != null && line.Size > 0) { + lines.Add(line); + line = new PdfLine(IndentLeft, IndentRight, alignment, leading); + } + + // checks if the ArrayList with the lines is empty + if (lines.Count == 0) { + return 0; + } + + // initialisation of some parameters + Object[] currentValues = new Object[2]; + PdfFont currentFont = null; + float displacement = 0; + + currentValues[1] = (float)0; + // looping over all the lines + foreach (PdfLine l in lines) { + + // this is a line in the loop + + float moveTextX = l.IndentLeft - IndentLeft + indentation.indentLeft + indentation.listIndentLeft + indentation.sectionIndentLeft; + text.MoveText(moveTextX, -l.Height); + // is the line preceeded by a symbol? + if (l.ListSymbol != null) { + ColumnText.ShowTextAligned(graphics, Element.ALIGN_LEFT, new Phrase(l.ListSymbol), text.XTLM - l.ListIndent, text.YTLM, 0); + } + + currentValues[0] = currentFont; + + WriteLineToContent(l, text, graphics, currentValues, writer.SpaceCharRatio); + + currentFont = (PdfFont)currentValues[0]; + + displacement += l.Height; + text.MoveText(-moveTextX, 0); + } + lines = new ArrayList(); + return displacement; + } + + /** The characters to be applied the hanging punctuation. */ + internal const String hangingPunctuation = ".,;:'"; + + /** + * Writes a text line to the document. It takes care of all the attributes. + *

    + * Before entering the line position must have been established and the + * text argument must be in text object scope (beginText()). + * @param line the line to be written + * @param text the PdfContentByte where the text will be written to + * @param graphics the PdfContentByte where the graphics will be written to + * @param currentValues the current font and extra spacing values + * @param ratio + * @throws DocumentException on error + */ + internal void WriteLineToContent(PdfLine line, PdfContentByte text, PdfContentByte graphics, Object[] currentValues, float ratio) { + PdfFont currentFont = (PdfFont)(currentValues[0]); + float lastBaseFactor = (float)currentValues[1]; + //PdfChunk chunkz; + int numberOfSpaces; + int lineLen; + bool isJustified; + float hangingCorrection = 0; + float hScale = 1; + float lastHScale = float.NaN; + float baseWordSpacing = 0; + float baseCharacterSpacing = 0; + float glueWidth = 0; + + numberOfSpaces = line.NumberOfSpaces; + lineLen = line.GetLineLengthUtf32(); + // does the line need to be justified? + isJustified = line.HasToBeJustified() && (numberOfSpaces != 0 || lineLen > 1); + int separatorCount = line.GetSeparatorCount(); + if (separatorCount > 0) { + glueWidth = line.WidthLeft / separatorCount; + } + else if (isJustified) { + if (line.NewlineSplit && line.WidthLeft >= (lastBaseFactor * (ratio * numberOfSpaces + lineLen - 1))) { + if (line.RTL) { + text.MoveText(line.WidthLeft - lastBaseFactor * (ratio * numberOfSpaces + lineLen - 1), 0); + } + baseWordSpacing = ratio * lastBaseFactor; + baseCharacterSpacing = lastBaseFactor; + } + else { + float width = line.WidthLeft; + PdfChunk last = line.GetChunk(line.Size - 1); + if (last != null) { + String s = last.ToString(); + char c; + if (s.Length > 0 && hangingPunctuation.IndexOf((c = s[s.Length - 1])) >= 0) { + float oldWidth = width; + width += last.Font.Width(c) * 0.4f; + hangingCorrection = width - oldWidth; + } + } + float baseFactor = width / (ratio * numberOfSpaces + lineLen - 1); + baseWordSpacing = ratio * baseFactor; + baseCharacterSpacing = baseFactor; + lastBaseFactor = baseFactor; + } + } + + int lastChunkStroke = line.LastStrokeChunk; + int chunkStrokeIdx = 0; + float xMarker = text.XTLM; + float baseXMarker = xMarker; + float yMarker = text.YTLM; + bool adjustMatrix = false; + float tabPosition = 0; + + // looping over all the chunks in 1 line + foreach (PdfChunk chunk in line) { + Color color = chunk.Color; + hScale = 1; + + if (chunkStrokeIdx <= lastChunkStroke) { + float width; + if (isJustified) { + width = chunk.GetWidthCorrected(baseCharacterSpacing, baseWordSpacing); + } + else { + width = chunk.Width; + } + if (chunk.IsStroked()) { + PdfChunk nextChunk = line.GetChunk(chunkStrokeIdx + 1); + if (chunk.IsSeparator()) { + width = glueWidth; + Object[] sep = (Object[])chunk.GetAttribute(Chunk.SEPARATOR); + IDrawInterface di = (IDrawInterface)sep[0]; + bool vertical = (bool)sep[1]; + float fontSize = chunk.Font.Size; + float ascender = chunk.Font.Font.GetFontDescriptor(BaseFont.ASCENT, fontSize); + float descender = chunk.Font.Font.GetFontDescriptor(BaseFont.DESCENT, fontSize); + if (vertical) { + di.Draw(graphics, baseXMarker, yMarker + descender, baseXMarker + line.OriginalWidth, ascender - descender, yMarker); + } + else { + di.Draw(graphics, xMarker, yMarker + descender, xMarker + width, ascender - descender, yMarker); + } + } + if (chunk.IsTab()) { + Object[] tab = (Object[])chunk.GetAttribute(Chunk.TAB); + IDrawInterface di = (IDrawInterface)tab[0]; + tabPosition = (float)tab[1] + (float)tab[3]; + float fontSize = chunk.Font.Size; + float ascender = chunk.Font.Font.GetFontDescriptor(BaseFont.ASCENT, fontSize); + float descender = chunk.Font.Font.GetFontDescriptor(BaseFont.DESCENT, fontSize); + if (tabPosition > xMarker) { + di.Draw(graphics, xMarker, yMarker + descender, tabPosition, ascender - descender, yMarker); + } + float tmp = xMarker; + xMarker = tabPosition; + tabPosition = tmp; + } + if (chunk.IsAttribute(Chunk.BACKGROUND)) { + float subtract = lastBaseFactor; + if (nextChunk != null && nextChunk.IsAttribute(Chunk.BACKGROUND)) + subtract = 0; + if (nextChunk == null) + subtract += hangingCorrection; + float fontSize = chunk.Font.Size; + float ascender = chunk.Font.Font.GetFontDescriptor(BaseFont.ASCENT, fontSize); + float descender = chunk.Font.Font.GetFontDescriptor(BaseFont.DESCENT, fontSize); + Object[] bgr = (Object[])chunk.GetAttribute(Chunk.BACKGROUND); + graphics.SetColorFill((Color)bgr[0]); + float[] extra = (float[])bgr[1]; + graphics.Rectangle(xMarker - extra[0], + yMarker + descender - extra[1] + chunk.TextRise, + width - subtract + extra[0] + extra[2], + ascender - descender + extra[1] + extra[3]); + graphics.Fill(); + graphics.SetGrayFill(0); + } + if (chunk.IsAttribute(Chunk.UNDERLINE)) { + float subtract = lastBaseFactor; + if (nextChunk != null && nextChunk.IsAttribute(Chunk.UNDERLINE)) + subtract = 0; + if (nextChunk == null) + subtract += hangingCorrection; + Object[][] unders = (Object[][])chunk.GetAttribute(Chunk.UNDERLINE); + Color scolor = null; + for (int k = 0; k < unders.Length; ++k) { + Object[] obj = unders[k]; + scolor = (Color)obj[0]; + float[] ps = (float[])obj[1]; + if (scolor == null) + scolor = color; + if (scolor != null) + graphics.SetColorStroke(scolor); + float fsize = chunk.Font.Size; + graphics.SetLineWidth(ps[0] + fsize * ps[1]); + float shift = ps[2] + fsize * ps[3]; + int cap2 = (int)ps[4]; + if (cap2 != 0) + graphics.SetLineCap(cap2); + graphics.MoveTo(xMarker, yMarker + shift); + graphics.LineTo(xMarker + width - subtract, yMarker + shift); + graphics.Stroke(); + if (scolor != null) + graphics.ResetGrayStroke(); + if (cap2 != 0) + graphics.SetLineCap(0); + } + graphics.SetLineWidth(1); + } + if (chunk.IsAttribute(Chunk.ACTION)) { + float subtract = lastBaseFactor; + if (nextChunk != null && nextChunk.IsAttribute(Chunk.ACTION)) + subtract = 0; + if (nextChunk == null) + subtract += hangingCorrection; + text.AddAnnotation(new PdfAnnotation(writer, xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.Font.Size, (PdfAction)chunk.GetAttribute(Chunk.ACTION))); + } + if (chunk.IsAttribute(Chunk.REMOTEGOTO)) { + float subtract = lastBaseFactor; + if (nextChunk != null && nextChunk.IsAttribute(Chunk.REMOTEGOTO)) + subtract = 0; + if (nextChunk == null) + subtract += hangingCorrection; + Object[] obj = (Object[])chunk.GetAttribute(Chunk.REMOTEGOTO); + String filename = (String)obj[0]; + if (obj[1] is String) + RemoteGoto(filename, (String)obj[1], xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.Font.Size); + else + RemoteGoto(filename, (int)obj[1], xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.Font.Size); + } + if (chunk.IsAttribute(Chunk.LOCALGOTO)) { + float subtract = lastBaseFactor; + if (nextChunk != null && nextChunk.IsAttribute(Chunk.LOCALGOTO)) + subtract = 0; + if (nextChunk == null) + subtract += hangingCorrection; + LocalGoto((String)chunk.GetAttribute(Chunk.LOCALGOTO), xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.Font.Size); + } + if (chunk.IsAttribute(Chunk.LOCALDESTINATION)) { + float subtract = lastBaseFactor; + if (nextChunk != null && nextChunk.IsAttribute(Chunk.LOCALDESTINATION)) + subtract = 0; + if (nextChunk == null) + subtract += hangingCorrection; + LocalDestination((String)chunk.GetAttribute(Chunk.LOCALDESTINATION), new PdfDestination(PdfDestination.XYZ, xMarker, yMarker + chunk.Font.Size, 0)); + } + if (chunk.IsAttribute(Chunk.GENERICTAG)) { + float subtract = lastBaseFactor; + if (nextChunk != null && nextChunk.IsAttribute(Chunk.GENERICTAG)) + subtract = 0; + if (nextChunk == null) + subtract += hangingCorrection; + Rectangle rect = new Rectangle(xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.Font.Size); + IPdfPageEvent pev = writer.PageEvent; + if (pev != null) + pev.OnGenericTag(writer, this, rect, (String)chunk.GetAttribute(Chunk.GENERICTAG)); + } + if (chunk.IsAttribute(Chunk.PDFANNOTATION)) { + float subtract = lastBaseFactor; + if (nextChunk != null && nextChunk.IsAttribute(Chunk.PDFANNOTATION)) + subtract = 0; + if (nextChunk == null) + subtract += hangingCorrection; + float fontSize = chunk.Font.Size; + float ascender = chunk.Font.Font.GetFontDescriptor(BaseFont.ASCENT, fontSize); + float descender = chunk.Font.Font.GetFontDescriptor(BaseFont.DESCENT, fontSize); + PdfAnnotation annot = PdfFormField.ShallowDuplicate((PdfAnnotation)chunk.GetAttribute(Chunk.PDFANNOTATION)); + annot.Put(PdfName.RECT, new PdfRectangle(xMarker, yMarker + descender, xMarker + width - subtract, yMarker + ascender)); + text.AddAnnotation(annot); + } + float[] paramsx = (float[])chunk.GetAttribute(Chunk.SKEW); + object hs = chunk.GetAttribute(Chunk.HSCALE); + if (paramsx != null || hs != null) { + float b = 0, c = 0; + if (paramsx != null) { + b = paramsx[0]; + c = paramsx[1]; + } + if (hs != null) + hScale = (float)hs; + text.SetTextMatrix(hScale, b, c, 1, xMarker, yMarker); + } + if (chunk.IsImage()) { + Image image = chunk.Image; + float[] matrix = image.Matrix; + matrix[Image.CX] = xMarker + chunk.ImageOffsetX - matrix[Image.CX]; + matrix[Image.CY] = yMarker + chunk.ImageOffsetY - matrix[Image.CY]; + graphics.AddImage(image, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); + text.MoveText(xMarker + lastBaseFactor + image.ScaledWidth - text.XTLM, 0); + } + } + xMarker += width; + ++chunkStrokeIdx; + } + + if (chunk.Font.CompareTo(currentFont) != 0) { + currentFont = chunk.Font; + text.SetFontAndSize(currentFont.Font, currentFont.Size); + } + float rise = 0; + Object[] textRender = (Object[])chunk.GetAttribute(Chunk.TEXTRENDERMODE); + int tr = 0; + float strokeWidth = 1; + Color strokeColor = null; + object fr = chunk.GetAttribute(Chunk.SUBSUPSCRIPT); + if (textRender != null) { + tr = (int)textRender[0] & 3; + if (tr != PdfContentByte.TEXT_RENDER_MODE_FILL) + text.SetTextRenderingMode(tr); + if (tr == PdfContentByte.TEXT_RENDER_MODE_STROKE || tr == PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE) { + strokeWidth = (float)textRender[1]; + if (strokeWidth != 1) + text.SetLineWidth(strokeWidth); + strokeColor = (Color)textRender[2]; + if (strokeColor == null) + strokeColor = color; + if (strokeColor != null) + text.SetColorStroke(strokeColor); + } + } + if (fr != null) + rise = (float)fr; + if (color != null) + text.SetColorFill(color); + if (rise != 0) + text.SetTextRise(rise); + if (chunk.IsImage()) { + adjustMatrix = true; + } + else if (chunk.IsHorizontalSeparator()) { + PdfTextArray array = new PdfTextArray(); + array.Add(-glueWidth * 1000f / chunk.Font.Size / hScale); + text.ShowText(array); + } + else if (chunk.IsTab()) { + PdfTextArray array = new PdfTextArray(); + array.Add((tabPosition - xMarker) * 1000f / chunk.Font.Size / hScale); + text.ShowText(array); + } + // If it is a CJK chunk or Unicode TTF we will have to simulate the + // space adjustment. + else if (isJustified && numberOfSpaces > 0 && chunk.IsSpecialEncoding()) { + if (hScale != lastHScale) { + lastHScale = hScale; + text.SetWordSpacing(baseWordSpacing / hScale); + text.SetCharacterSpacing(baseCharacterSpacing / hScale); + } + String s = chunk.ToString(); + int idx = s.IndexOf(' '); + if (idx < 0) + text.ShowText(s); + else { + float spaceCorrection = - baseWordSpacing * 1000f / chunk.Font.Size / hScale; + PdfTextArray textArray = new PdfTextArray(s.Substring(0, idx)); + int lastIdx = idx; + while ((idx = s.IndexOf(' ', lastIdx + 1)) >= 0) { + textArray.Add(spaceCorrection); + textArray.Add(s.Substring(lastIdx, idx - lastIdx)); + lastIdx = idx; + } + textArray.Add(spaceCorrection); + textArray.Add(s.Substring(lastIdx)); + text.ShowText(textArray); + } + } + else { + if (isJustified && hScale != lastHScale) { + lastHScale = hScale; + text.SetWordSpacing(baseWordSpacing / hScale); + text.SetCharacterSpacing(baseCharacterSpacing / hScale); + } + text.ShowText(chunk.ToString()); + } + + if (rise != 0) + text.SetTextRise(0); + if (color != null) + text.ResetRGBColorFill(); + if (tr != PdfContentByte.TEXT_RENDER_MODE_FILL) + text.SetTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL); + if (strokeColor != null) + text.ResetRGBColorStroke(); + if (strokeWidth != 1) + text.SetLineWidth(1); + if (chunk.IsAttribute(Chunk.SKEW) || chunk.IsAttribute(Chunk.HSCALE)) { + adjustMatrix = true; + text.SetTextMatrix(xMarker, yMarker); + } + } + if (isJustified) { + text.SetWordSpacing(0); + text.SetCharacterSpacing(0); + if (line.NewlineSplit) + lastBaseFactor = 0; + } + if (adjustMatrix) + text.MoveText(baseXMarker - text.XTLM, 0); + currentValues[0] = currentFont; + currentValues[1] = lastBaseFactor; + } + + protected internal Indentation indentation = new Indentation(); + public class Indentation { + /** This represents the current indentation of the PDF Elements on the left side. */ + internal float indentLeft = 0; + + /** Indentation to the left caused by a section. */ + internal float sectionIndentLeft = 0; + + /** This represents the current indentation of the PDF Elements on the left side. */ + internal float listIndentLeft = 0; + + /** This is the indentation caused by an image on the left. */ + internal float imageIndentLeft = 0; + + /** This represents the current indentation of the PDF Elements on the right side. */ + internal float indentRight = 0; + + /** Indentation to the right caused by a section. */ + internal float sectionIndentRight = 0; + + /** This is the indentation caused by an image on the right. */ + internal float imageIndentRight = 0; + + /** This represents the current indentation of the PDF Elements on the top side. */ + internal float indentTop = 0; + + /** This represents the current indentation of the PDF Elements on the bottom side. */ + internal float indentBottom = 0; + } + + /** + * Gets the indentation on the left side. + * + * @return a margin + */ + + protected internal float IndentLeft { + get { + return GetLeft(indentation.indentLeft + indentation.listIndentLeft + indentation.imageIndentLeft + indentation.sectionIndentLeft); + } + } + + /** + * Gets the indentation on the right side. + * + * @return a margin + */ + + protected internal float IndentRight { + get { + return GetRight(indentation.indentRight + indentation.sectionIndentRight + indentation.imageIndentRight); + } + } + + /** + * Gets the indentation on the top side. + * + * @return a margin + */ + + protected internal float IndentTop { + get { + return GetTop(indentation.indentTop); + } + } + + /** + * Gets the indentation on the bottom side. + * + * @return a margin + */ + + protected internal float IndentBottom { + get { + return GetBottom(indentation.indentBottom); + } + } + + /** + * Adds extra space. + * This method should probably be rewritten. + */ + protected internal void AddSpacing(float extraspace, float oldleading, Font f) { + if (extraspace == 0) return; + if (pageEmpty) return; + if (currentHeight + line.Height + leading > IndentTop - IndentBottom) return; + leading = extraspace; + CarriageReturn(); + if (f.IsUnderlined() || f.IsStrikethru()) { + f = new Font(f); + int style = f.Style; + style &= ~Font.UNDERLINE; + style &= ~Font.STRIKETHRU; + f.SetStyle(Font.UNDEFINED); + f.SetStyle(style); + } + Chunk space = new Chunk(" ", f); + space.Process(this); + CarriageReturn(); + leading = oldleading; + } + + // Info Dictionary and Catalog + + /** some meta information about the Document. */ + protected internal PdfInfo info = new PdfInfo(); + + /** + * Gets the PdfInfo-object. + * + * @return PdfInfo + */ + internal PdfInfo Info { + get { + return info; + } + } + + /** + * Gets the PdfCatalog-object. + * + * @param pages an indirect reference to this document pages + * @return PdfCatalog + */ + internal PdfCatalog GetCatalog(PdfIndirectReference pages) { + PdfCatalog catalog = new PdfCatalog(pages, writer); + + // [C1] outlines + if (rootOutline.Kids.Count > 0) { + catalog.Put(PdfName.PAGEMODE, PdfName.USEOUTLINES); + catalog.Put(PdfName.OUTLINES, rootOutline.IndirectReference); + } + + // [C2] version + writer.GetPdfVersion().AddToCatalog(catalog); + + // [C3] preferences + viewerPreferences.AddToCatalog(catalog); + + // [C4] pagelabels + if (pageLabels != null) { + catalog.Put(PdfName.PAGELABELS, pageLabels.GetDictionary(writer)); + } + + // [C5] named objects + catalog.AddNames(localDestinations, GetDocumentLevelJS(), documentFileAttachment, writer); + + // [C6] actions + if (openActionName != null) { + PdfAction action = GetLocalGotoAction(openActionName); + catalog.OpenAction = action; + } + else if (openActionAction != null) + catalog.OpenAction = openActionAction; + if (additionalActions != null) { + catalog.AdditionalActions = additionalActions; + } + + // [C7] portable collections + if (collection != null) { + catalog.Put(PdfName.COLLECTION, collection); + } + + // [C8] AcroForm + if (annotationsImp.HasValidAcroForm()) { + catalog.Put(PdfName.ACROFORM, writer.AddToBody(annotationsImp.AcroForm).IndirectReference); + } + + return catalog; + } + + // [C1] outlines + + /** This is the root outline of the document. */ + protected internal PdfOutline rootOutline; + + /** This is the current PdfOutline in the hierarchy of outlines. */ + protected internal PdfOutline currentOutline; + + /** + * Adds a named outline to the document . + * @param outline the outline to be added + * @param name the name of this local destination + */ + internal void AddOutline(PdfOutline outline, String name) { + LocalDestination(name, outline.PdfDestination); + } + + /** + * Gets the root outline. All the outlines must be created with a parent. + * The first level is created with this outline. + * @return the root outline + */ + public PdfOutline RootOutline { + get { + return rootOutline; + } + } + + internal void CalculateOutlineCount() { + if (rootOutline.Kids.Count == 0) + return; + TraverseOutlineCount(rootOutline); + } + + internal void TraverseOutlineCount(PdfOutline outline) { + ArrayList kids = outline.Kids; + PdfOutline parent = outline.Parent; + if (kids.Count == 0) { + if (parent != null) { + parent.Count = parent.Count + 1; + } + } + else { + for (int k = 0; k < kids.Count; ++k) { + TraverseOutlineCount((PdfOutline)kids[k]); + } + if (parent != null) { + if (outline.Open) { + parent.Count = outline.Count + parent.Count + 1; + } + else { + parent.Count = parent.Count + 1; + outline.Count = -outline.Count; + } + } + } + } + + internal void WriteOutlines() { + if (rootOutline.Kids.Count == 0) + return; + OutlineTree(rootOutline); + writer.AddToBody(rootOutline, rootOutline.IndirectReference); + } + + internal void OutlineTree(PdfOutline outline) { + outline.IndirectReference = writer.PdfIndirectReference; + if (outline.Parent != null) + outline.Put(PdfName.PARENT, outline.Parent.IndirectReference); + ArrayList kids = outline.Kids; + int size = kids.Count; + for (int k = 0; k < size; ++k) + OutlineTree((PdfOutline)kids[k]); + for (int k = 0; k < size; ++k) { + if (k > 0) + ((PdfOutline)kids[k]).Put(PdfName.PREV, ((PdfOutline)kids[k - 1]).IndirectReference); + if (k < size - 1) + ((PdfOutline)kids[k]).Put(PdfName.NEXT, ((PdfOutline)kids[k + 1]).IndirectReference); + } + if (size > 0) { + outline.Put(PdfName.FIRST, ((PdfOutline)kids[0]).IndirectReference); + outline.Put(PdfName.LAST, ((PdfOutline)kids[size - 1]).IndirectReference); + } + for (int k = 0; k < size; ++k) { + PdfOutline kid = (PdfOutline)kids[k]; + writer.AddToBody(kid, kid.IndirectReference); + } + } + + // [C3] PdfViewerPreferences interface + + /** Contains the Viewer preferences of this PDF document. */ + protected PdfViewerPreferencesImp viewerPreferences = new PdfViewerPreferencesImp(); + /** @see com.lowagie.text.pdf.interfaces.PdfViewerPreferences#setViewerPreferences(int) */ + internal int ViewerPreferences { + set { + this.viewerPreferences.ViewerPreferences = value; + } + } + + /** @see com.lowagie.text.pdf.interfaces.PdfViewerPreferences#addViewerPreference(com.lowagie.text.pdf.PdfName, com.lowagie.text.pdf.PdfObject) */ + internal void AddViewerPreference(PdfName key, PdfObject value) { + this.viewerPreferences.AddViewerPreference(key, value); + } + + // [C4] Page labels + + protected internal PdfPageLabels pageLabels; + + internal PdfPageLabels PageLabels { + set { + this.pageLabels = value; + } + } + + // [C5] named objects: local destinations, javascript, embedded files + + /** + * Implements a link to other part of the document. The jump will + * be made to a local destination with the same name, that must exist. + * @param name the name for this link + * @param llx the lower left x corner of the activation area + * @param lly the lower left y corner of the activation area + * @param urx the upper right x corner of the activation area + * @param ury the upper right y corner of the activation area + */ + internal void LocalGoto(String name, float llx, float lly, float urx, float ury) { + PdfAction action = GetLocalGotoAction(name); + annotationsImp.AddPlainAnnotation(new PdfAnnotation(writer, llx, lly, urx, ury, action)); + } + + /** + * Implements a link to another document. + * @param filename the filename for the remote document + * @param name the name to jump to + * @param llx the lower left x corner of the activation area + * @param lly the lower left y corner of the activation area + * @param urx the upper right x corner of the activation area + * @param ury the upper right y corner of the activation area + */ + internal void RemoteGoto(String filename, String name, float llx, float lly, float urx, float ury) { + annotationsImp.AddPlainAnnotation(new PdfAnnotation(writer, llx, lly, urx, ury, new PdfAction(filename, name))); + } + + /** + * Implements a link to another document. + * @param filename the filename for the remote document + * @param page the page to jump to + * @param llx the lower left x corner of the activation area + * @param lly the lower left y corner of the activation area + * @param urx the upper right x corner of the activation area + * @param ury the upper right y corner of the activation area + */ + internal void RemoteGoto(String filename, int page, float llx, float lly, float urx, float ury) { + AddAnnotation(new PdfAnnotation(writer, llx, lly, urx, ury, new PdfAction(filename, page))); + } + + /** Implements an action in an area. + * @param action the PdfAction + * @param llx the lower left x corner of the activation area + * @param lly the lower left y corner of the activation area + * @param urx the upper right x corner of the activation area + * @param ury the upper right y corner of the activation area + */ + internal void SetAction(PdfAction action, float llx, float lly, float urx, float ury) { + AddAnnotation(new PdfAnnotation(writer, llx, lly, urx, ury, action)); + } + + /** + * Stores the destinations keyed by name. Value is + * Object[]{PdfAction,PdfIndirectReference,PdfDestintion}. + */ + protected internal k_Tree localDestinations = new k_Tree(); + + internal PdfAction GetLocalGotoAction(String name) { + PdfAction action; + Object[] obj = (Object[])localDestinations[name]; + if (obj == null) + obj = new Object[3]; + if (obj[0] == null) { + if (obj[1] == null) { + obj[1] = writer.PdfIndirectReference; + } + action = new PdfAction((PdfIndirectReference)obj[1]); + obj[0] = action; + localDestinations[name] = obj; + } + else { + action = (PdfAction)obj[0]; + } + return action; + } + + /** + * The local destination to where a local goto with the same + * name will jump to. + * @param name the name of this local destination + * @param destination the PdfDestination with the jump coordinates + * @return true if the local destination was added, + * false if a local destination with the same name + * already existed + */ + internal bool LocalDestination(String name, PdfDestination destination) { + Object[] obj = (Object[])localDestinations[name]; + if (obj == null) + obj = new Object[3]; + if (obj[2] != null) + return false; + obj[2] = destination; + localDestinations[name] = obj; + destination.AddPage(writer.CurrentPage); + return true; + } + + /** + * Stores a list of document level JavaScript actions. + */ + private int jsCounter; + protected internal Hashtable documentLevelJS = new Hashtable(); + + internal void AddJavaScript(PdfAction js) { + if (js.Get(PdfName.JS) == null) + throw new ArgumentException("Only JavaScript actions are allowed."); + documentLevelJS[jsCounter.ToString().PadLeft(16, '0')] = writer.AddToBody(js).IndirectReference; + jsCounter++; + } + + internal void AddJavaScript(String name, PdfAction js) { + if (js.Get(PdfName.JS) == null) + throw new ArgumentException("Only JavaScript actions are allowed."); + documentLevelJS[name] = writer.AddToBody(js).IndirectReference; + } + + internal Hashtable GetDocumentLevelJS() { + return documentLevelJS; + } + + protected internal Hashtable documentFileAttachment = new Hashtable(); + + internal void AddFileAttachment(String description, PdfFileSpecification fs) { + if (description == null) { + PdfString desc = (PdfString)fs.Get(PdfName.DESC); + if (desc == null) { + description = ""; + } + else { + description = PdfEncodings.ConvertToString(desc.GetBytes(), null); + } + } + fs.AddDescription(description, true); + if (description.Length == 0) + description = "Unnamed"; + String fn = PdfEncodings.ConvertToString(new PdfString(description, PdfObject.TEXT_UNICODE).GetBytes(), null); + int k = 0; + while (documentFileAttachment.ContainsKey(fn)) { + ++k; + fn = PdfEncodings.ConvertToString(new PdfString(description + " " + k, PdfObject.TEXT_UNICODE).GetBytes(), null); + } + documentFileAttachment[fn] = fs.Reference; + } + + internal Hashtable GetDocumentFileAttachment() { + return documentFileAttachment; + } + + // [C6] document level actions + + protected internal String openActionName; + + internal void SetOpenAction(String name) { + openActionName = name; + openActionAction = null; + } + + protected internal PdfAction openActionAction; + + internal void SetOpenAction(PdfAction action) { + openActionAction = action; + openActionName = null; + } + + protected internal PdfDictionary additionalActions; + + internal void AddAdditionalAction(PdfName actionType, PdfAction action) { + if (additionalActions == null) { + additionalActions = new PdfDictionary(); + } + if (action == null) + additionalActions.Remove(actionType); + else + additionalActions.Put(actionType, action); + if (additionalActions.Size == 0) + additionalActions = null; + } + + // [C7] portable collections + + protected internal PdfCollection collection; + + /** + * Sets the collection dictionary. + * @param collection a dictionary of type PdfCollection + */ + public PdfCollection Collection { + set { + this.collection = value; + } + } + + // [C8] AcroForm + + internal PdfAnnotationsImp annotationsImp; + + /** + * Gets the AcroForm object. + * @return the PdfAcroform object of the PdfDocument + */ + public PdfAcroForm AcroForm { + get { + return annotationsImp.AcroForm; + } + } + + internal int SigFlags { + set { + annotationsImp.SigFlags = value; + } + } + + internal void AddCalculationOrder(PdfFormField formField) { + annotationsImp.AddCalculationOrder(formField); + } + + internal void AddAnnotation(PdfAnnotation annot) { + pageEmpty = false; + annotationsImp.AddAnnotation(annot); + } + + // [F12] tagged PDF + + protected int markPoint; + + internal int GetMarkPoint() { + return markPoint; + } + + internal void IncMarkPoint() { + ++markPoint; + } + + // [U1] page sizes + + /** This is the size of the next page. */ + protected Rectangle nextPageSize = null; + + /** This is the size of the several boxes of the current Page. */ + protected Hashtable thisBoxSize = new Hashtable(); + + /** This is the size of the several boxes that will be used in + * the next page. */ + protected Hashtable boxSize = new Hashtable(); + + internal Rectangle CropBoxSize { + set { + SetBoxSize("crop", value); + } + } + + internal void SetBoxSize(String boxName, Rectangle size) { + if (size == null) + boxSize.Remove(boxName); + else + boxSize[boxName] = new PdfRectangle(size); + } + + protected internal void SetNewPageSizeAndMargins() { + pageSize = nextPageSize; + if (marginMirroring && (PageNumber & 1) == 0) { + marginRight = nextMarginLeft; + marginLeft = nextMarginRight; + } + else { + marginLeft = nextMarginLeft; + marginRight = nextMarginRight; + } + marginTop = nextMarginTop; + marginBottom = nextMarginBottom; + } + + /** + * Gives the size of a trim, art, crop or bleed box, or null if not defined. + * @param boxName crop, trim, art or bleed + */ + internal Rectangle GetBoxSize(String boxName) { + PdfRectangle r = (PdfRectangle)thisBoxSize[boxName]; + if (r != null) return r.Rectangle; + return null; + } + + // [U2] empty pages + + /** This checks if the page is empty. */ + protected internal bool pageEmpty = true; + + internal bool PageEmpty { + set { + this.pageEmpty = value; + } + } + + + // [U3] page actions + + /** The duration of the page */ + protected int duration=-1; // negative values will indicate no duration + + /** The page transition */ + protected PdfTransition transition=null; + + /** + * Sets the display duration for the page (for presentations) + * @param seconds the number of seconds to display the page + */ + internal int Duration { + set { + if (value > 0) + this.duration=value; + else + this.duration=-1; + } + } + + /** + * Sets the transition for the page + * @param transition the PdfTransition object + */ + internal PdfTransition Transition { + set { + this.transition=value; + } + } + + protected PdfDictionary pageAA = null; + + internal void SetPageAction(PdfName actionType, PdfAction action) { + if (pageAA == null) { + pageAA = new PdfDictionary(); + } + pageAA.Put(actionType, action); + } + + // [U8] thumbnail images + + protected internal PdfIndirectReference thumb; + + internal Image Thumbnail { + set { + thumb = writer.GetImageReference(writer.AddDirectImageSimple(value)); + } + } + + // [M0] Page resources contain references to fonts, extgstate, images,... + + /** This are the page resources of the current Page. */ + protected internal PageResources pageResources; + + internal PageResources PageResources { + get { + return pageResources; + } + } + + // [M3] Images + + /** Holds value of property strictImageSequence. */ + protected internal bool strictImageSequence = false; + + /** Setter for property strictImageSequence. + * @param strictImageSequence New value of property strictImageSequence. + * + */ + internal bool StrictImageSequence { + set { + this.strictImageSequence = value; + } + get { + return strictImageSequence; + } + } + + /** This is the position where the image ends. */ + protected internal float imageEnd = -1; + + /** + * Method added by Pelikan Stephan + * @see com.lowagie.text.DocListener#clearTextWrap() + */ + public void ClearTextWrap() { + float tmpHeight = imageEnd - currentHeight; + if (line != null) { + tmpHeight += line.Height; + } + if ((imageEnd > -1) && (tmpHeight > 0)) { + CarriageReturn(); + currentHeight += tmpHeight; + } + } + + /** This is the image that could not be shown on a previous page. */ + protected internal Image imageWait = null; + + /** + * Adds an image to the document. + * @param image the Image to add + * @throws PdfException on error + * @throws DocumentException on error + */ + protected internal void Add(Image image) { + + if (image.HasAbsolutePosition()) { + graphics.AddImage(image); + pageEmpty = false; + return; + } + + // if there isn't enough room for the image on this page, save it for the next page + if (currentHeight != 0 && IndentTop - currentHeight - image.ScaledHeight < IndentBottom) { + if (!strictImageSequence && imageWait == null) { + imageWait = image; + return; + } + NewPage(); + if (currentHeight != 0 && IndentTop - currentHeight - image.ScaledHeight < IndentBottom) { + imageWait = image; + return; + } + } + pageEmpty = false; + // avoid endless loops + if (image == imageWait) + imageWait = null; + bool textwrap = (image.Alignment & Image.TEXTWRAP) == Image.TEXTWRAP + && !((image.Alignment & Image.MIDDLE_ALIGN) == Image.MIDDLE_ALIGN); + bool underlying = (image.Alignment & Image.UNDERLYING) == Image.UNDERLYING; + float diff = leading / 2; + if (textwrap) { + diff += leading; + } + float lowerleft = IndentTop - currentHeight - image.ScaledHeight - diff; + float[] mt = image.Matrix; + float startPosition = IndentLeft - mt[4]; + if ((image.Alignment & Image.RIGHT_ALIGN) == Image.RIGHT_ALIGN) startPosition = IndentRight - image.ScaledWidth - mt[4]; + if ((image.Alignment & Image.MIDDLE_ALIGN) == Image.MIDDLE_ALIGN) startPosition = IndentLeft + ((IndentRight - IndentLeft - image.ScaledWidth) / 2) - mt[4]; + if (image.HasAbsoluteX()) startPosition = image.AbsoluteX; + if (textwrap) { + if (imageEnd < 0 || imageEnd < currentHeight + image.ScaledHeight + diff) { + imageEnd = currentHeight + image.ScaledHeight + diff; + } + if ((image.Alignment & Image.RIGHT_ALIGN) == Image.RIGHT_ALIGN) { + // indentation suggested by Pelikan Stephan + indentation.imageIndentRight += image.ScaledWidth + image.IndentationLeft; + } + else { + // indentation suggested by Pelikan Stephan + indentation.imageIndentLeft += image.ScaledWidth + image.IndentationRight; + } + } + else { + if ((image.Alignment & Image.RIGHT_ALIGN) == Image.RIGHT_ALIGN) startPosition -= image.IndentationRight; + else if ((image.Alignment & Image.MIDDLE_ALIGN) == Image.MIDDLE_ALIGN) startPosition += image.IndentationLeft - image.IndentationRight; + else startPosition -= image.IndentationRight; + } + graphics.AddImage(image, mt[0], mt[1], mt[2], mt[3], startPosition, lowerleft - mt[5]); + if (!(textwrap || underlying)) { + currentHeight += image.ScaledHeight + diff; + FlushLines(); + text.MoveText(0, - (image.ScaledHeight + diff)); + NewLine(); + } + } + + // [M4] Adding a PdfPTable + + /** Adds a PdfPTable to the document. + * @param ptable the PdfPTable to be added to the document. + * @throws DocumentException on error + */ + internal void AddPTable(PdfPTable ptable) { + ColumnText ct = new ColumnText(writer.DirectContent); + if (currentHeight > 0) { + Paragraph p = new Paragraph(); + p.Leading = 0; + ct.AddElement(p); + //if the table prefers to be on a single page, and it wouldn't + //fit on the current page, start a new page. + if (ptable.KeepTogether && !FitsPage(ptable, 0f)) + NewPage(); + } + ct.AddElement(ptable); + bool he = ptable.HeadersInEvent; + ptable.HeadersInEvent = true; + int loop = 0; + while (true) { + ct.SetSimpleColumn(IndentLeft, IndentBottom, IndentRight, IndentTop - currentHeight); + int status = ct.Go(); + if ((status & ColumnText.NO_MORE_TEXT) != 0) { + text.MoveText(0, ct.YLine - IndentTop + currentHeight); + currentHeight = IndentTop - ct.YLine; + break; + } + if (IndentTop - currentHeight == ct.YLine) + ++loop; + else + loop = 0; + if (loop == 3) { + Add(new Paragraph("ERROR: Infinite table loop")); + break; + } + NewPage(); + } + ptable.HeadersInEvent = he; + } + + internal bool FitsPage(PdfPTable table, float margin) { + if (!table.LockedWidth) { + float totalWidth = (IndentRight - IndentLeft) * table.WidthPercentage / 100; + table.TotalWidth = totalWidth; + } + // ensuring that a new line has been started. + EnsureNewLine(); + return table.TotalHeight <= IndentTop - currentHeight - IndentBottom - margin; + } + + // [M4'] Adding a Table + + protected internal class RenderingContext { + internal float pagetop = -1; + internal float oldHeight = -1; + + internal PdfContentByte cellGraphics = null; + + internal float lostTableBottom; + + internal float maxCellBottom; + //internal float maxCellHeight; + + internal Hashtable rowspanMap; + internal Hashtable pageMap = new Hashtable(); + /** + * A PdfPTable + */ + public PdfTable table; + + /** + * Consumes the rowspan + * @param c + * @return a rowspan. + */ + public int ConsumeRowspan(PdfCell c) { + if (c.Rowspan == 1) { + return 1; + } + + object i = rowspanMap[c]; + if (i == null) { + i = c.Rowspan; + } + + i = (int)i - 1; + rowspanMap[c] = i; + + if ((int)i < 1) { + return 1; + } + return (int)i; + } + + /** + * Looks at the current rowspan. + * @param c + * @return the current rowspan + */ + public int CurrentRowspan(PdfCell c) { + object i = rowspanMap[c]; + if (i == null) { + return c.Rowspan; + } else { + return (int)i; + } + } + + public int CellRendered(PdfCell cell, int pageNumber) { + object i = pageMap[cell]; + if (i == null) { + i = 1; + } else { + i = (int)i + 1; + } + pageMap[cell] = i; + + Hashtable seti = (Hashtable)pageMap[pageNumber]; + + if (seti == null) { + seti = new Hashtable(); + pageMap[pageNumber] = seti; + } + + seti[cell] = null; + + return (int)i; + } + + public int NumCellRendered(PdfCell cell) { + object i = pageMap[cell]; + if (i == null) { + i = 0; + } + return (int)i; + } + + public bool IsCellRenderedOnPage(PdfCell cell, int pageNumber) { + Hashtable seti = (Hashtable) pageMap[pageNumber]; + + if (seti != null) { + return seti.ContainsKey(cell); + } + + return false; + } + }; + + /** + * Adds a new table to + * @param table Table to add. Rendered rows will be deleted after processing. + * @param onlyFirstPage Render only the first full page + * @throws DocumentException + */ + private void AddPdfTable(Table t) { + // before every table, we flush all lines + FlushLines(); + + PdfTable table = new PdfTable(t, IndentLeft, IndentRight, IndentTop - currentHeight); + RenderingContext ctx = new RenderingContext(); + ctx.pagetop = IndentTop; + ctx.oldHeight = currentHeight; + ctx.cellGraphics = new PdfContentByte(writer); + ctx.rowspanMap = new Hashtable(); + ctx.table = table; + + // initialisation of parameters + PdfCell cell; + + // drawing the table + ArrayList headercells = table.HeaderCells; + ArrayList cells = table.Cells; + ArrayList rows = ExtractRows(cells, ctx); + bool isContinue = false; + while (cells.Count != 0) { + // initialisation of some extra parameters; + ctx.lostTableBottom = 0; + + // loop over the cells + bool cellsShown = false; + + // draw the cells (line by line) + ListIterator iterator = new ListIterator(rows); + + bool atLeastOneFits = false; + while (iterator.HasNext()) { + ArrayList row = (ArrayList) iterator.Next(); + AnalyzeRow(rows, ctx); + RenderCells(ctx, row, table.HasToFitPageCells() & atLeastOneFits); + + if (!MayBeRemoved(row)) { + break; + } + + ConsumeRowspan(row, ctx); + iterator.Remove(); + atLeastOneFits = true; + } + + // compose cells array list for subsequent code + cells.Clear(); + Hashtable opt = new Hashtable(); + foreach (ArrayList row in rows) { + foreach (PdfCell cellp in row) { + if (!opt.ContainsKey(cellp)) { + cells.Add(cellp); + opt[cellp] = null; + } + } + } + // we paint the graphics of the table after looping through all the cells + Rectangle tablerec = new Rectangle(table); + tablerec.Border = table.Border; + tablerec.BorderWidth = table.BorderWidth; + tablerec.BorderColor = table.BorderColor; + tablerec.BackgroundColor = table.BackgroundColor; + PdfContentByte under = writer.DirectContentUnder; + under.Rectangle(tablerec.GetRectangle(Top, IndentBottom)); + under.Add(ctx.cellGraphics); + // bugfix by Gerald Fehringer: now again add the border for the table + // since it might have been covered by cell backgrounds + tablerec.BackgroundColor = null; + tablerec = tablerec.GetRectangle(Top, IndentBottom); + tablerec.Border = table.Border; + under.Rectangle(tablerec); + // end bugfix + ctx.cellGraphics = new PdfContentByte(null); + // if the table continues on the next page + if (rows.Count != 0) { + isContinue = true; + graphics.SetLineWidth(table.BorderWidth); + if (cellsShown && (table.Border & Rectangle.BOTTOM_BORDER) == Rectangle.BOTTOM_BORDER) { + // Draw the bottom line + + // the color is set to the color of the element + Color tColor = table.BorderColor; + if (tColor != null) { + graphics.SetColorStroke(tColor); + } + graphics.MoveTo(table.Left, Math.Max(table.Bottom, IndentBottom)); + graphics.LineTo(table.Right, Math.Max(table.Bottom, IndentBottom)); + graphics.Stroke(); + if (tColor != null) { + graphics.ResetRGBColorStroke(); + } + } + + // old page + pageEmpty = false; + float difference = ctx.lostTableBottom; + + // new page + NewPage(); + // G.F.: if something added in page event i.e. currentHeight > 0 + float heightCorrection = 0; + bool somethingAdded = false; + if (currentHeight > 0) { + heightCorrection = 6; + currentHeight += heightCorrection; + somethingAdded = true; + NewLine(); + FlushLines(); + indentation.indentTop = currentHeight - leading; + currentHeight = 0; + } + else { + FlushLines(); + } + + // this part repeats the table headers (if any) + int size = headercells.Count; + if (size > 0) { + // this is the top of the headersection + cell = (PdfCell) headercells[0]; + float oldTop = cell.GetTop(0); + // loop over all the cells of the table header + for (int ii = 0; ii < size; ii++) { + cell = (PdfCell) headercells[ii]; + // calculation of the new cellpositions + cell.Top = IndentTop - oldTop + cell.GetTop(0); + cell.Bottom = IndentTop - oldTop + cell.GetBottom(0); + ctx.pagetop = cell.Bottom; + // we paint the borders of the cell + ctx.cellGraphics.Rectangle(cell.Rectangle(IndentTop, IndentBottom)); + // we write the text of the cell + ArrayList images = cell.GetImages(IndentTop, IndentBottom); + foreach (Image image in images) { + cellsShown = true; + graphics.AddImage(image); + } + lines = cell.GetLines(IndentTop, IndentBottom); + float cellTop = cell.GetTop(IndentTop); + text.MoveText(0, cellTop-heightCorrection); + float cellDisplacement = FlushLines() - cellTop+heightCorrection; + text.MoveText(0, cellDisplacement); + } + currentHeight = IndentTop - ctx.pagetop + table.Cellspacing; + text.MoveText(0, ctx.pagetop - IndentTop - currentHeight); + } + else { + if (somethingAdded) { + ctx.pagetop = IndentTop; + text.MoveText(0, -table.Cellspacing); + } + } + ctx.oldHeight = currentHeight - heightCorrection; + // calculating the new positions of the table and the cells + size = Math.Min(cells.Count, table.Columns); + int i = 0; + while (i < size) { + cell = (PdfCell) cells[i]; + if (cell.GetTop(-table.Cellspacing) > ctx.lostTableBottom) { + float newBottom = ctx.pagetop - difference + cell.Bottom; + float neededHeight = cell.RemainingHeight; + if (newBottom > ctx.pagetop - neededHeight) { + difference += newBottom - (ctx.pagetop - neededHeight); + } + } + i++; + } + size = cells.Count; + table.Top = IndentTop; + table.Bottom = ctx.pagetop - difference + table.GetBottom(table.Cellspacing); + for (i = 0; i < size; i++) { + cell = (PdfCell) cells[i]; + float newBottom = ctx.pagetop - difference + cell.Bottom; + float newTop = ctx.pagetop - difference + cell.GetTop(-table.Cellspacing); + if (newTop > IndentTop - currentHeight) { + newTop = IndentTop - currentHeight; + } + cell.Top = newTop ; + cell.Bottom = newBottom ; + } + } + } + + float tableHeight = table.Top - table.Bottom; + // bugfix by Adauto Martins when have more than two tables and more than one page + // If continuation of table in other page (bug report #1460051) + if (isContinue) { + currentHeight = tableHeight; + text.MoveText(0, -(tableHeight - (ctx.oldHeight * 2))); + } + else { + currentHeight = ctx.oldHeight + tableHeight; + text.MoveText(0, -tableHeight); + } + pageEmpty = false; + } + + protected internal void AnalyzeRow(ArrayList rows, RenderingContext ctx) { + ctx.maxCellBottom = IndentBottom; + + // determine whether Row(index) is in a rowspan + int rowIndex = 0; + + ArrayList row = (ArrayList) rows[rowIndex]; + int maxRowspan = 1; + foreach (PdfCell cell in row) { + maxRowspan = Math.Max(ctx.CurrentRowspan(cell), maxRowspan); + } + rowIndex += maxRowspan; + + bool useTop = true; + if (rowIndex == rows.Count) { + rowIndex = rows.Count - 1; + useTop = false; + } + + if (rowIndex < 0 || rowIndex >= rows.Count) return; + + row = (ArrayList) rows[rowIndex]; + foreach (PdfCell cell in row) { + Rectangle cellRect = cell.Rectangle(ctx.pagetop, IndentBottom); + if (useTop) { + ctx.maxCellBottom = Math.Max(ctx.maxCellBottom, cellRect.Top); + } else { + if (ctx.CurrentRowspan(cell) == 1) { + ctx.maxCellBottom = Math.Max(ctx.maxCellBottom, cellRect.Bottom); + } + } + } + } + + protected internal bool MayBeRemoved(ArrayList row) { + bool mayBeRemoved = true; + foreach (PdfCell cell in row) { + mayBeRemoved &= cell.MayBeRemoved(); + } + return mayBeRemoved; + } + + protected internal void ConsumeRowspan(ArrayList row, RenderingContext ctx) { + foreach (PdfCell c in row) { + ctx.ConsumeRowspan(c); + } + } + + protected internal ArrayList ExtractRows(ArrayList cells, RenderingContext ctx) { + PdfCell cell; + PdfCell previousCell = null; + ArrayList rows = new ArrayList(); + ArrayList rowCells = new ArrayList(); + + ListIterator iterator = new ListIterator(cells); + while (iterator.HasNext()) { + cell = (PdfCell) iterator.Next(); + + bool isAdded = false; + + bool isEndOfRow = !iterator.HasNext(); + bool isCurrentCellPartOfRow = !iterator.HasNext(); + + if (previousCell != null) { + if (cell.Left <= previousCell.Left) { + isEndOfRow = true; + isCurrentCellPartOfRow = false; + } + } + + if (isCurrentCellPartOfRow) { + rowCells.Add(cell); + isAdded = true; + } + + if (isEndOfRow) { + if (rowCells.Count != 0) { + // add to rowlist + rows.Add(rowCells); + } + + // start a new list for next line + rowCells = new ArrayList(); + } + + if (!isAdded) { + rowCells.Add(cell); + } + + previousCell = cell; + } + + if (rowCells.Count != 0) { + rows.Add(rowCells); + } + + // fill row information with rowspan cells to get complete "scan lines" + for (int i = rows.Count - 1; i >= 0; i--) { + ArrayList row = (ArrayList) rows[i]; + + // iterator through row + for (int j = 0; j < row.Count; j++) { + PdfCell c = (PdfCell) row[j]; + int rowspan = c.Rowspan; + + // fill in missing rowspan cells to complete "scan line" + for (int k = 1; k < rowspan && rows.Count < i+k; k++) { + ArrayList spannedRow = ((ArrayList) rows[i + k]); + if (spannedRow.Count > j) + spannedRow.Insert(j, c); + } + } + } + + return rows; + } + + protected internal void RenderCells(RenderingContext ctx, ArrayList cells, bool hasToFit) { + if (hasToFit) { + foreach (PdfCell cell in cells) { + if (!cell.Header) { + if (cell.Bottom < IndentBottom) return; + } + } + } + foreach (PdfCell cell in cells) { + if (!ctx.IsCellRenderedOnPage(cell, PageNumber)) { + + float correction = 0; + if (ctx.NumCellRendered(cell) >= 1) { + correction = 1.0f; + } + + lines = cell.GetLines(ctx.pagetop, IndentBottom - correction); + + // if there is still text to render we render it + if (lines != null && lines.Count > 0) { + + // we write the text + float cellTop = cell.GetTop(ctx.pagetop - ctx.oldHeight); + text.MoveText(0, cellTop); + float cellDisplacement = FlushLines() - cellTop; + + text.MoveText(0, cellDisplacement); + if (ctx.oldHeight + cellDisplacement > currentHeight) { + currentHeight = ctx.oldHeight + cellDisplacement; + } + + ctx.CellRendered(cell, PageNumber); + } + + float indentBottom = Math.Max(cell.Bottom, IndentBottom); + + Rectangle tableRect = ctx.table.GetRectangle(ctx.pagetop, IndentBottom); + + indentBottom = Math.Max(tableRect.Bottom, indentBottom); + + // we paint the borders of the cells + Rectangle cellRect = cell.GetRectangle(tableRect.Top, indentBottom); + //cellRect.Bottom = cellRect.Bottom; + if (cellRect.Height > 0) { + ctx.lostTableBottom = indentBottom; + ctx.cellGraphics.Rectangle(cellRect); + } + + // and additional graphics + ArrayList images = cell.GetImages(ctx.pagetop, IndentBottom); + foreach (Image image in images) { + graphics.AddImage(image); + } + } + } + } + + /** + * Returns the bottomvalue of a Table if it were added to this document. + * + * @param table the table that may or may not be added to this document + * @return a bottom value + */ + internal float GetBottom(Table table) { + // constructing a PdfTable + PdfTable tmp = new PdfTable(table, IndentLeft, IndentRight, IndentTop - currentHeight); + return tmp.Bottom; + } + + // [M5] header/footer + protected internal void DoFooter() { + if (footer == null) return; + // Begin added by Edgar Leonardo Prieto Perilla + // Avoid footer identation + float tmpIndentLeft = indentation.indentLeft; + float tmpIndentRight = indentation.indentRight; + // Begin added: Bonf (Marc Schneider) 2003-07-29 + float tmpListIndentLeft = indentation.listIndentLeft; + float tmpImageIndentLeft = indentation.imageIndentLeft; + float tmpImageIndentRight = indentation.imageIndentRight; + // End added: Bonf (Marc Schneider) 2003-07-29 + + indentation.indentLeft = indentation.indentRight = 0; + // Begin added: Bonf (Marc Schneider) 2003-07-29 + indentation.listIndentLeft = 0; + indentation.imageIndentLeft = 0; + indentation.imageIndentRight = 0; + // End added: Bonf (Marc Schneider) 2003-07-29 + // End Added by Edgar Leonardo Prieto Perilla + footer.PageNumber = pageN; + leading = footer.Paragraph.TotalLeading; + Add(footer.Paragraph); + // adding the footer limits the height + indentation.indentBottom = currentHeight; + text.MoveText(Left, IndentBottom); + FlushLines(); + text.MoveText(-Left, -Bottom); + footer.Top = GetBottom(currentHeight); + footer.Bottom = Bottom - (0.75f * leading); + footer.Left = Left; + footer.Right = Right; + graphics.Rectangle(footer); + indentation.indentBottom = currentHeight + leading * 2; + currentHeight = 0; + // Begin added by Edgar Leonardo Prieto Perilla + indentation.indentLeft = tmpIndentLeft; + indentation.indentRight = tmpIndentRight; + // Begin added: Bonf (Marc Schneider) 2003-07-29 + indentation.listIndentLeft = tmpListIndentLeft; + indentation.imageIndentLeft = tmpImageIndentLeft; + indentation.imageIndentRight = tmpImageIndentRight; + // End added: Bonf (Marc Schneider) 2003-07-29 + // End added by Edgar Leonardo Prieto Perilla + } + + protected internal void DoHeader() { + // if there is a header, the header = added + if (header == null) return; + // Begin added by Edgar Leonardo Prieto Perilla + // Avoid header identation + float tmpIndentLeft = indentation.indentLeft; + float tmpIndentRight = indentation.indentRight; + // Begin added: Bonf (Marc Schneider) 2003-07-29 + float tmpListIndentLeft = indentation.listIndentLeft; + float tmpImageIndentLeft = indentation.imageIndentLeft; + float tmpImageIndentRight = indentation.imageIndentRight; + // End added: Bonf (Marc Schneider) 2003-07-29 + indentation.indentLeft = indentation.indentRight = 0; + // Added: Bonf + indentation.listIndentLeft = 0; + indentation.imageIndentLeft = 0; + indentation.imageIndentRight = 0; + // End added: Bonf + // Begin added by Edgar Leonardo Prieto Perilla + header.PageNumber = pageN; + leading = header.Paragraph.TotalLeading; + text.MoveText(0, leading); + Add(header.Paragraph); + NewLine(); + indentation.indentTop = currentHeight - leading; + header.Top = Top + leading; + header.Bottom = IndentTop + leading * 2 / 3; + header.Left = Left; + header.Right = Right; + graphics.Rectangle(header); + FlushLines(); + currentHeight = 0; + // Begin added by Edgar Leonardo Prieto Perilla + // Restore identation + indentation.indentLeft = tmpIndentLeft; + indentation.indentRight = tmpIndentRight; + // Begin added: Bonf (Marc Schneider) 2003-07-29 + indentation.listIndentLeft = tmpListIndentLeft; + indentation.imageIndentLeft = tmpImageIndentLeft; + indentation.imageIndentRight = tmpImageIndentRight; + // End added: Bonf (Marc Schneider) 2003-07-29 + // End Added by Edgar Leonardo Prieto Perilla + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfEncodings.cs b/iTechSharp/iTextSharp/text/pdf/PdfEncodings.cs new file mode 100644 index 0000000..e06fd12 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfEncodings.cs @@ -0,0 +1,782 @@ +using System; +using System.Collections; +using System.Globalization; +using System.IO; +using System.Text; +using System.util; +using iTextSharp.text.xml.simpleparser; + +/* + * Copyright 2002-2006 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { +/** Supports fast encodings for winansi and PDFDocEncoding. + * + * @author Paulo Soares (psoares@consiste.pt) + */ +public class PdfEncodings { + + protected const int CIDNONE = 0; + protected const int CIDRANGE = 1; + protected const int CIDCHAR = 2; + + internal static char[] winansiByteToChar = { + (char)0, (char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9, (char)10, (char)11, (char)12, (char)13, (char)14, (char)15, + (char)16, (char)17, (char)18, (char)19, (char)20, (char)21, (char)22, (char)23, (char)24, (char)25, (char)26, (char)27, (char)28, (char)29, (char)30, (char)31, + (char)32, (char)33, (char)34, (char)35, (char)36, (char)37, (char)38, (char)39, (char)40, (char)41, (char)42, (char)43, (char)44, (char)45, (char)46, (char)47, + (char)48, (char)49, (char)50, (char)51, (char)52, (char)53, (char)54, (char)55, (char)56, (char)57, (char)58, (char)59, (char)60, (char)61, (char)62, (char)63, + (char)64, (char)65, (char)66, (char)67, (char)68, (char)69, (char)70, (char)71, (char)72, (char)73, (char)74, (char)75, (char)76, (char)77, (char)78, (char)79, + (char)80, (char)81, (char)82, (char)83, (char)84, (char)85, (char)86, (char)87, (char)88, (char)89, (char)90, (char)91, (char)92, (char)93, (char)94, (char)95, + (char)96, (char)97, (char)98, (char)99, (char)100, (char)101, (char)102, (char)103, (char)104, (char)105, (char)106, (char)107, (char)108, (char)109, (char)110, (char)111, + (char)112, (char)113, (char)114, (char)115, (char)116, (char)117, (char)118, (char)119, (char)120, (char)121, (char)122, (char)123, (char)124, (char)125, (char)126, (char)127, + (char)8364, (char)65533, (char)8218, (char)402, (char)8222, (char)8230, (char)8224, (char)8225, (char)710, (char)8240, (char)352, (char)8249, (char)338, (char)65533, (char)381, (char)65533, + (char)65533, (char)8216, (char)8217, (char)8220, (char)8221, (char)8226, (char)8211, (char)8212, (char)732, (char)8482, (char)353, (char)8250, (char)339, (char)65533, (char)382, (char)376, + (char)160, (char)161, (char)162, (char)163, (char)164, (char)165, (char)166, (char)167, (char)168, (char)169, (char)170, (char)171, (char)172, (char)173, (char)174, (char)175, + (char)176, (char)177, (char)178, (char)179, (char)180, (char)181, (char)182, (char)183, (char)184, (char)185, (char)186, (char)187, (char)188, (char)189, (char)190, (char)191, + (char)192, (char)193, (char)194, (char)195, (char)196, (char)197, (char)198, (char)199, (char)200, (char)201, (char)202, (char)203, (char)204, (char)205, (char)206, (char)207, + (char)208, (char)209, (char)210, (char)211, (char)212, (char)213, (char)214, (char)215, (char)216, (char)217, (char)218, (char)219, (char)220, (char)221, (char)222, (char)223, + (char)224, (char)225, (char)226, (char)227, (char)228, (char)229, (char)230, (char)231, (char)232, (char)233, (char)234, (char)235, (char)236, (char)237, (char)238, (char)239, + (char)240, (char)241, (char)242, (char)243, (char)244, (char)245, (char)246, (char)247, (char)248, (char)249, (char)250, (char)251, (char)252, (char)253, (char)254, (char)255}; + + internal static char[] pdfEncodingByteToChar = { + (char)0, (char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9, (char)10, (char)11, (char)12, (char)13, (char)14, (char)15, + (char)16, (char)17, (char)18, (char)19, (char)20, (char)21, (char)22, (char)23, (char)24, (char)25, (char)26, (char)27, (char)28, (char)29, (char)30, (char)31, + (char)32, (char)33, (char)34, (char)35, (char)36, (char)37, (char)38, (char)39, (char)40, (char)41, (char)42, (char)43, (char)44, (char)45, (char)46, (char)47, + (char)48, (char)49, (char)50, (char)51, (char)52, (char)53, (char)54, (char)55, (char)56, (char)57, (char)58, (char)59, (char)60, (char)61, (char)62, (char)63, + (char)64, (char)65, (char)66, (char)67, (char)68, (char)69, (char)70, (char)71, (char)72, (char)73, (char)74, (char)75, (char)76, (char)77, (char)78, (char)79, + (char)80, (char)81, (char)82, (char)83, (char)84, (char)85, (char)86, (char)87, (char)88, (char)89, (char)90, (char)91, (char)92, (char)93, (char)94, (char)95, + (char)96, (char)97, (char)98, (char)99, (char)100, (char)101, (char)102, (char)103, (char)104, (char)105, (char)106, (char)107, (char)108, (char)109, (char)110, (char)111, + (char)112, (char)113, (char)114, (char)115, (char)116, (char)117, (char)118, (char)119, (char)120, (char)121, (char)122, (char)123, (char)124, (char)125, (char)126, (char)127, + (char)0x2022, (char)0x2020, (char)0x2021, (char)0x2026, (char)0x2014, (char)0x2013, (char)0x0192, (char)0x2044, (char)0x2039, (char)0x203a, (char)0x2212, (char)0x2030, (char)0x201e, (char)0x201c, (char)0x201d, (char)0x2018, + (char)0x2019, (char)0x201a, (char)0x2122, (char)0xfb01, (char)0xfb02, (char)0x0141, (char)0x0152, (char)0x0160, (char)0x0178, (char)0x017d, (char)0x0131, (char)0x0142, (char)0x0153, (char)0x0161, (char)0x017e, (char)65533, + (char)0x20ac, (char)161, (char)162, (char)163, (char)164, (char)165, (char)166, (char)167, (char)168, (char)169, (char)170, (char)171, (char)172, (char)173, (char)174, (char)175, + (char)176, (char)177, (char)178, (char)179, (char)180, (char)181, (char)182, (char)183, (char)184, (char)185, (char)186, (char)187, (char)188, (char)189, (char)190, (char)191, + (char)192, (char)193, (char)194, (char)195, (char)196, (char)197, (char)198, (char)199, (char)200, (char)201, (char)202, (char)203, (char)204, (char)205, (char)206, (char)207, + (char)208, (char)209, (char)210, (char)211, (char)212, (char)213, (char)214, (char)215, (char)216, (char)217, (char)218, (char)219, (char)220, (char)221, (char)222, (char)223, + (char)224, (char)225, (char)226, (char)227, (char)228, (char)229, (char)230, (char)231, (char)232, (char)233, (char)234, (char)235, (char)236, (char)237, (char)238, (char)239, + (char)240, (char)241, (char)242, (char)243, (char)244, (char)245, (char)246, (char)247, (char)248, (char)249, (char)250, (char)251, (char)252, (char)253, (char)254, (char)255}; + + internal static IntHashtable winansi = new IntHashtable(); + + internal static IntHashtable pdfEncoding = new IntHashtable(); + + internal static Hashtable extraEncodings = new Hashtable(); + + static PdfEncodings() { + for (int k = 128; k < 161; ++k) { + char c = winansiByteToChar[k]; + if (c != 65533) + winansi[c] = k; + } + + for (int k = 128; k < 161; ++k) { + char c = pdfEncodingByteToChar[k]; + if (c != 65533) + pdfEncoding[c] = k; + } + + AddExtraEncoding("Wingdings", new WingdingsConversion()); + AddExtraEncoding("Symbol", new SymbolConversion(true)); + AddExtraEncoding("ZapfDingbats", new SymbolConversion(false)); + AddExtraEncoding("SymbolTT", new SymbolTTConversion()); + AddExtraEncoding("Cp437", new Cp437Conversion()); + } + + /** + * Converts a string to a byte array according + * to the font's encoding. + * @param text the string to be converted + * @return an array of byte representing the conversion according to the font's encoding + */ + public static byte[] ConvertToBytes(string text, string encoding) { + if (text == null) + return new byte[0]; + if (encoding == null || encoding.Length == 0) { + int len = text.Length; + byte[] b = new byte[len]; + for (int k = 0; k < len; ++k) + b[k] = (byte)text[k]; + return b; + } + IExtraEncoding extra = (IExtraEncoding)extraEncodings[encoding.ToLower(System.Globalization.CultureInfo.InvariantCulture)]; + if (extra != null) { + byte[] b = extra.CharToByte(text, encoding); + if (b != null) + return b; + } + IntHashtable hash = null; + if (encoding.Equals(BaseFont.CP1252)) + hash = winansi; + else if (encoding.Equals(PdfObject.TEXT_PDFDOCENCODING)) + hash = pdfEncoding; + if (hash != null) { + char[] cc = text.ToCharArray(); + int len = cc.Length; + int ptr = 0; + byte[] b = new byte[len]; + int c = 0; + for (int k = 0; k < len; ++k) { + char char1 = cc[k]; + if (char1 < 128 || (char1 > 160 && char1 <= 255)) + c = char1; + else + c = hash[char1]; + if (c != 0) + b[ptr++] = (byte)c; + } + if (ptr == len) + return b; + byte[] b2 = new byte[ptr]; + Array.Copy(b, 0, b2, 0, ptr); + return b2; + } + Encoding encw = IanaEncodings.GetEncodingEncoding(encoding); + byte[] preamble = encw.GetPreamble(); + if (preamble.Length == 0) + return encw.GetBytes(text); + byte[] encoded = encw.GetBytes(text); + byte[] total = new byte[encoded.Length + preamble.Length]; + Array.Copy(preamble, 0, total, 0, preamble.Length); + Array.Copy(encoded, 0, total, preamble.Length, encoded.Length); + return total; + } + + /** Converts a String to a byte array according + * to the font's encoding. + * @return an array of byte representing the conversion according to the font's encoding + * @param encoding the encoding + * @param char1 the char to be converted + */ + public static byte[] ConvertToBytes(char char1, String encoding) { + if (encoding == null || encoding.Length == 0) + return new byte[]{(byte)char1}; + IExtraEncoding extra = (IExtraEncoding)extraEncodings[encoding.ToLower(System.Globalization.CultureInfo.InvariantCulture)]; + if (extra != null) { + byte[] b = extra.CharToByte(char1, encoding); + if (b != null) + return b; + } + IntHashtable hash = null; + if (encoding.Equals(BaseFont.WINANSI)) + hash = winansi; + else if (encoding.Equals(PdfObject.TEXT_PDFDOCENCODING)) + hash = pdfEncoding; + if (hash != null) { + int c = 0; + if (char1 < 128 || (char1 > 160 && char1 <= 255)) + c = char1; + else + c = hash[char1]; + if (c != 0) + return new byte[]{(byte)c}; + else + return new byte[0]; + } + Encoding encw = IanaEncodings.GetEncodingEncoding(encoding); + byte[] preamble = encw.GetPreamble(); + char[] text = new char[]{char1}; + if (preamble.Length == 0) + return encw.GetBytes(text); + byte[] encoded = encw.GetBytes(text); + byte[] total = new byte[encoded.Length + preamble.Length]; + Array.Copy(preamble, 0, total, 0, preamble.Length); + Array.Copy(encoded, 0, total, preamble.Length, encoded.Length); + return total; + } + + public static string ConvertToString(byte[] bytes, string encoding) { + if (bytes == null) + return PdfObject.NOTHING; + if (encoding == null || encoding.Length == 0) { + char[] c = new char[bytes.Length]; + for (int k = 0; k < bytes.Length; ++k) + c[k] = (char)(bytes[k] & 0xff); + return new String(c); + } + IExtraEncoding extra = (IExtraEncoding)extraEncodings[encoding.ToLower(System.Globalization.CultureInfo.InvariantCulture)]; + if (extra != null) { + String text = extra.ByteToChar(bytes, encoding); + if (text != null) + return text; + } + char[] ch = null; + if (encoding.Equals(BaseFont.WINANSI)) + ch = winansiByteToChar; + else if (encoding.Equals(PdfObject.TEXT_PDFDOCENCODING)) + ch = pdfEncodingByteToChar; + if (ch != null) { + int len = bytes.Length; + char[] c = new char[len]; + for (int k = 0; k < len; ++k) { + c[k] = ch[bytes[k] & 0xff]; + } + return new String(c); + } + String nameU = encoding.ToUpper(System.Globalization.CultureInfo.InvariantCulture); + bool marker = false; + bool big = false; + int offset = 0; + if (bytes.Length >= 2) { + if (bytes[0] == (byte)254 && bytes[1] == (byte)255) { + marker = true; + big = true; + offset = 2; + } + else if (bytes[0] == (byte)255 && bytes[1] == (byte)254) { + marker = true; + big = false; + offset = 2; + } + } + Encoding enc = null; + if (nameU.Equals("UNICODEBIGUNMARKED") || nameU.Equals("UNICODEBIG")) + enc = new UnicodeEncoding(marker ? big : true, false); + if (nameU.Equals("UNICODELITTLEUNMARKED") || nameU.Equals("UNICODELITTLE")) + enc = new UnicodeEncoding(marker ? big : false, false); + if (enc != null) + return enc.GetString(bytes, offset, bytes.Length - offset); + return IanaEncodings.GetEncodingEncoding(encoding).GetString(bytes); + } + + /** Checks is text only has PdfDocEncoding characters. + * @param text the String to test + * @return true if only PdfDocEncoding characters are present + */ + public static bool IsPdfDocEncoding(String text) { + if (text == null) + return true; + int len = text.Length; + for (int k = 0; k < len; ++k) { + char char1 = text[k]; + if (char1 < 128 || (char1 > 160 && char1 <= 255)) + continue; + if (!pdfEncoding.ContainsKey(char1)) + return false; + } + return true; + } + + internal static Hashtable cmaps = new Hashtable(); + /** Assumes that '\\n' and '\\r\\n' are the newline sequences. It may not work for + * all CJK encodings. To be used with LoadCmap(). + */ + public static byte[][] CRLF_CID_NEWLINE = new byte[][]{new byte[]{(byte)'\n'}, new byte[]{(byte)'\r', (byte)'\n'}}; + + /** Clears the CJK cmaps from the cache. If name is the + * empty string then all the cache is cleared. Calling this method + * has no consequences other than the need to reload the cmap + * if needed. + * @param name the name of the cmap to clear or all the cmaps if the empty string + */ + public static void ClearCmap(String name) { + lock (cmaps) { + if (name.Length == 0) + cmaps.Clear(); + else + cmaps.Remove(name); + } + } + + /** Loads a CJK cmap to the cache with the option of associating + * sequences to the newline. + * @param name the CJK cmap name + * @param newline the sequences to be replaced bi a newline in the resulting CID. See CRLF_CID_NEWLINE + */ + public static void LoadCmap(String name, byte[][] newline) { + char[][] planes = null; + lock (cmaps) { + planes = (char[][])cmaps[name]; + } + if (planes == null) { + planes = ReadCmap(name, newline); + lock (cmaps) { + cmaps[name] = planes; + } + } + } + + /** Converts a byte array encoded as name + * to a CID string. This is needed to reach some CJK characters + * that don't exist in 16 bit Unicode.

    + * The font to use this result must use the encoding "Identity-H" + * or "Identity-V".

    + * See ftp://ftp.oreilly.com/pub/examples/nutshell/cjkv/adobe/. + * @param name the CJK encoding name + * @param seq the byte array to be decoded + * @return the CID string + */ + public static String ConvertCmap(String name, byte[] seq) { + return ConvertCmap(name, seq, 0, seq.Length); + } + + /** Converts a byte array encoded as name + * to a CID string. This is needed to reach some CJK characters + * that don't exist in 16 bit Unicode.

    + * The font to use this result must use the encoding "Identity-H" + * or "Identity-V".

    + * See ftp://ftp.oreilly.com/pub/examples/nutshell/cjkv/adobe/. + * @param name the CJK encoding name + * @param start the start offset in the data + * @param length the number of bytes to convert + * @param seq the byte array to be decoded + * @return the CID string + */ + public static String ConvertCmap(String name, byte[] seq, int start, int length) { + char[][] planes = null; + lock (cmaps) { + planes = (char[][])cmaps[name]; + } + if (planes == null) { + planes = ReadCmap(name, (byte[][])null); + lock (cmaps) { + cmaps[name] = planes; + } + } + return DecodeSequence(seq, start, length, planes); + } + + internal static String DecodeSequence(byte[] seq, int start, int length, char[][] planes) { + StringBuilder buf = new StringBuilder(); + int end = start + length; + int currentPlane = 0; + for (int k = start; k < end; ++k) { + int one = (int)seq[k] & 0xff; + char[] plane = planes[currentPlane]; + int cid = plane[one]; + if ((cid & 0x8000) == 0) { + buf.Append((char)cid); + currentPlane = 0; + } + else + currentPlane = cid & 0x7fff; + } + return buf.ToString(); + } + + internal static char[][] ReadCmap(String name, byte[][] newline) { + ArrayList planes = new ArrayList(); + planes.Add(new char[256]); + ReadCmap(name, planes); + if (newline != null) { + for (int k = 0; k < newline.Length; ++k) + EncodeSequence(newline[k].Length, newline[k], BaseFont.CID_NEWLINE, planes); + } + char[][] ret = new char[planes.Count][]; + planes.CopyTo(ret, 0); + return ret; + } + + internal static void ReadCmap(String name, ArrayList planes) { + String fullName = BaseFont.RESOURCE_PATH + "cmaps." + name; + Stream inp = BaseFont.GetResourceStream(fullName); + if (inp == null) + throw new IOException("The Cmap " + name + " was not found."); + EncodeStream(inp, planes); + inp.Close(); + } + + internal static void EncodeStream(Stream inp, ArrayList planes) { + StreamReader rd = new StreamReader(inp, Encoding.ASCII); + String line = null; + int state = CIDNONE; + byte[] seqs = new byte[7]; + while ((line = rd.ReadLine()) != null) { + if (line.Length < 6) + continue; + switch (state) { + case CIDNONE: { + if (line.IndexOf("begincidrange") >= 0) + state = CIDRANGE; + else if (line.IndexOf("begincidchar") >= 0) + state = CIDCHAR; + else if (line.IndexOf("usecmap") >= 0) { + StringTokenizer tk = new StringTokenizer(line); + String t = tk.NextToken(); + ReadCmap(t.Substring(1), planes); + } + break; + } + case CIDRANGE: { + if (line.IndexOf("endcidrange") >= 0) { + state = CIDNONE; + break; + } + StringTokenizer tk = new StringTokenizer(line); + String t = tk.NextToken(); + int size = t.Length / 2 - 1; + long start = long.Parse(t.Substring(1, t.Length - 2), NumberStyles.HexNumber); + t = tk.NextToken(); + long end = long.Parse(t.Substring(1, t.Length - 2), NumberStyles.HexNumber); + t = tk.NextToken(); + int cid = int.Parse(t); + for (long k = start; k <= end; ++k) { + BreakLong(k, size, seqs); + EncodeSequence(size, seqs, (char)cid, planes); + ++cid; + } + break; + } + case CIDCHAR: { + if (line.IndexOf("endcidchar") >= 0) { + state = CIDNONE; + break; + } + StringTokenizer tk = new StringTokenizer(line); + String t = tk.NextToken(); + int size = t.Length / 2 - 1; + long start = long.Parse(t.Substring(1, t.Length - 2), NumberStyles.HexNumber); + t = tk.NextToken(); + int cid = int.Parse(t); + BreakLong(start, size, seqs); + EncodeSequence(size, seqs, (char)cid, planes); + break; + } + } + } + } + + internal static void BreakLong(long n, int size, byte[] seqs) { + for (int k = 0; k < size; ++k) { + seqs[k] = (byte)(n >> ((size - 1 - k) * 8)); + } + } + + internal static void EncodeSequence(int size, byte[] seqs, char cid, ArrayList planes) { + --size; + int nextPlane = 0; + char[] plane; + for (int idx = 0; idx < size; ++idx) { + plane = (char[])planes[nextPlane]; + int one = (int)seqs[idx] & 0xff; + char c = plane[one]; + if (c != 0 && (c & 0x8000) == 0) + throw new Exception("Inconsistent mapping."); + if (c == 0) { + planes.Add(new char[256]); + c = (char)((planes.Count - 1) | 0x8000); + plane[one] = c; + } + nextPlane = c & 0x7fff; + } + plane = (char[])planes[nextPlane]; + int ones = (int)seqs[size] & 0xff; + char cc = plane[ones]; + if ((cc & 0x8000) != 0) + throw new Exception("Inconsistent mapping."); + plane[ones] = cid; + } + + /** Adds an extra encoding. + * @param name the name of the encoding. The encoding recognition is case insensitive + * @param enc the conversion class + */ + public static void AddExtraEncoding(String name, IExtraEncoding enc) { + lock (extraEncodings) { // This serializes concurrent updates + Hashtable newEncodings = (Hashtable)extraEncodings.Clone(); + newEncodings[name.ToLower(System.Globalization.CultureInfo.InvariantCulture)] = enc; + extraEncodings = newEncodings; // This swap does not require synchronization with reader + } + } + + private class WingdingsConversion : IExtraEncoding { + + public byte[] CharToByte(char char1, String encoding) { + if (char1 == ' ') + return new byte[]{(byte)char1}; + else if (char1 >= '\u2701' && char1 <= '\u27BE') { + byte v = table[char1 - 0x2700]; + if (v != 0) + return new byte[]{v}; + } + return new byte[0]; + } + + public byte[] CharToByte(String text, String encoding) { + char[] cc = text.ToCharArray(); + byte[] b = new byte[cc.Length]; + int ptr = 0; + int len = cc.Length; + for (int k = 0; k < len; ++k) { + char c = cc[k]; + if (c == ' ') + b[ptr++] = (byte)c; + else if (c >= '\u2701' && c <= '\u27BE') { + byte v = table[c - 0x2700]; + if (v != 0) + b[ptr++] = v; + } + } + if (ptr == len) + return b; + byte[] b2 = new byte[ptr]; + Array.Copy(b, 0, b2, 0, ptr); + return b2; + } + + public String ByteToChar(byte[] b, String encoding) { + return null; + } + + private static byte[] table = { + 0, 35, 34, 0, 0, 0, 41, 62, 81, 42, + 0, 0, 65, 63, 0, 0, 0, 0, 0, (byte)(256-4), + 0, 0, 0, (byte)(256-5), 0, 0, 0, 0, 0, 0, + 86, 0, 88, 89, 0, 0, 0, 0, 0, 0, + 0, 0, (byte)(256-75), 0, 0, 0, 0, 0, (byte)(256-74), 0, + 0, 0, (byte)(256-83), (byte)(256-81), (byte)(256-84), 0, 0, 0, 0, 0, + 0, 0, 0, 124, 123, 0, 0, 0, 84, 0, + 0, 0, 0, 0, 0, 0, 0, (byte)(256-90), 0, 0, + 0, 113, 114, 0, 0, 0, 117, 0, 0, 0, + 0, 0, 0, 125, 126, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, (byte)(256-116), (byte)(256-115), + (byte)(256-114), (byte)(256-113), (byte)(256-112), (byte)(256-111), (byte)(256-110), (byte)(256-109), (byte)(256-108), (byte)(256-107), (byte)(256-127), (byte)(256-126), + (byte)(256-125), (byte)(256-124), (byte)(256-123), (byte)(256-122), (byte)(256-121), (byte)(256-120), (byte)(256-119), (byte)(256-118), (byte)(256-116), (byte)(256-115), + (byte)(256-114), (byte)(256-113), (byte)(256-112), (byte)(256-111), (byte)(256-110), (byte)(256-109), (byte)(256-108), (byte)(256-107), (byte)(256-24), 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, (byte)(256-24), (byte)(256-40), 0, 0, (byte)(256-60), (byte)(256-58), 0, 0, (byte)(256-16), + 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte)(256-36), + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0 + }; + } + + private class Cp437Conversion : IExtraEncoding { + private static IntHashtable c2b = new IntHashtable(); + + public byte[] CharToByte(String text, String encoding) { + char[] cc = text.ToCharArray(); + byte[] b = new byte[cc.Length]; + int ptr = 0; + int len = cc.Length; + for (int k = 0; k < len; ++k) { + char c = cc[k]; + if (c < 128) + b[ptr++] = (byte)c; + else { + byte v = (byte)c2b[c]; + if (v != 0) + b[ptr++] = v; + } + } + if (ptr == len) + return b; + byte[] b2 = new byte[ptr]; + Array.Copy(b, 0, b2, 0, ptr); + return b2; + } + + public byte[] CharToByte(char char1, String encoding) { + if (char1 < 128) + return new byte[]{(byte)char1}; + else { + byte v = (byte)c2b[char1]; + if (v != 0) + return new byte[]{v}; + else + return new byte[0]; + } + } + + public String ByteToChar(byte[] b, String encoding) { + int len = b.Length; + char[] cc = new char[len]; + int ptr = 0; + for (int k = 0; k < len; ++k) { + int c = b[k] & 0xff; + if (c < ' ') + continue; + if (c < 128) + cc[ptr++] = (char)c; + else { + char v = table[c - 128]; + cc[ptr++] = v; + } + } + return new String(cc, 0, ptr); + } + + private static char[] table = { + '\u00C7', '\u00FC', '\u00E9', '\u00E2', '\u00E4', '\u00E0', '\u00E5', '\u00E7', '\u00EA', '\u00EB', '\u00E8', '\u00EF', '\u00EE', '\u00EC', '\u00C4', '\u00C5', + '\u00C9', '\u00E6', '\u00C6', '\u00F4', '\u00F6', '\u00F2', '\u00FB', '\u00F9', '\u00FF', '\u00D6', '\u00DC', '\u00A2', '\u00A3', '\u00A5', '\u20A7', '\u0192', + '\u00E1', '\u00ED', '\u00F3', '\u00FA', '\u00F1', '\u00D1', '\u00AA', '\u00BA', '\u00BF', '\u2310', '\u00AC', '\u00BD', '\u00BC', '\u00A1', '\u00AB', '\u00BB', + '\u2591', '\u2592', '\u2593', '\u2502', '\u2524', '\u2561', '\u2562', '\u2556', '\u2555', '\u2563', '\u2551', '\u2557', '\u255D', '\u255C', '\u255B', '\u2510', + '\u2514', '\u2534', '\u252C', '\u251C', '\u2500', '\u253C', '\u255E', '\u255F', '\u255A', '\u2554', '\u2569', '\u2566', '\u2560', '\u2550', '\u256C', '\u2567', + '\u2568', '\u2564', '\u2565', '\u2559', '\u2558', '\u2552', '\u2553', '\u256B', '\u256A', '\u2518', '\u250C', '\u2588', '\u2584', '\u258C', '\u2590', '\u2580', + '\u03B1', '\u00DF', '\u0393', '\u03C0', '\u03A3', '\u03C3', '\u00B5', '\u03C4', '\u03A6', '\u0398', '\u03A9', '\u03B4', '\u221E', '\u03C6', '\u03B5', '\u2229', + '\u2261', '\u00B1', '\u2265', '\u2264', '\u2320', '\u2321', '\u00F7', '\u2248', '\u00B0', '\u2219', '\u00B7', '\u221A', '\u207F', '\u00B2', '\u25A0', '\u00A0' + }; + + static Cp437Conversion() { + for (int k = 0; k < table.Length; ++k) + c2b[table[k]] = k + 128; + } + } + + private class SymbolConversion : IExtraEncoding { + + private static IntHashtable t1 = new IntHashtable(); + private static IntHashtable t2 = new IntHashtable(); + private IntHashtable translation; + + internal SymbolConversion(bool symbol) { + if (symbol) + translation = t1; + else + translation = t2; + } + + public byte[] CharToByte(String text, String encoding) { + char[] cc = text.ToCharArray(); + byte[] b = new byte[cc.Length]; + int ptr = 0; + int len = cc.Length; + for (int k = 0; k < len; ++k) { + char c = cc[k]; + byte v = (byte)translation[(int)c]; + if (v != 0) + b[ptr++] = v; + } + if (ptr == len) + return b; + byte[] b2 = new byte[ptr]; + Array.Copy(b, 0, b2, 0, ptr); + return b2; + } + + public byte[] CharToByte(char char1, String encoding) { + byte v = (byte)translation[(int)char1]; + if (v != 0) + return new byte[]{v}; + else + return new byte[0]; + } + + public String ByteToChar(byte[] b, String encoding) { + return null; + } + + private static char[] table1 = { + ' ','!','\u2200','#','\u2203','%','&','\u220b','(',')','*','+',',','-','.','/', + '0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?', + '\u2245','\u0391','\u0392','\u03a7','\u0394','\u0395','\u03a6','\u0393','\u0397','\u0399','\u03d1','\u039a','\u039b','\u039c','\u039d','\u039f', + '\u03a0','\u0398','\u03a1','\u03a3','\u03a4','\u03a5','\u03c2','\u03a9','\u039e','\u03a8','\u0396','[','\u2234',']','\u22a5','_', + '\u0305','\u03b1','\u03b2','\u03c7','\u03b4','\u03b5','\u03d5','\u03b3','\u03b7','\u03b9','\u03c6','\u03ba','\u03bb','\u03bc','\u03bd','\u03bf', + '\u03c0','\u03b8','\u03c1','\u03c3','\u03c4','\u03c5','\u03d6','\u03c9','\u03be','\u03c8','\u03b6','{','|','}','~','\0', + '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0', + '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0', + '\u20ac','\u03d2','\u2032','\u2264','\u2044','\u221e','\u0192','\u2663','\u2666','\u2665','\u2660','\u2194','\u2190','\u2191','\u2192','\u2193', + '\u00b0','\u00b1','\u2033','\u2265','\u00d7','\u221d','\u2202','\u2022','\u00f7','\u2260','\u2261','\u2248','\u2026','\u2502','\u2500','\u21b5', + '\u2135','\u2111','\u211c','\u2118','\u2297','\u2295','\u2205','\u2229','\u222a','\u2283','\u2287','\u2284','\u2282','\u2286','\u2208','\u2209', + '\u2220','\u2207','\u00ae','\u00a9','\u2122','\u220f','\u221a','\u2022','\u00ac','\u2227','\u2228','\u21d4','\u21d0','\u21d1','\u21d2','\u21d3', + '\u25ca','\u2329','\0','\0','\0','\u2211','\u239b','\u239c','\u239d','\u23a1','\u23a2','\u23a3','\u23a7','\u23a8','\u23a9','\u23aa', + '\0','\u232a','\u222b','\u2320','\u23ae','\u2321','\u239e','\u239f','\u23a0','\u23a4','\u23a5','\u23a6','\u23ab','\u23ac','\u23ad','\0' + }; + + private static char[] table2 = { + '\u0020','\u2701','\u2702','\u2703','\u2704','\u260e','\u2706','\u2707','\u2708','\u2709','\u261b','\u261e','\u270C','\u270D','\u270E','\u270F', + '\u2710','\u2711','\u2712','\u2713','\u2714','\u2715','\u2716','\u2717','\u2718','\u2719','\u271A','\u271B','\u271C','\u271D','\u271E','\u271F', + '\u2720','\u2721','\u2722','\u2723','\u2724','\u2725','\u2726','\u2727','\u2605','\u2729','\u272A','\u272B','\u272C','\u272D','\u272E','\u272F', + '\u2730','\u2731','\u2732','\u2733','\u2734','\u2735','\u2736','\u2737','\u2738','\u2739','\u273A','\u273B','\u273C','\u273D','\u273E','\u273F', + '\u2740','\u2741','\u2742','\u2743','\u2744','\u2745','\u2746','\u2747','\u2748','\u2749','\u274A','\u274B','\u25cf','\u274D','\u25a0','\u274F', + '\u2750','\u2751','\u2752','\u25b2','\u25bc','\u25c6','\u2756','\u25d7','\u2758','\u2759','\u275A','\u275B','\u275C','\u275D','\u275E','\u0000', + '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0', + '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0', + '\u0000','\u2761','\u2762','\u2763','\u2764','\u2765','\u2766','\u2767','\u2663','\u2666','\u2665','\u2660','\u2460','\u2461','\u2462','\u2463', + '\u2464','\u2465','\u2466','\u2467','\u2468','\u2469','\u2776','\u2777','\u2778','\u2779','\u277A','\u277B','\u277C','\u277D','\u277E','\u277F', + '\u2780','\u2781','\u2782','\u2783','\u2784','\u2785','\u2786','\u2787','\u2788','\u2789','\u278A','\u278B','\u278C','\u278D','\u278E','\u278F', + '\u2790','\u2791','\u2792','\u2793','\u2794','\u2192','\u2194','\u2195','\u2798','\u2799','\u279A','\u279B','\u279C','\u279D','\u279E','\u279F', + '\u27A0','\u27A1','\u27A2','\u27A3','\u27A4','\u27A5','\u27A6','\u27A7','\u27A8','\u27A9','\u27AA','\u27AB','\u27AC','\u27AD','\u27AE','\u27AF', + '\u0000','\u27B1','\u27B2','\u27B3','\u27B4','\u27B5','\u27B6','\u27B7','\u27B8','\u27B9','\u27BA','\u27BB','\u27BC','\u27BD','\u27BE','\u0000' + }; + + static SymbolConversion(){ + for (int k = 0; k < table1.Length; ++k) { + int v = (int)table1[k]; + if (v != 0) + t1[v] = k + 32; + } + for (int k = 0; k < table2.Length; ++k) { + int v = (int)table2[k]; + if (v != 0) + t2[v] = k + 32; + } + } + } + + private class SymbolTTConversion : IExtraEncoding { + + public byte[] CharToByte(char char1, String encoding) { + if ((char1 & 0xff00) == 0 || (char1 & 0xff00) == 0xf000) + return new byte[]{(byte)char1}; + else + return new byte[0]; + } + + public byte[] CharToByte(String text, String encoding) { + char[] ch = text.ToCharArray(); + byte[] b = new byte[ch.Length]; + int ptr = 0; + int len = ch.Length; + for (int k = 0; k < len; ++k) { + char c = ch[k]; + if ((c & 0xff00) == 0 || (c & 0xff00) == 0xf000) + b[ptr++] = (byte)c; + } + if (ptr == len) + return b; + byte[] b2 = new byte[ptr]; + Array.Copy(b, 0, b2, 0, ptr); + return b2; + } + + public String ByteToChar(byte[] b, String encoding) { + return null; + } + } +} +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfEncryption.cs b/iTechSharp/iTextSharp/text/pdf/PdfEncryption.cs new file mode 100644 index 0000000..155e1d0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfEncryption.cs @@ -0,0 +1,512 @@ +using System; +using System.Collections; +using System.Security.Cryptography; +using System.Text; +using System.IO; +using iTextSharp.text.pdf.crypto; +using Org.BouncyCastle.X509; + +/* + * $Id: PdfEncryption.cs,v 1.13 2007/06/14 20:01:48 psoares33 Exp $ + * + * Copyright 2001-2006 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + +/** + * + * @author Paulo Soares (psoares@consiste.pt) + */ +public class PdfEncryption { + + public const int STANDARD_ENCRYPTION_40 = 2; + public const int STANDARD_ENCRYPTION_128 = 3; + public const int AES_128 = 4; + + private static byte[] pad = { + (byte)0x28, (byte)0xBF, (byte)0x4E, (byte)0x5E, (byte)0x4E, (byte)0x75, + (byte)0x8A, (byte)0x41, (byte)0x64, (byte)0x00, (byte)0x4E, (byte)0x56, + (byte)0xFF, (byte)0xFA, (byte)0x01, (byte)0x08, (byte)0x2E, (byte)0x2E, + (byte)0x00, (byte)0xB6, (byte)0xD0, (byte)0x68, (byte)0x3E, (byte)0x80, + (byte)0x2F, (byte)0x0C, (byte)0xA9, (byte)0xFE, (byte)0x64, (byte)0x53, + (byte)0x69, (byte)0x7A}; + + private static readonly byte[] salt = {(byte)0x73, (byte)0x41, (byte)0x6c, (byte)0x54}; + internal static readonly byte[] metadataPad = {(byte)255,(byte)255,(byte)255,(byte)255}; + /** The encryption key for a particular object/generation */ + internal byte[] key; + /** The encryption key length for a particular object/generation */ + internal int keySize; + /** The global encryption key */ + internal byte[] mkey; + /** Work area to prepare the object/generation bytes */ + internal byte[] extra = new byte[5]; + /** The message digest algorithm MD5 */ + internal MD5 md5; + /** The encryption key for the owner */ + internal byte[] ownerKey = new byte[32]; + /** The encryption key for the user */ + internal byte[] userKey = new byte[32]; + /** The public key security handler for certificate encryption */ + protected PdfPublicKeySecurityHandler publicKeyHandler = null; + internal int permissions; + internal byte[] documentID; + internal static long seq = DateTime.Now.Ticks + Environment.TickCount; + private int revision; + private ARCFOUREncryption rc4 = new ARCFOUREncryption(); + /** The generic key length. It may be 40 or 128. */ + private int keyLength; + private bool encryptMetadata; + private int cryptoMode; + + public PdfEncryption() { + md5 = new MD5CryptoServiceProvider(); + publicKeyHandler = new PdfPublicKeySecurityHandler(); + } + + public PdfEncryption(PdfEncryption enc) : this() { + mkey = (byte[])enc.mkey.Clone(); + ownerKey = (byte[])enc.ownerKey.Clone(); + userKey = (byte[])enc.userKey.Clone(); + permissions = enc.permissions; + if (enc.documentID != null) + documentID = (byte[])enc.documentID.Clone(); + revision = enc.revision; + keyLength = enc.keyLength; + encryptMetadata = enc.encryptMetadata; + publicKeyHandler = enc.publicKeyHandler; + } + + public void SetCryptoMode(int mode, int kl) { + cryptoMode = mode; + encryptMetadata = (mode & PdfWriter.DO_NOT_ENCRYPT_METADATA) == 0; + mode &= PdfWriter.ENCRYPTION_MASK; + switch (mode) { + case PdfWriter.STANDARD_ENCRYPTION_40: + encryptMetadata = true; + keyLength = 40; + revision = STANDARD_ENCRYPTION_40; + break; + case PdfWriter.STANDARD_ENCRYPTION_128: + if (kl > 0) + keyLength = kl; + else + keyLength = 128; + revision = STANDARD_ENCRYPTION_128; + break; + case PdfWriter.ENCRYPTION_AES_128: + keyLength = 128; + revision = AES_128; + break; + default: + throw new ArgumentException("No valid encryption mode"); + } + } + + public int GetCryptoMode() { + return cryptoMode; + } + + public bool IsMetadataEncrypted() { + return encryptMetadata; + } + + private byte[] PadPassword(byte[] userPassword) { + byte[] userPad = new byte[32]; + if (userPassword == null) { + Array.Copy(pad, 0, userPad, 0, 32); + } + else { + Array.Copy(userPassword, 0, userPad, 0, Math.Min(userPassword.Length, 32)); + if (userPassword.Length < 32) + Array.Copy(pad, 0, userPad, userPassword.Length, 32 - userPassword.Length); + } + + return userPad; + } + + /** + */ + private byte[] ComputeOwnerKey(byte[] userPad, byte[] ownerPad) { + byte[] ownerKey = new byte[32]; + + byte[] digest = md5.ComputeHash(ownerPad); + if (revision == STANDARD_ENCRYPTION_128 || revision == AES_128) { + byte[] mkey = new byte[keyLength / 8]; + // only use for the input as many bit as the key consists of + for (int k = 0; k < 50; ++k) + Array.Copy(md5.ComputeHash(digest), 0, digest, 0, mkey.Length); + Array.Copy(userPad, 0, ownerKey, 0, 32); + for (int i = 0; i < 20; ++i) { + for (int j = 0; j < mkey.Length ; ++j) + mkey[j] = (byte)(digest[j] ^ i); + rc4.PrepareARCFOURKey(mkey); + rc4.EncryptARCFOUR(ownerKey); + } + } + else { + rc4.PrepareARCFOURKey(digest, 0, 5); + rc4.EncryptARCFOUR(userPad, ownerKey); + } + + return ownerKey; + } + + /** + * + * ownerKey, documentID must be setuped + */ + private void SetupGlobalEncryptionKey(byte[] documentID, byte[] userPad, byte[] ownerKey, int permissions) { + this.documentID = documentID; + this.ownerKey = ownerKey; + this.permissions = permissions; + // use variable keylength + mkey = new byte[keyLength / 8]; + + //fixed by ujihara in order to follow PDF refrence + md5.Initialize(); + md5.TransformBlock(userPad, 0, userPad.Length, userPad, 0); + md5.TransformBlock(ownerKey, 0, ownerKey.Length, ownerKey, 0); + + byte[] ext = new byte[4]; + ext[0] = (byte)permissions; + ext[1] = (byte)(permissions >> 8); + ext[2] = (byte)(permissions >> 16); + ext[3] = (byte)(permissions >> 24); + md5.TransformBlock(ext, 0, 4, ext, 0); + if (documentID != null) + md5.TransformBlock(documentID, 0, documentID.Length, documentID, 0); + if (!encryptMetadata) + md5.TransformBlock(metadataPad, 0, metadataPad.Length, metadataPad, 0); + md5.TransformFinalBlock(ext, 0, 0); + + byte[] digest = new byte[mkey.Length]; + Array.Copy(md5.Hash, 0, digest, 0, mkey.Length); + + + md5.Initialize(); + // only use the really needed bits as input for the hash + if (revision == STANDARD_ENCRYPTION_128 || revision == AES_128) { + for (int k = 0; k < 50; ++k) { + Array.Copy(md5.ComputeHash(digest), 0, digest, 0, mkey.Length); + md5.Initialize(); + } + } + Array.Copy(digest, 0, mkey, 0, mkey.Length); + } + + /** + * + * mkey must be setuped + */ + // use the revision to choose the setup method + private void SetupUserKey() { + if (revision == STANDARD_ENCRYPTION_128 || revision == AES_128) { + md5.TransformBlock(pad, 0, pad.Length, pad, 0); + md5.TransformFinalBlock(documentID, 0, documentID.Length); + byte[] digest = md5.Hash; + md5.Initialize(); + Array.Copy(digest, 0, userKey, 0, 16); + for (int k = 16; k < 32; ++k) + userKey[k] = 0; + for (int i = 0; i < 20; ++i) { + for (int j = 0; j < mkey.Length; ++j) + digest[j] = (byte)(mkey[j] ^ i); + rc4.PrepareARCFOURKey(digest, 0, mkey.Length); + rc4.EncryptARCFOUR(userKey, 0, 16); + } + } + else { + rc4.PrepareARCFOURKey(mkey); + rc4.EncryptARCFOUR(pad, userKey); + } + } + + // gets keylength and revision and uses revison to choose the initial values for permissions + public void SetupAllKeys(byte[] userPassword, byte[] ownerPassword, int permissions) { + if (ownerPassword == null || ownerPassword.Length == 0) + ownerPassword = md5.ComputeHash(CreateDocumentId()); + md5.Initialize(); + permissions |= (int)((revision == STANDARD_ENCRYPTION_128 || revision == AES_128) ? (uint)0xfffff0c0 : (uint)0xffffffc0); + permissions &= unchecked((int)0xfffffffc); + //PDF refrence 3.5.2 Standard Security Handler, Algorithum 3.3-1 + //If there is no owner password, use the user password instead. + byte[] userPad = PadPassword(userPassword); + byte[] ownerPad = PadPassword(ownerPassword); + + this.ownerKey = ComputeOwnerKey(userPad, ownerPad); + documentID = CreateDocumentId(); + SetupByUserPad(this.documentID, userPad, this.ownerKey, permissions); + } + + public static byte[] CreateDocumentId() { + MD5 md5 = new MD5CryptoServiceProvider(); + long time = DateTime.Now.Ticks + Environment.TickCount; + long mem = GC.GetTotalMemory(false); + String s = time + "+" + mem + "+" + (seq++); + return md5.ComputeHash(Encoding.ASCII.GetBytes(s)); + } + + public void SetupByUserPassword(byte[] documentID, byte[] userPassword, byte[] ownerKey, int permissions) { + SetupByUserPad(documentID, PadPassword(userPassword), ownerKey, permissions); + } + + /** + */ + private void SetupByUserPad(byte[] documentID, byte[] userPad, byte[] ownerKey, int permissions) { + SetupGlobalEncryptionKey(documentID, userPad, ownerKey, permissions); + SetupUserKey(); + } + + /** + */ + public void SetupByOwnerPassword(byte[] documentID, byte[] ownerPassword, byte[] userKey, byte[] ownerKey, int permissions) { + SetupByOwnerPad(documentID, PadPassword(ownerPassword), userKey, ownerKey, permissions); + } + + private void SetupByOwnerPad(byte[] documentID, byte[] ownerPad, byte[] userKey, byte[] ownerKey, int permissions) { + byte[] userPad = ComputeOwnerKey(ownerKey, ownerPad); //userPad will be set in this.ownerKey + SetupGlobalEncryptionKey(documentID, userPad, ownerKey, permissions); //step 3 + SetupUserKey(); + } + + public void SetupByEncryptionKey(byte[] key, int keylength) { + mkey = new byte[keylength/8]; + System.Array.Copy(key, 0, mkey, 0, mkey.Length); + } + + public void SetHashKey(int number, int generation) { + md5.Initialize(); //added by ujihara + extra[0] = (byte)number; + extra[1] = (byte)(number >> 8); + extra[2] = (byte)(number >> 16); + extra[3] = (byte)generation; + extra[4] = (byte)(generation >> 8); + md5.TransformBlock(mkey, 0, mkey.Length, mkey, 0); + md5.TransformBlock(extra, 0, extra.Length, extra, 0); + if (revision == AES_128) + md5.TransformBlock(salt, 0, salt.Length, salt, 0); + md5.TransformFinalBlock(extra, 0, 0); + key = md5.Hash; + md5.Initialize(); + keySize = mkey.Length + 5; + if (keySize > 16) + keySize = 16; + } + + public static PdfObject CreateInfoId(byte[] id) { + ByteBuffer buf = new ByteBuffer(90); + buf.Append('[').Append('<'); + for (int k = 0; k < 16; ++k) + buf.AppendHex(id[k]); + buf.Append('>').Append('<'); + id = CreateDocumentId(); + for (int k = 0; k < 16; ++k) + buf.AppendHex(id[k]); + buf.Append('>').Append(']'); + return new PdfLiteral(buf.ToByteArray()); + } + + public PdfDictionary GetEncryptionDictionary() { + PdfDictionary dic = new PdfDictionary(); + + if (publicKeyHandler.GetRecipientsSize() > 0) { + PdfArray recipients = null; + + dic.Put(PdfName.FILTER, PdfName.PUBSEC); + dic.Put(PdfName.R, new PdfNumber(revision)); + + recipients = publicKeyHandler.GetEncodedRecipients(); + + if (revision == STANDARD_ENCRYPTION_40) { + dic.Put(PdfName.V, new PdfNumber(1)); + dic.Put(PdfName.SUBFILTER, PdfName.ADBE_PKCS7_S4); + dic.Put(PdfName.RECIPIENTS, recipients); + } + else if (revision == STANDARD_ENCRYPTION_128 && encryptMetadata) { + dic.Put(PdfName.V, new PdfNumber(2)); + dic.Put(PdfName.LENGTH, new PdfNumber(128)); + dic.Put(PdfName.SUBFILTER, PdfName.ADBE_PKCS7_S4); + dic.Put(PdfName.RECIPIENTS, recipients); + } + else { + dic.Put(PdfName.R, new PdfNumber(AES_128)); + dic.Put(PdfName.V, new PdfNumber(4)); + dic.Put(PdfName.SUBFILTER, PdfName.ADBE_PKCS7_S5); + + PdfDictionary stdcf = new PdfDictionary(); + stdcf.Put(PdfName.RECIPIENTS, recipients); + if (!encryptMetadata) + stdcf.Put(PdfName.ENCRYPTMETADATA, PdfBoolean.PDFFALSE); + + if (revision == AES_128) + stdcf.Put(PdfName.CFM, PdfName.AESV2); + else + stdcf.Put(PdfName.CFM, PdfName.V2); + PdfDictionary cf = new PdfDictionary(); + cf.Put(PdfName.DEFAULTCRYPTFILER, stdcf); + dic.Put(PdfName.CF, cf); + dic.Put(PdfName.STRF, PdfName.DEFAULTCRYPTFILER); + dic.Put(PdfName.STMF, PdfName.DEFAULTCRYPTFILER); + } + + SHA1 sh = new SHA1CryptoServiceProvider(); + byte[] encodedRecipient = null; + byte[] seed = publicKeyHandler.GetSeed(); + sh.TransformBlock(seed, 0, seed.Length, seed, 0); + for (int i=0; iPdfWriter. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param reader the read PDF + * @param os the output destination + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param strength128Bits true for 128 bit key length, false for 40 bit key length + * @throws DocumentException on error + * @throws IOException on error */ + public static void Encrypt(PdfReader reader, Stream os, byte[] userPassword, byte[] ownerPassword, int permissions, bool strength128Bits) { + PdfStamper stamper = new PdfStamper(reader, os); + stamper.SetEncryption(userPassword, ownerPassword, permissions, strength128Bits); + stamper.Close(); + } + + /** Entry point to encrypt a PDF document. The encryption parameters are the same as in + * PdfWriter. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param reader the read PDF + * @param os the output destination + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param strength128Bits true for 128 bit key length, false for 40 bit key length + * @param newInfo an optional String map to add or change + * the info dictionary. Entries with null + * values delete the key in the original info dictionary + * @throws DocumentException on error + * @throws IOException on error + */ + public static void Encrypt(PdfReader reader, Stream os, byte[] userPassword, byte[] ownerPassword, int permissions, bool strength128Bits, Hashtable newInfo) { + PdfStamper stamper = new PdfStamper(reader, os); + stamper.SetEncryption(userPassword, ownerPassword, permissions, strength128Bits); + stamper.MoreInfo = newInfo; + stamper.Close(); + } + + /** Entry point to encrypt a PDF document. The encryption parameters are the same as in + * PdfWriter. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param reader the read PDF + * @param os the output destination + * @param strength true for 128 bit key length, false for 40 bit key length + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @throws DocumentException on error + * @throws IOException on error */ + public static void Encrypt(PdfReader reader, Stream os, bool strength, String userPassword, String ownerPassword, int permissions) { + PdfStamper stamper = new PdfStamper(reader, os); + stamper.SetEncryption(strength, userPassword, ownerPassword, permissions); + stamper.Close(); + } + + /** Entry point to encrypt a PDF document. The encryption parameters are the same as in + * PdfWriter. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param reader the read PDF + * @param os the output destination + * @param strength true for 128 bit key length, false for 40 bit key length + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param newInfo an optional String map to add or change + * the info dictionary. Entries with null + * values delete the key in the original info dictionary + * @throws DocumentException on error + * @throws IOException on error + */ + public static void Encrypt(PdfReader reader, Stream os, bool strength, String userPassword, String ownerPassword, int permissions, Hashtable newInfo) { + PdfStamper stamper = new PdfStamper(reader, os); + stamper.SetEncryption(strength, userPassword, ownerPassword, permissions); + stamper.MoreInfo = newInfo; + stamper.Close(); + } + + /** Entry point to encrypt a PDF document. The encryption parameters are the same as in + * PdfWriter. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param reader the read PDF + * @param os the output destination + * @param type the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param newInfo an optional String map to add or change + * the info dictionary. Entries with null + * values delete the key in the original info dictionary + * @throws DocumentException on error + * @throws IOException on error + */ + public static void Encrypt(PdfReader reader, Stream os, int type, String userPassword, String ownerPassword, int permissions, Hashtable newInfo) { + PdfStamper stamper = new PdfStamper(reader, os); + stamper.SetEncryption(type, userPassword, ownerPassword, permissions); + stamper.MoreInfo = newInfo; + stamper.Close(); + } + + /** Entry point to encrypt a PDF document. The encryption parameters are the same as in + * PdfWriter. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param reader the read PDF + * @param os the output destination + * @param type the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * values delete the key in the original info dictionary + * @throws DocumentException on error + * @throws IOException on error + */ + public static void Encrypt(PdfReader reader, Stream os, int type, String userPassword, String ownerPassword, int permissions) { + PdfStamper stamper = new PdfStamper(reader, os); + stamper.SetEncryption(type, userPassword, ownerPassword, permissions); + stamper.Close(); + } + + /** + * Give you a verbose analysis of the permissions. + * @param permissions the permissions value of a PDF file + * @return a String that explains the meaning of the permissions value + */ + public static String GetPermissionsVerbose(int permissions) { + StringBuilder buf = new StringBuilder("Allowed:"); + if ((PdfWriter.ALLOW_PRINTING & permissions) == PdfWriter.ALLOW_PRINTING) buf.Append(" Printing"); + if ((PdfWriter.ALLOW_MODIFY_CONTENTS & permissions) == PdfWriter.ALLOW_MODIFY_CONTENTS) buf.Append(" Modify contents"); + if ((PdfWriter.ALLOW_COPY & permissions) == PdfWriter.ALLOW_COPY) buf.Append(" Copy"); + if ((PdfWriter.ALLOW_MODIFY_ANNOTATIONS & permissions) == PdfWriter.ALLOW_MODIFY_ANNOTATIONS) buf.Append(" Modify annotations"); + if ((PdfWriter.ALLOW_FILL_IN & permissions) == PdfWriter.ALLOW_FILL_IN) buf.Append(" Fill in"); + if ((PdfWriter.ALLOW_SCREENREADERS & permissions) == PdfWriter.ALLOW_SCREENREADERS) buf.Append(" Screen readers"); + if ((PdfWriter.ALLOW_ASSEMBLY & permissions) == PdfWriter.ALLOW_ASSEMBLY) buf.Append(" Assembly"); + if ((PdfWriter.ALLOW_DEGRADED_PRINTING & permissions) == PdfWriter.ALLOW_DEGRADED_PRINTING) buf.Append(" Degraded printing"); + return buf.ToString(); + } + + /** + * Tells you if printing is allowed. + * @param permissions the permissions value of a PDF file + * @return true if printing is allowed + * + * @since 2.0.7 + */ + public static bool IsPrintingAllowed(int permissions) { + return (PdfWriter.ALLOW_PRINTING & permissions) == PdfWriter.ALLOW_PRINTING; + } + + /** + * Tells you if modifying content is allowed. + * @param permissions the permissions value of a PDF file + * @return true if modifying content is allowed + * + * @since 2.0.7 + */ + public static bool IsModifyContentsAllowed(int permissions) { + return (PdfWriter.ALLOW_MODIFY_CONTENTS & permissions) == PdfWriter.ALLOW_MODIFY_CONTENTS; + } + + /** + * Tells you if copying is allowed. + * @param permissions the permissions value of a PDF file + * @return true if copying is allowed + * + * @since 2.0.7 + */ + public static bool IsCopyAllowed(int permissions) { + return (PdfWriter.ALLOW_COPY & permissions) == PdfWriter.ALLOW_COPY; + } + + /** + * Tells you if modifying annotations is allowed. + * @param permissions the permissions value of a PDF file + * @return true if modifying annotations is allowed + * + * @since 2.0.7 + */ + public static bool IsModifyAnnotationsAllowed(int permissions) { + return (PdfWriter.ALLOW_MODIFY_ANNOTATIONS & permissions) == PdfWriter.ALLOW_MODIFY_ANNOTATIONS; + } + + /** + * Tells you if filling in fields is allowed. + * @param permissions the permissions value of a PDF file + * @return true if filling in fields is allowed + * + * @since 2.0.7 + */ + public static bool IsFillInAllowed(int permissions) { + return (PdfWriter.ALLOW_FILL_IN & permissions) == PdfWriter.ALLOW_FILL_IN; + } + + /** + * Tells you if repurposing for screenreaders is allowed. + * @param permissions the permissions value of a PDF file + * @return true if repurposing for screenreaders is allowed + * + * @since 2.0.7 + */ + public static bool IsScreenReadersAllowed(int permissions) { + return (PdfWriter.ALLOW_SCREENREADERS & permissions) == PdfWriter.ALLOW_SCREENREADERS; + } + + /** + * Tells you if document assembly is allowed. + * @param permissions the permissions value of a PDF file + * @return true if document assembly is allowed + * + * @since 2.0.7 + */ + public static bool IsAssemblyAllowed(int permissions) { + return (PdfWriter.ALLOW_ASSEMBLY & permissions) == PdfWriter.ALLOW_ASSEMBLY; + } + + /** + * Tells you if degraded printing is allowed. + * @param permissions the permissions value of a PDF file + * @return true if degraded printing is allowed + * + * @since 2.0.7 + */ + public static bool IsDegradedPrintingAllowed(int permissions) { + return (PdfWriter.ALLOW_DEGRADED_PRINTING & permissions) == PdfWriter.ALLOW_DEGRADED_PRINTING; + } +} +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfException.cs b/iTechSharp/iTextSharp/text/pdf/PdfException.cs new file mode 100644 index 0000000..a31ac47 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfException.cs @@ -0,0 +1,68 @@ +using System; + +using iTextSharp.text; + +/* + * $Id: PdfException.cs,v 1.3 2008/05/13 11:25:20 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Signals that an unspecified problem while constructing a PDF document. + * + * @see BadPdfFormatException + */ + + public class PdfException : DocumentException { + public PdfException() : base() {} + + public PdfException(string message) : base(message) {} + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfFileSpecification.cs b/iTechSharp/iTextSharp/text/pdf/PdfFileSpecification.cs new file mode 100644 index 0000000..d6e77d5 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfFileSpecification.cs @@ -0,0 +1,261 @@ +using System; +using System.IO; +using System.Net; +using iTextSharp.text.pdf.collection; +/* + * Copyright 2003 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except inp compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added inp the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), inp which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed inp the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** Specifies a file or an URL. The file can be extern or embedded. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfFileSpecification : PdfDictionary { + protected PdfWriter writer; + protected PdfIndirectReference refi; + + /** Creates a new instance of PdfFileSpecification. The static methods are preferred. */ + public PdfFileSpecification() : base(PdfName.FILESPEC) { + } + + /** + * Creates a file specification of type URL. + * @param writer the PdfWriter + * @param url the URL + * @return the file specification + */ + public static PdfFileSpecification Url(PdfWriter writer, String url) { + PdfFileSpecification fs = new PdfFileSpecification(); + fs.writer = writer; + fs.Put(PdfName.FS, PdfName.URL); + fs.Put(PdfName.F, new PdfString(url)); + return fs; + } + + /** + * Creates a file specification with the file embedded. The file may + * come from the file system or from a byte array. The data is flate compressed. + * @param writer the PdfWriter + * @param filePath the file path + * @param fileDisplay the file information that is presented to the user + * @param fileStore the byte array with the file. If it is not null + * it takes precedence over filePath + * @throws IOException on error + * @return the file specification + */ + public static PdfFileSpecification FileEmbedded(PdfWriter writer, String filePath, String fileDisplay, byte[] fileStore) { + return FileEmbedded(writer, filePath, fileDisplay, fileStore, true); + } + + + /** + * Creates a file specification with the file embedded. The file may + * come from the file system or from a byte array. + * @param writer the PdfWriter + * @param filePath the file path + * @param fileDisplay the file information that is presented to the user + * @param fileStore the byte array with the file. If it is not null + * it takes precedence over filePath + * @param compress sets the compression on the data. Multimedia content will benefit little + * from compression + * @throws IOException on error + * @return the file specification + */ + public static PdfFileSpecification FileEmbedded(PdfWriter writer, String filePath, String fileDisplay, byte[] fileStore, bool compress) { + return FileEmbedded(writer, filePath, fileDisplay, fileStore, compress, null, null); + } + + /** + * Creates a file specification with the file embedded. The file may + * come from the file system or from a byte array. + * @param writer the PdfWriter + * @param filePath the file path + * @param fileDisplay the file information that is presented to the user + * @param fileStore the byte array with the file. If it is not null + * it takes precedence over filePath + * @param compress sets the compression on the data. Multimedia content will benefit little + * from compression + * @param mimeType the optional mimeType + * @param fileParameter the optional extra file parameters such as the creation or modification date + * @throws IOException on error + * @return the file specification + */ + public static PdfFileSpecification FileEmbedded(PdfWriter writer, String filePath, String fileDisplay, byte[] fileStore, bool compress, String mimeType, PdfDictionary fileParameter) { + PdfFileSpecification fs = new PdfFileSpecification(); + fs.writer = writer; + fs.Put(PdfName.F, new PdfString(fileDisplay)); + PdfStream stream; + Stream inp = null; + PdfIndirectReference refi; + PdfIndirectReference refFileLength; + try { + refFileLength = writer.PdfIndirectReference; + if (fileStore == null) { + if (File.Exists(filePath)) { + inp = new FileStream(filePath, FileMode.Open, FileAccess.Read); + } + else { + if (filePath.StartsWith("file:/") || filePath.StartsWith("http://") || filePath.StartsWith("https://")) { + WebRequest w = WebRequest.Create(filePath); + inp = w.GetResponse().GetResponseStream(); + } + else { + inp = BaseFont.GetResourceStream(filePath); + if (inp == null) + throw new IOException(filePath + " not found as file or resource."); + } + } + stream = new PdfStream(inp, writer); + } + else + stream = new PdfStream(fileStore); + stream.Put(PdfName.TYPE, PdfName.EMBEDDEDFILE); + if (compress) + stream.FlateCompress(); + stream.Put(PdfName.PARAMS, refFileLength); + if (mimeType != null) + stream.Put(PdfName.SUBTYPE, new PdfName(mimeType)); + refi = writer.AddToBody(stream).IndirectReference; + if (fileStore == null) { + stream.WriteLength(); + } + PdfDictionary param = new PdfDictionary(); + if (fileParameter != null) + param.Merge(fileParameter); + param.Put(PdfName.SIZE, new PdfNumber(stream.RawLength)); + writer.AddToBody(param, refFileLength); + } + finally { + if (inp != null) + try{inp.Close();}catch{} + } + PdfDictionary f = new PdfDictionary(); + f.Put(PdfName.F, refi); + fs.Put(PdfName.EF, f); + return fs; + } + + /** + * Creates a file specification for an external file. + * @param writer the PdfWriter + * @param filePath the file path + * @return the file specification + */ + public static PdfFileSpecification FileExtern(PdfWriter writer, String filePath) { + PdfFileSpecification fs = new PdfFileSpecification(); + fs.writer = writer; + fs.Put(PdfName.F, new PdfString(filePath)); + return fs; + } + + /** + * Gets the indirect reference to this file specification. + * Multiple invocations will retrieve the same value. + * @throws IOException on error + * @return the indirect reference + */ + public PdfIndirectReference Reference { + get { + if (refi != null) + return refi; + refi = writer.AddToBody(this).IndirectReference; + return refi; + } + } + + /** + * Sets the file name (the key /F) string as an hex representation + * to support multi byte file names. The name must have the slash and + * backslash escaped according to the file specification rules + * @param fileName the file name as a byte array + */ + public byte[] MultiByteFileName { + set { + Put(PdfName.F, new PdfString(value).SetHexWriting(true)); + } + } + + /** + * Adds the unicode file name (the key /UF). This entry was introduced + * in PDF 1.7. The filename must have the slash and backslash escaped + * according to the file specification rules. + * @param filename the filename + * @param unicode if true, the filename is UTF-16BE encoded; otherwise PDFDocEncoding is used; + */ + public void SetUnicodeFileName(String filename, bool unicode) { + Put(PdfName.UF, new PdfString(filename, unicode ? PdfObject.TEXT_UNICODE : PdfObject.TEXT_PDFDOCENCODING)); + } + + /** + * Sets a flag that indicates whether an external file referenced by the file + * specification is volatile. If the value is true, applications should never + * cache a copy of the file. + * @param volatile_file if true, the external file should not be cached + */ + public bool Volatile { + set { + Put(PdfName.V, new PdfBoolean(value)); + } + } + + /** + * Adds a description for the file that is specified here. + * @param description some text + * @param unicode if true, the text is added as a unicode string + */ + public void AddDescription(String description, bool unicode) { + Put(PdfName.DESC, new PdfString(description, unicode ? PdfObject.TEXT_UNICODE : PdfObject.TEXT_PDFDOCENCODING)); + } + + /** + * Adds the Collection item dictionary. + */ + public void AddCollectionItem(PdfCollectionItem ci) { + Put(PdfName.CI, ci); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfFont.cs b/iTechSharp/iTextSharp/text/pdf/PdfFont.cs new file mode 100644 index 0000000..c4649b6 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfFont.cs @@ -0,0 +1,193 @@ +using System; +using iTextSharp.text; +/* + * $Id: PdfFont.cs,v 1.4 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfFont is the Pdf Font object. + *

    + * Limitation: in this class only base 14 Type 1 fonts (courier, courier bold, courier oblique, + * courier boldoblique, helvetica, helvetica bold, helvetica oblique, helvetica boldoblique, + * symbol, times roman, times bold, times italic, times bolditalic, zapfdingbats) and their + * standard encoding (standard, MacRoman, (MacExpert,) WinAnsi) are supported.
    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 7.7 (page 198-203). + * + * @see PdfName + * @see PdfDictionary + * @see BadPdfFormatException + */ + + public class PdfFont : IComparable { + + + /** the font metrics. */ + private BaseFont font; + + /** the size. */ + private float size; + + /** an image. */ + protected Image image; + + protected float hScale = 1; + + // constructors + + internal PdfFont(BaseFont bf, float size) { + this.size = size; + font = bf; + } + + // methods + + /** + * Compares this PdfFont with another + * + * @param object the other PdfFont + * @return a value + */ + + public int CompareTo(Object obj) { + if (image != null) + return 0; + if (obj == null) { + return -1; + } + PdfFont pdfFont; + try { + pdfFont = (PdfFont) obj; + if (font != pdfFont.font) { + return 1; + } + if (this.Size != pdfFont.Size) { + return 2; + } + return 0; + } + catch (InvalidCastException) { + return -2; + } + } + + /** + * Returns the size of this font. + * + * @return a size + */ + + internal float Size { + get { + if (image == null) + return size; + else { + return image.ScaledHeight; + } + } + } + + /** + * Returns the approximative width of 1 character of this font. + * + * @return a width in Text Space + */ + + internal float Width() { + return Width(' '); + } + + /** + * Returns the width of a certain character of this font. + * + * @param character a certain character + * @return a width in Text Space + */ + + internal float Width(int character) { + if (image == null) + return font.GetWidthPoint(character, size) * hScale; + else + return image.ScaledWidth; + } + + internal float Width(String s) { + if (image == null) + return font.GetWidthPoint(s, size) * hScale; + else + return image.ScaledWidth; + } + + internal BaseFont Font { + get { + return font; + } + } + + internal Image Image { + set { + this.image = value; + } + } + + internal static PdfFont DefaultFont { + get { + BaseFont bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.WINANSI, false); + return new PdfFont(bf, 12); + } + } + + internal float HorizontalScaling { + set { + this.hScale = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfFormField.cs b/iTechSharp/iTextSharp/text/pdf/PdfFormField.cs new file mode 100644 index 0000000..d0cd5e4 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfFormField.cs @@ -0,0 +1,353 @@ +using System; +using System.Drawing; +using System.Collections; + +using iTextSharp.text; + +/* + * Copyright 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Implements form fields. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfFormField : PdfAnnotation { + + public const int FF_READ_ONLY = 1; + public const int FF_REQUIRED = 2; + public const int FF_NO_EXPORT = 4; + public const int FF_NO_TOGGLE_TO_OFF = 16384; + public const int FF_RADIO = 32768; + public const int FF_PUSHBUTTON = 65536; + public const int FF_MULTILINE = 4096; + public const int FF_PASSWORD = 8192; + public const int FF_COMBO = 131072; + public const int FF_EDIT = 262144; + public const int FF_FILESELECT = 1048576; + public const int FF_MULTISELECT = 2097152; + public const int FF_DONOTSPELLCHECK = 4194304; + public const int FF_DONOTSCROLL = 8388608; + public const int FF_COMB = 16777216; + public const int FF_RADIOSINUNISON = 1 << 25; + public const int Q_LEFT = 0; + public const int Q_CENTER = 1; + public const int Q_RIGHT = 2; + public const int MK_NO_ICON = 0; + public const int MK_NO_CAPTION = 1; + public const int MK_CAPTION_BELOW = 2; + public const int MK_CAPTION_ABOVE = 3; + public const int MK_CAPTION_RIGHT = 4; + public const int MK_CAPTION_LEFT = 5; + public const int MK_CAPTION_OVERLAID = 6; + public static readonly PdfName IF_SCALE_ALWAYS = PdfName.A; + public static readonly PdfName IF_SCALE_BIGGER = PdfName.B; + public static readonly PdfName IF_SCALE_SMALLER = PdfName.S; + public static readonly PdfName IF_SCALE_NEVER = PdfName.N; + public static readonly PdfName IF_SCALE_ANAMORPHIC = PdfName.A; + public static readonly PdfName IF_SCALE_PROPORTIONAL = PdfName.P; + public const bool MULTILINE = true; + public const bool SINGLELINE = false; + public const bool PLAINTEXT = false; + public const bool PASSWORD = true; + public static PdfName[] mergeTarget = {PdfName.FONT, PdfName.XOBJECT, PdfName.COLORSPACE, PdfName.PATTERN}; + + /** Holds value of property parent. */ + internal PdfFormField parent; + + internal ArrayList kids; + + /** + * Constructs a new PdfAnnotation of subtype link (Action). + */ + + public PdfFormField(PdfWriter writer, float llx, float lly, float urx, float ury, PdfAction action) : base(writer, llx, lly, urx, ury, action) { + Put(PdfName.TYPE, PdfName.ANNOT); + Put(PdfName.SUBTYPE, PdfName.WIDGET); + annotation = true; + } + + /** Creates new PdfFormField */ + internal PdfFormField(PdfWriter writer) : base(writer, null) { + form = true; + annotation = false; + } + + public void SetWidget(Rectangle rect, PdfName highlight) { + Put(PdfName.TYPE, PdfName.ANNOT); + Put(PdfName.SUBTYPE, PdfName.WIDGET); + Put(PdfName.RECT, new PdfRectangle(rect)); + annotation = true; + if (highlight != null && !highlight.Equals(HIGHLIGHT_INVERT)) + Put(PdfName.H, highlight); + } + + public static PdfFormField CreateEmpty(PdfWriter writer) { + PdfFormField field = new PdfFormField(writer); + return field; + } + + public int Button { + set { + Put(PdfName.FT, PdfName.BTN); + if (value != 0) + Put(PdfName.FF, new PdfNumber(value)); + } + } + + protected static PdfFormField CreateButton(PdfWriter writer, int flags) { + PdfFormField field = new PdfFormField(writer); + field.Button = flags; + return field; + } + + public static PdfFormField CreatePushButton(PdfWriter writer) { + return CreateButton(writer, FF_PUSHBUTTON); + } + + public static PdfFormField CreateCheckBox(PdfWriter writer) { + return CreateButton(writer, 0); + } + + public static PdfFormField CreateRadioButton(PdfWriter writer, bool noToggleToOff) { + return CreateButton(writer, FF_RADIO + (noToggleToOff ? FF_NO_TOGGLE_TO_OFF : 0)); + } + + public static PdfFormField CreateTextField(PdfWriter writer, bool multiline, bool password, int maxLen) { + PdfFormField field = new PdfFormField(writer); + field.Put(PdfName.FT, PdfName.TX); + int flags = (multiline ? FF_MULTILINE : 0); + flags += (password ? FF_PASSWORD : 0); + field.Put(PdfName.FF, new PdfNumber(flags)); + if (maxLen > 0) + field.Put(PdfName.MAXLEN, new PdfNumber(maxLen)); + return field; + } + + protected static PdfFormField CreateChoice(PdfWriter writer, int flags, PdfArray options, int topIndex) { + PdfFormField field = new PdfFormField(writer); + field.Put(PdfName.FT, PdfName.CH); + field.Put(PdfName.FF, new PdfNumber(flags)); + field.Put(PdfName.OPT, options); + if (topIndex > 0) + field.Put(PdfName.TI, new PdfNumber(topIndex)); + return field; + } + + public static PdfFormField CreateList(PdfWriter writer, String[] options, int topIndex) { + return CreateChoice(writer, 0, ProcessOptions(options), topIndex); + } + + public static PdfFormField CreateList(PdfWriter writer, String[,] options, int topIndex) { + return CreateChoice(writer, 0, ProcessOptions(options), topIndex); + } + + public static PdfFormField CreateCombo(PdfWriter writer, bool edit, String[] options, int topIndex) { + return CreateChoice(writer, FF_COMBO + (edit ? FF_EDIT : 0), ProcessOptions(options), topIndex); + } + + public static PdfFormField CreateCombo(PdfWriter writer, bool edit, String[,] options, int topIndex) { + return CreateChoice(writer, FF_COMBO + (edit ? FF_EDIT : 0), ProcessOptions(options), topIndex); + } + + protected static PdfArray ProcessOptions(String[] options) { + PdfArray array = new PdfArray(); + for (int k = 0; k < options.Length; ++k) { + array.Add(new PdfString(options[k], PdfObject.TEXT_UNICODE)); + } + return array; + } + + protected static PdfArray ProcessOptions(String[,] options) { + PdfArray array = new PdfArray(); + for (int k = 0; k < options.GetLength(0); ++k) { + PdfArray ar2 = new PdfArray(new PdfString(options[k, 0], PdfObject.TEXT_UNICODE)); + ar2.Add(new PdfString(options[k, 1], PdfObject.TEXT_UNICODE)); + array.Add(ar2); + } + return array; + } + + public static PdfFormField CreateSignature(PdfWriter writer) { + PdfFormField field = new PdfFormField(writer); + field.Put(PdfName.FT, PdfName.SIG); + return field; + } + + /** Getter for property parent. + * @return Value of property parent. + */ + public PdfFormField Parent { + get { + return parent; + } + } + + public void AddKid(PdfFormField field) { + field.parent = this; + if (kids == null) + kids = new ArrayList(); + kids.Add(field); + } + + public ArrayList Kids { + get { + return kids; + } + } + + public int SetFieldFlags(int flags) { + PdfNumber obj = (PdfNumber)Get(PdfName.FF); + int old; + if (obj == null) + old = 0; + else + old = obj.IntValue; + int v = old | flags; + Put(PdfName.FF, new PdfNumber(v)); + return old; + } + + public string ValueAsString { + set { + Put(PdfName.V, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public string ValueAsName { + set { + Put(PdfName.V, new PdfName(value)); + } + } + + public PdfSignature ValueAsSig { + set { + Put(PdfName.V, value); + } + } + + public string DefaultValueAsString { + set { + Put(PdfName.DV, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public string DefaultValueAsName { + set { + Put(PdfName.DV, new PdfName(value)); + } + } + + public string FieldName { + set { + if (value != null) + Put(PdfName.T, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public string UserName { + set { + Put(PdfName.TU, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public string MappingName { + set { + Put(PdfName.TM, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public int Quadding { + set { + Put(PdfName.Q, new PdfNumber(value)); + } + } + + internal static void MergeResources(PdfDictionary result, PdfDictionary source, PdfStamperImp writer) { + PdfDictionary dic = null; + PdfDictionary res = null; + PdfName target = null; + for (int k = 0; k < mergeTarget.Length; ++k) { + target = mergeTarget[k]; + PdfDictionary pdfDict = (PdfDictionary)PdfReader.GetPdfObject(source.Get(target)); + if ((dic = pdfDict) != null) { + if ((res = (PdfDictionary)PdfReader.GetPdfObject(result.Get(target), result)) == null) { + res = new PdfDictionary(); + } + res.MergeDifferent(dic); + result.Put(target, res); + if (writer != null) + writer.MarkUsed(res); + } + } + } + + internal static void MergeResources(PdfDictionary result, PdfDictionary source) { + MergeResources(result, source, null); + } + + public override void SetUsed() { + used = true; + if (parent != null) + Put(PdfName.PARENT, parent.IndirectReference); + if (kids != null) { + PdfArray array = new PdfArray(); + for (int k = 0; k < kids.Count; ++k) + array.Add(((PdfFormField)kids[k]).IndirectReference); + Put(PdfName.KIDS, array); + } + if (templates == null) + return; + PdfDictionary dic = new PdfDictionary(); + foreach (PdfTemplate template in templates.Keys) { + MergeResources(dic, (PdfDictionary)template.Resources); + } + Put(PdfName.DR, dic); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfFormXObject.cs b/iTechSharp/iTextSharp/text/pdf/PdfFormXObject.cs new file mode 100644 index 0000000..fc9916a --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfFormXObject.cs @@ -0,0 +1,104 @@ +using System; + +/* + * $Id: PdfFormXObject.cs,v 1.3 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfFormObject is a type of XObject containing a template-object. + */ + + public class PdfFormXObject : PdfStream { + + // public static variables + + /** This is a PdfNumber representing 0. */ + public static PdfNumber ZERO = new PdfNumber(0); + + /** This is a PdfNumber representing 1. */ + public static PdfNumber ONE = new PdfNumber(1); + + /** This is the 1 - matrix. */ + public static PdfLiteral MATRIX = new PdfLiteral("[1 0 0 1 0 0]"); + + // membervariables + + + // constructor + + /** + * Constructs a PdfFormXObject-object. + * + * @param template the template + */ + + internal PdfFormXObject(PdfTemplate template) : base() { + Put(PdfName.TYPE, PdfName.XOBJECT); + Put(PdfName.SUBTYPE, PdfName.FORM); + Put(PdfName.RESOURCES, template.Resources); + Put(PdfName.BBOX, new PdfRectangle(template.BoundingBox)); + Put(PdfName.FORMTYPE, ONE); + PdfArray matrix = template.Matrix; + if (template.Layer != null) + Put(PdfName.OC, template.Layer.Ref); + if (template.Group != null) + Put(PdfName.GROUP, template.Group); + if (matrix == null) + Put(PdfName.MATRIX, MATRIX); + else + Put(PdfName.MATRIX, matrix); + bytes = template.ToPdf(null); + Put(PdfName.LENGTH, new PdfNumber(bytes.Length)); + FlateCompress(); + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfFunction.cs b/iTechSharp/iTextSharp/text/pdf/PdfFunction.cs new file mode 100644 index 0000000..ad484ec --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfFunction.cs @@ -0,0 +1,141 @@ +using System; +using System.IO; + +/* + * Copyright 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** Implements PDF functions. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfFunction { + + protected PdfWriter writer; + + protected PdfIndirectReference reference; + + protected PdfDictionary dictionary; + + /** Creates new PdfFunction */ + protected PdfFunction(PdfWriter writer) { + this.writer = writer; + } + + internal PdfIndirectReference Reference { + get { + if (reference == null) { + reference = writer.AddToBody(dictionary).IndirectReference; + } + return reference; + } + } + + public static PdfFunction Type0(PdfWriter writer, float[] domain, float[] range, int[] size, + int bitsPerSample, int order, float[] encode, float[] decode, byte[] stream) { + PdfFunction func = new PdfFunction(writer); + func.dictionary = new PdfStream(stream); + ((PdfStream)func.dictionary).FlateCompress(); + func.dictionary.Put(PdfName.FUNCTIONTYPE, new PdfNumber(0)); + func.dictionary.Put(PdfName.DOMAIN, new PdfArray(domain)); + func.dictionary.Put(PdfName.RANGE, new PdfArray(range)); + func.dictionary.Put(PdfName.SIZE, new PdfArray(size)); + func.dictionary.Put(PdfName.BITSPERSAMPLE, new PdfNumber(bitsPerSample)); + if (order != 1) + func.dictionary.Put(PdfName.ORDER, new PdfNumber(order)); + if (encode != null) + func.dictionary.Put(PdfName.ENCODE, new PdfArray(encode)); + if (decode != null) + func.dictionary.Put(PdfName.DECODE, new PdfArray(decode)); + return func; + } + + public static PdfFunction Type2(PdfWriter writer, float[] domain, float[] range, float[] c0, float[] c1, float n) { + PdfFunction func = new PdfFunction(writer); + func.dictionary = new PdfDictionary(); + func.dictionary.Put(PdfName.FUNCTIONTYPE, new PdfNumber(2)); + func.dictionary.Put(PdfName.DOMAIN, new PdfArray(domain)); + if (range != null) + func.dictionary.Put(PdfName.RANGE, new PdfArray(range)); + if (c0 != null) + func.dictionary.Put(PdfName.C0, new PdfArray(c0)); + if (c1 != null) + func.dictionary.Put(PdfName.C1, new PdfArray(c1)); + func.dictionary.Put(PdfName.N, new PdfNumber(n)); + return func; + } + + public static PdfFunction Type3(PdfWriter writer, float[] domain, float[] range, PdfFunction[] functions, float[] bounds, float[] encode) { + PdfFunction func = new PdfFunction(writer); + func.dictionary = new PdfDictionary(); + func.dictionary.Put(PdfName.FUNCTIONTYPE, new PdfNumber(3)); + func.dictionary.Put(PdfName.DOMAIN, new PdfArray(domain)); + if (range != null) + func.dictionary.Put(PdfName.RANGE, new PdfArray(range)); + PdfArray array = new PdfArray(); + for (int k = 0; k < functions.Length; ++k) + array.Add(functions[k].Reference); + func.dictionary.Put(PdfName.FUNCTIONS, array); + func.dictionary.Put(PdfName.BOUNDS, new PdfArray(bounds)); + func.dictionary.Put(PdfName.ENCODE, new PdfArray(encode)); + return func; + } + + public static PdfFunction Type4(PdfWriter writer, float[] domain, float[] range, string postscript) { + byte[] b = new byte[postscript.Length]; + for (int k = 0; k < b.Length; ++k) + b[k] = (byte)postscript[k]; + PdfFunction func = new PdfFunction(writer); + func.dictionary = new PdfStream(b); + ((PdfStream)func.dictionary).FlateCompress(); + func.dictionary.Put(PdfName.FUNCTIONTYPE, new PdfNumber(4)); + func.dictionary.Put(PdfName.DOMAIN, new PdfArray(domain)); + func.dictionary.Put(PdfName.RANGE, new PdfArray(range)); + return func; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfGState.cs b/iTechSharp/iTextSharp/text/pdf/PdfGState.cs new file mode 100644 index 0000000..f9f81e8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfGState.cs @@ -0,0 +1,170 @@ +using System; +/* + * Copyright 2003 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** The graphic state dictionary. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfGState : PdfDictionary { + /** A possible blend mode */ + public static PdfName BM_NORMAL = new PdfName("Normal"); + /** A possible blend mode */ + public static PdfName BM_COMPATIBLE = new PdfName("Compatible"); + /** A possible blend mode */ + public static PdfName BM_MULTIPLY = new PdfName("Multiply"); + /** A possible blend mode */ + public static PdfName BM_SCREEN = new PdfName("Screen"); + /** A possible blend mode */ + public static PdfName BM_OVERLAY = new PdfName("Overlay"); + /** A possible blend mode */ + public static PdfName BM_DARKEN = new PdfName("Darken"); + /** A possible blend mode */ + public static PdfName BM_LIGHTEN = new PdfName("Lighten"); + /** A possible blend mode */ + public static PdfName BM_COLORDODGE = new PdfName("ColorDodge"); + /** A possible blend mode */ + public static PdfName BM_COLORBURN = new PdfName("ColorBurn"); + /** A possible blend mode */ + public static PdfName BM_HARDLIGHT = new PdfName("HardLight"); + /** A possible blend mode */ + public static PdfName BM_SOFTLIGHT = new PdfName("SoftLight"); + /** A possible blend mode */ + public static PdfName BM_DIFFERENCE = new PdfName("Difference"); + /** A possible blend mode */ + public static PdfName BM_EXCLUSION = new PdfName("Exclusion"); + + /** + * Sets the flag whether to apply overprint for stroking. + * @param ov + */ + public bool OverPrintStroking { + set { + Put(PdfName.OP, value ? PdfBoolean.PDFTRUE : PdfBoolean.PDFFALSE); + } + } + + /** + * Sets the flag whether to apply overprint for non stroking painting operations. + * @param ov + */ + public bool OverPrintNonStroking { + set { + Put(PdfName.op_, value ? PdfBoolean.PDFTRUE : PdfBoolean.PDFFALSE); + } + } + + /** + * Sets the flag whether to toggle knockout behavior for overprinted objects. + * @param ov - accepts 0 or 1 + */ + public int OverPrintMode { + set { + Put(PdfName.OPM, new PdfNumber(value == 0 ? 0 : 1)); + } + } + + /** + * Sets the current stroking alpha constant, specifying the constant shape or + * constant opacity value to be used for stroking operations in the transparent + * imaging model. + * @param n + */ + public float StrokeOpacity { + set { + Put(PdfName.CA, new PdfNumber(value)); + } + } + + /** + * Sets the current stroking alpha constant, specifying the constant shape or + * constant opacity value to be used for nonstroking operations in the transparent + * imaging model. + * @param n + */ + public float FillOpacity { + set { + Put(PdfName.ca_, new PdfNumber(value)); + } + } + + /** + * The alpha source flag specifying whether the current soft mask + * and alpha constant are to be interpreted as shape values (true) + * or opacity values (false). + * @param v + */ + public bool AlphaIsShape { + set { + Put(PdfName.AIS, value ? PdfBoolean.PDFTRUE : PdfBoolean.PDFFALSE); + } + } + + /** + * Determines the behaviour of overlapping glyphs within a text object + * in the transparent imaging model. + * @param v + */ + public bool TextKnockout { + set { + Put(PdfName.TK, value ? PdfBoolean.PDFTRUE : PdfBoolean.PDFFALSE); + } + } + + /** + * The current blend mode to be used in the transparent imaging model. + * @param bm + */ + public PdfName BlendMode { + set { + Put(PdfName.BM, value); + } + } + + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfICCBased.cs b/iTechSharp/iTextSharp/text/pdf/PdfICCBased.cs new file mode 100644 index 0000000..fdcc782 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfICCBased.cs @@ -0,0 +1,33 @@ +using System; + +namespace iTextSharp.text.pdf { + + /** + * A PdfICCBased defines a ColorSpace + * + * @see PdfStream + */ + + public class PdfICCBased : PdfStream { + + public PdfICCBased(ICC_Profile profile) { + int numberOfComponents = profile.NumComponents; + switch (numberOfComponents) { + case 1: + Put(PdfName.ALTERNATE, PdfName.DEVICEGRAY); + break; + case 3: + Put(PdfName.ALTERNATE, PdfName.DEVICERGB); + break; + case 4: + Put(PdfName.ALTERNATE, PdfName.DEVICECMYK); + break; + default: + throw new PdfException(numberOfComponents + " Component(s) is not supported in iText"); + } + Put(PdfName.N, new PdfNumber(numberOfComponents)); + bytes = profile.Data; + FlateCompress(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfImage.cs b/iTechSharp/iTextSharp/text/pdf/PdfImage.cs new file mode 100644 index 0000000..68b80f8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfImage.cs @@ -0,0 +1,281 @@ +using System; +using System.IO; +using System.Net; +using iTextSharp.text; +/* + * $Id: PdfImage.cs,v 1.6 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfImage is a PdfStream containing an image-Dictionary and -stream. + */ + + public class PdfImage : PdfStream { + + internal const int TRANSFERSIZE = 4096; + // membervariables + + /** This is the PdfName of the image. */ + protected PdfName name = null; + + // constructor + + /** + * Constructs a PdfImage-object. + * + * @param image the Image-object + * @param name the PdfName for this image + * @throws BadPdfFormatException on error + */ + + public PdfImage(Image image, String name, PdfIndirectReference maskRef) { + this.name = new PdfName(name); + Put(PdfName.TYPE, PdfName.XOBJECT); + Put(PdfName.SUBTYPE, PdfName.IMAGE); + Put(PdfName.WIDTH, new PdfNumber(image.Width)); + Put(PdfName.HEIGHT, new PdfNumber(image.Height)); + if (image.Layer != null) + Put(PdfName.OC, image.Layer.Ref); + if (image.IsMask() && (image.Bpc == 1 || image.Bpc > 0xff)) + Put(PdfName.IMAGEMASK, PdfBoolean.PDFTRUE); + if (maskRef != null) { + if (image.Smask) + Put(PdfName.SMASK, maskRef); + else + Put(PdfName.MASK, maskRef); + } + if (image.IsMask() && image.Inverted) + Put(PdfName.DECODE, new PdfLiteral("[1 0]")); + if (image.Interpolation) + Put(PdfName.INTERPOLATE, PdfBoolean.PDFTRUE); + Stream isp = null; + try { + // Raw Image data + if (image.IsImgRaw()) { + // will also have the CCITT parameters + int colorspace = image.Colorspace; + int[] transparency = image.Transparency; + if (transparency != null && !image.IsMask() && maskRef == null) { + String s = "["; + for (int k = 0; k < transparency.Length; ++k) + s += transparency[k] + " "; + s += "]"; + Put(PdfName.MASK, new PdfLiteral(s)); + } + bytes = image.RawData; + Put(PdfName.LENGTH, new PdfNumber(bytes.Length)); + int bpc = image.Bpc; + if (bpc > 0xff) { + if (!image.IsMask()) + Put(PdfName.COLORSPACE, PdfName.DEVICEGRAY); + Put(PdfName.BITSPERCOMPONENT, new PdfNumber(1)); + Put(PdfName.FILTER, PdfName.CCITTFAXDECODE); + int k = bpc - Image.CCITTG3_1D; + PdfDictionary decodeparms = new PdfDictionary(); + if (k != 0) + decodeparms.Put(PdfName.K, new PdfNumber(k)); + if ((colorspace & Image.CCITT_BLACKIS1) != 0) + decodeparms.Put(PdfName.BLACKIS1, PdfBoolean.PDFTRUE); + if ((colorspace & Image.CCITT_ENCODEDBYTEALIGN) != 0) + decodeparms.Put(PdfName.ENCODEDBYTEALIGN, PdfBoolean.PDFTRUE); + if ((colorspace & Image.CCITT_ENDOFLINE) != 0) + decodeparms.Put(PdfName.ENDOFLINE, PdfBoolean.PDFTRUE); + if ((colorspace & Image.CCITT_ENDOFBLOCK) != 0) + decodeparms.Put(PdfName.ENDOFBLOCK, PdfBoolean.PDFFALSE); + decodeparms.Put(PdfName.COLUMNS, new PdfNumber(image.Width)); + decodeparms.Put(PdfName.ROWS, new PdfNumber(image.Height)); + Put(PdfName.DECODEPARMS, decodeparms); + } + else { + switch (colorspace) { + case 1: + Put(PdfName.COLORSPACE, PdfName.DEVICEGRAY); + if (image.Inverted) + Put(PdfName.DECODE, new PdfLiteral("[1 0]")); + break; + case 3: + Put(PdfName.COLORSPACE, PdfName.DEVICERGB); + if (image.Inverted) + Put(PdfName.DECODE, new PdfLiteral("[1 0 1 0 1 0]")); + break; + case 4: + default: + Put(PdfName.COLORSPACE, PdfName.DEVICECMYK); + if (image.Inverted) + Put(PdfName.DECODE, new PdfLiteral("[1 0 1 0 1 0 1 0]")); + break; + } + PdfDictionary additional = image.Additional; + if (additional != null) + Merge(additional); + if (image.IsMask() && (image.Bpc == 1 || image.Bpc > 8)) + Remove(PdfName.COLORSPACE); + Put(PdfName.BITSPERCOMPONENT, new PdfNumber(image.Bpc)); + if (image.Deflated) + Put(PdfName.FILTER, PdfName.FLATEDECODE); + else { + FlateCompress(); + } + } + return; + } + + // GIF, JPEG or PNG + String errorID; + if (image.RawData == null){ + isp = WebRequest.Create(image.Url).GetResponse().GetResponseStream(); + errorID = image.Url.ToString(); + } + else{ + isp = new MemoryStream(image.RawData); + errorID = "Byte array"; + } + switch (image.Type) { + case Image.JPEG: + Put(PdfName.FILTER, PdfName.DCTDECODE); + switch (image.Colorspace) { + case 1: + Put(PdfName.COLORSPACE, PdfName.DEVICEGRAY); + break; + case 3: + Put(PdfName.COLORSPACE, PdfName.DEVICERGB); + break; + default: + Put(PdfName.COLORSPACE, PdfName.DEVICECMYK); + if (image.Inverted) { + Put(PdfName.DECODE, new PdfLiteral("[1 0 1 0 1 0 1 0]")); + } + break; + } + Put(PdfName.BITSPERCOMPONENT, new PdfNumber(8)); + if (image.RawData != null){ + bytes = image.RawData; + Put(PdfName.LENGTH, new PdfNumber(bytes.Length)); + return; + } + streamBytes = new MemoryStream(); + TransferBytes(isp, streamBytes, -1); + break; + case Image.JPEG2000: + Put(PdfName.FILTER, PdfName.JPXDECODE); + if (image.Colorspace > 0) { + switch (image.Colorspace) { + case 1: + Put(PdfName.COLORSPACE, PdfName.DEVICEGRAY); + break; + case 3: + Put(PdfName.COLORSPACE, PdfName.DEVICERGB); + break; + default: + Put(PdfName.COLORSPACE, PdfName.DEVICECMYK); + break; + } + Put(PdfName.BITSPERCOMPONENT, new PdfNumber(image.Bpc)); + } + if (image.RawData != null){ + bytes = image.RawData; + Put(PdfName.LENGTH, new PdfNumber(bytes.Length)); + return; + } + streamBytes = new MemoryStream(); + TransferBytes(isp, streamBytes, -1); + break; + default: + throw new IOException(errorID + " is an unknown Image format."); + } + Put(PdfName.LENGTH, new PdfNumber(streamBytes.Length)); + } + finally { + if (isp != null) { + try{ + isp.Close(); + } + catch { + // empty on purpose + } + } + } + } + + /** + * Returns the PdfName of the image. + * + * @return the name + */ + + public PdfName Name { + get { + return name; + } + } + + internal static void TransferBytes(Stream inp, Stream outp, int len) { + byte[] buffer = new byte[TRANSFERSIZE]; + if (len < 0) + len = 0x7ffffff; + int size; + while (len != 0) { + size = inp.Read(buffer, 0, Math.Min(len, TRANSFERSIZE)); + if (size <= 0) + return; + outp.Write(buffer, 0, size); + len -= size; + } + } + + protected void ImportAll(PdfImage dup) { + name = dup.name; + compressed = dup.compressed; + streamBytes = dup.streamBytes; + bytes = dup.bytes; + hashMap = dup.hashMap; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfImportedPage.cs b/iTechSharp/iTextSharp/text/pdf/PdfImportedPage.cs new file mode 100644 index 0000000..4b12b79 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfImportedPage.cs @@ -0,0 +1,162 @@ +using System; + +using iTextSharp.text; + +/* + * $Id: PdfImportedPage.cs,v 1.3 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Represents an imported page. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfImportedPage : PdfTemplate { + + internal PdfReaderInstance readerInstance; + internal int pageNumber; + + internal PdfImportedPage(PdfReaderInstance readerInstance, PdfWriter writer, int pageNumber) { + this.readerInstance = readerInstance; + this.pageNumber = pageNumber; + thisReference = writer.PdfIndirectReference; + bBox = readerInstance.Reader.GetPageSize(pageNumber); + type = TYPE_IMPORTED; + } + + /** Reads the content from this PdfImportedPage-object from a reader. + * + * @return self + * + */ + public PdfImportedPage FromReader { + get { + return this; + } + } + + public int PageNumber { + get { + return pageNumber; + } + } + + /** Always throws an error. This operation is not allowed. + * @param image dummy + * @param a dummy + * @param b dummy + * @param c dummy + * @param d dummy + * @param e dummy + * @param f dummy + * @throws DocumentException dummy */ + public override void AddImage(Image image, float a, float b, float c, float d, float e, float f) { + ThrowError(); + } + + /** Always throws an error. This operation is not allowed. + * @param template dummy + * @param a dummy + * @param b dummy + * @param c dummy + * @param d dummy + * @param e dummy + * @param f dummy */ + public override void AddTemplate(PdfTemplate template, float a, float b, float c, float d, float e, float f) { + ThrowError(); + } + + /** Always throws an error. This operation is not allowed. + * @return dummy */ + public override PdfContentByte Duplicate { + get { + ThrowError(); + return null; + } + } + + internal override PdfStream FormXObject { + get { + return readerInstance.GetFormXObject(pageNumber); + } + } + + public override void SetColorFill(PdfSpotColor sp, float tint) { + ThrowError(); + } + + public override void SetColorStroke(PdfSpotColor sp, float tint) { + ThrowError(); + } + + internal override PdfObject Resources { + get { + return readerInstance.GetResources(pageNumber); + } + } + + /** Always throws an error. This operation is not allowed. + * @param bf dummy + * @param size dummy */ + public override void SetFontAndSize(BaseFont bf, float size) { + ThrowError(); + } + + internal void ThrowError() { + throw new Exception("Content can not be added to a PdfImportedPage."); + } + + internal PdfReaderInstance PdfReaderInstance { + get { + return readerInstance; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfIndirectObject.cs b/iTechSharp/iTextSharp/text/pdf/PdfIndirectObject.cs new file mode 100644 index 0000000..ec01fc6 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfIndirectObject.cs @@ -0,0 +1,157 @@ +using System; +using System.IO; + +using iTextSharp.text; + +/* + * $Id: PdfIndirectObject.cs,v 1.3 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { +/** + * PdfIndirectObject is the Pdf indirect object. + *

    + * An indirect object is an object that has been labeled so that it can be referenced by + * other objects. Any type of PdfObject may be labeled as an indirect object.
    + * An indirect object consists of an object identifier, a direct object, and the endobj + * keyword. The object identifier consists of an integer object number, an integer + * generation number, and the obj keyword.
    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.10 (page 53). + * + * @see PdfObject + * @see PdfIndirectReference + */ + +public class PdfIndirectObject { + + // membervariables + + /** The object number */ + protected int number; + + /** the generation number */ + protected int generation = 0; + + internal static byte[] STARTOBJ = DocWriter.GetISOBytes(" obj"); + internal static byte[] ENDOBJ = DocWriter.GetISOBytes("\nendobj\n"); + internal static int SIZEOBJ = STARTOBJ.Length + ENDOBJ.Length; + internal PdfObject objecti; + internal PdfWriter writer; + + // constructors + + /** + * Constructs a PdfIndirectObject. + * + * @param number the objecti number + * @param objecti the direct objecti + */ + + internal PdfIndirectObject(int number, PdfObject objecti, PdfWriter writer) : this(number, 0, objecti, writer) { + } + + internal PdfIndirectObject(PdfIndirectReference refi, PdfObject objecti, PdfWriter writer) : this(refi.Number,refi.Generation,objecti,writer) { + } + /** + * Constructs a PdfIndirectObject. + * + * @param number the objecti number + * @param generation the generation number + * @param objecti the direct objecti + */ + + internal PdfIndirectObject(int number, int generation, PdfObject objecti, PdfWriter writer) { + this.writer = writer; + this.number = number; + this.generation = generation; + this.objecti = objecti; + PdfEncryption crypto = null; + if (writer != null) + crypto = writer.Encryption; + if (crypto != null) { + crypto.SetHashKey(number, generation); + } + } + + // methods + + /** + * Returns a PdfIndirectReference to this PdfIndirectObject. + * + * @return a PdfIndirectReference + */ + + public PdfIndirectReference IndirectReference { + get { + return new PdfIndirectReference(objecti.Type, number, generation); + } + } + + /** + * Writes eficiently to a stream + * + * @param os the stream to write to + * @throws IOException on write error + */ + internal void WriteTo(Stream os) { + byte[] tmp = DocWriter.GetISOBytes(number.ToString()); + os.Write(tmp, 0, tmp.Length); + os.WriteByte((byte)' '); + tmp = DocWriter.GetISOBytes(generation.ToString()); + os.Write(tmp, 0, tmp.Length); + os.Write(STARTOBJ, 0, STARTOBJ.Length); + int type = objecti.Type; + if (type != PdfObject.ARRAY && type != PdfObject.DICTIONARY && type != PdfObject.NAME && type != PdfObject.STRING) + os.WriteByte((byte)' '); + objecti.ToPdf(writer, os); + os.Write(ENDOBJ, 0, ENDOBJ.Length); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfIndirectReference.cs b/iTechSharp/iTextSharp/text/pdf/PdfIndirectReference.cs new file mode 100644 index 0000000..443751a --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfIndirectReference.cs @@ -0,0 +1,137 @@ +using System; +using System.Text; + +/* + * $Id: PdfIndirectReference.cs,v 1.5 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfIndirectReference contains a reference to a PdfIndirectObject. + *

    + * Any object used as an element of an array or as a value in a dictionary may be specified + * by either a direct object of an indirect reference. An indirect reference is a reference + * to an indirect object, and consists of the indirect object's object number, generation number + * and the R keyword.
    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.11 (page 54). + * + * @see PdfObject + * @see PdfIndirectObject + */ + + public class PdfIndirectReference : PdfObject { + + // membervariables + + /** the object number */ + protected int number; + + /** the generation number */ + protected int generation = 0; + + // constructors + + protected PdfIndirectReference() : base(0) { + } + + /** + * Constructs a PdfIndirectReference. + * + * @param type the type of the PdfObject that is referenced to + * @param number the object number. + * @param generation the generation number. + */ + + internal PdfIndirectReference(int type, int number, int generation) : base(0, new StringBuilder().Append(number).Append(' ').Append(generation).Append(" R").ToString()) { + this.number = number; + this.generation = generation; + } + + /** + * Constructs a PdfIndirectReference. + * + * @param type the type of the PdfObject that is referenced to + * @param number the object number. + */ + + internal PdfIndirectReference(int type, int number) : this(type, number, 0) {} + + // methods + + /** + * Returns the number of the object. + * + * @return a number. + */ + + public int Number { + get { + return number; + } + } + + /** + * Returns the generation of the object. + * + * @return a number. + */ + + public int Generation { + get { + return generation; + } + } + + public override String ToString() { + return new StringBuilder().Append(number).Append(' ').Append(generation).Append(" R").ToString(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfLayer.cs b/iTechSharp/iTextSharp/text/pdf/PdfLayer.cs new file mode 100644 index 0000000..4cb3f39 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfLayer.cs @@ -0,0 +1,321 @@ +using System; +using System.Collections; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * An optional content group is a dictionary representing a collection of graphics + * that can be made visible or invisible dynamically by users of viewer applications. + * In iText they are referenced as layers. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfLayer : PdfDictionary, IPdfOCG { + protected PdfIndirectReference refi; + protected ArrayList children; + protected PdfLayer parent; + protected String title; + + /** + * Holds value of property on. + */ + private bool on = true; + + /** + * Holds value of property onPanel. + */ + private bool onPanel = true; + + internal PdfLayer(String title) { + this.title = title; + } + + /** + * Creates a title layer. A title layer is not really a layer but a collection of layers + * under the same title heading. + * @param title the title text + * @param writer the PdfWriter + * @return the title layer + */ + public static PdfLayer CreateTitle(String title, PdfWriter writer) { + if (title == null) + throw new ArgumentNullException("Title cannot be null."); + PdfLayer layer = new PdfLayer(title); + writer.RegisterLayer(layer); + return layer; + } + /** + * Creates a new layer. + * @param name the name of the layer + * @param writer the writer + */ + public PdfLayer(String name, PdfWriter writer) : base(PdfName.OCG) { + Name = name; + refi = writer.PdfIndirectReference; + writer.RegisterLayer(this); + } + + internal String Title { + get { + return title; + } + } + + /** + * Adds a child layer. Nested layers can only have one parent. + * @param child the child layer + */ + public void AddChild(PdfLayer child) { + if (child.parent != null) + throw new ArgumentException("The layer '" + ((PdfString)child.Get(PdfName.NAME)).ToUnicodeString() + "' already has a parent."); + child.parent = this; + if (children == null) + children = new ArrayList(); + children.Add(child); + } + + + /** + * Gets the parent layer. + * @return the parent layer or null if the layer has no parent + */ + public PdfLayer Parent { + get { + return parent; + } + } + + /** + * Gets the children layers. + * @return the children layers or null if the layer has no children + */ + public ArrayList Children { + get { + return children; + } + } + + /** + * Gets the PdfIndirectReference that represents this layer. + * @return the PdfIndirectReference that represents this layer + */ + public PdfIndirectReference Ref { + get { + return refi; + } + set { + refi = value; + } + } + + /** + * Sets the name of this layer. + * @param name the name of this layer + */ + public string Name { + set { + Put(PdfName.NAME, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + /** + * Gets the dictionary representing the layer. It just returns this. + * @return the dictionary representing the layer + */ + public PdfObject PdfObject { + get { + return this; + } + } + + /** + * Gets the initial visibility of the layer. + * @return the initial visibility of the layer + */ + public bool On { + get { + return this.on; + } + set { + on = value; + } + } + + + private PdfDictionary Usage { + get { + PdfDictionary usage = (PdfDictionary)Get(PdfName.USAGE); + if (usage == null) { + usage = new PdfDictionary(); + Put(PdfName.USAGE, usage); + } + return usage; + } + } + + /** + * Used by the creating application to store application-specific + * data associated with this optional content group. + * @param creator a text string specifying the application that created the group + * @param subtype a string defining the type of content controlled by the group. Suggested + * values include but are not limited to Artwork, for graphic-design or publishing + * applications, and Technical, for technical designs such as building plans or + * schematics + */ + public void SetCreatorInfo(String creator, String subtype) { + PdfDictionary usage = Usage; + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.CREATOR, new PdfString(creator, PdfObject.TEXT_UNICODE)); + dic.Put(PdfName.SUBTYPE, new PdfName(subtype)); + usage.Put(PdfName.CREATORINFO, dic); + } + + /** + * Specifies the language of the content controlled by this + * optional content group + * @param lang a language string which specifies a language and possibly a locale + * (for example, es-MX represents Mexican Spanish) + * @param preferred used by viewer applications when there is a partial match but no exact + * match between the system language and the language strings in all usage dictionaries + */ + public void SetLanguage(String lang, bool preferred) { + PdfDictionary usage = Usage; + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.LANG, new PdfString(lang, PdfObject.TEXT_UNICODE)); + if (preferred) + dic.Put(PdfName.PREFERRED, PdfName.ON); + usage.Put(PdfName.LANGUAGE, dic); + } + + /** + * Specifies the recommended state for content in this + * group when the document (or part of it) is saved by a viewer application to a format + * that does not support optional content (for example, an earlier version of + * PDF or a raster image format). + * @param export the export state + */ + public bool Export { + set { + PdfDictionary usage = Usage; + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.EXPORTSTATE, value ? PdfName.ON : PdfName.OFF); + usage.Put(PdfName.EXPORT, dic); + } + } + + /** + * Specifies a range of magnifications at which the content + * in this optional content group is best viewed. + * @param min the minimum recommended magnification factors at which the group + * should be ON. A negative value will set the default to 0 + * @param max the maximum recommended magnification factor at which the group + * should be ON. A negative value will set the largest possible magnification supported by the + * viewer application + */ + public void SetZoom(float min, float max) { + if (min <= 0 && max < 0) + return; + PdfDictionary usage = Usage; + PdfDictionary dic = new PdfDictionary(); + if (min > 0) + dic.Put(PdfName.MIN, new PdfNumber(min)); + if (max >= 0) + dic.Put(PdfName.MAX, new PdfNumber(max)); + usage.Put(PdfName.ZOOM, dic); + } + + /** + * Specifies that the content in this group is intended for + * use in printing + * @param subtype a name specifying the kind of content controlled by the group; + * for example, Trapping, PrintersMarks and Watermark + * @param printstate indicates that the group should be + * set to that state when the document is printed from a viewer application + */ + public void SetPrint(String subtype, bool printstate) { + PdfDictionary usage = Usage; + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.SUBTYPE, new PdfName(subtype)); + dic.Put(PdfName.PRINTSTATE, printstate ? PdfName.ON : PdfName.OFF); + usage.Put(PdfName.PRINT, dic); + } + + /** + * Indicates that the group should be set to that state when the + * document is opened in a viewer application. + * @param view the view state + */ + public bool View { + set { + PdfDictionary usage = Usage; + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.VIEWSTATE, value ? PdfName.ON : PdfName.OFF); + usage.Put(PdfName.VIEW, dic); + } + } + + /** + * Gets the layer visibility in Acrobat's layer panel + * @return the layer visibility in Acrobat's layer panel + */ + /** + * Sets the visibility of the layer in Acrobat's layer panel. If false + * the layer cannot be directly manipulated by the user. Note that any children layers will + * also be absent from the panel. + * @param onPanel the visibility of the layer in Acrobat's layer panel + */ + public bool OnPanel { + get { + return this.onPanel; + } + set { + onPanel = value; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfLayerMembership.cs b/iTechSharp/iTextSharp/text/pdf/PdfLayerMembership.cs new file mode 100644 index 0000000..c7130cb --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfLayerMembership.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Content typically belongs to a single optional content group, + * and is visible when the group is ON and invisible when it is OFF. To express more + * complex visibility policies, content should not declare itself to belong to an optional + * content group directly, but rather to an optional content membership dictionary + * represented by this class. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfLayerMembership : PdfDictionary, IPdfOCG { + + /** + * Visible only if all of the entries are ON. + */ + public static readonly PdfName ALLON = new PdfName("AllOn"); + /** + * Visible if any of the entries are ON. + */ + public static readonly PdfName ANYON = new PdfName("AnyOn"); + /** + * Visible if any of the entries are OFF. + */ + public static readonly PdfName ANYOFF = new PdfName("AnyOff"); + /** + * Visible only if all of the entries are OFF. + */ + public static readonly PdfName ALLOFF = new PdfName("AllOff"); + + internal PdfIndirectReference refi; + internal PdfArray members = new PdfArray(); + internal Hashtable layers = new Hashtable(); + + /** + * Creates a new, empty, membership layer. + * @param writer the writer + */ + public PdfLayerMembership(PdfWriter writer) : base(PdfName.OCMD) { + Put(PdfName.OCGS, members); + refi = writer.PdfIndirectReference; + } + + /** + * Gets the PdfIndirectReference that represents this membership layer. + * @return the PdfIndirectReference that represents this layer + */ + public PdfIndirectReference Ref { + get { + return refi; + } + } + + /** + * Adds a new member to the layer. + * @param layer the new member to the layer + */ + public void AddMember(PdfLayer layer) { + if (!layers.ContainsKey(layer)) { + members.Add(layer.Ref); + layers[layer] = null; + } + } + + /** + * Gets the member layers. + * @return the member layers + */ + public ICollection Layers { + get { + return layers.Keys; + } + } + + /** + * Sets the visibility policy for content belonging to this + * membership dictionary. Possible values are ALLON, ANYON, ANYOFF and ALLOFF. + * The default value is ANYON. + * @param type the visibility policy + */ + public PdfName VisibilityPolicy { + set { + Put(PdfName.P, value); + } + } + + /** + * Gets the dictionary representing the membership layer. It just returns this. + * @return the dictionary representing the layer + */ + public PdfObject PdfObject { + get { + return this; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfLine.cs b/iTechSharp/iTextSharp/text/pdf/PdfLine.cs new file mode 100644 index 0000000..8d0ef90 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfLine.cs @@ -0,0 +1,539 @@ +using System; +using System.Text; +using System.Collections; + +using iTextSharp.text; + +/* + * $Id: PdfLine.cs,v 1.7 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfLine defines an array with PdfChunk-objects + * that fit into 1 line. + */ + + public class PdfLine { + + // membervariables + + /** The arraylist containing the chunks. */ + protected internal ArrayList line; + + /** The left indentation of the line. */ + protected internal float left; + + /** The width of the line. */ + protected internal float width; + + /** The alignment of the line. */ + protected internal int alignment; + + /** The heigth of the line. */ + protected internal float height; + + /** The listsymbol (if necessary). */ + protected internal Chunk listSymbol = null; + + /** The listsymbol (if necessary). */ + protected internal float symbolIndent; + + /** true if the chunk splitting was caused by a newline. */ + protected internal bool newlineSplit = false; + + /** The original width. */ + protected internal float originalWidth; + + protected internal bool isRTL = false; + + // constructors + + /** + * Constructs a new PdfLine-object. + * + * @param left the limit of the line at the left + * @param right the limit of the line at the right + * @param alignment the alignment of the line + * @param height the height of the line + */ + + internal PdfLine(float left, float right, int alignment, float height) { + this.left = left; + this.width = right - left; + this.originalWidth = this.width; + this.alignment = alignment; + this.height = height; + this.line = new ArrayList(); + } + + /** + * Creates a PdfLine object. + * @param left the left offset + * @param originalWidth the original width of the line + * @param remainingWidth bigger than 0 if the line isn't completely filled + * @param alignment the alignment of the line + * @param newlineSplit was the line splitted (or does the paragraph end with this line) + * @param line an array of PdfChunk objects + * @param isRTL do you have to read the line from Right to Left? + */ + internal PdfLine(float left, float originalWidth, float remainingWidth, int alignment, bool newlineSplit, ArrayList line, bool isRTL) { + this.left = left; + this.originalWidth = originalWidth; + this.width = remainingWidth; + this.alignment = alignment; + this.line = line; + this.newlineSplit = newlineSplit; + this.isRTL = isRTL; + } + + // methods + + /** + * Adds a PdfChunk to the PdfLine. + * + * @param chunk the PdfChunk to add + * @return null if the chunk could be added completely; if not + * a PdfChunk containing the part of the chunk that could + * not be added is returned + */ + + internal PdfChunk Add(PdfChunk chunk) { + // nothing happens if the chunk is null. + if (chunk == null || chunk.ToString().Equals("")) { + return null; + } + + // we split the chunk to be added + PdfChunk overflow = chunk.Split(width); + newlineSplit = (chunk.IsNewlineSplit() || overflow == null); + // if (chunk.IsNewlineSplit() && alignment == Element.ALIGN_JUSTIFIED) + // alignment = Element.ALIGN_LEFT; + if (chunk.IsTab()) { + Object[] tab = (Object[])chunk.GetAttribute(Chunk.TAB); + float tabPosition = (float)tab[1]; + bool newline = (bool)tab[2]; + if (newline && tabPosition < originalWidth - width) { + return chunk; + } + width = originalWidth - tabPosition; + chunk.AdjustLeft(left); + AddToLine(chunk); + } + // if the length of the chunk > 0 we add it to the line + else if (chunk.Length > 0) { + if (overflow != null) + chunk.TrimLastSpace(); + width -= chunk.Width; + AddToLine(chunk); + } + + // if the length == 0 and there were no other chunks added to the line yet, + // we risk to end up in an endless loop trying endlessly to add the same chunk + else if (line.Count < 1) { + chunk = overflow; + overflow = chunk.Truncate(width); + width -= chunk.Width; + if (chunk.Length > 0) { + AddToLine(chunk); + return overflow; + } + // if the chunck couldn't even be truncated, we add everything, so be it + else { + if (overflow != null) + AddToLine(chunk); + return null; + } + } + else { + width += ((PdfChunk)(line[line.Count - 1])).TrimLastSpace(); + } + return overflow; + } + + private void AddToLine(PdfChunk chunk) { + if (chunk.ChangeLeading && chunk.IsImage()) { + float f = chunk.Image.ScaledHeight + chunk.ImageOffsetY; + if (f > height) height = f; + } + line.Add(chunk); + } + + // methods to retrieve information + + /** + * Returns the number of chunks in the line. + * + * @return a value + */ + + public int Size { + get { + return line.Count; + } + } + + /** + * Returns an iterator of PdfChunks. + * + * @return an Iterator + */ + + public IEnumerator GetEnumerator() { + return line.GetEnumerator(); + } + + /** + * Returns the height of the line. + * + * @return a value + */ + + internal float Height { + get { + return height; + } + } + + /** + * Returns the left indentation of the line taking the alignment of the line into account. + * + * @return a value + */ + + internal float IndentLeft { + get { + if (isRTL) { + switch (alignment) { + case Element.ALIGN_LEFT: + return left + width; + case Element.ALIGN_CENTER: + return left + (width / 2f); + default: + return left; + } + } + else { + switch (alignment) { + case Element.ALIGN_RIGHT: + return left + width; + case Element.ALIGN_CENTER: + return left + (width / 2f); + default: + return left; + } + } + } + } + + /** + * Checks if this line has to be justified. + * + * @return true if the alignment equals ALIGN_JUSTIFIED and there is some width left. + */ + + public bool HasToBeJustified() { + return ((alignment == Element.ALIGN_JUSTIFIED || alignment == Element.ALIGN_JUSTIFIED_ALL) && width != 0); + } + + /** + * Resets the alignment of this line. + *

    + * The alignment of the last line of for instance a Paragraph + * that has to be justified, has to be reset to ALIGN_LEFT. + */ + + public void ResetAlignment() { + if (alignment == Element.ALIGN_JUSTIFIED) { + alignment = Element.ALIGN_LEFT; + } + } + + /** Adds extra indentation to the left (for Paragraph.setFirstLineIndent). */ + internal void SetExtraIndent(float extra) { + left += extra; + width -= extra; + } + + /** + * Returns the width that is left, after a maximum of characters is added to the line. + * + * @return a value + */ + + internal float WidthLeft { + get { + return width; + } + } + + /** + * Returns the number of space-characters in this line. + * + * @return a value + */ + + internal int NumberOfSpaces { + get { + string str = ToString(); + int length = str.Length; + int numberOfSpaces = 0; + for (int i = 0; i < length; i++) { + if (str[i] == ' ') { + numberOfSpaces++; + } + } + return numberOfSpaces; + } + } + + /** + * Sets the listsymbol of this line. + *

    + * This is only necessary for the first line of a ListItem. + * + * @param listItem the list symbol + */ + + public ListItem ListItem { + set { + this.listSymbol = value.ListSymbol; + this.symbolIndent = value.IndentationLeft; + } + } + + /** + * Returns the listsymbol of this line. + * + * @return a PdfChunk if the line has a listsymbol; null otherwise + */ + + public Chunk ListSymbol { + get { + return listSymbol; + } + } + + /** + * Return the indentation needed to show the listsymbol. + * + * @return a value + */ + + public float ListIndent { + get { + return symbolIndent; + } + } + + /** + * Get the string representation of what is in this line. + * + * @return a string + */ + + public override string ToString() { + StringBuilder tmp = new StringBuilder(); + foreach (PdfChunk c in line) { + tmp.Append(c.ToString()); + } + return tmp.ToString(); + } + + public int GetLineLengthUtf32() { + int total = 0; + foreach (PdfChunk c in line) { + total += c.LengthUtf32; + } + return total; + } + + /** + * Checks if a newline caused the line split. + * @return true if a newline caused the line split + */ + public bool NewlineSplit { + get { + return newlineSplit && (alignment != Element.ALIGN_JUSTIFIED_ALL); + } + } + + /** + * Gets the index of the last PdfChunk with metric attributes + * @return the last PdfChunk with metric attributes + */ + public int LastStrokeChunk { + get { + int lastIdx = line.Count - 1; + for (; lastIdx >= 0; --lastIdx) { + PdfChunk chunk = (PdfChunk)line[lastIdx]; + if (chunk.IsStroked()) + break; + } + return lastIdx; + } + } + + /** + * Gets a PdfChunk by index. + * @param idx the index + * @return the PdfChunk or null if beyond the array + */ + public PdfChunk GetChunk(int idx) { + if (idx < 0 || idx >= line.Count) + return null; + return (PdfChunk)line[idx]; + } + + /** + * Gets the original width of the line. + * @return the original width of the line + */ + public float OriginalWidth { + get { + return originalWidth; + } + } + + /** + * Gets the maximum size of all the fonts used in this line + * including images. + * @return maximum size of all the fonts used in this line + */ + internal float MaxSizeSimple { + get { + float maxSize = 0; + for (int k = 0; k < line.Count; ++k) { + PdfChunk chunk = (PdfChunk)line[k]; + if (!chunk.IsImage()) { + maxSize = Math.Max(chunk.Font.Size, maxSize); + } + else { + maxSize = Math.Max(chunk.Image.ScaledHeight + chunk.ImageOffsetY , maxSize); + } + } + return maxSize; + } + } + + internal bool RTL { + get { + return isRTL; + } + } + + /** + * Gets the number of separators in the line. + * @return the number of separators in the line + * @since 2.1.2 + */ + internal int GetSeparatorCount() { + int s = 0; + foreach (PdfChunk ck in line) { + if (ck.IsTab()) { + return 0; + } + if (ck.IsHorizontalSeparator()) { + s++; + } + } + return s; + } + + public float GetWidthCorrected(float charSpacing, float wordSpacing) { + float total = 0; + for (int k = 0; k < line.Count; ++k) { + PdfChunk ck = (PdfChunk)line[k]; + total += ck.GetWidthCorrected(charSpacing, wordSpacing); + } + return total; + } + + /** + * Gets the maximum size of the ascender for all the fonts used + * in this line. + * @return maximum size of all the ascenders used in this line + */ + public float Ascender { + get { + float ascender = 0; + foreach (PdfChunk ck in line) { + if (ck.IsImage()) + ascender = Math.Max(ascender, ck.Image.ScaledHeight + ck.ImageOffsetY); + else { + PdfFont font = ck.Font; + ascender = Math.Max(ascender, font.Font.GetFontDescriptor(BaseFont.ASCENT, font.Size)); + } + } + return ascender; + } + } + + /** + * Gets the biggest descender for all the fonts used + * in this line. Note that this is a negative number. + * @return maximum size of all the ascenders used in this line + */ + public float Descender { + get { + float descender = 0; + foreach (PdfChunk ck in line) { + if (ck.IsImage()) + descender = Math.Min(descender, ck.ImageOffsetY); + else { + PdfFont font = ck.Font; + descender = Math.Min(descender, font.Font.GetFontDescriptor(BaseFont.DESCENT, font.Size)); + } + } + return descender; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfLiteral.cs b/iTechSharp/iTextSharp/text/pdf/PdfLiteral.cs new file mode 100644 index 0000000..4e70fa7 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfLiteral.cs @@ -0,0 +1,101 @@ +using System; +using System.IO; + +/* + * $Id: PdfLiteral.cs,v 1.3 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf +{ + + /** + * a Literal + */ + + public class PdfLiteral : PdfObject { + + private int position; + + public PdfLiteral(string text) : base(0, text) {} + + public PdfLiteral(byte[] b) : base(0, b) {} + + public PdfLiteral(int type, string text) : base(type, text) {} + + public PdfLiteral(int type, byte[] b) : base(type, b) {} + + public PdfLiteral(int size) : base(0, (byte[])null) { + bytes = new byte[size]; + for (int k = 0; k < size; ++k) { + bytes[k] = 32; + } + } + + public override void ToPdf(PdfWriter writer, Stream os) { + if (os is OutputStreamCounter) + position = ((OutputStreamCounter)os).Counter; + base.ToPdf(writer, os); + } + + public int Position { + get { + return position; + } + } + + public int PosLength { + get { + if (bytes != null) + return bytes.Length; + else + return 0; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfMediaClipData.cs b/iTechSharp/iTextSharp/text/pdf/PdfMediaClipData.cs new file mode 100644 index 0000000..66d1abd --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfMediaClipData.cs @@ -0,0 +1,63 @@ +using System; +/* + * Copyright 2003 Galo Gimenez + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + public class PdfMediaClipData : PdfDictionary { + + internal PdfMediaClipData(String file, PdfFileSpecification fs, String mimeType) { + Put(PdfName.TYPE,new PdfName("MediaClip")); + Put(PdfName.S, new PdfName("MCD")); + Put(PdfName.N, new PdfString("Media clip for "+file)); + Put(new PdfName("CT"), new PdfString(mimeType)); + PdfDictionary dic = new PdfDictionary(); + dic.Put(new PdfName("TF"), new PdfString("TEMPACCESS")); + Put(new PdfName("P"), dic); + Put(PdfName.D, fs.Reference); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfName.cs b/iTechSharp/iTextSharp/text/pdf/PdfName.cs new file mode 100644 index 0000000..1a0951b --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfName.cs @@ -0,0 +1,1257 @@ +using System; +using System.Text; + +/* + * $Id: PdfName.cs,v 1.31 2008/05/24 18:41:23 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfName is an object that can be used as a name in a PDF-file. + *

    + * A name, like a string, is a sequence of characters. It must begin with a slash + * followed by a sequence of ASCII characters in the range 32 through 136 except + * %, (, ), [, ], <, >, {, }, / and #. Any character except 0x00 may be included + * in a name by writing its twocharacter hex code, preceded by #. The maximum number + * of characters in a name is 127.
    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.5 (page 39-40). + *

    + * + * @see PdfObject + * @see PdfDictionary + * @see BadPdfFormatException + */ + + public class PdfName : PdfObject, IComparable { + + // static membervariables (a variety of standard names used in PDF) + + /** A name */ + public static readonly PdfName A = new PdfName("A"); + /** A name */ + public static readonly PdfName AA = new PdfName("AA"); + /** A name */ + public static readonly PdfName ABSOLUTECALORIMETRIC = new PdfName("AbsoluteColorimetric"); + /** A name */ + public static readonly PdfName AC = new PdfName("AC"); + /** A name */ + public static readonly PdfName ACROFORM = new PdfName("AcroForm"); + /** A name */ + public static readonly PdfName ACTION = new PdfName("Action"); + /** A name */ + public static readonly PdfName ADBE_PKCS7_DETACHED = new PdfName("adbe.pkcs7.detached"); + /** A name */ + public static readonly PdfName ADBE_PKCS7_S4 =new PdfName("adbe.pkcs7.s4"); + /** A name */ + public static readonly PdfName ADBE_PKCS7_S5 =new PdfName("adbe.pkcs7.s5"); + /** A name */ + public static readonly PdfName ADBE_PKCS7_SHA1 = new PdfName("adbe.pkcs7.sha1"); + /** A name */ + public static readonly PdfName ADBE_X509_RSA_SHA1 = new PdfName("adbe.x509.rsa_sha1"); + /** A name */ + public static readonly PdfName ADOBE_PPKLITE = new PdfName("Adobe.PPKLite"); + /** A name */ + public static readonly PdfName ADOBE_PPKMS = new PdfName("Adobe.PPKMS"); + /** A name */ + public static readonly PdfName AESV2 = new PdfName("AESV2"); + /** A name */ + public static readonly PdfName AIS = new PdfName("AIS"); + /** A name */ + public static readonly PdfName ALLPAGES = new PdfName("AllPages"); + /** A name */ + public static readonly PdfName ALT = new PdfName("Alt"); + /** A name */ + public static readonly PdfName ALTERNATE = new PdfName("Alternate"); + /** A name */ + public static readonly PdfName ANNOT = new PdfName("Annot"); + /** A name */ + public static readonly PdfName ANTIALIAS = new PdfName("AntiAlias"); + /** A name */ + public static readonly PdfName ANNOTS = new PdfName("Annots"); + /** A name */ + public static readonly PdfName AP = new PdfName("AP"); + /** A name */ + public static readonly PdfName APPDEFAULT = new PdfName("AppDefault"); + /** A name */ + public static readonly PdfName ARTBOX = new PdfName("ArtBox"); + /** A name */ + public static readonly PdfName ASCENT = new PdfName("Ascent"); + /** A name */ + public static readonly PdfName AS = new PdfName("AS"); + /** A name */ + public static readonly PdfName ASCII85DECODE = new PdfName("ASCII85Decode"); + /** A name */ + public static readonly PdfName ASCIIHEXDECODE = new PdfName("ASCIIHexDecode"); + /** A name */ + public static readonly PdfName AUTHEVENT = new PdfName("AuthEvent"); + /** A name */ + public static readonly PdfName AUTHOR = new PdfName("Author"); + /** A name */ + public static readonly PdfName B = new PdfName("B"); + /** A name */ + public static readonly PdfName BASEENCODING = new PdfName("BaseEncoding"); + /** A name */ + public static readonly PdfName BASEFONT = new PdfName("BaseFont"); + /** A name */ + public static readonly PdfName BBOX = new PdfName("BBox"); + /** A name */ + public static readonly PdfName BC = new PdfName("BC"); + /** A name */ + public static readonly PdfName BG = new PdfName("BG"); + /** A name */ + public static readonly PdfName BIGFIVE = new PdfName("BigFive"); + /** A name */ + public static readonly PdfName BITSPERCOMPONENT = new PdfName("BitsPerComponent"); + /** A name */ + public static readonly PdfName BITSPERSAMPLE = new PdfName("BitsPerSample"); + /** A name */ + public static readonly PdfName BL = new PdfName("Bl"); + /** A name */ + public static readonly PdfName BLACKIS1 = new PdfName("BlackIs1"); + /** A name */ + public static readonly PdfName BLACKPOINT = new PdfName("BlackPoint"); + /** A name */ + public static readonly PdfName BLEEDBOX = new PdfName("BleedBox"); + /** A name */ + public static readonly PdfName BLINDS = new PdfName("Blinds"); + /** A name */ + public static readonly PdfName BM = new PdfName("BM"); + /** A name */ + public static readonly PdfName BORDER = new PdfName("Border"); + /** A name */ + public static readonly PdfName BOUNDS = new PdfName("Bounds"); + /** A name */ + public static readonly PdfName BOX = new PdfName("Box"); + /** A name */ + public static readonly PdfName BS = new PdfName("BS"); + /** A name */ + public static readonly PdfName BTN = new PdfName("Btn"); + /** A name */ + public static readonly PdfName BYTERANGE = new PdfName("ByteRange"); + /** A name */ + public static readonly PdfName C = new PdfName("C"); + /** A name */ + public static readonly PdfName C0 = new PdfName("C0"); + /** A name */ + public static readonly PdfName C1 = new PdfName("C1"); + /** A name */ + public static readonly PdfName CA = new PdfName("CA"); + /** A name */ + public static readonly PdfName ca_ = new PdfName("ca"); + /** A name */ + public static readonly PdfName CALGRAY = new PdfName("CalGray"); + /** A name */ + public static readonly PdfName CALRGB = new PdfName("CalRGB"); + /** A name */ + public static readonly PdfName CAPHEIGHT = new PdfName("CapHeight"); + /** A name */ + public static readonly PdfName CATALOG = new PdfName("Catalog"); + /** A name */ + public static readonly PdfName CATEGORY = new PdfName("Category"); + /** A name */ + public static readonly PdfName CCITTFAXDECODE = new PdfName("CCITTFaxDecode"); + /** A name */ + public static readonly PdfName CENTERWINDOW = new PdfName("CenterWindow"); + /** A name */ + public static readonly PdfName CERT = new PdfName("Cert"); + /** A name */ + public static readonly PdfName CF = new PdfName("CF"); + /** A name */ + public static readonly PdfName CFM = new PdfName("CFM"); + /** A name */ + public static readonly PdfName CH = new PdfName("Ch"); + /** A name */ + public static readonly PdfName CHARPROCS = new PdfName("CharProcs"); + /** A name */ + public static readonly PdfName CI = new PdfName("CI"); + /** A name */ + public static readonly PdfName CIDFONTTYPE0 = new PdfName("CIDFontType0"); + /** A name */ + public static readonly PdfName CIDFONTTYPE2 = new PdfName("CIDFontType2"); + /** A name */ + public static readonly PdfName CIDSET = new PdfName("CIDSet"); + /** A name */ + public static readonly PdfName CIDSYSTEMINFO = new PdfName("CIDSystemInfo"); + /** A name */ + public static readonly PdfName CIDTOGIDMAP = new PdfName("CIDToGIDMap"); + /** A name */ + public static readonly PdfName CIRCLE = new PdfName("Circle"); + /** A name */ + public static readonly PdfName CO = new PdfName("CO"); + /** A name */ + public static readonly PdfName COLORS = new PdfName("Colors"); + /** A name */ + public static readonly PdfName COLORSPACE = new PdfName("ColorSpace"); + /** A name */ + public static readonly PdfName COLLECTION = new PdfName("Collection"); + /** A name */ + public static readonly PdfName COLLECTIONFIELD = new PdfName("CollectionField"); + /** A name */ + public static readonly PdfName COLLECTIONITEM = new PdfName("CollectionItem"); + /** A name */ + public static readonly PdfName COLLECTIONSCHEMA = new PdfName("CollectionSchema"); + /** A name */ + public static readonly PdfName COLLECTIONSORT = new PdfName("CollectionSort"); + /** A name */ + public static readonly PdfName COLLECTIONSUBITEM = new PdfName("CollectionSubitem"); + /** A name */ + public static readonly PdfName COLUMNS = new PdfName("Columns"); + /** A name */ + public static readonly PdfName CONTACTINFO = new PdfName("ContactInfo"); + /** A name */ + public static readonly PdfName CONTENT = new PdfName("Content"); + /** A name */ + public static readonly PdfName CONTENTS = new PdfName("Contents"); + /** A name */ + public static readonly PdfName COORDS = new PdfName("Coords"); + /** A name */ + public static readonly PdfName COUNT = new PdfName("Count"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName COURIER = new PdfName("Courier"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName COURIER_BOLD = new PdfName("Courier-Bold"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName COURIER_OBLIQUE = new PdfName("Courier-Oblique"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName COURIER_BOLDOBLIQUE = new PdfName("Courier-BoldOblique"); + /** A name */ + public static readonly PdfName CREATIONDATE = new PdfName("CreationDate"); + /** A name */ + public static readonly PdfName CREATOR = new PdfName("Creator"); + /** A name */ + public static readonly PdfName CREATORINFO = new PdfName("CreatorInfo"); + /** A name */ + public static readonly PdfName CROPBOX = new PdfName("CropBox"); + /** A name */ + public static readonly PdfName CRYPT = new PdfName("Crypt"); + /** A name */ + public static readonly PdfName CS = new PdfName("CS"); + /** A name */ + public static readonly PdfName D = new PdfName("D"); + /** A name */ + public static readonly PdfName DA = new PdfName("DA"); + /** A name */ + public static readonly PdfName DATA = new PdfName("Data"); + /** A name */ + public static readonly PdfName DC = new PdfName("DC"); + /** A name */ + public static readonly PdfName DCTDECODE = new PdfName("DCTDecode"); + /** A name */ + public static readonly PdfName DECODE = new PdfName("Decode"); + /** A name */ + public static readonly PdfName DECODEPARMS = new PdfName("DecodeParms"); + /** A name */ + public static readonly PdfName DEFAULTCRYPTFILER = new PdfName("DefaultCryptFilter"); + /** A name */ + public static readonly PdfName DEFAULTCMYK = new PdfName("DefaultCMYK"); + /** A name */ + public static readonly PdfName DEFAULTGRAY = new PdfName("DefaultGray"); + /** A name */ + public static readonly PdfName DEFAULTRGB = new PdfName("DefaultRGB"); + /** A name */ + public static readonly PdfName DESC = new PdfName("Desc"); + /** A name */ + public static readonly PdfName DESCENDANTFONTS = new PdfName("DescendantFonts"); + /** A name */ + public static readonly PdfName DESCENT = new PdfName("Descent"); + /** A name */ + public static readonly PdfName DEST = new PdfName("Dest"); + /** A name */ + public static readonly PdfName DESTOUTPUTPROFILE = new PdfName("DestOutputProfile"); + /** A name */ + public static readonly PdfName DESTS = new PdfName("Dests"); + /** A name */ + public static readonly PdfName DEVICEGRAY = new PdfName("DeviceGray"); + /** A name */ + public static readonly PdfName DEVICERGB = new PdfName("DeviceRGB"); + /** A name */ + public static readonly PdfName DEVICECMYK = new PdfName("DeviceCMYK"); + /** A name */ + public static readonly PdfName DI = new PdfName("Di"); + /** A name */ + public static readonly PdfName DIFFERENCES = new PdfName("Differences"); + /** A name */ + public static readonly PdfName DISSOLVE = new PdfName("Dissolve"); + /** A name */ + public static readonly PdfName DIRECTION = new PdfName("Direction"); + /** A name */ + public static readonly PdfName DISPLAYDOCTITLE = new PdfName("DisplayDocTitle"); + /** A name */ + public static readonly PdfName DIV = new PdfName("Div"); + /** A name */ + public static readonly PdfName DM = new PdfName("Dm"); + /** A name */ + public static readonly PdfName DOCMDP = new PdfName("DocMDP"); + /** A name */ + public static readonly PdfName DOCOPEN = new PdfName("DocOpen"); + /** A name */ + public static readonly PdfName DOMAIN = new PdfName("Domain"); + /** A name */ + public static readonly PdfName DP = new PdfName("DP"); + /** A name */ + public static readonly PdfName DR = new PdfName("DR"); + /** A name */ + public static readonly PdfName DS = new PdfName("DS"); + /** A name */ + public static readonly PdfName DUR = new PdfName("Dur"); + /** A name */ + public static readonly PdfName DUPLEX = new PdfName("Duplex"); + /** A name */ + public static readonly PdfName DUPLEXFLIPSHORTEDGE = new PdfName("DuplexFlipShortEdge"); + /** A name */ + public static readonly PdfName DUPLEXFLIPLONGEDGE = new PdfName("DuplexFlipLongEdge"); + /** A name */ + public static readonly PdfName DV = new PdfName("DV"); + /** A name */ + public static readonly PdfName DW = new PdfName("DW"); + /** A name */ + public static readonly PdfName E = new PdfName("E"); + /** A name */ + public static readonly PdfName EARLYCHANGE = new PdfName("EarlyChange"); + /** A name */ + public static readonly PdfName EF = new PdfName("EF"); + /** A name */ + public static readonly PdfName EMBEDDEDFILE = new PdfName("EmbeddedFile"); + /** A name */ + public static readonly PdfName EMBEDDEDFILES = new PdfName("EmbeddedFiles"); + /** A name */ + public static readonly PdfName ENCODE = new PdfName("Encode"); + /** A name */ + public static readonly PdfName ENCODEDBYTEALIGN = new PdfName("EncodedByteAlign"); + /** A name */ + public static readonly PdfName ENCODING = new PdfName("Encoding"); + /** A name */ + public static readonly PdfName ENCRYPT = new PdfName("Encrypt"); + /** A name */ + public static readonly PdfName ENCRYPTMETADATA = new PdfName("EncryptMetadata"); + /** A name */ + public static readonly PdfName ENDOFBLOCK = new PdfName("EndOfBlock"); + /** A name */ + public static readonly PdfName ENDOFLINE = new PdfName("EndOfLine"); + /** A name */ + public static readonly PdfName EXTEND = new PdfName("Extend"); + /** A name */ + public static readonly PdfName EXTGSTATE = new PdfName("ExtGState"); + /** A name */ + public static readonly PdfName EXPORT = new PdfName("Export"); + /** A name */ + public static readonly PdfName EXPORTSTATE = new PdfName("ExportState"); + /** A name */ + public static readonly PdfName EVENT = new PdfName("Event"); + /** A name */ + public static readonly PdfName F = new PdfName("F"); + /** A name */ + public static readonly PdfName FB = new PdfName("FB"); + /** A name */ + public static readonly PdfName FDECODEPARMS = new PdfName("FDecodeParms"); + /** A name */ + public static readonly PdfName FDF = new PdfName("FDF"); + /** A name */ + public static readonly PdfName FF = new PdfName("Ff"); + /** A name */ + public static readonly PdfName FFILTER = new PdfName("FFilter"); + /** A name */ + public static readonly PdfName FIELDS = new PdfName("Fields"); + /** A name */ + public static readonly PdfName FILEATTACHMENT = new PdfName("FileAttachment"); + /** A name */ + public static readonly PdfName FILESPEC = new PdfName("Filespec"); + /** A name */ + public static readonly PdfName FILTER = new PdfName("Filter"); + /** A name */ + public static readonly PdfName FIRST = new PdfName("First"); + /** A name */ + public static readonly PdfName FIRSTCHAR = new PdfName("FirstChar"); + /** A name */ + public static readonly PdfName FIRSTPAGE = new PdfName("FirstPage"); + /** A name */ + public static readonly PdfName FIT = new PdfName("Fit"); + /** A name */ + public static readonly PdfName FITH = new PdfName("FitH"); + /** A name */ + public static readonly PdfName FITV = new PdfName("FitV"); + /** A name */ + public static readonly PdfName FITR = new PdfName("FitR"); + /** A name */ + public static readonly PdfName FITB = new PdfName("FitB"); + /** A name */ + public static readonly PdfName FITBH = new PdfName("FitBH"); + /** A name */ + public static readonly PdfName FITBV = new PdfName("FitBV"); + /** A name */ + public static readonly PdfName FITWINDOW = new PdfName("FitWindow"); + /** A name */ + public static readonly PdfName FLAGS = new PdfName("Flags"); + /** A name */ + public static readonly PdfName FLATEDECODE = new PdfName("FlateDecode"); + /** A name */ + public static readonly PdfName FO = new PdfName("Fo"); + /** A name */ + public static readonly PdfName FONT = new PdfName("Font"); + /** A name */ + public static readonly PdfName FONTBBOX = new PdfName("FontBBox"); + /** A name */ + public static readonly PdfName FONTDESCRIPTOR = new PdfName("FontDescriptor"); + /** A name */ + public static readonly PdfName FONTFILE = new PdfName("FontFile"); + /** A name */ + public static readonly PdfName FONTFILE2 = new PdfName("FontFile2"); + /** A name */ + public static readonly PdfName FONTFILE3 = new PdfName("FontFile3"); + /** A name */ + public static readonly PdfName FONTMATRIX = new PdfName("FontMatrix"); + /** A name */ + public static readonly PdfName FONTNAME = new PdfName("FontName"); + /** A name */ + public static readonly PdfName FORM = new PdfName("Form"); + /** A name */ + public static readonly PdfName FORMTYPE = new PdfName("FormType"); + /** A name */ + public static readonly PdfName FREETEXT = new PdfName("FreeText"); + /** A name */ + public static readonly PdfName FRM = new PdfName("FRM"); + /** A name */ + public static readonly PdfName FS = new PdfName("FS"); + /** A name */ + public static readonly PdfName FT = new PdfName("FT"); + /** A name */ + public static readonly PdfName FULLSCREEN = new PdfName("FullScreen"); + /** A name */ + public static readonly PdfName FUNCTION = new PdfName("Function"); + /** A name */ + public static readonly PdfName FUNCTIONS = new PdfName("Functions"); + /** A name */ + public static readonly PdfName FUNCTIONTYPE = new PdfName("FunctionType"); + /** A name of an attribute. */ + public static readonly PdfName GAMMA = new PdfName("Gamma"); + /** A name of an attribute. */ + public static readonly PdfName GBK = new PdfName("GBK"); + /** A name of an attribute. */ + public static readonly PdfName GLITTER = new PdfName("Glitter"); + /** A name of an attribute. */ + public static readonly PdfName GOTO = new PdfName("GoTo"); + /** A name of an attribute. */ + public static readonly PdfName GOTOE = new PdfName("GoToE"); + /** A name of an attribute. */ + public static readonly PdfName GOTOR = new PdfName("GoToR"); + /** A name of an attribute. */ + public static readonly PdfName GROUP = new PdfName("Group"); + /** A name of an attribute. */ + public static readonly PdfName GTS_PDFA1 = new PdfName("GTS_PDFA1"); + /** A name of an attribute. */ + public static readonly PdfName GTS_PDFX = new PdfName("GTS_PDFX"); + /** A name of an attribute. */ + public static readonly PdfName GTS_PDFXVERSION = new PdfName("GTS_PDFXVersion"); + /** A name of an attribute. */ + public static readonly PdfName H = new PdfName("H"); + /** A name of an attribute. */ + public static readonly PdfName HEIGHT = new PdfName("Height"); + /** A name */ + public static readonly PdfName HELV = new PdfName("Helv"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName HELVETICA = new PdfName("Helvetica"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName HELVETICA_BOLD = new PdfName("Helvetica-Bold"); + /** This is a static PdfName PdfName of a base 14 type 1 font */ + public static readonly PdfName HELVETICA_OBLIQUE = new PdfName("Helvetica-Oblique"); + /** This is a static PdfName PdfName of a base 14 type 1 font */ + public static readonly PdfName HELVETICA_BOLDOBLIQUE = new PdfName("Helvetica-BoldOblique"); + /** A name */ + public static readonly PdfName HID = new PdfName("Hid"); + /** A name */ + public static readonly PdfName HIDE = new PdfName("Hide"); + /** A name */ + public static readonly PdfName HIDEMENUBAR = new PdfName("HideMenubar"); + /** A name */ + public static readonly PdfName HIDETOOLBAR = new PdfName("HideToolbar"); + /** A name */ + public static readonly PdfName HIDEWINDOWUI = new PdfName("HideWindowUI"); + /** A name */ + public static readonly PdfName HIGHLIGHT = new PdfName("Highlight"); + /** A name */ + public static readonly PdfName I = new PdfName("I"); + /** A name */ + public static readonly PdfName ICCBASED = new PdfName("ICCBased"); + /** A name */ + public static readonly PdfName ID = new PdfName("ID"); + /** A name */ + public static readonly PdfName IDENTITY = new PdfName("Identity"); + /** A name */ + public static readonly PdfName IF = new PdfName("IF"); + /** A name */ + public static readonly PdfName IMAGE = new PdfName("Image"); + /** A name */ + public static readonly PdfName IMAGEB = new PdfName("ImageB"); + /** A name */ + public static readonly PdfName IMAGEC = new PdfName("ImageC"); + /** A name */ + public static readonly PdfName IMAGEI = new PdfName("ImageI"); + /** A name */ + public static readonly PdfName IMAGEMASK = new PdfName("ImageMask"); + /** A name */ + public static readonly PdfName INDEX = new PdfName("Index"); + /** A name */ + public static readonly PdfName INDEXED = new PdfName("Indexed"); + /** A name */ + public static readonly PdfName INFO = new PdfName("Info"); + /** A name */ + public static readonly PdfName INK = new PdfName("Ink"); + /** A name */ + public static readonly PdfName INKLIST = new PdfName("InkList"); + /** A name */ + public static readonly PdfName IMPORTDATA = new PdfName("ImportData"); + /** A name */ + public static readonly PdfName INTENT = new PdfName("Intent"); + /** A name */ + public static readonly PdfName INTERPOLATE = new PdfName("Interpolate"); + /** A name */ + public static readonly PdfName ISMAP = new PdfName("IsMap"); + /** A name */ + public static readonly PdfName IRT = new PdfName("IRT"); + /** A name */ + public static readonly PdfName ITALICANGLE = new PdfName("ItalicAngle"); + /** A name */ + public static readonly PdfName IX = new PdfName("IX"); + /** A name */ + public static readonly PdfName JAVASCRIPT = new PdfName("JavaScript"); + /** A name */ + public static readonly PdfName JPXDECODE = new PdfName("JPXDecode"); + /** A name */ + public static readonly PdfName JS = new PdfName("JS"); + /** A name */ + public static readonly PdfName K = new PdfName("K"); + /** A name */ + public static readonly PdfName KEYWORDS = new PdfName("Keywords"); + /** A name */ + public static readonly PdfName KIDS = new PdfName("Kids"); + /** A name */ + public static readonly PdfName L = new PdfName("L"); + /** A name */ + public static readonly PdfName L2R = new PdfName("L2R"); + /** A name */ + public static readonly PdfName LANG = new PdfName("Lang"); + /** A name */ + public static readonly PdfName LANGUAGE = new PdfName("Language"); + /** A name */ + public static readonly PdfName LAST = new PdfName("Last"); + /** A name */ + public static readonly PdfName LASTCHAR = new PdfName("LastChar"); + /** A name */ + public static readonly PdfName LASTPAGE = new PdfName("LastPage"); + /** A name */ + public static readonly PdfName LAUNCH = new PdfName("Launch"); + /** A name */ + public static readonly PdfName LENGTH = new PdfName("Length"); + /** A name */ + public static readonly PdfName LENGTH1 = new PdfName("Length1"); + /** A name */ + public static readonly PdfName LIMITS = new PdfName("Limits"); + /** A name */ + public static readonly PdfName LINE = new PdfName("Line"); + /** A name */ + public static readonly PdfName LINK = new PdfName("Link"); + /** A name */ + public static readonly PdfName LISTMODE = new PdfName("ListMode"); + /** A name */ + public static readonly PdfName LOCATION = new PdfName("Location"); + /** A name */ + public static readonly PdfName LOCK = new PdfName("Lock"); + /** A name */ + public static readonly PdfName LOCKED = new PdfName("Locked"); + /** A name */ + public static readonly PdfName LZWDECODE = new PdfName("LZWDecode"); + /** A name */ + public static readonly PdfName M = new PdfName("M"); + /** A name */ + public static readonly PdfName MATRIX = new PdfName("Matrix"); + /** A name of an encoding */ + public static readonly PdfName MAC_EXPERT_ENCODING = new PdfName("MacExpertEncoding"); + /** A name of an encoding */ + public static readonly PdfName MAC_ROMAN_ENCODING = new PdfName("MacRomanEncoding"); + /** A name */ + public static readonly PdfName MARKED = new PdfName("Marked"); + /** A name */ + public static readonly PdfName MARKINFO = new PdfName("MarkInfo"); + /** A name */ + public static readonly PdfName MASK = new PdfName("Mask"); + /** A name */ + public static readonly PdfName MAX = new PdfName("max"); + /** A name */ + public static readonly PdfName MAXLEN = new PdfName("MaxLen"); + /** A name */ + public static readonly PdfName MEDIABOX = new PdfName("MediaBox"); + /** A name */ + public static readonly PdfName MCID = new PdfName("MCID"); + /** A name */ + public static readonly PdfName MCR = new PdfName("MCR"); + /** A name */ + public static readonly PdfName METADATA = new PdfName("Metadata"); + /** A name */ + public static readonly PdfName MIN = new PdfName("min"); + /** A name */ + public static readonly PdfName MK = new PdfName("MK"); + /** A name */ + public static readonly PdfName MMTYPE1 = new PdfName("MMType1"); + /** A name */ + public static readonly PdfName MODDATE = new PdfName("ModDate"); + /** A name */ + public static readonly PdfName N = new PdfName("N"); + /** A name */ + public static readonly PdfName N0 = new PdfName("n0"); + /** A name */ + public static readonly PdfName N1 = new PdfName("n1"); + /** A name */ + public static readonly PdfName N2 = new PdfName("n2"); + /** A name */ + public static readonly PdfName N3 = new PdfName("n3"); + /** A name */ + public static readonly PdfName N4 = new PdfName("n4"); + /** A name */ + public new static readonly PdfName NAME = new PdfName("Name"); + /** A name */ + public static readonly PdfName NAMED = new PdfName("Named"); + /** A name */ + public static readonly PdfName NAMES = new PdfName("Names"); + /** A name */ + public static readonly PdfName NEEDAPPEARANCES = new PdfName("NeedAppearances"); + /** A name */ + public static readonly PdfName NEWWINDOW = new PdfName("NewWindow"); + /** A name */ + public static readonly PdfName NEXT = new PdfName("Next"); + /** A name */ + public static readonly PdfName NEXTPAGE = new PdfName("NextPage"); + /** A name */ + public static readonly PdfName NM = new PdfName("NM"); + /** A name */ + public static readonly PdfName NONE = new PdfName("None"); + /** A name */ + public static readonly PdfName NONFULLSCREENPAGEMODE = new PdfName("NonFullScreenPageMode"); + /** A name */ + public static readonly PdfName NUMCOPIES = new PdfName("NumCopies"); + /** A name */ + public static readonly PdfName NUMS = new PdfName("Nums"); + /** A name */ + public static readonly PdfName O = new PdfName("O"); + /** A name */ + public static readonly PdfName OBJSTM = new PdfName("ObjStm"); + /** A name */ + public static readonly PdfName OC = new PdfName("OC"); + /** A name */ + public static readonly PdfName OCG = new PdfName("OCG"); + /** A name */ + public static readonly PdfName OCGS = new PdfName("OCGs"); + /** A name */ + public static readonly PdfName OCMD = new PdfName("OCMD"); + /** A name */ + public static readonly PdfName OCPROPERTIES = new PdfName("OCProperties"); + /** A name */ + public static readonly PdfName Off_ = new PdfName("Off"); + /** A name */ + public static readonly PdfName OFF = new PdfName("OFF"); + /** A name */ + public static readonly PdfName ON = new PdfName("ON"); + /** A name */ + public static readonly PdfName ONECOLUMN = new PdfName("OneColumn"); + /** A name */ + public static readonly PdfName OPEN = new PdfName("Open"); + /** A name */ + public static readonly PdfName OPENACTION = new PdfName("OpenAction"); + /** A name */ + public static readonly PdfName OP = new PdfName("OP"); + /** A name */ + public static readonly PdfName op_ = new PdfName("op"); + /** A name */ + public static readonly PdfName OPM = new PdfName("OPM"); + /** A name */ + public static readonly PdfName OPT = new PdfName("Opt"); + /** A name */ + public static readonly PdfName ORDER = new PdfName("Order"); + /** A name */ + public static readonly PdfName ORDERING = new PdfName("Ordering"); + /** A name */ + public static readonly PdfName OUTLINES = new PdfName("Outlines"); + /** A name */ + public static readonly PdfName OUTPUTCONDITION = new PdfName("OutputCondition"); + /** A name */ + public static readonly PdfName OUTPUTCONDITIONIDENTIFIER = new PdfName("OutputConditionIdentifier"); + /** A name */ + public static readonly PdfName OUTPUTINTENT = new PdfName("OutputIntent"); + /** A name */ + public static readonly PdfName OUTPUTINTENTS = new PdfName("OutputIntents"); + /** A name */ + public static readonly PdfName P = new PdfName("P"); + /** A name */ + public static readonly PdfName PAGE = new PdfName("Page"); + /** A name */ + public static readonly PdfName PAGELABELS = new PdfName("PageLabels"); + /** A name */ + public static readonly PdfName PAGELAYOUT = new PdfName("PageLayout"); + /** A name */ + public static readonly PdfName PAGEMODE = new PdfName("PageMode"); + /** A name */ + public static readonly PdfName PAGES = new PdfName("Pages"); + /** A name */ + public static readonly PdfName PAINTTYPE = new PdfName("PaintType"); + /** A name */ + public static readonly PdfName PANOSE = new PdfName("Panose"); + /** A name */ + public static readonly PdfName PARAMS = new PdfName("Params"); + /** A name */ + public static readonly PdfName PARENT = new PdfName("Parent"); + /** A name */ + public static readonly PdfName PARENTTREE = new PdfName("ParentTree"); + /** A name */ + public static readonly PdfName PATTERN = new PdfName("Pattern"); + /** A name */ + public static readonly PdfName PATTERNTYPE = new PdfName("PatternType"); + /** A name */ + public static readonly PdfName PDF = new PdfName("PDF"); + /** A name */ + public static readonly PdfName PDFDOCENCODING = new PdfName("PDFDocEncoding"); + /** A name */ + public static readonly PdfName PERCEPTUAL = new PdfName("Perceptual"); + /** A name */ + public static readonly PdfName PERMS = new PdfName("Perms"); + /** A name */ + public static readonly PdfName PG = new PdfName("Pg"); + /** A name */ + public static readonly PdfName PICKTRAYBYPDFSIZE = new PdfName("PickTrayByPDFSize"); + /** A name */ + public static readonly PdfName POPUP = new PdfName("Popup"); + /** A name */ + public static readonly PdfName PREDICTOR = new PdfName("Predictor"); + /** A name */ + public static readonly PdfName PREFERRED = new PdfName("Preferred"); + /** A name */ + public static readonly PdfName PRESERVERB = new PdfName("PreserveRB"); + /** A name */ + public static readonly PdfName PREV = new PdfName("Prev"); + /** A name */ + public static readonly PdfName PREVPAGE = new PdfName("PrevPage"); + /** A name */ + public static readonly PdfName PRINT = new PdfName("Print"); + /** A name */ + public static readonly PdfName PRINTAREA = new PdfName("PrintArea"); + /** A name */ + public static readonly PdfName PRINTCLIP = new PdfName("PrintClip"); + /** A name */ + public static readonly PdfName PRINTPAGERANGE = new PdfName("PrintPageRange"); + /** A name */ + public static readonly PdfName PRINTSCALING = new PdfName("PrintScaling"); + /** A name */ + public static readonly PdfName PRINTSTATE = new PdfName("PrintState"); + /** A name */ + public static readonly PdfName PROCSET = new PdfName("ProcSet"); + /** A name */ + public static readonly PdfName PRODUCER = new PdfName("Producer"); + /** A name */ + public static readonly PdfName PROPERTIES = new PdfName("Properties"); + /** A name */ + public static readonly PdfName PS = new PdfName("PS"); + /** A name */ + public static readonly PdfName PUBSEC = new PdfName("Adobe.PubSec"); + /** A name */ + public static readonly PdfName Q = new PdfName("Q"); + /** A name */ + public static readonly PdfName QUADPOINTS = new PdfName("QuadPoints"); + /** A name */ + public static readonly PdfName R = new PdfName("R"); + /** A name */ + public static readonly PdfName R2L = new PdfName("R2L"); + /** A name */ + public static readonly PdfName RANGE = new PdfName("Range"); + /** A name */ + public static readonly PdfName RC = new PdfName("RC"); + /** A name */ + public static readonly PdfName RBGROUPS = new PdfName("RBGroups"); + /** A name */ + public static readonly PdfName REASON = new PdfName("Reason"); + /** A name */ + public static readonly PdfName RECIPIENTS = new PdfName("Recipients"); + /** A name */ + public static readonly PdfName RECT = new PdfName("Rect"); + /** A name */ + public static readonly PdfName REFERENCE = new PdfName("Reference"); + /** A name */ + public static readonly PdfName REGISTRY = new PdfName("Registry"); + /** A name */ + public static readonly PdfName REGISTRYNAME = new PdfName("RegistryName"); + /** A name */ + public static readonly PdfName RELATIVECALORIMETRIC = new PdfName("RelativeColorimetric"); + /** A name */ + public static readonly PdfName RENDITION = new PdfName("Rendition"); + /** A name */ + public static readonly PdfName RESETFORM = new PdfName("ResetForm"); + /** A name */ + public static readonly PdfName RESOURCES = new PdfName("Resources"); + /** A name */ + public static readonly PdfName RI = new PdfName("RI"); + /** A name */ + public static readonly PdfName ROLEMAP = new PdfName("RoleMap"); + /** A name */ + public static readonly PdfName ROOT = new PdfName("Root"); + /** A name */ + public static readonly PdfName ROTATE = new PdfName("Rotate"); + /** A name */ + public static readonly PdfName ROWS = new PdfName("Rows"); + /** A name */ + public static readonly PdfName RUNLENGTHDECODE = new PdfName("RunLengthDecode"); + /** A name */ + public static readonly PdfName RV = new PdfName("RV"); + /** A name */ + public static readonly PdfName S = new PdfName("S"); + /** A name */ + public static readonly PdfName SATURATION = new PdfName("Saturation"); + /** A name */ + public static readonly PdfName SCHEMA = new PdfName("Schema"); + /** A name */ + public static readonly PdfName SCREEN = new PdfName("Screen"); + /** A name */ + public static readonly PdfName SECT = new PdfName("Sect"); + /** A name */ + public static readonly PdfName SEPARATION = new PdfName("Separation"); + /** A name */ + public static readonly PdfName SETOCGSTATE = new PdfName("SetOCGState"); + /** A name */ + public static readonly PdfName SHADING = new PdfName("Shading"); + /** A name */ + public static readonly PdfName SHADINGTYPE = new PdfName("ShadingType"); + /** A name */ + public static readonly PdfName SHIFT_JIS = new PdfName("Shift-JIS"); + /** A name */ + public static readonly PdfName SIG = new PdfName("Sig"); + /** A name */ + public static readonly PdfName SIGFLAGS = new PdfName("SigFlags"); + /** A name */ + public static readonly PdfName SIGREF = new PdfName("SigRef"); + /** A name */ + public static readonly PdfName SIMPLEX = new PdfName("Simplex"); + /** A name */ + public static readonly PdfName SINGLEPAGE = new PdfName("SinglePage"); + /** A name */ + public static readonly PdfName SIZE = new PdfName("Size"); + /** A name */ + public static readonly PdfName SMASK = new PdfName("SMask"); + /** A name */ + public static readonly PdfName SORT = new PdfName("Sort"); + /** A name */ + public static readonly PdfName SPAN = new PdfName("Span"); + /** A name */ + public static readonly PdfName SPLIT = new PdfName("Split"); + /** A name */ + public static readonly PdfName SQUARE = new PdfName("Square"); + /** A name */ + public static readonly PdfName SQUIGGLY = new PdfName("Squiggly"); + /** A name */ + public static readonly PdfName ST = new PdfName("St"); + /** A name */ + public static readonly PdfName STAMP = new PdfName("Stamp"); + /** A name */ + public static readonly PdfName STANDARD = new PdfName("Standard"); + /** A name */ + public static readonly PdfName STATE = new PdfName("State"); + /** A name */ + public static readonly PdfName STDCF = new PdfName("StdCF"); + /** A name */ + public static readonly PdfName STEMV = new PdfName("StemV"); + /** A name */ + public static readonly PdfName STMF = new PdfName("StmF"); + /** A name */ + public static readonly PdfName STRF = new PdfName("StrF"); + /** A name */ + public static readonly PdfName STRIKEOUT = new PdfName("StrikeOut"); + /** A name */ + public static readonly PdfName STRUCTPARENT = new PdfName("StructParent"); + /** A name */ + public static readonly PdfName STRUCTPARENTS = new PdfName("StructParents"); + /** A name */ + public static readonly PdfName STRUCTTREEROOT = new PdfName("StructTreeRoot"); + /** A name */ + public static readonly PdfName STYLE = new PdfName("Style"); + /** A name */ + public static readonly PdfName SUBFILTER = new PdfName("SubFilter"); + /** A name */ + public static readonly PdfName SUBJECT = new PdfName("Subject"); + /** A name */ + public static readonly PdfName SUBMITFORM = new PdfName("SubmitForm"); + /** A name */ + public static readonly PdfName SUBTYPE = new PdfName("Subtype"); + /** A name */ + public static readonly PdfName SUPPLEMENT = new PdfName("Supplement"); + /** A name */ + public static readonly PdfName SV = new PdfName("SV"); + /** A name */ + public static readonly PdfName SW = new PdfName("SW"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName SYMBOL = new PdfName("Symbol"); + /** A name */ + public static readonly PdfName T = new PdfName("T"); + /** A name */ + public static readonly PdfName TEXT = new PdfName("Text"); + /** A name */ + public static readonly PdfName THUMB = new PdfName("Thumb"); + /** A name */ + public static readonly PdfName THREADS = new PdfName("Threads"); + /** A name */ + public static readonly PdfName TI = new PdfName("TI"); + /** A name */ + public static readonly PdfName TILINGTYPE = new PdfName("TilingType"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName TIMES_ROMAN = new PdfName("Times-Roman"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName TIMES_BOLD = new PdfName("Times-Bold"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName TIMES_ITALIC = new PdfName("Times-Italic"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName TIMES_BOLDITALIC = new PdfName("Times-BoldItalic"); + /** A name */ + public static readonly PdfName TITLE = new PdfName("Title"); + /** A name */ + public static readonly PdfName TK = new PdfName("TK"); + /** A name */ + public static readonly PdfName TM = new PdfName("TM"); + /** A name */ + public static readonly PdfName TOGGLE = new PdfName("Toggle"); + /** A name */ + public static readonly PdfName TOUNICODE = new PdfName("ToUnicode"); + /** A name */ + public static readonly PdfName TP = new PdfName("TP"); + /** A name */ + public static readonly PdfName TRANS = new PdfName("Trans"); + /** A name */ + public static readonly PdfName TRANSFORMPARAMS = new PdfName("TransformParams"); + /** A name */ + public static readonly PdfName TRANSFORMMETHOD = new PdfName("TransformMethod"); + /** A name */ + public static readonly PdfName TRANSPARENCY = new PdfName("Transparency"); + /** A name */ + public static readonly PdfName TRAPPED = new PdfName("Trapped"); + /** A name */ + public static readonly PdfName TRIMBOX = new PdfName("TrimBox"); + /** A name */ + public static readonly PdfName TRUETYPE = new PdfName("TrueType"); + /** A name */ + public static readonly PdfName TU = new PdfName("TU"); + /** A name */ + public static readonly PdfName TWOCOLUMNLEFT = new PdfName("TwoColumnLeft"); + /** A name */ + public static readonly PdfName TWOCOLUMNRIGHT = new PdfName("TwoColumnRight"); + /** A name */ + public static readonly PdfName TWOPAGELEFT = new PdfName("TwoPageLeft"); + /** A name */ + public static readonly PdfName TWOPAGERIGHT = new PdfName("TwoPageRight"); + /** A name */ + public static readonly PdfName TX = new PdfName("Tx"); + /** A name */ + public static readonly PdfName TYPE = new PdfName("Type"); + /** A name */ + public static readonly PdfName TYPE0 = new PdfName("Type0"); + /** A name */ + public static readonly PdfName TYPE1 = new PdfName("Type1"); + /** A name of an attribute. */ + public static readonly PdfName TYPE3 = new PdfName("Type3"); + /** A name of an attribute. */ + public static readonly PdfName U = new PdfName("U"); + /** A name of an attribute. */ + public static readonly PdfName UF = new PdfName("UF"); + /** A name of an attribute. */ + public static readonly PdfName UHC = new PdfName("UHC"); + /** A name of an attribute. */ + public static readonly PdfName UNDERLINE = new PdfName("Underline"); + /** A name */ + public static readonly PdfName UR = new PdfName("UR"); + /** A name */ + public static readonly PdfName UR3 = new PdfName("UR3"); + /** A name */ + public static readonly PdfName URI = new PdfName("URI"); + /** A name */ + public static readonly PdfName URL = new PdfName("URL"); + /** A name */ + public static readonly PdfName USAGE = new PdfName("Usage"); + /** A name */ + public static readonly PdfName USEATTACHMENTS = new PdfName("UseAttachments"); + /** A name */ + public static readonly PdfName USENONE = new PdfName("UseNone"); + /** A name */ + public static readonly PdfName USEOC = new PdfName("UseOC"); + /** A name */ + public static readonly PdfName USEOUTLINES = new PdfName("UseOutlines"); + /** A name */ + public static readonly PdfName USER = new PdfName("User"); + /** A name */ + public static readonly PdfName USERPROPERTIES = new PdfName("UserProperties"); + /** A name */ + public static readonly PdfName USERUNIT = new PdfName("UserUnit"); + /** A name */ + public static readonly PdfName USETHUMBS = new PdfName("UseThumbs"); + /** A name */ + public static readonly PdfName V = new PdfName("V"); + /** A name */ + public static readonly PdfName V2 = new PdfName("V2"); + /** A name */ + public static readonly PdfName VERISIGN_PPKVS = new PdfName("VeriSign.PPKVS"); + /** A name */ + public static readonly PdfName VERSION = new PdfName("Version"); + /** A name */ + public static readonly PdfName VIEW = new PdfName("View"); + /** A name */ + public static readonly PdfName VIEWAREA = new PdfName("ViewArea"); + /** A name */ + public static readonly PdfName VIEWCLIP = new PdfName("ViewClip"); + /** A name */ + public static readonly PdfName VIEWERPREFERENCES = new PdfName("ViewerPreferences"); + /** A name */ + public static readonly PdfName VIEWSTATE = new PdfName("ViewState"); + /** A name */ + public static readonly PdfName VISIBLEPAGES = new PdfName("VisiblePages"); + /** A name of an attribute. */ + public static readonly PdfName W = new PdfName("W"); + /** A name of an attribute. */ + public static readonly PdfName W2 = new PdfName("W2"); + /** A name of an attribute. */ + public static readonly PdfName WC = new PdfName("WC"); + /** A name of an attribute. */ + public static readonly PdfName WIDGET = new PdfName("Widget"); + /** A name of an attribute. */ + public static readonly PdfName WIDTH = new PdfName("Width"); + /** A name */ + public static readonly PdfName WIDTHS = new PdfName("Widths"); + /** A name of an encoding */ + public static readonly PdfName WIN = new PdfName("Win"); + /** A name of an encoding */ + public static readonly PdfName WIN_ANSI_ENCODING = new PdfName("WinAnsiEncoding"); + /** A name of an encoding */ + public static readonly PdfName WIPE = new PdfName("Wipe"); + /** A name */ + public static readonly PdfName WHITEPOINT = new PdfName("WhitePoint"); + /** A name */ + public static readonly PdfName WP = new PdfName("WP"); + /** A name of an encoding */ + public static readonly PdfName WS = new PdfName("WS"); + /** A name */ + public static readonly PdfName X = new PdfName("X"); + /** A name */ + public static readonly PdfName XFA = new PdfName("XFA"); + /** A name */ + public static readonly PdfName XML = new PdfName("XML"); + /** A name */ + public static readonly PdfName XOBJECT = new PdfName("XObject"); + /** A name */ + public static readonly PdfName XSTEP = new PdfName("XStep"); + /** A name */ + public static readonly PdfName XREF = new PdfName("XRef"); + /** A name */ + public static readonly PdfName XREFSTM = new PdfName("XRefStm"); + /** A name */ + public static readonly PdfName XYZ = new PdfName("XYZ"); + /** A name */ + public static readonly PdfName YSTEP = new PdfName("YStep"); + /** A name */ + public static readonly PdfName ZADB = new PdfName("ZaDb"); + /** A name of a base 14 type 1 font */ + public static readonly PdfName ZAPFDINGBATS = new PdfName("ZapfDingbats"); + /** A name */ + public static readonly PdfName ZOOM = new PdfName("Zoom"); + + private int hash = 0; + + // constructors + + /** + * Constructs a new PdfName. The name length will be checked. + * @param name the new name + */ + public PdfName(String name) : this(name, true) { + } + + /** + * Constructs a new PdfName. + * @param name the new name + * @param lengthCheck if true check the lenght validity, if false the name can + * have any length + */ + public PdfName(string name, bool lengthCheck) : base(PdfObject.NAME) { + // The minimum number of characters in a name is 0, the maximum is 127 (the '/' not included) + int length = name.Length; + if (lengthCheck && length > 127) { + throw new ArgumentException("The name '" + name + "' is too long (" + length + " characters)."); + } + // every special character has to be substituted + ByteBuffer pdfName = new ByteBuffer(length + 20); + pdfName.Append('/'); + char[] chars = name.ToCharArray(); + char character; + // loop over all the characters + foreach (char cc in chars) { + character = (char)(cc & 0xff); + // special characters are escaped (reference manual p.39) + switch (character) { + case ' ': + case '%': + case '(': + case ')': + case '<': + case '>': + case '[': + case ']': + case '{': + case '}': + case '/': + case '#': + pdfName.Append('#'); + pdfName.Append(System.Convert.ToString(character, 16)); + break; + default: + if (character > 126 || character < 32) { + pdfName.Append('#'); + if (character < 16) + pdfName.Append('0'); + pdfName.Append(System.Convert.ToString(character, 16)); + } + else + pdfName.Append(character); + break; + } + } + bytes = pdfName.ToByteArray(); + } + + public PdfName(byte[] bytes) : base(PdfObject.NAME, bytes) { + } + + // methods + + /** + * Compares this object with the specified object for order. Returns a + * negative int, zero, or a positive int as this object is less + * than, equal to, or greater than the specified object.

    + * + * + * @param object the Object to be compared. + * @return a negative int, zero, or a positive int as this object + * is less than, equal to, or greater than the specified object. + * + * @throws Exception if the specified object's type prevents it + * from being compared to this Object. + */ + public int CompareTo(Object obj) { + PdfName name = (PdfName) obj; + + byte[] myBytes = bytes; + byte[] objBytes = name.bytes; + int len = Math.Min(myBytes.Length, objBytes.Length); + for (int i=0; i objBytes[i]) + return 1; + + if (myBytes[i] < objBytes[i]) + return -1; + } + if (myBytes.Length < objBytes.Length) + return -1; + if (myBytes.Length > objBytes.Length) + return 1; + return 0; + } + + /** + * Indicates whether some other object is "equal to" this one. + * + * @param obj the reference object with which to compare. + * @return true if this object is the same as the obj + * argument; false otherwise. + */ + public override bool Equals(Object obj) { + if (this == obj) + return true; + if (obj is PdfName) + return CompareTo(obj) == 0; + return false; + } + + /** + * Returns a hash code value for the object. This method is + * supported for the benefit of hashtables such as those provided by + * java.util.Hashtable. + * + * @return a hash code value for this object. + */ + public override int GetHashCode() { + int h = hash; + if (h == 0) { + int ptr = 0; + int len = bytes.Length; + + for (int i = 0; i < len; i++) + h = 31*h + (bytes[ptr++] & 0xff); + hash = h; + } + return h; + } + + /** Decodes an escaped name in the form "/AB#20CD" into "AB CD". + * @param name the name to decode + * @return the decoded name + */ + public static string DecodeName(string name) { + StringBuilder buf = new StringBuilder(); + int len = name.Length; + for (int k = 1; k < len; ++k) { + char c = name[k]; + if (c == '#') { + c = (char)((PRTokeniser.GetHex(name[k + 1]) << 4) + PRTokeniser.GetHex(name[k + 2])); + k += 2; + } + buf.Append(c); + } + return buf.ToString(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfNameTree.cs b/iTechSharp/iTextSharp/text/pdf/PdfNameTree.cs new file mode 100644 index 0000000..a7617ef --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfNameTree.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Creates a name tree. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfNameTree { + + private const int leafSize = 64; + + /** + * Creates a name tree. + * @param items the item of the name tree. The key is a String + * and the value is a PdfObject. Note that although the + * keys are strings only the lower byte is used and no check is made for chars + * with the same lower byte and different upper byte. This will generate a wrong + * tree name. + * @param writer the writer + * @throws IOException on error + * @return the dictionary with the name tree. This dictionary is the one + * generally pointed to by the key /Dests, for example + */ + public static PdfDictionary WriteTree(Hashtable items, PdfWriter writer) { + if (items.Count == 0) + return null; + String[] names = new String[items.Count]; + items.Keys.CopyTo(names, 0); + Array.Sort(names); + if (names.Length <= leafSize) { + PdfDictionary dic = new PdfDictionary(); + PdfArray ar = new PdfArray(); + for (int k = 0; k < names.Length; ++k) { + ar.Add(new PdfString(names[k], null)); + ar.Add((PdfObject)items[names[k]]); + } + dic.Put(PdfName.NAMES, ar); + return dic; + } + int skip = leafSize; + PdfIndirectReference[] kids = new PdfIndirectReference[(names.Length + leafSize - 1) / leafSize]; + for (int k = 0; k < kids.Length; ++k) { + int offset = k * leafSize; + int end = Math.Min(offset + leafSize, names.Length); + PdfDictionary dic = new PdfDictionary(); + PdfArray arr = new PdfArray(); + arr.Add(new PdfString(names[offset], null)); + arr.Add(new PdfString(names[end - 1], null)); + dic.Put(PdfName.LIMITS, arr); + arr = new PdfArray(); + for (; offset < end; ++offset) { + arr.Add(new PdfString(names[offset], null)); + arr.Add((PdfObject)items[names[offset]]); + } + dic.Put(PdfName.NAMES, arr); + kids[k] = writer.AddToBody(dic).IndirectReference; + } + int top = kids.Length; + while (true) { + if (top <= leafSize) { + PdfArray arr = new PdfArray(); + for (int k = 0; k < top; ++k) + arr.Add(kids[k]); + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.KIDS, arr); + return dic; + } + skip *= leafSize; + int tt = (names.Length + skip - 1 )/ skip; + for (int k = 0; k < tt; ++k) { + int offset = k * leafSize; + int end = Math.Min(offset + leafSize, top); + PdfDictionary dic = new PdfDictionary(); + PdfArray arr = new PdfArray(); + arr.Add(new PdfString(names[k * skip], null)); + arr.Add(new PdfString(names[Math.Min((k + 1) * skip, names.Length) - 1], null)); + dic.Put(PdfName.LIMITS, arr); + arr = new PdfArray(); + for (; offset < end; ++offset) { + arr.Add(kids[offset]); + } + dic.Put(PdfName.KIDS, arr); + kids[k] = writer.AddToBody(dic).IndirectReference; + } + top = tt; + } + } + + private static void IterateItems(PdfDictionary dic, Hashtable items) { + PdfArray nn = (PdfArray)PdfReader.GetPdfObjectRelease(dic.Get(PdfName.NAMES)); + if (nn != null) { + ArrayList arr = nn.ArrayList; + for (int k = 0; k < arr.Count; ++k) { + PdfString s = (PdfString)PdfReader.GetPdfObjectRelease((PdfObject)arr[k++]); + items[PdfEncodings.ConvertToString(s.GetBytes(), null)] = arr[k]; + } + } + else if ((nn = (PdfArray)PdfReader.GetPdfObjectRelease(dic.Get(PdfName.KIDS))) != null) { + ArrayList arr = nn.ArrayList; + for (int k = 0; k < arr.Count; ++k) { + PdfDictionary kid = (PdfDictionary)PdfReader.GetPdfObjectRelease((PdfObject)arr[k]); + IterateItems(kid, items); + } + } + } + + public static Hashtable ReadTree(PdfDictionary dic) { + Hashtable items = new Hashtable(); + if (dic != null) + IterateItems(dic, items); + return items; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfNull.cs b/iTechSharp/iTextSharp/text/pdf/PdfNull.cs new file mode 100644 index 0000000..8e066a9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfNull.cs @@ -0,0 +1,85 @@ +using System; + +/* + * $Id: PdfNull.cs,v 1.4 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfNull is the Null object represented by the keyword null. + *

    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.9 (page 53). + * + * @see PdfObject + */ + + public class PdfNull : PdfObject { + + // static membervariables + + /** This is an instance of the PdfNull-object. */ + public static PdfNull PDFNULL = new PdfNull(); + + // constructors + + /** + * Constructs a PdfNull-object. + *

    + * You never need to do this yourself, you can always use the static object PDFNULL. + */ + + public PdfNull() : base(NULL, "null") {} + + public override String ToString() { + return "null"; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfNumber.cs b/iTechSharp/iTextSharp/text/pdf/PdfNumber.cs new file mode 100644 index 0000000..421c437 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfNumber.cs @@ -0,0 +1,163 @@ +using System; + +/* + * $Id: PdfNumber.cs,v 1.4 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfNumber provides two types of numbers, int and real. + *

    + * ints may be specified by signed or unsigned constants. Reals may only be + * in decimal format.
    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.3 (page 37). + * + * @see PdfObject + * @see BadPdfFormatException + */ + + public class PdfNumber : PdfObject { + + /** actual value of this PdfNumber, represented as a double */ + private double value; + + // constructors + + /** + * Constructs a PdfNumber-object. + * + * @param content value of the new PdfNumber-object + */ + + public PdfNumber(string content) : base(NUMBER) { + try { + value = Double.Parse(content.Trim(), System.Globalization.NumberFormatInfo.InvariantInfo); + this.Content = content; + } + catch (Exception nfe){ + throw new Exception(content + " is not a valid number - " + nfe.ToString()); + } + } + + /** + * Constructs a new int PdfNumber-object. + * + * @param value value of the new PdfNumber-object + */ + + public PdfNumber(int value) : base(NUMBER) { + this.value = value; + this.Content = value.ToString(); + } + + /** + * Constructs a new REAL PdfNumber-object. + * + * @param value value of the new PdfNumber-object + */ + + public PdfNumber(double value) : base(NUMBER) { + this.value = value; + Content = ByteBuffer.FormatDouble(value); + } + + /** + * Constructs a new REAL PdfNumber-object. + * + * @param value value of the new PdfNumber-object + */ + + public PdfNumber(float value) : this((double)value) {} + + // methods returning the value of this object + + /** + * Returns the primitive int value of this object. + * + * @return a value + */ + + public int IntValue { + get { + return (int) value; + } + } + + /** + * Returns the primitive double value of this object. + * + * @return a value + */ + + public double DoubleValue { + get { + return value; + } + } + + public float FloatValue { + get { + return (float)value; + } + } + + // other methods + + /** + * Increments the value of the PdfNumber-object with 1. + */ + + public void Increment() { + value += 1.0; + Content = ByteBuffer.FormatDouble(value); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfNumberTree.cs b/iTechSharp/iTextSharp/text/pdf/PdfNumberTree.cs new file mode 100644 index 0000000..d41c1af --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfNumberTree.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections; +/* + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Creates a number tree. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfNumberTree { + + private const int leafSize = 64; + + /** + * Creates a number tree. + * @param items the item of the number tree. The key is an Integer + * and the value is a PdfObject. + * @param writer the writer + * @throws IOException on error + * @return the dictionary with the number tree. + */ + public static PdfDictionary WriteTree(Hashtable items, PdfWriter writer) { + if (items.Count == 0) + return null; + int[] numbers = new int[items.Count]; + items.Keys.CopyTo(numbers, 0); + Array.Sort(numbers); + if (numbers.Length <= leafSize) { + PdfDictionary dic = new PdfDictionary(); + PdfArray ar = new PdfArray(); + for (int k = 0; k < numbers.Length; ++k) { + ar.Add(new PdfNumber(numbers[k])); + ar.Add((PdfObject)items[numbers[k]]); + } + dic.Put(PdfName.NUMS, ar); + return dic; + } + int skip = leafSize; + PdfIndirectReference[] kids = new PdfIndirectReference[(numbers.Length + leafSize - 1) / leafSize]; + for (int k = 0; k < kids.Length; ++k) { + int offset = k * leafSize; + int end = Math.Min(offset + leafSize, numbers.Length); + PdfDictionary dic = new PdfDictionary(); + PdfArray arr = new PdfArray(); + arr.Add(new PdfNumber(numbers[offset])); + arr.Add(new PdfNumber(numbers[end - 1])); + dic.Put(PdfName.LIMITS, arr); + arr = new PdfArray(); + for (; offset < end; ++offset) { + arr.Add(new PdfNumber(numbers[offset])); + arr.Add((PdfObject)items[numbers[offset]]); + } + dic.Put(PdfName.NUMS, arr); + kids[k] = writer.AddToBody(dic).IndirectReference; + } + int top = kids.Length; + while (true) { + if (top <= leafSize) { + PdfArray arr = new PdfArray(); + for (int k = 0; k < top; ++k) + arr.Add(kids[k]); + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.KIDS, arr); + return dic; + } + skip *= leafSize; + int tt = (numbers.Length + skip - 1 )/ skip; + for (int k = 0; k < tt; ++k) { + int offset = k * leafSize; + int end = Math.Min(offset + leafSize, top); + PdfDictionary dic = new PdfDictionary(); + PdfArray arr = new PdfArray(); + arr.Add(new PdfNumber(numbers[k * skip])); + arr.Add(new PdfNumber(numbers[Math.Min((k + 1) * skip, numbers.Length) - 1])); + dic.Put(PdfName.LIMITS, arr); + arr = new PdfArray(); + for (; offset < end; ++offset) { + arr.Add(kids[offset]); + } + dic.Put(PdfName.KIDS, arr); + kids[k] = writer.AddToBody(dic).IndirectReference; + } + top = tt; + } + } + + private static void IterateItems(PdfDictionary dic, Hashtable items) { + PdfArray nn = (PdfArray)PdfReader.GetPdfObjectRelease(dic.Get(PdfName.NUMS)); + if (nn != null) { + ArrayList arr = nn.ArrayList; + for (int k = 0; k < arr.Count; ++k) { + PdfNumber s = (PdfNumber)PdfReader.GetPdfObjectRelease((PdfObject)arr[k++]); + items[s.IntValue] = arr[k]; + } + } + else if ((nn = (PdfArray)PdfReader.GetPdfObjectRelease(dic.Get(PdfName.KIDS))) != null) { + ArrayList arr = nn.ArrayList; + for (int k = 0; k < arr.Count; ++k) { + PdfDictionary kid = (PdfDictionary)PdfReader.GetPdfObjectRelease((PdfObject)arr[k]); + IterateItems(kid, items); + } + } + } + + public static Hashtable ReadTree(PdfDictionary dic) { + Hashtable items = new Hashtable(); + if (dic != null) + IterateItems(dic, items); + return items; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfOCProperties.cs b/iTechSharp/iTextSharp/text/pdf/PdfOCProperties.cs new file mode 100644 index 0000000..0b5de68 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfOCProperties.cs @@ -0,0 +1,52 @@ +using System; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + public class PdfOCProperties : PdfDictionary { + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfObject.cs b/iTechSharp/iTextSharp/text/pdf/PdfObject.cs new file mode 100644 index 0000000..f08296d --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfObject.cs @@ -0,0 +1,369 @@ +/* + * $Id: PdfObject.cs,v 1.3 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +using System; +using System.IO; + +namespace iTextSharp.text.pdf { + /** + * PdfObject is the abstract baseclass of all PDF objects. + *

    + * PDF supports seven basic types of objects: bools, numbers, strings, names, + * arrays, dictionaries and streams. In addition, PDF provides a null object. + * Objects may be labeled so that they can be referred to by other objects.
    + * All these basic PDF objects are described in the 'Portable Document Format + * Reference Manual version 1.3' Chapter 4 (pages 37-54). + * + * @see PdfNull + * @see Pdfbool + * @see PdfNumber + * @see PdfString + * @see PdfName + * @see PdfArray + * @see PdfDictionary + * @see PdfStream + * @see PdfIndirectReference + */ + + public abstract class PdfObject { + + // static membervariables (all the possible types of a PdfObject) + + /** a possible type of PdfObject */ + public const int BOOLEAN = 1; + + /** a possible type of PdfObject */ + public const int NUMBER = 2; + + /** a possible type of PdfObject */ + public const int STRING = 3; + + /** a possible type of PdfObject */ + public const int NAME = 4; + + /** a possible type of PdfObject */ + public const int ARRAY = 5; + + /** a possible type of PdfObject */ + public const int DICTIONARY = 6; + + /** a possible type of PdfObject */ + public const int STREAM = 7; + + /** a possible type of PdfObject */ + public const int NULL = 8; + + /** a possible type of PdfObject */ + public const int INDIRECT = 10; + + /** This is an empty string used for the PdfNull-object and for an empty PdfString-object. */ + public const string NOTHING = ""; + + /** This is the default encoding to be used for converting strings into bytes and vice versa. + * The default encoding is PdfDocEcoding. + */ + public const string TEXT_PDFDOCENCODING = "PDF"; + + /** This is the encoding to be used to output text in Unicode. */ + public const string TEXT_UNICODE = "UnicodeBig"; + + // membervariables + + /** the content of this PdfObject */ + protected byte[] bytes; + + /** the type of this PdfObject */ + protected int type; + + /** + * Holds value of property indRef. + */ + protected PRIndirectReference indRef; + + // constructors + + /** + * Constructs a PdfObject of a certain type without any content. + * + * @param type type of the new PdfObject + */ + + protected PdfObject(int type) { + this.type = type; + } + + /** + * Constructs a PdfObject of a certain type with a certain content. + * + * @param type type of the new PdfObject + * @param content content of the new PdfObject as a String. + */ + + protected PdfObject(int type, string content) { + this.type = type; + bytes = PdfEncodings.ConvertToBytes(content, null); + } + + /** + * Constructs a PdfObject of a certain type with a certain content. + * + * @param type type of the new PdfObject + * @param bytes content of the new PdfObject as an array of byte. + */ + + protected PdfObject(int type, byte[] bytes) { + this.bytes = bytes; + this.type = type; + } + + // methods dealing with the content of this object + + /** + * Writes the PDF representation of this PdfObject as an array of bytes to the writer. + * @param writer for backwards compatibility + * @param os the outputstream to write the bytes to. + * @throws IOException + */ + + public virtual void ToPdf(PdfWriter writer, Stream os) { + if (bytes != null) + os.Write(bytes, 0, bytes.Length); + } + + /** + * Gets the presentation of this object in a byte array + * @return a byte array + */ + public virtual byte[] GetBytes() { + return bytes; + } + + /** + * Can this object be in an object stream? + * @return true if this object can be in an object stream. + */ + public bool CanBeInObjStm() { + return (type >= 1 && type <= 6) || type == 8; + } + + /** + * Returns the length of the PDF representation of the PdfObject. + *

    + * In some cases, namely for PdfString and PdfStream, + * this method differs from the method length because length + * returns the length of the actual content of the PdfObject.

    + *

    + * Remark: the actual content of an object is in most cases identical to its representation. + * The following statement is always true: Length() >= PdfLength().

    + * + * @return a length + */ + + // public int PdfLength() { + // return ToPdf(null).length; + // } + + /** + * Returns the String-representation of this PdfObject. + * + * @return a String + */ + + public override string ToString() { + if (bytes == null) + return ""; + else + return PdfEncodings.ConvertToString(bytes, null); + } + + /** + * Returns the length of the actual content of the PdfObject. + *

    + * In some cases, namely for PdfString and PdfStream, + * this method differs from the method pdfLength because pdfLength + * returns the length of the PDF representation of the object, not of the actual content + * as does the method length.

    + *

    + * Remark: the actual content of an object is in some cases identical to its representation. + * The following statement is always true: Length() >= PdfLength().

    + * + * @return a length + */ + + public int Length { + get { + return ToString().Length; + } + } + + /** + * Changes the content of this PdfObject. + * + * @param content the new content of this PdfObject + */ + + protected string Content { + set { + bytes = PdfEncodings.ConvertToBytes(value, null); + } + } + + // methods dealing with the type of this object + + /** + * Returns the type of this PdfObject. + * + * @return a type + */ + + public int Type { + get { + return type; + } + } + + /** + * Checks if this PdfObject is of the type PdfNull. + * + * @return true or false + */ + + public bool IsNull() { + return (this.type == NULL); + } + + /** + * Checks if this PdfObject is of the type PdfBoolean. + * + * @return true or false + */ + + public bool IsBoolean() { + return (this.type == BOOLEAN); + } + + /** + * Checks if this PdfObject is of the type PdfNumber. + * + * @return true or false + */ + + public bool IsNumber() { + return (this.type == NUMBER); + } + + /** + * Checks if this PdfObject is of the type PdfString. + * + * @return true or false + */ + + public bool IsString() { + return (this.type == STRING); + } + + /** + * Checks if this PdfObject is of the type PdfName. + * + * @return true or false + */ + + public bool IsName() { + return (this.type == NAME); + } + + /** + * Checks if this PdfObject is of the type PdfArray. + * + * @return true or false + */ + + public bool IsArray() { + return (this.type == ARRAY); + } + + /** + * Checks if this PdfObject is of the type PdfDictionary. + * + * @return true or false + */ + + public bool IsDictionary() { + return (this.type == DICTIONARY); + } + + /** + * Checks if this PdfObject is of the type PdfStream. + * + * @return true or false + */ + + public bool IsStream() { + return (this.type == STREAM); + } + + /** + * Checks if this is an indirect object. + * @return true if this is an indirect object + */ + public bool IsIndirect() { + return (this.type == INDIRECT); + } + + public PRIndirectReference IndRef { + get { + return indRef; + } + set { + indRef = value; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfOutline.cs b/iTechSharp/iTextSharp/text/pdf/PdfOutline.cs new file mode 100644 index 0000000..2061f4a --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfOutline.cs @@ -0,0 +1,485 @@ +using System; +using System.Text; +using System.IO; +using System.Collections; + +using iTextSharp.text; + +/* + * $Id: PdfOutline.cs,v 1.5 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfOutline is an object that represents a PDF outline entry. + *

    + * An outline allows a user to access views of a document by name.
    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 6.7 (page 104-106) + * + * @see PdfDictionary + */ + + public class PdfOutline : PdfDictionary { + + // membervariables + + /** the PdfIndirectReference of this object */ + private PdfIndirectReference reference; + + /** value of the Count-key */ + private int count = 0; + + /** value of the Parent-key */ + private PdfOutline parent; + + /** value of the Destination-key */ + private PdfDestination destination; + + /** The PdfAction for this outline. + */ + private PdfAction action; + + protected ArrayList kids = new ArrayList(); + + protected PdfWriter writer; + + /** Holds value of property tag. */ + private string tag; + + /** Holds value of property open. */ + private bool open; + + /** Holds value of property color. */ + private Color color; + + /** Holds value of property style. */ + private int style = 0; + + // constructors + + /** + * Constructs a PdfOutline. + *

    + * This is the constructor for the outlines object. + */ + + internal PdfOutline(PdfWriter writer) : base(OUTLINES) { + open = true; + parent = null; + this.writer = writer; + } + + /** + * Constructs a PdfOutline. + *

    + * This is the constructor for an outline entry. The open mode is + * true. + * + * @param parent the parent of this outline item + * @param action the PdfAction for this outline item + * @param title the title of this outline item + */ + + public PdfOutline(PdfOutline parent, PdfAction action, string title) : this(parent, action, title, true) {} + + /** + * Constructs a PdfOutline. + *

    + * This is the constructor for an outline entry. + * + * @param parent the parent of this outline item + * @param action the PdfAction for this outline item + * @param title the title of this outline item + * @param open true if the children are visible + */ + public PdfOutline(PdfOutline parent, PdfAction action, string title, bool open) : base() { + this.action = action; + InitOutline(parent, title, open); + } + + /** + * Constructs a PdfOutline. + *

    + * This is the constructor for an outline entry. The open mode is + * true. + * + * @param parent the parent of this outline item + * @param destination the destination for this outline item + * @param title the title of this outline item + */ + + public PdfOutline(PdfOutline parent, PdfDestination destination, string title) : this(parent, destination, title, true) {} + + /** + * Constructs a PdfOutline. + *

    + * This is the constructor for an outline entry. + * + * @param parent the parent of this outline item + * @param destination the destination for this outline item + * @param title the title of this outline item + * @param open true if the children are visible + */ + public PdfOutline(PdfOutline parent, PdfDestination destination, string title, bool open) : base() { + this.destination = destination; + InitOutline(parent, title, open); + } + + /** + * Constructs a PdfOutline. + *

    + * This is the constructor for an outline entry. The open mode is + * true. + * + * @param parent the parent of this outline item + * @param action the PdfAction for this outline item + * @param title the title of this outline item + */ + public PdfOutline(PdfOutline parent, PdfAction action, PdfString title) : this(parent, action, title, true) {} + + /** + * Constructs a PdfOutline. + *

    + * This is the constructor for an outline entry. + * + * @param parent the parent of this outline item + * @param action the PdfAction for this outline item + * @param title the title of this outline item + * @param open true if the children are visible + */ + public PdfOutline(PdfOutline parent, PdfAction action, PdfString title, bool open) : this(parent, action, title.ToString(), open) {} + + /** + * Constructs a PdfOutline. + *

    + * This is the constructor for an outline entry. The open mode is + * true. + * + * @param parent the parent of this outline item + * @param destination the destination for this outline item + * @param title the title of this outline item + */ + + public PdfOutline(PdfOutline parent, PdfDestination destination, PdfString title) : this(parent, destination, title, true) {} + + /** + * Constructs a PdfOutline. + *

    + * This is the constructor for an outline entry. + * + * @param parent the parent of this outline item + * @param destination the destination for this outline item + * @param title the title of this outline item + * @param open true if the children are visible + */ + public PdfOutline(PdfOutline parent, PdfDestination destination, PdfString title, bool open) : this(parent, destination, title.ToString(), true) {} + + /** + * Constructs a PdfOutline. + *

    + * This is the constructor for an outline entry. The open mode is + * true. + * + * @param parent the parent of this outline item + * @param action the PdfAction for this outline item + * @param title the title of this outline item + */ + + public PdfOutline(PdfOutline parent, PdfAction action, Paragraph title) : this(parent, action, title, true) {} + + /** + * Constructs a PdfOutline. + *

    + * This is the constructor for an outline entry. + * + * @param parent the parent of this outline item + * @param action the PdfAction for this outline item + * @param title the title of this outline item + * @param open true if the children are visible + */ + public PdfOutline(PdfOutline parent, PdfAction action, Paragraph title, bool open) : base() { + StringBuilder buf = new StringBuilder(); + foreach (Chunk chunk in title.Chunks) { + buf.Append(chunk.Content); + } + this.action = action; + InitOutline(parent, buf.ToString(), open); + } + + /** + * Constructs a PdfOutline. + *

    + * This is the constructor for an outline entry. The open mode is + * true. + * + * @param parent the parent of this outline item + * @param destination the destination for this outline item + * @param title the title of this outline item + */ + + public PdfOutline(PdfOutline parent, PdfDestination destination, Paragraph title) : this(parent, destination, title, true) {} + + /** + * Constructs a PdfOutline. + *

    + * This is the constructor for an outline entry. + * + * @param parent the parent of this outline item + * @param destination the destination for this outline item + * @param title the title of this outline item + * @param open true if the children are visible + */ + public PdfOutline(PdfOutline parent, PdfDestination destination, Paragraph title, bool open) : base() { + StringBuilder buf = new StringBuilder(); + foreach (Chunk chunk in title.Chunks) { + buf.Append(chunk.Content); + } + this.destination = destination; + InitOutline(parent, buf.ToString(), open); + } + + + // methods + + /** Helper for the constructors. + * @param parent the parent outline + * @param title the title for this outline + * @param open true if the children are visible + */ + internal void InitOutline(PdfOutline parent, string title, bool open) { + this.open = open; + this.parent = parent; + writer = parent.writer; + Put(PdfName.TITLE, new PdfString(title, PdfObject.TEXT_UNICODE)); + parent.AddKid(this); + if (destination != null && !destination.HasPage()) // bugfix Finn Bock + SetDestinationPage(writer.CurrentPage); + } + + /** + * Gets the indirect reference of this PdfOutline. + * + * @return the PdfIndirectReference to this outline. + */ + + public PdfIndirectReference IndirectReference { + get { + return reference; + } + + set { + this.reference = value; + } + } + + /** + * Gets the parent of this PdfOutline. + * + * @return the PdfOutline that is the parent of this outline. + */ + + public PdfOutline Parent { + get { + return parent; + } + } + + /** + * Set the page of the PdfDestination-object. + * + * @param pageReference indirect reference to the page + * @return true if this page was set as the PdfDestination-page. + */ + + public bool SetDestinationPage(PdfIndirectReference pageReference) { + if (destination == null) { + return false; + } + return destination.AddPage(pageReference); + } + + /** + * Gets the destination for this outline. + * @return the destination + */ + public PdfDestination PdfDestination { + get { + return destination; + } + } + + internal int Count { + get { + return count; + } + + set { + this.count = value; + } + } + + /** + * returns the level of this outline. + * + * @return a level + */ + + public int Level { + get { + if (parent == null) { + return 0; + } + return (parent.Level + 1); + } + } + + /** + * Returns the PDF representation of this PdfOutline. + * + * @param writer the encryption information + * @param os + * @throws IOException + */ + + public override void ToPdf(PdfWriter writer, Stream os) { + if (color != null && !color.Equals(Color.BLACK)) { + Put(PdfName.C, new PdfArray(new float[]{color.R/255f,color.G/255f,color.B/255f})); + } + int flag = 0; + if ((style & Font.BOLD) != 0) + flag |= 2; + if ((style & Font.ITALIC) != 0) + flag |= 1; + if (flag != 0) + Put(PdfName.F, new PdfNumber(flag)); + if (parent != null) { + Put(PdfName.PARENT, parent.IndirectReference); + } + if (destination != null && destination.HasPage()) { + Put(PdfName.DEST, destination); + } + if (action != null) + Put(PdfName.A, action); + if (count != 0) { + Put(PdfName.COUNT, new PdfNumber(count)); + } + base.ToPdf(writer, os); + } + + public void AddKid(PdfOutline outline) { + kids.Add(outline); + } + + public ArrayList Kids { + get { + return kids; + } + + set { + this.kids = value; + } + } + + /** Getter for property tag. + * @return Value of property tag. + */ + public string Tag { + get { + return tag; + } + + set { + this.tag = value; + } + } + + public string Title { + get { + PdfString title = (PdfString)Get(PdfName.TITLE); + return title.ToString(); + } + + set { + Put(PdfName.TITLE, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + /** Setter for property open. + * @param open New value of property open. + */ + public bool Open { + set { + this.open = value; + } + get { + return open; + } + } + + public Color Color { + get { + return color; + } + set { + color = value; + } + } + + public int Style { + get { + return style; + } + set { + style = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPCell.cs b/iTechSharp/iTextSharp/text/pdf/PdfPCell.cs new file mode 100644 index 0000000..7bd36ae --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPCell.cs @@ -0,0 +1,696 @@ +using System; +using System.Collections; +using iTextSharp.text; +using iTextSharp.text.pdf.events; + +/* + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** A cell in a PdfPTable. + */ + + public class PdfPCell : Rectangle{ + + private ColumnText column = new ColumnText(null); + + /** Holds value of property verticalAlignment. */ + private int verticalAlignment = Element.ALIGN_TOP; + + /** Holds value of property paddingLeft. */ + private float paddingLeft = 2; + + /** Holds value of property paddingLeft. */ + private float paddingRight = 2; + + /** Holds value of property paddingTop. */ + private float paddingTop = 2; + + /** Holds value of property paddingBottom. */ + private float paddingBottom = 2; + + /** Holds value of property fixedHeight. */ + private float fixedHeight = 0; + + /** Holds value of property noWrap. */ + private bool noWrap = false; + + /** Holds value of property table. */ + private PdfPTable table; + + /** Holds value of property minimumHeight. */ + private float minimumHeight; + + /** Holds value of property colspan. */ + private int colspan = 1; + + /** Holds value of property image. */ + private Image image; + + /** Holds value of property cellEvent. */ + private IPdfPCellEvent cellEvent; + + /** Holds value of property useDescender. */ + private bool useDescender; + + /** Increases padding to include border if true */ + private bool useBorderPadding = false; + + + /** The text in the cell. */ + protected Phrase phrase; + + /** Constructs an empty PdfPCell. + * The default padding is 2. + */ + public PdfPCell() : base(0, 0, 0, 0) { + borderWidth = 0.5f; + border = BOX; + column.SetLeading(0, 1); + } + + /** Constructs a PdfPCell with a Phrase. + * The default padding is 2. + * @param phrase the text + */ + public PdfPCell(Phrase phrase) : base(0, 0, 0, 0) { + borderWidth = 0.5f; + border = BOX; + column.AddText(this.phrase = phrase); + column.SetLeading(0, 1); + } + + /** Constructs a PdfPCell with an Image. + * The default padding is 0. + * @param image the Image + */ + public PdfPCell(Image image) : this(image, false) { + } + + /** Constructs a PdfPCell with an Image. + * The default padding is 0.25 for a border width of 0.5. + * @param image the Image + * @param fit true to fit the image to the cell + */ + public PdfPCell(Image image, bool fit) : base(0, 0, 0, 0) { + if (fit) { + borderWidth = 0.5f; + border = BOX; + this.image = image; + column.SetLeading(0, 1); + Padding = borderWidth / 2; + } + else { + borderWidth = 0.5f; + border = BOX; + column.AddText(this.phrase = new Phrase(new Chunk(image, 0, 0))); + column.SetLeading(0, 1); + Padding = 0; + } + } + + /** Constructs a PdfPCell with a PdfPtable. + * This constructor allows nested tables. + * The default padding is 0. + * @param table The PdfPTable + */ + public PdfPCell(PdfPTable table) : this(table, null) { + } + + /** Constructs a PdfPCell with a PdfPtable. + * This constructor allows nested tables. + * + * @param table The PdfPTable + * @param style The style to apply to the cell (you could use getDefaultCell()) + * @since 2.1.0 + */ + public PdfPCell(PdfPTable table, PdfPCell style) : base(0, 0, 0, 0) { + borderWidth = 0.5f; + border = BOX; + column.SetLeading(0, 1); + this.table = table; + table.WidthPercentage = 100; + table.ExtendLastRow = true; + column.AddElement(table); + if (style != null) { + CloneNonPositionParameters(style); + verticalAlignment = style.verticalAlignment; + paddingLeft = style.paddingLeft; + paddingRight = style.paddingRight; + paddingTop = style.paddingTop; + paddingBottom = style.paddingBottom; + colspan = style.colspan; + cellEvent = style.cellEvent; + useDescender = style.useDescender; + useBorderPadding = style.useBorderPadding; + rotation = style.rotation; + } + else { + Padding = 0; + } + } + + /** Constructs a deep copy of a PdfPCell. + * @param cell the PdfPCell to duplicate + */ + public PdfPCell(PdfPCell cell) : base(cell.llx, cell.lly, cell.urx, cell.ury) { + CloneNonPositionParameters(cell); + verticalAlignment = cell.verticalAlignment; + paddingLeft = cell.paddingLeft; + paddingRight = cell.paddingRight; + paddingTop = cell.paddingTop; + paddingBottom = cell.paddingBottom; + phrase = cell.phrase; + fixedHeight = cell.fixedHeight; + minimumHeight = cell.minimumHeight; + noWrap = cell.noWrap; + colspan = cell.colspan; + if (cell.table != null) + table = new PdfPTable(cell.table); + image = Image.GetInstance(cell.image); + cellEvent = cell.cellEvent; + useDescender = cell.useDescender; + column = ColumnText.Duplicate(cell.column); + useBorderPadding = cell.useBorderPadding; + rotation = cell.rotation; + } + + /** + * Adds an iText element to the cell. + * @param element + */ + public void AddElement(IElement element) { + if (table != null) { + table = null; + column.SetText(null); + } + column.AddElement(element); + } + + /** Gets the Phrase from this cell. + * @return the Phrase + */ + public Phrase Phrase { + get { + return phrase; + } + set { + table = null; + image = null; + column.SetText(this.phrase = value); + } + } + + /** Gets the horizontal alignment for the cell. + * @return the horizontal alignment for the cell + */ + public int HorizontalAlignment { + get { + return column.Alignment; + } + set { + column.Alignment = value; + } + } + + /** Gets the vertical alignment for the cell. + * @return the vertical alignment for the cell + */ + public int VerticalAlignment { + get { + return verticalAlignment; + } + set { + verticalAlignment = value; + if (table != null) + table.ExtendLastRow = (verticalAlignment == Element.ALIGN_TOP); + } + } + + /** Gets the effective left padding. This will include + * the left border width if {@link #UseBorderPadding} is true. + * @return effective value of property paddingLeft. + */ + public float EffectivePaddingLeft { + get { + return paddingLeft + (UseBorderPadding ? (BorderWidthLeft/(UseVariableBorders?1f:2f)) : 0); + } + } + + /** + * @return Value of property paddingLeft. + */ + public float PaddingLeft { + get { + return paddingLeft; + } + set { + paddingLeft = value; + } + } + + /** Gets the effective right padding. This will include + * the right border width if {@link #UseBorderPadding} is true. + * @return effective value of property paddingRight. + */ + public float EffectivePaddingRight { + get { + return paddingRight + (UseBorderPadding ? (BorderWidthRight/(UseVariableBorders?1f:2f)) : 0); + } + } + + /** + * Getter for property paddingRight. + * @return Value of property paddingRight. + */ + public float PaddingRight { + get { + return paddingRight; + } + set { + paddingRight = value; + } + } + + /** Gets the effective top padding. This will include + * the top border width if {@link #isUseBorderPadding()} is true. + * @return effective value of property paddingTop. + */ + public float EffectivePaddingTop { + get { + return paddingTop + (UseBorderPadding ? (BorderWidthTop/(UseVariableBorders?1f:2f)) : 0); + } + } + + /** + * Getter for property paddingTop. + * @return Value of property paddingTop. + */ + public float PaddingTop { + get { + return paddingTop; + } + set { + paddingTop = value; + } + } + + /** + /** Gets the effective bottom padding. This will include + * the bottom border width if {@link #UseBorderPadding} is true. + * @return effective value of property paddingBottom. + */ + public float EffectivePaddingBottom { + get { + return paddingBottom + (UseBorderPadding ? (BorderWidthBottom/(UseVariableBorders?1f:2f)) : 0); + } + } + + /** + * Getter for property paddingBottom. + * @return Value of property paddingBottom. + */ + public float PaddingBottom { + get { + return paddingBottom; + } + set { + paddingBottom = value; + } + } + + /** + * Sets the padding of the contents in the cell (space between content and border). + * @param padding + */ + public float Padding { + set { + paddingBottom = value; + paddingTop = value; + paddingLeft = value; + paddingRight = value; + } + } + + /** + * Adjusts effective padding to include border widths. + * @param use adjust effective padding if true + */ + public bool UseBorderPadding { + set { + useBorderPadding = value; + } + get { + return useBorderPadding; + } + } + + /** + * Sets the leading fixed and variable. The resultant leading will be + * fixedLeading+multipliedLeading*maxFontSize where maxFontSize is the + * size of the bigest font in the line. + * @param fixedLeading the fixed leading + * @param multipliedLeading the variable leading + */ + public void SetLeading(float fixedLeading, float multipliedLeading) { + column.SetLeading(fixedLeading, multipliedLeading); + } + + /** + * Gets the fixed leading + * @return the leading + */ + public float Leading { + get { + return column.Leading; + } + } + + /** + * Gets the variable leading + * @return the leading + */ + public float MultipliedLeading { + get { + return column.MultipliedLeading; + } + } + + /** + * Gets the first paragraph line indent. + * @return the indent + */ + public float Indent { + get { + return column.Indent; + } + set { + column.Indent = value; + } + } + + /** + * Gets the extra space between paragraphs. + * @return the extra space between paragraphs + */ + public float ExtraParagraphSpace { + get { + return column.ExtraParagraphSpace; + } + set { + column.ExtraParagraphSpace = value; + } + } + + /** + * Getter for property fixedHeight. + * @return Value of property fixedHeight. + */ + public float FixedHeight { + get { + return fixedHeight; + } + set { + fixedHeight = value; + minimumHeight = 0; + } + } + + /** + * Setter for property noWrap. + * @param noWrap New value of property noWrap. + */ + public bool NoWrap { + set { + noWrap = value; + } + get { + return noWrap; + } + } + + /** + * Getter for property table. + * @return Value of property table. + */ + internal PdfPTable Table { + get { + return table; + } + set { + table = value; + column.SetText(null); + image = null; + if (table != null) { + table.ExtendLastRow = (verticalAlignment == Element.ALIGN_TOP); + column.AddElement(table); + table.WidthPercentage = 100; + } + } + } + + /** Getter for property minimumHeight. + * @return Value of property minimumHeight. + */ + public float MinimumHeight { + get { + return minimumHeight; + } + set { + this.minimumHeight = value; + fixedHeight = 0; + } + } + + /** Getter for property colspan. + * @return Value of property colspan. + */ + public int Colspan { + get { + return colspan; + } + set { + colspan = value; + } + } + + /** + * Gets the following paragraph lines indent. + * @return the indent + */ + public float FollowingIndent { + get { + return column.FollowingIndent; + } + set { + column.FollowingIndent = value; + } + } + + /** + * Gets the right paragraph lines indent. + * @return the indent + */ + public float RightIndent { + get { + return column.RightIndent; + } + set { + column.RightIndent = value; + } + } + + /** Gets the space/character extra spacing ratio for + * fully justified text. + * @return the space/character extra spacing ratio + */ + public float SpaceCharRatio { + get { + return column.SpaceCharRatio; + } + set { + column.SpaceCharRatio = value; + } + } + + /** + * Gets the run direction of the text content in the cell + * @return One of the following values: PdfWriter.RUN_DIRECTION_DEFAULT, PdfWriter.RUN_DIRECTION_NO_BIDI, PdfWriter.RUN_DIRECTION_LTR or PdfWriter.RUN_DIRECTION_RTL. + */ + public int RunDirection { + get { + return column.RunDirection; + } + set { + column.RunDirection = value; + } + } + + /** Getter for property image. + * @return Value of property image. + * + */ + public Image Image { + get { + return this.image; + } + set { + column.SetText(null); + table = null; + this.image = value; + } + } + + /** Gets the cell event for this cell. + * @return the cell event + * + */ + public IPdfPCellEvent CellEvent { + get { + return this.cellEvent; + } + set { + if (value == null) this.cellEvent = null; + else if (this.cellEvent == null) this.cellEvent = value; + else if (this.cellEvent is PdfPCellEventForwarder) ((PdfPCellEventForwarder)this.cellEvent).AddCellEvent(value); + else { + PdfPCellEventForwarder forward = new PdfPCellEventForwarder(); + forward.AddCellEvent(this.cellEvent); + forward.AddCellEvent(value); + this.cellEvent = forward; + } + } + } + + /** Gets the arabic shaping options. + * @return the arabic shaping options + */ + public int ArabicOptions { + get { + return column.ArabicOptions; + } + set { + column.ArabicOptions = value; + } + } + + /** Gets state of first line height based on max ascender + * @return true if an ascender is to be used. + */ + public bool UseAscender { + get { + return column.UseAscender; + } + set { + column.UseAscender = value; + } + } + + /** Getter for property useDescender. + * @return Value of property useDescender. + * + */ + public bool UseDescender { + get { + return this.useDescender; + } + set { + useDescender = value; + } + } + + /** + * Gets the ColumnText with the content of the cell. + * @return a columntext object + */ + public ColumnText Column { + get { + return column; + } + set { + column = value; + } + } + + /** + * Returns the list of composite elements of the column. + * @return a List object. + * @since 2.1.1 + */ + public ArrayList CompositeElements { + get { + return column.compositeElements; + } + } + + /** + * The rotation of the cell. Possible values are + * 0, 90, 180 and 270. + */ + private new int rotation; + + /** + * Sets the rotation of the cell. Possible values are + * 0, 90, 180 and 270. + * @param rotation the rotation of the cell + */ + public new int Rotation { + set { + int rot = value % 360; + if (rot < 0) + rot += 360; + if ((rot % 90) != 0) + throw new ArgumentException("Rotation must be a multiple of 90."); + rotation = rot; + } + get { + return rotation; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPKCS7.cs b/iTechSharp/iTextSharp/text/pdf/PdfPKCS7.cs new file mode 100644 index 0000000..7949d85 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPKCS7.cs @@ -0,0 +1,1170 @@ +using System; +using System.Collections; +using System.Text; +using System.IO; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Utilities; + +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + /** + * This class does all the processing related to signing and verifying a PKCS#7 + * signature. + *

    + * It's based in code found at org.bouncycastle. + */ + public class PdfPKCS7 { + + private byte[] sigAttr; + private byte[] digestAttr; + private int version, signerversion; + private Hashtable digestalgos; + private ArrayList certs, crls; + private X509Certificate signCert; + private byte[] digest; + private IDigest messageDigest; + private String digestAlgorithm, digestEncryptionAlgorithm; + private ISigner sig; + private ICipherParameters privKey; + private byte[] RSAdata; + private bool verified; + private bool verifyResult; + private byte[] externalDigest; + private byte[] externalRSAdata; + + private const String ID_PKCS7_DATA = "1.2.840.113549.1.7.1"; + private const String ID_PKCS7_SIGNED_DATA = "1.2.840.113549.1.7.2"; + private const String ID_MD5 = "1.2.840.113549.2.5"; + private const String ID_MD2 = "1.2.840.113549.2.2"; + private const String ID_SHA1 = "1.3.14.3.2.26"; + private const String ID_RSA = "1.2.840.113549.1.1.1"; + private const String ID_DSA = "1.2.840.10040.4.1"; + private const String ID_CONTENT_TYPE = "1.2.840.113549.1.9.3"; + private const String ID_MESSAGE_DIGEST = "1.2.840.113549.1.9.4"; + private const String ID_SIGNING_TIME = "1.2.840.113549.1.9.5"; + private const String ID_MD2RSA = "1.2.840.113549.1.1.2"; + private const String ID_MD5RSA = "1.2.840.113549.1.1.4"; + private const String ID_SHA1RSA = "1.2.840.113549.1.1.5"; + /** + * Holds value of property reason. + */ + private String reason; + + /** + * Holds value of property location. + */ + private String location; + + /** + * Holds value of property signDate. + */ + private DateTime signDate; + + /** + * Holds value of property signName. + */ + private String signName; + + /** + * Verifies a signature using the sub-filter adbe.x509.rsa_sha1. + * @param contentsKey the /Contents key + * @param certsKey the /Cert key + * @param provider the provider or null for the default provider + * @throws SecurityException on error + * @throws CRLException on error + * @throws InvalidKeyException on error + * @throws CertificateException on error + * @throws NoSuchProviderException on error + * @throws NoSuchAlgorithmException on error + * @throws IOException on error + */ + public PdfPKCS7(byte[] contentsKey, byte[] certsKey) { + + X509CertificateParser cf = new X509CertificateParser(); + certs = new ArrayList(); + foreach (X509Certificate cc in cf.ReadCertificates(certsKey)) { + certs.Add(cc); + } + signCert = (X509Certificate)certs[0]; + crls = new ArrayList(); + Asn1InputStream inp = new Asn1InputStream(new MemoryStream(contentsKey)); + digest = ((DerOctetString)inp.ReadObject()).GetOctets(); + sig = SignerUtilities.GetSigner("SHA1withRSA"); + sig.Init(false, signCert.GetPublicKey()); + } + + /** + * Verifies a signature using the sub-filter adbe.pkcs7.detached or + * adbe.pkcs7.sha1. + * @param contentsKey the /Contents key + * @param provider the provider or null for the default provider + * @throws SecurityException on error + * @throws CRLException on error + * @throws InvalidKeyException on error + * @throws CertificateException on error + * @throws NoSuchProviderException on error + * @throws NoSuchAlgorithmException on error + */ + public PdfPKCS7(byte[] contentsKey) { + Asn1InputStream din = new Asn1InputStream(new MemoryStream(contentsKey)); + + // + // Basic checks to make sure it's a PKCS#7 SignedData Object + // + Asn1Object pkcs; + + try { + pkcs = din.ReadObject(); + } + catch { + throw new ArgumentException("can't decode PKCS7SignedData object"); + } + if (!(pkcs is Asn1Sequence)) { + throw new ArgumentException("Not a valid PKCS#7 object - not a sequence"); + } + Asn1Sequence signedData = (Asn1Sequence)pkcs; + DerObjectIdentifier objId = (DerObjectIdentifier)signedData[0]; + if (!objId.Id.Equals(ID_PKCS7_SIGNED_DATA)) + throw new ArgumentException("Not a valid PKCS#7 object - not signed data"); + Asn1Sequence content = (Asn1Sequence)((DerTaggedObject)signedData[1]).GetObject(); + // the positions that we care are: + // 0 - version + // 1 - digestAlgorithms + // 2 - possible ID_PKCS7_DATA + // (the certificates and crls are taken out by other means) + // last - signerInfos + + // the version + version = ((DerInteger)content[0]).Value.IntValue; + + // the digestAlgorithms + digestalgos = new Hashtable(); + IEnumerator e = ((Asn1Set)content[1]).GetEnumerator(); + while (e.MoveNext()) + { + Asn1Sequence s = (Asn1Sequence)e.Current; + DerObjectIdentifier o = (DerObjectIdentifier)s[0]; + digestalgos[o.Id] = null; + } + + // the certificates and crls + X509CertificateParser cf = new X509CertificateParser(); + certs = new ArrayList(); + foreach (X509Certificate cc in cf.ReadCertificates(contentsKey)) { + certs.Add(cc); + } + crls = new ArrayList(); + + // the possible ID_PKCS7_DATA + Asn1Sequence rsaData = (Asn1Sequence)content[2]; + if (rsaData.Count > 1) { + DerOctetString rsaDataContent = (DerOctetString)((DerTaggedObject)rsaData[1]).GetObject(); + RSAdata = rsaDataContent.GetOctets(); + } + + // the signerInfos + int next = 3; + while (content[next] is DerTaggedObject) + ++next; + Asn1Set signerInfos = (Asn1Set)content[next]; + if (signerInfos.Count != 1) + throw new ArgumentException("This PKCS#7 object has multiple SignerInfos - only one is supported at this time"); + Asn1Sequence signerInfo = (Asn1Sequence)signerInfos[0]; + // the positions that we care are + // 0 - version + // 1 - the signing certificate serial number + // 2 - the digest algorithm + // 3 or 4 - digestEncryptionAlgorithm + // 4 or 5 - encryptedDigest + signerversion = ((DerInteger)signerInfo[0]).Value.IntValue; + // Get the signing certificate + Asn1Sequence issuerAndSerialNumber = (Asn1Sequence)signerInfo[1]; + BigInteger serialNumber = ((DerInteger)issuerAndSerialNumber[1]).Value; + foreach (X509Certificate cert in certs) { + if (serialNumber.Equals(cert.SerialNumber)) { + signCert = cert; + break; + } + } + if (signCert == null) { + throw new ArgumentException("Can't find signing certificate with serial " + serialNumber.ToString(16)); + } + digestAlgorithm = ((DerObjectIdentifier)((Asn1Sequence)signerInfo[2])[0]).Id; + next = 3; + if (signerInfo[next] is Asn1TaggedObject) { + Asn1TaggedObject tagsig = (Asn1TaggedObject)signerInfo[next]; + Asn1Sequence sseq = (Asn1Sequence)tagsig.GetObject(); + MemoryStream bOut = new MemoryStream(); + Asn1OutputStream dout = new Asn1OutputStream(bOut); + try { + Asn1EncodableVector attribute = new Asn1EncodableVector(); + for (int k = 0; k < sseq.Count; ++k) { + attribute.Add(sseq[k]); + } + dout.WriteObject(new DerSet(attribute)); + dout.Close(); + } + catch (IOException){} + sigAttr = bOut.ToArray(); + + for (int k = 0; k < sseq.Count; ++k) { + Asn1Sequence seq2 = (Asn1Sequence)sseq[k]; + if (((DerObjectIdentifier)seq2[0]).Id.Equals(ID_MESSAGE_DIGEST)) { + Asn1Set sset = (Asn1Set)seq2[1]; + digestAttr = ((DerOctetString)sset[0]).GetOctets(); + break; + } + } + if (digestAttr == null) + throw new ArgumentException("Authenticated attribute is missing the digest."); + ++next; + } + digestEncryptionAlgorithm = ((DerObjectIdentifier)((Asn1Sequence)signerInfo[next++])[0]).Id; + digest = ((DerOctetString)signerInfo[next]).GetOctets(); + if (RSAdata != null || digestAttr != null) { + messageDigest = GetHashClass(); + } + sig = SignerUtilities.GetSigner(GetDigestAlgorithm()); + sig.Init(false, signCert.GetPublicKey()); + } + + /** + * Generates a signature. + * @param privKey the private key + * @param certChain the certificate chain + * @param crlList the certificate revocation list + * @param hashAlgorithm the hash algorithm + * @param provider the provider or null for the default provider + * @param hasRSAdata true if the sub-filter is adbe.pkcs7.sha1 + * @throws SecurityException on error + * @throws InvalidKeyException on error + * @throws NoSuchProviderException on error + * @throws NoSuchAlgorithmException on error + */ + public PdfPKCS7(ICipherParameters privKey, X509Certificate[] certChain, object[] crlList, + String hashAlgorithm, bool hasRSAdata) { + this.privKey = privKey; + + if (hashAlgorithm.Equals("MD5")) { + digestAlgorithm = ID_MD5; + } + else if (hashAlgorithm.Equals("MD2")) { + digestAlgorithm = ID_MD2; + } + else if (hashAlgorithm.Equals("SHA")) { + digestAlgorithm = ID_SHA1; + } + else if (hashAlgorithm.Equals("SHA1")) { + digestAlgorithm = ID_SHA1; + } + else { + throw new ArgumentException("Unknown Hash Algorithm "+hashAlgorithm); + } + + version = signerversion = 1; + certs = new ArrayList(); + crls = new ArrayList(); + digestalgos = new Hashtable(); + digestalgos[digestAlgorithm] = null; + + // + // Copy in the certificates and crls used to sign the private key. + // + signCert = certChain[0]; + for (int i = 0;i < certChain.Length;i++) { + certs.Add(certChain[i]); + } + +// if (crlList != null) { +// for (int i = 0;i < crlList.length;i++) { +// crls.Add(crlList[i]); +// } +// } + + if (privKey != null) { + // + // Now we have private key, find out what the digestEncryptionAlgorithm is. + // + if (privKey is RsaKeyParameters) + digestEncryptionAlgorithm = ID_RSA; + else if (privKey is DsaKeyParameters) + digestEncryptionAlgorithm = ID_DSA; + else + throw new ArgumentException("Unknown Key Algorithm "+privKey.ToString()); + + } + if (hasRSAdata) { + RSAdata = new byte[0]; + messageDigest = GetHashClass(); + } + + if (privKey != null) { + sig = SignerUtilities.GetSigner(GetDigestAlgorithm()); + sig.Init(true, privKey); + } + } + + /** + * Update the digest with the specified bytes. This method is used both for signing and verifying + * @param buf the data buffer + * @param off the offset in the data buffer + * @param len the data length + * @throws SignatureException on error + */ + public void Update(byte[] buf, int off, int len) { + if (RSAdata != null || digestAttr != null) + messageDigest.BlockUpdate(buf, off, len); + else + sig.BlockUpdate(buf, off, len); + } + + /** + * Verify the digest. + * @throws SignatureException on error + * @return true if the signature checks out, false otherwise + */ + public bool Verify() { + if (verified) + return verifyResult; + if (sigAttr != null) { + byte[] msd = new byte[messageDigest.GetDigestSize()]; + sig.BlockUpdate(sigAttr, 0, sigAttr.Length); + if (RSAdata != null) { + messageDigest.DoFinal(msd, 0); + messageDigest.BlockUpdate(msd, 0, msd.Length); + } + messageDigest.DoFinal(msd, 0); + verifyResult = (Arrays.AreEqual(msd, digestAttr) && sig.VerifySignature(digest)); + } + else { + if (RSAdata != null){ + byte[] msd = new byte[messageDigest.GetDigestSize()]; + messageDigest.DoFinal(msd, 0); + sig.BlockUpdate(msd, 0, msd.Length); + } + verifyResult = sig.VerifySignature(digest); + } + verified = true; + return verifyResult; + } + + /** + * Get the X.509 certificates associated with this PKCS#7 object + * @return the X.509 certificates associated with this PKCS#7 object + */ + public X509Certificate[] Certificates { + get { + X509Certificate[] c = new X509Certificate[certs.Count]; + certs.CopyTo(c); + return c; + } + } + + /** + * Get the X.509 certificate revocation lists associated with this PKCS#7 object + * @return the X.509 certificate revocation lists associated with this PKCS#7 object + */ + public ArrayList CRLs { + get { + return crls; + } + } + + /** + * Get the X.509 certificate actually used to sign the digest. + * @return the X.509 certificate actually used to sign the digest + */ + public X509Certificate SigningCertificate { + get { + return signCert; + } + } + + /** + * Get the version of the PKCS#7 object. Always 1 + * @return the version of the PKCS#7 object. Always 1 + */ + public int Version { + get { + return version; + } + } + + /** + * Get the version of the PKCS#7 "SignerInfo" object. Always 1 + * @return the version of the PKCS#7 "SignerInfo" object. Always 1 + */ + public int SigningInfoVersion { + get { + return signerversion; + } + } + + /** + * Get the algorithm used to calculate the message digest + * @return the algorithm used to calculate the message digest + */ + public String GetDigestAlgorithm() { + String dea = digestEncryptionAlgorithm; + + if (digestEncryptionAlgorithm.Equals(ID_RSA) || digestEncryptionAlgorithm.Equals(ID_MD5RSA) + || digestEncryptionAlgorithm.Equals(ID_MD2RSA) || digestEncryptionAlgorithm.Equals(ID_SHA1RSA)) { + dea = "RSA"; + } + else if (digestEncryptionAlgorithm.Equals(ID_DSA)) { + dea = "DSA"; + } + + return GetHashAlgorithm() + "with" + dea; + } + + /** + * Returns the algorithm. + * @return the digest algorithm + */ + public String GetHashAlgorithm() { + String da = digestAlgorithm; + + if (digestAlgorithm.Equals(ID_MD5) || digestAlgorithm.Equals(ID_MD5RSA)) { + da = "MD5"; + } + else if (digestAlgorithm.Equals(ID_MD2) || digestAlgorithm.Equals(ID_MD2RSA)) { + da = "MD2"; + } + else if (digestAlgorithm.Equals(ID_SHA1) || digestAlgorithm.Equals(ID_SHA1RSA)) { + da = "SHA1"; + } + return da; + } + + public IDigest GetHashClass() { + if (digestAlgorithm.Equals(ID_MD5) || digestAlgorithm.Equals(ID_MD5RSA)) { + return new MD5Digest(); + } + else if (digestAlgorithm.Equals(ID_MD2) || digestAlgorithm.Equals(ID_MD2RSA)) { + return new MD2Digest(); + } + else if (digestAlgorithm.Equals(ID_SHA1) || digestAlgorithm.Equals(ID_SHA1RSA)) { + return new Sha1Digest(); + } + return null; + } + + /** + * Loads the default root certificates at <java.home>/lib/security/cacerts + * with the default provider. + * @return a KeyStore + */ +// public static KeyStore LoadCacertsKeyStore() { +// return LoadCacertsKeyStore(null); +// } + + /** + * Loads the default root certificates at <java.home>/lib/security/cacerts. + * @param provider the provider or null for the default provider + * @return a KeyStore + */ +// public static KeyStore LoadCacertsKeyStore(String provider) { +// File file = new File(System.GetProperty("java.home"), "lib"); +// file = new File(file, "security"); +// file = new File(file, "cacerts"); +// FileInputStream fin = null; +// try { +// fin = new FileInputStream(file); +// KeyStore k; +// if (provider == null) +// k = KeyStore.GetInstance("JKS"); +// else +// k = KeyStore.GetInstance("JKS", provider); +// k.Load(fin, null); +// return k; +// } +// catch (Exception e) { +// throw new ExceptionConverter(e); +// } +// finally { +// try{fin.Close();}catch(Exception ex){} +// } +// } + + /** + * Verifies a single certificate. + * @param cert the certificate to verify + * @param crls the certificate revocation list or null + * @param calendar the date or null for the current date + * @return a String with the error description or null + * if no error + */ + public static String VerifyCertificate(X509Certificate cert, object[] crls, DateTime calendar) { + try { + if (!cert.IsValid(calendar)) + return "The certificate has expired or is not yet valid"; + } + catch (Exception e) { + return e.ToString(); + } + return null; + } + + /** + * Verifies a certificate chain against a KeyStore. + * @param certs the certificate chain + * @param keystore the KeyStore + * @param crls the certificate revocation list or null + * @param calendar the date or null for the current date + * @return null if the certificate chain could be validade or a + * Object[]{cert,error} where cert is the + * failed certificate and error is the error message + */ + public static Object[] VerifyCertificates(X509Certificate[] certs, ArrayList keystore, object[] crls, DateTime calendar) { + for (int k = 0; k < certs.Length; ++k) { + X509Certificate cert = certs[k]; + String err = VerifyCertificate(cert, crls, calendar); + if (err != null) + return new Object[]{cert, err}; + foreach (X509Certificate certStoreX509 in keystore) { + try { + if (VerifyCertificate(certStoreX509, crls, calendar) != null) + continue; + try { + cert.Verify(certStoreX509.GetPublicKey()); + return null; + } + catch { + continue; + } + } + catch { + } + } + int j; + for (j = 0; j < certs.Length; ++j) { + if (j == k) + continue; + X509Certificate certNext = certs[j]; + try { + cert.Verify(certNext.GetPublicKey()); + break; + } + catch { + } + } + if (j == certs.Length) + return new Object[]{cert, "Cannot be verified against the KeyStore or the certificate chain"}; + } + return new Object[]{null, "Invalid state. Possible circular certificate chain"}; + } + + /** + * Get the "issuer" from the TBSCertificate bytes that are passed in + * @param enc a TBSCertificate in a byte array + * @return a DERObject + */ + private static Asn1Object GetIssuer(byte[] enc) { + Asn1InputStream inp = new Asn1InputStream(new MemoryStream(enc)); + Asn1Sequence seq = (Asn1Sequence)inp.ReadObject(); + return (Asn1Object)seq[seq[0] is DerTaggedObject ? 3 : 2]; + } + + /** + * Get the "subject" from the TBSCertificate bytes that are passed in + * @param enc A TBSCertificate in a byte array + * @return a DERObject + */ + private static Asn1Object GetSubject(byte[] enc) { + Asn1InputStream inp = new Asn1InputStream(new MemoryStream(enc)); + Asn1Sequence seq = (Asn1Sequence)inp.ReadObject(); + return (Asn1Object)seq[seq[0] is DerTaggedObject ? 5 : 4]; + } + + /** + * Get the issuer fields from an X509 Certificate + * @param cert an X509Certificate + * @return an X509Name + */ + public static X509Name GetIssuerFields(X509Certificate cert) { + return new X509Name((Asn1Sequence)GetIssuer(cert.GetTbsCertificate())); + } + + /** + * Get the subject fields from an X509 Certificate + * @param cert an X509Certificate + * @return an X509Name + */ + public static X509Name GetSubjectFields(X509Certificate cert) { + return new X509Name((Asn1Sequence)GetSubject(cert.GetTbsCertificate())); + } + + /** + * Gets the bytes for the PKCS#1 object. + * @return a byte array + */ + public byte[] GetEncodedPKCS1() { + if (externalDigest != null) + digest = externalDigest; + else + digest = sig.GenerateSignature(); + MemoryStream bOut = new MemoryStream(); + + Asn1OutputStream dout = new Asn1OutputStream(bOut); + dout.WriteObject(new DerOctetString(digest)); + dout.Close(); + + return bOut.ToArray(); + } + + /** + * Sets the digest/signature to an external calculated value. + * @param digest the digest. This is the actual signature + * @param RSAdata the extra data that goes into the data tag in PKCS#7 + * @param digestEncryptionAlgorithm the encryption algorithm. It may must be null if the digest + * is also null. If the digest is not null + * then it may be "RSA" or "DSA" + */ + public void SetExternalDigest(byte[] digest, byte[] RSAdata, String digestEncryptionAlgorithm) { + externalDigest = digest; + externalRSAdata = RSAdata; + if (digestEncryptionAlgorithm != null) { + if (digestEncryptionAlgorithm.Equals("RSA")) { + this.digestEncryptionAlgorithm = ID_RSA; + } + else if (digestEncryptionAlgorithm.Equals("DSA")) { + this.digestEncryptionAlgorithm = ID_DSA; + } + else + throw new ArgumentException("Unknown Key Algorithm "+digestEncryptionAlgorithm); + } + } + + /** + * Gets the bytes for the PKCS7SignedData object. + * @return the bytes for the PKCS7SignedData object + */ + public byte[] GetEncodedPKCS7() { + return GetEncodedPKCS7(null, DateTime.Now); + } + + /** + * Gets the bytes for the PKCS7SignedData object. Optionally the authenticatedAttributes + * in the signerInfo can also be set. If either of the parameters is null, none will be used. + * @param secondDigest the digest in the authenticatedAttributes + * @param signingTime the signing time in the authenticatedAttributes + * @return the bytes for the PKCS7SignedData object + */ + public byte[] GetEncodedPKCS7(byte[] secondDigest, DateTime signingTime) { + if (externalDigest != null) { + digest = externalDigest; + if (RSAdata != null) + RSAdata = externalRSAdata; + } + else if (externalRSAdata != null && RSAdata != null) { + RSAdata = externalRSAdata; + sig.BlockUpdate(RSAdata, 0, RSAdata.Length); + digest = sig.GenerateSignature(); + } + else { + if (RSAdata != null) { + RSAdata = new byte[messageDigest.GetDigestSize()]; + messageDigest.DoFinal(RSAdata, 0); + sig.BlockUpdate(RSAdata, 0, RSAdata.Length); + } + digest = sig.GenerateSignature(); + } + + // Create the set of Hash algorithms + Asn1EncodableVector digestAlgorithms = new Asn1EncodableVector(); + foreach (string dal in digestalgos.Keys) { + Asn1EncodableVector algos = new Asn1EncodableVector(); + algos.Add(new DerObjectIdentifier(dal)); + algos.Add(DerNull.Instance); + digestAlgorithms.Add(new DerSequence(algos)); + } + + // Create the contentInfo. + Asn1EncodableVector v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(ID_PKCS7_DATA)); + if (RSAdata != null) + v.Add(new DerTaggedObject(0, new DerOctetString(RSAdata))); + DerSequence contentinfo = new DerSequence(v); + + // Get all the certificates + // + v = new Asn1EncodableVector(); + foreach (X509Certificate xcert in certs) { + Asn1InputStream tempstream = new Asn1InputStream(new MemoryStream(xcert.GetEncoded())); + v.Add(tempstream.ReadObject()); + } + + DerSet dercertificates = new DerSet(v); + + // Create signerinfo structure. + // + Asn1EncodableVector signerinfo = new Asn1EncodableVector(); + + // Add the signerInfo version + // + signerinfo.Add(new DerInteger(signerversion)); + + v = new Asn1EncodableVector(); + v.Add(GetIssuer(signCert.GetTbsCertificate())); + v.Add(new DerInteger(signCert.SerialNumber)); + signerinfo.Add(new DerSequence(v)); + + // Add the digestAlgorithm + v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(digestAlgorithm)); + v.Add(DerNull.Instance); + signerinfo.Add(new DerSequence(v)); + + // add the authenticated attribute if present + if (secondDigest != null /*&& signingTime != null*/) { + Asn1EncodableVector attribute = new Asn1EncodableVector(); + v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(ID_CONTENT_TYPE)); + v.Add(new DerSet(new DerObjectIdentifier(ID_PKCS7_DATA))); + attribute.Add(new DerSequence(v)); + v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(ID_SIGNING_TIME)); + v.Add(new DerSet(new DerUtcTime(signingTime))); + attribute.Add(new DerSequence(v)); + v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(ID_MESSAGE_DIGEST)); + v.Add(new DerSet(new DerOctetString(secondDigest))); + attribute.Add(new DerSequence(v)); + signerinfo.Add(new DerTaggedObject(false, 0, new DerSet(attribute))); + } + // Add the digestEncryptionAlgorithm + v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(digestEncryptionAlgorithm)); + v.Add(DerNull.Instance); + signerinfo.Add(new DerSequence(v)); + + // Add the digest + signerinfo.Add(new DerOctetString(digest)); + + + // Finally build the body out of all the components above + Asn1EncodableVector body = new Asn1EncodableVector(); + body.Add(new DerInteger(version)); + body.Add(new DerSet(digestAlgorithms)); + body.Add(contentinfo); + body.Add(new DerTaggedObject(false, 0, dercertificates)); + +// if (crls.Count > 0) { +// v = new Asn1EncodableVector(); +// for (Iterator i = crls.Iterator();i.HasNext();) { +// Asn1InputStream t = new Asn1InputStream(new ByteArrayInputStream((((X509CRL)i.Next()).GetEncoded()))); +// v.Add(t.ReadObject()); +// } +// DERSet dercrls = new DERSet(v); +// body.Add(new DERTaggedObject(false, 1, dercrls)); +// } + + // Only allow one signerInfo + body.Add(new DerSet(new DerSequence(signerinfo))); + + // Now we have the body, wrap it in it's PKCS7Signed shell + // and return it + // + Asn1EncodableVector whole = new Asn1EncodableVector(); + whole.Add(new DerObjectIdentifier(ID_PKCS7_SIGNED_DATA)); + whole.Add(new DerTaggedObject(0, new DerSequence(body))); + + MemoryStream bOut = new MemoryStream(); + + Asn1OutputStream dout = new Asn1OutputStream(bOut); + dout.WriteObject(new DerSequence(whole)); + dout.Close(); + + return bOut.ToArray(); + } + + + /** + * When using authenticatedAttributes the authentication process is different. + * The document digest is generated and put inside the attribute. The signing is done over the DER encoded + * authenticatedAttributes. This method provides that encoding and the parameters must be + * exactly the same as in {@link #getEncodedPKCS7(byte[],Calendar)}. + *

    + * A simple example: + *

    + *

    +        * Calendar cal = Calendar.GetInstance();
    +        * PdfPKCS7 pk7 = new PdfPKCS7(key, chain, null, "SHA1", null, false);
    +        * MessageDigest messageDigest = MessageDigest.GetInstance("SHA1");
    +        * byte buf[] = new byte[8192];
    +        * int n;
    +        * Stream inp = sap.GetRangeStream();
    +        * while ((n = inp.Read(buf)) > 0) {
    +        *    messageDigest.Update(buf, 0, n);
    +        * }
    +        * byte hash[] = messageDigest.Digest();
    +        * byte sh[] = pk7.GetAuthenticatedAttributeBytes(hash, cal);
    +        * pk7.Update(sh, 0, sh.length);
    +        * byte sg[] = pk7.GetEncodedPKCS7(hash, cal);
    +        * 
    + * @param secondDigest the content digest + * @param signingTime the signing time + * @return the byte array representation of the authenticatedAttributes ready to be signed + */ + public byte[] GetAuthenticatedAttributeBytes(byte[] secondDigest, DateTime signingTime) { + Asn1EncodableVector attribute = new Asn1EncodableVector(); + Asn1EncodableVector v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(ID_CONTENT_TYPE)); + v.Add(new DerSet(new DerObjectIdentifier(ID_PKCS7_DATA))); + attribute.Add(new DerSequence(v)); + v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(ID_SIGNING_TIME)); + v.Add(new DerSet(new DerUtcTime(signingTime))); + attribute.Add(new DerSequence(v)); + v = new Asn1EncodableVector(); + v.Add(new DerObjectIdentifier(ID_MESSAGE_DIGEST)); + v.Add(new DerSet(new DerOctetString(secondDigest))); + attribute.Add(new DerSequence(v)); + MemoryStream bOut = new MemoryStream(); + + Asn1OutputStream dout = new Asn1OutputStream(bOut); + dout.WriteObject(new DerSet(attribute)); + dout.Close(); + + return bOut.ToArray(); + } + + + public string Reason { + get { + return reason; + } + set { + reason = value; + } + } + + + public string Location { + get { + return location; + } + set { + location = value; + } + } + + + public DateTime SignDate { + get { + return signDate; + } + set { + signDate = value; + } + } + + + public string SignName { + get { + return signName; + } + set { + signName = value; + } + } + + /** + * a class that holds an X509 name + */ + public class X509Name { + /** + * country code - StringType(SIZE(2)) + */ + public static DerObjectIdentifier C = new DerObjectIdentifier("2.5.4.6"); + + /** + * organization - StringType(SIZE(1..64)) + */ + public static DerObjectIdentifier O = new DerObjectIdentifier("2.5.4.10"); + + /** + * organizational unit name - StringType(SIZE(1..64)) + */ + public static DerObjectIdentifier OU = new DerObjectIdentifier("2.5.4.11"); + + /** + * Title + */ + public static DerObjectIdentifier T = new DerObjectIdentifier("2.5.4.12"); + + /** + * common name - StringType(SIZE(1..64)) + */ + public static DerObjectIdentifier CN = new DerObjectIdentifier("2.5.4.3"); + + /** + * device serial number name - StringType(SIZE(1..64)) + */ + public static DerObjectIdentifier SN = new DerObjectIdentifier("2.5.4.5"); + + /** + * locality name - StringType(SIZE(1..64)) + */ + public static DerObjectIdentifier L = new DerObjectIdentifier("2.5.4.7"); + + /** + * state, or province name - StringType(SIZE(1..64)) + */ + public static DerObjectIdentifier ST = new DerObjectIdentifier("2.5.4.8"); + + /** Naming attribute of type X520name */ + public static DerObjectIdentifier SURNAME = new DerObjectIdentifier("2.5.4.4"); + /** Naming attribute of type X520name */ + public static DerObjectIdentifier GIVENNAME = new DerObjectIdentifier("2.5.4.42"); + /** Naming attribute of type X520name */ + public static DerObjectIdentifier INITIALS = new DerObjectIdentifier("2.5.4.43"); + /** Naming attribute of type X520name */ + public static DerObjectIdentifier GENERATION = new DerObjectIdentifier("2.5.4.44"); + /** Naming attribute of type X520name */ + public static DerObjectIdentifier UNIQUE_IDENTIFIER = new DerObjectIdentifier("2.5.4.45"); + + /** + * Email address (RSA PKCS#9 extension) - IA5String. + *

    Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here. + */ + public static DerObjectIdentifier EmailAddress = new DerObjectIdentifier("1.2.840.113549.1.9.1"); + + /** + * email address in Verisign certificates + */ + public static DerObjectIdentifier E = EmailAddress; + + /** object identifier */ + public static DerObjectIdentifier DC = new DerObjectIdentifier("0.9.2342.19200300.100.1.25"); + + /** LDAP User id. */ + public static DerObjectIdentifier UID = new DerObjectIdentifier("0.9.2342.19200300.100.1.1"); + + /** A Hashtable with default symbols */ + public static Hashtable DefaultSymbols = new Hashtable(); + + static X509Name(){ + DefaultSymbols[C] = "C"; + DefaultSymbols[O] = "O"; + DefaultSymbols[T] = "T"; + DefaultSymbols[OU] = "OU"; + DefaultSymbols[CN] = "CN"; + DefaultSymbols[L] = "L"; + DefaultSymbols[ST] = "ST"; + DefaultSymbols[SN] = "SN"; + DefaultSymbols[EmailAddress] = "E"; + DefaultSymbols[DC] = "DC"; + DefaultSymbols[UID] = "UID"; + DefaultSymbols[SURNAME] = "SURNAME"; + DefaultSymbols[GIVENNAME] = "GIVENNAME"; + DefaultSymbols[INITIALS] = "INITIALS"; + DefaultSymbols[GENERATION] = "GENERATION"; + } + /** A Hashtable with values */ + public Hashtable values = new Hashtable(); + + /** + * Constructs an X509 name + * @param seq an Asn1 Sequence + */ + public X509Name(Asn1Sequence seq) { + IEnumerator e = seq.GetEnumerator(); + + while (e.MoveNext()) { + Asn1Set sett = (Asn1Set)e.Current; + + for (int i = 0; i < sett.Count; i++) { + Asn1Sequence s = (Asn1Sequence)sett[i]; + String id = (String)DefaultSymbols[s[0]]; + if (id == null) + continue; + ArrayList vs = (ArrayList)values[id]; + if (vs == null) { + vs = new ArrayList(); + values[id] = vs; + } + vs.Add(((DerStringBase)s[1]).GetString()); + } + } + } + /** + * Constructs an X509 name + * @param dirName a directory name + */ + public X509Name(String dirName) { + X509NameTokenizer nTok = new X509NameTokenizer(dirName); + + while (nTok.HasMoreTokens()) { + String token = nTok.NextToken(); + int index = token.IndexOf('='); + + if (index == -1) { + throw new ArgumentException("badly formated directory string"); + } + + String id = token.Substring(0, index).ToUpper(System.Globalization.CultureInfo.InvariantCulture); + String value = token.Substring(index + 1); + ArrayList vs = (ArrayList)values[id]; + if (vs == null) { + vs = new ArrayList(); + values[id] = vs; + } + vs.Add(value); + } + + } + + public String GetField(String name) { + ArrayList vs = (ArrayList)values[name]; + return vs == null ? null : (String)vs[0]; + } + + /** + * gets a field array from the values Hashmap + * @param name + * @return an ArrayList + */ + public ArrayList GetFieldArray(String name) { + ArrayList vs = (ArrayList)values[name]; + return vs == null ? null : vs; + } + + /** + * getter for values + * @return a Hashtable with the fields of the X509 name + */ + public Hashtable GetFields() { + return values; + } + + /** + * @see java.lang.Object#toString() + */ + public override String ToString() { + return values.ToString(); + } + } + + /** + * class for breaking up an X500 Name into it's component tokens, ala + * java.util.StringTokenizer. We need this class as some of the + * lightweight Java environment don't support classes like + * StringTokenizer. + */ + public class X509NameTokenizer { + private String oid; + private int index; + private StringBuilder buf = new StringBuilder(); + + public X509NameTokenizer( + String oid) { + this.oid = oid; + this.index = -1; + } + + public bool HasMoreTokens() { + return (index != oid.Length); + } + + public String NextToken() { + if (index == oid.Length) { + return null; + } + + int end = index + 1; + bool quoted = false; + bool escaped = false; + + buf.Length = 0; + + while (end != oid.Length) { + char c = oid[end]; + + if (c == '"') { + if (!escaped) { + quoted = !quoted; + } + else { + buf.Append(c); + } + escaped = false; + } + else { + if (escaped || quoted) { + buf.Append(c); + escaped = false; + } + else if (c == '\\') { + escaped = true; + } + else if (c == ',') { + break; + } + else { + buf.Append(c); + } + } + end++; + } + + index = end; + return buf.ToString().Trim(); + } + } + } +} + diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPRow.cs b/iTechSharp/iTextSharp/text/pdf/PdfPRow.cs new file mode 100644 index 0000000..ecb339d --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPRow.cs @@ -0,0 +1,649 @@ +using System; + +using iTextSharp.text; + +/* + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A row in a PdfPTable. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + + public class PdfPRow { + + /** the bottom limit (bottom right y) */ + public const float BOTTOM_LIMIT = -(1 << 30); + + protected PdfPCell[] cells; + + protected float[] widths; + + protected float maxHeight = 0; + + protected bool calculated = false; + + private int[] canvasesPos; + + /** + * Constructs a new PdfPRow with the cells in the array that was passed as a parameter. + * @param cells + */ + public PdfPRow(PdfPCell[] cells) { + this.cells = cells; + widths = new float[cells.Length]; + } + + /** + * Makes a copy of an existing row. + * @param row + */ + public PdfPRow(PdfPRow row) { + maxHeight = row.maxHeight; + calculated = row.calculated; + cells = new PdfPCell[row.cells.Length]; + for (int k = 0; k < cells.Length; ++k) { + if (row.cells[k] != null) + cells[k] = new PdfPCell(row.cells[k]); + } + widths = new float[cells.Length]; + Array.Copy(row.widths, 0, widths, 0, cells.Length); + } + + /** + * Sets the widths of the columns in the row. + * @param widths + * @return true if everything went right + */ + public bool SetWidths(float[] widths) { + if (widths.Length != cells.Length) + return false; + Array.Copy(widths, 0, this.widths, 0, cells.Length); + float total = 0; + calculated = false; + for (int k = 0; k < widths.Length; ++k) { + PdfPCell cell = cells[k]; + cell.Left = total; + int last = k + cell.Colspan; + for (; k < last; ++k) + total += widths[k]; + --k; + cell.Right = total; + cell.Top = 0; + } + return true; + } + + /** + * Calculates the heights of each cell in the row. + * @return the maximum height of the row. + */ + public float CalculateHeights() { + maxHeight = 0; + for (int k = 0; k < cells.Length; ++k) { + PdfPCell cell = cells[k]; + if (cell == null) + continue; + Image img = cell.Image; + if (img != null) { + img.ScalePercent(100); + float refWidth = img.ScaledWidth; + if (cell.Rotation == 90 || cell.Rotation == 270) { + refWidth = img.ScaledHeight; + } + float scale = (cell.Right - cell.EffectivePaddingRight + - cell.EffectivePaddingLeft - cell.Left) + / refWidth; + img.ScalePercent(scale * 100); + float refHeight = img.ScaledHeight; + if (cell.Rotation == 90 || cell.Rotation == 270) { + refHeight = img.ScaledWidth; + } + cell.Bottom = cell.Top - cell.EffectivePaddingTop + - cell.EffectivePaddingBottom + - refHeight; + } else { + if (cell.Rotation == 0 || cell.Rotation == 180) { + float rightLimit = cell.NoWrap ? 20000 : cell.Right + - cell.EffectivePaddingRight; + float bry = (cell.FixedHeight > 0) ? cell.Top + - cell.EffectivePaddingTop + + cell.EffectivePaddingBottom + - cell.FixedHeight : BOTTOM_LIMIT; + ColumnText ct = ColumnText.Duplicate(cell.Column); + SetColumn(ct, + cell.Left + cell.EffectivePaddingLeft, bry, + rightLimit, cell.Top - cell.EffectivePaddingTop); + ct.Go(true); + float yLine = ct.YLine; + if (cell.UseDescender) + yLine += ct.Descender; + cell.Bottom = yLine - cell.EffectivePaddingBottom; + } + else { + if (cell.FixedHeight > 0) { + cell.Bottom = cell.Top - cell.FixedHeight; + } + else { + ColumnText ct = ColumnText.Duplicate(cell.Column); + SetColumn(ct, 0, cell.Left + cell.EffectivePaddingLeft, + 20000, cell.Right - cell.EffectivePaddingRight); + ct.Go(true); + cell.Bottom = cell.Top - cell.EffectivePaddingTop + - cell.EffectivePaddingBottom - ct.FilledWidth; + } + } + } + float height = cell.FixedHeight; + if (height <= 0) + height = cell.Height; + if (height < cell.FixedHeight) + height = cell.FixedHeight; + else if (height < cell.MinimumHeight) + height = cell.MinimumHeight; + if (height > maxHeight) + maxHeight = height; + } + calculated = true; + return maxHeight; + } + + /** + * Writes the border and background of one cell in the row. + * @param xPos + * @param yPos + * @param cell + * @param canvases + */ + public void WriteBorderAndBackground(float xPos, float yPos, PdfPCell cell, + PdfContentByte[] canvases) { + PdfContentByte lines = canvases[PdfPTable.LINECANVAS]; + PdfContentByte backgr = canvases[PdfPTable.BACKGROUNDCANVAS]; + // the coordinates of the border are retrieved + float x1 = cell.Left + xPos; + float y2 = cell.Top + yPos; + float x2 = cell.Right + xPos; + float y1 = y2 - maxHeight; + + // the backgroundcolor is set + Color background = cell.BackgroundColor; + if (background != null) { + backgr.SetColorFill(background); + backgr.Rectangle(x1, y1, x2 - x1, y2 - y1); + backgr.Fill(); + } + // if the element hasn't got any borders, nothing is added + if (cell.HasBorders()) { + if (cell.UseVariableBorders) { + Rectangle borderRect = new Rectangle(cell.Left + xPos, cell.Top + - maxHeight + yPos, cell.Right + xPos, cell.Top + + yPos); + borderRect.CloneNonPositionParameters(cell); + borderRect.BackgroundColor = null; + lines.Rectangle(borderRect); + } else { + // the width is set to the width of the element + if (cell.BorderWidth != Rectangle.UNDEFINED) { + lines.SetLineWidth(cell.BorderWidth); + } + // the color is set to the color of the element + Color color = cell.BorderColor; + if (color != null) { + lines.SetColorStroke(color); + } + + // if the box is a rectangle, it is added as a rectangle + if (cell.HasBorder(Rectangle.BOX)) { + lines.Rectangle(x1, y1, x2 - x1, y2 - y1); + } + // if the border isn't a rectangle, the different sides are + // added apart + else { + if (cell.HasBorder(Rectangle.RIGHT_BORDER)) { + lines.MoveTo(x2, y1); + lines.LineTo(x2, y2); + } + if (cell.HasBorder(Rectangle.LEFT_BORDER)) { + lines.MoveTo(x1, y1); + lines.LineTo(x1, y2); + } + if (cell.HasBorder(Rectangle.BOTTOM_BORDER)) { + lines.MoveTo(x1, y1); + lines.LineTo(x2, y1); + } + if (cell.HasBorder(Rectangle.TOP_BORDER)) { + lines.MoveTo(x1, y2); + lines.LineTo(x2, y2); + } + } + lines.Stroke(); + if (color != null) { + lines.ResetRGBColorStroke(); + } + } + } + } + + private void SaveAndRotateCanvases(PdfContentByte[] canvases, float a, float b, float c, float d, float e, float f) { + int last = PdfPTable.TEXTCANVAS + 1; + if (canvasesPos == null) { + canvasesPos = new int[last * 2]; + } + for (int k = 0; k < last; ++k) { + ByteBuffer bb = canvases[k].InternalBuffer; + canvasesPos[k * 2] = bb.Size; + canvases[k].SaveState(); + canvases[k].ConcatCTM(a, b, c, d, e, f); + canvasesPos[k * 2 + 1] = bb.Size; + } + } + + private void RestoreCanvases(PdfContentByte[] canvases) { + int last = PdfPTable.TEXTCANVAS + 1; + for (int k = 0; k < last; ++k) { + ByteBuffer bb = canvases[k].InternalBuffer; + int p1 = bb.Size; + canvases[k].RestoreState(); + if (p1 == canvasesPos[k * 2 + 1]) + bb.Size = canvasesPos[k * 2]; + } + } + + private float SetColumn(ColumnText ct, float llx, float lly, float urx, float ury) { + if (llx > urx) + urx = llx; + if (lly > ury) + ury = lly; + ct.SetSimpleColumn(llx, lly, urx, ury); + return ury; + } + + /** + * Writes a number of cells (not necessarily all cells). + * @param colStart + * @param colEnd + * @param xPos + * @param yPos + * @param canvases + */ + public void WriteCells(int colStart, int colEnd, float xPos, float yPos, + PdfContentByte[] canvases) { + if (!calculated) + CalculateHeights(); + if (colEnd < 0) + colEnd = cells.Length; + colEnd = Math.Min(colEnd, cells.Length); + if (colStart < 0) + colStart = 0; + if (colStart >= colEnd) + return; + int newStart; + for (newStart = colStart; newStart >= 0; --newStart) { + if (cells[newStart] != null) + break; + xPos -= widths[newStart - 1]; + } + xPos -= cells[newStart].Left; + for (int k = newStart; k < colEnd; ++k) { + PdfPCell cell = cells[k]; + if (cell == null) + continue; + WriteBorderAndBackground(xPos, yPos, cell, canvases); + Image img = cell.Image; + float tly = 0; + switch (cell.VerticalAlignment) { + case Element.ALIGN_BOTTOM: + tly = cell.Top + yPos - maxHeight + cell.Height + - cell.EffectivePaddingTop; + break; + case Element.ALIGN_MIDDLE: + tly = cell.Top + yPos + (cell.Height - maxHeight) / 2 + - cell.EffectivePaddingTop; + break; + default: + tly = cell.Top + yPos - cell.EffectivePaddingTop; + break; + } + if (img != null) { + if (cell.Rotation != 0) { + img = Image.GetInstance(img); + img.Rotation = img.GetImageRotation() + (float)(cell.Rotation * Math.PI / 180.0); + } + bool vf = false; + if (cell.Height > maxHeight) { + img.ScalePercent(100); + float scale = (maxHeight - cell.EffectivePaddingTop - cell + .EffectivePaddingBottom) + / img.ScaledHeight; + img.ScalePercent(scale * 100); + vf = true; + } + float left = cell.Left + xPos + + cell.EffectivePaddingLeft; + if (vf) { + switch (cell.HorizontalAlignment) { + case Element.ALIGN_CENTER: + left = xPos + + (cell.Left + cell.EffectivePaddingLeft + + cell.Right + - cell.EffectivePaddingRight - img + .ScaledWidth) / 2; + break; + case Element.ALIGN_RIGHT: + left = xPos + cell.Right + - cell.EffectivePaddingRight + - img.ScaledWidth; + break; + default: + break; + } + tly = cell.Top + yPos - cell.EffectivePaddingTop; + } + img.SetAbsolutePosition(left, tly - img.ScaledHeight); + canvases[PdfPTable.TEXTCANVAS].AddImage(img); + } else { + if (cell.Rotation == 90 || cell.Rotation == 270) { + float netWidth = maxHeight - cell.EffectivePaddingTop - cell.EffectivePaddingBottom; + float netHeight = cell.Width - cell.EffectivePaddingLeft - cell.EffectivePaddingRight; + ColumnText ct = ColumnText.Duplicate(cell.Column); + ct.Canvases = canvases; + ct.SetSimpleColumn(0, 0, netWidth + 0.001f, -netHeight); + ct.Go(true); + float calcHeight = -ct.YLine; + if (netWidth <= 0 || netHeight <= 0) + calcHeight = 0; + if (calcHeight > 0) { + if (cell.UseDescender) + calcHeight -= ct.Descender; + ct = ColumnText.Duplicate(cell.Column); + ct.Canvases = canvases; + ct.SetSimpleColumn(0, -0.001f, netWidth + 0.001f, calcHeight); + float pivotX; + float pivotY; + if (cell.Rotation == 90) { + pivotY = cell.Top + yPos - maxHeight + cell.EffectivePaddingBottom; + switch (cell.VerticalAlignment) { + case Element.ALIGN_BOTTOM: + pivotX = cell.Left + xPos + cell.Width - cell.EffectivePaddingRight; + break; + case Element.ALIGN_MIDDLE: + pivotX = cell.Left + xPos + (cell.Width + cell.EffectivePaddingLeft - cell.EffectivePaddingRight + calcHeight) / 2; + break; + default: //top + pivotX = cell.Left + xPos + cell.EffectivePaddingLeft + calcHeight; + break; + } + SaveAndRotateCanvases(canvases, 0,1,-1,0,pivotX,pivotY); + } + else { + pivotY = cell.Top + yPos - cell.EffectivePaddingTop; + switch (cell.VerticalAlignment) { + case Element.ALIGN_BOTTOM: + pivotX = cell.Left + xPos + cell.EffectivePaddingLeft; + break; + case Element.ALIGN_MIDDLE: + pivotX = cell.Left + xPos + (cell.Width + cell.EffectivePaddingLeft - cell.EffectivePaddingRight - calcHeight) / 2; + break; + default: //top + pivotX = cell.Left + xPos + cell.Width - cell.EffectivePaddingRight - calcHeight; + break; + } + SaveAndRotateCanvases(canvases, 0,-1,1,0,pivotX,pivotY); + } + try { + ct.Go(); + } finally { + RestoreCanvases(canvases); + } + } + } + else { + float fixedHeight = cell.FixedHeight; + float rightLimit = cell.Right + xPos + - cell.EffectivePaddingRight; + float leftLimit = cell.Left + xPos + + cell.EffectivePaddingLeft; + if (cell.NoWrap) { + switch (cell.HorizontalAlignment) { + case Element.ALIGN_CENTER: + rightLimit += 10000; + leftLimit -= 10000; + break; + case Element.ALIGN_RIGHT: + leftLimit -= 20000; + break; + default: + rightLimit += 20000; + break; + } + } + ColumnText ct = ColumnText.Duplicate(cell.Column); + ct.Canvases = canvases; + float bry = tly + - (maxHeight /* cell.Height */ + - cell.EffectivePaddingTop - cell + .EffectivePaddingBottom); + if (fixedHeight > 0) { + if (cell.Height > maxHeight) { + tly = cell.Top + yPos - cell.EffectivePaddingTop; + bry = cell.Top + yPos - maxHeight + + cell.EffectivePaddingBottom; + } + } + if ((tly > bry || ct.ZeroHeightElement()) && leftLimit < rightLimit) { + ct.SetSimpleColumn(leftLimit, bry - 0.001f, rightLimit, tly); + if (cell.Rotation == 180) { + float shx = leftLimit + rightLimit; + float shy = yPos + yPos - maxHeight + cell.EffectivePaddingBottom - cell.EffectivePaddingTop; + SaveAndRotateCanvases(canvases, -1,0,0,-1,shx,shy); + } + try { + ct.Go(); + } finally { + if (cell.Rotation == 180) { + RestoreCanvases(canvases); + } + } + } + } + } + IPdfPCellEvent evt = cell.CellEvent; + if (evt != null) { + Rectangle rect = new Rectangle(cell.Left + xPos, cell.Top + + yPos - maxHeight, cell.Right + xPos, cell.Top + + yPos); + evt.CellLayout(cell, rect, canvases); + } + } + } + + /** + * Checks if the dimensions of the columns were calculated. + * @return true if the dimensions of the columns were calculated + */ + public bool IsCalculated() { + return calculated; + } + + /** + * Gets the maximum height of the row (i.e. of the 'highest' cell). + * @return the maximum height of the row + */ + public float MaxHeights { + get { + if (calculated) + return maxHeight; + else + return CalculateHeights(); + } + set { + this.maxHeight = value; + } + } + + + internal float[] GetEventWidth(float xPos) { + int n = 0; + for (int k = 0; k < cells.Length; ++k) { + if (cells[k] != null) + ++n; + } + float[] width = new float[n + 1]; + n = 0; + width[n++] = xPos; + for (int k = 0; k < cells.Length; ++k) { + if (cells[k] != null) { + width[n] = width[n - 1] + cells[k].Width; + ++n; + } + } + return width; + } + + /** + * Splits a row to newHeight. The returned row is the remainder. It will + * return null if the newHeight was so small that only an empty row would + * result. + * + * @param newHeight + * the new height + * @return the remainder row or null if the newHeight was so small that only + * an empty row would result + */ + public PdfPRow SplitRow(float newHeight) { + PdfPCell[] newCells = new PdfPCell[cells.Length]; + float[] fh = new float[cells.Length * 2]; + bool allEmpty = true; + for (int k = 0; k < cells.Length; ++k) { + PdfPCell cell = cells[k]; + if (cell == null) + continue; + fh[k * 2] = cell.FixedHeight; + fh[k * 2 + 1] = cell.MinimumHeight; + Image img = cell.Image; + PdfPCell c2 = new PdfPCell(cell); + if (img != null) { + if (newHeight > cell.EffectivePaddingBottom + + cell.EffectivePaddingTop + 2) { + c2.Phrase = null; + allEmpty = false; + } + } else { + int status; + float y; + ColumnText ct = ColumnText.Duplicate(cell.Column); + if (cell.Rotation == 90 || cell.Rotation == 270) { + y = SetColumn(ct, + cell.Top - newHeight + cell.EffectivePaddingBottom, + cell.Left + cell.EffectivePaddingLeft, + cell.Top - cell.EffectivePaddingTop, + cell.Right - cell.EffectivePaddingRight); + } + else { + float rightLimit = cell.NoWrap ? 20000 : cell.Right + - cell.EffectivePaddingRight; + float y1 = cell.Top - newHeight + + cell.EffectivePaddingBottom; + float y2 = cell.Top - cell.EffectivePaddingTop; + y = Math.Max(y1, y2); + y = SetColumn(ct, + cell.Left + cell.EffectivePaddingLeft, y1, + rightLimit, y2); + } + status = ct.Go(true); + bool thisEmpty = (ct.YLine == y); + if (thisEmpty) + ct = ColumnText.Duplicate(cell.Column); + allEmpty = (allEmpty && thisEmpty); + if ((status & ColumnText.NO_MORE_TEXT) == 0 || thisEmpty) { + c2.Column = ct; + ct.FilledWidth = 0; + } else { + c2.Phrase = null; + } + } + newCells[k] = c2; + cell.FixedHeight = newHeight; + } + if (allEmpty) { + for (int k = 0; k < cells.Length; ++k) { + PdfPCell cell = cells[k]; + if (cell == null) + continue; + float f = fh[k * 2]; + float m = fh[k * 2 + 1]; + if (f <= 0) + cell.MinimumHeight = m; + else + cell.FixedHeight = f; + } + return null; + } + CalculateHeights(); + PdfPRow split = new PdfPRow(newCells); + split.widths = (float[]) widths.Clone(); + split.CalculateHeights(); + return split; + } + + /** + * Returns the array of cells in the row. + * Please be extremely careful with this method. + * Use the cells as read only objects. + * @return an array of cells + * @since 2.1.1 + */ + public PdfPCell[] Cells { + get { + return cells; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPSXObject.cs b/iTechSharp/iTextSharp/text/pdf/PdfPSXObject.cs new file mode 100644 index 0000000..78f0a4f --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPSXObject.cs @@ -0,0 +1,101 @@ +using System; +/* + * Copyright 2005 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Implements the PostScript XObject. + */ + public class PdfPSXObject : PdfTemplate { + + /** Creates a new instance of PdfPSXObject */ + protected PdfPSXObject() { + } + + /** + * Constructs a PSXObject + * @param wr + */ + public PdfPSXObject(PdfWriter wr) : base(wr) { + } + + /** + * Gets the stream representing this object. + * + * @return the stream representing this object + * @throws IOException + */ + + internal override PdfStream FormXObject { + get { + PdfStream s = new PdfStream(content.ToByteArray()); + s.Put(PdfName.TYPE, PdfName.XOBJECT); + s.Put(PdfName.SUBTYPE, PdfName.PS); + s.FlateCompress(); + return s; + } + } + + /** + * Gets a duplicate of this PdfPSXObject. All + * the members are copied by reference but the buffer stays different. + * @return a copy of this PdfPSXObject + */ + + public override PdfContentByte Duplicate { + get { + PdfPSXObject tpl = new PdfPSXObject(); + tpl.writer = writer; + tpl.pdf = pdf; + tpl.thisReference = thisReference; + tpl.pageResources = pageResources; + tpl.separator = separator; + return tpl; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPTable.cs b/iTechSharp/iTextSharp/text/pdf/PdfPTable.cs new file mode 100644 index 0000000..3f82101 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPTable.cs @@ -0,0 +1,1050 @@ +using System; +using System.Collections; + +using iTextSharp.text; +using iTextSharp.text.pdf.events; + +/* + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** This is a table that can be put at an absolute position but can also + * be added to the document as the class Table. + * In the last case when crossing pages the table always break at full rows; if a + * row is bigger than the page it is dropped silently to avoid infinite loops. + *

    + * A PdfPTableEvent can be associated to the table to do custom drawing + * when the table is rendered. + * @author Paulo Soares (psoares@consiste.pt) + */ + + public class PdfPTable : ILargeElement{ + + /** The index of the original PdfcontentByte. + */ + public const int BASECANVAS = 0; + /** The index of the duplicate PdfContentByte where the background will be drawn. + */ + public const int BACKGROUNDCANVAS = 1; + /** The index of the duplicate PdfContentByte where the border lines will be drawn. + */ + public const int LINECANVAS = 2; + /** The index of the duplicate PdfContentByte where the text will be drawn. + */ + public const int TEXTCANVAS = 3; + + protected ArrayList rows = new ArrayList(); + protected float totalHeight = 0; + protected PdfPCell[] currentRow; + protected int currentRowIdx = 0; + protected PdfPCell defaultCell = new PdfPCell((Phrase)null); + protected float totalWidth = 0; + protected float[] relativeWidths; + protected float[] absoluteWidths; + protected IPdfPTableEvent tableEvent; + + /** Holds value of property headerRows. */ + protected int headerRows; + + /** Holds value of property widthPercentage. */ + protected float widthPercentage = 80; + + /** Holds value of property horizontalAlignment. */ + private int horizontalAlignment = Element.ALIGN_CENTER; + + /** Holds value of property skipFirstHeader. */ + private bool skipFirstHeader = false; + + protected bool isColspan = false; + + protected int runDirection = PdfWriter.RUN_DIRECTION_DEFAULT; + + /** + * Holds value of property lockedWidth. + */ + private bool lockedWidth = false; + + /** + * Holds value of property splitRows. + */ + private bool splitRows = true; + + /** The spacing before the table. */ + protected float spacingBefore; + + /** The spacing after the table. */ + protected float spacingAfter; + + /** + * Holds value of property extendLastRow. + */ + private bool extendLastRow; + + /** + * Holds value of property headersInEvent. + */ + private bool headersInEvent; + + /** + * Holds value of property splitLate. + */ + private bool splitLate = true; + + /** + * Defines if the table should be kept + * on one page if possible + */ + private bool keepTogether; + + /** + * Indicates if the PdfPTable is complete once added to the document. + * @since iText 2.0.8 + */ + protected bool complete = true; + + private int footerRows; + + protected PdfPTable() { + } + + /** Constructs a PdfPTable with the relative column widths. + * @param relativeWidths the relative column widths + */ + public PdfPTable(float[] relativeWidths) { + if (relativeWidths == null) + throw new ArgumentNullException("The widths array in PdfPTable constructor can not be null."); + if (relativeWidths.Length == 0) + throw new ArgumentException("The widths array in PdfPTable constructor can not have zero length."); + this.relativeWidths = new float[relativeWidths.Length]; + Array.Copy(relativeWidths, 0, this.relativeWidths, 0, relativeWidths.Length); + absoluteWidths = new float[relativeWidths.Length]; + CalculateWidths(); + currentRow = new PdfPCell[absoluteWidths.Length]; + keepTogether = false; + } + + /** Constructs a PdfPTable with numColumns columns. + * @param numColumns the number of columns + */ + public PdfPTable(int numColumns) { + if (numColumns <= 0) + throw new ArgumentException("The number of columns in PdfPTable constructor must be greater than zero."); + relativeWidths = new float[numColumns]; + for (int k = 0; k < numColumns; ++k) + relativeWidths[k] = 1; + absoluteWidths = new float[relativeWidths.Length]; + CalculateWidths(); + currentRow = new PdfPCell[absoluteWidths.Length]; + keepTogether = false; + } + + /** Constructs a copy of a PdfPTable. + * @param table the PdfPTable to be copied + */ + public PdfPTable(PdfPTable table) { + CopyFormat(table); + for (int k = 0; k < currentRow.Length; ++k) { + if (table.currentRow[k] == null) + break; + currentRow[k] = new PdfPCell(table.currentRow[k]); + } + for (int k = 0; k < table.rows.Count; ++k) { + PdfPRow row = (PdfPRow)(table.rows[k]); + if (row != null) + row = new PdfPRow(row); + rows.Add(row); + } + } + + /** + * Makes a shallow copy of a table (format without content). + * @param table + * @return a shallow copy of the table + */ + public static PdfPTable ShallowCopy(PdfPTable table) { + PdfPTable nt = new PdfPTable(); + nt.CopyFormat(table); + return nt; + } + + /** + * Copies the format of the sourceTable without copying the content. + * @param sourceTable + */ + private void CopyFormat(PdfPTable sourceTable) { + relativeWidths = new float[sourceTable.relativeWidths.Length]; + absoluteWidths = new float[sourceTable.relativeWidths.Length]; + Array.Copy(sourceTable.relativeWidths, 0, relativeWidths, 0, relativeWidths.Length); + Array.Copy(sourceTable.absoluteWidths, 0, absoluteWidths, 0, relativeWidths.Length); + totalWidth = sourceTable.totalWidth; + totalHeight = sourceTable.totalHeight; + currentRowIdx = 0; + tableEvent = sourceTable.tableEvent; + runDirection = sourceTable.runDirection; + defaultCell = new PdfPCell(sourceTable.defaultCell); + currentRow = new PdfPCell[sourceTable.currentRow.Length]; + isColspan = sourceTable.isColspan; + splitRows = sourceTable.splitRows; + spacingAfter = sourceTable.spacingAfter; + spacingBefore = sourceTable.spacingBefore; + headerRows = sourceTable.headerRows; + footerRows = sourceTable.footerRows; + lockedWidth = sourceTable.lockedWidth; + extendLastRow = sourceTable.extendLastRow; + headersInEvent = sourceTable.headersInEvent; + widthPercentage = sourceTable.widthPercentage; + splitLate = sourceTable.splitLate; + skipFirstHeader = sourceTable.skipFirstHeader; + horizontalAlignment = sourceTable.horizontalAlignment; + keepTogether = sourceTable.keepTogether; + complete = sourceTable.complete; + } + + /** Sets the relative widths of the table. + * @param relativeWidths the relative widths of the table. + * @throws DocumentException if the number of widths is different than the number + * of columns + */ + public void SetWidths(float[] relativeWidths) { + if (relativeWidths.Length != this.relativeWidths.Length) + throw new DocumentException("Wrong number of columns."); + this.relativeWidths = new float[relativeWidths.Length]; + Array.Copy(relativeWidths, 0, this.relativeWidths, 0, relativeWidths.Length); + absoluteWidths = new float[relativeWidths.Length]; + totalHeight = 0; + CalculateWidths(); + CalculateHeights(); + } + + /** Sets the relative widths of the table. + * @param relativeWidths the relative widths of the table. + * @throws DocumentException if the number of widths is different than the number + * of columns + */ + public void SetWidths(int[] relativeWidths) { + float[] tb = new float[relativeWidths.Length]; + for (int k = 0; k < relativeWidths.Length; ++k) + tb[k] = relativeWidths[k]; + SetWidths(tb); + } + + private void CalculateWidths() { + if (totalWidth <= 0) + return; + float total = 0; + for (int k = 0; k < absoluteWidths.Length; ++k) { + total += relativeWidths[k]; + } + for (int k = 0; k < absoluteWidths.Length; ++k) { + absoluteWidths[k] = totalWidth * relativeWidths[k] / total; + } + } + + /** Sets the full width of the table from the absolute column width. + * @param columnWidth the absolute width of each column + * @throws DocumentException if the number of widths is different than the number + * of columns + */ + public void SetTotalWidth(float[] columnWidth) { + if (columnWidth.Length != this.relativeWidths.Length) + throw new DocumentException("Wrong number of columns."); + totalWidth = 0; + for (int k = 0; k < columnWidth.Length; ++k) + totalWidth += columnWidth[k]; + SetWidths(columnWidth); + } + + /** Sets the percentage width of the table from the absolute column width. + * @param columnWidth the absolute width of each column + * @param pageSize the page size + * @throws DocumentException + */ + public void SetWidthPercentage(float[] columnWidth, Rectangle pageSize) { + if (columnWidth.Length != this.relativeWidths.Length) + throw new ArgumentException("Wrong number of columns."); + float totalWidth = 0; + for (int k = 0; k < columnWidth.Length; ++k) + totalWidth += columnWidth[k]; + widthPercentage = totalWidth / (pageSize.Right - pageSize.Left) * 100f; + SetWidths(columnWidth); + } + + /** Gets the full width of the table. + * @return the full width of the table + */ + public float TotalWidth { + get { + return totalWidth; + } + set { + if (this.totalWidth == value) + return; + this.totalWidth = value; + totalHeight = 0; + CalculateWidths(); + CalculateHeights(); + } + } + + internal void CalculateHeights() { + if (totalWidth <= 0) + return; + totalHeight = 0; + for (int k = 0; k < rows.Count; ++k) { + PdfPRow row = (PdfPRow)rows[k]; + if (row != null) { + row.SetWidths(absoluteWidths); + totalHeight += row.MaxHeights; + } + } + } + + /** + * Calculates the heights of the table. + */ + public void CalculateHeightsFast() { + if (totalWidth <= 0) + return; + totalHeight = 0; + for (int k = 0; k < rows.Count; ++k) { + PdfPRow row = (PdfPRow)rows[k]; + if (row != null) + totalHeight += row.MaxHeights; + } + } + + /** Gets the default PdfPCell that will be used as + * reference for all the addCell methods except + * addCell(PdfPCell). + * @return default PdfPCell + */ + public PdfPCell DefaultCell { + get { + return defaultCell; + } + } + + /** Adds a cell element. + * @param cell the cell element + */ + public void AddCell(PdfPCell cell) { + PdfPCell ncell = new PdfPCell(cell); + int colspan = ncell.Colspan; + colspan = Math.Max(colspan, 1); + colspan = Math.Min(colspan, currentRow.Length - currentRowIdx); + ncell.Colspan = colspan; + if (colspan != 1) + isColspan = true; + int rdir = ncell.RunDirection; + if (rdir == PdfWriter.RUN_DIRECTION_DEFAULT) + ncell.RunDirection = runDirection; + currentRow[currentRowIdx] = ncell; + currentRowIdx += colspan; + if (currentRowIdx >= currentRow.Length) { + if (runDirection == PdfWriter.RUN_DIRECTION_RTL) { + PdfPCell[] rtlRow = new PdfPCell[absoluteWidths.Length]; + int rev = currentRow.Length; + for (int k = 0; k < currentRow.Length; ++k) { + PdfPCell rcell = currentRow[k]; + int cspan = rcell.Colspan; + rev -= cspan; + rtlRow[rev] = rcell; + k += cspan - 1; + } + currentRow = rtlRow; + } + PdfPRow row = new PdfPRow(currentRow); + if (totalWidth > 0) { + row.SetWidths(absoluteWidths); + totalHeight += row.MaxHeights; + } + rows.Add(row); + currentRow = new PdfPCell[absoluteWidths.Length]; + currentRowIdx = 0; + } + } + + /** Adds a cell element. + * @param text the text for the cell + */ + public void AddCell(String text) { + AddCell(new Phrase(text)); + } + + /** + * Adds a nested table. + * @param table the table to be added to the cell + */ + public void AddCell(PdfPTable table) { + defaultCell.Table = table; + AddCell(defaultCell); + defaultCell.Table = null; + } + + /** + * Adds an Image as Cell. + * @param image the Image to add to the table. This image will fit in the cell + */ + public void AddCell(Image image) { + defaultCell.Image = image; + AddCell(defaultCell); + defaultCell.Image = null; + } + + /** + * Adds a cell element. + * @param phrase the Phrase to be added to the cell + */ + public void AddCell(Phrase phrase) { + defaultCell.Phrase = phrase; + AddCell(defaultCell); + defaultCell.Phrase = null; + } + + /** + * Writes the selected rows to the document. + *

    + * canvases is obtained from beginWritingRows(). + * @param rowStart the first row to be written, zero index + * @param rowEnd the last row to be written + 1. If it is -1 all the + * rows to the end are written + * @param xPos the x write coodinate + * @param yPos the y write coodinate + * @param canvases an array of 4 PdfContentByte obtained from + * beginWrittingRows() + * @return the y coordinate position of the bottom of the last row + * @see #beginWritingRows(com.lowagie.text.pdf.PdfContentByte) + */ + public float WriteSelectedRows(int rowStart, int rowEnd, float xPos, float yPos, PdfContentByte[] canvases) { + return WriteSelectedRows(0, -1, rowStart, rowEnd, xPos, yPos, canvases); + } + + /** Writes the selected rows and columns to the document. + * This method does not clip the columns; this is only important + * if there are columns with colspan at boundaries. + *

    + * canvases is obtained from beginWritingRows(). + *

    + * The table event is only fired for complete rows. + * @param colStart the first column to be written, zero index + * @param colEnd the last column to be written + 1. If it is -1 all the + * columns to the end are written + * @param rowStart the first row to be written, zero index + * @param rowEnd the last row to be written + 1. If it is -1 all the + * rows to the end are written + * @param xPos the x write coodinate + * @param yPos the y write coodinate + * @param canvases an array of 4 PdfContentByte obtained from + * beginWrittingRows() + * @return the y coordinate position of the bottom of the last row + * @see #beginWritingRows(com.lowagie.text.pdf.PdfContentByte) + */ + public float WriteSelectedRows(int colStart, int colEnd, int rowStart, int rowEnd, float xPos, float yPos, PdfContentByte[] canvases) { + if (totalWidth <= 0) + throw new ArgumentException("The table width must be greater than zero."); + int size = rows.Count; + if (rowEnd < 0) + rowEnd = size; + rowEnd = Math.Min(rowEnd, size); + if (rowStart < 0) + rowStart = 0; + if (rowStart >= rowEnd) + return yPos; + if (colEnd < 0) + colEnd = absoluteWidths.Length; + colEnd = Math.Min(colEnd, absoluteWidths.Length); + if (colStart < 0) + colStart = 0; + colStart = Math.Min(colStart, absoluteWidths.Length); + float yPosStart = yPos; + for (int k = rowStart; k < rowEnd; ++k) { + PdfPRow row = (PdfPRow)rows[k]; + if (row != null) { + row.WriteCells(colStart, colEnd, xPos, yPos, canvases); + yPos -= row.MaxHeights; + } + } + if (tableEvent != null && colStart == 0 && colEnd == absoluteWidths.Length) { + float[] heights = new float[rowEnd - rowStart + 1]; + heights[0] = yPosStart; + for (int k = rowStart; k < rowEnd; ++k) { + PdfPRow row = (PdfPRow)rows[k]; + float hr = 0; + if (row != null) + hr = row.MaxHeights; + heights[k - rowStart + 1] = heights[k - rowStart] - hr; + } + tableEvent.TableLayout(this, GetEventWidths(xPos, rowStart, rowEnd, headersInEvent), heights, headersInEvent ? headerRows : 0, rowStart, canvases); + } + return yPos; + } + + /** + * Writes the selected rows to the document. + * + * @param rowStart the first row to be written, zero index + * @param rowEnd the last row to be written + 1. If it is -1 all the + * rows to the end are written + * @param xPos the x write coodinate + * @param yPos the y write coodinate + * @param canvas the PdfContentByte where the rows will + * be written to + * @return the y coordinate position of the bottom of the last row + */ + public float WriteSelectedRows(int rowStart, int rowEnd, float xPos, float yPos, PdfContentByte canvas) { + return WriteSelectedRows(0, -1, rowStart, rowEnd, xPos, yPos, canvas); + } + + /** + * Writes the selected rows to the document. + * This method clips the columns; this is only important + * if there are columns with colspan at boundaries. + *

    + * The table event is only fired for complete rows. + * + * @param colStart the first column to be written, zero index + * @param colEnd the last column to be written + 1. If it is -1 all the + * @param rowStart the first row to be written, zero index + * @param rowEnd the last row to be written + 1. If it is -1 all the + * rows to the end are written + * @param xPos the x write coodinate + * @param yPos the y write coodinate + * @param canvas the PdfContentByte where the rows will + * be written to + * @return the y coordinate position of the bottom of the last row + */ + public float WriteSelectedRows(int colStart, int colEnd, int rowStart, int rowEnd, float xPos, float yPos, PdfContentByte canvas) { + if (colEnd < 0) + colEnd = absoluteWidths.Length; + colEnd = Math.Min(colEnd, absoluteWidths.Length); + if (colStart < 0) + colStart = 0; + colStart = Math.Min(colStart, absoluteWidths.Length); + if (colStart != 0 || colEnd != absoluteWidths.Length) { + float w = 0; + for (int k = colStart; k < colEnd; ++k) + w += absoluteWidths[k]; + canvas.SaveState(); + float lx = 0; + float rx = 0; + if (colStart == 0) + lx = 10000; + if (colEnd == absoluteWidths.Length) + rx = 10000; + canvas.Rectangle(xPos - lx, -10000, w + lx + rx, 20000); + canvas.Clip(); + canvas.NewPath(); + } + PdfContentByte[] canvases = BeginWritingRows(canvas); + float y = WriteSelectedRows(colStart, colEnd, rowStart, rowEnd, xPos, yPos, canvases); + EndWritingRows(canvases); + if (colStart != 0 || colEnd != absoluteWidths.Length) + canvas.RestoreState(); + return y; + } + + /** Gets and initializes the 4 layers where the table is written to. The text or graphics are added to + * one of the 4 PdfContentByte returned with the following order:

    + *

      + *
    • PdfPtable.BASECANVAS - the original PdfContentByte. Anything placed here + * will be under the table. + *
    • PdfPtable.BACKGROUNDCANVAS - the layer where the background goes to. + *
    • PdfPtable.LINECANVAS - the layer where the lines go to. + *
    • PdfPtable.TEXTCANVAS - the layer where the text go to. Anything placed here + * will be over the table. + *

    + * The layers are placed in sequence on top of each other. + * @param canvas the PdfContentByte where the rows will + * be written to + * @return an array of 4 PdfContentByte + * @see #writeSelectedRows(int, int, float, float, PdfContentByte[]) + */ + public static PdfContentByte[] BeginWritingRows(PdfContentByte canvas) { + return new PdfContentByte[]{ + canvas, + canvas.Duplicate, + canvas.Duplicate, + canvas.Duplicate, + }; + } + + /** Finishes writing the table. + * @param canvases the array returned by beginWritingRows() + */ + public static void EndWritingRows(PdfContentByte[] canvases) { + PdfContentByte canvas = canvases[BASECANVAS]; + canvas.SaveState(); + canvas.Add(canvases[BACKGROUNDCANVAS]); + canvas.RestoreState(); + canvas.SaveState(); + canvas.SetLineCap(2); + canvas.ResetRGBColorStroke(); + canvas.Add(canvases[LINECANVAS]); + canvas.RestoreState(); + canvas.Add(canvases[TEXTCANVAS]); + } + + /** Gets the number of rows in this table. + * @return the number of rows in this table + */ + public int Size { + get { + return rows.Count; + } + } + + /** Gets the total height of the table. + * @return the total height of the table + */ + public float TotalHeight { + get { + return totalHeight; + } + } + + /** Gets the height of a particular row. + * @param idx the row index (starts at 0) + * @return the height of a particular row + */ + public float GetRowHeight(int idx) { + if (totalWidth <= 0 || idx < 0 || idx >= rows.Count) + return 0; + PdfPRow row = (PdfPRow)rows[idx]; + if (row == null) + return 0; + return row.MaxHeights; + } + + /** Gets the height of the rows that constitute the header as defined by + * setHeaderRows(). + * @return the height of the rows that constitute the header and footer + */ + public float HeaderHeight { + get { + float total = 0; + int size = Math.Min(rows.Count, headerRows); + for (int k = 0; k < size; ++k) { + PdfPRow row = (PdfPRow)rows[k]; + if (row != null) + total += row.MaxHeights; + } + return total; + } + } + + /** Gets the height of the rows that constitute the header as defined by + * setFooterRows(). + * @return the height of the rows that constitute the footer + * @since 2.1.1 + */ + public float FooterHeight { + get { + float total = 0; + int start = Math.Min(0, headerRows - footerRows); + int size = Math.Min(rows.Count, footerRows); + for (int k = start; k < size; ++k) { + PdfPRow row = (PdfPRow)rows[k]; + if (row != null) + total += row.MaxHeights; + } + return total; + } + } + + /** Deletes a row from the table. + * @param rowNumber the row to be deleted + * @return true if the row was deleted + */ + public bool DeleteRow(int rowNumber) { + if (rowNumber < 0 || rowNumber >= rows.Count) { + return false; + } + if (totalWidth > 0) { + PdfPRow row = (PdfPRow)rows[rowNumber]; + if (row != null) + totalHeight -= row.MaxHeights; + } + rows.RemoveAt(rowNumber); + return true; + } + + /** Deletes the last row in the table. + * @return true if the last row was deleted + */ + public bool DeleteLastRow() { + return DeleteRow(rows.Count - 1); + } + + /** + * Removes all of the rows except headers + */ + public void DeleteBodyRows() { + ArrayList rows2 = new ArrayList(); + for (int k = 0; k < headerRows; ++k) + rows2.Add(rows[k]); + rows = rows2; + totalHeight = 0; + if (totalWidth > 0) + totalHeight = HeaderHeight; + } + + /** Returns the number of columns. + * @return the number of columns. + * @since 2.1.1 + */ + public int NumberOfColumns { + get { + return relativeWidths.Length; + } + } + public int HeaderRows { + get { + return headerRows; + } + set { + headerRows = value; + if (headerRows < 0) + headerRows = 0; + } + } + + public int FooterRows { + get { + return footerRows; + } + set { + footerRows = value; + if (footerRows < 0) + footerRows = 0; + } + } + + /** + * Gets all the chunks in this element. + * + * @return an ArrayList + */ + public ArrayList Chunks { + get { + return new ArrayList(); + } + } + + /** + * Gets the type of the text element. + * + * @return a type + */ + public int Type { + get { + return Element.PTABLE; + } + } + + /** + * @see com.lowagie.text.Element#isContent() + * @since iText 2.0.8 + */ + public bool IsContent() { + return true; + } + + /** + * @see com.lowagie.text.Element#isNestable() + * @since iText 2.0.8 + */ + public bool IsNestable() { + return true; + } + + /** + * Processes the element by adding it (or the different parts) to an + * ElementListener. + * + * @param listener an ElementListener + * @return true if the element was processed successfully + */ + public bool Process(IElementListener listener) { + try { + return listener.Add(this); + } + catch (DocumentException) { + return false; + } + } + + public float WidthPercentage { + get { + return widthPercentage; + } + set { + widthPercentage = value; + } + } + + public int HorizontalAlignment { + get { + return horizontalAlignment; + } + set { + horizontalAlignment = value; + } + } + + /** + * Gets a row with a given index + * (added by Jin-Hsia Yang). + * @param idx + * @return the row at position idx + */ + public PdfPRow GetRow(int idx) { + return (PdfPRow)rows[idx]; + } + + /** + * Gets an arraylist with all the rows in the table. + * @return an arraylist + */ + public ArrayList Rows { + get { + return rows; + } + } + + public IPdfPTableEvent TableEvent { + get { + return tableEvent; + } + set { + if (value == null) this.tableEvent = null; + else if (this.tableEvent == null) this.tableEvent = value; + else if (this.tableEvent is PdfPTableEventForwarder) ((PdfPTableEventForwarder)this.tableEvent).AddTableEvent(value); + else { + PdfPTableEventForwarder forward = new PdfPTableEventForwarder(); + forward.AddTableEvent(this.tableEvent); + forward.AddTableEvent(value); + this.tableEvent = forward; + } + } + } + + /** Gets the absolute sizes of each column width. + * @return he absolute sizes of each column width + */ + public float[] AbsoluteWidths { + get { + return absoluteWidths; + } + } + + internal float [][] GetEventWidths(float xPos, int firstRow, int lastRow, bool includeHeaders) { + if (includeHeaders) { + firstRow = Math.Max(firstRow, headerRows); + lastRow = Math.Max(lastRow, headerRows); + } + float[][] widths = new float[(includeHeaders ? headerRows : 0) + lastRow - firstRow][]; + if (isColspan) { + int n = 0; + if (includeHeaders) { + for (int k = 0; k < headerRows; ++k) { + PdfPRow row = (PdfPRow)rows[k]; + if (row == null) + ++n; + else + widths[n++] = row.GetEventWidth(xPos); + } + } + for (; firstRow < lastRow; ++firstRow) { + PdfPRow row = (PdfPRow)rows[firstRow]; + if (row == null) + ++n; + else + widths[n++] = row.GetEventWidth(xPos); + } + } + else { + float[] width = new float[absoluteWidths.Length + 1]; + width[0] = xPos; + for (int k = 0; k < absoluteWidths.Length; ++k) + width[k + 1] = width[k] + absoluteWidths[k]; + for (int k = 0; k < widths.Length; ++k) + widths[k] = width; + } + return widths; + } + + public bool SkipFirstHeader { + get { + return skipFirstHeader; + } + set { + skipFirstHeader = value; + } + } + + public int RunDirection { + get { + return runDirection; + } + set { + if (value < PdfWriter.RUN_DIRECTION_DEFAULT || value > PdfWriter.RUN_DIRECTION_RTL) + throw new ArgumentException("Invalid run direction: " + value); + runDirection = value; + } + } + + public bool LockedWidth { + get { + return lockedWidth; + } + set { + lockedWidth = value; + } + } + + public bool SplitRows { + get { + return splitRows; + } + set { + splitRows = value; + } + } + + public float SpacingBefore { + get { + return spacingBefore; + } + set { + spacingBefore = value; + } + } + + public float SpacingAfter { + get { + return spacingAfter; + } + set { + spacingAfter = value; + } + } + + public bool ExtendLastRow { + get { + return extendLastRow; + } + set { + extendLastRow = value; + } + } + + public bool HeadersInEvent { + get { + return headersInEvent; + } + set { + headersInEvent = value; + } + } + public bool SplitLate { + get { + return splitLate; + } + set { + splitLate = value; + } + } + + /** + * If true the table will be kept on one page if it fits, by forcing a + * new page if it doesn't fit on the current page. The default is to + * split the table over multiple pages. + * + * @param p_KeepTogether whether to try to keep the table on one page + */ + public bool KeepTogether { + set { + keepTogether = value; + } + get { + return keepTogether; + } + } + + /** + * Completes the current row with the default cell. An incomplete row will be dropped + * but calling this method will make sure that it will be present in the table. + */ + public void CompleteRow() { + while (currentRowIdx > 0) { + AddCell(defaultCell); + } + } + + /** + * @since iText 2.0.8 + * @see com.lowagie.text.LargeElement#flushContent() + */ + public void FlushContent() { + DeleteBodyRows(); + SkipFirstHeader = true; + } + + /** + * @since iText 2.0.8 + * @see com.lowagie.text.LargeElement#isComplete() + */ + public bool ElementComplete { + get { + return complete; + } + set { + complete = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPage.cs b/iTechSharp/iTextSharp/text/pdf/PdfPage.cs new file mode 100644 index 0000000..a32fd29 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPage.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections; + +using iTextSharp.text; + +/* + * $Id: PdfPage.cs,v 1.3 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfPage is the PDF Page-object. + *

    + * A Page object is a dictionary whose keys describe a single page containing text, + * graphics, and images. A Page onjects is a leaf of the Pages tree.
    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 6.4 (page 73-81) + * + * @see PdfPageElement + * @see PdfPages + */ + + public class PdfPage : PdfDictionary { + + // membervariables + private static String[] boxStrings = {"crop", "trim", "art", "bleed"}; + private static PdfName[] boxNames = {PdfName.CROPBOX, PdfName.TRIMBOX, PdfName.ARTBOX, PdfName.BLEEDBOX}; + + /** value of the Rotate key for a page in PORTRAIT */ + public static PdfNumber PORTRAIT = new PdfNumber(0); + + /** value of the Rotate key for a page in LANDSCAPE */ + public static PdfNumber LANDSCAPE = new PdfNumber(90); + + /** value of the Rotate key for a page in INVERTEDPORTRAIT */ + public static PdfNumber INVERTEDPORTRAIT = new PdfNumber(180); + + /** value of the Rotate key for a page in SEASCAPE */ + public static PdfNumber SEASCAPE = new PdfNumber(270); + + /** value of the MediaBox key */ + PdfRectangle mediaBox; + + // constructors + + /** + * Constructs a PdfPage. + * + * @param mediaBox a value for the MediaBox key + * @param resources an indirect reference to a PdfResources-object + * @param rotate a value for the Rotate key + */ + + internal PdfPage(PdfRectangle mediaBox, Hashtable boxSize, PdfDictionary resources, int rotate) : base(PAGE) { + this.mediaBox = mediaBox; + Put(PdfName.MEDIABOX, mediaBox); + Put(PdfName.RESOURCES, resources); + if (rotate != 0) { + Put(PdfName.ROTATE, new PdfNumber(rotate)); + } + for (int k = 0; k < boxStrings.Length; ++k) { + PdfObject rect = (PdfObject)boxSize[boxStrings[k]]; + if (rect != null) + Put(boxNames[k], rect); + } + } + + /** + * Constructs a PdfPage. + * + * @param mediaBox a value for the MediaBox key + * @param resources an indirect reference to a PdfResources-object + */ + + internal PdfPage(PdfRectangle mediaBox, Hashtable boxSize, PdfDictionary resources) : this(mediaBox, boxSize, resources, 0) { + } + + /** + * Checks if this page element is a tree of pages. + *

    + * This method allways returns false. + * + * @return false because this is a single page + */ + + public bool IsParent() { + return false; + } + + // methods + + /** + * Adds an indirect reference pointing to a PdfContents-object. + * + * @param contents an indirect reference to a PdfContents-object + */ + + internal void Add(PdfIndirectReference contents) { + Put(PdfName.CONTENTS, contents); + } + + /** + * Rotates the mediabox, but not the text in it. + * + * @return a PdfRectangle + */ + + internal PdfRectangle RotateMediaBox() { + this.mediaBox = mediaBox.Rotate; + Put(PdfName.MEDIABOX, this.mediaBox); + return this.mediaBox; + } + + /** + * Returns the MediaBox of this Page. + * + * @return a PdfRectangle + */ + + internal PdfRectangle MediaBox { + get { + return mediaBox; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPageEventHelper.cs b/iTechSharp/iTextSharp/text/pdf/PdfPageEventHelper.cs new file mode 100644 index 0000000..28afb85 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPageEventHelper.cs @@ -0,0 +1,202 @@ +using System; + +using iTextSharp.text; + +/* + * $Id: PdfPageEventHelper.cs,v 1.3 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Helps the use of PdfPageEvent by implementing all the interface methods. + * A class can extend PdfPageEventHelper and only implement the + * needed methods. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + + public class PdfPageEventHelper : IPdfPageEvent { + + /** + * Called when the document is opened. + * + * @param writer the PdfWriter for this document + * @param document the document + */ + public virtual void OnOpenDocument(PdfWriter writer,Document document) { + } + + /** + * Called when a page is initialized. + *

    + * Note that if even if a page is not written this method is still + * called. It is preferable to use onEndPage to avoid + * infinite loops. + * + * @param writer the PdfWriter for this document + * @param document the document + */ + public virtual void OnStartPage(PdfWriter writer,Document document) { + } + + /** + * Called when a page is finished, just before being written to the document. + * + * @param writer the PdfWriter for this document + * @param document the document + */ + public virtual void OnEndPage(PdfWriter writer,Document document) { + } + + /** + * Called when the document is closed. + *

    + * Note that this method is called with the page number equal + * to the last page plus one. + * + * @param writer the PdfWriter for this document + * @param document the document + */ + public virtual void OnCloseDocument(PdfWriter writer,Document document) { + } + + /** + * Called when a Paragraph is written. + *

    + * paragraphPosition will hold the height at which the + * paragraph will be written to. This is useful to insert bookmarks with + * more control. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position the paragraph will be written to + */ + public virtual void OnParagraph(PdfWriter writer,Document document,float paragraphPosition) { + } + + /** + * Called when a Paragraph is written. + *

    + * paragraphPosition will hold the height of the end of the paragraph. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position of the end of the paragraph + */ + public virtual void OnParagraphEnd(PdfWriter writer,Document document,float paragraphPosition) { + } + + /** + * Called when a Chapter is written. + *

    + * position will hold the height at which the + * chapter will be written to. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position the chapter will be written to + * @param title the title of the Chapter + */ + public virtual void OnChapter(PdfWriter writer,Document document,float paragraphPosition,Paragraph title) { + } + + /** + * Called when the end of a Chapter is reached. + *

    + * position will hold the height of the end of the chapter. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param position the position of the end of the chapter. + */ + public virtual void OnChapterEnd(PdfWriter writer,Document document,float position) { + } + + /** + * Called when a Section is written. + *

    + * position will hold the height at which the + * section will be written to. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param paragraphPosition the position the chapter will be written to + * @param title the title of the Chapter + */ + public virtual void OnSection(PdfWriter writer,Document document,float paragraphPosition,int depth,Paragraph title) { + } + + /** + * Called when the end of a Section is reached. + *

    + * position will hold the height of the section end. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param position the position of the end of the section + */ + public virtual void OnSectionEnd(PdfWriter writer,Document document,float position) { + } + + /** + * Called when a Chunk with a generic tag is written. + *

    + * It is usefull to pinpoint the Chunk location to generate + * bookmarks, for example. + * + * @param writer the PdfWriter for this document + * @param document the document + * @param rect the Rectangle containing the Chunk + * @param text the text of the tag + */ + public virtual void OnGenericTag(PdfWriter writer,Document document,Rectangle rect,string text) { + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPageLabels.cs b/iTechSharp/iTextSharp/text/pdf/PdfPageLabels.cs new file mode 100644 index 0000000..e8c76b7 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPageLabels.cs @@ -0,0 +1,289 @@ +using System; +using System.Collections; +using System.util; +using iTextSharp.text; +using iTextSharp.text.factories; + +/* + * $Id: PdfPageLabels.cs,v 1.9 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Page labels are used to identify each + * page visually on the screen or in print. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfPageLabels { + + /** Logical pages will have the form 1,2,3,... + */ + public const int DECIMAL_ARABIC_NUMERALS = 0; + /** Logical pages will have the form I,II,III,IV,... + */ + public const int UPPERCASE_ROMAN_NUMERALS = 1; + /** Logical pages will have the form i,ii,iii,iv,... + */ + public const int LOWERCASE_ROMAN_NUMERALS = 2; + /** Logical pages will have the form of uppercase letters + * (A to Z for the first 26 pages, AA to ZZ for the next 26, and so on) + */ + public const int UPPERCASE_LETTERS = 3; + /** Logical pages will have the form of uppercase letters + * (a to z for the first 26 pages, aa to zz for the next 26, and so on) + */ + public const int LOWERCASE_LETTERS = 4; + /** No logical page numbers are generated but fixed text may + * still exist + */ + public const int EMPTY = 5; + /** Dictionary values to set the logical page styles + */ + internal static PdfName[] numberingStyle = {PdfName.D, PdfName.R, + new PdfName("r"), PdfName.A, new PdfName("a")}; + /** The sequence of logical pages. Will contain at least a value for page 1 + */ + internal Hashtable map; + + /** Creates a new PdfPageLabel with a default logical page 1 + */ + public PdfPageLabels() { + map = new Hashtable(); + AddPageLabel(1, DECIMAL_ARABIC_NUMERALS, null, 1); + } + + /** Adds or replaces a page label. + * @param page the real page to start the numbering. First page is 1 + * @param numberStyle the numbering style such as LOWERCASE_ROMAN_NUMERALS + * @param text the text to prefix the number. Can be null or empty + * @param firstPage the first logical page number + */ + public void AddPageLabel(int page, int numberStyle, string text, int firstPage) { + if (page < 1 || firstPage < 1) + throw new ArgumentException("In a page label the page numbers must be greater or equal to 1."); + PdfDictionary dic = new PdfDictionary(); + if (numberStyle >= 0 && numberStyle < numberingStyle.Length) + dic.Put(PdfName.S, numberingStyle[numberStyle]); + if (text != null) + dic.Put(PdfName.P, new PdfString(text, PdfObject.TEXT_UNICODE)); + if (firstPage != 1) + dic.Put(PdfName.ST, new PdfNumber(firstPage)); + map[page - 1] = dic; + } + + /** Adds or replaces a page label. The first logical page has the default + * of 1. + * @param page the real page to start the numbering. First page is 1 + * @param numberStyle the numbering style such as LOWERCASE_ROMAN_NUMERALS + * @param text the text to prefix the number. Can be null or empty + */ + public void AddPageLabel(int page, int numberStyle, string text) { + AddPageLabel(page, numberStyle, text, 1); + } + + /** Adds or replaces a page label. There is no text prefix and the first + * logical page has the default of 1. + * @param page the real page to start the numbering. First page is 1 + * @param numberStyle the numbering style such as LOWERCASE_ROMAN_NUMERALS + */ + public void AddPageLabel(int page, int numberStyle) { + AddPageLabel(page, numberStyle, null, 1); + } + + /** Adds or replaces a page label. + */ + public void AddPageLabel(PdfPageLabelFormat format) { + AddPageLabel(format.physicalPage, format.numberStyle, format.prefix, format.logicalPage); + } + + /** Removes a page label. The first page lagel can not be removed, only changed. + * @param page the real page to remove + */ + public void RemovePageLabel(int page) { + if (page <= 1) + return; + map.Remove(page - 1); + } + + /** Gets the page label dictionary to insert into the document. + * @return the page label dictionary + */ + internal PdfDictionary GetDictionary(PdfWriter writer) { + return PdfNumberTree.WriteTree(map, writer); + } + + /** + * Retrieves the page labels from a PDF as an array of String objects. + * @param reader a PdfReader object that has the page labels you want to retrieve + * @return a String array or null if no page labels are present + */ + public static String[] GetPageLabels(PdfReader reader) { + + int n = reader.NumberOfPages; + + PdfDictionary dict = reader.Catalog; + PdfDictionary labels = (PdfDictionary)PdfReader.GetPdfObjectRelease(dict.Get(PdfName.PAGELABELS)); + if (labels == null) + return null; + + String[] labelstrings = new String[n]; + Hashtable numberTree = PdfNumberTree.ReadTree(labels); + + int pagecount = 1; + String prefix = ""; + char type = 'D'; + for (int i = 0; i < n; i++) { + if (numberTree.ContainsKey(i)) { + PdfDictionary d = (PdfDictionary)PdfReader.GetPdfObjectRelease((PdfObject)numberTree[i]); + if (d.Contains(PdfName.ST)) { + pagecount = ((PdfNumber)d.Get(PdfName.ST)).IntValue; + } + else { + pagecount = 1; + } + if (d.Contains(PdfName.P)) { + prefix = ((PdfString)d.Get(PdfName.P)).ToUnicodeString(); + } + if (d.Contains(PdfName.S)) { + type = ((PdfName)d.Get(PdfName.S)).ToString()[1]; + } + } + switch (type) { + default: + labelstrings[i] = prefix + pagecount; + break; + case 'R': + labelstrings[i] = prefix + RomanNumberFactory.GetUpperCaseString(pagecount); + break; + case 'r': + labelstrings[i] = prefix + RomanNumberFactory.GetLowerCaseString(pagecount); + break; + case 'A': + labelstrings[i] = prefix + RomanAlphabetFactory.GetUpperCaseString(pagecount); + break; + case 'a': + labelstrings[i] = prefix + RomanAlphabetFactory.GetLowerCaseString(pagecount); + break; + } + pagecount++; + } + return labelstrings; + } + + /** + * Retrieves the page labels from a PDF as an array of {@link PdfPageLabelFormat} objects. + * @param reader a PdfReader object that has the page labels you want to retrieve + * @return a PdfPageLabelEntry array, containing an entry for each format change + * or null if no page labels are present + */ + public static PdfPageLabelFormat[] GetPageLabelFormats(PdfReader reader) { + PdfDictionary dict = reader.Catalog; + PdfDictionary labels = (PdfDictionary)PdfReader.GetPdfObjectRelease(dict.Get(PdfName.PAGELABELS)); + if (labels == null) + return null; + Hashtable numberTree = PdfNumberTree.ReadTree(labels); + int[] numbers = new int[numberTree.Count]; + numberTree.Keys.CopyTo(numbers, 0); + Array.Sort(numbers); + PdfPageLabelFormat[] formats = new PdfPageLabelFormat[numberTree.Count]; + String prefix; + int numberStyle; + int pagecount; + for (int k = 0; k < numbers.Length; ++k) { + int key = numbers[k]; + PdfDictionary d = (PdfDictionary)PdfReader.GetPdfObjectRelease((PdfObject)numberTree[key]); + if (d.Contains(PdfName.ST)) { + pagecount = ((PdfNumber)d.Get(PdfName.ST)).IntValue; + } else { + pagecount = 1; + } + if (d.Contains(PdfName.P)) { + prefix = ((PdfString)d.Get(PdfName.P)).ToUnicodeString(); + } else { + prefix = ""; + } + if (d.Contains(PdfName.S)) { + char type = ((PdfName)d.Get(PdfName.S)).ToString()[1]; + switch (type) { + case 'R': numberStyle = UPPERCASE_ROMAN_NUMERALS; break; + case 'r': numberStyle = LOWERCASE_ROMAN_NUMERALS; break; + case 'A': numberStyle = UPPERCASE_LETTERS; break; + case 'a': numberStyle = LOWERCASE_LETTERS; break; + default: numberStyle = DECIMAL_ARABIC_NUMERALS; break; + } + } else { + numberStyle = EMPTY; + } + formats[k] = new PdfPageLabelFormat(key + 1, numberStyle, prefix, pagecount); + } + return formats; + } + + public class PdfPageLabelFormat { + + public int physicalPage; + public int numberStyle; + public String prefix; + public int logicalPage; + + /** Creates a page label format. + * @param physicalPage the real page to start the numbering. First page is 1 + * @param numberStyle the numbering style such as LOWERCASE_ROMAN_NUMERALS + * @param prefix the text to prefix the number. Can be null or empty + * @param logicalPage the first logical page number + */ + public PdfPageLabelFormat(int physicalPage, int numberStyle, String prefix, int logicalPage) { + this.physicalPage = physicalPage; + this.numberStyle = numberStyle; + this.prefix = prefix; + this.logicalPage = logicalPage; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPages.cs b/iTechSharp/iTextSharp/text/pdf/PdfPages.cs new file mode 100644 index 0000000..2634da6 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPages.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections; +using System.IO; +/* + * $Id: PdfPages.cs,v 1.3 2008/05/13 11:25:21 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfPages is the PDF Pages-object. + *

    + * The Pages of a document are accessible through a tree of nodes known as the Pages tree. + * This tree defines the ordering of the pages in the document.
    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 6.3 (page 71-73) + * + * @see PdfPageElement + * @see PdfPage + */ + + public class PdfPages { + + private ArrayList pages = new ArrayList(); + private ArrayList parents = new ArrayList(); + private int leafSize = 10; + private PdfWriter writer; + private PdfIndirectReference topParent; + + // constructors + + /** + * Constructs a PdfPages-object. + */ + + internal PdfPages(PdfWriter writer) { + this.writer = writer; + } + + internal void AddPage(PdfDictionary page) { + if ((pages.Count % leafSize) == 0) + parents.Add(writer.PdfIndirectReference); + PdfIndirectReference parent = (PdfIndirectReference)parents[parents.Count - 1]; + page.Put(PdfName.PARENT, parent); + PdfIndirectReference current = writer.CurrentPage; + writer.AddToBody(page, current); + pages.Add(current); + } + + internal PdfIndirectReference AddPageRef(PdfIndirectReference pageRef) { + if ((pages.Count % leafSize) == 0) + parents.Add(writer.PdfIndirectReference); + pages.Add(pageRef); + return (PdfIndirectReference)parents[parents.Count - 1]; + } + + // returns the top parent to include in the catalog + internal PdfIndirectReference WritePageTree() { + if (pages.Count == 0) + throw new IOException("The document has no pages."); + int leaf = 1; + ArrayList tParents = parents; + ArrayList tPages = pages; + ArrayList nextParents = new ArrayList(); + while (true) { + leaf *= leafSize; + int stdCount = leafSize; + int rightCount = tPages.Count % leafSize; + if (rightCount == 0) + rightCount = leafSize; + for (int p = 0; p < tParents.Count; ++p) { + int count; + int thisLeaf = leaf; + if (p == tParents.Count - 1) { + count = rightCount; + thisLeaf = pages.Count % leaf; + if (thisLeaf == 0) + thisLeaf = leaf; + } + else + count = stdCount; + PdfDictionary top = new PdfDictionary(PdfName.PAGES); + top.Put(PdfName.COUNT, new PdfNumber(thisLeaf)); + PdfArray kids = new PdfArray(); + ArrayList intern = kids.ArrayList; + intern.AddRange(tPages.GetRange(p * stdCount, count)); + top.Put(PdfName.KIDS, kids); + if (tParents.Count > 1) { + if ((p % leafSize) == 0) + nextParents.Add(writer.PdfIndirectReference); + top.Put(PdfName.PARENT, (PdfIndirectReference)nextParents[p / leafSize]); + } + writer.AddToBody(top, (PdfIndirectReference)tParents[p]); + } + if (tParents.Count == 1) { + topParent = (PdfIndirectReference)tParents[0]; + return topParent; + } + tPages = tParents; + tParents = nextParents; + nextParents = new ArrayList(); + } + } + + internal PdfIndirectReference TopParent { + get { + return topParent; + } + } + + internal void SetLinearMode(PdfIndirectReference topParent) { + if (parents.Count > 1) + throw new Exception("Linear page mode can only be called with a single parent."); + if (topParent != null) { + this.topParent = topParent; + parents.Clear(); + parents.Add(topParent); + } + leafSize = 10000000; + } + + internal void AddPage(PdfIndirectReference page) { + pages.Add(page); + } + + internal int ReorderPages(int[] order) { + if (order == null) + return pages.Count; + if (parents.Count > 1) + throw new DocumentException("Page reordering requires a single parent in the page tree. Call PdfWriter.SetLinearMode() after open."); + if (order.Length != pages.Count) + throw new DocumentException("Page reordering requires an array with the same size as the number of pages."); + int max = pages.Count; + bool[] temp = new bool[max]; + for (int k = 0; k < max; ++k) { + int p = order[k]; + if (p < 1 || p > max) + throw new DocumentException("Page reordering requires pages between 1 and " + max + ". Found " + p + "."); + if (temp[p - 1]) + throw new DocumentException("Page reordering requires no page repetition. Page " + p + " is repeated."); + temp[p - 1] = true; + } + Object[] copy = pages.ToArray(); + for (int k = 0; k < max; ++k) { + pages[k] = copy[order[k] - 1]; + } + return max; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPattern.cs b/iTechSharp/iTextSharp/text/pdf/PdfPattern.cs new file mode 100644 index 0000000..1f1917d --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPattern.cs @@ -0,0 +1,79 @@ +using System; +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfPattern defines a ColorSpace + * + * @see PdfStream + */ + + public class PdfPattern : PdfStream { + + internal PdfPattern(PdfPatternPainter painter) : base() { + PdfNumber one = new PdfNumber(1); + PdfArray matrix = painter.Matrix; + if ( matrix != null ) { + Put(PdfName.MATRIX, matrix); + } + Put(PdfName.TYPE, PdfName.PATTERN); + Put(PdfName.BBOX, new PdfRectangle(painter.BoundingBox)); + Put(PdfName.RESOURCES, painter.Resources); + Put(PdfName.TILINGTYPE, one); + Put(PdfName.PATTERNTYPE, one); + if (painter.IsStencil()) + Put(PdfName.PAINTTYPE, new PdfNumber(2)); + else + Put(PdfName.PAINTTYPE, one); + Put(PdfName.XSTEP, new PdfNumber(painter.XStep)); + Put(PdfName.YSTEP, new PdfNumber(painter.YStep)); + bytes = painter.ToPdf(null); + Put(PdfName.LENGTH, new PdfNumber(bytes.Length)); + FlateCompress(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPatternPainter.cs b/iTechSharp/iTextSharp/text/pdf/PdfPatternPainter.cs new file mode 100644 index 0000000..6172575 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPatternPainter.cs @@ -0,0 +1,360 @@ +using System; +using iTextSharp.text; +/* + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Implements the pattern. + */ + + public sealed class PdfPatternPainter : PdfTemplate { + + internal float xstep, ystep; + internal bool stencil = false; + internal Color defaultColor; + + /** + *Creates a PdfPattern. + */ + + private PdfPatternPainter() : base() { + type = TYPE_PATTERN; + } + + /** + * Creates new PdfPattern + * + * @param wr the PdfWriter + */ + + internal PdfPatternPainter(PdfWriter wr) : base(wr) { + type = TYPE_PATTERN; + } + + internal PdfPatternPainter(PdfWriter wr, Color defaultColor) : this(wr) { + stencil = true; + if (defaultColor == null) + this.defaultColor = new Color(System.Drawing.Color.Gray); + else + this.defaultColor = defaultColor; + } + + public float XStep { + get { + return this.xstep; + } + + set { + this.xstep = value; + } + } + + public float YStep { + get { + return this.ystep; + } + + set { + this.ystep = value; + } + } + + public bool IsStencil() { + return stencil; + } + + public void SetPatternMatrix(float a, float b, float c, float d, float e, float f) { + SetMatrix(a, b, c, d, e, f); + } + /** + * Gets the stream representing this pattern + * + * @return the stream representing this pattern + */ + + internal PdfPattern Pattern { + get { + return new PdfPattern(this); + } + } + + /** + * Gets a duplicate of this PdfPatternPainter. All + * the members are copied by reference but the buffer stays different. + * @return a copy of this PdfPatternPainter + */ + + public override PdfContentByte Duplicate { + get { + PdfPatternPainter tpl = new PdfPatternPainter(); + tpl.writer = writer; + tpl.pdf = pdf; + tpl.thisReference = thisReference; + tpl.pageResources = pageResources; + tpl.bBox = new Rectangle(bBox); + tpl.xstep = xstep; + tpl.ystep = ystep; + tpl.matrix = matrix; + tpl.stencil = stencil; + tpl.defaultColor = defaultColor; + return tpl; + } + } + + public Color DefaultColor { + get { + return defaultColor; + } + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setGrayFill(float) + */ + public override void SetGrayFill(float gray) { + CheckNoColor(); + base.SetGrayFill(gray); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#resetGrayFill() + */ + public override void ResetGrayFill() { + CheckNoColor(); + base.ResetGrayFill(); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setGrayStroke(float) + */ + public override void SetGrayStroke(float gray) { + CheckNoColor(); + base.SetGrayStroke(gray); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#resetGrayStroke() + */ + public override void ResetGrayStroke() { + CheckNoColor(); + base.ResetGrayStroke(); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setRGBColorFillF(float, float, float) + */ + public override void SetRGBColorFillF(float red, float green, float blue) { + CheckNoColor(); + base.SetRGBColorFillF(red, green, blue); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#resetRGBColorFill() + */ + public override void ResetRGBColorFill() { + CheckNoColor(); + base.ResetRGBColorFill(); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setRGBColorStrokeF(float, float, float) + */ + public override void SetRGBColorStrokeF(float red, float green, float blue) { + CheckNoColor(); + base.SetRGBColorStrokeF(red, green, blue); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#resetRGBColorStroke() + */ + public override void ResetRGBColorStroke() { + CheckNoColor(); + base.ResetRGBColorStroke(); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setCMYKColorFillF(float, float, float, float) + */ + public override void SetCMYKColorFillF(float cyan, float magenta, float yellow, float black) { + CheckNoColor(); + base.SetCMYKColorFillF(cyan, magenta, yellow, black); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#resetCMYKColorFill() + */ + public override void ResetCMYKColorFill() { + CheckNoColor(); + base.ResetCMYKColorFill(); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setCMYKColorStrokeF(float, float, float, float) + */ + public override void SetCMYKColorStrokeF(float cyan, float magenta, float yellow, float black) { + CheckNoColor(); + base.SetCMYKColorStrokeF(cyan, magenta, yellow, black); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#resetCMYKColorStroke() + */ + public override void ResetCMYKColorStroke() { + CheckNoColor(); + base.ResetCMYKColorStroke(); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#addImage(com.lowagie.text.Image, float, float, float, float, float, float) + */ + public override void AddImage(Image image, float a, float b, float c, float d, float e, float f) { + if (stencil && !image.IsMask()) + CheckNoColor(); + base.AddImage(image, a, b, c, d, e, f); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setCMYKColorFill(int, int, int, int) + */ + public override void SetCMYKColorFill(int cyan, int magenta, int yellow, int black) { + CheckNoColor(); + base.SetCMYKColorFill(cyan, magenta, yellow, black); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setCMYKColorStroke(int, int, int, int) + */ + public override void SetCMYKColorStroke(int cyan, int magenta, int yellow, int black) { + CheckNoColor(); + base.SetCMYKColorStroke(cyan, magenta, yellow, black); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setRGBColorFill(int, int, int) + */ + public override void SetRGBColorFill(int red, int green, int blue) { + CheckNoColor(); + base.SetRGBColorFill(red, green, blue); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setRGBColorStroke(int, int, int) + */ + public override void SetRGBColorStroke(int red, int green, int blue) { + CheckNoColor(); + base.SetRGBColorStroke(red, green, blue); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setColorStroke(java.awt.Color) + */ + public override void SetColorStroke(Color color) { + CheckNoColor(); + base.SetColorStroke(color); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setColorFill(java.awt.Color) + */ + public override void SetColorFill(Color color) { + CheckNoColor(); + base.SetColorFill(color); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setColorFill(com.lowagie.text.pdf.PdfSpotColor, float) + */ + public override void SetColorFill(PdfSpotColor sp, float tint) { + CheckNoColor(); + base.SetColorFill(sp, tint); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setColorStroke(com.lowagie.text.pdf.PdfSpotColor, float) + */ + public override void SetColorStroke(PdfSpotColor sp, float tint) { + CheckNoColor(); + base.SetColorStroke(sp, tint); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setPatternFill(com.lowagie.text.pdf.PdfPatternPainter) + */ + public override void SetPatternFill(PdfPatternPainter p) { + CheckNoColor(); + base.SetPatternFill(p); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setPatternFill(com.lowagie.text.pdf.PdfPatternPainter, java.awt.Color, float) + */ + public override void SetPatternFill(PdfPatternPainter p, Color color, float tint) { + CheckNoColor(); + base.SetPatternFill(p, color, tint); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setPatternStroke(com.lowagie.text.pdf.PdfPatternPainter, java.awt.Color, float) + */ + public override void SetPatternStroke(PdfPatternPainter p, Color color, float tint) { + CheckNoColor(); + base.SetPatternStroke(p, color, tint); + } + + /** + * @see com.lowagie.text.pdf.PdfContentByte#setPatternStroke(com.lowagie.text.pdf.PdfPatternPainter) + */ + public override void SetPatternStroke(PdfPatternPainter p) { + CheckNoColor(); + base.SetPatternStroke(p); + } + + internal void CheckNoColor() { + if (stencil) + throw new ArgumentException("Colors are not allowed in uncolored tile patterns."); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPublicKeyRecipient.cs b/iTechSharp/iTextSharp/text/pdf/PdfPublicKeyRecipient.cs new file mode 100644 index 0000000..5febe94 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPublicKeyRecipient.cs @@ -0,0 +1,41 @@ +using System; +using Org.BouncyCastle.X509; + + +namespace iTextSharp.text.pdf { + + public class PdfPublicKeyRecipient { + + private X509Certificate certificate = null; + + private int permission = 0; + + protected byte[] cms = null; + + public PdfPublicKeyRecipient(X509Certificate certificate, int permission) { + this.certificate = certificate; + this.permission = permission; + } + + public X509Certificate Certificate { + get { + return certificate; + } + } + + public int Permission { + get { + return permission; + } + } + + protected internal byte[] Cms { + set { + cms = value; + } + get { + return cms; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfPublicKeySecurityHandler.cs b/iTechSharp/iTextSharp/text/pdf/PdfPublicKeySecurityHandler.cs new file mode 100644 index 0000000..3cbcb98 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfPublicKeySecurityHandler.cs @@ -0,0 +1,197 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text.pdf.crypto; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Security; + + +/** + * The below 2 methods are from pdfbox. + * + * private DERObject CreateDERForRecipient(byte[] in, X509Certificate cert) ; + * private KeyTransRecipientInfo ComputeRecipientInfo(X509Certificate x509certificate, byte[] abyte0); + * + * 2006-11-22 Aiken Sam. + */ + +/** + * Copyright (c) 2003-2006, www.pdfbox.org + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of pdfbox; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://www.pdfbox.org + * + */ + +namespace iTextSharp.text.pdf { + + /** + * @author Aiken Sam (aikensam@ieee.org) + */ + public class PdfPublicKeySecurityHandler { + + private const int SEED_LENGTH = 20; + + private ArrayList recipients = null; + + private byte[] seed; + + public PdfPublicKeySecurityHandler() { + seed = IVGenerator.GetIV(SEED_LENGTH); + recipients = new ArrayList(); + } + + + public void AddRecipient(PdfPublicKeyRecipient recipient) { + recipients.Add(recipient); + } + + protected internal byte[] GetSeed() { + return (byte[])seed.Clone(); + } + + public int GetRecipientsSize() { + return recipients.Count; + } + + public byte[] GetEncodedRecipient(int index) { + //Certificate certificate = recipient.GetX509(); + PdfPublicKeyRecipient recipient = (PdfPublicKeyRecipient)recipients[index]; + byte[] cms = recipient.Cms; + + if (cms != null) return cms; + + X509Certificate certificate = recipient.Certificate; + int permission = recipient.Permission;//PdfWriter.AllowCopy | PdfWriter.AllowPrinting | PdfWriter.AllowScreenReaders | PdfWriter.AllowAssembly; + int revision = 3; + + permission |= (int)(revision==3 ? (uint)0xfffff0c0 : (uint)0xffffffc0); + permission &= unchecked((int)0xfffffffc); + permission += 1; + + byte[] pkcs7input = new byte[24]; + + byte one = (byte)(permission); + byte two = (byte)(permission >> 8); + byte three = (byte)(permission >> 16); + byte four = (byte)(permission >> 24); + + System.Array.Copy(seed, 0, pkcs7input, 0, 20); // put this seed in the pkcs7 input + + pkcs7input[20] = four; + pkcs7input[21] = three; + pkcs7input[22] = two; + pkcs7input[23] = one; + + Asn1Object obj = CreateDERForRecipient(pkcs7input, certificate); + + MemoryStream baos = new MemoryStream(); + + DerOutputStream k = new DerOutputStream(baos); + + k.WriteObject(obj); + + cms = baos.ToArray(); + + recipient.Cms = cms; + + return cms; + } + + public PdfArray GetEncodedRecipients() { + PdfArray EncodedRecipients = new PdfArray(); + byte[] cms = null; + for (int i=0; i -1, 0 + // type 1 -> offset, 0 + // type 2 -> index, obj num + protected internal int[] xref; + protected internal Hashtable objStmMark; + protected internal IntHashtable objStmToOffset; + protected internal bool newXrefType; + private ArrayList xrefObj; + PdfDictionary rootPages; + protected internal PdfDictionary trailer; + protected internal PdfDictionary catalog; + protected internal PageRefs pageRefs; + protected internal PRAcroForm acroForm = null; + protected internal bool acroFormParsed = false; + protected internal bool encrypted = false; + protected internal bool rebuilt = false; + protected internal int freeXref; + protected internal bool tampered = false; + protected internal int lastXref; + protected internal int eofPos; + protected internal char pdfVersion; + protected internal PdfEncryption decrypt; + protected internal byte[] password = null; //added by ujihara for decryption + protected ICipherParameters certificateKey = null; //added by Aiken Sam for certificate decryption + protected X509Certificate certificate = null; //added by Aiken Sam for certificate decryption + private bool ownerPasswordUsed; + protected internal ArrayList strings = new ArrayList(); + protected internal bool sharedStreams = true; + protected internal bool consolidateNamedDestinations = false; + protected internal int rValue; + protected internal int pValue; + private int objNum; + private int objGen; + private int fileLength; + private bool hybridXref; + private int lastXrefPartial = -1; + private bool partial; + private PRIndirectReference cryptoRef; + private PdfViewerPreferencesImp viewerPreferences = new PdfViewerPreferencesImp(); + private bool encryptionError; + + /** + * Holds value of property appendable. + */ + private bool appendable; + + protected internal PdfReader() { + } + + /** Reads and parses a PDF document. + * @param filename the file name of the document + * @throws IOException on error + */ + public PdfReader(String filename) : this(filename, null) { + } + + /** Reads and parses a PDF document. + * @param filename the file name of the document + * @param ownerPassword the password to read the document + * @throws IOException on error + */ + public PdfReader(String filename, byte[] ownerPassword) { + password = ownerPassword; + tokens = new PRTokeniser(filename); + ReadPdf(); + } + + /** Reads and parses a PDF document. + * @param pdfIn the byte array with the document + * @throws IOException on error + */ + public PdfReader(byte[] pdfIn) : this(pdfIn, null) { + } + + /** Reads and parses a PDF document. + * @param pdfIn the byte array with the document + * @param ownerPassword the password to read the document + * @throws IOException on error + */ + public PdfReader(byte[] pdfIn, byte[] ownerPassword) { + password = ownerPassword; + tokens = new PRTokeniser(pdfIn); + ReadPdf(); + } + + /** Reads and parses a PDF document. + * @param filename the file name of the document + * @param certificate the certificate to read the document + * @param certificateKey the private key of the certificate + * @param certificateKeyProvider the security provider for certificateKey + * @throws IOException on error + */ + public PdfReader(String filename, X509Certificate certificate, ICipherParameters certificateKey) { + this.certificate = certificate; + this.certificateKey = certificateKey; + tokens = new PRTokeniser(filename); + ReadPdf(); + } + + /** Reads and parses a PDF document. + * @param url the Uri of the document + * @throws IOException on error + */ + public PdfReader(Uri url) : this(url, null) { + } + + /** Reads and parses a PDF document. + * @param url the Uri of the document + * @param ownerPassword the password to read the document + * @throws IOException on error + */ + public PdfReader(Uri url, byte[] ownerPassword) { + password = ownerPassword; + tokens = new PRTokeniser(new RandomAccessFileOrArray(url)); + ReadPdf(); + } + + /** + * Reads and parses a PDF document. + * @param is the InputStream containing the document. The stream is read to the + * end but is not closed + * @param ownerPassword the password to read the document + * @throws IOException on error + */ + public PdfReader(Stream isp, byte[] ownerPassword) { + password = ownerPassword; + tokens = new PRTokeniser(new RandomAccessFileOrArray(isp)); + ReadPdf(); + } + + /** + * Reads and parses a PDF document. + * @param isp the InputStream containing the document. The stream is read to the + * end but is not closed + * @throws IOException on error + */ + public PdfReader(Stream isp) : this(isp, null) { + } + + /** + * Reads and parses a pdf document. Contrary to the other constructors only the xref is read + * into memory. The reader is said to be working in "partial" mode as only parts of the pdf + * are read as needed. The pdf is left open but may be closed at any time with + * PdfReader.Close(), reopen is automatic. + * @param raf the document location + * @param ownerPassword the password or null for no password + * @throws IOException on error + */ + public PdfReader(RandomAccessFileOrArray raf, byte[] ownerPassword) { + password = ownerPassword; + partial = true; + tokens = new PRTokeniser(raf); + ReadPdfPartial(); + } + + /** Creates an independent duplicate. + * @param reader the PdfReader to duplicate + */ + public PdfReader(PdfReader reader) { + this.appendable = reader.appendable; + this.consolidateNamedDestinations = reader.consolidateNamedDestinations; + this.encrypted = reader.encrypted; + this.rebuilt = reader.rebuilt; + this.sharedStreams = reader.sharedStreams; + this.tampered = reader.tampered; + this.password = reader.password; + this.pdfVersion = reader.pdfVersion; + this.eofPos = reader.eofPos; + this.freeXref = reader.freeXref; + this.lastXref = reader.lastXref; + this.tokens = new PRTokeniser(reader.tokens.SafeFile); + if (reader.decrypt != null) + this.decrypt = new PdfEncryption(reader.decrypt); + this.pValue = reader.pValue; + this.rValue = reader.rValue; + this.xrefObj = new ArrayList(reader.xrefObj); + for (int k = 0; k < reader.xrefObj.Count; ++k) { + this.xrefObj[k] = DuplicatePdfObject((PdfObject)reader.xrefObj[k], this); + } + this.pageRefs = new PageRefs(reader.pageRefs, this); + this.trailer = (PdfDictionary)DuplicatePdfObject(reader.trailer, this); + this.catalog = (PdfDictionary)GetPdfObject(trailer.Get(PdfName.ROOT)); + this.rootPages = (PdfDictionary)GetPdfObject(catalog.Get(PdfName.PAGES)); + this.fileLength = reader.fileLength; + this.partial = reader.partial; + this.hybridXref = reader.hybridXref; + this.objStmToOffset = reader.objStmToOffset; + this.xref = reader.xref; + this.cryptoRef = (PRIndirectReference)DuplicatePdfObject(reader.cryptoRef, this); + this.ownerPasswordUsed = reader.ownerPasswordUsed; + } + + /** Gets a new file instance of the original PDF + * document. + * @return a new file instance of the original PDF document + */ + public RandomAccessFileOrArray SafeFile { + get { + return tokens.SafeFile; + } + } + + protected internal PdfReaderInstance GetPdfReaderInstance(PdfWriter writer) { + return new PdfReaderInstance(this, writer); + } + + /** Gets the number of pages in the document. + * @return the number of pages in the document + */ + public int NumberOfPages { + get { + return pageRefs.Size; + } + } + + /** Returns the document's catalog. This dictionary is not a copy, + * any changes will be reflected in the catalog. + * @return the document's catalog + */ + public PdfDictionary Catalog { + get { + return catalog; + } + } + + /** Returns the document's acroform, if it has one. + * @return the document's acroform + */ + public PRAcroForm AcroForm { + get { + if (!acroFormParsed) { + acroFormParsed = true; + PdfObject form = catalog.Get(PdfName.ACROFORM); + if (form != null) { + try { + acroForm = new PRAcroForm(this); + acroForm.ReadAcroForm((PdfDictionary)GetPdfObject(form)); + } + catch { + acroForm = null; + } + } + } + return acroForm; + } + } + /** + * Gets the page rotation. This value can be 0, 90, 180 or 270. + * @param index the page number. The first page is 1 + * @return the page rotation + */ + public int GetPageRotation(int index) { + return GetPageRotation(pageRefs.GetPageNRelease(index)); + } + + internal int GetPageRotation(PdfDictionary page) { + PdfNumber rotate = (PdfNumber)GetPdfObject(page.Get(PdfName.ROTATE)); + if (rotate == null) + return 0; + else { + int n = rotate.IntValue; + n %= 360; + return n < 0 ? n + 360 : n; + } + } + /** Gets the page size, taking rotation into account. This + * is a Rectangle with the value of the /MediaBox and the /Rotate key. + * @param index the page number. The first page is 1 + * @return a Rectangle + */ + public Rectangle GetPageSizeWithRotation(int index) { + return GetPageSizeWithRotation(pageRefs.GetPageNRelease(index)); + } + + /** + * Gets the rotated page from a page dictionary. + * @param page the page dictionary + * @return the rotated page + */ + public Rectangle GetPageSizeWithRotation(PdfDictionary page) { + Rectangle rect = GetPageSize(page); + int rotation = GetPageRotation(page); + while (rotation > 0) { + rect = rect.Rotate(); + rotation -= 90; + } + return rect; + } + + /** Gets the page size without taking rotation into account. This + * is the value of the /MediaBox key. + * @param index the page number. The first page is 1 + * @return the page size + */ + public Rectangle GetPageSize(int index) { + return GetPageSize(pageRefs.GetPageNRelease(index)); + } + + /** + * Gets the page from a page dictionary + * @param page the page dictionary + * @return the page + */ + public Rectangle GetPageSize(PdfDictionary page) { + PdfArray mediaBox = (PdfArray)GetPdfObject(page.Get(PdfName.MEDIABOX)); + return GetNormalizedRectangle(mediaBox); + } + + /** Gets the crop box without taking rotation into account. This + * is the value of the /CropBox key. The crop box is the part + * of the document to be displayed or printed. It usually is the same + * as the media box but may be smaller. If the page doesn't have a crop + * box the page size will be returned. + * @param index the page number. The first page is 1 + * @return the crop box + */ + public Rectangle GetCropBox(int index) { + PdfDictionary page = pageRefs.GetPageNRelease(index); + PdfArray cropBox = (PdfArray)GetPdfObjectRelease(page.Get(PdfName.CROPBOX)); + if (cropBox == null) + return GetPageSize(page); + return GetNormalizedRectangle(cropBox); + } + + /** Gets the box size. Allowed names are: "crop", "trim", "art", "bleed" and "media". + * @param index the page number. The first page is 1 + * @param boxName the box name + * @return the box rectangle or null + */ + public Rectangle GetBoxSize(int index, String boxName) { + PdfDictionary page = pageRefs.GetPageNRelease(index); + PdfArray box = null; + if (boxName.Equals("trim")) + box = (PdfArray)GetPdfObjectRelease(page.Get(PdfName.TRIMBOX)); + else if (boxName.Equals("art")) + box = (PdfArray)GetPdfObjectRelease(page.Get(PdfName.ARTBOX)); + else if (boxName.Equals("bleed")) + box = (PdfArray)GetPdfObjectRelease(page.Get(PdfName.BLEEDBOX)); + else if (boxName.Equals("crop")) + box = (PdfArray)GetPdfObjectRelease(page.Get(PdfName.CROPBOX)); + else if (boxName.Equals("media")) + box = (PdfArray)GetPdfObjectRelease(page.Get(PdfName.MEDIABOX)); + if (box == null) + return null; + return GetNormalizedRectangle(box); + } + + /** Returns the content of the document information dictionary as a Hashtable + * of String. + * @return content of the document information dictionary + */ + public Hashtable Info { + get { + Hashtable map = new Hashtable(); + PdfDictionary info = (PdfDictionary)GetPdfObject(trailer.Get(PdfName.INFO)); + if (info == null) + return map; + foreach (PdfName key in info.Keys) { + PdfObject obj = GetPdfObject(info.Get(key)); + if (obj == null) + continue; + String value = obj.ToString(); + switch (obj.Type) { + case PdfObject.STRING: { + value = ((PdfString)obj).ToUnicodeString(); + break; + } + case PdfObject.NAME: { + value = PdfName.DecodeName(value); + break; + } + } + map[PdfName.DecodeName(key.ToString())] = value; + } + return map; + } + } + + /** Normalizes a Rectangle so that llx and lly are smaller than urx and ury. + * @param box the original rectangle + * @return a normalized Rectangle + */ + public static Rectangle GetNormalizedRectangle(PdfArray box) { + ArrayList rect = box.ArrayList; + float llx = ((PdfNumber)GetPdfObjectRelease((PdfObject)rect[0])).FloatValue; + float lly = ((PdfNumber)GetPdfObjectRelease((PdfObject)rect[1])).FloatValue; + float urx = ((PdfNumber)GetPdfObjectRelease((PdfObject)rect[2])).FloatValue; + float ury = ((PdfNumber)GetPdfObjectRelease((PdfObject)rect[3])).FloatValue; + return new Rectangle(Math.Min(llx, urx), Math.Min(lly, ury), + Math.Max(llx, urx), Math.Max(lly, ury)); + } + + protected internal virtual void ReadPdf() { + try { + fileLength = tokens.File.Length; + pdfVersion = tokens.CheckPdfHeader(); + try { + ReadXref(); + } + catch (Exception e) { + try { + rebuilt = true; + RebuildXref(); + lastXref = -1; + } + catch (Exception ne) { + throw new IOException("Rebuild failed: " + ne.Message + "; Original message: " + e.Message); + } + } + try { + ReadDocObj(); + } + catch (Exception ne) { + if (rebuilt || encryptionError) + throw ne; + rebuilt = true; + encrypted = false; + RebuildXref(); + lastXref = -1; + ReadDocObj(); + } + + strings.Clear(); + ReadPages(); + EliminateSharedStreams(); + RemoveUnusedObjects(); + } + finally { + try { + tokens.Close(); + } + catch { + // empty on purpose + } + } + } + + protected internal void ReadPdfPartial() { + try { + fileLength = tokens.File.Length; + pdfVersion = tokens.CheckPdfHeader(); + try { + ReadXref(); + } + catch (Exception e) { + try { + rebuilt = true; + RebuildXref(); + lastXref = -1; + } + catch (Exception ne) { + throw new IOException("Rebuild failed: " + ne.Message + "; Original message: " + e.Message); + } + } + ReadDocObjPartial(); + ReadPages(); + } + catch (IOException e) { + try{tokens.Close();}catch{} + throw e; + } + } + + private bool EqualsArray(byte[] ar1, byte[] ar2, int size) { + for (int k = 0; k < size; ++k) { + if (ar1[k] != ar2[k]) + return false; + } + return true; + } + + /** + * @throws IOException + */ + private void ReadDecryptedDocObj() { + if (encrypted) + return; + PdfObject encDic = trailer.Get(PdfName.ENCRYPT); + if (encDic == null || encDic.ToString().Equals("null")) + return; + encryptionError = true; + byte[] encryptionKey = null; + + encrypted = true; + PdfDictionary enc = (PdfDictionary)GetPdfObject(encDic); + + String s; + PdfObject o; + + PdfArray documentIDs = (PdfArray)GetPdfObject(trailer.Get(PdfName.ID)); + byte[] documentID = null; + if (documentIDs != null) { + o = (PdfObject)documentIDs.ArrayList[0]; + strings.Remove(o); + s = o.ToString(); + documentID = DocWriter.GetISOBytes(s); + if (documentIDs.Size > 1) + strings.Remove(documentIDs.ArrayList[1]); + } + // just in case we have a broken producer + if (documentID == null) + documentID = new byte[0]; + + byte[] uValue = null; + byte[] oValue = null; + int cryptoMode = PdfWriter.STANDARD_ENCRYPTION_40; + int lengthValue = 0; + + PdfObject filter = GetPdfObjectRelease(enc.Get(PdfName.FILTER)); + + if (filter.Equals(PdfName.STANDARD)) { + s = enc.Get(PdfName.U).ToString(); + strings.Remove(enc.Get(PdfName.U)); + uValue = DocWriter.GetISOBytes(s); + s = enc.Get(PdfName.O).ToString(); + strings.Remove(enc.Get(PdfName.O)); + oValue = DocWriter.GetISOBytes(s); + + o = enc.Get(PdfName.R); + if (!o.IsNumber()) throw new IOException("Illegal R value."); + rValue = ((PdfNumber)o).IntValue; + if (rValue != 2 && rValue != 3 && rValue != 4) throw new IOException("Unknown encryption type (" + rValue + ")"); + + o = enc.Get(PdfName.P); + if (!o.IsNumber()) throw new IOException("Illegal P value."); + pValue = ((PdfNumber)o).IntValue; + + if ( rValue == 3 ){ + o = enc.Get(PdfName.LENGTH); + if (!o.IsNumber()) + throw new IOException("Illegal Length value."); + lengthValue = ((PdfNumber)o).IntValue; + if (lengthValue > 128 || lengthValue < 40 || lengthValue % 8 != 0) + throw new IOException("Illegal Length value."); + cryptoMode = PdfWriter.STANDARD_ENCRYPTION_128; + } + else if (rValue == 4) { + lengthValue = 128; + PdfDictionary dic = (PdfDictionary)enc.Get(PdfName.CF); + if (dic == null) + throw new IOException("/CF not found (encryption)"); + dic = (PdfDictionary)dic.Get(PdfName.STDCF); + if (dic == null) + throw new IOException("/StdCF not found (encryption)"); + if (PdfName.V2.Equals(dic.Get(PdfName.CFM))) + cryptoMode = PdfWriter.STANDARD_ENCRYPTION_128; + else if (PdfName.AESV2.Equals(dic.Get(PdfName.CFM))) + cryptoMode = PdfWriter.ENCRYPTION_AES_128; + else + throw new IOException("No compatible encryption found"); + PdfObject em = enc.Get(PdfName.ENCRYPTMETADATA); + if (em != null && em.ToString().Equals("false")) + cryptoMode |= PdfWriter.DO_NOT_ENCRYPT_METADATA; + } else { + cryptoMode = PdfWriter.STANDARD_ENCRYPTION_40; + } + } else if (filter.Equals(PdfName.PUBSEC)) { + bool foundRecipient = false; + byte[] envelopedData = null; + PdfArray recipients = null; + + o = enc.Get(PdfName.V); + if (!o.IsNumber()) throw new IOException("Illegal V value."); + int vValue = ((PdfNumber)o).IntValue; + if (vValue != 1 && vValue != 2 && vValue != 4) + throw new IOException("Unknown encryption type V = " + rValue); + + if ( vValue == 2 ){ + o = enc.Get(PdfName.LENGTH); + if (!o.IsNumber()) + throw new IOException("Illegal Length value."); + lengthValue = ((PdfNumber)o).IntValue; + if (lengthValue > 128 || lengthValue < 40 || lengthValue % 8 != 0) + throw new IOException("Illegal Length value."); + cryptoMode = PdfWriter.STANDARD_ENCRYPTION_128; + recipients = (PdfArray)enc.Get(PdfName.RECIPIENTS); + } else if (vValue == 4) { + PdfDictionary dic = (PdfDictionary)enc.Get(PdfName.CF); + if (dic == null) + throw new IOException("/CF not found (encryption)"); + dic = (PdfDictionary)dic.Get(PdfName.DEFAULTCRYPTFILER); + if (dic == null) + throw new IOException("/DefaultCryptFilter not found (encryption)"); + if (PdfName.V2.Equals(dic.Get(PdfName.CFM))) + { + cryptoMode = PdfWriter.STANDARD_ENCRYPTION_128; + lengthValue = 128; + } + else if (PdfName.AESV2.Equals(dic.Get(PdfName.CFM))) + { + cryptoMode = PdfWriter.ENCRYPTION_AES_128; + lengthValue = 128; + } + else + throw new IOException("No compatible encryption found"); + PdfObject em = dic.Get(PdfName.ENCRYPTMETADATA); + if (em != null && em.ToString().Equals("false")) + cryptoMode |= PdfWriter.DO_NOT_ENCRYPT_METADATA; + + recipients = (PdfArray)dic.Get(PdfName.RECIPIENTS); + } else { + cryptoMode = PdfWriter.STANDARD_ENCRYPTION_40; + lengthValue = 40; + recipients = (PdfArray)enc.Get(PdfName.RECIPIENTS); + } + + for (int i = 0; iPdfObject resolving an indirect reference + * if needed. + * @param obj the PdfObject to read + * @return the resolved PdfObject + */ + public static PdfObject GetPdfObject(PdfObject obj) { + if (obj == null) + return null; + if (!obj.IsIndirect()) + return obj; + PRIndirectReference refi = (PRIndirectReference)obj; + int idx = refi.Number; + bool appendable = refi.Reader.appendable; + obj = refi.Reader.GetPdfObject(idx); + if (obj == null) { + return null; + } + else { + if (appendable) { + switch (obj.Type) { + case PdfObject.NULL: + obj = new PdfNull(); + break; + case PdfObject.BOOLEAN: + obj = new PdfBoolean(((PdfBoolean)obj).BooleanValue); + break; + case PdfObject.NAME: + obj = new PdfName(obj.GetBytes()); + break; + } + obj.IndRef = refi; + } + return obj; + } + } + + /** + * Reads a PdfObject resolving an indirect reference + * if needed. If the reader was opened in partial mode the object will be released + * to save memory. + * @param obj the PdfObject to read + * @param parent + * @return a PdfObject + */ + public static PdfObject GetPdfObjectRelease(PdfObject obj, PdfObject parent) { + PdfObject obj2 = GetPdfObject(obj, parent); + ReleaseLastXrefPartial(obj); + return obj2; + } + + /** + * @param obj + * @param parent + * @return a PdfObject + */ + public static PdfObject GetPdfObject(PdfObject obj, PdfObject parent) { + if (obj == null) + return null; + if (!obj.IsIndirect()) { + PRIndirectReference refi = null; + if (parent != null && (refi = parent.IndRef) != null && refi.Reader.Appendable) { + switch (obj.Type) { + case PdfObject.NULL: + obj = new PdfNull(); + break; + case PdfObject.BOOLEAN: + obj = new PdfBoolean(((PdfBoolean)obj).BooleanValue); + break; + case PdfObject.NAME: + obj = new PdfName(obj.GetBytes()); + break; + } + obj.IndRef = refi; + } + return obj; + } + return GetPdfObject(obj); + } + + /** + * @param idx + * @return a PdfObject + */ + public PdfObject GetPdfObjectRelease(int idx) { + PdfObject obj = GetPdfObject(idx); + ReleaseLastXrefPartial(); + return obj; + } + + /** + * @param idx + * @return aPdfObject + */ + public PdfObject GetPdfObject(int idx) { + lastXrefPartial = -1; + if (idx < 0 || idx >= xrefObj.Count) + return null; + PdfObject obj = (PdfObject)xrefObj[idx]; + if (!partial || obj != null) + return obj; + if (idx * 2 >= xref.Length) + return null; + obj = ReadSingleObject(idx); + lastXrefPartial = -1; + if (obj != null) + lastXrefPartial = idx; + return obj; + } + + /** + * + */ + public void ResetLastXrefPartial() { + lastXrefPartial = -1; + } + + /** + * + */ + public void ReleaseLastXrefPartial() { + if (partial && lastXrefPartial != -1) { + xrefObj[lastXrefPartial] = null; + lastXrefPartial = -1; + } + } + + /** + * @param obj + */ + public static void ReleaseLastXrefPartial(PdfObject obj) { + if (obj == null) + return; + if (!obj.IsIndirect()) + return; + PRIndirectReference refi = (PRIndirectReference)obj; + PdfReader reader = refi.Reader; + if (reader.partial && reader.lastXrefPartial != -1 && reader.lastXrefPartial == refi.Number) { + reader.xrefObj[reader.lastXrefPartial] = null; + } + reader.lastXrefPartial = -1; + } + + private void SetXrefPartialObject(int idx, PdfObject obj) { + if (!partial || idx < 0) + return; + xrefObj[idx] = obj; + } + + /** + * @param obj + * @return an indirect reference + */ + public PRIndirectReference AddPdfObject(PdfObject obj) { + xrefObj.Add(obj); + return new PRIndirectReference(this, xrefObj.Count - 1); + } + + protected internal void ReadPages() { + catalog = (PdfDictionary)GetPdfObject(trailer.Get(PdfName.ROOT)); + rootPages = (PdfDictionary)GetPdfObject(catalog.Get(PdfName.PAGES)); + pageRefs = new PageRefs(this); + } + + protected internal void ReadDocObjPartial() { + xrefObj = ArrayList.Repeat(null, xref.Length / 2); + ReadDecryptedDocObj(); + if (objStmToOffset != null) { + int[] keys = objStmToOffset.GetKeys(); + for (int k = 0; k < keys.Length; ++k) { + int n = keys[k]; + objStmToOffset[n] = xref[n * 2]; + xref[n * 2] = -1; + } + } + } + + protected internal PdfObject ReadSingleObject(int k) { + strings.Clear(); + int k2 = k * 2; + int pos = xref[k2]; + if (pos < 0) + return null; + if (xref[k2 + 1] > 0) + pos = objStmToOffset[xref[k2 + 1]]; + if (pos == 0) + return null; + tokens.Seek(pos); + tokens.NextValidToken(); + if (tokens.TokenType != PRTokeniser.TK_NUMBER) + tokens.ThrowError("Invalid object number."); + objNum = tokens.IntValue; + tokens.NextValidToken(); + if (tokens.TokenType != PRTokeniser.TK_NUMBER) + tokens.ThrowError("Invalid generation number."); + objGen = tokens.IntValue; + tokens.NextValidToken(); + if (!tokens.StringValue.Equals("obj")) + tokens.ThrowError("Token 'obj' expected."); + PdfObject obj; + try { + obj = ReadPRObject(); + for (int j = 0; j < strings.Count; ++j) { + PdfString str = (PdfString)strings[j]; + str.Decrypt(this); + } + if (obj.IsStream()) { + CheckPRStreamLength((PRStream)obj); + } + } + catch { + obj = null; + } + if (xref[k2 + 1] > 0) { + obj = ReadOneObjStm((PRStream)obj, xref[k2]); + } + xrefObj[k] = obj; + return obj; + } + + protected internal PdfObject ReadOneObjStm(PRStream stream, int idx) { + int first = ((PdfNumber)GetPdfObject(stream.Get(PdfName.FIRST))).IntValue; + byte[] b = GetStreamBytes(stream, tokens.File); + PRTokeniser saveTokens = tokens; + tokens = new PRTokeniser(b); + try { + int address = 0; + bool ok = true; + ++idx; + for (int k = 0; k < idx; ++k) { + ok = tokens.NextToken(); + if (!ok) + break; + if (tokens.TokenType != PRTokeniser.TK_NUMBER) { + ok = false; + break; + } + ok = tokens.NextToken(); + if (!ok) + break; + if (tokens.TokenType != PRTokeniser.TK_NUMBER) { + ok = false; + break; + } + address = tokens.IntValue + first; + } + if (!ok) + throw new IOException("Error reading ObjStm"); + tokens.Seek(address); + return ReadPRObject(); + } + finally { + tokens = saveTokens; + } + } + + /** + * @return the percentage of the cross reference table that has been read + */ + public double DumpPerc() { + int total = 0; + for (int k = 0; k < xrefObj.Count; ++k) { + if (xrefObj[k] != null) + ++total; + } + return (total * 100.0 / xrefObj.Count); + } + + protected internal void ReadDocObj() { + ArrayList streams = new ArrayList(); + xrefObj = ArrayList.Repeat(null, xref.Length / 2); + for (int k = 2; k < xref.Length; k += 2) { + int pos = xref[k]; + if (pos <= 0 || xref[k + 1] > 0) + continue; + tokens.Seek(pos); + tokens.NextValidToken(); + if (tokens.TokenType != PRTokeniser.TK_NUMBER) + tokens.ThrowError("Invalid object number."); + objNum = tokens.IntValue; + tokens.NextValidToken(); + if (tokens.TokenType != PRTokeniser.TK_NUMBER) + tokens.ThrowError("Invalid generation number."); + objGen = tokens.IntValue; + tokens.NextValidToken(); + if (!tokens.StringValue.Equals("obj")) + tokens.ThrowError("Token 'obj' expected."); + PdfObject obj; + try { + obj = ReadPRObject(); + if (obj.IsStream()) { + streams.Add(obj); + } + } + catch { + obj = null; + } + xrefObj[k / 2] = obj; + } + for (int k = 0; k < streams.Count; ++k) { + CheckPRStreamLength((PRStream)streams[k]); + } + ReadDecryptedDocObj(); + if (objStmMark != null) { + foreach (DictionaryEntry entry in objStmMark) { + int n = (int)entry.Key; + IntHashtable h = (IntHashtable)entry.Value; + ReadObjStm((PRStream)xrefObj[n], h); + xrefObj[n] = null; + } + objStmMark = null; + } + xref = null; + } + + private void CheckPRStreamLength(PRStream stream) { + int fileLength = tokens.Length; + int start = stream.Offset; + bool calc = false; + int streamLength = 0; + PdfObject obj = GetPdfObjectRelease(stream.Get(PdfName.LENGTH)); + if (obj != null && obj.Type == PdfObject.NUMBER) { + streamLength = ((PdfNumber)obj).IntValue; + if (streamLength + start > fileLength - 20) + calc = true; + else { + tokens.Seek(start + streamLength); + String line = tokens.ReadString(20); + if (!line.StartsWith("\nendstream") && + !line.StartsWith("\r\nendstream") && + !line.StartsWith("\rendstream") && + !line.StartsWith("endstream")) + calc = true; + } + } + else + calc = true; + if (calc) { + byte[] tline = new byte[16]; + tokens.Seek(start); + while (true) { + int pos = tokens.FilePointer; + if (!tokens.ReadLineSegment(tline)) + break; + if (Equalsn(tline, endstream)) { + streamLength = pos - start; + break; + } + if (Equalsn(tline, endobj)) { + tokens.Seek(pos - 16); + String s = tokens.ReadString(16); + int index = s.IndexOf("endstream"); + if (index >= 0) + pos = pos - 16 + index; + streamLength = pos - start; + break; + } + } + } + stream.Length = streamLength; + } + + protected internal void ReadObjStm(PRStream stream, IntHashtable map) { + int first = ((PdfNumber)GetPdfObject(stream.Get(PdfName.FIRST))).IntValue; + int n = ((PdfNumber)GetPdfObject(stream.Get(PdfName.N))).IntValue; + byte[] b = GetStreamBytes(stream, tokens.File); + PRTokeniser saveTokens = tokens; + tokens = new PRTokeniser(b); + try { + int[] address = new int[n]; + int[] objNumber = new int[n]; + bool ok = true; + for (int k = 0; k < n; ++k) { + ok = tokens.NextToken(); + if (!ok) + break; + if (tokens.TokenType != PRTokeniser.TK_NUMBER) { + ok = false; + break; + } + objNumber[k] = tokens.IntValue; + ok = tokens.NextToken(); + if (!ok) + break; + if (tokens.TokenType != PRTokeniser.TK_NUMBER) { + ok = false; + break; + } + address[k] = tokens.IntValue + first; + } + if (!ok) + throw new IOException("Error reading ObjStm"); + for (int k = 0; k < n; ++k) { + if (map.ContainsKey(k)) { + tokens.Seek(address[k]); + PdfObject obj = ReadPRObject(); + xrefObj[objNumber[k]] = obj; + } + } + } + finally { + tokens = saveTokens; + } + } + + /** + * Eliminates the reference to the object freeing the memory used by it and clearing + * the xref entry. + * @param obj the object. If it's an indirect reference it will be eliminated + * @return the object or the already erased dereferenced object + */ + public static PdfObject KillIndirect(PdfObject obj) { + if (obj == null || obj.IsNull()) + return null; + PdfObject ret = GetPdfObjectRelease(obj); + if (obj.IsIndirect()) { + PRIndirectReference refi = (PRIndirectReference)obj; + PdfReader reader = refi.Reader; + int n = refi.Number; + reader.xrefObj[n] = null; + if (reader.partial) + reader.xref[n * 2] = -1; + } + return ret; + } + + private void EnsureXrefSize(int size) { + if (size == 0) + return; + if (xref == null) + xref = new int[size]; + else { + if (xref.Length < size) { + int[] xref2 = new int[size]; + Array.Copy(xref, 0, xref2, 0, xref.Length); + xref = xref2; + } + } + } + + protected internal void ReadXref() { + hybridXref = false; + newXrefType = false; + tokens.Seek(tokens.Startxref); + tokens.NextToken(); + if (!tokens.StringValue.Equals("startxref")) + throw new IOException("startxref not found."); + tokens.NextToken(); + if (tokens.TokenType != PRTokeniser.TK_NUMBER) + throw new IOException("startxref is not followed by a number."); + int startxref = tokens.IntValue; + lastXref = startxref; + eofPos = tokens.FilePointer; + try { + if (ReadXRefStream(startxref)) { + newXrefType = true; + return; + } + } + catch {} + xref = null; + tokens.Seek(startxref); + trailer = ReadXrefSection(); + PdfDictionary trailer2 = trailer; + while (true) { + PdfNumber prev = (PdfNumber)trailer2.Get(PdfName.PREV); + if (prev == null) + break; + tokens.Seek(prev.IntValue); + trailer2 = ReadXrefSection(); + } + } + + protected internal PdfDictionary ReadXrefSection() { + tokens.NextValidToken(); + if (!tokens.StringValue.Equals("xref")) + tokens.ThrowError("xref subsection not found"); + int start = 0; + int end = 0; + int pos = 0; + int gen = 0; + while (true) { + tokens.NextValidToken(); + if (tokens.StringValue.Equals("trailer")) + break; + if (tokens.TokenType != PRTokeniser.TK_NUMBER) + tokens.ThrowError("Object number of the first object in this xref subsection not found"); + start = tokens.IntValue; + tokens.NextValidToken(); + if (tokens.TokenType != PRTokeniser.TK_NUMBER) + tokens.ThrowError("Number of entries in this xref subsection not found"); + end = tokens.IntValue + start; + if (start == 1) { // fix incorrect start number + int back = tokens.FilePointer; + tokens.NextValidToken(); + pos = tokens.IntValue; + tokens.NextValidToken(); + gen = tokens.IntValue; + if (pos == 0 && gen == 65535) { + --start; + --end; + } + tokens.Seek(back); + } + EnsureXrefSize(end * 2); + for (int k = start; k < end; ++k) { + tokens.NextValidToken(); + pos = tokens.IntValue; + tokens.NextValidToken(); + gen = tokens.IntValue; + tokens.NextValidToken(); + int p = k * 2; + if (tokens.StringValue.Equals("n")) { + if (xref[p] == 0 && xref[p + 1] == 0) { + // if (pos == 0) + // tokens.ThrowError("File position 0 cross-reference entry in this xref subsection"); + xref[p] = pos; + } + } + else if (tokens.StringValue.Equals("f")) { + if (xref[p] == 0 && xref[p + 1] == 0) + xref[p] = -1; + } + else + tokens.ThrowError("Invalid cross-reference entry in this xref subsection"); + } + } + PdfDictionary trailer = (PdfDictionary)ReadPRObject(); + PdfNumber xrefSize = (PdfNumber)trailer.Get(PdfName.SIZE); + EnsureXrefSize(xrefSize.IntValue * 2); + PdfObject xrs = trailer.Get(PdfName.XREFSTM); + if (xrs != null && xrs.IsNumber()) { + int loc = ((PdfNumber)xrs).IntValue; + try { + ReadXRefStream(loc); + newXrefType = true; + hybridXref = true; + } + catch (IOException e) { + xref = null; + throw e; + } + } + return trailer; + } + + protected internal bool ReadXRefStream(int ptr) { + tokens.Seek(ptr); + int thisStream = 0; + if (!tokens.NextToken()) + return false; + if (tokens.TokenType != PRTokeniser.TK_NUMBER) + return false; + thisStream = tokens.IntValue; + if (!tokens.NextToken() || tokens.TokenType != PRTokeniser.TK_NUMBER) + return false; + if (!tokens.NextToken() || !tokens.StringValue.Equals("obj")) + return false; + PdfObject objecto = ReadPRObject(); + PRStream stm = null; + if (objecto.IsStream()) { + stm = (PRStream)objecto; + if (!PdfName.XREF.Equals(stm.Get(PdfName.TYPE))) + return false; + } + else + return false; + if (trailer == null) { + trailer = new PdfDictionary(); + trailer.Merge(stm); + } + stm.Length = ((PdfNumber)stm.Get(PdfName.LENGTH)).IntValue; + int size = ((PdfNumber)stm.Get(PdfName.SIZE)).IntValue; + PdfArray index; + PdfObject obj = stm.Get(PdfName.INDEX); + if (obj == null) { + index = new PdfArray(); + index.Add(new int[]{0, size}); + } + else + index = (PdfArray)obj; + PdfArray w = (PdfArray)stm.Get(PdfName.W); + int prev = -1; + obj = stm.Get(PdfName.PREV); + if (obj != null) + prev = ((PdfNumber)obj).IntValue; + // Each xref pair is a position + // type 0 -> -1, 0 + // type 1 -> offset, 0 + // type 2 -> index, obj num + EnsureXrefSize(size * 2); + if (objStmMark == null && !partial) + objStmMark = new Hashtable(); + if (objStmToOffset == null && partial) + objStmToOffset = new IntHashtable(); + byte[] b = GetStreamBytes(stm, tokens.File); + int bptr = 0; + ArrayList wa = w.ArrayList; + int[] wc = new int[3]; + for (int k = 0; k < 3; ++k) + wc[k] = ((PdfNumber)wa[k]).IntValue; + ArrayList sections = index.ArrayList; + for (int idx = 0; idx < sections.Count; idx += 2) { + int start = ((PdfNumber)sections[idx]).IntValue; + int length = ((PdfNumber)sections[idx + 1]).IntValue; + EnsureXrefSize((start + length) * 2); + while (length-- > 0) { + int type = 1; + if (wc[0] > 0) { + type = 0; + for (int k = 0; k < wc[0]; ++k) + type = (type << 8) + (b[bptr++] & 0xff); + } + int field2 = 0; + for (int k = 0; k < wc[1]; ++k) + field2 = (field2 << 8) + (b[bptr++] & 0xff); + int field3 = 0; + for (int k = 0; k < wc[2]; ++k) + field3 = (field3 << 8) + (b[bptr++] & 0xff); + int baseb = start * 2; + if (xref[baseb] == 0 && xref[baseb + 1] == 0) { + switch (type) { + case 0: + xref[baseb] = -1; + break; + case 1: + xref[baseb] = field2; + break; + case 2: + xref[baseb] = field3; + xref[baseb + 1] = field2; + if (partial) { + objStmToOffset[field2] = 0; + } + else { + IntHashtable seq = (IntHashtable)objStmMark[field2]; + if (seq == null) { + seq = new IntHashtable(); + seq[field3] = 1; + objStmMark[field2] = seq; + } + else + seq[field3] = 1; + } + break; + } + } + ++start; + } + } + thisStream *= 2; + if (thisStream < xref.Length) + xref[thisStream] = -1; + + if (prev == -1) + return true; + return ReadXRefStream(prev); + } + + protected internal void RebuildXref() { + hybridXref = false; + newXrefType = false; + tokens.Seek(0); + int[][] xr = new int[1024][]; + int top = 0; + trailer = null; + byte[] line = new byte[64]; + for (;;) { + int pos = tokens.FilePointer; + if (!tokens.ReadLineSegment(line)) + break; + if (line[0] == 't') { + if (!PdfEncodings.ConvertToString(line, null).StartsWith("trailer")) + continue; + tokens.Seek(pos); + tokens.NextToken(); + pos = tokens.FilePointer; + try { + PdfDictionary dic = (PdfDictionary)ReadPRObject(); + if (dic.Get(PdfName.ROOT) != null) + trailer = dic; + else + tokens.Seek(pos); + } + catch { + tokens.Seek(pos); + } + } + else if (line[0] >= '0' && line[0] <= '9') { + int[] obj = PRTokeniser.CheckObjectStart(line); + if (obj == null) + continue; + int num = obj[0]; + int gen = obj[1]; + if (num >= xr.Length) { + int newLength = num * 2; + int[][] xr2 = new int[newLength][]; + Array.Copy(xr, 0, xr2, 0, top); + xr = xr2; + } + if (num >= top) + top = num + 1; + if (xr[num] == null || gen >= xr[num][1]) { + obj[0] = pos; + xr[num] = obj; + } + } + } + if (trailer == null) + throw new IOException("trailer not found."); + xref = new int[top * 2]; + for (int k = 0; k < top; ++k) { + int[] obj = xr[k]; + if (obj != null) + xref[k * 2] = obj[0]; + } + } + + protected internal PdfDictionary ReadDictionary() { + PdfDictionary dic = new PdfDictionary(); + while (true) { + tokens.NextValidToken(); + if (tokens.TokenType == PRTokeniser.TK_END_DIC) + break; + if (tokens.TokenType != PRTokeniser.TK_NAME) + tokens.ThrowError("Dictionary key is not a name."); + PdfName name = new PdfName(tokens.StringValue, false); + PdfObject obj = ReadPRObject(); + int type = obj.Type; + if (-type == PRTokeniser.TK_END_DIC) + tokens.ThrowError("Unexpected '>>'"); + if (-type == PRTokeniser.TK_END_ARRAY) + tokens.ThrowError("Unexpected ']'"); + dic.Put(name, obj); + } + return dic; + } + + protected internal PdfArray ReadArray() { + PdfArray array = new PdfArray(); + while (true) { + PdfObject obj = ReadPRObject(); + int type = obj.Type; + if (-type == PRTokeniser.TK_END_ARRAY) + break; + if (-type == PRTokeniser.TK_END_DIC) + tokens.ThrowError("Unexpected '>>'"); + array.Add(obj); + } + return array; + } + + protected internal PdfObject ReadPRObject() { + tokens.NextValidToken(); + int type = tokens.TokenType; + switch (type) { + case PRTokeniser.TK_START_DIC: { + PdfDictionary dic = ReadDictionary(); + int pos = tokens.FilePointer; + // be careful in the trailer. May not be a "next" token. + if (tokens.NextToken() && tokens.StringValue.Equals("stream")) { + int ch = tokens.Read(); + if (ch != '\n') + ch = tokens.Read(); + if (ch != '\n') + tokens.BackOnePosition(ch); + PRStream stream = new PRStream(this, tokens.FilePointer); + stream.Merge(dic); + stream.ObjNum = objNum; + stream.ObjGen = objGen; + return stream; + } + else { + tokens.Seek(pos); + return dic; + } + } + case PRTokeniser.TK_START_ARRAY: + return ReadArray(); + case PRTokeniser.TK_NUMBER: + return new PdfNumber(tokens.StringValue); + case PRTokeniser.TK_STRING: + PdfString str = new PdfString(tokens.StringValue, null).SetHexWriting(tokens.IsHexString()); + str.SetObjNum(objNum, objGen); + if (strings != null) + strings.Add(str); + return str; + case PRTokeniser.TK_NAME: + return new PdfName(tokens.StringValue, false); + case PRTokeniser.TK_REF: + int num = tokens.Reference; + PRIndirectReference refi = new PRIndirectReference(this, num, tokens.Generation); + return refi; + default: + String sv = tokens.StringValue; + if ("null".Equals(sv)) + return PdfNull.PDFNULL; + else if ("true".Equals(sv)) + return PdfBoolean.PDFTRUE; + else if ("false".Equals(sv)) + return PdfBoolean.PDFFALSE; + return new PdfLiteral(-type, tokens.StringValue); + } + } + + /** Decodes a stream that has the FlateDecode filter. + * @param in the input data + * @return the decoded data + */ + public static byte[] FlateDecode(byte[] inp) { + byte[] b = FlateDecode(inp, true); + if (b == null) + return FlateDecode(inp, false); + return b; + } + + /** + * @param in + * @param dicPar + * @return a byte array + */ + public static byte[] DecodePredictor(byte[] inp, PdfObject dicPar) { + if (dicPar == null || !dicPar.IsDictionary()) + return inp; + PdfDictionary dic = (PdfDictionary)dicPar; + PdfObject obj = GetPdfObject(dic.Get(PdfName.PREDICTOR)); + if (obj == null || !obj.IsNumber()) + return inp; + int predictor = ((PdfNumber)obj).IntValue; + if (predictor < 10) + return inp; + int width = 1; + obj = GetPdfObject(dic.Get(PdfName.COLUMNS)); + if (obj != null && obj.IsNumber()) + width = ((PdfNumber)obj).IntValue; + int colors = 1; + obj = GetPdfObject(dic.Get(PdfName.COLORS)); + if (obj != null && obj.IsNumber()) + colors = ((PdfNumber)obj).IntValue; + int bpc = 8; + obj = GetPdfObject(dic.Get(PdfName.BITSPERCOMPONENT)); + if (obj != null && obj.IsNumber()) + bpc = ((PdfNumber)obj).IntValue; + MemoryStream dataStream = new MemoryStream(inp); + MemoryStream fout = new MemoryStream(inp.Length); + int bytesPerPixel = colors * bpc / 8; + int bytesPerRow = (colors*width*bpc + 7)/8; + byte[] curr = new byte[bytesPerRow]; + byte[] prior = new byte[bytesPerRow]; + + // Decode the (sub)image row-by-row + while (true) { + // Read the filter type byte and a row of data + int filter = 0; + try { + filter = dataStream.ReadByte(); + if (filter < 0) { + return fout.ToArray(); + } + int tot = 0; + while (tot < bytesPerRow) { + int n = dataStream.Read(curr, tot, bytesPerRow - tot); + if (n <= 0) + return fout.ToArray(); + tot += n; + } + } catch { + return fout.ToArray(); + } + + switch (filter) { + case 0: //PNG_FILTER_NONE + break; + case 1: //PNG_FILTER_SUB + for (int i = bytesPerPixel; i < bytesPerRow; i++) { + curr[i] += curr[i - bytesPerPixel]; + } + break; + case 2: //PNG_FILTER_UP + for (int i = 0; i < bytesPerRow; i++) { + curr[i] += prior[i]; + } + break; + case 3: //PNG_FILTER_AVERAGE + for (int i = 0; i < bytesPerPixel; i++) { + curr[i] += (byte)(prior[i] / 2); + } + for (int i = bytesPerPixel; i < bytesPerRow; i++) { + curr[i] += (byte)(((curr[i - bytesPerPixel] & 0xff) + (prior[i] & 0xff))/2); + } + break; + case 4: //PNG_FILTER_PAETH + for (int i = 0; i < bytesPerPixel; i++) { + curr[i] += prior[i]; + } + + for (int i = bytesPerPixel; i < bytesPerRow; i++) { + int a = curr[i - bytesPerPixel] & 0xff; + int b = prior[i] & 0xff; + int c = prior[i - bytesPerPixel] & 0xff; + + int p = a + b - c; + int pa = Math.Abs(p - a); + int pb = Math.Abs(p - b); + int pc = Math.Abs(p - c); + + int ret; + + if ((pa <= pb) && (pa <= pc)) { + ret = a; + } else if (pb <= pc) { + ret = b; + } else { + ret = c; + } + curr[i] += (byte)(ret); + } + break; + default: + // Error -- uknown filter type + throw new Exception("PNG filter unknown."); + } + fout.Write(curr, 0, curr.Length); + + // Swap curr and prior + byte[] tmp = prior; + prior = curr; + curr = tmp; + } + } + + /** A helper to FlateDecode. + * @param in the input data + * @param strict true to read a correct stream. false + * to try to read a corrupted stream + * @return the decoded data + */ + public static byte[] FlateDecode(byte[] inp, bool strict) { + MemoryStream stream = new MemoryStream(inp); + ZInflaterInputStream zip = new ZInflaterInputStream(stream); + MemoryStream outp = new MemoryStream(); + byte[] b = new byte[strict ? 4092 : 1]; + try { + int n; + while ((n = zip.Read(b, 0, b.Length)) > 0) { + outp.Write(b, 0, n); + } + zip.Close(); + outp.Close(); + return outp.ToArray(); + } + catch { + if (strict) + return null; + return outp.ToArray(); + } + } + + /** Decodes a stream that has the ASCIIHexDecode filter. + * @param in the input data + * @return the decoded data + */ + public static byte[] ASCIIHexDecode(byte[] inp) { + MemoryStream outp = new MemoryStream(); + bool first = true; + int n1 = 0; + for (int k = 0; k < inp.Length; ++k) { + int ch = inp[k] & 0xff; + if (ch == '>') + break; + if (PRTokeniser.IsWhitespace(ch)) + continue; + int n = PRTokeniser.GetHex(ch); + if (n == -1) + throw new ArgumentException("Illegal character in ASCIIHexDecode."); + if (first) + n1 = n; + else + outp.WriteByte((byte)((n1 << 4) + n)); + first = !first; + } + if (!first) + outp.WriteByte((byte)(n1 << 4)); + return outp.ToArray(); + } + + /** Decodes a stream that has the ASCII85Decode filter. + * @param in the input data + * @return the decoded data + */ + public static byte[] ASCII85Decode(byte[] inp) { + MemoryStream outp = new MemoryStream(); + int state = 0; + int[] chn = new int[5]; + for (int k = 0; k < inp.Length; ++k) { + int ch = inp[k] & 0xff; + if (ch == '~') + break; + if (PRTokeniser.IsWhitespace(ch)) + continue; + if (ch == 'z' && state == 0) { + outp.WriteByte(0); + outp.WriteByte(0); + outp.WriteByte(0); + outp.WriteByte(0); + continue; + } + if (ch < '!' || ch > 'u') + throw new ArgumentException("Illegal character in ASCII85Decode."); + chn[state] = ch - '!'; + ++state; + if (state == 5) { + state = 0; + int rx = 0; + for (int j = 0; j < 5; ++j) + rx = rx * 85 + chn[j]; + outp.WriteByte((byte)(rx >> 24)); + outp.WriteByte((byte)(rx >> 16)); + outp.WriteByte((byte)(rx >> 8)); + outp.WriteByte((byte)rx); + } + } + int r = 0; + // We'll ignore the next two lines for the sake of perpetuating broken PDFs +// if (state == 1) +// throw new ArgumentException("Illegal length in ASCII85Decode."); + if (state == 2) { + r = chn[0] * 85 * 85 * 85 * 85 + chn[1] * 85 * 85 * 85 + 85 * 85 * 85 + 85 * 85 + 85; + outp.WriteByte((byte)(r >> 24)); + } + else if (state == 3) { + r = chn[0] * 85 * 85 * 85 * 85 + chn[1] * 85 * 85 * 85 + chn[2] * 85 * 85 + 85 * 85 + 85; + outp.WriteByte((byte)(r >> 24)); + outp.WriteByte((byte)(r >> 16)); + } + else if (state == 4) { + r = chn[0] * 85 * 85 * 85 * 85 + chn[1] * 85 * 85 * 85 + chn[2] * 85 * 85 + chn[3] * 85 + 85; + outp.WriteByte((byte)(r >> 24)); + outp.WriteByte((byte)(r >> 16)); + outp.WriteByte((byte)(r >> 8)); + } + return outp.ToArray(); + } + + /** Decodes a stream that has the LZWDecode filter. + * @param in the input data + * @return the decoded data + */ + public static byte[] LZWDecode(byte[] inp) { + MemoryStream outp = new MemoryStream(); + LZWDecoder lzw = new LZWDecoder(); + lzw.Decode(inp, outp); + return outp.ToArray(); + } + + /** Checks if the document had errors and was rebuilt. + * @return true if rebuilt. + * + */ + public bool IsRebuilt() { + return this.rebuilt; + } + + /** Gets the dictionary that represents a page. + * @param pageNum the page number. 1 is the first + * @return the page dictionary + */ + public PdfDictionary GetPageN(int pageNum) { + PdfDictionary dic = pageRefs.GetPageN(pageNum); + if (dic == null) + return null; + if (appendable) + dic.IndRef = pageRefs.GetPageOrigRef(pageNum); + return dic; + } + + /** + * @param pageNum + * @return a Dictionary object + */ + public PdfDictionary GetPageNRelease(int pageNum) { + PdfDictionary dic = GetPageN(pageNum); + pageRefs.ReleasePage(pageNum); + return dic; + } + + /** + * @param pageNum + */ + public void ReleasePage(int pageNum) { + pageRefs.ReleasePage(pageNum); + } + + /** + * + */ + public void ResetReleasePage() { + pageRefs.ResetReleasePage(); + } + + /** Gets the page reference to this page. + * @param pageNum the page number. 1 is the first + * @return the page reference + */ + public PRIndirectReference GetPageOrigRef(int pageNum) { + return pageRefs.GetPageOrigRef(pageNum); + } + + /** Gets the contents of the page. + * @param pageNum the page number. 1 is the first + * @param file the location of the PDF document + * @throws IOException on error + * @return the content + */ + public byte[] GetPageContent(int pageNum, RandomAccessFileOrArray file) { + PdfDictionary page = GetPageNRelease(pageNum); + if (page == null) + return null; + PdfObject contents = GetPdfObjectRelease(page.Get(PdfName.CONTENTS)); + if (contents == null) + return new byte[0]; + MemoryStream bout = null; + if (contents.IsStream()) { + return GetStreamBytes((PRStream)contents, file); + } + else if (contents.IsArray()) { + PdfArray array = (PdfArray)contents; + ArrayList list = array.ArrayList; + bout = new MemoryStream(); + for (int k = 0; k < list.Count; ++k) { + PdfObject item = GetPdfObjectRelease((PdfObject)list[k]); + if (item == null || !item.IsStream()) + continue; + byte[] b = GetStreamBytes((PRStream)item, file); + bout.Write(b, 0, b.Length); + if (k != list.Count - 1) + bout.WriteByte((byte)'\n'); + } + return bout.ToArray(); + } + else + return new byte[0]; + } + + /** Gets the contents of the page. + * @param pageNum the page number. 1 is the first + * @throws IOException on error + * @return the content + */ + public byte[] GetPageContent(int pageNum) { + RandomAccessFileOrArray rf = SafeFile; + try { + rf.ReOpen(); + return GetPageContent(pageNum, rf); + } + finally { + try{rf.Close();}catch{} + } + } + + protected internal void KillXref(PdfObject obj) { + if (obj == null) + return; + if ((obj is PdfIndirectReference) && !obj.IsIndirect()) + return; + switch (obj.Type) { + case PdfObject.INDIRECT: { + int xr = ((PRIndirectReference)obj).Number; + obj = (PdfObject)xrefObj[xr]; + xrefObj[xr] = null; + freeXref = xr; + KillXref(obj); + break; + } + case PdfObject.ARRAY: { + ArrayList t = ((PdfArray)obj).ArrayList; + for (int i = 0; i < t.Count; ++i) + KillXref((PdfObject)t[i]); + break; + } + case PdfObject.STREAM: + case PdfObject.DICTIONARY: { + PdfDictionary dic = (PdfDictionary)obj; + foreach (PdfName key in dic.Keys){ + KillXref(dic.Get(key)); + } + break; + } + } + } + + /** Sets the contents of the page. + * @param content the new page content + * @param pageNum the page number. 1 is the first + * @throws IOException on error + */ + public void SetPageContent(int pageNum, byte[] content) { + PdfDictionary page = GetPageN(pageNum); + if (page == null) + return; + PdfObject contents = page.Get(PdfName.CONTENTS); + freeXref = -1; + KillXref(contents); + if (freeXref == -1) { + xrefObj.Add(null); + freeXref = xrefObj.Count - 1; + } + page.Put(PdfName.CONTENTS, new PRIndirectReference(this, freeXref)); + xrefObj[freeXref] = new PRStream(this, content); + } + + /** Get the content from a stream applying the required filters. + * @param stream the stream + * @param file the location where the stream is + * @throws IOException on error + * @return the stream content + */ + public static byte[] GetStreamBytes(PRStream stream, RandomAccessFileOrArray file) { + PdfObject filter = GetPdfObjectRelease(stream.Get(PdfName.FILTER)); + byte[] b = GetStreamBytesRaw(stream, file); + ArrayList filters = new ArrayList(); + if (filter != null) { + if (filter.IsName()) + filters.Add(filter); + else if (filter.IsArray()) + filters = ((PdfArray)filter).ArrayList; + } + ArrayList dp = new ArrayList(); + PdfObject dpo = GetPdfObjectRelease(stream.Get(PdfName.DECODEPARMS)); + if (dpo == null || (!dpo.IsDictionary() && !dpo.IsArray())) + dpo = GetPdfObjectRelease(stream.Get(PdfName.DP)); + if (dpo != null) { + if (dpo.IsDictionary()) + dp.Add(dpo); + else if (dpo.IsArray()) + dp = ((PdfArray)dpo).ArrayList; + } + String name; + for (int j = 0; j < filters.Count; ++j) { + name = ((PdfName)GetPdfObjectRelease((PdfObject)filters[j])).ToString(); + if (name.Equals("/FlateDecode") || name.Equals("/Fl")) { + b = FlateDecode(b); + PdfObject dicParam = null; + if (j < dp.Count) { + dicParam = (PdfObject)dp[j]; + b = DecodePredictor(b, dicParam); + } + } + else if (name.Equals("/ASCIIHexDecode") || name.Equals("/AHx")) + b = ASCIIHexDecode(b); + else if (name.Equals("/ASCII85Decode") || name.Equals("/A85")) + b = ASCII85Decode(b); + else if (name.Equals("/LZWDecode")) { + b = LZWDecode(b); + PdfObject dicParam = null; + if (j < dp.Count) { + dicParam = (PdfObject)dp[j]; + b = DecodePredictor(b, dicParam); + } + } + else if (name.Equals("/Crypt")) { + } + else + throw new IOException("The filter " + name + " is not supported."); + } + return b; + } + + /** Get the content from a stream applying the required filters. + * @param stream the stream + * @throws IOException on error + * @return the stream content + */ + public static byte[] GetStreamBytes(PRStream stream) { + RandomAccessFileOrArray rf = stream.Reader.SafeFile; + try { + rf.ReOpen(); + return GetStreamBytes(stream, rf); + } + finally { + try{rf.Close();}catch{} + } + } + + /** Get the content from a stream as it is without applying any filter. + * @param stream the stream + * @param file the location where the stream is + * @throws IOException on error + * @return the stream content + */ + public static byte[] GetStreamBytesRaw(PRStream stream, RandomAccessFileOrArray file) { + PdfReader reader = stream.Reader; + byte[] b; + if (stream.Offset < 0) + b = stream.GetBytes(); + else { + b = new byte[stream.Length]; + file.Seek(stream.Offset); + file.ReadFully(b); + PdfEncryption decrypt = reader.Decrypt; + if (decrypt != null) { + PdfObject filter = GetPdfObjectRelease(stream.Get(PdfName.FILTER)); + ArrayList filters = new ArrayList(); + if (filter != null) { + if (filter.IsName()) + filters.Add(filter); + else if (filter.IsArray()) + filters = ((PdfArray)filter).ArrayList; + } + bool skip = false; + for (int k = 0; k < filters.Count; ++k) { + PdfObject obj = GetPdfObjectRelease((PdfObject)filters[k]); + if (obj != null && obj.ToString().Equals("/Crypt")) { + skip = true; + break; + } + } + if (!skip) { + decrypt.SetHashKey(stream.ObjNum, stream.ObjGen); + b = decrypt.DecryptByteArray(b); + } + } + } + return b; + } + + /** Get the content from a stream as it is without applying any filter. + * @param stream the stream + * @throws IOException on error + * @return the stream content + */ + public static byte[] GetStreamBytesRaw(PRStream stream) { + RandomAccessFileOrArray rf = stream.Reader.SafeFile; + try { + rf.ReOpen(); + return GetStreamBytesRaw(stream, rf); + } + finally { + try{rf.Close();}catch{} + } + } + + /** Eliminates shared streams if they exist. */ + public void EliminateSharedStreams() { + if (!sharedStreams) + return; + sharedStreams = false; + if (pageRefs.Size == 1) + return; + ArrayList newRefs = new ArrayList(); + ArrayList newStreams = new ArrayList(); + IntHashtable visited = new IntHashtable(); + for (int k = 1; k <= pageRefs.Size; ++k) { + PdfDictionary page = pageRefs.GetPageN(k); + if (page == null) + continue; + PdfObject contents = GetPdfObject(page.Get(PdfName.CONTENTS)); + if (contents == null) + continue; + if (contents.IsStream()) { + PRIndirectReference refi = (PRIndirectReference)page.Get(PdfName.CONTENTS); + if (visited.ContainsKey(refi.Number)) { + // need to duplicate + newRefs.Add(refi); + newStreams.Add(new PRStream((PRStream)contents, null)); + } + else + visited[refi.Number] = 1; + } + else if (contents.IsArray()) { + PdfArray array = (PdfArray)contents; + ArrayList list = array.ArrayList; + for (int j = 0; j < list.Count; ++j) { + PRIndirectReference refi = (PRIndirectReference)list[j]; + if (visited.ContainsKey(refi.Number)) { + // need to duplicate + newRefs.Add(refi); + newStreams.Add(new PRStream((PRStream)GetPdfObject(refi), null)); + } + else + visited[refi.Number] = 1; + } + } + } + if (newStreams.Count == 0) + return; + for (int k = 0; k < newStreams.Count; ++k) { + xrefObj.Add(newStreams[k]); + PRIndirectReference refi = (PRIndirectReference)newRefs[k]; + refi.SetNumber(xrefObj.Count - 1, 0); + } + } + + /** + * Sets the tampered state. A tampered PdfReader cannot be reused in PdfStamper. + * @param tampered the tampered state + */ + public bool Tampered { + get { + return tampered; + } + set { + tampered = value; + pageRefs.KeepPages(); } + } + + /** Gets the XML metadata. + * @throws IOException on error + * @return the XML metadata + */ + public byte[] Metadata { + get { + PdfObject obj = GetPdfObject(catalog.Get(PdfName.METADATA)); + if (!(obj is PRStream)) + return null; + RandomAccessFileOrArray rf = SafeFile; + byte[] b = null; + try { + rf.ReOpen(); + b = GetStreamBytes((PRStream)obj, rf); + } + finally { + try { + rf.Close(); + } + catch{ + // empty on purpose + } + } + return b; + } + } + + /** + * Gets the byte address of the last xref table. + * @return the byte address of the last xref table + */ + public int LastXref { + get { + return lastXref; + } + } + + /** + * Gets the number of xref objects. + * @return the number of xref objects + */ + public int XrefSize { + get { + return xrefObj.Count; + } + } + + /** + * Gets the byte address of the %%EOF marker. + * @return the byte address of the %%EOF marker + */ + public int EofPos { + get { + return eofPos; + } + } + + /** + * Gets the PDF version. Only the last version char is returned. For example + * version 1.4 is returned as '4'. + * @return the PDF version + */ + public char PdfVersion { + get { + return pdfVersion; + } + } + + /** + * Returns true if the PDF is encrypted. + * @return true if the PDF is encrypted + */ + public bool IsEncrypted() { + return encrypted; + } + + /** + * Gets the encryption permissions. It can be used directly in + * PdfWriter.SetEncryption(). + * @return the encryption permissions + */ + public int Permissions { + get { + return pValue; + } + } + + /** + * Returns true if the PDF has a 128 bit key encryption. + * @return true if the PDF has a 128 bit key encryption + */ + public bool Is128Key() { + return rValue == 3; + } + + /** + * Gets the trailer dictionary + * @return the trailer dictionary + */ + public PdfDictionary Trailer { + get { + return trailer; + } + } + + internal PdfEncryption Decrypt { + get { + return decrypt; + } + } + + internal static bool Equalsn(byte[] a1, byte[] a2) { + int length = a2.Length; + for (int k = 0; k < length; ++k) { + if (a1[k] != a2[k]) + return false; + } + return true; + } + + internal static bool ExistsName(PdfDictionary dic, PdfName key, PdfName value) { + PdfObject type = GetPdfObjectRelease(dic.Get(key)); + if (type == null || !type.IsName()) + return false; + PdfName name = (PdfName)type; + return name.Equals(value); + } + + internal static String GetFontName(PdfDictionary dic) { + if (dic == null) + return null; + PdfObject type = GetPdfObjectRelease(dic.Get(PdfName.BASEFONT)); + if (type == null || !type.IsName()) + return null; + return PdfName.DecodeName(type.ToString()); + } + + internal static String GetSubsetPrefix(PdfDictionary dic) { + if (dic == null) + return null; + String s = GetFontName(dic); + if (s == null) + return null; + if (s.Length < 8 || s[6] != '+') + return null; + for (int k = 0; k < 6; ++k) { + char c = s[k]; + if (c < 'A' || c > 'Z') + return null; + } + return s; + } + + /** Finds all the font subsets and changes the prefixes to some + * random values. + * @return the number of font subsets altered + */ + public int ShuffleSubsetNames() { + int total = 0; + for (int k = 1; k < xrefObj.Count; ++k) { + PdfObject obj = GetPdfObjectRelease(k); + if (obj == null || !obj.IsDictionary()) + continue; + PdfDictionary dic = (PdfDictionary)obj; + if (!ExistsName(dic, PdfName.TYPE, PdfName.FONT)) + continue; + if (ExistsName(dic, PdfName.SUBTYPE, PdfName.TYPE1) + || ExistsName(dic, PdfName.SUBTYPE, PdfName.MMTYPE1) + || ExistsName(dic, PdfName.SUBTYPE, PdfName.TRUETYPE)) { + String s = GetSubsetPrefix(dic); + if (s == null) + continue; + String ns = BaseFont.CreateSubsetPrefix() + s.Substring(7); + PdfName newName = new PdfName(ns); + dic.Put(PdfName.BASEFONT, newName); + SetXrefPartialObject(k, dic); + ++total; + PdfDictionary fd = (PdfDictionary)GetPdfObject(dic.Get(PdfName.FONTDESCRIPTOR)); + if (fd == null) + continue; + fd.Put(PdfName.FONTNAME, newName); + } + else if (ExistsName(dic, PdfName.SUBTYPE, PdfName.TYPE0)) { + String s = GetSubsetPrefix(dic); + PdfArray arr = (PdfArray)GetPdfObject(dic.Get(PdfName.DESCENDANTFONTS)); + if (arr == null) + continue; + ArrayList list = arr.ArrayList; + if (list.Count == 0) + continue; + PdfDictionary desc = (PdfDictionary)GetPdfObject((PdfObject)list[0]); + String sde = GetSubsetPrefix(desc); + if (sde == null) + continue; + String ns = BaseFont.CreateSubsetPrefix(); + if (s != null) + dic.Put(PdfName.BASEFONT, new PdfName(ns + s.Substring(7))); + SetXrefPartialObject(k, dic); + PdfName newName = new PdfName(ns + sde.Substring(7)); + desc.Put(PdfName.BASEFONT, newName); + ++total; + PdfDictionary fd = (PdfDictionary)GetPdfObject(desc.Get(PdfName.FONTDESCRIPTOR)); + if (fd == null) + continue; + fd.Put(PdfName.FONTNAME, newName); + } + } + return total; + } + + /** Finds all the fonts not subset but embedded and marks them as subset. + * @return the number of fonts altered + */ + public int CreateFakeFontSubsets() { + int total = 0; + for (int k = 1; k < xrefObj.Count; ++k) { + PdfObject obj = GetPdfObjectRelease(k); + if (obj == null || !obj.IsDictionary()) + continue; + PdfDictionary dic = (PdfDictionary)obj; + if (!ExistsName(dic, PdfName.TYPE, PdfName.FONT)) + continue; + if (ExistsName(dic, PdfName.SUBTYPE, PdfName.TYPE1) + || ExistsName(dic, PdfName.SUBTYPE, PdfName.MMTYPE1) + || ExistsName(dic, PdfName.SUBTYPE, PdfName.TRUETYPE)) { + String s = GetSubsetPrefix(dic); + if (s != null) + continue; + s = GetFontName(dic); + if (s == null) + continue; + String ns = BaseFont.CreateSubsetPrefix() + s; + PdfDictionary fd = (PdfDictionary)GetPdfObjectRelease(dic.Get(PdfName.FONTDESCRIPTOR)); + if (fd == null) + continue; + if (fd.Get(PdfName.FONTFILE) == null && fd.Get(PdfName.FONTFILE2) == null + && fd.Get(PdfName.FONTFILE3) == null) + continue; + fd = (PdfDictionary)GetPdfObject(dic.Get(PdfName.FONTDESCRIPTOR)); + PdfName newName = new PdfName(ns); + dic.Put(PdfName.BASEFONT, newName); + fd.Put(PdfName.FONTNAME, newName); + SetXrefPartialObject(k, dic); + ++total; + } + } + return total; + } + + private static PdfArray GetNameArray(PdfObject obj) { + if (obj == null) + return null; + obj = GetPdfObjectRelease(obj); + if (obj == null) + return null; + if (obj.IsArray()) + return (PdfArray)obj; + else if (obj.IsDictionary()) { + PdfObject arr2 = GetPdfObjectRelease(((PdfDictionary)obj).Get(PdfName.D)); + if (arr2 != null && arr2.IsArray()) + return (PdfArray)arr2; + } + return null; + } + + /** + * Gets all the named destinations as an Hashtable. The key is the name + * and the value is the destinations array. + * @return gets all the named destinations + */ + public Hashtable GetNamedDestination() { + Hashtable names = GetNamedDestinationFromNames(); + Hashtable names2 = GetNamedDestinationFromStrings(); + foreach (DictionaryEntry ie in names2) + names[ie.Key] = ie.Value; + return names; + } + + /** + * Gets the named destinations from the /Dests key in the catalog as an Hashtable. The key is the name + * and the value is the destinations array. + * @return gets the named destinations + */ + public Hashtable GetNamedDestinationFromNames() { + Hashtable names = new Hashtable(); + if (catalog.Get(PdfName.DESTS) != null) { + PdfDictionary dic = (PdfDictionary)GetPdfObjectRelease(catalog.Get(PdfName.DESTS)); + if (dic == null) + return names; + foreach (PdfName key in dic.Keys) { + String name = PdfName.DecodeName(key.ToString()); + PdfArray arr = GetNameArray(dic.Get(key)); + if (arr != null) + names[name] = arr; + } + } + return names; + } + + /** + * Gets the named destinations from the /Names key in the catalog as an Hashtable. The key is the name + * and the value is the destinations array. + * @return gets the named destinations + */ + public Hashtable GetNamedDestinationFromStrings() { + if (catalog.Get(PdfName.NAMES) != null) { + PdfDictionary dic = (PdfDictionary)GetPdfObjectRelease(catalog.Get(PdfName.NAMES)); + if (dic != null) { + dic = (PdfDictionary)GetPdfObjectRelease(dic.Get(PdfName.DESTS)); + if (dic != null) { + Hashtable names = PdfNameTree.ReadTree(dic); + object[] keys = new object[names.Count]; + names.Keys.CopyTo(keys, 0); + foreach (object key in keys) { + PdfArray arr = GetNameArray((PdfObject)names[key]); + if (arr != null) + names[key] = arr; + else + names.Remove(key); + } + return names; + } + } + } + return new Hashtable(); + } + + private bool ReplaceNamedDestination(PdfObject obj, Hashtable names) { + obj = GetPdfObject(obj); + int objIdx = lastXrefPartial; + ReleaseLastXrefPartial(); + if (obj != null && obj.IsDictionary()) { + PdfObject ob2 = GetPdfObjectRelease(((PdfDictionary)obj).Get(PdfName.DEST)); + String name = null; + if (ob2 != null) { + if (ob2.IsName()) + name = PdfName.DecodeName(ob2.ToString()); + else if (ob2.IsString()) + name = ob2.ToString(); + if (name != null) { + PdfArray dest = (PdfArray)names[name]; + if (dest != null) { + ((PdfDictionary)obj).Put(PdfName.DEST, dest); + SetXrefPartialObject(objIdx, obj); + return true; + } + } + } + else if ((ob2 = GetPdfObject(((PdfDictionary)obj).Get(PdfName.A))) != null) { + int obj2Idx = lastXrefPartial; + ReleaseLastXrefPartial(); + PdfDictionary dic = (PdfDictionary)ob2; + PdfName type = (PdfName)GetPdfObjectRelease(dic.Get(PdfName.S)); + if (PdfName.GOTO.Equals(type)) { + PdfObject ob3 = GetPdfObjectRelease(dic.Get(PdfName.D)); + if (ob3 != null) { + if (ob3.IsName()) + name = PdfName.DecodeName(ob3.ToString()); + else if (ob3.IsString()) + name = ob3.ToString(); + } + if (name != null) { + PdfArray dest = (PdfArray)names[name]; + if (dest != null) { + dic.Put(PdfName.D, dest); + SetXrefPartialObject(obj2Idx, ob2); + SetXrefPartialObject(objIdx, obj); + return true; + } + } + } + } + } + return false; + } + + /** + * Removes all the fields from the document. + */ + public void RemoveFields() { + pageRefs.ResetReleasePage(); + for (int k = 1; k <= pageRefs.Size; ++k) { + PdfDictionary page = pageRefs.GetPageN(k); + PdfArray annots = (PdfArray)GetPdfObject(page.Get(PdfName.ANNOTS)); + if (annots == null) { + pageRefs.ReleasePage(k); + continue; + } + ArrayList arr = annots.ArrayList; + for (int j = 0; j < arr.Count; ++j) { + PdfObject obj = GetPdfObjectRelease((PdfObject)arr[j]); + if (obj == null || !obj.IsDictionary()) + continue; + PdfDictionary annot = (PdfDictionary)obj; + if (PdfName.WIDGET.Equals(annot.Get(PdfName.SUBTYPE))) + arr.RemoveAt(j--); + } + if (arr.Count == 0) + page.Remove(PdfName.ANNOTS); + else + pageRefs.ReleasePage(k); + } + catalog.Remove(PdfName.ACROFORM); + pageRefs.ResetReleasePage(); + } + + /** + * Removes all the annotations and fields from the document. + */ + public void RemoveAnnotations() { + pageRefs.ResetReleasePage(); + for (int k = 1; k <= pageRefs.Size; ++k) { + PdfDictionary page = pageRefs.GetPageN(k); + if (page.Get(PdfName.ANNOTS) == null) + pageRefs.ReleasePage(k); + else + page.Remove(PdfName.ANNOTS); + } + catalog.Remove(PdfName.ACROFORM); + pageRefs.ResetReleasePage(); + } + + public ArrayList GetLinks(int page) { + pageRefs.ResetReleasePage(); + ArrayList result = new ArrayList(); + PdfDictionary pageDic = pageRefs.GetPageN(page); + if (pageDic.Get(PdfName.ANNOTS) != null) { + PdfArray annots = (PdfArray)GetPdfObject(pageDic.Get(PdfName.ANNOTS)); + ArrayList arr = annots.ArrayList; + for (int j = 0; j < arr.Count; ++j) { + PdfDictionary annot = (PdfDictionary)GetPdfObjectRelease((PdfObject)arr[j]); + + if (PdfName.LINK.Equals(annot.Get(PdfName.SUBTYPE))) { + result.Add(new PdfAnnotation.PdfImportedLink(annot)); + } + } + } + pageRefs.ReleasePage(page); + pageRefs.ResetReleasePage(); + return result; + } + + private void IterateBookmarks(PdfObject outlineRef, Hashtable names) { + while (outlineRef != null) { + ReplaceNamedDestination(outlineRef, names); + PdfDictionary outline = (PdfDictionary)GetPdfObjectRelease(outlineRef); + PdfObject first = outline.Get(PdfName.FIRST); + if (first != null) { + IterateBookmarks(first, names); + } + outlineRef = outline.Get(PdfName.NEXT); + } + } + + /** Replaces all the local named links with the actual destinations. */ + public void ConsolidateNamedDestinations() { + if (consolidateNamedDestinations) + return; + consolidateNamedDestinations = true; + Hashtable names = GetNamedDestination(); + if (names.Count == 0) + return; + for (int k = 1; k <= pageRefs.Size; ++k) { + PdfDictionary page = pageRefs.GetPageN(k); + PdfObject annotsRef; + PdfArray annots = (PdfArray)GetPdfObject(annotsRef = page.Get(PdfName.ANNOTS)); + int annotIdx = lastXrefPartial; + ReleaseLastXrefPartial(); + if (annots == null) { + pageRefs.ReleasePage(k); + continue; + } + ArrayList list = annots.ArrayList; + bool commitAnnots = false; + for (int an = 0; an < list.Count; ++an) { + PdfObject objRef = (PdfObject)list[an]; + if (ReplaceNamedDestination(objRef, names) && !objRef.IsIndirect()) + commitAnnots = true; + } + if (commitAnnots) + SetXrefPartialObject(annotIdx, annots); + if (!commitAnnots || annotsRef.IsIndirect()) + pageRefs.ReleasePage(k); + } + PdfDictionary outlines = (PdfDictionary)GetPdfObjectRelease(catalog.Get(PdfName.OUTLINES)); + if (outlines == null) + return; + IterateBookmarks(outlines.Get(PdfName.FIRST), names); + } + + protected internal static PdfDictionary DuplicatePdfDictionary(PdfDictionary original, PdfDictionary copy, PdfReader newReader) { + if (copy == null) + copy = new PdfDictionary(); + foreach (PdfName key in original.Keys) { + copy.Put(key, DuplicatePdfObject(original.Get(key), newReader)); + } + return copy; + } + + protected internal static PdfObject DuplicatePdfObject(PdfObject original, PdfReader newReader) { + if (original == null) + return null; + switch (original.Type) { + case PdfObject.DICTIONARY: { + return DuplicatePdfDictionary((PdfDictionary)original, null, newReader); + } + case PdfObject.STREAM: { + PRStream org = (PRStream)original; + PRStream stream = new PRStream(org, null, newReader); + DuplicatePdfDictionary(org, stream, newReader); + return stream; + } + case PdfObject.ARRAY: { + ArrayList list = ((PdfArray)original).ArrayList; + PdfArray arr = new PdfArray(); + foreach (PdfObject ob in list) { + arr.Add(DuplicatePdfObject(ob, newReader)); + } + return arr; + } + case PdfObject.INDIRECT: { + PRIndirectReference org = (PRIndirectReference)original; + return new PRIndirectReference(newReader, org.Number, org.Generation); + } + default: + return original; + } + } + + /** + * Closes the reader + */ + public void Close() { + if (!partial) + return; + tokens.Close(); + } + + protected internal void RemoveUnusedNode(PdfObject obj, bool[] hits) { + Stack state = new Stack(); + state.Push(obj); + while (state.Count != 0) { + Object current = state.Pop(); + if (current == null) + continue; + ArrayList ar = null; + PdfDictionary dic = null; + PdfName[] keys = null; + Object[] objs = null; + int idx = 0; + if (current is PdfObject) { + obj = (PdfObject)current; + switch (obj.Type) { + case PdfObject.DICTIONARY: + case PdfObject.STREAM: + dic = (PdfDictionary)obj; + keys = new PdfName[dic.Size]; + dic.Keys.CopyTo(keys, 0); + break; + case PdfObject.ARRAY: + ar = ((PdfArray)obj).ArrayList; + break; + case PdfObject.INDIRECT: + PRIndirectReference refi = (PRIndirectReference)obj; + int num = refi.Number; + if (!hits[num]) { + hits[num] = true; + state.Push(GetPdfObjectRelease(refi)); + } + continue; + default: + continue; + } + } + else { + objs = (Object[])current; + if (objs[0] is ArrayList) { + ar = (ArrayList)objs[0]; + idx = (int)objs[1]; + } + else { + keys = (PdfName[])objs[0]; + dic = (PdfDictionary)objs[1]; + idx = (int)objs[2]; + } + } + if (ar != null) { + for (int k = idx; k < ar.Count; ++k) { + PdfObject v = (PdfObject)ar[k]; + if (v.IsIndirect()) { + int num = ((PRIndirectReference)v).Number; + if (num >= xrefObj.Count || (!partial && xrefObj[num] == null)) { + ar[k] = PdfNull.PDFNULL; + continue; + } + } + if (objs == null) + state.Push(new Object[]{ar, k + 1}); + else { + objs[1] = k + 1; + state.Push(objs); + } + state.Push(v); + break; + } + } + else { + for (int k = idx; k < keys.Length; ++k) { + PdfName key = keys[k]; + PdfObject v = dic.Get(key); + if (v.IsIndirect()) { + int num = ((PRIndirectReference)v).Number; + if (num >= xrefObj.Count || (!partial && xrefObj[num] == null)) { + dic.Put(key, PdfNull.PDFNULL); + continue; + } + } + if (objs == null) + state.Push(new Object[]{keys, dic, k + 1}); + else { + objs[2] = k + 1; + state.Push(objs); + } + state.Push(v); + break; + } + } + } + } + + /** Removes all the unreachable objects. + * @return the number of indirect objects removed + */ + public int RemoveUnusedObjects() { + bool[] hits = new bool[xrefObj.Count]; + RemoveUnusedNode(trailer, hits); + int total = 0; + if (partial) { + for (int k = 1; k < hits.Length; ++k) { + if (!hits[k]) { + xref[k * 2] = -1; + xref[k * 2 + 1] = 0; + xrefObj[k] = null; + ++total; + } + } + } + else { + for (int k = 1; k < hits.Length; ++k) { + if (!hits[k]) { + xrefObj[k] = null; + ++total; + } + } + } + return total; + } + + /** Gets a read-only version of AcroFields. + * @return a read-only version of AcroFields + */ + public AcroFields AcroFields { + get { + return new AcroFields(this, null); + } + } + + /** + * Gets the global document JavaScript. + * @param file the document file + * @throws IOException on error + * @return the global document JavaScript + */ + public String GetJavaScript(RandomAccessFileOrArray file) { + PdfDictionary names = (PdfDictionary)GetPdfObjectRelease(catalog.Get(PdfName.NAMES)); + if (names == null) + return null; + PdfDictionary js = (PdfDictionary)GetPdfObjectRelease(names.Get(PdfName.JAVASCRIPT)); + if (js == null) + return null; + Hashtable jscript = PdfNameTree.ReadTree(js); + String[] sortedNames = new String[jscript.Count]; + jscript.Keys.CopyTo(sortedNames, 0); + Array.Sort(sortedNames); + StringBuilder buf = new StringBuilder(); + for (int k = 0; k < sortedNames.Length; ++k) { + PdfDictionary j = (PdfDictionary)GetPdfObjectRelease((PdfIndirectReference)jscript[sortedNames[k]]); + if (j == null) + continue; + PdfObject obj = GetPdfObjectRelease(j.Get(PdfName.JS)); + if (obj != null) { + if (obj.IsString()) + buf.Append(((PdfString)obj).ToUnicodeString()).Append('\n'); + else if (obj.IsStream()) { + byte[] bytes = GetStreamBytes((PRStream)obj, file); + if (bytes.Length >= 2 && bytes[0] == (byte)254 && bytes[1] == (byte)255) + buf.Append(PdfEncodings.ConvertToString(bytes, PdfObject.TEXT_UNICODE)); + else + buf.Append(PdfEncodings.ConvertToString(bytes, PdfObject.TEXT_PDFDOCENCODING)); + buf.Append('\n'); + } + } + } + return buf.ToString(); + } + + /** + * Gets the global document JavaScript. + * @throws IOException on error + * @return the global document JavaScript + */ + public String JavaScript { + get { + RandomAccessFileOrArray rf = SafeFile; + try { + rf.ReOpen(); + return GetJavaScript(rf); + } + finally { + try{rf.Close();}catch{} + } + } + } + + /** + * Selects the pages to keep in the document. The pages are described as + * ranges. The page ordering can be changed but + * no page repetitions are allowed. Note that it may be very slow in partial mode. + * @param ranges the comma separated ranges as described in {@link SequenceList} + */ + public void SelectPages(String ranges) { + SelectPages(SequenceList.Expand(ranges, NumberOfPages)); + } + + /** + * Selects the pages to keep in the document. The pages are described as a + * List of Integer. The page ordering can be changed but + * no page repetitions are allowed. Note that it may be very slow in partial mode. + * @param pagesToKeep the pages to keep in the document + */ + public void SelectPages(ArrayList pagesToKeep) { + pageRefs.SelectPages(pagesToKeep); + RemoveUnusedObjects(); + } + + /** Sets the viewer preferences as the sum of several constants. + * @param preferences the viewer preferences + * @see PdfViewerPreferences#setViewerPreferences + */ + public virtual int ViewerPreferences { + set { + this.viewerPreferences.ViewerPreferences = value; + SetViewerPreferences(this.viewerPreferences); + } + } + + /** Adds a viewer preference + * @param key a key for a viewer preference + * @param value a value for the viewer preference + * @see PdfViewerPreferences#addViewerPreference + */ + public virtual void AddViewerPreference(PdfName key, PdfObject value) { + this.viewerPreferences.AddViewerPreference(key, value); + SetViewerPreferences(this.viewerPreferences); + } + + internal virtual void SetViewerPreferences(PdfViewerPreferencesImp vp) { + vp.AddToCatalog(catalog); + } + + /** + * @return an int that contains the Viewer Preferences. + */ + public virtual int SimpleViewerPreferences { + get { + return PdfViewerPreferencesImp.GetViewerPreferences(catalog).PageLayoutAndMode; + } + } + + public bool Appendable { + set { + appendable = value; + if (appendable) + GetPdfObject(trailer.Get(PdfName.ROOT)); + } + get { + return appendable; + } + } + + /** + * Getter for property newXrefType. + * @return Value of property newXrefType. + */ + public bool IsNewXrefType() { + return newXrefType; + } + + /** + * Getter for property fileLength. + * @return Value of property fileLength. + */ + public int FileLength { + get { + return fileLength; + } + } + + /** + * Getter for property hybridXref. + * @return Value of property hybridXref. + */ + public bool IsHybridXref() { + return hybridXref; + } + + public class PageRefs { + private PdfReader reader; + private IntHashtable refsp; + private ArrayList refsn; + private ArrayList pageInh; + private int lastPageRead = -1; + private int sizep; + private bool keepPages; + + internal PageRefs(PdfReader reader) { + this.reader = reader; + if (reader.partial) { + refsp = new IntHashtable(); + PdfNumber npages = (PdfNumber)PdfReader.GetPdfObjectRelease(reader.rootPages.Get(PdfName.COUNT)); + sizep = npages.IntValue; + } + else { + ReadPages(); + } + } + + internal PageRefs(PageRefs other, PdfReader reader) { + this.reader = reader; + this.sizep = other.sizep; + if (other.refsn != null) { + refsn = new ArrayList(other.refsn); + for (int k = 0; k < refsn.Count; ++k) { + refsn[k] = DuplicatePdfObject((PdfObject)refsn[k], reader); + } + } + else + this.refsp = (IntHashtable)other.refsp.Clone(); + } + + internal int Size { + get { + if (refsn != null) + return refsn.Count; + else + return sizep; + } + } + + internal void ReadPages() { + if (refsn != null) + return; + refsp = null; + refsn = new ArrayList(); + pageInh = new ArrayList(); + IteratePages((PRIndirectReference)reader.catalog.Get(PdfName.PAGES)); + pageInh = null; + reader.rootPages.Put(PdfName.COUNT, new PdfNumber(refsn.Count)); + } + + internal void ReReadPages() { + refsn = null; + ReadPages(); + } + + /** Gets the dictionary that represents a page. + * @param pageNum the page number. 1 is the first + * @return the page dictionary + */ + public PdfDictionary GetPageN(int pageNum) { + PRIndirectReference refi = GetPageOrigRef(pageNum); + return (PdfDictionary)PdfReader.GetPdfObject(refi); + } + + /** + * @param pageNum + * @return a dictionary object + */ + public PdfDictionary GetPageNRelease(int pageNum) { + PdfDictionary page = GetPageN(pageNum); + ReleasePage(pageNum); + return page; + } + + /** + * @param pageNum + * @return an indirect reference + */ + public PRIndirectReference GetPageOrigRefRelease(int pageNum) { + PRIndirectReference refi = GetPageOrigRef(pageNum); + ReleasePage(pageNum); + return refi; + } + + /** Gets the page reference to this page. + * @param pageNum the page number. 1 is the first + * @return the page reference + */ + public PRIndirectReference GetPageOrigRef(int pageNum) { + --pageNum; + if (pageNum < 0 || pageNum >= Size) + return null; + if (refsn != null) + return (PRIndirectReference)refsn[pageNum]; + else { + int n = refsp[pageNum]; + if (n == 0) { + PRIndirectReference refi = GetSinglePage(pageNum); + if (reader.lastXrefPartial == -1) + lastPageRead = -1; + else + lastPageRead = pageNum; + reader.lastXrefPartial = -1; + refsp[pageNum] = refi.Number; + if (keepPages) + lastPageRead = -1; + return refi; + } + else { + if (lastPageRead != pageNum) + lastPageRead = -1; + if (keepPages) + lastPageRead = -1; + return new PRIndirectReference(reader, n); + } + } + } + + internal void KeepPages() { + if (refsp == null || keepPages) + return; + keepPages = true; + refsp.Clear(); + } + + /** + * @param pageNum + */ + public void ReleasePage(int pageNum) { + if (refsp == null) + return; + --pageNum; + if (pageNum < 0 || pageNum >= Size) + return; + if (pageNum != lastPageRead) + return; + lastPageRead = -1; + reader.lastXrefPartial = refsp[pageNum]; + reader.ReleaseLastXrefPartial(); + refsp.Remove(pageNum); + } + + /** + * + */ + public void ResetReleasePage() { + if (refsp == null) + return; + lastPageRead = -1; + } + + internal void InsertPage(int pageNum, PRIndirectReference refi) { + --pageNum; + if (refsn != null) { + if (pageNum >= refsn.Count) + refsn.Add(refi); + else + refsn.Insert(pageNum, refi); + } + else { + ++sizep; + lastPageRead = -1; + if (pageNum >= Size) { + refsp[Size] = refi.Number; + } + else { + IntHashtable refs2 = new IntHashtable((refsp.Size + 1) * 2); + for (IntHashtable.IntHashtableIterator it = refsp.GetEntryIterator(); it.HasNext();) { + IntHashtable.IntHashtableEntry entry = (IntHashtable.IntHashtableEntry)it.Next(); + int p = entry.Key; + refs2[p >= pageNum ? p + 1 : p] = entry.Value; + } + refs2[pageNum] = refi.Number; + refsp = refs2; + } + } + } + + private void PushPageAttributes(PdfDictionary nodePages) { + PdfDictionary dic = new PdfDictionary(); + if (pageInh.Count != 0) { + dic.Merge((PdfDictionary)pageInh[pageInh.Count - 1]); + } + for (int k = 0; k < pageInhCandidates.Length; ++k) { + PdfObject obj = nodePages.Get(pageInhCandidates[k]); + if (obj != null) + dic.Put(pageInhCandidates[k], obj); + } + pageInh.Add(dic); + } + + private void PopPageAttributes() { + pageInh.RemoveAt(pageInh.Count - 1); + } + + private void IteratePages(PRIndirectReference rpage) { + PdfDictionary page = (PdfDictionary)GetPdfObject(rpage); + PdfArray kidsPR = (PdfArray)GetPdfObject(page.Get(PdfName.KIDS)); + if (kidsPR == null) { + page.Put(PdfName.TYPE, PdfName.PAGE); + PdfDictionary dic = (PdfDictionary)pageInh[pageInh.Count - 1]; + foreach (PdfName key in dic.Keys) { + if (page.Get(key) == null) + page.Put(key, dic.Get(key)); + } + if (page.Get(PdfName.MEDIABOX) == null) { + PdfArray arr = new PdfArray(new float[]{0,0,PageSize.LETTER.Right,PageSize.LETTER.Top}); + page.Put(PdfName.MEDIABOX, arr); + } + refsn.Add(rpage); + } + else { + page.Put(PdfName.TYPE, PdfName.PAGES); + PushPageAttributes(page); + ArrayList kids = kidsPR.ArrayList; + for (int k = 0; k < kids.Count; ++k){ + PdfObject obj = (PdfObject)kids[k]; + if (!obj.IsIndirect()) { + while (k < kids.Count) + kids.RemoveAt(k); + break; + } + IteratePages((PRIndirectReference)obj); + } + PopPageAttributes(); + } + } + + protected internal PRIndirectReference GetSinglePage(int n) { + PdfDictionary acc = new PdfDictionary(); + PdfDictionary top = reader.rootPages; + int baseb = 0; + while (true) { + for (int k = 0; k < pageInhCandidates.Length; ++k) { + PdfObject obj = top.Get(pageInhCandidates[k]); + if (obj != null) + acc.Put(pageInhCandidates[k], obj); + } + PdfArray kids = (PdfArray)PdfReader.GetPdfObjectRelease(top.Get(PdfName.KIDS)); + for (ListIterator it = new ListIterator(kids.ArrayList); it.HasNext();) { + PRIndirectReference refi = (PRIndirectReference)it.Next(); + PdfDictionary dic = (PdfDictionary)GetPdfObject(refi); + int last = reader.lastXrefPartial; + PdfObject count = GetPdfObjectRelease(dic.Get(PdfName.COUNT)); + reader.lastXrefPartial = last; + int acn = 1; + if (count != null && count.Type == PdfObject.NUMBER) + acn = ((PdfNumber)count).IntValue; + if (n < baseb + acn) { + if (count == null) { + dic.MergeDifferent(acc); + return refi; + } + reader.ReleaseLastXrefPartial(); + top = dic; + break; + } + reader.ReleaseLastXrefPartial(); + baseb += acn; + } + } + } + + internal void SelectPages(ArrayList pagesToKeep) { + IntHashtable pg = new IntHashtable(); + ArrayList finalPages = new ArrayList(); + int psize = Size; + foreach (int p in pagesToKeep) { + if (p >= 1 && p <= psize && !pg.ContainsKey(p)) { + pg[p] = 1; + finalPages.Add(p); + } + } + if (reader.partial) { + for (int k = 1; k <= psize; ++k) { + GetPageOrigRef(k); + ResetReleasePage(); + } + } + PRIndirectReference parent = (PRIndirectReference)reader.catalog.Get(PdfName.PAGES); + PdfDictionary topPages = (PdfDictionary)PdfReader.GetPdfObject(parent); + ArrayList newPageRefs = new ArrayList(finalPages.Count); + PdfArray kids = new PdfArray(); + foreach (int p in finalPages) { + PRIndirectReference pref = GetPageOrigRef(p); + ResetReleasePage(); + kids.Add(pref); + newPageRefs.Add(pref); + GetPageN(p).Put(PdfName.PARENT, parent); + } + AcroFields af = reader.AcroFields; + bool removeFields = (af.Fields.Count > 0); + for (int k = 1; k <= psize; ++k) { + if (!pg.ContainsKey(k)) { + if (removeFields) + af.RemoveFieldsFromPage(k); + PRIndirectReference pref = GetPageOrigRef(k); + int nref = pref.Number; + reader.xrefObj[nref] = null; + if (reader.partial) { + reader.xref[nref * 2] = -1; + reader.xref[nref * 2 + 1] = 0; + } + } + } + topPages.Put(PdfName.COUNT, new PdfNumber(finalPages.Count)); + topPages.Put(PdfName.KIDS, kids); + refsp = null; + refsn = newPageRefs; + } + } + + internal PdfIndirectReference GetCryptoRef() { + if (cryptoRef == null) + return null; + return new PdfIndirectReference(0, cryptoRef.Number, cryptoRef.Generation); + } + + /** + * Removes any usage rights that this PDF may have. Only Adobe can grant usage rights + * and any PDF modification with iText will invalidate them. Invalidated usage rights may + * confuse Acrobat and it's advisabe to remove them altogether. + */ + public void RemoveUsageRights() { + PdfDictionary perms = (PdfDictionary)GetPdfObject(catalog.Get(PdfName.PERMS)); + if (perms == null) + return; + perms.Remove(PdfName.UR); + perms.Remove(PdfName.UR3); + if (perms.Size == 0) + catalog.Remove(PdfName.PERMS); + } + + /** + * Gets the certification level for this document. The return values can be PdfSignatureAppearance.NOT_CERTIFIED, + * PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED, + * PdfSignatureAppearance.CERTIFIED_FORM_FILLING and + * PdfSignatureAppearance.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS. + *

    + * No signature validation is made, use the methods availabe for that in AcroFields. + *

    + * @return gets the certification level for this document + */ + public int GetCertificationLevel() { + PdfDictionary dic = (PdfDictionary)GetPdfObject(catalog.Get(PdfName.PERMS)); + if (dic == null) + return PdfSignatureAppearance.NOT_CERTIFIED; + dic = (PdfDictionary)GetPdfObject(dic.Get(PdfName.DOCMDP)); + if (dic == null) + return PdfSignatureAppearance.NOT_CERTIFIED; + PdfArray arr = (PdfArray)GetPdfObject(dic.Get(PdfName.REFERENCE)); + if (arr == null || arr.Size == 0) + return PdfSignatureAppearance.NOT_CERTIFIED; + dic = (PdfDictionary)GetPdfObject((PdfObject)(arr.ArrayList[0])); + if (dic == null) + return PdfSignatureAppearance.NOT_CERTIFIED; + dic = (PdfDictionary)GetPdfObject(dic.Get(PdfName.TRANSFORMPARAMS)); + if (dic == null) + return PdfSignatureAppearance.NOT_CERTIFIED; + PdfNumber p = (PdfNumber)GetPdfObject(dic.Get(PdfName.P)); + if (p == null) + return PdfSignatureAppearance.NOT_CERTIFIED; + return p.IntValue; + } + + /** + * Checks if the document was opened with the owner password so that the end application + * can decide what level of access restrictions to apply. If the document is not encrypted + * it will return true. + * @return true if the document was opened with the owner password or if it's not encrypted, + * false if the document was opened with the user password + */ + public bool IsOpenedWithFullPermissions { + get { + return !encrypted || ownerPasswordUsed; + } + } + + public int GetCryptoMode() { + if (decrypt == null) + return -1; + else + return decrypt.GetCryptoMode(); + } + + public bool IsMetadataEncrypted() { + if (decrypt == null) + return false; + else + return decrypt.IsMetadataEncrypted(); + } + + public byte[] ComputeUserPassword() { + if (!encrypted || !ownerPasswordUsed) return null; + return decrypt.ComputeUserPassword(password); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfReaderInstance.cs b/iTechSharp/iTextSharp/text/pdf/PdfReaderInstance.cs new file mode 100644 index 0000000..e17b847 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfReaderInstance.cs @@ -0,0 +1,185 @@ +using System; +using System.IO; +using System.Collections; + +using iTextSharp.text; + +/* + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Instance of PdfReader in each output document. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfReaderInstance { + internal static PdfLiteral IDENTITYMATRIX = new PdfLiteral("[1 0 0 1 0 0]"); + internal static PdfNumber ONE = new PdfNumber(1); + internal int[] myXref; + internal PdfReader reader; + internal RandomAccessFileOrArray file; + internal Hashtable importedPages = new Hashtable(); + internal PdfWriter writer; + internal Hashtable visited = new Hashtable(); + internal ArrayList nextRound = new ArrayList(); + + internal PdfReaderInstance(PdfReader reader, PdfWriter writer) { + this.reader = reader; + this.writer = writer; + file = reader.SafeFile; + myXref = new int[reader.XrefSize]; + } + + internal PdfReader Reader { + get { + return reader; + } + } + + internal PdfImportedPage GetImportedPage(int pageNumber) { + if (!reader.IsOpenedWithFullPermissions) + throw new ArgumentException("PdfReader not opened with owner password"); + if (pageNumber < 1 || pageNumber > reader.NumberOfPages) + throw new ArgumentException("Invalid page number: " + pageNumber); + PdfImportedPage pageT = (PdfImportedPage)importedPages[pageNumber]; + if (pageT == null) { + pageT = new PdfImportedPage(this, writer, pageNumber); + importedPages[pageNumber] = pageT; + } + return pageT; + } + + internal int GetNewObjectNumber(int number, int generation) { + if (myXref[number] == 0) { + myXref[number] = writer.IndirectReferenceNumber; + nextRound.Add(number); + } + return myXref[number]; + } + + internal RandomAccessFileOrArray ReaderFile { + get { + return file; + } + } + + internal PdfObject GetResources(int pageNumber) { + PdfObject obj = PdfReader.GetPdfObjectRelease(reader.GetPageNRelease(pageNumber).Get(PdfName.RESOURCES)); + return obj; + } + + + internal PdfStream GetFormXObject(int pageNumber) { + PdfDictionary page = reader.GetPageNRelease(pageNumber); + PdfObject contents = PdfReader.GetPdfObjectRelease(page.Get(PdfName.CONTENTS)); + PdfDictionary dic = new PdfDictionary(); + byte[] bout = null; + if (contents != null) { + if (contents.IsStream()) + dic.Merge((PRStream)contents); + else + bout = reader.GetPageContent(pageNumber, file); + } + else + bout = new byte[0]; + dic.Put(PdfName.RESOURCES, PdfReader.GetPdfObjectRelease(page.Get(PdfName.RESOURCES))); + dic.Put(PdfName.TYPE, PdfName.XOBJECT); + dic.Put(PdfName.SUBTYPE, PdfName.FORM); + PdfImportedPage impPage = (PdfImportedPage)importedPages[pageNumber]; + dic.Put(PdfName.BBOX, new PdfRectangle(impPage.BoundingBox)); + PdfArray matrix = impPage.Matrix; + if (matrix == null) + dic.Put(PdfName.MATRIX, IDENTITYMATRIX); + else + dic.Put(PdfName.MATRIX, matrix); + dic.Put(PdfName.FORMTYPE, ONE); + PRStream stream; + if (bout == null) { + stream = new PRStream((PRStream)contents, dic); + } + else { + stream = new PRStream(reader, bout); + stream.Merge(dic); + } + return stream; + } + + internal void WriteAllVisited() { + while (nextRound.Count > 0) { + ArrayList vec = nextRound; + nextRound = new ArrayList(); + for (int k = 0; k < vec.Count; ++k) { + int i = (int)vec[k]; + if (!visited.ContainsKey(i)) { + visited[i] = null; + writer.AddToBody(reader.GetPdfObjectRelease(i), myXref[i]); + } + } + } + } + + internal void WriteAllPages() { + try { + file.ReOpen(); + foreach (PdfImportedPage ip in importedPages.Values) { + writer.AddToBody(ip.FormXObject, ip.IndirectReference); + } + WriteAllVisited(); + } + finally { + try { + reader.Close(); + file.Close(); + } + catch { + //Empty on purpose + } + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfRectangle.cs b/iTechSharp/iTextSharp/text/pdf/PdfRectangle.cs new file mode 100644 index 0000000..42b36b5 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfRectangle.cs @@ -0,0 +1,290 @@ +using System; + +using iTextSharp.text; + +/* + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfRectangle is the PDF Rectangle object. + *

    + * Rectangles are used to describe locations on the page and bounding boxes for several + * objects in PDF, such as fonts. A rectangle is represented as an array of + * four numbers, specifying the lower lef x, lower left y, upper right x, + * and upper right y coordinates of the rectangle, in that order.
    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 7.1 (page 183). + * + * @see iTextSharp.text.Rectangle + * @see PdfArray + */ + + public class PdfRectangle : PdfArray { + + // membervariables + + /** lower left x */ + private float llx = 0; + + /** lower left y */ + private float lly = 0; + + /** upper right x */ + private float urx = 0; + + /** upper right y */ + private float ury = 0; + + // constructors + + /** + * Constructs a PdfRectangle-object. + * + * @param llx lower left x + * @param lly lower left y + * @param urx upper right x + * @param ury upper right y + * + * @since rugPdf0.10 + */ + + public PdfRectangle(float llx, float lly, float urx, float ury, int rotation) : base() { + if (rotation == 90 || rotation == 270) { + this.llx = lly; + this.lly = llx; + this.urx = ury; + this.ury = urx; + } + else { + this.llx = llx; + this.lly = lly; + this.urx = urx; + this.ury = ury; + } + base.Add(new PdfNumber(this.llx)); + base.Add(new PdfNumber(this.lly)); + base.Add(new PdfNumber(this.urx)); + base.Add(new PdfNumber(this.ury)); + } + + public PdfRectangle(float llx, float lly, float urx, float ury) : this(llx, lly, urx, ury, 0) {} + + /** + * Constructs a PdfRectangle-object starting from the origin (0, 0). + * + * @param urx upper right x + * @param ury upper right y + */ + + public PdfRectangle(float urx, float ury, int rotation) : this(0, 0, urx, ury, rotation) {} + + public PdfRectangle(float urx, float ury) : this(0, 0, urx, ury, 0) {} + + /** + * Constructs a PdfRectangle-object with a Rectangle-object. + * + * @param rectangle a Rectangle + */ + + public PdfRectangle(Rectangle rectangle, int rotation) : this(rectangle.Left, rectangle.Bottom, rectangle.Right, rectangle.Top, rotation) {} + + public PdfRectangle(Rectangle rectangle) : this(rectangle.Left, rectangle.Bottom, rectangle.Right, rectangle.Top, 0) {} + + // methods + + /** + * Returns the high level version of this PdfRectangle + * @return this PdfRectangle translated to class Rectangle + */ + public Rectangle Rectangle { + get { + return new Rectangle(Left, Bottom, Right, Top); + } + } + + /** + * Overrides the add-method in PdfArray in order to prevent the adding of extra object to the array. + * + * @param object PdfObject to add (will not be added here) + * @return false + */ + + public override bool Add(PdfObject obj) { + return false; + } + + /** + * Returns the lower left x-coordinate. + * + * @return the lower left x-coordinaat + */ + + public float Left { + get { + return llx; + } + } + + /** + * Returns the upper right x-coordinate. + * + * @return the upper right x-coordinate + */ + + public float Right { + get { + return urx; + } + } + + /** + * Returns the upper right y-coordinate. + * + * @return the upper right y-coordinate + */ + + public float Top { + get { + return ury; + } + } + + /** + * Returns the lower left y-coordinate. + * + * @return the lower left y-coordinate + */ + + public float Bottom { + get { + return lly; + } + } + + /** + * Returns the lower left x-coordinate, considering a given margin. + * + * @param margin a margin + * @return the lower left x-coordinate + */ + + public float GetLeft(int margin) { + return llx + margin; + } + + /** + * Returns the upper right x-coordinate, considering a given margin. + * + * @param margin a margin + * @return the upper right x-coordinate + */ + + public float GetRight(int margin) { + return urx - margin; + } + + /** + * Returns the upper right y-coordinate, considering a given margin. + * + * @param margin a margin + * @return the upper right y-coordinate + */ + + public float GetTop(int margin) { + return ury - margin; + } + + /** + * Returns the lower left y-coordinate, considering a given margin. + * + * @param margin a margin + * @return the lower left y-coordinate + */ + + public float GetBottom(int margin) { + return lly + margin; + } + + /** + * Returns the width of the rectangle. + * + * @return a width + */ + + public float Width { + get { + return urx - llx; + } + } + + /** + * Returns the height of the rectangle. + * + * @return a height + */ + + public float Height { + get { + return ury - lly; + } + } + + /** + * Swaps the values of urx and ury and of lly and llx in order to rotate the rectangle. + * + * @return a PdfRectangle + */ + + public PdfRectangle Rotate { + get { + return new PdfRectangle(lly, llx, ury, urx, 0); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfRendition.cs b/iTechSharp/iTextSharp/text/pdf/PdfRendition.cs new file mode 100644 index 0000000..f859ef9 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfRendition.cs @@ -0,0 +1,60 @@ +using System; +/* + * Copyright 2003 Galo Gimenez + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * A Rendition dictionary (pdf spec 1.5) + */ + public class PdfRendition : PdfDictionary { + public PdfRendition(String file, PdfFileSpecification fs, String mimeType) { + Put(PdfName.S, new PdfName("MR")); + Put(PdfName.N, new PdfString("Rendition for "+file)); + Put(PdfName.C, new PdfMediaClipData(file, fs, mimeType)); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfResources.cs b/iTechSharp/iTextSharp/text/pdf/PdfResources.cs new file mode 100644 index 0000000..1d44d88 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfResources.cs @@ -0,0 +1,92 @@ +using System; + +/* + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfResources is the PDF Resources-object. + *

    + * The marking operations for drawing a page are stored in a stream that is the value of the + * Contents key in the Page object's dictionary. Each marking context includes a list + * of the named resources it uses. This resource list is stored as a dictionary that is the + * value of the context's Resources key, and it serves two functions: it enumerates + * the named resources in the contents stream, and it established the mapping from the names + * to the objects used by the marking operations.
    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 7.5 (page 195-197). + * + * @see PdfResource + * @see PdfProcSet + * @see PdfFontDictionary + * @see PdfPage + */ + + internal class PdfResources : PdfDictionary { + + // constructor + + /** + * Constructs a PDF ResourcesDictionary. + */ + + internal PdfResources() : base() {} + + // methods + + internal void Add(PdfName key, PdfDictionary resource) { + if (resource.Size == 0) + return; + PdfDictionary dic = (PdfDictionary)PdfReader.GetPdfObject(Get(key)); + if (dic == null) + Put(key, resource); + else + dic.Merge(resource); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfShading.cs b/iTechSharp/iTextSharp/text/pdf/PdfShading.cs new file mode 100644 index 0000000..5a8fb1e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfShading.cs @@ -0,0 +1,277 @@ +using System; +using iTextSharp.text; +/* + * Copyright 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** Implements the shading dictionary (or stream). + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfShading { + + protected PdfDictionary shading; + + protected PdfWriter writer; + + protected int shadingType; + + protected ColorDetails colorDetails; + + protected PdfName shadingName; + + protected PdfIndirectReference shadingReference; + + /** Holds value of property bBox. */ + protected float[] bBox; + + /** Holds value of property antiAlias. */ + protected bool antiAlias = false; + + private Color cspace; + + /** Creates new PdfShading */ + protected PdfShading(PdfWriter writer) { + this.writer = writer; + } + + protected void SetColorSpace(Color color) { + cspace = color; + int type = ExtendedColor.GetType(color); + PdfObject colorSpace = null; + switch (type) { + case ExtendedColor.TYPE_GRAY: { + colorSpace = PdfName.DEVICEGRAY; + break; + } + case ExtendedColor.TYPE_CMYK: { + colorSpace = PdfName.DEVICECMYK; + break; + } + case ExtendedColor.TYPE_SEPARATION: { + SpotColor spot = (SpotColor)color; + colorDetails = writer.AddSimple(spot.PdfSpotColor); + colorSpace = colorDetails.IndirectReference; + break; + } + case ExtendedColor.TYPE_PATTERN: + case ExtendedColor.TYPE_SHADING: { + ThrowColorSpaceError(); + break; + } + default: + colorSpace = PdfName.DEVICERGB; + break; + } + shading.Put(PdfName.COLORSPACE, colorSpace); + } + + public Color ColorSpace { + get { + return cspace; + } + } + + public static void ThrowColorSpaceError() { + throw new ArgumentException("A tiling or shading pattern cannot be used as a color space in a shading pattern"); + } + + public static void CheckCompatibleColors(Color c1, Color c2) { + int type1 = ExtendedColor.GetType(c1); + int type2 = ExtendedColor.GetType(c2); + if (type1 != type2) + throw new ArgumentException("Both colors must be of the same type."); + if (type1 == ExtendedColor.TYPE_SEPARATION && ((SpotColor)c1).PdfSpotColor != ((SpotColor)c2).PdfSpotColor) + throw new ArgumentException("The spot color must be the same, only the tint can vary."); + if (type1 == ExtendedColor.TYPE_PATTERN || type1 == ExtendedColor.TYPE_SHADING) + ThrowColorSpaceError(); + } + + public static float[] GetColorArray(Color color) { + int type = ExtendedColor.GetType(color); + switch (type) { + case ExtendedColor.TYPE_GRAY: { + return new float[]{((GrayColor)color).Gray}; + } + case ExtendedColor.TYPE_CMYK: { + CMYKColor cmyk = (CMYKColor)color; + return new float[]{cmyk.Cyan, cmyk.Magenta, cmyk.Yellow, cmyk.Black}; + } + case ExtendedColor.TYPE_SEPARATION: { + return new float[]{((SpotColor)color).Tint}; + } + case ExtendedColor.TYPE_RGB: { + return new float[]{color.R / 255f, color.G / 255f, color.B / 255f}; + } + } + ThrowColorSpaceError(); + return null; + } + + public static PdfShading Type1(PdfWriter writer, Color colorSpace, float[] domain, float[] tMatrix, PdfFunction function) { + PdfShading sp = new PdfShading(writer); + sp.shading = new PdfDictionary(); + sp.shadingType = 1; + sp.shading.Put(PdfName.SHADINGTYPE, new PdfNumber(sp.shadingType)); + sp.SetColorSpace(colorSpace); + if (domain != null) + sp.shading.Put(PdfName.DOMAIN, new PdfArray(domain)); + if (tMatrix != null) + sp.shading.Put(PdfName.MATRIX, new PdfArray(tMatrix)); + sp.shading.Put(PdfName.FUNCTION, function.Reference); + return sp; + } + + public static PdfShading Type2(PdfWriter writer, Color colorSpace, float[] coords, float[] domain, PdfFunction function, bool[] extend) { + PdfShading sp = new PdfShading(writer); + sp.shading = new PdfDictionary(); + sp.shadingType = 2; + sp.shading.Put(PdfName.SHADINGTYPE, new PdfNumber(sp.shadingType)); + sp.SetColorSpace(colorSpace); + sp.shading.Put(PdfName.COORDS, new PdfArray(coords)); + if (domain != null) + sp.shading.Put(PdfName.DOMAIN, new PdfArray(domain)); + sp.shading.Put(PdfName.FUNCTION, function.Reference); + if (extend != null && (extend[0] || extend[1])) { + PdfArray array = new PdfArray(extend[0] ? PdfBoolean.PDFTRUE : PdfBoolean.PDFFALSE); + array.Add(extend[1] ? PdfBoolean.PDFTRUE : PdfBoolean.PDFFALSE); + sp.shading.Put(PdfName.EXTEND, array); + } + return sp; + } + + public static PdfShading Type3(PdfWriter writer, Color colorSpace, float[] coords, float[] domain, PdfFunction function, bool[] extend) { + PdfShading sp = Type2(writer, colorSpace, coords, domain, function, extend); + sp.shadingType = 3; + sp.shading.Put(PdfName.SHADINGTYPE, new PdfNumber(sp.shadingType)); + return sp; + } + + public static PdfShading SimpleAxial(PdfWriter writer, float x0, float y0, float x1, float y1, Color startColor, Color endColor, bool extendStart, bool extendEnd) { + CheckCompatibleColors(startColor, endColor); + PdfFunction function = PdfFunction.Type2(writer, new float[]{0, 1}, null, GetColorArray(startColor), + GetColorArray(endColor), 1); + return Type2(writer, startColor, new float[]{x0, y0, x1, y1}, null, function, new bool[]{extendStart, extendEnd}); + } + + public static PdfShading SimpleAxial(PdfWriter writer, float x0, float y0, float x1, float y1, Color startColor, Color endColor) { + return SimpleAxial(writer, x0, y0, x1, y1, startColor, endColor, true, true); + } + + public static PdfShading SimpleRadial(PdfWriter writer, float x0, float y0, float r0, float x1, float y1, float r1, Color startColor, Color endColor, bool extendStart, bool extendEnd) { + CheckCompatibleColors(startColor, endColor); + PdfFunction function = PdfFunction.Type2(writer, new float[]{0, 1}, null, GetColorArray(startColor), + GetColorArray(endColor), 1); + return Type3(writer, startColor, new float[]{x0, y0, r0, x1, y1, r1}, null, function, new bool[]{extendStart, extendEnd}); + } + + public static PdfShading SimpleRadial(PdfWriter writer, float x0, float y0, float r0, float x1, float y1, float r1, Color startColor, Color endColor) { + return SimpleRadial(writer, x0, y0, r0, x1, y1, r1, startColor, endColor, true, true); + } + + internal PdfName ShadingName { + get { + return shadingName; + } + } + + internal PdfIndirectReference ShadingReference { + get { + if (shadingReference == null) + shadingReference = writer.PdfIndirectReference; + return shadingReference; + } + } + + internal int Name { + set { + shadingName = new PdfName("Sh" + value); + } + } + + internal void AddToBody() { + if (bBox != null) + shading.Put(PdfName.BBOX, new PdfArray(bBox)); + if (antiAlias) + shading.Put(PdfName.ANTIALIAS, PdfBoolean.PDFTRUE); + writer.AddToBody(shading, this.ShadingReference); + } + + internal PdfWriter Writer { + get { + return writer; + } + } + + internal ColorDetails ColorDetails { + get { + return colorDetails; + } + } + + public float[] BBox { + get { + return bBox; + } + set { + if (value.Length != 4) + throw new ArgumentException("BBox must be a 4 element array."); + this.bBox = value; + } + } + + public bool AntiAlias { + set { + this.antiAlias = value; + } + get { + return antiAlias; + } + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfShadingPattern.cs b/iTechSharp/iTextSharp/text/pdf/PdfShadingPattern.cs new file mode 100644 index 0000000..b633e95 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfShadingPattern.cs @@ -0,0 +1,137 @@ +using System; + +/* + * Copyright 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** Implements the shading pattern dictionary. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfShadingPattern : PdfDictionary { + + protected PdfShading shading; + + protected PdfWriter writer; + + protected float[] matrix = {1, 0, 0, 1, 0, 0}; + + protected PdfName patternName; + + protected PdfIndirectReference patternReference; + + /** Creates new PdfShadingPattern */ + public PdfShadingPattern(PdfShading shading) { + writer = shading.Writer; + Put(PdfName.PATTERNTYPE, new PdfNumber(2)); + this.shading = shading; + } + + internal PdfName PatternName { + get { + return patternName; + } + } + + internal PdfName ShadingName { + get { + return shading.ShadingName; + } + } + + internal PdfIndirectReference PatternReference { + get { + if (patternReference == null) + patternReference = writer.PdfIndirectReference; + return patternReference; + } + } + + internal PdfIndirectReference ShadingReference { + get { + return shading.ShadingReference; + } + } + + internal int Name { + set { + patternName = new PdfName("P" + value); + } + } + + internal void AddToBody() { + Put(PdfName.SHADING, ShadingReference); + Put(PdfName.MATRIX, new PdfArray(matrix)); + writer.AddToBody(this, PatternReference); + } + + public float[] Matrix { + get { + return matrix; + } + + set { + if (value.Length != 6) + throw new Exception("The matrix size must be 6."); + this.matrix = value; + } + } + + public PdfShading Shading { + get { + return shading; + } + } + + internal ColorDetails ColorDetails { + get { + return shading.ColorDetails; + } + } + + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfSigGenericPKCS.cs b/iTechSharp/iTextSharp/text/pdf/PdfSigGenericPKCS.cs new file mode 100644 index 0000000..469a8d5 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfSigGenericPKCS.cs @@ -0,0 +1,196 @@ +using System; +using System.IO; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.Crypto; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** + * A signature dictionary representation for the standard filters. + */ + public abstract class PdfSigGenericPKCS : PdfSignature { + /** + * The hash algorith, for example "SHA1" + */ + protected String hashAlgorithm; + /** + * The class instance that calculates the PKCS#1 and PKCS#7 + */ + protected PdfPKCS7 pkcs; + /** + * The subject name in the signing certificate (the element "CN") + */ + protected String name; + + private byte[] externalDigest; + private byte[] externalRSAdata; + private String digestEncryptionAlgorithm; + + /** + * Creates a generic standard filter. + * @param filter the filter name + * @param subFilter the sub-filter name + */ + public PdfSigGenericPKCS(PdfName filter, PdfName subFilter) : base(filter, subFilter) { + } + + /** + * Sets the crypto information to sign. + * @param privKey the private key + * @param certChain the certificate chain + * @param crlList the certificate revocation list. It can be null + */ + public void SetSignInfo(ICipherParameters privKey, X509Certificate[] certChain, object[] crlList) { + pkcs = new PdfPKCS7(privKey, certChain, crlList, hashAlgorithm, PdfName.ADBE_PKCS7_SHA1.Equals(Get(PdfName.SUBFILTER))); + pkcs.SetExternalDigest(externalDigest, externalRSAdata, digestEncryptionAlgorithm); + if (PdfName.ADBE_X509_RSA_SHA1.Equals(Get(PdfName.SUBFILTER))) { + MemoryStream bout = new MemoryStream(); + for (int k = 0; k < certChain.Length; ++k) { + byte[] tmp = certChain[k].GetEncoded(); + bout.Write(tmp, 0, tmp.Length); + } + bout.Close(); + Cert = bout.ToArray(); + Contents = pkcs.GetEncodedPKCS1(); + } + else + Contents = pkcs.GetEncodedPKCS7(); + name = PdfPKCS7.GetSubjectFields(pkcs.SigningCertificate).GetField("CN"); + if (name != null) + Put(PdfName.NAME, new PdfString(name, PdfObject.TEXT_UNICODE)); + pkcs = new PdfPKCS7(privKey, certChain, crlList, hashAlgorithm, PdfName.ADBE_PKCS7_SHA1.Equals(Get(PdfName.SUBFILTER))); + pkcs.SetExternalDigest(externalDigest, externalRSAdata, digestEncryptionAlgorithm); + } + + /** + * Sets the digest/signature to an external calculated value. + * @param digest the digest. This is the actual signature + * @param RSAdata the extra data that goes into the data tag in PKCS#7 + * @param digestEncryptionAlgorithm the encryption algorithm. It may must be null if the digest + * is also null. If the digest is not null + * then it may be "RSA" or "DSA" + */ + public void SetExternalDigest(byte[] digest, byte[] RSAdata, String digestEncryptionAlgorithm) { + externalDigest = digest; + externalRSAdata = RSAdata; + this.digestEncryptionAlgorithm = digestEncryptionAlgorithm; + } + + /** + * Gets the subject name in the signing certificate (the element "CN") + * @return the subject name in the signing certificate (the element "CN") + */ + public new String Name { + get { + return name; + } + } + + /** + * Gets the class instance that does the actual signing. + * @return the class instance that does the actual signing + */ + public PdfPKCS7 Signer { + get { + return pkcs; + } + } + + /** + * Gets the signature content. This can be a PKCS#1 or a PKCS#7. It corresponds to + * the /Contents key. + * @return the signature content + */ + public byte[] SignerContents { + get { + if (PdfName.ADBE_X509_RSA_SHA1.Equals(Get(PdfName.SUBFILTER))) + return pkcs.GetEncodedPKCS1(); + else + return pkcs.GetEncodedPKCS7(); + } + } + + /** + * Creates a standard filter of the type VeriSign. + */ + public class VeriSign : PdfSigGenericPKCS { + /** + * The constructor for the default provider. + */ + public VeriSign() : base(PdfName.VERISIGN_PPKVS, PdfName.ADBE_PKCS7_DETACHED) { + hashAlgorithm = "MD5"; + Put(PdfName.R, new PdfNumber(65537)); + } + } + + /** + * Creates a standard filter of the type self signed. + */ + public class PPKLite : PdfSigGenericPKCS { + /** + * The constructor for the default provider. + */ + public PPKLite() : base(PdfName.ADOBE_PPKLITE, PdfName.ADBE_X509_RSA_SHA1) { + hashAlgorithm = "SHA1"; + Put(PdfName.R, new PdfNumber(65541)); + } + } + + /** + * Creates a standard filter of the type Windows Certificate. + */ + public class PPKMS : PdfSigGenericPKCS { + /** + * The constructor for the default provider. + */ + public PPKMS() : base(PdfName.ADOBE_PPKMS, PdfName.ADBE_PKCS7_SHA1) { + hashAlgorithm = "SHA1"; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfSignature.cs b/iTechSharp/iTextSharp/text/pdf/PdfSignature.cs new file mode 100644 index 0000000..570fae7 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfSignature.cs @@ -0,0 +1,115 @@ +using System; + +/* + * Copyright 2002 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Implements the signature dictionary. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfSignature : PdfDictionary { + + /** Creates new PdfSignature */ + public PdfSignature(PdfName filter, PdfName subFilter) : base(PdfName.SIG) { + Put(PdfName.FILTER, filter); + Put(PdfName.SUBFILTER, subFilter); + } + + public int[] ByteRange { + set { + PdfArray array = new PdfArray(); + for (int k = 0; k < value.Length; ++k) + array.Add(new PdfNumber(value[k])); + Put(PdfName.BYTERANGE, array); + } + } + + public byte[] Contents { + set { + Put(PdfName.CONTENTS, new PdfString(value).SetHexWriting(true)); + } + } + + public byte[] Cert { + set { + Put(PdfName.CERT, new PdfString(value)); + } + } + + public string Name { + set { + Put(PdfName.NAME, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public PdfDate Date { + set { + Put(PdfName.M, value); + } + } + + public string Location { + set { + Put(PdfName.LOCATION, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public string Reason { + set { + Put(PdfName.REASON, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + + public string Contact { + set { + Put(PdfName.CONTACTINFO, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfSignatureAppearance.cs b/iTechSharp/iTextSharp/text/pdf/PdfSignatureAppearance.cs new file mode 100644 index 0000000..2393763 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfSignatureAppearance.cs @@ -0,0 +1,1445 @@ +using System; +using System.Collections; +using System.Text; +using System.IO; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.Crypto; +using iTextSharp.text; +/* + * $Id: PdfSignatureAppearance.cs,v 1.13 2008/04/17 15:32:39 psoares33 Exp $ + * + * Copyright 2004-2006 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** + * This class takes care of the cryptographic options and appearances that form a signature. + */ + public class PdfSignatureAppearance { + + /** + * Enumeration representing the different rendering options of a signature + */ + public enum SignatureRender { + Description, + NameAndDescription, + GraphicAndDescription + } + + /** + * The self signed filter. + */ + public static PdfName SELF_SIGNED = PdfName.ADOBE_PPKLITE; + /** + * The VeriSign filter. + */ + public static PdfName VERISIGN_SIGNED = PdfName.VERISIGN_PPKVS; + /** + * The Windows Certificate Security. + */ + public static PdfName WINCER_SIGNED = PdfName.ADOBE_PPKMS; + + public const int NOT_CERTIFIED = 0; + public const int CERTIFIED_NO_CHANGES_ALLOWED = 1; + public const int CERTIFIED_FORM_FILLING = 2; + public const int CERTIFIED_FORM_FILLING_AND_ANNOTATIONS = 3; + + private const float TOP_SECTION = 0.3f; + private const float MARGIN = 2; + private Rectangle rect; + private Rectangle pageRect; + private PdfTemplate[] app = new PdfTemplate[5]; + private PdfTemplate frm; + private PdfStamperImp writer; + private String layer2Text; + private String reason; + private String location; + private DateTime signDate; + private int page = 1; + private String fieldName; + private ICipherParameters privKey; + private X509Certificate[] certChain; + private object[] crlList; + private PdfName filter; + private bool newField; + private ByteBuffer sigout; + private Stream originalout; + private string tempFile; + private PdfDictionary cryptoDictionary; + private PdfStamper stamper; + private bool preClosed = false; + private PdfSigGenericPKCS sigStandard; + private int[] range; + private FileStream raf; + private byte[] bout; + private int boutLen; + private byte[] externalDigest; + private byte[] externalRSAdata; + private String digestEncryptionAlgorithm; + private Hashtable exclusionLocations; + + internal PdfSignatureAppearance(PdfStamperImp writer) { + this.writer = writer; + signDate = DateTime.Now; + fieldName = GetNewSigName(); + } + + /** + * Gets the rendering mode for this signature . + * @return the rectangle rendering mode for this signature. + */ + private SignatureRender render = SignatureRender.Description; + + public SignatureRender Render { + get { + return render; + } + set { + render = value; + } + } + + /** + * Sets the Image object to render when Render is set to SignatureRender.GraphicAndDescription + * @param image rendered. If null the mode is defaulted + * to SignatureRender.Description + */ + private Image signatureGraphic = null; + + public Image SignatureGraphic { + get { + return signatureGraphic; + } + set { + signatureGraphic = value; + } + } + + /** + * Sets the signature text identifying the signer. + * @param text the signature text identifying the signer. If null or not set + * a standard description will be used + */ + public string Layer2Text { + get { + return layer2Text; + } + set { + layer2Text = value; + } + } + + /** + * Sets the text identifying the signature status. + * @param text the text identifying the signature status. If null or not set + * the description "Signature Not Verified" will be used + */ + public string Layer4Text { + get { + return layer4Text; + } + set { + layer4Text = value; + } + } + + /** + * Gets the rectangle representing the signature dimensions. + * @return the rectangle representing the signature dimensions. It may be null + * or have zero width or height for invisible signatures + */ + public Rectangle Rect { + get { + return rect; + } + } + + /** + * Gets the visibility status of the signature. + * @return the visibility status of the signature + */ + public bool IsInvisible() { + return (rect == null || rect.Width == 0 || rect.Height == 0); + } + + /** + * Sets the cryptographic parameters. + * @param privKey the private key + * @param certChain the certificate chain + * @param crlList the certificate revocation list. It may be null + * @param filter the crytographic filter type. It can be SELF_SIGNED, VERISIGN_SIGNED or WINCER_SIGNED + */ + public void SetCrypto(ICipherParameters privKey, X509Certificate[] certChain, object[] crlList, PdfName filter) { + this.privKey = privKey; + this.certChain = certChain; + this.crlList = crlList; + this.filter = filter; + } + + /** + * Sets the signature to be visible. It creates a new visible signature field. + * @param pageRect the position and dimension of the field in the page + * @param page the page to place the field. The fist page is 1 + * @param fieldName the field name or null to generate automatically a new field name + */ + public void SetVisibleSignature(Rectangle pageRect, int page, String fieldName) { + if (fieldName != null) { + if (fieldName.IndexOf('.') >= 0) + throw new ArgumentException("Field names cannot contain a dot."); + AcroFields af = writer.AcroFields; + AcroFields.Item item = af.GetFieldItem(fieldName); + if (item != null) + throw new ArgumentException("The field " + fieldName + " already exists."); + this.fieldName = fieldName; + } + if (page < 1 || page > writer.reader.NumberOfPages) + throw new ArgumentException("Invalid page number: " + page); + this.pageRect = new Rectangle(pageRect); + this.pageRect.Normalize(); + rect = new Rectangle(this.pageRect.Width, this.pageRect.Height); + this.page = page; + newField = true; + } + + /** + * Sets the signature to be visible. An empty signature field with the same name must already exist. + * @param fieldName the existing empty signature field name + */ + public void SetVisibleSignature(String fieldName) { + AcroFields af = writer.AcroFields; + AcroFields.Item item = af.GetFieldItem(fieldName); + if (item == null) + throw new ArgumentException("The field " + fieldName + " does not exist."); + PdfDictionary merged = (PdfDictionary)item.merged[0]; + if (!PdfName.SIG.Equals(PdfReader.GetPdfObject(merged.Get(PdfName.FT)))) + throw new ArgumentException("The field " + fieldName + " is not a signature field."); + this.fieldName = fieldName; + PdfArray r = (PdfArray)PdfReader.GetPdfObject(merged.Get(PdfName.RECT)); + ArrayList ar = r.ArrayList; + float llx = ((PdfNumber)PdfReader.GetPdfObject((PdfObject)ar[0])).FloatValue; + float lly = ((PdfNumber)PdfReader.GetPdfObject((PdfObject)ar[1])).FloatValue; + float urx = ((PdfNumber)PdfReader.GetPdfObject((PdfObject)ar[2])).FloatValue; + float ury = ((PdfNumber)PdfReader.GetPdfObject((PdfObject)ar[3])).FloatValue; + pageRect = new Rectangle(llx, lly, urx, ury); + pageRect.Normalize(); + page = (int)item.page[0]; + int rotation = writer.reader.GetPageRotation(page); + Rectangle pageSize = writer.reader.GetPageSizeWithRotation(page); + switch (rotation) { + case 90: + pageRect = new Rectangle( + pageRect.Bottom, + pageSize.Top - pageRect.Left, + pageRect.Top, + pageSize.Top - pageRect.Right); + break; + case 180: + pageRect = new Rectangle( + pageSize.Right - pageRect.Left, + pageSize.Top - pageRect.Bottom, + pageSize.Right - pageRect.Right, + pageSize.Top - pageRect.Top); + break; + case 270: + pageRect = new Rectangle( + pageSize.Right - pageRect.Bottom, + pageRect.Left, + pageSize.Right - pageRect.Top, + pageRect.Right); + break; + } + if (rotation != 0) + pageRect.Normalize(); + rect = new Rectangle(this.pageRect.Width, this.pageRect.Height); + } + + /** + * Gets a template layer to create a signature appearance. The layers can go from 0 to 4. + *

    + * Consult PPKAppearances.pdf + * for further details. + * @param layer the layer + * @return a template + */ + public PdfTemplate GetLayer(int layer) { + if (layer < 0 || layer >= app.Length) + return null; + PdfTemplate t = app[layer]; + if (t == null) { + t = app[layer] = new PdfTemplate(writer); + t.BoundingBox = rect; + writer.AddDirectTemplateSimple(t, new PdfName("n" + layer)); + } + return t; + } + + /** + * Gets the template that aggregates all appearance layers. This corresponds to the /FRM resource. + *

    + * Consult PPKAppearances.pdf + * for further details. + * @return the template that aggregates all appearance layers + */ + public PdfTemplate GetTopLayer() { + if (frm == null) { + frm = new PdfTemplate(writer); + frm.BoundingBox = rect; + writer.AddDirectTemplateSimple(frm, new PdfName("FRM")); + } + return frm; + } + + /** + * Gets the main appearance layer. + *

    + * Consult PPKAppearances.pdf + * for further details. + * @return the main appearance layer + * @throws DocumentException on error + * @throws IOException on error + */ + public PdfTemplate GetAppearance() { + if (IsInvisible()) { + PdfTemplate t = new PdfTemplate(writer); + t.BoundingBox = new Rectangle(0, 0); + writer.AddDirectTemplateSimple(t, null); + return t; + } + if (app[0] == null) { + PdfTemplate t = app[0] = new PdfTemplate(writer); + t.BoundingBox = new Rectangle(100, 100); + writer.AddDirectTemplateSimple(t, new PdfName("n0")); + t.SetLiteral("% DSBlank\n"); + } + if (app[1] == null && !acro6Layers) { + PdfTemplate t = app[1] = new PdfTemplate(writer); + t.BoundingBox = new Rectangle(100, 100); + writer.AddDirectTemplateSimple(t, new PdfName("n1")); + t.SetLiteral(questionMark); + } + if (app[2] == null) { + String text; + if (layer2Text == null) { + StringBuilder buf = new StringBuilder(); + buf.Append("Digitally signed by ").Append(PdfPKCS7.GetSubjectFields((X509Certificate)certChain[0]).GetField("CN")).Append('\n'); + buf.Append("Date: ").Append(signDate.ToString("yyyy.MM.dd HH:mm:ss zzz")); + if (reason != null) + buf.Append('\n').Append("Reason: ").Append(reason); + if (location != null) + buf.Append('\n').Append("Location: ").Append(location); + text = buf.ToString(); + } + else + text = layer2Text; + PdfTemplate t = app[2] = new PdfTemplate(writer); + t.BoundingBox = rect; + writer.AddDirectTemplateSimple(t, new PdfName("n2")); + if (image != null) { + if (imageScale == 0) { + t.AddImage(image, rect.Width, 0, 0, rect.Height, 0, 0); + } + else { + float usableScale = imageScale; + if (imageScale < 0) + usableScale = Math.Min(rect.Width / image.Width, rect.Height / image.Height); + float w = image.Width * usableScale; + float h = image.Height * usableScale; + float x = (rect.Width - w) / 2; + float y = (rect.Height - h) / 2; + t.AddImage(image, w, 0, 0, h, x, y); + } + } + Font font; + if (layer2Font == null) + font = new Font(); + else + font = new Font(layer2Font); + float size = font.Size; + + Rectangle dataRect = null; + Rectangle signatureRect = null; + + if (Render == SignatureRender.NameAndDescription || + (Render == SignatureRender.GraphicAndDescription && this.SignatureGraphic != null)) { + // origin is the bottom-left + signatureRect = new Rectangle( + MARGIN, + MARGIN, + rect.Width / 2 - MARGIN, + rect.Height - MARGIN); + dataRect = new Rectangle( + rect.Width / 2 + MARGIN / 2, + MARGIN, + rect.Width - MARGIN / 2, + rect.Height - MARGIN); + + if (rect.Height > rect.Width) { + signatureRect = new Rectangle( + MARGIN, + rect.Height / 2, + rect.Width - MARGIN, + rect.Height); + dataRect = new Rectangle( + MARGIN, + MARGIN, + rect.Width - MARGIN, + rect.Height / 2 - MARGIN); + } + } + else { + dataRect = new Rectangle( + MARGIN, + MARGIN, + rect.Width - MARGIN, + rect.Height * (1 - TOP_SECTION) - MARGIN); + } + + if (Render == SignatureRender.NameAndDescription) { + string signedBy = iTextSharp.text.pdf.PdfPKCS7.GetSubjectFields(this.certChain[0]).GetField("CN"); + Rectangle sr2 = new Rectangle(signatureRect.Width - MARGIN, signatureRect.Height - MARGIN ); + float signedSize = FitText(font, signedBy, sr2, -1, runDirection); + + ColumnText ct2 = new ColumnText(t); + ct2.RunDirection = runDirection; + ct2.SetSimpleColumn(new Phrase(signedBy, font), signatureRect.Left, signatureRect.Bottom, signatureRect.Right, signatureRect.Top, signedSize, Element.ALIGN_LEFT); + + ct2.Go(); + } + else if (Render == SignatureRender.GraphicAndDescription) { + ColumnText ct2 = new ColumnText(t); + ct2.RunDirection = runDirection; + ct2.SetSimpleColumn(signatureRect.Left, signatureRect.Bottom, signatureRect.Right, signatureRect.Top, 0, Element.ALIGN_RIGHT); + + Image im = Image.GetInstance(SignatureGraphic); + im.ScaleToFit(signatureRect.Width, signatureRect.Height); + + Paragraph p = new Paragraph(); + // must calculate the point to draw from to make image appear in middle of column + float x = 0; + // experimentation found this magic number to counteract Adobe's signature graphic, which + // offsets the y co-ordinate by 15 units + float y = -im.ScaledHeight + 15; + + x = x + (signatureRect.Width - im.ScaledWidth) / 2; + y = y - (signatureRect.Height - im.ScaledHeight) / 2; + p.Add(new Chunk(im, x + (signatureRect.Width - im.ScaledWidth) / 2, y, false)); + ct2.AddElement(p); + ct2.Go(); + } + + if (size <= 0) { + Rectangle sr = new Rectangle(dataRect.Width, dataRect.Height); + size = FitText(font, text, sr, 12, runDirection); + } + ColumnText ct = new ColumnText(t); + ct.RunDirection = runDirection; + ct.SetSimpleColumn(new Phrase(text, font), dataRect.Left, dataRect.Bottom, dataRect.Right, dataRect.Top, size, Element.ALIGN_LEFT); + ct.Go(); + + } + if (app[3] == null && !acro6Layers) { + PdfTemplate t = app[3] = new PdfTemplate(writer); + t.BoundingBox = new Rectangle(100, 100); + writer.AddDirectTemplateSimple(t, new PdfName("n3")); + t.SetLiteral("% DSBlank\n"); + } + if (app[4] == null && !acro6Layers) { + PdfTemplate t = app[4] = new PdfTemplate(writer); + t.BoundingBox = new Rectangle(0, rect.Height * (1 - TOP_SECTION), rect.Right, rect.Top); + writer.AddDirectTemplateSimple(t, new PdfName("n4")); + Font font; + if (layer2Font == null) + font = new Font(); + else + font = new Font(layer2Font); + float size = font.Size; + String text = "Signature Not Verified"; + if (layer4Text != null) + text = layer4Text; + Rectangle sr = new Rectangle(rect.Width - 2 * MARGIN, rect.Height * TOP_SECTION - 2 * MARGIN); + size = FitText(font, text, sr, 15, runDirection); + ColumnText ct = new ColumnText(t); + ct.RunDirection = runDirection; + ct.SetSimpleColumn(new Phrase(text, font), MARGIN, 0, rect.Width - MARGIN, rect.Height - MARGIN, size, Element.ALIGN_LEFT); + ct.Go(); + } + int rotation = writer.reader.GetPageRotation(page); + Rectangle rotated = new Rectangle(rect); + int n = rotation; + while (n > 0) { + rotated = rotated.Rotate(); + n -= 90; + } + if (frm == null) { + frm = new PdfTemplate(writer); + frm.BoundingBox = rotated; + writer.AddDirectTemplateSimple(frm, new PdfName("FRM")); + float scale = Math.Min(rect.Width, rect.Height) * 0.9f; + float x = (rect.Width - scale) / 2; + float y = (rect.Height - scale) / 2; + scale /= 100; + if (rotation == 90) + frm.ConcatCTM(0, 1, -1, 0, rect.Height, 0); + else if (rotation == 180) + frm.ConcatCTM(-1, 0, 0, -1, rect.Width, rect.Height); + else if (rotation == 270) + frm.ConcatCTM(0, -1, 1, 0, 0, rect.Width); + frm.AddTemplate(app[0], 0, 0); + if (!acro6Layers) + frm.AddTemplate(app[1], scale, 0, 0, scale, x, y); + frm.AddTemplate(app[2], 0, 0); + if (!acro6Layers) { + frm.AddTemplate(app[3], scale, 0, 0, scale, x, y); + frm.AddTemplate(app[4], 0, 0); + } + } + PdfTemplate napp = new PdfTemplate(writer); + napp.BoundingBox = rotated; + writer.AddDirectTemplateSimple(napp, null); + napp.AddTemplate(frm, 0, 0); + return napp; + } + + /** + * Fits the text to some rectangle adjusting the font size as needed. + * @param font the font to use + * @param text the text + * @param rect the rectangle where the text must fit + * @param maxFontSize the maximum font size + * @param runDirection the run direction + * @return the calculated font size that makes the text fit + */ + public static float FitText(Font font, String text, Rectangle rect, float maxFontSize, int runDirection) { + ColumnText ct = null; + int status = 0; + if (maxFontSize <= 0) { + int cr = 0; + int lf = 0; + char[] t = text.ToCharArray(); + for (int k = 0; k < t.Length; ++k) { + if (t[k] == '\n') + ++lf; + else if (t[k] == '\r') + ++cr; + } + int minLines = Math.Max(cr, lf) + 1; + maxFontSize = Math.Abs(rect.Height) / minLines - 0.001f; + } + font.Size = maxFontSize; + Phrase ph = new Phrase(text, font); + ct = new ColumnText(null); + ct.SetSimpleColumn(ph, rect.Left, rect.Bottom, rect.Right, rect.Top, maxFontSize, Element.ALIGN_LEFT); + ct.RunDirection = runDirection; + status = ct.Go(true); + if ((status & ColumnText.NO_MORE_TEXT) != 0) + return maxFontSize; + float precision = 0.1f; + float min = 0; + float max = maxFontSize; + float size = maxFontSize; + for (int k = 0; k < 50; ++k) { //just in case it doesn't converge + size = (min + max) / 2; + ct = new ColumnText(null); + font.Size = size; + ct.SetSimpleColumn(new Phrase(text, font), rect.Left, rect.Bottom, rect.Right, rect.Top, size, Element.ALIGN_LEFT); + ct.RunDirection = runDirection; + status = ct.Go(true); + if ((status & ColumnText.NO_MORE_TEXT) != 0) { + if (max - min < size * precision) + return size; + min = size; + } + else + max = size; + } + return size; + } + + /** + * Sets the digest/signature to an external calculated value. + * @param digest the digest. This is the actual signature + * @param RSAdata the extra data that goes into the data tag in PKCS#7 + * @param digestEncryptionAlgorithm the encryption algorithm. It may must be null if the digest + * is also null. If the digest is not null + * then it may be "RSA" or "DSA" + */ + public void SetExternalDigest(byte[] digest, byte[] RSAdata, String digestEncryptionAlgorithm) { + externalDigest = digest; + externalRSAdata = RSAdata; + this.digestEncryptionAlgorithm = digestEncryptionAlgorithm; + } + + /** + * Sets the signing reason. + * @param reason the signing reason + */ + public string Reason { + get { + return reason; + } + set { + reason = value; + } + } + + /** + * Sets the signing location. + * @param location the signing location + */ + public string Location { + get { + return location; + } + set { + location = value; + } + } + + /** + * Gets the private key. + * @return the private key + */ + public ICipherParameters PrivKey { + get { + return privKey; + } + } + + /** + * Gets the certificate chain. + * @return the certificate chain + */ + public X509Certificate[] CertChain { + get { + return this.certChain; + } + } + + /** + * Gets the certificate revocation list. + * @return the certificate revocation list + */ + public object[] CrlList { + get { + return this.crlList; + } + } + + /** + * Gets the filter used to sign the document. + * @return the filter used to sign the document + */ + public PdfName Filter { + get { + return filter; + } + } + + /** + * Checks if a new field was created. + * @return true if a new field was created, false if signing + * an existing field or if the signature is invisible + */ + public bool IsNewField() { + return this.newField; + } + + /** + * Gets the page number of the field. + * @return the page number of the field + */ + public int Page { + get { + return page; + } + } + + /** + * Gets the field name. + * @return the field name + */ + public String FieldName { + get { + return fieldName; + } + } + + /** + * Gets the rectangle that represent the position and dimension of the signature in the page. + * @return the rectangle that represent the position and dimension of the signature in the page + */ + public Rectangle PageRect { + get { + return pageRect; + } + } + + /** + * Gets the signature date. + * @return the signature date + */ + public DateTime SignDate { + get { + return signDate; + } + set { + signDate = value; + } + } + + internal ByteBuffer Sigout { + get { + return sigout; + } + set { + sigout = value; + } + } + + internal Stream Originalout { + get { + return originalout; + } + set { + originalout = value; + } + } + + /** + * Gets the temporary file. + * @return the temporary file or null is the document is created in memory + */ + public string TempFile { + get { + return tempFile; + } + } + + internal void SetTempFile(string tempFile) { + this.tempFile = tempFile; + } + + /** + * Gets a new signature fied name that doesn't clash with any existing name. + * @return a new signature fied name + */ + public String GetNewSigName() { + AcroFields af = writer.AcroFields; + String name = "Signature"; + int step = 0; + bool found = false; + while (!found) { + ++step; + String n1 = name + step; + if (af.GetFieldItem(n1) != null) + continue; + n1 += "."; + found = true; + foreach (String fn in af.Fields.Keys) { + if (fn.StartsWith(n1)) { + found = false; + break; + } + } + } + name += step; + return name; + } + + /** + * This is the first method to be called when using external signatures. The general sequence is: + * PreClose(), GetDocumentBytes() and Close(). + *

    + * If calling PreClose() dont't call PdfStamper.Close(). + *

    + * No external signatures are allowed if this methos is called. + * @throws IOException on error + * @throws DocumentException on error + */ + public void PreClose() { + PreClose(null); + } + /** + * This is the first method to be called when using external signatures. The general sequence is: + * PreClose(), GetDocumentBytes() and Close(). + *

    + * If calling PreClose() dont't call PdfStamper.Close(). + *

    + * If using an external signature exclusionSizes must contain at least + * the PdfName.CONTENTS key with the size that it will take in the + * document. Note that due to the hex string coding this size should be + * byte_size*2+2. + * @param exclusionSizes a Hashtable with names and sizes to be excluded in the signature + * calculation. The key is a PdfName and the value an + * Integer. At least the PdfName.CONTENTS must be present + * @throws IOException on error + * @throws DocumentException on error + */ + public void PreClose(Hashtable exclusionSizes) { + if (preClosed) + throw new DocumentException("Document already pre closed."); + preClosed = true; + AcroFields af = writer.AcroFields; + String name = FieldName; + bool fieldExists = !(IsInvisible() || IsNewField()); + PdfIndirectReference refSig = writer.PdfIndirectReference; + writer.SigFlags = 3; + if (fieldExists) { + ArrayList widgets = af.GetFieldItem(name).widgets; + PdfDictionary widget = (PdfDictionary)widgets[0]; + writer.MarkUsed(widget); + widget.Put(PdfName.P, writer.GetPageReference(Page)); + widget.Put(PdfName.V, refSig); + PdfObject obj = PdfReader.GetPdfObjectRelease(widget.Get(PdfName.F)); + int flags = 0; + if (obj != null && obj.IsNumber()) + flags = ((PdfNumber)obj).IntValue; + flags |= PdfAnnotation.FLAGS_LOCKED; + widget.Put(PdfName.F, new PdfNumber(flags)); + PdfDictionary ap = new PdfDictionary(); + ap.Put(PdfName.N, GetAppearance().IndirectReference); + widget.Put(PdfName.AP, ap); + } + else { + PdfFormField sigField = PdfFormField.CreateSignature(writer); + sigField.FieldName = name; + sigField.Put(PdfName.V, refSig); + sigField.Flags = PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_LOCKED; + + int pagen = Page; + if (!IsInvisible()) + sigField.SetWidget(PageRect, null); + else + sigField.SetWidget(new Rectangle(0, 0), null); + sigField.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, GetAppearance()); + sigField.Page = pagen; + writer.AddAnnotation(sigField, pagen); + } + + exclusionLocations = new Hashtable(); + if (cryptoDictionary == null) { + if (PdfName.ADOBE_PPKLITE.Equals(Filter)) + sigStandard = new PdfSigGenericPKCS.PPKLite(); + else if (PdfName.ADOBE_PPKMS.Equals(Filter)) + sigStandard = new PdfSigGenericPKCS.PPKMS(); + else if (PdfName.VERISIGN_PPKVS.Equals(Filter)) + sigStandard = new PdfSigGenericPKCS.VeriSign(); + else + throw new ArgumentException("Unknown filter: " + Filter); + sigStandard.SetExternalDigest(externalDigest, externalRSAdata, digestEncryptionAlgorithm); + if (Reason != null) + sigStandard.Reason = Reason; + if (Location != null) + sigStandard.Location = Location; + if (Contact != null) + sigStandard.Contact = Contact; + sigStandard.Put(PdfName.M, new PdfDate(SignDate)); + sigStandard.SetSignInfo(PrivKey, CertChain, CrlList); + PdfString contents = (PdfString)sigStandard.Get(PdfName.CONTENTS); + PdfLiteral lit = new PdfLiteral((contents.ToString().Length + (PdfName.ADOBE_PPKLITE.Equals(Filter)?0:64)) * 2 + 2); + exclusionLocations[PdfName.CONTENTS] = lit; + sigStandard.Put(PdfName.CONTENTS, lit); + lit = new PdfLiteral(80); + exclusionLocations[PdfName.BYTERANGE] = lit; + sigStandard.Put(PdfName.BYTERANGE, lit); + if (certificationLevel > 0) + AddDocMDP(sigStandard); + if (signatureEvent != null) + signatureEvent.GetSignatureDictionary(sigStandard); + writer.AddToBody(sigStandard, refSig, false); + } + else { + PdfLiteral lit = new PdfLiteral(80); + exclusionLocations[PdfName.BYTERANGE] = lit; + cryptoDictionary.Put(PdfName.BYTERANGE, lit); + foreach (DictionaryEntry entry in exclusionSizes) { + PdfName key = (PdfName)entry.Key; + int v = (int)entry.Value; + lit = new PdfLiteral(v); + exclusionLocations[key] = lit; + cryptoDictionary.Put(key, lit); + } + if (certificationLevel > 0) + AddDocMDP(cryptoDictionary); + if (signatureEvent != null) + signatureEvent.GetSignatureDictionary(cryptoDictionary); + writer.AddToBody(cryptoDictionary, refSig, false); + } + if (certificationLevel > 0) { + // add DocMDP entry to root + PdfDictionary docmdp = new PdfDictionary(); + docmdp.Put(new PdfName("DocMDP"), refSig); + writer.reader.Catalog.Put(new PdfName("Perms"), docmdp); + } + writer.Close(stamper.MoreInfo); + + range = new int[exclusionLocations.Count * 2]; + int byteRangePosition = ((PdfLiteral)exclusionLocations[PdfName.BYTERANGE]).Position; + exclusionLocations.Remove(PdfName.BYTERANGE); + int idx = 1; + foreach (PdfLiteral lit in exclusionLocations.Values) { + int n = lit.Position; + range[idx++] = n; + range[idx++] = lit.PosLength + n; + } + Array.Sort(range, 1, range.Length - 2); + for (int k = 3; k < range.Length - 2; k += 2) + range[k] -= range[k - 1]; + + if (tempFile == null) { + bout = sigout.Buffer; + boutLen = sigout.Size; + range[range.Length - 1] = boutLen - range[range.Length - 2]; + ByteBuffer bf = new ByteBuffer(); + bf.Append('['); + for (int k = 0; k < range.Length; ++k) + bf.Append(range[k]).Append(' '); + bf.Append(']'); + Array.Copy(bf.Buffer, 0, bout, byteRangePosition, bf.Size); + } + else { + try { + raf = new FileStream(tempFile, FileMode.Open, FileAccess.ReadWrite); + int boutLen = (int)raf.Length; + range[range.Length - 1] = boutLen - range[range.Length - 2]; + ByteBuffer bf = new ByteBuffer(); + bf.Append('['); + for (int k = 0; k < range.Length; ++k) + bf.Append(range[k]).Append(' '); + bf.Append(']'); + raf.Seek(byteRangePosition, SeekOrigin.Begin); + raf.Write(bf.Buffer, 0, bf.Size); + } + catch (IOException e) { + try{raf.Close();}catch{} + try{File.Delete(tempFile);}catch{} + throw e; + } + } + } + + /** + * This is the last method to be called when using external signatures. The general sequence is: + * PreClose(), GetDocumentBytes() and Close(). + *

    + * update is a PdfDictionary that must have exactly the + * same keys as the ones provided in {@link #preClose(Hashtable)}. + * @param update a PdfDictionary with the key/value that will fill the holes defined + * in {@link #preClose(Hashtable)} + * @throws DocumentException on error + * @throws IOException on error + */ + public void Close(PdfDictionary update) { + try { + if (!preClosed) + throw new DocumentException("preClose() must be called first."); + ByteBuffer bf = new ByteBuffer(); + foreach (PdfName key in update.Keys) { + PdfObject obj = update.Get(key); + PdfLiteral lit = (PdfLiteral)exclusionLocations[key]; + if (lit == null) + throw new ArgumentException("The key " + key.ToString() + " didn't reserve space in PreClose()."); + bf.Reset(); + obj.ToPdf(null, bf); + if (bf.Size > lit.PosLength) + throw new ArgumentException("The key " + key.ToString() + " is too big. Is " + bf.Size + ", reserved " + lit.PosLength); + if (tempFile == null) + Array.Copy(bf.Buffer, 0, bout, lit.Position, bf.Size); + else { + raf.Seek(lit.Position, SeekOrigin.Begin); + raf.Write(bf.Buffer, 0, bf.Size); + } + } + if (update.Size != exclusionLocations.Count) + throw new ArgumentException("The update dictionary has less keys than required."); + if (tempFile == null) { + originalout.Write(bout, 0, boutLen); + } + else { + if (originalout != null) { + raf.Seek(0, SeekOrigin.Begin); + int length = (int)raf.Length; + byte[] buf = new byte[8192]; + while (length > 0) { + int r = raf.Read(buf, 0, Math.Min(buf.Length, length)); + if (r < 0) + throw new EndOfStreamException("Unexpected EOF"); + originalout.Write(buf, 0, r); + length -= r; + } + } + } + } + finally { + if (tempFile != null) { + try{raf.Close();}catch{} + if (originalout != null) + try{File.Delete(tempFile);}catch{} + } + if (originalout != null) + try{originalout.Close();}catch{} + } + } + + private void AddDocMDP(PdfDictionary crypto) { + PdfDictionary reference = new PdfDictionary(); + PdfDictionary transformParams = new PdfDictionary(); + transformParams.Put(PdfName.P, new PdfNumber(certificationLevel)); + transformParams.Put(PdfName.V, new PdfName("1.2")); + transformParams.Put(PdfName.TYPE, PdfName.TRANSFORMPARAMS); + reference.Put(PdfName.TRANSFORMMETHOD, PdfName.DOCMDP); + reference.Put(PdfName.TYPE, PdfName.SIGREF); + reference.Put(PdfName.TRANSFORMPARAMS, transformParams); + reference.Put(new PdfName("DigestValue"), new PdfString("aa")); + PdfArray loc = new PdfArray(); + loc.Add(new PdfNumber(0)); + loc.Add(new PdfNumber(0)); + reference.Put(new PdfName("DigestLocation"), loc); + reference.Put(new PdfName("DigestMethod"), new PdfName("MD5")); + reference.Put(PdfName.DATA, writer.reader.Trailer.Get(PdfName.ROOT)); + PdfArray types = new PdfArray(); + types.Add(reference); + crypto.Put(PdfName.REFERENCE, types); + } + + /** + * Gets the document bytes that are hashable when using external signatures. The general sequence is: + * PreClose(), GetRangeStream() and Close(). + *

    + * @return the document bytes that are hashable + */ + public Stream RangeStream { + get { + return new PdfSignatureAppearance.FRangeStream(raf, bout, range); + } + } + + /** + * Gets the user made signature dictionary. This is the dictionary at the /V key. + * @return the user made signature dictionary + */ + public PdfDictionary CryptoDictionary { + get { + return cryptoDictionary; + } + set { + cryptoDictionary = value; + } + } + + /** + * Gets the PdfStamper associated with this instance. + * @return the PdfStamper associated with this instance + */ + public PdfStamper Stamper { + get { + return stamper; + } + } + + internal void SetStamper(PdfStamper stamper) { + this.stamper = stamper; + } + + /** + * Checks if the document is in the process of closing. + * @return true if the document is in the process of closing, + * false otherwise + */ + public bool IsPreClosed() { + return preClosed; + } + + /** + * Gets the instance of the standard signature dictionary. This instance + * is only available after pre close. + *

    + * The main use is to insert external signatures. + * @return the instance of the standard signature dictionary + */ + public PdfSigGenericPKCS SigStandard { + get { + return sigStandard; + } + } + + /** + * Sets the signing contact. + * @param contact the signing contact + */ + public string Contact { + get { + return contact; + } + set { + contact = value; + } + } + + /** + * Sets the n2 and n4 layer font. If the font size is zero, auto-fit will be used. + * @param layer2Font the n2 and n4 font + */ + public Font Layer2Font { + get { + return layer2Font; + } + set { + layer2Font = value; + } + } + + /** + * Acrobat 6.0 and higher recomends that only layer n2 and n4 be present. This method sets that mode. + * @param acro6Layers if true only the layers n2 and n4 will be present + */ + public bool Acro6Layers { + get { + return acro6Layers; + } + set { + acro6Layers = value; + } + } + + /** Sets the run direction in the n2 and n4 layer. + * @param runDirection the run direction + */ + public int RunDirection { + set { + if (value < PdfWriter.RUN_DIRECTION_DEFAULT || value > PdfWriter.RUN_DIRECTION_RTL) + throw new ArgumentException("Invalid run direction: " + runDirection); + this.runDirection = value; + } + get { + return runDirection; + } + } + + /** + * Sets the signature event to allow modification of the signature dictionary. + * @param signatureEvent the signature event + */ + public ISignatureEvent SignatureEvent { + get { + return signatureEvent; + } + set { + signatureEvent = value; + } + } + /** + * Gets the background image for the layer 2. + * @return the background image for the layer 2 + */ + public Image GetImage() { + return this.image; + } + + /** + * Sets the background image for the layer 2. + * @param image the background image for the layer 2 + */ + public Image Image { + get { + return image; + } + set { + image = value; + } + } + + /** + * Sets the scaling to be applied to the background image. If it's zero the image + * will fully fill the rectangle. If it's less than zero the image will fill the rectangle but + * will keep the proportions. If it's greater than zero that scaling will be applied. + * In any of the cases the image will always be centered. It's zero by default. + * @param imageScale the scaling to be applied to the background image + */ + public float ImageScale { + get { + return imageScale; + } + set { + imageScale = value; + } + } + + /** + * Commands to draw a yellow question mark in a stream content + */ + public const String questionMark = + "% DSUnknown\n" + + "q\n" + + "1 G\n" + + "1 g\n" + + "0.1 0 0 0.1 9 0 cm\n" + + "0 J 0 j 4 M []0 d\n" + + "1 i \n" + + "0 g\n" + + "313 292 m\n" + + "313 404 325 453 432 529 c\n" + + "478 561 504 597 504 645 c\n" + + "504 736 440 760 391 760 c\n" + + "286 760 271 681 265 626 c\n" + + "265 625 l\n" + + "100 625 l\n" + + "100 828 253 898 381 898 c\n" + + "451 898 679 878 679 650 c\n" + + "679 555 628 499 538 435 c\n" + + "488 399 467 376 467 292 c\n" + + "313 292 l\n" + + "h\n" + + "308 214 170 -164 re\n" + + "f\n" + + "0.44 G\n" + + "1.2 w\n" + + "1 1 0.4 rg\n" + + "287 318 m\n" + + "287 430 299 479 406 555 c\n" + + "451 587 478 623 478 671 c\n" + + "478 762 414 786 365 786 c\n" + + "260 786 245 707 239 652 c\n" + + "239 651 l\n" + + "74 651 l\n" + + "74 854 227 924 355 924 c\n" + + "425 924 653 904 653 676 c\n" + + "653 581 602 525 512 461 c\n" + + "462 425 441 402 441 318 c\n" + + "287 318 l\n" + + "h\n" + + "282 240 170 -164 re\n" + + "B\n" + + "Q\n"; + + /** + * Holds value of property contact. + */ + private String contact; + + /** + * Holds value of property layer2Font. + */ + private Font layer2Font; + + /** + * Holds value of property layer4Text. + */ + private String layer4Text; + + /** + * Holds value of property acro6Layers. + */ + private bool acro6Layers; + + /** + * Holds value of property runDirection. + */ + private int runDirection = PdfWriter.RUN_DIRECTION_NO_BIDI; + + /** + * Holds value of property signatureEvent. + */ + private ISignatureEvent signatureEvent; + + /** + * Holds value of property image. + */ + private Image image; + + /** + * Holds value of property imageScale. + */ + private float imageScale; + + /** + * + */ + public class FRangeStream : Stream { + private byte[] b = new byte[1]; + private FileStream raf; + private byte[] bout; + private int[] range; + private int rangePosition = 0; + + internal FRangeStream(FileStream raf, byte[] bout, int[] range) { + this.raf = raf; + this.bout = bout; + this.range = range; + } + + /** + * @see java.io.Stream#read() + */ + public override int ReadByte() { + int n = Read(b, 0, 1); + if (n != 1) + return -1; + return b[0] & 0xff; + } + + /** + * @see java.io.Stream#read(byte[], int, int) + */ + public override int Read(byte[] b, int off, int len) { + if (b == null) { + throw new ArgumentNullException(); + } else if ((off < 0) || (off > b.Length) || (len < 0) || + ((off + len) > b.Length) || ((off + len) < 0)) { + throw new ArgumentOutOfRangeException(); + } else if (len == 0) { + return 0; + } + if (rangePosition >= range[range.Length - 2] + range[range.Length - 1]) { + return -1; + } + for (int k = 0; k < range.Length; k += 2) { + int start = range[k]; + int end = start + range[k + 1]; + if (rangePosition < start) + rangePosition = start; + if (rangePosition >= start && rangePosition < end) { + int lenf = Math.Min(len, end - rangePosition); + if (raf == null) + Array.Copy(bout, rangePosition, b, off, lenf); + else { + raf.Seek(rangePosition, SeekOrigin.Begin); + ReadFully(b, off, lenf); + } + rangePosition += lenf; + return lenf; + } + } + return -1; + } + + private void ReadFully(byte[] b, int offset, int count) { + while (count > 0) { + int n = raf.Read(b, offset, count); + if (n <= 0) + throw new IOException("Insufficient data."); + count -= n; + offset += n; + } + } + + public override bool CanRead { + get { + return true; + } + } + + public override bool CanSeek { + get { + return false; + } + } + + public override bool CanWrite { + get { + return false; + } + } + + public override long Length { + get { + return 0; + } + } + + public override long Position { + get { + return 0; + } + set { + } + } + + public override void Flush() { + } + + public override long Seek(long offset, SeekOrigin origin) { + return 0; + } + + public override void SetLength(long value) { + } + + public override void Write(byte[] buffer, int offset, int count) { + } + + public override void WriteByte(byte value) { + } + } + + /** + * An interface to retrieve the signature dictionary for modification. + */ + public interface ISignatureEvent { + /** + * Allows modification of the signature dictionary. + * @param sig the signature dictionary + */ + void GetSignatureDictionary(PdfDictionary sig); + } + + private int certificationLevel = NOT_CERTIFIED; + + /** + * Sets the document type to certified instead of simply signed. + * @param certificationLevel the values can be: NOT_CERTIFIED, CERTIFIED_NO_CHANGES_ALLOWED, + * CERTIFIED_FORM_FILLING and CERTIFIED_FORM_FILLING_AND_ANNOTATIONS + */ + public int CertificationLevel { + get { + return certificationLevel; + } + set { + certificationLevel = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfSmartCopy.cs b/iTechSharp/iTextSharp/text/pdf/PdfSmartCopy.cs new file mode 100644 index 0000000..1311cfa --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfSmartCopy.cs @@ -0,0 +1,228 @@ +using System; +using System.IO; +using System.Collections; +using System.Security.Cryptography; +using iTextSharp.text; +/* + * $Id: PdfSmartCopy.cs,v 1.7 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 2007 Michael Neuweiler and Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * This class was written by Michael Neuweiler based on hints given by Bruno Lowagie + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** + * PdfSmartCopy has the same functionality as PdfCopy, + * but when resources (such as fonts, images,...) are + * encountered, a reference to these resources is saved + * in a cache, so that they can be reused. + * This requires more memory, but reduces the file size + * of the resulting PDF document. + */ + + public class PdfSmartCopy : PdfCopy { + + /** the cache with the streams and references. */ + private Hashtable streamMap = null; + + /** Creates a PdfSmartCopy instance. */ + public PdfSmartCopy(Document document, Stream os) : base(document, os) { + this.streamMap = new Hashtable(); + } + /** + * Translate a PRIndirectReference to a PdfIndirectReference + * In addition, translates the object numbers, and copies the + * referenced object to the output file if it wasn't available + * in the cache yet. If it's in the cache, the reference to + * the already used stream is returned. + * + * NB: PRIndirectReferences (and PRIndirectObjects) really need to know what + * file they came from, because each file has its own namespace. The translation + * we do from their namespace to ours is *at best* heuristic, and guaranteed to + * fail under some circumstances. + */ + protected override PdfIndirectReference CopyIndirect(PRIndirectReference inp) { + PdfObject srcObj = PdfReader.GetPdfObjectRelease(inp); + ByteStore streamKey = null; + bool validStream = false; + if (srcObj.IsStream()) { + streamKey = new ByteStore((PRStream)srcObj); + validStream = true; + PdfIndirectReference streamRef = (PdfIndirectReference) streamMap[streamKey]; + if (streamRef != null) { + return streamRef; + } + } + + PdfIndirectReference theRef; + RefKey key = new RefKey(inp); + IndirectReferences iRef = (IndirectReferences) indirects[key]; + if (iRef != null) { + theRef = iRef.Ref; + if (iRef.Copied) { + return theRef; + } + } else { + theRef = body.PdfIndirectReference; + iRef = new IndirectReferences(theRef); + indirects[key] = iRef; + } + if (srcObj != null && srcObj.IsDictionary()) { + PdfObject type = PdfReader.GetPdfObjectRelease(((PdfDictionary)srcObj).Get(PdfName.TYPE)); + if (type != null && PdfName.PAGE.Equals(type)) { + return theRef; + } + } + iRef.SetCopied(); + + if (validStream) { + streamMap[streamKey] = theRef; + } + + PdfObject obj = CopyObject(srcObj); + AddToBody(obj, theRef); + return theRef; + } + + internal class ByteStore { + private byte[] b; + private int hash; + private MD5 md5; + + private void SerObject(PdfObject obj, int level, ByteBuffer bb) { + if (level <= 0) + return; + if (obj == null) { + bb.Append("$Lnull"); + return; + } + obj = PdfReader.GetPdfObject(obj); + if (obj.IsStream()) { + bb.Append("$B"); + SerDic((PdfDictionary)obj, level - 1, bb); + if (level > 0) { + md5.Initialize(); + bb.Append(md5.ComputeHash(PdfReader.GetStreamBytesRaw((PRStream)obj))); + } + } + else if (obj.IsDictionary()) { + SerDic((PdfDictionary)obj, level - 1, bb); + } + else if (obj.IsArray()) { + SerArray((PdfArray)obj, level - 1, bb); + } + else if (obj.IsString()) { + bb.Append("$S").Append(obj.ToString()); + } + else if (obj.IsName()) { + bb.Append("$N").Append(obj.ToString()); + } + else + bb.Append("$L").Append(obj.ToString()); + } + + private void SerDic(PdfDictionary dic, int level, ByteBuffer bb) { + bb.Append("$D"); + if (level <= 0) + return; + Object[] keys = new Object[dic.Size]; + dic.Keys.CopyTo(keys, 0); + Array.Sort(keys); + for (int k = 0; k < keys.Length; ++k) { + SerObject((PdfObject)keys[k], level, bb); + SerObject(dic.Get((PdfName)keys[k]), level, bb); + } + } + + private void SerArray(PdfArray array, int level, ByteBuffer bb) { + bb.Append("$A"); + if (level <= 0) + return; + ArrayList ar = array.ArrayList; + for (int k = 0; k < ar.Count; ++k) { + SerObject((PdfObject)ar[k], level, bb); + } + } + + internal ByteStore(PRStream str) { + md5 = new MD5CryptoServiceProvider(); + ByteBuffer bb = new ByteBuffer(); + int level = 10; + SerObject(str, level, bb); + this.b = bb.ToByteArray(); + md5 = null; + } + + public override bool Equals(Object obj) { + if (obj == null || !(obj is ByteStore)) + return false; + if (GetHashCode() != obj.GetHashCode()) + return false; + byte[] b2 = ((ByteStore)obj).b; + if (b2.Length != b.Length) + return false; + int len = b.Length; + for (int k = 0; k < len; ++k) { + if (b[k] != b2[k]) + return false; + } + return true; + } + + public override int GetHashCode() { + if (hash == 0) { + int len = b.Length; + for (int k = 0; k < len; ++k) { + hash = hash * 31 + b[k]; + } + } + return hash; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfSpotColor.cs b/iTechSharp/iTextSharp/text/pdf/PdfSpotColor.cs new file mode 100644 index 0000000..0cfe5de --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfSpotColor.cs @@ -0,0 +1,126 @@ +using System; + +/* + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfSpotColor defines a ColorSpace + * + * @see PdfDictionary + */ + + public class PdfSpotColor{ + + /* The tint value */ + protected float tint; + + /* The color name */ + public PdfName name; + + /* The alternative color space */ + public Color altcs; + // constructors + + /** + * Constructs a new PdfSpotColor. + * + * @param name a string value + * @param tint a tint value between 0 and 1 + * @param altcs a altnative colorspace value + */ + + public PdfSpotColor(string name, float tint, Color altcs) { + this.name = new PdfName(name); + this.tint = tint; + this.altcs = altcs; + } + + public float Tint { + get { + return tint; + } + } + + public Color AlternativeCS { + get { + return altcs; + } + } + + protected internal PdfObject GetSpotObject(PdfWriter writer) { + PdfArray array = new PdfArray(PdfName.SEPARATION); + array.Add(name); + PdfFunction func = null; + if (altcs is ExtendedColor) { + int type = ((ExtendedColor)altcs).Type; + switch (type) { + case ExtendedColor.TYPE_GRAY: + array.Add(PdfName.DEVICEGRAY); + func = PdfFunction.Type2(writer, new float[]{0, 1}, null, new float[]{0}, new float[]{((GrayColor)altcs).Gray}, 1); + break; + case ExtendedColor.TYPE_CMYK: + array.Add(PdfName.DEVICECMYK); + CMYKColor cmyk = (CMYKColor)altcs; + func = PdfFunction.Type2(writer, new float[]{0, 1}, null, new float[]{0, 0, 0, 0}, + new float[]{cmyk.Cyan, cmyk.Magenta, cmyk.Yellow, cmyk.Black}, 1); + break; + default: + throw new Exception("Only RGB, Gray and CMYK are supported as alternative color spaces."); + } + } + else { + array.Add(PdfName.DEVICERGB); + func = PdfFunction.Type2(writer, new float[]{0, 1}, null, new float[]{1, 1, 1}, + new float[]{(float)altcs.R / 255, (float)altcs.G / 255, (float)altcs.B / 255}, 1); + } + array.Add(func.Reference); + return array; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfStamper.cs b/iTechSharp/iTextSharp/text/pdf/PdfStamper.cs new file mode 100644 index 0000000..4ec5833 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfStamper.cs @@ -0,0 +1,742 @@ +using System; +using System.IO; +using System.Collections; +using iTextSharp.text.pdf.interfaces; +using iTextSharp.text.pdf.collection; +using Org.BouncyCastle.X509; +/* + * Copyright 2003, 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** Applies extra content to the pages of a PDF document. + * This extra content can be all the objects allowed in PdfContentByte + * including pages from other Pdfs. The original PDF will keep + * all the interactive elements including bookmarks, links and form fields. + *

    + * It is also possible to change the field values and to + * flatten them. New fields can be added but not flattened. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfStamper : IPdfViewerPreferences, IPdfEncryptionSettings { + /** + * The writer + */ + protected PdfStamperImp stamper; + private Hashtable moreInfo; + private bool hasSignature; + private PdfSignatureAppearance sigApp; + + /** Starts the process of adding extra content to an existing PDF + * document. + * @param reader the original document. It cannot be reused + * @param os the output stream + * @throws DocumentException on error + * @throws IOException on error + */ + public PdfStamper(PdfReader reader, Stream os) { + stamper = new PdfStamperImp(reader, os, '\0', false); + } + + /** + * Starts the process of adding extra content to an existing PDF + * document. + * @param reader the original document. It cannot be reused + * @param os the output stream + * @param pdfVersion the new pdf version or '\0' to keep the same version as the original + * document + * @throws DocumentException on error + * @throws IOException on error + */ + public PdfStamper(PdfReader reader, Stream os, char pdfVersion) { + stamper = new PdfStamperImp(reader, os, pdfVersion, false); + } + + /** + * Starts the process of adding extra content to an existing PDF + * document, possibly as a new revision. + * @param reader the original document. It cannot be reused + * @param os the output stream + * @param pdfVersion the new pdf version or '\0' to keep the same version as the original + * document + * @param append if true appends the document changes as a new revision. This is + * only useful for multiple signatures as nothing is gained in speed or memory + * @throws DocumentException on error + * @throws IOException on error + */ + public PdfStamper(PdfReader reader, Stream os, char pdfVersion, bool append) { + stamper = new PdfStamperImp(reader, os, pdfVersion, append); + } + + /** Gets the optional String map to add or change values in + * the info dictionary. + * @return the map or null + * + */ + /** An optional String map to add or change values in + * the info dictionary. Entries with null + * values delete the key in the original info dictionary + * @param moreInfo additional entries to the info dictionary + * + */ + public Hashtable MoreInfo { + set { + moreInfo = value; + } + get { + return moreInfo; + } + } + + /** + * Replaces a page from this document with a page from other document. Only the content + * is replaced not the fields and annotations. This method must be called before + * getOverContent() or getUndercontent() are called for the same page. + * @param r the PdfReader from where the new page will be imported + * @param pageImported the page number of the imported page + * @param pageReplaced the page to replace in this document + */ + public void ReplacePage(PdfReader r, int pageImported, int pageReplaced) { + stamper.ReplacePage(r, pageImported, pageReplaced); + } + + /** + * Inserts a blank page. All the pages above and including pageNumber will + * be shifted up. If pageNumber is bigger than the total number of pages + * the new page will be the last one. + * @param pageNumber the page number position where the new page will be inserted + * @param mediabox the size of the new page + */ + public void InsertPage(int pageNumber, Rectangle mediabox) { + stamper.InsertPage(pageNumber, mediabox); + } + + /** + * Gets the signing instance. The appearances and other parameters can the be set. + * @return the signing instance + */ + public PdfSignatureAppearance SignatureAppearance { + get { + return sigApp; + } + } + + /** + * Closes the document. No more content can be written after the + * document is closed. + *

    + * If closing a signed document with an external signature the closing must be done + * in the PdfSignatureAppearance instance. + * @throws DocumentException on error + * @throws IOException on error + */ + public void Close() { + if (!hasSignature) { + stamper.Close(moreInfo); + return; + } + sigApp.PreClose(); + PdfSigGenericPKCS sig = sigApp.SigStandard; + PdfLiteral lit = (PdfLiteral)sig.Get(PdfName.CONTENTS); + int totalBuf = (lit.PosLength - 2) / 2; + byte[] buf = new byte[8192]; + int n; + Stream inp = sigApp.RangeStream; + while ((n = inp.Read(buf, 0, buf.Length)) > 0) { + sig.Signer.Update(buf, 0, n); + } + buf = new byte[totalBuf]; + byte[] bsig = sig.SignerContents; + Array.Copy(bsig, 0, buf, 0, bsig.Length); + PdfString str = new PdfString(buf); + str.SetHexWriting(true); + PdfDictionary dic = new PdfDictionary(); + dic.Put(PdfName.CONTENTS, str); + sigApp.Close(dic); + stamper.reader.Close(); + } + + /** Gets a PdfContentByte to write under the page of + * the original document. + * @param pageNum the page number where the extra content is written + * @return a PdfContentByte to write under the page of + * the original document + */ + public PdfContentByte GetUnderContent(int pageNum) { + return stamper.GetUnderContent(pageNum); + } + + /** Gets a PdfContentByte to write over the page of + * the original document. + * @param pageNum the page number where the extra content is written + * @return a PdfContentByte to write over the page of + * the original document + */ + public PdfContentByte GetOverContent(int pageNum) { + return stamper.GetOverContent(pageNum); + } + + /** Checks if the content is automatically adjusted to compensate + * the original page rotation. + * @return the auto-rotation status + */ + /** Flags the content to be automatically adjusted to compensate + * the original page rotation. The default is true. + * @param rotateContents true to set auto-rotation, false + * otherwise + */ + public bool RotateContents { + set { + stamper.RotateContents = value; + } + get { + return stamper.RotateContents; + } + } + + /** Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param strength128Bits true for 128 bit key length, false for 40 bit key length + * @throws DocumentException if anything was already written to the output + */ + public void SetEncryption(byte[] userPassword, byte[] ownerPassword, int permissions, bool strength128Bits) { + if (stamper.append) + throw new DocumentException("Append mode does not support changing the encryption status."); + if (stamper.ContentWritten) + throw new DocumentException("Content was already written to the output."); + stamper.SetEncryption(userPassword, ownerPassword, permissions, strength128Bits ? PdfWriter.STANDARD_ENCRYPTION_128 : PdfWriter.STANDARD_ENCRYPTION_40); + } + + /** Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @throws DocumentException if the document is already open + */ + public void SetEncryption(byte[] userPassword, byte[] ownerPassword, int permissions, int encryptionType) { + if (stamper.IsAppend()) + throw new DocumentException("Append mode does not support changing the encryption status."); + if (stamper.ContentWritten) + throw new DocumentException("Content was already written to the output."); + stamper.SetEncryption(userPassword, ownerPassword, permissions, encryptionType); + } + + /** + * Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param strength true for 128 bit key length, false for 40 bit key length + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @throws DocumentException if anything was already written to the output + */ + public void SetEncryption(bool strength, String userPassword, String ownerPassword, int permissions) { + SetEncryption(DocWriter.GetISOBytes(userPassword), DocWriter.GetISOBytes(ownerPassword), permissions, strength); + } + + /** + * Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @throws DocumentException if the document is already open + */ + public void SetEncryption(int encryptionType, String userPassword, String ownerPassword, int permissions) { + SetEncryption(DocWriter.GetISOBytes(userPassword), DocWriter.GetISOBytes(ownerPassword), permissions, encryptionType); + } + + /** + * Sets the certificate encryption options for this document. An array of one or more public certificates + * must be provided together with an array of the same size for the permissions for each certificate. + * The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @param certs the public certificates to be used for the encryption + * @param permissions the user permissions for each of the certicates + * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * @throws DocumentException if the encryption was set too late + */ + public void SetEncryption(X509Certificate[] certs, int[] permissions, int encryptionType) { + if (stamper.IsAppend()) + throw new DocumentException("Append mode does not support changing the encryption status."); + if (stamper.ContentWritten) + throw new DocumentException("Content was already written to the output."); + stamper.SetEncryption(certs, permissions, encryptionType); + } + + /** Gets a page from other PDF document. Note that calling this method more than + * once with the same parameters will retrieve the same object. + * @param reader the PDF document where the page is + * @param pageNumber the page number. The first page is 1 + * @return the template representing the imported page + */ + public PdfImportedPage GetImportedPage(PdfReader reader, int pageNumber) { + return stamper.GetImportedPage(reader, pageNumber); + } + + /** Gets the underlying PdfWriter. + * @return the underlying PdfWriter + */ + public PdfWriter Writer { + get { + return stamper; + } + } + + /** Gets the underlying PdfReader. + * @return the underlying PdfReader + */ + public PdfReader Reader { + get { + return stamper.reader; + } + } + + /** Gets the AcroFields object that allows to get and set field values + * and to merge FDF forms. + * @return the AcroFields object + */ + public AcroFields AcroFields { + get { + return stamper.AcroFields; + } + } + + /** Determines if the fields are flattened on close. The fields added with + * {@link #addAnnotation(PdfAnnotation,int)} will never be flattened. + * @param flat true to flatten the fields, false + * to keep the fields + */ + public bool FormFlattening { + set { + stamper.FormFlattening = value; + } + } + + /** Determines if the FreeText annotations are flattened on close. + * @param flat true to flatten the FreeText annotations, false + * (the default) to keep the FreeText annotations as active content. + */ + public bool FreeTextFlattening { + set { + stamper.FreeTextFlattening = value; + } + } + /** + * Adds an annotation of form field in a specific page. This page number + * can be overridden with {@link PdfAnnotation#setPlaceInPage(int)}. + * @param annot the annotation + * @param page the page + */ + public void AddAnnotation(PdfAnnotation annot, int page) { + stamper.AddAnnotation(annot, page); + } + + /** + * Adds the comments present in an FDF file. + * @param fdf the FDF file + * @throws IOException on error + */ + public void AddComments(FdfReader fdf) { + stamper.AddComments(fdf); + } + + /** + * Sets the bookmarks. The list structure is defined in + * {@link SimpleBookmark}. + * @param outlines the bookmarks or null to remove any + */ + public ArrayList Outlines { + set { + stamper.Outlines = value; + } + } + + /** + * Sets the thumbnail image for a page. + * @param image the image + * @param page the page + * @throws PdfException on error + * @throws DocumentException on error + */ + public void SetThumbnail(Image image, int page) { + stamper.SetThumbnail(image, page); + } + + /** + * Adds name to the list of fields that will be flattened on close, + * all the other fields will remain. If this method is never called or is called + * with invalid field names, all the fields will be flattened. + *

    + * Calling setFormFlattening(true) is needed to have any kind of + * flattening. + * @param name the field name + * @return true if the field exists, false otherwise + */ + public bool PartialFormFlattening(String name) { + return stamper.PartialFormFlattening(name); + } + + /** Adds a JavaScript action at the document level. When the document + * opens all this JavaScript runs. The existing JavaScript will be replaced. + * @param js the JavaScript code + */ + public string JavaScript { + set { + stamper.AddJavaScript(value, !PdfEncodings.IsPdfDocEncoding(value)); + } + } + + /** Adds a file attachment at the document level. Existing attachments will be kept. + * @param description the file description + * @param fileStore an array with the file. If it's null + * the file will be read from the disk + * @param file the path to the file. It will only be used if + * fileStore is not null + * @param fileDisplay the actual file name stored in the pdf + * @throws IOException on error + */ + public void AddFileAttachment(String description, byte[] fileStore, String file, String fileDisplay) { + AddFileAttachment(description, PdfFileSpecification.FileEmbedded(stamper, file, fileDisplay, fileStore)); + } + + /** Adds a file attachment at the document level. Existing attachments will be kept. + * @param description the file description + * @param fs the file specification + */ + public void AddFileAttachment(String description, PdfFileSpecification fs) { + stamper.AddFileAttachment(description, fs); + } + + /** + * This is the most simple way to change a PDF into a + * portable collection. Choose one of the following names: + *

      + *
    • PdfName.D (detailed view) + *
    • PdfName.T (tiled view) + *
    • PdfName.H (hidden) + *
    + * Pass this name as a parameter and your PDF will be + * a portable collection with all the embedded and + * attached files as entries. + * @param initialView can be PdfName.D, PdfName.T or PdfName.H + */ + public void MakePackage( PdfName initialView ) { + PdfCollection collection = new PdfCollection(0); + collection.Put(PdfName.VIEW, initialView); + stamper.MakePackage( collection ); + } + + /** + * Adds or replaces the Collection Dictionary in the Catalog. + * @param collection the new collection dictionary. + */ + public void MakePackage(PdfCollection collection) { + stamper.MakePackage(collection); + } + + /** + * Sets the viewer preferences. + * @param preferences the viewer preferences + * @see PdfViewerPreferences#setViewerPreferences(int) + */ + public virtual int ViewerPreferences { + set { + stamper.ViewerPreferences = value; + } + } + + /** Adds a viewer preference + * @param preferences the viewer preferences + * @see PdfViewerPreferences#addViewerPreference + */ + + public virtual void AddViewerPreference(PdfName key, PdfObject value) { + stamper.AddViewerPreference(key, value); + } + + /** + * Sets the XMP metadata. + * @param xmp + * @see PdfWriter#setXmpMetadata(byte[]) + */ + public byte[] XmpMetadata { + set { + stamper.XmpMetadata = value; + } + } + + /** + * Gets the 1.5 compression status. + * @return true if the 1.5 compression is on + */ + public bool FullCompression { + get { + return stamper.FullCompression; + } + } + + /** + * Sets the document's compression to the new 1.5 mode with object streams and xref + * streams. It can be set at any time but once set it can't be unset. + */ + public void SetFullCompression() { + if (stamper.append) + return; + stamper.SetFullCompression(); + } + + /** + * Sets the open and close page additional action. + * @param actionType the action type. It can be PdfWriter.PAGE_OPEN + * or PdfWriter.PAGE_CLOSE + * @param action the action to perform + * @param page the page where the action will be applied. The first page is 1 + * @throws PdfException if the action type is invalid + */ + public void SetPageAction(PdfName actionType, PdfAction action, int page) { + stamper.SetPageAction(actionType, action, page); + } + + /** + * Sets the display duration for the page (for presentations) + * @param seconds the number of seconds to display the page. A negative value removes the entry + * @param page the page where the duration will be applied. The first page is 1 + */ + public void SetDuration(int seconds, int page) { + stamper.SetDuration(seconds, page); + } + + /** + * Sets the transition for the page + * @param transition the transition object. A null removes the transition + * @param page the page where the transition will be applied. The first page is 1 + */ + public void SetTransition(PdfTransition transition, int page) { + stamper.SetTransition(transition, page); + } + + /** + * Applies a digital signature to a document, possibly as a new revision, making + * possible multiple signatures. The returned PdfStamper + * can be used normally as the signature is only applied when closing. + *

    + * A possible use for adding a signature without invalidating an existing one is: + *

    + *

    +        * KeyStore ks = KeyStore.getInstance("pkcs12");
    +        * ks.load(new FileInputStream("my_private_key.pfx"), "my_password".toCharArray());
    +        * String alias = (String)ks.aliases().nextElement();
    +        * PrivateKey key = (PrivateKey)ks.getKey(alias, "my_password".toCharArray());
    +        * Certificate[] chain = ks.getCertificateChain(alias);
    +        * PdfReader reader = new PdfReader("original.pdf");
    +        * FileOutputStream fout = new FileOutputStream("signed.pdf");
    +        * PdfStamper stp = PdfStamper.createSignature(reader, fout, '\0', new
    +        * File("/temp"), true);
    +        * PdfSignatureAppearance sap = stp.getSignatureAppearance();
    +        * sap.setCrypto(key, chain, null, PdfSignatureAppearance.WINCER_SIGNED);
    +        * sap.setReason("I'm the author");
    +        * sap.setLocation("Lisbon");
    +        * // comment next line to have an invisible signature
    +        * sap.setVisibleSignature(new Rectangle(100, 100, 200, 200), 1, null);
    +        * stp.close();
    +        * 
    + * @param reader the original document + * @param os the output stream or null to keep the document in the temporary file + * @param pdfVersion the new pdf version or '\0' to keep the same version as the original + * document + * @param tempFile location of the temporary file. If it's a directory a temporary file will be created there. + * If it's a file it will be used directly. The file will be deleted on exit unless os is null. + * In that case the document can be retrieved directly from the temporary file. If it's null + * no temporary file will be created and memory will be used + * @param append if true the signature and all the other content will be added as a + * new revision thus not invalidating existing signatures + * @return a PdfStamper + * @throws DocumentException on error + * @throws IOException on error + */ + public static PdfStamper CreateSignature(PdfReader reader, Stream os, char pdfVersion, string tempFile, bool append) { + PdfStamper stp; + if (tempFile == null) { + ByteBuffer bout = new ByteBuffer(); + stp = new PdfStamper(reader, bout, pdfVersion, append); + stp.sigApp = new PdfSignatureAppearance(stp.stamper); + stp.sigApp.Sigout = bout; + } + else { + if (Directory.Exists(tempFile)) + tempFile = Path.GetTempFileName(); + FileStream fout = new FileStream(tempFile, FileMode.Create, FileAccess.Write); + stp = new PdfStamper(reader, fout, pdfVersion, append); + stp.sigApp = new PdfSignatureAppearance(stp.stamper); + stp.sigApp.SetTempFile(tempFile); + } + stp.sigApp.Originalout = os; + stp.sigApp.SetStamper(stp); + stp.hasSignature = true; + PdfDictionary catalog = reader.Catalog; + PdfDictionary acroForm = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.ACROFORM), catalog); + if (acroForm != null) { + acroForm.Remove(PdfName.NEEDAPPEARANCES); + stp.stamper.MarkUsed(acroForm); + } + return stp; + } + + /** + * Applies a digital signature to a document. The returned PdfStamper + * can be used normally as the signature is only applied when closing. + *

    + * Note that the pdf is created in memory. + *

    + * A possible use is: + *

    + *

    +        * KeyStore ks = KeyStore.getInstance("pkcs12");
    +        * ks.load(new FileInputStream("my_private_key.pfx"), "my_password".toCharArray());
    +        * String alias = (String)ks.aliases().nextElement();
    +        * PrivateKey key = (PrivateKey)ks.getKey(alias, "my_password".toCharArray());
    +        * Certificate[] chain = ks.getCertificateChain(alias);
    +        * PdfReader reader = new PdfReader("original.pdf");
    +        * FileOutputStream fout = new FileOutputStream("signed.pdf");
    +        * PdfStamper stp = PdfStamper.createSignature(reader, fout, '\0');
    +        * PdfSignatureAppearance sap = stp.getSignatureAppearance();
    +        * sap.setCrypto(key, chain, null, PdfSignatureAppearance.WINCER_SIGNED);
    +        * sap.setReason("I'm the author");
    +        * sap.setLocation("Lisbon");
    +        * // comment next line to have an invisible signature
    +        * sap.setVisibleSignature(new Rectangle(100, 100, 200, 200), 1, null);
    +        * stp.close();
    +        * 
    + * @param reader the original document + * @param os the output stream + * @param pdfVersion the new pdf version or '\0' to keep the same version as the original + * document + * @throws DocumentException on error + * @throws IOException on error + * @return a PdfStamper + */ + public static PdfStamper CreateSignature(PdfReader reader, Stream os, char pdfVersion) { + return CreateSignature(reader, os, pdfVersion, null, false); + } + + /** + * Applies a digital signature to a document. The returned PdfStamper + * can be used normally as the signature is only applied when closing. + *

    + * A possible use is: + *

    + *

    +        * KeyStore ks = KeyStore.getInstance("pkcs12");
    +        * ks.load(new FileInputStream("my_private_key.pfx"), "my_password".toCharArray());
    +        * String alias = (String)ks.aliases().nextElement();
    +        * PrivateKey key = (PrivateKey)ks.getKey(alias, "my_password".toCharArray());
    +        * Certificate[] chain = ks.getCertificateChain(alias);
    +        * PdfReader reader = new PdfReader("original.pdf");
    +        * FileOutputStream fout = new FileOutputStream("signed.pdf");
    +        * PdfStamper stp = PdfStamper.createSignature(reader, fout, '\0', new File("/temp"));
    +        * PdfSignatureAppearance sap = stp.getSignatureAppearance();
    +        * sap.setCrypto(key, chain, null, PdfSignatureAppearance.WINCER_SIGNED);
    +        * sap.setReason("I'm the author");
    +        * sap.setLocation("Lisbon");
    +        * // comment next line to have an invisible signature
    +        * sap.setVisibleSignature(new Rectangle(100, 100, 200, 200), 1, null);
    +        * stp.close();
    +        * 
    + * @param reader the original document + * @param os the output stream or null to keep the document in the temporary file + * @param pdfVersion the new pdf version or '\0' to keep the same version as the original + * document + * @param tempFile location of the temporary file. If it's a directory a temporary file will be created there. + * If it's a file it will be used directly. The file will be deleted on exit unless os is null. + * In that case the document can be retrieved directly from the temporary file. If it's null + * no temporary file will be created and memory will be used + * @return a PdfStamper + * @throws DocumentException on error + * @throws IOException on error + */ + public static PdfStamper CreateSignature(PdfReader reader, Stream os, char pdfVersion, string tempFile) { + return CreateSignature(reader, os, pdfVersion, tempFile, false); + } + + /** + * Gets the PdfLayer objects in an existing document as a Map + * with the names/titles of the layers as keys. + * @return a Map with all the PdfLayers in the document (and the name/title of the layer as key) + * @since 2.1.2 + */ + public Hashtable GetPdfLayers() { + return stamper.GetPdfLayers(); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfStamperImp.cs b/iTechSharp/iTextSharp/text/pdf/PdfStamperImp.cs new file mode 100644 index 0000000..a99a24f --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfStamperImp.cs @@ -0,0 +1,1625 @@ +using System; +using System.IO; +using System.Collections; +using System.util; +using iTextSharp.text.pdf.interfaces; +using iTextSharp.text.pdf.intern; +using iTextSharp.text.pdf.collection; +/* + * Copyright 2003 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + public class PdfStamperImp : PdfWriter { + internal Hashtable readers2intrefs = new Hashtable(); + internal Hashtable readers2file = new Hashtable(); + internal RandomAccessFileOrArray file; + internal PdfReader reader; + internal IntHashtable myXref = new IntHashtable(); + /** Integer(page number) -> PageStamp */ + internal Hashtable pagesToContent = new Hashtable(); + internal bool closed = false; + /** Holds value of property rotateContents. */ + private bool rotateContents = true; + protected AcroFields acroFields; + protected bool flat = false; + protected bool flatFreeText = false; + protected int[] namePtr = {0}; + protected Hashtable partialFlattening = new Hashtable(); + protected bool useVp = false; + protected PdfViewerPreferencesImp viewerPreferences = new PdfViewerPreferencesImp(); + protected Hashtable fieldTemplates = new Hashtable(); + protected bool fieldsAdded = false; + protected int sigFlags = 0; + protected internal bool append; + protected IntHashtable marked; + protected int initialXrefSize; + protected PdfAction openAction; + + /** Creates new PdfStamperImp. + * @param reader the read PDF + * @param os the output destination + * @param pdfVersion the new pdf version or '\0' to keep the same version as the original + * document + * @param append + * @throws DocumentException on error + * @throws IOException + */ + internal PdfStamperImp(PdfReader reader, Stream os, char pdfVersion, bool append) : base(new PdfDocument(), os) { + if (!reader.IsOpenedWithFullPermissions) + throw new ArgumentException("PdfReader not opened with owner password"); + if (reader.Tampered) + throw new DocumentException("The original document was reused. Read it again from file."); + reader.Tampered = true; + this.reader = reader; + file = reader.SafeFile; + this.append = append; + if (append) { + if (reader.IsRebuilt()) + throw new DocumentException("Append mode requires a document without errors even if recovery was possible."); + if (reader.IsEncrypted()) + crypto = new PdfEncryption(reader.Decrypt); + pdf_version.SetAppendmode(true); + file.ReOpen(); + byte[] buf = new byte[8192]; + int n; + while ((n = file.Read(buf)) > 0) + this.os.Write(buf, 0, n); + file.Close(); + prevxref = reader.LastXref; + reader.Appendable = true; + } + else { + if (pdfVersion == 0) + base.PdfVersion = reader.PdfVersion; + else + base.PdfVersion = pdfVersion; + } + base.Open(); + pdf.AddWriter(this); + if (append) { + body.Refnum = reader.XrefSize; + marked = new IntHashtable(); + if (reader.IsNewXrefType()) + fullCompression = true; + if (reader.IsHybridXref()) + fullCompression = false; + } + initialXrefSize = reader.XrefSize; + } + + internal void Close(Hashtable moreInfo) { + if (closed) + return; + if (useVp) { + reader.SetViewerPreferences(viewerPreferences); + MarkUsed(reader.Trailer.Get(PdfName.ROOT)); + } + if (flat) + FlatFields(); + if (flatFreeText) + FlatFreeTextFields(); + AddFieldResources(); + PdfDictionary acroForm = (PdfDictionary)PdfReader.GetPdfObject(reader.Catalog.Get(PdfName.ACROFORM), reader.Catalog); + if (acroFields != null && acroFields.Xfa.Changed) { + MarkUsed(acroForm); + if (!flat) + acroFields.Xfa.SetXfa(this); + } + if (sigFlags != 0) { + if (acroForm != null) { + acroForm.Put(PdfName.SIGFLAGS, new PdfNumber(sigFlags)); + MarkUsed(acroForm); + } + } + closed = true; + AddSharedObjectsToBody(); + SetOutlines(); + SetJavaScript(); + AddFileAttachments(); + PdfDictionary catalog = reader.Catalog; + if (openAction != null) { + catalog.Put(PdfName.OPENACTION, openAction); + } + if (pdf.pageLabels != null) + catalog.Put(PdfName.PAGELABELS, pdf.pageLabels.GetDictionary(this)); + byte[] altMetadata = null; + PdfObject xmpo = PdfReader.GetPdfObject(catalog.Get(PdfName.METADATA)); + if (xmpo != null && xmpo.IsStream()) { + altMetadata = PdfReader.GetStreamBytesRaw((PRStream)xmpo); + PdfReader.KillIndirect(catalog.Get(PdfName.METADATA)); + } + if (xmpMetadata != null) { + altMetadata = xmpMetadata; + } + // if there is XMP data to add: add it + if (altMetadata != null) { + PdfStream xmp = new PdfStream(altMetadata); + xmp.Put(PdfName.TYPE, PdfName.METADATA); + xmp.Put(PdfName.SUBTYPE, PdfName.XML); + if (crypto != null && !crypto.IsMetadataEncrypted()) { + PdfArray ar = new PdfArray(); + ar.Add(PdfName.CRYPT); + xmp.Put(PdfName.FILTER, ar); + } + catalog.Put(PdfName.METADATA, body.Add(xmp).IndirectReference); + MarkUsed(catalog); + } + if (documentOCG.Count != 0) { + FillOCProperties(false); + PdfDictionary ocdict = catalog.GetAsDict(PdfName.OCPROPERTIES); + if (ocdict == null) { + reader.Catalog.Put(PdfName.OCPROPERTIES, OCProperties); + } + else { + ocdict.Put(PdfName.OCGS, OCProperties.Get(PdfName.OCGS)); + PdfDictionary ddict = ocdict.GetAsDict(PdfName.D); + ddict.Put(PdfName.ORDER, OCProperties.GetAsDict(PdfName.D).Get(PdfName.ORDER)); + ddict.Put(PdfName.RBGROUPS, OCProperties.GetAsDict(PdfName.D).Get(PdfName.RBGROUPS)); + ddict.Put(PdfName.OFF, OCProperties.GetAsDict(PdfName.D).Get(PdfName.OFF)); + ddict.Put(PdfName.AS, OCProperties.GetAsDict(PdfName.D).Get(PdfName.AS)); + } + } + PRIndirectReference iInfo = null; + try { + file.ReOpen(); + AlterContents(); + iInfo = (PRIndirectReference)reader.trailer.Get(PdfName.INFO); + int skip = -1; + if (iInfo != null) + skip = iInfo.Number; + int rootN = ((PRIndirectReference)reader.trailer.Get(PdfName.ROOT)).Number; + if (append) { + int[] keys = marked.GetKeys(); + for (int k = 0; k < keys.Length; ++k) { + int j = keys[k]; + PdfObject obj = reader.GetPdfObjectRelease(j); + if (obj != null && skip != j && j < initialXrefSize) { + AddToBody(obj, j, j != rootN); + } + } + for (int k = initialXrefSize; k < reader.XrefSize; ++k) { + PdfObject obj = reader.GetPdfObject(k); + if (obj != null) { + AddToBody(obj, GetNewObjectNumber(reader, k, 0)); + } + } + } + else { + for (int k = 1; k < reader.XrefSize; ++k) { + PdfObject obj = reader.GetPdfObjectRelease(k); + if (obj != null && skip != k) { + AddToBody(obj, GetNewObjectNumber(reader, k, 0), k != rootN); + } + } + } + } + finally { + try { + file.Close(); + } + catch { + // empty on purpose + } + } + PdfIndirectReference encryption = null; + PdfObject fileID = null; + if (crypto != null) { + if (append) { + encryption = reader.GetCryptoRef(); + } + else { + PdfIndirectObject encryptionObject = AddToBody(crypto.GetEncryptionDictionary(), false); + encryption = encryptionObject.IndirectReference; + } + fileID = crypto.FileID; + } + else + fileID = PdfEncryption.CreateInfoId(PdfEncryption.CreateDocumentId()); + PRIndirectReference iRoot = (PRIndirectReference)reader.trailer.Get(PdfName.ROOT); + PdfIndirectReference root = new PdfIndirectReference(0, GetNewObjectNumber(reader, iRoot.Number, 0)); + PdfIndirectReference info = null; + PdfDictionary oldInfo = (PdfDictionary)PdfReader.GetPdfObject(iInfo); + PdfDictionary newInfo = new PdfDictionary(); + if (oldInfo != null) { + foreach (PdfName key in oldInfo.Keys) { + PdfObject value = PdfReader.GetPdfObject(oldInfo.Get(key)); + newInfo.Put(key, value); + } + } + if (moreInfo != null) { + foreach (DictionaryEntry entry in moreInfo) { + PdfName keyName = new PdfName((String)entry.Key); + String value = (String)entry.Value; + if (value == null) + newInfo.Remove(keyName); + else + newInfo.Put(keyName, new PdfString(value, PdfObject.TEXT_UNICODE)); + } + } + if (altMetadata == null) // hack because changing the modification data makes the XMP data inconsistent + newInfo.Put(PdfName.MODDATE, new PdfDate()); + if (append) { + if (iInfo == null) + info = AddToBody(newInfo, false).IndirectReference; + else + info = AddToBody(newInfo, iInfo.Number, false).IndirectReference; + } + else { + info = AddToBody(newInfo, false).IndirectReference; + } + // write the cross-reference table of the body + body.WriteCrossReferenceTable(os, root, info, encryption, fileID, prevxref); + if (fullCompression) { + byte[] tmp = GetISOBytes("startxref\n"); + os.Write(tmp, 0, tmp.Length); + tmp = GetISOBytes(body.Offset.ToString()); + os.Write(tmp, 0, tmp.Length); + tmp = GetISOBytes("\n%%EOF\n"); + os.Write(tmp, 0, tmp.Length); + } + else { + PdfTrailer trailer = new PdfTrailer(body.Size, + body.Offset, + root, + info, + encryption, + fileID, prevxref); + trailer.ToPdf(this, os); + } + os.Flush(); + if (CloseStream) + os.Close(); + reader.Close(); + } + + internal void ApplyRotation(PdfDictionary pageN, ByteBuffer out_p) { + if (!rotateContents) + return; + Rectangle page = reader.GetPageSizeWithRotation(pageN); + int rotation = page.Rotation; + switch (rotation) { + case 90: + out_p.Append(PdfContents.ROTATE90); + out_p.Append(page.Top); + out_p.Append(' ').Append('0').Append(PdfContents.ROTATEFINAL); + break; + case 180: + out_p.Append(PdfContents.ROTATE180); + out_p.Append(page.Right); + out_p.Append(' '); + out_p.Append(page.Top); + out_p.Append(PdfContents.ROTATEFINAL); + break; + case 270: + out_p.Append(PdfContents.ROTATE270); + out_p.Append('0').Append(' '); + out_p.Append(page.Right); + out_p.Append(PdfContents.ROTATEFINAL); + break; + } + } + + internal void AlterContents() { + foreach (PageStamp ps in pagesToContent.Values) { + PdfDictionary pageN = ps.pageN; + MarkUsed(pageN); + PdfArray ar = null; + PdfObject content = PdfReader.GetPdfObject(pageN.Get(PdfName.CONTENTS), pageN); + if (content == null) { + ar = new PdfArray(); + pageN.Put(PdfName.CONTENTS, ar); + } + else if (content.IsArray()) { + ar = (PdfArray)content; + MarkUsed(ar); + } + else if (content.IsStream()) { + ar = new PdfArray(); + ar.Add(pageN.Get(PdfName.CONTENTS)); + pageN.Put(PdfName.CONTENTS, ar); + } + else { + ar = new PdfArray(); + pageN.Put(PdfName.CONTENTS, ar); + } + ByteBuffer out_p = new ByteBuffer(); + if (ps.under != null) { + out_p.Append(PdfContents.SAVESTATE); + ApplyRotation(pageN, out_p); + out_p.Append(ps.under.InternalBuffer); + out_p.Append(PdfContents.RESTORESTATE); + } + if (ps.over != null) + out_p.Append(PdfContents.SAVESTATE); + PdfStream stream = new PdfStream(out_p.ToByteArray()); + stream.FlateCompress(); + ar.AddFirst(AddToBody(stream).IndirectReference); + out_p.Reset(); + if (ps.over != null) { + out_p.Append(' '); + out_p.Append(PdfContents.RESTORESTATE); + ByteBuffer buf = ps.over.InternalBuffer; + out_p.Append(buf.Buffer, 0, ps.replacePoint); + out_p.Append(PdfContents.SAVESTATE); + ApplyRotation(pageN, out_p); + out_p.Append(buf.Buffer, ps.replacePoint, buf.Size - ps.replacePoint); + out_p.Append(PdfContents.RESTORESTATE); + stream = new PdfStream(out_p.ToByteArray()); + stream.FlateCompress(); + ar.Add(AddToBody(stream).IndirectReference); + } + AlterResources(ps); + } + } + + internal void AlterResources(PageStamp ps) { + ps.pageN.Put(PdfName.RESOURCES, ps.pageResources.Resources); + } + + protected internal override int GetNewObjectNumber(PdfReader reader, int number, int generation) { + IntHashtable ref_p = (IntHashtable)readers2intrefs[reader]; + if (ref_p != null) { + int n = ref_p[number]; + if (n == 0) { + n = IndirectReferenceNumber; + ref_p[number] = n; + } + return n; + } + if (currentPdfReaderInstance == null) { + if (append && number < initialXrefSize) + return number; + int n = myXref[number]; + if (n == 0) { + n = IndirectReferenceNumber; + myXref[number] = n; + } + return n; + } + else + return currentPdfReaderInstance.GetNewObjectNumber(number, generation); + } + + internal override RandomAccessFileOrArray GetReaderFile(PdfReader reader) { + if (readers2intrefs.ContainsKey(reader)) { + RandomAccessFileOrArray raf = (RandomAccessFileOrArray)readers2file[reader]; + if (raf != null) + return raf; + return reader.SafeFile; + } + if (currentPdfReaderInstance == null) + return file; + else + return currentPdfReaderInstance.ReaderFile; + } + + /** + * @param reader + * @param openFile + * @throws IOException + */ + public void RegisterReader(PdfReader reader, bool openFile) { + if (readers2intrefs.ContainsKey(reader)) + return; + readers2intrefs[reader] = new IntHashtable(); + if (openFile) { + RandomAccessFileOrArray raf = reader.SafeFile; + readers2file[reader] = raf; + raf.ReOpen(); + } + } + + /** + * @param reader + */ + public void UnRegisterReader(PdfReader reader) { + if (!readers2intrefs.ContainsKey(reader)) + return; + readers2intrefs.Remove(reader); + RandomAccessFileOrArray raf = (RandomAccessFileOrArray)readers2file[reader]; + if (raf == null) + return; + readers2file.Remove(reader); + try{raf.Close();}catch{} + } + + internal static void FindAllObjects(PdfReader reader, PdfObject obj, IntHashtable hits) { + if (obj == null) + return; + switch (obj.Type) { + case PdfObject.INDIRECT: + PRIndirectReference iref = (PRIndirectReference)obj; + if (reader != iref.Reader) + return; + if (hits.ContainsKey(iref.Number)) + return; + hits[iref.Number] = 1; + FindAllObjects(reader, PdfReader.GetPdfObject(obj), hits); + return; + case PdfObject.ARRAY: + ArrayList lst = ((PdfArray)obj).ArrayList; + for (int k = 0; k < lst.Count; ++k) { + FindAllObjects(reader, (PdfObject)lst[k], hits); + } + return; + case PdfObject.DICTIONARY: + case PdfObject.STREAM: + PdfDictionary dic = (PdfDictionary)obj; + foreach (PdfName name in dic.Keys) { + FindAllObjects(reader, dic.Get(name), hits); + } + return; + } + } + + /** + * @param fdf + * @throws IOException + */ + public void AddComments(FdfReader fdf) { + if (readers2intrefs.ContainsKey(fdf)) + return; + PdfDictionary catalog = fdf.Catalog; + catalog = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.FDF)); + if (catalog == null) + return; + PdfArray annots = (PdfArray)PdfReader.GetPdfObject(catalog.Get(PdfName.ANNOTS)); + if (annots == null || annots.Size == 0) + return; + RegisterReader(fdf, false); + IntHashtable hits = new IntHashtable(); + Hashtable irt = new Hashtable(); + ArrayList an = new ArrayList(); + ArrayList ar = annots.ArrayList; + for (int k = 0; k < ar.Count; ++k) { + PdfObject obj = (PdfObject)ar[k]; + PdfDictionary annot = (PdfDictionary)PdfReader.GetPdfObject(obj); + PdfNumber page = (PdfNumber)PdfReader.GetPdfObject(annot.Get(PdfName.PAGE)); + if (page == null || page.IntValue >= reader.NumberOfPages) + continue; + FindAllObjects(fdf, obj, hits); + an.Add(obj); + if (obj.Type == PdfObject.INDIRECT) { + PdfObject nm = PdfReader.GetPdfObject(annot.Get(PdfName.NM)); + if (nm != null && nm.Type == PdfObject.STRING) + irt[nm.ToString()] = obj; + } + } + int[] arhits = hits.GetKeys(); + for (int k = 0; k < arhits.Length; ++k) { + int n = arhits[k]; + PdfObject obj = fdf.GetPdfObject(n); + if (obj.Type == PdfObject.DICTIONARY) { + PdfObject str = PdfReader.GetPdfObject(((PdfDictionary)obj).Get(PdfName.IRT)); + if (str != null && str.Type == PdfObject.STRING) { + PdfObject i = (PdfObject)irt[str.ToString()]; + if (i != null) { + PdfDictionary dic2 = new PdfDictionary(); + dic2.Merge((PdfDictionary)obj); + dic2.Put(PdfName.IRT, i); + obj = dic2; + } + } + } + AddToBody(obj, GetNewObjectNumber(fdf, n, 0)); + } + for (int k = 0; k < an.Count; ++k) { + PdfObject obj = (PdfObject)an[k]; + PdfDictionary annot = (PdfDictionary)PdfReader.GetPdfObject(obj); + PdfNumber page = (PdfNumber)PdfReader.GetPdfObject(annot.Get(PdfName.PAGE)); + PdfDictionary dic = reader.GetPageN(page.IntValue + 1); + PdfArray annotsp = (PdfArray)PdfReader.GetPdfObject(dic.Get(PdfName.ANNOTS), dic); + if (annotsp == null) { + annotsp = new PdfArray(); + dic.Put(PdfName.ANNOTS, annotsp); + MarkUsed(dic); + } + MarkUsed(annotsp); + annotsp.Add(obj); + } + } + + internal PageStamp GetPageStamp(int pageNum) { + PdfDictionary pageN = reader.GetPageN(pageNum); + PageStamp ps = (PageStamp)pagesToContent[pageN]; + if (ps == null) { + ps = new PageStamp(this, reader, pageN); + pagesToContent[pageN] = ps; + } + return ps; + } + + internal PdfContentByte GetUnderContent(int pageNum) { + if (pageNum < 1 || pageNum > reader.NumberOfPages) + return null; + PageStamp ps = GetPageStamp(pageNum); + if (ps.under == null) + ps.under = new StampContent(this, ps); + return ps.under; + } + + internal PdfContentByte GetOverContent(int pageNum) { + if (pageNum < 1 || pageNum > reader.NumberOfPages) + return null; + PageStamp ps = GetPageStamp(pageNum); + if (ps.over == null) + ps.over = new StampContent(this, ps); + return ps.over; + } + + internal void CorrectAcroFieldPages(int page) { + if (acroFields == null) + return; + if (page > reader.NumberOfPages) + return; + Hashtable fields = acroFields.Fields; + foreach (AcroFields.Item item in fields.Values) { + ArrayList pages = item.page; + for (int k = 0; k < pages.Count; ++k) { + int p = (int)pages[k]; + if (p >= page) + pages[k] = p + 1; + } + } + } + + private static void MoveRectangle(PdfDictionary dic2, PdfReader r, int pageImported, PdfName key, String name) { + Rectangle m = r.GetBoxSize(pageImported, name); + if (m == null) + dic2.Remove(key); + else + dic2.Put(key, new PdfRectangle(m)); + } + + internal void ReplacePage(PdfReader r, int pageImported, int pageReplaced) { + PdfDictionary pageN = reader.GetPageN(pageReplaced); + if (pagesToContent.ContainsKey(pageN)) + throw new InvalidOperationException("This page cannot be replaced: new content was already added"); + PdfImportedPage p = GetImportedPage(r, pageImported); + PdfDictionary dic2 = reader.GetPageNRelease(pageReplaced); + dic2.Remove(PdfName.RESOURCES); + dic2.Remove(PdfName.CONTENTS); + MoveRectangle(dic2, r, pageImported, PdfName.MEDIABOX, "media"); + MoveRectangle(dic2, r, pageImported, PdfName.CROPBOX, "crop"); + MoveRectangle(dic2, r, pageImported, PdfName.TRIMBOX, "trim"); + MoveRectangle(dic2, r, pageImported, PdfName.ARTBOX, "art"); + MoveRectangle(dic2, r, pageImported, PdfName.BLEEDBOX, "bleed"); + dic2.Put(PdfName.ROTATE, new PdfNumber(r.GetPageRotation(pageImported))); + PdfContentByte cb = GetOverContent(pageReplaced); + cb.AddTemplate(p, 0, 0); + PageStamp ps = (PageStamp)pagesToContent[pageN]; + ps.replacePoint = ps.over.InternalBuffer.Size; + } + + internal void InsertPage(int pageNumber, Rectangle mediabox) { + Rectangle media = new Rectangle(mediabox); + int rotation = media.Rotation % 360; + PdfDictionary page = new PdfDictionary(PdfName.PAGE); + PdfDictionary resources = new PdfDictionary(); + PdfArray procset = new PdfArray(); + procset.Add(PdfName.PDF); + procset.Add(PdfName.TEXT); + procset.Add(PdfName.IMAGEB); + procset.Add(PdfName.IMAGEC); + procset.Add(PdfName.IMAGEI); + resources.Put(PdfName.PROCSET, procset); + page.Put(PdfName.RESOURCES, resources); + page.Put(PdfName.ROTATE, new PdfNumber(rotation)); + page.Put(PdfName.MEDIABOX, new PdfRectangle(media, rotation)); + PRIndirectReference pref = reader.AddPdfObject(page); + PdfDictionary parent; + PRIndirectReference parentRef; + if (pageNumber > reader.NumberOfPages) { + PdfDictionary lastPage = reader.GetPageNRelease(reader.NumberOfPages); + parentRef = (PRIndirectReference)lastPage.Get(PdfName.PARENT); + parentRef = new PRIndirectReference(reader, parentRef.Number); + parent = (PdfDictionary)PdfReader.GetPdfObject(parentRef); + PdfArray kids = (PdfArray)PdfReader.GetPdfObject(parent.Get(PdfName.KIDS), parent); + kids.Add(pref); + MarkUsed(kids); + reader.pageRefs.InsertPage(pageNumber, pref); + } + else { + if (pageNumber < 1) + pageNumber = 1; + PdfDictionary firstPage = reader.GetPageN(pageNumber); + PRIndirectReference firstPageRef = reader.GetPageOrigRef(pageNumber); + reader.ReleasePage(pageNumber); + parentRef = (PRIndirectReference)firstPage.Get(PdfName.PARENT); + parentRef = new PRIndirectReference(reader, parentRef.Number); + parent = (PdfDictionary)PdfReader.GetPdfObject(parentRef); + PdfArray kids = (PdfArray)PdfReader.GetPdfObject(parent.Get(PdfName.KIDS), parent); + ArrayList ar = kids.ArrayList; + int len = ar.Count; + int num = firstPageRef.Number; + for (int k = 0; k < len; ++k) { + PRIndirectReference cur = (PRIndirectReference)ar[k]; + if (num == cur.Number) { + ar.Insert(k, pref); + break; + } + } + if (len == ar.Count) + throw new Exception("Internal inconsistence."); + MarkUsed(kids); + reader.pageRefs.InsertPage(pageNumber, pref); + CorrectAcroFieldPages(pageNumber); + } + page.Put(PdfName.PARENT, parentRef); + while (parent != null) { + MarkUsed(parent); + PdfNumber count = (PdfNumber)PdfReader.GetPdfObjectRelease(parent.Get(PdfName.COUNT)); + parent.Put(PdfName.COUNT, new PdfNumber(count.IntValue + 1)); + parent = (PdfDictionary)PdfReader.GetPdfObject(parent.Get(PdfName.PARENT)); + } + } + + internal bool RotateContents { + set { + this.rotateContents = value; + } + get { + return rotateContents; + } + } + + internal bool ContentWritten { + get { + return body.Size > 1; + } + } + + internal AcroFields AcroFields { + get { + if (acroFields == null) { + acroFields = new AcroFields(reader, this); + } + return acroFields; + } + } + + internal bool FormFlattening { + set { + flat = value; + } + } + + internal bool FreeTextFlattening { + set { + flatFreeText = value; + } + } + + internal bool PartialFormFlattening(String name) { + AcroFields af = AcroFields; + if (acroFields.Xfa.XfaPresent) + throw new InvalidOperationException("Partial form flattening is not supported with XFA forms."); + if (!acroFields.Fields.ContainsKey(name)) + return false; + partialFlattening[name] = null; + return true; + } + + internal void FlatFields() { + if (append) + throw new ArgumentException("Field flattening is not supported in append mode."); + AcroFields af = AcroFields; + Hashtable fields = acroFields.Fields; + if (fieldsAdded && partialFlattening.Count == 0) { + foreach (object obf in fields.Keys) { + partialFlattening[obf] = null; + } + } + PdfDictionary acroForm = (PdfDictionary)PdfReader.GetPdfObject(reader.Catalog.Get(PdfName.ACROFORM)); + ArrayList acroFds = null; + if (acroForm != null) { + PdfArray array = (PdfArray)PdfReader.GetPdfObject(acroForm.Get(PdfName.FIELDS), acroForm); + if (array != null) + acroFds = array.ArrayList; + } + foreach (DictionaryEntry entry in fields) { + String name = (String)entry.Key; + if (partialFlattening.Count != 0 && !partialFlattening.ContainsKey(name)) + continue; + AcroFields.Item item = (AcroFields.Item)entry.Value; + for (int k = 0; k < item.merged.Count; ++k) { + PdfDictionary merged = (PdfDictionary)item.merged[k]; + PdfNumber ff = (PdfNumber)PdfReader.GetPdfObject(merged.Get(PdfName.F)); + int flags = 0; + if (ff != null) + flags = ff.IntValue; + int page = (int)item.page[k]; + PdfDictionary appDic = (PdfDictionary)PdfReader.GetPdfObject(merged.Get(PdfName.AP)); + if (appDic != null && (flags & PdfFormField.FLAGS_PRINT) != 0 && (flags & PdfFormField.FLAGS_HIDDEN) == 0) { + PdfObject obj = appDic.Get(PdfName.N); + PdfAppearance app = null; + if (obj != null) { + PdfObject objReal = PdfReader.GetPdfObject(obj); + if (obj is PdfIndirectReference && !obj.IsIndirect()) + app = new PdfAppearance((PdfIndirectReference)obj); + else if (objReal is PdfStream) { + ((PdfDictionary)objReal).Put(PdfName.SUBTYPE, PdfName.FORM); + app = new PdfAppearance((PdfIndirectReference)obj); + } + else { + if (objReal != null && objReal.IsDictionary()) { + PdfName as_p = (PdfName)PdfReader.GetPdfObject(merged.Get(PdfName.AS)); + if (as_p != null) { + PdfIndirectReference iref = (PdfIndirectReference)((PdfDictionary)objReal).Get(as_p); + if (iref != null) { + app = new PdfAppearance(iref); + if (iref.IsIndirect()) { + objReal = PdfReader.GetPdfObject(iref); + ((PdfDictionary)objReal).Put(PdfName.SUBTYPE, PdfName.FORM); + } + } + } + } + } + } + if (app != null) { + Rectangle box = PdfReader.GetNormalizedRectangle((PdfArray)PdfReader.GetPdfObject(merged.Get(PdfName.RECT))); + PdfContentByte cb = GetOverContent(page); + cb.SetLiteral("Q "); + cb.AddTemplate(app, box.Left, box.Bottom); + cb.SetLiteral("q "); + } + } + if (partialFlattening.Count == 0) + continue; + PdfDictionary pageDic = reader.GetPageN(page); + PdfArray annots = (PdfArray)PdfReader.GetPdfObject(pageDic.Get(PdfName.ANNOTS)); + if (annots == null) + continue; + ArrayList ar = annots.ArrayList; + for (int idx = 0; idx < ar.Count; ++idx) { + PdfObject ran = (PdfObject)ar[idx]; + if (!ran.IsIndirect()) + continue; + PdfObject ran2 = (PdfObject)item.widget_refs[k]; + if (!ran2.IsIndirect()) + continue; + if (((PRIndirectReference)ran).Number == ((PRIndirectReference)ran2).Number) { + ar.RemoveAt(idx--); + PRIndirectReference wdref = (PRIndirectReference)ran2; + while (true) { + PdfDictionary wd = (PdfDictionary)PdfReader.GetPdfObject(wdref); + PRIndirectReference parentRef = (PRIndirectReference)wd.Get(PdfName.PARENT); + PdfReader.KillIndirect(wdref); + if (parentRef == null) { // reached AcroForm + for (int fr = 0; fr < acroFds.Count; ++fr) { + PdfObject h = (PdfObject)acroFds[fr]; + if (h.IsIndirect() && ((PRIndirectReference)h).Number == wdref.Number) { + acroFds.RemoveAt(fr); + --fr; + } + } + break; + } + PdfDictionary parent = (PdfDictionary)PdfReader.GetPdfObject(parentRef); + PdfArray kids = (PdfArray)PdfReader.GetPdfObject(parent.Get(PdfName.KIDS)); + ArrayList kar = kids.ArrayList; + for (int fr = 0; fr < kar.Count; ++fr) { + PdfObject h = (PdfObject)kar[fr]; + if (h.IsIndirect() && ((PRIndirectReference)h).Number == wdref.Number) { + kar.RemoveAt(fr); + --fr; + } + } + if (kar.Count != 0) + break; + wdref = parentRef; + } + } + } + if (ar.Count == 0) { + PdfReader.KillIndirect(pageDic.Get(PdfName.ANNOTS)); + pageDic.Remove(PdfName.ANNOTS); + } + } + } + if (!fieldsAdded && partialFlattening.Count == 0) { + for (int page = 1; page <= reader.NumberOfPages; ++page) { + PdfDictionary pageDic = reader.GetPageN(page); + PdfArray annots = (PdfArray)PdfReader.GetPdfObject(pageDic.Get(PdfName.ANNOTS)); + if (annots == null) + continue; + ArrayList ar = annots.ArrayList; + for (int idx = 0; idx < ar.Count; ++idx) { + PdfObject annoto = PdfReader.GetPdfObject((PdfObject)ar[idx]); + if ((annoto is PdfIndirectReference) && !annoto.IsIndirect()) + continue; + if (!annoto.IsDictionary() || PdfName.WIDGET.Equals(((PdfDictionary)annoto).Get(PdfName.SUBTYPE))) { + ar.RemoveAt(idx); + --idx; + } + } + if (ar.Count == 0) { + PdfReader.KillIndirect(pageDic.Get(PdfName.ANNOTS)); + pageDic.Remove(PdfName.ANNOTS); + } + } + EliminateAcroformObjects(); + } + } + + internal void EliminateAcroformObjects() { + PdfObject acro = reader.Catalog.Get(PdfName.ACROFORM); + if (acro == null) + return; + PdfDictionary acrodic = (PdfDictionary)PdfReader.GetPdfObject(acro); + reader.KillXref(acrodic.Get(PdfName.XFA)); + acrodic.Remove(PdfName.XFA); + PdfObject iFields = acrodic.Get(PdfName.FIELDS); + if (iFields != null) { + PdfDictionary kids = new PdfDictionary(); + kids.Put(PdfName.KIDS, iFields); + SweepKids(kids); + PdfReader.KillIndirect(iFields); + acrodic.Put(PdfName.FIELDS, new PdfArray()); + } + // PdfReader.KillIndirect(acro); + // reader.GetCatalog().Remove(PdfName.ACROFORM); + } + + internal void SweepKids(PdfObject obj) { + PdfObject oo = PdfReader.KillIndirect(obj); + if (oo == null || !oo.IsDictionary()) + return; + PdfDictionary dic = (PdfDictionary)oo; + PdfArray kids = (PdfArray)PdfReader.KillIndirect(dic.Get(PdfName.KIDS)); + if (kids == null) + return; + ArrayList ar = kids.ArrayList; + for (int k = 0; k < ar.Count; ++k) { + SweepKids((PdfObject)ar[k]); + } + } + + private void FlatFreeTextFields() { + if (append) + throw new ArgumentException("FreeText flattening is not supported in append mode."); + + for (int page = 1; page <= reader.NumberOfPages; ++page) { + PdfDictionary pageDic = reader.GetPageN(page); + PdfArray annots = (PdfArray)PdfReader.GetPdfObject(pageDic.Get(PdfName.ANNOTS)); + if (annots == null) + continue; + ArrayList ar = annots.ArrayList; + for (int idx = 0; idx < ar.Count; ++idx) { + PdfObject annoto = PdfReader.GetPdfObject((PdfObject)ar[idx]); + if ((annoto is PdfIndirectReference) && !annoto.IsIndirect()) + continue; + + PdfDictionary annDic = (PdfDictionary)annoto; + if (!((PdfName)annDic.Get(PdfName.SUBTYPE)).Equals(PdfName.FREETEXT)) + continue; + PdfNumber ff = (PdfNumber)PdfReader.GetPdfObject(annDic.Get(PdfName.F)); + int flags = (ff != null) ? ff.IntValue : 0; + + if ( (flags & PdfFormField.FLAGS_PRINT) != 0 && (flags & PdfFormField.FLAGS_HIDDEN) == 0) { + PdfObject obj1 = annDic.Get(PdfName.AP); + if (obj1 == null) + continue; + PdfDictionary appDic = (obj1 is PdfIndirectReference) ? + (PdfDictionary) PdfReader.GetPdfObject(obj1) : (PdfDictionary) obj1; + PdfObject obj = appDic.Get(PdfName.N); + PdfAppearance app = null; + if (obj != null) { + PdfObject objReal = PdfReader.GetPdfObject(obj); + + if (obj is PdfIndirectReference && !obj.IsIndirect()) + app = new PdfAppearance((PdfIndirectReference)obj); + else if (objReal is PdfStream) { + ((PdfDictionary)objReal).Put(PdfName.SUBTYPE, PdfName.FORM); + app = new PdfAppearance((PdfIndirectReference)obj); + } + else { + if (objReal.IsDictionary()) { + PdfName as_p = (PdfName)PdfReader.GetPdfObject(appDic.Get(PdfName.AS)); + if (as_p != null) { + PdfIndirectReference iref = (PdfIndirectReference)((PdfDictionary)objReal).Get(as_p); + if (iref != null) { + app = new PdfAppearance(iref); + if (iref.IsIndirect()) { + objReal = PdfReader.GetPdfObject(iref); + ((PdfDictionary)objReal).Put(PdfName.SUBTYPE, PdfName.FORM); + } + } + } + } + } + } + if (app != null) { + Rectangle box = PdfReader.GetNormalizedRectangle((PdfArray)PdfReader.GetPdfObject(annDic.Get(PdfName.RECT))); + PdfContentByte cb = this.GetOverContent(page); + cb.SetLiteral("Q "); + cb.AddTemplate(app, box.Left, box.Bottom); + cb.SetLiteral("q "); + } + } + } + for (int idx = 0; idx < ar.Count; ++idx) { + PdfObject annoto = PdfReader.GetPdfObject((PdfObject)ar[idx]); + if (annoto != null && annoto.IsDictionary()) { + PdfDictionary annot = (PdfDictionary)annoto; + if (PdfName.FREETEXT.Equals(annot.Get(PdfName.SUBTYPE))) { + ar.RemoveAt(idx); + --idx; + } + } + } + if (ar.Count == 0) { + PdfReader.KillIndirect(pageDic.Get(PdfName.ANNOTS)); + pageDic.Remove(PdfName.ANNOTS); + } + } + } + + /** + * @see com.lowagie.text.pdf.PdfWriter#getPageReference(int) + */ + public override PdfIndirectReference GetPageReference(int page) { + PdfIndirectReference ref_p = reader.GetPageOrigRef(page); + if (ref_p == null) + throw new ArgumentException("Invalid page number " + page); + return ref_p; + } + + /** + * @see com.lowagie.text.pdf.PdfWriter#addAnnotation(com.lowagie.text.pdf.PdfAnnotation) + */ + public override void AddAnnotation(PdfAnnotation annot) { + throw new Exception("Unsupported in this context. Use PdfStamper.AddAnnotation()"); + } + + internal void AddDocumentField(PdfIndirectReference ref_p) { + PdfDictionary catalog = reader.Catalog; + PdfDictionary acroForm = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.ACROFORM), catalog); + if (acroForm == null) { + acroForm = new PdfDictionary(); + catalog.Put(PdfName.ACROFORM, acroForm); + MarkUsed(catalog); + } + PdfArray fields = (PdfArray)PdfReader.GetPdfObject(acroForm.Get(PdfName.FIELDS), acroForm); + if (fields == null) { + fields = new PdfArray(); + acroForm.Put(PdfName.FIELDS, fields); + MarkUsed(acroForm); + } + if (!acroForm.Contains(PdfName.DA)) { + acroForm.Put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g ")); + MarkUsed(acroForm); + } + fields.Add(ref_p); + MarkUsed(fields); + } + + internal void AddFieldResources() { + if (fieldTemplates.Count == 0) + return; + PdfDictionary catalog = reader.Catalog; + PdfDictionary acroForm = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.ACROFORM), catalog); + if (acroForm == null) { + acroForm = new PdfDictionary(); + catalog.Put(PdfName.ACROFORM, acroForm); + MarkUsed(catalog); + } + PdfDictionary dr = (PdfDictionary)PdfReader.GetPdfObject(acroForm.Get(PdfName.DR), acroForm); + if (dr == null) { + dr = new PdfDictionary(); + acroForm.Put(PdfName.DR, dr); + MarkUsed(acroForm); + } + MarkUsed(dr); + foreach (PdfTemplate template in fieldTemplates.Keys) { + PdfFormField.MergeResources(dr, (PdfDictionary)template.Resources, this); + } + if (dr.Get(PdfName.ENCODING) == null) + dr.Put(PdfName.ENCODING, PdfName.WIN_ANSI_ENCODING); + PdfDictionary fonts = (PdfDictionary)PdfReader.GetPdfObject(dr.Get(PdfName.FONT)); + if (fonts == null) { + fonts = new PdfDictionary(); + dr.Put(PdfName.FONT, fonts); + } + if (!fonts.Contains(PdfName.HELV)) { + PdfDictionary dic = new PdfDictionary(PdfName.FONT); + dic.Put(PdfName.BASEFONT, PdfName.HELVETICA); + dic.Put(PdfName.ENCODING, PdfName.WIN_ANSI_ENCODING); + dic.Put(PdfName.NAME, PdfName.HELV); + dic.Put(PdfName.SUBTYPE, PdfName.TYPE1); + fonts.Put(PdfName.HELV, AddToBody(dic).IndirectReference); + } + if (!fonts.Contains(PdfName.ZADB)) { + PdfDictionary dic = new PdfDictionary(PdfName.FONT); + dic.Put(PdfName.BASEFONT, PdfName.ZAPFDINGBATS); + dic.Put(PdfName.NAME, PdfName.ZADB); + dic.Put(PdfName.SUBTYPE, PdfName.TYPE1); + fonts.Put(PdfName.ZADB, AddToBody(dic).IndirectReference); + } + if (acroForm.Get(PdfName.DA) == null) { + acroForm.Put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g ")); + MarkUsed(acroForm); + } + } + + internal void ExpandFields(PdfFormField field, ArrayList allAnnots) { + allAnnots.Add(field); + ArrayList kids = field.Kids; + if (kids != null) { + for (int k = 0; k < kids.Count; ++k) { + ExpandFields((PdfFormField)kids[k], allAnnots); + } + } + } + + internal void AddAnnotation(PdfAnnotation annot, PdfDictionary pageN) { + ArrayList allAnnots = new ArrayList(); + if (annot.IsForm()) { + fieldsAdded = true; + AcroFields afdummy = AcroFields; + PdfFormField field = (PdfFormField)annot; + if (field.Parent != null) + return; + ExpandFields(field, allAnnots); + } + else + allAnnots.Add(annot); + for (int k = 0; k < allAnnots.Count; ++k) { + annot = (PdfAnnotation)allAnnots[k]; + if (annot.PlaceInPage > 0) + pageN = reader.GetPageN(annot.PlaceInPage); + if (annot.IsForm()) { + if (!annot.IsUsed()) { + Hashtable templates = annot.Templates; + if (templates != null) { + foreach (object tpl in templates.Keys) { + fieldTemplates[tpl] = null; + } + } + } + PdfFormField field = (PdfFormField)annot; + if (field.Parent == null) + AddDocumentField(field.IndirectReference); + } + if (annot.IsAnnotation()) { + PdfObject pdfobj = PdfReader.GetPdfObject(pageN.Get(PdfName.ANNOTS), pageN); + PdfArray annots = null; + if (pdfobj == null || !pdfobj.IsArray()) { + annots = new PdfArray(); + pageN.Put(PdfName.ANNOTS, annots); + MarkUsed(pageN); + } + else + annots = (PdfArray)pdfobj; + annots.Add(annot.IndirectReference); + MarkUsed(annots); + if (!annot.IsUsed()) { + PdfRectangle rect = (PdfRectangle)annot.Get(PdfName.RECT); + if (rect != null && (rect.Left != 0 || rect.Right != 0 || rect.Top != 0 || rect.Bottom != 0)) { + int rotation = reader.GetPageRotation(pageN); + Rectangle pageSize = reader.GetPageSizeWithRotation(pageN); + switch (rotation) { + case 90: + annot.Put(PdfName.RECT, new PdfRectangle( + pageSize.Top - rect.Bottom, + rect.Left, + pageSize.Top - rect.Top, + rect.Right)); + break; + case 180: + annot.Put(PdfName.RECT, new PdfRectangle( + pageSize.Right - rect.Left, + pageSize.Top - rect.Bottom, + pageSize.Right - rect.Right, + pageSize.Top - rect.Top)); + break; + case 270: + annot.Put(PdfName.RECT, new PdfRectangle( + rect.Bottom, + pageSize.Right - rect.Left, + rect.Top, + pageSize.Right - rect.Right)); + break; + } + } + } + } + if (!annot.IsUsed()) { + annot.SetUsed(); + AddToBody(annot, annot.IndirectReference); + } + } + } + + internal override void AddAnnotation(PdfAnnotation annot, int page) { + AddAnnotation(annot, reader.GetPageN(page)); + } + + private void OutlineTravel(PRIndirectReference outline) { + while (outline != null) { + PdfDictionary outlineR = (PdfDictionary)PdfReader.GetPdfObjectRelease(outline); + PRIndirectReference first = (PRIndirectReference)outlineR.Get(PdfName.FIRST); + if (first != null) { + OutlineTravel(first); + } + PdfReader.KillIndirect(outlineR.Get(PdfName.DEST)); + PdfReader.KillIndirect(outlineR.Get(PdfName.A)); + PdfReader.KillIndirect(outline); + outline = (PRIndirectReference)outlineR.Get(PdfName.NEXT); + } + } + + internal void DeleteOutlines() { + PdfDictionary catalog = reader.Catalog; + PRIndirectReference outlines = (PRIndirectReference)catalog.Get(PdfName.OUTLINES); + if (outlines == null) + return; + OutlineTravel(outlines); + PdfReader.KillIndirect(outlines); + catalog.Remove(PdfName.OUTLINES); + MarkUsed(catalog); + } + + internal void SetJavaScript() { + Hashtable djs = pdf.GetDocumentLevelJS(); + if (djs.Count == 0) + return; + PdfDictionary catalog = reader.Catalog; + PdfDictionary names = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.NAMES), catalog); + if (names == null) { + names = new PdfDictionary(); + catalog.Put(PdfName.NAMES, names); + MarkUsed(catalog); + } + MarkUsed(names); + PdfDictionary tree = PdfNameTree.WriteTree(djs, this); + names.Put(PdfName.JAVASCRIPT, AddToBody(tree).IndirectReference); + } + + void AddFileAttachments() { + Hashtable fs = pdf.GetDocumentFileAttachment(); + if (fs.Count == 0) + return; + PdfDictionary catalog = reader.Catalog; + PdfDictionary names = (PdfDictionary)PdfReader.GetPdfObject(catalog.Get(PdfName.NAMES), catalog); + if (names == null) { + names = new PdfDictionary(); + catalog.Put(PdfName.NAMES, names); + MarkUsed(catalog); + } + MarkUsed(names); + Hashtable old = PdfNameTree.ReadTree((PdfDictionary)PdfReader.GetPdfObjectRelease(names.Get(PdfName.EMBEDDEDFILES))); + foreach (DictionaryEntry entry in fs) { + String name = (String)entry.Key; + int k = 0; + String nn = name; + while (old.ContainsKey(nn)) { + ++k; + nn += " " + k; + } + old[nn] = entry.Value; + } + PdfDictionary tree = PdfNameTree.WriteTree(old, this); + names.Put(PdfName.EMBEDDEDFILES, AddToBody(tree).IndirectReference); + } + + /** + * Adds or replaces the Collection Dictionary in the Catalog. + * @param collection the new collection dictionary. + */ + internal void MakePackage(PdfCollection collection) { + PdfDictionary catalog = reader.Catalog; + catalog.Put( PdfName.COLLECTION, collection ); + } + + internal void SetOutlines() { + if (newBookmarks == null) + return; + DeleteOutlines(); + if (newBookmarks.Count == 0) + return; + PdfDictionary catalog = reader.Catalog; + bool namedAsNames = (catalog.Get(PdfName.DESTS) != null); + WriteOutlines(catalog, namedAsNames); + MarkUsed(catalog); + } + + /** + * Sets the viewer preferences. + * @param preferences the viewer preferences + * @see PdfWriter#setViewerPreferences(int) + */ + public override int ViewerPreferences { + set { + useVp = true; + this.viewerPreferences.ViewerPreferences = value; + } + } + + /** Adds a viewer preference + * @param preferences the viewer preferences + * @see PdfViewerPreferences#addViewerPreference + */ + public override void AddViewerPreference(PdfName key, PdfObject value) { + useVp = true; + this.viewerPreferences.AddViewerPreference(key, value); + } + + /** + * Set the signature flags. + * @param f the flags. This flags are ORed with current ones + */ + public override int SigFlags { + set { + sigFlags |= value; + } + } + + /** Always throws an UnsupportedOperationException. + * @param actionType ignore + * @param action ignore + * @throws PdfException ignore + * @see PdfStamper#setPageAction(PdfName, PdfAction, int) + */ + public override void SetPageAction(PdfName actionType, PdfAction action) { + throw new InvalidOperationException("Use SetPageAction(PdfName actionType, PdfAction action, int page)"); + } + + /** + * Sets the open and close page additional action. + * @param actionType the action type. It can be PdfWriter.PAGE_OPEN + * or PdfWriter.PAGE_CLOSE + * @param action the action to perform + * @param page the page where the action will be applied. The first page is 1 + * @throws PdfException if the action type is invalid + */ + internal void SetPageAction(PdfName actionType, PdfAction action, int page) { + if (!actionType.Equals(PAGE_OPEN) && !actionType.Equals(PAGE_CLOSE)) + throw new PdfException("Invalid page additional action type: " + actionType.ToString()); + PdfDictionary pg = reader.GetPageN(page); + PdfDictionary aa = (PdfDictionary)PdfReader.GetPdfObject(pg.Get(PdfName.AA), pg); + if (aa == null) { + aa = new PdfDictionary(); + pg.Put(PdfName.AA, aa); + MarkUsed(pg); + } + aa.Put(actionType, action); + MarkUsed(aa); + } + + /** + * Always throws an UnsupportedOperationException. + * @param seconds ignore + */ + public override int Duration { + set { + throw new InvalidOperationException("Use the methods at Pdfstamper."); + } + } + + /** + * Always throws an UnsupportedOperationException. + * @param transition ignore + */ + public override PdfTransition Transition { + set { + throw new InvalidOperationException("Use the methods at Pdfstamper."); + } + } + + /** + * Sets the display duration for the page (for presentations) + * @param seconds the number of seconds to display the page. A negative value removes the entry + * @param page the page where the duration will be applied. The first page is 1 + */ + internal void SetDuration(int seconds, int page) { + PdfDictionary pg = reader.GetPageN(page); + if (seconds < 0) + pg.Remove(PdfName.DUR); + else + pg.Put(PdfName.DUR, new PdfNumber(seconds)); + MarkUsed(pg); + } + + /** + * Sets the transition for the page + * @param transition the transition object. A null removes the transition + * @param page the page where the transition will be applied. The first page is 1 + */ + internal void SetTransition(PdfTransition transition, int page) { + PdfDictionary pg = reader.GetPageN(page); + if (transition == null) + pg.Remove(PdfName.TRANS); + else + pg.Put(PdfName.TRANS, transition.TransitionDictionary); + MarkUsed(pg); + } + + protected internal void MarkUsed(PdfObject obj) { + if (append && obj != null) { + PRIndirectReference ref_p = null; + if (obj.Type == PdfObject.INDIRECT) + ref_p = (PRIndirectReference)obj; + else + ref_p = obj.IndRef; + if (ref_p != null) + marked[ref_p.Number] = 1; + } + } + + protected internal void MarkUsed(int num) { + if (append) + marked[num] = 1; + } + + /** + * Getter for property append. + * @return Value of property append. + */ + internal bool IsAppend() { + return append; + } + + /** Additional-actions defining the actions to be taken in + * response to various trigger events affecting the document + * as a whole. The actions types allowed are: DOCUMENT_CLOSE, + * WILL_SAVE, DID_SAVE, WILL_PRINT + * and DID_PRINT. + * + * @param actionType the action type + * @param action the action to execute in response to the trigger + * @throws PdfException on invalid action type + */ + public override void SetAdditionalAction(PdfName actionType, PdfAction action) { + if (!(actionType.Equals(DOCUMENT_CLOSE) || + actionType.Equals(WILL_SAVE) || + actionType.Equals(DID_SAVE) || + actionType.Equals(WILL_PRINT) || + actionType.Equals(DID_PRINT))) { + throw new PdfException("Invalid additional action type: " + actionType.ToString()); + } + PdfDictionary aa = (PdfDictionary)PdfReader.GetPdfObject(reader.Catalog.Get(PdfName.AA)); + if (aa == null) { + if (action == null) + return; + aa = new PdfDictionary(); + reader.Catalog.Put(PdfName.AA, aa); + } + MarkUsed(aa); + if (action == null) + aa.Remove(actionType); + else + aa.Put(actionType, action); + } + + /** + * @see com.lowagie.text.pdf.PdfWriter#setOpenAction(com.lowagie.text.pdf.PdfAction) + */ + public override void SetOpenAction(PdfAction action) { + openAction = action; + } + + /** + * @see com.lowagie.text.pdf.PdfWriter#setOpenAction(java.lang.String) + */ + public override void SetOpenAction(String name) { + throw new InvalidOperationException("Open actions by name are not supported."); + } + + /** + * @see com.lowagie.text.pdf.PdfWriter#setThumbnail(com.lowagie.text.Image) + */ + public override Image Thumbnail { + set { + throw new InvalidOperationException("Use PdfStamper.Thumbnail"); + } + } + + internal void SetThumbnail(Image image, int page) { + PdfIndirectReference thumb = GetImageReference(AddDirectImageSimple(image)); + reader.ResetReleasePage(); + PdfDictionary dic = reader.GetPageN(page); + dic.Put(PdfName.THUMB, thumb); + reader.ResetReleasePage(); + } + + /** + * Reads the OCProperties dictionary from the catalog of the existing document + * and fills the documentOCG, documentOCGorder and OCGRadioGroup variables in PdfWriter. + * Note that the original OCProperties of the existing document can contain more information. + * @since 2.1.2 + */ + protected void ReadOCProperties() { + if (documentOCG.Count != 0) { + return; + } + PdfDictionary dict = reader.Catalog.GetAsDict(PdfName.OCPROPERTIES); + if (dict == null) { + return; + } + PdfArray ocgs = dict.GetAsArray(PdfName.OCGS); + PdfIndirectReference refi; + PdfLayer layer; + Hashtable ocgmap = new Hashtable(); + for (ListIterator i = ocgs.GetListIterator(); i.HasNext();) { + refi = (PdfIndirectReference)i.Next(); + layer = new PdfLayer(null); + layer.Ref = refi; + layer.OnPanel = false; + layer.Merge((PdfDictionary)PdfReader.GetPdfObject(refi)); + ocgmap[refi.ToString()] = layer; + } + PdfDictionary d = dict.GetAsDict(PdfName.D); + PdfArray off = d.GetAsArray(PdfName.OFF); + if (off != null) { + for (ListIterator i = off.GetListIterator(); i.HasNext(); ) { + refi = (PdfIndirectReference)i.Next(); + layer = (PdfLayer)ocgmap[refi.ToString()]; + layer.On = false; + } + } + PdfArray order = d.GetAsArray(PdfName.ORDER); + if (order != null) { + AddOrder(null, order, ocgmap); + } + foreach (object o in ocgmap.Values) + documentOCG[o] = null; + OCGRadioGroup = d.GetAsArray(PdfName.RBGROUPS); + OCGLocked = d.GetAsArray(PdfName.LOCKED); + } + + /** + * Recursive method to reconstruct the documentOCGorder variable in the writer. + * @param parent a parent PdfLayer (can be null) + * @param arr an array possibly containing children for the parent PdfLayer + * @param ocgmap a Hashtable with indirect reference Strings as keys and PdfLayer objects as values. + * @since 2.1.2 + */ + private void AddOrder(PdfLayer parent, PdfArray arr, Hashtable ocgmap) { + PdfObject obj; + PdfLayer layer; + for (int i = 0; i < arr.Size; i++) { + obj = arr.GetPdfObject(i); + if (obj.IsIndirect()) { + layer = (PdfLayer)ocgmap[obj.ToString()]; + layer.OnPanel = true; + RegisterLayer(layer); + if (parent != null) { + parent.AddChild(layer); + } + if (arr.Size > i + 1 && arr.GetPdfObject(i + 1).IsArray()) { + i++; + AddOrder(layer, (PdfArray)arr.GetPdfObject(i), ocgmap); + } + } + else if (obj.IsArray()) { + ArrayList sub = ((PdfArray)obj).ArrayList; + if (sub.Count == 0) return; + obj = (PdfObject)sub[0]; + if (obj.IsString()) { + layer = new PdfLayer(sub[0].ToString()); + layer.OnPanel = true; + RegisterLayer(layer); + if (parent != null) { + parent.AddChild(layer); + } + PdfArray array = new PdfArray(); + foreach (PdfObject o2 in sub) { + array.Add(o2); + } + AddOrder(layer, array, ocgmap); + } + else { + AddOrder(parent, (PdfArray)obj, ocgmap); + } + } + } + } + + /** + * Gets the PdfLayer objects in an existing document as a Map + * with the names/titles of the layers as keys. + * @return a Map with all the PdfLayers in the document (and the name/title of the layer as key) + * @since 2.1.2 + */ + public Hashtable GetPdfLayers() { + if (documentOCG.Count == 0) { + ReadOCProperties(); + } + Hashtable map = new Hashtable(); + String key; + foreach (PdfLayer layer in documentOCG) { + if (layer.Title == null) { + key = layer.GetAsString(PdfName.NAME).ToString(); + } + else { + key = layer.Title; + } + if (map.ContainsKey(key)) { + int seq = 2; + String tmp = key + "(" + seq + ")"; + while (map.ContainsKey(tmp)) { + seq++; + tmp = key + "(" + seq + ")"; + } + key = tmp; + } + map[key] = layer; + } + return map; + } + + internal class PageStamp { + + internal PdfDictionary pageN; + internal StampContent under; + internal StampContent over; + internal PageResources pageResources; + internal int replacePoint = 0; + + internal PageStamp(PdfStamperImp stamper, PdfReader reader, PdfDictionary pageN) { + this.pageN = pageN; + pageResources = new PageResources(); + PdfDictionary resources = (PdfDictionary)PdfReader.GetPdfObject(pageN.Get(PdfName.RESOURCES)); + pageResources.SetOriginalResources(resources, stamper.namePtr); + } + } + + public override PdfContentByte DirectContent { + get { + throw new InvalidOperationException("Use PdfStamper.GetUnderContent() or PdfStamper.GetOverContent()"); + } + } + + public override PdfContentByte DirectContentUnder { + get { + throw new InvalidOperationException("Use PdfStamper.GetUnderContent() or PdfStamper.GetOverContent()"); + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfStream.cs b/iTechSharp/iTextSharp/text/pdf/PdfStream.cs new file mode 100644 index 0000000..4abfed8 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfStream.cs @@ -0,0 +1,324 @@ +using System; +using System.IO; +using System.Collections; + +using System.util.zlib; + +/* + * $Id: PdfStream.cs,v 1.12 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * PdfStream is the Pdf stream object. + *

    + * A stream, like a string, is a sequence of characters. However, an application can + * read a small portion of a stream at a time, while a string must be read in its entirety. + * For this reason, objects with potentially large amounts of data, such as images and + * page descriptions, are represented as streams.
    + * A stream consists of a dictionary that describes a sequence of characters, followed by + * the keyword stream, followed by zero or more lines of characters, followed by + * the keyword endstream.
    + * All streams must be PdfIndirectObjects. The stream dictionary must be a direct + * object. The keyword stream that follows the stream dictionary should be followed by + * a carriage return and linefeed or just a linefeed.
    + * Remark: In this version only the FLATEDECODE-filter is supported.
    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.8 (page 41-53).
    + * + * @see PdfObject + * @see PdfDictionary + */ + + public class PdfStream : PdfDictionary { + + // membervariables + + /** is the stream compressed? */ + protected bool compressed = false; + + protected MemoryStream streamBytes = null; + + protected Stream inputStream; + protected PdfIndirectReference iref; + protected int inputStreamLength = -1; + protected PdfWriter writer; + protected int rawLength; + + internal static byte[] STARTSTREAM = DocWriter.GetISOBytes("stream\n"); + internal static byte[] ENDSTREAM = DocWriter.GetISOBytes("\nendstream"); + internal static int SIZESTREAM = STARTSTREAM.Length + ENDSTREAM.Length; + + // constructors + + /** + * Constructs a PdfStream-object. + * + * @param bytes content of the new PdfObject as an array of byte. + */ + + public PdfStream(byte[] bytes) : base() { + type = STREAM; + this.bytes = bytes; + rawLength = bytes.Length; + Put(PdfName.LENGTH, new PdfNumber(bytes.Length)); + } + + /** + * Creates an efficient stream. No temporary array is ever created. The InputStream + * is totally consumed but is not closed. The general usage is: + *

    + *

    +         * InputStream in = ...;
    +         * PdfStream stream = new PdfStream(in, writer);
    +         * stream.FlateCompress();
    +         * writer.AddToBody(stream);
    +         * stream.WriteLength();
    +         * in.Close();
    +         * 
    + * @param inputStream the data to write to this stream + * @param writer the PdfWriter for this stream + */ + public PdfStream(Stream inputStream, PdfWriter writer) { + type = STREAM; + this.inputStream = inputStream; + this.writer = writer; + iref = writer.PdfIndirectReference; + Put(PdfName.LENGTH, iref); + } + + /** + * Constructs a PdfStream-object. + */ + + protected PdfStream() : base() { + type = STREAM; + } + + // methods overriding some methods of PdfObject + + /** + * Writes the stream length to the PdfWriter. + *

    + * This method must be called and can only be called if the contructor {@link #PdfStream(InputStream,PdfWriter)} + * is used to create the stream. + * @throws IOException on error + * @see #PdfStream(InputStream,PdfWriter) + */ + public void WriteLength() { + if (inputStream == null) + throw new PdfException("WriteLength() can only be called in a contructed PdfStream(InputStream,PdfWriter)."); + if (inputStreamLength == -1) + throw new PdfException("WriteLength() can only be called after output of the stream body."); + writer.AddToBody(new PdfNumber(inputStreamLength), iref, false); + } + + public int RawLength { + get { + return rawLength; + } + } + + // methods + + /** + * Compresses the stream. + * + * @throws PdfException if a filter is allready defined + */ + + public void FlateCompress() { + if (!Document.Compress) + return; + // check if the flateCompress-method has allready been + if (compressed) { + return; + } + if (inputStream != null) { + compressed = true; + return; + } + // check if a filter allready exists + PdfObject filter = PdfReader.GetPdfObject(Get(PdfName.FILTER)); + if (filter != null) { + if (filter.IsName()) { + if (PdfName.FLATEDECODE.Equals(filter)) + return; + } + else if (filter.IsArray()) { + if (((PdfArray) filter).Contains(PdfName.FLATEDECODE)) + return; + } + else { + throw new PdfException("Stream could not be compressed: filter is not a name or array."); + } + } + // compress + MemoryStream stream = new MemoryStream(); + ZDeflaterOutputStream zip = new ZDeflaterOutputStream(stream); + if (streamBytes != null) + streamBytes.WriteTo(zip); + else + zip.Write(bytes, 0, bytes.Length); + //zip.Close(); + zip.Finish(); + // update the object + streamBytes = stream; + bytes = null; + Put(PdfName.LENGTH, new PdfNumber(streamBytes.Length)); + if (filter == null) { + Put(PdfName.FILTER, PdfName.FLATEDECODE); + } + else { + PdfArray filters = new PdfArray(filter); + filters.Add(PdfName.FLATEDECODE); + Put(PdfName.FILTER, filters); + } + compressed = true; + } + + protected virtual void SuperToPdf(PdfWriter writer, Stream os) { + base.ToPdf(writer, os); + } + + public override void ToPdf(PdfWriter writer, Stream os) { + if (inputStream != null && compressed) + Put(PdfName.FILTER, PdfName.FLATEDECODE); + PdfEncryption crypto = null; + if (writer != null) + crypto = writer.Encryption; + if (crypto != null) { + PdfObject filter = Get(PdfName.FILTER); + if (filter != null) { + if (PdfName.CRYPT.Equals(filter)) + crypto = null; + else if (filter.IsArray()) { + ArrayList af = ((PdfArray)filter).ArrayList; + if (af.Count > 0 && PdfName.CRYPT.Equals(af[0])) + crypto = null; + } + } + } + PdfObject nn = Get(PdfName.LENGTH); + if (crypto != null && nn != null && nn.IsNumber()) { + int sz = ((PdfNumber)nn).IntValue; + Put(PdfName.LENGTH, new PdfNumber(crypto.CalculateStreamSize(sz))); + SuperToPdf(writer, os); + Put(PdfName.LENGTH, nn); + } + else + SuperToPdf(writer, os); + os.Write(STARTSTREAM, 0, STARTSTREAM.Length); + if (inputStream != null) { + rawLength = 0; + ZDeflaterOutputStream def = null; + OutputStreamCounter osc = new OutputStreamCounter(os); + OutputStreamEncryption ose = null; + Stream fout = osc; + if (crypto != null) + fout = ose = crypto.GetEncryptionStream(fout); + if (compressed) + fout = def = new ZDeflaterOutputStream(fout); + + byte[] buf = new byte[4192]; + while (true) { + int n = inputStream.Read(buf, 0, buf.Length); + if (n <= 0) + break; + fout.Write(buf, 0, n); + rawLength += n; + } + if (def != null) + def.Finish(); + if (ose != null) + ose.Finish(); + inputStreamLength = osc.Counter; + } + else { + if (crypto == null) { + if (streamBytes != null) + streamBytes.WriteTo(os); + else + os.Write(bytes, 0, bytes.Length); + } + else { + byte[] b; + if (streamBytes != null) { + b = crypto.EncryptByteArray(streamBytes.ToArray()); + } + else { + b = crypto.EncryptByteArray(bytes); + } + os.Write(b, 0, b.Length); + } + } + os.Write(ENDSTREAM, 0, ENDSTREAM.Length); + } + + /** + * Writes the data content to an Stream. + * @param os the destination to write to + * @throws IOException on error + */ + public void WriteContent(Stream os) { + if (streamBytes != null) + streamBytes.WriteTo(os); + else if (bytes != null) + os.Write(bytes, 0, bytes.Length); + } + + /** + * @see com.lowagie.text.pdf.PdfObject#toString() + */ + public override String ToString() { + if (Get(PdfName.TYPE) == null) return "Stream"; + return "Stream of type: " + Get(PdfName.TYPE); + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfString.cs b/iTechSharp/iTextSharp/text/pdf/PdfString.cs new file mode 100644 index 0000000..01eedef --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfString.cs @@ -0,0 +1,232 @@ +using System; +using System.IO; + +/* + * $Id: PdfString.cs,v 1.6 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * A PdfString-class is the PDF-equivalent of a JAVA-string-object. + *

    + * A string is a sequence of characters delimited by parenthesis. If a string is too long + * to be conveniently placed on a single line, it may be split across multiple lines by using + * the backslash character (\) at the end of a line to indicate that the string continues + * on the following line. Within a string, the backslash character is used as an escape to + * specify unbalanced parenthesis, non-printing ASCII characters, and the backslash character + * itself. Use of the \ddd escape sequence is the preferred way to represent characters + * outside the printable ASCII character set.
    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 4.4 (page 37-39). + * + * @see PdfObject + * @see BadPdfFormatException + */ + + public class PdfString : PdfObject { + + // membervariables + + /** The value of this object. */ + protected string value = NOTHING; + protected string originalValue = null; + + /** The encoding. */ + protected string encoding = TEXT_PDFDOCENCODING; + protected int objNum = 0; + protected int objGen = 0; + protected bool hexWriting = false; + // constructors + + /** + * Constructs an empty PdfString-object. + */ + + public PdfString() : base(STRING) {} + + /** + * Constructs a PdfString-object. + * + * @param value the content of the string + */ + + public PdfString(string value) : base(STRING) { + this.value = value; + } + + /** + * Constructs a PdfString-object. + * + * @param value the content of the string + * @param encoding an encoding + */ + + public PdfString(string value, string encoding) : base(STRING) { + this.value = value; + this.encoding = encoding; + } + + /** + * Constructs a PdfString-object. + * + * @param bytes an array of byte + */ + + public PdfString(byte[] bytes) : base(STRING) { + value = PdfEncodings.ConvertToString(bytes, null); + encoding = NOTHING; + } + + // methods overriding some methods in PdfObject + + /** + * Returns the PDF representation of this PdfString. + * + * @return an array of bytes + */ + + public override void ToPdf(PdfWriter writer, Stream os) { + byte[] b = GetBytes(); + PdfEncryption crypto = null; + if (writer != null) + crypto = writer.Encryption; + if (crypto != null) { + b = crypto.EncryptByteArray(b); + } + if (hexWriting) { + ByteBuffer buf = new ByteBuffer(); + buf.Append('<'); + int len = b.Length; + for (int k = 0; k < len; ++k) + buf.AppendHex(b[k]); + buf.Append('>'); + os.Write(buf.ToByteArray(), 0, buf.Size); + } + else { + b = PdfContentByte.EscapeString(b); + os.Write(b, 0, b.Length); + } + } + + /** + * Returns the string value of the PdfString-object. + * + * @return a string + */ + + public override string ToString() { + return value; + } + + // other methods + + /** + * Gets the encoding of this string. + * + * @return a string + */ + + public string Encoding { + get { + return encoding; + } + } + public String ToUnicodeString() { + if (encoding != null && encoding.Length != 0) + return value; + GetBytes(); + if (bytes.Length >= 2 && bytes[0] == (byte)254 && bytes[1] == (byte)255) + return PdfEncodings.ConvertToString(bytes, PdfObject.TEXT_UNICODE); + else + return PdfEncodings.ConvertToString(bytes, PdfObject.TEXT_PDFDOCENCODING); + } + + internal void SetObjNum(int objNum, int objGen) { + this.objNum = objNum; + this.objGen = objGen; + } + + internal void Decrypt(PdfReader reader) { + PdfEncryption decrypt = reader.Decrypt; + if (decrypt != null) { + originalValue = value; + decrypt.SetHashKey(objNum, objGen); + bytes = PdfEncodings.ConvertToBytes(value, null); + bytes = decrypt.DecryptByteArray(bytes); + value = PdfEncodings.ConvertToString(bytes, null); + } + } + + public override byte[] GetBytes() { + if (bytes == null) { + if (encoding != null && encoding.Equals(TEXT_UNICODE) && PdfEncodings.IsPdfDocEncoding(value)) + bytes = PdfEncodings.ConvertToBytes(value, TEXT_PDFDOCENCODING); + else + bytes = PdfEncodings.ConvertToBytes(value, encoding); + } + return bytes; + } + + public byte[] GetOriginalBytes() { + if (originalValue == null) + return GetBytes(); + return PdfEncodings.ConvertToBytes(originalValue, null); + } + + public PdfString SetHexWriting(bool hexWriting) { + this.hexWriting = hexWriting; + return this; + } + + public bool IsHexWriting() { + return hexWriting; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfStructureElement.cs b/iTechSharp/iTextSharp/text/pdf/PdfStructureElement.cs new file mode 100644 index 0000000..08c8608 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfStructureElement.cs @@ -0,0 +1,136 @@ +using System; + +/* + * $Id: PdfStructureElement.cs,v 1.3 2005/11/02 12:24:06 psoares33 Exp $ + * + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * This is a node in a document logical structure. It may contain a mark point or it may contain + * other nodes. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfStructureElement : PdfDictionary { + + /** + * Holds value of property kids. + */ + private PdfStructureElement parent; + private PdfStructureTreeRoot top; + + /** + * Holds value of property reference. + */ + private PdfIndirectReference reference; + + /** + * Creates a new instance of PdfStructureElement. + * @param parent the parent of this node + * @param structureType the type of structure. It may be a standard type or a user type mapped by the role map + */ + public PdfStructureElement(PdfStructureElement parent, PdfName structureType) { + top = parent.top; + Init(parent, structureType); + this.parent = parent; + Put(PdfName.P, parent.reference); + } + + /** + * Creates a new instance of PdfStructureElement. + * @param parent the parent of this node + * @param structureType the type of structure. It may be a standard type or a user type mapped by the role map + */ + public PdfStructureElement(PdfStructureTreeRoot parent, PdfName structureType) { + top = parent; + Init(parent, structureType); + Put(PdfName.P, parent.Reference); + } + + private void Init(PdfDictionary parent, PdfName structureType) { + PdfObject kido = parent.Get(PdfName.K); + PdfArray kids = null; + if (kido != null && !kido.IsArray()) + throw new ArgumentException("The parent has already another function."); + if (kido == null) { + kids = new PdfArray(); + parent.Put(PdfName.K, kids); + } + else + kids = (PdfArray)kido; + kids.Add(this); + Put(PdfName.S, structureType); + reference = top.Writer.PdfIndirectReference; + } + + /** + * Gets the parent of this node. + * @return the parent of this node + */ + public PdfDictionary Parent { + get { + return parent; + } + } + + internal void SetPageMark(int page, int mark) { + if (mark >= 0) + Put(PdfName.K, new PdfNumber(mark)); + top.SetPageMark(page, reference); + } + + /** + * Gets the reference this object will be written to. + * @return the reference this object will be written to + */ + public PdfIndirectReference Reference { + get { + return this.reference; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfStructureTreeRoot.cs b/iTechSharp/iTextSharp/text/pdf/PdfStructureTreeRoot.cs new file mode 100644 index 0000000..f5c47ba --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfStructureTreeRoot.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections; + +/* + * $Id: PdfStructureTreeRoot.cs,v 1.2 2005/10/18 15:29:53 psoares33 Exp $ + * + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +namespace iTextSharp.text.pdf { + + /** + * The structure tree root corresponds to the highest hierarchy level in a tagged PDF. + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfStructureTreeRoot : PdfDictionary { + + private Hashtable parentTree = new Hashtable(); + private PdfIndirectReference reference; + + /** + * Holds value of property writer. + */ + private PdfWriter writer; + + /** Creates a new instance of PdfStructureTreeRoot */ + internal PdfStructureTreeRoot(PdfWriter writer) : base(PdfName.STRUCTTREEROOT) { + this.writer = writer; + reference = writer.PdfIndirectReference; + } + + /** + * Maps the user tags to the standard tags. The mapping will allow a standard application to make some sense of the tagged + * document whatever the user tags may be. + * @param used the user tag + * @param standard the standard tag + */ + public void MapRole(PdfName used, PdfName standard) { + PdfDictionary rm = (PdfDictionary)Get(PdfName.ROLEMAP); + if (rm == null) { + rm = new PdfDictionary(); + Put(PdfName.ROLEMAP, rm); + } + rm.Put(used, standard); + } + + /** + * Gets the writer. + * @return the writer + */ + public PdfWriter Writer { + get { + return this.writer; + } + } + + /** + * Gets the reference this object will be written to. + * @return the reference this object will be written to + */ + public PdfIndirectReference Reference { + get { + return this.reference; + } + } + + internal void SetPageMark(int page, PdfIndirectReference struc) { + PdfArray ar = (PdfArray)parentTree[page]; + if (ar == null) { + ar = new PdfArray(); + parentTree[page] = ar; + } + ar.Add(struc); + } + + private void NodeProcess(PdfDictionary struc, PdfIndirectReference reference) { + PdfObject obj = struc.Get(PdfName.K); + if (obj != null && obj.IsArray() && !((PdfObject)((PdfArray)obj).ArrayList[0]).IsNumber()) { + PdfArray ar = (PdfArray)obj; + ArrayList a = ar.ArrayList; + for (int k = 0; k < a.Count; ++k) { + PdfStructureElement e = (PdfStructureElement)a[k]; + a[k] = e.Reference; + NodeProcess(e, e.Reference); + } + } + if (reference != null) + writer.AddToBody(struc, reference); + } + + internal void BuildTree() { + Hashtable numTree = new Hashtable(); + foreach (int i in parentTree.Keys) { + PdfArray ar = (PdfArray)parentTree[i]; + numTree[i] = writer.AddToBody(ar).IndirectReference; + } + PdfDictionary dicTree = PdfNumberTree.WriteTree(numTree, writer); + if (dicTree != null) + Put(PdfName.PARENTTREE, writer.AddToBody(dicTree).IndirectReference); + + NodeProcess(this, reference); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfTable.cs b/iTechSharp/iTextSharp/text/pdf/PdfTable.cs new file mode 100644 index 0000000..f8d567e --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfTable.cs @@ -0,0 +1,319 @@ +using System; +using System.Collections; + +using iTextSharp.text; + +/* + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfTable is an object that contains the graphics and text of a table. + * + * @see iTextSharp.text.Table + * @see iTextSharp.text.Row + * @see iTextSharp.text.Cell + * @see PdfCell + */ + + public class PdfTable : Rectangle { + + // membervariables + + /** this is the number of columns in the table. */ + private int columns; + + /** this is the ArrayList with all the cell of the table header. */ + private ArrayList headercells; + + /** this is the ArrayList with all the cells in the table. */ + private ArrayList cells; + + /** Original table used to build this object*/ + protected Table table; + + /** Cached column widths. */ + protected float[] positions; + + // constructors + + /** + * Constructs a PdfTable-object. + * + * @param table a Table + * @param left the left border on the page + * @param right the right border on the page + * @param top the start position of the top of the table + */ + + internal PdfTable(Table table, float left, float right, float top) : base(left, top, right, top) { + // constructs a Rectangle (the bottomvalue will be changed afterwards) + this.table = table; + table.Complete(); + + // copying the attributes from class Table + CloneNonPositionParameters(table); + + this.columns = table.Columns; + positions = table.GetWidths(left, right - left); + + // initialisation of some parameters + Left = positions[0]; + Right = positions[positions.Length - 1]; + + headercells = new ArrayList(); + cells = new ArrayList(); + + UpdateRowAdditionsInternal(); + } + + // methods + + /** + * Updates the table row additions in the underlying table object and deletes all table rows, + * in order to preserve memory and detect future row additions. + *

    Pre-requisite: the object must have been built with the parameter supportUpdateRowAdditions equals to true. + */ + + internal void UpdateRowAdditions() { + table.Complete(); + UpdateRowAdditionsInternal(); + table.DeleteAllRows(); + } + + /** + * Updates the table row additions in the underlying table object + */ + + private void UpdateRowAdditionsInternal() { + // correct table : fill empty cells/ parse table in table + int prevRows = Rows; + int rowNumber = 0; + int groupNumber = 0; + bool groupChange; + int firstDataRow = table.LastHeaderRow + 1; + Cell cell; + PdfCell currentCell; + ArrayList newCells = new ArrayList(); + int rows = table.Size + 1; + float[] offsets = new float[rows]; + for (int i = 0; i < rows; i++) { + offsets[i] = Bottom; + } + + // loop over all the rows + foreach (Row row in table) { + groupChange = false; + if (row.IsEmpty()) { + if (rowNumber < rows - 1 && offsets[rowNumber + 1] > offsets[rowNumber]) offsets[rowNumber + 1] = offsets[rowNumber]; + } + else { + for (int i = 0; i < row.Columns; i++) { + cell = (Cell) row.GetCell(i); + if (cell != null) { + currentCell = new PdfCell(cell, rowNumber+prevRows, positions[i], positions[i + cell.Colspan], offsets[rowNumber], Cellspacing, Cellpadding); + if (rowNumber < firstDataRow) { + currentCell.SetHeader(); + headercells.Add(currentCell); + if (!table.NotAddedYet) + continue; + } + try { + if (offsets[rowNumber] - currentCell.Height - Cellpadding < offsets[rowNumber + currentCell.Rowspan]) { + offsets[rowNumber + currentCell.Rowspan] = offsets[rowNumber] - currentCell.Height - Cellpadding; + } + } + catch (ArgumentOutOfRangeException) { + if (offsets[rowNumber] - currentCell.Height < offsets[rows - 1]) { + offsets[rows - 1] = offsets[rowNumber] - currentCell.Height; + } + } + currentCell.GroupNumber = groupNumber; + groupChange |= cell.GroupChange; + newCells.Add(currentCell); + } + } + } + rowNumber++; + if ( groupChange ) groupNumber++; + } + + // loop over all the cells + int n = newCells.Count; + for (int i = 0; i < n; i++) { + currentCell = (PdfCell) newCells[i]; + try { + currentCell.Bottom = offsets[currentCell.Rownumber-prevRows + currentCell.Rowspan]; + } + catch (ArgumentOutOfRangeException) { + currentCell.Bottom = offsets[rows - 1]; + } + } + cells.AddRange(newCells); + Bottom = offsets[rows - 1]; + } + + /** + * Get the number of rows + */ + + internal int Rows { + get { + return cells.Count == 0 ? 0 : ((PdfCell)cells[cells.Count-1]).Rownumber+1; + } + } + + /** @see com.lowagie.text.Element#type() */ + public override int Type { + get { + return Element.TABLE; + } + } + + /** + * Returns the arraylist with the cells of the table header. + * + * @return an ArrayList + */ + + internal ArrayList HeaderCells { + get { + return headercells; + } + } + + /** + * Checks if there is a table header. + * + * @return an ArrayList + */ + + internal bool HasHeader() { + return headercells.Count > 0; + } + + /** + * Returns the arraylist with the cells of the table. + * + * @return an ArrayList + */ + + internal ArrayList Cells { + get { + return cells; + } + } + + /** + * Returns the number of columns of the table. + * + * @return the number of columns + */ + + internal int Columns { + get { + return columns; + } + } + + /** + * Returns the cellpadding of the table. + * + * @return the cellpadding + */ + + internal float Cellpadding { + get { + return table.Cellpadding; + } + } + + /** + * Returns the cellspacing of the table. + * + * @return the cellspacing + */ + + internal float Cellspacing { + get { + return table.Cellspacing; + } + } + + /** + * Checks if this Table has to fit a page. + * + * @return true if the table may not be split + */ + + public bool HasToFitPageTable() { + return table.TableFitsPage; + } + + /** + * Checks if the cells of this Table have to fit a page. + * + * @return true if the cells may not be split + */ + + public bool HasToFitPageCells() { + return table.CellsFitPage; + } + + /** + * Gets the offset of this table. + * + * @return the space between this table and the previous element. + */ + public float Offset { + get { + return table.Offset; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfTemplate.cs b/iTechSharp/iTextSharp/text/pdf/PdfTemplate.cs new file mode 100644 index 0000000..f1af760 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfTemplate.cs @@ -0,0 +1,281 @@ +using System; +using iTextSharp.text; +/* + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * Implements the form XObject. + */ + + public class PdfTemplate : PdfContentByte { + public const int TYPE_TEMPLATE = 1; + public const int TYPE_IMPORTED = 2; + public const int TYPE_PATTERN = 3; + protected int type; + /** The indirect reference to this template */ + protected PdfIndirectReference thisReference; + + /** The resources used by this template */ + protected PageResources pageResources; + + /** The bounding box of this template */ + protected Rectangle bBox = new Rectangle(0, 0); + + protected PdfArray matrix; + + protected PdfTransparencyGroup group; + + protected IPdfOCG layer; + + /** + *Creates a PdfTemplate. + */ + + protected PdfTemplate() : base(null) { + type = TYPE_TEMPLATE; + } + + /** + * Creates new PdfTemplate + * + * @param wr the PdfWriter + */ + + internal PdfTemplate(PdfWriter wr) : base(wr) { + type = TYPE_TEMPLATE; + pageResources = new PageResources(); + pageResources.AddDefaultColor(wr.DefaultColorspace); + thisReference = writer.PdfIndirectReference; + } + + /** + * Creates a new template. + *

    + * Creates a new template that is nothing more than a form XObject. This template can be included + * in this PdfContentByte or in another template. Templates are only written + * to the output when the document is closed permitting things like showing text in the first page + * that is only defined in the last page. + * + * @param width the bounding box width + * @param height the bounding box height + * @return the templated created + */ + public static PdfTemplate CreateTemplate(PdfWriter writer, float width, float height) { + return CreateTemplate(writer, width, height, null); + } + + internal static PdfTemplate CreateTemplate(PdfWriter writer, float width, float height, PdfName forcedName) { + PdfTemplate template = new PdfTemplate(writer); + template.Width = width; + template.Height = height; + writer.AddDirectTemplateSimple(template, forcedName); + return template; + } + + /** + * Gets the bounding width of this template. + * + * @return width the bounding width + */ + public float Width { + get { + return bBox.Width; + } + + set { + bBox.Left = 0; + bBox.Right = value; + } + } + + /** + * Gets the bounding heigth of this template. + * + * @return heigth the bounding height + */ + + public float Height { + get { + return bBox.Height; + } + + set { + bBox.Bottom = 0; + bBox.Top = value; + } + } + + public Rectangle BoundingBox { + get { + return bBox; + } + set { + this.bBox = value; + } + } + + /** + * Gets the layer this template belongs to. + * @return the layer this template belongs to or null for no layer defined + */ + public IPdfOCG Layer { + get { + return layer; + } + set { + layer = value; + } + } + + public void SetMatrix(float a, float b, float c, float d, float e, float f) { + matrix = new PdfArray(); + matrix.Add(new PdfNumber(a)); + matrix.Add(new PdfNumber(b)); + matrix.Add(new PdfNumber(c)); + matrix.Add(new PdfNumber(d)); + matrix.Add(new PdfNumber(e)); + matrix.Add(new PdfNumber(f)); + } + + internal PdfArray Matrix { + get { + return matrix; + } + } + + /** + * Gets the indirect reference to this template. + * + * @return the indirect reference to this template + */ + + public PdfIndirectReference IndirectReference { + get { + return thisReference; + } + } + + public void BeginVariableText() { + content.Append("/Tx BMC "); + } + + public void EndVariableText() { + content.Append("EMC "); + } + + /** + * Constructs the resources used by this template. + * + * @return the resources used by this template + */ + + internal virtual PdfObject Resources { + get { + return PageResources.Resources; + } + } + + /** + * Gets the stream representing this template. + * + * @return the stream representing this template + */ + + internal virtual PdfStream FormXObject { + get { + return new PdfFormXObject(this); + } + } + + /** + * Gets a duplicate of this PdfTemplate. All + * the members are copied by reference but the buffer stays different. + * @return a copy of this PdfTemplate + */ + + public override PdfContentByte Duplicate { + get { + PdfTemplate tpl = new PdfTemplate(); + tpl.writer = writer; + tpl.pdf = pdf; + tpl.thisReference = thisReference; + tpl.pageResources = pageResources; + tpl.bBox = new Rectangle(bBox); + tpl.group = group; + tpl.layer = layer; + if (matrix != null) { + tpl.matrix = new PdfArray(matrix); + } + tpl.separator = separator; + return tpl; + } + } + + public int Type { + get { + return type; + } + } + + internal override PageResources PageResources { + get { + return pageResources; + } + } + + public PdfTransparencyGroup Group { + get { + return this.group; + } + set { + group = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfTextArray.cs b/iTechSharp/iTextSharp/text/pdf/PdfTextArray.cs new file mode 100644 index 0000000..f86d366 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfTextArray.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections; + +/* + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** + * PdfTextArray defines an array with displacements and PdfString-objects. + *

    + * A TextArray is used with the operator TJ in PdfText. + * The first object in this array has to be a PdfString; + * see reference manual version 1.3 section 8.7.5, pages 346-347. + * OR + * see reference manual version 1.6 section 5.3.2, pages 378-379. + */ + + public class PdfTextArray{ + ArrayList arrayList = new ArrayList(); + + // To emit a more efficient array, we consolidate + // repeated numbers or strings into single array entries. + // "add( 50 ); Add( -50 );" will REMOVE the combined zero from the array. + // the alternative (leaving a zero in there) was Just Weird. + // --Mark Storer, May 12, 2008 + private String lastStr; + private float lastNum = float.NaN; + + // constructors + public PdfTextArray(String str) { + Add(str); + } + + public PdfTextArray() { + } + + /** + * Adds a PdfNumber to the PdfArray. + * + * @param number displacement of the string + */ + public void Add(PdfNumber number) { + Add((float)number.DoubleValue); + } + + public void Add(float number) { + if (number != 0) { + if (!float.IsNaN(lastNum)) { + lastNum += number; + if (lastNum != 0) { + ReplaceLast(lastNum); + } else { + arrayList.RemoveAt(arrayList.Count - 1); + } + } else { + lastNum = number; + arrayList.Add(lastNum); + } + lastStr = null; + } + // adding zero doesn't modify the TextArray at all + } + + public void Add(String str) { + if (str.Length > 0) { + if (lastStr != null) { + lastStr = lastStr + str; + ReplaceLast(lastStr); + } else { + lastStr = str; + arrayList.Add(lastStr); + } + lastNum = float.NaN; + } + // adding an empty string doesn't modify the TextArray at all + } + + internal ArrayList ArrayList { + get { + return arrayList; + } + } + + private void ReplaceLast(Object obj) { + // deliberately throw the IndexOutOfBoundsException if we screw up. + arrayList[arrayList.Count - 1] = obj; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfTransition.cs b/iTechSharp/iTextSharp/text/pdf/PdfTransition.cs new file mode 100644 index 0000000..993d0dd --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfTransition.cs @@ -0,0 +1,257 @@ +using System; + +/* + * Copyright 2002 by Josselin PUJO. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + public class PdfTransition { + /** + * Out Vertical Split + */ + public const int SPLITVOUT = 1; + /** + * Out Horizontal Split + */ + public const int SPLITHOUT = 2; + /** + * In Vertical Split + */ + public const int SPLITVIN = 3; + /** + * IN Horizontal Split + */ + public const int SPLITHIN = 4; + /** + * Vertical Blinds + */ + public const int BLINDV = 5; + /** + * Vertical Blinds + */ + public const int BLINDH = 6; + /** + * Inward Box + */ + public const int INBOX = 7; + /** + * Outward Box + */ + public const int OUTBOX = 8; + /** + * Left-Right Wipe + */ + public const int LRWIPE = 9; + /** + * Right-Left Wipe + */ + public const int RLWIPE = 10; + /** + * Bottom-Top Wipe + */ + public const int BTWIPE = 11; + /** + * Top-Bottom Wipe + */ + public const int TBWIPE = 12; + /** + * Dissolve + */ + public const int DISSOLVE = 13; + /** + * Left-Right Glitter + */ + public const int LRGLITTER = 14; + /** + * Top-Bottom Glitter + */ + public const int TBGLITTER = 15; + /** + * Diagonal Glitter + */ + public const int DGLITTER = 16; + + /** + * duration of the transition effect + */ + protected int duration; + /** + * type of the transition effect + */ + protected int type; + + /** + * Constructs a Transition. + * + */ + public PdfTransition() : this(BLINDH) {} + + /** + * Constructs a Transition. + * + *@param type type of the transition effect + */ + public PdfTransition(int type) : this(type,1) {} + + /** + * Constructs a Transition. + * + *@param type type of the transition effect + *@param duration duration of the transition effect + */ + public PdfTransition(int type, int duration) { + this.duration = duration; + this.type = type; + } + + + public int Duration { + get { + return duration; + } + } + + + public int Type { + get { + return type; + } + } + + public PdfDictionary TransitionDictionary { + get { + PdfDictionary trans = new PdfDictionary(PdfName.TRANS); + switch (type) { + case SPLITVOUT: + trans.Put(PdfName.S,PdfName.SPLIT); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DM,PdfName.V); + trans.Put(PdfName.M,PdfName.O); + break; + case SPLITHOUT: + trans.Put(PdfName.S,PdfName.SPLIT); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DM,PdfName.H); + trans.Put(PdfName.M,PdfName.O); + break; + case SPLITVIN: + trans.Put(PdfName.S,PdfName.SPLIT); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DM,PdfName.V); + trans.Put(PdfName.M,PdfName.I); + break; + case SPLITHIN: + trans.Put(PdfName.S,PdfName.SPLIT); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DM,PdfName.H); + trans.Put(PdfName.M,PdfName.I); + break; + case BLINDV: + trans.Put(PdfName.S,PdfName.BLINDS); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DM,PdfName.V); + break; + case BLINDH: + trans.Put(PdfName.S,PdfName.BLINDS); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DM,PdfName.H); + break; + case INBOX: + trans.Put(PdfName.S,PdfName.BOX); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.M,PdfName.I); + break; + case OUTBOX: + trans.Put(PdfName.S,PdfName.BOX); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.M,PdfName.O); + break; + case LRWIPE: + trans.Put(PdfName.S,PdfName.WIPE); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DI,new PdfNumber(0)); + break; + case RLWIPE: + trans.Put(PdfName.S,PdfName.WIPE); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DI,new PdfNumber(180)); + break; + case BTWIPE: + trans.Put(PdfName.S,PdfName.WIPE); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DI,new PdfNumber(90)); + break; + case TBWIPE: + trans.Put(PdfName.S,PdfName.WIPE); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DI,new PdfNumber(270)); + break; + case DISSOLVE: + trans.Put(PdfName.S,PdfName.DISSOLVE); + trans.Put(PdfName.D,new PdfNumber(duration)); + break; + case LRGLITTER: + trans.Put(PdfName.S,PdfName.GLITTER); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DI,new PdfNumber(0)); + break; + case TBGLITTER: + trans.Put(PdfName.S,PdfName.GLITTER); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DI,new PdfNumber(270)); + break; + case DGLITTER: + trans.Put(PdfName.S,PdfName.GLITTER); + trans.Put(PdfName.D,new PdfNumber(duration)); + trans.Put(PdfName.DI,new PdfNumber(315)); + break; + } + return trans; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfTransparencyGroup.cs b/iTechSharp/iTextSharp/text/pdf/PdfTransparencyGroup.cs new file mode 100644 index 0000000..214bd95 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfTransparencyGroup.cs @@ -0,0 +1,90 @@ +using System; +/* + * Copyright 2003 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** The transparency group dictionary. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PdfTransparencyGroup : PdfDictionary { + + /** + * Constructs a transparencyGroup. + */ + public PdfTransparencyGroup() { + Put(PdfName.S, PdfName.TRANSPARENCY); + } + + /** + * Determining the initial backdrop against which its stack is composited. + * @param isolated + */ + public bool Isolated { + set { + if (value) + Put(PdfName.I, PdfBoolean.PDFTRUE); + else + Remove(PdfName.I); + } + } + + /** + * Determining whether the objects within the stack are composited with one another or only with the group's backdrop. + * @param knockout + */ + public bool Knockout { + set { + if (value) + Put(PdfName.K, PdfBoolean.PDFTRUE); + else + Remove(PdfName.K); + } + } + + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PdfWriter.cs b/iTechSharp/iTextSharp/text/pdf/PdfWriter.cs new file mode 100644 index 0000000..dafd59d --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfWriter.cs @@ -0,0 +1,2973 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.util.collections; +using System.util; +using iTextSharp.text; +using iTextSharp.text.pdf.events; +using iTextSharp.text.pdf.interfaces; +using iTextSharp.text.pdf.intern; +using iTextSharp.text.pdf.collection; +using iTextSharp.text.xml.xmp; +using Org.BouncyCastle.X509; +/* + * $Id: PdfWriter.cs,v 1.48 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * A DocWriter class for PDF. + *

    + * When this PdfWriter is added + * to a certain PdfDocument, the PDF representation of every Element + * added to this Document will be written to the outputstream.

    + */ + + public class PdfWriter : DocWriter, + IPdfViewerPreferences, + IPdfEncryptionSettings, + IPdfVersion, + IPdfDocumentActions, + IPdfPageActions, + IPdfXConformance, + IPdfRunDirection, + IPdfAnnotations { + + // INNER CLASSES + + /** + * This class generates the structure of a PDF document. + *

    + * This class covers the third section of Chapter 5 in the 'Portable Document Format + * Reference Manual version 1.3' (page 55-60). It contains the body of a PDF document + * (section 5.14) and it can also generate a Cross-reference Table (section 5.15). + * + * @see PdfWriter + * @see PdfObject + * @see PdfIndirectObject + */ + + public class PdfBody { + + // inner classes + + /** + * PdfCrossReference is an entry in the PDF Cross-Reference table. + */ + + internal class PdfCrossReference : IComparable { + + // membervariables + private int type; + + /** Byte offset in the PDF file. */ + private int offset; + + private int refnum; + /** generation of the object. */ + private int generation; + + // constructors + /** + * Constructs a cross-reference element for a PdfIndirectObject. + * @param refnum + * @param offset byte offset of the object + * @param generation generationnumber of the object + */ + + internal PdfCrossReference(int refnum, int offset, int generation) { + type = 0; + this.offset = offset; + this.refnum = refnum; + this.generation = generation; + } + + /** + * Constructs a cross-reference element for a PdfIndirectObject. + * @param refnum + * @param offset byte offset of the object + */ + + internal PdfCrossReference(int refnum, int offset) { + type = 1; + this.offset = offset; + this.refnum = refnum; + this.generation = 0; + } + + internal PdfCrossReference(int type, int refnum, int offset, int generation) { + this.type = type; + this.offset = offset; + this.refnum = refnum; + this.generation = generation; + } + + internal int Refnum { + get { + return refnum; + } + } + + /** + * Returns the PDF representation of this PdfObject. + * @param os + * @throws IOException + */ + + public void ToPdf(Stream os) { + String s1 = offset.ToString().PadLeft(10, '0'); + String s2 = generation.ToString().PadLeft(5, '0'); + ByteBuffer buf = new ByteBuffer(40); + if (generation == 65535) { + buf.Append(s1).Append(' ').Append(s2).Append(" f \n"); + } + else { + buf.Append(s1).Append(' ').Append(s2).Append(" n \n"); + } + os.Write(buf.Buffer, 0, buf.Size); + } + + /** + * Writes PDF syntax to the Stream + * @param midSize + * @param os + * @throws IOException + */ + public void ToPdf(int midSize, Stream os) { + os.WriteByte((byte)type); + while (--midSize >= 0) + os.WriteByte((byte)((offset >> (8 * midSize)) & 0xff)); + os.WriteByte((byte)((generation >> 8) & 0xff)); + os.WriteByte((byte)(generation & 0xff)); + } + + /** + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int CompareTo(Object o) { + PdfCrossReference other = (PdfCrossReference)o; + return (refnum < other.refnum ? -1 : (refnum==other.refnum ? 0 : 1)); + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + public override bool Equals(Object obj) { + if (obj is PdfCrossReference) { + PdfCrossReference other = (PdfCrossReference)obj; + return (refnum == other.refnum); + } + else + return false; + } + + + public override int GetHashCode() { + return refnum; + } + } + + // membervariables + + private const int OBJSINSTREAM = 200; + + /** array containing the cross-reference table of the normal objects. */ + private k_Tree xrefs; + private int refnum; + /** the current byteposition in the body. */ + private int position; + private PdfWriter writer; + private ByteBuffer index; + private ByteBuffer streamObjects; + private int currentObjNum; + private int numObj = 0; + + // constructors + + /** + * Constructs a new PdfBody. + * @param writer + */ + internal PdfBody(PdfWriter writer) { + xrefs = new k_Tree(); + xrefs[new PdfCrossReference(0, 0, 65535)] = null; + position = writer.Os.Counter; + refnum = 1; + this.writer = writer; + } + + // methods + + internal int Refnum { + set { + this.refnum = value; + } + } + + private PdfWriter.PdfBody.PdfCrossReference AddToObjStm(PdfObject obj, int nObj) { + if (numObj >= OBJSINSTREAM) + FlushObjStm(); + if (index == null) { + index = new ByteBuffer(); + streamObjects = new ByteBuffer(); + currentObjNum = IndirectReferenceNumber; + numObj = 0; + } + int p = streamObjects.Size; + int idx = numObj++; + PdfEncryption enc = writer.crypto; + writer.crypto = null; + obj.ToPdf(writer, streamObjects); + writer.crypto = enc; + streamObjects.Append(' '); + index.Append(nObj).Append(' ').Append(p).Append(' '); + return new PdfWriter.PdfBody.PdfCrossReference(2, nObj, currentObjNum, idx); + } + + internal void FlushObjStm() { + if (numObj == 0) + return; + int first = index.Size; + index.Append(streamObjects); + PdfStream stream = new PdfStream(index.ToByteArray()); + stream.FlateCompress(); + stream.Put(PdfName.TYPE, PdfName.OBJSTM); + stream.Put(PdfName.N, new PdfNumber(numObj)); + stream.Put(PdfName.FIRST, new PdfNumber(first)); + Add(stream, currentObjNum); + index = null; + streamObjects = null; + numObj = 0; + } + + /** + * Adds a PdfObject to the body. + *

    + * This methods creates a PdfIndirectObject with a + * certain number, containing the given PdfObject. + * It also adds a PdfCrossReference for this object + * to an ArrayList that will be used to build the + * Cross-reference Table. + * + * @param object a PdfObject + * @return a PdfIndirectObject + * @throws IOException + */ + + internal PdfIndirectObject Add(PdfObject objecta) { + return Add(objecta, IndirectReferenceNumber); + } + + internal PdfIndirectObject Add(PdfObject objecta, bool inObjStm) { + return Add(objecta, IndirectReferenceNumber, inObjStm); + } + + /** + * Gets a PdfIndirectReference for an object that will be created in the future. + * @return a PdfIndirectReference + */ + + internal PdfIndirectReference PdfIndirectReference { + get { + return new PdfIndirectReference(0, IndirectReferenceNumber); + } + } + + internal int IndirectReferenceNumber { + get { + int n = refnum++; + xrefs[new PdfCrossReference(n, 0, 65536)] = null; + return n; + } + } + + /** + * Adds a PdfObject to the body given an already existing + * PdfIndirectReference. + *

    + * This methods creates a PdfIndirectObject with the number given by + * ref, containing the given PdfObject. + * It also adds a PdfCrossReference for this object + * to an ArrayList that will be used to build the + * Cross-reference Table. + * + * @param object a PdfObject + * @param ref a PdfIndirectReference + * @return a PdfIndirectObject + * @throws IOException + */ + + internal PdfIndirectObject Add(PdfObject objecta, PdfIndirectReference refa) { + return Add(objecta, refa.Number); + } + + internal PdfIndirectObject Add(PdfObject objecta, PdfIndirectReference refa, bool inObjStm) { + return Add(objecta, refa.Number, inObjStm); + } + + internal PdfIndirectObject Add(PdfObject objecta, int refNumber) { + return Add(objecta, refNumber, true); // to false + } + + internal PdfIndirectObject Add(PdfObject objecta, int refNumber, bool inObjStm) { + if (inObjStm && objecta.CanBeInObjStm() && writer.FullCompression) { + PdfCrossReference pxref = AddToObjStm(objecta, refNumber); + PdfIndirectObject indirect = new PdfIndirectObject(refNumber, objecta, writer); + xrefs.Remove(pxref); + xrefs[pxref] = null; + return indirect; + } + else { + PdfIndirectObject indirect = new PdfIndirectObject(refNumber, objecta, writer); + PdfCrossReference pxref = new PdfCrossReference(refNumber, position); + xrefs.Remove(pxref); + xrefs[pxref] = null; + indirect.WriteTo(writer.Os); + position = writer.Os.Counter; + return indirect; + } + } + + /** + * Returns the offset of the Cross-Reference table. + * + * @return an offset + */ + + internal int Offset { + get { + return position; + } + } + + /** + * Returns the total number of objects contained in the CrossReferenceTable of this Body. + * + * @return a number of objects + */ + + internal int Size { + get { + k_Iterator it = xrefs.End.Clone(); + it.Prev(); + return Math.Max(((PdfCrossReference)((DictionaryEntry)it.Current).Key).Refnum + 1, refnum); + } + } + + /** + * Returns the CrossReferenceTable of the Body. + * @param os + * @param root + * @param info + * @param encryption + * @param fileID + * @param prevxref + * @throws IOException + */ + + internal void WriteCrossReferenceTable(Stream os, PdfIndirectReference root, PdfIndirectReference info, PdfIndirectReference encryption, PdfObject fileID, int prevxref) { + int refNumber = 0; + if (writer.FullCompression) { + FlushObjStm(); + refNumber = IndirectReferenceNumber; + xrefs[new PdfCrossReference(refNumber, position)] = null; + } + PdfCrossReference entry = (PdfCrossReference)((DictionaryEntry)xrefs.Begin.Current).Key; + int first = entry.Refnum; + int len = 0; + ArrayList sections = new ArrayList(); + for (k_Iterator i = xrefs.Begin.Clone(); i != xrefs.End; i.Next()) { + entry = (PdfCrossReference)((DictionaryEntry)i.Current).Key; + if (first + len == entry.Refnum) + ++len; + else { + sections.Add(first); + sections.Add(len); + first = entry.Refnum; + len = 1; + } + } + sections.Add(first); + sections.Add(len); + if (writer.FullCompression) { + int mid = 4; + uint mask = 0xff000000; + for (; mid > 1; --mid) { + if ((mask & position) != 0) + break; + mask >>= 8; + } + ByteBuffer buf = new ByteBuffer(); + + for (k_Iterator i = xrefs.Begin.Clone(); i != xrefs.End; i.Next()) { + entry = (PdfCrossReference)((DictionaryEntry)i.Current).Key; + entry.ToPdf(mid, buf); + } + PdfStream xr = new PdfStream(buf.ToByteArray()); + buf = null; + xr.FlateCompress(); + xr.Put(PdfName.SIZE, new PdfNumber(Size)); + xr.Put(PdfName.ROOT, root); + if (info != null) { + xr.Put(PdfName.INFO, info); + } + if (encryption != null) + xr.Put(PdfName.ENCRYPT, encryption); + if (fileID != null) + xr.Put(PdfName.ID, fileID); + xr.Put(PdfName.W, new PdfArray(new int[]{1, mid, 2})); + xr.Put(PdfName.TYPE, PdfName.XREF); + PdfArray idx = new PdfArray(); + for (int k = 0; k < sections.Count; ++k) + idx.Add(new PdfNumber((int)sections[k])); + xr.Put(PdfName.INDEX, idx); + if (prevxref > 0) + xr.Put(PdfName.PREV, new PdfNumber(prevxref)); + PdfEncryption enc = writer.crypto; + writer.crypto = null; + PdfIndirectObject indirect = new PdfIndirectObject(refNumber, xr, writer); + indirect.WriteTo(writer.Os); + writer.crypto = enc; + } + else { + byte[] tmp = GetISOBytes("xref\n"); + os.Write(tmp, 0, tmp.Length); + k_Iterator i = xrefs.Begin.Clone(); + for (int k = 0; k < sections.Count; k += 2) { + first = (int)sections[k]; + len = (int)sections[k + 1]; + tmp = GetISOBytes(first.ToString()); + os.Write(tmp, 0, tmp.Length); + os.WriteByte((byte)' '); + tmp = GetISOBytes(len.ToString()); + os.Write(tmp, 0, tmp.Length); + os.WriteByte((byte)'\n'); + while (len-- > 0) { + entry = (PdfCrossReference)((DictionaryEntry)i.Current).Key; + entry.ToPdf(os); + i.Next(); + } + } + } + } + } + + /** + * PdfTrailer is the PDF Trailer object. + *

    + * This object is described in the 'Portable Document Format Reference Manual version 1.3' + * section 5.16 (page 59-60). + */ + + internal class PdfTrailer : PdfDictionary { + + // membervariables + + internal int offset; + + // constructors + + /** + * Constructs a PDF-Trailer. + * + * @param size the number of entries in the PdfCrossReferenceTable + * @param offset offset of the PdfCrossReferenceTable + * @param root an indirect reference to the root of the PDF document + * @param info an indirect reference to the info object of the PDF document + * @param encryption + * @param fileID + * @param prevxref + */ + + internal PdfTrailer(int size, int offset, PdfIndirectReference root, PdfIndirectReference info, PdfIndirectReference encryption, PdfObject fileID, int prevxref) { + this.offset = offset; + Put(PdfName.SIZE, new PdfNumber(size)); + Put(PdfName.ROOT, root); + if (info != null) { + Put(PdfName.INFO, info); + } + if (encryption != null) + Put(PdfName.ENCRYPT, encryption); + if (fileID != null) + Put(PdfName.ID, fileID); + if (prevxref > 0) + Put(PdfName.PREV, new PdfNumber(prevxref)); + } + + /** + * Returns the PDF representation of this PdfObject. + * @param writer + * @param os + * @throws IOException + */ + public override void ToPdf(PdfWriter writer, Stream os) { + byte[] tmp = GetISOBytes("trailer\n"); + os.Write(tmp, 0, tmp.Length); + base.ToPdf(null, os); + tmp = GetISOBytes("\nstartxref\n"); + os.Write(tmp, 0, tmp.Length); + tmp = GetISOBytes(offset.ToString()); + os.Write(tmp, 0, tmp.Length); + tmp = GetISOBytes("\n%%EOF\n"); + os.Write(tmp, 0, tmp.Length); + } + } + + // ESSENTIALS + + // Construct a PdfWriter instance + + /** + * Constructs a PdfWriter. + */ + protected PdfWriter() { + root = new PdfPages(this); + } + + /** + * Constructs a PdfWriter. + *

    + * Remark: a PdfWriter can only be constructed by calling the method + * getInstance(Document document, Stream os). + * + * @param document The PdfDocument that has to be written + * @param os The Stream the writer has to write to. + */ + + protected PdfWriter(PdfDocument document, Stream os) : base(document, os) { + root = new PdfPages(this); + pdf = document; + directContent = new PdfContentByte(this); + directContentUnder = new PdfContentByte(this); + } + + // get an instance of the PdfWriter + + /** + * Use this method to get an instance of the PdfWriter. + * + * @param document The Document that has to be written + * @param os The Stream the writer has to write to. + * @return a new PdfWriter + * + * @throws DocumentException on error + */ + + public static PdfWriter GetInstance(Document document, Stream os) + { + PdfDocument pdf = new PdfDocument(); + document.AddDocListener(pdf); + PdfWriter writer = new PdfWriter(pdf, os); + pdf.AddWriter(writer); + return writer; + } + + /** + * Use this method to get an instance of the PdfWriter. + * + * @return a new PdfWriter + * @param document The Document that has to be written + * @param os The Stream the writer has to write to. + * @param listener A DocListener to pass to the PdfDocument. + * @throws DocumentException on error + */ + + public static PdfWriter GetInstance(Document document, Stream os, IDocListener listener) + { + PdfDocument pdf = new PdfDocument(); + pdf.AddDocListener(listener); + document.AddDocListener(pdf); + PdfWriter writer = new PdfWriter(pdf, os); + pdf.AddWriter(writer); + return writer; + } + + // the PdfDocument instance + /** the pdfdocument object. */ + protected internal PdfDocument pdf; + + /** + * Gets the PdfDocument associated with this writer. + * @return the PdfDocument + */ + internal PdfDocument PdfDocument { + get { + return pdf; + } + } + + /** + * Use this method to get the info dictionary if you want to + * change it directly (add keys and values to the info dictionary). + * @return the info dictionary + */ + public PdfDictionary Info { + get { + return ((PdfDocument)document).Info; + } + } + + /** + * Use this method to get the current vertical page position. + * @param ensureNewLine Tells whether a new line shall be enforced. This may cause side effects + * for elements that do not terminate the lines they've started because those lines will get + * terminated. + * @return The current vertical page position. + */ + public float GetVerticalPosition(bool ensureNewLine) { + return pdf.GetVerticalPosition(ensureNewLine); + } + + // the PdfDirectContentByte instances + + /* + * You should see Direct Content as a canvas on which you can draw + * graphics and text. One canvas goes on top of the page (getDirectContent), + * the other goes underneath (getDirectContentUnder). + * You can always the same object throughout your document, + * even if you have moved to a new page. Whatever you add on + * the canvas will be displayed on top or under the current page. + */ + + /** The direct content in this document. */ + protected PdfContentByte directContent; + + /** The direct content under in this document. */ + protected PdfContentByte directContentUnder; + + /** + * Use this method to get the direct content for this document. + * There is only one direct content, multiple calls to this method + * will allways retrieve the same object. + * @return the direct content + */ + public virtual PdfContentByte DirectContent { + get { + if (!open) + throw new Exception("The document is not open."); + return directContent; + } + } + + /** + * Use this method to get the direct content under for this document. + * There is only one direct content, multiple calls to this method + * will allways retrieve the same object. + * @return the direct content + */ + public virtual PdfContentByte DirectContentUnder { + get { + if (!open) + throw new Exception("The document is not open."); + return directContentUnder; + } + } + + /** + * Resets all the direct contents to empty. + * This happens when a new page is started. + */ + internal void ResetContent() { + directContent.Reset(); + directContentUnder.Reset(); + } + + // PDF body + + /* + * A PDF file has 4 parts: a header, a body, a cross-reference table, and a trailer. + * The body contains all the PDF objects that make up the PDF document. + * Each element gets a reference (a set of numbers) and the byte position of + * every object is stored in the cross-reference table. + * Use these methods only if you know what you're doing. + */ + + /** body of the PDF document */ + protected internal PdfBody body; + + /** + * Adds the local destinations to the body of the document. + * @param dest the Hashtable containing the destinations + * @throws IOException on error + */ + internal void AddLocalDestinations(k_Tree dest) { + foreach (String name in dest.Keys) { + Object[] obj = (Object[])dest[name]; + PdfDestination destination = (PdfDestination)obj[2]; + if (destination == null) + throw new Exception("The name '" + name + "' has no local destination."); + if (obj[1] == null) + obj[1] = PdfIndirectReference; + AddToBody(destination, (PdfIndirectReference)obj[1]); + } + } + + /** + * Adds an object to the PDF body. + * @param object + * @return a PdfIndirectObject + * @throws IOException + */ + public PdfIndirectObject AddToBody(PdfObject objecta) { + PdfIndirectObject iobj = body.Add(objecta); + return iobj; + } + + /** + * Adds an object to the PDF body. + * @param object + * @param inObjStm + * @return a PdfIndirectObject + * @throws IOException + */ + public PdfIndirectObject AddToBody(PdfObject objecta, bool inObjStm) { + PdfIndirectObject iobj = body.Add(objecta, inObjStm); + return iobj; + } + + /** + * Adds an object to the PDF body. + * @param object + * @param ref + * @return a PdfIndirectObject + * @throws IOException + */ + public PdfIndirectObject AddToBody(PdfObject objecta, PdfIndirectReference refa) { + PdfIndirectObject iobj = body.Add(objecta, refa); + return iobj; + } + + /** + * Adds an object to the PDF body. + * @param object + * @param ref + * @param inObjStm + * @return a PdfIndirectObject + * @throws IOException + */ + public PdfIndirectObject AddToBody(PdfObject objecta, PdfIndirectReference refa, bool inObjStm) { + PdfIndirectObject iobj = body.Add(objecta, refa, inObjStm); + return iobj; + } + + /** + * Adds an object to the PDF body. + * @param object + * @param refNumber + * @return a PdfIndirectObject + * @throws IOException + */ + public PdfIndirectObject AddToBody(PdfObject objecta, int refNumber) { + PdfIndirectObject iobj = body.Add(objecta, refNumber); + return iobj; + } + + /** + * Adds an object to the PDF body. + * @param object + * @param refNumber + * @param inObjStm + * @return a PdfIndirectObject + * @throws IOException + */ + public PdfIndirectObject AddToBody(PdfObject objecta, int refNumber, bool inObjStm) { + PdfIndirectObject iobj = body.Add(objecta, refNumber, inObjStm); + return iobj; + } + + /** + * Gets a PdfIndirectReference for an object that + * will be created in the future. + * @return the PdfIndirectReference + */ + public PdfIndirectReference PdfIndirectReference { + get { + return body.PdfIndirectReference; + } + } + + internal int IndirectReferenceNumber { + get { + return body.IndirectReferenceNumber; + } + } + + /** + * Returns the outputStreamCounter. + * @return the outputStreamCounter + */ + internal OutputStreamCounter Os { + get { + return os; + } + } + + // PDF Catalog + + /* + * The Catalog is also called the root object of the document. + * Whereas the Cross-Reference maps the objects number with the + * byte offset so that the viewer can find the objects, the + * Catalog tells the viewer the numbers of the objects needed + * to render the document. + */ + + protected virtual PdfDictionary GetCatalog(PdfIndirectReference rootObj) { + PdfDictionary catalog = pdf.GetCatalog(rootObj); + // [F12] tagged PDF + if (tagged) { + this.StructureTreeRoot.BuildTree(); + catalog.Put(PdfName.STRUCTTREEROOT, structureTreeRoot.Reference); + PdfDictionary mi = new PdfDictionary(); + mi.Put(PdfName.MARKED, PdfBoolean.PDFTRUE); + if (userProperties) + mi.Put(PdfName.USERPROPERTIES, PdfBoolean.PDFTRUE); + catalog.Put(PdfName.MARKINFO, mi); + } + // [F13] OCG + if (documentOCG.Count != 0) { + FillOCProperties(false); + catalog.Put(PdfName.OCPROPERTIES, vOCProperties); + } + return catalog; + } + + /** Holds value of property extraCatalog. */ + protected internal PdfDictionary extraCatalog; + + /** + * Sets extra keys to the catalog. + * @return the catalog to change + */ + public PdfDictionary ExtraCatalog { + get { + if (extraCatalog == null) + extraCatalog = new PdfDictionary(); + return this.extraCatalog; + } + } + + // PdfPages + + /* + * The page root keeps the complete page tree of the document. + * There's an entry in the Catalog that refers to the root + * of the page tree, the page tree contains the references + * to pages and other page trees. + */ + + /** The root of the page tree. */ + protected PdfPages root; + /** The PdfIndirectReference to the pages. */ + protected ArrayList pageReferences = new ArrayList(); + /** The current page number. */ + protected int currentPageNumber = 1; + + /** + * Use this method to make sure the page tree has a lineair structure + * (every leave is attached directly to the root). + * Use this method to allow page reordering with method reorderPages. + */ + public void SetLinearPageMode() { + root.SetLinearMode(null); + } + + /** + * Use this method to reorder the pages in the document. + * A null argument value only returns the number of pages to process. + * It is advisable to issue a Document.newPage() before using this method. + * @return the total number of pages + * @param order an array with the new page sequence. It must have the + * same size as the number of pages. + * @throws DocumentException if all the pages are not present in the array + */ + public int ReorderPages(int[] order) { + return root.ReorderPages(order); + } + + /** + * Use this method to get a reference to a page existing or not. + * If the page does not exist yet the reference will be created + * in advance. If on closing the document, a page number greater + * than the total number of pages was requested, an exception + * is thrown. + * @param page the page number. The first page is 1 + * @return the reference to the page + */ + public virtual PdfIndirectReference GetPageReference(int page) { + --page; + if (page < 0) + throw new ArgumentOutOfRangeException("The page numbers start at 1."); + PdfIndirectReference refa; + if (page < pageReferences.Count) { + refa = (PdfIndirectReference)pageReferences[page]; + if (refa == null) { + refa = body.PdfIndirectReference; + pageReferences[page] = refa; + } + } + else { + int empty = page - pageReferences.Count; + for (int k = 0; k < empty; ++k) + pageReferences.Add(null); + refa = body.PdfIndirectReference; + pageReferences.Add(refa); + } + return refa; + } + + /** + * Gets the pagenumber of this document. + * This number can be different from the real pagenumber, + * if you have (re)set the page number previously. + * @return a page number + */ + public int PageNumber { + get { + return pdf.PageNumber; + } + } + + internal virtual PdfIndirectReference CurrentPage { + get { + return GetPageReference(currentPageNumber); + } + } + + public virtual int CurrentPageNumber { + get { + return currentPageNumber; + } + } + + /** + * Adds some PdfContents to this Writer. + *

    + * The document has to be open before you can begin to add content + * to the body of the document. + * + * @return a PdfIndirectReference + * @param page the PdfPage to add + * @param contents the PdfContents of the page + * @throws PdfException on error + */ + internal virtual PdfIndirectReference Add(PdfPage page, PdfContents contents) { + if (!open) { + throw new PdfException("The document isn't open."); + } + PdfIndirectObject objecta; + objecta = AddToBody(contents); + page.Add(objecta.IndirectReference); + if (group != null) { + page.Put(PdfName.GROUP, group); + group = null; + } + else if (rgbTransparencyBlending) { + PdfDictionary pp = new PdfDictionary(); + pp.Put(PdfName.TYPE, PdfName.GROUP); + pp.Put(PdfName.S, PdfName.TRANSPARENCY); + pp.Put(PdfName.CS, PdfName.DEVICERGB); + page.Put(PdfName.GROUP, pp); + } + root.AddPage(page); + currentPageNumber++; + return null; + } + + // page events + + /* + * Page events are specific for iText, not for PDF. + * Upon specific events (for instance when a page starts + * or ends), the corresponing method in the page event + * implementation that is added to the writer is invoked. + */ + + /** The PdfPageEvent for this document. */ + private IPdfPageEvent pageEvent; + + /** + * Gets the PdfPageEvent for this document or null + * if none is set. + * @return the PdfPageEvent for this document or null + * if none is set + */ + public IPdfPageEvent PageEvent { + get { + return pageEvent; + } + set { + if (value == null) this.pageEvent = null; + else if (this.pageEvent == null) this.pageEvent = value; + else if (this.pageEvent is PdfPageEventForwarder) ((PdfPageEventForwarder)this.pageEvent).AddPageEvent(value); + else { + PdfPageEventForwarder forward = new PdfPageEventForwarder(); + forward.AddPageEvent(this.pageEvent); + forward.AddPageEvent(value); + this.pageEvent = forward; + } + } + } + + // Open en Close method + method that create the PDF + + /** A number refering to the previous Cross-Reference Table. */ + protected int prevxref = 0; + + /** + * Signals that the Document has been opened and that + * Elements can be added. + *

    + * When this method is called, the PDF-document header is + * written to the outputstream. + */ + public override void Open() { + base.Open(); + pdf_version.WriteHeader(os); + body = new PdfBody(this); + if (pdfxConformance.IsPdfX32002()) { + PdfDictionary sec = new PdfDictionary(); + sec.Put(PdfName.GAMMA, new PdfArray(new float[]{2.2f,2.2f,2.2f})); + sec.Put(PdfName.MATRIX, new PdfArray(new float[]{0.4124f,0.2126f,0.0193f,0.3576f,0.7152f,0.1192f,0.1805f,0.0722f,0.9505f})); + sec.Put(PdfName.WHITEPOINT, new PdfArray(new float[]{0.9505f,1f,1.089f})); + PdfArray arr = new PdfArray(PdfName.CALRGB); + arr.Add(sec); + SetDefaultColorspace(PdfName.DEFAULTRGB, AddToBody(arr).IndirectReference); + } + } + + /** + * Signals that the Document was closed and that no other + * Elements will be added. + *

    + * The pages-tree is built and written to the outputstream. + * A Catalog is constructed, as well as an Info-object, + * the referencetable is composed and everything is written + * to the outputstream embedded in a Trailer. + */ + public override void Close() { + if (open) { + if ((currentPageNumber - 1) != pageReferences.Count) + throw new Exception("The page " + pageReferences.Count + + " was requested but the document has only " + (currentPageNumber - 1) + " pages."); + pdf.Close(); + AddSharedObjectsToBody(); + // add the root to the body + PdfIndirectReference rootRef = root.WritePageTree(); + // make the catalog-object and add it to the body + PdfDictionary catalog = GetCatalog(rootRef); + // [C9] if there is XMP data to add: add it + if (xmpMetadata != null) { + PdfStream xmp = new PdfStream(xmpMetadata); + xmp.Put(PdfName.TYPE, PdfName.METADATA); + xmp.Put(PdfName.SUBTYPE, PdfName.XML); + if (crypto != null && !crypto.IsMetadataEncrypted()) { + PdfArray ar = new PdfArray(); + ar.Add(PdfName.CRYPT); + xmp.Put(PdfName.FILTER, ar); + } + catalog.Put(PdfName.METADATA, body.Add(xmp).IndirectReference); + } + // [C10] make pdfx conformant + if (IsPdfX()) { + pdfxConformance.CompleteInfoDictionary(Info); + pdfxConformance.CompleteExtraCatalog(ExtraCatalog); + } + // [C11] Output Intents + if (extraCatalog != null) { + catalog.MergeDifferent(extraCatalog); + } + + WriteOutlines(catalog, false); + + // add the Catalog to the body + PdfIndirectObject indirectCatalog = AddToBody(catalog, false); + // add the info-object to the body + PdfIndirectObject infoObj = AddToBody(Info, false); + + // [F1] encryption + PdfIndirectReference encryption = null; + PdfObject fileID = null; + body.FlushObjStm(); + if (crypto != null) { + PdfIndirectObject encryptionObject = AddToBody(crypto.GetEncryptionDictionary(), false); + encryption = encryptionObject.IndirectReference; + fileID = crypto.FileID; + } + else + fileID = PdfEncryption.CreateInfoId(PdfEncryption.CreateDocumentId()); + + // write the cross-reference table of the body + body.WriteCrossReferenceTable(os, indirectCatalog.IndirectReference, + infoObj.IndirectReference, encryption, fileID, prevxref); + + // make the trailer + // [F2] full compression + if (fullCompression) { + byte[] tmp = GetISOBytes("startxref\n"); + os.Write(tmp, 0, tmp.Length); + tmp = GetISOBytes(body.Offset.ToString()); + os.Write(tmp, 0, tmp.Length); + tmp = GetISOBytes("\n%%EOF\n"); + os.Write(tmp, 0, tmp.Length); + } + else { + PdfTrailer trailer = new PdfTrailer(body.Size, + body.Offset, + indirectCatalog.IndirectReference, + infoObj.IndirectReference, + encryption, + fileID, prevxref); + trailer.ToPdf(this, os); + } + base.Close(); + } + } + + protected void AddSharedObjectsToBody() { + // add the fonts + foreach (FontDetails details in documentFonts.Values) { + details.WriteFont(this); + } + // add the form XObjects + foreach (Object[] objs in formXObjects.Values) { + PdfTemplate template = (PdfTemplate)objs[1]; + if (template != null && template.IndirectReference is PRIndirectReference) + continue; + if (template != null && template.Type == PdfTemplate.TYPE_TEMPLATE) { + AddToBody(template.FormXObject, template.IndirectReference); + } + } + // add all the dependencies in the imported pages + foreach (PdfReaderInstance rd in importedPages.Values) { + currentPdfReaderInstance = rd; + currentPdfReaderInstance.WriteAllPages(); + } + currentPdfReaderInstance = null; + // add the color + foreach (ColorDetails color in documentColors.Values) { + AddToBody(color.GetSpotColor(this), color.IndirectReference); + } + // add the pattern + foreach (PdfPatternPainter pat in documentPatterns.Keys) { + AddToBody(pat.Pattern, pat.IndirectReference); + } + // add the shading patterns + foreach (PdfShadingPattern shadingPattern in documentShadingPatterns.Keys) { + shadingPattern.AddToBody(); + } + // add the shadings + foreach (PdfShading shading in documentShadings.Keys) { + shading.AddToBody(); + } + // add the extgstate + foreach (DictionaryEntry entry in documentExtGState) { + PdfDictionary gstate = (PdfDictionary)entry.Key; + PdfObject[] obj = (PdfObject[])entry.Value; + AddToBody(gstate, (PdfIndirectReference)obj[1]); + } + + // add the properties + foreach (DictionaryEntry entry in documentProperties) { + Object prop = entry.Key; + PdfObject[] obj = (PdfObject[])entry.Value; + if (prop is PdfLayerMembership){ + PdfLayerMembership layer = (PdfLayerMembership)prop; + AddToBody(layer.PdfObject, layer.Ref); + } + else if ((prop is PdfDictionary) && !(prop is PdfLayer)){ + AddToBody((PdfDictionary)prop, (PdfIndirectReference)obj[1]); + } + } + foreach (IPdfOCG layer in documentOCG.Keys) { + AddToBody(layer.PdfObject, layer.Ref); + } + } + + // Root data for the PDF document (used when composing the Catalog) + + // [C1] Outlines (bookmarks) + + /** + * Use this method to get the root outline + * and construct bookmarks. + * @return the root outline + */ + public PdfOutline RootOutline { + get { + return directContent.RootOutline; + } + } + + protected ArrayList newBookmarks; + + /** + * Sets the bookmarks. The list structure is defined in + * {@link SimpleBookmark}. + * @param outlines the bookmarks or null to remove any + */ + public ArrayList Outlines { + set { + newBookmarks = value; + } + } + + protected internal void WriteOutlines(PdfDictionary catalog, bool namedAsNames) { + if (newBookmarks == null || newBookmarks.Count == 0) + return; + PdfDictionary top = new PdfDictionary(); + PdfIndirectReference topRef = this.PdfIndirectReference; + Object[] kids = SimpleBookmark.IterateOutlines(this, topRef, newBookmarks, namedAsNames); + top.Put(PdfName.FIRST, (PdfIndirectReference)kids[0]); + top.Put(PdfName.LAST, (PdfIndirectReference)kids[1]); + top.Put(PdfName.COUNT, new PdfNumber((int)kids[2])); + AddToBody(top, topRef); + catalog.Put(PdfName.OUTLINES, topRef); + } + + // [C2] PdfVersion interface + /** possible PDF version (header) */ + public const char VERSION_1_2 = '2'; + /** possible PDF version (header) */ + public const char VERSION_1_3 = '3'; + /** possible PDF version (header) */ + public const char VERSION_1_4 = '4'; + /** possible PDF version (header) */ + public const char VERSION_1_5 = '5'; + /** possible PDF version (header) */ + public const char VERSION_1_6 = '6'; + /** possible PDF version (header) */ + public const char VERSION_1_7 = '7'; + + /** possible PDF version (catalog) */ + public static readonly PdfName PDF_VERSION_1_2 = new PdfName("1.2"); + /** possible PDF version (catalog) */ + public static readonly PdfName PDF_VERSION_1_3 = new PdfName("1.3"); + /** possible PDF version (catalog) */ + public static readonly PdfName PDF_VERSION_1_4 = new PdfName("1.4"); + /** possible PDF version (catalog) */ + public static readonly PdfName PDF_VERSION_1_5 = new PdfName("1.5"); + /** possible PDF version (catalog) */ + public static readonly PdfName PDF_VERSION_1_6 = new PdfName("1.6"); + /** possible PDF version (catalog) */ + public static readonly PdfName PDF_VERSION_1_7 = new PdfName("1.7"); + + /** Stores the version information for the header and the catalog. */ + protected PdfVersionImp pdf_version = new PdfVersionImp(); + + /** + * @see com.lowagie.text.pdf.interfaces.PdfVersion#setPdfVersion(char) + */ + public virtual char PdfVersion { + set { + pdf_version.PdfVersion = value; + } + } + + /** + * @see com.lowagie.text.pdf.interfaces.PdfVersion#setAtLeastPdfVersion(char) + */ + public void SetAtLeastPdfVersion(char version) { + pdf_version.SetAtLeastPdfVersion(version); + } + + /** + * @see com.lowagie.text.pdf.interfaces.PdfVersion#setPdfVersion(com.lowagie.text.pdf.PdfName) + */ + public void SetPdfVersion(PdfName version) { + pdf_version.SetPdfVersion(version); + } + + /** + * Returns the version information. + */ + internal PdfVersionImp GetPdfVersion() { + return pdf_version; + } + + // [C3] PdfViewerPreferences interface + + // page layout (section 13.1.1 of "iText in Action") + + /** A viewer preference */ + public const int PageLayoutSinglePage = 1; + /** A viewer preference */ + public const int PageLayoutOneColumn = 2; + /** A viewer preference */ + public const int PageLayoutTwoColumnLeft = 4; + /** A viewer preference */ + public const int PageLayoutTwoColumnRight = 8; + /** A viewer preference */ + public const int PageLayoutTwoPageLeft = 16; + /** A viewer preference */ + public const int PageLayoutTwoPageRight = 32; + + // page mode (section 13.1.2 of "iText in Action") + + /** A viewer preference */ + public const int PageModeUseNone = 64; + /** A viewer preference */ + public const int PageModeUseOutlines = 128; + /** A viewer preference */ + public const int PageModeUseThumbs = 256; + /** A viewer preference */ + public const int PageModeFullScreen = 512; + /** A viewer preference */ + public const int PageModeUseOC = 1024; + /** A viewer preference */ + public const int PageModeUseAttachments = 2048; + + // values for setting viewer preferences in iText versions older than 2.x + + /** A viewer preference */ + public const int HideToolbar = 1 << 12; + /** A viewer preference */ + public const int HideMenubar = 1 << 13; + /** A viewer preference */ + public const int HideWindowUI = 1 << 14; + /** A viewer preference */ + public const int FitWindow = 1 << 15; + /** A viewer preference */ + public const int CenterWindow = 1 << 16; + /** A viewer preference */ + public const int DisplayDocTitle = 1 << 17; + + /** A viewer preference */ + public const int NonFullScreenPageModeUseNone = 1 << 18; + /** A viewer preference */ + public const int NonFullScreenPageModeUseOutlines = 1 << 19; + /** A viewer preference */ + public const int NonFullScreenPageModeUseThumbs = 1 << 20; + /** A viewer preference */ + public const int NonFullScreenPageModeUseOC = 1 << 21; + + /** A viewer preference */ + public const int DirectionL2R = 1 << 22; + /** A viewer preference */ + public const int DirectionR2L = 1 << 23; + + /** A viewer preference */ + public const int PrintScalingNone = 1 << 24; + + /** + * Sets the viewer preferences as the sum of several constants. + * @param preferences the viewer preferences + * @see PdfViewerPreferences#setViewerPreferences + */ + public virtual int ViewerPreferences { + set { + pdf.ViewerPreferences = value; + } + } + + /** Adds a viewer preference + * @param preferences the viewer preferences + * @see PdfViewerPreferences#addViewerPreference + */ + public virtual void AddViewerPreference(PdfName key, PdfObject value) { + pdf.AddViewerPreference(key, value); + } + + // [C4] Page labels + + /** + * Use this method to add page labels + * @param pageLabels the page labels + */ + public virtual PdfPageLabels PageLabels { + set { + pdf.PageLabels = value; + } + } + + // [C5] named objects: named destinations, javascript, embedded files + + /** + * Use this method to add a JavaScript action at the document level. + * When the document opens, all this JavaScript runs. + * @param js The JavaScript action + */ + public virtual void AddJavaScript(PdfAction js) { + pdf.AddJavaScript(js); + } + + /** Adds a JavaScript action at the document level. When the document + * opens all this JavaScript runs. + * @param code the JavaScript code + * @param unicode select JavaScript unicode. Note that the internal + * Acrobat JavaScript engine does not support unicode, + * so this may or may not work for you + */ + public virtual void AddJavaScript(String code, bool unicode) { + AddJavaScript(PdfAction.JavaScript(code, this, unicode)); + } + + /** Adds a JavaScript action at the document level. When the document + * opens all this JavaScript runs. + * @param code the JavaScript code + */ + public virtual void AddJavaScript(String code) { + AddJavaScript(code, false); + } + + /** + * Use this method to add a JavaScript action at the document level. + * When the document opens, all this JavaScript runs. + * @param name The name of the JS Action in the name tree + * @param js The JavaScript action + */ + public void AddJavaScript(String name, PdfAction js) { + pdf.AddJavaScript(name, js); + } + + /** + * Use this method to add a JavaScript action at the document level. + * When the document opens, all this JavaScript runs. + * @param name The name of the JS Action in the name tree + * @param code the JavaScript code + * @param unicode select JavaScript unicode. Note that the internal + * Acrobat JavaScript engine does not support unicode, + * so this may or may not work for you + */ + public void AddJavaScript(String name, String code, bool unicode) { + AddJavaScript(name, PdfAction.JavaScript(code, this, unicode)); + } + + /** + * Use this method to adds a JavaScript action at the document level. + * When the document opens, all this JavaScript runs. + * @param name The name of the JS Action in the name tree + * @param code the JavaScript code + */ + public void AddJavaScript(String name, String code) { + AddJavaScript(name, code, false); + } + + /** Adds a file attachment at the document level. + * @param description the file description + * @param fileStore an array with the file. If it's null + * the file will be read from the disk + * @param file the path to the file. It will only be used if + * fileStore is not null + * @param fileDisplay the actual file name stored in the pdf + * @throws IOException on error + */ + public virtual void AddFileAttachment(String description, byte[] fileStore, String file, String fileDisplay) { + AddFileAttachment(description, PdfFileSpecification.FileEmbedded(this, file, fileDisplay, fileStore)); + } + + /** Adds a file attachment at the document level. + * @param description the file description + * @param fs the file specification + */ + public virtual void AddFileAttachment(String description, PdfFileSpecification fs) { + pdf.AddFileAttachment(description, fs); + } + + /** Adds a file attachment at the document level. + * @param fs the file specification + */ + public void AddFileAttachment(PdfFileSpecification fs) { + pdf.AddFileAttachment(null, fs); + } + + // [C6] Actions (open and additional) + + /** action value */ + public static PdfName DOCUMENT_CLOSE = PdfName.WC; + /** action value */ + public static PdfName WILL_SAVE = PdfName.WS; + /** action value */ + public static PdfName DID_SAVE = PdfName.DS; + /** action value */ + public static PdfName WILL_PRINT = PdfName.WP; + /** action value */ + public static PdfName DID_PRINT = PdfName.DP; + + /** When the document opens it will jump to the destination with + * this name. + * @param name the name of the destination to jump to + */ + public virtual void SetOpenAction(String name) { + pdf.SetOpenAction(name); + } + + /** When the document opens this action will be + * invoked. + * @param action the action to be invoked + */ + public virtual void SetOpenAction(PdfAction action) { + pdf.SetOpenAction(action); + } + + /** Additional-actions defining the actions to be taken in + * response to various trigger events affecting the document + * as a whole. The actions types allowed are: DOCUMENT_CLOSE, + * WILL_SAVE, DID_SAVE, WILL_PRINT + * and DID_PRINT. + * + * @param actionType the action type + * @param action the action to execute in response to the trigger + * @throws PdfException on invalid action type + */ + public virtual void SetAdditionalAction(PdfName actionType, PdfAction action) { + if (!(actionType.Equals(DOCUMENT_CLOSE) || + actionType.Equals(WILL_SAVE) || + actionType.Equals(DID_SAVE) || + actionType.Equals(WILL_PRINT) || + actionType.Equals(DID_PRINT))) { + throw new PdfException("Invalid additional action type: " + actionType.ToString()); + } + pdf.AddAdditionalAction(actionType, action); + } + + // [C7] portable collections + /** + * Sets the Collection dictionary. + * @param collection a dictionary of type PdfCollection + */ + public PdfCollection Collection { + set { + SetAtLeastPdfVersion(VERSION_1_7); + pdf.Collection = value; + } + } + + // [C8] AcroForm + + /** signature value */ + public const int SIGNATURE_EXISTS = 1; + /** signature value */ + public const int SIGNATURE_APPEND_ONLY = 2; + + /** Gets the AcroForm object. + * @return the PdfAcroForm + */ + + public PdfAcroForm AcroForm { + get { + return pdf.AcroForm; + } + } + + /** Adds a PdfAnnotation or a PdfFormField + * to the document. Only the top parent of a PdfFormField + * needs to be added. + * @param annot the PdfAnnotation or the PdfFormField to add + */ + public virtual void AddAnnotation(PdfAnnotation annot) { + pdf.AddAnnotation(annot); + } + + internal virtual void AddAnnotation(PdfAnnotation annot, int page) { + AddAnnotation(annot); + } + + /** Adds the PdfAnnotation to the calculation order + * array. + * @param annot the PdfAnnotation to be added + */ + public virtual void AddCalculationOrder(PdfFormField annot) { + pdf.AddCalculationOrder(annot); + } + + /** Set the signature flags. + * @param f the flags. This flags are ORed with current ones + */ + public virtual int SigFlags { + set { + pdf.SigFlags = value; + } + } + + // [C9] Metadata + + /** XMP Metadata for the document. */ + protected byte[] xmpMetadata = null; + + /** + * Sets XMP Metadata. + * @param xmpMetadata The xmpMetadata to set. + */ + public byte[] XmpMetadata { + set { + this.xmpMetadata = value; + } + get { + return this.xmpMetadata; + } + } + + /** + * Use this method to set the XMP Metadata for each page. + * @param xmpMetadata The xmpMetadata to set. + */ + public byte[] PageXmpMetadata { + set { + pdf.XmpMetadata = value; + } + } + + /** + * Creates XMP Metadata based on the metadata in the PdfDocument. + */ + public void CreateXmpMetadata() { + XmpMetadata = CreateXmpMetadataBytes(); + } + + /** + * @return an XmpMetadata byte array + */ + private byte[] CreateXmpMetadataBytes() { + MemoryStream baos = new MemoryStream(); + try { + XmpWriter xmp = new XmpWriter(baos, pdf.Info, pdfxConformance.PDFXConformance); + xmp.Close(); + } + catch(IOException) { + } + return baos.ToArray(); + } + + // [C10] PDFX Conformance + + /** PDF/X level */ + public const int PDFXNONE = 0; + /** PDF/X level */ + public const int PDFX1A2001 = 1; + /** PDF/X level */ + public const int PDFX32002 = 2; + /** PDFA-1A level. */ + public const int PDFA1A = 3; + /** PDFA-1B level. */ + public const int PDFA1B = 4; + + /** Stores the PDF/X level. */ + private PdfXConformanceImp pdfxConformance = new PdfXConformanceImp(); + + /** + * Sets the PDFX conformance level. Allowed values are PDFX1A2001 and PDFX32002. It + * must be called before opening the document. + * @param pdfxConformance the conformance level + */ + public int PDFXConformance { + set { + if (pdfxConformance.PDFXConformance == value) + return; + if (pdf.IsOpen()) + throw new PdfXConformanceException("PDFX conformance can only be set before opening the document."); + if (crypto != null) + throw new PdfXConformanceException("A PDFX conforming document cannot be encrypted."); + if (value == PDFA1A || value == PDFA1B) + PdfVersion = VERSION_1_4; + else if (value != PDFXNONE) + PdfVersion = VERSION_1_3; + pdfxConformance.PDFXConformance = value; + } + get { + return pdfxConformance.PDFXConformance; + } + } + + /** @see com.lowagie.text.pdf.interfaces.PdfXConformance#isPdfX() */ + public bool IsPdfX() { + return pdfxConformance.IsPdfX(); + } + + // [C11] Output intents + + /** + * Sets the values of the output intent dictionary. Null values are allowed to + * suppress any key. + * @param outputConditionIdentifier a value + * @param outputCondition a value + * @param registryName a value + * @param info a value + * @param destOutputProfile a value + * @throws IOException on error + */ + public void SetOutputIntents(String outputConditionIdentifier, String outputCondition, String registryName, String info, byte[] destOutputProfile) { + PdfDictionary outa = ExtraCatalog; //force the creation + outa = new PdfDictionary(PdfName.OUTPUTINTENT); + if (outputCondition != null) + outa.Put(PdfName.OUTPUTCONDITION, new PdfString(outputCondition, PdfObject.TEXT_UNICODE)); + if (outputConditionIdentifier != null) + outa.Put(PdfName.OUTPUTCONDITIONIDENTIFIER, new PdfString(outputConditionIdentifier, PdfObject.TEXT_UNICODE)); + if (registryName != null) + outa.Put(PdfName.REGISTRYNAME, new PdfString(registryName, PdfObject.TEXT_UNICODE)); + if (info != null) + outa.Put(PdfName.INFO, new PdfString(info, PdfObject.TEXT_UNICODE)); + if (destOutputProfile != null) { + PdfStream stream = new PdfStream(destOutputProfile); + stream.FlateCompress(); + outa.Put(PdfName.DESTOUTPUTPROFILE, AddToBody(stream).IndirectReference); + } + outa.Put(PdfName.S, PdfName.GTS_PDFX); + extraCatalog.Put(PdfName.OUTPUTINTENTS, new PdfArray(outa)); + } + + /** + * Copies the output intent dictionary from other document to this one. + * @param reader the other document + * @param checkExistence true to just check for the existence of a valid output intent + * dictionary, false to insert the dictionary if it exists + * @throws IOException on error + * @return true if the output intent dictionary exists, false + * otherwise + */ + public bool SetOutputIntents(PdfReader reader, bool checkExistence) { + PdfDictionary catalog = reader.Catalog; + PdfArray outs = (PdfArray)PdfReader.GetPdfObject(catalog.Get(PdfName.OUTPUTINTENTS)); + if (outs == null) + return false; + ArrayList arr = outs.ArrayList; + if (arr.Count == 0) + return false; + PdfDictionary outa = (PdfDictionary)PdfReader.GetPdfObject((PdfObject)arr[0]); + PdfObject obj = PdfReader.GetPdfObject(outa.Get(PdfName.S)); + if (obj == null || !PdfName.GTS_PDFX.Equals(obj)) + return false; + if (checkExistence) + return true; + PRStream stream = (PRStream)PdfReader.GetPdfObject(outa.Get(PdfName.DESTOUTPUTPROFILE)); + byte[] destProfile = null; + if (stream != null) { + destProfile = PdfReader.GetStreamBytes(stream); + } + SetOutputIntents(GetNameString(outa, PdfName.OUTPUTCONDITIONIDENTIFIER), GetNameString(outa, PdfName.OUTPUTCONDITION), + GetNameString(outa, PdfName.REGISTRYNAME), GetNameString(outa, PdfName.INFO), destProfile); + return true; + } + + private static String GetNameString(PdfDictionary dic, PdfName key) { + PdfObject obj = PdfReader.GetPdfObject(dic.Get(key)); + if (obj == null || !obj.IsString()) + return null; + return ((PdfString)obj).ToUnicodeString(); + } + + // PDF Objects that have an impact on the PDF body + + // [F1] PdfEncryptionSettings interface + + // types of encryption + + /** Type of encryption */ + public const int STANDARD_ENCRYPTION_40 = 0; + /** Type of encryption */ + public const int STANDARD_ENCRYPTION_128 = 1; + /** Type of encryption */ + public const int ENCRYPTION_AES_128 = 2; + /** Mask to separate the encryption type from the encryption mode. */ + internal const int ENCRYPTION_MASK = 7; + /** Add this to the mode to keep the metadata in clear text */ + public const int DO_NOT_ENCRYPT_METADATA = 8; + + // permissions + + /** The operation permitted when the document is opened with the user password + * + * @since 2.0.7 + */ + public const int ALLOW_PRINTING = 4 + 2048; + + /** The operation permitted when the document is opened with the user password + * + * @since 2.0.7 + */ + public const int ALLOW_MODIFY_CONTENTS = 8; + + /** The operation permitted when the document is opened with the user password + * + * @since 2.0.7 + */ + public const int ALLOW_COPY = 16; + + /** The operation permitted when the document is opened with the user password + * + * @since 2.0.7 + */ + public const int ALLOW_MODIFY_ANNOTATIONS = 32; + + /** The operation permitted when the document is opened with the user password + * + * @since 2.0.7 + */ + public const int ALLOW_FILL_IN = 256; + + /** The operation permitted when the document is opened with the user password + * + * @since 2.0.7 + */ + public const int ALLOW_SCREENREADERS = 512; + + /** The operation permitted when the document is opened with the user password + * + * @since 2.0.7 + */ + public const int ALLOW_ASSEMBLY = 1024; + + /** The operation permitted when the document is opened with the user password + * + * @since 2.0.7 + */ + public const int ALLOW_DEGRADED_PRINTING = 4; + + /** @deprecated As of iText 2.0.7, use {@link #ALLOW_PRINTING} instead. Scheduled for removal at or after 2.2.0 */ + public const int AllowPrinting = ALLOW_PRINTING; + /** @deprecated As of iText 2.0.7, use {@link #ALLOW_MODIFY_CONTENTS} instead. Scheduled for removal at or after 2.2.0 */ + public const int AllowModifyContents = ALLOW_MODIFY_CONTENTS; + /** @deprecated As of iText 2.0.7, use {@link #ALLOW_COPY} instead. Scheduled for removal at or after 2.2.0 */ + public const int AllowCopy = ALLOW_COPY; + /** @deprecated As of iText 2.0.7, use {@link #ALLOW_MODIFY_ANNOTATIONS} instead. Scheduled for removal at or after 2.2.0 */ + public const int AllowModifyAnnotations = ALLOW_MODIFY_ANNOTATIONS; + /** @deprecated As of iText 2.0.7, use {@link #ALLOW_FILL_IN} instead. Scheduled for removal at or after 2.2.0 */ + public const int AllowFillIn = ALLOW_FILL_IN; + /** @deprecated As of iText 2.0.7, use {@link #ALLOW_SCREENREADERS} instead. Scheduled for removal at or after 2.2.0 */ + public const int AllowScreenReaders = ALLOW_SCREENREADERS; + /** @deprecated As of iText 2.0.7, use {@link #ALLOW_ASSEMBLY} instead. Scheduled for removal at or after 2.2.0 */ + public const int AllowAssembly = ALLOW_ASSEMBLY; + /** @deprecated As of iText 2.0.7, use {@link #ALLOW_DEGRADED_PRINTING} instead. Scheduled for removal at or after 2.2.0 */ + public const int AllowDegradedPrinting = ALLOW_DEGRADED_PRINTING; + + // Strength of the encryption (kept for historical reasons) + /** @deprecated As of iText 2.0.7, use {@link #STANDARD_ENCRYPTION_40} instead. Scheduled for removal at or after 2.2.0 */ + public const bool STRENGTH40BITS = false; + /** @deprecated As of iText 2.0.7, use {@link #STANDARD_ENCRYPTION_128} instead. Scheduled for removal at or after 2.2.0 */ + public const bool STRENGTH128BITS = true; + + /** Contains the business logic for cryptography. */ + protected PdfEncryption crypto; + + internal PdfEncryption Encryption { + get { + return crypto; + } + } + + /** Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @throws DocumentException if the document is already open + */ + public void SetEncryption(byte[] userPassword, byte[] ownerPassword, int permissions, int encryptionType) { + if (pdf.IsOpen()) + throw new DocumentException("Encryption can only be added before opening the document."); + crypto = new PdfEncryption(); + crypto.SetCryptoMode(encryptionType, 0); + crypto.SetupAllKeys(userPassword, ownerPassword, permissions); + } + + /** + * Sets the certificate encryption options for this document. An array of one or more public certificates + * must be provided together with an array of the same size for the permissions for each certificate. + * The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @param certs the public certificates to be used for the encryption + * @param permissions the user permissions for each of the certicates + * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * @throws DocumentException if the document is already open + */ + public void SetEncryption(X509Certificate[] certs, int[] permissions, int encryptionType) { + if (pdf.IsOpen()) + throw new DocumentException("Encryption can only be added before opening the document."); + crypto = new PdfEncryption(); + if (certs != null) { + for (int i=0; i < certs.Length; i++) { + crypto.AddRecipient(certs[i], permissions[i]); + } + } + crypto.SetCryptoMode(encryptionType, 0); + crypto.GetEncryptionDictionary(); + } + + /** Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @param strength128Bits true for 128 bit key length, false for 40 bit key length + * @throws DocumentException if the document is already open + */ + public void SetEncryption(byte[] userPassword, byte[] ownerPassword, int permissions, bool strength128Bits) { + SetEncryption(userPassword, ownerPassword, permissions, strength128Bits ? STANDARD_ENCRYPTION_128 : STANDARD_ENCRYPTION_40); + } + + /** + * Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param strength true for 128 bit key length, false for 40 bit key length + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @throws DocumentException if the document is already open + */ + public void SetEncryption(bool strength, String userPassword, String ownerPassword, int permissions) { + SetEncryption(GetISOBytes(userPassword), GetISOBytes(ownerPassword), permissions, strength); + } + + /** + * Sets the encryption options for this document. The userPassword and the + * ownerPassword can be null or have zero length. In this case the ownerPassword + * is replaced by a random string. The open permissions for the document can be + * AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations, + * AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting. + * The permissions can be combined by ORing them. + * @param encryptionType the type of encryption. It can be one of STANDARD_ENCRYPTION_40, STANDARD_ENCRYPTION_128 or ENCRYPTION_AES128. + * Optionally DO_NOT_ENCRYPT_METADATA can be ored to output the metadata in cleartext + * @param userPassword the user password. Can be null or empty + * @param ownerPassword the owner password. Can be null or empty + * @param permissions the user permissions + * @throws DocumentException if the document is already open + */ + public void SetEncryption(int encryptionType, String userPassword, String ownerPassword, int permissions) { + SetEncryption(GetISOBytes(userPassword), GetISOBytes(ownerPassword), permissions, encryptionType); + } + + // [F2] compression + + /** + * Holds value of property fullCompression. + */ + protected bool fullCompression = false; + + /** + * Gets the 1.5 compression status. + * @return true if the 1.5 compression is on + */ + public bool FullCompression { + get { + return this.fullCompression; + } + } + + /** + * Sets the document's compression to the new 1.5 mode with object streams and xref + * streams. It can be set at any time but once set it can't be unset. + *

    + * If set before opening the document it will also set the pdf version to 1.5. + */ + public void SetFullCompression() { + this.fullCompression = true; + SetAtLeastPdfVersion(VERSION_1_5); + } + + // [F3] adding fonts + + /** The fonts of this document */ + protected Hashtable documentFonts = new Hashtable(); + + /** The font number counter for the fonts in the document. */ + protected int fontNumber = 1; + + /** + * Adds a BaseFont to the document but not to the page resources. + * It is used for templates. + * @param bf the BaseFont to add + * @return an Object[] where position 0 is a PdfName + * and position 1 is an PdfIndirectReference + */ + internal FontDetails AddSimple(BaseFont bf) { + if (bf.FontType == BaseFont.FONT_TYPE_DOCUMENT) { + return new FontDetails(new PdfName("F" + (fontNumber++)), ((DocumentFont)bf).IndirectReference, bf); + } + FontDetails ret = (FontDetails)documentFonts[bf]; + if (ret == null) { + PdfXConformanceImp.CheckPDFXConformance(this, PdfXConformanceImp.PDFXKEY_FONT, bf); + ret = new FontDetails(new PdfName("F" + (fontNumber++)), body.PdfIndirectReference, bf); + documentFonts[bf] = ret; + } + return ret; + } + + internal void EliminateFontSubset(PdfDictionary fonts) { + foreach (FontDetails ft in documentFonts.Values) { + if (fonts.Get(ft.FontName) != null) + ft.Subset = false; + } + } + + // [F4] adding (and releasing) form XObjects + + /** The form XObjects in this document. The key is the xref and the value + is Object[]{PdfName, template}.*/ + protected Hashtable formXObjects = new Hashtable(); + + /** The name counter for the form XObjects name. */ + protected int formXObjectsCounter = 1; + + /** + * Adds a template to the document but not to the page resources. + * @param template the template to add + * @param forcedName the template name, rather than a generated one. Can be null + * @return the PdfName for this template + */ + internal PdfName AddDirectTemplateSimple(PdfTemplate template, PdfName forcedName) { + PdfIndirectReference refa = template.IndirectReference; + Object[] obj = (Object[])formXObjects[refa]; + PdfName name = null; + if (obj == null) { + if (forcedName == null) { + name = new PdfName("Xf" + formXObjectsCounter); + ++formXObjectsCounter; + } + else + name = forcedName; + if (template.Type == PdfTemplate.TYPE_IMPORTED) { + // If we got here from PdfCopy we'll have to fill importedPages + PdfImportedPage ip = (PdfImportedPage)template; + PdfReader r = ip.PdfReaderInstance.Reader; + if (!importedPages.ContainsKey(r)) { + importedPages[r] = ip.PdfReaderInstance; + } + template = null; + } + formXObjects[refa] = new Object[]{name, template}; + } + else + name = (PdfName)obj[0]; + return name; + } + + /** + * Releases the memory used by a template by writing it to the output. The template + * can still be added to any content but changes to the template itself won't have + * any effect. + * @param tp the template to release + * @throws IOException on error + */ + public void ReleaseTemplate(PdfTemplate tp) { + PdfIndirectReference refi = tp.IndirectReference; + Object[] objs = (Object[])formXObjects[refi]; + if (objs == null || objs[1] == null) + return; + PdfTemplate template = (PdfTemplate)objs[1]; + if (template.IndirectReference is PRIndirectReference) + return; + if (template.Type == PdfTemplate.TYPE_TEMPLATE) { + AddToBody(template.FormXObject, template.IndirectReference); + objs[1] = null; + } + } + + // [F5] adding pages imported form other PDF documents + + protected Hashtable importedPages = new Hashtable(); + + /** Gets a page from other PDF document. The page can be used as + * any other PdfTemplate. Note that calling this method more than + * once with the same parameters will retrieve the same object. + * @param reader the PDF document where the page is + * @param pageNumber the page number. The first page is 1 + * @return the template representing the imported page + */ + public virtual PdfImportedPage GetImportedPage(PdfReader reader, int pageNumber) { + PdfReaderInstance inst = (PdfReaderInstance)importedPages[reader]; + if (inst == null) { + inst = reader.GetPdfReaderInstance(this); + importedPages[reader] = inst; + } + return inst.GetImportedPage(pageNumber); + } + + /** Writes the reader to the document and frees the memory used by it. + * The main use is when concatenating multiple documents to keep the + * memory usage restricted to the current appending document. + * @param reader the PdfReader to free + * @throws IOException on error + */ + public virtual void FreeReader(PdfReader reader) { + currentPdfReaderInstance = (PdfReaderInstance)importedPages[reader]; + if (currentPdfReaderInstance == null) + return; + currentPdfReaderInstance.WriteAllPages(); + currentPdfReaderInstance = null; + importedPages.Remove(reader); + } + + /** Gets the current document size. This size only includes + * the data already writen to the output stream, it does not + * include templates or fonts. It is usefull if used with + * freeReader() when concatenating many documents + * and an idea of the current size is needed. + * @return the approximate size without fonts or templates + */ + public int CurrentDocumentSize { + get { + return body.Offset + body.Size * 20 + 0x48; + } + } + + protected PdfReaderInstance currentPdfReaderInstance; + + protected internal virtual int GetNewObjectNumber(PdfReader reader, int number, int generation) { + return currentPdfReaderInstance.GetNewObjectNumber(number, generation); + } + + internal virtual RandomAccessFileOrArray GetReaderFile(PdfReader reader) { + return currentPdfReaderInstance.ReaderFile; + } + + // [F6] spot colors + + /** The colors of this document */ + protected Hashtable documentColors = new Hashtable(); + + /** The color number counter for the colors in the document. */ + protected int colorNumber = 1; + + internal PdfName GetColorspaceName() { + return new PdfName("CS" + (colorNumber++)); + } + + /** + * Adds a SpotColor to the document but not to the page resources. + * @param spc the SpotColor to add + * @return an Object[] where position 0 is a PdfName + * and position 1 is an PdfIndirectReference + */ + internal ColorDetails AddSimple(PdfSpotColor spc) { + ColorDetails ret = (ColorDetails)documentColors[spc]; + if (ret == null) { + ret = new ColorDetails(GetColorspaceName(), body.PdfIndirectReference, spc); + documentColors[spc] = ret; + } + return ret; + } + + // [F7] document patterns + + /** The patterns of this document */ + protected Hashtable documentPatterns = new Hashtable(); + + /** The patten number counter for the colors in the document. */ + protected int patternNumber = 1; + + internal PdfName AddSimplePattern(PdfPatternPainter painter) { + PdfName name = (PdfName)documentPatterns[painter]; + if ( name == null ) { + name = new PdfName("P" + patternNumber); + ++patternNumber; + documentPatterns[painter] = name; + } + return name; + } + + // [F8] shading patterns + + protected Hashtable documentShadingPatterns = new Hashtable(); + + internal void AddSimpleShadingPattern(PdfShadingPattern shading) { + if (!documentShadingPatterns.ContainsKey(shading)) { + shading.Name = patternNumber; + ++patternNumber; + documentShadingPatterns[shading] = null; + AddSimpleShading(shading.Shading); + } + } + + // [F9] document shadings + + protected Hashtable documentShadings = new Hashtable(); + + internal void AddSimpleShading(PdfShading shading) { + if (!documentShadings.ContainsKey(shading)) { + documentShadings[shading] = null; + shading.Name = documentShadings.Count; + } + } + + // [F10] extended graphics state (for instance for transparency) + + protected Hashtable documentExtGState = new Hashtable(); + + internal PdfObject[] AddSimpleExtGState(PdfDictionary gstate) { + if (!documentExtGState.ContainsKey(gstate)) { + PdfXConformanceImp.CheckPDFXConformance(this, PdfXConformanceImp.PDFXKEY_GSTATE, gstate); + documentExtGState[gstate] = new PdfObject[]{new PdfName("GS" + (documentExtGState.Count + 1)), PdfIndirectReference}; + } + return (PdfObject[])documentExtGState[gstate]; + } + + // [F11] adding properties (OCG, marked content) + + protected Hashtable documentProperties = new Hashtable(); + + internal PdfObject[] AddSimpleProperty(Object prop, PdfIndirectReference refi) { + if (!documentProperties.ContainsKey(prop)) { + if (prop is IPdfOCG) + PdfXConformanceImp.CheckPDFXConformance(this, PdfXConformanceImp.PDFXKEY_LAYER, null); + documentProperties[prop] = new PdfObject[]{new PdfName("Pr" + (documentProperties.Count + 1)), refi}; + } + return (PdfObject[])documentProperties[prop]; + } + + internal bool PropertyExists(Object prop) { + return documentProperties.ContainsKey(prop); + } + + // [F12] tagged PDF + + protected bool tagged = false; + protected PdfStructureTreeRoot structureTreeRoot; + + /** + * Mark this document for tagging. It must be called before open. + */ + public void SetTagged() { + if (open) + throw new ArgumentException("Tagging must be set before opening the document."); + tagged = true; + } + + /** + * Check if the document is marked for tagging. + * @return true if the document is marked for tagging + */ + public bool IsTagged() { + return tagged; + } + + /** + * Gets the structure tree root. If the document is not marked for tagging it will return null. + * @return the structure tree root + */ + public PdfStructureTreeRoot StructureTreeRoot { + get { + if (tagged && structureTreeRoot == null) + structureTreeRoot = new PdfStructureTreeRoot(this); + return structureTreeRoot; + } + } + + // [F13] Optional Content Groups + + protected Hashtable documentOCG = new Hashtable(); + protected ArrayList documentOCGorder = new ArrayList(); + protected PdfOCProperties vOCProperties; + protected PdfArray OCGRadioGroup = new PdfArray(); + protected PdfArray OCGLocked = new PdfArray(); + + /** + * Gets the Optional Content Properties Dictionary. Each call fills the dictionary with the current layer + * state. It's advisable to only call this method right before close and do any modifications + * at that time. + * @return the Optional Content Properties Dictionary + */ + public PdfOCProperties OCProperties { + get { + FillOCProperties(true); + return vOCProperties; + } + } + + /** + * Sets a collection of optional content groups whose states are intended to follow + * a "radio button" paradigm. That is, the state of at most one optional + * content group in the array should be ON at a time: if one group is turned + * ON, all others must be turned OFF. + * @param group the radio group + */ + public void AddOCGRadioGroup(ArrayList group) { + PdfArray ar = new PdfArray(); + for (int k = 0; k < group.Count; ++k) { + PdfLayer layer = (PdfLayer)group[k]; + if (layer.Title == null) + ar.Add(layer.Ref); + } + if (ar.Size == 0) + return; + OCGRadioGroup.Add(ar); + } + + /** + * Use this method to lock an optional content group. + * The state of a locked group cannot be changed through the user interface + * of a viewer application. Producers can use this entry to prevent the visibility + * of content that depends on these groups from being changed by users. + * @param layer the layer that needs to be added to the array of locked OCGs + * @since 2.1.2 + */ + public void LockLayer(PdfLayer layer) { + OCGLocked.Add(layer.Ref); + } + + private static void GetOCGOrder(PdfArray order, PdfLayer layer) { + if (!layer.OnPanel) + return; + if (layer.Title == null) + order.Add(layer.Ref); + ArrayList children = layer.Children; + if (children == null) + return; + PdfArray kids = new PdfArray(); + if (layer.Title != null) + kids.Add(new PdfString(layer.Title, PdfObject.TEXT_UNICODE)); + for (int k = 0; k < children.Count; ++k) { + GetOCGOrder(kids, (PdfLayer)children[k]); + } + if (kids.Size > 0) + order.Add(kids); + } + + private void AddASEvent(PdfName eventa, PdfName category) { + PdfArray arr = new PdfArray(); + foreach (PdfLayer layer in documentOCG.Keys) { + PdfDictionary usage = (PdfDictionary)layer.Get(PdfName.USAGE); + if (usage != null && usage.Get(category) != null) + arr.Add(layer.Ref); + } + if (arr.Size == 0) + return; + PdfDictionary d = (PdfDictionary)vOCProperties.Get(PdfName.D); + PdfArray arras = (PdfArray)d.Get(PdfName.AS); + if (arras == null) { + arras = new PdfArray(); + d.Put(PdfName.AS, arras); + } + PdfDictionary asa = new PdfDictionary(); + asa.Put(PdfName.EVENT, eventa); + asa.Put(PdfName.CATEGORY, new PdfArray(category)); + asa.Put(PdfName.OCGS, arr); + arras.Add(asa); + } + + protected void FillOCProperties(bool erase) { + if (vOCProperties == null) + vOCProperties = new PdfOCProperties(); + if (erase) { + vOCProperties.Remove(PdfName.OCGS); + vOCProperties.Remove(PdfName.D); + } + if (vOCProperties.Get(PdfName.OCGS) == null) { + PdfArray gr = new PdfArray(); + foreach (PdfLayer layer in documentOCG.Keys) { + gr.Add(layer.Ref); + } + vOCProperties.Put(PdfName.OCGS, gr); + } + if (vOCProperties.Get(PdfName.D) != null) + return; + ArrayList docOrder = new ArrayList(documentOCGorder); + for (ListIterator it = new ListIterator(docOrder); it.HasNext();) { + PdfLayer layer = (PdfLayer)it.Next(); + if (layer.Parent != null) + it.Remove(); + } + PdfArray order = new PdfArray(); + foreach (PdfLayer layer in docOrder) { + GetOCGOrder(order, layer); + } + PdfDictionary d = new PdfDictionary(); + vOCProperties.Put(PdfName.D, d); + d.Put(PdfName.ORDER, order); + PdfArray grx = new PdfArray(); + foreach (PdfLayer layer in documentOCG.Keys) { + if (!layer.On) + grx.Add(layer.Ref); + } + if (grx.Size > 0) + d.Put(PdfName.OFF, grx); + if (OCGRadioGroup.Size > 0) + d.Put(PdfName.RBGROUPS, OCGRadioGroup); + if (OCGLocked.Size > 0) + d.Put(PdfName.LOCKED, OCGLocked); + AddASEvent(PdfName.VIEW, PdfName.ZOOM); + AddASEvent(PdfName.VIEW, PdfName.VIEW); + AddASEvent(PdfName.PRINT, PdfName.PRINT); + AddASEvent(PdfName.EXPORT, PdfName.EXPORT); + d.Put(PdfName.LISTMODE, PdfName.VISIBLEPAGES); + } + + internal void RegisterLayer(IPdfOCG layer) { + PdfXConformanceImp.CheckPDFXConformance(this, PdfXConformanceImp.PDFXKEY_LAYER, null); + if (layer is PdfLayer) { + PdfLayer la = (PdfLayer)layer; + if (la.Title == null) { + if (!documentOCG.ContainsKey(layer)) { + documentOCG[layer] = null; + documentOCGorder.Add(layer); + } + } + else { + documentOCGorder.Add(layer); + } + } + else + throw new ArgumentException("Only PdfLayer is accepted."); + } + + // User methods to change aspects of the page + + // [U1] page size + + /** + * Gives the size of the media box. + * @return a Rectangle + */ + public Rectangle PageSize { + get { + return pdf.PageSize; + } + } + + /** Sets the crop box. The crop box should not be rotated even if the + * page is rotated. This change only takes effect in the next + * page. + * @param crop the crop box + */ + public virtual Rectangle CropBoxSize { + set { + pdf.CropBoxSize = value; + } + } + + /** + * Sets the page box sizes. Allowed names are: "crop", "trim", "art" and "bleed". + * @param boxName the box size + * @param size the size + */ + public void SetBoxSize(String boxName, Rectangle size) { + pdf.SetBoxSize(boxName, size); + } + + /** + * Gives the size of a trim, art, crop or bleed box, or null if not defined. + * @param boxName crop, trim, art or bleed + */ + public Rectangle GetBoxSize(String boxName) { + return pdf.GetBoxSize(boxName); + } + + // [U2] take care of empty pages + + /** + * If you use SetPageEmpty(false), invoking NewPage() after a blank page will add a newPage. + * @param pageEmpty the state + */ + public bool PageEmpty { + set { + pdf.PageEmpty = value; + } + } + + // [U3] page actions (open and close) + + /** action value */ + public static readonly PdfName PAGE_OPEN = PdfName.O; + /** action value */ + public static readonly PdfName PAGE_CLOSE = PdfName.C; + + /** Sets the open and close page additional action. + * @param actionType the action type. It can be PdfWriter.PAGE_OPEN + * or PdfWriter.PAGE_CLOSE + * @param action the action to perform + * @throws PdfException if the action type is invalid + */ + public virtual void SetPageAction(PdfName actionType, PdfAction action) { + if (!actionType.Equals(PAGE_OPEN) && !actionType.Equals(PAGE_CLOSE)) + throw new PdfException("Invalid page additional action type: " + actionType.ToString()); + pdf.SetPageAction(actionType, action); + } + + /** + * Sets the display duration for the page (for presentations) + * @param seconds the number of seconds to display the page + */ + public virtual int Duration { + set { + pdf.Duration = value; + } + } + + /** + * Sets the transition for the page + * @param transition the Transition object + */ + public virtual PdfTransition Transition { + set { + pdf.Transition = value; + } + } + + // [U4] Thumbnail image + + /** + * Sets the the thumbnail image for the current page. + * @param image the image + * @throws PdfException on error + * @throws DocumentException or error + */ + public virtual Image Thumbnail { + set { + pdf.Thumbnail = value; + } + } + + // [U5] Transparency groups + + /** + * A group attributes dictionary specifying the attributes + * of the page’s page group for use in the transparent + * imaging model + */ + protected PdfDictionary group; + + public PdfDictionary Group { + get { + return this.group; + } + set { + group = value; + } + } + + // [U6] space char ratio + + /** The default space-char ratio. */ + public const float SPACE_CHAR_RATIO_DEFAULT = 2.5f; + /** Disable the inter-character spacing. */ + public const float NO_SPACE_CHAR_RATIO = 10000000f; + + /** + * The ratio between the extra word spacing and the extra character spacing. + * Extra word spacing will grow ratio times more than extra character spacing. + */ + private float spaceCharRatio = SPACE_CHAR_RATIO_DEFAULT; + + /** Sets the ratio between the extra word spacing and the extra character spacing + * when the text is fully justified. + * Extra word spacing will grow spaceCharRatio times more than extra character spacing. + * If the ratio is PdfWriter.NO_SPACE_CHAR_RATIO then the extra character spacing + * will be zero. + * @param spaceCharRatio the ratio between the extra word spacing and the extra character spacing + */ + public virtual float SpaceCharRatio { + set { + if (value < 0.001f) + this.spaceCharRatio = 0.001f; + else + this.spaceCharRatio = value; + } + get { + return spaceCharRatio; + } + } + + // [U7] run direction (doesn't actually do anything) + + /** Use the default run direction. */ + public const int RUN_DIRECTION_DEFAULT = 0; + /** Do not use bidirectional reordering. */ + public const int RUN_DIRECTION_NO_BIDI = 1; + /** Use bidirectional reordering with left-to-right + * preferential run direction. + */ + public const int RUN_DIRECTION_LTR = 2; + /** Use bidirectional reordering with right-to-left + * preferential run direction. + */ + public const int RUN_DIRECTION_RTL = 3; + protected int runDirection = RUN_DIRECTION_NO_BIDI; + + /** Sets the run direction. This is only used as a placeholder + * as it does not affect anything. + * @param runDirection the run direction + */ + public virtual int RunDirection { + set { + if (value < RUN_DIRECTION_NO_BIDI || value > RUN_DIRECTION_RTL) + throw new Exception("Invalid run direction: " + value); + this.runDirection = value; + } + get { + return runDirection; + } + } + + // [U8] user units + + protected float userunit = 0f; + + /** + * A UserUnit is a value that defines the default user space unit. + * The minimum UserUnit is 1 (1 unit = 1/72 inch). + * The maximum UserUnit is 75,000. + * Remark that this userunit only works starting with PDF1.6! + */ + public float Userunit { + get { + return userunit; + } + set { + if (value < 1f || value > 75000f) throw new DocumentException("UserUnit should be a value between 1 and 75000."); + this.userunit = value; + SetAtLeastPdfVersion(VERSION_1_6); + } + } + + // Miscellaneous topics + + // [M1] Color settings + + protected PdfDictionary defaultColorspace = new PdfDictionary(); + + /** + * Gets the default colorspaces. + * @return the default colorspaces + */ + public PdfDictionary DefaultColorspace { + get { + return defaultColorspace; + } + } + + /** + * Sets the default colorspace that will be applied to all the document. + * The colorspace is only applied if another colorspace with the same name + * is not present in the content. + *

    + * The colorspace is applied immediately when creating templates and at the page + * end for the main document content. + * @param key the name of the colorspace. It can be PdfName.DEFAULTGRAY, PdfName.DEFAULTRGB + * or PdfName.DEFAULTCMYK + * @param cs the colorspace. A null or PdfNull removes any colorspace with the same name + */ + public void SetDefaultColorspace(PdfName key, PdfObject cs) { + if (cs == null || cs.IsNull()) + defaultColorspace.Remove(key); + defaultColorspace.Put(key, cs); + } + + // [M2] spot patterns + + protected Hashtable documentSpotPatterns = new Hashtable(); + protected ColorDetails patternColorspaceRGB; + protected ColorDetails patternColorspaceGRAY; + protected ColorDetails patternColorspaceCMYK; + + internal ColorDetails AddSimplePatternColorspace(Color color) { + int type = ExtendedColor.GetType(color); + if (type == ExtendedColor.TYPE_PATTERN || type == ExtendedColor.TYPE_SHADING) + throw new Exception("An uncolored tile pattern can not have another pattern or shading as color."); + switch (type) { + case ExtendedColor.TYPE_RGB: + if (patternColorspaceRGB == null) { + patternColorspaceRGB = new ColorDetails(GetColorspaceName(), body.PdfIndirectReference, null); + PdfArray array = new PdfArray(PdfName.PATTERN); + array.Add(PdfName.DEVICERGB); + AddToBody(array, patternColorspaceRGB.IndirectReference); + } + return patternColorspaceRGB; + case ExtendedColor.TYPE_CMYK: + if (patternColorspaceCMYK == null) { + patternColorspaceCMYK = new ColorDetails(GetColorspaceName(), body.PdfIndirectReference, null); + PdfArray array = new PdfArray(PdfName.PATTERN); + array.Add(PdfName.DEVICECMYK); + AddToBody(array, patternColorspaceCMYK.IndirectReference); + } + return patternColorspaceCMYK; + case ExtendedColor.TYPE_GRAY: + if (patternColorspaceGRAY == null) { + patternColorspaceGRAY = new ColorDetails(GetColorspaceName(), body.PdfIndirectReference, null); + PdfArray array = new PdfArray(PdfName.PATTERN); + array.Add(PdfName.DEVICEGRAY); + AddToBody(array, patternColorspaceGRAY.IndirectReference); + } + return patternColorspaceGRAY; + case ExtendedColor.TYPE_SEPARATION: { + ColorDetails details = AddSimple(((SpotColor)color).PdfSpotColor); + ColorDetails patternDetails = (ColorDetails)documentSpotPatterns[details]; + if (patternDetails == null) { + patternDetails = new ColorDetails(GetColorspaceName(), body.PdfIndirectReference, null); + PdfArray array = new PdfArray(PdfName.PATTERN); + array.Add(details.IndirectReference); + AddToBody(array, patternDetails.IndirectReference); + documentSpotPatterns[details] = patternDetails; + } + return patternDetails; + } + default: + throw new Exception("Invalid color type in PdfWriter.AddSimplePatternColorspace()."); + } + } + + // [M3] Images + + /** Sets the image sequence to follow the text in strict order. + * @param strictImageSequence new value of property strictImageSequence + * + */ + public bool StrictImageSequence { + set { + pdf.StrictImageSequence = value; + } + get { + return pdf.StrictImageSequence; + } + } + + /** + * Clears text wrapping around images (if applicable). + * Method suggested by Pelikan Stephan + * @throws DocumentException + */ + public void ClearTextWrap() { + pdf.ClearTextWrap(); + } + + /** Dictionary, containing all the images of the PDF document */ + protected PdfDictionary imageDictionary = new PdfDictionary(); + + /** This is the list with all the images in the document. */ + private Hashtable images = new Hashtable(); + + /** + * Adds an image to the document but not to the page resources. It is used with + * templates and Document.Add(Image). + * @param image the Image to add + * @return the name of the image added + * @throws PdfException on error + * @throws DocumentException on error + */ + public PdfName AddDirectImageSimple(Image image) { + return AddDirectImageSimple(image, null); + } + + /** + * Adds an image to the document but not to the page resources. It is used with + * templates and Document.Add(Image). + * @param image the Image to add + * @param fixedRef the reference to used. It may be null, + * a PdfIndirectReference or a PRIndirectReference. + * @return the name of the image added + * @throws PdfException on error + * @throws DocumentException on error + */ + public PdfName AddDirectImageSimple(Image image, PdfIndirectReference fixedRef) { + PdfName name; + // if the images is already added, just retrieve the name + if (images.ContainsKey(image.MySerialId)) { + name = (PdfName) images[image.MySerialId]; + } + // if it's a new image, add it to the document + else { + if (image.IsImgTemplate()) { + name = new PdfName("img" + images.Count); + if (image is ImgWMF){ + ImgWMF wmf = (ImgWMF)image; + wmf.ReadWMF(PdfTemplate.CreateTemplate(this, 0, 0)); + } + } + else { + PdfIndirectReference dref = image.DirectReference; + if (dref != null) { + PdfName rname = new PdfName("img" + images.Count); + images[image.MySerialId] = rname; + imageDictionary.Put(rname, dref); + return rname; + } + Image maskImage = image.ImageMask; + PdfIndirectReference maskRef = null; + if (maskImage != null) { + PdfName mname = (PdfName)images[maskImage.MySerialId]; + maskRef = GetImageReference(mname); + } + PdfImage i = new PdfImage(image, "img" + images.Count, maskRef); + if (image.HasICCProfile()) { + PdfICCBased icc = new PdfICCBased(image.TagICC); + PdfIndirectReference iccRef = Add(icc); + PdfArray iccArray = new PdfArray(); + iccArray.Add(PdfName.ICCBASED); + iccArray.Add(iccRef); + PdfObject colorspace = i.Get(PdfName.COLORSPACE); + if (colorspace != null && colorspace.IsArray()) { + ArrayList ar = ((PdfArray)colorspace).ArrayList; + if (ar.Count > 1 && PdfName.INDEXED.Equals(ar[0])) + ar[1] = iccArray; + else + i.Put(PdfName.COLORSPACE, iccArray); + } + else + i.Put(PdfName.COLORSPACE, iccArray); + } + Add(i, fixedRef); + name = i.Name; + } + images[image.MySerialId] = name; + } + return name; + } + + /** + * Writes a PdfImage to the outputstream. + * + * @param pdfImage the image to be added + * @return a PdfIndirectReference to the encapsulated image + * @throws PdfException when a document isn't open yet, or has been closed + */ + internal virtual PdfIndirectReference Add(PdfImage pdfImage, PdfIndirectReference fixedRef) { + if (! imageDictionary.Contains(pdfImage.Name)) { + PdfXConformanceImp.CheckPDFXConformance(this, PdfXConformanceImp.PDFXKEY_IMAGE, pdfImage); + if (fixedRef is PRIndirectReference) { + PRIndirectReference r2 = (PRIndirectReference)fixedRef; + fixedRef = new PdfIndirectReference(0, GetNewObjectNumber(r2.Reader, r2.Number, r2.Generation)); + } + if (fixedRef == null) + fixedRef = AddToBody(pdfImage).IndirectReference; + else + AddToBody(pdfImage, fixedRef); + imageDictionary.Put(pdfImage.Name, fixedRef); + return fixedRef; + } + return (PdfIndirectReference)imageDictionary.Get(pdfImage.Name); + } + + /** + * return the PdfIndirectReference to the image with a given name. + * + * @param name the name of the image + * @return a PdfIndirectReference + */ + internal virtual PdfIndirectReference GetImageReference(PdfName name) { + return (PdfIndirectReference) imageDictionary.Get(name); + } + + protected virtual PdfIndirectReference Add(PdfICCBased icc) { + PdfIndirectObject objecta; + objecta = AddToBody(icc); + return objecta.IndirectReference; + } + + // [M4] Old table functionality; do we still need it? + + /** + * Checks if a Table fits the current page of the PdfDocument. + * + * @param table the table that has to be checked + * @param margin a certain margin + * @return true if the Table fits the page, false otherwise. + */ + public bool FitsPage(Table table, float margin) { + return pdf.GetBottom(table) > pdf.IndentBottom + margin; + } + + /** + * Checks if a Table fits the current page of the PdfDocument. + * + * @param table the table that has to be checked + * @return true if the Table fits the page, false otherwise. + */ + public bool FitsPage(Table table) { + return FitsPage(table, 0); + } + + // [F12] tagged PDF + /** + * A flag indicating the presence of structure elements that contain user properties attributes. + */ + private bool userProperties; + + /** + * Sets the flag indicating the presence of structure elements that contain user properties attributes. + * @param userProperties the user properties flag + */ + public bool UserProperties { + set { + userProperties = value; + } + get { + return userProperties; + } + } + + /** + * Holds value of property RGBTranparency. + */ + private bool rgbTransparencyBlending; + + /** + * Sets the transparency blending colorspace to RGB. The default blending colorspace is + * CMYK and will result in faded colors in the screen and in printing. Calling this method + * will return the RGB colors to what is expected. The RGB blending will be applied to all subsequent pages + * until other value is set. + * Note that this is a generic solution that may not work in all cases. + * @param rgbTransparencyBlending true to set the transparency blending colorspace to RGB, false + * to use the default blending colorspace + */ + public bool RgbTransparencyBlending { + get { + return this.rgbTransparencyBlending; + } + set { + this.rgbTransparencyBlending = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/PdfXConformanceException.cs b/iTechSharp/iTextSharp/text/pdf/PdfXConformanceException.cs new file mode 100644 index 0000000..78b7490 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PdfXConformanceException.cs @@ -0,0 +1,67 @@ +using System; +/* + * Copyright 2004 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * + * @author psoares + */ + public class PdfXConformanceException : Exception { + + /** Creates a new instance of PdfXConformanceException. */ + public PdfXConformanceException() { + } + + /** + * Creates a new instance of PdfXConformanceException. + * @param s + */ + public PdfXConformanceException(String s) : base(s) { + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/Pfm2afm.cs b/iTechSharp/iTextSharp/text/pdf/Pfm2afm.cs new file mode 100644 index 0000000..3f96e12 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/Pfm2afm.cs @@ -0,0 +1,805 @@ +using System; +using System.IO; +using System.Text; +/* + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except inp compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2007 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2007 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added inp the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), inp which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed inp the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ +/******************************************************************** + * * + * Title: pfm2afm - Convert Windows .pfm files to .afm files * + * * + * Author: Ken Borgendale 10/9/91 Version 1.0 * + * * + * Function: * + * Convert a Windows .pfm (Printer Font Metrics) file to a * + * .afm (Adobe Font Metrics) file. The purpose of this is * + * to allow fonts put outp for Windows to be used with OS/2. * + * * + * Syntax: * + * pfm2afm infile [outfile] -a * + * * + * Copyright: * + * pfm2afm - Copyright (C) IBM Corp., 1991 * + * * + * This code is released for public use as long as the * + * copyright remains intact. This code is provided asis * + * without any warrenties, express or implied. * + * * + * Notes: * + * 1. Much of the information inp the original .afm file is * + * lost when the .pfm file is created, and thus cannot be * + * reconstructed by this utility. This is especially true * + * of data for characters not inp the Windows character set. * + * * + * 2. This module is coded to be compiled by the MSC 6.0. * + * For other compilers, be careful of the packing of the * + * PFM structure. * + * * + ********************************************************************/ + +/******************************************************************** + * * + * Modifications by Rod Smith, 5/22/96 * + * * + * These changes look for the strings "italic", "bold", "black", * + * and "light" inp the font's name and set the weight accordingly * + * and adds an ItalicAngle line with a value of "0" or "-12.00". * + * This allows OS/2 programs such as DeScribe to handle the bold * + * and italic attributes appropriately, which was not the case * + * when I used the original version on fonts from the KeyFonts * + * Pro 2002 font CD. * + * * + * I've also increased the size of the buffer used to load the * + * .PFM file; the old size was inadequate for most of the fonts * + * from the SoftKey collection. * + * * + * Compiled with Watcom C 10.6 * + * * + ********************************************************************/ + +/******************************************************************** + * * + * Further modifications, 4/21/98, by Rod Smith * + * * + * Minor changes to get the program to compile with gcc under * + * Linux (Red Hat 5.0, to be precise). I had to add an itoa * + * function from the net (the function was buggy, so I had to fix * + * it, too!). I also made the program more friendly towards * + * files with mixed-case filenames. * + * * + ********************************************************************/ + +/******************************************************************** + * * + * 1/31/2005, by Paulo Soares * + * * + * This code was integrated into iText. * + * Note that the itoa function mentioned in the comment by Rod * + * Smith is no longer in the code because Java has native support * + * in PrintWriter to convert integers to strings * + * * + ********************************************************************/ + +/******************************************************************** + * * + * 7/16/2005, by Bruno Lowagie * + * * + * I solved an Eclipse Warning. * + * * + ********************************************************************/ + +/******************************************************************** + * * + * 9/14/2006, by Xavier Le Vourch * + * * + * expand import clauses (import java.io.*) * + * the removal of an exception in readString was restored on 9/16 * + * * + ********************************************************************/ + +namespace iTextSharp.text.pdf { + /** + * Converts a PFM file into an AFM file. + */ + public sealed class Pfm2afm { + private RandomAccessFileOrArray inp; + private StreamWriter outp; + private Encoding encoding; + + /** Creates a new instance of Pfm2afm */ + private Pfm2afm(RandomAccessFileOrArray inp, Stream outp) { + this.inp = inp; + encoding = Encoding.GetEncoding(1252); + this.outp = new StreamWriter(outp, encoding); + } + + /** + * Converts a PFM file into an AFM file. + * @param inp the PFM file + * @param outp the AFM file + * @throws IOException on error + */ + public static void Convert(RandomAccessFileOrArray inp, Stream outp) { + Pfm2afm p = new Pfm2afm(inp, outp); + p.Openpfm(); + p.Putheader(); + p.Putchartab(); + p.Putkerntab(); + p.Puttrailer(); + p.outp.Flush(); + } + +/* public static void Main(String[] args) { + try { + RandomAccessFileOrArray inp = new RandomAccessFileOrArray(args[0]); + Stream outp = new FileOutputStream(args[1]); + Convert(inp, outp); + inp.Close(); + outp.Close(); + } + catch (Exception e) { + e.PrintStackTrace(); + } + }*/ + + private String ReadString(int n) { + byte[] b = new byte[n]; + inp.ReadFully(b); + int k; + for (k = 0; k < b.Length; ++k) { + if (b[k] == 0) + break; + } + return encoding.GetString(b, 0, k); + } + + private String ReadString() { + StringBuilder buf = new StringBuilder(); + while (true) { + int c = inp.Read(); + if (c <= 0) + break; + buf.Append((char)c); + } + return buf.ToString(); + } + + private void Outval(int n) { + outp.Write(' '); + outp.Write(n); + } + + /* + * Output a character entry + */ + private void Outchar(int code, int width, String name) { + outp.Write("C "); + Outval(code); + outp.Write(" ; WX "); + Outval(width); + if (name != null) { + outp.Write(" ; N "); + outp.Write(name); + } + outp.Write(" ;\n"); + } + + private void Openpfm() { + inp.Seek(0); + vers = inp.ReadShortLE(); + h_len = inp.ReadIntLE(); + copyright = ReadString(60); + type = inp.ReadShortLE(); + points = inp.ReadShortLE(); + verres = inp.ReadShortLE(); + horres = inp.ReadShortLE(); + ascent = inp.ReadShortLE(); + intleading = inp.ReadShortLE(); + extleading = inp.ReadShortLE(); + italic = (byte)inp.Read(); + uline = (byte)inp.Read(); + overs = (byte)inp.Read(); + weight = inp.ReadShortLE(); + charset = (byte)inp.Read(); + pixwidth = inp.ReadShortLE(); + pixheight = inp.ReadShortLE(); + kind = (byte)inp.Read(); + avgwidth = inp.ReadShortLE(); + maxwidth = inp.ReadShortLE(); + firstchar = inp.Read(); + lastchar = inp.Read(); + defchar = (byte)inp.Read(); + brkchar = (byte)inp.Read(); + widthby = inp.ReadShortLE(); + device = inp.ReadIntLE(); + face = inp.ReadIntLE(); + bits = inp.ReadIntLE(); + bitoff = inp.ReadIntLE(); + extlen = inp.ReadShortLE(); + psext = inp.ReadIntLE(); + chartab = inp.ReadIntLE(); + res1 = inp.ReadIntLE(); + kernpairs = inp.ReadIntLE(); + res2 = inp.ReadIntLE(); + fontname = inp.ReadIntLE(); + if (h_len != inp.Length || extlen != 30 || fontname < 75 || fontname > 512) + throw new IOException("Not a valid PFM file."); + inp.Seek(psext + 14); + capheight = inp.ReadShortLE(); + xheight = inp.ReadShortLE(); + ascender = inp.ReadShortLE(); + descender = inp.ReadShortLE(); + } + + private void Putheader() { + outp.Write("StartFontMetrics 2.0\n"); + if (copyright.Length > 0) + outp.Write("Comment " + copyright + '\n'); + outp.Write("FontName "); + inp.Seek(fontname); + String fname = ReadString(); + outp.Write(fname); + outp.Write("\nEncodingScheme "); + if (charset != 0) + outp.Write("FontSpecific\n"); + else + outp.Write("AdobeStandardEncoding\n"); + /* + * The .pfm is missing full name, so construct from font name by + * changing the hyphen to a space. This actually works inp a lot + * of cases. + */ + outp.Write("FullName " + fname.Replace('-', ' ')); + if (face != 0) { + inp.Seek(face); + outp.Write("\nFamilyName " + ReadString()); + } + + outp.Write("\nWeight "); + if (weight > 475 || fname.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf("bold") >= 0) + outp.Write("Bold"); + else if ((weight < 325 && weight != 0) || fname.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf("light") >= 0) + outp.Write("Light"); + else if (fname.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf("black") >= 0) + outp.Write("Black"); + else + outp.Write("Medium"); + + outp.Write("\nItalicAngle "); + if (italic != 0 || fname.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf("italic") >= 0) + outp.Write("-12.00"); + /* this is a typical value; something else may work better for a + specific font */ + else + outp.Write("0"); + + /* + * The mono flag inp the pfm actually indicates whether there is a + * table of font widths, not if they are all the same. + */ + outp.Write("\nIsFixedPitch "); + if ((kind & 1) == 0 || /* Flag for mono */ + avgwidth == maxwidth ) { /* Avg width = max width */ + outp.Write("true"); + isMono = true; + } + else { + outp.Write("false"); + isMono = false; + } + + /* + * The font bounding box is lost, but try to reconstruct it. + * Much of this is just guess work. The bounding box is required inp + * the .afm, but is not used by the PM font installer. + */ + outp.Write("\nFontBBox"); + if (isMono) + Outval(-20); /* Just guess at left bounds */ + else + Outval(-100); + Outval(-(descender+5)); /* Descender is given as positive value */ + Outval(maxwidth+10); + Outval(ascent+5); + + /* + * Give other metrics that were kept + */ + outp.Write("\nCapHeight"); + Outval(capheight); + outp.Write("\nXHeight"); + Outval(xheight); + outp.Write("\nDescender"); + Outval(descender); + outp.Write("\nAscender"); + Outval(ascender); + outp.Write('\n'); + } + + private void Putchartab() { + int count = lastchar - firstchar + 1; + int[] ctabs = new int[count]; + inp.Seek(chartab); + for (int k = 0; k < count; ++k) + ctabs[k] = inp.ReadUnsignedShortLE(); + int[] back = new int[256]; + if (charset == 0) { + for (int i = firstchar; i <= lastchar; ++i) { + if (Win2PSStd[i] != 0) + back[Win2PSStd[i]] = i; + } + } + /* Put outp the header */ + outp.Write("StartCharMetrics"); + Outval(count); + outp.Write('\n'); + + /* Put outp all encoded chars */ + if (charset != 0) { + /* + * If the charset is not the Windows standard, just put outp + * unnamed entries. + */ + for (int i = firstchar; i <= lastchar; i++) { + if (ctabs[i - firstchar] != 0) { + Outchar(i, ctabs[i - firstchar], null); + } + } + } + else { + for (int i = 0; i < 256; i++) { + int j = back[i]; + if (j != 0) { + Outchar(i, ctabs[j - firstchar], WinChars[j]); + ctabs[j - firstchar] = 0; + } + } + /* Put outp all non-encoded chars */ + for (int i = firstchar; i <= lastchar; i++) { + if (ctabs[i - firstchar] != 0) { + Outchar(-1, ctabs[i - firstchar], WinChars[i]); + } + } + } + /* Put outp the trailer */ + outp.Write("EndCharMetrics\n"); + + } + + private void Putkerntab() { + if (kernpairs == 0) + return; + inp.Seek(kernpairs); + int count = inp.ReadUnsignedShortLE(); + int nzero = 0; + int[] kerns = new int[count * 3]; + for (int k = 0; k < kerns.Length;) { + kerns[k++] = inp.Read(); + kerns[k++] = inp.Read(); + if ((kerns[k++] = inp.ReadShortLE()) != 0) + ++nzero; + } + if (nzero == 0) + return; + outp.Write("StartKernData\nStartKernPairs"); + Outval(nzero); + outp.Write('\n'); + for (int k = 0; k < kerns.Length; k += 3) { + if (kerns[k + 2] != 0) { + outp.Write("KPX "); + outp.Write(WinChars[kerns[k]]); + outp.Write(' '); + outp.Write(WinChars[kerns[k + 1]]); + Outval(kerns[k + 2]); + outp.Write('\n'); + } + } + /* Put outp trailer */ + outp.Write("EndKernPairs\nEndKernData\n"); + } + + + private void Puttrailer() { + outp.Write("EndFontMetrics\n"); + } + + private short vers; + private int h_len; /* Total length of .pfm file */ + private String copyright; /* Copyright string [60]*/ + private short type; + private short points; + private short verres; + private short horres; + private short ascent; + private short intleading; + private short extleading; + private byte italic; + private byte uline; + private byte overs; + private short weight; + private byte charset; /* 0=windows, otherwise nomap */ + private short pixwidth; /* Width for mono fonts */ + private short pixheight; + private byte kind; /* Lower bit off inp mono */ + private short avgwidth; /* Mono if avg=max width */ + private short maxwidth; /* Use to compute bounding box */ + private int firstchar; /* First char inp table */ + private int lastchar; /* Last char inp table */ + private byte defchar; + private byte brkchar; + private short widthby; + private int device; + private int face; /* Face name */ + private int bits; + private int bitoff; + private short extlen; + private int psext; /* PostScript extension */ + private int chartab; /* Character width tables */ + private int res1; + private int kernpairs; /* Kerning pairs */ + private int res2; + private int fontname; /* Font name */ + + /* + * Some metrics from the PostScript extension + */ + private short capheight; /* Cap height */ + private short xheight; /* X height */ + private short ascender; /* Ascender */ + private short descender; /* Descender (positive) */ + + + private bool isMono; + /* + * Translate table from 1004 to psstd. 1004 is an extension of the + * Windows translate table used inp PM. + */ + private int[] Win2PSStd = { + 0, 0, 0, 0, 197, 198, 199, 0, 202, 0, 205, 206, 207, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 32, 33, 34, 35, 36, 37, 38, 169, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 193, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 0, 0, 184, 0, 185, 188, 178, 179, 94, 189, 0, 172, 234, 0, 0, 0, + 0, 96, 0, 170, 186, 0, 177, 208, 126, 0, 0, 173, 250, 0, 0, 0, + 0, 161, 162, 163, 168, 165, 0, 167, 200, 0, 227, 171, 0, 0, 0, 0, + 0, 0, 0, 0, 194, 0, 182, 180, 203, 0, 235, 187, 0, 0, 0, 191, + 0, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 251, + 0, 0, 0, 0, 0, 0, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 249, 0, 0, 0, 0, 0, 0, 0 + }; + + /* + * Character class. This is a minor attempt to overcome the problem that + * inp the pfm file, all unused characters are given the width of space. + */ + private int[] WinClass = { + 0, 0, 0, 0, 2, 2, 2, 0, 2, 0, 2, 2, 2, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, /* 70 */ + 0, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, /* 80 */ + 0, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, /* 90 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a0 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b0 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* c0 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d0 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e0 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* f0 */ + }; + + /* + * Windows chararacter names. Give a name to the usused locations + * for when the all flag is specified. + */ + private String[] WinChars = { + "W00", /* 00 */ + "W01", /* 01 */ + "W02", /* 02 */ + "W03", /* 03 */ + "macron", /* 04 */ + "breve", /* 05 */ + "dotaccent", /* 06 */ + "W07", /* 07 */ + "ring", /* 08 */ + "W09", /* 09 */ + "W0a", /* 0a */ + "W0b", /* 0b */ + "W0c", /* 0c */ + "W0d", /* 0d */ + "W0e", /* 0e */ + "W0f", /* 0f */ + "hungarumlaut", /* 10 */ + "ogonek", /* 11 */ + "caron", /* 12 */ + "W13", /* 13 */ + "W14", /* 14 */ + "W15", /* 15 */ + "W16", /* 16 */ + "W17", /* 17 */ + "W18", /* 18 */ + "W19", /* 19 */ + "W1a", /* 1a */ + "W1b", /* 1b */ + "W1c", /* 1c */ + "W1d", /* 1d */ + "W1e", /* 1e */ + "W1f", /* 1f */ + "space", /* 20 */ + "exclam", /* 21 */ + "quotedbl", /* 22 */ + "numbersign", /* 23 */ + "dollar", /* 24 */ + "percent", /* 25 */ + "ampersand", /* 26 */ + "quotesingle", /* 27 */ + "parenleft", /* 28 */ + "parenright", /* 29 */ + "asterisk", /* 2A */ + "plus", /* 2B */ + "comma", /* 2C */ + "hyphen", /* 2D */ + "period", /* 2E */ + "slash", /* 2F */ + "zero", /* 30 */ + "one", /* 31 */ + "two", /* 32 */ + "three", /* 33 */ + "four", /* 34 */ + "five", /* 35 */ + "six", /* 36 */ + "seven", /* 37 */ + "eight", /* 38 */ + "nine", /* 39 */ + "colon", /* 3A */ + "semicolon", /* 3B */ + "less", /* 3C */ + "equal", /* 3D */ + "greater", /* 3E */ + "question", /* 3F */ + "at", /* 40 */ + "A", /* 41 */ + "B", /* 42 */ + "C", /* 43 */ + "D", /* 44 */ + "E", /* 45 */ + "F", /* 46 */ + "G", /* 47 */ + "H", /* 48 */ + "I", /* 49 */ + "J", /* 4A */ + "K", /* 4B */ + "L", /* 4C */ + "M", /* 4D */ + "N", /* 4E */ + "O", /* 4F */ + "P", /* 50 */ + "Q", /* 51 */ + "R", /* 52 */ + "S", /* 53 */ + "T", /* 54 */ + "U", /* 55 */ + "V", /* 56 */ + "W", /* 57 */ + "X", /* 58 */ + "Y", /* 59 */ + "Z", /* 5A */ + "bracketleft", /* 5B */ + "backslash", /* 5C */ + "bracketright", /* 5D */ + "asciicircum", /* 5E */ + "underscore", /* 5F */ + "grave", /* 60 */ + "a", /* 61 */ + "b", /* 62 */ + "c", /* 63 */ + "d", /* 64 */ + "e", /* 65 */ + "f", /* 66 */ + "g", /* 67 */ + "h", /* 68 */ + "i", /* 69 */ + "j", /* 6A */ + "k", /* 6B */ + "l", /* 6C */ + "m", /* 6D */ + "n", /* 6E */ + "o", /* 6F */ + "p", /* 70 */ + "q", /* 71 */ + "r", /* 72 */ + "s", /* 73 */ + "t", /* 74 */ + "u", /* 75 */ + "v", /* 76 */ + "w", /* 77 */ + "x", /* 78 */ + "y", /* 79 */ + "z", /* 7A */ + "braceleft", /* 7B */ + "bar", /* 7C */ + "braceright", /* 7D */ + "asciitilde", /* 7E */ + "W7f", /* 7F */ + "W80", /* 80 */ + "W81", /* 81 */ + "quotesinglbase", /* 82 */ + "W83", /* 83 */ + "quotedblbase", /* 84 */ + "ellipsis", /* 85 */ + "dagger", /* 86 */ + "daggerdbl", /* 87 */ + "asciicircum", /* 88 */ + "perthousand", /* 89 */ + "Scaron", /* 8A */ + "guilsinglleft", /* 8B */ + "OE", /* 8C */ + "W8d", /* 8D */ + "W8e", /* 8E */ + "W8f", /* 8F */ + "W90", /* 90 */ + "quoteleft", /* 91 */ + "quoteright", /* 92 */ + "quotedblleft", /* 93 */ + "quotedblright", /* 94 */ + "bullet1", /* 95 */ + "endash", /* 96 */ + "emdash", /* 97 */ + "asciitilde", /* 98 */ + "trademark", /* 99 */ + "scaron", /* 9A */ + "guilsinglright", /* 9B */ + "oe", /* 9C */ + "W9d", /* 9D */ + "W9e", /* 9E */ + "Ydieresis", /* 9F */ + "reqspace", /* A0 */ + "exclamdown", /* A1 */ + "cent", /* A2 */ + "sterling", /* A3 */ + "currency", /* A4 */ + "yen", /* A5 */ + "brokenbar", /* A6 */ + "section", /* A7 */ + "dieresis", /* A8 */ + "copyright", /* A9 */ + "ordfeminine", /* AA */ + "guillemotleft", /* AB */ + "logicalnot", /* AC */ + "syllable", /* AD */ + "registered", /* AE */ + "overbar", /* AF */ + "degree", /* B0 */ + "plusminus", /* B1 */ + "twosuperior", /* B2 */ + "threesuperior", /* B3 */ + "acute", /* B4 */ + "mu", /* B5 */ + "paragraph", /* B6 */ + "periodcentered", /* B7 */ + "cedilla", /* B8 */ + "onesuperior", /* B9 */ + "ordmasculine", /* BA */ + "guillemotright", /* BB */ + "onequarter", /* BC */ + "onehalf", /* BD */ + "threequarters", /* BE */ + "questiondown", /* BF */ + "Agrave", /* C0 */ + "Aacute", /* C1 */ + "Acircumflex", /* C2 */ + "Atilde", /* C3 */ + "Adieresis", /* C4 */ + "Aring", /* C5 */ + "AE", /* C6 */ + "Ccedilla", /* C7 */ + "Egrave", /* C8 */ + "Eacute", /* C9 */ + "Ecircumflex", /* CA */ + "Edieresis", /* CB */ + "Igrave", /* CC */ + "Iacute", /* CD */ + "Icircumflex", /* CE */ + "Idieresis", /* CF */ + "Eth", /* D0 */ + "Ntilde", /* D1 */ + "Ograve", /* D2 */ + "Oacute", /* D3 */ + "Ocircumflex", /* D4 */ + "Otilde", /* D5 */ + "Odieresis", /* D6 */ + "multiply", /* D7 */ + "Oslash", /* D8 */ + "Ugrave", /* D9 */ + "Uacute", /* DA */ + "Ucircumflex", /* DB */ + "Udieresis", /* DC */ + "Yacute", /* DD */ + "Thorn", /* DE */ + "germandbls", /* DF */ + "agrave", /* E0 */ + "aacute", /* E1 */ + "acircumflex", /* E2 */ + "atilde", /* E3 */ + "adieresis", /* E4 */ + "aring", /* E5 */ + "ae", /* E6 */ + "ccedilla", /* E7 */ + "egrave", /* E8 */ + "eacute", /* E9 */ + "ecircumflex", /* EA */ + "edieresis", /* EB */ + "igrave", /* EC */ + "iacute", /* ED */ + "icircumflex", /* EE */ + "idieresis", /* EF */ + "eth", /* F0 */ + "ntilde", /* F1 */ + "ograve", /* F2 */ + "oacute", /* F3 */ + "ocircumflex", /* F4 */ + "otilde", /* F5 */ + "odieresis", /* F6 */ + "divide", /* F7 */ + "oslash", /* F8 */ + "ugrave", /* F9 */ + "uacute", /* FA */ + "ucircumflex", /* FB */ + "udieresis", /* FC */ + "yacute", /* FD */ + "thorn", /* FE */ + "ydieresis" /* FF */ + }; + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/PushbuttonField.cs b/iTechSharp/iTextSharp/text/pdf/PushbuttonField.cs new file mode 100644 index 0000000..df38a5a --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/PushbuttonField.cs @@ -0,0 +1,628 @@ +using System; +using iTextSharp.text; +/* + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Creates a pushbutton field. It supports all the text and icon alignments. + * The icon may be an image or a template. + *

    + * Example usage: + *

    + *

    +    * Document document = new Document(PageSize.A4, 50, 50, 50, 50);
    +    * PdfWriter writer = PdfWriter.GetInstance(document, new FileOutputStream("output.pdf"));
    +    * document.Open();
    +    * PdfContentByte cb = writer.GetDirectContent();
    +    * Image img = Image.GetInstance("image.png");
    +    * PushbuttonField bt = new PushbuttonField(writer, new Rectangle(100, 100, 200, 200), "Button1");
    +    * bt.SetText("My Caption");
    +    * bt.SetFontSize(0);
    +    * bt.SetImage(img);
    +    * bt.SetLayout(PushbuttonField.LAYOUT_ICON_TOP_LABEL_BOTTOM);
    +    * bt.SetBackgroundColor(Color.cyan);
    +    * bt.SetBorderStyle(PdfBorderDictionary.STYLE_SOLID);
    +    * bt.SetBorderColor(Color.red);
    +    * bt.SetBorderWidth(3);
    +    * PdfFormField ff = bt.GetField();
    +    * PdfAction ac = PdfAction.CreateSubmitForm("http://www.submit-site.com", null, 0);
    +    * ff.SetAction(ac);
    +    * writer.AddAnnotation(ff);
    +    * document.Close();
    +    * 
    + * @author Paulo Soares (psoares@consiste.pt) + */ + public class PushbuttonField : BaseField { + + /** A layout option */ + public const int LAYOUT_LABEL_ONLY = 1; + /** A layout option */ + public const int LAYOUT_ICON_ONLY = 2; + /** A layout option */ + public const int LAYOUT_ICON_TOP_LABEL_BOTTOM = 3; + /** A layout option */ + public const int LAYOUT_LABEL_TOP_ICON_BOTTOM = 4; + /** A layout option */ + public const int LAYOUT_ICON_LEFT_LABEL_RIGHT = 5; + /** A layout option */ + public const int LAYOUT_LABEL_LEFT_ICON_RIGHT = 6; + /** A layout option */ + public const int LAYOUT_LABEL_OVER_ICON = 7; + /** An icon scaling option */ + public const int SCALE_ICON_ALWAYS = 1; + /** An icon scaling option */ + public const int SCALE_ICON_NEVER = 2; + /** An icon scaling option */ + public const int SCALE_ICON_IS_TOO_BIG = 3; + /** An icon scaling option */ + public const int SCALE_ICON_IS_TOO_SMALL = 4; + + /** + * Holds value of property layout. + */ + private int layout = LAYOUT_LABEL_ONLY; + + /** + * Holds value of property image. + */ + private Image image; + + /** + * Holds value of property template. + */ + private PdfTemplate template; + + /** + * Holds value of property scaleIcon. + */ + private int scaleIcon = SCALE_ICON_ALWAYS; + + /** + * Holds value of property proportionalIcon. + */ + private bool proportionalIcon = true; + + /** + * Holds value of property iconVerticalAdjustment. + */ + private float iconVerticalAdjustment = 0.5f; + + /** + * Holds value of property iconHorizontalAdjustment. + */ + private float iconHorizontalAdjustment = 0.5f; + + /** + * Holds value of property iconFitToBounds. + */ + private bool iconFitToBounds; + + private PdfTemplate tp; + + /** + * Creates a new instance of PushbuttonField + * @param writer the document PdfWriter + * @param box the field location and dimensions + * @param fieldName the field name. If null only the widget keys + * will be included in the field allowing it to be used as a kid field. + */ + public PushbuttonField(PdfWriter writer, Rectangle box, String fieldName) : base(writer, box, fieldName) { + } + + /** + * Sets the icon and label layout. Possible values are LAYOUT_LABEL_ONLY, + * LAYOUT_ICON_ONLY, LAYOUT_ICON_TOP_LABEL_BOTTOM, + * LAYOUT_LABEL_TOP_ICON_BOTTOM, LAYOUT_ICON_LEFT_LABEL_RIGHT, + * LAYOUT_LABEL_LEFT_ICON_RIGHT and LAYOUT_LABEL_OVER_ICON. + * The default is LAYOUT_LABEL_ONLY. + * @param layout New value of property layout. + */ + public int Layout { + set { + if (value < LAYOUT_LABEL_ONLY || value > LAYOUT_LABEL_OVER_ICON) + throw new ArgumentException("Layout out of bounds."); + this.layout = value; + } + get { + return layout; + } + } + + /** + * Sets the icon as an image. + * @param image the image + */ + public Image Image { + get { + return this.image; + } + set { + image = value; + template = null; + } + } + + /** + * Sets the icon as a template. + * @param template the template + */ + public PdfTemplate Template { + set { + this.template = value; + image = null; + } + get { + return template; + } + } + + /** + * Sets the way the icon will be scaled. Possible values are + * SCALE_ICON_ALWAYS, SCALE_ICON_NEVER, + * SCALE_ICON_IS_TOO_BIG and SCALE_ICON_IS_TOO_SMALL. + * The default is SCALE_ICON_ALWAYS. + * @param scaleIcon the way the icon will be scaled + */ + public int ScaleIcon { + set { + if (value < SCALE_ICON_ALWAYS || value > SCALE_ICON_IS_TOO_SMALL) + scaleIcon = SCALE_ICON_ALWAYS; + else + scaleIcon = value; + } + get { + return scaleIcon; + } + } + + /** + * Sets the way the icon is scaled. If true the icon is scaled proportionally, + * if false the scaling is done anamorphicaly. + * @param proportionalIcon the way the icon is scaled + */ + public bool ProportionalIcon { + get { + return proportionalIcon; + } + set { + proportionalIcon = value; + } + } + + /** + * A number between 0 and 1 indicating the fraction of leftover space to allocate at the bottom of the icon. + * A value of 0 positions the icon at the bottom of the annotation rectangle. + * A value of 0.5 centers it within the rectangle. The default is 0.5. + * @param iconVerticalAdjustment a number between 0 and 1 indicating the fraction of leftover space to allocate at the bottom of the icon + */ + public float IconVerticalAdjustment { + get { + return iconVerticalAdjustment; + } + set { + iconVerticalAdjustment = value; + if (iconVerticalAdjustment < 0) + iconVerticalAdjustment = 0; + else if (iconVerticalAdjustment > 1) + iconVerticalAdjustment = 1; + } + } + + /** + * A number between 0 and 1 indicating the fraction of leftover space to allocate at the left of the icon. + * A value of 0 positions the icon at the left of the annotation rectangle. + * A value of 0.5 centers it within the rectangle. The default is 0.5. + * @param iconHorizontalAdjustment a number between 0 and 1 indicating the fraction of leftover space to allocate at the left of the icon + */ + public float IconHorizontalAdjustment { + get { + return iconHorizontalAdjustment; + } + set { + iconHorizontalAdjustment = value; + if (iconHorizontalAdjustment < 0) + iconHorizontalAdjustment = 0; + else if (iconHorizontalAdjustment > 1) + iconHorizontalAdjustment = 1; + } + } + private float CalculateFontSize(float w, float h) { + BaseFont ufont = RealFont; + float fsize = fontSize; + if (fsize == 0) { + float bw = ufont.GetWidthPoint(text, 1); + if (bw == 0) + fsize = 12; + else + fsize = w / bw; + float nfsize = h / (1 - ufont.GetFontDescriptor(BaseFont.DESCENT, 1)); + fsize = Math.Min(fsize, nfsize); + if (fsize < 4) + fsize = 4; + } + return fsize; + } + + /** + * Gets the button appearance. + * @throws IOException on error + * @throws DocumentException on error + * @return the button appearance + */ + public PdfAppearance GetAppearance() { + PdfAppearance app = GetBorderAppearance(); + Rectangle box = new Rectangle(app.BoundingBox); + if ((text == null || text.Length == 0) && (layout == LAYOUT_LABEL_ONLY || (image == null && template == null && iconReference == null))) { + return app; + } + if (layout == LAYOUT_ICON_ONLY && image == null && template == null && iconReference == null) + return app; + BaseFont ufont = RealFont; + bool borderExtra = borderStyle == PdfBorderDictionary.STYLE_BEVELED || borderStyle == PdfBorderDictionary.STYLE_INSET; + float h = box.Height - borderWidth * 2; + float bw2 = borderWidth; + if (borderExtra) { + h -= borderWidth * 2; + bw2 *= 2; + } + float offsetX = (borderExtra ? 2 * borderWidth : borderWidth); + offsetX = Math.Max(offsetX, 1); + float offX = Math.Min(bw2, offsetX); + tp = null; + float textX = float.NaN; + float textY = 0; + float fsize = fontSize; + float wt = box.Width - 2 * offX - 2; + float ht = box.Height - 2 * offX; + float adj = (iconFitToBounds ? 0 : offX + 1); + int nlayout = layout; + if (image == null && template == null && iconReference == null) + nlayout = LAYOUT_LABEL_ONLY; + Rectangle iconBox = null; + while (true) { + switch (nlayout) { + case LAYOUT_LABEL_ONLY: + case LAYOUT_LABEL_OVER_ICON: + if (text != null && text.Length > 0 && wt > 0 && ht > 0) { + fsize = CalculateFontSize(wt, ht); + textX = (box.Width - ufont.GetWidthPoint(text, fsize)) / 2; + textY = (box.Height - ufont.GetFontDescriptor(BaseFont.ASCENT, fsize)) / 2; + } + goto case LAYOUT_ICON_ONLY; + case LAYOUT_ICON_ONLY: + if (nlayout == LAYOUT_LABEL_OVER_ICON || nlayout == LAYOUT_ICON_ONLY) + iconBox = new Rectangle(box.Left + adj, box.Bottom + adj, box.Right - adj, box.Top - adj); + break; + case LAYOUT_ICON_TOP_LABEL_BOTTOM: + if (text == null || text.Length == 0 || wt <= 0 || ht <= 0) { + nlayout = LAYOUT_ICON_ONLY; + continue; + } + float nht = box.Height * 0.35f - offX; + if (nht > 0) + fsize = CalculateFontSize(wt, nht); + else + fsize = 4; + textX = (box.Width - ufont.GetWidthPoint(text, fsize)) / 2; + textY = offX - ufont.GetFontDescriptor(BaseFont.DESCENT, fsize); + iconBox = new Rectangle(box.Left + adj, textY + fsize, box.Right - adj, box.Top - adj); + break; + case LAYOUT_LABEL_TOP_ICON_BOTTOM: + if (text == null || text.Length == 0 || wt <= 0 || ht <= 0) { + nlayout = LAYOUT_ICON_ONLY; + continue; + } + nht = box.Height * 0.35f - offX; + if (nht > 0) + fsize = CalculateFontSize(wt, nht); + else + fsize = 4; + textX = (box.Width - ufont.GetWidthPoint(text, fsize)) / 2; + textY = box.Height - offX - fsize; + if (textY < offX) + textY = offX; + iconBox = new Rectangle(box.Left + adj, box.Bottom + adj, box.Right - adj, textY + ufont.GetFontDescriptor(BaseFont.DESCENT, fsize)); + break; + case LAYOUT_LABEL_LEFT_ICON_RIGHT: + if (text == null || text.Length == 0 || wt <= 0 || ht <= 0) { + nlayout = LAYOUT_ICON_ONLY; + continue; + } + float nw = box.Width * 0.35f - offX; + if (nw > 0) + fsize = CalculateFontSize(wt, nw); + else + fsize = 4; + if (ufont.GetWidthPoint(text, fsize) >= wt) { + nlayout = LAYOUT_LABEL_ONLY; + fsize = fontSize; + continue; + } + textX = offX + 1; + textY = (box.Height - ufont.GetFontDescriptor(BaseFont.ASCENT, fsize)) / 2; + iconBox = new Rectangle(textX + ufont.GetWidthPoint(text, fsize), box.Bottom + adj, box.Right - adj, box.Top - adj); + break; + case LAYOUT_ICON_LEFT_LABEL_RIGHT: + if (text == null || text.Length == 0 || wt <= 0 || ht <= 0) { + nlayout = LAYOUT_ICON_ONLY; + continue; + } + nw = box.Width * 0.35f - offX; + if (nw > 0) + fsize = CalculateFontSize(wt, nw); + else + fsize = 4; + if (ufont.GetWidthPoint(text, fsize) >= wt) { + nlayout = LAYOUT_LABEL_ONLY; + fsize = fontSize; + continue; + } + textX = box.Width - ufont.GetWidthPoint(text, fsize) - offX - 1; + textY = (box.Height - ufont.GetFontDescriptor(BaseFont.ASCENT, fsize)) / 2; + iconBox = new Rectangle(box.Left + adj, box.Bottom + adj, textX - 1, box.Top - adj); + break; + } + break; + } + if (textY < box.Bottom + offX) + textY = box.Bottom + offX; + if (iconBox != null && (iconBox.Width <= 0 || iconBox.Height <= 0)) + iconBox = null; + bool haveIcon = false; + float boundingBoxWidth = 0; + float boundingBoxHeight = 0; + PdfArray matrix = null; + if (iconBox != null) { + if (image != null) { + tp = new PdfTemplate(writer); + tp.BoundingBox = new Rectangle(image); + writer.AddDirectTemplateSimple(tp, PdfName.FRM); + tp.AddImage(image, image.Width, 0, 0, image.Height, 0, 0); + haveIcon = true; + boundingBoxWidth = tp.BoundingBox.Width; + boundingBoxHeight = tp.BoundingBox.Height; + } + else if (template != null) { + tp = new PdfTemplate(writer); + tp.BoundingBox = new Rectangle(template.Width, template.Height); + writer.AddDirectTemplateSimple(tp, PdfName.FRM); + tp.AddTemplate(template, template.BoundingBox.Left, template.BoundingBox.Bottom); + haveIcon = true; + boundingBoxWidth = tp.BoundingBox.Width; + boundingBoxHeight = tp.BoundingBox.Height; + } + else if (iconReference != null) { + PdfDictionary dic = (PdfDictionary)PdfReader.GetPdfObject(iconReference); + if (dic != null) { + Rectangle r2 = PdfReader.GetNormalizedRectangle((PdfArray)PdfReader.GetPdfObject(dic.Get(PdfName.BBOX))); + matrix = (PdfArray)PdfReader.GetPdfObject(dic.Get(PdfName.MATRIX)); + haveIcon = true; + boundingBoxWidth = r2.Width; + boundingBoxHeight = r2.Height; + } + } + } + if (haveIcon) { + float icx = iconBox.Width / boundingBoxWidth; + float icy = iconBox.Height / boundingBoxHeight; + if (proportionalIcon) { + switch (scaleIcon) { + case SCALE_ICON_IS_TOO_BIG: + icx = Math.Min(icx, icy); + icx = Math.Min(icx, 1); + break; + case SCALE_ICON_IS_TOO_SMALL: + icx = Math.Min(icx, icy); + icx = Math.Max(icx, 1); + break; + case SCALE_ICON_NEVER: + icx = 1; + break; + default: + icx = Math.Min(icx, icy); + break; + } + icy = icx; + } + else { + switch (scaleIcon) { + case SCALE_ICON_IS_TOO_BIG: + icx = Math.Min(icx, 1); + icy = Math.Min(icy, 1); + break; + case SCALE_ICON_IS_TOO_SMALL: + icx = Math.Max(icx, 1); + icy = Math.Max(icy, 1); + break; + case SCALE_ICON_NEVER: + icx = icy = 1; + break; + default: + break; + } + } + float xpos = iconBox.Left + (iconBox.Width - (boundingBoxWidth * icx)) * iconHorizontalAdjustment; + float ypos = iconBox.Bottom + (iconBox.Height - (boundingBoxHeight * icy)) * iconVerticalAdjustment; + app.SaveState(); + app.Rectangle(iconBox.Left, iconBox.Bottom, iconBox.Width, iconBox.Height); + app.Clip(); + app.NewPath(); + if (tp != null) + app.AddTemplate(tp, icx, 0, 0, icy, xpos, ypos); + else { + float cox = 0; + float coy = 0; + if (matrix != null && matrix.Size == 6) { + PdfNumber nm = (PdfNumber)PdfReader.GetPdfObject((PdfObject)matrix.ArrayList[4]); + if (nm != null) + cox = nm.FloatValue; + nm = (PdfNumber)PdfReader.GetPdfObject((PdfObject)matrix.ArrayList[5]); + if (nm != null) + coy = nm.FloatValue; + } + app.AddTemplateReference(iconReference, PdfName.FRM, icx, 0, 0, icy, xpos - cox * icx, ypos - coy * icy); + } + app.RestoreState(); + } + if (!float.IsNaN(textX)) { + app.SaveState(); + app.Rectangle(offX, offX, box.Width - 2 * offX, box.Height - 2 * offX); + app.Clip(); + app.NewPath(); + if (textColor == null) + app.ResetGrayFill(); + else + app.SetColorFill(textColor); + app.BeginText(); + app.SetFontAndSize(ufont, fsize); + app.SetTextMatrix(textX, textY); + app.ShowText(text); + app.EndText(); + app.RestoreState(); + } + return app; + } + + /** + * Gets the pushbutton field. + * @throws IOException on error + * @throws DocumentException on error + * @return the pushbutton field + */ + public PdfFormField Field { + get { + PdfFormField field = PdfFormField.CreatePushButton(writer); + field.SetWidget(box, PdfAnnotation.HIGHLIGHT_INVERT); + if (fieldName != null) { + field.FieldName = fieldName; + if ((options & READ_ONLY) != 0) + field.SetFieldFlags(PdfFormField.FF_READ_ONLY); + if ((options & REQUIRED) != 0) + field.SetFieldFlags(PdfFormField.FF_REQUIRED); + } + if (text != null) + field.MKNormalCaption = text; + if (rotation != 0) + field.MKRotation = rotation; + field.BorderStyle = new PdfBorderDictionary(borderWidth, borderStyle, new PdfDashPattern(3)); + PdfAppearance tpa = GetAppearance(); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, tpa); + PdfAppearance da = (PdfAppearance)tpa.Duplicate; + da.SetFontAndSize(RealFont, fontSize); + if (textColor == null) + da.SetGrayFill(0); + else + da.SetColorFill(textColor); + field.DefaultAppearanceString = da; + if (borderColor != null) + field.MKBorderColor = borderColor; + if (backgroundColor != null) + field.MKBackgroundColor = backgroundColor; + switch (visibility) { + case HIDDEN: + field.Flags = PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_HIDDEN; + break; + case VISIBLE_BUT_DOES_NOT_PRINT: + break; + case HIDDEN_BUT_PRINTABLE: + field.Flags = PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_NOVIEW; + break; + default: + field.Flags = PdfAnnotation.FLAGS_PRINT; + break; + } + if (tp != null) + field.MKNormalIcon = tp; + field.MKTextPosition = layout - 1; + PdfName scale = PdfName.A; + if (scaleIcon == SCALE_ICON_IS_TOO_BIG) + scale = PdfName.B; + else if (scaleIcon == SCALE_ICON_IS_TOO_SMALL) + scale = PdfName.S; + else if (scaleIcon == SCALE_ICON_NEVER) + scale = PdfName.N; + field.SetMKIconFit(scale, proportionalIcon ? PdfName.P : PdfName.A, iconHorizontalAdjustment, + iconVerticalAdjustment, iconFitToBounds); + return field; + } + } + + /** + * If true the icon will be scaled to fit fully within the bounds of the annotation, + * if false the border width will be taken into account. The default + * is false. + * @param iconFitToBounds if true the icon will be scaled to fit fully within the bounds of the annotation, + * if false the border width will be taken into account + */ + public bool IconFitToBounds { + get { + return iconFitToBounds; + } + set { + iconFitToBounds = value; + } + } + /** + * Holds value of property iconReference. + */ + private PRIndirectReference iconReference; + + /** + * Sets the reference to an existing icon. + * @param iconReference the reference to an existing icon + */ + public PRIndirectReference IconReference { + get { + return iconReference; + } + set { + iconReference = value; + } + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/RadioCheckField.cs b/iTechSharp/iTextSharp/text/pdf/RadioCheckField.cs new file mode 100644 index 0000000..f373fb0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/RadioCheckField.cs @@ -0,0 +1,401 @@ +using System; +/* + * Copyright 2005 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Creates a radio or a check field. + *

    + * Example usage: + *

    + *

    +    * Document document = new Document(PageSize.A4, 50, 50, 50, 50);
    +    * PdfWriter writer = PdfWriter.GetInstance(document, new FileOutputStream("output.pdf"));
    +    * document.Open();
    +    * PdfContentByte cb = writer.GetDirectContent();
    +    * RadioCheckField bt = new RadioCheckField(writer, new Rectangle(100, 100, 200, 200), "radio", "v1");
    +    * bt.SetCheckType(RadioCheckField.TYPE_CIRCLE);
    +    * bt.SetBackgroundColor(Color.CYAN);
    +    * bt.SetBorderStyle(PdfBorderDictionary.STYLE_SOLID);
    +    * bt.SetBorderColor(Color.red);
    +    * bt.SetTextColor(Color.yellow);
    +    * bt.SetBorderWidth(BaseField.BORDER_WIDTH_THICK);
    +    * bt.SetChecked(false);
    +    * PdfFormField f1 = bt.GetRadioField();
    +    * bt.SetOnValue("v2");
    +    * bt.SetChecked(true);
    +    * bt.SetBox(new Rectangle(100, 300, 200, 400));
    +    * PdfFormField f2 = bt.GetRadioField();
    +    * bt.SetChecked(false);
    +    * PdfFormField top = bt.GetRadioGroup(true, false);
    +    * bt.SetOnValue("v3");
    +    * bt.SetBox(new Rectangle(100, 500, 200, 600));
    +    * PdfFormField f3 = bt.GetRadioField();
    +    * top.AddKid(f1);
    +    * top.AddKid(f2);
    +    * top.AddKid(f3);
    +    * writer.AddAnnotation(top);
    +    * bt = new RadioCheckField(writer, new Rectangle(300, 300, 400, 400), "check1", "Yes");
    +    * bt.SetCheckType(RadioCheckField.TYPE_CHECK);
    +    * bt.SetBorderWidth(BaseField.BORDER_WIDTH_THIN);
    +    * bt.SetBorderColor(Color.black);
    +    * bt.SetBackgroundColor(Color.white);
    +    * PdfFormField ck = bt.GetCheckField();
    +    * writer.AddAnnotation(ck);
    +    * document.Close();
    +    * 
    + * @author Paulo Soares (psoares@consiste.pt) + */ + public class RadioCheckField : BaseField { + + /** A field with the symbol check */ + public const int TYPE_CHECK = 1; + /** A field with the symbol circle */ + public const int TYPE_CIRCLE = 2; + /** A field with the symbol cross */ + public const int TYPE_CROSS = 3; + /** A field with the symbol diamond */ + public const int TYPE_DIAMOND = 4; + /** A field with the symbol square */ + public const int TYPE_SQUARE = 5; + /** A field with the symbol star */ + public const int TYPE_STAR = 6; + + private static String[] typeChars = {"4", "l", "8", "u", "n", "H"}; + + /** + * Holds value of property checkType. + */ + private int checkType; + + /** + * Holds value of property onValue. + */ + private String onValue; + + /** + * Holds value of property checked. + */ + private bool vchecked; + + /** + * Creates a new instance of RadioCheckField + * @param writer the document PdfWriter + * @param box the field location and dimensions + * @param fieldName the field name. It must not be null + * @param onValue the value when the field is checked + */ + public RadioCheckField(PdfWriter writer, Rectangle box, String fieldName, String onValue) : base(writer, box, fieldName) { + OnValue = onValue; + CheckType = TYPE_CIRCLE; + } + + /** + * Sets the checked symbol. It can be + * TYPE_CHECK, + * TYPE_CIRCLE, + * TYPE_CROSS, + * TYPE_DIAMOND, + * TYPE_SQUARE and + * TYPE_STAR. + * @param checkType the checked symbol + */ + public int CheckType { + get { + return checkType; + } + set { + checkType = value; + if (checkType < TYPE_CHECK || checkType > TYPE_STAR) + checkType = TYPE_CIRCLE; + Text = typeChars[checkType - 1]; + Font = BaseFont.CreateFont(BaseFont.ZAPFDINGBATS, BaseFont.WINANSI, false); + } + } + + /** + * Sets the value when the field is checked. + * @param onValue the value when the field is checked + */ + public string OnValue { + get { + return onValue; + } + set { + onValue = value; + } + } + + /** + * Sets the state of the field to checked or unchecked. + * @param checked the state of the field, true for checked + * and false for unchecked + */ + public bool Checked { + get { + return vchecked; + } + set { + vchecked = value; + } + } + /** + * Gets the field appearance. + * @param isRadio true for a radio field and false + * for a check field + * @param on true for the checked state, false + * otherwise + * @throws IOException on error + * @throws DocumentException on error + * @return the appearance + */ + public PdfAppearance GetAppearance(bool isRadio, bool on) { + if (isRadio && checkType == TYPE_CIRCLE) + return GetAppearanceRadioCircle(on); + PdfAppearance app = GetBorderAppearance(); + if (!on) + return app; + BaseFont ufont = RealFont; + bool borderExtra = borderStyle == PdfBorderDictionary.STYLE_BEVELED || borderStyle == PdfBorderDictionary.STYLE_INSET; + float h = box.Height - borderWidth * 2; + float bw2 = borderWidth; + if (borderExtra) { + h -= borderWidth * 2; + bw2 *= 2; + } + float offsetX = (borderExtra ? 2 * borderWidth : borderWidth); + offsetX = Math.Max(offsetX, 1); + float offX = Math.Min(bw2, offsetX); + float wt = box.Width - 2 * offX; + float ht = box.Height - 2 * offX; + float fsize = fontSize; + if (fsize == 0) { + float bw = ufont.GetWidthPoint(text, 1); + if (bw == 0) + fsize = 12; + else + fsize = wt / bw; + float nfsize = h / (ufont.GetFontDescriptor(BaseFont.ASCENT, 1)); + fsize = Math.Min(fsize, nfsize); + } + app.SaveState(); + app.Rectangle(offX, offX, wt, ht); + app.Clip(); + app.NewPath(); + if (textColor == null) + app.ResetGrayFill(); + else + app.SetColorFill(textColor); + app.BeginText(); + app.SetFontAndSize(ufont, fsize); + app.SetTextMatrix((box.Width - ufont.GetWidthPoint(text, fsize)) / 2, + (box.Height - ufont.GetAscentPoint(text, fsize)) / 2); + app.ShowText(text); + app.EndText(); + app.RestoreState(); + return app; + } + + /** + * Gets the special field appearance for the radio circle. + * @param on true for the checked state, false + * otherwise + * @return the appearance + */ + public PdfAppearance GetAppearanceRadioCircle(bool on) { + PdfAppearance app = PdfAppearance.CreateAppearance(writer, box.Width, box.Height); + switch (rotation) { + case 90: + app.SetMatrix(0, 1, -1, 0, box.Height, 0); + break; + case 180: + app.SetMatrix(-1, 0, 0, -1, box.Width, box.Height); + break; + case 270: + app.SetMatrix(0, -1, 1, 0, 0, box.Width); + break; + } + Rectangle boxc = new Rectangle(app.BoundingBox); + float cx = boxc.Width / 2; + float cy = boxc.Height / 2; + float r = (Math.Min(boxc.Width, boxc.Height) - borderWidth) / 2; + if (r <= 0) + return app; + if (backgroundColor != null) { + app.SetColorFill(backgroundColor); + app.Circle(cx, cy, r + borderWidth / 2); + app.Fill(); + } + if (borderWidth > 0 && borderColor != null) { + app.SetLineWidth(borderWidth); + app.SetColorStroke(borderColor); + app.Circle(cx, cy, r); + app.Stroke(); + } + if (on) { + if (textColor == null) + app.ResetGrayFill(); + else + app.SetColorFill(textColor); + app.Circle(cx, cy, r / 2); + app.Fill(); + } + return app; + } + + /** + * Gets a radio group. It's composed of the field specific keys, without the widget + * ones. This field is to be used as a field aggregator with {@link PdfFormField#addKid(PdfFormField) AddKid()}. + * @param noToggleToOff if true, exactly one radio button must be selected at all + * times; clicking the currently selected button has no effect. + * If false, clicking + * the selected button deselects it, leaving no button selected. + * @param radiosInUnison if true, a group of radio buttons within a radio button field that + * use the same value for the on state will turn on and off in unison; that is if + * one is checked, they are all checked. If false, the buttons are mutually exclusive + * (the same behavior as HTML radio buttons) + * @return the radio group + */ + public PdfFormField GetRadioGroup(bool noToggleToOff, bool radiosInUnison) { + PdfFormField field = PdfFormField.CreateRadioButton(writer, noToggleToOff); + if (radiosInUnison) + field.SetFieldFlags(PdfFormField.FF_RADIOSINUNISON); + field.FieldName = fieldName; + if ((options & READ_ONLY) != 0) + field.SetFieldFlags(PdfFormField.FF_READ_ONLY); + if ((options & REQUIRED) != 0) + field.SetFieldFlags(PdfFormField.FF_REQUIRED); + field.ValueAsName = vchecked ? onValue : "Off"; + return field; + } + + /** + * Gets the radio field. It's only composed of the widget keys and must be used + * with {@link #getRadioGroup(bool,bool)}. + * @return the radio field + * @throws IOException on error + * @throws DocumentException on error + */ + public PdfFormField RadioField { + get { + return GetField(true); + } + } + + /** + * Gets the check field. + * @return the check field + * @throws IOException on error + * @throws DocumentException on error + */ + public PdfFormField CheckField { + get { + return GetField(false); + } + } + + /** + * Gets a radio or check field. + * @param isRadio true to get a radio field, false to get + * a check field + * @throws IOException on error + * @throws DocumentException on error + * @return the field + */ + protected PdfFormField GetField(bool isRadio) { + PdfFormField field = null; + if (isRadio) + field = PdfFormField.CreateEmpty(writer); + else + field = PdfFormField.CreateCheckBox(writer); + field.SetWidget(box, PdfAnnotation.HIGHLIGHT_INVERT); + if (!isRadio) { + field.FieldName = fieldName; + if ((options & READ_ONLY) != 0) + field.SetFieldFlags(PdfFormField.FF_READ_ONLY); + if ((options & REQUIRED) != 0) + field.SetFieldFlags(PdfFormField.FF_REQUIRED); + field.ValueAsName = vchecked ? onValue : "Off"; + } + if (text != null) + field.MKNormalCaption = text; + if (rotation != 0) + field.MKRotation = rotation; + field.BorderStyle = new PdfBorderDictionary(borderWidth, borderStyle, new PdfDashPattern(3)); + PdfAppearance tpon = GetAppearance(isRadio, true); + PdfAppearance tpoff = GetAppearance(isRadio, false); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, onValue, tpon); + field.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, "Off", tpoff); + field.AppearanceState = vchecked ? onValue : "Off"; + PdfAppearance da = (PdfAppearance)tpon.Duplicate; + da.SetFontAndSize(RealFont, fontSize); + if (textColor == null) + da.SetGrayFill(0); + else + da.SetColorFill(textColor); + field.DefaultAppearanceString = da; + if (borderColor != null) + field.MKBorderColor = borderColor; + if (backgroundColor != null) + field.MKBackgroundColor = backgroundColor; + switch (visibility) { + case HIDDEN: + field.Flags = PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_HIDDEN; + break; + case VISIBLE_BUT_DOES_NOT_PRINT: + break; + case HIDDEN_BUT_PRINTABLE: + field.Flags = PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_NOVIEW; + break; + default: + field.Flags = PdfAnnotation.FLAGS_PRINT; + break; + } + return field; + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/RandomAccessFileOrArray.cs b/iTechSharp/iTextSharp/text/pdf/RandomAccessFileOrArray.cs new file mode 100644 index 0000000..ea6a7b0 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/RandomAccessFileOrArray.cs @@ -0,0 +1,607 @@ +using System; +using System.IO; +using System.Text; +using System.Net; +/* + * $Id: RandomAccessFileOrArray.cs,v 1.9 2008/05/13 11:25:23 psoares33 Exp $ + * + * + * Copyright 2001, 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** An implementation of a RandomAccessFile for input only + * that accepts a file or a byte array as data source. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class RandomAccessFileOrArray { + + internal FileStream rf; + internal String filename; + internal byte[] arrayIn; + internal int arrayInPtr; + internal byte back; + internal bool isBack = false; + + /** Holds value of property startOffset. */ + private int startOffset = 0; + + public RandomAccessFileOrArray(String filename) : this(filename, false) { + } + + public RandomAccessFileOrArray(String filename, bool forceRead) { + if (!File.Exists(filename)) { + if (filename.StartsWith("file:/") || filename.StartsWith("http://") || filename.StartsWith("https://")) { + Stream isp = WebRequest.Create(new Uri(filename)).GetResponse().GetResponseStream(); + try { + this.arrayIn = InputStreamToArray(isp); + return; + } + finally { + try {isp.Close();}catch{} + } + } + else { + Stream isp = BaseFont.GetResourceStream(filename); + if (isp == null) + throw new IOException(filename + " not found as file or resource."); + try { + this.arrayIn = InputStreamToArray(isp); + return; + } + finally { + try {isp.Close();}catch{} + } + } + } + else if (forceRead) { + Stream s = null; + try { + s = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); + this.arrayIn = InputStreamToArray(s); + } + finally { + try{if (s != null) s.Close();}catch{} + } + return; + } + this.filename = filename; + rf = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); + } + + public RandomAccessFileOrArray(Uri url) { + Stream isp = WebRequest.Create(url).GetResponse().GetResponseStream(); + try { + this.arrayIn = InputStreamToArray(isp); + } + finally { + try {isp.Close();}catch{} + } + } + + public RandomAccessFileOrArray(Stream isp) { + this.arrayIn = InputStreamToArray(isp); + } + + public static byte[] InputStreamToArray(Stream isp) { + byte[] b = new byte[8192]; + MemoryStream outp = new MemoryStream(); + while (true) { + int read = isp.Read(b, 0, b.Length); + if (read < 1) + break; + outp.Write(b, 0, read); + } + return outp.ToArray(); + } + + public RandomAccessFileOrArray(byte[] arrayIn) { + this.arrayIn = arrayIn; + } + + public RandomAccessFileOrArray(RandomAccessFileOrArray file) { + filename = file.filename; + arrayIn = file.arrayIn; + startOffset = file.startOffset; + } + + public void PushBack(byte b) { + back = b; + isBack = true; + } + + public int Read() { + if (isBack) { + isBack = false; + return back & 0xff; + } + if (arrayIn == null) + return rf.ReadByte(); + else { + if (arrayInPtr >= arrayIn.Length) + return -1; + return arrayIn[arrayInPtr++] & 0xff; + } + } + + public int Read(byte[] b, int off, int len) { + if (len == 0) + return 0; + int n = 0; + if (isBack) { + isBack = false; + if (len == 1) { + b[off] = back; + return 1; + } + else { + n = 1; + b[off++] = back; + --len; + } + } + if (arrayIn == null) { + return rf.Read(b, off, len) + n; + } + else { + if (arrayInPtr >= arrayIn.Length) + return -1; + if (arrayInPtr + len > arrayIn.Length) + len = arrayIn.Length - arrayInPtr; + Array.Copy(arrayIn, arrayInPtr, b, off, len); + arrayInPtr += len; + return len + n; + } + } + + public int Read(byte[] b) { + return Read(b, 0, b.Length); + } + + public void ReadFully(byte[] b) { + ReadFully(b, 0, b.Length); + } + + public void ReadFully(byte[] b, int off, int len) { + if (len == 0) + return; + int n = 0; + do { + int count = Read(b, off + n, len - n); + if (count <= 0) + throw new EndOfStreamException(); + n += count; + } while (n < len); + } + + public long Skip(long n) { + return SkipBytes((int)n); + } + + public int SkipBytes(int n) { + if (n <= 0) { + return 0; + } + int adj = 0; + if (isBack) { + isBack = false; + if (n == 1) { + return 1; + } + else { + --n; + adj = 1; + } + } + int pos; + int len; + int newpos; + + pos = FilePointer; + len = Length; + newpos = pos + n; + if (newpos > len) { + newpos = len; + } + Seek(newpos); + + /* return the actual number of bytes skipped */ + return newpos - pos + adj; + } + + public void ReOpen() { + if (filename != null && rf == null) + rf = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); + Seek(0); + } + + protected void InsureOpen() { + if (filename != null && rf == null) { + ReOpen(); + } + } + + public bool IsOpen() { + return (filename == null || rf != null); + } + + public void Close() { + isBack = false; + if (rf != null) { + rf.Close(); + rf = null; + } + } + + public int Length { + get { + if (arrayIn == null) { + InsureOpen(); + return (int)rf.Length - startOffset; + } + else + return arrayIn.Length - startOffset; + } + } + + public void Seek(int pos) { + pos += startOffset; + isBack = false; + if (arrayIn == null) { + InsureOpen(); + rf.Position = pos; + } + else + arrayInPtr = pos; + } + + public void Seek(long pos) { + Seek((int)pos); + } + + public int FilePointer { + get { + InsureOpen(); + int n = isBack ? 1 : 0; + if (arrayIn == null) { + return (int)rf.Position - n - startOffset; + } + else + return arrayInPtr - n - startOffset; + } + } + + public bool ReadBoolean() { + int ch = this.Read(); + if (ch < 0) + throw new EndOfStreamException(); + return (ch != 0); + } + + public byte ReadByte() { + int ch = this.Read(); + if (ch < 0) + throw new EndOfStreamException(); + return (byte)(ch); + } + + public int ReadUnsignedByte() { + int ch = this.Read(); + if (ch < 0) + throw new EndOfStreamException(); + return ch; + } + + public short ReadShort() { + int ch1 = this.Read(); + int ch2 = this.Read(); + if ((ch1 | ch2) < 0) + throw new EndOfStreamException(); + return (short)((ch1 << 8) + ch2); + } + + /** + * Reads a signed 16-bit number from this stream in little-endian order. + * The method reads two + * bytes from this stream, starting at the current stream pointer. + * If the two bytes read, in order, are + * b1 and b2, where each of the two values is + * between 0 and 255, inclusive, then the + * result is equal to: + *
    +        *     (short)((b2 << 8) | b1)
    +        * 
    + *

    + * This method blocks until the two bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return the next two bytes of this stream, interpreted as a signed + * 16-bit number. + * @exception EOFException if this stream reaches the end before reading + * two bytes. + * @exception IOException if an I/O error occurs. + */ + public short ReadShortLE() { + int ch1 = this.Read(); + int ch2 = this.Read(); + if ((ch1 | ch2) < 0) + throw new EndOfStreamException(); + return (short)((ch2 << 8) + (ch1 << 0)); + } + + public int ReadUnsignedShort() { + int ch1 = this.Read(); + int ch2 = this.Read(); + if ((ch1 | ch2) < 0) + throw new EndOfStreamException(); + return (ch1 << 8) + ch2; + } + + /** + * Reads an unsigned 16-bit number from this stream in little-endian order. + * This method reads + * two bytes from the stream, starting at the current stream pointer. + * If the bytes read, in order, are + * b1 and b2, where + * 0 <= b1, b2 <= 255, + * then the result is equal to: + *

    +        *     (b2 << 8) | b1
    +        * 
    + *

    + * This method blocks until the two bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return the next two bytes of this stream, interpreted as an + * unsigned 16-bit integer. + * @exception EOFException if this stream reaches the end before reading + * two bytes. + * @exception IOException if an I/O error occurs. + */ + public int ReadUnsignedShortLE() { + int ch1 = this.Read(); + int ch2 = this.Read(); + if ((ch1 | ch2) < 0) + throw new EndOfStreamException(); + return (ch2 << 8) + (ch1 << 0); + } + + public char ReadChar() { + int ch1 = this.Read(); + int ch2 = this.Read(); + if ((ch1 | ch2) < 0) + throw new EndOfStreamException(); + return (char)((ch1 << 8) + ch2); + } + + /** + * Reads a Unicode character from this stream in little-endian order. + * This method reads two + * bytes from the stream, starting at the current stream pointer. + * If the bytes read, in order, are + * b1 and b2, where + * 0 <= b1, b2 <= 255, + * then the result is equal to: + *

    +        *     (char)((b2 << 8) | b1)
    +        * 
    + *

    + * This method blocks until the two bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return the next two bytes of this stream as a Unicode character. + * @exception EOFException if this stream reaches the end before reading + * two bytes. + * @exception IOException if an I/O error occurs. + */ + public char ReadCharLE() { + int ch1 = this.Read(); + int ch2 = this.Read(); + if ((ch1 | ch2) < 0) + throw new EndOfStreamException(); + return (char)((ch2 << 8) + (ch1 << 0)); + } + + public int ReadInt() { + int ch1 = this.Read(); + int ch2 = this.Read(); + int ch3 = this.Read(); + int ch4 = this.Read(); + if ((ch1 | ch2 | ch3 | ch4) < 0) + throw new EndOfStreamException(); + return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + ch4); + } + + /** + * Reads a signed 32-bit integer from this stream in little-endian order. + * This method reads 4 + * bytes from the stream, starting at the current stream pointer. + * If the bytes read, in order, are b1, + * b2, b3, and b4, where + * 0 <= b1, b2, b3, b4 <= 255, + * then the result is equal to: + *

    +        *     (b4 << 24) | (b3 << 16) + (b2 << 8) + b1
    +        * 
    + *

    + * This method blocks until the four bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return the next four bytes of this stream, interpreted as an + * int. + * @exception EOFException if this stream reaches the end before reading + * four bytes. + * @exception IOException if an I/O error occurs. + */ + public int ReadIntLE() { + int ch1 = this.Read(); + int ch2 = this.Read(); + int ch3 = this.Read(); + int ch4 = this.Read(); + if ((ch1 | ch2 | ch3 | ch4) < 0) + throw new EndOfStreamException(); + return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0)); + } + + /** + * Reads an unsigned 32-bit integer from this stream. This method reads 4 + * bytes from the stream, starting at the current stream pointer. + * If the bytes read, in order, are b1, + * b2, b3, and b4, where + * 0 <= b1, b2, b3, b4 <= 255, + * then the result is equal to: + *

    +        *     (b1 << 24) | (b2 << 16) + (b3 << 8) + b4
    +        * 
    + *

    + * This method blocks until the four bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return the next four bytes of this stream, interpreted as a + * long. + * @exception EOFException if this stream reaches the end before reading + * four bytes. + * @exception IOException if an I/O error occurs. + */ + public long ReadUnsignedInt() { + long ch1 = this.Read(); + long ch2 = this.Read(); + long ch3 = this.Read(); + long ch4 = this.Read(); + if ((ch1 | ch2 | ch3 | ch4) < 0) + throw new EndOfStreamException(); + return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); + } + + public long ReadUnsignedIntLE() { + long ch1 = this.Read(); + long ch2 = this.Read(); + long ch3 = this.Read(); + long ch4 = this.Read(); + if ((ch1 | ch2 | ch3 | ch4) < 0) + throw new EndOfStreamException(); + return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0)); + } + + public long ReadLong() { + return ((long)(ReadInt()) << 32) + (ReadInt() & 0xFFFFFFFFL); + } + + public long ReadLongLE() { + int i1 = ReadIntLE(); + int i2 = ReadIntLE(); + return ((long)i2 << 32) + (i1 & 0xFFFFFFFFL); + } + + public float ReadFloat() { + int[] a = {ReadInt()}; + float[] b = {0}; + Buffer.BlockCopy(a, 0, b, 0, 4); + return b[0]; + } + + public float ReadFloatLE() { + int[] a = {ReadIntLE()}; + float[] b = {0}; + Buffer.BlockCopy(a, 0, b, 0, 4); + return b[0]; + } + + public double ReadDouble() { + long[] a = {ReadLong()}; + double[] b = {0}; + Buffer.BlockCopy(a, 0, b, 0, 8); + return b[0]; + } + + public double ReadDoubleLE() { + long[] a = {ReadLongLE()}; + double[] b = {0}; + Buffer.BlockCopy(a, 0, b, 0, 8); + return b[0]; + } + + public String ReadLine() { + StringBuilder input = new StringBuilder(); + int c = -1; + bool eol = false; + + while (!eol) { + switch (c = Read()) { + case -1: + case '\n': + eol = true; + break; + case '\r': + eol = true; + int cur = FilePointer; + if ((Read()) != '\n') { + Seek(cur); + } + break; + default: + input.Append((char)c); + break; + } + } + + if ((c == -1) && (input.Length == 0)) { + return null; + } + return input.ToString(); + } + + public int StartOffset { + get { + return startOffset; + } + set { + startOffset = value; + } + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/SequenceList.cs b/iTechSharp/iTextSharp/text/pdf/SequenceList.cs new file mode 100644 index 0000000..04b6b7b --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/SequenceList.cs @@ -0,0 +1,317 @@ +using System; +using System.Collections; +using System.Text; +using System.util; +/* + * Copyright 2004 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * This class expands a string into a list of numbers. The main use is to select a + * range of pages. + *

    + * The general systax is:
    + * [!][o][odd][e][even]start-end + *

    + * You can have multiple ranges separated by commas ','. The '!' modifier removes the + * range from what is already selected. The range changes are incremental, that is, + * numbers are added or deleted as the range appears. The start or the end, but not both, can be ommited. + */ + public class SequenceList { + protected const int COMMA = 1; + protected const int MINUS = 2; + protected const int NOT = 3; + protected const int TEXT = 4; + protected const int NUMBER = 5; + protected const int END = 6; + protected const char EOT = '\uffff'; + + private const int FIRST = 0; + private const int DIGIT = 1; + private const int OTHER = 2; + private const int DIGIT2 = 3; + private const String NOT_OTHER = "-,!0123456789"; + + protected char[] text; + protected int ptr; + protected int number; + protected String other; + + protected int low; + protected int high; + protected bool odd; + protected bool even; + protected bool inverse; + + protected SequenceList(String range) { + ptr = 0; + text = range.ToCharArray(); + } + + protected char NextChar() { + while (true) { + if (ptr >= text.Length) + return EOT; + char c = text[ptr++]; + if (c > ' ') + return c; + } + } + + protected void PutBack() { + --ptr; + if (ptr < 0) + ptr = 0; + } + + protected int Type { + get { + StringBuilder buf = new StringBuilder(); + int state = FIRST; + while (true) { + char c = NextChar(); + if (c == EOT) { + if (state == DIGIT) { + number = int.Parse(other = buf.ToString()); + return NUMBER; + } + else if (state == OTHER) { + other = buf.ToString().ToLower(System.Globalization.CultureInfo.InvariantCulture); + return TEXT; + } + return END; + } + switch (state) { + case FIRST: + switch (c) { + case '!': + return NOT; + case '-': + return MINUS; + case ',': + return COMMA; + } + buf.Append(c); + if (c >= '0' && c <= '9') + state = DIGIT; + else + state = OTHER; + break; + case DIGIT: + if (c >= '0' && c <= '9') + buf.Append(c); + else { + PutBack(); + number = int.Parse(other = buf.ToString()); + return NUMBER; + } + break; + case OTHER: + if (NOT_OTHER.IndexOf(c) < 0) + buf.Append(c); + else { + PutBack(); + other = buf.ToString().ToLower(System.Globalization.CultureInfo.InvariantCulture); + return TEXT; + } + break; + } + } + } + } + + private void OtherProc() { + if (other.Equals("odd") || other.Equals("o")) { + odd = true; + even = false; + } + else if (other.Equals("even") || other.Equals("e")) { + odd = false; + even = true; + } + } + + protected bool GetAttributes() { + low = -1; + high = -1; + odd = even = inverse = false; + int state = OTHER; + while (true) { + int type = Type; + if (type == END || type == COMMA) { + if (state == DIGIT) + high = low; + return (type == END); + } + switch (state) { + case OTHER: + switch (type) { + case NOT: + inverse = true; + break; + case MINUS: + state = DIGIT2; + break; + default: + if (type == NUMBER) { + low = number; + state = DIGIT; + } + else + OtherProc(); + break; + } + break; + case DIGIT: + switch (type) { + case NOT: + inverse = true; + state = OTHER; + high = low; + break; + case MINUS: + state = DIGIT2; + break; + default: + high = low; + state = OTHER; + OtherProc(); + break; + } + break; + case DIGIT2: + switch (type) { + case NOT: + inverse = true; + state = OTHER; + break; + case MINUS: + break; + case NUMBER: + high = number; + state = OTHER; + break; + default: + state = OTHER; + OtherProc(); + break; + } + break; + } + } + } + + /** + * Generates a list of numbers from a string. + * @param ranges the comma separated ranges + * @param maxNumber the maximum number in the range + * @return a list with the numbers as Integer + */ + public static ArrayList Expand(String ranges, int maxNumber) { + SequenceList parse = new SequenceList(ranges); + ArrayList list = new ArrayList(); + bool sair = false; + while (!sair) { + sair = parse.GetAttributes(); + if (parse.low == -1 && parse.high == -1 && !parse.even && !parse.odd) + continue; + if (parse.low < 1) + parse.low = 1; + if (parse.high < 1 || parse.high > maxNumber) + parse.high = maxNumber; + if (parse.low > maxNumber) + parse.low = maxNumber; + + //System.out.Println("low="+parse.low+",high="+parse.high+",odd="+parse.odd+",even="+parse.even+",inverse="+parse.inverse); + int inc = 1; + if (parse.inverse) { + if (parse.low > parse.high) { + int t = parse.low; + parse.low = parse.high; + parse.high = t; + } + for (ListIterator it = new ListIterator(list); it.HasNext();) { + int n = (int)it.Next(); + if (parse.even && (n & 1) == 1) + continue; + if (parse.odd && (n & 1) == 0) + continue; + if (n >= parse.low && n <= parse.high) + it.Remove(); + } + } + else { + if (parse.low > parse.high) { + inc = -1; + if (parse.odd || parse.even) { + --inc; + if (parse.even) + parse.low &= ~1; + else + parse.low -= ((parse.low & 1) == 1 ? 0 : 1); + } + for (int k = parse.low; k >= parse.high; k += inc) { + list.Add(k); + } + } + else { + if (parse.odd || parse.even) { + ++inc; + if (parse.odd) + parse.low |= 1; + else + parse.low += ((parse.low & 1) == 1 ? 1 : 0); + } + for (int k = parse.low; k <= parse.high; k += inc) + list.Add(k); + } + } + } + return list; + } + } +} diff --git a/iTechSharp/iTextSharp/text/pdf/ShadingColor.cs b/iTechSharp/iTextSharp/text/pdf/ShadingColor.cs new file mode 100644 index 0000000..3a4d7c3 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/ShadingColor.cs @@ -0,0 +1,78 @@ +using System; + +/* + * Copyright 2002 Paulo Soares + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + + /** Implements a shading pattern as a Color. + * + * @author Paulo Soares (psoares@consiste.pt) + */ + public class ShadingColor : ExtendedColor { + + PdfShadingPattern shadingPattern; + + public ShadingColor(PdfShadingPattern shadingPattern) : base(TYPE_SHADING, .5f, .5f, .5f) { + this.shadingPattern = shadingPattern; + } + + public PdfShadingPattern PdfShadingPattern { + get { + return shadingPattern; + } + } + + public override bool Equals(Object obj) { + return this == obj; + } + + public override int GetHashCode() { + return shadingPattern.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/iTechSharp/iTextSharp/text/pdf/SimpleBookmark.cs b/iTechSharp/iTextSharp/text/pdf/SimpleBookmark.cs new file mode 100644 index 0000000..c7c5a50 --- /dev/null +++ b/iTechSharp/iTextSharp/text/pdf/SimpleBookmark.cs @@ -0,0 +1,799 @@ +using System; +using System.IO; +using System.Collections; +using System.Text; +using System.util; +using iTextSharp.text.xml.simpleparser; + +/* + * Copyright 2003 by Paulo Soares. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'iText, a free JAVA-PDF library'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * http://www.lowagie.com/iText/ + */ + +namespace iTextSharp.text.pdf { + /** + * Bookmark processing in a simple way. It has some limitations, mainly the only + * action types supported are GoTo, GoToR, URI and Launch. + *

    + * The list structure is composed by a number of Hashtable, keyed by strings, one Hashtable + * for each bookmark. + * The element values are all strings with the exception of the key "Kids" that has + * another list for the child bookmarks. + *

    + * All the bookmarks have a "Title" with the + * bookmark title and optionally a "Style" that can be "bold", "italic" or a + * combination of both. They can also have a "Color" key with a value of three + * floats separated by spaces. The key "Open" can have the values "true" or "false" and + * signals the open status of the children. It's "true" by default. + *

    + * The actions and the parameters can be: + *

  • K33L~IXN)aX* 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 FE> z*#NAW3KZTsDk*+Xd<^ft16A}!v;qDi^r0T~EyCD{g9$Y-JZuBWq_7LQC64(@q12t{ z`2@#taHfq-`A_}nA(_p?DRA3FO6&%_3580{U@_6J{AmV95nB+57hscMW*kkDJ0`F& z&ISY{?O4-apf4Ri9q@dE>X;Qy^uU9M7o1cK(Jn=o<^4AqPFx6NA2EIUv6Gl2hNB28 zD(NM0h+v|^IQqp683u;Iy8OXb>nVoP@_dWHd{;BYj)0&rdduPPg|Skoj0FnoQ<^@I+sqAsgUKCiWTRrD}bXNeE2kBUevBpc^#8Lt<-xvgDyL zGd7$MU4_-yTHiezuJX!!ATb4V^W};oKd-EJT=Z6#fo|j4t~X& z7|Z1{wo%x>A2BI`u*)F*BxsvM>r8LRz`K%oF%qOzH+(iV;h!N9dD$=gDQ^SfZS`EH zdypie(?+c%Fp#4e2Pp6;*C44uBSYS!{nI^CI$m^`csvZkrsP#Lno@z1MD<#lGpZMi z8Z*7wakPPZRh=9?nGZ5p%1BTRvd5-R5+SEtOdD<07+wiCovoemj@D~iJK~*<*9D$h zTH6|rb@aKdcHZ$P9?!V!Tv47!b+81wWZ^j(%YL`jU*J_%M#jfXkL9h+z*b)11 zB93A^fNp_I>+WrBu|kbW+neKky{&kIxaImT8#)nhYVT_7z22ONH^!RV+wps>>u6W^ z@h-A%yujByJMrdmXJcP8zK76woeKfi(cOKt@knc9ivj4-3Ev9QsZtbLF3Ecs#3AIk z&fv^h(TmDV~5kYgQ1^`jyT!~`xcHAUayFwECa*tZDtmXT7j|ngfsWh zG3*d9pJvc-CYKvYNJAti#5wQq8n8SF7lWQP4j>>|FuQU6VR9-P&p^ziB$Sj;eXX1|V$vk#T%qlmeO(i8{l@#p2W6Or z?m);stdwpO<;IFq5~{?T(GrwCL#{}kRIXo;{b`nE@PpF>X>2-D<>-{|NSwyI@g!pa z*~gCXWLE$u)2m>{ZiU+>%cdi;5X0RRJU3jx$qXe(|9Co+j63qs7RA+KN-SL}Xfntn zeYs7{RpCet2}d9ea$!M&o!mTLjl%I&mri9yid9g+QRMgxiViA!B0y#wAHxWbP1&>( zrQvvvo?5tgD8S{qMOLI{q)kmkAP3*!&t%kV4Y;^nv9|T%=HcaNlkb zUet5k@Q=%ZM2$FtX_2z87E=Ju5XCOe5CyZ5R+Mc5uOu$Q65|a7#CmtanHjPl&gGKI zo)os^1k(kjSbf=ee>rAT_*J;#<(Ear!K0SED#!H7D;ngY3%s`&3~qHkaA4oT zBt%m^1ZmgxrXRKhmpkl9hBv}s6$1s0KR7S?`%SSQe8r_QxOIe}-wclrLJ)%8Ve{d* zX;ByU_=U4_U}O-+BYzi-S0-L*As3)KpT6hIf6NEgDhLMjuDTBpaW)b{ry$(989nKH}J~VgtTyHws@l~8g zI6|Njn4cx0n^=OeF$7p4(*DXqwHnGDPD(6!;IzhT3$R^fk|qVJU=(O`selw{F_bp0 zkuqmS_2dSHEmvi-EHduQvp$XDO&<&aPHFInw4F-jGe!?3REgxAnK5!g8ZPpKXW)f) z&=q+Q4+CM(U{@)$v$gL?cZ-1zKMaC4_caLID{zlM9L@uNw-G%XGtEa@n~yf=&tCo6 zqd&OEIo^E~Aciq*?2L0HPQ<%fVHAitaU$N@+uPM0NYL902Ng_+#=b_z$pg(77j8P% z=7nj&w|95hXPhe+aS4-F0(g~`){Z_EGcEwz6{`&JH-B)W!@!t~HGcRsoW=F>1Gp%D z9M{W}*P&1#=*iDyJqXKGs-VU|DGJInF^Y?DOR-WpaJVBH#$+R=jDdo}?wqHQ!FjUi z7wPFaW&+V=5$)Y^kf047Ke>{{S#Vfx!6N1jAy!OL5xSdiagk)DwHr?t zYXEm?op0RZ4Q_8)AYr#Iu&;JIc}Br+9VzfMxfj31AjhpNQUf%dn(%>ZTC9*@ZcY_0 ztLz(56-x!3CnalzxElZ5pYfMol)jMlDn4cLBPz5E#Z*GyKnr}6p?npfV&AUb^Z~bU zs&1um?+4u*3uV=nRfThW$Kds?mqmjRiQ2PO?zLe^?r4xm5#&V4t#Ax*@z{|bObtv8 zKw!r}F>X_FUJqlct7+z`8TFBC!7>PaaNFo<2GxO0G;U@8!I^b}!Gy>sU?x~Og1hXf zEqEzvQ7swG&1E<)d845z&IGTF1Uw7wK@!oz6yZCXn6$Q#Saf|9$Z*$kVqtD#j?lQ0 zl*Bq6goAR}lSZL*!@#UFJXL_2ai2G25e$;p7$vzN>h))j{_NGC2L0KmKbPvye*HNh zB{)tdHKm+`+*g6!i*l`BNjAUfJW@_I$9iL8$@5q#wJu1+A31w~%d0u)>gvEAyK|Yy zI;N?;F9s1Bx0=rWLTk15Hg?3Q*AByfudyx_*FVT2S$kW1;(Ozl8vLF>pnkW8>g(h6 zdk;|2VL;&8a%MY;%uy(aa`T^Dyf;(@gVERVRO?=I2{-tBAwvycFpMyarY47$jkTIC zie0$`9j_Ih=xA@kPJ}E7&EXU6Jvab~c zqG-d-QCbG>%{r|Inq(hKo-l}Vv`HT9tD{3m<*QY-lsNt46Y$TvQ5U1_w7}9T2O+|- z8qDV4ib<)HmScPZ@5uGRa|VA5)Vnp_ML@%q8+Ar86#Ir@J6Ukqi3?t%&4$3v&uytjZ{q;Zlje#y$As$0fbdJBEWKRW6<)N9w zcn?Q*&0GL{z>R4kC`>?&^m1#CaSUxZ5No;1mco?K=MEKJE6xNSr_VkN88Gr%6$g%7T{1aE*H zefE*`!A{e!Y~_Xel)ymPnD_tI6LXFM%DM>V05MQ zdjbagwk9Xv%7OL7?G5b9;2v%!(CLd&r|82*5kq=0D?V~<>Z0g4rlxy#MrV3l{146Z%lU4>Y*iZbwCK+;y4L1?luUJAw{7zz87 zJEr{Hjy~#k8y@YYkqN9|KtHHM@2F1MU7K=95j}=;9{Wc4QWD>1^ON&X7(|nwfaewc zSKU+aI?6SUAUWuTvSF8jr0~E%H^OHDNyuY&rt+Erc~u%WfyoN}R3dLfqp(sExbRBu zF!p`Du$XfgF$e_M-$DZd88@6^(^thI@o|Tmy%mn={mQ0TR`Tu*r>izGw)*0R3@2TQZe_69{|va(xyRxxqoxbXG$c%dz1+yV?(3E?dbq zrOD~XH298_d}aqEq8Nb7CUEbEV^*KG_MLF$O+B+mX2pmI?@K-2<%LD>B!%ghE474W z?3vu8duY{@`IuU0JJa2!G07fugh8dpPSrf?1!v(OP3tjB${ zq`^TCj2Qy(5a@L<%#5nLIdViUejhz%Abgv(0DboI1H=1n(Ve{sy7E_gMPDNv%95f0^K*#{v` z51;^eQ?=C;Ba`rjusYS;xC%h}Bd_H;TSpgix5!SYhz3ZOEa!Xq5kR9>x<8P8Io?dE zQ(sIGdC+MCC!-igwiYxTD#9hgQ%qvbV0n-2gt1(thlL~!BjC^E?9HDd`H!TbMsOsuwIIebRQ<9NA8`%*cA5hS}=;RCaj7G2O}!y37L z&_8855qMjdR*83D*P2IoMNow}{6PFfQ4*?GBpoEC?v)!H>`6fWZcE zKA%pe?1XXri4`DTUnx$3quE|=F9(jZqP>>x+y}E+?NKKi;nA`?OXXo`>e-hCRn7LD_PSU5r#OpHEFYbv%Ni-8c~9)IV}-hjqkp=M&zW1BI;wF_7EtwItFRFU|~D zdzj-2sRm}lz7Tf~Dz60PWq?(%EZcrrBiql#qCM;&Y!B^qIJ#}n|>O{DR$>k)k9I>Sa`S)@Px z_7R6TWOpSqAR9ZJqB+bu*%q=MbZC1ro%Mq=`+(gQ5<_Y)y3 zxqhNk8sFn_PHCWmPU#8wWKBPGUIzbLZ(|XUNgGzmRPp7(@}q}yc+6xo21@f(f%|C! zz!d>ki>!Ab0LVW45P`B-U`?yy(Bi@Kw4o@0b#0sA!hwt?MS>k={RVni47SOuv{5EW zNvrYU$0qJ)!Jsv#xOt~GEHD^!&w91T+T{`ee1^qW<}L!WnMWHdBfL|hl~H|ptljAz zt&D1hQpZv6$_RVjvND3orXtdsCGJXOo&d;Az&N7$nVG`p4`690n-PXpS6QT-A+AJ2 zGGo(l91I4kS4P7t=5FQoBb#%h*W#N^@bmk)!{ceV^FeripV2gT#E=LF&>_WqtnENc zIsx+!UzZ#x!0ClsZ-=;T;3rcY7=%oq8{jxT$oBE(g-HnoI*0>-G}BlgqWbxn#K4e> z8Yi%FmO)`I2K15uIr=JJS(Hm=Alt~DQeGZh$+ZT~b%~T}mro3!0vC(31x;|B;teL7 zjhD8P-Ebu;7x3Q8OuoU&tf)Kh1ag3Etm;@_8}1*@58)M`Y_WSBLKa7XhM;epx!8%gI~Zd@OEO!E<-M6~{*Pdr@5wv=G(>zO}_;mD0^4iGtdvY>0*g`d8db zGQr_UL9Q5cABpg*>h9;;2bkC%Gf<&(Y3nH@(LA}axFaSbIUK~ZJup+CBduOK2J;&( zg>LBGLGZg@5%5q>JQOEOO8ZW$y}ySCwdjWev5=7~P}I>xQ`WS1`(-r4GhGn-eh?>a z{3e&;WgUaw@(p}B_?ilQ*V8gJM>Utlkde7E;OnaM1}9g@$BB$zm2z7XU6yF2UUDED z3HL{it?q#HTp3laui!x}ob}5W@No<-VQdO@%vyvTcSAjr0E7;FV*@+@nV5l{62$Vc z1GYN9!VyT}P>gQRrkD}D4^N*nlR;iA6HF^MwsG*mzF&u5+*<8EaM?}`(mfa)W1Qyc zl)ZF1G=-xWD8NZ@40k-pPx!;>s$G`}tTo2Dy^yND6xq`eo)RRx2f`0Ty zM+8I*Ze2-d3Rm7%U%&t0?%i$8J1^aT@Y0Xub+wRFrcjLc-{X6SX@f3)w)1Zf6CHs>cTsl_VkSBEOj6LHMZ)dZZp4^yeS3v+( zath|6{Ss~KB0pD zQtubS(K6_IhiiuZ$&CgEPE|YFWaR~?pW(U2+$fGCP1@-Q{mt(vw7^$!N)L!*^7!G{ z6r8c3$$)=l2zM>T(Iw_1pXfuNVWJmbi+Cqm0zHW&kBfOo`)sdQ#G739J}vRHL5b^! z0@RTPc{uFX>qWwU;I8QBw1>iDLMK6o^@x>}*NM-h^3}{%*_F}bWXkYLW{UxhSVA*I z2mEdF`W8g49FoRq0eDJim(mqToXSHiTX<;?5s-W^$lc}hC8|`UYL4##X9FS&)v45x zrU>WZ#+bwuj*<-XeS45gMGeGBYz(Rm(?2%e4=Yp`V|WB>sR_+l2yca?C;y-rDHT13 z)F|+TKC0n#$gKNKO^80ciB9z^zv#xHD+l6n zEL^cLof73)k98)`!Go7tcti?Py4p=?SN6x_yR{T3d2p37Nujd92A~?^aa^T}$cngI*Mx++!L zisdK-7D6~`;r#eOK3B*M7VDb1Ccu~52lBJOX4FPqxevsLLym0x>#vT)fccyUC${C+3$Vu2e%c=5pOx6;1(6i4ssleY3;pU zva+JM;1UI*RI<3%JA;iCmE%|j)*?`K9-U;gq5qS(OwdtQ7z2DuYXc?^f5bo`@jxig z7IMWSAC|^$iHA=KE5~y7#&r9EwP?kbQ~|DcrO0XHGAan}_!tq3&f=g0JNnPsIkUsN^1>)J~k{5=|g!~>l9K2rP$|R-Gp)2>q-D#L=j39%R z9`J5yfTeJ#T|caz9;-W{HvmjsStsqYc3BmEa+f?HdmSi><7bDitdH|hFjVYwqz@K- zD0St&c${)}KlZip4U~Ndj`EsaOv%iY_w^f}sNM&>pR)_jtbC5QY%4v|+;thrQ*{oD4UHM4x0JapnTw;-hWDL)x+mDqyzb@a&Ab9$)+^ zT^KYBrl9LpH&j`g>*wLv$Q-ske8al5ki7?3NNe^~8t>?d6PKf4RT|v?visPY#pj*J zQ)TttaGp|>?QTHknKN8kS=+vIXQ*#z zsAwRUb2Hbm_dvBAd(M%geowU=d#lvjaL!V8SIM!j3hvT#l>+mtl)?7xK8XHS;>s;o zrrUe2k`GoXv$YHBSO(jO~9IKhgz%X7w(J;h6HfveN~XKdXVQ_~K2c&BMFd(D1h7H>B=kcGpk zDeSL~njOX*J%KHZG1HCXs&J4Cj0I9$W-c?gnce0Nv)yDQ*D1hmq{PeRz};r*5w}DB znf-lc82H+fI%gy36n?SXL>pKRPFdr( z6&N0=okG1uv^OWE;5B;0VP^=rnCcXMGbks;GLQRDEO%Vmq;04*LzV*AtwqR{!IoVL zN{yIH5Xwo+?m&1a`Wm{t2en|I8a0s~aPt8U;+JiJ>cKB=j6;3c=#kQyK8+j&WAugSrRQ=@kUR})ia@lVITG+iw?g%nPp1TCAr=7f>Yva&t_lSm#nd zR~J%^BHl!H8FN=3(vYjjiCIfarFj}@3dmb)nvnu_Gs?xDK1y_aO3u_io_kK!3B_=Z zTR2G5lJC&2xxFYcfpX2<7(yxVqB-bBKR9zM`NxgFD;K4;YuW8+)gL*t=eMD)j z=KCXKLMDQGmXpQ>w6zOqMrEGojk!SOMx8k=QsOeqls%9Y=D6!mHjtY0Z4i`n+{u}b z_t*eQeU9Y>QjDV&NrcIF1AvqtwdNrHp%weJz8kDey2&ua8gG(0Jcj%Qa|LACB=CD7 z*RB)EWwt1lNN>MJmK>CWW?%4$5-E>=F)TZpxnP9d}fy4Q4C*)QqU=sg! znj`pk8E8KWh&Rz78Ll!{Ax~Py!_2BPH-bNJG#7#D7h&GqjIwV8j+h&P6t>YOi_o?xd?KA<=LFetEDirq*T<6vJt+@m_?eo{7&LY%QW3Y3N_+bJtJUL0GTHp3HTCue#K{!}xxp|&DQ zq9#Obkt6tv;jb5ejri-pU%N3o$N@~F<3fH_Z83!Y)`|w@*nD490=E{ZwqLra}m% z?vS==sjN#%U9}x^l`-3dTeKhBfC)*PmSq&uRa@1ifEU(4^X0GEnf9~#*xw~toxx3uW@nAZ$obz4t>=FsU zRK`miln0^6QHB*U2R@%%RKhvnn`Y*?q9n(2m*JPW znY_3E`Pc5}bori7oBdo;-zq2B$3P{@Vrs!WIdYfNqMfD@`iFK-4wRyla5SV1gX2=* zKWKw%Vvr7F_?PjdUwN6dgK7Iv&r_x~Ld(VQOFk~QzER>LT$+HgJkD-+A*ahVzS2^u z$ILw-I=LR2dr!c^-edN`0yo>bq#gYz-ATTLSoh?yfPHg=qXFj>XAx~vT2(j=3~R(+ zd6e77K6i1pagO7ZHFDuaR`f~MBsH{0289yfzWtp-6|OQIby-F&>LSfabhlWnK2LsICI(*bTpqVvsJcjO1s z(OI-k?w4u(E+7vtjEIhP07_QC4mtDV@aZlvYwUHC4$$uMV{a|C~jjEJ1dmT~|`a73D4R+rr$s zK4OkaKaAhPU>VMmEX}Rb968{nQdVYfX%Aa=Eu#)~4dtgw4cGUQmLCk(%5ZreQh+&v z8s-jzHk9N%CNrS4wi$C?US6mFj5qbrg1yj8<#kf4Rnn?OxRq8;(CbptLpwI)OZ88x zudf#VTi>=RudN;ynAB(6`iJGVZLQMJCbXA2hvUokRMM7ux3Zt*-e1y|mVbcHtJGEt zS*|NIwFmp3CsqCNV91qGQd=3PF@BGy0y@N*#;GB4 z@DS2bZ&L+v_HHlXOtpQSW}nGU^0m8}enq9h;FhA7qj+i%6^II*`YfOUTu4wOar#kA za7xx%^Q9Z{)wU9L+4y#(t#n61g^PU|s^+sW zDx5n6uI&NmV)pf|-y7XxU~gFyd!nsVcN$5}RyZRsNEaPA>r%dof}k302C9l8_K7tQ zBUTn1H@V*XrLr&Qrhwne%KrPb0R=qTIYA?&#>xF^t3rH=O0@i_SYoLepBsbi>t z8#d3i%~GvRx&+nH338cYd^?loFrQ4L>mf&gv{eJ(59r%e<;)vEDRfghdEryy`Sy)% zvpaJ2n)(edE8zO+>;ixZGv>Tssf=US!i3d$n# zFD1CjZZ1a+uFRU0JT&jLl%UZ=)xz1^DCXa|jGr@${JDhFSru({lwmu`W!%c4ZsBZD z9>`Ttg7Tv%qeGqW{L6F_y_6U33BYd~qI+(NQiH}psdb*Q@7%=DRRw0gc3mroj3bFTLJ|ax&rSwfwJaJUjyHoMhH*=W279(}bLMTz=KM z@wXZ%7j$v>TusuUc1`*)n^c{aG?qwB&Nlj1N_`=vXAr74*qt}2-sC@&mZc4U%kyn` zyKFuGzuv%oWFp;|=5d!=$Y^f*_*M=l6h#;(p=u*Iziwr($|s%AY>uERjVYU{JDr88 zwvKWEr}4Sj-EqL5{c%kB{G0TLG3Nah$`<8uzY0zHzNG zY&yeK*EydFc6xQ~9{G0Pn)1+w_b(jY~6_T8>U53J^75T`8Ks4e7ZY zS0$kwL>(q4I&nGgbGc}AA?qAJ6eKG3gQWM*O~NfQ{hD?($C+-<1XGE_`Kd?r+!{)a z79M}Zg|uQxlAu9z&zUFMIVx6`NpF<%SGetK?P4`gQ|PV}LME;ygInNkt*C08lCgT- z$_Uz4rlQG7$vtyR)b!D|fGB6ybM%AWbDh~rOKRD2t4!maKx3tvHt2k*71h_?4N`B|0pNoL<=2HTxL7|rs1NT>lTsQF+6%o(RW+<_Bxd07U$a~S39?nb4RIC zgn|U1}yg*-J+WdBrdopMJPeE2VA|d zMgClOy>m`Oa{<*oxnNA@vZwer)MDp17{gOvN!jn^IWO$_iX&15qAS&LOXUtx(5R@s z6X)Ct8?X>14V{CAiNAXLG&@6Rr=|aD0(P3}fJA0$&AIO_p zin+i|OO=w&t~Sfv*z2iyTlbd6l6L9LpaVt?BIO`c6KuVi#XWR0{W2|(Y%_}C(cNJ^ z(&OxCb|bjC6I2cicc6>vaXW&PKAV*@Az}qTi#cd{hgpP1slEkG_Rb+u4X^|7}aQO{TnwupIYfJ;x^$Q zT>2UxDTp+Wps$|s1>f3B?L%K@NvNrlI2VbO?v@wvLVuT0Uee;SYQA_D2UCFj1 zV|67HRC?uo(zyism24rC?#xd?IP=D=-CD&b37kdw#|X?iW4z;Ylr6ZB6Ea2>FunXV zx~RB(dxaK^e?XoFp_|vLmM+ENy?x-!OTkqp-GiL;y;pxthJB!tp-(V}G@L6Mb_c}N zUrm1{&57V^I9KA?uPd~woJ+lZqek+hE6>?>s@hne&IZ~?>i_bMW~U6?D+T5DA?>>0 znpo$M@1r;Kow~shg#!CZ9`|vzP?~HR`>c*19!jTbV!I}6i(HFo#ExTp7^k)!<;%=Q zKB#}J)EDS`k2PP=$>nU@psnf~&_Poyba)#Hx%VPv3^H zAL}R{n(LITS=@=fk&9jL`Pz$em6_iQI?x2k!PiS};*m~L$Q*rst+))!8cM4zXh~&j zbo4`2UxBE_3lL?mK&;g{O0&39zL`ZdgtV=6wwY~?%Y5_D?E+}M)-+hEoD)M{%`u8s zMrO_%95-9S^qcrz15JF2NwNs1o&R1JS=;wM)81k69CUZE%uOXaVM?dCP76)%n6a93 zSgkphsDglmAd$d`mzOf4>zb>dOD})=l}=($r>(bLL0)44Z z_kGSv++H+vK**xRW0Pj`IH?XNuLoZsb9`+s)(-e`K$p=~IcA4X3Z2tV8aXMUhAK$7 zk1eF0biCwC8^=>s_+raUxk~tNzRnBI5_3(E(rT}jN}C}4n$ad*Tu{PuYof|ab|dXb zL)tzc2lO9Vmv=n3I-juD{=Pn$?s<-LO^~+O%eV+J0! zCAH!XMO%)!_R5ZH>LO93EZSC1N+e6PL)cPmOY)CIhC)eei!CL}BxTw0`LN5%I2)Is zZfjqiT-Yq9N{-C&kCB~tie zwM5O&wQHFKrbdKmKYNblRxukoko2)!o3?^A&H~RkttP@H^O0^MU1~~!d~`3YARUuz zU@&bVy(MQuyXd96v>~;v+y<wNwqAHlVM@1p zEu~1(Yj<2l{()`AFsD0-4kb9V_y#aGzh(OaG*=KH;-y3u^?*ngXjxN{m|xApKNKiJ zx9uNFhLM7kf{-{GiFyqm2x`F8IBMR&^fA?3_(bDZJb*z~YdZ$xl zBEMXk4lt)bJy<3XUvpM$HO(}Kyw?ZlF?~G3q2%FiII&_-+ z^hUK5$8Kc*;M412DZLZL*cO4gPp_{;Isd{wLkT(J$Eytp{F5S-H}3Fu;AB69jlCZs z-o^1Ac8>0Hd)y{C+lyvD+RC#<}K?Oxi^-9z-c7w1po zxSOk8K)jpdJ+2rdEvt7iU>QTB+p4n_7)4W++Y z?fh}O?2u)bOi@YwB=*L;%UVe%@3!eqyWWyLZ|3IfxmF9q zJ>wME(*$T0zE^#ijWA^bhqt=hweueAhA|6O;=Zk%7%8OQrtW?Or<83HZcayQLg`&^ z$Bk{TT1SN*hdF9={<_3wo4rooV4|>#?4Cc+Z6o=eUjDq%?p)j3rCnmDsWS`{i#lpy z7!~Vk+|*rTH}@yoev{ti(JuAX<$OMCJ#91bLYJDEeNg-q_I;SvyM288$@`XTJ8e~) z%*{tg-Vz|gBoimGShmFne^HC(nMx@u++#r>-aGt@+THp|M(lj%yFW?I-40h4AQVpz z!%yJr#*fB_D>L@dWvoNfrcV)?tWJ!H$L z?WFK1o^uZ@pwNRL*PZqz^NqT;cv2eGNrHb#NWt)Tg5dpOFk=Ar7M;{lC8ZM!W4!ivTBnRL1@p*TBJq`u@-nw zc|gGs3)_273uaM3laTB}Ww!mf%qSI?OZK!R%NdG+$j!0^N`oL9-O_zM!=Qc?eG(;j z*VcG~+Y~arWh1-w#Ae%B%6BjPvl!9HLb~+9DDl=(*yJfBL4H9e9+LAYS+lhEPDMK#rFbxXwZs=ZC!6A8gB^VM))t%+J`MM4xi@%Ef{8q+*L zdsbaWZZRe#*Xi0xiZ#83P;uN*JZzx9TkD_4owiayWBOyYH0oMP^bx--q`)bzu+yOq4Hg3DHXhOJ`?>-jQ50UP7(lgGTzsFylJV~m& z9K}gLs>cb3{bY-pcfF+7B>N~ZrZIY3NAg%d>c*Vp+8YpN6#dHL(z|AH*#ygayQMUi zbZLrv?`C0JtKq_)`c~M-?4HqH{KfVUb`fSVoM~abT1a%1&GaNcf=fJ;hNQe}pXs)aXxWM?wv{Gs%=6J`! z7b$B_nOPdWnS&SRJJ?k+9k;ZxX?=}Pa}@PsT7=;Jz+G+I+cmOv6R!W%)+KaH)`h$Q zjcSJQ+U@*}A%X4{dQK?cA~$0^v`1>26IB$p#C5-ffHPOuIVb7SVRoqPmG( zd7oQcZz*)0vg?vX!K_BqVvhM2aLeZ=7?au6<@86geMnw~ceiY8_QB4C<25eL&uzvp zY?>Ccjg!f?Nwer}FK-FPmWMFwd3qZ)a`h>Bwz&9We?+@wbce@CJ2IIqoyvcves@4MqiN4~;I-!|X_Kr|hwiE~%{iA*VI- zFS4Ajn1R-|xjT@}?|3~2mdjo0O>}QUFuy|jqK+Rif={)@aYkZqy{ly-6FVSG*b?k= z-jTw$&O5rT+Yib<2atWc+x@hhZZbl~3u@mhs7LLNPqvtM`dr3BSYg6?<^C;c1rS*)A=H;;X>ZZPYW%;T2sL6ZgB14T@qnEjK)%cDtcY$`RfH+m4< zr`Uak9Sagv77h*AO_D*J7_!u=#H~ zKaroacy?m5;k1l=uB7ioLx0kq^+v=i_o=(|cA%S6vJ||MW?upIc$La>GqG{F_)hRG zen`19i_`4P5<0j&MzW!cXTB*Fq_3?#t(bc266~cV7Pa}2&uDMNvS@=t;+w1-R=@Mc z!Yo9I51#OPGV;Xx2I8@9iB9ODF{f{9?3OcXZ8cu)mRiZAAU*=8C38AysW~)DXSR7; z*85DgPFl|*O4)kuRTSI1;Z#leHx`jjVik`%%Ph^DYBsme?PJwe+sVjW?OP_u$@+j_ zL4(Qq?#odBPN&su{{|Rp{-b2un;biti-ZVAxV8zAnq52y<)xk5yK%ClNNNj6P0yBV zBa31!%ex;&xKUvoE1$NnHFKL{H4xTM4D`|tyZL7&KrbCQSZo8`-Toq=w=O?0)7Xn^ zN;>5Gy5YJlrCGYB$dK;V`(fp)%gzhg!(H*hBmyE0-d%1Nh?bvfF&1$znr>h@o=N9h z>LG~;3dTgIWUYL{KsKXF{bFy|e&=(F?=?1QtHYW3(u&&fKJcEZ{@!DMIez9}{op@- z_uC)-OE3Dt*AG5$&6c;G4+r9Pe%!ni6r)_R8s$Acd0$DOB&S4~`GS%nNulohaVbw) zDb@o{gRq{{p^~e6m3-Z+Zcvfx1}-BNiwfkmzEMl?ag{@7hKf9&o&XLp`+ciyr) zZ@G(i?BX3-3e*yb7q52!kkZb(R^Z*dN4`pwDOy%0LsDVE8B_#dtq?`rAYX9$WJQ)0 zl*`qPjD17C2w*|6k}FcJs0PS*r&Jt>M}tcH@?CDO4~l{Azev(LujI*~Sf+668%my2 zwYPFZ;9>||a1s?bVdSI?S?ABW^S5034kZGLGB6c*Hy?3IURik#kjr%1%Xf`NILN@` z=4B18SEsEf-Edn^Qd{|?y*edB1us#rkI@YV#Zu_y;l@ zy;BtBLNI=f>XoKNG9AtH^cVx^(msLh$;(;C&xu_!XfJ9?JLNQQLX)(6b zK7+7E098CEV9>Y(B}DM*m@*|?es#M}Bgj|`>)t?h$`3eSrOXj`e?+H4?vxZPyzVqd z^YsFZRe_V7a&%x`s#GEe05o+RatZkUuvd`k?0a$Z`(J8K!N% zNKyi(HIOwfai{sBq)Pv-^RSq1s{tR%G1S)~A5C+juT&p zDE;Epc+%vg-*a*z+`?zRQ-NHd3{4x_$vRXu(8_qLSkBG@G98J~91%^5SS8B26X<6* zjefL4wrknluN7!U1(BHdo#b%QTQ4M8upc}qtr}E<_&7WR(*QiD8vF6Q=f#h6N{7ND z5ZK{3MB?gryuJii#;4S)$j6Yxrc&_k#!h7+562@6t}CUJr^r2TXmF>ZIOWP^wJP}w zl2T{WQfCFeiY50hr1vhMd;G|axZPF-|HW|+7STF9mli*lnVveMoZ)^Da9moq%3~V^LMDNcJ%*kOTqj6vVB* zh>w@|YdS)M0v|D&-NE*9NBTydl^;dD$|%$#cbhD3&i^c1k-^49}9?gFYxQ;GyYlDisqz1PL8jW4eZBcXJnf|J+ZAx~i=Pv<2 zw2WJC1jW3L_b6$So0np!6{8Y!3=WYp5N5gOAg3lz4U7oYHPB%90@M|)S6gRLXW;D( zyax1D`z%_8BDc&4N4rwT*KtK6U8)Af<$*)CT7dy`eMahTl4Ih9Y>Ovl*MWn(J0j$^ zbr02Wo_tA)!T)_^A5>ObFPJaH31x%`mx+TaU(s>{$8u+k<<21Da;+SzodLDjO3cKo z1$-4yc2LMUs^p|J8_*9%@*}{G`v)5g>7l4v7krk-HRWJsYhqfpAF_gPh+&0;{Li3s z{zD}nDEV6@|C{8hdXJh>TiHLMF1e=qntEwb5it8qE$R9<$KA7bwXq!7t2vIO%z2z$BE>fL|4Qw~B1oMILIUjCosfad=|$*W4pd)>SM zBPc~gQ$}3$WZ_C^ABgIX^2|$-ymp;9IeJ6z?N)Nkc;E%84O##|ja(=bxj4uK>4-;? zb4QmU&%%{1C@m@V@y&7HOC$vtIVjaiCF=S$PIOxhi$TjK^5p=}T$f-OtCnYyMx(8B z4xZ*;Hec0ycJfWnd(rdIt|VOFzi;O#2nPSY_oHL4{p-KJdg8bL^xvJk#sBNSxc0*8 ze{tp~-}>QKxBSs9FMa3b`S<_mr!U-g^@(qe{OBh`JGNbZW#q)m7yg<5XXC%~?UCPj z^M`MK?{~g)_-8-(H$VQ{yMO+l{m=cU|90y$Pv3FrhZAGh{{HV@cP>6X_wDx@r>4i^ zoI6u1_<^p#TmwIG2TQ^au-;cta4E~Ej z^9MdJioK)p*whLAQhfdN)cmpf6QjdhhewBRtFN66Mt!z%eCCP9(fZVh`egmlQ}d^08}%m|vvX53 zC)D2ju||D*>hSF3>{G*ae%rggb9%lpdxD>MA3t$q=BQwpJaKes?t!_<#~L&`H_tB^ z6QcWq?`=Kx$*Y4$oF1XHH_xnBQ(r7JI1b=b5J}*K^RmmAHqh;N0}+CtQYd>Fama&&~xokYMS8Esc$ zPvkBnKAe1kNvH1xU)XM!+w5{%`;vq1uHzW{yp^~y-8eEoGrNCw@<_wA7q=b(R`Ak3 zOlow5PqqPbb*#dmt7Ad+_UaglhbRljFz0d*eY`#!Q)^0UCdZiZ2jw2-V0>BuuZV^4 znyW-Pkim?R-g4FLx5j#)Zlt>gCzEir#@s z%M_o+!oEUkr_&-8Q&nV&fDoPnb_b_Y94%pMeOIJ*)&=$U$AG}$Pas8nK!yows`L3;2?FTG&XgA|W+0F|=dZ?3V7riaO93b85+H6qJ3h&}L<<6LCuE z=RecTrrP=sPV@$8F&bQQbBQJlI&nmU9*1e+KHrW2IqkQtieG*|}a5hFVLaLHNQHzFC< zv;4c0b8+*WJ2}t%zeinNuz#1SbC-FM$Ql2#Fas;(mMth@+C#+#rl|%8!XC`@dR$>p zZQ>rV8h{UgUQt+$Btlw?QZNduF~C)lK;k$gLv9qW_k|&K(Q1DsjR4wZtD4OCgHQ@^ zaB#3EESAA36fG8=mOmeeALQl5t@AQmSfuSTS*^dRRKry=YYKTu|3W93#ghSeWqvYJ z8w}Qjy)M*612lUc(APpL*-ikJsXoF$M|z(T-LWd;sNM3Olf z2&;yPVi6vNw+Jd!H}pYc4Tj0K(}yVAJdqxmXGPT_n1K020S%!GI2S;o>IT{r)k~qc z4x|?86J7=J%|G|ctHQjU#H~x{EYHQ{P-fM!Rj&FNI+=3SF?w&G72?)^fi-2k7*+@- z0Wc0%xe)*W{m?s&Njo#!lC3XGC|Ym2_;_8G;4>j=U$-fV0<_`6jub)&qnwnU(9WPD zsAd21Oh7sAoXRt*B3~Slpf|+fhXA}FM2f|fqX)Uyh2dYB|dl^b%E?~A-Oa=7A3lhE; zMKIF~gz7@ebJ@(h5-ot5X#Nm~^x`k=kbY8+^x>IPv-Qc7C#R>5OwQx7&ei9R&77J( zTCe{S&gPWw9oc^+=ea&Nb>avva@*(rC7fdO{NmP!E?~W&XhOW;YgQIj&~b<%w<;_3 zCdYW7-uLno^9?qZ!+d^a5NVYLkrHuHFdUA4uOek~spEd&nGpDuP_%q{MUL$h|AM~l z93|j1QAn#2T&FOfj~BRm$tiE^LJdE!ww-2Go(nJz4&ub%>S>u2ui$E_BO-l~c}>;r zsv)n5Ii+;l4RAdAp?O)eBmUb!aOQwfX{kK!_lHFBR5Tq;fJ4TVNgZhVR9&dK=~Ky_ zDHl-s{eI-E^$1tAts=T{4S94SrEC+h&YiW{J8h?}t-J|VBWl&5fC*iU=jp`@>rmwJ z<29*pLB@Z8iZE9%Irf9cfq22Db^xrIrt`V{atO+uGbj%kNIf?TTv%_zFt?O8v7ieZ zUHr;*LC6BtP8M_6g;51kZ4S$MzjuAd!4y2LKX1F32{1tqfzO4l_TSs*=dSbmuJiO) zDg&hpx~`Rab!XiN7a|xGPbK%Uu|cpZ%(ctuveV4jPBUlic5+B7$ZDq*E_5nfunNf` ztswi2erk8`uG0GFI`z+4{p66=mv@j>xY((1(JCYdIU0BeK`?k#D1Qdl>F@^{lvOk{ z(QqaHDQXoH6v~o##8nDW6>TpQ#|^GnGL;V_P0iZ4e1K93115gAB|7x9Jb)nX>tyND z)j<(QW!X&31`CI-+Iz5UD0AJG1`}JV;E*XobVJw^z!^Km82VqUMf*-6$IGS_Iy~W= zig9d^7Rv?AL3c(ty`vO*=#X63DAv^-9s9a7n?vOBN@O_z>^iHzJQZB$)20CN(( zNiJyrVCRlFJ|H2+!;(^)7b(;dE zc;R6V3oIBP=kT~&t#)1ubt3B#hZPMJFErvR(fUR#XzB$_Iy~f~W_-zT)N#LDY+PAXiDBU}Ja#YY{G} z8<4UzA*HYR#*z=yOI$`pPa#FP7K=bxwUd^1XF>3pu-~<)64p=BSa4m~kDcrj0Is^a zv?2v24G21sWv*QwSm@=-;Xw8bI9zvkGM2{ETB+NO{ae<)sB0& zPt}{M(6Rb*7S@cBxT27$qmg|!w z7px1fQAP&YZ7jK_7@pXN5{3b_&NvwSV2x!#ylNo9{Vn@BAXLpD$3jwYo!5)v(vp%A zH)&&y2!>;A$f72#4Xl#jHRs|1%{nA+8<_T>9Tr|f{P55R=!{Gkg9`?uYr|ER!D1Rx zffEkU5(1iBEjzy<9vEz2JE#VQ%F7D!yPySm#iDT5{oUH6n9hP^54Bes?sJTQ_UpZat>~| zIE_X~3QQ+xh`EG}NC~;RF}%w97ISLtgnyOgk6sT3B~CP-q82NV)z;fe-ibpZW639O zy}{jqFjk%Jk0d=R!>!6@=+khV&WV~baf!PNQ^Kv0ysIwWSMpOOAGGN?&sdvI9_Oo^Swtxg1B&ehd-KFg;3XD#NS>-PDamzRqAE z6;i?KX$3vU4F@%A{LJ-O3gn8#M7$`i%`C90SY6O47J64W_a7IRnvBX*lX?)DwamJ} z{9S}n;F&E3tXlSktC)Q|QW_L49LOS!SL^rC)3OY_3BI@_p`hj)6Yv$xrvr~^9o3H=-*Xo%{_01zAx7Igu7#($i zaRTAJz8Bg&i`dv&-|L^4IWcwQ=D9lS8)>Twf9-A@KJ}RAeZ}_&IA~ znAR%A*Qqi&d*s;E6OFmy`my=>lb_$T>GbK-!>nR7PEI$T)Enyv0XHal~A&Xs-Tz3qEdR4ZpY`F`+H=zVZHWC?Be zzSr(3TrU0b{#~y`zwzJiJp0mNZB;w+`GXx;4}y+^Gl&2FK?mzWhooWhhEE&aF3@nommp}&FQKSv1Dd%)Yr)6ja2*ZrK?E4~hK z-0R)RlQ8=H+x-9fnHF(NeA&&=IeyXICFsmie4G8CYAE>tyUb^4$DVz*z56q+*k@g> z{oK{FXLFrrz4Sz|eO}M+2UZ`Lw9no4)-P>o#Ff!2@9b|2d)mQ)cb>j|Uif8irm?4_ zd2-I}dbg)C)U*9CR`NWE-m$5D{JL+CO?;iRrN3yU_cPVmORrz1I?1~o^k%Em?r)f< zTI{KEdtTDsks}y3c}rhqSLfM*?DHVoDbsL!@*mT)06bsZ+Zn@22isFn#eOSBINI&t zT>J_^k7vx*P%pui+Dx7VO Ch4xJV literal 0 HcmV?d00001 diff --git a/Ionic/Ionic.Zip.pdb b/Ionic/Ionic.Zip.pdb new file mode 100644 index 0000000000000000000000000000000000000000..553bd4b0a22616313c9e47fe407843676dda44cd GIT binary patch literal 765440 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