1 /* wvWare
2  * Copyright (C) Caolan McNamara, Dom Lachowicz, and others
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program 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
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17  * 02111-1307, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include "wv.h"
27 
28 /*
29 To find the beginning of the paragraph containing a character in a complex
30 document, it's first necessary to
31 
32 1) search for the piece containing the character in the piece table.
33 
34 2) Then calculate the FC in the file that stores the character from the piece
35 	table information.
36 
37 3) Using the FC, search the FCs FKP for the largest FC less than the character's
38 	FC, call it fcTest.
39 
40 4) If the character at fcTest-1 is contained in the current piece, then the
41 	character corresponding to that FC in the piece is the first character of
42 	the paragraph.
43 
44 5) If that FC is before or marks the beginning of the piece, scan a piece at a
45 time towards the beginning of the piece table until a piece is found that
46 contains a paragraph mark.
47 
48 (This can be done by using the end of the piece FC, finding the largest FC in
49 its FKP that is less than or equal to the end of piece FC, and checking to see
50 if the character in front of the FKP FC (which must mark a paragraph end) is
51 within the piece.)
52 
53 6) When such an FKP FC is found, the FC marks the first byte of paragraph text.
54 */
55 
56 /*
57 To find the end of a paragraph for a character in a complex format file,
58 again
59 
60 1) it is necessary to know the piece that contains the character and the
61 FC assigned to the character.
62 
63 2) Using the FC of the character, first search the FKP that describes the
64 character to find the smallest FC in the rgfc that is larger than the character
65 FC.
66 
67 3) If the FC found in the FKP is less than or equal to the limit FC of the
68 piece, the end of the paragraph that contains the character is at the FKP FC
69 minus 1.
70 
71 4) If the FKP FC that was found was greater than the FC of the end of the
72 piece, scan piece by piece toward the end of the document until a piece is
73 found that contains a paragraph end mark.
74 
75 5) It's possible to check if a piece contains a paragraph mark by using the
76 FC of the beginning of the piece to search in the FKPs for the smallest FC in
77 the FKP rgfc that is greater than the FC of the beginning of the piece.
78 
79 If the FC found is less than or equal to the limit FC of the
80 piece, then the character that ends the paragraph is the character
81 immediately before the FKP FC.
82 */
83 int
wvGetComplexParaBounds(wvVersion ver,PAPX_FKP * fkp,U32 * fcFirst,U32 * fcLim,U32 currentfc,CLX * clx,BTE * bte,U32 * pos,int nobte,U32 piece,wvStream * fd)84 wvGetComplexParaBounds (wvVersion ver, PAPX_FKP * fkp, U32 * fcFirst,
85 			U32 * fcLim, U32 currentfc, CLX * clx, BTE * bte,
86 			U32 * pos, int nobte, U32 piece, wvStream * fd)
87 {
88     /*
89        U32 currentfc;
90      */
91     BTE entry;
92     long currentpos;
93 
94     if (currentfc == 0xffffffffL)
95       {
96 	  wvError (
97 		   ("Para Bounds not found !, this is ok if this is the last para, otherwise its a disaster\n"));
98 	  return (-1);
99       }
100 
101     if (0 != wvGetBTE_FromFC (&entry, currentfc, bte, pos, nobte))
102       {
103 	  wvError (("BTE not found !\n"));
104 	  return (-1);
105       }
106     currentpos = wvStream_tell (fd);
107     /*The pagenumber of the FKP is entry.pn */
108 
109     wvTrace (("the entry.pn is %d\n", entry.pn));
110     wvGetPAPX_FKP (ver, fkp, entry.pn, fd);
111 
112     wvGetComplexParafcFirst (ver, fcFirst, currentfc, clx, bte, pos, nobte,
113 			     piece, fkp, fd);
114 
115     wvReleasePAPX_FKP (fkp);
116     wvTrace (("BREAK\n"));
117     wvGetPAPX_FKP (ver, fkp, entry.pn, fd);
118 
119     piece =
120 	wvGetComplexParafcLim (ver, fcLim, currentfc, clx, bte, pos, nobte,
121 			       piece, fkp, fd);
122 
123     wvStream_goto (fd, currentpos);
124     return (piece);
125 }
126 
127 int
wvGetComplexParafcLim(wvVersion ver,U32 * fcLim,U32 currentfc,CLX * clx,BTE * bte,U32 * pos,int nobte,U32 piece,PAPX_FKP * fkp,wvStream * fd)128 wvGetComplexParafcLim (wvVersion ver, U32 * fcLim, U32 currentfc, CLX * clx,
129 		       BTE * bte, U32 * pos, int nobte, U32 piece,
130 		       PAPX_FKP * fkp, wvStream * fd)
131 {
132     U32 fcTest, beginfc;
133     BTE entry;
134     *fcLim = 0xffffffffL;
135     wvTrace (("here is fcLim, currentfc is %x\n", currentfc));
136     fcTest = wvSearchNextSmallestFCPAPX_FKP (fkp, currentfc);
137 
138     wvTrace (
139 	     ("fcTest is %x, end is %x\n", fcTest,
140 	      wvGetEndFCPiece (piece, clx)));
141 
142 
143     if (fcTest <= wvGetEndFCPiece (piece, clx))
144       {
145 	  *fcLim = fcTest;
146       }
147     else
148       {
149 	  /*get end fc of previous piece */
150 	  piece++;
151 	  while (piece < clx->nopcd)
152 	    {
153 		wvTrace (("piece is %d\n", piece));
154 		beginfc = wvNormFC (clx->pcd[piece].fc, NULL);
155 		if (0 != wvGetBTE_FromFC (&entry, beginfc, bte, pos, nobte))
156 		  {
157 		      wvError (("BTE not found !\n"));
158 		      return (-1);
159 		  }
160 		wvReleasePAPX_FKP (fkp);
161 		wvGetPAPX_FKP (ver, fkp, entry.pn, fd);
162 		fcTest = wvSearchNextSmallestFCPAPX_FKP (fkp, beginfc);
163 		wvTrace (
164 			 ("fcTest(t) is %x, end is %x\n", fcTest,
165 			  wvGetEndFCPiece (piece, clx)));
166 		if (fcTest <= wvGetEndFCPiece (piece, clx))
167 		  {
168 		      *fcLim = fcTest;
169 		      break;
170 		  }
171 		piece++;
172 	    }
173       }
174     wvTrace (("fcLim is %x\n", *fcLim));
175     if (piece == clx->nopcd)
176       {
177 	  wvTrace (("failed to find a solution to end of paragraph\n"));
178 	  *fcLim = fcTest;
179 	  return (clx->nopcd - 1);	/* test using this */
180       }
181     return (piece);
182 }
183 
184 
185 int
wvGetComplexParafcFirst(wvVersion ver,U32 * fcFirst,U32 currentfc,CLX * clx,BTE * bte,U32 * pos,int nobte,U32 piece,PAPX_FKP * fkp,wvStream * fd)186 wvGetComplexParafcFirst (wvVersion ver, U32 * fcFirst, U32 currentfc,
187 			 CLX * clx, BTE * bte, U32 * pos, int nobte,
188 			 U32 piece, PAPX_FKP * fkp, wvStream * fd)
189 {
190     U32 fcTest, endfc;
191     BTE entry;
192     fcTest = wvSearchNextLargestFCPAPX_FKP (fkp, currentfc);
193 
194     wvTrace (("fcTest (s) is %x\n", fcTest));
195 
196     if (wvQuerySamePiece (fcTest - 1, clx, piece))
197       {
198 	  wvTrace (("same piece\n"));
199 	  *fcFirst = fcTest - 1;
200       }
201     else
202       {
203 	  /*
204 	     get end fc of previous piece ??, or use the end of the current piece
205 	   */
206 	  piece--;
207 	  while (piece != 0xffffffffL)
208 	    {
209 		wvTrace (("piece is %d\n", piece));
210 		endfc = wvGetEndFCPiece (piece, clx);
211 		wvTrace (("endfc is %x\n", endfc));
212 		if (0 != wvGetBTE_FromFC (&entry, endfc, bte, pos, nobte))
213 		  {
214 		      wvError (("BTE not found !\n"));
215 		      return (-1);
216 		  }
217 		wvReleasePAPX_FKP (fkp);
218 		wvGetPAPX_FKP (ver, fkp, entry.pn, fd);
219 		fcTest = wvSearchNextLargestFCPAPX_FKP (fkp, endfc);
220 		wvTrace (("fcTest(ft) is %x\n", fcTest));
221 		if (wvQuerySamePiece (fcTest - 1, clx, piece))
222 		  {
223 		      *fcFirst = fcTest - 1;
224 		      break;
225 		  }
226 		piece--;
227 	    }
228 
229       }
230     if (piece == 0xffffffffL)
231       {
232 	  wvTrace (
233 		   ("failed to find a solution to the beginning of the paragraph\n"));
234 	  *fcFirst = currentfc;
235       }
236     wvTrace (("fcFirst is finally %x\n", *fcFirst));
237     return (0);
238 }
239 
240 
241 /* char properties version of the above -JB */
242 /* only difference is that we're using CHPX FKP pages,
243  * and specifically just the Get and Release functions are
244  * different between the two. We might be able to
245  * abstract the necessary functions to avoid duplicating them... */
246 
247 int
wvGetComplexCharBounds(wvVersion ver,CHPX_FKP * fkp,U32 * fcFirst,U32 * fcLim,U32 currentfc,CLX * clx,BTE * bte,U32 * pos,int nobte,U32 piece,wvStream * fd)248 wvGetComplexCharBounds (wvVersion ver, CHPX_FKP * fkp, U32 * fcFirst,
249 			U32 * fcLim, U32 currentfc, CLX * clx, BTE * bte,
250 			U32 * pos, int nobte, U32 piece, wvStream * fd)
251 {
252     BTE entry;
253     long currentpos;
254 
255     wvTrace (("current fc is %x\n", currentfc));
256 
257     if (currentfc == 0xffffffffL)
258       {
259 	  wvTrace (
260 		   ("Char Bounds not found !, this is ok if this is the last char, otherwise its a disaster\n"));
261 	  return (-1);
262       }
263 
264     if (0 != wvGetBTE_FromFC (&entry, currentfc, bte, pos, nobte))
265       {
266 	  wvError (("BTE not found !\n"));
267 	  return (-1);
268       }
269     currentpos = wvStream_tell (fd);
270     /*The pagenumber of the FKP is entry.pn */
271 
272     wvGetCHPX_FKP (ver, fkp, entry.pn, fd);
273 
274     wvGetComplexCharfcFirst (ver, fcFirst, currentfc, clx, bte, pos, nobte,
275 			     piece, fkp, fd);
276     wvTrace (("BEFORE PIECE is %d\n", piece));
277 
278     wvReleaseCHPX_FKP (fkp);
279     wvGetCHPX_FKP (ver, fkp, entry.pn, fd);
280 
281     piece =
282 	wvGetComplexCharfcLim (ver, fcLim, currentfc, clx, bte, pos, nobte,
283 			       piece, fkp, fd);
284     wvTrace (("AFTER PIECE is %d\n", piece));
285 
286     wvStream_goto (fd, currentpos);
287     return (piece);
288 }
289 
290 int
wvGetComplexCharfcLim(wvVersion ver,U32 * fcLim,U32 currentfc,CLX * clx,BTE * bte,U32 * pos,int nobte,U32 piece,CHPX_FKP * fkp,wvStream * fd)291 wvGetComplexCharfcLim (wvVersion ver, U32 * fcLim, U32 currentfc, CLX * clx,
292 		       BTE * bte, U32 * pos, int nobte, U32 piece,
293 		       CHPX_FKP * fkp, wvStream * fd)
294 {
295     U32 fcTest;
296     /*
297        BTE entry;
298      */
299     *fcLim = 0xffffffffL;
300     /* this only works with the initial rgfc array, which is the
301      * same for both CHPX and PAPX FKPs */
302     fcTest = wvSearchNextSmallestFCPAPX_FKP ((PAPX_FKP *) fkp, currentfc);
303 
304     wvTrace (("fcTest is %x\n", fcTest));
305 
306     /*
307        this single line replaces all the rest, is it conceivable that i overengineered,
308        careful rereading of the spec makes no mention of repeating the para process to
309        find the boundaries of the exception text runs
310      */
311     *fcLim = fcTest;
312     wvTrace (("fcLim is %x\n", *fcLim));
313     if (piece == clx->nopcd)
314 	return (clx->nopcd - 1);	/* test using this */
315     return (piece);
316 }
317 
318 
319 int
wvGetComplexCharfcFirst(wvVersion ver,U32 * fcFirst,U32 currentfc,CLX * clx,BTE * bte,U32 * pos,int nobte,U32 piece,CHPX_FKP * fkp,wvStream * fd)320 wvGetComplexCharfcFirst (wvVersion ver, U32 * fcFirst, U32 currentfc,
321 			 CLX * clx, BTE * bte, U32 * pos, int nobte,
322 			 U32 piece, CHPX_FKP * fkp, wvStream * fd)
323 {
324     U32 fcTest /*,endfc */ ;
325     /*BTE entry; */
326     /* this only works with the initial rgfc array, which is the */
327     fcTest = wvSearchNextLargestFCCHPX_FKP (fkp, currentfc);
328 
329     wvTrace (("fcTest (s) is %x\n", fcTest));
330 
331     /*
332        this single line replaces all the rest, is it conceivable that i overengineered,
333        careful rereading of the spec makes no mention of repeating the para process to
334        find the boundaries of the exception text runs
335      */
336     *fcFirst = fcTest;
337     return (0);
338 }
339 
340 /*
341 how this works,
342 we seek to the beginning of the text, we loop for a count of charaters that is stored in the fib.
343 
344 the piecetable divides the text up into various sections, we keep track of our location vs
345 the next entry in that table, when we reach that location, we seek to the position that
346 the table tells us to go.
347 
348 there are special cases for coming to the end of a section, and for the beginning and ends of
349 pages. for the purposes of headers and footers etc.
350 */
351 void
wvDecodeComplex(wvParseStruct * ps)352 wvDecodeComplex (wvParseStruct * ps)
353 {
354     U32 piececount = 0, i, j, spiece = 0;
355     U32 beginfc, endfc;
356 	U32 stream_size;
357     U32 begincp, endcp;
358     int ichartype;
359     U8  chartype;
360     U16 eachchar;
361     U32 para_fcFirst, para_fcLim = 0xffffffffL;
362     U32 dummy, nextpara_fcLim = 0xffffffffL;
363     U32 char_fcFirst, char_fcLim = 0xffffffffL;
364     U32 section_fcFirst, section_fcLim = 0xffffffffL;
365     U32 comment_cpFirst = 0xffffffffL, comment_cpLim = 0xffffffffL;
366     BTE *btePapx = NULL, *bteChpx = NULL;
367     U32 *posPapx = NULL, *posChpx = NULL;
368     U32 para_intervals, char_intervals, section_intervals, atrd_intervals;
369     int cpiece = 0, npiece = 0;
370     PAPX_FKP para_fkp;
371     PAP apap;
372     CHPX_FKP char_fkp;
373     CHP achp;
374     int para_pendingclose = 0, comment_pendingclose = 0, char_pendingclose =
375 	0, section_pendingclose = 0;
376     int para_dirty = 0, char_dirty = 0, section_dirty = 0;
377     SED *sed;
378     SEP sep;
379     U32 *posSedx;
380     ATRD *atrd, *catrd = NULL;
381     U32 *posAtrd;
382     STTBF grpXstAtnOwners, SttbfAtnbkmk;
383     BKF *bkf;
384     U32 *posBKF;
385     U32 bkf_intervals;
386     BKL *bkl;
387     U32 *posBKL;
388     U32 bkl_intervals;
389     wvVersion ver = wvQuerySupported (&ps->fib, NULL);
390     external_wvReleasePAPX_FKP ();
391     external_wvReleaseCHPX_FKP ();
392 
393     /*dop */
394     wvGetDOP (ver, &ps->dop, ps->fib.fcDop,
395 	      ps->fib.lcbDop, ps->tablefd);
396 
397 #if 0
398 /*
399 this is the versioning name information, the first 22 bytes of each sttbf entry are
400 unknown, the rest is a ordinary unicode string, is the time and date and saved by
401 encoded into the first 22 bytes.
402 */
403     STTBF versioning;
404     if (ver == 0)
405       {
406 	  U16 *str;
407 	  wvError (("into the versions\n"));
408 	  wvGetSTTBF (&versioning, ps->fib.fcSttbfUssr, ps->fib.lcbSttbfUssr,
409 		      ps->tablefd);
410 	  str = UssrStrBegin (&versioning, 0);
411 	  wvError (("versioning text is %s\n", wvWideStrToMB (str)));
412       }
413 #endif
414 
415     wvGetATRD_PLCF (&atrd, &posAtrd, &atrd_intervals, ps->fib.fcPlcfandRef,
416 		    ps->fib.lcbPlcfandRef, ps->tablefd);
417     wvGetGrpXst (&grpXstAtnOwners, ps->fib.fcGrpXstAtnOwners,
418 		 ps->fib.lcbGrpXstAtnOwners, ps->tablefd);
419     wvTrace (
420 	     ("offset is %x, len is %d\n", ps->fib.fcSttbfAtnbkmk,
421 	      ps->fib.lcbSttbfAtnbkmk));
422     wvGetSTTBF (&SttbfAtnbkmk, ps->fib.fcSttbfAtnbkmk,
423 		ps->fib.lcbSttbfAtnbkmk, ps->tablefd);
424     wvGetBKF_PLCF (&bkf, &posBKF, &bkf_intervals, ps->fib.fcPlcfAtnbkf,
425 		   ps->fib.lcbPlcfAtnbkf, ps->tablefd);
426     wvGetBKL_PLCF (&bkl, &posBKL, &bkl_intervals, ps->fib.fcPlcfAtnbkl,
427            ps->fib.lcbPlcfAtnbkl, ps->fib.fcPlcfAtnbkf, ps->fib.lcbPlcfAtnbkf,
428            ps->tablefd);
429 
430     /*we will need the stylesheet to do anything useful with layout and look */
431     wvGetSTSH (&ps->stsh, ps->fib.fcStshf, ps->fib.lcbStshf, ps->tablefd);
432 
433     /* get font list */
434     if ((ver == WORD6)
435 	|| (ver == WORD7))
436 	wvGetFFN_STTBF6 (&ps->fonts, ps->fib.fcSttbfffn, ps->fib.lcbSttbfffn,
437 			 ps->tablefd);
438     else
439 	wvGetFFN_STTBF (&ps->fonts, ps->fib.fcSttbfffn, ps->fib.lcbSttbfffn,
440 			ps->tablefd);
441 
442     /*we will need the table of names to answer questions like the name of the doc */
443     if ((ver == WORD6)
444 	|| (ver == WORD7))
445       {
446 	  wvGetSTTBF6 (&ps->anSttbfAssoc, ps->fib.fcSttbfAssoc,
447 		       ps->fib.lcbSttbfAssoc, ps->tablefd);
448 	  wvGetSTTBF6 (&ps->Sttbfbkmk, ps->fib.fcSttbfbkmk,
449 		       ps->fib.lcbSttbfbkmk, ps->tablefd);
450       }
451     else
452       {
453 	  wvGetSTTBF (&ps->anSttbfAssoc, ps->fib.fcSttbfAssoc,
454 		      ps->fib.lcbSttbfAssoc, ps->tablefd);
455 	  wvGetSTTBF (&ps->Sttbfbkmk, ps->fib.fcSttbfbkmk,
456 		      ps->fib.lcbSttbfbkmk, ps->tablefd);
457       }
458 
459     /*Extract all the list information that we will need to handle lists later on */
460     wvGetLST (&ps->lst, &ps->noofLST, ps->fib.fcPlcfLst, ps->fib.lcbPlcfLst,
461 	      ps->tablefd);
462     wvGetLFO_records (&ps->lfo, &ps->lfolvl, &ps->lvl, &ps->nolfo,
463 		      &ps->nooflvl, ps->fib.fcPlfLfo, ps->fib.lcbPlfLfo,
464 		      ps->tablefd);
465     /* init the starting list number table */
466     if (ps->nolfo)
467       {
468 	  ps->liststartnos = (U32 *) wvMalloc (9 * ps->nolfo * sizeof (U32));
469 	  ps->listnfcs = (U8 *) wvMalloc (9 * ps->nolfo);
470 	  ps->finallvl = (LVL *) wvMalloc (9 * ps->nolfo * sizeof (LVL));
471 	  for (i = 0; i < 9 * ps->nolfo; i++)
472 	    {
473 		ps->liststartnos[i] = 0xffffffffL;
474 		ps->listnfcs[i] = 0xff;
475 		wvInitLVL (&(ps->finallvl[i]));
476 	    }
477       }
478     else
479       {
480 	  ps->liststartnos = NULL;
481 	  ps->listnfcs = NULL;
482 	  ps->finallvl = NULL;
483       }
484 
485     /*Extract Graphic Information */
486     wvGetFSPA_PLCF (&ps->fspa, &ps->fspapos, &ps->nooffspa,
487 		    ps->fib.fcPlcspaMom, ps->fib.lcbPlcspaMom, ps->tablefd);
488     wvGetFDOA_PLCF (&ps->fdoa, &ps->fdoapos, &ps->nooffdoa,
489 		    ps->fib.fcPlcdoaMom, ps->fib.lcbPlcdoaMom, ps->tablefd);
490 
491     wvGetCLX (ver, &ps->clx,
492 	      (U32) ps->fib.fcClx, ps->fib.lcbClx, (U8) ps->fib.fExtChar,
493 	      ps->tablefd);
494 
495     para_fcFirst = char_fcFirst = section_fcFirst =
496 	wvConvertCPToFC (0, &ps->clx);
497 
498 #ifdef DEBUG
499     if ((ps->fib.ccpFtn) || (ps->fib.ccpHdr))
500 	wvTrace (("Special ending\n"));
501 #endif
502 
503     /*
504        we will need the paragraph and character bounds table to make decisions as
505        to where a table begins and ends
506      */
507     if ((ver == WORD6)
508 	|| (ver == WORD7))
509       {
510 	  wvGetBTE_PLCF6 (&btePapx, &posPapx, &para_intervals,
511 			  ps->fib.fcPlcfbtePapx, ps->fib.lcbPlcfbtePapx,
512 			  ps->tablefd);
513 	  wvGetBTE_PLCF6 (&bteChpx, &posChpx, &char_intervals,
514 			  ps->fib.fcPlcfbteChpx, ps->fib.lcbPlcfbteChpx,
515 			  ps->tablefd);
516       }
517     else
518       {
519 	  wvGetBTE_PLCF (&btePapx, &posPapx, &para_intervals,
520 			 ps->fib.fcPlcfbtePapx, ps->fib.lcbPlcfbtePapx,
521 			 ps->tablefd);
522 	  wvGetBTE_PLCF (&bteChpx, &posChpx, &char_intervals,
523 			 ps->fib.fcPlcfbteChpx, ps->fib.lcbPlcfbteChpx,
524 			 ps->tablefd);
525       }
526 
527     wvGetSED_PLCF (&sed, &posSedx, &section_intervals, ps->fib.fcPlcfsed,
528 		   ps->fib.lcbPlcfsed, ps->tablefd);
529     wvTrace (("section_intervals is %d\n", section_intervals));
530 
531     wvInitPAPX_FKP (&para_fkp);
532     wvInitCHPX_FKP (&char_fkp);
533 
534     if(wvHandleDocument (ps, DOCBEGIN))
535 		goto  finish_processing;
536 
537 	/*get stream size for bounds checking*/
538 	stream_size = wvStream_size(ps->mainfd);
539 
540     /*for each piece */
541     for (piececount = 0; piececount < ps->clx.nopcd; piececount++)
542       {
543 	  ichartype =
544 	      wvGetPieceBoundsFC (&beginfc, &endfc, &ps->clx, piececount);
545 	  if(ichartype==-1)
546 		  break;
547 	  chartype = (U8) ichartype;
548 	  /*lvm007@aha.ru fix antiloop: check stream size */
549 	  if(beginfc>stream_size || endfc>stream_size){
550 		  wvError (
551 		   ("Piece Bounds out of range!, its a disaster\n"));
552 		  continue;
553 	  }
554 	  wvStream_goto (ps->mainfd, beginfc);
555 	  /*lvm007@aha.ru fix antiloop fix*/
556 	  if(wvGetPieceBoundsCP (&begincp, &endcp, &ps->clx, piececount)==-1)
557 		  break;
558 	  wvTrace (
559 		   ("piece begins at %x and ends just before %x. the char end is %x\n",
560 		    beginfc, endfc, char_fcLim));
561 
562 	  /*
563 	     text that is not in the same piece is not guaranteed to have the same properties as
564 	     the rest of the exception run, so force a stop and restart of these properties.
565 	   */
566 	  char_fcLim = beginfc;
567 
568 	  for (i = begincp, j = beginfc; (i < endcp /*&& i<ps->fib.ccpText */ );
569 	       i++, j += wvIncFC (chartype))
570 	    {
571 		ps->currentcp = i;
572 		/* character properties */
573 		if (j == char_fcLim)
574 		  {
575 		      wvHandleElement (ps, CHARPROPEND, (void *) &achp,
576 				       char_dirty);
577 		      char_pendingclose = 0;
578 		  }
579 
580 		/* comment ending location */
581 		if (i == comment_cpLim)
582 		  {
583 		      wvHandleElement (ps, COMMENTEND, (void *) catrd, 0);
584 		      comment_pendingclose = 0;
585 		  }
586 
587 		/* paragraph properties */
588 		if (j == para_fcLim)
589 		  {
590 		      wvHandleElement (ps, PARAEND, (void *) &apap, para_dirty);
591 		      para_pendingclose = 0;
592 		  }
593 
594 		/* section properties */
595 		if (j == section_fcLim)
596 		  {
597 		      wvHandleElement (ps, SECTIONEND, (void *) &sep,
598 				       section_dirty);
599 		      section_pendingclose = 0;
600 		  }
601 
602 		if ((section_fcLim == 0xffffffff) || (section_fcLim == j))
603 		  {
604 		      section_dirty =
605 			  wvGetSimpleSectionBounds (ver, ps,
606 						    &sep, &section_fcFirst,
607 						    &section_fcLim, i,
608 						    &ps->clx, sed, &spiece,
609 						    posSedx,
610 						    section_intervals,
611 						    &ps->stsh, ps->mainfd);
612 		      section_dirty =
613 			  (wvGetComplexSEP
614 			   (ver, &sep, spiece,
615 			    &ps->stsh, &ps->clx) ? 1 : section_dirty);
616 		  }
617 
618 		if (j == section_fcFirst)
619 		  {
620 		      wvHandleElement (ps, SECTIONBEGIN, (void *) &sep,
621 				       section_dirty);
622 		      section_pendingclose = 1;
623 		  }
624 
625 
626 		if ((para_fcLim == 0xffffffffL) || (para_fcLim == j))
627 		  {
628 		      wvReleasePAPX_FKP (&para_fkp);
629 		      wvTrace (
630 			       ("cp and fc are %x(%d) %x\n", i, i,
631 				wvConvertCPToFC (i, &ps->clx)));
632 		      cpiece =
633 			  wvGetComplexParaBounds (ver, &para_fkp,
634 						  &para_fcFirst, &para_fcLim,
635 						  wvConvertCPToFC (i,
636 								   &ps->clx),
637 						  &ps->clx, btePapx, posPapx,
638 						  para_intervals, piececount,
639 						  ps->mainfd);
640 		      wvTrace (
641 			       ("para begin and end is %x %x\n", para_fcFirst,
642 				para_fcLim));
643 
644 		      if (0 == para_pendingclose)
645 			{
646 			    /*
647 			       if there's no paragraph open, but there should be then I believe that the fcFirst search
648 			       has failed me, so I set it to now. I need to investigate this further. I believe it occurs
649 			       when a the last piece ended simultaneously with the last paragraph, and that the algorithm
650 			       for finding the beginning of a para breaks under that condition. I need more examples to
651 			       be sure, but it happens is very large complex files so its hard to find
652 			     */
653 			    if (j != para_fcFirst)
654 			      {
655 				  wvWarning (
656 					     ("There is no paragraph due to open but one should be, plugging the gap.\n"));
657 				  para_fcFirst = j;
658 			      }
659 			}
660 
661 		  }
662 
663 		if (j == para_fcFirst)
664 		  {
665 		      para_dirty =
666 			  wvAssembleSimplePAP (ver, &apap, para_fcLim, &para_fkp, ps);
667 		      para_dirty =
668 			  (wvAssembleComplexPAP
669 			   (ver, &apap, cpiece, ps) ? 1 : para_dirty);
670 #ifdef SPRMTEST
671 		      {
672 			  int p;
673 			  wvTrace (("Assembled Complex\n"));
674 			  for (p = 0; p < apap.itbdMac; p++)
675 			      wvError (
676 				       ("Tab stop positions are %f inches (%d)\n",
677 					((float) (apap.rgdxaTab[p])) / 1440,
678 					apap.rgdxaTab[p]));
679 		      }
680 #endif
681 
682 		      /* test section */
683 		      wvReleasePAPX_FKP (&para_fkp);
684 		      wvTrace (
685 			       ("cp and fc are %x(%d) %x\n", i, i,
686 				wvConvertCPToFC (i, &ps->clx)));
687 		      npiece =
688 			  wvGetComplexParaBounds (ver, &para_fkp,
689 						  &dummy, &nextpara_fcLim,
690 						  para_fcLim, &ps->clx,
691 						  btePapx, posPapx,
692 						  para_intervals, piececount,
693 						  ps->mainfd);
694 		      wvTrace (
695 			       ("para begin and end is %x %x\n", para_fcFirst,
696 				para_fcLim));
697 		      if (npiece > -1)
698 			{
699 			    wvAssembleSimplePAP (ver, &ps->nextpap, nextpara_fcLim, &para_fkp, ps);
700 			    wvAssembleComplexPAP (ver, &ps->nextpap, npiece,ps);
701 			}
702 		      else
703 			  wvInitPAP (&ps->nextpap);
704 		      /* end test section */
705 
706 		      if ((apap.fInTable) && (!apap.fTtp))
707 			{
708 			    wvGetComplexFullTableInit (ps, para_intervals,
709 						       btePapx, posPapx,
710 						       piececount);
711 			    wvGetComplexRowTap (ps, &apap, para_intervals,
712 						btePapx, posPapx, piececount);
713 			}
714 		      else if (apap.fInTable == 0)
715 			  ps->intable = 0;
716 
717 		      wvHandleElement (ps, PARABEGIN, (void *) &apap,
718 				       para_dirty);
719 
720 		      char_fcLim = j;
721 		      para_pendingclose = 1;
722 		  }
723 
724 
725 		if ((comment_cpLim == 0xffffffffL) || (comment_cpLim == i))
726 		  {
727 		      wvTrace (
728 			       ("searching for the next comment begin cp is %d\n",
729 				i));
730 		      catrd =
731 			  wvGetCommentBounds (&comment_cpFirst,
732 					      &comment_cpLim, i, atrd,
733 					      posAtrd, atrd_intervals,
734 					      &SttbfAtnbkmk, bkf, posBKF,
735 					      bkf_intervals, bkl, posBKL,
736 					      bkl_intervals);
737 		      wvTrace (
738 			       ("begin and end are %d %d\n", comment_cpFirst,
739 				comment_cpLim));
740 		  }
741 
742 		if (i == comment_cpFirst)
743 		  {
744 		      wvHandleElement (ps, COMMENTBEGIN, (void *) catrd, 0);
745 		      comment_pendingclose = 1;
746 		  }
747 
748 
749 		if ((char_fcLim == 0xffffffffL) || (char_fcLim == j))
750 		  {
751 		      wvReleaseCHPX_FKP (&char_fkp);
752 		      /*try this without using the piece of the end char for anything */
753 		      wvGetComplexCharBounds (ver, &char_fkp,
754 					      &char_fcFirst, &char_fcLim,
755 					      wvConvertCPToFC (i, &ps->clx),
756 					      &ps->clx, bteChpx, posChpx,
757 					      char_intervals, piececount,
758 					      ps->mainfd);
759 		      wvTrace (
760 			       ("Bounds from %x to %x\n", char_fcFirst,
761 				char_fcLim));
762 		      if (char_fcLim == char_fcFirst)
763 			  wvError (
764 				   ("I believe that this is an error, and you might see incorrect character properties\n"));
765 		      if (0 == char_pendingclose)
766 			{
767 			    /*
768 			       if there's no character run open, but there should be then I believe that the fcFirst search
769 			       has failed me, so I set it to now. I need to investigate this further.
770 			     */
771 			    if (j != char_fcFirst)
772 			      {
773 				  wvTrace (
774 					   ("There is no character run due to open but one should be, plugging the gap.\n"));
775 				  char_fcFirst = j;
776 			      }
777 
778 			}
779 		      else{
780   			 /* lvm007@aha.ru fix: if currentfc>fcFirst but CHARPROP's changed look examples/charprops.doc for decode_simple*/
781 			 if(char_fcFirst< j)
782 				char_fcFirst = j;
783 		       }
784 		  }
785 
786 		if (j == char_fcFirst)
787 		  {
788 		      /* a CHP's base style is in the para style */
789 		      /*achp.istd = apap.istd;*/
790 		      wvTrace (("getting chp\n"));
791 		      char_dirty =
792 				  wvAssembleSimpleCHP (ver, &achp, &apap,
793 					       char_fcLim, &char_fkp,
794 					       &ps->stsh);
795 		      wvTrace (("getting complex chp\n"));
796 		      char_dirty =
797 			  (wvAssembleComplexCHP
798 			   (ver, &achp, cpiece,
799 			    &ps->stsh, &ps->clx) ? 1 : char_dirty);
800 		      wvHandleElement (ps, CHARPROPBEGIN, (void *) &achp,
801 				       char_dirty);
802 		      char_pendingclose = 1;
803 		  }
804 
805 
806 		eachchar = wvGetChar (ps->mainfd, chartype);
807 
808 		/* previously, in place of ps there was a NULL,
809 		 * but it was crashing Abiword. Was it NULL for a
810 		 * reason? -JB */
811 		/*
812 		   nah, it was a oversight from when i didn't actually
813 		   use ps in this function
814 		   C.
815 		 */
816 		if ((eachchar == 0x07) && (!achp.fSpec))
817 		    ps->endcell = 1;
818 
819 		wvTrace (("char pos is %x %x\n", j, eachchar));
820 		wvOutputTextChar (eachchar, chartype, ps, &achp);
821 	    }
822 
823 	  if (j == para_fcLim)
824 	    {
825 		wvHandleElement (ps, PARAEND, (void *) &apap, para_dirty);
826 		para_pendingclose = 0;
827 		para_fcLim = 0xffffffffL;
828 	    }
829 
830 	  if (i == comment_cpLim)
831 	    {
832 		wvHandleElement (ps, COMMENTEND, (void *) catrd, 0);
833 		comment_pendingclose = 0;
834 		comment_cpLim = 0xffffffffL;
835 	    }
836 
837 	  if (j == char_fcLim)
838 	    {
839 		wvHandleElement (ps, CHARPROPEND, (void *) &achp, char_dirty);
840 		char_pendingclose = 0;
841 		char_fcLim = 0xffffffffL;
842 	    }
843 
844 #if 0
845 	  /*
846 	     I might have to rethink this closing tag enforcer for complex mode, have to think the
847 	     flow out a bit more, this section one is plain wrong, im leaving it here so i won't
848 	     forget and be tempted to put it back in :-)
849 	     if (j == section_fcLim)
850 	     {
851 	     wvHandleElement(ps, SECTIONEND, (void*)&sep,section_dirty);
852 	     section_pendingclose=0;
853 	     }
854 	   */
855 #endif
856       }
857 
858  finish_processing:
859     if (char_pendingclose)
860       {
861 	  wvInitCHP (&achp);
862 	  wvHandleElement (ps, CHARPROPEND, (void *) &achp, char_dirty);
863       }
864 
865     if (comment_pendingclose)
866 	wvHandleElement (ps, COMMENTEND, (void *) catrd, 0);
867 
868     if (para_pendingclose)
869       {
870 	  wvInitPAP (&apap);
871 	  wvHandleElement (ps, PARAEND, (void *) &apap, para_dirty);
872       }
873 
874     if (section_pendingclose)
875 	wvHandleElement (ps, SECTIONEND, (void *) &sep, section_dirty);
876 
877     wvFree (ps->fspa);
878     wvFree (ps->fspapos);
879     wvFree (ps->fdoa);
880     wvFree (ps->fdoapos);
881 
882     wvFree (posBKL);
883     wvFree (bkl);
884     wvFree (posBKF);
885     wvFree (bkf);
886     wvFree (posAtrd);
887     wvFree (atrd);
888 
889     wvReleasePAPX_FKP (&para_fkp);
890     wvReleaseCHPX_FKP (&char_fkp);
891 
892     wvHandleDocument (ps, DOCEND);
893     wvFree (posSedx);
894     wvFree (sed);
895 
896     wvFree (ps->liststartnos);
897     wvFree (ps->listnfcs);
898     for (i = 0; i < 9 * ps->nolfo; i++)
899 	wvReleaseLVL (&(ps->finallvl[i]));
900     wvFree (ps->finallvl);
901 
902     wvReleaseLST (&ps->lst, ps->noofLST);
903     wvReleaseLFO_records (&ps->lfo, &ps->lfolvl, &ps->lvl, ps->nooflvl);
904     wvReleaseSTTBF (&ps->anSttbfAssoc);
905 
906     wvFree (btePapx);
907     wvFree (posPapx);
908     wvFree (bteChpx);
909     wvFree (posChpx);
910     wvReleaseCLX (&ps->clx);
911     wvReleaseFFN_STTBF (&ps->fonts);
912     wvReleaseSTSH (&ps->stsh);
913     wvReleaseSTTBF (&SttbfAtnbkmk);
914     wvReleaseSTTBF (&grpXstAtnOwners);
915     if (ps->vmerges)
916       {
917 	  for (i = 0; i < ps->norows; i++)
918 	      wvFree (ps->vmerges[i]);
919 	  wvFree (ps->vmerges);
920       }
921     wvFree (ps->cellbounds);
922 	wvOLEFree(ps);
923     tokenTreeFreeAll ();
924 }
925 
926 /*
927  The process thus far has created a SEP that describes what the section properties of
928  the section at the last full save.
929 
930  1) Now apply any section sprms that were linked to the piece that contains the
931  section's section mark.
932 
933  2) If pcd.prm.fComplex is 0, pcd.prm contains 1 sprm which should be applied to
934  the local SEP if it is a section sprm.
935 
936  3) If pcd.prm.fComplex is 1, pcd.prm.igrpprl is the index of a grpprl in the CLX.
937  If that grpprl contains any section sprms, they should be applied to the local SEP
938 */
939 int
wvGetComplexSEP(wvVersion ver,SEP * sep,U32 cpiece,STSH * stsh,CLX * clx)940 wvGetComplexSEP (wvVersion ver, SEP * sep, U32 cpiece, STSH * stsh, CLX * clx)
941 {
942     int ret = 0;
943     U16 sprm, pos = 0, i = 0;
944     U8 *pointer;
945     U16 index;
946     U8 val;
947     Sprm RetSprm;
948 
949     if (clx->pcd[cpiece].prm.fComplex == 0)
950       {
951 	  val = clx->pcd[cpiece].prm.para.var1.val;
952 	  pointer = &val;
953 #ifdef SPRMTEST
954 	  wvError (("singleton\n", clx->pcd[cpiece].prm.para.var1.isprm));
955 #endif
956 	  RetSprm =
957 	      wvApplySprmFromBucket (ver,
958 				     (U16) wvGetrgsprmPrm ( (U16) clx->pcd[cpiece].prm.
959 						     para.var1.isprm), NULL,
960 				     NULL, sep, stsh, pointer, &pos, NULL);
961 	  if (RetSprm.sgc == sgcSep)
962 	      ret = 1;
963       }
964     else
965       {
966 	  index = clx->pcd[cpiece].prm.para.var2.igrpprl;
967 #ifdef SPRMTEST
968 	  fprintf (stderr, "\n");
969 	  while (i < clx->cbGrpprl[index])
970 	    {
971 		fprintf (stderr, "%x (%d)\n", *(clx->grpprl[index] + i),
972 			 *(clx->grpprl[index] + i));
973 		i++;
974 	    }
975 	  fprintf (stderr, "\n");
976 	  i = 0;
977 #endif
978 	  while (i < clx->cbGrpprl[index])
979 	    {
980 		if (ver == WORD8)
981 		    sprm = bread_16ubit (clx->grpprl[index] + i, &i);
982 		else
983 		  {
984 		      sprm = bread_8ubit (clx->grpprl[index] + i, &i);
985 		      sprm = (U8) wvGetrgsprmWord6 ( (U8) sprm);
986 		  }
987 		pointer = clx->grpprl[index] + i;
988 		RetSprm =
989 		    wvApplySprmFromBucket (ver, sprm, NULL, NULL, sep, stsh,
990 					   pointer, &i, NULL);
991 		if (RetSprm.sgc == sgcSep)
992 		    ret = 1;
993 	    }
994       }
995     return (ret);
996 }
997 
998 /*
999 The process thus far has created a PAP that describes
1000 what the paragraph properties of the paragraph were at the last full save.
1001 
1002 1) Now it's necessary to apply any paragraph sprms that were linked to the
1003 piece that contains the paragraph's paragraph mark.
1004 
1005 2) If pcd.prm.fComplex is 0, pcd.prm contains 1 sprm which should only be
1006 applied to the local PAP if it is a paragraph sprm.
1007 
1008 3) If pcd.prm.fComplex is 1, pcd.prm.igrpprl is the index of a grpprl in the
1009 CLX.  If that grpprl contains any paragraph sprms, they should be applied to
1010 the local PAP.
1011 */
1012 int
wvAssembleComplexPAP(wvVersion ver,PAP * apap,U32 cpiece,wvParseStruct * ps)1013 wvAssembleComplexPAP (wvVersion ver, PAP * apap, U32 cpiece, wvParseStruct *ps)
1014 {
1015     int ret = 0;
1016     U16 sprm, pos = 0, i = 0;
1017     U8 sprm8;
1018     U8 *pointer;
1019     U16 index;
1020     U8 val;
1021     Sprm RetSprm;
1022 
1023     if (ps->clx.pcd[cpiece].prm.fComplex == 0)
1024       {
1025 	  val = ps->clx.pcd[cpiece].prm.para.var1.val;
1026 	  pointer = &val;
1027 #ifdef SPRMTEST
1028 	  wvError (("singleton\n", ps->clx.pcd[cpiece].prm.para.var1.isprm));
1029 #endif
1030 	  RetSprm =
1031 	      wvApplySprmFromBucket (ver,
1032 				     (U16) wvGetrgsprmPrm ( (U16) ps->clx.pcd[cpiece].prm.
1033 						     para.var1.isprm), apap,
1034 				     NULL, NULL, &ps->stsh, pointer, &pos, ps->data);
1035 	  if (RetSprm.sgc == sgcPara)
1036 	      ret = 1;
1037       }
1038     else
1039       {
1040 	  index = ps->clx.pcd[cpiece].prm.para.var2.igrpprl;
1041 #ifdef SPRMTEST
1042 	  wvError (("HERE-->\n"));
1043 	  fprintf (stderr, "\n");
1044 	  for (i = 0; i < ps->clx.cbGrpprl[index]; i++)
1045 	      fprintf (stderr, "%x ", *(ps->clx.grpprl[index] + i));
1046 	  fprintf (stderr, "\n");
1047 	  i = 0;
1048 #endif
1049 	  while (i < ps->clx.cbGrpprl[index])
1050 	    {
1051 		if (ver == WORD8)
1052 		    sprm = bread_16ubit (ps->clx.grpprl[index] + i, &i);
1053 		else
1054 		  {
1055 		      sprm8 = bread_8ubit (ps->clx.grpprl[index] + i, &i);
1056 		      sprm = (U16) wvGetrgsprmWord6 (sprm8);
1057 		      wvTrace (("sprm is %x\n", sprm));
1058 		  }
1059 		pointer = ps->clx.grpprl[index] + i;
1060 		RetSprm =
1061 		    wvApplySprmFromBucket (ver, sprm, apap, NULL, NULL, &ps->stsh,
1062 					   pointer, &i, ps->data);
1063 		if (RetSprm.sgc == sgcPara)
1064 		    ret = 1;
1065 	    }
1066       }
1067     return (ret);
1068 }
1069 
1070 /* CHP version of the above. follows the same rules -JB */
1071 int
wvAssembleComplexCHP(wvVersion ver,CHP * achp,U32 cpiece,STSH * stsh,CLX * clx)1072 wvAssembleComplexCHP (wvVersion ver, CHP * achp, U32 cpiece, STSH * stsh,
1073 		      CLX * clx)
1074 {
1075     int ret = 0;
1076     U16 sprm, pos = 0, i = 0;
1077     U8 sprm8;
1078     U8 *pointer;
1079     U16 index;
1080     U8 val;
1081     Sprm RetSprm;
1082 
1083     if (clx->pcd[cpiece].prm.fComplex == 0)
1084       {
1085 	  val = clx->pcd[cpiece].prm.para.var1.val;
1086 	  pointer = &val;
1087 #ifdef SPRMTEST
1088 	  wvError (("singleton %d\n", clx->pcd[cpiece].prm.para.var1.isprm));
1089 #endif
1090 	  RetSprm =
1091 	      wvApplySprmFromBucket (ver,
1092 				     (U16) wvGetrgsprmPrm ( (U16) clx->pcd[cpiece].prm.
1093 						     para.var1.isprm), NULL,
1094 				     achp, NULL, stsh, pointer, &pos, NULL);
1095 	  if (RetSprm.sgc == sgcChp)
1096 	      ret = 1;
1097       }
1098     else
1099       {
1100 	  index = clx->pcd[cpiece].prm.para.var2.igrpprl;
1101 #ifdef SPRMTEST
1102 	  fprintf (stderr, "\n");
1103 	  for (i = 0; i < clx->cbGrpprl[index]; i++)
1104 	      fprintf (stderr, "%x ", *(clx->grpprl[index] + i));
1105 	  fprintf (stderr, "\n");
1106 	  i = 0;
1107 #endif
1108 	  while (i < clx->cbGrpprl[index])
1109 	    {
1110 		if (ver == WORD8)
1111 		    sprm = bread_16ubit (clx->grpprl[index] + i, &i);
1112 		else
1113 		  {
1114 		      sprm8 = bread_8ubit (clx->grpprl[index] + i, &i);
1115 		      sprm = (U16) wvGetrgsprmWord6 (sprm8);
1116 		  }
1117 		pointer = clx->grpprl[index] + i;
1118 		RetSprm =
1119 		    wvApplySprmFromBucket (ver, sprm, NULL, achp, NULL, stsh,
1120 					   pointer, &i, NULL);
1121 		if (RetSprm.sgc == sgcChp)
1122 		    ret = 1;
1123 	    }
1124       }
1125     return (ret);
1126 }
1127