ofz#70674 Null-dereference READ

xCursorTunnel.get() is a SvxUnoTextCursor in this case

Change-Id: Iaa50a4895923bc1635dc69325203de7bfb77886b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171064
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
This commit is contained in:
Caolán McNamara 2024-07-26 09:05:56 +01:00
parent 6148e1a0e0
commit 19a73f096a
2 changed files with 184 additions and 173 deletions

View file

@ -631,179 +631,7 @@ void SwXMLImport::endDocument()
if( HasShapeImport() )
ClearShapeImport();
SwDoc *pDoc = nullptr;
if( (getImportFlags() & SvXMLImportFlags::CONTENT) && !IsStylesOnlyMode() )
{
Reference<XInterface> xCursorTunnel( GetTextImport()->GetCursor(),
UNO_QUERY);
assert(xCursorTunnel.is() && "missing XUnoTunnel for Cursor");
OTextCursorHelper* pTextCursor = dynamic_cast<OTextCursorHelper*>(xCursorTunnel.get());
assert(pTextCursor && "SwXTextCursor missing");
SwPaM *pPaM = pTextCursor->GetPaM();
if( IsInsertMode() && m_oSttNdIdx->GetIndex() )
{
// If we are in insert mode, join the split node that is in front
// of the new content with the first new node. Or in other words:
// Revert the first split node.
SwTextNode* pTextNode = m_oSttNdIdx->GetNode().GetTextNode();
SwNodeIndex aNxtIdx( *m_oSttNdIdx );
if( pTextNode && pTextNode->CanJoinNext( &aNxtIdx ) &&
m_oSttNdIdx->GetIndex() + 1 == aNxtIdx.GetIndex() )
{
// If the PaM points to the first new node, move the PaM to the
// end of the previous node.
if( pPaM->GetPoint()->GetNode() == aNxtIdx.GetNode() )
{
pPaM->GetPoint()->Assign( *pTextNode,
pTextNode->GetText().getLength());
}
#if OSL_DEBUG_LEVEL > 0
// !!! This should be impossible !!!!
OSL_ENSURE( m_oSttNdIdx->GetIndex()+1 !=
pPaM->GetBound().GetNodeIndex(),
"PaM.Bound1 point to new node " );
OSL_ENSURE( m_oSttNdIdx->GetIndex()+1 !=
pPaM->GetBound( false ).GetNodeIndex(),
"PaM.Bound2 points to new node" );
if( m_oSttNdIdx->GetIndex()+1 ==
pPaM->GetBound().GetNodeIndex() )
{
const sal_Int32 nCntPos =
pPaM->GetBound().GetContentIndex();
pPaM->GetBound().SetContent(
pTextNode->GetText().getLength() + nCntPos );
}
if( m_oSttNdIdx->GetIndex()+1 ==
pPaM->GetBound( false ).GetNodeIndex() )
{
const sal_Int32 nCntPos =
pPaM->GetBound( false ).GetContentIndex();
pPaM->GetBound( false ).SetContent(
pTextNode->GetText().getLength() + nCntPos );
}
#endif
// If the first new node isn't empty, convert the node's text
// attributes into hints. Otherwise, set the new node's
// paragraph style at the previous (empty) node.
SwTextNode* pDelNd = aNxtIdx.GetNode().GetTextNode();
if (!pTextNode->GetText().isEmpty())
pDelNd->FormatToTextAttr( pTextNode );
else
{
pTextNode->ResetAttr(RES_CHRATR_BEGIN, RES_CHRATR_END);
pTextNode->ChgFormatColl( pDelNd->GetTextColl() );
if (!pDelNd->GetNoCondAttr(RES_PARATR_LIST_ID, /*bInParents=*/false))
{
// MergeListsAtDocumentInsertPosition() will deal with lists below, copy
// paragraph direct formatting otherwise.
pDelNd->CopyCollFormat(*pTextNode);
}
}
pTextNode->JoinNext();
}
}
SwPosition* pPos = pPaM->GetPoint();
OSL_ENSURE( !pPos->GetContentIndex(), "last paragraph isn't empty" );
if( !pPos->GetContentIndex() )
{
SwTextNode* pCurrNd;
SwNodeOffset nNodeIdx = pPos->GetNodeIndex();
pDoc = &pPaM->GetDoc();
OSL_ENSURE( pPos->GetNode().IsContentNode(),
"insert position is not a content node" );
if( !IsInsertMode() )
{
// If we're not in insert mode, the last node is deleted.
const SwNode *pPrev = pDoc->GetNodes()[nNodeIdx -1];
if( pPrev->IsContentNode() ||
( pPrev->IsEndNode() &&
pPrev->StartOfSectionNode()->IsSectionNode() ) )
{
SwContentNode* pCNd = pPaM->GetPointContentNode();
if( pCNd && pCNd->StartOfSectionIndex()+2 <
pCNd->EndOfSectionIndex() )
{
SwNode& rDelNode = pPaM->GetPoint()->GetNode();
// move so we don't have a dangling SwContentIndex to the deleted node
pPaM->GetPoint()->Adjust(SwNodeOffset(+1));
if (pPaM->HasMark())
pPaM->GetMark()->Adjust(SwNodeOffset(+1));
pDoc->GetNodes().Delete( rDelNode );
}
}
}
else if( nullptr != (pCurrNd = pDoc->GetNodes()[nNodeIdx]->GetTextNode()) )
{
// Id we're in insert mode, the empty node is joined with
// the next and the previous one.
if( pCurrNd->CanJoinNext( pPos ))
{
SwTextNode* pNextNd = pPos->GetNode().GetTextNode();
bool endNodeFound = pDoc->GetNodes()[nNodeIdx-1]->IsEndNode();
SwNode *pLastPar = pDoc->GetNodes()[nNodeIdx -2];
if ( !pLastPar->IsTextNode() ) {
pLastPar = pDoc->GetNodes()[nNodeIdx -1];
}
if ( !endNodeFound && pLastPar->IsTextNode() )
{
pNextNd->ChgFormatColl(pLastPar->GetTextNode()->GetTextColl());
}
pPaM->SetMark(); pPaM->DeleteMark();
pNextNd->JoinPrev();
// Remove line break that has been inserted by the import,
// but only if one has been inserted and
// no endNode found to avoid removing section
if( pNextNd->CanJoinPrev(/* &pPos->nNode*/ ) && !endNodeFound &&
*m_oSttNdIdx != pPos->GetNode() )
{
pNextNd->JoinPrev();
}
}
else if (pCurrNd->GetText().isEmpty())
{
pPaM->SetMark(); pPaM->DeleteMark();
SwNode& rDelNode = pPos->GetNode();
// move so we don't have a dangling SwContentIndex to the deleted node
pPaM->GetPoint()->Adjust(SwNodeOffset(+1));
pDoc->GetNodes().Delete( rDelNode );
pPaM->Move( fnMoveBackward );
}
}
// tdf#113877
// when we insert one document with list inside into another one with list at the insert position,
// the resulting numbering in these lists is not consequent.
//
// Main document:
// 1. One
// 2. Two
// 3. Three
// 4. <-- insert position
//
// Inserted document:
// 1. One
// 2. Two
// 3. Three
// 4.
//
// Expected result
// 1. One
// 2. Two
// 3. Three
// 4. One
// 5. Two
// 6. Three
// 7.
//
MergeListsAtDocumentInsertPosition(pDoc);
}
}
SwDoc *pDoc = endDocAdjustNodes();
/* Was called too early. Moved from SwXMLBodyContext_Impl::EndElement */
@ -1069,6 +897,188 @@ void SwXMLImport::MergeListsAtDocumentInsertPosition(SwDoc *pDoc)
}
}
SwDoc* SwXMLImport::endDocAdjustNodes()
{
SwDoc *pDoc = nullptr;
if( (getImportFlags() & SvXMLImportFlags::CONTENT) && !IsStylesOnlyMode() )
{
Reference<XInterface> xCursorTunnel( GetTextImport()->GetCursor(),
UNO_QUERY);
assert(xCursorTunnel.is() && "missing XUnoTunnel for Cursor");
OTextCursorHelper* pTextCursor = dynamic_cast<OTextCursorHelper*>(xCursorTunnel.get());
if (!pTextCursor)
{
SAL_WARN("sw", "SwXMLImport::endDocAdjustNodes: SwXTextCursor missing");
return nullptr;
}
SwPaM *pPaM = pTextCursor->GetPaM();
if( IsInsertMode() && m_oSttNdIdx->GetIndex() )
{
// If we are in insert mode, join the split node that is in front
// of the new content with the first new node. Or in other words:
// Revert the first split node.
SwTextNode* pTextNode = m_oSttNdIdx->GetNode().GetTextNode();
SwNodeIndex aNxtIdx( *m_oSttNdIdx );
if( pTextNode && pTextNode->CanJoinNext( &aNxtIdx ) &&
m_oSttNdIdx->GetIndex() + 1 == aNxtIdx.GetIndex() )
{
// If the PaM points to the first new node, move the PaM to the
// end of the previous node.
if( pPaM->GetPoint()->GetNode() == aNxtIdx.GetNode() )
{
pPaM->GetPoint()->Assign( *pTextNode,
pTextNode->GetText().getLength());
}
#if OSL_DEBUG_LEVEL > 0
// !!! This should be impossible !!!!
OSL_ENSURE( m_oSttNdIdx->GetIndex()+1 !=
pPaM->GetBound().GetNodeIndex(),
"PaM.Bound1 point to new node " );
OSL_ENSURE( m_oSttNdIdx->GetIndex()+1 !=
pPaM->GetBound( false ).GetNodeIndex(),
"PaM.Bound2 points to new node" );
if( m_oSttNdIdx->GetIndex()+1 ==
pPaM->GetBound().GetNodeIndex() )
{
const sal_Int32 nCntPos =
pPaM->GetBound().GetContentIndex();
pPaM->GetBound().SetContent(
pTextNode->GetText().getLength() + nCntPos );
}
if( m_oSttNdIdx->GetIndex()+1 ==
pPaM->GetBound( false ).GetNodeIndex() )
{
const sal_Int32 nCntPos =
pPaM->GetBound( false ).GetContentIndex();
pPaM->GetBound( false ).SetContent(
pTextNode->GetText().getLength() + nCntPos );
}
#endif
// If the first new node isn't empty, convert the node's text
// attributes into hints. Otherwise, set the new node's
// paragraph style at the previous (empty) node.
SwTextNode* pDelNd = aNxtIdx.GetNode().GetTextNode();
if (!pTextNode->GetText().isEmpty())
pDelNd->FormatToTextAttr( pTextNode );
else
{
pTextNode->ResetAttr(RES_CHRATR_BEGIN, RES_CHRATR_END);
pTextNode->ChgFormatColl( pDelNd->GetTextColl() );
if (!pDelNd->GetNoCondAttr(RES_PARATR_LIST_ID, /*bInParents=*/false))
{
// MergeListsAtDocumentInsertPosition() will deal with lists below, copy
// paragraph direct formatting otherwise.
pDelNd->CopyCollFormat(*pTextNode);
}
}
pTextNode->JoinNext();
}
}
SwPosition* pPos = pPaM->GetPoint();
OSL_ENSURE( !pPos->GetContentIndex(), "last paragraph isn't empty" );
if( !pPos->GetContentIndex() )
{
SwTextNode* pCurrNd;
SwNodeOffset nNodeIdx = pPos->GetNodeIndex();
pDoc = &pPaM->GetDoc();
OSL_ENSURE( pPos->GetNode().IsContentNode(),
"insert position is not a content node" );
if( !IsInsertMode() )
{
// If we're not in insert mode, the last node is deleted.
const SwNode *pPrev = pDoc->GetNodes()[nNodeIdx -1];
if( pPrev->IsContentNode() ||
( pPrev->IsEndNode() &&
pPrev->StartOfSectionNode()->IsSectionNode() ) )
{
SwContentNode* pCNd = pPaM->GetPointContentNode();
if( pCNd && pCNd->StartOfSectionIndex()+2 <
pCNd->EndOfSectionIndex() )
{
SwNode& rDelNode = pPaM->GetPoint()->GetNode();
// move so we don't have a dangling SwContentIndex to the deleted node
pPaM->GetPoint()->Adjust(SwNodeOffset(+1));
if (pPaM->HasMark())
pPaM->GetMark()->Adjust(SwNodeOffset(+1));
pDoc->GetNodes().Delete( rDelNode );
}
}
}
else if( nullptr != (pCurrNd = pDoc->GetNodes()[nNodeIdx]->GetTextNode()) )
{
// Id we're in insert mode, the empty node is joined with
// the next and the previous one.
if( pCurrNd->CanJoinNext( pPos ))
{
SwTextNode* pNextNd = pPos->GetNode().GetTextNode();
bool endNodeFound = pDoc->GetNodes()[nNodeIdx-1]->IsEndNode();
SwNode *pLastPar = pDoc->GetNodes()[nNodeIdx -2];
if ( !pLastPar->IsTextNode() ) {
pLastPar = pDoc->GetNodes()[nNodeIdx -1];
}
if ( !endNodeFound && pLastPar->IsTextNode() )
{
pNextNd->ChgFormatColl(pLastPar->GetTextNode()->GetTextColl());
}
pPaM->SetMark(); pPaM->DeleteMark();
pNextNd->JoinPrev();
// Remove line break that has been inserted by the import,
// but only if one has been inserted and
// no endNode found to avoid removing section
if( pNextNd->CanJoinPrev(/* &pPos->nNode*/ ) && !endNodeFound &&
*m_oSttNdIdx != pPos->GetNode() )
{
pNextNd->JoinPrev();
}
}
else if (pCurrNd->GetText().isEmpty())
{
pPaM->SetMark(); pPaM->DeleteMark();
SwNode& rDelNode = pPos->GetNode();
// move so we don't have a dangling SwContentIndex to the deleted node
pPaM->GetPoint()->Adjust(SwNodeOffset(+1));
pDoc->GetNodes().Delete( rDelNode );
pPaM->Move( fnMoveBackward );
}
}
// tdf#113877
// when we insert one document with list inside into another one with list at the insert position,
// the resulting numbering in these lists is not consequent.
//
// Main document:
// 1. One
// 2. Two
// 3. Three
// 4. <-- insert position
//
// Inserted document:
// 1. One
// 2. Two
// 3. Three
// 4.
//
// Expected result
// 1. One
// 2. Two
// 3. Three
// 4. One
// 5. Two
// 6. Three
// 7.
//
MergeListsAtDocumentInsertPosition(pDoc);
}
}
return pDoc;
}
namespace {
// Locally derive XMLTextShapeImportHelper, so we can take care of the

View file

@ -96,6 +96,7 @@ class SwXMLImport: public SvXMLImport
const css::uno::Reference< css::text::XTextRange > & rInsertPos );
void setStyleInsertMode( SfxStyleFamily nFamilies,
bool bOverwrite );
SwDoc* endDocAdjustNodes();
protected: