diff --git a/main/HSSF/UserModel/HSSFPicture.cs b/main/HSSF/UserModel/HSSFPicture.cs index a1c0672cd..ff9210f86 100644 --- a/main/HSSF/UserModel/HSSFPicture.cs +++ b/main/HSSF/UserModel/HSSFPicture.cs @@ -91,23 +91,22 @@ public void Resize(double scale) Resize(scale, scale); } - /** - * Resize the image - *

- * Please note, that this method works correctly only for workbooks - * with default font size (Arial 10pt for .xls). - * If the default font is changed the resized image can be streched vertically or horizontally. - *

- *

- * resize(1.0,1.0) keeps the original size,
- * resize(0.5,0.5) resize to 50% of the original,
- * resize(2.0,2.0) resizes to 200% of the original.
- * resize({@link Double#MAX_VALUE},{@link Double#MAX_VALUE}) resizes to the dimension of the embedded image. - *

- * - * @param scaleX the amount by which the image width is multiplied relative to the original width. - * @param scaleY the amount by which the image height is multiplied relative to the original height. - */ + /// + /// Resize the image + /// + /// Please note, that this method works correctly only for workbooks + /// with default font size (Arial 10pt for .xls). + /// If the default font is changed the resized image can be streched vertically or horizontally. + /// + /// resize(1.0,1.0) keeps the original size, + /// resize(0.5,0.5) resize to 50% of the original, + /// resize(2.0,2.0) resizes to 200% of the original. + /// resize(,) resizes to the dimension of the embedded image. + /// + /// + /// + /// the amount by which the image width is multiplied relative to the original width. + /// the amount by which the image height is multiplied relative to the original height. public void Resize(double scaleX, double scaleY) { HSSFClientAnchor anchor = (HSSFClientAnchor)ClientAnchor; @@ -118,7 +117,7 @@ public void Resize(double scaleX, double scaleY) int row2 = anchor.Row1 + (pref.Row2 - pref.Row1); int col2 = anchor.Col1 + (pref.Col2 - pref.Col1); - anchor.Col2=((short)col2); + anchor.Col2=((short) col2); // anchor.setDx1(0); anchor.Dx2=(pref.Dx2); @@ -135,7 +134,7 @@ public int PictureIndex get { EscherSimpleProperty property = (EscherSimpleProperty)GetOptRecord().Lookup(EscherProperties.BLIP__BLIPTODISPLAY); - if (null == property) + if(null == property) { return -1; } @@ -146,17 +145,17 @@ public int PictureIndex SetPropertyValue(new EscherSimpleProperty(EscherProperties.BLIP__BLIPTODISPLAY, false, true, value)); } } - /** - * Calculate the preferred size for this picture. - * - * @param scale the amount by which image dimensions are multiplied relative to the original size. - * @return HSSFClientAnchor with the preferred size for this image - * @since POI 3.0.2 - */ + + /// + /// Calculate the preferred size for this picture. + /// + /// the amount by which image dimensions are multiplied relative to the original size. + /// HSSFClientAnchor with the preferred size for this image public IClientAnchor GetPreferredSize(double scale) { return GetPreferredSize(scale, scale); } + /// /// Calculate the preferred size for this picture. /// @@ -167,7 +166,7 @@ public IClientAnchor GetPreferredSize(double scaleX, double scaleY) { ImageUtils.SetPreferredSize(this, scaleX, scaleY); return ClientAnchor; - + } /// @@ -194,7 +193,7 @@ protected Size GetResolution(Image r) { //int hdpi = 96, vdpi = 96; //double mm2inch = 25.4; - return new Size((int)r.Metadata.HorizontalResolution, (int)r.Metadata.VerticalResolution); + return new Size((int) r.Metadata.HorizontalResolution, (int) r.Metadata.VerticalResolution); } /// @@ -208,24 +207,35 @@ public Size GetImageDimension() byte[] data = bse.BlipRecord.PictureData; //int type = bse.BlipTypeWin32; - using (MemoryStream ms = RecyclableMemory.GetStream(data)) + using(MemoryStream ms = RecyclableMemory.GetStream(data)) { - using (Image img = Image.Load(ms)) + using(Image img = Image.Load(ms)) { return img.Size(); } } } - /** - * Return picture data for this shape - * - * @return picture data for this shape - */ + + /// + /// Return picture data for this shape + /// public IPictureData PictureData { get { - InternalWorkbook iwb = ((_patriarch.Sheet.Workbook) as HSSFWorkbook).Workbook; + HSSFPatriarch patriarch = Patriarch; + HSSFShape parent = Parent as HSSFShape; + while(patriarch == null && parent != null) + { + patriarch = parent.Patriarch; + parent = parent.Parent as HSSFShape; + } + if(patriarch == null) + { + throw new InvalidOperationException("Could not find a patriarch for a HSSPicture"); + } + + InternalWorkbook iwb = (patriarch.Sheet.Workbook as HSSFWorkbook).Workbook; EscherBSERecord bse = iwb.GetBSERecord(PictureIndex); EscherBlipRecord blipRecord = bse.BlipRecord; return new HSSFPictureData(blipRecord); @@ -237,7 +247,7 @@ internal override void AfterInsert(HSSFPatriarch patriarch) { EscherAggregate agg = patriarch.GetBoundAggregate(); agg.AssociateShapeToObjRecord(GetEscherContainer().GetChildById(EscherClientDataRecord.RECORD_ID), GetObjRecord()); - if (PictureIndex != -1) + if(PictureIndex != -1) { EscherBSERecord bse = (patriarch.Sheet.Workbook as HSSFWorkbook).Workbook.GetBSERecord(PictureIndex); @@ -245,9 +255,9 @@ internal override void AfterInsert(HSSFPatriarch patriarch) } } - /** - * The color applied to the lines of this shape. - */ + /// + /// The color applied to the lines of this shape. + /// public String FileName { get @@ -271,11 +281,11 @@ private String Trim(string value) //int off = offset; /* avoid getfield opcode */ char[] val = value.ToCharArray(); /* avoid getfield opcode */ - while ((st < end) && (val[st] <= ' ')) + while((st < end) && (val[st] <= ' ')) { st++; } - while ((st < end) && (val[end - 1] <= ' ')) + while((st < end) && (val[end - 1] <= ' ')) { end--; } @@ -302,22 +312,22 @@ internal override HSSFShape CloneShape() } - /** - * @return the anchor that is used by this picture. - */ + /// + /// the anchor that is used by this picture. + /// public IClientAnchor ClientAnchor { get { HSSFAnchor a = Anchor as HSSFAnchor; - return (a is HSSFClientAnchor) ? (HSSFClientAnchor)a : null; + return (a is HSSFClientAnchor) ? (HSSFClientAnchor) a : null; } } - /** - * @return the sheet which contains the picture shape - */ + /// + /// the sheet which contains the picture shape + /// public ISheet Sheet { get diff --git a/testcases/main/POITestCase.cs b/testcases/main/POITestCase.cs index a68aefc78..7f207beca 100644 --- a/testcases/main/POITestCase.cs +++ b/testcases/main/POITestCase.cs @@ -32,31 +32,58 @@ namespace TestCases */ public class POITestCase { - public static void AssertContains(String haystack, String needle) + public static void AssertStartsWith(String actual, String prefix) { - Assert.IsTrue( - haystack.Contains(needle), - "Unable to find expected text '" + needle + "' in text:\n" + haystack - ); + Assert.IsNotNull(actual); + Assert.IsNotNull(prefix); + StringAssert.StartsWith(prefix, actual); } - public static void AssertContainsIgnoreCase(String haystack, String needle, CultureInfo locale) + + public static void AssertStartsWith(String message, String actual, String prefix) + { + Assert.IsNotNull(message, actual); + Assert.IsNotNull(message, prefix); + StringAssert.StartsWith(prefix, actual, message); + } + + public static void AssertEndsWith(String actual, String suffix) + { + Assert.IsNotNull(actual); + Assert.IsNotNull(suffix); + StringAssert.EndsWith(suffix, actual); + } + + public static void AssertContains(String actual, String expected) + { + Assert.IsNotNull(actual); + Assert.IsNotNull(expected); + StringAssert.Contains(expected, actual); + } + public static void AssertContains(String message, String actual, String expected) + { + Assert.IsNotNull(actual, message); + Assert.IsNotNull(expected, message); + StringAssert.Contains(expected, actual, message); + } + + public static void AssertContainsIgnoreCase(String actual, String expected, CultureInfo locale) { - Assert.IsNotNull(haystack); - Assert.IsNotNull(needle); - String hay = haystack.ToLower(locale); - String n = needle.ToLower(locale); - Assert.IsTrue(hay.Contains(n), "Unable to find expected text '" + needle + "' in1 text:\n" + haystack); + Assert.IsNotNull(actual); + Assert.IsNotNull(expected); + string hay = actual.ToLower(locale); + string n = expected.ToLower(locale); + StringAssert.Contains(n, hay, "Unable to find expected text '" + expected + "' in1 text:\n" + actual); } - public static void AssertContainsIgnoreCase(String haystack, String needle) + public static void AssertContainsIgnoreCase(String actual, String expected) { - AssertContainsIgnoreCase(haystack, needle, CultureInfo.CurrentCulture); + AssertContainsIgnoreCase(actual, expected, CultureInfo.CurrentCulture); } - public static void AssertNotContained(String haystack, String needle) + public static void AssertNotContained(String actual, String expected) { - Assert.IsFalse(haystack.Contains(needle), - "Unexpectedly found text '" + needle + "' in text:\n" + haystack - ); + Assert.IsNotNull(actual); + Assert.IsNotNull(expected); + StringAssert.DoesNotContain(expected, actual, "Unexpectedly found text '" + expected + "' in text:\n" + actual); } /** @@ -65,7 +92,7 @@ public static void AssertNotContained(String haystack, String needle) */ public static void AssertContains(Dictionary map, TKey key) { - if (map.ContainsKey(key)) + if(map.ContainsKey(key)) { return; } @@ -74,7 +101,7 @@ public static void AssertContains(Dictionary map, TK public static void AssertEquals(T[] expected, T[] actual) { Assert.AreEqual(expected.Length, actual.Length, "Non-matching lengths"); - for (int i = 0; i < expected.Length; i++) + for(int i = 0; i < expected.Length; i++) { Assert.AreEqual(expected[i], actual[i], "Mis-match at offset " + i); } @@ -82,7 +109,7 @@ public static void AssertEquals(T[] expected, T[] actual) public static void AssertEquals(byte[] expected, byte[] actual) { Assert.AreEqual(expected.Length, actual.Length, "Non-matching lengths"); - for (int i = 0; i < expected.Length; i++) + for(int i = 0; i < expected.Length; i++) { Assert.AreEqual(expected[i], actual[i], "Mis-match at offset " + i); } @@ -90,9 +117,9 @@ public static void AssertEquals(byte[] expected, byte[] actual) public static void AssertContains(T needle, T[] haystack) { // Check - foreach (T thing in haystack) + foreach(T thing in haystack) { - if (thing.Equals(needle)) + if(thing.Equals(needle)) { return; } @@ -101,7 +128,7 @@ public static void AssertContains(T needle, T[] haystack) // Failed, try to build a nice error StringBuilder sb = new StringBuilder(); sb.Append("Unable to find ").Append(needle).Append(" in ["); - foreach (T thing in haystack) + foreach(T thing in haystack) { sb.Append(" ").Append(thing.ToString()).Append(" ,"); } @@ -112,7 +139,7 @@ public static void AssertContains(T needle, T[] haystack) public static void AssertContains(T needle, IList haystack) { - if (haystack.Contains(needle)) + if(haystack.Contains(needle)) { return; } @@ -125,10 +152,10 @@ public static R GetFieldValue(Type clazz, T instance, Type fieldType, Stri try { FieldInfo fieldInfo = clazz.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance); - return (R)fieldInfo.GetValue(instance); + return (R) fieldInfo.GetValue(instance); } - catch (Exception pae) + catch(Exception pae) { throw new RuntimeException("Cannot access field '" + fieldName + "' of class " + clazz, pae.InnerException); } diff --git a/testcases/main/TestPOITestCase.cs b/testcases/main/TestPOITestCase.cs index d81a99c54..bd3236786 100644 --- a/testcases/main/TestPOITestCase.cs +++ b/testcases/main/TestPOITestCase.cs @@ -28,6 +28,22 @@ namespace TestCases [TestFixture] public class TestPOITestCase { + [Test] + public void AssertStartsWith() + { + POITestCase.AssertStartsWith("Apache POI", ""); + POITestCase.AssertStartsWith("Apache POI", "Apache"); + POITestCase.AssertStartsWith("Apache POI", "Apache POI"); + } + + [Test] + public void AssertEndsWith() + { + POITestCase.AssertEndsWith("Apache POI", ""); + POITestCase.AssertEndsWith("Apache POI", "POI"); + POITestCase.AssertEndsWith("Apache POI", "Apache POI"); + } + [Test] public void AssertContains() { diff --git a/testcases/openxml4net/TestPackage.cs b/testcases/openxml4net/TestPackage.cs index 5bd3d73c1..8caa26f3e 100644 --- a/testcases/openxml4net/TestPackage.cs +++ b/testcases/openxml4net/TestPackage.cs @@ -20,15 +20,12 @@ limitations under the License. using System.IO; using System.Collections.Generic; using System; -using TestCases.OpenXml4Net; using NPOI.Util; using System.Reflection; using System.Text.RegularExpressions; using NUnit.Framework; using System.Xml; using System.Text; -using ICSharpCode.SharpZipLib.Zip; -using System.Collections; using NPOI.SS.UserModel; using NPOI; using NPOI.Openxml4Net.Exceptions; @@ -842,7 +839,7 @@ public void NonOOXMLFileTypes() // { // ZipEntry e2 = (ZipEntry)entries.Current; // ZipEntry e = new ZipEntry(e2.Name); - + // e.DateTime = (e2.DateTime); // e.Comment = (e2.Comment); // e.Size = (e2.Size); @@ -889,6 +886,47 @@ public void NonOOXMLFileTypes() // zipFile.Close(); //} + [Test, Ignore("need ExtractorFactory class")] + public void ZipBombSampleFiles() { + + openZipBombFile("poc-shared-strings.xlsx"); + openZipBombFile("poc-xmlbomb.xlsx"); + openZipBombFile("poc-xmlbomb-empty.xlsx"); + } + + private void openZipBombFile(String file) + { + try + { + IWorkbook wb = NPOI.XSSF.XSSFTestDataSamples.OpenSampleWorkbook(file); + wb.Close(); + + //POITextExtractor extractor = ExtractorFactory.CreateExtractor(TestCases.HSSF.HSSFTestDataSamples.GetSampleFile("poc-shared-strings.xlsx")); + //try + //{ + // Assert.IsNotNull(extractor); + // var _ = extractor.Text; + //} + //finally + //{ + // extractor.Close(); + //} + + Assert.Fail("Should catch an exception because of a ZipBomb"); + } + catch (InvalidOperationException e) + { + if (!e.Message.Contains("The text would exceed the max allowed overall size of extracted text.")) + { + throw e; + } + } + catch (POIXMLException e) + { + checkForZipBombException(e); + } + } + [Test, Ignore("need ZipSecureFile class")] public void ZipBombCheckSizes() { @@ -964,16 +1002,15 @@ public void ZipBombCheckSizes() private void checkForZipBombException(Exception e) { + // unwrap InvocationTargetException as they usually contain the nested exception in the "target" member //if (e is InvocationTargetException) { - // InvocationTargetException t = (InvocationTargetException)e; - // IOException t2 = (IOException)t.getTargetException(); - // if (t2.Message.StartsWith("Zip bomb detected!")) - // { - // return; - // } + // e = ((InvocationTargetException)e).getTargetException(); //} - if (e.Message.StartsWith("Zip bomb detected! Exiting.")) + String msg = e.Message; + if (msg != null && (msg.StartsWith("Zip bomb detected!") || + msg.Contains("The parser has encountered more than \"4,096\" entity expansions in this document;") || + msg.Contains("The parser has encountered more than \"4096\" entity expansions in this document;"))) { return; } diff --git a/testcases/test-data/spreadsheet/poc-xmlbomb-empty.xlsx b/testcases/test-data/spreadsheet/poc-xmlbomb-empty.xlsx new file mode 100644 index 000000000..e69de29bb