1 /* This file is part of the wvWare 2 project
2 Copyright (C) 2002-2003 KO GmbH <jean.nicolas.artaud@kogmbh.>
3 Copyright (C) 2010, 2011 Matus Uzak <matus.uzak@ixonos.com>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License version 2 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02111-1307, USA.
18 */
19
20 #include "bookmark.h"
21 #include "word_helper.h"
22 #include "word97_generated.h"
23 #include "olestream.h"
24
25 #include "wvlog.h"
26 #include <QList>
27
28 using namespace wvWare;
29
Bookmarks(OLEStreamReader * tableStream,const Word97::FIB & fib)30 Bookmarks::Bookmarks( OLEStreamReader* tableStream, const Word97::FIB& fib ) :
31 m_start(0), m_startIt(0), m_end(0), m_endIt(0), m_nFib(fib.nFib)
32 {
33 #ifdef WV2_DEBUG_BOOKMARK
34 wvlog << endl
35 << " fcPlcfbkf=" << fib.fcPlcfbkf << " lcbPlcfbkf=" << fib.lcbPlcfbkf << endl
36 << " fcPlcfbkl=" << fib.fcPlcfbkl << " lcbPlcfbkl=" << fib.lcbPlcfbkl << endl
37 << " lcbSttbfbkmk=" << fib.fcSttbfbkmk << " lcbSttbfbkmk=" << fib.lcbSttbfbkmk << endl;
38 #endif
39
40 tableStream->push();
41
42 if (fib.lcbPlcfbkf != 0)
43 {
44 tableStream->seek( fib.fcPlcfbkf, WV2_SEEK_SET );
45
46 m_start = new PLCF<Word97::BKF>(fib.lcbPlcfbkf, tableStream);
47 m_startIt = new PLCFIterator<Word97::BKF>(*m_start);
48
49 #ifdef WV2_DEBUG_BOOKMARK
50 wvlog << "Num. of bookmarks to start: " << m_start->count() << endl;
51 wvlog << "m_start init done" << endl;
52 m_start->dumpCPs();
53 #endif
54 }
55
56 if ( fib.lcbSttbfbkmk != 0 )
57 {
58 if ( static_cast<U32>( tableStream->tell() ) != fib.fcSttbfbkmk ) {
59 tableStream->seek( fib.fcSttbfbkmk, WV2_SEEK_SET );
60 }
61 // The bookmark names in the STTBF are always Unicode, the lid doesn't matter
62 U16 usLid = 0x409;
63 STTBF* name = new STTBF( usLid, tableStream, false );
64
65 #ifdef WV2_DEBUG_BOOKMARK
66 name->dumpStrings();
67 #endif
68 for (uint i = 0; i < name->count(); i++ ) {
69 m_name.push_back(name->stringAt(i));
70 }
71
72 delete name;
73 }
74
75 //The BKL is no longer stored in the plcfbkl or plcfatnbkl, and is instead
76 //reconstructed from the plcfbkf or plcfatnbkf when the file is opened.
77 //Microsoft Word 97 (aka Version 8)
78
79 //TODO: Reconstruct BKL!
80
81 if (fib.lcbPlcfbkl != 0)
82 {
83 int count = 0;
84 tableStream->seek( fib.fcPlcfbkl, WV2_SEEK_SET );
85
86 //Word Version 6,7
87 if ( fib.nFib < Word8nFib ) {
88 m_end = new PLCF<Word97::BKL>(fib.lcbPlcfbkl, tableStream);
89 m_endIt = new PLCFIterator<Word97::BKL>(*m_end);
90 count = m_end->count();
91 } else {
92 count = (fib.lcbPlcfbkl - 4) / 4;
93 for ( int i = 0; i < count + 1; i++ ) {
94 m_endCP.push_back( tableStream->readU32() );
95 }
96 }
97
98 #ifdef WV2_DEBUG_BOOKMARK
99 wvlog << "Num. of bookmarks to end: " << count << endl;
100 wvlog << "m_end/m_endCP init done" << endl;
101
102 if ( fib.nFib < Word8nFib ) {
103 m_end->dumpCPs();
104 } else {
105 for ( uint i = 0; i < m_endCP.size(); i++ ) {
106 wvlog << "dumpCPs: " << m_endCP[i] << endl;
107 }
108 }
109 #endif
110 }
111
112 #ifdef WV2_DEBUG_BOOKMARK
113 wvlog << "Bookmark init done" << endl;
114 #endif
115
116 tableStream->pop();
117
118 U16 num = 0;
119 if (!valid(num, fib.ccpText)) {
120 wvlog << "Num. of invalid bookmarks:" << num;
121 }
122
123 //using custom bookmark names if missing!
124 m_nameIt = m_name.begin();
125 }
126
~Bookmarks()127 Bookmarks::~Bookmarks()
128 {
129 if ( m_nFib < Word8nFib ) {
130 delete m_endIt;
131 delete m_end;
132 }
133 delete m_startIt;
134 delete m_start;
135 }
136
bookmark(const U32 globalCP,bool & ok)137 BookmarkData Bookmarks::bookmark( const U32 globalCP, bool& ok )
138 {
139 #ifdef WV2_DEBUG_BOOKMARK
140 wvlog << " globalCP=" << globalCP << endl;
141 #endif
142 ok = false;
143 if ( (m_startIt && m_startIt->current()) &&
144 (m_startIt->currentStart() == globalCP) &&
145 (m_nameIt != m_name.end()) )
146 {
147 if (m_valid.isEmpty()) {
148 wvlog << "BUG: m_valid empty?";
149 } else if (m_valid.first()) {
150 ok = true;
151 }
152
153 U32 start = m_startIt->currentStart();
154 U32 end = start;
155
156 if (m_nFib < Word8nFib) {
157 end = m_endIt->currentStart();
158 ++( *m_endIt );
159 } else {
160 U16 ibkl = m_startIt->current()->ibkl;
161 end = m_endCP[ibkl];
162 }
163
164 ++( *m_startIt );
165 m_valid.removeFirst();
166
167 UString name = *m_nameIt;
168 ++m_nameIt;
169
170 #ifdef WV2_DEBUG_BOOKMARK
171 wvlog << "start = " << start << endl;
172 wvlog << "end = " << end << endl;
173 wvlog << "name = " << name.ascii() << endl;
174 wvlog << "valid = " << ok << endl;
175 #endif
176 return BookmarkData( start, end, name );
177 }
178 return BookmarkData( 0, 0, wvWare::UString("") );
179 }
180
bookmark(const UString & name,bool & ok) const181 BookmarkData Bookmarks::bookmark(const UString& name, bool& ok ) const
182 {
183 std::vector<UString>::const_iterator nameIt = m_name.begin();
184 PLCFIterator<Word97::BKF> startIt(*m_start);
185
186 PLCFIterator<Word97::BKL>* endIt = 0;
187 if (m_nFib < Word8nFib) {
188 endIt = new PLCFIterator<Word97::BKL>(*m_end);
189 }
190
191 while (startIt.current()) {
192 if (*nameIt == name) {
193 U32 start = startIt.currentStart();
194 U32 end = start;
195 if (m_nFib < Word8nFib) {
196 end = endIt->currentStart();
197 delete endIt;
198 } else {
199 U16 ibkl = startIt.current()->ibkl;
200 end = m_endCP[ibkl];
201 }
202 ok = true;
203 return BookmarkData( start, end, name );
204 }
205 ++startIt;
206 ++nameIt;
207
208 if (m_nFib < Word8nFib) {
209 ++( *endIt );
210 }
211 }
212 if (m_nFib < Word8nFib) {
213 delete endIt;
214 }
215 ok = false;
216 return BookmarkData( 0, 0, UString("") );
217 }
218
nextBookmarkStart()219 U32 Bookmarks::nextBookmarkStart()
220 {
221 U32 ret = 0xffffffff;
222
223 //find the next valid bookmark
224 while (m_startIt && m_startIt->current()) {
225
226 if (m_valid.isEmpty()) {
227 wvlog << "BUG: m_valid empty?";
228 break;
229 }
230 else if (m_valid.first()) {
231 ret = m_startIt->currentStart();
232 break;
233 } else {
234 //NOTE: Add logic to process invalid bookmarks here.
235
236 if (m_nFib < Word8nFib) {
237 ++( *m_endIt );
238 }
239 m_valid.removeFirst();
240 ++( *m_startIt );
241 ++m_nameIt;
242
243 #ifdef WV2_DEBUG_BOOKMARK
244 wvlog << "Warning: Skipped invalid bookmark!";
245 #endif
246 }
247 }
248 return ret;
249 }
250
nextBookmarkEnd() const251 U32 Bookmarks::nextBookmarkEnd() const
252 {
253 U32 ret = 0xffffffff;
254
255 if (m_nFib < Word8nFib) {
256 if (m_endIt && m_endIt->current()) {
257 ret = m_endIt->currentStart();
258 }
259 } else {
260 if (m_startIt && m_startIt->current()) {
261 U16 ibkl = (m_startIt->current())->ibkl;
262 ret = m_endCP[ibkl];
263 }
264 }
265 return ret;
266 }
267
check(U32 globalCP)268 void Bookmarks::check( U32 globalCP )
269 {
270 while (nextBookmarkStart() < globalCP)
271 {
272 if (m_nFib < Word8nFib) {
273 ++( *m_endIt );
274 }
275 ++( *m_startIt );
276 ++m_nameIt;
277
278 if (m_valid.isEmpty()) {
279 wvlog << "BUG: m_valid empty?";
280 } else {
281 m_valid.removeFirst();
282 }
283
284 #ifdef WV2_DEBUG_BOOKMARK
285 wvlog << "Bookmark skipped! CP:" << globalCP;
286 #endif
287 }
288 }
289
valid(U16 & num,const U32 ccpText)290 bool Bookmarks::valid(U16 &num, const U32 ccpText)
291 {
292 PLCFIterator<Word97::BKF> startIt(*m_start);
293 QList<U16> ibkls;
294 bool ret = true;
295 U16 ibkl = 0;
296 num = 0;
297
298 #ifdef WV2_DEBUG_BOOKMARK
299 U16 n = 1;
300 #endif
301
302 if (m_nFib < Word8nFib) {
303 PLCFIterator<Word97::BKL> endIt(*m_end);
304 while (startIt.current()) {
305 if ( !endIt.current() ||
306 (startIt.currentStart() > endIt.currentStart()) ||
307 (startIt.currentStart() > ccpText) )
308 {
309 m_valid.append(false);
310 ret = false;
311 num++;
312 #ifdef WV2_DEBUG_BOOKMARK
313 wvlog << "bkmk" << n << ": (startCP > endCP) || endCP missing";
314 #endif
315 } else {
316 m_valid.append(true);
317 }
318 #ifdef WV2_DEBUG_BOOKMARK
319 n++;
320 #endif
321 ++startIt;
322 ++endIt;
323 }
324 } else {
325 while (startIt.current()) {
326 ibkl = (startIt.current())->ibkl;
327 //MUST be unique for all FBKFs inside a given PlcfBkf
328 if (ibkls.contains(ibkl) || (ibkl > m_endCP.size())) {
329 m_valid.append(false);
330 ret = false;
331 num++;
332 #ifdef WV2_DEBUG_BOOKMARK
333 wvlog << "bkmk" << n << ": ibkl invalid!";
334 n++;
335 #endif
336 ++startIt;
337 continue;
338 } else {
339 ibkls.append(ibkl);
340 }
341
342 if ( (startIt.currentStart() > m_endCP[ibkl]) ||
343 (startIt.currentStart() > ccpText) )
344 {
345 m_valid.append(false);
346 ret = false;
347 num++;
348 #ifdef WV2_DEBUG_BOOKMARK
349 wvlog << "bkmk" << n << ": startCP > endCP (" <<
350 startIt.currentStart() << "|" << m_endCP[ibkl] << ")";
351 #endif
352 } else {
353 m_valid.append(true);
354 }
355 #ifdef WV2_DEBUG_BOOKMARK
356 n++;
357 #endif
358 ++startIt;
359 }
360 }
361
362 //check bookmark names
363 for (uint i = 0; i < m_name.size(); i++) {
364 if ( (m_name[i] == UString::null) ) {
365 m_name[i] = UString().from(i + 1);
366 }
367 }
368 if (m_name.size() < m_start->count()) {
369 for (uint i = m_name.size(); i < m_start->count(); i++) {
370 m_name.push_back(UString().from(i + 1));
371 }
372 #ifdef WV2_DEBUG_BOOKMARK
373 wvlog << "Warning: bookmark names missing! Using custom names.";
374 wvlog << "Num. of bookmark names:" << m_name.size();
375
376 std::vector<UString>::const_iterator it = m_name.begin();
377 while(it != m_name.end()) {
378 wvlog << "bkmk name:" << (*it).ascii();
379 ++it;
380 }
381 #endif
382 }
383 return ret;
384 }
385