From e360f2c5360801eb98aa8501e1a47191f6867fe5 Mon Sep 17 00:00:00 2001 From: Pascal Brunot Date: Sat, 29 Oct 2022 11:43:06 +0200 Subject: [PATCH 1/4] fix for #930 Tested with 277 cultures successfully --- ooxml/XSSF/UserModel/Charts/XSSFChartUtil.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ooxml/XSSF/UserModel/Charts/XSSFChartUtil.cs b/ooxml/XSSF/UserModel/Charts/XSSFChartUtil.cs index e37faad10..61a4cae52 100644 --- a/ooxml/XSSF/UserModel/Charts/XSSFChartUtil.cs +++ b/ooxml/XSSF/UserModel/Charts/XSSFChartUtil.cs @@ -134,7 +134,7 @@ private static void FillNumCache(CT_NumData cache, IChartDataSource dataSo { CT_NumVal ctNumVal = cache.AddNewPt(); ctNumVal.idx = (uint)(i); - ctNumVal.v = (value.ToString()); + ctNumVal.v = (value.ToString(System.Globalization.CultureInfo.InvariantCulture)); } } } From 75ce5a3fa03ee9cc6782fe774dc410a8e73c2900 Mon Sep 17 00:00:00 2001 From: Pascal Brunot Date: Sat, 29 Oct 2022 11:47:12 +0200 Subject: [PATCH 2/4] reverting previous wrong fix for #930 --- OpenXmlFormats/Drawing/Chart/Chart.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenXmlFormats/Drawing/Chart/Chart.cs b/OpenXmlFormats/Drawing/Chart/Chart.cs index 8b8ecf02d..a83abfe98 100644 --- a/OpenXmlFormats/Drawing/Chart/Chart.cs +++ b/OpenXmlFormats/Drawing/Chart/Chart.cs @@ -8943,7 +8943,7 @@ internal void Write(StreamWriter sw, string nodeName) XmlHelper.WriteAttribute(sw, "formatCode", this.formatCode); sw.Write(">"); if (this.v != null) - sw.Write(string.Format("{0}", this.v.ToString(CultureInfo.InvariantCulture))); + sw.Write(string.Format("{0}", this.v.ToString())); sw.Write(string.Format("", nodeName)); } From e5ce18105c97a65c44ebf0bd3d4bd5e5f535963b Mon Sep 17 00:00:00 2001 From: Pascal Brunot Date: Sat, 29 Oct 2022 11:55:20 +0200 Subject: [PATCH 3/4] fix for #944 --- openxml4Net/OPC/PackagePartName.cs | 2 +- openxml4Net/OPC/PackagingUriHelper.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openxml4Net/OPC/PackagePartName.cs b/openxml4Net/OPC/PackagePartName.cs index 692b535c9..d3de6eb10 100644 --- a/openxml4Net/OPC/PackagePartName.cs +++ b/openxml4Net/OPC/PackagePartName.cs @@ -475,7 +475,7 @@ public String Extension String fragment = this.partNameURI.OriginalString; if (fragment.Length > 0) { - int i = fragment.LastIndexOf("."); + int i = fragment.LastIndexOf(".", StringComparison.Ordinal); if (i > -1) return fragment.Substring(i + 1); } diff --git a/openxml4Net/OPC/PackagingUriHelper.cs b/openxml4Net/OPC/PackagingUriHelper.cs index a856dd199..fe51839d4 100644 --- a/openxml4Net/OPC/PackagingUriHelper.cs +++ b/openxml4Net/OPC/PackagingUriHelper.cs @@ -198,7 +198,7 @@ public static String GetFilename(Uri uri) public static String GetFilenameWithoutExtension(Uri uri) { String filename = GetFilename(uri); - int dotIndex = filename.LastIndexOf("."); + int dotIndex = filename.LastIndexOf(".", StringComparison.Ordinal); if (dotIndex == -1) return filename; return filename.Substring(0, dotIndex); From c892c4ef9cae02178e5cac60555aee25e2a1b33a Mon Sep 17 00:00:00 2001 From: Pascal Brunot Date: Sun, 30 Oct 2022 08:50:10 +0100 Subject: [PATCH 4/4] added testcase for GetFilenameWithoutExtension Without the PR fix, this testcase fails in th-TH culture. With the PR fix, it passes and there are no regressions on other cultures. --- .../openxml4net/TestPackagingURIHelper.cs | 189 ++++++++++++------ 1 file changed, 125 insertions(+), 64 deletions(-) diff --git a/testcases/openxml4net/TestPackagingURIHelper.cs b/testcases/openxml4net/TestPackagingURIHelper.cs index ad22fce07..ff27dfe56 100644 --- a/testcases/openxml4net/TestPackagingURIHelper.cs +++ b/testcases/openxml4net/TestPackagingURIHelper.cs @@ -15,8 +15,12 @@ the License. You may obtain a copy of the License at limitations under the License. ==================================================================== */ using NPOI.OpenXml4Net.OPC; +using NPOI.OpenXmlFormats; using NUnit.Framework; using System; +using System.Globalization; +using System.Threading; + namespace TestCases.OpenXml4Net.OPC { @@ -30,45 +34,51 @@ public class TestPackagingURIHelper [Test] public void TestRelativizeUri() { - Uri Uri1 = new Uri("/word/document.xml", UriKind.Relative); - Uri Uri2 = new Uri("/word/media/image1.gif", UriKind.Relative); - Uri Uri3 = new Uri("/word/media/image1.gif#Sheet1!A1", UriKind.Relative); - Uri Uri4 = new Uri("#'My%20Sheet1'!A1", UriKind.Relative); - - // Document to image is down a directory - Uri retUri1to2 = PackagingUriHelper.RelativizeUri(Uri1, Uri2); - Assert.AreEqual("media/image1.gif", retUri1to2.OriginalString); - // Image to document is up a directory - Uri retUri2to1 = PackagingUriHelper.RelativizeUri(Uri2, Uri1); - Assert.AreEqual("../document.xml", retUri2to1.OriginalString); - - // Document and CustomXML parts totally different [Julien C.] - Uri UriCustomXml = new Uri("/customXml/item1.xml", UriKind.RelativeOrAbsolute); - - Uri UriRes = PackagingUriHelper.RelativizeUri(Uri1, UriCustomXml); - Assert.AreEqual("../customXml/item1.xml", UriRes.ToString()); - - // Document to itself is the same place (empty Uri) - Uri retUri2 = PackagingUriHelper.RelativizeUri(Uri1, Uri1); - // YK: the line below used to assert empty string which is wrong - // if source and target are the same they should be relaitivized as the last segment, - // see Bugzilla 51187 - Assert.AreEqual("document.xml", retUri2.OriginalString); - - // relativization against root - Uri root = new Uri("/", UriKind.Relative); - UriRes = PackagingUriHelper.RelativizeUri(root, Uri1); - Assert.AreEqual("/word/document.xml", UriRes.ToString()); - - //Uri compatible with MS Office and OpenOffice: leading slash is Removed - UriRes = PackagingUriHelper.RelativizeUri(root, Uri1, true); - Assert.AreEqual("word/document.xml", UriRes.ToString()); - - //preserve Uri fragments - UriRes = PackagingUriHelper.RelativizeUri(Uri1, Uri3, true); - Assert.AreEqual("media/image1.gif#Sheet1!A1", UriRes.ToString()); - UriRes = PackagingUriHelper.RelativizeUri(root, Uri4, true); - Assert.AreEqual("#'My%20Sheet1'!A1", UriRes.ToString()); + CultureInfo orig = Thread.CurrentThread.CurrentCulture; + foreach (var ci in System.Globalization.CultureInfo.GetCultures(System.Globalization.CultureTypes.NeutralCultures)) + { + Thread.CurrentThread.CurrentCulture = ci; + Uri Uri1 = new Uri("/word/document.xml", UriKind.Relative); + Uri Uri2 = new Uri("/word/media/image1.gif", UriKind.Relative); + Uri Uri3 = new Uri("/word/media/image1.gif#Sheet1!A1", UriKind.Relative); + Uri Uri4 = new Uri("#'My%20Sheet1'!A1", UriKind.Relative); + + // Document to image is down a directory + Uri retUri1to2 = PackagingUriHelper.RelativizeUri(Uri1, Uri2); + Assert.AreEqual("media/image1.gif", retUri1to2.OriginalString); + // Image to document is up a directory + Uri retUri2to1 = PackagingUriHelper.RelativizeUri(Uri2, Uri1); + Assert.AreEqual("../document.xml", retUri2to1.OriginalString); + + // Document and CustomXML parts totally different [Julien C.] + Uri UriCustomXml = new Uri("/customXml/item1.xml", UriKind.RelativeOrAbsolute); + + Uri UriRes = PackagingUriHelper.RelativizeUri(Uri1, UriCustomXml); + Assert.AreEqual("../customXml/item1.xml", UriRes.ToString()); + + // Document to itself is the same place (empty Uri) + Uri retUri2 = PackagingUriHelper.RelativizeUri(Uri1, Uri1); + // YK: the line below used to assert empty string which is wrong + // if source and target are the same they should be relaitivized as the last segment, + // see Bugzilla 51187 + Assert.AreEqual("document.xml", retUri2.OriginalString); + + // relativization against root + Uri root = new Uri("/", UriKind.Relative); + UriRes = PackagingUriHelper.RelativizeUri(root, Uri1); + Assert.AreEqual("/word/document.xml", UriRes.ToString()); + + //Uri compatible with MS Office and OpenOffice: leading slash is Removed + UriRes = PackagingUriHelper.RelativizeUri(root, Uri1, true); + Assert.AreEqual("word/document.xml", UriRes.ToString()); + + //preserve Uri fragments + UriRes = PackagingUriHelper.RelativizeUri(Uri1, Uri3, true); + Assert.AreEqual("media/image1.gif#Sheet1!A1", UriRes.ToString()); + UriRes = PackagingUriHelper.RelativizeUri(root, Uri4, true); + Assert.AreEqual("#'My%20Sheet1'!A1", UriRes.ToString()); + } + Thread.CurrentThread.CurrentCulture = orig; } /** @@ -77,21 +87,27 @@ public void TestRelativizeUri() [Test] public void TestCreatePartNameRelativeString() { - PackagePartName partNameToValid = PackagingUriHelper + CultureInfo orig = Thread.CurrentThread.CurrentCulture; + foreach (var ci in System.Globalization.CultureInfo.GetCultures(System.Globalization.CultureTypes.NeutralCultures)) + { + Thread.CurrentThread.CurrentCulture = ci; + PackagePartName partNameToValid = PackagingUriHelper .CreatePartName("/word/media/image1.gif"); - OPCPackage pkg = OPCPackage.Create("DELETEIFEXISTS.docx"); - // Base part - PackagePartName nameBase = PackagingUriHelper - .CreatePartName("/word/document.xml"); - PackagePart partBase = pkg.CreatePart(nameBase, ContentTypes.XML); - // Relative part name - PackagePartName relativeName = PackagingUriHelper.CreatePartName( - "media/image1.gif", partBase); - Assert.AreEqual(partNameToValid - , relativeName, "The part name must be equal to " - + partNameToValid.Name); - pkg.Revert(); + OPCPackage pkg = OPCPackage.Create("DELETEIFEXISTS.docx"); + // Base part + PackagePartName nameBase = PackagingUriHelper + .CreatePartName("/word/document.xml"); + PackagePart partBase = pkg.CreatePart(nameBase, ContentTypes.XML); + // Relative part name + PackagePartName relativeName = PackagingUriHelper.CreatePartName( + "media/image1.gif", partBase); + Assert.AreEqual(partNameToValid + , relativeName, "The part name must be equal to " + + partNameToValid.Name); + pkg.Revert(); + } + Thread.CurrentThread.CurrentCulture = orig; } /** @@ -100,20 +116,26 @@ public void TestCreatePartNameRelativeString() [Test] public void TestCreatePartNameRelativeUri() { - PackagePartName partNameToValid = PackagingUriHelper + CultureInfo orig = Thread.CurrentThread.CurrentCulture; + foreach (var ci in System.Globalization.CultureInfo.GetCultures(System.Globalization.CultureTypes.NeutralCultures)) + { + Thread.CurrentThread.CurrentCulture = ci; + PackagePartName partNameToValid = PackagingUriHelper .CreatePartName("/word/media/image1.gif"); - OPCPackage pkg = OPCPackage.Create("DELETEIFEXISTS.docx"); - // Base part - PackagePartName nameBase = PackagingUriHelper - .CreatePartName("/word/document.xml"); - PackagePart partBase = pkg.CreatePart(nameBase, ContentTypes.XML); - // Relative part name - PackagePartName relativeName = PackagingUriHelper.CreatePartName( - new Uri("media/image1.gif", UriKind.RelativeOrAbsolute), partBase); - Assert.AreEqual(partNameToValid, relativeName, "The part name must be equal to " - + partNameToValid.Name); - pkg.Revert(); + OPCPackage pkg = OPCPackage.Create("DELETEIFEXISTS.docx"); + // Base part + PackagePartName nameBase = PackagingUriHelper + .CreatePartName("/word/document.xml"); + PackagePart partBase = pkg.CreatePart(nameBase, ContentTypes.XML); + // Relative part name + PackagePartName relativeName = PackagingUriHelper.CreatePartName( + new Uri("media/image1.gif", UriKind.RelativeOrAbsolute), partBase); + Assert.AreEqual(partNameToValid, relativeName, "The part name must be equal to " + + partNameToValid.Name); + pkg.Revert(); + } + Thread.CurrentThread.CurrentCulture = orig; } [Test] public void TestCreateUriFromString() @@ -147,5 +169,44 @@ public void Test53734() Assert.AreEqual("javascript:///", uri.ToString()); } + [Test] + public void TestGetFilenameWithoutExtension() + { + // Testing fix for th-TH culture see https://github.com/nissl-lab/npoi/issues/944 + String[] href = { + "..\\\\\\cygwin\\home\\yegor\\.vim\\filetype.vim", + "..\\Program%20Files\\AGEIA%20Technologies\\v2.3.3\\NxCooking.dll", + "file:///D:\\seva\\1981\\r810102ns.mp3", + "..\\cygwin\\home\\yegor\\dinom\\%5baccess%5d.2010-10-26.log", + "#'Instructions (Text)'!B21", + "javascript://" }; + String[] fileNameNoExt = { + "filetype", + "NxCooking", + "r810102ns", + "%5baccess%5d.2010-10-26", + "", + "" }; + + CultureInfo orig = Thread.CurrentThread.CurrentCulture; + foreach (var ci in System.Globalization.CultureInfo.GetCultures(System.Globalization.CultureTypes.NeutralCultures)) + { + Thread.CurrentThread.CurrentCulture = ci; + for (int idx = 0; idx < href.Length; idx++) + { + try + { + Uri Uri = PackagingUriHelper.ToUri(href[idx]); + String fileName = PackagingUriHelper.GetFilenameWithoutExtension(Uri); + Assert.AreEqual(fileNameNoExt[idx], fileName, "GetFilenameWithoutExtension fails with culture : " + ci.Name); + } + catch (UriFormatException) + { + Assert.Fail("Failed to create Uri from " + href[idx]); + } + } + } + Thread.CurrentThread.CurrentCulture = orig; + } } } \ No newline at end of file