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 #include "wvinternal.h"
28 
29 /*
30 how this works,
31 we seek to the beginning of the text, we loop for a count of charaters that is stored in the fib.
32 
33 the piecetable divides the text up into various sections, we keep track of our location vs
34 the next entry in that table, when we reach that location, we seek to the position that
35 the table tells us to go.
36 
37 there are special cases for coming to the end of a section, and for the beginning and ends of
38 pages. for the purposes of headers and footers etc.
39 */
40 void
wvDecodeSimple(wvParseStruct * ps,subdocument whichdoc)41 wvDecodeSimple (wvParseStruct * ps, subdocument whichdoc)
42 {
43     PAPX_FKP para_fkp;
44     CHPX_FKP char_fkp;
45     PAP apap;
46     CHP achp;
47     U32 piececount = 0, i, j = 0, spiece;
48     U32 beginfc, endfc;
49 	U32 stream_size;
50     U32 begincp, endcp;
51     int ichartype;
52     U8  chartype;
53     U16 eachchar;
54     U32 para_fcFirst, para_fcLim = 0xffffffff;
55     U32 dummy, nextpara_fcLim = 0xffffffff;
56     U32 char_fcFirst, char_fcLim = 0xffffffff;
57     U32 section_fcFirst, section_fcLim = 0xffffffff;
58     U32 comment_cpFirst = 0xffffffffL, comment_cpLim = 0xffffffffL;
59     BTE *btePapx, *bteChpx;
60     U32 *posPapx, *posChpx;
61     U32 para_intervals, char_intervals, section_intervals, atrd_intervals;
62     int para_pendingclose = 0, char_pendingclose = 0, section_pendingclose =
63 	0, comment_pendingclose = 0;
64     int para_dirty = 0, char_dirty = 0, section_dirty = 0;
65     SED *sed;
66     SEP sep;
67     U32 *posSedx;
68     ATRD *atrd, *catrd = NULL;
69     U32 *posAtrd;
70     STTBF grpXstAtnOwners, SttbfAtnbkmk;
71     BKF *bkf;
72     U32 *posBKF;
73     U32 bkf_intervals;
74     BKL *bkl;
75     U32 *posBKL;
76     U32 bkl_intervals;
77     FTXBXS *ftxbx;
78     U32 *txbxTxt;
79     U32 txbxTxt_intervals;
80     BKD *bkd;
81     U32 *posBKD;
82     U32 bkd_intervals;
83     wvVersion ver;
84 
85     external_wvReleasePAPX_FKP ();
86     external_wvReleaseCHPX_FKP ();
87 
88     ver = wvQuerySupported (&ps->fib, NULL);
89 
90 
91     /*
92        despite what some parts of the spec might have you believe you still need to
93        get the piecetable from even simple files, some simple files can have 8bit
94        chars in one part, and 16bit chars in another, so you have to watch out for
95        that
96      */
97     wvGetCLX (ver, &ps->clx, ps->fib.fcClx, (U32) ps->fib.lcbClx,
98 	      (U8) ps->fib.fExtChar, ps->tablefd);
99     /* for word 6 and just in case */
100     if (ps->clx.nopcd == 0)
101 	wvBuildCLXForSimple6 (&ps->clx, &ps->fib);
102 
103     para_fcFirst = char_fcFirst = section_fcFirst = wvGetBeginFC (ps, whichdoc);
104     /*we will need the stylesheet to do anything useful with layout and look */
105     wvGetSTSH (&ps->stsh, ps->fib.fcStshf, ps->fib.lcbStshf, ps->tablefd);
106 
107     /*dop */
108     wvGetDOP (ver, &ps->dop, ps->fib.fcDop, ps->fib.lcbDop, ps->tablefd);
109     wvTrace (("tabstops are every %d twips\n", ps->dop.dxaTab));
110 
111     /*textbox information */
112     wvGetFTXBXS_PLCF (&ftxbx, &txbxTxt, &txbxTxt_intervals,
113 		      ps->fib.fcPlcftxbxTxt, ps->fib.lcbPlcftxbxTxt,
114 		      ps->tablefd);
115     wvGetBKD_PLCF (&bkd, &posBKD, &bkd_intervals, ps->fib.fcPlcftxbxBkd,
116 		   ps->fib.lcbPlcftxbxBkd, ps->tablefd);
117 
118 
119     /* this mountain of informatio is just to get comments organized */
120     wvGetATRD_PLCF (&atrd, &posAtrd, &atrd_intervals, ps->fib.fcPlcfandRef,
121 		    ps->fib.lcbPlcfandRef, ps->tablefd);
122     wvGetGrpXst (&grpXstAtnOwners, ps->fib.fcGrpXstAtnOwners,
123 		 ps->fib.lcbGrpXstAtnOwners, ps->tablefd);
124     wvTrace (
125 	     ("offset is %x, len is %d\n", ps->fib.fcSttbfAtnbkmk,
126 	      ps->fib.lcbSttbfAtnbkmk));
127     wvGetSTTBF (&SttbfAtnbkmk, ps->fib.fcSttbfAtnbkmk,
128 		ps->fib.lcbSttbfAtnbkmk, ps->tablefd);
129     wvGetBKF_PLCF (&bkf, &posBKF, &bkf_intervals, ps->fib.fcPlcfAtnbkf,
130 		   ps->fib.lcbPlcfAtnbkf, ps->tablefd);
131     wvGetBKL_PLCF (&bkl, &posBKL, &bkl_intervals, ps->fib.fcPlcfAtnbkl,
132            ps->fib.lcbPlcfAtnbkl,ps->fib.fcPlcfAtnbkf, ps->fib.lcbPlcfAtnbkf,
133            ps->tablefd);
134 
135 
136     /* get font list */
137     if ((ver == WORD6)
138 	|| (ver == WORD7))
139 	wvGetFFN_STTBF6 (&ps->fonts, ps->fib.fcSttbfffn, ps->fib.lcbSttbfffn,
140 			 ps->tablefd);
141     else
142 	wvGetFFN_STTBF (&ps->fonts, ps->fib.fcSttbfffn, ps->fib.lcbSttbfffn,
143 			ps->tablefd);
144 
145     /*we will need the table of names to answer questions like the name of the doc */
146     if ((ver == WORD6)
147 	|| (ver == WORD7))
148       {
149 	  wvGetSTTBF6 (&ps->anSttbfAssoc, ps->fib.fcSttbfAssoc,
150 		       ps->fib.lcbSttbfAssoc, ps->tablefd);
151 	  wvGetSTTBF6 (&ps->Sttbfbkmk, ps->fib.fcSttbfbkmk,
152 		       ps->fib.lcbSttbfbkmk, ps->tablefd);
153       }
154     else			/*word 97 */
155       {
156 	  wvGetSTTBF (&ps->anSttbfAssoc, ps->fib.fcSttbfAssoc,
157 		      ps->fib.lcbSttbfAssoc, ps->tablefd);
158 	  wvGetSTTBF (&ps->Sttbfbkmk, ps->fib.fcSttbfbkmk,
159 		      ps->fib.lcbSttbfbkmk, ps->tablefd);
160       }
161 
162     /*Extract all the list information that we will need to handle lists later on */
163     wvGetLST (&ps->lst, &ps->noofLST, ps->fib.fcPlcfLst, ps->fib.lcbPlcfLst,
164 	      ps->tablefd);
165     wvGetLFO_records (&ps->lfo, &ps->lfolvl, &ps->lvl, &ps->nolfo,
166 		      &ps->nooflvl, ps->fib.fcPlfLfo, ps->fib.lcbPlfLfo,
167 		      ps->tablefd);
168     /* init the starting list number table */
169     if (ps->nolfo)
170       {
171 	  ps->liststartnos = (U32 *) wvMalloc (9 * ps->nolfo * sizeof (U32));
172 	  ps->listnfcs = (U8 *) wvMalloc (9 * ps->nolfo);
173 	  ps->finallvl = (LVL *) wvMalloc (9 * ps->nolfo * sizeof (LVL));
174 	  for (i = 0; i < 9 * ps->nolfo; i++)
175 	    {
176 		ps->liststartnos[i] = 0xffffffffL;
177 		ps->listnfcs[i] = 0xff;
178 		wvInitLVL (&(ps->finallvl[i]));
179 	    }
180       }
181     else
182       {
183 	  ps->liststartnos = NULL;
184 	  ps->listnfcs = NULL;
185 	  ps->finallvl = NULL;
186       }
187     /*Extract Graphic Information */
188     wvGetFSPA_PLCF (&ps->fspa, &ps->fspapos, &ps->nooffspa,
189 		    ps->fib.fcPlcspaMom, ps->fib.lcbPlcspaMom, ps->tablefd);
190     wvGetFDOA_PLCF (&ps->fdoa, &ps->fdoapos, &ps->nooffdoa,
191 		    ps->fib.fcPlcdoaMom, ps->fib.lcbPlcdoaMom, ps->tablefd);
192 
193 
194 
195     /*
196        we will need the paragraph and character bounds table to make decisions as
197        to where a para/char run begins and ends
198      */
199     if ((ver == WORD6)
200 	|| (ver == WORD7))
201       {
202 	  wvGetBTE_PLCF6 (&btePapx, &posPapx, &para_intervals,
203 			  ps->fib.fcPlcfbtePapx, ps->fib.lcbPlcfbtePapx,
204 			  ps->tablefd);
205 	  wvGetBTE_PLCF6 (&bteChpx, &posChpx, &char_intervals,
206 			  ps->fib.fcPlcfbteChpx, ps->fib.lcbPlcfbteChpx,
207 			  ps->tablefd);
208       }
209     else			/* word 97 */
210       {
211 	  wvGetBTE_PLCF (&btePapx, &posPapx, &para_intervals,
212 			 ps->fib.fcPlcfbtePapx, ps->fib.lcbPlcfbtePapx,
213 			 ps->tablefd);
214 	  wvGetBTE_PLCF (&bteChpx, &posChpx, &char_intervals,
215 			 ps->fib.fcPlcfbteChpx, ps->fib.lcbPlcfbteChpx,
216 			 ps->tablefd);
217       }
218 
219     wvGetSED_PLCF (&sed, &posSedx, &section_intervals, ps->fib.fcPlcfsed,
220 		   ps->fib.lcbPlcfsed, ps->tablefd);
221     wvTrace (("section_intervals is %d\n", section_intervals));
222 
223     /*
224        The text of the file starts at fib.fcMin, but we will use the piecetable
225        records rather than this basic seek.
226        fseek(ps->mainfd,ps->fib.fcMin,SEEK_SET);
227      */
228 
229     /*
230        If !fib.fComplex, the document text stream is represented by the text
231        beginning at fib.fcMin up to (but not including) fib.fcMac.
232      */
233 
234     if ((ver == WORD2) && !ps->fib.fComplex)
235       {
236 	  wvHandleDocument (ps, DOCBEGIN);
237 	  wvStream_goto (ps->mainfd, ps->fib.fcMin);
238 	  for (i = ps->fib.fcMin; i < ps->fib.fcMac; i++)
239 	    {
240 		eachchar = wvGetChar (ps->mainfd, 1);
241 		(*(ps->charhandler)) (ps, eachchar, 1, ps->fib.lid);
242 		/* (*(ps->scharhandler))(ps,eachchar,&achp;  no go */
243 		/* wvOutputTextChar(eachchar, 1, ps, &achp); no go */
244 		/* Formatting still lacking. This is just a start. */
245 	    }
246 	  wvHandleDocument (ps, DOCEND);
247 	  wvReleaseSTTBF (&ps->anSttbfAssoc);
248 	  wvReleaseSTTBF (&ps->Sttbfbkmk);
249 	  wvFree (posChpx);
250 	  wvFree (bteChpx);
251 	  wvFree (btePapx);
252 	  wvReleaseCLX (&ps->clx);
253 	  wvReleaseSTSH (&ps->stsh);
254 	  return;
255       }
256 
257 
258 #ifdef DEBUG
259     if (ps->fib.fcMac != wvGetEndFCPiece (ps->clx.nopcd - 1, &ps->clx))
260 	wvTrace (
261 		 ("fcMac is not the same as the piecetable %x %x!\n",
262 		  ps->fib.fcMac, wvGetEndFCPiece (ps->clx.nopcd - 1,
263 						  &ps->clx)));
264 #endif
265 
266     wvInitPAPX_FKP (&para_fkp);
267     wvInitCHPX_FKP (&char_fkp);
268 
269     if(wvHandleDocument (ps, DOCBEGIN))
270 		goto  finish_processing;
271 
272 
273 	/*get stream size for bounds checking*/
274 	stream_size = wvStream_size(ps->mainfd);
275 
276     /*for each piece */
277     for (piececount = 0; piececount < ps->clx.nopcd; piececount++)
278       {
279 	  ichartype =
280 	      wvGetPieceBoundsFC (&beginfc, &endfc, &ps->clx, piececount);
281 	  if(ichartype==-1)
282 		  break;
283 	  chartype = (U8) ichartype;
284 	  /*lvm007@aha.ru fix antiloop: check stream size */
285 	  if(beginfc>stream_size || endfc>stream_size){
286 		  wvError (
287 		   ("Piece Bounds out of range!, its a disaster\n"));
288 		  continue;
289 	  }
290 
291 	  wvStream_goto (ps->mainfd, beginfc);
292 
293 	  wvTrace (("SEEK %x\n", beginfc));
294 
295 	  /*lvm007@aha.ru fix antiloop fix*/
296 	  if(wvGetPieceBoundsCP (&begincp, &endcp, &ps->clx, piececount)==-1)
297 		  break;
298 
299 	  /*
300 	     text that is not in the same piece is not guaranteed to have the same properties as
301 	     the rest of the exception run, so force a stop and restart of these properties.
302 	   */
303 	  char_fcLim = beginfc;
304 	  wvTrace (("%d %d %d\n", begincp, endcp, ps->fib.ccpText));
305 	  for (i = begincp, j = beginfc; (i < endcp /*&& i<ps->fib.ccpText */ );
306 	       i++, j += wvIncFC (chartype))
307 	    {
308 		/* character properties */
309 		if (j == char_fcLim)
310 		  {
311 		      wvHandleElement (ps, CHARPROPEND, (void *) &achp,
312 				       char_dirty);
313 		      char_pendingclose = 0;
314 		  }
315 
316 		/* comment ending location */
317 		if (i == comment_cpLim)
318 		  {
319 		      wvHandleElement (ps, COMMENTEND, (void *) catrd, 0);
320 		      comment_pendingclose = 0;
321 		  }
322 
323 
324 		/* paragraph properties */
325 		if (j == para_fcLim)
326 		  {
327 		      wvHandleElement (ps, PARAEND, (void *) &apap, para_dirty);
328 		      para_pendingclose = 0;
329 		  }
330 
331 		if (j == section_fcLim)
332 		  {
333 		      wvHandleElement (ps, SECTIONEND, (void *) &sep,
334 				       section_dirty);
335 		      section_pendingclose = 0;
336 		  }
337 
338 		if ((section_fcLim == 0xffffffff) || (section_fcLim == j))
339 		  {
340 		      wvTrace (("j i is %x %d\n", j, i));
341 		      section_dirty =
342 			  wvGetSimpleSectionBounds (ver, ps,
343 						    &sep, &section_fcFirst,
344 						    &section_fcLim, i,
345 						    &ps->clx, sed, &spiece,
346 						    posSedx,
347 						    section_intervals,
348 						    &ps->stsh, ps->mainfd);
349 		      wvTrace (
350 			       ("section begins at %x ends %x\n",
351 				section_fcFirst, section_fcLim));
352 		  }
353 
354 		if (j == section_fcFirst)
355 		  {
356 		      wvHandleElement (ps, SECTIONBEGIN, (void *) &sep,
357 				       section_dirty);
358 		      section_pendingclose = 1;
359 		  }
360 
361 		if ((para_fcLim == 0xffffffff) || (para_fcLim == j))
362 		  {
363 		      wvReleasePAPX_FKP (&para_fkp);
364 		      wvGetSimpleParaBounds (ver, &para_fkp,
365 					     &para_fcFirst, &para_fcLim,
366 					     wvConvertCPToFC (i, &ps->clx),
367 					     btePapx, posPapx, para_intervals,
368 					     ps->mainfd);
369 		      wvTrace (
370 			       ("Para from %x to %x, j is %x\n", para_fcFirst,
371 				para_fcLim, j));
372 
373 		      if (0 == para_pendingclose)
374 			{
375 			    /*
376 			       if there's no paragraph open, but there should be then I believe that the fcFirst search
377 			       has failed me, so I set it to now. I need to investigate this further. I believe it occurs
378 			       when a the last piece ended simultaneously with the last paragraph, and that the algorithm
379 			       for finding the beginning of a para breaks under that condition. I need more examples to
380 			       be sure, but it happens is very large complex files so its hard to find
381 			     */
382 			    if (j != para_fcFirst)
383 			      {
384 				  wvWarning (
385 					     ("There is no paragraph due to open but one should be, plugging the gap.\n"));
386 				  para_fcFirst = j;
387 			      }
388 			}
389 		  }
390 
391 		if (j == para_fcFirst)
392 		  {
393 		      para_dirty =
394 			  wvAssembleSimplePAP (ver, &apap, para_fcLim, &para_fkp, ps);
395 
396 		      /* test section */
397 		      wvReleasePAPX_FKP (&para_fkp);
398 		      wvGetSimpleParaBounds (ver, &para_fkp,
399 					     &dummy, &nextpara_fcLim,
400 					     para_fcLim, btePapx, posPapx,
401 					     para_intervals, ps->mainfd);
402 		      wvAssembleSimplePAP (ver, &ps->nextpap, nextpara_fcLim, &para_fkp, ps);
403 		      /* end test section */
404 
405 		      if ((apap.fInTable) && (!apap.fTtp))
406 			{
407 			    wvGetFullTableInit (ps, para_intervals, btePapx,
408 						posPapx);
409 			    wvGetRowTap (ps, &apap, para_intervals, btePapx,
410 					 posPapx);
411 			}
412 		      else if (apap.fInTable == 0)
413 			  ps->intable = 0;
414 		      wvHandleElement (ps, PARABEGIN, (void *) &apap,
415 				       para_dirty);
416 
417 		      char_fcLim = j;
418 		      para_pendingclose = 1;
419 		  }
420 
421 		if ((comment_cpLim == 0xffffffffL) || (comment_cpLim == i))
422 		  {
423 		      wvTrace (
424 			       ("searching for the next comment begin cp is %d\n",
425 				i));
426 		      catrd =
427 			  wvGetCommentBounds (&comment_cpFirst,
428 					      &comment_cpLim, i, atrd,
429 					      posAtrd, atrd_intervals,
430 					      &SttbfAtnbkmk, bkf, posBKF,
431 					      bkf_intervals, bkl, posBKL,
432 					      bkl_intervals);
433 		      wvTrace (
434 			       ("begin and end are %d %d\n", comment_cpFirst,
435 				comment_cpLim));
436 		  }
437 
438 		if (i == comment_cpFirst)
439 		  {
440 		      wvHandleElement (ps, COMMENTBEGIN, (void *) catrd, 0);
441 		      comment_pendingclose = 1;
442 		  }
443 
444 
445 		if ((char_fcLim == 0xffffffff) || (char_fcLim == j))
446 		  {
447 		      wvTrace (("j i is %x %d\n", j, i));
448 		      wvReleaseCHPX_FKP (&char_fkp);
449 		      wvGetSimpleCharBounds (ver, &char_fkp,
450 					     &char_fcFirst, &char_fcLim, i,
451 					     &ps->clx, bteChpx, posChpx,
452 					     char_intervals, ps->mainfd);
453 		      wvTrace (
454 			       ("char begins at %x ends %x, j is %x\n",
455 				char_fcFirst, char_fcLim, j));
456 		      if (0 == char_pendingclose)
457 			{
458 			    /*
459 			       if there's no character run open, but there should be then I believe that the fcFirst search
460 			       has failed me, so I set it to now. I need to investigate this further.
461 			     */
462 			    if (j != char_fcFirst)
463 			      {
464 				  wvWarning (
465 					     ("There is no character run due to open but one should be, plugging the gap.\n"));
466 				  char_fcFirst = j;
467 			      }
468 
469 			}
470 		      else{
471   			/* lvm007@aha.ru fix: if currentfc>fcFirst but CHARPROP's changed look examples/charprops.doc*/
472 			if(char_fcFirst< j)
473 				char_fcFirst = j;
474 		       }
475 		  }
476 
477 		if (j == char_fcFirst)
478 		  {
479 		      wvTrace (("assembling CHP...\n"));
480 		      /* a CHP's base style is in the para style */
481 		      /* achp.istd = apap.istd; */
482 		      char_dirty =
483 				  wvAssembleSimpleCHP (ver, &achp, &apap,
484 					       char_fcLim, &char_fkp,
485 					       &ps->stsh);
486 		      wvTrace (("CHP assembled.\n"));
487 		      wvTrace (("font is %d\n", achp.ftcAscii));
488 		      wvTrace (("char spec is %d\n", achp.ftcSym));
489 		      wvHandleElement (ps, CHARPROPBEGIN, (void *) &achp,
490 				       char_dirty);
491 		      wvTrace (("char lid is %x\n", achp.lidDefault));
492 		      char_pendingclose = 1;
493 		  }
494 
495 		eachchar = wvGetChar (ps->mainfd, chartype);
496 
497 		if ((eachchar == 0x07) && (!achp.fSpec))
498 		    ps->endcell = 1;
499 
500 		ps->currentcp = i;
501 		wvTrace (("char pos is %x %x\n", j, eachchar));
502 		wvOutputTextChar (eachchar, chartype, ps, &achp);
503 	    }
504 
505 	  if (j == para_fcLim)
506 	    {
507 		wvHandleElement (ps, PARAEND, (void *) &apap, para_dirty);
508 		para_pendingclose = 0;
509 		para_fcLim = 0xffffffffL;
510 	    }
511 
512 	  if (i == comment_cpLim)
513 	    {
514 		wvHandleElement (ps, COMMENTEND, (void *) catrd, 0);
515 		comment_pendingclose = 0;
516 		comment_cpLim = 0xffffffffL;
517 	    }
518 
519 	  if (j == char_fcLim)
520 	    {
521 		wvHandleElement (ps, CHARPROPEND, (void *) &achp, char_dirty);
522 		char_pendingclose = 0;
523 		char_fcLim = 0xffffffffL;
524 	    }
525 
526       }
527 
528  finish_processing:
529     if (char_pendingclose)
530       {
531 	  wvInitCHP (&achp);
532 	  wvHandleElement (ps, CHARPROPEND, (void *) &achp, char_dirty);
533       }
534 
535     if (comment_pendingclose)
536 	wvHandleElement (ps, COMMENTEND, (void *) catrd, 0);
537 
538     if (para_pendingclose)
539       {
540 	  wvInitPAP (&apap);
541 	  wvHandleElement (ps, PARAEND, (void *) &apap, para_dirty);
542       }
543 
544     if (section_pendingclose)
545 	wvHandleElement (ps, SECTIONEND, (void *) &sep, section_dirty);
546 
547     wvFree (ps->fspa);
548     wvFree (ps->fspapos);
549     wvFree (ps->fdoa);
550     wvFree (ps->fdoapos);
551 
552     wvFree (posBKL);
553     wvFree (bkl);
554     wvFree (posBKF);
555     wvFree (bkf);
556     wvFree (posAtrd);
557     wvFree (atrd);
558 
559     internal_wvReleasePAPX_FKP (&para_fkp);
560     internal_wvReleaseCHPX_FKP (&char_fkp);
561     wvHandleDocument (ps, DOCEND);
562     wvFree (posSedx);
563     wvFree (sed);
564     wvFree(bkd);
565     wvFree(posBKD);
566     wvFree(ftxbx);
567     wvFree(txbxTxt);
568 #if defined(WIN32)
569    wvReleasePAPX_FKP (&para_fkp);
570    wvReleaseCHPX_FKP (&char_fkp);
571 
572    external_wvReleasePAPX_FKP ();
573    external_wvReleaseCHPX_FKP();
574 #endif
575 
576 
577     wvFree (ps->liststartnos);
578     wvFree (ps->listnfcs);
579     for (i = 0; i < 9 * ps->nolfo; i++)
580 	wvReleaseLVL (&(ps->finallvl[i]));
581     wvFree (ps->finallvl);
582 
583     wvReleaseLST (&ps->lst, ps->noofLST);
584     wvReleaseLFO_records (&ps->lfo, &ps->lfolvl, &ps->lvl, ps->nooflvl);
585     wvReleaseSTTBF (&ps->anSttbfAssoc);
586     wvReleaseSTTBF (&ps->Sttbfbkmk);
587     wvFree (btePapx);
588     wvFree (posPapx);
589     wvFree (bteChpx);
590     wvFree (posChpx);
591     wvFree (bkd);
592     wvFree (posBKD);
593     wvFree (txbxTxt);
594     wvFree (ftxbx);
595 #if 0
596     /*
597        so what, this is meaningless
598        C.
599      */
600     if (ps->fib.fcMac != ftell (ps->mainfd))
601 	wvError (("fcMac did not match end of input !\n"));
602 #endif
603     wvReleaseCLX (&ps->clx);
604     wvReleaseFFN_STTBF (&ps->fonts);
605     wvReleaseSTSH (&ps->stsh);
606     wvReleaseSTTBF (&SttbfAtnbkmk);
607     wvReleaseSTTBF (&grpXstAtnOwners);
608     if (ps->vmerges)
609       {
610 	  for (i = 0; i < ps->norows; i++)
611 	      wvFree (ps->vmerges[i]);
612 	  wvFree (ps->vmerges);
613       }
614     wvFree (ps->cellbounds);
615 	wvOLEFree(ps);
616     tokenTreeFreeAll ();
617 }
618 
619 
620 /*
621 When a document is recorded in non-complex format, the bounds of the
622 paragraph that contains a particular character can be found by
623 
624 1) calculating the FC coordinate of the character,
625 
626 2) searching the bin table to find an FKP page that describes that FC,
627 
628 3) fetching that FKP, and
629 
630 4) then searching the FKP to find the interval in the rgfc that encloses the character.
631 
632 5) The bounds of the interval are the fcFirst and fcLim of the containing paragraph.
633 
634 Every character greater than or equal to fcFirst and less than fcLim is part of
635 the containing paragraph.
636 
637 */
638 int
wvGetSimpleParaBounds(wvVersion ver,PAPX_FKP * fkp,U32 * fcFirst,U32 * fcLim,U32 currentfc,BTE * bte,U32 * pos,int nobte,wvStream * fd)639 wvGetSimpleParaBounds (wvVersion ver, PAPX_FKP * fkp, U32 * fcFirst,
640 		       U32 * fcLim, U32 currentfc, BTE * bte, U32 * pos,
641 		       int nobte, wvStream * fd)
642 {
643     BTE entry;
644     long currentpos;
645 
646     /*
647        currentfc = wvConvertCPToFC(currentcp,clx);
648      */
649 
650     wvTrace (("currentfc is %x\n", currentfc));
651     if (currentfc == 0xffffffffL)
652       {
653 	  wvError (("Para Bounds not found !\n"));
654 	  return (1);
655       }
656 
657     if (0 != wvGetBTE_FromFC (&entry, currentfc, bte, pos, nobte))
658       {
659 	  wvError (("BTE not found !\n"));
660 	  return (1);
661       }
662     currentpos = wvStream_tell (fd);
663     /*The pagenumber of the FKP is entry.pn */
664 
665     wvTrace (("pn is %d\n", entry.pn));
666     wvGetPAPX_FKP (ver, fkp, entry.pn, fd);
667     wvTrace (("last entry is %x\n", fkp->rgfc[fkp->crun]));
668     while (fkp->rgfc[fkp->crun] <= currentfc)
669       {
670 	  if ((fkp->rgfc[fkp->crun] == currentfc) && (currentfc == pos[nobte]))
671 	      break;
672 
673 	  /* Bad things man... */
674 	  wvError (("Alert, insane repeat \"insane\" paragraph structure,"
675 		    "making wild stab in the dark to attempt to continue\n"));
676 	  wvReleasePAPX_FKP (fkp);
677 	  entry.pn++;
678 	  wvGetPAPX_FKP (ver, fkp, entry.pn, fd);
679       }
680 
681     wvStream_goto (fd, currentpos);
682 
683     return (wvGetIntervalBounds
684 	    (fcFirst, fcLim, currentfc, fkp->rgfc, fkp->crun + 1));
685 }
686 
687 int
wvGetSimpleCharBounds(wvVersion ver,CHPX_FKP * fkp,U32 * fcFirst,U32 * fcLim,U32 currentcp,CLX * clx,BTE * bte,U32 * pos,int nobte,wvStream * fd)688 wvGetSimpleCharBounds (wvVersion ver, CHPX_FKP * fkp, U32 * fcFirst,
689 		       U32 * fcLim, U32 currentcp, CLX * clx, BTE * bte,
690 		       U32 * pos, int nobte, wvStream * fd)
691 {
692     U32 currentfc;
693     BTE entry;
694     long currentpos;
695 
696     currentfc = wvConvertCPToFC (currentcp, clx);
697 
698     if (currentfc == 0xffffffffL)
699       {
700 	  wvError (("Char Bounds not found !\n"));
701 	  return (1);
702       }
703 
704     wvTrace (("char fc is %x\n", currentfc));
705 
706     if (0 != wvGetBTE_FromFC (&entry, currentfc, bte, pos, nobte))
707       {
708 	  wvError (("BTE not found !\n"));
709 	  return (1);
710       }
711     currentpos = wvStream_tell (fd);
712     /*The pagenumber of the FKP is entry.pn */
713 
714     wvTrace (("pn is %d\n", entry.pn));
715     wvGetCHPX_FKP (ver, fkp, entry.pn, fd);
716 
717     while (fkp->rgfc[fkp->crun] <= currentfc)
718       {
719 	  if ((fkp->rgfc[fkp->crun] == currentfc) && (currentfc == pos[nobte]))
720 	      break;
721 
722 	  /* Bad things man... */
723 	  wvError (("Alert, insane repeat \"insane\" character run structure,"
724 		    "making wild stab in the dark to attempt to continue\n"));
725 	  wvReleaseCHPX_FKP (fkp);
726 	  entry.pn++;
727 	  wvGetCHPX_FKP (ver, fkp, entry.pn, fd);
728       }
729 
730     wvStream_goto (fd, currentpos);
731 
732     return (wvGetIntervalBounds
733 	    (fcFirst, fcLim, currentfc, fkp->rgfc, fkp->crun + 1));
734 }
735 
736 int
wvGetIntervalBounds(U32 * fcFirst,U32 * fcLim,U32 currentfc,U32 * rgfc,U32 nopos)737 wvGetIntervalBounds (U32 * fcFirst, U32 * fcLim, U32 currentfc, U32 * rgfc,
738 		     U32 nopos)
739 {
740     U32 i = 0;
741     while (i < nopos - 1)
742       {
743 	  wvTrace (
744 		   ("searching...%x %x %x\n", currentfc,
745 		    wvNormFC (rgfc[i], NULL), wvNormFC (rgfc[i + 1], NULL)));
746 	  /*
747 	     if ( (wvNormFC(rgfc[i],NULL) >= currentfc) && (currentfc <= wvNormFC(rgfc[i+1],NULL)) )
748 	   */
749 	  if ((currentfc >= wvNormFC (rgfc[i], NULL))
750 	      && (currentfc < wvNormFC (rgfc[i + 1], NULL)))
751 	    {
752 		*fcFirst = wvNormFC (rgfc[i], NULL);
753 		*fcLim = wvNormFC (rgfc[i + 1], NULL);
754 		return (0);
755 	    }
756 	  i++;
757       }
758     *fcFirst = wvNormFC (rgfc[nopos - 2], NULL);
759     *fcLim = wvNormFC (rgfc[nopos - 1], NULL);
760     wvTrace (("I'd rather not see this happen at all :-)\n"));
761     return (0);
762 }
763 
764 /*
765 it is necessary to use the CP of the character to search the
766 plcfsed for the index i of the largest CP that is less than or equal to the
767 character's CP.
768 
769 plcfsed.rgcp[i] is the CP of the first character of the
770 section and plcfsed.rgcp[i+1] is the CP of the character following the
771 section mark that terminates the section (call it cpLim).
772 
773 Then retrieve plcfsed.rgsed[i]. The FC in this SED gives the location where the SEPX for
774 the section is stored.
775 
776 Then create a local SEP with default section properties. If the
777 sed.fc != 0xFFFFFFFF, then the sprms within the SEPX that is stored at offset
778 sed.fc must be applied to the local SEP. The process thus far has created a
779 SEP that describes what the section properties of the section at the last
780 full save.
781 */
782 int
wvGetSimpleSectionBounds(wvVersion ver,wvParseStruct * ps,SEP * sep,U32 * fcFirst,U32 * fcLim,U32 cp,CLX * clx,SED * sed,U32 * spiece,U32 * posSedx,U32 section_intervals,STSH * stsh,wvStream * fd)783 wvGetSimpleSectionBounds (wvVersion ver, wvParseStruct * ps, SEP * sep,
784 			  U32 * fcFirst, U32 * fcLim, U32 cp, CLX * clx,
785 			  SED * sed, U32 * spiece, U32 * posSedx,
786 			  U32 section_intervals, STSH * stsh, wvStream * fd)
787 {
788     U32 i = 0;
789     int ret = 0;
790     SEPX sepx;
791     long pos = wvStream_tell (fd);
792     U32 cpTest = 0, j, dummy;
793 
794     if (section_intervals == 0)
795       {
796 	  wvGetPieceBoundsFC (fcFirst, &dummy, &ps->clx, 0);
797 	  wvGetPieceBoundsFC (&dummy, fcLim, &ps->clx, ps->clx.nopcd);
798 	  return (0);
799       }
800 
801     j = section_intervals - 1;
802 
803     if (cp == 0)
804 	j = 0;
805     while (i < section_intervals)
806       {
807 	  wvTrace (("searching for sep %d %d\n", posSedx[i], cp));
808 	  if ((posSedx[i] <= cp) && (posSedx[i] > cpTest))
809 	    {
810 		cpTest = posSedx[i];
811 		j = i;
812 		*spiece = wvGetPieceFromCP (cpTest, clx);
813 	    }
814 	  i++;
815       }
816 
817     wvTrace (("found at %d %d\n", posSedx[j], posSedx[j + 1]));
818     *fcFirst = wvConvertCPToFC (posSedx[j], clx);
819     *fcLim = wvConvertCPToFC (posSedx[j + 1], clx);
820     wvTrace (("found at %x %x\n", *fcFirst, *fcLim));
821 
822     wvInitSEP (sep);
823 
824     if (sed[j].fcSepx != 0xffffffffL)
825       {
826 	  wvStream_goto (fd, wvNormFC (sed[j].fcSepx, NULL));
827 	  wvGetSEPX (ver, &sepx, fd);
828 	  if (ver == WORD8)
829 	      ret = wvAddSEPXFromBucket (sep, &sepx, stsh);
830 	  else
831 	      ret = wvAddSEPXFromBucket6 (sep, &sepx, stsh);
832 	  wvReleaseSEPX (&sepx);
833       }
834 
835     wvStream_goto (fd, pos);
836     return (ret);
837 }
838 
839 U32
wvGetBeginFC(wvParseStruct * ps,subdocument whichdoc)840 wvGetBeginFC (wvParseStruct * ps, subdocument whichdoc)
841 {
842     U32 para_fcFirst = 0x400;
843     switch (whichdoc)
844       {
845       case Dmain:
846       default:
847 	  para_fcFirst = wvConvertCPToFC (0, &ps->clx);
848 	  break;
849       case Dfootnote:
850 	  para_fcFirst = wvConvertCPToFC (ps->fib.ccpText, &ps->clx);
851 	  break;
852       case Dheader:
853 	  para_fcFirst = wvConvertCPToFC (ps->fib.ccpText + ps->fib.ccpFtn,
854 					  &ps->clx);
855 	  break;
856       case Dannotation:
857 	  para_fcFirst = wvConvertCPToFC (ps->fib.ccpText + ps->fib.ccpFtn +
858 					  ps->fib.ccpHdr, &ps->clx);
859 	  break;
860       case Dendnote:
861 	  para_fcFirst = wvConvertCPToFC (ps->fib.ccpText + ps->fib.ccpFtn +
862 					  ps->fib.ccpHdr + ps->fib.ccpAtn,
863 					  &ps->clx);
864 	  break;
865       case Dtextbox:
866 	  para_fcFirst = wvConvertCPToFC (ps->fib.ccpText + ps->fib.ccpFtn +
867 					  ps->fib.ccpHdr + ps->fib.ccpAtn +
868 					  ps->fib.ccpEdn, &ps->clx);
869 	  break;
870       case Dheader_textbox:
871 	  para_fcFirst = wvConvertCPToFC (ps->fib.ccpText + ps->fib.ccpFtn +
872 					  ps->fib.ccpHdr + ps->fib.ccpAtn +
873 					  ps->fib.ccpEdn + ps->fib.ccpTxbx,
874 					  &ps->clx);
875 	  break;
876       }
877     return (para_fcFirst);
878 }
879