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 <string.h>
27 #include "wv.h"
28 
29 /*
30 To apply a UPX.papx to a UPE.pap, set UPE.pap.istd equal to UPX.papx.istd, and
31 then apply the UPX.papx.grpprl to UPE.pap.
32 */
33 void
wvAddPAPXFromBucket(PAP * apap,UPXF * upxf,STSH * stsh,wvStream * data)34 wvAddPAPXFromBucket (PAP * apap, UPXF * upxf, STSH * stsh, wvStream * data)
35 {
36     U8 *pointer;
37     U16 i = 0;
38     U16 sprm;
39     apap->istd = upxf->upx.papx.istd;
40     if (upxf->cbUPX <= 2)
41 	return;
42     wvTrace (("no is %d\n", upxf->cbUPX));
43 #ifdef SPRMTEST
44     fprintf (stderr, "\n");
45     while (i < upxf->cbUPX - 2)
46       {
47 	  fprintf (stderr, "%x (%d) ", *(upxf->upx.papx.grpprl + i),
48 		   *(upxf->upx.papx.grpprl + i));
49 	  i++;
50       }
51     fprintf (stderr, "\n");
52     i = 0;
53 #endif
54     /*
55        while (i < upxf->cbUPX-2)
56      */
57     while (i < upxf->cbUPX - 4)	/* the end of the list is at -2, but there has to be a full sprm of
58 				   len 2 as well */
59       {
60 	  sprm = bread_16ubit (upxf->upx.papx.grpprl + i, &i);
61 #ifdef SPRMTEST
62 	  wvError (("sprm is %x\n", sprm));
63 #endif
64 	  pointer = upxf->upx.papx.grpprl + i;
65 	  if (i < upxf->cbUPX - 2)
66 	      wvApplySprmFromBucket (WORD8, sprm, apap, NULL, NULL, stsh,
67 				     pointer, &i, data);
68       }
69 }
70 
71 void
wvAddPAPXFromBucket6(PAP * apap,UPXF * upxf,STSH * stsh)72 wvAddPAPXFromBucket6 (PAP * apap, UPXF * upxf, STSH * stsh)
73 {
74     U8 *pointer;
75     U16 i = 0;
76     U16 sprm;
77     U8 sprm8;
78     apap->istd = upxf->upx.papx.istd;
79     if (upxf->cbUPX <= 2)
80 	return;
81     wvTrace (("no is %d\n", upxf->cbUPX));
82 
83 #ifdef SPRMTEST
84     fprintf (stderr, "\n");
85     while (i < upxf->cbUPX - 2)
86       {
87 	  fprintf (stderr, "%x (%d) ", *(upxf->upx.papx.grpprl + i),
88 		   *(upxf->upx.papx.grpprl + i));
89 	  i++;
90       }
91     fprintf (stderr, "\n");
92     i = 0;
93 #endif
94 
95     while (i < upxf->cbUPX - 3)	/* the end of the list is at -2, but there has to be a full sprm of
96 				   len 1 as well */
97       {
98 	  sprm8 = bread_8ubit (upxf->upx.papx.grpprl + i, &i);
99 #ifdef SPRMTEST
100 	  wvError (("pap word 6 sprm is %x (%d)\n", sprm8, sprm8));
101 #endif
102 	  sprm = (U16) wvGetrgsprmWord6 (sprm8);
103 #ifdef SPRMTEST
104 	  wvError (("pap word 6 sprm is converted to %x\n", sprm));
105 #endif
106 	  pointer = upxf->upx.papx.grpprl + i;
107 	  /* hmm, maybe im wrong here, but there appears to be corrupt
108 	   * word 6 sprm lists being stored in the file
109 	   */
110 	  if (i < upxf->cbUPX - 2)
111 	      wvApplySprmFromBucket (WORD6, sprm, apap, NULL, NULL, stsh,
112 				     pointer, &i, NULL);
113       }
114 }
115 
116 
117 void
wvInitPAPFromIstd(PAP * apap,U16 istdBase,STSH * stsh)118 wvInitPAPFromIstd (PAP * apap, U16 istdBase, STSH * stsh)
119 {
120     if (istdBase == istdNil)
121 	wvInitPAP (apap);
122     else
123       {
124 	  if (istdBase >= stsh->Stshi.cstd)
125 	    {
126 		wvError (
127 			 ("ISTD out of bounds, requested %d of %d\n",
128 			  istdBase, stsh->Stshi.cstd));
129 		wvInitPAP (apap);	/*it can't hurt to try and start with a blank istd */
130 		return;
131 	    }
132 	  else
133 	    {
134 		if (stsh->std[istdBase].cupx == 0)	/*empty slot in the array, i don't think this should happen */
135 		  {
136 		      wvTrace (("Empty style slot used (chp)\n"));
137 		      wvInitPAP (apap);
138 		  }
139 		else
140 		  {
141 		    wvCopyPAP (apap, &(stsh->std[istdBase].grupe[0].apap));
142 		    strncpy(apap->stylename,stsh->std[istdBase].xstzName, sizeof(apap->stylename));
143 		  }
144 	    }
145       }
146 }
147 
148 void
wvCopyPAP(PAP * dest,PAP * src)149 wvCopyPAP (PAP * dest, PAP * src)
150 {
151     memcpy (dest, src, sizeof (PAP));
152 }
153 
154 
155 void
wvInitPAP(PAP * item)156 wvInitPAP (PAP * item)
157 {
158     int i;
159     item->istd = 0;
160     item->jc = 0;
161     item->fKeep = 0;
162     item->fKeepFollow = 0;
163     item->fPageBreakBefore = 0;
164     item->fBrLnAbove = 0;
165     item->fBrLnBelow = 0;
166     item->fUnused = 0;
167     item->pcVert = 0;
168     item->pcHorz = 0;
169     item->brcp = 0;
170     item->brcl = 0;
171     item->reserved1 = 0;
172     item->ilvl = 0;
173     item->fNoLnn = 0;
174     item->ilfo = 0;
175     item->nLvlAnm = 0;
176     item->reserved2 = 0;
177     item->fSideBySide = 0;
178     item->reserved3 = 0;
179     item->fNoAutoHyph = 0;
180     item->fWidowControl = 1;
181     item->dxaRight = 0;
182     item->dxaLeft = 0;
183     item->dxaLeft1 = 0;
184     /*
185        wvInitLSPD(&item->lspd);
186      */
187     item->lspd.fMultLinespace = 1;
188     item->lspd.dyaLine = 240;
189 
190     item->dyaBefore = 0;
191     item->dyaAfter = 0;
192 
193     wvInitPHE (&item->phe, 0);
194 
195     item->fCrLf = 0;
196     item->fUsePgsuSettings = 0;
197     item->fAdjustRight = 0;
198     item->reserved4 = 0;
199     item->fKinsoku = 0;
200     item->fWordWrap = 0;
201     item->fOverflowPunct = 0;
202     item->fTopLinePunct = 0;
203     item->fAutoSpaceDE = 0;
204     item->fAtuoSpaceDN = 0;
205     item->wAlignFont = 4;
206     item->fVertical = 0;
207     item->fBackward = 0;
208     item->fRotateFont = 0;
209     item->reserved5 = 0;
210     item->reserved6 = 0;
211     item->fInTable = 0;
212     item->fTtp = 0;
213     item->wr = 0;
214     item->fLocked = 0;
215 
216     wvInitTAP (&item->ptap);
217 
218     item->dxaAbs = 0;
219     item->dyaAbs = 0;
220     item->dxaWidth = 0;
221 
222     wvInitBRC (&item->brcTop);
223     wvInitBRC (&item->brcLeft);
224     wvInitBRC (&item->brcBottom);
225     wvInitBRC (&item->brcRight);
226     wvInitBRC (&item->brcBetween);
227     wvInitBRC (&item->brcBar);
228 
229     item->dxaFromText = 0;
230     item->dyaFromText = 0;
231     item->dyaHeight = 0;
232     item->fMinHeight = 0;
233 
234     wvInitSHD (&item->shd);
235     wvInitDCS (&item->dcs);
236     item->lvl = 9;
237     item->fNumRMIns = 0;
238     wvInitANLD (&item->anld);
239     item->fPropRMark = 0;
240     item->ibstPropRMark = 0;
241     wvInitDTTM (&item->dttmPropRMark);
242     wvInitNUMRM (&item->numrm);
243     item->itbdMac = 0;
244     for (i = 0; i < itbdMax; i++)
245 	item->rgdxaTab[i] = 0;
246     for (i = 0; i < itbdMax; i++)
247 	wvInitTBD (&item->rgtbd[i]);
248 
249     item->fBidi = 0;
250 	item->stylename[0] = 0;
251 
252 	memset(&item->linfo,0,sizeof(item->linfo));
253 }
254 
255 /*
256 1) Having found the index i of the FC in an FKP that marks the character stored
257 in the file immediately after the paragraph's paragraph mark,
258 
259 1 is done in Simple mode through wvGetSimpleParaBounds which places this index
260 in fcLim by default
261 
262 2) it is necessary to use the word offset stored in the first byte of the
263 fkp.rgbx[i - 1] to find the PAPX for the paragraph.
264 
265 3) Using papx.istd to index into the properties stored for the style sheet ,
266 
267 4) the paragraph properties of the style are copied to a local PAP.
268 
269 5) Then the grpprl stored in the PAPX is applied to the local PAP,
270 
271 6) and papx.istd along with fkp.rgbx.phe are moved into the local PAP.
272 
273 7) The process thus far has created a PAP that describes what the paragraph properties
274 of the paragraph were at the last full save.
275 */
276 
277 int
wvAssembleSimplePAP(wvVersion ver,PAP * apap,U32 fc,PAPX_FKP * fkp,wvParseStruct * ps)278 wvAssembleSimplePAP (wvVersion ver, PAP * apap, U32 fc, PAPX_FKP * fkp, wvParseStruct * ps)
279 {
280     PAPX *papx;
281     int index;
282     UPXF upxf;
283     int ret = 0;
284 
285 	/* list processing vars */
286 	U32 myListId = 0;
287 	LVLF * myLVLF = NULL;
288 	LVL * myLVL = NULL;
289 	LFO * myLFO = NULL;
290 	LST * myLST = NULL;
291 	LFOLVL * myLFOLVL = NULL;
292 
293 	S32 myStartAt = -1;
294 	U8 * mygPAPX = NULL;
295 	U8 * mygCHPX = NULL;
296 	XCHAR * myNumberStr = NULL;
297 	S32 myNumberStr_count = 0;
298 	U32 mygPAPX_count = 0, mygCHPX_count = 0;
299 
300 	PAPX myPAPX;
301 	CHPX myCHPX;
302 
303 	S32 i = 0, j = 0, k = 0;
304 
305 	int bNeedLST_LVL;
306 	int bLST_LVL_format;
307 
308 	LVL * prevLVL;
309 	LVLF * prevLVLF;
310 
311     /*index is the i in the text above */
312     index = wvGetIndexFCInFKP_PAPX (fkp, fc);
313 
314     wvTrace (("index is %d, using %d\n", index, index - 1));
315     papx = &(fkp->grppapx[index - 1]);
316 
317     if (papx)
318       {
319 	  wvTrace (("istd index is %d\n", papx->istd));
320 	  wvInitPAPFromIstd (apap, papx->istd, &ps->stsh);
321       }
322     else
323 	wvInitPAPFromIstd (apap, istdNil, &ps->stsh);
324 
325     if ((papx) && (papx->cb > 2))
326       {
327 	  ret = 1;
328 #ifdef SPRMTEST
329 	  fprintf (stderr, "cbUPX is %d\n", papx->cb);
330 	  for (i = 0; i < papx->cb - 2; i++)
331 	      fprintf (stderr, "%x ", papx->grpprl[i]);
332 	  fprintf (stderr, "\n");
333 #endif
334 	  upxf.cbUPX = papx->cb;
335 	  upxf.upx.papx.istd = papx->istd;
336 	  upxf.upx.papx.grpprl = papx->grpprl;
337 	  if (ver == WORD8)
338 	      wvAddPAPXFromBucket (apap, &upxf, &ps->stsh, ps->data);
339 	  else
340 	      wvAddPAPXFromBucket6 (apap, &upxf, &ps->stsh);
341       }
342 
343     if (papx)
344 	apap->istd = papx->istd;
345 
346     if (fkp->rgbx != NULL)
347       wvCopyPHE (&apap->phe, &(fkp->rgbx[index - 1].phe), apap->fTtp);
348 
349 	/*
350 	  By now we have assembled the paragraph properties based on the
351 	  info in the style associated with this pap and also in any of the
352 	  PAPX overrides; next step is to see if this paragraph is a part of
353 	  a list, and if so, to apply any list-specific overrides
354 
355 	  The MS documentation on lists really sucks, but we've been able to decipher
356 	  some meaning from it and get simple lists to sorta work. This code mostly prints out
357 	  debug messages with useful information in them, but it will also append a list
358 	  and add a given paragraph to a given list
359 	*/
360 
361 	if (!apap->ilfo)
362 		return ret;
363 
364 	/* This is really silly, but it would seem that if there are both
365 	PAPX for the paragraph and the list, the paragraph ones take
366 	priority (basically, when a list is applied to a custom indented
367 	block, the block's indents become part of the list PAPX; if the
368 	indents of the block are subsequently modified, the PAPX of the
369 	list stays the same, and the PAPX of the block changes); this
370 	means that we now have to apply the list PAPX over what we have
371 	and then reapply the block PAPX (we had to apply the block's PAPX
372 	in order to find out if we are in a list !!!)*/
373 
374 	if (!ps->lfo)
375 	  return ret;
376 
377 	wvTrace(("list: ilvl %d, ilfo %d\n",apap->ilvl,apap->ilfo));	/* ilvl is the list level */
378 
379 	/* first, get the LFO, and then find the lfovl for this paragraph */
380 	if (ps->lfo)
381 	  myLFO = &ps->lfo[apap->ilfo - 1];
382 
383 	while(i < (S32)apap->ilfo - 1 && i < (S32)ps->nolfo)
384 	{
385 		j += ps->lfo[i].clfolvl;
386 		i++;
387 	}
388 
389 	/* 	remember how many overrides are there for this record */
390         if (ps->lfo)
391 	  k = ps->lfo[i].clfolvl;
392 	else
393 	  k = 0;
394 
395 	/* 	if there are any overrides, then see if one of them applies to this level */
396 	if(k && ps->lfolvl)
397 	{
398 		i = 0;
399 		while(i < k && ps->lfolvl[j].ilvl != apap->ilvl)
400 		{
401 			j++;
402 			i++;
403 		}
404 
405 		if(i >= k)
406 		{
407 			wvTrace(("list: no LFOLVL found for this level (1)\n"));
408 			myLFOLVL = NULL;
409 		}
410 		else
411 		{
412 			myLFOLVL = &ps->lfolvl[j];
413 			wvTrace(("list: lfovl: iStartAt %d, fStartAt\n", myLFOLVL->iStartAt,myLFOLVL->fStartAt,myLFOLVL->fFormatting));
414 			if(!myLFOLVL->fFormatting && myLFOLVL->fStartAt)
415 				myStartAt = myLFOLVL->iStartAt;
416 		}
417 	}
418 	else
419 	{
420 		wvTrace(("list: no LFOLVL found for this level (2)\n"));
421 		myLFOLVL = NULL;
422 	}
423 
424 	/* now that we might have the LFOLVL, let's see if we should use
425 	   the LVL from the LFO */
426 	bNeedLST_LVL = (!myLFOLVL || !myLFOLVL->fStartAt || !myLFOLVL->fFormatting);
427 	bLST_LVL_format = 1;
428 
429 	if(myLFOLVL)
430 	{
431 		/* this branch has not been (thoroughly) debugged
432 		   Abi bugs 2205 and 2393 exhibit this behavior */
433 		wvTrace(("list: using the LVL from LFO\n"));
434 		myListId = myLFOLVL->iStartAt;
435 		i = 0;
436 		wvTrace(("list: number of LSTs %d, my lsid %d\n", ps->noofLST,myListId));
437 		while(i < ps->noofLST && ps->lst[i].lstf.lsid != myListId)
438 		{
439 			i++;
440 			wvTrace(("list: lsid in LST %d\n", ps->lst[i-1].lstf.lsid));
441 		}
442 
443 		if(i == ps->noofLST || ps->lst[i].lstf.lsid != myListId)
444 		{
445 			wvTrace(("error: could not locate LST entry\n"));
446 			goto list_error;
447 		}
448 
449 		myLST = &ps->lst[i];
450 		myLVL = &myLST->lvl[apap->ilvl];
451 
452 		/* now we should have the LVL */
453 		if(!myLVL)
454 			return ret;
455 
456 		myLVLF = &myLVL->lvlf;
457 
458 		if(!myLVLF)
459 			return ret;
460 
461 		myStartAt = myLFOLVL->fStartAt ? (S32)(myLVLF->iStartAt) : -1;
462 
463 		mygPAPX = myLFOLVL->fFormatting ? myLVL->grpprlPapx : NULL;
464 		mygPAPX_count = myLFOLVL->fFormatting ? myLVLF->cbGrpprlPapx : 0;
465 
466 		/* not sure about this, the CHPX applies to the number, so it
467 		   might be that we should take this if the fStartAt is set --
468 		   the docs are not clear */
469 		mygCHPX = myLFOLVL->fFormatting ? myLVL->grpprlChpx : NULL;
470 		mygCHPX_count = myLFOLVL->fFormatting ? myLVLF->cbGrpprlChpx : 0;
471 
472 		myNumberStr = myLFOLVL->fStartAt && myLVL->numbertext ? myLVL->numbertext + 1 : NULL;
473 		myNumberStr_count = myNumberStr ? *(myLVL->numbertext) : 0;
474 
475 		if(myLFOLVL->fFormatting)
476 			bLST_LVL_format = 0;
477 
478 	}
479 
480 	if(bNeedLST_LVL)
481 	{
482 		prevLVL = myLVL;
483 		prevLVLF = myLVLF;
484 		myListId = myLFO ? myLFO->lsid : 0;
485 		wvTrace(("list: using the LVL from LST\n"));
486 		i = 0;
487 
488 		wvTrace(("list: number of LSTs %d, my lsid %d\n", ps->noofLST,myListId));
489 		while(i < ps->noofLST && ps->lst[i].lstf.lsid != myListId)
490 		{
491 			i++;
492 			wvTrace(("list: lsid in LST %d\n", ps->lst[i-1].lstf.lsid));
493 		}
494 
495 		if(i == ps->noofLST || ps->lst[i].lstf.lsid != myListId)
496 		{
497 			wvTrace(("error: could not locate LST entry\n"));
498 			goto list_error;
499 		}
500 
501 		myLST = &ps->lst[i];
502 		wvTrace(("is a simple list? %d - requested level %d\n", myLST->lstf.fSimpleList, apap->ilvl));
503 		if(myLST->lstf.fSimpleList)
504 			myLVL = myLST->lvl;
505 		else
506 			myLVL = &myLST->lvl[apap->ilvl];
507 
508 		/* now we should have the correct LVL */
509 		if(!myLVL)
510 			return ret;
511 
512 		myLVLF = &myLVL->lvlf;
513 
514 		if(!myLVLF)
515 			return ret;
516 
517 		/* retrieve any stuff we need from here (i.e., only what we
518 		   did not get from the LFO LVL) */
519 		myStartAt = myStartAt == -1 ? myLVLF->iStartAt : myStartAt;
520 
521 		mygPAPX_count = !mygPAPX ? myLVLF->cbGrpprlPapx : mygPAPX_count;
522 		mygPAPX = !mygPAPX ? myLVL->grpprlPapx : mygPAPX;
523 
524 		mygCHPX_count = !mygCHPX ? myLVLF->cbGrpprlChpx : mygCHPX_count;
525 		mygCHPX = !mygCHPX ? myLVL->grpprlChpx : mygCHPX;
526 
527 		myNumberStr_count = !myNumberStr && myLVL->numbertext ? *(myLVL->numbertext) : myNumberStr_count;
528 		myNumberStr = !myNumberStr && myLVL->numbertext ? myLVL->numbertext + 1 : myNumberStr;
529 
530 
531 		/* if there was a valid LFO LVL record that pertained to
532 		   formatting then we will set the myLVL and myLVLF variables
533 		   back to this record so that it can be used */
534 		if(!bLST_LVL_format && prevLVL && prevLVLF)
535 		{
536 			myLVL = prevLVL;
537 			myLVLF = prevLVLF;
538 		}
539 	}
540 
541 	wvTrace(("list: number text len %d, papx len %d, chpx len%d\n",myNumberStr_count,mygPAPX_count,mygCHPX_count));
542 	myPAPX.cb = mygPAPX_count;
543 	myPAPX.grpprl = mygPAPX;
544 	myPAPX.istd = apap->istd;
545 
546 	/*
547 	  IMPORTANT now we have the list formatting sutff retrieved; it is found in several
548 	  different places:
549 	  apap->ilvl - the level of this list (0-8)
550 
551 	  myStartAt	- the value at which the numbering for this listshould start
552 	  (i.e., the number of the first item on the list)
553 
554 	  myListId	- the id of this list, we need this to know to which list this
555 	  paragraph belongs; unfortunately, there seem to be some cases where separate
556 	  lists *share* the same id, for instance when two lists, of different formatting,
557 	  are separated by only empty paragraphs. As a hack, AW will add the format number
558 	  to the list id, so gaining different id for different formattings (it is not foolproof,
559 	  for if id1 + format1 == id2 + format2 then we get two lists joined, but the probability
560 	  of that should be small). Further problem is that in AW, list id refers to the set of
561 	  list elements on the same level, while in Word the id is that of the entire list. The
562 	  easiest way to tranform the Word id to AW id is to add the level to the id
563 
564 	  PAPX - the formatting information that needs to be added to the
565 	  format of this list
566 
567 	  CHPX - the formatting of the list number
568 
569 	  myNumberStr - the actual number string to display (XCHAR *); we probably need
570 	  this to work out the number separator, since there does not seem
571 	  to be any reference to this anywhere
572 
573 	  myNumberStr_count - length of the number string
574 
575 	  myLVLF->nfc - number format (see the enum below)
576 
577 	  myLVLF->jc	- number alignment [0: lft, 1: rght, 2: cntr]
578 
579 	  myLVLF->ixchFollow - what character stands between the number and the para
580 	  [0:= tab, 1: spc, 2: none]
581 
582 	  we shall copy this info, except the ilvl, to the wv extension of
583 	  the PAP structure
584 
585 	*/
586 	wvTrace(("list: id %d \n",myListId));
587 	wvTrace(("list: iStartAt %d\n", myStartAt));
588 	wvTrace(("list: lvlf: format %d\n",myLVLF->nfc)); /* see the comment above for nfc values */
589 	wvTrace(("list: lvlf: number align %d [0: lft, 1: rght, 2: cntr]\n",myLVLF->jc));
590 	wvTrace(("list: lvlf: ixchFollow %d [0:= tab, 1: spc, 2: none]\n",myLVLF->ixchFollow));
591 
592 	apap->linfo.id = myListId;
593 	apap->linfo.start = myStartAt;
594 	apap->linfo.numberstr = myNumberStr;
595 	apap->linfo.numberstr_size = myNumberStr_count;
596 	apap->linfo.format = myLVLF->nfc;
597 	apap->linfo.align = myLVLF->jc;
598 	apap->linfo.ixchFollow = myLVLF->ixchFollow;
599 
600 	/* the number formatting */
601 	myCHPX.cbGrpprl = mygCHPX_count;
602 	myCHPX.grpprl = mygCHPX;
603 	myCHPX.istd = 4095;
604 
605 	/* next we need to apply the list PAPX to our PAP */
606     if (myPAPX.cb > 2)
607 	{
608 		ret = 1;
609 		upxf.cbUPX = myPAPX.cb;
610 		upxf.upx.papx.istd = myPAPX.istd;
611 		upxf.upx.papx.grpprl = myPAPX.grpprl;
612 		if (ver == WORD8)
613 			wvAddPAPXFromBucket (apap, &upxf, &ps->stsh, ps->data);
614 		else
615 			wvAddPAPXFromBucket6 (apap, &upxf, &ps->stsh);
616 
617 		/* now we have to reapply the original PAPX, see note at top
618 		   of the list code */
619 		if((papx) && (papx->cb > 2))
620 		{
621 			ret = 1;
622 			upxf.cbUPX = papx->cb;
623 			upxf.upx.papx.istd = papx->istd;
624 			upxf.upx.papx.grpprl = papx->grpprl;
625 			if (ver == WORD8)
626 				wvAddPAPXFromBucket (apap, &upxf, &ps->stsh, ps->data);
627 			else
628 				wvAddPAPXFromBucket6 (apap, &upxf, &ps->stsh);
629 		}
630 	}
631 
632 	/* next see if the list number comes with
633 	   additional char formatting information; if it does, we will
634 	   stre it the linfo.chp */
635 
636 	if(myCHPX.cbGrpprl)
637 	{
638 		ret = 1;
639 
640 		wvAssembleSimpleCHP(ver, &apap->linfo.chp, apap, 0, NULL, &ps->stsh);
641 		upxf.cbUPX = myCHPX.cbGrpprl;
642 		upxf.upx.chpx.grpprl = myCHPX.grpprl;
643 		if (ver == WORD8)
644 			wvAddCHPXFromBucket (&apap->linfo.chp, &upxf, &ps->stsh);
645 		else
646 			wvAddCHPXFromBucket6 (&apap->linfo.chp, &upxf, &ps->stsh);
647 	}
648 
649 
650 
651     if (myPAPX.istd != istdNil)
652 		apap->istd = myPAPX.istd;
653 
654 list_error:
655     return (ret);
656 }
657 
658 void
wvReleasePAPX(PAPX * item)659 wvReleasePAPX (PAPX * item)
660 {
661     item->cb = 0;
662     item->istd = 0;
663     wvFree (item->grpprl);
664     item->grpprl = NULL;
665 }
666 
667 void
wvInitPAPX(PAPX * item)668 wvInitPAPX (PAPX * item)
669 {
670     item->cb = 0;
671     item->istd = 0;
672     item->grpprl = NULL;
673 }
674 
675 void
wvGetPAPX(wvVersion ver,PAPX * item,U8 * page,U16 * pos)676 wvGetPAPX (wvVersion ver, PAPX * item, U8 * page, U16 * pos)
677 {
678     U16 cw;
679     cw = bread_8ubit (&(page[*pos]), pos);
680     if ((cw == 0) && (ver == WORD8))	/* only do this for word 97 */
681       {
682 	  wvTrace (("cw was pad %d\n", cw));
683 	  cw = bread_8ubit (&(page[*pos]), pos);
684 	  wvTrace (("cw was %d\n", cw));
685       }
686     item->cb = cw * 2;
687     item->istd = bread_16ubit (&(page[*pos]), pos);
688     wvTrace (("papx istd is %x\n", item->istd));
689     wvTrace (("no of bytes is %d\n", item->cb));
690     if (item->cb > 2)
691       {
692 	  item->grpprl = (U8 *) wvMalloc (item->cb - 2);
693 	  memcpy (item->grpprl, &(page[*pos]), (item->cb) - 2);
694       }
695     else
696 	item->grpprl = NULL;
697 }
698 
699 
700 int
isPAPConform(PAP * current,PAP * previous)701 isPAPConform (PAP * current, PAP * previous)
702 {
703     if ((current) && (previous))
704 	if (wvEqualBRC (&current->brcLeft, &previous->brcLeft))
705 	    if (wvEqualBRC (&current->brcRight, &previous->brcRight))
706 		if (current->dxaWidth == previous->dxaWidth)
707 		    if (current->fInTable == previous->fInTable)
708 			return (1);
709     return (0);
710 }
711 
712 
713 
714 
715 void
wvCopyConformPAP(PAP * dest,PAP * src)716 wvCopyConformPAP (PAP * dest, PAP * src)
717 {
718     if (src)
719       {
720 #ifdef PURIFY
721 	  wvInitPAP (dest);
722 #endif
723 	  dest->brcLeft = src->brcLeft;
724 	  dest->brcRight = src->brcRight;
725 	  dest->dxaWidth = src->dxaWidth;
726 	  dest->fInTable = src->fInTable;
727       }
728     else
729 	wvInitPAP (dest);
730 }
731