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