[Libreoffice-commits] core.git: sw/qa writerfilter/source

Mike Kaganski (via logerrit) logerrit at kemper.freedesktop.org
Sun Jul 4 12:17:10 UTC 2021


 sw/qa/extras/ooxmlexport/data/tdf142464_ampm.docx |binary
 sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx     |   26 +++++++++
 writerfilter/source/dmapper/ConversionHelper.cxx  |   62 ++++++++++++----------
 3 files changed, 62 insertions(+), 26 deletions(-)

New commits:
commit cd0ab69d4afee0c77884ae17ab9410216695b58b
Author:     Mike Kaganski <mike.kaganski at collabora.com>
AuthorDate: Sun Jul 4 12:29:08 2021 +0300
Commit:     Mike Kaganski <mike.kaganski at collabora.com>
CommitDate: Sun Jul 4 14:16:35 2021 +0200

    tdf#142464: do not escape '/' is AM/PM when importing DOCX.
    
    See also commit a2e964afc5187fc1e3b38720ec10ad9856b87020, doing the
    same for DOC.
    
    Change-Id: Ib0ddb36de8589f9264fe857b20a6ef2aa2607c52
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/118369
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>

diff --git a/sw/qa/extras/ooxmlexport/data/tdf142464_ampm.docx b/sw/qa/extras/ooxmlexport/data/tdf142464_ampm.docx
new file mode 100644
index 000000000000..d63398488858
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf142464_ampm.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
index e828519ed4cf..d92c29fefbe7 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
@@ -10,6 +10,7 @@
 #include <swmodeltestbase.hxx>
 
 #include <com/sun/star/text/XTextFieldsSupplier.hpp>
+#include <com/sun/star/text/XTextField.hpp>
 
 #include <xmloff/odffields.hxx>
 
@@ -688,6 +689,31 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testConditionalText, "conditional-text.fodt"
     assertXPathContent(pXmlDoc, "/w:document/w:body/w:p/w:r[2]/w:instrText", OUString(aExpected));
 }
 
+DECLARE_OOXMLEXPORT_TEST(testTdf142464_ampm, "tdf142464_ampm.docx")
+{
+    css::uno::Reference<css::text::XTextFieldsSupplier> xTextFieldsSupplier(
+        mxComponent, css::uno::UNO_QUERY_THROW);
+    auto xFieldsAccess(xTextFieldsSupplier->getTextFields());
+    auto xFields(xFieldsAccess->createEnumeration());
+    css::uno::Reference<css::text::XTextField> xField(xFields->nextElement(),
+                                                      css::uno::UNO_QUERY_THROW);
+
+    // Without the fix in place, this would have failed with:
+    //   - Expected: 12:32 PM
+    //   - Actual  : 12:32 a12/p12
+    CPPUNIT_ASSERT_EQUAL(OUString("12:32 PM"), xField->getPresentation(false));
+
+    if (xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"))
+    {
+        // Without the fix in place, this would have failed with:
+        //   - Expected:  DATE \@"H:mm\ AM/PM"
+        //   - Actual  :  DATE \@"H:mm' a'M'/p'M"
+        // i.e., the AM/PM would be treated as literal 'a' and 'p' followed by a month code
+        assertXPathContent(pXmlDoc, "/w:document/w:body/w:p/w:r[2]/w:instrText",
+                           " DATE \\@\"H:mm\\ AM/PM\" ");
+    }
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/ConversionHelper.cxx b/writerfilter/source/dmapper/ConversionHelper.cxx
index e0385a5c6a65..c5b1d3e5d027 100644
--- a/writerfilter/source/dmapper/ConversionHelper.cxx
+++ b/writerfilter/source/dmapper/ConversionHelper.cxx
@@ -295,8 +295,17 @@ bool lcl_IsNotAM(OUString const & rFmt, sal_Int32 nPos)
             )
         );
 }
+bool IsPreviousAM(OUString const& rParams, sal_Int32 nPos)
+{
+    return nPos >= 2 && rParams.matchIgnoreAsciiCase("am", nPos - 2);
+}
+bool IsNextPM(OUString const& rParams, sal_Int32 nPos)
+{
+    return nPos + 2 < rParams.getLength() && rParams.matchIgnoreAsciiCase("pm", nPos + 1);
+}
 }
 
+// See also sw::ms::MSDateTimeFormatToSwFormat
 OUString ConvertMSFormatStringToSO(
         const OUString& rFormat, lang::Locale& rLocale, bool bHijri)
 {
@@ -306,37 +315,38 @@ OUString ConvertMSFormatStringToSO(
     //#102782#, #102815#, #108341# & #111944# have to work at the same time :-)
     bool bForceJapanese(false);
     bool bForceNatNum(false);
-    sal_Int32 nLen = sFormat.getLength();
+    const sal_Int32 nLen = sFormat.getLength();
     sal_Int32 nI = 0;
+    sal_Int32 nAddedChars = 0;
 //    const sal_Unicode* pFormat = sFormat.getStr();
     OUStringBuffer aNewFormat( sFormat );
     while (nI < nLen)
     {
-        if (aNewFormat[nI] == '\\')
-            nI++;
-        else if (aNewFormat[nI] == '\"')
+        if (sFormat[nI] == '\\')
+            ++nI;
+        else if (sFormat[nI] == '\"')
         {
             ++nI;
             //While not at the end and not at an unescaped end quote
-            while ((nI < nLen) && ((aNewFormat[nI] != '\"') && (aNewFormat[nI-1] != '\\')))
+            while ((nI < nLen) && ((sFormat[nI] != '\"') && (sFormat[nI-1] != '\\')))
                 ++nI;
         }
         else //normal unquoted section
         {
-            sal_Unicode nChar = aNewFormat[nI];
+            sal_Unicode nChar = sFormat[nI];
             if (nChar == 'O')
             {
-                aNewFormat[nI] = 'M';
+                aNewFormat[nI + nAddedChars] = 'M';
                 bForceNatNum = true;
             }
             else if (nChar == 'o')
             {
-                aNewFormat[nI] = 'm';
+                aNewFormat[nI + nAddedChars] = 'm';
                 bForceNatNum = true;
             }
             else if ((nChar == 'A') && lcl_IsNotAM(sFormat, nI))
             {
-                aNewFormat[nI] = 'D';
+                aNewFormat[nI + nAddedChars] = 'D';
                 bForceNatNum = true;
             }
             else if ((nChar == 'g') || (nChar == 'G'))
@@ -345,38 +355,38 @@ OUString ConvertMSFormatStringToSO(
                 bForceJapanese = true;
             else if (nChar == 'E')
             {
-                if ((nI != nLen-1) && (aNewFormat[nI+1] == 'E'))
+                if ((nI != nLen-1) && (sFormat[nI+1] == 'E'))
                 {
                     //todo: this cannot be the right way to replace a part of the string!
-                    aNewFormat[nI] = 'Y';
-                    aNewFormat[nI + 1] = 'Y';
-                    aNewFormat.insert(nI + 2, "YY");
-                    nLen+=2;
-                    nI+=3;
+                    aNewFormat[nI + nAddedChars] = 'Y';
+                    aNewFormat[nI + nAddedChars + 1] = 'Y';
+                    aNewFormat.insert(nI + nAddedChars + 2, "YY");
+                    nAddedChars += 2;
+                    ++nI;
                 }
                 bForceJapanese = true;
             }
             else if (nChar == 'e')
             {
-                if ((nI != nLen-1) && (aNewFormat[nI+1] == 'e'))
+                if ((nI != nLen-1) && (sFormat[nI+1] == 'e'))
                 {
                     //todo: this cannot be the right way to replace a part of the string!
-                    aNewFormat[nI] = 'y';
-                    aNewFormat[nI + 1] = 'y';
-                    aNewFormat.insert(nI + 2, "yy");
-                    nLen+=2;
-                    nI+=3;
+                    aNewFormat[nI + nAddedChars] = 'y';
+                    aNewFormat[nI + nAddedChars + 1] = 'y';
+                    aNewFormat.insert(nI + nAddedChars + 2, "yy");
+                    nAddedChars += 2;
+                    ++nI;
                 }
                 bForceJapanese = true;
             }
-            else if (nChar == '/')
+            else if (nChar == '/' && !(IsPreviousAM(sFormat, nI) && IsNextPM(sFormat, nI)))
             {
                 // MM We have to escape '/' in case it's used as a char
                 //todo: this cannot be the right way to replace a part of the string!
-                aNewFormat[nI] = '\\';
-                aNewFormat.insert(nI + 1, "/");
-                nI++;
-                nLen++;
+                aNewFormat[nI + nAddedChars] = '\\';
+                aNewFormat.insert(nI + nAddedChars + 1, "/");
+                ++nAddedChars;
+                ++nI;
             }
         }
         ++nI;


More information about the Libreoffice-commits mailing list