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 (¤t->brcLeft, &previous->brcLeft))
705 if (wvEqualBRC (¤t->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