1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <memory>
21 #include <tools/urlobj.hxx>
22 #include <svl/urihelper.hxx>
23 #include <osl/diagnose.h>
24 #include <ndtxt.hxx>
25 #include <pam.hxx>
26 #include <poolfmt.hxx>
27 #include <shellio.hxx>
28 #include <docsh.hxx>
29 #include <fmtanchr.hxx>
30 #include <frmfmt.hxx>
31 #include <doc.hxx>
32 #include <IDocumentStylePoolAccess.hxx>
33 #include <frameformats.hxx>
34 #include "ww8glsy.hxx"
35 #include "ww8par.hxx"
36 
WW8Glossary(tools::SvRef<SotStorageStream> & refStrm,sal_uInt8 nVersion,SotStorage * pStg)37 WW8Glossary::WW8Glossary(tools::SvRef<SotStorageStream> &refStrm, sal_uInt8 nVersion, SotStorage *pStg)
38     : rStrm(refStrm)
39     , xStg(pStg)
40     , nStrings(0)
41 {
42     refStrm->SetEndian(SvStreamEndian::LITTLE);
43     WW8Fib aWwFib(*refStrm, nVersion);
44 
45     if (aWwFib.m_nFibBack >= 0x6A)   //Word97
46     {
47         xTableStream = pStg->OpenSotStream(
48             aWwFib.m_fWhichTableStm ? OUString(SL::a1Table) : OUString(SL::a0Table),
49             StreamMode::STD_READ);
50 
51         if (xTableStream.is() && ERRCODE_NONE == xTableStream->GetError())
52         {
53             xTableStream->SetEndian(SvStreamEndian::LITTLE);
54             xGlossary = std::make_shared<WW8GlossaryFib>(*refStrm, nVersion, aWwFib);
55         }
56     }
57 }
58 
HasBareGraphicEnd(SwDoc * pDoc,SwNodeIndex const & rIdx)59 bool WW8Glossary::HasBareGraphicEnd(SwDoc *pDoc,SwNodeIndex const &rIdx)
60 {
61     bool bRet=false;
62     for( sal_uInt16 nCnt = pDoc->GetSpzFrameFormats()->size(); nCnt; )
63     {
64         const SwFrameFormat* pFrameFormat = (*pDoc->GetSpzFrameFormats())[ --nCnt ];
65         if ( RES_FLYFRMFMT != pFrameFormat->Which() &&
66             RES_DRAWFRMFMT != pFrameFormat->Which() )
67                 continue;
68         const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
69         SwPosition const*const pAPos = rAnchor.GetContentAnchor();
70         if (pAPos &&
71             ((RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId()) ||
72              (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId())) &&
73             rIdx == pAPos->nNode.GetIndex() )
74             {
75                 bRet=true;
76                 break;
77             }
78     }
79     return bRet;
80 }
81 
MakeEntries(SwDoc * pD,SwTextBlocks & rBlocks,bool bSaveRelFile,const std::vector<OUString> & rStrings,const std::vector<ww::bytes> & rExtra)82 bool WW8Glossary::MakeEntries(SwDoc *pD, SwTextBlocks &rBlocks,
83     bool bSaveRelFile, const std::vector<OUString>& rStrings,
84     const std::vector<ww::bytes>& rExtra)
85 {
86     // this code will be called after reading all text into the
87     // empty sections
88     const OUString aOldURL( rBlocks.GetBaseURL() );
89     bool bRet=false;
90     if( bSaveRelFile )
91     {
92         rBlocks.SetBaseURL(
93             URIHelper::SmartRel2Abs(
94                 INetURLObject(), rBlocks.GetFileName(),
95                 URIHelper::GetMaybeFileHdl()));
96     }
97     else
98         rBlocks.SetBaseURL( OUString() );
99 
100     SwNodeIndex aDocEnd( pD->GetNodes().GetEndOfContent() );
101     SwNodeIndex aStart( *aDocEnd.GetNode().StartOfSectionNode(), 1 );
102 
103     // search the first NormalStartNode
104     while( !( aStart.GetNode().IsStartNode() && SwNormalStartNode ==
105            aStart.GetNode().GetStartNode()->GetStartNodeType()) &&
106             aStart < aDocEnd )
107         ++aStart;
108 
109     if( aStart < aDocEnd )
110     {
111         SwTextFormatColl* pColl = pD->getIDocumentStylePoolAccess().GetTextCollFromPool
112             (RES_POOLCOLL_STANDARD, false);
113         sal_uInt16 nGlosEntry = 0;
114         SwContentNode* pCNd = nullptr;
115         do {
116             SwPaM aPam( aStart );
117             {
118                 SwNodeIndex& rIdx = aPam.GetPoint()->nNode;
119                 ++rIdx;
120                 pCNd = rIdx.GetNode().GetTextNode();
121                 if( nullptr == pCNd )
122                 {
123                     pCNd = pD->GetNodes().MakeTextNode( rIdx, pColl );
124                     rIdx = *pCNd;
125                 }
126             }
127             aPam.GetPoint()->nContent.Assign( pCNd, 0 );
128             aPam.SetMark();
129             {
130                 SwNodeIndex& rIdx = aPam.GetPoint()->nNode;
131                 rIdx = aStart.GetNode().EndOfSectionIndex() - 1;
132                 if(( nullptr == ( pCNd = rIdx.GetNode().GetContentNode() ) )
133                         || HasBareGraphicEnd(pD,rIdx))
134                 {
135                     ++rIdx;
136                     pCNd = pD->GetNodes().MakeTextNode( rIdx, pColl );
137                     rIdx = *pCNd;
138                 }
139             }
140             aPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() );
141 
142             // now we have the right selection for one entry.  Copy this to
143             // the defined TextBlock, but only if it is not an autocorrection
144             // entry (== -1) otherwise the group indicates the group in the
145             // sttbfglsystyle list that this entry belongs to. Unused at the
146             // moment
147             const ww::bytes &rData = rExtra[nGlosEntry];
148             sal_uInt16 n = SVBT16ToUInt16( &(rData[2]) );
149             if(n != 0xFFFF)
150             {
151                 rBlocks.ClearDoc();
152                 const OUString &rLNm = rStrings[nGlosEntry];
153 
154                 OUString sShortcut = rLNm;
155 
156                 // Need to check make sure the shortcut is not already being used
157                 sal_Int32 nStart = 0;
158                 sal_uInt16 nCurPos = rBlocks.GetIndex( sShortcut );
159                 while( sal_uInt16(-1) != nCurPos )
160                 {
161                     sShortcut = rLNm + OUString::number(++nStart);    // add a Number to it
162                     nCurPos = rBlocks.GetIndex( sShortcut );
163                 }
164 
165                 if( rBlocks.BeginPutDoc( sShortcut, sShortcut ))    // Make the shortcut and the name the same
166 
167                 {
168                     SwDoc* pGlDoc = rBlocks.GetDoc();
169                     SwNodeIndex aIdx( pGlDoc->GetNodes().GetEndOfContent(),
170                         -1 );
171                     pCNd = aIdx.GetNode().GetContentNode();
172                     SwPosition aPos(aIdx, SwIndex(pCNd, pCNd ? pCNd->Len() : 0));
173                     pD->getIDocumentContentOperations().CopyRange(aPam, aPos, SwCopyFlags::CheckPosInFly);
174                     rBlocks.PutDoc();
175                 }
176             }
177             aStart = aStart.GetNode().EndOfSectionIndex() + 1;
178             ++nGlosEntry;
179         } while( aStart.GetNode().IsStartNode() &&
180                 SwNormalStartNode == aStart.GetNode().
181                     GetStartNode()->GetStartNodeType());
182         bRet=true;
183     }
184 
185 // this code will be called after reading all text into the empty sections
186 
187     rBlocks.SetBaseURL( aOldURL );
188     return bRet;
189 }
190 
Load(SwTextBlocks & rBlocks,bool bSaveRelFile)191 bool WW8Glossary::Load( SwTextBlocks &rBlocks, bool bSaveRelFile )
192 {
193     bool bRet=false;
194     if (xGlossary && xGlossary->IsGlossaryFib() && rBlocks.StartPutMuchBlockEntries())
195     {
196         //read the names of the autotext entries
197         std::vector<OUString> aStrings;
198         std::vector<ww::bytes> aData;
199 
200         rtl_TextEncoding eStructCharSet =
201             WW8Fib::GetFIBCharset(xGlossary->m_chseTables, xGlossary->m_lid);
202 
203         WW8ReadSTTBF(true, *xTableStream, xGlossary->m_fcSttbfglsy,
204             xGlossary->m_lcbSttbfglsy, 0, eStructCharSet, aStrings, &aData );
205 
206         rStrm->Seek(0);
207 
208         nStrings = static_cast< sal_uInt16 >(aStrings.size());
209         if ( 0 != nStrings )
210         {
211             SfxObjectShellLock xDocSh(new SwDocShell(SfxObjectCreateMode::INTERNAL));
212             if (xDocSh->DoInitNew())
213             {
214                 SwDoc *pD =  static_cast<SwDocShell*>((&xDocSh))->GetDoc();
215 
216                 SwNodeIndex aIdx(
217                     *pD->GetNodes().GetEndOfContent().StartOfSectionNode(), 1);
218                 if( !aIdx.GetNode().IsTextNode() )
219                 {
220                     OSL_ENSURE( false, "Where is the TextNode?" );
221                     pD->GetNodes().GoNext( &aIdx );
222                 }
223                 SwPaM aPamo( aIdx );
224                 aPamo.GetPoint()->nContent.Assign(aIdx.GetNode().GetContentNode(),
225                     0);
226                 std::unique_ptr<SwWW8ImplReader> xRdr(new SwWW8ImplReader(
227                     xGlossary->m_nVersion, xStg.get(), rStrm.get(), *pD, rBlocks.GetBaseURL(),
228                     true, false, *aPamo.GetPoint()));
229                 xRdr->LoadDoc(this);
230                 bRet = MakeEntries(pD, rBlocks, bSaveRelFile, aStrings, aData);
231             }
232             xDocSh->DoClose();
233             rBlocks.EndPutMuchBlockEntries();
234         }
235     }
236     return bRet;
237 }
238 
FindGlossaryFibOffset(const WW8Fib & rFib)239 sal_uInt32 WW8GlossaryFib::FindGlossaryFibOffset(const WW8Fib &rFib)
240 {
241     sal_uInt32 nGlossaryFibOffset = 0;
242     if ( rFib.m_fDot ) // it's a template
243     {
244         if ( rFib.m_pnNext  )
245             nGlossaryFibOffset = ( rFib.m_pnNext * 512 );
246     }
247     return nGlossaryFibOffset;
248 }
249 
250 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
251