Blob Blame History Raw
From 4298d223b77706c60b1c5ed0e260b766c70d17f0 Mon Sep 17 00:00:00 2001
From: Michael Stahl <mstahl@redhat.com>
Date: Sat, 1 Mar 2014 22:05:51 +0100
Subject: [PATCH 3/3] writerfilter: salvage a field parameter parsing train
 wreck

Field parameters get horribly maimed by lcl_ExtractParameter which
clearly has never worked in its 7 years of existence (and looking at the
inanity at the call sites makes one wonder what the author was smoking).

The format is actually quite annoying, since spaces between parameters
are optional.

The old RTF filter was at least able to parse "PAGEREF bookmark" fields,
so this fixes such regressions (related: rhbz#1065629).

(cherry picked from commit 3dc548476c7e88f7a67cc38daf622631a34e34dd)

Conflicts:
	writerfilter/source/dmapper/DomainMapper_Impl.cxx

Conflicts:
	writerfilter/source/dmapper/DomainMapper_Impl.cxx

Change-Id: I9b2e32c3c7264be0fc1077cb8fb3f1bc5c1955bb
---
 writerfilter/CppunitTest_writerfilter_misc.mk     |  36 ++++
 writerfilter/Module_writerfilter.mk               |   1 +
 writerfilter/qa/cppunittests/misc/misc.cxx        | 162 ++++++++++++++++
 writerfilter/source/dmapper/DomainMapper_Impl.cxx | 224 +++++++++++++++-------
 writerfilter/source/dmapper/DomainMapper_Impl.hxx |   3 +-
 5 files changed, 356 insertions(+), 70 deletions(-)
 create mode 100644 writerfilter/CppunitTest_writerfilter_misc.mk
 create mode 100644 writerfilter/qa/cppunittests/misc/misc.cxx

diff --git a/writerfilter/CppunitTest_writerfilter_misc.mk b/writerfilter/CppunitTest_writerfilter_misc.mk
new file mode 100644
index 0000000..1cdcd80
--- /dev/null
+++ b/writerfilter/CppunitTest_writerfilter_misc.mk
@@ -0,0 +1,36 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,writerfilter_misc))
+
+$(eval $(call gb_CppunitTest_use_api,writerfilter_misc,\
+	offapi \
+	udkapi \
+))
+
+$(eval $(call gb_CppunitTest_use_external,writerfilter_misc,boost_headers))
+
+$(eval $(call gb_CppunitTest_use_libraries,writerfilter_misc, \
+	writerfilter \
+	cppu \
+	sal \
+	$(gb_UWINAPI) \
+))
+
+$(eval $(call gb_CppunitTest_set_include,writerfilter_misc, \
+	$$(INCLUDE) \
+	-I$(SRCDIR)/writerfilter/inc \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,writerfilter_misc, \
+	writerfilter/qa/cppunittests/misc/misc \
+))
+
+
+# vim: set noet sw=4 ts=4:
diff --git a/writerfilter/Module_writerfilter.mk b/writerfilter/Module_writerfilter.mk
index fe73d1d..a1ddc4e 100644
--- a/writerfilter/Module_writerfilter.mk
+++ b/writerfilter/Module_writerfilter.mk
@@ -16,6 +16,7 @@ $(eval $(call gb_Module_add_targets,writerfilter,\
 
 $(eval $(call gb_Module_add_check_targets,writerfilter,\
     CppunitTest_writerfilter_rtftok \
+    CppunitTest_writerfilter_misc \
 ))
 
 #    CppunitTest_writerfilter_doctok \
diff --git a/writerfilter/qa/cppunittests/misc/misc.cxx b/writerfilter/qa/cppunittests/misc/misc.cxx
new file mode 100644
index 0000000..f7031b4
--- /dev/null
+++ b/writerfilter/qa/cppunittests/misc/misc.cxx
@@ -0,0 +1,162 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <limits>
+#include <vector>
+
+#include <boost/tuple/tuple.hpp>
+
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+#include <sal/types.h>
+
+#include <rtl/ustring.hxx>
+
+#include <WriterFilterDllApi.hxx>
+
+
+using namespace std;
+
+
+namespace writerfilter { namespace dmapper {
+
+SAL_DLLPUBLIC_IMPORT // export just for test
+boost::tuple<OUString, vector<OUString>, vector<OUString> >
+lcl_SplitFieldCommand(const OUString& rCommand);
+
+} }
+
+
+namespace {
+
+class WriterfilterMiscTest
+    : public ::CppUnit::TestFixture
+{
+public:
+    virtual void setUp();
+    virtual void tearDown();
+
+    void testFieldParameters();
+
+    CPPUNIT_TEST_SUITE(WriterfilterMiscTest);
+    CPPUNIT_TEST(testFieldParameters);
+    CPPUNIT_TEST_SUITE_END();
+};
+
+void WriterfilterMiscTest::setUp()
+{
+}
+
+void WriterfilterMiscTest::tearDown()
+{
+}
+
+void WriterfilterMiscTest::testFieldParameters()
+{
+    using writerfilter::dmapper::lcl_SplitFieldCommand;
+    boost::tuple<OUString, vector<OUString>, vector<OUString> > result;
+
+    result = lcl_SplitFieldCommand("PAGEREF last_page");
+    CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), boost::get<0>(result));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), boost::get<1>(result).size());
+    CPPUNIT_ASSERT_EQUAL(OUString("last_page"), boost::get<1>(result)[0]);
+    CPPUNIT_ASSERT(boost::get<2>(result).empty());
+
+    result = lcl_SplitFieldCommand(" PAGEREF last_page ");
+    CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), boost::get<0>(result));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), boost::get<1>(result).size());
+    CPPUNIT_ASSERT_EQUAL(OUString("last_page"), boost::get<1>(result)[0]);
+
+    result = lcl_SplitFieldCommand("pageref last_page");
+    CPPUNIT_ASSERT(boost::get<2>(result).empty());
+    CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), boost::get<0>(result));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), boost::get<1>(result).size());
+    CPPUNIT_ASSERT_EQUAL(OUString("last_page"), boost::get<1>(result)[0]);
+    CPPUNIT_ASSERT(boost::get<2>(result).empty());
+
+    result = lcl_SplitFieldCommand("pageref \"last_page\"");
+    CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), boost::get<0>(result));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), boost::get<1>(result).size());
+    CPPUNIT_ASSERT_EQUAL(OUString("last_page"), boost::get<1>(result)[0]);
+    CPPUNIT_ASSERT(boost::get<2>(result).empty());
+
+    result = lcl_SplitFieldCommand("\"PAGEREF\" \"last_page\" \"\" ");
+    CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), boost::get<0>(result));
+    CPPUNIT_ASSERT_EQUAL(size_t(2), boost::get<1>(result).size());
+    CPPUNIT_ASSERT_EQUAL(OUString("last_page"), boost::get<1>(result)[0]);
+    CPPUNIT_ASSERT_EQUAL(OUString(), boost::get<1>(result)[1]);
+    CPPUNIT_ASSERT(boost::get<2>(result).empty());
+
+    result = lcl_SplitFieldCommand("\"PAGEREF\"\"last_page\"  ");
+    CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), boost::get<0>(result));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), boost::get<1>(result).size());
+    CPPUNIT_ASSERT_EQUAL(OUString("last_page"), boost::get<1>(result)[0]);
+    CPPUNIT_ASSERT(boost::get<2>(result).empty());
+
+    result = lcl_SplitFieldCommand("PAGEREF\"last_page\"  ");
+    CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), boost::get<0>(result));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), boost::get<1>(result).size());
+    CPPUNIT_ASSERT_EQUAL(OUString("last_page"), boost::get<1>(result)[0]);
+    CPPUNIT_ASSERT(boost::get<2>(result).empty());
+
+    result = lcl_SplitFieldCommand("\"PAGEREF\"last_page \"\"");
+    CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), boost::get<0>(result));
+    CPPUNIT_ASSERT_EQUAL(size_t(2), boost::get<1>(result).size());
+    CPPUNIT_ASSERT_EQUAL(OUString("last_page"), boost::get<1>(result)[0]);
+    CPPUNIT_ASSERT_EQUAL(OUString(), boost::get<1>(result)[1]);
+    CPPUNIT_ASSERT(boost::get<2>(result).empty());
+
+    result = lcl_SplitFieldCommand("\"PAGEREF\"last_page \"\"");
+    CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), boost::get<0>(result));
+    CPPUNIT_ASSERT_EQUAL(size_t(2), boost::get<1>(result).size());
+    CPPUNIT_ASSERT_EQUAL(OUString("last_page"), boost::get<1>(result)[0]);
+    CPPUNIT_ASSERT_EQUAL(OUString(), boost::get<1>(result)[1]);
+    CPPUNIT_ASSERT(boost::get<2>(result).empty());
+
+    result = lcl_SplitFieldCommand("pageref \"last\\\\pa\\\"ge\"");
+    CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), boost::get<0>(result));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), boost::get<1>(result).size());
+    CPPUNIT_ASSERT_EQUAL(OUString("last\\pa\"ge"), boost::get<1>(result)[0]);
+    CPPUNIT_ASSERT(boost::get<2>(result).empty());
+
+    result = lcl_SplitFieldCommand("PAGEREF\"last_page\"\\*");
+    CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), boost::get<0>(result));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), boost::get<1>(result).size());
+    CPPUNIT_ASSERT_EQUAL(OUString("last_page"), boost::get<1>(result)[0]);
+    CPPUNIT_ASSERT_EQUAL(size_t(1), boost::get<2>(result).size());
+    CPPUNIT_ASSERT_EQUAL(OUString("\\*"), boost::get<2>(result)[0]);
+
+    result = lcl_SplitFieldCommand("PAGEREF  last_page   \\b   foobar ");
+    CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), boost::get<0>(result));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), boost::get<1>(result).size());
+    CPPUNIT_ASSERT_EQUAL(OUString("last_page"), boost::get<1>(result)[0]);
+    CPPUNIT_ASSERT_EQUAL(size_t(2), boost::get<2>(result).size());
+    CPPUNIT_ASSERT_EQUAL(OUString("\\B"), boost::get<2>(result)[0]);
+    CPPUNIT_ASSERT_EQUAL(OUString("foobar"), boost::get<2>(result)[1]);
+
+    result = lcl_SplitFieldCommand("PAGEREF\\bfoobar\\A\"\"");
+    CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), boost::get<0>(result));
+    CPPUNIT_ASSERT(boost::get<1>(result).empty());
+    CPPUNIT_ASSERT_EQUAL(size_t(4), boost::get<2>(result).size());
+    CPPUNIT_ASSERT_EQUAL(OUString("\\B"), boost::get<2>(result)[0]);
+    CPPUNIT_ASSERT_EQUAL(OUString("foobar"), boost::get<2>(result)[1]);
+    CPPUNIT_ASSERT_EQUAL(OUString("\\A"), boost::get<2>(result)[2]);
+    CPPUNIT_ASSERT_EQUAL(OUString(), boost::get<2>(result)[3]);
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(WriterfilterMiscTest);
+
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index b0cde8d..6d8feba 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -66,6 +66,7 @@
 #include <ooxml/OOXMLFastTokens.hxx>
 
 #include <map>
+#include <boost/tuple/tuple.hpp>
 
 #include <comphelper/configurationhelper.hxx>
 #include <comphelper/stlunosequence.hxx>
@@ -1933,37 +1934,133 @@ OUString lcl_ParseFormat( const OUString& rCommand )
 /*-------------------------------------------------------------------------
 extract a parameter (with or without quotes) between the command and the following backslash
   -----------------------------------------------------------------------*/
-OUString lcl_ExtractParameter(const OUString& rCommand, sal_Int32 nCommandLength )
+static OUString lcl_ExtractToken(OUString const& rCommand,
+        sal_Int32 & rIndex, bool & rHaveToken, bool & rIsSwitch)
 {
-    sal_Int32 nStartIndex = nCommandLength;
-    sal_Int32 nEndIndex = 0;
-    sal_Int32 nQuoteIndex = rCommand.indexOf( '\"', nStartIndex);
-    if( nQuoteIndex >= 0)
+    rHaveToken = false;
+    rIsSwitch = false;
+
+    OUStringBuffer token;
+    bool bQuoted(false);
+    for (; rIndex < rCommand.getLength(); ++rIndex)
     {
-        nStartIndex = nQuoteIndex + 1;
-        nEndIndex = rCommand.indexOf( '\"', nStartIndex + 1) - 1;
+        sal_Unicode const currentChar(rCommand[rIndex]);
+        switch (currentChar)
+        {
+            case '\\':
+            {
+                if (rIndex == rCommand.getLength() - 1)
+                {
+                    SAL_INFO("writerfilter.dmapper", "field: trailing escape");
+                    ++rIndex;
+                    return OUString();
+                }
+                sal_Unicode const nextChar(rCommand[rIndex+1]);
+                if (bQuoted || '\\' == nextChar)
+                {
+                    ++rIndex; // read 2 chars
+                    token.append(nextChar);
+                }
+                else // field switch (case insensitive)
+                {
+                    rHaveToken = true;
+                    if (token.isEmpty())
+                    {
+                        rIsSwitch = true;
+                        rIndex += 2; // read 2 chars
+                        return rCommand.copy(rIndex - 2, 2).toAsciiUpperCase();
+                    }
+                    else
+                    {   // leave rIndex, read it again next time
+                        return token.makeStringAndClear();
+                    }
+                }
+            }
+            break;
+            case '\"':
+                if (bQuoted || !token.isEmpty())
+                {
+                    rHaveToken = true;
+                    if (bQuoted)
+                    {
+                        ++rIndex;
+                    }
+                    return token.makeStringAndClear();
+                }
+                else
+                {
+                    bQuoted = true;
+                }
+            break;
+            case ' ':
+                if (bQuoted)
+                {
+                    token.append(' ');
+                }
+                else
+                {
+                    if (!token.isEmpty())
+                    {
+                        rHaveToken = true;
+                        ++rIndex;
+                        return token.makeStringAndClear();
+                    }
+                }
+            break;
+            default:
+                token.append(currentChar);
+            break;
+        }
+    }
+    assert(rIndex == rCommand.getLength());
+    if (bQuoted)
+    {
+        SAL_INFO("writerfilter.dmapper",
+                    "field argument with unterminated quote");
+        return OUString();
     }
     else
     {
-        nEndIndex = rCommand.indexOf(" \\", nStartIndex);
+        rHaveToken = !token.isEmpty();
+        return token.makeStringAndClear();
     }
-    OUString sRet;
-    if( nEndIndex > nStartIndex + 1 )
+}
+
+SAL_DLLPUBLIC_EXPORT // export just for test
+boost::tuple<OUString, vector<OUString>, vector<OUString> >
+lcl_SplitFieldCommand(const OUString& rCommand)
+{
+    OUString sType;
+    vector<OUString> arguments;
+    vector<OUString> switches;
+    sal_Int32 nStartIndex(0);
+
+    do
     {
-        //remove spaces at start and end of the result
-        if(nQuoteIndex <= 0)
+        bool bHaveToken;
+        bool bIsSwitch;
+        OUString const token =
+            lcl_ExtractToken(rCommand, nStartIndex, bHaveToken, bIsSwitch);
+        assert(nStartIndex <= rCommand.getLength());
+        if (bHaveToken)
         {
-            const sal_Unicode* pCommandStr = rCommand.getStr();
-            while( nStartIndex < nEndIndex && pCommandStr[nStartIndex] == ' ')
-                    ++nStartIndex;
-            while( nEndIndex > nStartIndex && pCommandStr[nEndIndex] == ' ')
-                    --nEndIndex;
+            if (sType.isEmpty())
+            {
+                sType = token.toAsciiUpperCase();
+            }
+            else if (bIsSwitch || !switches.empty())
+            {
+                switches.push_back(token);
+            }
+            else
+            {
+                arguments.push_back(token);
+            }
         }
-        sRet = rCommand.copy( nStartIndex, nEndIndex - nStartIndex + 1);
-    }
-    return sRet;
-}
+    } while (nStartIndex < rCommand.getLength());
 
+    return boost::make_tuple(sType, arguments, switches);
+}
 
 
 OUString lcl_ExctractAskVariableAndHint( const OUString& rCommand, OUString& rHint )
@@ -2411,7 +2508,7 @@ void DomainMapper_Impl::handleAutoNum
 }
 
 void DomainMapper_Impl::handleAuthor
-    (FieldContextPtr pContext,
+    (OUString const& rFirstParam,
     PropertyNameSupplier& rPropNameSupplier,
      uno::Reference< uno::XInterface > & /*xFieldInterface*/,
      uno::Reference< beans::XPropertySet > xFieldProperties,
@@ -2421,19 +2518,7 @@ void DomainMapper_Impl::handleAuthor
         xFieldProperties->setPropertyValue
             ( rPropNameSupplier.GetName(PROP_FULL_NAME), uno::makeAny( true ));
 
-    sal_Int32 nLen = sizeof( " AUTHOR" );
-    if ( eFieldId != FIELD_AUTHOR )
-    {
-        if (  eFieldId == FIELD_USERINITIALS )
-            nLen = sizeof( " USERINITIALS" );
-        else if (  eFieldId == FIELD_USERNAME )
-            nLen = sizeof( " USERNAME" );
-    }
-
-    OUString sParam =
-        lcl_ExtractParameter(pContext->GetCommand(), nLen );
-
-    if(!sParam.isEmpty())
+    if (!rFirstParam.isEmpty())
     {
         xFieldProperties->setPropertyValue(
                 rPropNameSupplier.GetName( PROP_IS_FIXED ),
@@ -2444,16 +2529,14 @@ void DomainMapper_Impl::handleAuthor
 
     void DomainMapper_Impl::handleDocProperty
         (FieldContextPtr pContext,
+        OUString const& rFirstParam,
         PropertyNameSupplier& rPropNameSupplier,
         uno::Reference< uno::XInterface > & xFieldInterface,
         uno::Reference< beans::XPropertySet > xFieldProperties)
 {
     //some docproperties should be imported as document statistic fields, some as DocInfo fields
     //others should be user fields
-    OUString sParam =
-        lcl_ExtractParameter(pContext->GetCommand(), sizeof(" DOCPROPERTY") );
-
-    if(!sParam.isEmpty())
+    if (!rFirstParam.isEmpty())
     {
         #define SET_ARABIC      0x01
         #define SET_FULL_NAME   0x02
@@ -2493,7 +2576,7 @@ void DomainMapper_Impl::handleAuthor
         for( ; nMap < sizeof(aDocProperties) / sizeof(DocPropertyMap);
             ++nMap )
         {
-            if(sParam.equalsAscii(aDocProperties[nMap].pDocPropertyName))
+            if (rFirstParam.equalsAscii(aDocProperties[nMap].pDocPropertyName))
             {
                 sFieldServiceName =
                 OUString::createFromAscii
@@ -2520,7 +2603,7 @@ void DomainMapper_Impl::handleAuthor
                 uno::UNO_QUERY_THROW);
         if( bIsCustomField )
             xFieldProperties->setPropertyValue(
-                rPropNameSupplier.GetName(PROP_NAME), uno::makeAny( sParam ));
+                rPropNameSupplier.GetName(PROP_NAME), uno::makeAny(rFirstParam));
         else
         {
             if(0 != (aDocProperties[nMap].nFlags & SET_ARABIC))
@@ -2820,13 +2903,14 @@ void DomainMapper_Impl::CloseFieldCommand()
         try
         {
             uno::Reference< uno::XInterface > xFieldInterface;
-            //at first determine the field type - erase leading and trailing whitespaces
-            OUString sCommand( pContext->GetCommand().trim() );
-            sal_Int32 nSpaceIndex = sCommand.indexOf( ' ' );
-            if( 0 <= nSpaceIndex )
-                sCommand = sCommand.copy( 0, nSpaceIndex );
 
-            FieldConversionMap_t::iterator aIt = aFieldConversionMap.find(sCommand);
+            boost::tuple<OUString, vector<OUString>, vector<OUString> > const
+                field(lcl_SplitFieldCommand(pContext->GetCommand()));
+            OUString const sFirstParam(boost::get<1>(field).empty()
+                    ? OUString() : boost::get<1>(field).front());
+
+            FieldConversionMap_t::iterator const aIt =
+                aFieldConversionMap.find(boost::get<0>(field));
             if(aIt != aFieldConversionMap.end())
             {
                 uno::Reference< beans::XPropertySet > xFieldProperties;
@@ -2868,7 +2952,8 @@ void DomainMapper_Impl::CloseFieldCommand()
                     if ( bCreateEnhancedField )
                     {
                         FieldConversionMap_t aEnhancedFieldConversionMap = lcl_GetEnhancedFieldConversion();
-                        FieldConversionMap_t::iterator aEnhancedIt = aEnhancedFieldConversionMap.find(sCommand);
+                        FieldConversionMap_t::iterator aEnhancedIt =
+                            aEnhancedFieldConversionMap.find(boost::get<0>(field));
                         if ( aEnhancedIt != aEnhancedFieldConversionMap.end())
                             sServiceName += OUString::createFromAscii(aEnhancedIt->second.cFieldServiceName );
                     }
@@ -2906,7 +2991,9 @@ void DomainMapper_Impl::CloseFieldCommand()
                     case FIELD_AUTHOR       :
                     case FIELD_USERNAME     :
                     case FIELD_USERINITIALS :
-                        handleAuthor(pContext, rPropNameSupplier, xFieldInterface, xFieldProperties, aIt->second.eFieldId  );
+                        handleAuthor(sFirstParam, rPropNameSupplier,
+                            xFieldInterface, xFieldProperties,
+                            aIt->second.eFieldId);
                     break;
                     case FIELD_DATE:
                     if (xFieldProperties.is())
@@ -2945,14 +3032,14 @@ void DomainMapper_Impl::CloseFieldCommand()
                     }
                     break;
                     case FIELD_DOCPROPERTY :
-                        handleDocProperty(pContext, rPropNameSupplier, xFieldInterface, xFieldProperties);
+                        handleDocProperty(pContext, sFirstParam, rPropNameSupplier,
+                                xFieldInterface, xFieldProperties);
                     break;
                     case FIELD_DOCVARIABLE  :
                     {
-                        OUString sParam = lcl_ExtractParameter(pContext->GetCommand(), sizeof(" DOCVARIABLE") );
                         //create a user field and type
                         uno::Reference< beans::XPropertySet > xMaster =
-                            FindOrCreateFieldMaster( "com.sun.star.text.FieldMaster.User", sParam );
+                            FindOrCreateFieldMaster("com.sun.star.text.FieldMaster.User", sFirstParam);
                         uno::Reference< text::XDependentTextField > xDependentField( xFieldInterface, uno::UNO_QUERY_THROW );
                         xDependentField->attachTextFieldMaster( xMaster );
                         m_bSetUserFieldContent = true;
@@ -2964,7 +3051,7 @@ void DomainMapper_Impl::CloseFieldCommand()
                     case FIELD_EQ:
                     {
                         OUString aCommand = pContext->GetCommand().trim();
-                        nSpaceIndex = aCommand.indexOf(' ');
+                        sal_Int32 nSpaceIndex = aCommand.indexOf(' ');
                         if(nSpaceIndex > 0)
                             aCommand = aCommand.copy(nSpaceIndex).trim();
                         if (aCommand.startsWith("\\s"))
@@ -3094,8 +3181,7 @@ void DomainMapper_Impl::CloseFieldCommand()
                     case FIELD_INCLUDEPICTURE: break;
                     case FIELD_KEYWORDS     :
                     {
-                        OUString sParam = lcl_ExtractParameter(pContext->GetCommand(), sizeof(" KEYWORDS") );
-                        if(!sParam.isEmpty())
+                        if (!sFirstParam.isEmpty())
                         {
                             xFieldProperties->setPropertyValue(
                                     rPropNameSupplier.GetName( PROP_IS_FIXED ), uno::makeAny( true ));
@@ -3125,10 +3211,9 @@ void DomainMapper_Impl::CloseFieldCommand()
                     case FIELD_MERGEFIELD  :
                     {
                         //todo: create a database field and fieldmaster pointing to a column, only
-                        OUString sParam = lcl_ExtractParameter(pContext->GetCommand(), sizeof(" MERGEFIELD") );
                         //create a user field and type
                         uno::Reference< beans::XPropertySet > xMaster =
-                            FindOrCreateFieldMaster( "com.sun.star.text.FieldMaster.Database", sParam );
+                            FindOrCreateFieldMaster("com.sun.star.text.FieldMaster.Database", sFirstParam);
 
     //                    xFieldProperties->setPropertyValue(
     //                             "FieldCode",
@@ -3159,21 +3244,21 @@ void DomainMapper_Impl::CloseFieldCommand()
                     if (xFieldProperties.is())
                     {
                         bool bPageRef = aIt->second.eFieldId == FIELD_PAGEREF;
-                        OUString sBookmark = lcl_ExtractParameter(pContext->GetCommand(),
-                                (bPageRef ? sizeof(" PAGEREF") : sizeof(" REF")));
 
                         // Do we need a GetReference (default) or a GetExpression field?
                         uno::Reference< text::XTextFieldsSupplier > xFieldsSupplier( GetTextDocument(), uno::UNO_QUERY );
                         uno::Reference< container::XNameAccess > xFieldMasterAccess = xFieldsSupplier->getTextFieldMasters();
 
-                        if (!xFieldMasterAccess->hasByName("com.sun.star.text.FieldMaster.SetExpression." + sBookmark))
+                        if (!xFieldMasterAccess->hasByName(
+                                "com.sun.star.text.FieldMaster.SetExpression."
+                                + sFirstParam))
                         {
                         xFieldProperties->setPropertyValue(
                             rPropNameSupplier.GetName(PROP_REFERENCE_FIELD_SOURCE),
                             uno::makeAny( sal_Int16(text::ReferenceFieldSource::BOOKMARK)) );
                         xFieldProperties->setPropertyValue(
                             rPropNameSupplier.GetName(PROP_SOURCE_NAME),
-                            uno::makeAny( sBookmark) );
+                            uno::makeAny(sFirstParam) );
                         sal_Int16 nFieldPart = (bPageRef ? text::ReferenceFieldPart::PAGE : text::ReferenceFieldPart::TEXT);
                         OUString sValue;
                         if( lcl_FindInCommand( pContext->GetCommand(), 'p', sValue ))
@@ -3203,7 +3288,9 @@ void DomainMapper_Impl::CloseFieldCommand()
                         {
                             xFieldInterface = m_xTextFactory->createInstance("com.sun.star.text.TextField.GetExpression");
                             xFieldProperties.set(xFieldInterface, uno::UNO_QUERY);
-                            xFieldProperties->setPropertyValue(rPropNameSupplier.GetName(PROP_CONTENT), uno::makeAny(sBookmark));
+                            xFieldProperties->setPropertyValue(
+                                rPropNameSupplier.GetName(PROP_CONTENT),
+                                uno::makeAny(sFirstParam));
                             xFieldProperties->setPropertyValue(rPropNameSupplier.GetName(PROP_SUB_TYPE), uno::makeAny(text::SetVariableType::STRING));
                         }
                     }
@@ -3270,8 +3357,7 @@ void DomainMapper_Impl::CloseFieldCommand()
                     case FIELD_STYLEREF     : break;
                     case FIELD_SUBJECT      :
                     {
-                        OUString sParam = lcl_ExtractParameter(pContext->GetCommand(), sizeof(" SUBJECT") );
-                        if(!sParam.isEmpty())
+                        if (!sFirstParam.isEmpty())
                         {
                             xFieldProperties->setPropertyValue(
                                     rPropNameSupplier.GetName( PROP_IS_FIXED ), uno::makeAny( true ));
@@ -3286,8 +3372,7 @@ void DomainMapper_Impl::CloseFieldCommand()
                     break;
                     case FIELD_TITLE        :
                     {
-                        OUString sParam = lcl_ExtractParameter(pContext->GetCommand(), sizeof(" TITLE") );
-                        if(!sParam.isEmpty())
+                        if (!sFirstParam.isEmpty())
                         {
                             xFieldProperties->setPropertyValue(
                                     rPropNameSupplier.GetName( PROP_IS_FIXED ), uno::makeAny( true ));
@@ -3307,10 +3392,11 @@ void DomainMapper_Impl::CloseFieldCommand()
                             m_xTextFactory->createInstance(
                                 OUString::createFromAscii(aIt->second.cFieldServiceName)),
                                 uno::UNO_QUERY_THROW);
-                        OUString sTCText = lcl_ExtractParameter(pContext->GetCommand(), sizeof(" TC") );
-                        if( !sTCText.isEmpty())
+                        if (!sFirstParam.isEmpty())
+                        {
                             xTC->setPropertyValue(rPropNameSupplier.GetName(PROP_ALTERNATIVE_TEXT),
-                                uno::makeAny(sTCText));
+                                uno::makeAny(sFirstParam));
+                        }
                         OUString sValue;
                         // \f TC entry in doc with multiple tables
     //                    if( lcl_FindInCommand( pContext->GetCommand(), 'f', sValue ))
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index 8bc422f..5ac6204 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -573,13 +573,14 @@ public:
         uno::Reference< uno::XInterface > & xFieldInterface,
         uno::Reference< beans::XPropertySet > xFieldProperties);
     void handleAuthor
-        (FieldContextPtr pContext,
+        (OUString const& rFirstParam,
         PropertyNameSupplier& rPropNameSupplier,
         uno::Reference< uno::XInterface > & xFieldInterface,
         uno::Reference< beans::XPropertySet > xFieldProperties,
         FieldId eFieldId);
     void handleDocProperty
         (FieldContextPtr pContext,
+        OUString const& rFirstParam,
         PropertyNameSupplier& rPropNameSupplier,
         uno::Reference< uno::XInterface > & xFieldInterface,
         uno::Reference< beans::XPropertySet > xFieldProperties);
-- 
1.8.3.1