| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,227 @@ | ||
| /* | ||
| This file is part of the iText (R) project. | ||
| Copyright (c) 1998-2019 iText Group NV | ||
| Authors: iText Software. | ||
| This program is free software; you can redistribute it and/or modify | ||
| it under the terms of the GNU Affero General Public License version 3 | ||
| as published by the Free Software Foundation with the addition of the | ||
| following permission added to Section 15 as permitted in Section 7(a): | ||
| FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY | ||
| ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT | ||
| OF THIRD PARTY RIGHTS | ||
| This program is distributed in the hope that it will be useful, but | ||
| WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| or FITNESS FOR A PARTICULAR PURPOSE. | ||
| See the GNU Affero General Public License for more details. | ||
| You should have received a copy of the GNU Affero General Public License | ||
| along with this program; if not, see http://www.gnu.org/licenses or write to | ||
| the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| Boston, MA, 02110-1301 USA, or download the license from the following URL: | ||
| http://itextpdf.com/terms-of-use/ | ||
| The interactive user interfaces in modified source and object code versions | ||
| of this program must display Appropriate Legal Notices, as required under | ||
| Section 5 of the GNU Affero General Public License. | ||
| In accordance with Section 7(b) of the GNU Affero General Public License, | ||
| a covered work must retain the producer line in every PDF that is created | ||
| or manipulated using iText. | ||
| You can be released from the requirements of the license by purchasing | ||
| a commercial license. Buying such a license is mandatory as soon as you | ||
| develop commercial activities involving the iText software without | ||
| disclosing the source code of your own applications. | ||
| These activities include: offering paid services to customers as an ASP, | ||
| serving PDFs on the fly in a web application, shipping iText with a closed | ||
| source product. | ||
| For more information, please contact iText Software Corp. at this | ||
| address: sales@itextpdf.com | ||
| */ | ||
| using System; | ||
| using System.IO; | ||
| using iText.Kernel; | ||
| using iText.Test; | ||
| using iText.Test.Attributes; | ||
|
|
||
| namespace iText.Kernel.Pdf { | ||
| public class PdfReaderDecodeTest : ExtendedITextTest { | ||
| public static readonly String sourceFolder = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext | ||
| .CurrentContext.TestDirectory) + "/resources/itext/kernel/pdf/PdfReaderDecodeTest/"; | ||
|
|
||
| public static readonly String destinationFolder = NUnit.Framework.TestContext.CurrentContext.TestDirectory | ||
| + "/test/itext/kernel/pdf/PdfReaderDecodeTest/"; | ||
|
|
||
| [NUnit.Framework.OneTimeSetUp] | ||
| public static void BeforeClass() { | ||
| CreateDestinationFolder(destinationFolder); | ||
| } | ||
|
|
||
| /// <exception cref="System.IO.IOException"/> | ||
| [NUnit.Framework.Test] | ||
| public virtual void NoMemoryHandlerTest() { | ||
| PdfDocument pdfDocument = new PdfDocument(new PdfWriter(new MemoryStream())); | ||
| FileStream @is = new FileStream(sourceFolder + "stream", FileMode.Open, FileAccess.Read); | ||
| byte[] b = new byte[51]; | ||
| @is.Read(b); | ||
| PdfArray array = new PdfArray(); | ||
| PdfStream stream = new PdfStream(b); | ||
| stream.Put(PdfName.Filter, array); | ||
| stream.MakeIndirect(pdfDocument); | ||
| NUnit.Framework.Assert.AreEqual(51, PdfReader.DecodeBytes(b, stream).Length); | ||
| array.Add(PdfName.Fl); | ||
| NUnit.Framework.Assert.AreEqual(40, PdfReader.DecodeBytes(b, stream).Length); | ||
| array.Add(PdfName.Fl); | ||
| NUnit.Framework.Assert.AreEqual(992, PdfReader.DecodeBytes(b, stream).Length); | ||
| array.Add(PdfName.Fl); | ||
| NUnit.Framework.Assert.AreEqual(1000000, PdfReader.DecodeBytes(b, stream).Length); | ||
| } | ||
|
|
||
| /// <exception cref="System.IO.IOException"/> | ||
| [NUnit.Framework.Test] | ||
| [LogMessage(iText.IO.LogMessageConstant.INVALID_INDIRECT_REFERENCE)] | ||
| [LogMessage(iText.IO.LogMessageConstant.XREF_ERROR)] | ||
| public virtual void DefaultMemoryHandlerTest() { | ||
| PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + "timing.pdf"), new PdfWriter(new MemoryStream | ||
| ())); | ||
| PdfStream stream = pdfDocument.GetFirstPage().GetContentStream(0); | ||
| byte[] b = stream.GetBytes(false); | ||
| PdfArray array = new PdfArray(); | ||
| stream.Put(PdfName.Filter, array); | ||
| NUnit.Framework.Assert.AreEqual(51, PdfReader.DecodeBytes(b, stream).Length); | ||
| array.Add(PdfName.Fl); | ||
| NUnit.Framework.Assert.AreEqual(40, PdfReader.DecodeBytes(b, stream).Length); | ||
| array.Add(PdfName.Fl); | ||
| NUnit.Framework.Assert.AreEqual(992, PdfReader.DecodeBytes(b, stream).Length); | ||
| array.Add(PdfName.Fl); | ||
| NUnit.Framework.Assert.AreEqual(1000000, PdfReader.DecodeBytes(b, stream).Length); | ||
| } | ||
|
|
||
| /// <exception cref="System.IO.IOException"/> | ||
| [NUnit.Framework.Test] | ||
| [LogMessage(iText.IO.LogMessageConstant.INVALID_INDIRECT_REFERENCE)] | ||
| [LogMessage(iText.IO.LogMessageConstant.XREF_ERROR)] | ||
| public virtual void CustomMemoryHandlerSingleTest() { | ||
| MemoryLimitsAwareHandler handler = new MemoryLimitsAwareHandler(); | ||
| handler.SetMaxSizeOfSingleDecompressedPdfStream(1000); | ||
| PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + "timing.pdf", new ReaderProperties( | ||
| ).SetMemoryLimitsAwareHandler(handler)), new PdfWriter(new MemoryStream())); | ||
| PdfStream stream = pdfDocument.GetFirstPage().GetContentStream(0); | ||
| byte[] b = stream.GetBytes(false); | ||
| PdfArray array = new PdfArray(); | ||
| stream.Put(PdfName.Filter, array); | ||
| NUnit.Framework.Assert.AreEqual(51, PdfReader.DecodeBytes(b, stream).Length); | ||
| array.Add(PdfName.Fl); | ||
| NUnit.Framework.Assert.AreEqual(40, PdfReader.DecodeBytes(b, stream).Length); | ||
| array.Add(PdfName.Fl); | ||
| NUnit.Framework.Assert.AreEqual(992, PdfReader.DecodeBytes(b, stream).Length); | ||
| array.Add(PdfName.Fl); | ||
| String expectedExceptionMessage = PdfException.DuringDecompressionSingleStreamOccupiedMoreMemoryThanAllowed; | ||
| String thrownExceptionMessage = null; | ||
| try { | ||
| PdfReader.DecodeBytes(b, stream); | ||
| } | ||
| catch (MemoryLimitsAwareException e) { | ||
| thrownExceptionMessage = e.Message; | ||
| } | ||
| NUnit.Framework.Assert.AreEqual(expectedExceptionMessage, thrownExceptionMessage); | ||
| } | ||
|
|
||
| /// <exception cref="System.IO.IOException"/> | ||
| [NUnit.Framework.Test] | ||
| [LogMessage(iText.IO.LogMessageConstant.INVALID_INDIRECT_REFERENCE)] | ||
| [LogMessage(iText.IO.LogMessageConstant.XREF_ERROR)] | ||
| public virtual void OneFilterCustomMemoryHandlerSingleTest() { | ||
| MemoryLimitsAwareHandler handler = new MemoryLimitsAwareHandler(); | ||
| handler.SetMaxSizeOfSingleDecompressedPdfStream(20); | ||
| PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + "timing.pdf", new ReaderProperties( | ||
| ).SetMemoryLimitsAwareHandler(handler)), new PdfWriter(new MemoryStream())); | ||
| PdfStream stream = pdfDocument.GetFirstPage().GetContentStream(0); | ||
| byte[] b = stream.GetBytes(false); | ||
| PdfArray array = new PdfArray(); | ||
| stream.Put(PdfName.Filter, array); | ||
| // Limit is reached, but the stream has no filters. Therefore we don't consider ot to be suspicious | ||
| NUnit.Framework.Assert.AreEqual(51, PdfReader.DecodeBytes(b, stream).Length); | ||
| // Limit is reached, but the stream has only one filter. Therefore we don't consider ot to be suspicious | ||
| array.Add(PdfName.Fl); | ||
| NUnit.Framework.Assert.AreEqual(40, PdfReader.DecodeBytes(b, stream).Length); | ||
| } | ||
|
|
||
| [NUnit.Framework.Test] | ||
| public virtual void DifferentFiltersEmptyTest() { | ||
| byte[] b = new byte[1000]; | ||
| PdfArray array = new PdfArray(); | ||
| array.Add(PdfName.Fl); | ||
| array.Add(PdfName.AHx); | ||
| array.Add(PdfName.A85); | ||
| array.Add(PdfName.RunLengthDecode); | ||
| PdfStream stream = new PdfStream(b); | ||
| stream.Put(PdfName.Filter, array); | ||
| NUnit.Framework.Assert.AreEqual(0, PdfReader.DecodeBytes(b, stream).Length); | ||
| } | ||
|
|
||
| /// <exception cref="System.IO.IOException"/> | ||
| [NUnit.Framework.Test] | ||
| [LogMessage(iText.IO.LogMessageConstant.INVALID_INDIRECT_REFERENCE)] | ||
| [LogMessage(iText.IO.LogMessageConstant.XREF_ERROR)] | ||
| public virtual void CustomMemoryHandlerSumTest() { | ||
| MemoryLimitsAwareHandler handler = new MemoryLimitsAwareHandler(); | ||
| handler.SetMaxSizeOfDecompressedPdfStreamsSum(100000); | ||
| PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + "timing.pdf", new ReaderProperties( | ||
| ).SetMemoryLimitsAwareHandler(handler)), new PdfWriter(new MemoryStream())); | ||
| PdfStream stream = pdfDocument.GetFirstPage().GetContentStream(0); | ||
| byte[] b = stream.GetBytes(false); | ||
| String expectedExceptionMessage = PdfException.DuringDecompressionMultipleStreamsInSumOccupiedMoreMemoryThanAllowed; | ||
| String thrownExceptionMessage = null; | ||
| try { | ||
| PdfReader.DecodeBytes(b, stream); | ||
| } | ||
| catch (MemoryLimitsAwareException e) { | ||
| thrownExceptionMessage = e.Message; | ||
| } | ||
| NUnit.Framework.Assert.AreEqual(expectedExceptionMessage, thrownExceptionMessage); | ||
| } | ||
|
|
||
| /// <exception cref="System.IO.IOException"/> | ||
| [NUnit.Framework.Test] | ||
| [LogMessage(iText.IO.LogMessageConstant.INVALID_INDIRECT_REFERENCE)] | ||
| [LogMessage(iText.IO.LogMessageConstant.XREF_ERROR)] | ||
| public virtual void PageSumTest() { | ||
| MemoryLimitsAwareHandler handler = new MemoryLimitsAwareHandler(); | ||
| handler.SetMaxSizeOfDecompressedPdfStreamsSum(1500000); | ||
| PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + "timing.pdf", new ReaderProperties( | ||
| ).SetMemoryLimitsAwareHandler(handler)), new PdfWriter(new MemoryStream())); | ||
| String expectedExceptionMessage = PdfException.DuringDecompressionMultipleStreamsInSumOccupiedMoreMemoryThanAllowed; | ||
| String thrownExceptionMessage = null; | ||
| try { | ||
| pdfDocument.GetFirstPage().GetContentBytes(); | ||
| } | ||
| catch (MemoryLimitsAwareException e) { | ||
| thrownExceptionMessage = e.Message; | ||
| } | ||
| NUnit.Framework.Assert.AreEqual(expectedExceptionMessage, thrownExceptionMessage); | ||
| } | ||
|
|
||
| /// <exception cref="System.IO.IOException"/> | ||
| [NUnit.Framework.Test] | ||
| [LogMessage(iText.IO.LogMessageConstant.INVALID_INDIRECT_REFERENCE)] | ||
| [LogMessage(iText.IO.LogMessageConstant.XREF_ERROR)] | ||
| public virtual void PageAsSingleStreamTest() { | ||
| MemoryLimitsAwareHandler handler = new MemoryLimitsAwareHandler(); | ||
| handler.SetMaxSizeOfSingleDecompressedPdfStream(1500000); | ||
| PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + "timing.pdf", new ReaderProperties( | ||
| ).SetMemoryLimitsAwareHandler(handler)), new PdfWriter(new MemoryStream())); | ||
| String expectedExceptionMessage = PdfException.DuringDecompressionSingleStreamOccupiedMoreMemoryThanAllowed; | ||
| String thrownExceptionMessage = null; | ||
| try { | ||
| pdfDocument.GetFirstPage().GetContentBytes(); | ||
| } | ||
| catch (MemoryLimitsAwareException e) { | ||
| thrownExceptionMessage = e.Message; | ||
| } | ||
| NUnit.Framework.Assert.AreEqual(expectedExceptionMessage, thrownExceptionMessage); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| /* | ||
| This file is part of the iText (R) project. | ||
| Copyright (c) 1998-2019 iText Group NV | ||
| Authors: iText Software. | ||
| This program is free software; you can redistribute it and/or modify | ||
| it under the terms of the GNU Affero General Public License version 3 | ||
| as published by the Free Software Foundation with the addition of the | ||
| following permission added to Section 15 as permitted in Section 7(a): | ||
| FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY | ||
| ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT | ||
| OF THIRD PARTY RIGHTS | ||
| This program is distributed in the hope that it will be useful, but | ||
| WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| or FITNESS FOR A PARTICULAR PURPOSE. | ||
| See the GNU Affero General Public License for more details. | ||
| You should have received a copy of the GNU Affero General Public License | ||
| along with this program; if not, see http://www.gnu.org/licenses or write to | ||
| the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| Boston, MA, 02110-1301 USA, or download the license from the following URL: | ||
| http://itextpdf.com/terms-of-use/ | ||
| The interactive user interfaces in modified source and object code versions | ||
| of this program must display Appropriate Legal Notices, as required under | ||
| Section 5 of the GNU Affero General Public License. | ||
| In accordance with Section 7(b) of the GNU Affero General Public License, | ||
| a covered work must retain the producer line in every PDF that is created | ||
| or manipulated using iText. | ||
| You can be released from the requirements of the license by purchasing | ||
| a commercial license. Buying such a license is mandatory as soon as you | ||
| develop commercial activities involving the iText software without | ||
| disclosing the source code of your own applications. | ||
| These activities include: offering paid services to customers as an ASP, | ||
| serving PDFs on the fly in a web application, shipping iText with a closed | ||
| source product. | ||
| For more information, please contact iText Software Corp. at this | ||
| address: sales@itextpdf.com | ||
| */ | ||
| using System; | ||
| using iText.Kernel; | ||
|
|
||
| namespace iText.Kernel.Pdf { | ||
| /// <summary>Exception class for exceptions occurred during decompressed pdf streams processing.</summary> | ||
| public class MemoryLimitsAwareException : PdfException { | ||
| /// <summary>Creates a new instance of MemoryLimitsAwareException.</summary> | ||
| /// <param name="message">the detail message.</param> | ||
| public MemoryLimitsAwareException(String message) | ||
| : base(message) { | ||
| } | ||
|
|
||
| /// <summary>Creates a new instance of MemoryLimitsAwareException.</summary> | ||
| /// <param name="cause"> | ||
| /// the cause (which is saved for later retrieval by | ||
| /// <see cref="System.Exception.InnerException()"/> | ||
| /// method). | ||
| /// </param> | ||
| public MemoryLimitsAwareException(Exception cause) | ||
| : this(UnknownPdfException, cause) { | ||
| } | ||
|
|
||
| /// <summary>Creates a new instance of MemoryLimitsAwareException.</summary> | ||
| /// <param name="message">the detail message.</param> | ||
| /// <param name="cause"> | ||
| /// the cause (which is saved for later retrieval by | ||
| /// <see cref="System.Exception.InnerException()"/> | ||
| /// method). | ||
| /// </param> | ||
| public MemoryLimitsAwareException(String message, Exception cause) | ||
| : base(message, cause) { | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| /* | ||
| This file is part of the iText (R) project. | ||
| Copyright (c) 1998-2019 iText Group NV | ||
| Authors: iText Software. | ||
| This program is free software; you can redistribute it and/or modify | ||
| it under the terms of the GNU Affero General Public License version 3 | ||
| as published by the Free Software Foundation with the addition of the | ||
| following permission added to Section 15 as permitted in Section 7(a): | ||
| FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY | ||
| ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT | ||
| OF THIRD PARTY RIGHTS | ||
| This program is distributed in the hope that it will be useful, but | ||
| WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| or FITNESS FOR A PARTICULAR PURPOSE. | ||
| See the GNU Affero General Public License for more details. | ||
| You should have received a copy of the GNU Affero General Public License | ||
| along with this program; if not, see http://www.gnu.org/licenses or write to | ||
| the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| Boston, MA, 02110-1301 USA, or download the license from the following URL: | ||
| http://itextpdf.com/terms-of-use/ | ||
| The interactive user interfaces in modified source and object code versions | ||
| of this program must display Appropriate Legal Notices, as required under | ||
| Section 5 of the GNU Affero General Public License. | ||
| In accordance with Section 7(b) of the GNU Affero General Public License, | ||
| a covered work must retain the producer line in every PDF that is created | ||
| or manipulated using iText. | ||
| You can be released from the requirements of the license by purchasing | ||
| a commercial license. Buying such a license is mandatory as soon as you | ||
| develop commercial activities involving the iText software without | ||
| disclosing the source code of your own applications. | ||
| These activities include: offering paid services to customers as an ASP, | ||
| serving PDFs on the fly in a web application, shipping iText with a closed | ||
| source product. | ||
| For more information, please contact iText Software Corp. at this | ||
| address: sales@itextpdf.com | ||
| */ | ||
| using System.IO; | ||
| using iText.Kernel.Pdf.Filters; | ||
|
|
||
| namespace iText.Kernel.Pdf { | ||
| /// <summary>Handles memory limits aware processing.</summary> | ||
| /// <seealso> | ||
| /// | ||
| /// <see cref="MemoryLimitsAwareHandler"/> | ||
| /// </seealso> | ||
| public abstract class MemoryLimitsAwareFilter : IFilterHandler { | ||
| /// <summary> | ||
| /// Creates a | ||
| /// <see cref="MemoryLimitsAwareOutputStream"/> | ||
| /// which will be used for decompression of the passed pdf stream. | ||
| /// </summary> | ||
| /// <param name="streamDictionary">the pdf stream which is going to be decompressed.</param> | ||
| /// <returns> | ||
| /// the | ||
| /// <see cref="System.IO.MemoryStream"/> | ||
| /// which will be used for decompression of the passed pdf stream | ||
| /// </returns> | ||
| public virtual MemoryStream EnableMemoryLimitsAwareHandler(PdfDictionary streamDictionary) { | ||
| MemoryLimitsAwareOutputStream outputStream = new MemoryLimitsAwareOutputStream(); | ||
| MemoryLimitsAwareHandler memoryLimitsAwareHandler = null; | ||
| if (null != streamDictionary.GetIndirectReference()) { | ||
| memoryLimitsAwareHandler = streamDictionary.GetIndirectReference().GetDocument().memoryLimitsAwareHandler; | ||
| } | ||
| else { | ||
| // We do not reuse some static instance because one can process pdfs in different threads. | ||
| memoryLimitsAwareHandler = new MemoryLimitsAwareHandler(); | ||
| } | ||
| if (null != memoryLimitsAwareHandler && memoryLimitsAwareHandler.considerCurrentPdfStream) { | ||
| outputStream.SetMaxStreamSize(memoryLimitsAwareHandler.GetMaxSizeOfSingleDecompressedPdfStream()); | ||
| } | ||
| return outputStream; | ||
| } | ||
|
|
||
| public abstract byte[] Decode(byte[] arg1, PdfName arg2, PdfObject arg3, PdfDictionary arg4); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,231 @@ | ||
| /* | ||
| This file is part of the iText (R) project. | ||
| Copyright (c) 1998-2019 iText Group NV | ||
| Authors: iText Software. | ||
| This program is free software; you can redistribute it and/or modify | ||
| it under the terms of the GNU Affero General Public License version 3 | ||
| as published by the Free Software Foundation with the addition of the | ||
| following permission added to Section 15 as permitted in Section 7(a): | ||
| FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY | ||
| ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT | ||
| OF THIRD PARTY RIGHTS | ||
| This program is distributed in the hope that it will be useful, but | ||
| WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| or FITNESS FOR A PARTICULAR PURPOSE. | ||
| See the GNU Affero General Public License for more details. | ||
| You should have received a copy of the GNU Affero General Public License | ||
| along with this program; if not, see http://www.gnu.org/licenses or write to | ||
| the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| Boston, MA, 02110-1301 USA, or download the license from the following URL: | ||
| http://itextpdf.com/terms-of-use/ | ||
| The interactive user interfaces in modified source and object code versions | ||
| of this program must display Appropriate Legal Notices, as required under | ||
| Section 5 of the GNU Affero General Public License. | ||
| In accordance with Section 7(b) of the GNU Affero General Public License, | ||
| a covered work must retain the producer line in every PDF that is created | ||
| or manipulated using iText. | ||
| You can be released from the requirements of the license by purchasing | ||
| a commercial license. Buying such a license is mandatory as soon as you | ||
| develop commercial activities involving the iText software without | ||
| disclosing the source code of your own applications. | ||
| These activities include: offering paid services to customers as an ASP, | ||
| serving PDFs on the fly in a web application, shipping iText with a closed | ||
| source product. | ||
| For more information, please contact iText Software Corp. at this | ||
| address: sales@itextpdf.com | ||
| */ | ||
| using iText.Kernel; | ||
|
|
||
| namespace iText.Kernel.Pdf { | ||
| /// <summary> | ||
| /// A | ||
| /// <see cref="MemoryLimitsAwareHandler"/> | ||
| /// handles memory allocation and prevents decompressed pdf streams from occupation of more space than allowed. | ||
| /// </summary> | ||
| public class MemoryLimitsAwareHandler { | ||
| private const int SINGLE_SCALE_COEFFICIENT = 100; | ||
|
|
||
| private const int SUM_SCALE_COEFFICIENT = 500; | ||
|
|
||
| private const int SINGLE_DECOMPRESSED_PDF_STREAM_MIN_SIZE = int.MaxValue / 100; | ||
|
|
||
| private const long SUM_OF_DECOMPRESSED_PDF_STREAMW_MIN_SIZE = int.MaxValue / 20; | ||
|
|
||
| private int maxSizeOfSingleDecompressedPdfStream; | ||
|
|
||
| private long maxSizeOfDecompressedPdfStreamsSum; | ||
|
|
||
| private long allMemoryUsedForDecompression = 0; | ||
|
|
||
| private long memoryUsedForCurrentPdfStreamDecompression = 0; | ||
|
|
||
| internal bool considerCurrentPdfStream = false; | ||
|
|
||
| /// <summary> | ||
| /// Creates a | ||
| /// <see cref="MemoryLimitsAwareHandler"/> | ||
| /// which will be used to handle decompression of pdf streams. | ||
| /// The max allowed memory limits will be generated by default. | ||
| /// </summary> | ||
| public MemoryLimitsAwareHandler() { | ||
| maxSizeOfSingleDecompressedPdfStream = SINGLE_DECOMPRESSED_PDF_STREAM_MIN_SIZE; | ||
| maxSizeOfDecompressedPdfStreamsSum = SUM_OF_DECOMPRESSED_PDF_STREAMW_MIN_SIZE; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Creates a | ||
| /// <see cref="MemoryLimitsAwareHandler"/> | ||
| /// which will be used to handle decompression of pdf streams. | ||
| /// The max allowed memory limits will be generated by default, based on the size of the document. | ||
| /// </summary> | ||
| /// <param name="documentSize">the size of the document, which is going to be handled by iText.</param> | ||
| public MemoryLimitsAwareHandler(long documentSize) { | ||
| maxSizeOfSingleDecompressedPdfStream = (int)CalculateDefaultParameter(documentSize, SINGLE_SCALE_COEFFICIENT | ||
| , SINGLE_DECOMPRESSED_PDF_STREAM_MIN_SIZE); | ||
| maxSizeOfDecompressedPdfStreamsSum = CalculateDefaultParameter(documentSize, SUM_SCALE_COEFFICIENT, SUM_OF_DECOMPRESSED_PDF_STREAMW_MIN_SIZE | ||
| ); | ||
| } | ||
|
|
||
| /// <summary>Gets the maximum allowed size which can be occupied by a single decompressed pdf stream.</summary> | ||
| /// <returns>the maximum allowed size which can be occupied by a single decompressed pdf stream.</returns> | ||
| public virtual int GetMaxSizeOfSingleDecompressedPdfStream() { | ||
| return maxSizeOfSingleDecompressedPdfStream; | ||
| } | ||
|
|
||
| /// <summary>Sets the maximum allowed size which can be occupied by a single decompressed pdf stream.</summary> | ||
| /// <remarks> | ||
| /// Sets the maximum allowed size which can be occupied by a single decompressed pdf stream. | ||
| /// This value correlates with maximum heap size. This value should not exceed limit of the heap size. | ||
| /// iText will throw an exception if during decompression a pdf stream with two or more filters of identical type | ||
| /// occupies more memory than allowed. | ||
| /// </remarks> | ||
| /// <param name="maxSizeOfSingleDecompressedPdfStream">the maximum allowed size which can be occupied by a single decompressed pdf stream. | ||
| /// </param> | ||
| /// <returns> | ||
| /// this | ||
| /// <see cref="MemoryLimitsAwareHandler"/> | ||
| /// instance. | ||
| /// </returns> | ||
| public virtual iText.Kernel.Pdf.MemoryLimitsAwareHandler SetMaxSizeOfSingleDecompressedPdfStream(int maxSizeOfSingleDecompressedPdfStream | ||
| ) { | ||
| this.maxSizeOfSingleDecompressedPdfStream = maxSizeOfSingleDecompressedPdfStream; | ||
| return this; | ||
| } | ||
|
|
||
| /// <summary>Gets the maximum allowed size which can be occupied by all decompressed pdf streams.</summary> | ||
| /// <returns>the maximum allowed size value which streams may occupy</returns> | ||
| public virtual long GetMaxSizeOfDecompressedPdfStreamsSum() { | ||
| return maxSizeOfDecompressedPdfStreamsSum; | ||
| } | ||
|
|
||
| /// <summary>Sets the maximum allowed size which can be occupied by all decompressed pdf streams.</summary> | ||
| /// <remarks> | ||
| /// Sets the maximum allowed size which can be occupied by all decompressed pdf streams. | ||
| /// This value can be limited by the maximum expected PDF file size when it's completely decompressed. | ||
| /// Setting this value correlates with the maximum processing time spent on document reading | ||
| /// iText will throw an exception if during decompression pdf streams with two or more filters of identical type | ||
| /// occupy more memory than allowed. | ||
| /// </remarks> | ||
| /// <param name="maxSizeOfDecompressedPdfStreamsSum">he maximum allowed size which can be occupied by all decompressed pdf streams. | ||
| /// </param> | ||
| /// <returns> | ||
| /// this | ||
| /// <see cref="MemoryLimitsAwareHandler"/> | ||
| /// instance. | ||
| /// </returns> | ||
| public virtual iText.Kernel.Pdf.MemoryLimitsAwareHandler SetMaxSizeOfDecompressedPdfStreamsSum(long maxSizeOfDecompressedPdfStreamsSum | ||
| ) { | ||
| this.maxSizeOfDecompressedPdfStreamsSum = maxSizeOfDecompressedPdfStreamsSum; | ||
| return this; | ||
| } | ||
|
|
||
| /// <summary>Considers the number of bytes which are occupied by the decompressed pdf stream.</summary> | ||
| /// <remarks> | ||
| /// Considers the number of bytes which are occupied by the decompressed pdf stream. | ||
| /// If memory limits have not been faced, throws an exception. | ||
| /// </remarks> | ||
| /// <param name="numOfOccupiedBytes">the number of bytes which are occupied by the decompressed pdf stream.</param> | ||
| /// <returns> | ||
| /// this | ||
| /// <see cref="MemoryLimitsAwareHandler"/> | ||
| /// instance. | ||
| /// </returns> | ||
| /// <seealso> | ||
| /// | ||
| /// <see cref="MemoryLimitsAwareException"/> | ||
| /// </seealso> | ||
| internal virtual iText.Kernel.Pdf.MemoryLimitsAwareHandler ConsiderBytesOccupiedByDecompressedPdfStream(long | ||
| numOfOccupiedBytes) { | ||
| if (considerCurrentPdfStream && memoryUsedForCurrentPdfStreamDecompression < numOfOccupiedBytes) { | ||
| memoryUsedForCurrentPdfStreamDecompression = numOfOccupiedBytes; | ||
| if (memoryUsedForCurrentPdfStreamDecompression > maxSizeOfSingleDecompressedPdfStream) { | ||
| throw new MemoryLimitsAwareException(PdfException.DuringDecompressionSingleStreamOccupiedMoreMemoryThanAllowed | ||
| ); | ||
| } | ||
| } | ||
| return this; | ||
| } | ||
|
|
||
| /// <summary>Begins handling of current pdf stream decompression.</summary> | ||
| /// <returns> | ||
| /// this | ||
| /// <see cref="MemoryLimitsAwareHandler"/> | ||
| /// instance. | ||
| /// </returns> | ||
| internal virtual iText.Kernel.Pdf.MemoryLimitsAwareHandler BeginDecompressedPdfStreamProcessing() { | ||
| EnsureCurrentStreamIsReset(); | ||
| considerCurrentPdfStream = true; | ||
| return this; | ||
| } | ||
|
|
||
| /// <summary>Ends handling of current pdf stream decompression.</summary> | ||
| /// <remarks> | ||
| /// Ends handling of current pdf stream decompression. | ||
| /// If memory limits have not been faced, throws an exception. | ||
| /// </remarks> | ||
| /// <returns> | ||
| /// this | ||
| /// <see cref="MemoryLimitsAwareHandler"/> | ||
| /// instance. | ||
| /// </returns> | ||
| /// <seealso> | ||
| /// | ||
| /// <see cref="MemoryLimitsAwareException"/> | ||
| /// </seealso> | ||
| internal virtual iText.Kernel.Pdf.MemoryLimitsAwareHandler EndDecompressedPdfStreamProcessing() { | ||
| allMemoryUsedForDecompression += memoryUsedForCurrentPdfStreamDecompression; | ||
| if (allMemoryUsedForDecompression > maxSizeOfDecompressedPdfStreamsSum) { | ||
| throw new MemoryLimitsAwareException(PdfException.DuringDecompressionMultipleStreamsInSumOccupiedMoreMemoryThanAllowed | ||
| ); | ||
| } | ||
| EnsureCurrentStreamIsReset(); | ||
| considerCurrentPdfStream = false; | ||
| return this; | ||
| } | ||
|
|
||
| internal virtual long GetAllMemoryUsedForDecompression() { | ||
| return allMemoryUsedForDecompression; | ||
| } | ||
|
|
||
| private static long CalculateDefaultParameter(long documentSize, int scale, long min) { | ||
| long result = documentSize * scale; | ||
| if (result < min) { | ||
| result = min; | ||
| } | ||
| if (result > min * scale) { | ||
| result = min * scale; | ||
| } | ||
| return result; | ||
| } | ||
|
|
||
| private void EnsureCurrentStreamIsReset() { | ||
| memoryUsedForCurrentPdfStreamDecompression = 0; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| /* | ||
| This file is part of the iText (R) project. | ||
| Copyright (c) 1998-2019 iText Group NV | ||
| Authors: iText Software. | ||
| This program is free software; you can redistribute it and/or modify | ||
| it under the terms of the GNU Affero General Public License version 3 | ||
| as published by the Free Software Foundation with the addition of the | ||
| following permission added to Section 15 as permitted in Section 7(a): | ||
| FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY | ||
| ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT | ||
| OF THIRD PARTY RIGHTS | ||
| This program is distributed in the hope that it will be useful, but | ||
| WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| or FITNESS FOR A PARTICULAR PURPOSE. | ||
| See the GNU Affero General Public License for more details. | ||
| You should have received a copy of the GNU Affero General Public License | ||
| along with this program; if not, see http://www.gnu.org/licenses or write to | ||
| the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| Boston, MA, 02110-1301 USA, or download the license from the following URL: | ||
| http://itextpdf.com/terms-of-use/ | ||
| The interactive user interfaces in modified source and object code versions | ||
| of this program must display Appropriate Legal Notices, as required under | ||
| Section 5 of the GNU Affero General Public License. | ||
| In accordance with Section 7(b) of the GNU Affero General Public License, | ||
| a covered work must retain the producer line in every PDF that is created | ||
| or manipulated using iText. | ||
| You can be released from the requirements of the license by purchasing | ||
| a commercial license. Buying such a license is mandatory as soon as you | ||
| develop commercial activities involving the iText software without | ||
| disclosing the source code of your own applications. | ||
| These activities include: offering paid services to customers as an ASP, | ||
| serving PDFs on the fly in a web application, shipping iText with a closed | ||
| source product. | ||
| For more information, please contact iText Software Corp. at this | ||
| address: sales@itextpdf.com | ||
| */ | ||
| using System; | ||
| using System.IO; | ||
| using iText.IO.Util; | ||
| using iText.Kernel; | ||
|
|
||
| namespace iText.Kernel.Pdf { | ||
| /// <summary>This class implements an output stream which can be used for memory limits aware decompression of pdf streams. | ||
| /// </summary> | ||
| internal class MemoryLimitsAwareOutputStream : MemoryStream { | ||
| /// <summary>The maximum size of array to allocate.</summary> | ||
| /// <remarks> | ||
| /// The maximum size of array to allocate. | ||
| /// Attempts to allocate larger arrays will result in an exception. | ||
| /// </remarks> | ||
| private const int DEFAULT_MAX_STREAM_SIZE = int.MaxValue - 8; | ||
|
|
||
| /// <summary>The maximum size of array to allocate.</summary> | ||
| /// <remarks> | ||
| /// The maximum size of array to allocate. | ||
| /// Attempts to allocate larger arrays will result in an exception. | ||
| /// </remarks> | ||
| private int maxStreamSize = DEFAULT_MAX_STREAM_SIZE; | ||
|
|
||
| /// <summary>Creates a new byte array output stream.</summary> | ||
| /// <remarks> | ||
| /// Creates a new byte array output stream. The buffer capacity is | ||
| /// initially 32 bytes, though its size increases if necessary. | ||
| /// </remarks> | ||
| public MemoryLimitsAwareOutputStream() | ||
| : base() { | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Creates a new byte array output stream, with a buffer capacity of | ||
| /// the specified size, in bytes. | ||
| /// </summary> | ||
| /// <param name="size">the initial size.</param> | ||
| /// <exception cref="System.ArgumentException">if size is negative.</exception> | ||
| public MemoryLimitsAwareOutputStream(int size) | ||
| : base(size) { | ||
| } | ||
|
|
||
| /// <summary>Gets the maximum size which can be occupied by this output stream.</summary> | ||
| /// <returns>the maximum size which can be occupied by this output stream.</returns> | ||
| public virtual long GetMaxStreamSize() { | ||
| return maxStreamSize; | ||
| } | ||
|
|
||
| /// <summary>Sets the maximum size which can be occupied by this output stream.</summary> | ||
| /// <param name="maxStreamSize">the maximum size which can be occupied by this output stream.</param> | ||
| /// <returns> | ||
| /// this | ||
| /// <see cref="MemoryLimitsAwareOutputStream"/> | ||
| /// </returns> | ||
| public virtual iText.Kernel.Pdf.MemoryLimitsAwareOutputStream SetMaxStreamSize(int maxStreamSize) { | ||
| this.maxStreamSize = maxStreamSize; | ||
| return this; | ||
| } | ||
|
|
||
| /// <summary><inheritDoc/></summary> | ||
| public override void Write(byte[] b, int off, int len) { | ||
| if ((off < 0) || (off > b.Length) || (len < 0) || ((off + len) - b.Length > 0)) { | ||
| throw new IndexOutOfRangeException(); | ||
| } | ||
| int minCapacity = (int) this.Position + len; | ||
| if (minCapacity < 0) { | ||
| // overflow | ||
| throw new MemoryLimitsAwareException(PdfException.DuringDecompressionSingleStreamOccupiedMoreThanMaxIntegerValue | ||
| ); | ||
| } | ||
| if (minCapacity > maxStreamSize) { | ||
| throw new MemoryLimitsAwareException(PdfException.DuringDecompressionSingleStreamOccupiedMoreMemoryThanAllowed | ||
| ); | ||
| } | ||
| // calculate new capacity | ||
| int oldCapacity = this.GetBuffer().Length; | ||
| int newCapacity = oldCapacity << 1; | ||
| if (newCapacity < 0 || newCapacity - minCapacity < 0) { | ||
| // overflow | ||
| newCapacity = minCapacity; | ||
| } | ||
| if (newCapacity - maxStreamSize > 0) { | ||
| newCapacity = maxStreamSize; | ||
| this.Capacity = newCapacity; | ||
| } | ||
| base.Write(b, off, len); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| /* | ||
| This file is part of the iText (R) project. | ||
| Copyright (c) 1998-2019 iText Group NV | ||
| Authors: iText Software. | ||
| This program is free software; you can redistribute it and/or modify | ||
| it under the terms of the GNU Affero General Public License version 3 | ||
| as published by the Free Software Foundation with the addition of the | ||
| following permission added to Section 15 as permitted in Section 7(a): | ||
| FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY | ||
| ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT | ||
| OF THIRD PARTY RIGHTS | ||
| This program is distributed in the hope that it will be useful, but | ||
| WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| or FITNESS FOR A PARTICULAR PURPOSE. | ||
| See the GNU Affero General Public License for more details. | ||
| You should have received a copy of the GNU Affero General Public License | ||
| along with this program; if not, see http://www.gnu.org/licenses or write to | ||
| the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| Boston, MA, 02110-1301 USA, or download the license from the following URL: | ||
| http://itextpdf.com/terms-of-use/ | ||
| The interactive user interfaces in modified source and object code versions | ||
| of this program must display Appropriate Legal Notices, as required under | ||
| Section 5 of the GNU Affero General Public License. | ||
| In accordance with Section 7(b) of the GNU Affero General Public License, | ||
| a covered work must retain the producer line in every PDF that is created | ||
| or manipulated using iText. | ||
| You can be released from the requirements of the license by purchasing | ||
| a commercial license. Buying such a license is mandatory as soon as you | ||
| develop commercial activities involving the iText software without | ||
| disclosing the source code of your own applications. | ||
| These activities include: offering paid services to customers as an ASP, | ||
| serving PDFs on the fly in a web application, shipping iText with a closed | ||
| source product. | ||
| For more information, please contact iText Software Corp. at this | ||
| address: sales@itextpdf.com | ||
| */ | ||
| using System; | ||
| using System.IO; | ||
| using System.util.zlib; | ||
| using iText.Kernel.Pdf; | ||
|
|
||
| namespace iText.Kernel.Pdf.Filters { | ||
| /// <summary>Handles strict FlateDecode filter.</summary> | ||
| public class FlateDecodeStrictFilter : FlateDecodeFilter { | ||
| /// <summary><inheritDoc/></summary> | ||
| public override byte[] Decode(byte[] b, PdfName filterName, PdfObject decodeParams, PdfDictionary streamDictionary | ||
| ) { | ||
| MemoryStream outputStream = EnableMemoryLimitsAwareHandler(streamDictionary); | ||
| byte[] res = FlateDecode(b, outputStream); | ||
| b = DecodePredictor(res, decodeParams); | ||
| return b; | ||
| } | ||
|
|
||
| /// <summary>A helper to flateDecode.</summary> | ||
| /// <param name="in">the input data</param> | ||
| /// <param name="out">the out stream which will be used to write the bytes.</param> | ||
| /// <returns>the decoded data</returns> | ||
| private static byte[] FlateDecode(byte[] @in, MemoryStream @out) { | ||
| MemoryStream stream = new MemoryStream(@in); | ||
| ZInflaterInputStream zip = new ZInflaterInputStream(stream); | ||
| byte[] b = new byte[4092]; | ||
| try { | ||
| int n; | ||
| while ((n = zip.Read(b)) >= 0) { | ||
| @out.Write(b, 0, n); | ||
| } | ||
| zip.Dispose(); | ||
| @out.Dispose(); | ||
| return @out.ToArray(); | ||
| } | ||
| catch (MemoryLimitsAwareException e) { | ||
| throw; | ||
| } | ||
| catch (Exception) { | ||
| return null; | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| 696df736f8c4c6385dae5c4eff22163d5eca29b6 |