summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2021-07-04 12:29:08 +0300
committerMike Kaganski <mike.kaganski@collabora.com>2021-07-04 14:16:35 +0200
commitcd0ab69d4afee0c77884ae17ab9410216695b58b (patch)
tree12021c27adc1dcc46689444e00e53f37636ad4f1
parent0151a178d4e26b4546f7b27d569f0d94420caa9d (diff)
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@collabora.com>
-rw-r--r--sw/qa/extras/ooxmlexport/data/tdf142464_ampm.docxbin0 -> 15171 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx26
-rw-r--r--writerfilter/source/dmapper/ConversionHelper.cxx62
3 files changed, 62 insertions, 26 deletions
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
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf142464_ampm.docx
Binary files 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;