Kaydet (Commit) 5342cd75 authored tarafından Caolán McNamara's avatar Caolán McNamara

Resolves: fdo#66400 import combined characters from docx

move .doc combined character parser stuff from sw to filter for reuse in .docx

and fix bad length problem when nSavPtr == -1 after String->OUString conversion

thanks for the pasta CloudOn

Change-Id: I368ca30c14fd089271902b9b874de1099eb40038
üst 2de32959
......@@ -9,6 +9,7 @@
#include <rtl/ustring.hxx>
#include <rtl/strbuf.hxx>
#include <tools/string.hxx>
#include <unotools/fontcvt.hxx>
#include <unotools/fontdefs.hxx>
#include <vcl/svapp.hxx>
......@@ -445,6 +446,289 @@ OUString findQuotedText( const OUString& rCommand,
}
WW8ReadFieldParams::WW8ReadFieldParams( const OUString& _rData )
: aData( _rData )
, nFnd( 0 )
, nNext( 0 )
, nSavPtr( 0 )
{
/*
erstmal nach einer oeffnenden Klammer oder einer Leerstelle oder einem
Anfuehrungszeichen oder einem Backslash suchen, damit der Feldbefehl
(also INCLUDEPICTURE bzw EINFUeGENGRAFIK bzw ...) ueberlesen wird
*/
const sal_Int32 nLen = aData.getLength();
while ( nNext<nLen && aData[nNext]==' ' )
++nNext;
while ( nNext<nLen )
{
const sal_Unicode c = aData[nNext];
if ( c==' ' || c=='"' || c=='\\' || c==132 || c==0x201c )
break;
++nNext;
}
nFnd = nNext;
nSavPtr = nNext;
}
WW8ReadFieldParams::~WW8ReadFieldParams()
{
}
OUString WW8ReadFieldParams::GetResult() const
{
if (nFnd<0 && nSavPtr>nFnd)
return OUString();
else
{
return nSavPtr == -1 ? aData.copy(nFnd) : aData.copy(nFnd, nSavPtr-nFnd);
}
}
bool WW8ReadFieldParams::GoToTokenParam()
{
const sal_Int32 nOld = nNext;
if( -2 == SkipToNextToken() )
return GetTokenSttPtr()>=0;
nNext = nOld;
return false;
}
// ret: -2: NOT a '\' parameter but normal Text
sal_Int32 WW8ReadFieldParams::SkipToNextToken()
{
if ( nNext<0 || nNext>=aData.getLength() )
return -1;
nFnd = FindNextStringPiece(nNext);
if ( nFnd<0 )
return -1;
nSavPtr = nNext;
if ( aData[nFnd]=='\\' && nFnd+1<aData.getLength() && aData[nFnd+1]!='\\' )
{
const sal_Int32 nRet = aData[++nFnd];
nNext = ++nFnd; // und dahinter setzen
return nRet;
}
if ( nSavPtr>0 && (aData[nSavPtr-1]=='"' || aData[nSavPtr-1]==0x201d ) )
{
--nSavPtr;
}
return -2;
}
// FindNextPara sucht naechsten Backslash-Parameter oder naechste Zeichenkette
// bis zum Blank oder naechsten "\" oder zum schliessenden Anfuehrungszeichen
// oder zum String-Ende von pStr.
//
// Ausgabe ppNext (falls ppNext != 0) Suchbeginn fuer naechsten Parameter bzw. 0
//
// Returnwert: 0 falls String-Ende erreicht,
// ansonsten Anfang des Paramters bzw. der Zeichenkette
//
sal_Int32 WW8ReadFieldParams::FindNextStringPiece(const sal_Int32 nStart)
{
const sal_Int32 nLen = aData.getLength();
sal_Int32 n = nStart<0 ? nFnd : nStart; // Anfang
sal_Int32 n2; // Ende
nNext = -1; // Default fuer nicht gefunden
while ( n<nLen && aData[n]==' ' )
++n;
if ( n==nLen )
return -1;
if ( aData[n]==0x13 )
{
// Skip the nested field code since it's not supported
while ( n<nLen && aData[n]!=0x14 )
++n;
if ( n==nLen )
return -1;
}
// Anfuehrungszeichen vor Para?
if ( aData[n]=='"' || aData[n]==0x201c || aData[n]==132 || aData[n]==0x14 )
{
n++; // Anfuehrungszeichen ueberlesen
n2 = n; // ab hier nach Ende suchen
while( (nLen > n2)
&& (aData[n2] != '"')
&& (aData[n2] != 0x201d)
&& (aData[n2] != 147)
&& (aData[n2] != 0x15) )
n2++; // Ende d. Paras suchen
}
else // keine Anfuehrungszeichen
{
n2 = n; // ab hier nach Ende suchen
while ( n2<nLen && aData[n2]!=' ' ) // Ende d. Paras suchen
{
if ( aData[n2]=='\\' )
{
if ( n2+1<nLen && aData[n2+1]=='\\' )
n2 += 2; // Doppel-Backslash -> OK
else
{
if( n2 > n )
n2--;
break; // einfach-Backslash -> Ende
}
}
else
n2++; // kein Backslash -> OK
}
}
if( nLen > n2 )
{
if (aData[n2]!=' ') ++n2;
nNext = n2;
}
return n;
}
// read parameters "1-3" or 1-3 with both values between 1 and nMax
bool WW8ReadFieldParams::GetTokenSttFromTo(sal_Int32* pFrom, sal_Int32* pTo, sal_Int32 nMax)
{
sal_Int32 nStart = 0;
sal_Int32 nEnd = 0;
if ( GoToTokenParam() )
{
const OUString sParams( GetResult() );
sal_Int32 nIndex = 0;
const OUString sStart( sParams.getToken(0, '-', nIndex) );
if (nIndex>=0)
{
nStart = sStart.toInt32();
nEnd = sParams.copy(nIndex).toInt32();
}
}
if( pFrom ) *pFrom = nStart;
if( pTo ) *pTo = nEnd;
return nStart && nEnd && (nMax >= nStart) && (nMax >= nEnd);
}
EquationResult Read_SubF_Combined(WW8ReadFieldParams& rReadParam)
{
EquationResult aResult;
String sCombinedCharacters;
WW8ReadFieldParams aOriFldParam = rReadParam;
const sal_Int32 cGetChar = rReadParam.SkipToNextToken();
switch( cGetChar )
{
case 'a':
case 'A':
if ( !rReadParam.GetResult().startsWithIgnoreAsciiCase("d") )
{
break;
}
rReadParam.SkipToNextToken();
// intentional fall-through
case -2:
{
if ( rReadParam.GetResult().startsWithIgnoreAsciiCase("(") )
{
for (int i=0;i<2;i++)
{
if ('s' == rReadParam.SkipToNextToken())
{
const sal_Int32 cChar = rReadParam.SkipToNextToken();
if (-2 != rReadParam.SkipToNextToken())
break;
const OUString sF = rReadParam.GetResult();
if ((('u' == cChar) && sF.startsWithIgnoreAsciiCase("p"))
|| (('d' == cChar) && sF.startsWithIgnoreAsciiCase("o")))
{
if (-2 == rReadParam.SkipToNextToken())
{
String sPart = rReadParam.GetResult();
xub_StrLen nBegin = sPart.Search('(');
//Word disallows brackets in this field, which
//aids figuring out the case of an end of )) vs )
xub_StrLen nEnd = sPart.Search(')');
if ((nBegin != STRING_NOTFOUND) &&
(nEnd != STRING_NOTFOUND))
{
sCombinedCharacters +=
sPart.Copy(nBegin+1,nEnd-nBegin-1);
}
}
}
}
}
if (sCombinedCharacters.Len())
{
aResult.sType = "CombinedCharacters";
aResult.sResult = sCombinedCharacters;
}
else
{
const String sPart = aOriFldParam.GetResult();
xub_StrLen nBegin = sPart.Search('(');
xub_StrLen nEnd = sPart.Search(',');
if ( nEnd == STRING_NOTFOUND )
{
nEnd = sPart.Search(')');
}
if ( (nBegin != STRING_NOTFOUND) && (nEnd != STRING_NOTFOUND) )
{
// skip certain leading characters
for (int i = nBegin;i < nEnd-1;i++)
{
const sal_Unicode cC = sPart.GetChar(nBegin+1);
if ( cC < 32 )
{
nBegin++;
}
else
break;
}
sCombinedCharacters = sPart.Copy( nBegin+1, nEnd-nBegin-1 );
if ( sCombinedCharacters.Len() )
{
aResult.sType = "Input";
aResult.sResult = sCombinedCharacters;
}
}
}
}
}
default:
break;
}
return aResult;
}
EquationResult ParseCombinedChars(const OUString& rStr)
{
EquationResult aResult;
WW8ReadFieldParams aReadParam( rStr );
const sal_Int32 cChar = aReadParam.SkipToNextToken();
if ('o' == cChar || 'O' == cChar)
aResult = Read_SubF_Combined(aReadParam);
return aResult;
}
}
}
......
......@@ -95,7 +95,38 @@ public:
* Example: SEQ "Figure" \someoption -> "Figure"
*/
MSFILTER_DLLPUBLIC OUString findQuotedText( const OUString& rCommand, const sal_Char* cStartQuote, const sal_Unicode uEndQuote );
class MSFILTER_DLLPUBLIC WW8ReadFieldParams
{
private:
const OUString aData;
sal_Int32 nFnd;
sal_Int32 nNext;
sal_Int32 nSavPtr;
public:
WW8ReadFieldParams( const OUString& rData );
~WW8ReadFieldParams();
bool GoToTokenParam();
sal_Int32 SkipToNextToken();
sal_Int32 GetTokenSttPtr() const { return nFnd; }
sal_Int32 FindNextStringPiece( sal_Int32 _nStart = -1 );
bool GetTokenSttFromTo(sal_Int32* _pFrom, sal_Int32* _pTo, sal_Int32 _nMax);
OUString GetResult() const;
};
struct MSFILTER_DLLPUBLIC EquationResult
{
OUString sResult;
OUString sType;
};
MSFILTER_DLLPUBLIC EquationResult ParseCombinedChars(const OUString& rStr);
}
}
#endif
......
......@@ -23,6 +23,7 @@
#include <tools/string.hxx>
#include "rtl/ustring.hxx"
#include <filter/msfilter/msdffimp.hxx>
#include <filter/msfilter/util.hxx>
#include <editeng/frmdir.hxx>
#include <fltshell.hxx>
......@@ -100,7 +101,6 @@ class SwAttrSet;
class GDIMetaFile;
struct ESelection;
class SfxItemSet;
class WW8ReadFieldParams;
class wwZOrderer;
class OutlinerParaObject;
......@@ -111,6 +111,8 @@ namespace com{namespace sun {namespace star{
namespace lang{class XMultiServiceFactory;}
}}}
using namespace msfilter::util;
// defines nur fuer die WW8-variable der INI-Datei
#define WW8FL_NO_TEXT 1
#define WW8FL_NO_STYLES 2
......@@ -1771,7 +1773,6 @@ public: // eigentlich private, geht aber leider nur public
eF_ResT Read_F_DBNum( WW8FieldDesc*, OUString& );
eF_ResT Read_F_Equation( WW8FieldDesc*, OUString& );
void Read_SubF_Ruby( WW8ReadFieldParams& rReadParam);
void Read_SubF_Combined( WW8ReadFieldParams& rReadParam);
eF_ResT Read_F_IncludePicture( WW8FieldDesc*, OUString& rStr );
eF_ResT Read_F_IncludeText( WW8FieldDesc*, OUString& rStr );
eF_ResT Read_F_Seq( WW8FieldDesc*, OUString& rStr );
......
......@@ -3000,29 +3000,44 @@ void DomainMapper_Impl::CloseFieldCommand()
case FIELD_EQ:
{
OUString aCommand = pContext->GetCommand().trim();
nSpaceIndex = aCommand.indexOf(' ');
if(nSpaceIndex > 0)
aCommand = aCommand.copy(nSpaceIndex).trim();
if (aCommand.startsWith("\\s"))
msfilter::util::EquationResult aResult(msfilter::util::ParseCombinedChars(aCommand));
if (!aResult.sType.isEmpty() && m_xTextFactory.is())
{
OUString sServiceName("com.sun.star.text.TextField.");
xFieldInterface = m_xTextFactory->createInstance(sServiceName + aResult.sType);
xFieldProperties =
uno::Reference< beans::XPropertySet >( xFieldInterface,
uno::UNO_QUERY_THROW);
xFieldProperties->setPropertyValue(rPropNameSupplier.GetName(PROP_CONTENT), uno::makeAny(aResult.sResult));
}
else
{
aCommand = aCommand.copy(2);
if (aCommand.startsWith("\\do"))
//merge Read_SubF_Ruby into filter/.../util.cxx and reuse that ?
nSpaceIndex = aCommand.indexOf(' ');
if(nSpaceIndex > 0)
aCommand = aCommand.copy(nSpaceIndex).trim();
if (aCommand.startsWith("\\s"))
{
aCommand = aCommand.copy(3);
sal_Int32 nStartIndex = aCommand.indexOf('(');
sal_Int32 nEndIndex = aCommand.indexOf(')');
if (nStartIndex > 0 && nEndIndex > 0)
aCommand = aCommand.copy(2);
if (aCommand.startsWith("\\do"))
{
// nDown is the requested "lower by" value in points.
sal_Int32 nDown = aCommand.copy(0, nStartIndex).toInt32();
OUString aContent = aCommand.copy(nStartIndex + 1, nEndIndex - nStartIndex - 1);
PropertyMapPtr pCharContext = GetTopContext();
// dHeight is the font size of the current style.
double dHeight = 0;
if (GetPropertyFromStyleSheet(PROP_CHAR_HEIGHT) >>= dHeight)
// Character escapement should be given in negative percents for subscripts.
pCharContext->Insert(PROP_CHAR_ESCAPEMENT, uno::makeAny( sal_Int16(- 100 * nDown / dHeight) ) );
appendTextPortion(aContent, pCharContext);
aCommand = aCommand.copy(3);
sal_Int32 nStartIndex = aCommand.indexOf('(');
sal_Int32 nEndIndex = aCommand.indexOf(')');
if (nStartIndex > 0 && nEndIndex > 0)
{
// nDown is the requested "lower by" value in points.
sal_Int32 nDown = aCommand.copy(0, nStartIndex).toInt32();
OUString aContent = aCommand.copy(nStartIndex + 1, nEndIndex - nStartIndex - 1);
PropertyMapPtr pCharContext = GetTopContext();
// dHeight is the font size of the current style.
double dHeight = 0;
if (GetPropertyFromStyleSheet(PROP_CHAR_HEIGHT) >>= dHeight)
// Character escapement should be given in negative percents for subscripts.
pCharContext->Insert(PROP_CHAR_ESCAPEMENT, uno::makeAny( sal_Int16(- 100 * nDown / dHeight) ) );
appendTextPortion(aContent, pCharContext);
}
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment