/*
 * Autorship:   Originally obtained from Word View by Caolan.McNamara@ul.ie.  *
 * Licency:     GPL
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if defined(__BORLANDC__) && (__BORLANDC__ < 0x0540)
  #include "atoms/include/typedfs.h"
  #include "word/bintree.h"
  #include "word/wrd_type.h"
#else
  #include "../atoms/include/typedfs.h"
  #include "bintree.h"
  #include "wrd_type.h"
#endif
#include "struct.h"

#define wvTrace(xxx) {}
#define wvError(xxx) {}


/*Ensure that prototypes are correctly declared even for C*/
#ifdef __cplusplus
extern "C" {
#endif

uint16_t fil_sreadU16(const uint8_t *in);
uint32_t fil_sreadU32(const uint8_t *in);

int loadstruct(FILE *F,const char *description, ...);
int savestruct(FILE *F,const char *description, ...);
#ifdef __cplusplus
}
#endif


#define Rd_word(f,w) RdWORD_LoEnd(w,f);
#define Rd_dword(f,d) RdDWORD_LoEnd(d,f);
#define Wr_word(f,w) WrWORD_LoEnd(w,f);
#define Wr_dword(f,d) WrDWORD_LoEnd(d,f);

#ifndef _
 #define _(x) x
#endif



static uint8_t sread_8ubit (const uint8_t * in)
{
  return (*in);
}


uint8_t bread_8ubit (uint8_t * in, uint16_t * pos)
{
  (*pos)++;
  return (*in);
}


uint16_t bread_16ubit (uint8_t * in, uint16_t * pos)
{
uint8_t temp1, temp2;
uint16_t ret;

    if (in == 0) /* this really ought to be called more sanely */
      {
	(*pos) = 0xffff;
	return 0;
      }

    temp1 = *in;
    temp2 = *(in + 1);
    ret = temp2;
    ret = ret << 8;
    ret += temp1;
    (*pos) += 2;
    return (ret);
}


static uint8_t dread_8ubit (FILE * in, uint8_t ** list)
{
uint8_t *temp;
   if (in != NULL)
      return(fgetc(in));
   else
	{
	temp = *list;
	(*list)++;
	return (sread_8ubit(temp));
	}
}


static uint16_t dread_16ubit (FILE * in, uint8_t ** list)
{
uint8_t *temp;
uint16_t ret;
  if (in != NULL)
	{
	Rd_word(in,&ret);
	return(ret);
	}
    else
	{
	if(list==NULL) return 0;	// JFO: Dereferenced NULL pointer fixed.
	temp = *list;
	if(temp==NULL) return 0;	// JFO: Dereferenced NULL pointer fixed.
	(*list) += 2;
	ret = fil_sreadU16 (temp);
	return (ret);
	}
}


static uint32_t bread_32ubit (uint8_t * in, uint16_t * pos)
{
uint32_t ret;
  ret = fil_sreadU32(in);
  (*pos) += 4;
  return (ret);
}


static uint32_t dread_32ubit (FILE * in, uint8_t ** list)
{
uint8_t *temp;
uint32_t ret;
  if (in != NULL)
	{
	Rd_dword(in,&ret);
	return(ret);
	}
  else
	{
	temp = *list;
	(*list) += 4;
	ret = fil_sreadU32(temp);
	return (ret);
	}
}


/* --------- End of miscellaneous tools -----------*/


static void wvInitFIB (FIB *item)
{
   memset(item,0,sizeof(*item));
//   wvInitFILETIME (&item->ftModified);
}


static void wvGetFILETIME (FILETIME * ft, FILE* fd)
{
  Rd_dword(fd,&ft->dwLowDateTime);
  Rd_dword(fd,&ft->dwHighDateTime);
}


void wvGetFIB2(FIB *item, FILE* fd)
{
uint16_t temp16 = 0;

  wvInitFIB (item);

  Rd_word(fd,&item->wIdent);
  Rd_word(fd,&item->nFib);

  Rd_word(fd,&item->nProduct);
  Rd_word(fd,&item->lid);
  wvTrace (("lid is %x\n", item->lid));
  Rd_word(fd,(uint16_t *)&item->pnNext);

  Rd_word(fd,&temp16);
  item->fDot = (temp16 & 0x0001);
  item->fGlsy = (temp16 & 0x0002) >> 1;
  item->fComplex = (temp16 & 0x0004) >> 2;
  item->fHasPic = (temp16 & 0x0008) >> 3;
  item->cQuickSaves = (temp16 & 0x00F0) >> 4;
  item->fEncrypted = (temp16 & 0x0100) >> 8;
  item->fWhichTblStm = 0;	/* Unused from here on */
  item->fReadOnlyRecommended = 0;
  item->fWriteReservation = 0;
  item->fExtChar = 0;
  item->fLoadOverride = 0;
  item->fFarEast = 0;
  item->fCrypto = 0;

  Rd_word(fd,&item->nFibBack);
  wvTrace (("nFibBack is %d\n", item->nFibBack));

  Rd_dword(fd,&item->Spare);			/* A spare for W2 */
  Rd_word(fd,&item->rgwSpare0[0]);
  Rd_word(fd,&item->rgwSpare0[1]);
  Rd_word(fd,&item->rgwSpare0[2]);

  Rd_dword(fd,&item->fcMin);	/* These appear correct MV 29.8.2000 */
  Rd_dword(fd,&item->fcMac);
  wvTrace (("fc from %d to %d\n", item->fcMin, item->fcMac));
  Rd_dword(fd,(uint32_t *)&item->cbMac);	/* Last byte file position plus one. */

  Rd_dword(fd,&item->fcSpare0);
  Rd_dword(fd,&item->fcSpare1);
  Rd_dword(fd,&item->fcSpare2);
  Rd_dword(fd,&item->fcSpare3);

  Rd_dword(fd,&item->ccpText);
  wvTrace (("length %d == %d\n", item->fcMac - item->fcMin, item->ccpText));
  Rd_dword(fd,(uint32_t *)&item->ccpFtn);
  Rd_dword(fd,(uint32_t *)&item->ccpHdr);
  Rd_dword(fd,(uint32_t *)&item->ccpMcr);
  Rd_dword(fd,(uint32_t *)&item->ccpAtn);

  Rd_dword(fd,&item->ccpSpare0);
  Rd_dword(fd,&item->ccpSpare1);
  Rd_dword(fd,&item->ccpSpare2);
  Rd_dword(fd,&item->ccpSpare3);

  Rd_dword(fd,(uint32_t *)&item->fcStshfOrig);
  Rd_dword(fd,(uint32_t *)&item->lcbStshfOrig);
  Rd_dword(fd,(uint32_t *)&item->fcStshf);
  Rd_dword(fd,(uint32_t *)&item->lcbStshf);

  Rd_dword(fd,(uint32_t *)&item->fcPlcffndRef);
  Rd_word(fd,(uint16_t *)&item->lcbPlcffndRef);
  Rd_dword(fd,(uint32_t *)&item->fcPlcffndTxt);
  Rd_word(fd,(uint16_t *)&item->lcbPlcffndTxt);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfandRef);
  Rd_word(fd,(uint16_t *)&item->lcbPlcfandRef);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfandTxt);
  Rd_word(fd,(uint16_t *)&item->lcbPlcfandTxt);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfsed);
  Rd_word(fd,(uint16_t *)&item->lcbPlcfsed);
  Rd_dword(fd,&item->fcPlcfpgd);
  Rd_word(fd,(uint16_t *)&item->cbPlcfpgd);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfphe);
  Rd_word(fd,(uint16_t *)&item->lcbPlcfphe);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfglsy);
  Rd_word(fd,(uint16_t *)&item->lcbPlcfglsy);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfhdd);
  Rd_word(fd,(uint16_t *)&item->lcbPlcfhdd);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfbteChpx);
  Rd_word(fd,(uint16_t *)&item->lcbPlcfbteChpx);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfbtePapx);
  Rd_word(fd,(uint16_t *)&item->lcbPlcfbtePapx);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfsea);
  Rd_word(fd,(uint16_t *)&item->lcbPlcfsea);
  Rd_dword(fd,(uint32_t *)&item->fcSttbfffn);
  Rd_word(fd,(uint16_t *)&item->lcbSttbfffn);
  Rd_dword(fd,(uint32_t *)&item->fcPlcffldMom);
  Rd_word(fd,(uint16_t *)&item->lcbPlcffldMom);
  Rd_dword(fd,(uint32_t *)&item->fcPlcffldHdr);
  Rd_word(fd,(uint16_t *)&item->lcbPlcffldHdr);
  Rd_dword(fd,(uint32_t *)&item->fcPlcffldFtn);
  Rd_word(fd,(uint16_t *)&item->lcbPlcffldFtn);
  Rd_dword(fd,(uint32_t *)&item->fcPlcffldAtn);
  Rd_word(fd,(uint16_t *)&item->lcbPlcffldAtn);
  Rd_dword(fd,(uint32_t *)&item->fcPlcffldMcr);
  Rd_word(fd,(uint16_t *)&item->lcbPlcffldMcr);
  Rd_dword(fd,(uint32_t *)&item->fcSttbfbkmk);
  Rd_word(fd,(uint16_t *)&item->lcbSttbfbkmk);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfbkf);
  Rd_word(fd,(uint16_t *)&item->lcbPlcfbkf);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfbkl);
  Rd_word(fd,(uint16_t *)&item->lcbPlcfbkl);
  Rd_dword(fd,(uint32_t *)&item->fcCmds);
  Rd_word(fd,(uint16_t *)&item->lcbCmds);
  Rd_dword(fd,(uint32_t *)&item->fcPlcmcr);
  Rd_word(fd,(uint16_t *)&item->lcbPlcmcr);
  Rd_dword(fd,(uint32_t *)&item->fcSttbfmcr);
  Rd_word(fd,(uint16_t *)&item->lcbSttbfmcr);
  Rd_dword(fd,(uint32_t *)&item->fcPrDrvr);
  Rd_word(fd,(uint16_t *)&item->lcbPrDrvr);
  Rd_dword(fd,(uint32_t *)&item->fcPrEnvPort);
  Rd_word(fd,(uint16_t *)&item->lcbPrEnvPort);
  Rd_dword(fd,(uint32_t *)&item->fcPrEnvLand);
  Rd_word(fd,(uint16_t *)&item->lcbPrEnvLand);
  Rd_dword(fd,(uint32_t *)&item->fcWss);
  Rd_word(fd,(uint16_t *)&item->lcbWss);
  Rd_dword(fd,(uint32_t *)&item->fcDop);
  Rd_word(fd,(uint16_t *)&item->lcbDop);
  Rd_dword(fd,(uint32_t *)&item->fcSttbfAssoc);
  Rd_word(fd,(uint16_t *)&item->lcbSttbfAssoc);
  Rd_dword(fd,(uint32_t *)&item->fcClx);
  Rd_word(fd,(uint16_t *)&item->lcbClx);

  Rd_dword(fd,(uint32_t *)&item->fcPlcfpgdFtn);
  Rd_word(fd,(uint16_t *)&item->lcbPlcfpgdFtn);
  Rd_dword(fd,(uint32_t *)&item->fcAutosaveSource);
  Rd_word(fd,(uint16_t *)&item->lcbAutosaveSource);

  Rd_dword(fd,&item->fcSpare5);
  Rd_word(fd,&item->cbSpare5);
  Rd_dword(fd,&item->fcSpare6);
  Rd_word(fd,&item->cbSpare6);
  Rd_word(fd,&item->wSpare4);
  Rd_word(fd,(uint16_t *)&item->pnChpFirst);
  Rd_word(fd,(uint16_t *)&item->pnPapFirst);
  Rd_word(fd,(uint16_t *)&item->cpnBteChp);
  Rd_word(fd,(uint16_t *)&item->cpnBtePap);
}


/*this procedure reads File Info Block for Word 6.x*/
void wvGetFIB6(FIB *item, FILE* fd)
{
uint16_t temp16;
uint8_t temp8;

  wvInitFIB (item);

  Rd_word(fd,&item->wIdent);
  Rd_word(fd,&item->nFib);

  Rd_word(fd,&item->nProduct);
  Rd_word(fd,&item->lid);

  wvTrace (("lid is %x\n", item->lid));
  Rd_word(fd,(uint16_t *)&item->pnNext);
  Rd_word(fd,&temp16);
  item->fDot = (temp16 & 0x0001);
  item->fGlsy = (temp16 & 0x0002) >> 1;
  item->fComplex = (temp16 & 0x0004) >> 2;
  item->fHasPic = (temp16 & 0x0008) >> 3;
  item->cQuickSaves = (temp16 & 0x00F0) >> 4;
  item->fEncrypted = (temp16 & 0x0100) >> 8;
  item->fWhichTblStm = 0;	/* word 6 files only have one table stream */
  item->fReadOnlyRecommended = (temp16 & 0x0400) >> 10;
  item->fWriteReservation = (temp16 & 0x0800) >> 11;
  item->fExtChar = (temp16 & 0x1000) >> 12;
  wvTrace (("fExtChar is %d\n", item->fExtChar));
  item->fLoadOverride = 0;
  item->fFarEast = 0;
  item->fCrypto = 0;
  Rd_word(fd,&item->nFibBack);
  Rd_dword(fd,&item->lKey);
  item->envr = fgetc(fd);
  temp8 = fgetc(fd);
  item->fMac = 0;
  item->fEmptySpecial = 0;
  item->fLoadOverridePage = 0;
  item->fFutureSavedUndo = 0;
  item->fWord97Saved = 0;
  item->fSpare0 = 0;
  Rd_word(fd,&item->chse);
  Rd_word(fd,&item->chsTables);
  Rd_dword(fd,&item->fcMin);
  Rd_dword(fd,&item->fcMac);
  item->csw = 14;
  item->wMagicCreated = 0xCA0;	/*this is the unique id of the creater, so its me :-) */
  Rd_dword(fd,(uint32_t *)&item->cbMac);

  fseek(fd, 2*8, SEEK_CUR);

  Rd_dword(fd,&item->ccpText);
  Rd_dword(fd,(uint32_t *)&item->ccpFtn);
  Rd_dword(fd,(uint32_t *)&item->ccpHdr);
  Rd_dword(fd,(uint32_t *)&item->ccpMcr);
  Rd_dword(fd,(uint32_t *)&item->ccpAtn);

  Rd_dword(fd,(uint32_t *)&item->ccpEdn);
  Rd_dword(fd,(uint32_t *)&item->ccpTxbx);
  Rd_dword(fd,(uint32_t *)&item->ccpHdrTxbx);

  fseek(fd, 4, SEEK_CUR);

  Rd_dword(fd,(uint32_t *)&item->fcStshfOrig);
  Rd_dword(fd,&item->lcbStshfOrig);
  Rd_dword(fd,(uint32_t *)&item->fcStshf);
  Rd_dword(fd,&item->lcbStshf);

  Rd_dword(fd,(uint32_t *)&item->fcPlcffndRef);
  Rd_dword(fd,&item->lcbPlcffndRef);
  Rd_dword(fd,(uint32_t *)&item->fcPlcffndTxt);
  Rd_dword(fd,&item->lcbPlcffndTxt);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfandRef);
  Rd_dword(fd,&item->lcbPlcfandRef);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfandTxt);
  Rd_dword(fd,&item->lcbPlcfandTxt);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfsed);
  Rd_dword(fd,&item->lcbPlcfsed);

  Rd_dword(fd,(uint32_t *)&item->fcPlcpad);
  Rd_dword(fd,&item->lcbPlcpad);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfphe);
  Rd_dword(fd,&item->lcbPlcfphe);
  Rd_dword(fd,(uint32_t *)&item->fcSttbfglsy);
  Rd_dword(fd,&item->lcbSttbfglsy);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfglsy);
  Rd_dword(fd,&item->lcbPlcfglsy);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfhdd);
  Rd_dword(fd,&item->lcbPlcfhdd);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfbteChpx);
  Rd_dword(fd,&item->lcbPlcfbteChpx);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfbtePapx);
  Rd_dword(fd,&item->lcbPlcfbtePapx);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfsea);
  Rd_dword(fd,&item->lcbPlcfsea);
  Rd_dword(fd,(uint32_t *)&item->fcSttbfffn);
  Rd_dword(fd,&item->lcbSttbfffn);
  Rd_dword(fd,(uint32_t *)&item->fcPlcffldMom);
  Rd_dword(fd,&item->lcbPlcffldMom);
  Rd_dword(fd,(uint32_t *)&item->fcPlcffldHdr);
  Rd_dword(fd,&item->lcbPlcffldHdr);
  Rd_dword(fd,(uint32_t *)&item->fcPlcffldFtn);
  Rd_dword(fd,&item->lcbPlcffldFtn);
  Rd_dword(fd,(uint32_t *)&item->fcPlcffldAtn);
  Rd_dword(fd,&item->lcbPlcffldAtn);
  Rd_dword(fd,(uint32_t *)&item->fcPlcffldMcr);
  Rd_dword(fd,&item->lcbPlcffldMcr);
  Rd_dword(fd,(uint32_t *)&item->fcSttbfbkmk);
  Rd_dword(fd,&item->lcbSttbfbkmk);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfbkf);
  Rd_dword(fd,&item->lcbPlcfbkf);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfbkl);
  Rd_dword(fd,&item->lcbPlcfbkl);
  Rd_dword(fd,(uint32_t *)&item->fcCmds);
  Rd_dword(fd,&item->lcbCmds);
  Rd_dword(fd,(uint32_t *)&item->fcPlcmcr);
  Rd_dword(fd,&item->lcbPlcmcr);
  Rd_dword(fd,(uint32_t *)&item->fcSttbfmcr);
  Rd_dword(fd,&item->lcbSttbfmcr);
  Rd_dword(fd,(uint32_t *)&item->fcPrDrvr);
  Rd_dword(fd,&item->lcbPrDrvr);
  Rd_dword(fd,(uint32_t *)&item->fcPrEnvPort);
  Rd_dword(fd,&item->lcbPrEnvPort);
  Rd_dword(fd,(uint32_t *)&item->fcPrEnvLand);
  Rd_dword(fd,&item->lcbPrEnvLand);
  Rd_dword(fd,(uint32_t *)&item->fcWss);
  Rd_dword(fd,&item->lcbWss);
  Rd_dword(fd,(uint32_t *)&item->fcDop);
  Rd_dword(fd,&item->lcbDop);
  Rd_dword(fd,(uint32_t *)&item->fcSttbfAssoc);
  Rd_dword(fd,&item->lcbSttbfAssoc);
  Rd_dword(fd,(uint32_t *)&item->fcClx);
  Rd_dword(fd,&item->lcbClx);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfpgdFtn);
  Rd_dword(fd,&item->lcbPlcfpgdFtn);
  Rd_dword(fd,(uint32_t *)&item->fcAutosaveSource);
  Rd_dword(fd,&item->lcbAutosaveSource);
  Rd_dword(fd,(uint32_t *)&item->fcGrpXstAtnOwners);
  Rd_dword(fd,&item->lcbGrpXstAtnOwners);
  Rd_dword(fd,(uint32_t *)&item->fcSttbfAtnbkmk);
  Rd_dword(fd,&item->lcbSttbfAtnbkmk);

  fseek(fd, 2, SEEK_CUR);

  Rd_word(fd,(uint16_t *)&item->pnChpFirst_W6);
  Rd_word(fd,(uint16_t *)&item->pnPapFirst_W6);
  Rd_word(fd,(uint16_t *)&item->cpnBteChp_W6);
  Rd_word(fd,(uint16_t *)&item->cpnBtePap_W6);

  Rd_dword(fd,(uint32_t *)&item->fcPlcdoaMom);
  Rd_dword(fd,&item->lcbPlcdoaMom);
  Rd_dword(fd,(uint32_t *)&item->fcPlcdoaHdr);
  Rd_dword(fd,&item->lcbPlcdoaHdr);

  fseek(fd, 4*4, SEEK_CUR);

  Rd_dword(fd,(uint32_t *)&item->fcPlcfAtnbkf);
  Rd_dword(fd,&item->lcbPlcfAtnbkf);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfAtnbkl);
  Rd_dword(fd,&item->lcbPlcfAtnbkl);
  Rd_dword(fd,(uint32_t *)&item->fcPms);
  Rd_dword(fd,&item->lcbPms);
  Rd_dword(fd,(uint32_t *)&item->fcFormFldSttbs);
  Rd_dword(fd,&item->lcbFormFldSttbs);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfendRef);
  Rd_dword(fd,&item->lcbPlcfendRef);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfendTxt);
  Rd_dword(fd,&item->lcbPlcfendTxt);
  Rd_dword(fd,(uint32_t *)&item->fcPlcffldEdn);
  Rd_dword(fd,&item->lcbPlcffldEdn);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfpgdEdn);
  Rd_dword(fd,&item->lcbPlcfpgdEdn);

  fseek(fd, 2*4, SEEK_CUR);

  Rd_dword(fd,(uint32_t *)&item->fcSttbfRMark);
  Rd_dword(fd,&item->lcbSttbfRMark);
  Rd_dword(fd,(uint32_t *)&item->fcSttbCaption);
  Rd_dword(fd,&item->lcbSttbCaption);
  Rd_dword(fd,(uint32_t *)&item->fcSttbAutoCaption);
  Rd_dword(fd,&item->lcbSttbAutoCaption);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfwkb);
  Rd_dword(fd,&item->lcbPlcfwkb);

  fseek(fd, 2*4, SEEK_CUR);

  Rd_dword(fd,(uint32_t *)&item->fcPlcftxbxTxt);
  Rd_dword(fd,&item->lcbPlcftxbxTxt);
  Rd_dword(fd,(uint32_t *)&item->fcPlcffldTxbx);
  Rd_dword(fd,&item->lcbPlcffldTxbx);
  Rd_dword(fd,(uint32_t *)&item->fcPlcfhdrtxbxTxt);
  Rd_dword(fd,&item->lcbPlcfhdrtxbxTxt);
  Rd_dword(fd,(uint32_t *)&item->fcPlcffldHdrTxbx);
  Rd_dword(fd,&item->lcbPlcffldHdrTxbx);
  Rd_dword(fd,(uint32_t *)&item->fcStwUser);
  Rd_dword(fd,&item->lcbStwUser);
  Rd_dword(fd,(uint32_t *)&item->fcSttbttmbd);
  Rd_dword(fd,&item->cbSttbttmbd);
  Rd_dword(fd,(uint32_t *)&item->fcUnused);
  Rd_dword(fd,&item->lcbUnused);
  Rd_dword(fd,(uint32_t *)&item->fcPgdMother);
  Rd_dword(fd,&item->lcbPgdMother);
  Rd_dword(fd,(uint32_t *)&item->fcBkdMother);
  Rd_dword(fd,&item->lcbBkdMother);

  Rd_dword(fd,(uint32_t *)&item->fcPgdFtn);
  Rd_dword(fd,&item->lcbPgdFtn);
  Rd_dword(fd,(uint32_t *)&item->fcBkdFtn);
  Rd_dword(fd,&item->lcbBkdFtn);
  Rd_dword(fd,(uint32_t *)&item->fcPgdEdn);
  Rd_dword(fd,&item->lcbPgdEdn);
  Rd_dword(fd,(uint32_t *)&item->fcBkdEdn);
  Rd_dword(fd,&item->lcbBkdEdn);
  Rd_dword(fd,(uint32_t *)&item->fcSttbfIntlFld);
  Rd_dword(fd,&item->lcbSttbfIntlFld);
  Rd_dword(fd,(uint32_t *)&item->fcRouteSlip);
  Rd_dword(fd,&item->lcbRouteSlip);

  Rd_dword(fd,(uint32_t *)&item->fcSttbSavedBy);
  Rd_dword(fd,&item->lcbSttbSavedBy);
  Rd_dword(fd,(uint32_t *)&item->fcSttbFnm);
  Rd_dword(fd,&item->lcbSttbFnm);
}


void wvGetFIB8(FIB *item, FILE* fd)
{
uint16_t temp16;
uint8_t temp8;

    fseek(fd, 0, SEEK_SET);
    wvInitFIB (item);

    Rd_word(fd,&item->wIdent);
    Rd_word(fd,&item->nFib);

    Rd_word(fd,&item->nProduct);
    Rd_word(fd,&item->lid);
    wvTrace (("lid is %x\n", item->lid));
    Rd_word(fd,(uint16_t *)&item->pnNext);
    Rd_word(fd,&temp16);
    item->fDot = (temp16 & 0x0001);
    item->fGlsy = (temp16 & 0x0002) >> 1;
    item->fComplex = (temp16 & 0x0004) >> 2;
    item->fHasPic = (temp16 & 0x0008) >> 3;
    item->cQuickSaves = (temp16 & 0x00F0) >> 4;
    item->fEncrypted = (temp16 & 0x0100) >> 8;
    item->fWhichTblStm = (temp16 & 0x0200) >> 9;
    item->fReadOnlyRecommended = (temp16 & 0x0400) >> 10;
    item->fWriteReservation = (temp16 & 0x0800) >> 11;
    item->fExtChar = (temp16 & 0x1000) >> 12;
    wvTrace (("fExtChar is %d\n", item->fExtChar));
    item->fLoadOverride = (temp16 & 0x2000) >> 13;
    item->fFarEast = (temp16 & 0x4000) >> 14;
    item->fCrypto = (temp16 & 0x8000) >> 15;
    Rd_word(fd,&item->nFibBack);
    Rd_dword(fd,&item->lKey);
    item->envr = fgetc(fd);
    temp8 = fgetc(fd);
    item->fMac = (temp8 & 0x01);
    item->fEmptySpecial = (temp8 & 0x02) >> 1;
    item->fLoadOverridePage = (temp8 & 0x04) >> 2;
    item->fFutureSavedUndo = (temp8 & 0x08) >> 3;
    item->fWord97Saved = (temp8 & 0x10) >> 4;
    item->fSpare0 = (temp8 & 0xFE) >> 5;
    Rd_word(fd,&item->chse);
    Rd_word(fd,&item->chsTables);
    Rd_dword(fd,&item->fcMin);
    Rd_dword(fd,&item->fcMac);
    Rd_word(fd,&item->csw);
    Rd_word(fd,&item->wMagicCreated);
    Rd_word(fd,&item->wMagicRevised);
    Rd_word(fd,&item->wMagicCreatedPrivate);
    Rd_word(fd,&item->wMagicRevisedPrivate);
    Rd_word(fd,(uint16_t *)&item->pnFbpChpFirst_W6);
    Rd_word(fd,(uint16_t *)&item->pnChpFirst_W6);
    Rd_word(fd,(uint16_t *)&item->cpnBteChp_W6);
    Rd_word(fd,(uint16_t *)&item->pnFbpPapFirst_W6);
    Rd_word(fd,(uint16_t *)&item->pnPapFirst_W6);
    Rd_word(fd,(uint16_t *)&item->cpnBtePap_W6);
    Rd_word(fd,(uint16_t *)&item->pnFbpLvcFirst_W6);
    Rd_word(fd,(uint16_t *)&item->pnLvcFirst_W6);
    Rd_word(fd,(uint16_t *)&item->cpnBteLvc_W6);
    Rd_word(fd,(uint16_t *)&item->lidFE);
    Rd_word(fd,&item->clw);
    Rd_dword(fd,(uint32_t *)&item->cbMac);
    Rd_dword(fd,&item->lProductCreated);
    Rd_dword(fd,&item->lProductRevised);
    Rd_dword(fd,&item->ccpText);
    Rd_dword(fd,(uint32_t *)&item->ccpFtn);
    Rd_dword(fd,(uint32_t *)&item->ccpHdr);
    Rd_dword(fd,(uint32_t *)&item->ccpMcr);
    Rd_dword(fd,(uint32_t *)&item->ccpAtn);
    Rd_dword(fd,(uint32_t *)&item->ccpEdn);
    Rd_dword(fd,(uint32_t *)&item->ccpTxbx);
    Rd_dword(fd,(uint32_t *)&item->ccpHdrTxbx);
    Rd_dword(fd,(uint32_t *)&item->pnFbpChpFirst);
    Rd_dword(fd,(uint32_t *)&item->pnChpFirst);
    Rd_dword(fd,(uint32_t *)&item->cpnBteChp);
    Rd_dword(fd,(uint32_t *)&item->pnFbpPapFirst);
    Rd_dword(fd,(uint32_t *)&item->pnPapFirst);
    Rd_dword(fd,(uint32_t *)&item->cpnBtePap);
    Rd_dword(fd,(uint32_t *)&item->pnFbpLvcFirst);
    Rd_dword(fd,(uint32_t *)&item->pnLvcFirst);
    Rd_dword(fd,(uint32_t *)&item->cpnBteLvc);
    Rd_dword(fd,(uint32_t *)&item->fcIslandFirst);
    Rd_dword(fd,(uint32_t *)&item->fcIslandLim);
    Rd_word(fd,&item->cfclcb);
    Rd_dword(fd,(uint32_t *)&item->fcStshfOrig);
    Rd_dword(fd,(uint32_t *)&item->lcbStshfOrig);
    Rd_dword(fd,(uint32_t *)&item->fcStshf);
    Rd_dword(fd,(uint32_t *)&item->lcbStshf);

    Rd_dword(fd,(uint32_t *)&item->fcPlcffndRef);
    Rd_dword(fd,&item->lcbPlcffndRef);
    Rd_dword(fd,(uint32_t *)&item->fcPlcffndTxt);
    Rd_dword(fd,&item->lcbPlcffndTxt);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfandRef);
    Rd_dword(fd,&item->lcbPlcfandRef);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfandTxt);
    Rd_dword(fd,&item->lcbPlcfandTxt);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfsed);
    Rd_dword(fd,&item->lcbPlcfsed);
    Rd_dword(fd,(uint32_t *)&item->fcPlcpad);
    Rd_dword(fd,&item->lcbPlcpad);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfphe);
    Rd_dword(fd,&item->lcbPlcfphe);
    Rd_dword(fd,(uint32_t *)&item->fcSttbfglsy);
    Rd_dword(fd,&item->lcbSttbfglsy);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfglsy);
    Rd_dword(fd,&item->lcbPlcfglsy);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfhdd);
    Rd_dword(fd,&item->lcbPlcfhdd);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfbteChpx);
    Rd_dword(fd,&item->lcbPlcfbteChpx);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfbtePapx);
    Rd_dword(fd,&item->lcbPlcfbtePapx);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfsea);
    Rd_dword(fd,&item->lcbPlcfsea);
    Rd_dword(fd,(uint32_t *)&item->fcSttbfffn);
    Rd_dword(fd,&item->lcbSttbfffn);
    Rd_dword(fd,(uint32_t *)&item->fcPlcffldMom);
    Rd_dword(fd,&item->lcbPlcffldMom);
    Rd_dword(fd,(uint32_t *)&item->fcPlcffldHdr);
    Rd_dword(fd,&item->lcbPlcffldHdr);
    Rd_dword(fd,(uint32_t *)&item->fcPlcffldFtn);
    Rd_dword(fd,&item->lcbPlcffldFtn);
    Rd_dword(fd,(uint32_t *)&item->fcPlcffldAtn);
    Rd_dword(fd,&item->lcbPlcffldAtn);
    Rd_dword(fd,(uint32_t *)&item->fcPlcffldMcr);
    Rd_dword(fd,&item->lcbPlcffldMcr);
    Rd_dword(fd,(uint32_t *)&item->fcSttbfbkmk);
    Rd_dword(fd,&item->lcbSttbfbkmk);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfbkf);
    Rd_dword(fd,&item->lcbPlcfbkf);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfbkl);
    Rd_dword(fd,&item->lcbPlcfbkl);
    Rd_dword(fd,(uint32_t *)&item->fcCmds);
    Rd_dword(fd,&item->lcbCmds);
    Rd_dword(fd,(uint32_t *)&item->fcPlcmcr);
    Rd_dword(fd,&item->lcbPlcmcr);
    Rd_dword(fd,(uint32_t *)&item->fcSttbfmcr);
    Rd_dword(fd,&item->lcbSttbfmcr);
    Rd_dword(fd,(uint32_t *)&item->fcPrDrvr);
    Rd_dword(fd,&item->lcbPrDrvr);
    Rd_dword(fd,(uint32_t *)&item->fcPrEnvPort);
    Rd_dword(fd,&item->lcbPrEnvPort);
    Rd_dword(fd,(uint32_t *)&item->fcPrEnvLand);
    Rd_dword(fd,&item->lcbPrEnvLand);
    Rd_dword(fd,(uint32_t *)&item->fcWss);
    Rd_dword(fd,&item->lcbWss);
    Rd_dword(fd,(uint32_t *)&item->fcDop);
    Rd_dword(fd,&item->lcbDop);
    Rd_dword(fd,(uint32_t *)&item->fcSttbfAssoc);
    Rd_dword(fd,&item->lcbSttbfAssoc);
    Rd_dword(fd,(uint32_t *)&item->fcClx);
    Rd_dword(fd,&item->lcbClx);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfpgdFtn);
    Rd_dword(fd,&item->lcbPlcfpgdFtn);
    Rd_dword(fd,(uint32_t *)&item->fcAutosaveSource);
    Rd_dword(fd,&item->lcbAutosaveSource);
    Rd_dword(fd,(uint32_t *)&item->fcGrpXstAtnOwners);
    Rd_dword(fd,&item->lcbGrpXstAtnOwners);
    Rd_dword(fd,(uint32_t *)&item->fcSttbfAtnbkmk);
    Rd_dword(fd,&item->lcbSttbfAtnbkmk);
    Rd_dword(fd,(uint32_t *)&item->fcPlcdoaMom);
    Rd_dword(fd,&item->lcbPlcdoaMom);
    Rd_dword(fd,(uint32_t *)&item->fcPlcdoaHdr);
    Rd_dword(fd,&item->lcbPlcdoaHdr);
    Rd_dword(fd,(uint32_t *)&item->fcPlcspaMom);
    Rd_dword(fd,&item->lcbPlcspaMom);
    Rd_dword(fd,(uint32_t *)&item->fcPlcspaHdr);
    Rd_dword(fd,&item->lcbPlcspaHdr);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfAtnbkf);
    Rd_dword(fd,&item->lcbPlcfAtnbkf);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfAtnbkl);
    Rd_dword(fd,&item->lcbPlcfAtnbkl);
    Rd_dword(fd,(uint32_t *)&item->fcPms);
    Rd_dword(fd,&item->lcbPms);
    Rd_dword(fd,(uint32_t *)&item->fcFormFldSttbs);
    Rd_dword(fd,&item->lcbFormFldSttbs);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfendRef);
    Rd_dword(fd,&item->lcbPlcfendRef);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfendTxt);
    Rd_dword(fd,&item->lcbPlcfendTxt);
    Rd_dword(fd,(uint32_t *)&item->fcPlcffldEdn);
    Rd_dword(fd,&item->lcbPlcffldEdn);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfpgdEdn);
    Rd_dword(fd,&item->lcbPlcfpgdEdn);
    Rd_dword(fd,(uint32_t *)&item->fcDggInfo);
    Rd_dword(fd,&item->lcbDggInfo);
    Rd_dword(fd,(uint32_t *)&item->fcSttbfRMark);
    Rd_dword(fd,&item->lcbSttbfRMark);
    Rd_dword(fd,(uint32_t *)&item->fcSttbCaption);
    Rd_dword(fd,&item->lcbSttbCaption);
    Rd_dword(fd,(uint32_t *)&item->fcSttbAutoCaption);
    Rd_dword(fd,&item->lcbSttbAutoCaption);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfwkb);
    Rd_dword(fd,&item->lcbPlcfwkb);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfspl);
    Rd_dword(fd,&item->lcbPlcfspl);
    Rd_dword(fd,(uint32_t *)&item->fcPlcftxbxTxt);
    Rd_dword(fd,&item->lcbPlcftxbxTxt);
    Rd_dword(fd,(uint32_t *)&item->fcPlcffldTxbx);
    Rd_dword(fd,&item->lcbPlcffldTxbx);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfhdrtxbxTxt);
    Rd_dword(fd,&item->lcbPlcfhdrtxbxTxt);
    Rd_dword(fd,(uint32_t *)&item->fcPlcffldHdrTxbx);
    Rd_dword(fd,&item->lcbPlcffldHdrTxbx);
    Rd_dword(fd,(uint32_t *)&item->fcStwUser);
    Rd_dword(fd,&item->lcbStwUser);
    Rd_dword(fd,(uint32_t *)&item->fcSttbttmbd);
    Rd_dword(fd,&item->cbSttbttmbd);
    Rd_dword(fd,(uint32_t *)&item->fcUnused);
    Rd_dword(fd,&item->lcbUnused);
    Rd_dword(fd,(uint32_t *)&item->fcPgdMother);
    Rd_dword(fd,&item->lcbPgdMother);
    Rd_dword(fd,(uint32_t *)&item->fcBkdMother);
    Rd_dword(fd,&item->lcbBkdMother);
    Rd_dword(fd,(uint32_t *)&item->fcPgdFtn);
    Rd_dword(fd,&item->lcbPgdFtn);
    Rd_dword(fd,(uint32_t *)&item->fcBkdFtn);
    Rd_dword(fd,&item->lcbBkdFtn);
    Rd_dword(fd,(uint32_t *)&item->fcPgdEdn);
    Rd_dword(fd,&item->lcbPgdEdn);
    Rd_dword(fd,(uint32_t *)&item->fcBkdEdn);
    Rd_dword(fd,&item->lcbBkdEdn);
    Rd_dword(fd,(uint32_t *)&item->fcSttbfIntlFld);
    Rd_dword(fd,&item->lcbSttbfIntlFld);
    Rd_dword(fd,(uint32_t *)&item->fcRouteSlip);
    Rd_dword(fd,&item->lcbRouteSlip);
    Rd_dword(fd,(uint32_t *)&item->fcSttbSavedBy);
    Rd_dword(fd,&item->lcbSttbSavedBy);
    Rd_dword(fd,(uint32_t *)&item->fcSttbFnm);
    Rd_dword(fd,&item->lcbSttbFnm);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfLst);
    Rd_dword(fd,&item->lcbPlcfLst);
    Rd_dword(fd,(uint32_t *)&item->fcPlfLfo);
    Rd_dword(fd,&item->lcbPlfLfo);
    Rd_dword(fd,(uint32_t *)&item->fcPlcftxbxBkd);
    Rd_dword(fd,&item->lcbPlcftxbxBkd);
    Rd_dword(fd,(uint32_t *)&item->fcPlcftxbxHdrBkd);
    Rd_dword(fd,&item->lcbPlcftxbxHdrBkd);
    Rd_dword(fd,(uint32_t *)&item->fcDocUndo);
    Rd_dword(fd,&item->lcbDocUndo);
    Rd_dword(fd,(uint32_t *)&item->fcRgbuse);
    Rd_dword(fd,&item->lcbRgbuse);
    Rd_dword(fd,(uint32_t *)&item->fcUsp);
    Rd_dword(fd,&item->lcbUsp);
    Rd_dword(fd,(uint32_t *)&item->fcUskf);
    Rd_dword(fd,&item->lcbUskf);
    Rd_dword(fd,(uint32_t *)&item->fcPlcupcRgbuse);
    Rd_dword(fd,&item->lcbPlcupcRgbuse);
    Rd_dword(fd,(uint32_t *)&item->fcPlcupcUsp);
    Rd_dword(fd,&item->lcbPlcupcUsp);
    Rd_dword(fd,(uint32_t *)&item->fcSttbGlsyStyle);
    Rd_dword(fd,&item->lcbSttbGlsyStyle);
    Rd_dword(fd,(uint32_t *)&item->fcPlgosl);
    Rd_dword(fd,&item->lcbPlgosl);
    Rd_dword(fd,(uint32_t *)&item->fcPlcocx);
    Rd_dword(fd,&item->lcbPlcocx);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfbteLvc);
    Rd_dword(fd,&item->lcbPlcfbteLvc);
    wvGetFILETIME (&(item->ftModified), fd);
    Rd_dword(fd,(uint32_t *)&item->fcPlcflvc);
    Rd_dword(fd,&item->lcbPlcflvc);
    Rd_dword(fd,(uint32_t *)&item->fcPlcasumy);
    Rd_dword(fd,&item->lcbPlcasumy);
    Rd_dword(fd,(uint32_t *)&item->fcPlcfgram);
    Rd_dword(fd,&item->lcbPlcfgram);
    Rd_dword(fd,(uint32_t *)&item->fcSttbListNames);
    Rd_dword(fd,&item->lcbSttbListNames);
    Rd_dword(fd,(uint32_t *)&item->fcSttbfUssr);
    Rd_dword(fd,&item->lcbSttbfUssr);
//printf("pos is %ld \n",ftell(fd));
}

//-------End of FIB processing--------

uint32_t wvNormFC(uint32_t fc, int *flag)
{
    if (fc & 0x40000000UL)
      {
	  fc = fc & 0xbfffffffUL;
	  fc = fc / 2;
	  if (flag)
	      *flag = 1;
      }
    else if (flag)
	*flag = 0;
    return (fc);
}

//-----

static void wvGetPRM (PRM * item, FILE *fd)
{
uint16_t temp16;
  Rd_word(fd,&temp16);
  item->fComplex = temp16 & 0x0001;
  wvTrace(("u16 is %x,fComplex is %d %d\n", temp16, temp16 & 0x0001,item->fComplex));

    if (item->fComplex)
	item->para.var2.igrpprl = (temp16 & 0xfffe) >> 1;
    else
      {
	  item->para.var1.isprm = (temp16 & 0x00fe) >> 1;
	  item->para.var1.val = (temp16 & 0xff00) >> 8;
      }
}

static void wvInitPRM (PRM * item)
{
    item->fComplex = 0;
    item->para.var2.igrpprl = 0;
}

//--------- end of PRM processing ------------

static void wvInitPHE (PHE * item)
{
  memset(item,0,sizeof(*item));
}


static void wvGetPHE6 (PHE * dest, uint8_t * page, uint16_t * pos)
{
uint8_t temp8;

#ifdef PURIFY
    wvInitPHE (dest, 0);
#endif

    temp8 = bread_8ubit (&(page[*pos]), pos);
    dest->var1.fSpare = temp8 & 0x01;
    dest->var1.fUnk = (temp8 & 0x02) >> 1;

    dest->var1.fDiffLines = (temp8 & 0x04) >> 2;
    dest->var1.reserved1 = (temp8 & 0xf8) >> 3;

    dest->var1.clMac = bread_8ubit (&(page[*pos]), pos);

    dest->var1.dxaCol = (int16_t) bread_16ubit (&(page[*pos]), pos);
    dest->var1.dymHeight = (int32_t) bread_16ubit (&(page[*pos]), pos);
}


static void wvGetPHE (PHE * dest, int which, uint8_t * page, uint16_t * pos)
{
uint8_t temp8;
uint32_t temp32;

#ifdef PURIFY
    wvInitPHE (dest, which);
#endif

    if (which)
      {
	  temp32 = bread_32ubit (&(page[*pos]), pos);
	  dest->var2.fSpare = temp32 & 0x0001;
	  dest->var2.fUnk = (temp32 & 0x0002) >> 1;
	  dest->var2.dcpTtpNext = (temp32 & 0xfffffffc) >> 2;
	  dest->var2.dxaCol = (int32_t) bread_32ubit (&(page[*pos]), pos);
	  dest->var2.dymHeight = (int32_t) bread_32ubit (&(page[*pos]), pos);
      }
    else
      {
	  temp8 = bread_8ubit (&(page[*pos]), pos);
	  dest->var1.fSpare = temp8 & 0x01;
	  dest->var1.fUnk = (temp8 & 0x02) >> 1;

	  dest->var1.fDiffLines = (temp8 & 0x04) >> 2;
	  dest->var1.reserved1 = (temp8 & 0xf8) >> 3;

	  dest->var1.clMac = bread_8ubit (&(page[*pos]), pos);

	  dest->var1.reserved2 = bread_16ubit (&(page[*pos]), pos);

	  dest->var1.dxaCol = (int32_t) bread_32ubit (&(page[*pos]), pos);
	  dest->var1.dymHeight = (int32_t) bread_32ubit (&(page[*pos]), pos);
      }
}

static void wvCopyPHE(PHE * dest, PHE * src, int which)
{
    if (which)
      {
	  dest->var2.fSpare = src->var2.fSpare;
	  dest->var2.fUnk = src->var2.fUnk;
	  dest->var2.dcpTtpNext = src->var2.dcpTtpNext;
	  dest->var2.dxaCol = src->var2.dxaCol;
	  dest->var2.dymHeight = src->var2.dymHeight;
      }
    else
      {
	  dest->var1.fSpare = src->var1.fSpare;
	  dest->var1.fUnk = src->var1.fUnk;

	  dest->var1.fDiffLines = src->var1.fDiffLines;
	  dest->var1.reserved1 = src->var1.reserved1;
	  dest->var1.clMac = src->var1.clMac;
	  dest->var1.reserved2 = src->var1.reserved2;

	  dest->var1.dxaCol = src->var1.dxaCol;
	  dest->var1.dymHeight = src->var1.dymHeight;
      }
}


//--------End of PHE processing----------


static void wvInitTLP (TLP * item)
{
  memset(item,0,sizeof(*item));
}


static void wvGetTLP_internal (TLP * dest, FILE * infd, uint8_t * pointer)
{
uint16_t temp16;

  dest->itl = dread_16ubit (infd, &pointer);

  temp16 = dread_16ubit (infd, &pointer);
  dest->fBorders = temp16 & 0x0001;
  dest->fShading = (temp16 & 0x0002) >> 1;
  dest->fFont = (temp16 & 0x0004) >> 2;
  dest->fColor = (temp16 & 0x0008) >> 3;
  dest->fBestFit = (temp16 & 0x0010) >> 4;
  dest->fHdrRows = (temp16 & 0x0020) >> 5;
  dest->fLastRow = (temp16 & 0x0040) >> 6;
  dest->fHdrCols = (temp16 & 0x0080) >> 7;
  dest->fLastCol = (temp16 & 0x0100) >> 8;
}



static void wvGetTLPFromBucket (TLP * item, uint8_t * pointer)
{
    wvGetTLP_internal (item, NULL, pointer);
}



//--------- end of TLP processing ------------

static void wvInitBRC (BRC * abrc)
{
  memset(abrc,0,sizeof(*abrc));
}


static void wvGetBRC10_internal (BRC10 * item, FILE * infd, uint8_t * pointer)
{
uint16_t temp16;
  temp16 = dread_16ubit (infd, &pointer);
#ifdef PURIFY
  wvInitBRC10 (item);
#endif
  item->dxpLine2Width = (temp16 & 0x0007);
  item->dxpSpaceBetween = (temp16 & 0x0038) >> 3;
  item->dxpLine1Width = (temp16 & 0x01C0) >> 6;
  item->dxpSpace = (temp16 & 0x3E00) >> 9;
  item->fShadow = (temp16 & 0x4000) >> 14;
  item->fSpare = (temp16 & 0x8000) >> 15;
}


static int wvGetBRC10FromBucket (BRC10 * abrc10, uint8_t * pointer)
{
  wvGetBRC10_internal (abrc10, NULL, pointer);
  return (cbBRC10);
}


static void wvGetBRC_internal (BRC * abrc, FILE * infd, uint8_t * pointer)
{
    uint8_t temp8;

#ifdef PURIFY
    wvInitBRC (abrc);
#endif

    abrc->dptLineWidth = dread_8ubit (infd, &pointer);
    abrc->brcType = dread_8ubit (infd, &pointer);
    abrc->ico = dread_8ubit (infd, &pointer);
    temp8 = dread_8ubit (infd, &pointer);
    abrc->dptSpace = temp8 & 0x1f;
    abrc->fShadow = (temp8 & 0x20) >> 5;
    abrc->fFrame = (temp8 & 0x40) >> 6;
    abrc->reserved = (temp8 & 0x80) >> 7;
}


static void wvGetBRC_internal6 (BRC * abrc, FILE * infd, uint8_t * pointer)
{
uint16_t temp16;

#ifdef PURIFY
  wvInitBRC (abrc);
#endif

  temp16 = dread_16ubit (infd, &pointer);

  abrc->dptLineWidth = (temp16 & 0x0007);
  abrc->brcType = (temp16 & 0x0018) >> 3;
  abrc->fShadow = (temp16 & 0x0020) >> 5;
  abrc->ico = (temp16 & 0x07C0) >> 6;
  abrc->dptSpace = (temp16 & 0xF800) >> 11;
}


static int wvGetBRCFromBucket (int ver, BRC * abrc, uint8_t * pointer)
{
  if (ver == 8) //WORD8
	wvGetBRC_internal (abrc, NULL, pointer);
  else
	{
	wvGetBRC_internal6 (abrc, NULL, pointer);
	return (cb6BRC);
	}
  return (cbBRC);
}


/* I'm not certain as to how this should work, but it will probably
   never occur, its in here for the sake of completeness */
static void wvConvertBRC10ToBRC (BRC * item, BRC10 * in)
{
    wvInitBRC (item);
    item->dptSpace = in->dxpSpace;
    item->fShadow = in->fShadow;
    /*
       The border lines and their brc10 settings follow:

       line type        dxpLine1Width               dxpSpaceBetween dxpLine2Width

       no border        0                           0               0

       single line      1                           0               0
       border

       two single line  1                           1               1
       border

       fat solid border 4                           0               0

       thick solid      2                           0               0
       border

       dotted border    6 (special value meaning    0               0
       dotted line)

       hairline border  7(special value meaning     0               0
       hairline)
     */
    if ((in->dxpLine1Width == 0) && (in->dxpSpaceBetween == 0)
	&& (in->dxpLine2Width == 0))
	item->brcType = 0;
    else if ((in->dxpLine1Width == 1) && (in->dxpSpaceBetween == 0)
	     && (in->dxpLine2Width == 0))
	item->brcType = 1;
    else if ((in->dxpLine1Width == 1) && (in->dxpSpaceBetween == 1)
	     && (in->dxpLine2Width == 1))
	item->brcType = 3;
    else if ((in->dxpLine1Width == 4) && (in->dxpSpaceBetween == 0)
	     && (in->dxpLine2Width == 0))
	item->brcType = 3;
    else if ((in->dxpLine1Width == 2) && (in->dxpSpaceBetween == 0)
	     && (in->dxpLine2Width == 0))
	item->brcType = 2;
    else if ((in->dxpLine1Width == 6) && (in->dxpSpaceBetween == 0)
	     && (in->dxpLine2Width == 0))
	item->brcType = 6;
    else if ((in->dxpLine1Width == 7) && (in->dxpSpaceBetween == 0)
	     && (in->dxpLine2Width == 0))
	item->brcType = 5;
    else
	item->brcType = 0;
}


static void wvCopyBRC (BRC * dest, BRC * src)
{
  dest->dptLineWidth = src->dptLineWidth;
  dest->brcType = src->brcType;
  dest->ico = src->ico;
  dest->dptSpace = src->dptSpace;
  dest->fShadow = src->fShadow;
  dest->fFrame = src->fFrame;
  dest->reserved = src->reserved;
}


//--------- end of BRC processing ------------

static void wvInitTC (TC * item)
{
  memset(item,0,sizeof(*item));

  wvInitBRC (&item->brcTop);
  wvInitBRC (&item->brcLeft);
  wvInitBRC (&item->brcBottom);
  wvInitBRC (&item->brcRight);
}


static int wvGetTC_internal (int ver, TC * tc, FILE * infd, uint8_t * pointer)
{
uint16_t temp16;
BRC10 brc10;
    wvTrace (("TC ver %d\n", ver));

#ifdef PURIFY
    wvInitTC (tc);
#endif
    temp16 = dread_16ubit (infd, &pointer);
    wvTrace (("temp16 is %x\n", temp16));

    if (ver == 8)
      {  tc->fFirstMerged = temp16 & 0x0001;  tc->fMerged = (temp16 & 0x0002) >> 1;  tc->fVertical = (temp16 & 0x0004) >> 2;  tc->fBackward = (temp16 & 0x0008) >> 3;  tc->fRotateFont = (temp16 & 0x0010) >> 4;  tc->fVertMerge = (temp16 & 0x0020) >> 5;  tc->fVertRestart = (temp16 & 0x0040) >> 6;  tc->vertAlign = (temp16 & 0x0180) >> 7;  tc->fUnused = (temp16 & 0xFE00) >> 9;
  tc->wUnused = dread_16ubit (infd, &pointer);  wvGetBRC_internal (&tc->brcTop, infd, pointer);  pointer += cbBRC;  wvGetBRC_internal (&tc->brcLeft, infd, pointer);  pointer += cbBRC;  wvGetBRC_internal (&tc->brcBottom, infd, pointer);  pointer += cbBRC;  wvGetBRC_internal (&tc->brcRight, infd, pointer);  pointer += cbBRC;
      }
    else
      {  wvInitTC (tc);  tc->fFirstMerged = temp16 & 0x0001;  tc->fMerged = (temp16 & 0x0002) >> 1;  /*     This + word 6 205 in sprm.c I thought     would make sense together, until I get     another example I have disabled the two     of them   */  tc->fVertical = (temp16 & 0x0004) >> 2;  tc->fBackward = (temp16 & 0x0008) >> 3;  tc->fRotateFont = (temp16 & 0x0010) >> 4;  tc->fVertMerge = (temp16 & 0x0020) >> 5;  tc->fVertRestart = (temp16 & 0x0040) >> 6;  tc->vertAlign = (temp16 & 0x0180) >> 7;  tc->fUnused = (temp16 & 0xFE00) >> 9;
  wvGetBRC10_internal (&brc10, infd, pointer);  wvConvertBRC10ToBRC (&tc->brcTop, &brc10);  pointer += cb6BRC;  wvGetBRC10_internal (&brc10, infd, pointer);  wvConvertBRC10ToBRC (&tc->brcLeft, &brc10);  pointer += cb6BRC;  wvGetBRC10_internal (&brc10, infd, pointer);  wvConvertBRC10ToBRC (&tc->brcBottom, &brc10);  pointer += cb6BRC;  wvGetBRC10_internal (&brc10, infd, pointer);  wvConvertBRC10ToBRC (&tc->brcRight, &brc10);  pointer += cb6BRC;  return (cb6TC);
      }
return (cbTC);
}



static int wvGetTCFromBucket (int ver, TC * abrc, uint8_t * pointer)
{
  return (wvGetTC_internal (ver, abrc, NULL, pointer));
}


static void wvCopyTC (TC * dest, TC * src)
{
  dest->fFirstMerged = src->fFirstMerged;
  dest->fMerged = src->fMerged;
  dest->fVertical = src->fVertical;
  dest->fBackward = src->fBackward;
  dest->fRotateFont = src->fRotateFont;
  dest->fVertMerge = src->fVertMerge;
  dest->fVertRestart = src->fVertRestart;
  dest->vertAlign = src->vertAlign;
  dest->fUnused = src->fUnused;
  dest->wUnused = src->wUnused;

  wvCopyBRC (&src->brcTop, &dest->brcTop);
  wvCopyBRC (&src->brcLeft, &dest->brcLeft);
  wvCopyBRC (&src->brcBottom, &dest->brcBottom);
  wvCopyBRC (&src->brcRight, &dest->brcRight);
}



//--------- end of TC processing ------------

static void wvInitSHD (SHD * item)
{
  item->icoFore = 0;
  item->icoBack = 0;
  item->ipat = 0;
}


static void wvGetSHD_internal (SHD * item, FILE * fd, uint8_t * pointer)
{
uint16_t temp16;
#ifdef PURIFY
  wvInitSHD (item);
#endif
  temp16 = dread_16ubit (fd, &pointer);
  item->icoFore = temp16 & 0x001F;
  item->icoBack = (temp16 & 0x03E0) >> 5;
  item->ipat = (temp16 & 0xFC00) >> 10;
}


static void wvGetSHDFromBucket (SHD * item, uint8_t * pointer)
{
  wvGetSHD_internal (item, NULL, pointer);
}


static void wvCopySHD (SHD * dest, SHD * src)
{
  memcpy (dest, src, sizeof (SHD));
}


//--------- end of SHD processing ------------

TAP * cache_TAP=NULL;


void wvCopyTAP (TAP * dest, TAP * src)
{
  memcpy (dest, src, sizeof (TAP));
}


static void wvInitTAP(TAP * item)
{
int i;

  if(item==NULL) return;
  if (cache_TAP==NULL)
      {
      cache_TAP = (TAP *)calloc(1,sizeof(TAP));	/* This might be is a memory leak - only 2kb once */
      if(cache_TAP==NULL)
	  {
	  memset(item,0,sizeof(TAP));
	  fprintf(stderr,"No Memory");
	  return;
	  }

      // memset(cache_TAP,0,sizeof(cache_TAP));  calloc provides zero initialisation.

      wvInitTLP (&cache_TAP->tlp);
      for (i = 0; i < itcMax; i++)
	  {
	  wvInitTC(&(cache_TAP->rgtc[i]));
	  wvInitSHD(&(cache_TAP->rgshd[i]));
	  }
      for (i = 0; i < 6; i++)
	  wvInitBRC (&(cache_TAP->rgbrcTable[i]));
      }
  wvCopyTAP(item, cache_TAP);
}

//--------- end of TAP processing ------------

static void wvInitDCS (DCS * item)
{
    item->fdct = 0;
    item->count = 0;
    item->reserved = 0;
}


static void wvGetDCS_internal (DCS * item, FILE * fd, uint8_t * pointer)
{
uint16_t temp16;
  temp16 = dread_16ubit (fd, &pointer);
  item->fdct = temp16 & 0x0007;
  item->count = (temp16 & 0x00F8) >> 3;
  item->reserved = (temp16 & 0xff00) >> 8;
}


static void wvGetDCSFromBucket (DCS * item, uint8_t * pointer)
{
  wvGetDCS_internal (item, NULL, pointer);
}


//--------- end of DCS processing ------------

static void wvInitANLV(ANLV * item)
{
  if(item) memset(item,0,sizeof(*item));
}


static void wvGetANLV_internal (ANLV * item, FILE * fd, uint8_t * pointer)
{
  uint8_t temp8;
  item->nfc = dread_8ubit (fd, &pointer);
  item->cxchTextBefore = dread_8ubit (fd, &pointer);
  item->cxchTextAfter = dread_8ubit (fd, &pointer);
  temp8 = dread_8ubit (fd, &pointer);
  item->jc = temp8 & 0x03;
  item->fPrev = (temp8 & 0x04) >> 2;
  item->fHang = (temp8 & 0x08) >> 3;
  item->fSetBold = (temp8 & 0x10) >> 4;
  item->fSetItalic = (temp8 & 0x20) >> 5;
  item->fSetSmallCaps = (temp8 & 0x40) >> 6;
  item->fSetCaps = (temp8 & 0x80) >> 7;
  temp8 = dread_8ubit (fd, &pointer);
  item->fSetStrike = temp8 & 0x01;
  item->fSetKul = (temp8 & 0x02) >> 1;
  item->fPrevSpace = (temp8 & 0x04) >> 2;
  item->fBold = (temp8 & 0x08) >> 3;
  item->fItalic = (temp8 & 0x10) >> 4;
  item->fSmallCaps = (temp8 & 0x20) >> 5;
  item->fCaps = (temp8 & 0x40) >> 6;
  item->fStrike = (temp8 & 0x80) >> 7;
  temp8 = dread_8ubit (fd, &pointer);
  item->kul = temp8 & 0x07;
  item->ico = (temp8 & 0xF1) >> 3;
  item->ftc = (int16_t) dread_16ubit (fd, &pointer);
  item->hps = dread_16ubit (fd, &pointer);
  item->iStartAt = dread_16ubit (fd, &pointer);
  item->dxaIndent = dread_16ubit (fd, &pointer);
  item->dxaSpace = (int16_t) dread_16ubit (fd, &pointer);
}



//--------- end of ANLV processing ------------

static void wvInitANLD (ANLD * item)
{
  memset(item,0,sizeof(*item));
}

static void wvGetANLD_FromBucket (int ver, ANLD * item, uint8_t * pointer8)
{
uint8_t temp8;
int i;

#ifdef PURIFY
    wvInitANLD (item);
#endif
    item->nfc = dread_8ubit (NULL, &pointer8);
    item->cxchTextBefore = dread_8ubit (NULL, &pointer8);
    item->cxchTextAfter = dread_8ubit (NULL, &pointer8);
    temp8 = dread_8ubit (NULL, &pointer8);
    item->jc = temp8 & 0x03;
    item->fPrev = (temp8 & 0x04) >> 2;
    item->fHang = (temp8 & 0x08) >> 3;
    item->fSetBold = (temp8 & 0x10) >> 4;
    item->fSetItalic = (temp8 & 0x20) >> 5;
    item->fSetSmallCaps = (temp8 & 0x40) >> 6;
    item->fSetCaps = (temp8 & 0x80) >> 7;
    temp8 = dread_8ubit (NULL, &pointer8);
    item->fSetStrike = temp8 & 0x01;
    item->fSetKul = (temp8 & 0x02) >> 1;
    item->fPrevSpace = (temp8 & 0x04) >> 2;
    item->fBold = (temp8 & 0x08) >> 3;
    item->fItalic = (temp8 & 0x10) >> 4;
    item->fSmallCaps = (temp8 & 0x20) >> 5;
    item->fCaps = (temp8 & 0x40) >> 6;
    item->fStrike = (temp8 & 0x80) >> 7;
    temp8 = dread_8ubit (NULL, &pointer8);
    item->kul = temp8 & 0x07;
    item->ico = (temp8 & 0xF1) >> 3;
    item->ftc = (int16_t)dread_16ubit (NULL, &pointer8);
    item->hps = dread_16ubit (NULL, &pointer8);
    item->iStartAt = dread_16ubit (NULL, &pointer8);
    item->dxaIndent = (int16_t) dread_16ubit (NULL, &pointer8);
    item->dxaSpace = dread_16ubit (NULL, &pointer8);
    item->fNumber1 = dread_8ubit (NULL, &pointer8);
#if 0
    if (item->fNumber1 == 46)
	wvTrace (("This level has not been modified, so you can't believe its nfc\n"));
#endif
    item->fNumberAcross = dread_8ubit (NULL, &pointer8);
    item->fRestartHdn = dread_8ubit (NULL, &pointer8);
    item->fSpareX = dread_8ubit (NULL, &pointer8);
    for (i = 0; i < 32; i++)
      {
	  if (ver == 8) //WORD8)
	      item->rgxch[i] = dread_16ubit (NULL, &pointer8);
	  else
	      item->rgxch[i] = dread_8ubit (NULL, &pointer8);
      }
}



//--------- end of ANLD processing ------------

static void wvInitDTTM (DTTM * dttm)
{
    dttm->mint = 0;
    dttm->hr = 0;
    dttm->dom = 0;

    dttm->mon = 0;
    dttm->yr = 0;
    dttm->wdy = 0;
}

static void wvCreateDTTM (DTTM * dttm, uint16_t temp1_16, uint16_t temp2_16)
{
    dttm->mint = temp1_16 & 0x003F;
    dttm->hr = (temp1_16 & 0x07C0) >> 6;
    dttm->dom = (temp1_16 & 0xF800) >> 11;

    dttm->mon = temp2_16 & 0x000F;
    dttm->yr = (temp2_16 & 0x1FF0) >> 4;
    dttm->wdy = (temp2_16 & 0xE000) >> 13;
}


static void wvGetDTTMFromBucket (DTTM * item, uint8_t * pointer)
{
    uint16_t a = dread_16ubit (NULL, &pointer);
    uint16_t b = dread_16ubit (NULL, &pointer);
    wvCreateDTTM (item, a, b);
}


static void wvGetDTTM (DTTM * item, FILE * fd)
{
uint16_t a,b;
  Rd_word(fd,&a);
  Rd_word(fd,&b);
  wvCreateDTTM (item, a, b);
}


static void wvCopyDTTM (DTTM * dest, DTTM * src)
{
  memcpy (dest, src, sizeof (DTTM));
}


//--------- end of DTTM processing ------------

static void wvInitNUMRM (NUMRM * item)
{
  memset(item,0,sizeof(*item));
  wvInitDTTM (&(item->dttmNumRM));
}


static void wvGetNUMRM_internal (NUMRM * item, FILE * fd, uint8_t * pointer)
{
int i;
  item->fNumRM = dread_8ubit (fd, &pointer);
  item->Spare1 = dread_8ubit (fd, &pointer);
  item->ibstNumRM = (int16_t) dread_16ubit (fd, &pointer);
  if (fd != NULL)
	wvGetDTTM (&(item->dttmNumRM), fd);
  else
	{
	wvGetDTTMFromBucket (&(item->dttmNumRM), pointer);
	pointer += cbDTTM;
	}
  for (i = 0; i < 9; i++)
	item->rgbxchNums[i] = dread_8ubit (fd, &pointer);
  for (i = 0; i < 9; i++)
	item->rgnfc[i] = dread_8ubit (fd, &pointer);
  item->Spare2 = (int16_t) dread_16ubit (fd, &pointer);
  for (i = 0; i < 9; i++)
	item->PNBR[i] = (int32_t) dread_32ubit (fd, &pointer);
  for (i = 0; i < 32; i++)
	item->xst[i] = dread_16ubit (fd, &pointer);
}


static void wvGetNUMRMFromBucket (NUMRM * item, uint8_t * pointer)
{
  wvGetNUMRM_internal (item, NULL, pointer);
}


//--------- end of NUMRM processing ------------

static void wvInitTBD (TBD * item)
{
    item->jc = 0;
    item->tlc = 0;
    item->reserved = 0;
}


static void wvGetTBD_internal (TBD * item, FILE * fd, uint8_t * pointer)
{
uint8_t temp8;

    temp8 = dread_8ubit (fd,&pointer);
#ifdef PURIFY
    wvInitTBD (item);
#endif
    item->jc = temp8 & 0x07;
    item->tlc = (temp8 & 0x38) >> 3;
    item->reserved = (temp8 & 0xC0) >> 6;
}


static void wvGetTBDFromBucket (TBD * item, uint8_t * pointer)
{
  wvGetTBD_internal (item, NULL, pointer);
}


static void wvCopyTBD (TBD * dest, TBD * src)
{
  memcpy (dest, src, sizeof (TBD));
}


//--------- end of TBD processing ------------

static void wvGetLSPDFromBucket (LSPD * item, uint8_t * pointer)
{
  item->dyaLine = dread_16ubit (NULL, &pointer);
  item->fMultLinespace = dread_16ubit (NULL, &pointer);
}


/* To apply a UPX.chpx to a UPE.chp, apply the UPX.chpx.grpprl to
 * UPE.chp. Note that a UPE.chp for a paragraph style should always have
 * UPE.chp.istd == istdNormalChar.  */
static void wvAddCHPXFromBucket (CHP * achp, UPXF * upxf, STSH * stsh)
{
uint8_t *pointer;
uint16_t i = 0;
uint16_t sprm;

#ifdef SPRMTEST
    fprintf (stderr, "\n");
    while (i < upxf->cbUPX)
      {
	  fprintf (stderr, "%x (%d) ", *(upxf->upx.chpx.grpprl + i),
		   *(upxf->upx.chpx.grpprl + i));
	  i++;
      }
    fprintf (stderr, "\n");
    i = 0;
#endif
    while (i + 2 < upxf->cbUPX) /* is this check sufficient ?? */
      {
	  sprm = bread_16ubit (upxf->upx.chpx.grpprl + i, &i);
#ifdef SPRMTEST
	  wvError (("sprm is %x, i is %d\n", sprm, i));
#endif
	  pointer = upxf->upx.chpx.grpprl + i;
	  wvApplySprmFromBucket (8, sprm, NULL, achp, NULL, stsh, pointer,
				 &i, NULL);
      }
}


static void wvReleaseCHPX (CHPX * item)
{
  free(item->grpprl);
}


//--------- end of LSPD processing ------------


static void wvInitCHP (CHP * item)
{
  memset(item,0,sizeof(*item));

  item->fUsePgsuSettings = -1;     /*-1 ? */
  item->hps = 20;
  item->lidDefault = 0x0400;
  item->lidFE = 0x0400;
  item->wCharScale = 100;
  item->fcPic_fcObj_lTagObj = -1;

  wvInitDTTM (&item->dttmRMark);
  wvInitDTTM (&item->dttmRMarkDel);

  item->istd = istdNormalChar;

  wvInitDTTM (&item->dttmPropRMark);

  wvInitDTTM (&item->reserved10);

  wvInitDTTM (&item->dttmDispFldRMark);

  wvInitSHD (&item->shd);

  wvInitBRC (&item->brc);
}


static void wvCopyCHP (CHP * dest, CHP * src)
{
int i;

    dest->fBold = src->fBold;
    dest->fItalic = src->fItalic;
    dest->fRMarkDel = src->fRMarkDel;
    dest->fOutline = src->fOutline;
    dest->fFldVanish = src->fFldVanish;
    dest->fSmallCaps = src->fSmallCaps;
    dest->fCaps = src->fCaps;
    dest->fVanish = src->fVanish;
    dest->fRMark = src->fRMark;
    dest->fSpec = src->fSpec;
    dest->fStrike = src->fStrike;
    dest->fObj = src->fObj;
    dest->fShadow = src->fShadow;
    dest->fLowerCase = src->fLowerCase;
    dest->fData = src->fData;
    dest->fOle2 = src->fOle2;
    dest->fEmboss = src->fEmboss;
    dest->fImprint = src->fImprint;
    dest->fDStrike = src->fDStrike;
    dest->fUsePgsuSettings = src->fUsePgsuSettings;
    dest->reserved1 = src->reserved1;
    dest->reserved2 = src->reserved2;
    dest->reserved11 = src->reserved11;
    dest->ftc = src->ftc;
    dest->ftcAscii = src->ftcAscii;
    dest->ftcFE = src->ftcFE;
    dest->ftcOther = src->ftcOther;
    dest->hps = src->hps;
    dest->dxaSpace = src->dxaSpace;
    dest->iss = src->iss;
    dest->kul = src->kul;
    dest->fSpecSymbol = src->fSpecSymbol;
    dest->ico = src->ico;
    dest->reserved3 = src->reserved3;
    dest->fSysVanish = src->fSysVanish;
    dest->hpsPos = src->hpsPos;
    dest->super_sub = src->super_sub;
    dest->lid = src->lid;
    dest->lidDefault = src->lidDefault;
    dest->lidFE = src->lidFE;
    dest->idct = src->idct;
    dest->idctHint = src->idctHint;
    dest->wCharScale = src->wCharScale;
    dest->fcPic_fcObj_lTagObj = src->fcPic_fcObj_lTagObj;
    dest->ibstRMark = src->ibstRMark;
    dest->ibstRMarkDel = src->ibstRMarkDel;

    wvCopyDTTM (&dest->dttmRMark, &src->dttmRMark);
    wvCopyDTTM (&dest->dttmRMarkDel, &src->dttmRMarkDel);

    dest->reserved4 = src->reserved4;
    dest->istd = src->istd;
    dest->ftcSym = src->ftcSym;
    dest->xchSym = src->xchSym;
    dest->idslRMReason = src->idslRMReason;
    dest->idslReasonDel = src->idslReasonDel;
    dest->ysr = src->ysr;
    dest->chYsr = src->chYsr;
    dest->cpg = src->cpg;
    dest->hpsKern = src->hpsKern;
    dest->icoHighlight = src->icoHighlight;
    dest->fHighlight = src->fHighlight;
    dest->kcd = src->kcd;
    dest->fNavHighlight = src->fNavHighlight;
    dest->fChsDiff = src->fChsDiff;
    dest->fMacChs = src->fMacChs;
    dest->fFtcAsciSym = src->fFtcAsciSym;
    dest->reserved5 = src->reserved5;
    dest->fPropRMark = src->fPropRMark;
    dest->ibstPropRMark = src->ibstPropRMark;

    wvCopyDTTM (&dest->dttmPropRMark, &src->dttmPropRMark);

    dest->sfxtText = src->sfxtText;
    dest->reserved6 = src->reserved6;
    dest->reserved7 = src->reserved7;
    dest->reserved8 = src->reserved8;
    dest->reserved9 = src->reserved9;

    wvCopyDTTM (&dest->reserved10, &src->reserved10);

    dest->fDispFldRMark = src->fDispFldRMark;
    dest->ibstDispFldRMark = src->ibstDispFldRMark;

    wvCopyDTTM (&dest->dttmDispFldRMark, &src->dttmDispFldRMark);

    for (i = 0; i < 16; i++)
	dest->xstDispFldRMark[i] = src->xstDispFldRMark[i];

    wvCopySHD (&dest->shd, &src->shd);

    wvCopyBRC (&dest->brc, &src->brc);

    /* bidi */
    dest->fBidi = src->fBidi;
    dest->fBoldBidi = src->fBoldBidi;
    dest->fItalicBidi = src->fItalicBidi;
    dest->ftcBidi = src->ftcBidi;
    dest->hpsBidi = src->hpsBidi;
    dest->icoBidi = src->icoBidi;
    dest->lidBidi = src->lidBidi;
}


static void wvApplyCHPXFromBucket (CHP * achp, CHPX * chpx, STSH * stsh)
{
uint8_t *pointer;
uint16_t i = 0;
uint16_t sprm;

#ifdef SPRMTEST
    fprintf (stderr, "\n");
    while (i < chpx->cbGrpprl)
      {
	  fprintf (stderr, "%x (%d) ", *(chpx->grpprl + i),
		   *(chpx->grpprl + i));
	  i++;
      }
    fprintf (stderr, "\n");
    i = 0;
#endif
    while (i < chpx->cbGrpprl)
      {
	  sprm = bread_16ubit (chpx->grpprl + i, &i);
	  wvTrace (("the sprm is %d\n", sprm));
	  pointer = chpx->grpprl + i;
	  wvApplySprmFromBucket (8, sprm, NULL, achp, NULL, stsh, pointer,
				 &i, NULL);
      }
    achp->istd = chpx->istd;
}


static void wvInitCHPFromIstd (CHP * achp, uint16_t istdBase, STSH * stsh)
{
    wvTrace (("initing from %d\n", istdBase));
    if (istdBase == istdNil)
	wvInitCHP (achp);
    else
      {
	  if (istdBase >= stsh->Stshi.cstd)
	    {
	    //wvError (("ISTD out of bounds, requested %d of %d\n",istdBase, stsh->Stshi.cstd));
	    wvInitCHP (achp);	/*it can't hurt to try and start with a blank istd */
	    return;
	    }
	  else
	    {
		if (stsh->std[istdBase].cupx == 0)	/*empty slot in the array, i don't think this should happen */
		  {
		  wvTrace (("Empty style slot used (chp)\n"));
		  wvInitCHP (achp);
		  }
		else
		  {
		  wvTrace (("type is %d\n", stsh->std[istdBase].sgc));
		  switch (stsh->std[istdBase].sgc)
		    {
		    case sgcPara:
			wvCopyCHP (achp,
				   &(stsh->std[istdBase].grupe[1].achp));
			break;
		    case sgcChp:
			wvInitCHP (achp);
			wvApplyCHPXFromBucket (achp,
					       &(stsh->std[istdBase].
						 grupe[0].chpx), stsh);
			break;
		    }
		  }
	    }
      }

}


/*
 * The chpx for the null style has an istd of zero, a cbGrpprl of zero
 * (and an empty grpprl) this only exists in the UPD/UPE
 */
static void wvInitCHPX (CHPX * item)
{
    item->istd = 0;
    item->cbGrpprl = 0;
    item->grpprl = NULL;
}


static void wvCopyCHPX (CHPX * dest, CHPX * src)
{
    int i;
    dest->istd = src->istd;
    dest->cbGrpprl = src->cbGrpprl;
    if (dest->cbGrpprl)
	dest->grpprl = (uint8_t *)malloc(dest->cbGrpprl);
    else
	dest->grpprl = NULL;
    if (dest->grpprl == NULL)
	return;
    for (i = 0; i < dest->cbGrpprl; i++)
	dest->grpprl[i] = src->grpprl[i];
}



/*  * For a character style, the UPE.chpx can be constructed by starting with
 * the first UPE from the based-on style (std.istdBase).*/
static void wvInitCHPXFromIstd (CHPX * chpx, uint16_t istdBase, STSH * stsh)
{
    if (istdBase == istdNil)
	wvInitCHPX (chpx);
    else
      {
	  if (istdBase >= stsh->Stshi.cstd)
	    {
//		wvError (("ISTD out of bounds, requested %d of %d\n", istdBase, stsh->Stshi.cstd));
		wvInitCHPX (chpx);	/*it can't hurt to try and start with a blank istd */
		return;
	    }
	  else
	      wvCopyCHPX (chpx, &(stsh->std[istdBase].grupe[0].chpx));
      }
}


static void wvAddCHPXFromBucket6 (CHP * achp, UPXF * upxf, STSH * stsh)
{
uint8_t *pointer;
uint16_t i = 0;
uint8_t sprm8;
uint16_t sprm;
    wvTrace (("cbUPX word 6 is %d\n", upxf->cbUPX));

#ifdef SPRMTEST
    fprintf (stderr, "\n");
    while (i < upxf->cbUPX)
      {
	  fprintf (stderr, "%x (%d) ", *(upxf->upx.chpx.grpprl + i),
		   *(upxf->upx.chpx.grpprl + i));
	  i++;
      }
    fprintf (stderr, "\n");
    i = 0;
#endif
    while (i < upxf->cbUPX)
      {
	  sprm8 = bread_8ubit (upxf->upx.chpx.grpprl + i, &i);
#ifdef SPRMTEST
	  wvError (("chp word 6 sprm is %x (%d)\n", sprm8, sprm8));
#endif
	  sprm = (uint16_t) wvGetrgsprmWord6 (sprm8);
#ifdef SPRMTEST
	  wvError (("chp word 6 sprm is converted to %x\n", sprm));
#endif

	  pointer = upxf->upx.chpx.grpprl + i;
	  wvApplySprmFromBucket(6, sprm, NULL, achp, NULL, stsh, pointer,
				 &i, NULL);
      }
}


static void wvUpdateCHPXBucket (UPXF * src)
{
uint16_t i = 0, j;
uint16_t sprm;
uint8_t sprm8;
uint16_t len = 0;
int temp;

uint8_t *pointer, *dpointer;
uint8_t *grpprl = NULL;

    i = 0;
    if (src->cbUPX == 0)
	return;
    pointer = src->upx.chpx.grpprl;
    wvTrace (("Msrc->cbUPX len is %d\n", src->cbUPX));
    for (i = 0; i < src->cbUPX; i++)
	wvTrace (("%x\n", src->upx.chpx.grpprl[i]));
    wvTrace (("Mend\n"));
    i = 0;
    len = 0;
    while (i < src->cbUPX)
      {
	  sprm8 = dread_8ubit (NULL, &pointer);
	  wvTrace (("Mpre the sprm is %x\n", sprm8));
	  sprm = (uint16_t) wvGetrgsprmWord6 (sprm8);
	  wvTrace (("Mpost the sprm is %x\n", sprm));
	  i++;
	  len += 2;
	  temp = wvEatSprm (sprm, pointer, &i);
	  wvTrace (("Mlen of op is %d\n", temp));
	  pointer += temp;
	  wvTrace (("Mp dis is %d\n", pointer - src->upx.chpx.grpprl));
	  len += temp;
      }
    wvTrace (("Mlen ends up as %d\n", len));

    if (len == 0)
	return;

    grpprl = (uint8_t *)malloc(len);

    dpointer = grpprl;

    i = 0;
    pointer = src->upx.chpx.grpprl;
    while (i < src->cbUPX)
      {
	  sprm8 = dread_8ubit (NULL, &pointer);
	  sprm = (uint16_t) wvGetrgsprmWord6 (sprm8);
	  i++;
	  *dpointer++ = (sprm & 0x00FF);
	  *dpointer++ = (sprm & 0xff00) >> 8;
	  temp = wvEatSprm (sprm, pointer, &i);
	  for (j = 0; j < temp; j++)
	      *dpointer++ = *pointer++;
	  wvTrace (("Mlen of op is %d\n", temp));
      }
    free(src->upx.chpx.grpprl);
    src->upx.chpx.grpprl = grpprl;
    src->cbUPX = len;
    for (i = 0; i < src->cbUPX; i++)
	wvTrace (("%x\n", src->upx.chpx.grpprl[i]));
}


int wvCompLT (void *a, void *b)
{
    uint8_t *a2, *b2;
    uint16_t sprm1, sprm2;
    a2 = (uint8_t *) a;
    b2 = (uint8_t *) b;
    sprm1 = fil_sreadU16 (a2);
    sprm2 = fil_sreadU16 (b2);
    return (sprm1 < sprm2);
}

int wvCompEQ (void *a, void *b)
{
    uint8_t *a2, *b2;
    uint16_t sprm1, sprm2;
    a2 = (uint8_t *) a;
    b2 = (uint8_t *) b;
    sprm1 = fil_sreadU16 (a2);
    sprm2 = fil_sreadU16 (b2);
    return (sprm1 == sprm2);
}



/*
Apply the first UPX (UPX.chpx) in std.grupx to the UPE.

To apply a UPX.chpx to a UPE.chpx, take the grpprl in UPE.chpx.grpprl (which
has a length of UPE.chpx.cbGrpprl) and merge the grpprl in UPX.chpx.grpprl
into it.

Merging grpprls is a tricky business, but for character styles it is easy
because no prls in character style grpprls should interact with each other.
Each prl from the source (the UPX.chpx.grpprl) should be inserted into the
destination (the UPE.chpx.grpprl) so that the sprm of each prl is in increasing
order, and any prls that have the same sprm are replaced by the prl in the
source.

UPE.chpx.cbGrpprl is then set to the length of resulting grpprl, and
UPE.chpx.istd is set to the style's istd. */
static void wvMergeCHPXFromBucket (CHPX * dest, UPXF * src)
{
    BintreeInfo tree;
    Node *testn, *testp;
    uint16_t i = 0, j;
    uint16_t sprm;
    uint8_t len = 0;
    uint8_t temp;
    Node *test = NULL;

    uint8_t *pointer, *dpointer;
    uint8_t *grpprl = NULL;

    /*
       use a binary tree ala the wmf stuff and first insert every dest sprm into it,
       then insert every src sprm into it, take the full count and take them out of
       the tree and create the list from them
     */
    InitBintree (&tree, wvCompLT, wvCompEQ);
    pointer = dest->grpprl;

    while (i < dest->cbGrpprl)
      {
	  wvTrace (("gotcha the sprm is %x\n", *((uint16_t *) pointer)));
	  test = InsertNode (&tree, (void *) pointer);
	  sprm = dread_16ubit (NULL, &pointer);
	  wvTrace (("the sprm is %x\n", sprm));
	  temp = wvEatSprm (sprm, pointer, &i);
	  pointer += temp;
	  i += 2;
	  if (test)
	      len += temp + 2;
      }

    pointer = src->upx.chpx.grpprl;
    i = 0;
    while (i < src->cbUPX)
      {
	  wvTrace(("gotcha 2 the sprm is %x\n",*((uint16_t *)pointer)));
	  test = InsertNode (&tree, (void *) pointer);
	  sprm = dread_16ubit (NULL, &pointer);
	  i += 2;
	  wvTrace (("the sprm is %x\n", sprm));
	  temp = wvEatSprm (sprm, pointer, &i);
	  wvTrace (("len of op is %d\n", temp));
	  pointer += temp;
	  wvTrace (("p dis is %d\n", pointer - src->upx.chpx.grpprl));
	  if (test)
	      len += temp + 2;
      }

    if (len != 0)
	grpprl = (uint8_t *)malloc(len);
    else
	return;


    dpointer = grpprl;

    testn = NextNode (&tree, NULL);
    while (testn != NULL)
      {
	  pointer = (uint8_t *) testn->Data;
	  sprm = fil_sreadU16 (pointer);
	  wvTrace (("methinks the sprm is %x\n", sprm));
	  pointer += 2;

	  i = 0;
	  wvEatSprm (sprm, pointer, &i);
	  wvTrace (("i is now %d\n", i));

	  pointer = (uint8_t *) testn->Data;
	  for (j = 0; j < i + 2; j++)
	      *dpointer++ = *pointer++;

	  testp = NextNode (&tree, testn);
	  wvDeleteNode (&tree, testn);
	  testn = testp;
      }
    free(dest->grpprl);
    dest->grpprl = grpprl;
    dest->cbGrpprl = len;

    /*test */
    i = 0;
    pointer = dest->grpprl;
    while (i < dest->cbGrpprl)
      {
	  sprm = dread_16ubit (NULL, &pointer);
	  wvTrace (("final test the sprm is %x\n", sprm));
	  temp = wvEatSprm (sprm, pointer, &i);
	  pointer += temp;
	  i += 2;
	  if (test)
	      len += temp + 2;
      }
}


static void wvGetCHPX(CHPX * item, uint8_t * page, uint16_t * pos)
{
uint8_t i;
    item->cbGrpprl = bread_8ubit (&(page[*pos]), pos);
    if (item->cbGrpprl > 0)
      {
	  item->grpprl = (uint8_t *)malloc(item->cbGrpprl);
	  memcpy (item->grpprl, &(page[*pos]), item->cbGrpprl);
      }
    else
	item->grpprl = NULL;

    item->istd = 0;		/* I have no idea what to set this to... */

    for(i = 0; i < item->cbGrpprl; i++)
	wvTrace (("chpx byte is %x\n", item->grpprl[i]));
}


/* taken from wvAssembleSimplePAP in pap.c and modified
 * to handle CHP's  * -JB  */
int wvAssembleSimpleCHP(int ver, CHP * achp, uint32_t fc, CHPX_FKP * fkp, STSH * stsh)
{
CHPX *chpx;
int index;
UPXF upxf;
int ret = 0;
uint16_t tistd;

    /* initialize CHP to para's stylesheet character properties
       * this should have resolved all the other stylesheet dependencies
       * for us, when the stsh's were initialized. */

    /* before this function was called, achp->istd should have
       * been set to the current paragraph properties' stylesheet */
    tistd = achp->istd;
    wvInitCHPFromIstd (achp, achp->istd, stsh);
    achp->istd = tistd;

    /*index is the i in the text above */
    /* the PAPX version of the function only looks at rgfc's, which are
       * the same for CHPX and PAPX FKPs, so we'll reuse the function */
    index = wvGetIndexFCInFKP_PAPX ((PAPX_FKP *) fkp, fc);

    wvTrace (("index is %d, using %d\n", index, index - 1));

    /* get CHPX */
    if(index-1<=fkp->crun)
       chpx=NULL; //BAD - fix - chpx could not be obtained!!!!!!
    else
       chpx = &(fkp->grpchpx[index - 1]);

    /* apply CHPX from FKP */
    if ((chpx) && (chpx->cbGrpprl > 0))
      {
	  ret = 1;
	  /* for (int i = 0; i < chpx->cbGrpprl; i++) */
	  upxf.cbUPX = chpx->cbGrpprl;
	  upxf.upx.chpx.grpprl = chpx->grpprl;
	  if (ver == 8)
	      wvAddCHPXFromBucket (achp, &upxf, stsh);
	  else
	      wvAddCHPXFromBucket6 (achp, &upxf, stsh);
      }
  return (ret);
}

//--------- end of CHP processing ------------


static void wvInitOLST (OLST * item)
{
uint8_t i;
  memset(item,0,sizeof(*item));
  for (i = 0; i < 9; i++)
      wvInitANLV (&item->rganlv[i]);
}


static void wvGetOLST_internal (int ver, OLST * item, FILE * fd, uint8_t * pointer)
{
  uint8_t i;
  for (i = 0; i < 9; i++)
      wvGetANLV_internal (&item->rganlv[i], fd, pointer);
  item->fRestartHdr = dread_8ubit (fd, &pointer);
  item->fSpareOlst2 = dread_8ubit (fd, &pointer);
  item->fSpareOlst3 = dread_8ubit (fd, &pointer);
  item->fSpareOlst4 = dread_8ubit (fd, &pointer);
  if (ver == 8)
    {
	for (i = 0; i < 32; i++)
	    item->rgxch[i] = dread_16ubit (fd, &pointer);
    }
  else
    {
	for (i = 0; i < 64; i++)
	    item->rgxch[i] = dread_8ubit (fd, &pointer);
    }
}


static void wvGetOLSTFromBucket (int ver, OLST * item, uint8_t * pointer)
{
  wvGetOLST_internal (ver, item, NULL, pointer);
}


//--------End of OLST processing----------



static void wvApplysprmPIstdPermute (PAP * apap, uint8_t * pointer, uint16_t * pos)
{
uint8_t cch;
uint8_t fLongg;
uint8_t fSpare;
uint16_t istdFirst;
uint16_t istdLast;
uint16_t *rgistd;
uint16_t i;

    cch = dread_8ubit (NULL, &pointer);
    (*pos)++;
    fLongg = dread_8ubit (NULL, &pointer);
    (*pos)++;
    fSpare = dread_8ubit (NULL, &pointer);
    (*pos)++;
    istdFirst = dread_16ubit (NULL, &pointer);
    (*pos) += 2;
    istdLast = dread_16ubit (NULL, &pointer);
    (*pos) += 2;

    if ( cch > 6)
      {
  rgistd = (uint16_t *) malloc(sizeof (uint16_t) * ((cch - 6) / 2));
  if (rgistd == NULL)
    {
    //wvError ( ("Could not allocate %d\n",  sizeof (uint16_t) * ((cch - 6) / 2)));
    return;
    }
  for (i = 0; i < (cch - 6) / 2; i++)
    {
    rgistd[i] = dread_16ubit (NULL, &pointer);
    (*pos) += 2;
    }
      }
    else
	rgistd = NULL;
    /* First check if pap.istd is greater than the istdFirst recorded in the sprm
       and less than or equal to the istdLast recorded in the sprm If not, the sprm
       has no effect. If it is, pap.istd is set to rgistd[pap.istd - istdFirst] */

    if ((apap->istd > istdFirst) && (apap->istd <= istdLast))
	{
	wvTrace (("%d %d %d\n", apap->istd, istdFirst, istdLast));
	apap->istd = rgistd[apap->istd - istdFirst];
	}
  free (rgistd);
}


static void wvApplysprmPIncLvl (PAP * apap, uint8_t * pointer, uint16_t * pos)
{
uint8_t temp8;
int8_t tempS8;
    temp8 = bread_8ubit (pointer, pos);
    /*
       If pap.stc is < 1 or > 9, sprmPIncLvl has no effect. Otherwise, if the value
       stored in the byte has its highest order bit off, the value is a positive
       difference which should be added to pap.istd and pap.lvl and then pap.stc
       should be set to min(pap.istd, 9). If the byte value has its highest order
       bit on, the value is a negative difference which should be sign extended to
       a word and then subtracted from pap.istd and pap.lvl. Then pap.stc should be
       set to max(1, pap.istd).

       Now... hang on a sec coz

       Note that the storage and behavior of styles has changed radically since
       Word 2 for Windows, beginning with nFib 63. Some of the differences are:
       <chomp>
       * The style code is called an istd, rather than an stc.

       So, for the purposes of this filter, we ignore the stc component of the
       instructions

     */

    if ((apap->istd < 1) || (apap->istd > 9))
	return;

    if ((temp8 & 0x80) >> 7 == 0)
      {
	  apap->istd += temp8;
	  apap->lvl += temp8;
	  /*
	     apap->stc = min(apap->istd, 9);
	   */
      }
    else
      {
	  tempS8 = (int8_t)temp8;
	  apap->istd += tempS8;
	  apap->lvl += tempS8;
	  /*
	     apap->stc = max(1, apap->istd);
	   */
      }
}


static void wvApplysprmPChgTabsPapx (PAP * apap, uint8_t * pointer, uint16_t * pos)
{
int16_t temp_rgdxaTab[itbdMax];
TBD temp_rgtbd[itbdMax];
int i, j, k = 0;
uint8_t itbdDelMax, cch;
int16_t *rgdxaDel;
uint8_t itbdAddMax;
int16_t *rgdxaAdd;
int add = 0;
TBD *rgtbdAdd;
#ifdef DEBUG
int oldpos;
    oldpos = *pos;
#endif

    cch = dread_8ubit (NULL, &pointer);
    (*pos)++;
    itbdDelMax = dread_8ubit (NULL, &pointer);
    (*pos)++;
    if (itbdDelMax != 0)
      {
	  rgdxaDel = (int16_t *) malloc(sizeof (uint16_t) * itbdDelMax);
	  for (i = 0; i < itbdDelMax; i++)
	    {
		rgdxaDel[i] = (int16_t) dread_16ubit (NULL, &pointer);
		(*pos) += 2;
	    }
      }
    else
	rgdxaDel = NULL;
    itbdAddMax = dread_8ubit (NULL, &pointer);
    wvTrace (("itbdAddMax is %d\n", itbdAddMax));
    (*pos)++;
    if (itbdAddMax != 0)
      {
	  rgdxaAdd = (int16_t *)malloc(sizeof (uint16_t) * itbdAddMax);
	  for (i = 0; i < itbdAddMax; i++)
	    {
		rgdxaAdd[i] = (int16_t) dread_16ubit (NULL, &pointer);
		wvTrace (("stops are %d\n", rgdxaAdd[i]));
		(*pos) += 2;
	    }
	  rgtbdAdd = (TBD *)malloc(itbdAddMax * sizeof (TBD));
	  for (i = 0; i < itbdAddMax; i++)
	    {
		wvGetTBDFromBucket(&rgtbdAdd[i], pointer);
		(*pos)++;
	    }
      }
    else
      {
	  rgdxaAdd = NULL;
	  rgtbdAdd = NULL;
      }

/*
#ifdef DEBUG
    if (*pos - oldpos != cch + 1)
	fprintf(cq->log,_("Offset Problem in wvApplysprmPChgTabsPapx\n"));
#endif
*/
    /*
       When sprmPChgTabsPapx is interpreted, the rgdxaDel of the sprm is applied
       first to the pap that is being transformed. This is done by deleting from
       the pap the rgdxaTab entry and rgtbd entry of any tab whose rgdxaTab value
       is equal to one of the rgdxaDel values in the sprm. It is guaranteed that
       the entries in pap.rgdxaTab and the sprm's rgdxaDel and rgdxaAdd are
       recorded in ascending dxa order.

       Then the rgdxaAdd and rgtbdAdd entries are merged into the pap's rgdxaTab
       and rgtbd arrays so that the resulting pap rgdxaTab is sorted in ascending
       order with no duplicates.
     */
    for (j = 0; j < apap->itbdMac; j++)
      {
	  add = 1;
	  for (i = 0; i < itbdDelMax; i++)
	    {
		if (rgdxaDel[i] == apap->rgdxaTab[j])
		  {
		      add = 0;
		      break;
		  }
	    }
	  if (add)
	    {
		temp_rgdxaTab[k] = apap->rgdxaTab[j];
		wvCopyTBD (&temp_rgtbd[k++], &apap->rgtbd[j]);
	    }
      }
    /*temp_rgdxaTab now contains all the tab stops to be retained after the delete */
    apap->itbdMac = k;
    k = 0;
    j = 0;
    i = 0;
    while ((j < apap->itbdMac) || (i < itbdAddMax))
      {
#if 0
	  wvTrace (("i %d j apap->itbdMac %d %d\n", i, j, apap->itbdMac));
	  wvTrace (("temp_rgdxaTab[j] %d\n", temp_rgdxaTab[j]));
	  wvTrace (("rgdxaAdd[i] %d\n", rgdxaAdd[i]));
#endif
	  if ((j < apap->itbdMac)
	      && (i >= itbdAddMax || temp_rgdxaTab[j] < rgdxaAdd[i]))
	    {
		/* if we have one from the retained group that should be added */
		apap->rgdxaTab[k] = temp_rgdxaTab[j];
		wvCopyTBD (&apap->rgtbd[k++], &temp_rgtbd[j++]);
	    }
	  else if ((j < apap->itbdMac) && (temp_rgdxaTab[j] == rgdxaAdd[i]))
	    {
		/* if we have one from the retained group that should be added
		   which is the same as one from the new group */
		apap->rgdxaTab[k] = rgdxaAdd[i];
		wvCopyTBD (&apap->rgtbd[k++], &rgtbdAdd[i++]);
		j++;
	    }
	  else			/*if (i < itbdAddMax) */
	    {
		/* if we have one from the new group to be added */
		apap->rgdxaTab[k] = rgdxaAdd[i];
		wvCopyTBD (&apap->rgtbd[k++], &rgtbdAdd[i++]);
	    }
      }
    wvTrace (("k is %d\n", k));

    apap->itbdMac = k;

    for (i = 0; i < apap->itbdMac; i++)
      {
      wvTrace (("tab %d rgdxa %d %x\n", i, apap->rgdxaTab[i],apap->rgdxaTab[i]));
      }

    free (rgtbdAdd);
    free (rgdxaAdd);
    free (rgdxaDel);
}


static int wvApplysprmPChgTabs (PAP * apap, uint8_t * pointer, uint16_t * pos)
{
int16_t temp_rgdxaTab[itbdMax];
TBD temp_rgtbd[itbdMax];
uint8_t cch;
uint8_t itbdDelMax;
int16_t *rgdxaDel;
int16_t *rgdxaClose;
uint8_t itbdAddMax;
int16_t *rgdxaAdd;
TBD *rgtbdAdd;
int add = 0;
uint8_t i, j, k = 0;

    wvTrace (("entering wvApplysprmPChgTabs\n"));
    /*
       itbdDelMax and itbdAddMax are defined to be equal to 50. This means that the
       largest possible instance of sprmPChgTabs is 354. When the length of the
       sprm is greater than or equal to 255, the cch field will be set equal to
       255. When cch == 255, the actual length of the sprm can be calculated as
       follows: length = 2 + itbdDelMax * 4 + itbdAddMax * 3.
     */

    cch = dread_8ubit (NULL, &pointer);
    wvTrace (("cch is %d\n", cch));
    (*pos)++;
    itbdDelMax = dread_8ubit (NULL, &pointer);
    (*pos)++;

    wvTrace (("itbdDelMax is %d\n", itbdDelMax));
    if (itbdDelMax != 0)
      {
	  rgdxaDel = (int16_t *)malloc(sizeof (int16_t) * itbdDelMax);
	  rgdxaClose = (int16_t *)malloc(sizeof (int16_t) * itbdDelMax);
	  for (i = 0; i < itbdDelMax; i++)
	    {
		rgdxaDel[i] = (int16_t) dread_16ubit (NULL, &pointer);
		(*pos) += 2;
	    }
	  for (i = 0; i < itbdDelMax; i++)
	    {
		rgdxaClose[i] = dread_16ubit (NULL, &pointer);
		(*pos) += 2;
	    }
      }
    else
      {
	  rgdxaDel = NULL;
	  rgdxaClose = NULL;
      }
    itbdAddMax = dread_8ubit (NULL, &pointer);
    wvTrace (("itbdAddMax is %d\n", itbdAddMax));
    (*pos)++;
    if (itbdAddMax != 0)
      {
	  rgdxaAdd = (int16_t *)malloc(sizeof (int16_t) * itbdAddMax);
	  rgtbdAdd = (TBD *)malloc(itbdAddMax * sizeof (TBD));
	  for (i = 0; i < itbdAddMax; i++)
	    {
		rgdxaAdd[i] = (int16_t) dread_16ubit (NULL, &pointer);
		wvTrace (("rgdxaAdd %d is %x\n", i, rgdxaAdd[i]));
		(*pos) += 2;
	    }
	  for (i = 0; i < itbdAddMax; i++)
	    {
		wvGetTBDFromBucket (&rgtbdAdd[i], pointer);
		(*pos)++;
	    }
      }
    else
      {
	  rgdxaAdd = NULL;
	  rgtbdAdd = NULL;
      }

    if (cch == 225)
	cch = 2 + itbdDelMax * 4 + itbdAddMax * 3;

    /* When sprmPChgTabs is interpreted, the rgdxaDel of the sprm is applied first
       to the pap that is being transformed. This is done by deleting from the pap
       the rgdxaTab entry and rgtbd entry of any tab whose rgdxaTab value is within
       the interval [rgdxaDel[i] - rgdxaClose[i], rgdxaDel[i] + rgdxaClose[i]] It
       is guaranteed that the entries in pap.rgdxaTab and the sprm's rgdxaDel and
       rgdxaAdd are recorded in ascending dxa order.

       Then the rgdxaAdd and rgtbdAdd entries are merged into the pap's rgdxaTab
       and rgtbd arrays so that the resulting pap rgdxaTab is sorted in ascending
       order with no duplicates. */
    if (apap == NULL)
      {
	  free (rgdxaDel);
	  free (rgtbdAdd);
	  free (rgdxaAdd);
	  free (rgdxaClose);
	  return (cch);
      }

    wvTrace (("here %d\n", apap->itbdMac));
    for (j = 0; j < apap->itbdMac; j++)
      {
	  add = 1;
	  for (i = 0; i < itbdDelMax; i++)
	    {
		wvTrace (("examing %x against %x\n", apap->rgdxaTab[j], rgdxaDel[i]));
		if ((apap->rgdxaTab[j] >= rgdxaDel[i] - rgdxaClose[i])
		    && (apap->rgdxaTab[j] <= rgdxaDel[i] + rgdxaClose[i]))
		  {
		      wvTrace (("deleting\n"));
		      add = 0;
		      break;
		  }
	    }
	  if (add)
	    {
		temp_rgdxaTab[k] = apap->rgdxaTab[j];
		wvCopyTBD (&temp_rgtbd[k++], &apap->rgtbd[j]);
	    }
      }
    apap->itbdMac = k;
    wvTrace (("here %d\n", apap->itbdMac));

    k = 0;
    j = 0;
    i = 0;
    while ((j < apap->itbdMac) || (i < itbdAddMax))
      {
	  if ((j < apap->itbdMac)
	      && (i >= itbdAddMax || temp_rgdxaTab[j] < rgdxaAdd[i]))
	    {
		wvTrace (("adding from nondeleted tab stops\n"));
		apap->rgdxaTab[k] = temp_rgdxaTab[j];
		wvCopyTBD (&apap->rgtbd[k++], &temp_rgtbd[j++]);
	    }
	  else if ((j < apap->itbdMac) && (temp_rgdxaTab[j] == rgdxaAdd[i]))
	    {
		wvTrace (("adding from new tab stops\n"));
		apap->rgdxaTab[k] = rgdxaAdd[i];
		wvCopyTBD (&apap->rgtbd[k++], &rgtbdAdd[i++]);
		j++;
	    }
	  else			/*if (i < itbdAddMax) */
	    {
		wvTrace (("adding from new tab stops\n"));
		apap->rgdxaTab[k] = rgdxaAdd[i];
		wvCopyTBD (&apap->rgtbd[k++], &rgtbdAdd[i++]);
	    }
      }

    apap->itbdMac = k;
    wvTrace (("here %d\n", apap->itbdMac));

    for (i = 0; i < apap->itbdMac; i++)
      {
	wvTrace (("tab %d rgdxa %d %x\n", i, apap->rgdxaTab[i], apap->rgdxaTab[i]));
      }

  free (rgdxaDel);
  free (rgtbdAdd);
  free (rgdxaAdd);
  free (rgdxaClose);
    wvTrace (("Exiting Successfully\n"));
  return (cch);
}


static void wvApplysprmPPc (PAP * apap, uint8_t * pointer, uint16_t * pos)
{
uint8_t temp8;
struct _temp {
	unsigned reserved:4;
	unsigned pcVert:2;
	unsigned pcHorz:2;
    } temp;


    temp8 = bread_8ubit (pointer, pos);
#ifdef PURIFY
    temp.pcVert = 0;
    temp.pcHorz = 0;
#endif
    temp.pcVert = (temp8 & 0x0C) >> 4;
    temp.pcHorz = (temp8 & 0x03) >> 6;

    /* sprmPPc is interpreted by moving pcVert to pap.pcVert if pcVert != 3 and by
       moving pcHorz to pap.pcHorz if pcHorz != 3. */

    if (temp.pcVert != 3)
	apap->pcVert = temp.pcVert;
    if (temp.pcHorz != 3)
	apap->pcHorz = temp.pcHorz;
}


static void wvApplysprmPFrameTextFlow (PAP * apap, uint8_t * pointer, uint16_t * pos)
{
    uint16_t temp16 = bread_16ubit (pointer, pos);

    apap->fVertical = temp16 & 0x0001;
    apap->fBackward = (temp16 & 0x0002) >> 1;
    apap->fRotateFont = (temp16 & 0x0004) >> 2;
}


static void wvApplysprmPAnld (int ver, PAP * apap, uint8_t * pointer, uint16_t * pos)
{
  dread_8ubit (NULL, &pointer);
  (*pos)++;
  wvGetANLD_FromBucket (ver, &apap->anld, pointer);
  if (ver == 8) //WORD8)
	(*pos) += cbANLD;
  else
	(*pos) += cb6ANLD;
}


static void wvApplysprmPPropRMark (PAP * apap, uint8_t * pointer, uint16_t * pos)
{
  dread_8ubit (NULL, &pointer);
    /* sprmPPropRMark is interpreted by moving the first parameter
       byte to pap.fPropRMark, the next two bytes to pap.ibstPropRMark, and the
       remaining four bytes to pap.dttmPropRMark. */
  apap->fPropRMark = dread_8ubit (NULL, &pointer);
  (*pos)++;
  apap->ibstPropRMark = dread_16ubit (NULL, &pointer);
  (*pos) += 2;
  wvGetDTTMFromBucket (&apap->dttmPropRMark, pointer);
  (*pos) += 4;
}


static void wvApplysprmPNumRM (PAP * apap, uint8_t * pointer, uint16_t * pos)
{
    dread_8ubit (NULL, &pointer);
    (*pos)++;
    wvGetNUMRMFromBucket (&apap->numrm, pointer);
    (*pos) += cbNUMRM;
}


static void wvApplysprmPHugePapx (PAP * apap, uint8_t * pointer, uint16_t * pos, FILE * data, STSH * stsh)
{
uint32_t offset;
uint16_t len, i, sprm;
uint8_t *grpprl, *pointer2;
    /* sprmPHugePapx is stored in PAPX FKPs in place of the grpprl of a PAPX which
       would otherwise be too big to fit in an FKP (as of this writing, 488 bytes
       is the size of the largest PAPX which can fit in an FKP). The parameter fc
       gives the location of the grpprl in the data stream. The first word at that
       fc counts the number of bytes in the grpprl (not including the byte count
       itself). A sprmPHugePapx should therefore only be found in a PAPX FKP and
       should be the only sprm in that PAPX's grpprl.
     */
    offset = dread_32ubit (NULL, &pointer);
    (*pos) += 4;
    wvTrace (("Offset is %x in data stream\n", offset));
    if (!(data))
      {
	  //wvError (("No data stream!!\n"));
	  return;
      }
    if (0 != fseek(data, offset, SEEK_SET))
      {
	  //wvError (("Couldn't seek data stream!!\n"));
	  apap->fTtp++;
	  return;
      }
    Rd_word(data,&len);
    if (!len)
      {
	  //wvWarning ("sprmPHugePapx len is 0, seems unlikely\n");
	  return;
      }

    grpprl = (uint8_t *)malloc(len);

    for (i = 0; i < len; i++)
	grpprl[i] = fgetc(data);

    i = 0;
    while (i < len - 2)
      {
	  sprm = bread_16ubit (grpprl + i, &i);
#ifdef SPRMTEST
	  wvError (("sprm is %x\n", sprm));
#endif
	  pointer2 = grpprl + i;
	  if (i < len)
	      wvApplySprmFromBucket (8, sprm, apap, NULL, NULL, stsh,
				     pointer2, &i, data);
      }
    free (grpprl);
}


static void wvApplysprmCChs (CHP * achp, uint8_t * pointer, uint16_t * pos)
{
    /* When this sprm is interpreted, the first byte of the operand is moved to
       chp.fChsDiff and the remaining word is moved to chp.chse. */
  achp->fChsDiff = dread_8ubit (NULL, &pointer);
  (*pos)++;
  /*achp->chse ???? */
  /* the doc says to set this, but it doesnt exist anywhere else in the docs */
  dread_16ubit (NULL, &pointer);
  (*pos) += 2;
}


static void wvApplysprmCSymbol(int ver, CHP * achp, uint8_t * pointer, uint16_t * pos)
{
  if (ver == 8) //WORD8)
      {
	  /* Word 8 This sprm's operand is 4 bytes. The first 2 hold the font code; the last 2
	     hold a character specifier. When this sprm is interpreted, the font code is
	     moved to chp.ftcSym and the character specifier is moved to chp.xchSym and
	     chp.fSpec is set to 1.   */
	achp->ftcSym = dread_16ubit (NULL, &pointer);
	(*pos) += 2;
	achp->xchSym = dread_16ubit (NULL, &pointer);
	(*pos) += 2;
	wvTrace (("%d %d\n", achp->ftcSym, achp->xchSym));
	}
    else
	{
	/* Word 6 and 7
	     The length byte recorded at offset 1 in this
	     sprm will always be 3. When this sprm is interpreted the two byte
	     font code recorded at offset 2 is moved to chp.ftcSym, the single
	     byte character specifier recorded at offset 4 is moved to chp.chSym
	     and chp.fSpec is set to 1.   */
	  dread_8ubit (NULL, &pointer);
	  (*pos)++;
	  achp->ftcSym = dread_16ubit (NULL, &pointer);
	  (*pos) += 2;
	  achp->xchSym = dread_8ubit (NULL, &pointer);
	  achp->xchSym += 61440;	/* promote this char into a unicode char to
					   be consistent with what word 8 does */
	  (*pos)++;
      }
    achp->fSpec = 1;
}


static void wvApplysprmCIstdPermute (CHP * achp, uint8_t * pointer, uint16_t * pos)
{
uint8_t cch;
uint8_t fLongg;
uint8_t fSpare;
uint16_t istdFirst;
uint16_t istdLast;
uint16_t *rgistd;
uint16_t i;

    cch = dread_8ubit (NULL, &pointer);
    (*pos)++;
    fLongg = dread_8ubit (NULL, &pointer);
    (*pos)++;
    fSpare = dread_8ubit (NULL, &pointer);
    (*pos)++;
    istdFirst = dread_16ubit (NULL, &pointer);
    (*pos) += 2;
    istdLast = dread_16ubit (NULL, &pointer);
    (*pos) += 2;
    if ((cch - 6) / 2 != 0)
      {
	  rgistd = (uint16_t *)malloc(sizeof (uint16_t) * ((cch - 6) / 2));
	  for (i = 0; i < (cch - 6) / 2; i++)
	    {
		rgistd[i] = dread_16ubit (NULL, &pointer);
		(*pos) += 2;
	    }
      }
    else
	rgistd = NULL;
    /* first check if chp.istd is greater than the
       istdFirst recorded in the sprm and less than or equal to the istdLast
       recorded in the sprm If not, the sprm has no effect. If it is, chp.istd is
       set to rgstd[chp.istd - istdFirst] and any chpx stored in that rgstd entry
       is applied to the chp.

       Note that it is possible that an istd may be recorded in the rgistd that
       refers to a paragraph style. This will no harmful consequences since the
       istd for a paragraph style should never be recorded in chp.istd. */

    if ((achp->istd > istdFirst) && (achp->istd <= istdLast))
      {
	  achp->istd = rgistd[achp->istd - istdFirst];
	  /* if really a chp style
	     wvAddCHPXFromUPEBucket(achp,&(stsh->std[achp->istd].grupe[0].chpx),stsh);
	     else
	     complain;  */
      }
    free (rgistd);
}


static void wvApplysprmCDefault (CHP * achp, uint8_t * pointer, uint16_t * pos)
{
  /* sprmCDefault (opcode 0x2A32) clears the fBold, fItalic, fOutline, fStrike,
     fShadow, fSmallCaps, fCaps, fVanish, kul and ico fields of the chp to 0. It
     was first defined for Word 3.01 and had to be backward compatible with Word
     3.00 so it is a variable length sprm whose count of bytes is 0. It consists
     of the sprmCDefault opcode followed by a byte of 0. */
  dread_8ubit (NULL, &pointer);
  (*pos)++;
  achp->fBold = 0;
  achp->fItalic = 0;
  achp->fOutline = 0;
  achp->fStrike = 0;
  achp->fShadow = 0;
  achp->fSmallCaps = 0;
  achp->fCaps = 0;
  achp->fVanish = 0;
  achp->kul = 0;
  achp->ico = 0;
}


static void wvApplysprmCPlain (CHP * achp, STSH * stsh)
{
uint8_t fSpec;
  /* the style sheet CHP is copied over the original CHP preserving the
       fSpec setting from the original CHP. */
  fSpec = achp->fSpec;
  wvInitCHPFromIstd (achp, achp->istd, stsh);
  achp->fSpec = fSpec;
}


/*
void wvToggle(int ret,CHP *in,STSH *stsh,uint8_t toggle,type)

When the parameter of the sprm is set to 0 or 1, then
the CHP property is set to the parameter value. */

/* When the parameter of the sprm is 128, then the CHP property is set to the
value that is stored for the property in the style sheet. CHP When the
parameter of the sprm is 129, the CHP property is set to the negation of the
value that is stored for the property in the style sheet CHP.
sprmCFBold through sprmCFVanish are stored only in grpprls linked to piece table
entries. */

/* an argument might be made that instead of in being returned or negated that
it should be the looked up in the original chp through the istd that should
be used, in which case this should be a macro that does the right thing.
but im uncertain as to which is the correct one to do, ideas on a postcard
to... etc etc

This argument which i left as a comment to the original function has been
bourne out in practice, so i converted this to a macro and did a lookup
on the original unmodified chp in the stylesheet to check against

Interestingly enough, even though the spec says that these are only used
in piece table grpprls this is untrue, examples/doc-that-needs-utf8.doc
has them in the stylesheet definition portion, which is a serious problem
as the style that must be checked is not generated before this modifier
comes along, a real nuisance. */

#define wvTOGGLE(ret,in,stsh,toggle,type) \
	{ \
	CHP ctemp; \
	if ((toggle == 0) || (toggle == 1))  \
		ret = toggle; \
	else \
		{ \
		\
		wvInitCHPFromIstd(&ctemp,in->istd,stsh); \
	\
		if (toggle == 128) \
			ret = ctemp.type; \
		else if (toggle == 129) \
			ret = !ctemp.type; \
		else \
			{}/*wvWarning("Strangle sprm toggle value, ignoring\n");*/ \
		} \
	}


static void wvApplysprmCSizePos (CHP * achp, uint8_t * pointer, uint16_t * pos)
{
//uint8_t prevhpsPos;
uint16_t temp8;
    struct _temp {
	unsigned hpsSize:8;
	unsigned cInc:7;
	unsigned fAdjust:1;
	unsigned hpsPos:8;
    } temp;

    temp.hpsSize = dread_8ubit (NULL, &pointer);
    (*pos)++;
    temp8 = dread_8ubit (NULL, &pointer);
    (*pos)++;
    temp.cInc = (temp8 & 0x7f) >> 8;
    temp.fAdjust = (temp8 & 0x80) >> 7;
    temp.hpsPos = dread_8ubit (NULL, &pointer);
    (*pos)++;

    /*
       if hpsSize != 0 then chp.hps is set to hpsSize.

       If cInc is != 0, the cInc is interpreted as a 7 bit twos complement
       number and the procedure described below for interpreting sprmCHpsInc is
       followed to increase or decrease the chp.hps by the specified number of
       levels.

       If hpsPos is != 128, then chp.hpsPos is set equal to hpsPos.

       If fAdjust is on , hpsPos != 128 and hpsPos != 0 and the previous value of
       chp.hpsPos == 0, then chp.hps is reduced by one level following the method
       described for sprmCHpsInc.

       If fAdjust is on, hpsPos == 0 and the previous value of chp.hpsPos != 0,
       then the chp.hps value is increased by one level using the method described
       below for sprmCHpsInc.
     */

    if (temp.hpsSize != 0)
	achp->hps = temp.hpsSize;

    if (temp.cInc != 0)
      {
      }

//    prevhpsPos = achp->hpsPos;

    if (temp.hpsPos != 128)
	achp->hpsPos = temp.hpsPos;
#if 0
    /*else ? who knows ? */
    if ((temp.fAdjust) && (temp.hpsPos != 128) && (temp.hpsPos != 0)
	&& (achp->hpsPos == 0))
	/*reduce level */ ;
    if ((temp.fAdjust) && (temp.hpsPos == 0) && (achp->hpsPos != 0))
	/*increase level */ ;
#endif

    /*This depends on an implementation of sprmCHpsInc, read wvApplysprmCHpsInc for
       some comments on the whole matter*/

//    wvError (("This document has an unsupported sprm (sprmCSizePos), please mail "));
//    wvError (("Caolan.McNamara@ul.ie with this document, as i haven't been able to "));
//    wvError (("get any examples of it so as to figure out how to handle it\n"));
}


static void wvApplysprmCHpsInc(uint8_t * pointer) //, uint16_t * pos)
{
//uint8_t param;
 /* sprmCHpsInc(opcode 0x2A44) is a three-byte sprm consisting of the sprm
    opcode and a one-byte parameter.

    Word keeps an ordered array of the font sizes that are defined for the fonts
    recorded in the system file with each font size transformed into an hps.

    The parameter is a one-byte twos complement number. Word uses this number
    to calculate an index in the font size array to determine the new hps for a
    run. When Word interprets this sprm and the parameter is positive, it searches
    the array of font sizes to find the index of the smallest entry in the font
    size table that is greater than the current chp.hps.It then adds the
    parameter minus 1 to the index and maxes this with the index of the last array
    entry. It uses the result as an index into the font size array and assigns that
    entry of the array to chp.hps.

    When the parameter is negative, Word searches the array of font sizes to
    find the index of the entry that is less than or equal to the current
    chp.hps. It then adds the negative parameter to the index and does a min of
    the result with 0. The result of the min function is used as an index into
    the font size array and that entry of the array is assigned to chp.hps.
    sprmCHpsInc is stored only in grpprls linked to piece table entries.  */

    fprintf(stderr,_("This document has an unsupported sprm (sprmCHpsInc), please mail"
		     "Caolan.McNamara@ul.ie with this document, as i haven't been able to "
		     "get any examples of it so as to figure out how to handle it\n"));
//    param =
	dread_8ubit (NULL, &pointer);
 /* Now for christ sake !!, how on earth would i have an "ordered array of the
    font sizes that are defined for the fonts recorded in the system file", that
    sounds to me that i would have to have access to the fonts on the actual
    machine that word was last run on !, it sounds to me that this sprm might only
    be used during the editing of a file, so im going to have to ignore it because
    it complete goobledegook to me  */
}


static void wvApplysprmCHpsPosAdj (CHP * achp, uint8_t * pointer, uint16_t * pos)
{
uint8_t param;
 /* sprmCHpsPosAdj (opcode 0x2A46) causes the hps of a run to be reduced the
    first time text is superscripted or subscripted and causes the hps of a run
    to be increased when superscripting/subscripting is removed from a run.

    The one byte parameter of this sprm is the new hpsPos value that is to be
    stored in chp.hpsPos.

    If the new hpsPos is not equal 0 (meaning that the text is to be super/
    subscripted), Word first examines the current value of chp.hpsPos
    to see if it is equal to 0.

    If so, Word uses the algorithm described for sprmCHpsInc to decrease chp.hps
    by one level.

    If the new hpsPos == 0 (meaning the text is not super/subscripted),
    Word examines the current chp.hpsPos to see if it is not equal to 0. If it is
    not (which means text is being restored to normal position), Word uses the
    sprmCHpsInc algorithm to increase chp.hps by one level.

    After chp.hps is adjusted, the parameter value is stored in chp.hpsPos.  */

//    wvError (("This document has an partially unsupported sprm (sprmCHpsPosAdj), please mail "));
//    wvError (("Caolan.McNamara@ul.ie with this document, as i haven't been able to "));
//    wvError (("get any examples of it so as to figure out how to handle it\n"));

    param = dread_8ubit (NULL, &pointer);
    (*pos)++;

    /* please see wvApplysprmCHpsInc for why this is unfinished */

#if 0
    if ((param != 0) && (achp->hpsPos == 0))
	/*decrease chp.hps */ ;
    else if ((param == 0) && (achp->hpsPos != 0))
	/*increase chp.hps */ ;
#endif

    achp->hpsPos = param;
}


static void wvApplysprmCMajority (CHP * achp, STSH * stsh, uint8_t * pointer, uint16_t * pos)
{
uint16_t i;
CHP base;
CHP orig;
UPXF upxf;
    /* Bytes 0 and 1 of
       sprmCMajority contains the opcode, byte 2 contains the length of the
       following list of character sprms. . Word begins interpretation of this sprm
       by applying the stored character sprm list to a standard chp. That chp has
       chp.istd = istdNormalChar. chp.hps=20, chp.lid=0x0400 and chp.ftc = 4. Word
       then compares fBold, fItalic, fStrike, fOutline, fShadow, fSmallCaps, fCaps,
       ftc, hps, hpsPos, kul, qpsSpace and ico in the original CHP with the values
       recorded for these fields in the generated CHP.. If a field in the original
       CHP has the same value as the field stored in the generated CHP, then that
       field is reset to the value stored in the style's CHP. If the two copies
       differ, then the original CHP value is left unchanged. */
    wvTrace (("This document has a sprm (sprmCMajority), that ive never seen in practice please mail "));
    wvTrace (("Caolan.McNamara@ul.ie with this document, as i haven't been able to "));
    wvTrace (("get any examples of it so as to figure out if its handled correctly\n"));

    wvInitCHP (&base);
    base.ftc = 4;

    /*generate a UPE and run wvAddCHPXFromBucket */

    upxf.cbUPX = dread_8ubit (NULL, &pointer);
    (*pos)++;
    upxf.upx.chpx.grpprl = (uint8_t *)malloc(upxf.cbUPX);

    for (i = 0; i < upxf.cbUPX; i++)
      {
	  upxf.upx.chpx.grpprl[i] = dread_8ubit (NULL, &pointer);
	  (*pos)++;
      }

    wvTrace (("achp istd is %d\n", achp->istd));

    wvAddCHPXFromBucket (&base, &upxf, stsh);

    wvTrace (("achp istd is %d\n", achp->istd));
    wvTrace (("my underline started as %d\n", achp->kul));

    wvInitCHPFromIstd (&orig, achp->istd, stsh);

    /* this might be a little wrong, review after doing dedicated CHP's */
    if (achp->fBold == base.fBold)
	achp->fBold = orig.fBold;
    if (achp->fItalic == base.fItalic)
	achp->fItalic = orig.fItalic;
    if (achp->fStrike == base.fStrike)
	achp->fStrike = orig.fStrike;
    if (achp->fOutline == base.fOutline)
	achp->fOutline = orig.fOutline;
    if (achp->fShadow == base.fShadow)
	achp->fShadow = orig.fShadow;
    if (achp->fSmallCaps == base.fSmallCaps)
	achp->fSmallCaps = orig.fSmallCaps;
    if (achp->fCaps == base.fCaps)
	achp->fCaps = orig.fCaps;
    if (achp->ftc == base.ftc)
	achp->ftc = orig.ftc;
    if (achp->hps == base.hps)
	achp->hps = orig.hps;
    if (achp->hpsPos == base.hpsPos)
	achp->hpsPos = orig.hpsPos;
    if (achp->kul == base.kul)
	achp->kul = orig.kul;
    /* ????
       if (achp->qpsSpace == base.qpsSpace)
       achp->qpsSpace = orig.qpsSpace;
     */
    if (achp->ico == base.ico)
	achp->ico = orig.ico;

    /* these ones are mentioned in a different part of the spec, that
       doesnt have as much weight as the above, but i'm going to add them
       anyway */
    if (achp->fVanish == base.fVanish)
	achp->fVanish = orig.fVanish;
    wvTrace (("%d\n", base.dxaSpace));
    wvTrace (("%d\n", achp->dxaSpace));
    if (achp->dxaSpace == base.dxaSpace)
	achp->dxaSpace = orig.dxaSpace;
    if (achp->lidDefault == base.lidDefault)
	achp->lidDefault = orig.lidDefault;
    if (achp->lidFE == base.lidFE)
	achp->lidFE = orig.lidFE;
    free (upxf.upx.chpx.grpprl);

    wvTrace (("my underline ended as %d\n", achp->kul));
}


static void wvApplysprmCHpsInc1 (CHP * achp, uint8_t * pointer, uint16_t * pos)
{
  /* This sprm is interpreted by adding the two byte increment
     stored as the opcode of the sprm to chp.hps. If this result is less than 8,
     the chp.hps is set to 8. If the result is greater than 32766, the chp.hps is
     set to 32766.  */
  dread_8ubit (NULL, &pointer);
  (*pos)++;
  achp->hps += dread_16ubit (NULL, &pointer);
  (*pos) += 2;
  if (achp->hps < 8)
      achp->hps = 8;
  else if (achp->hps > 32766)
      achp->hps = 32766;
}


static void wvApplysprmCMajority50 (CHP * achp, STSH * stsh, uint8_t * pointer, uint16_t * pos)
{
uint16_t i;
CHP base;
CHP orig;
UPXF upxf;
/* Bytes 0 and 1 of
   sprmCMajority contains the opcode, byte 2 contains the length of the
   following list of character sprms. . Word begins interpretation of this sprm
   by applying the stored character sprm list to a standard chp. That chp has
   chp.istd = istdNormalChar. chp.hps=20, chp.lid=0x0400 and chp.ftc = 4. Word
   then compares fBold, fItalic, fStrike, fOutline, fShadow, fSmallCaps, fCaps,
   ftc, hps, hpsPos, kul, qpsSpace and ico in the original CHP with the values
   recorded for these fields in the generated CHP.. If a field in the original
   CHP has the same value as the field stored in the generated CHP, then that
   field is reset to the value stored in the style's CHP. If the two copies
   differ, then the original CHP value is left unchanged. */
   wvTrace(("This document has a sprm (sprmCMajority50), that ive never seen in practice please mail "));
   wvTrace(("Caolan.McNamara@ul.ie with this document, as i haven't been able to "));
   wvTrace (("get any examples of it so as to figure out if its handled correctly\n"));

   wvInitCHP (&base);
   base.ftc = 4;

    /*generate a UPE and run wvAddCHPXFromBucket */

    upxf.cbUPX = dread_8ubit (NULL, &pointer);
    (*pos)++;
    upxf.upx.chpx.grpprl = (uint8_t *)malloc(upxf.cbUPX);

    for (i = 0; i < upxf.cbUPX; i++)
	{
	upxf.upx.chpx.grpprl[i] = dread_8ubit (NULL, &pointer);
	(*pos)++;
	}

    wvAddCHPXFromBucket (&base, &upxf, stsh);

    wvInitCHPFromIstd (&orig, achp->istd, stsh);

    /* this might be a little wrong, review after doing dedicated CHP's */
    wvTrace (("istd is %d\n", achp->istd));
    if (achp->fBold == base.fBold)
	achp->fBold = orig.fBold;
    if (achp->fItalic == base.fItalic)
	achp->fItalic = orig.fItalic;
    if (achp->fStrike == base.fStrike)
	achp->fStrike = orig.fStrike;
    if (achp->fSmallCaps == base.fSmallCaps)
	achp->fSmallCaps = orig.fSmallCaps;
    if (achp->fCaps == base.fCaps)
	achp->fCaps = orig.fCaps;
    if (achp->ftc == base.ftc)
	achp->ftc = orig.ftc;
    if (achp->hps == base.hps)
	achp->hps = orig.hps;
    if (achp->hpsPos == base.hpsPos)
	achp->hpsPos = orig.hpsPos;
    if (achp->kul == base.kul)
	achp->kul = orig.kul;
    if (achp->ico == base.ico)
	achp->ico = orig.ico;
    if (achp->fVanish == base.fVanish)
	achp->fVanish = orig.fVanish;
    if (achp->dxaSpace == base.dxaSpace)
	achp->dxaSpace = orig.dxaSpace;

    free (upxf.upx.chpx.grpprl); /* this seemed to be missing... */
}


static void wvGetSprmFromU16 (Sprm * aSprm, uint16_t sprm)
{
#ifdef PURIFY
    wvInitSprm (aSprm);
#endif
    aSprm->ispmd = sprm & 0x01ff;
    aSprm->fSpec = (sprm & 0x0200) >> 9;
    aSprm->sgc = (sprm & 0x1c00) >> 10;
    aSprm->spra = (sprm & 0xe000) >> 13;
}


/* spra value operand size
   0          1 byte (operand affects 1 bit)
   1          1 byte
   2          2 bytes
   3          4 bytes
   4          2 bytes
   5          2 bytes
   6          variable length -- following byte is size of operand
   7          3 bytes	*/
static int wvSprmLen(int spra)
{
  switch (spra)
      {
      case 0:
      case 1: return (1);
      case 2:
      case 4:
      case 5: return (2);
      case 7: return (3);
      case 3: return (4);
      case 6: return (-1);
		  /*variable length -- following byte is size of operand */
      default:
//	  wvError (("Incorrect spra value %d\n", spra));
		{}
      }
    return (-2);
}


static uint8_t wvEatSprm (uint16_t sprm, uint8_t * pointer, uint16_t * pos)
{
    int len;
    Sprm aSprm;
    wvTrace (("Eating sprm %x\n", sprm));
    wvGetSprmFromU16 (&aSprm, sprm);
    if (sprm == sprmPChgTabs)
      {
	  wvTrace (("sprmPChgTabs\n"));
	  len = wvApplysprmPChgTabs (NULL, pointer, pos);
	  len++;
	  return (len);
      }
    else if ((sprm == sprmTDefTable) || (sprm == sprmTDefTable10))
      {
	  wvTrace (("sprmTDefTable\\sprmTDefTable10\n"));
	  len = bread_16ubit (pointer, pos);
	  len--;
      }
    else
      {
	  len = wvSprmLen (aSprm.spra);
	  wvTrace (("wvSprmLen len is %d\n", len));
	  if (len < 0)
	    {
		len = bread_8ubit (pointer, pos);
		len++;
	    }
      }
    (*pos) += len;
    return (len);
}


static void wvApplysprmCPropRMark(CHP * achp, uint8_t * pointer, uint16_t * pos)
{
  dread_8ubit (NULL, &pointer);	/*len */
  (*pos)++;
  achp->fPropRMark = dread_8ubit (NULL, &pointer);
  (*pos)++;
  achp->ibstPropRMark = (int16_t)dread_16ubit(NULL, &pointer);
  (*pos) += 2;
  wvGetDTTMFromBucket (&achp->dttmPropRMark, pointer);
  (*pos) += 4;
}


static void wvApplysprmCDispFldRMark(CHP * achp, uint8_t * pointer, uint16_t * pos)
{
/* is interpreted by moving the first
   parameter byte to chp.fDispFldRMark, the next two bytes to
   chp.ibstDispFldRMark, the next four bytes to chp.dttmDispFldRMark,
   and the remaining 32 bytes to chp.xstDispFldRMark. */
int i;
  dread_8ubit (NULL, &pointer);	/*len */
  (*pos)++;
  achp->fDispFldRMark = dread_8ubit (NULL, &pointer);
  (*pos)++;
  achp->ibstDispFldRMark = (int16_t)dread_16ubit (NULL, &pointer);
  (*pos) += 2;
  wvGetDTTMFromBucket (&achp->dttmDispFldRMark, pointer);
  (*pos) += 4;
  pointer += 4;
  for (i = 0; i < 16; i++)
    {
	achp->xstDispFldRMark[i] = dread_16ubit (NULL, &pointer);
	(*pos) += 2;
    }
}


static void wvApplysprmSPropRMark(SEP * asep, uint8_t * pointer, uint16_t * pos)
{
  dread_8ubit (NULL, &pointer);
  (*pos)++;
  /*
     sprmPPropRMark is interpreted by moving the first parameter
     byte to pap.fPropRMark, the next two bytes to pap.ibstPropRMark, and the
     remaining four bytes to pap.dttmPropRMark.
   */
  asep->fPropRMark = dread_8ubit (NULL, &pointer);
  (*pos)++;
  asep->ibstPropRMark = dread_16ubit (NULL, &pointer);
  (*pos) += 2;
  wvGetDTTMFromBucket (&asep->dttmPropRMark, pointer);
  (*pos) += 4;
}


/* sprmTDxaLeft (opcode 0x9601) is called to adjust the x position within a
column which marks the left boundary of text within the first cell of a
table row. This sprm causes a whole table row to be shifted left or right
within its column leaving the horizontal width and vertical height of cells
in the row unchanged. Bytes 0-1 of the sprm contains the opcode, and the new
dxa position, call it dxaNew, is stored as an integer in bytes 2 and 3. Word
interprets this sprm by adding dxaNew - (rgdxaCenter[0] + tap.dxaGapHalf) to
every entry of tap.rgdxaCenter whose index is less than tap.itcMac.
sprmTDxaLeft is stored only in grpprls linked to piece table entries. */
static void wvApplysprmTDxaLeft (TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
  int16_t dxaNew = (int16_t) dread_16ubit (NULL, &pointer);
  int i;
  (*pos) += 2;
  dxaNew = dxaNew - (aTap->rgdxaCenter[0] + aTap->dxaGapHalf);
  for (i = 0; i < aTap->itcMac; i++)
      aTap->rgdxaCenter[i] += dxaNew;
}


/* sprmTDxaGapHalf (opcode 0x9602) adjusts the white space that is maintained
between columns by changing tap.dxaGapHalf. Because we want the left
boundary of text within the leftmost cell to be at the same location after
the sprm is applied, Word also adjusts tap.rgdxCenter[0] by the amount that
tap.dxaGapHalf changes. Bytes 0-1 of the sprm contains the opcode, and the
new dxaGapHalf, call it dxaGapHalfNew, is stored in bytes 2 and 3. When the
sprm is interpreted, the change between the old and new dxaGapHalf values,
tap.dxaGapHalf - dxaGapHalfNew, is added to tap.rgdxaCenter[0] and then
dxaGapHalfNew is moved to tap.dxaGapHalf. sprmTDxaGapHalf is stored in PAPXs
and also in grpprls linked to piece table entries.	*/
static void wvApplysprmTDxaGapHalf (TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
  int16_t dxaGapHalfNew = (int16_t) dread_16ubit (NULL, &pointer);
  (*pos) += 2;
  aTap->rgdxaCenter[0] += aTap->dxaGapHalf - dxaGapHalfNew;
  aTap->dxaGapHalf = dxaGapHalfNew;
}


static void wvApplysprmSOlstAnm (int ver, SEP * asep, uint8_t * pointer, uint16_t * pos)
{
  uint8_t len = dread_8ubit (NULL, &pointer);
  wvGetOLSTFromBucket (ver, &asep->olstAnm, pointer);
//  if (len != cbOLST)
//      wvError (("OLST len is different from expected\n"));
  (*pos) += len;
}


/* sprmTTableBorders (opcode 0xD605) sets the tap.rgbrcTable. The sprm is
interpreted by moving the 24 bytes of the sprm's operand to tap.rgbrcTable. */
static void wvApplysprmTTableBorders (int ver, TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
int i, d;
  if (ver == 8)
    {
	dread_8ubit (NULL, &pointer);
	(*pos)++;
    }
  for (i = 0; i < 6; i++)
    {
	d = wvGetBRCFromBucket (ver, &(aTap->rgbrcTable[i]), pointer);
	pointer += d;
	(*pos) += d;
    }
}


/* sprmTDefTable10 (opcode0xD606) is an obsolete version of sprmTDefTable
(opcode 0xD608) that was used in WinWord 1.x. Its contents are identical to
those in sprmTDefTable, except that the TC structures contain the obsolete
structures BRC10s. */
static void wvApplysprmTDefTable10 (TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
uint16_t len;
int i, t;
  len = dread_16ubit (NULL, &pointer);
  (*pos) += 2;
  aTap->itcMac = dread_8ubit (NULL, &pointer);
  (*pos)++;
  for (i = 0; i < aTap->itcMac + 1; i++)
    {
	aTap->rgdxaCenter[i] = (int16_t) dread_16ubit (NULL, &pointer);
	(*pos) += 2;
    }
  for (i = 0; i < aTap->itcMac; i++)
    {
	t = wvGetTCFromBucket (6, &(aTap->rgtc[i]), pointer);
	(*pos) += t;
	pointer += t;
    }
}


/* sprmTDefTable (opcode 0xD608) defines the boundaries of table cells
(tap.rgdxaCenter) and the properties of each cell in a table (tap.rgtc).
Bytes 0 and 1 of the sprm contain its opcode. Bytes 2 and 3 store a two-byte
length of the following parameter. Byte 4 contains the number of cells that
are to be defined by the sprm, call it itcMac. When the sprm is interpreted,
itcMac is moved to tap.itcMac. itcMac cannot be larger than 32. In bytes 5
through 5+2*(itcMac + 1) -1 , is stored an array of integer dxa values
sorted in ascending order which will be moved to tap.rgdxaCenter. In bytes
5+ 2*(itcMac + 1) through byte 5+2*(itcMac + 1) + 10*itcMac - 1 is stored an
array of TC entries corresponding to the stored tap.rgdxaCenter. This array
is moved to tap.rgtc. sprmTDefTable is only stored in PAPXs. */
static void wvApplysprmTDefTable (TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
uint16_t len;
int i, t, oldpos;
int type;
  len = dread_16ubit (NULL, &pointer);
  (*pos) += 2;
  wvTrace (("wvApplysprmTDefTable\n"));
  aTap->itcMac = dread_8ubit (NULL, &pointer);
  (*pos)++;
  oldpos = (*pos) - 2;
  wvTrace (("oldpos is %x\n", oldpos));
  wvTrace (("C: there are %d cells\n", aTap->itcMac));
  for (i = 0; i < aTap->itcMac + 1; i++)
    {
	aTap->rgdxaCenter[i] = (int16_t) dread_16ubit (NULL, &pointer);
	wvTrace (("C: cell boun is %d\n", aTap->rgdxaCenter[i]));
	(*pos) += 2;
    }

  wvTrace (("HERE-->pos is now %d, the len was %d, there is %d left\n",
	    *pos, len, len - (*pos - oldpos)));

  if ((len - (*pos - oldpos)) < (cb6TC * aTap->itcMac))
    {
	pointer += len - (*pos - oldpos);
	(*pos) += len - (*pos - oldpos);
	return;
    }

  if ((len - (*pos - oldpos)) < (cbTC * aTap->itcMac))
      type = 6;
  else
      type = 8;

  wvTrace (("type is %d\n", type));

  wvTrace (("left over is %d\n", len - (*pos - oldpos)));

  for (i = 0; i < aTap->itcMac; i++)
    {
	t = wvGetTCFromBucket (type, &(aTap->rgtc[i]), pointer);
	wvTrace (("DefTable merge is %d\n", aTap->rgtc[i].fVertMerge));
	/* for christ sake !!, word 8 stores word 6 sized TC's in this sprm ! */
	(*pos) += t;
	pointer += t;
	wvTrace (("t is %d, under is %x\n", t, *pointer));
    }

  wvTrace (("left over is %d\n", len - (*pos - oldpos)));

  while (len - (*pos - oldpos))
    {
	wvTrace (("Eating byte %x\n", dread_8ubit (NULL, &pointer)));
	(*pos)++;
    }
  wvTrace (("oldpos is %x, pos is %x, diff is %d\n", oldpos, *pos,*pos - oldpos - 2));
}



/*
Word 8

sprmTSetBrc (opcode 0xD620) allows the border definitions(BRCs) within TCs
to be set to new values. It has the following format:

 b10 b16 field          type  size bitfield comments

 0   0   sprm           short               opcode 0xD620

 2   2   count          byte                number of bytes for operand

 3   3   itcFirst       byte                the index of the first cell
					    that is to have its borders
					    changed.

 4   4   itcLim         byte                index of the cell that follows
					    the last cell to have its
					    borders changed

 5   5                  short :4   F0       reserved

	 fChangeRight   short :1   08       =1 when tap.rgtc[].brcRight is
					    to be changed

	 fChangeBottom  short :1   04       =1 when tap.rgtc[].brcBottom
					    is to be changed

	 fChangeLeft    short :1   02       =1 when tap.rgtc[].brcLeft is
					    to be changed

	 fChangeTop     short :1   01       =1 when tap.rgtc[].brcTop is
					    to be changed

 6   6   brc            BRC                 new BRC value to be stored in
					    TCs.

*/
/* Pre Word 8 *
0    0    	sprm byte opcode 193
1    1    	itcFirst  byte
2    2    	itcLim    byte
3    3         int  :4 F0   reserved
			fChangeRight int  :1   08
			fChangeBottom int  :1   04
			fChangeLeft int  :1   02
			fChangeTop int  :1   01
	4    4  brc  BRC
*/
static void wvApplysprmTSetBrc(int ver, TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
uint8_t itcFirst, itcLim, len, temp8;
BRC abrc;
int i;
  if (ver == 8)
    {
	len = dread_8ubit (NULL, &pointer);
	(*pos)++;
	wvTrace (("the len is %d", len));
    }
  itcFirst = dread_8ubit (NULL, &pointer);
  itcLim = dread_8ubit (NULL, &pointer);
  temp8 = dread_8ubit (NULL, &pointer);
  (*pos) += 3;
  (*pos) += wvGetBRCFromBucket (ver, &abrc, pointer);

  for (i = itcFirst; i < itcLim; i++)
    {
	if (temp8 & 0x08)
	    wvCopyBRC (&aTap->rgtc[i].brcRight, &abrc);
	if (temp8 & 0x04)
	    wvCopyBRC (&aTap->rgtc[i].brcBottom, &abrc);
	if (temp8 & 0x02)
	    wvCopyBRC (&aTap->rgtc[i].brcLeft, &abrc);
	if (temp8 & 0x01)
	    wvCopyBRC (&aTap->rgtc[i].brcTop, &abrc);
    }
}


/*sprmTInsert (opcode 0x7621) inserts new cell definitions in an existing
table's cell structure.

Bytes 0 and 1 of the sprm contain the opcode.

Byte 2 is the index within tap.rgdxaCenter and tap.rgtc at which the new dxaCenter
and tc values will be inserted. Call this index itcInsert.

Byte 3 contains a count of the cell definitions to be added to the tap, call it ctc.

Bytes 4 and 5 contain the width of the cells that will be added, call it dxaCol.

If there are already cells defined at the index where cells are to be inserted,
tap.rgdxaCenter entries at or above this index must be moved to the entry
ctc higher and must be adjusted by adding ctc*dxaCol to the value stored.

The contents of tap.rgtc at or above the index must be moved 10*ctc bytes
higher in tap.rgtc.

If itcInsert is greater than the original tap.itcMac, itcInsert - tap.ctc columns
beginning with index tap.itcMac must be added of width dxaCol
(loop from itcMac to itcMac+itcInsert-tap.ctc adding dxaCol to the rgdxaCenter
value of the previous entry and storing sum as dxaCenter of new entry),
whose TC entries are cleared to zeros.

Beginning with index itcInsert, ctc columns of width dxaCol must be added by
constructing new tap.rgdxaCenter and tap.rgtc entries with the newly defined
rgtc entries cleared to zeros.

Finally, the number of cells that were added to the tap is added to tap.itcMac.

sprmTInsert is stored only in grpprls linked to piece table entries. */
static void wvApplysprmTInsert (TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
uint8_t itcInsert = dread_8ubit (NULL, &pointer);
uint8_t ctc = dread_8ubit (NULL, &pointer);
int16_t dxaCol = (int16_t) dread_16ubit (NULL, &pointer);
int i;
  (*pos) += 4;

  if (itcInsert <= aTap->itcMac + 1)
    {
	for (i = aTap->itcMac + 1; i >= itcInsert; i--)
	  {
	      aTap->rgdxaCenter[i + ctc] =
		  aTap->rgdxaCenter[i] + ctc * dxaCol;
	      aTap->rgtc[i + ctc] = aTap->rgtc[i];
	  }
    }

  if (itcInsert > aTap->itcMac)
    {
	for (i = aTap->itcMac; i < aTap->itcMac + itcInsert - ctc; i++)
	  {
	      aTap->rgdxaCenter[i] = aTap->rgdxaCenter[i - 1] + dxaCol;
	      wvInitTC (&(aTap->rgtc[i]));
	  }
    }

  for (i = itcInsert; i < ctc + itcInsert; i++)
    {
	aTap->rgdxaCenter[i] = aTap->rgdxaCenter[i - 1] + dxaCol;
	wvInitTC (&(aTap->rgtc[i]));
    }

  aTap->itcMac += ctc;
}


/* sprmTDelete (opcode 0x5622) deletes cell definitions from an existing
table's cell structure. Bytes 0 and 1of the sprm contain the opcode. Byte 2
contains the index of the first cell to delete, call it itcFirst. Byte 3
contains the index of the cell that follows the last cell to be deleted,
call it itcLim. sprmTDelete causes any rgdxaCenter and rgtc entries whose
index is greater than or equal to itcLim to be moved to the entry that is
itcLim - itcFirst lower, and causes tap.itcMac to be decreased by the number
of cells deleted. sprmTDelete is stored only in grpprls linked to piece
table entries. */
static void wvApplysprmTDelete (TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
    uint8_t itcFirst = dread_8ubit (NULL, &pointer);
    uint8_t itcLim = dread_8ubit (NULL, &pointer);
    int i;
    (*pos) += 2;

    for (i = itcLim; i < aTap->itcMac + 1; i++)
      {
	  aTap->rgdxaCenter[i - (itcLim - itcFirst)] = aTap->rgdxaCenter[i];
	  wvCopyTC (&(aTap->rgtc[i - (itcLim - itcFirst)]), &(aTap->rgtc[i]));
      }
}




static void wv2ApplysprmTDefTableShd (TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
uint8_t len;
uint16_t itcMac;
int i;

  len = dread_8ubit (NULL, &pointer);
  (*pos)++;
  itcMac = len / cbSHD;
  wvTrace(("len in 2sprmTDefTableShd is %d, no of cells is %d\n", len, itcMac));

  for (i = 0; i < itcMac; i++)
    {
	wvGetSHDFromBucket (&(aTap->rgshd[i]), pointer);
	pointer += cbSHD;
	(*pos) += cbSHD;
    }
}


/* sprmTVertAlign (opcode 0xD62C) changes the vertical alignment property in
the tap.rgtc[]. Bytes 0 and 1 of the sprm contain the opcode. Byte 2
contains the index of the first cell whose shading is to be changed, call it
itcFirst. Byte 3 contains the index of the cell that follows the last cell
whose shading is to be changed, call it itcLim. This sprm causes the
vertAlign properties of the itcLim - itcFirst entries of tap.rgtc[] to be
set to the new vertical alignment property contained in Byte 4.
sprmTVertAlign is stored only in grpprls linked to piece table entries. */
static void wvApplysprmTVertAlign (TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
uint8_t itcFirst = dread_8ubit (NULL, &pointer);
uint8_t itcLim = dread_8ubit (NULL, &pointer);
uint8_t props = dread_8ubit (NULL, &pointer);
int i;
  (*pos) += 3;

  for (i = itcFirst; i < itcLim; i++)
      aTap->rgtc[i].vertAlign = props;
}


/* sprmTDxaCol (opcode 0x7623) changes the width of cells whose index is within
a certain range to be a certain value. Bytes 0 and 1of the sprm contain the
opcode. Byte 2 contains the index of the first cell whose width is to be
changed, call it itcFirst. Byte 3 contains the index of the cell that
follows the last cell whose width is to be changed, call it itcLim. Bytes 4
and 5 contain the new width of the cell, call it dxaCol.

This sprm causes the itcLim - itcFirst entries of tap.rgdxaCenter to be
adjusted so that tap.rgdxaCenter[i+1] = tap.rgdxaCenter[i] + dxaCol. Any
tap.rgdxaCenter entries that exist beyond itcLim are adjusted to take into
account the amount added to or removed from the previous columns. */
static void wvApplysprmTDxaCol (TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
uint8_t itcFirst = dread_8ubit (NULL, &pointer);
uint8_t itcLim = dread_8ubit (NULL, &pointer);
int16_t dxaCol = (int16_t) dread_16ubit (NULL, &pointer);
int16_t diff = 0;
int i;
    (*pos) += 4;
    for (i = itcFirst; i < itcLim; i++)
      {
	  diff += aTap->rgdxaCenter[i + 1] - (aTap->rgdxaCenter[i] + dxaCol);
	  aTap->rgdxaCenter[i + 1] = aTap->rgdxaCenter[i] + dxaCol;
      }
    for (i = itcLim; i < aTap->itcMac + 1; i++);
    aTap->rgdxaCenter[i + 1] += diff;
}


/* sprmTMerge (opcode 0x5624) merges the display areas of cells within a
specified range. Bytes 0 and 1 of the sprm contain the opcode. Byte 2
contains the index of the first cell that is to be merged, call it itcFirst.
Byte 3 contains the index of the cell that follows the last cell to be
merged, call it itcLim.

This sprm causes tap.rgtc[itcFirst].fFirstMerged to
be set to 1. Cells in the range whose index is greater than itcFirst and
less than itcLim have tap.rgtc[].fMerged set to 1. sprmTMerge is stored only
in grpprls linked to piece table entries. */
static void wvApplysprmTMerge (TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
    uint8_t itcFirst = dread_8ubit (NULL, &pointer);
    uint8_t itcLim = dread_8ubit (NULL, &pointer);
    int i;
    (*pos) += 2;

    aTap->rgtc[itcFirst].fFirstMerged = 1;
    for (i = itcFirst + 1; i < itcLim; i++)
	aTap->rgtc[i].fMerged = 1;
}


/* sprmTSplit (opcode 0x5625) splits the display areas of merged cells into
their originally assigned display areas. Bytes 0 and 1 of the sprm contain
the opcode. Byte 2 contains the index of the first cell that is to be split,
call it itcFirst. Byte 3 contains the index of the cell that follows the
last cell to be split, call it itcLim.

This sprm clears
tap.rgtc[].fFirstMerged and tap.rgtc[].fMerged for all rgtc entries >=
itcFirst and < itcLim. sprmTSplit is stored only in grpprls linked to piece
table entries. */
static void wvApplysprmTSplit (TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
    uint8_t itcFirst = dread_8ubit (NULL, &pointer);
    uint8_t itcLim = dread_8ubit (NULL, &pointer);
    int i;
    (*pos) += 2;

    for (i = itcFirst; i < itcLim; i++)
      {
	  aTap->rgtc[i].fMerged = 0;
	  aTap->rgtc[itcFirst].fFirstMerged = 0;
      }
}


/* sprmTSetShd (opcode 0x7627) allows the shading definitions(SHDs) within a
tap to be set to new values. Bytes 0 and 1 of the sprm contain the opcode.
Byte 2 contains the index of the first cell whose shading is to be changed,
call it itcFirst. Byte 3 contains the index of the cell that follows the
last cell whose shading is to be changed, call it itcLim. Bytes 4 and 5
contain the SHD structure, call it shd. This sprm causes the itcLim -
itcFirst entries of tap.rgshd to be set to shd. sprmTSetShd is stored only
in grpprls linked to piece table entries.
*/
static void wvApplysprmTSetShd (TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
    uint8_t itcFirst = dread_8ubit (NULL, &pointer);
    uint8_t itcLim = dread_8ubit (NULL, &pointer);
    int i;
    SHD shd;
    (*pos) += 2;

    wvGetSHDFromBucket (&shd, pointer);
    (*pos) += cbSHD;

    for (i = itcFirst; i < itcLim; i++)
	wvCopySHD (&aTap->rgshd[i], &shd);
}


/* sprmTSetShdOdd (opcode 0x7628) is identical to sprmTSetShd, but it only
changes the rgshd for odd indices between itcFirst and. sprmTSetShdOdd is
stored only in grpprls linked to piece table entries. */
static void wvApplysprmTSetShdOdd (TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
    uint8_t itcFirst = dread_8ubit (NULL, &pointer);
    uint8_t itcLim = dread_8ubit (NULL, &pointer);
    int i;
    SHD shd;
    (*pos) += 2;

    wvGetSHDFromBucket (&shd, pointer);
    (*pos) += cbSHD;

    for (i = itcFirst; i < itcLim; i++)
      {
	  if ((i / 2) != (i + 1) / 2)
	      wvCopySHD (&aTap->rgshd[i], &shd);
      }
}


/* guess */
static void wvApplysprmTTextFlow (TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
    uint8_t val = dread_8ubit (NULL, &pointer);
    int i;
    (*pos)++;

    for (i = 0; i < aTap->itcMac; i++)
      {
	  /* just a complete guess who knows */
	  aTap->rgtc[i].fVertical = val & 0x0001;
	  aTap->rgtc[i].fBackward = (val & 0x0002) >> 1;
	  aTap->rgtc[i].fRotateFont = (val & 0x0004) >> 2;
      }
}


/* sprmTVertMerge (opcode 0xD62B) changes the vertical cell merge properties
for a cell in the tap.rgtc[]. Bytes 0 and 1 of the sprm contain the opcode.
Byte 2 contains the index of the cell whose vertical cell merge properties
are to be changed. Byte 3 codes the new vertical cell merge properties for
the cell, a 0 clears both fVertMerge and fVertRestart, a 1 sets fVertMerge
and clears fVertRestart, and a 3 sets both flags. sprmTVertMerge is stored
only in grpprls linked to piece table entries. */
static void wvApplysprmTVertMerge (TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
    uint8_t index, props, count;
    wvTrace (("doing Vertical merge\n"));

    count = dread_8ubit (NULL, &pointer);
    wvTrace (("count is %d\n", count));	/* check against word 8 please */
    index = dread_8ubit (NULL, &pointer);
    props = dread_8ubit (NULL, &pointer);
    (*pos) += 3;

    switch (props)
      {
      case 0:
	  aTap->rgtc[index].fVertMerge = 0;
	  aTap->rgtc[index].fVertRestart = 0;
	  break;
      case 1:
	  aTap->rgtc[index].fVertMerge = 1;
	  aTap->rgtc[index].fVertRestart = 0;
	  break;
      case 3:
	  aTap->rgtc[index].fVertMerge = 1;
	  aTap->rgtc[index].fVertRestart = 1;
	  break;
      }
}


/* This is guess based upon SetBrc */
static void wvApplysprmTSetBrc10 (TAP * aTap, uint8_t * pointer, uint16_t * pos)
{
    uint8_t itcFirst, itcLim, len, temp8;
    BRC10 abrc;
    int i;
    len = dread_8ubit (NULL, &pointer);
    itcFirst = dread_8ubit (NULL, &pointer);
    itcLim = dread_8ubit (NULL, &pointer);
    temp8 = dread_8ubit (NULL, &pointer);
    (*pos) += 3;
    (*pos) += wvGetBRC10FromBucket (&abrc, pointer);

    for (i = itcFirst; i < itcLim; i++)
      {
	  if (temp8 & 0x08)
	      wvConvertBRC10ToBRC (&aTap->rgtc[i].brcRight, &abrc);
	  if (temp8 & 0x04)
	      wvConvertBRC10ToBRC (&aTap->rgtc[i].brcBottom, &abrc);
	  if (temp8 & 0x02)
	      wvConvertBRC10ToBRC (&aTap->rgtc[i].brcLeft, &abrc);
	  if (temp8 & 0x01)
	      wvConvertBRC10ToBRC (&aTap->rgtc[i].brcTop, &abrc);
      }
}




Sprm wvApplySprmFromBucket (uint8_t ver, uint16_t sprm, PAP * apap, CHP * achp,
		       SEP * asep, STSH * stsh, uint8_t * pointer, uint16_t * pos,
		       FILE * data)
{
BRC10 tempBRC10;
uint16_t temp16;
uint8_t temp8;
PAP *temppap=NULL;
CHP *tempchp=NULL;
SEP *tempsep=NULL;
uint8_t toggle;
Sprm RetSprm;

    /*bullet proofing */

    if (apap == NULL)
	{
	temppap=(PAP *)malloc(sizeof(PAP));
	wvInitPAP(temppap);
	apap = temppap;
	}
    if (achp == NULL)
	{
	tempchp=(CHP *)malloc(sizeof(CHP));
	wvInitCHP(tempchp);
	achp = tempchp;
	}
    if (asep == NULL)
	{
	tempsep=(SEP *)malloc(sizeof(SEP));
#ifdef PURIFY
	wvInitSEP (tempsep);
#endif
	asep = tempsep;
	}
#ifdef SPRMTEST
    wvError (("sprm is %x\n", sprm));
#endif

    switch (sprm)
      {
	  /*Beginning of PAP */
      case sprmPIstd:
	  apap->istd = bread_16ubit (pointer, pos);
	  break;
      case sprmPIstdPermute:
	  wvApplysprmPIstdPermute (apap, pointer, pos);
	  break;
      case sprmPIncLvl:
	  wvApplysprmPIncLvl (apap, pointer, pos);
	  break;
      case sprmPJc:
	  apap->jc = bread_8ubit (pointer, pos);
	  wvTrace (("jc is now %d\n", apap->jc));
	  break;
      case sprmPFSideBySide:
	  apap->fSideBySide = bread_8ubit (pointer, pos);
	  break;
      case sprmPFKeep:
	  apap->fKeep = bread_8ubit (pointer, pos);
	  break;
      case sprmPFKeepFollow:
	  apap->fKeepFollow = bread_8ubit (pointer, pos);
	  break;
      case sprmPFPageBreakBefore:
	  apap->fPageBreakBefore = bread_8ubit (pointer, pos);
	  break;
      case sprmPBrcl:
	  apap->brcl = bread_8ubit (pointer, pos);
	  break;
      case sprmPBrcp:
	  apap->brcp = bread_8ubit (pointer, pos);
	  break;
      case sprmPIlvl:
	  apap->ilvl = bread_8ubit (pointer, pos);
	  break;
      case sprmPIlfo:
	  apap->ilfo = (int16_t) bread_16ubit (pointer, pos);
	  wvTrace (("ilfo is %d\n", apap->ilfo));
	  break;
      case sprmPFNoLineNumb:
	  apap->fNoLnn = bread_8ubit (pointer, pos);
	  break;
      case sprmPChgTabsPapx:
	  wvApplysprmPChgTabsPapx (apap, pointer, pos);
	  break;
      case sprmPDxaRight:
	  apap->dxaRight = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmPDxaLeft:
	  apap->dxaLeft = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmPNest:
	  /* sprmPNest (opcode 0x4610) causes its operand, a two-byte dxa value to be
	     added to pap.dxaLeft. If the result of the addition is less than 0, 0 is
	     stored into pap.dxaLeft. */
	  temp16 = (int16_t) bread_16ubit (pointer, pos);
	  apap->dxaLeft += temp16;
	  if (apap->dxaLeft < 0)
	      apap->dxaLeft = 0;
	  break;
      case sprmPDxaLeft1:
	  apap->dxaLeft1 = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmPDyaLine:
	  wvGetLSPDFromBucket (&apap->lspd, pointer);
	  (*pos) += 4;
	  break;
      case sprmPDyaBefore:
	  apap->dyaBefore = bread_16ubit (pointer, pos);
	  break;
      case sprmPDyaAfter:
	  apap->dyaAfter = bread_16ubit (pointer, pos);
	  break;
      case sprmPChgTabs:
	  wvApplysprmPChgTabs (apap, pointer, pos);
	  break;
      case sprmPFInTable:
	  apap->fInTable = bread_8ubit (pointer, pos);
	  break;
      case sprmPFTtp:
	  apap->fTtp = bread_8ubit (pointer, pos);
	  break;
      case sprmPDxaAbs:
	  apap->dxaAbs = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmPDyaAbs:
	  apap->dyaAbs = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmPDxaWidth:
	  apap->dxaWidth = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmPPc:
	  wvApplysprmPPc (apap, pointer, pos);
	  break;
      case sprmPBrcTop10:
	  wvGetBRC10FromBucket (&tempBRC10, pointer);
	  (*pos) += 2;
	  wvConvertBRC10ToBRC (&apap->brcTop, &tempBRC10);
	  break;
      case sprmPBrcLeft10:
	  wvGetBRC10FromBucket (&tempBRC10, pointer);
	  (*pos) += 2;
	  wvConvertBRC10ToBRC (&apap->brcLeft, &tempBRC10);
	  break;
      case sprmPBrcBottom10:
	  wvGetBRC10FromBucket (&tempBRC10, pointer);
	  (*pos) += 2;
	  wvConvertBRC10ToBRC (&apap->brcBottom, &tempBRC10);
	  break;
      case sprmPBrcRight10:
	  wvGetBRC10FromBucket (&tempBRC10, pointer);
	  (*pos) += 2;
	  wvConvertBRC10ToBRC (&apap->brcRight, &tempBRC10);
	  break;
      case sprmPBrcBetween10:
	  wvGetBRC10FromBucket (&tempBRC10, pointer);
	  (*pos) += 2;
	  wvConvertBRC10ToBRC (&apap->brcBetween, &tempBRC10);
	  break;
      case sprmPBrcBar10:
	  wvGetBRC10FromBucket (&tempBRC10, pointer);
	  (*pos) += 2;
	  wvConvertBRC10ToBRC (&apap->brcBar, &tempBRC10);
	  break;
      case sprmPDxaFromText10:
	  apap->dxaFromText = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmPWr:
	  apap->wr = bread_8ubit (pointer, pos);
	  break;
      case sprmPBrcTop:
	  (*pos) += wvGetBRCFromBucket (ver, &apap->brcTop, pointer);
	  break;
      case sprmPBrcLeft:
	  (*pos) += wvGetBRCFromBucket (ver, &apap->brcLeft, pointer);
	  break;
      case sprmPBrcBottom:
	  (*pos) += wvGetBRCFromBucket (ver, &apap->brcBottom, pointer);
	  break;
      case sprmPBrcRight:
	  (*pos) += wvGetBRCFromBucket (ver, &apap->brcRight, pointer);
	  break;
      case sprmPBrcBetween:
	  (*pos) += wvGetBRCFromBucket (ver, &apap->brcBetween, pointer);
	  break;
      case sprmPBrcBar:
	  (*pos) += wvGetBRCFromBucket (ver, &apap->brcBar, pointer);
	  break;
      case sprmPFNoAutoHyph:
	  apap->fNoAutoHyph = bread_8ubit (pointer, pos);
	  break;
      case sprmPWHeightAbs:		/* ???? apap->wHeightAbs */
	  (*pos) += 2;
	  break;
      case sprmPDcs:
	  wvGetDCSFromBucket (&apap->dcs, pointer);
	  (*pos) += 2;
	  break;
      case sprmPShd:
	  wvGetSHDFromBucket (&apap->shd, pointer);
	  (*pos) += 2;
	  break;
      case sprmPDyaFromText:
	  apap->dyaFromText = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmPDxaFromText:
	  apap->dxaFromText = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmPFLocked:
	  apap->fLocked = bread_8ubit (pointer, pos);
	  break;
      case sprmPFWidowControl:
	  apap->fWidowControl = bread_8ubit (pointer, pos);
	  break;
      case sprmPFKinsoku:
	  apap->fKinsoku = bread_8ubit (pointer, pos);
	  break;
      case sprmPFWordWrap:
	  apap->fWordWrap = bread_8ubit (pointer, pos);
	  break;
      case sprmPFOverflowPunct:
	  apap->fOverflowPunct = bread_8ubit (pointer, pos);
	  break;
      case sprmPFTopLinePunct:
	  apap->fTopLinePunct = bread_8ubit (pointer, pos);
	  break;
      case sprmPFAutoSpaceDE:
	  apap->fAutoSpaceDE = bread_8ubit (pointer, pos);
	  break;
      case sprmPFAutoSpaceDN:	/* ???? apap->fAutoSpaceDN */
	  (*pos)++;
	  break;
      case sprmPWAlignFont:
	  apap->wAlignFont = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmPFrameTextFlow:
	  wvApplysprmPFrameTextFlow (apap, pointer, pos);
	  break;
      case sprmPISnapBaseLine:	/*obsolete: not applicable in Word97 and later versions */
	  (*pos)++;
	  break;
      case sprmPNLvlAnm:	/*obsolete: not applicable in Word97 and later version */
	  apap->nLvlAnm = bread_8ubit (pointer, pos);
	  wvTrace (("%d\n", apap->nLvlAnm));
	  break;
      case sprmPAnld:
	  wvApplysprmPAnld (ver, apap, pointer, pos);
	  break;
      case sprmPPropRMark:
	  wvApplysprmPPropRMark (apap, pointer, pos);
	  break;
      case sprmPOutLvl:		/*has no effect if pap.istd is < 1 or is > 9 */
	  temp8 = bread_8ubit (pointer, pos);
	  if ((apap->istd >= 1) && (apap->istd <= 9))
	      apap->lvl = temp8;
	  break;
      case sprmPFBiDi:
	apap->fBidi = bread_8ubit (pointer, pos);
	break;
      case sprmPFNumRMIns:
	  apap->fNumRMIns = bread_8ubit (pointer, pos);
	  break;
      case sprmPCrLf:		/* ???? */
	  (*pos)++;
	  break;
      case sprmPNumRM:
	  wvApplysprmPNumRM (apap, pointer, pos);
	  break;
      case sprmPHugePapx2:
      case sprmPHugePapx:
	  wvApplysprmPHugePapx (apap, pointer, pos, data, stsh);
	  break;
      case sprmPFUsePgsuSettings:
	  apap->fUsePgsuSettings = bread_8ubit (pointer, pos);
	  break;
      case sprmPFAdjustRight:
	  apap->fAdjustRight = bread_8ubit (pointer, pos);
	  break;
	  /*End of PAP */


	  /*Begin of CHP */
      case sprmCFRMarkDel:
	  achp->fRMarkDel = bread_8ubit (pointer, pos);
	  break;
      case sprmCFRMark:
	  achp->fRMark = bread_8ubit (pointer, pos);
	  break;
      case sprmCFFldVanish:
	  achp->fFldVanish = bread_8ubit (pointer, pos);
	  break;
      case sprmCPicLocation:
	  if (ver != 8) //WORD8)
	    {
		wvTrace (("byte is %x\n", bread_8ubit (pointer, pos)));
		pointer++;
	    }
	  /* This sprm moves the 4-byte operand of the sprm into the
	     chp.fcPic field. It simultaneously sets chp.fSpec to 1. */
	  achp->fcPic_fcObj_lTagObj = bread_32ubit (pointer, pos);
	  wvTrace (("Len is %x\n", achp->fcPic_fcObj_lTagObj));
	  achp->fSpec = 1;
	  break;
      case sprmCIbstRMark:
	  achp->ibstRMark = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmCDttmRMark:
	  wvGetDTTMFromBucket (&achp->dttmRMark, pointer);
	  (*pos) += 4;
	  break;
      case sprmCFData:
	  achp->fData = bread_8ubit (pointer, pos);
	  break;
      case sprmCIdslRMark:
	  achp->idslRMReason = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmCChs:
	  wvApplysprmCChs (achp, pointer, pos);
	  break;
      case sprmCSymbol:
	  wvApplysprmCSymbol (ver, achp, pointer, pos);
	  break;
      case sprmCFOle2:
	  achp->fOle2 = bread_8ubit (pointer, pos);
	  break;
      case sprmCHighlight:		/* ico (fHighlight is set to 1 iff ico is not 0) */
	  achp->icoHighlight = bread_8ubit (pointer, pos);
	  if (achp->icoHighlight)
	      achp->fHighlight = 1;	/*? */

	  /*another possibility is... */
	  /* if (achp->ico) achp->fHighlight = 1; */
	  /*
	     or is it something else, who knows the entire documentation on
	     the topic consist of the if and only if (iff) line, or maybe
	     iff is a type for if, who knows eh ?
	   */
	  break;
      case sprmCObjLocation:
	  achp->fcPic_fcObj_lTagObj = (int32_t) bread_32ubit (pointer, pos);
	  break;
      case sprmCIstd:
	  achp->istd = bread_16ubit (pointer, pos);
	  break;
      case sprmCIstdPermute:
	  wvApplysprmCIstdPermute (achp, pointer, pos);	/*unfinished */
	  break;
      case sprmCDefault:
	  wvApplysprmCDefault (achp, pointer, pos);
	  break;
      case sprmCPlain:
	  wvApplysprmCPlain (achp, stsh);
	  break;
      case sprmCFBold:
	  toggle = bread_8ubit (pointer, pos);
	  wvTrace (("toggle here is %d, istd is %d\n", toggle, achp->istd));
	  wvTOGGLE (achp->fBold, achp, stsh, toggle, fBold) break;
      case sprmCFItalic:
	  toggle = bread_8ubit (pointer, pos);
	  wvTrace (("Italic is %d, sprm val is %d\n", achp->fItalic, toggle));
	  wvTOGGLE (achp->fItalic, achp, stsh, toggle, fItalic)
	  wvTrace (("Italic is now %d\n", achp->fItalic));
	  break;
      case sprmCFStrike:
	  toggle = bread_8ubit (pointer, pos);
	  wvTOGGLE (achp->fStrike, achp, stsh, toggle, fStrike) break;
      case sprmCFOutline:
	  toggle = bread_8ubit (pointer, pos);
	  wvTOGGLE (achp->fOutline, achp, stsh, toggle, fOutline) break;
      case sprmCFShadow:
	  toggle = bread_8ubit (pointer, pos);
	  wvTOGGLE (achp->fShadow, achp, stsh, toggle, fShadow) break;
      case sprmCFSmallCaps:
	  toggle = bread_8ubit (pointer, pos);
	  wvTOGGLE (achp->fSmallCaps, achp, stsh, toggle, fSmallCaps) break;
      case sprmCFCaps:
	  toggle = bread_8ubit (pointer, pos);
	  wvTOGGLE (achp->fCaps, achp, stsh, toggle, fCaps) break;
      case sprmCFVanish:
	  wvTrace (("vanish modified\n"));
	  toggle = bread_8ubit (pointer, pos);
	  wvTOGGLE (achp->fVanish, achp, stsh, toggle, fVanish) break;
      case sprmCFtcDefault:
	  toggle = bread_8ubit (pointer, pos);
	  wvTOGGLE (achp->fBold, achp, stsh, toggle, fBold) break;
      case sprmCKul:
	  achp->kul = bread_8ubit (pointer, pos);
	  break;
      case sprmCSizePos:
	  wvApplysprmCSizePos (achp, pointer, pos);
	  break;
      case sprmCDxaSpace:
	  achp->dxaSpace = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmCIco:
	  achp->ico = bread_8ubit (pointer, pos);
	  break;
      case sprmCHps:		/*incorrect marked as being a byte in docs ? */
	  achp->hps = bread_16ubit (pointer, pos);
	  break;
      case sprmCHpsInc:
	  wvApplysprmCHpsInc(pointer); //achp , pos);
	  break;
      case sprmCHpsPos:		/*incorrect marked as being a byte in docs ? */
	  achp->hpsPos = bread_16ubit (pointer, pos);
	  break;
      case sprmCHpsPosAdj:
	  wvApplysprmCHpsPosAdj (achp, pointer, pos);
	  break;
      case sprmCMajority:
	  wvApplysprmCMajority (achp, stsh, pointer, pos);
	  break;
      case sprmCIss:
	  achp->iss = bread_8ubit (pointer, pos);
	  break;
      case sprmCHpsNew50:
	  bread_8ubit (pointer, pos);
	  achp->hps = bread_16ubit (pointer, pos);
	  break;
      case sprmCHpsInc1:
	  wvApplysprmCHpsInc1 (achp, pointer, pos);
	  break;
      case sprmCHpsKern:	/*the spec would you have you believe that this is a uint8_t */
	  achp->hpsKern = bread_16ubit (pointer, pos);
	  break;
      case sprmCMajority50:
	  wvApplysprmCMajority50 (achp, stsh, pointer, pos);
	  break;
      case sprmCHpsMul:		/*percentage to grow hps ?? */
	  achp->hps = achp->hps * bread_16ubit (pointer, pos) / 100;
	  break;
      case sprmCYsri:		/* ???? achp->ysri */
	  bread_8ubit (pointer, pos);
	  break;
      case sprmCRgFtc0:
	  achp->ftcAscii = bread_16ubit (pointer, pos);
	  break;
      case sprmCRgFtc1:
	  achp->ftcFE = bread_16ubit (pointer, pos);
	  break;
      case sprmCRgFtc2:
	  achp->ftcOther = bread_16ubit (pointer, pos);
	  break;
      case sprmCFDStrike:
	  achp->fDStrike = bread_8ubit (pointer, pos);
	  break;
      case sprmCFImprint:
	  achp->fImprint = bread_8ubit (pointer, pos);
	  break;
      case sprmCFSpec:
	  achp->fSpec = bread_8ubit (pointer, pos);
	  break;
      case sprmCFObj:
	  achp->fObj = bread_8ubit (pointer, pos);
	  break;
      case sprmCPropRMark:
	  wvApplysprmCPropRMark (achp, pointer, pos);
	  break;
      case sprmCFEmboss:
	  achp->fEmboss = bread_8ubit (pointer, pos);
	  break;
      case sprmCSfxText:
	  achp->sfxtText = bread_8ubit (pointer, pos);
	  break;
      case sprmCDispFldRMark:
	  wvApplysprmCDispFldRMark(achp, pointer, pos);
	  break;
      case sprmCIbstRMarkDel:
	  achp->ibstRMarkDel = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmCDttmRMarkDel:
	  wvGetDTTMFromBucket (&achp->dttmRMarkDel, pointer);
	  (*pos) += 4;
	  break;
      case sprmCBrc:
	  (*pos) += wvGetBRCFromBucket (ver, &achp->brc, pointer);
	  break;
      case sprmCShd:
	  wvGetSHDFromBucket (&apap->shd, pointer);
	  (*pos) += 2;
      case sprmCIdslRMarkDel:
	  /* achp->idslRMReasonDel ???? */
	  (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmCFUsePgsuSettings:
	  achp->fUsePgsuSettings = bread_8ubit (pointer, pos);
	  break;
      case sprmCRgLid0:
	  achp->lidDefault = bread_16ubit (pointer, pos);
	  break;
      case sprmCRgLid1:
	  achp->lidFE = bread_16ubit (pointer, pos);
	  break;
      case sprmCIdctHint:
	  achp->idctHint = bread_8ubit (pointer, pos);
	  break;
      case sprmCFFtcAsciSymb:	/* not fully mentioned in spec */
	  achp->fFtcAsciSym = bread_8ubit (pointer, pos);
	  break;
      case sprmCCpg:		/* not fully mentioned in spec */
	  achp->cpg = bread_16ubit (pointer, pos);
	  break;
      case sprmCLid:		/*
				   only used internally, never stored ( word 97 )
				   but exists in earlier versions so...
				 */
	  achp->lid = bread_16ubit (pointer, pos);
	  achp->lidDefault = achp->lid;
	  achp->lidFE = achp->lid;
	  wvTrace (("lid is %x\n", achp->lidDefault));
	  break;

	  /* BiDi */

      case sprmCFBiDi:		/* is this run BiDi */
	  achp->fBidi = bread_8ubit (pointer, pos);
	  break;

      case sprmCFDiacColor:	/* ???? */
	bread_16ubit (pointer, pos);
	break;

      case sprmCFBoldBi:
	achp->fBoldBidi = bread_8ubit (pointer, pos);
	break;

      case sprmCFItalicBi:
	achp->fItalicBidi = bread_8ubit (pointer, pos);
	break;

      case sprmCFtcBi:
	achp->ftcBidi = bread_16ubit (pointer, pos);
	break;

      case sprmCLidBi:
	achp->lidBidi = bread_16ubit (pointer, pos);
	break;

      case sprmCIcoBi:
	achp->icoBidi = bread_8ubit (pointer, pos);
	break;

      case sprmCHpsBi:
	achp->hpsBidi = bread_16ubit (pointer, pos);
	break;
	  /* End of CHP */


	  /* Begin of SEP */
      case sprmScnsPgn:
	  asep->cnsPgn = bread_8ubit (pointer, pos);
	  break;
      case sprmSiHeadingPgn:
	  asep->iHeadingPgn = bread_8ubit (pointer, pos);
	  break;
      case sprmSOlstAnm:
	  wvApplysprmSOlstAnm (ver, asep, pointer, pos);
	  break;
      case sprmSDxaColWidth:
      case sprmSDxaColSpacing:
	  /* well then no one has docs for these two , they're 3 long
	     but affects (i guess by name) a 89 long array so who
	     knows */
	  bread_8ubit (pointer, pos);
	  bread_8ubit (pointer, pos);
	  bread_8ubit (pointer, pos);
	  break;
      case sprmSFEvenlySpaced:
	  asep->fEvenlySpaced = bread_8ubit (pointer, pos);
	  break;
      case sprmSFProtected:
	  asep->fUnlocked = bread_8ubit (pointer, pos);
	  break;
      case sprmSDmBinFirst:
	  asep->dmBinFirst = bread_16ubit (pointer, pos);
	  break;
      case sprmSDmBinOther:
	  asep->dmBinFirst = bread_16ubit (pointer, pos);
	  break;
      case sprmSBkc:
	  asep->bkc = bread_8ubit (pointer, pos);
	  break;
      case sprmSFTitlePage:
	  asep->fTitlePage = bread_8ubit (pointer, pos);
	  break;
      case sprmSCcolumns:
	  asep->ccolM1 = bread_16ubit (pointer, pos);
	  break;
      case sprmSDxaColumns:
	  asep->dxaColumns = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmSFAutoPgn:
	  asep->fAutoPgn = bread_8ubit (pointer, pos);
	  break;
      case sprmSNfcPgn:
	  asep->nfcPgn = bread_8ubit (pointer, pos);
	  break;
      case sprmSDyaPgn:
	  asep->dyaPgn = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmSDxaPgn:
	  asep->dxaPgn = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmSFPgnRestart:
	  asep->fPgnRestart = bread_8ubit (pointer, pos);
	  break;
      case sprmSFEndnote:
	  asep->fEndNote = bread_8ubit (pointer, pos);
	  break;
      case sprmSLnc:
	  asep->lnc = bread_8ubit (pointer, pos);
	  break;
      case sprmSGprfIhdt:
	  asep->grpfIhdt = bread_8ubit (pointer, pos);
	  break;
      case sprmSNLnnMod:
	  asep->nLnnMod = bread_16ubit (pointer, pos);
	  break;
      case sprmSDxaLnn:
	  asep->dxaLnn = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmSDyaHdrTop:
	  asep->dyaHdrTop = bread_16ubit (pointer, pos);
	  break;
      case sprmSDyaHdrBottom:
	  asep->dyaHdrBottom = bread_16ubit (pointer, pos);
	  break;
      case sprmSLBetween:
	  asep->fLBetween = bread_8ubit (pointer, pos);
	  break;
      case sprmSVjc:
	  asep->fLBetween = bread_8ubit (pointer, pos);
	  break;
      case sprmSLnnMin:
	  asep->lnnMin = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmSPgnStart:
	  asep->pgnStart = bread_16ubit (pointer, pos);
	  break;
      case sprmSBOrientation:
	  asep->dmOrientPage = bread_8ubit (pointer, pos);
	  break;
      case sprmSBCustomize:	/*noone knows what this is */
	  bread_8ubit (pointer, pos);
	  break;
      case sprmSXaPage:
	  asep->xaPage = bread_16ubit (pointer, pos);
	  break;
      case sprmSYaPage:
	  asep->yaPage = bread_16ubit (pointer, pos);
	  break;
      case sprmSDxaLeft:
	  asep->dxaLeft = bread_16ubit (pointer, pos);
	  break;
      case sprmSDxaRight:
	  asep->dxaRight = bread_16ubit (pointer, pos);
	  break;
      case sprmSDyaTop:
	  asep->dyaTop = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmSDyaBottom:
	  asep->dyaBottom = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmSDzaGutter:
	  asep->dzaGutter = bread_16ubit (pointer, pos);
	  break;
      case sprmSDmPaperReq:
	  asep->dmPaperReq = bread_16ubit (pointer, pos);
	  break;
      case sprmSPropRMark:
	  wvApplysprmSPropRMark(asep, pointer, pos);
	  break;
      case sprmSFBiDi:		/* ?????? , what the hell are these three */
      case sprmSFFacingCol:
      case sprmSFRTLGutter:
	  bread_8ubit (pointer, pos);
	  break;
      case sprmSBrcTop:
	  (*pos) += wvGetBRCFromBucket (ver, &asep->brcTop, pointer);
	  break;
      case sprmSBrcLeft:
	  (*pos) += wvGetBRCFromBucket (ver, &asep->brcLeft, pointer);
	  break;
      case sprmSBrcBottom:
	  (*pos) += wvGetBRCFromBucket (ver, &asep->brcBottom, pointer);
	  break;
      case sprmSBrcRight:
	  (*pos) += wvGetBRCFromBucket (ver, &asep->brcRight, pointer);
	  break;
      case sprmSPgbProp:
	  asep->pgbProp = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmSDxtCharSpace:
	  asep->dxtCharSpace = (int32_t) bread_32ubit (pointer, pos);
	  break;
      case sprmSDyaLinePitch:
	  asep->dyaLinePitch = (int32_t) bread_32ubit (pointer, pos);
	  break;
      case sprmSClm:		/* who knows */
	  bread_16ubit (pointer, pos);
	  break;
      case sprmSTextFlow:
	  asep->wTextFlow = (int16_t) bread_16ubit (pointer, pos);
	  break;
	  /* End of SEP */

	  /* Begin of TAP */
      case sprmTJc:
	  apap->ptap.jc = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmTFCantSplit:
	  apap->ptap.fCantSplit = bread_8ubit (pointer, pos);
	  break;
      case sprmTTableHeader:
	  apap->ptap.fTableHeader = bread_8ubit (pointer, pos);
	  break;
      case sprmTDyaRowHeight:	/* check len */
	  asep->dyaLinePitch = (int16_t) bread_16ubit (pointer, pos);
	  break;
      case sprmTDiagLine:	/* ????? */
	  //wvError (("huh, show me this document\n"));
	  break;
      case sprmTHTMLProps:	/* ???? */
	  apap->ptap.lwHTMLProps = (int32_t) bread_32ubit (pointer, pos);
	  break;
      case sprmTDxaLeft:
	  wvApplysprmTDxaLeft (&apap->ptap, pointer, pos);
	  break;
      case sprmTDxaGapHalf:
	  wvApplysprmTDxaGapHalf (&apap->ptap, pointer, pos);
	  break;
      case sprmTTableBorders:
	  wvApplysprmTTableBorders (ver, &apap->ptap, pointer, pos);
	  break;
      case sprmTDefTable10:
	  wvApplysprmTDefTable10 (&apap->ptap, pointer, pos);
	  break;
      case sprmTDefTable:
	  wvApplysprmTDefTable (&apap->ptap, pointer, pos);
	  break;
      case sprmTDefTableShd:
	  /*
	     wvApplysprmTDefTableShd follows the written spec, but
	     it isnt't working out for me, maybe its my own fault,
	     anyhow Im trying wv2 out temporarily
	   */
	  wv2ApplysprmTDefTableShd (&apap->ptap, pointer, pos);
	  /*
	     wvApplysprmTDefTableShd(&apap->ptap,pointer,pos);
	   */
	  break;
      case sprmTTlp:
	  wvGetTLPFromBucket (&(apap->ptap.tlp), pointer);
	  (*pos) += cbTLP;
	  break;
      case sprmTSetBrc:
	  wvApplysprmTSetBrc (ver, &apap->ptap, pointer, pos);
	  break;
      case sprmTInsert:
	  wvApplysprmTInsert (&apap->ptap, pointer, pos);
	  break;
      case sprmTDelete:
	  wvApplysprmTDelete (&apap->ptap, pointer, pos);
	  break;
      case sprmTDxaCol:
	  wvApplysprmTDxaCol (&apap->ptap, pointer, pos);
	  break;
      case sprmTMerge:
	  wvApplysprmTMerge (&apap->ptap, pointer, pos);
	  break;
      case sprmTSplit:
	  wvApplysprmTSplit (&apap->ptap, pointer, pos);
	  break;
      case sprmTSetBrc10:
	  wvApplysprmTSetBrc10 (&apap->ptap, pointer, pos);
	  break;
      case sprmTSetShd:
	  wvApplysprmTSetShd (&apap->ptap, pointer, pos);
	  break;
      case sprmTSetShdOdd:
	  wvApplysprmTSetShdOdd (&apap->ptap, pointer, pos);
	  break;
      case sprmTTextFlow:
//	  wvError (("huh, show me this document\n"));
	  wvApplysprmTTextFlow (&apap->ptap, pointer, pos);
	  break;
      case sprmTVertMerge:
	  wvApplysprmTVertMerge (&apap->ptap, pointer, pos);
	  break;
      case sprmTFBiDi:		/* ????? */
	  bread_16ubit (pointer, pos);
	  break;
      case sprmTUNKNOWN1:
	  /* read wv.h and word 6 sprm 204 further down in this file to understand this */
	  bread_8ubit (pointer, pos);
	  bread_16ubit (pointer, pos);
	  break;
      case sprmTVertAlign:
	  wvApplysprmTVertAlign (&apap->ptap, pointer, pos);
	  break;

	  /* end of TAP */

	  /*
	     case sprmPicBrcl
	   */

      case sprmPRuler:		/* ???? */
      case sprmCIdCharType:	/* obsolete */
      case sprmCKcd:		/* ???? */
      case sprmCCharScale:	/* ???? */
      case sprmNoop:		/* no operand */
	  break;
      default:
	  wvEatSprm (sprm, pointer, pos);
	  break;
      }

    wvGetSprmFromU16 (&RetSprm, sprm);

    if(tempsep) free(tempsep);
    if(tempchp) free(tempchp);
    if(temppap) free(temppap);
    return (RetSprm);
}


SprmName rgsprmPrm[0x80] =
    { sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmPIncLvl, sprmPJc,
    sprmPFSideBySide, sprmPFKeep, sprmPFKeepFollow, sprmPFPageBreakBefore,
    sprmPBrcl, sprmPBrcp, sprmPIlvl, sprmNoop, sprmPFNoLineNumb, sprmNoop,
    sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
    sprmNoop, sprmPFInTable, sprmPFTtp, sprmNoop, sprmNoop, sprmNoop, sprmPPc,
    sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
    sprmPWr, sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
    sprmPFNoAutoHyph, sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
    sprmPFLocked, sprmPFWidowControl, sprmNoop, sprmPFKinsoku, sprmPFWordWrap,
    sprmPFOverflowPunct, sprmPFTopLinePunct, sprmPFAutoSpaceDE,
    sprmPFAutoSpaceDN, sprmNoop, sprmNoop, sprmPISnapBaseLine, sprmNoop,
    sprmNoop, sprmNoop, sprmCFStrikeRM, sprmCFRMark, sprmCFFldVanish,
    sprmNoop,
    sprmNoop, sprmNoop, sprmCFData, sprmNoop, sprmNoop, sprmNoop, sprmCFOle2,
    sprmNoop, sprmCHighlight, sprmCFEmboss, sprmCSfxText, sprmNoop, sprmNoop,
    sprmNoop, sprmCPlain, sprmNoop, sprmCFBold, sprmCFItalic, sprmCFStrike,
    sprmCFOutline, sprmCFShadow, sprmCFSmallCaps, sprmCFCaps, sprmCFVanish,
    sprmNoop, sprmCKul, sprmNoop, sprmNoop, sprmNoop, sprmCIco, sprmNoop,
    sprmCHpsInc, sprmNoop, sprmCHpsPosAdj, sprmNoop, sprmCIss, sprmNoop,
    sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
    sprmNoop, sprmNoop, sprmCFDStrike, sprmCFImprint, sprmCFSpec, sprmCFObj,
    sprmPicBrcl, sprmPOutLvl, sprmNoop, sprmNoop, sprmNoop, sprmNoop,
    sprmNoop,
    sprmPPnbrRMarkNot
};

SprmName wvGetrgsprmPrm (uint16_t in)
{
    if (in >= sizeof(rgsprmPrm)/sizeof(SprmName))	// 0x80
      {
	  wvError (("Impossible rgsprmPrm value\n"));
	  return (sprmNoop);
      }
    return (rgsprmPrm[in]);
}


SprmName rgsprmWord6[256] = {
    sprmNoop /*          0 */ ,
    sprmNoop /*                  1 */ ,
    sprmPIstd /*         2 */ ,
    sprmPIstdPermute /*  3 */ ,
    sprmPIncLvl /*       4 */ ,
    sprmPJc /*           5 */ ,
    sprmPFSideBySide /*  6 */ ,
    sprmPFKeep /*        7 */ ,
    sprmPFKeepFollow /*  8 */ ,
    sprmPFPageBreakBefore /*  9 */ ,	/* added F */
    sprmPBrcl /*         10 */ ,
    sprmPBrcp /*         11 */ ,
    sprmPAnld /*         12 */ ,
    sprmPNLvlAnm /*      13 */ ,
    sprmPFNoLineNumb /*  14 */ ,
    sprmPChgTabsPapx /*  15 */ ,
    sprmPDxaRight /*     16 */ ,
    sprmPDxaLeft /*      17 */ ,
    sprmPNest /*         18 */ ,
    sprmPDxaLeft1 /*     19 */ ,
    sprmPDyaLine /*      20 */ ,
    sprmPDyaBefore /*    21 */ ,
    sprmPDyaAfter /*     22 */ ,
    sprmPChgTabs /*      23 */ ,
    sprmPFInTable /*     24 */ ,
    sprmPFTtp /*         25 */ ,	/* added F */
    sprmPDxaAbs /*       26 */ ,
    sprmPDyaAbs /*       27 */ ,
    sprmPDxaWidth /*     28 */ ,
    sprmPPc /*           29 */ ,
    sprmPBrcTop10 /*     30 */ ,
    sprmPBrcLeft10 /*    31 */ ,
    sprmPBrcBottom10 /*  32 */ ,
    sprmPBrcRight10 /*   33 */ ,
    sprmPBrcBetween10 /* 34 */ ,
    sprmPBrcBar10 /*     35 */ ,
    sprmPDxaFromText10 /*   36 */ ,	/* new name */
    sprmPWr /*           37 */ ,
    sprmPBrcTop /*       38 */ ,
    sprmPBrcLeft /*      39 */ ,
    sprmPBrcBottom /*    40 */ ,
    sprmPBrcRight /*     41 */ ,
    sprmPBrcBetween /*   42 */ ,
    sprmPBrcBar /*       43 */ ,
    sprmPFNoAutoHyph /*  44 */ ,
    sprmPWHeightAbs /*   45 */ ,
    sprmPDcs /*          46 */ ,
    sprmPShd /*          47 */ ,
    sprmPDyaFromText /*  48 */ ,
    sprmPDxaFromText /*  49 */ ,
    sprmPFLocked /*      50 */ ,
    sprmPFWidowControl /*  51 */ ,
    sprmNoop /*          52 */ ,
    sprmNoop /*          53 */ ,
    sprmNoop /*          54 */ ,
    sprmNoop /*          55 */ ,
    sprmNoop /*          56 */ ,
    sprmPUNKNOWN2 /*     57 */ ,
    sprmPUNKNOWN3 /*     58 */ ,
    sprmPUNKNOWN4 /*     59 */ ,
    sprmNoop /*          60 */ ,
    sprmNoop /*          61 */ ,
    sprmNoop /*          62 */ ,
    sprmNoop /*          63 */ ,
    sprmNoop /*          64 */ ,
    sprmCFStrikeRM /*    65 */ ,
    sprmCFRMark /*       66 */ ,
    sprmCFFldVanish /*   67 */ ,
    sprmCPicLocation /*  68 */ ,
    sprmCIbstRMark /*    69 */ ,
    sprmCDttmRMark /*    70 */ ,
    sprmCFData /*        71 */ ,
    sprmCIdslRMark /*     72 */ ,	/* new name */
    sprmCChs /*         73 */ ,	/* new name */
    sprmCSymbol /*       74 */ ,
    sprmCFOle2 /*        75 */ ,
    sprmNoop /*          76 */ ,
    sprmNoop /*          77 */ ,
    sprmNoop /*          78 */ ,
    sprmNoop /*          79 */ ,
    sprmCIstd /*         80 */ ,
    sprmCIstdPermute /*  81 */ ,
    sprmCDefault /*      82 */ ,
    sprmCPlain /*        83 */ ,
    sprmNoop /*          84 */ ,
    sprmCFBold /*        85 */ ,
    sprmCFItalic /*      86 */ ,
    sprmCFStrike /*      87 */ ,
    sprmCFOutline /*     88 */ ,
    sprmCFShadow /*      89 */ ,
    sprmCFSmallCaps /*   90 */ ,
    sprmCFCaps /*        91 */ ,
    sprmCFVanish /*      92 */ ,
    sprmCFtc /*          93 */ ,
    sprmCKul /*          94 */ ,
    sprmCSizePos /*      95 */ ,
    sprmCDxaSpace /*     96 */ ,
    sprmCLid /*          97 */ ,
    sprmCIco /*          98 */ ,
    sprmCHps /*          99 */ ,
    sprmCHpsInc /*       100 */ ,
    sprmCHpsPos /*       101 */ ,
    sprmCHpsPosAdj /*    102 */ ,
    sprmCMajority /*     103 */ ,
    sprmCIss /*          104 */ ,
    sprmCHpsNew50 /*     105 */ ,
    sprmCHpsInc1 /*      106 */ ,
    sprmCHpsKern /*      107 */ ,
    sprmCMajority50 /*   108 */ ,
    sprmCHpsMul /*       109 */ ,
    sprmCYsri /*             110 */ ,	/* new name */
    sprmCUNKNOWN5 /*     111 */ ,
    sprmCUNKNOWN6 /*     112 */ ,
    sprmCUNKNOWN7 /*     113 */ ,
    sprmNoop /*          114 */ ,
    sprmNoop /*          115 */ ,
    sprmNoop /*          116 */ ,
    sprmCFSpec /*        117 */ ,
    sprmCFObj /*         118 */ ,
    sprmPicBrcl /*       119 */ ,
    sprmPicScale /*      120 */ ,
    sprmPicBrcTop /*     121 */ ,
    sprmPicBrcLeft /*    122 */ ,
    sprmPicBrcBottom /*  123 */ ,
    sprmPicBrcRight /*   124 */ ,
    sprmNoop /*          125 */ ,
    sprmNoop /*          126 */ ,
    sprmNoop /*          127 */ ,
    sprmNoop /*          128 */ ,
    sprmNoop /*          129 */ ,
    sprmNoop /*          130 */ ,
    sprmScnsPgn /*           131 */ ,	/* new name */
    sprmSiHeadingPgn /*  132 */ ,
    sprmSOlstAnm /*      133 */ ,
    sprmNoop /*          134 */ ,
    sprmNoop /*          135 */ ,
    sprmSDxaColWidth /*  136 */ ,
    sprmSDxaColWidth /*  137 */ ,	/* new name */
    sprmSFEvenlySpaced /*138 */ ,
    sprmSFProtected /*   139 */ ,
    sprmSDmBinFirst /*   140 */ ,
    sprmSDmBinOther /*   141 */ ,
    sprmSBkc /*          142 */ ,
    sprmSFTitlePage /*   143 */ ,
    sprmSCcolumns /*     144 */ ,
    sprmSDxaColumns /*   145 */ ,
    sprmSFAutoPgn /*     146 */ ,
    sprmSNfcPgn /*       147 */ ,
    sprmSDyaPgn /*       148 */ ,
    sprmSDxaPgn /*       149 */ ,
    sprmSFPgnRestart /*  150 */ ,
    sprmSFEndnote /*     151 */ ,
    sprmSLnc /*          152 */ ,
    sprmSGprfIhdt /*     153 */ ,
    sprmSNLnnMod /*      154 */ ,
    sprmSDxaLnn /*       155 */ ,
    sprmSDyaHdrTop /*    156 */ ,
    sprmSDyaHdrBottom /* 157 */ ,
    sprmNoop /*          158 */ ,
    sprmSVjc /*          159 */ ,
    sprmSLnnMin /*       160 */ ,
    sprmSPgnStart /*     161 */ ,
    sprmSBOrientation /* 162 */ ,
    sprmSBCustomize /*   163 */ ,
    sprmSXaPage /*       164 */ ,
    sprmSYaPage /*       165 */ ,
    sprmSDxaLeft /*      166 */ ,
    sprmSDxaRight /*     167 */ ,
    sprmSDyaTop /*       168 */ ,
    sprmSDyaBottom /*    169 */ ,
    sprmSDzaGutter /*    170 */ ,
    sprmSDmPaperReq /*   171 */ ,
    sprmNoop /*          172 */ ,
    sprmNoop /*          173 */ ,
    sprmNoop /*          174 */ ,
    sprmNoop /*          175 */ ,
    sprmNoop /*          176 */ ,
    sprmNoop /*          177 */ ,
    sprmNoop /*          178 */ ,
    sprmNoop /*          179 */ ,
    sprmNoop /*          180 */ ,
    sprmNoop /*          181 */ ,
    sprmTJc /*           182 */ ,
    sprmTDxaLeft /*      183 */ ,
    sprmTDxaGapHalf /*   184 */ ,
    sprmTFCantSplit /*   185 */ ,
    sprmTTableHeader /*  186 */ ,
    sprmTTableBorders /* 187 */ ,
    sprmTDefTable10 /*   188 */ ,
    sprmTDyaRowHeight /* 189 */ ,
    sprmTDefTable /*     190 */ ,
    sprmTDefTableShd /*  191 */ ,
    sprmTTlp /*          192 */ ,
    sprmTSetBrc /*       193 */ ,
    sprmTInsert /*       194 */ ,
    sprmTDelete /*       195 */ ,
    sprmTDxaCol /*       196 */ ,
    sprmTMerge /*        197 */ ,
    sprmTSplit /*        198 */ ,
    sprmTSetBrc10 /*     199 */ ,
    sprmTSetShd /*       200 */ ,
    sprmNoop /*          201 */ ,
    sprmNoop /*          202 */ ,
    sprmNoop /*          203 */ ,

    sprmTUNKNOWN1 /*    204 */ ,
    /*guess I know that this should be either
     * a) 3 bytes long,
     * b) complex with a len of 2,
     * its certainly a table related sprm, my guess is sprmTVertMerge
     * as that fits its profile, but it isn't working in practice.
     * */
#if 0
    sprmNoop /*          205 */ ,
    sprmNoop /*          206 */ ,
    sprmNoop /*          207 */ ,
    sprmMax  /*          208 */
#endif
};


SprmName wvGetrgsprmWord6 (uint8_t in)
{
  return (rgsprmWord6[in]);
}


//--------- end of SPRM processing ------------


void wvInitPAP (PAP * item)
{
int i;
    memset(item,0,sizeof(*item));
    item->fWidowControl = 1;
    /* wvInitLSPD(&item->lspd);*/
    item->lspd.fMultLinespace = 1;
    item->lspd.dyaLine = 240;

    wvInitPHE (&item->phe);

    wvInitTAP (&item->ptap);

    wvInitBRC (&item->brcTop);
    wvInitBRC (&item->brcLeft);
    wvInitBRC (&item->brcBottom);
    wvInitBRC (&item->brcRight);
    wvInitBRC (&item->brcBetween);
    wvInitBRC (&item->brcBar);

    wvInitSHD (&item->shd);
    wvInitDCS (&item->dcs);
    item->lvl = 9;
    wvInitANLD (&item->anld);
    wvInitDTTM (&item->dttmPropRMark);
    wvInitNUMRM (&item->numrm);
    for (i = 0; i < itbdMax; i++)
	wvInitTBD (&item->rgtbd[i]);
}


static void wvInitPAPX(PAPX * item)
{
  item->cb = 0;
  item->istd = 0;
  item->grpprl = NULL;
}


static void wvGetPAPX (int ver, PAPX * item, uint8_t * page, uint16_t * pos)
{
uint16_t cw;
  cw = bread_8ubit (&(page[*pos]), pos);
  if ((cw == 0) && (ver == 8))	/* only do this for word 97 */
    {
	wvTrace (("cw was pad %d\n", cw));
	cw = bread_8ubit (&(page[*pos]), pos);
	wvTrace (("cw was %d\n", cw));
   }
  item->cb = cw * 2;
  item->istd = bread_16ubit (&(page[*pos]), pos);
  wvTrace (("papx istd is %x\n", item->istd));
  wvTrace (("no of bytes is %d\n", item->cb));
  if (item->cb > 2)
    {
	item->grpprl = (uint8_t *) malloc (item->cb - 2);
	memcpy (item->grpprl, &(page[*pos]), (item->cb) - 2);
    }
  else
      item->grpprl = NULL;
}

static void wvReleasePAPX (PAPX * item)
{
  item->cb = 0;
  item->istd = 0;
  free(item->grpprl);
  item->grpprl = NULL;
}

void wvCopyPAP (PAP * dest, PAP * src)
{
  memcpy (dest, src, sizeof (PAP));
}


static void wvInitPAPFromIstd (PAP * apap, uint16_t istdBase, STSH * stsh)
{
    if (istdBase == istdNil)
	wvInitPAP (apap);
    else
      {
	  if (istdBase >= stsh->Stshi.cstd)
	    {
//		wvError (("ISTD out of bounds, requested %d of %d\n", istdBase, stsh->Stshi.cstd));
		wvInitPAP (apap);	/*it can't hurt to try and start with a blank istd */
		return;
	    }
	  else
	    {
		if (stsh->std[istdBase].cupx == 0)	/*empty slot in the array, i don't think this should happen */
		  {
		      wvTrace (("Empty style slot used (chp)\n"));
		      wvInitPAP (apap);
		  }
		else
		  {
		    wvCopyPAP (apap, &(stsh->std[istdBase].grupe[0].apap));
		    strcpy(apap->stylename,stsh->std[istdBase].xstzName);
		  }
	    }
      }
}


/* To apply a UPX.papx to a UPE.pap, set UPE.pap.istd equal to UPX.papx.istd, and
then apply the UPX.papx.grpprl to UPE.pap. */
static void wvAddPAPXFromBucket (PAP * apap, UPXF * upxf, STSH * stsh, FILE * data)
{
uint8_t *pointer;
uint16_t i = 0;
uint16_t sprm;
    apap->istd = upxf->upx.papx.istd;
    if (upxf->cbUPX <= 2)
	return;
    wvTrace (("no is %d\n", upxf->cbUPX));
#ifdef SPRMTEST
    fprintf (stderr, "\n");
    while (i < upxf->cbUPX - 2)
      {
	  fprintf (stderr, "%x (%d) ", *(upxf->upx.papx.grpprl + i),
		   *(upxf->upx.papx.grpprl + i));
	  i++;
      }
    fprintf (stderr, "\n");
    i = 0;
#endif
    /*
       while (i < upxf->cbUPX-2)
     */
    while (i < upxf->cbUPX - 4)	/* the end of the list is at -2, but there has to be a full sprm of
				   len 2 as well */
      {
	  sprm = bread_16ubit (upxf->upx.papx.grpprl + i, &i);
#ifdef SPRMTEST
	  wvError (("sprm is %x\n", sprm));
#endif
	  pointer = upxf->upx.papx.grpprl + i;
	  if (i < upxf->cbUPX - 2)
	      wvApplySprmFromBucket (8, sprm, apap, NULL, NULL, stsh,
				     pointer, &i, data);
      }
}


static void wvAddPAPXFromBucket6 (PAP * apap, UPXF * upxf, STSH * stsh)
{
    uint8_t *pointer;
    uint16_t i = 0;
    uint16_t sprm;
    uint8_t sprm8;
    apap->istd = upxf->upx.papx.istd;
    if (upxf->cbUPX <= 2)
	return;
    wvTrace (("no is %d\n", upxf->cbUPX));

#ifdef SPRMTEST
    fprintf (stderr, "\n");
    while (i < upxf->cbUPX - 2)
      {
	  fprintf (stderr, "%x (%d) ", *(upxf->upx.papx.grpprl + i),
		   *(upxf->upx.papx.grpprl + i));
	  i++;
      }
    fprintf (stderr, "\n");
    i = 0;
#endif

    while (i < upxf->cbUPX - 3)	/* the end of the list is at -2, but there has to be a full sprm of
				   len 1 as well */
      {
	  sprm8 = bread_8ubit (upxf->upx.papx.grpprl + i, &i);
#ifdef SPRMTEST
	  wvError (("pap word 6 sprm is %x (%d)\n", sprm8, sprm8));
#endif
	  sprm = (uint16_t) wvGetrgsprmWord6 (sprm8);
#ifdef SPRMTEST
	  wvError (("pap word 6 sprm is converted to %x\n", sprm));
#endif
	  pointer = upxf->upx.papx.grpprl + i;
	  /* hmm, maybe im wrong here, but there appears to be corrupt
	   * word 6 sprm lists being stored in the file
	   */
	  if (i < upxf->cbUPX - 2)
	      wvApplySprmFromBucket (6, sprm, apap, NULL, NULL, stsh,
				     pointer, &i, NULL);
      }
}


/*
1) Having found the index i of the FC in an FKP that marks the character stored
  in the file immediately after the paragraph's paragraph mark,
  1 is done in Simple mode through wvGetSimpleParaBounds which places this index
  in fcLim by default
2) it is necessary to use the word offset stored in the first byte of the
  fkp.rgbx[i - 1] to find the PAPX for the paragraph.
3) Using papx.istd to index into the properties stored for the style sheet ,
4) the paragraph properties of the style are copied to a local PAP.
5) Then the grpprl stored in the PAPX is applied to the local PAP,
6) and papx.istd along with fkp.rgbx.phe are moved into the local PAP.
7) The process thus far has created a PAP that describes what the paragraph properties
of the paragraph were at the last full save. */
int wvAssembleSimplePAP (int ver, PAP * apap, uint32_t fc, PAPX_FKP * fkp,
		     STSH * stsh, FILE * data)
{
PAPX *papx;
int index;
UPXF upxf;
int ret = 0;
#ifdef SPRMTEST
    int i;
#endif
    /*index is the i in the text above */
    index = wvGetIndexFCInFKP_PAPX (fkp, fc);

    wvTrace (("index is %d, using %d\n", index, index - 1));

    if(index-1<=fkp->crun)
	papx=NULL;	//BAD fix, something goes wrong!!!!!!
    else
        papx = &(fkp->grppapx[index-1]);

    if (papx)
      {
	  wvTrace (("istd index is %d\n", papx->istd));
	  wvInitPAPFromIstd (apap, papx->istd, stsh);
      }
    else
	wvInitPAPFromIstd (apap, istdNil, stsh);

    if ((papx) && (papx->cb > 2))
      {
	  ret = 1;
#ifdef SPRMTEST
	  fprintf (stderr, "cbUPX is %d\n", papx->cb);
	  for (i = 0; i < papx->cb - 2; i++)
	      fprintf (stderr, "%x ", papx->grpprl[i]);
	  fprintf (stderr, "\n");
#endif
	  upxf.cbUPX = papx->cb;
	  upxf.upx.papx.istd = papx->istd;
	  upxf.upx.papx.grpprl = papx->grpprl;
	  if (ver == 8)
	      wvAddPAPXFromBucket (apap, &upxf, stsh, data);
	  else
	      wvAddPAPXFromBucket6 (apap, &upxf, stsh);
      }

    if (papx)
	apap->istd = papx->istd;

    wvCopyPHE (&apap->phe, &(fkp->rgbx[index - 1].phe), apap->fTtp);
  return (ret);
}


//--------- end of PAP processing ------------


static void wvInitPCD(PCD * item)
{
    item->fNoParaLast = 0;
    item->fPaphNil = 0;
    item->fCopied = 0;
    item->reserved = 0;
    item->fn = 0;
    item->fc = 0;
    wvInitPRM (&item->prm);
}


static void wvGetPCD(PCD *item, FILE *fd)
{
uint8_t temp8;
    temp8 = fgetc(fd);
#ifdef PURIFY
    wvInitPCD (item);
#endif
    item->fNoParaLast = temp8 & 0x01;
    item->fPaphNil = (temp8 & 0x02) >> 1;
    item->fCopied = (temp8 & 0x04) >> 2;
    item->reserved = (temp8 & 0xf8) >> 3;
    item->fn = fgetc(fd);
    Rd_dword(fd, &item->fc);
    wvGetPRM (&item->prm, fd);
}


static int wvReleasePCD_PLCF (PCD * pcd, uint32_t * pos)
{
  free (pcd);
  free (pos);
return (0);
}


static int wvGetPCD_PLCF(PCD **pcd, uint32_t **pos, uint32_t *nopcd, uint32_t offset, uint32_t len, FILE *fd)
{
uint32_t i;
    if (len == 0)
      {
	  *pcd = NULL;
	  *pos = NULL;
	  *nopcd = 0;
      }
    else
      {
	  *nopcd = (len - 4) / (cbPCD + 4);
	  *pos = (uint32_t *) malloc ((*nopcd + 1) * sizeof (uint32_t));
	  if (*pos == NULL)
	    {
/*		wvError ( ("NO MEM 1, failed to alloc %d bytes\n",
			  (*nopcd + 1) * sizeof (uint32_t)));*/
		return (1);
	    }

	  *pcd = (PCD *) malloc (*nopcd * sizeof (PCD));
	  if (*pcd == NULL)
	    {
/*		wvError ( ("NO MEM 1, failed to alloc %d bytes\n",
			  *nopcd * sizeof (PCD)));*/
		free(*pos); *pos=NULL;		// JFO fix, possible bug.
		return (1);
	    }
	  fseek(fd, offset, SEEK_SET);
	  for (i = 0; i <= *nopcd; i++)
	    {
		Rd_dword(fd, &(*pos)[i]);
		wvTrace (("pcd pos is %x\n", (*pos)[i]));
	    }
	  for (i = 0; i < *nopcd; i++)
	    {
		wvGetPCD (&((*pcd)[i]), fd);
		wvTrace ( ("pcd fc is %x, complex is %d, index is %d\n",
			  (*pcd)[i].fc, (*pcd)[i].prm.fComplex,
			  (*pcd)[i].prm.para.var2.igrpprl));
	    }
      }
    return (0);
}


//------- End of PCB processing --------------


void wvInitCLX(CLX *item)
{
  if(item) memset(item,0,sizeof(CLX));
}


void wvReleaseCLX(CLX *clx)
{
uint16_t i;
  for (i = 0; i < clx->grpprl_count; i++)
	free(clx->grpprl[i]);
  free(clx->grpprl);
  free(clx->cbGrpprl);
  wvReleasePCD_PLCF (clx->pcd, clx->pos);
}


void wvBuildCLXForSimple6 (CLX * clx, FIB * fib)
{
    wvInitCLX (clx);
    clx->nopcd = 1;

    clx->pcd = (PCD *) malloc (clx->nopcd * sizeof (PCD));
    clx->pos = (uint32_t *) malloc ((clx->nopcd + 1) * sizeof (uint32_t));

    clx->pos[0] = 0;
    clx->pos[1] = fib->ccpText;

    wvInitPCD (&(clx->pcd[0]));
    clx->pcd[0].fc = fib->fcMin;

    /* reverse the special encoding thing they do for word97
       if we are using the usual 8 bit chars */

    if (fib->fExtChar == 0)
      {
	  clx->pcd[0].fc *= 2;
	  clx->pcd[0].fc |= 0x40000000UL;
      }

    clx->pcd[0].prm.fComplex = 0;
    clx->pcd[0].prm.para.var1.isprm = 0;
    /*
       these set the ones that *I* use correctly, but may break for other wv
       users, though i doubt it, im just marking a possible firepoint for the
       future
     */
}

/*The complex part of a file (CLX) is composed of a number of variable-sized
blocks of data. Recorded first are any grpprls that may be referenced by the
plcfpcd (if the plcfpcd has no grpprl references, no grpprls will be
recorded) followed by the plcfpcd. Each block in the complex part is
prefaced by a clxt (clx type), which is a 1-byte code, either 1 (meaning the
block contains a grpprl) or 2 (meaning this is the plcfpcd). A clxtGrpprl
(1) is followed by a 2-byte cb which is the count of bytes of the grpprl. A
clxtPlcfpcd (2) is followed by a 4-byte lcb which is the count of bytes of
the piece table. A full saved file will have no clxtGrpprl's.*/
void wvGetCLX (uint8_t ver, CLX *clx, uint32_t offset, uint32_t len, uint8_t fExtChar, FILE *fd)
{
uint8_t clxt;
uint16_t cb;
uint32_t lcb, i, j = 0;

//printf("offset %x len %d\n", offset, len);

    fseek(fd, offset, SEEK_SET);

    wvInitCLX (clx);

    while (j < len)
      {
	  clxt = fgetc (fd);
	  j++;
	  if (clxt == 1)
	    {
		Rd_word(fd,&cb);
		j += 2;
		clx->grpprl_count++;
		clx->cbGrpprl =
		    (uint16_t *) realloc (clx->cbGrpprl,
				     sizeof (uint16_t) * clx->grpprl_count);
		clx->cbGrpprl[clx->grpprl_count - 1] = cb;
		clx->grpprl =
		    (uint8_t **) realloc (clx->grpprl,
				     sizeof (uint8_t *) * (clx->grpprl_count));
		clx->grpprl[clx->grpprl_count - 1] = (uint8_t *) malloc (cb);
		for (i = 0; i < cb; i++)
		    clx->grpprl[clx->grpprl_count - 1][i] = fgetc (fd);
		j += i;
	    }
	  else if (clxt == 2)
	    {
		if (ver == 8)
		  {
		      Rd_dword(fd,&lcb);
		      j += 4;
		  }
		else
		  {
		      wvTrace (("Here so far\n"));
#if 0
		      lcb = read_16ubit (fd);	/* word 6 only has two bytes here */
		      j += 2;
#endif

		      Rd_dword(fd,&lcb);	/* word 6 specs appeared to have lied ! */
		      j += 4;
		  }
		wvGetPCD_PLCF (&clx->pcd, &clx->pos, &clx->nopcd,
			       ftell(fd), lcb, fd);
		j += lcb;

		if (ver <= 7)		/* MV 28.8.2000 Appears to be valid */
		  {
#if 0
		      /* DANGER !!, this is a completely mad attempt to differenciate 
		         between word 95 files that use 16 and 8 bit characters. It may
			 not work, it attempt to err on the side of 8 bit characters.*/
		      if (!(wvGuess16bit (clx->pcd, clx->pos, clx->nopcd)))
#else
		      /* I think that this is the correct reason for this behaviour */
		      if (fExtChar == 0)
#endif
			  for (i = 0; i < clx->nopcd; i++)
			    {
				clx->pcd[i].fc *= 2;
				clx->pcd[i].fc |= 0x40000000UL;
			    }
		  }
	    }
	  else
	    {
//		wvError (("clxt is not 1 or 2, it is %d\n", clxt));
		return;
	    }
      }
}


int wvGetPieceBoundsFC(uint32_t * begin, uint32_t * end, CLX * clx, uint32_t piececount)
{
int type;

    if ((piececount + 1) > clx->nopcd)
	{
	wvTrace (("piececount is > nopcd, i.e.%d > %d\n", piececount + 1, clx->nopcd));
	return (-1);
      }
    *begin = wvNormFC (clx->pcd[piececount].fc, &type);

    if (type)
	*end = *begin + (clx->pos[piececount + 1] - clx->pos[piececount]);
    else
	*end = *begin + ((clx->pos[piececount + 1] - clx->pos[piececount]) * 2);

    return (type);
}


int wvGetPieceBoundsCP (uint32_t * begin, uint32_t * end, CLX * clx, uint32_t piececount)
{
  if ((piececount + 1) > clx->nopcd)
	return (-1);
  *begin = clx->pos[piececount];
  *end = clx->pos[piececount + 1];
return (0);
}


uint32_t wvGetEndFCPiece (uint32_t piece, CLX * clx)
{
    int flag;
    uint32_t fc;
    uint32_t offset = clx->pos[piece + 1] - clx->pos[piece];

    wvTrace (("offset is %x, befc is %x\n", offset, clx->pcd[piece].fc));
    fc = wvNormFC (clx->pcd[piece].fc, &flag);
    wvTrace (("fc is %x, flag %d\n", fc, flag));
    if (flag)
	fc += offset;
    else
	fc += offset * 2;
    wvTrace (("fc is finally %x\n", fc));
    return (fc);
}


int wvQuerySamePiece (uint32_t fcTest, CLX * clx, uint32_t piece)
{
    /*
       wvTrace(("Same Piece, %x %x %x\n",fcTest,wvNormFC(clx->pcd[piece].fc,NULL),wvNormFC(clx->pcd[piece+1].fc,NULL)));
       if ( (fcTest >= wvNormFC(clx->pcd[piece].fc,NULL)) && (fcTest < wvNormFC(clx->pcd[piece+1].fc,NULL)) )
     */
    wvTrace (("Same Piece, %x %x %x\n", fcTest, clx->pcd[piece].fc,wvGetEndFCPiece (piece, clx)));
    if ((fcTest >= wvNormFC (clx->pcd[piece].fc, NULL))
	&& (fcTest < wvGetEndFCPiece (piece, clx)))
	return (1);
    return (0);
}


uint32_t wvGetPieceFromCP (uint32_t currentcp, CLX * clx)
{
    uint32_t i = 0;
    while (i < clx->nopcd)
      {
	  wvTrace (("i %d: currentcp is %d, clx->pos[i] is %d, clx->pos[i+1] is %d\n", i, currentcp, clx->pos[i], clx->pos[i + 1]));
	  if ((currentcp >= clx->pos[i]) && (currentcp < clx->pos[i + 1]))
	      return (i);
	  i++;
      }
    wvTrace (("cp was not in any piece ! \n", currentcp));
    return (0xffffffffL);
}


/*
1) search for the piece containing the character in the piece table.

2) Then calculate the FC in the file that stores the character from the piece
    table information.
*/
uint32_t wvConvertCPToFC (uint32_t currentcp, CLX * clx)
{
uint32_t currentfc = 0xffffffffL;
uint32_t i = 0;
int flag;

    while (i < clx->nopcd)
      {
	  if ((currentcp >= clx->pos[i]) && (currentcp < clx->pos[i + 1]))
	    {
		currentfc = wvNormFC (clx->pcd[i].fc, &flag);
		if (flag)
		    currentfc += (currentcp - clx->pos[i]);
		else
		    currentfc += ((currentcp - clx->pos[i]) * 2);
		break;
	    }
	  i++;
      }

    if (currentfc == 0xffffffffL)
      {
	  i--;
	  currentfc = wvNormFC (clx->pcd[i].fc, &flag);
	  if (flag)
	      currentfc += (currentcp - clx->pos[i]);
	  else
	      currentfc += ((currentcp - clx->pos[i]) * 2);
	  wvTrace (("flaky cp to fc conversion underway\n"));
      }

return (currentfc);
}

struct test {
    uint32_t fc;
    uint32_t offset;
};


/*In word 95 files there is no flag attached to each offset as there is in word 97 to tell you that we are
talking about 16 bit chars, so I attempt here to make an educated guess based on overlapping offsets to
figure it out, If I had some actual information as the how word 95 actually stores it it would help.*/
/*
static int wvGuess16bit (PCD * pcd, uint32_t * pos, uint32_t nopcd)
{
    struct test *fcs;
    uint32_t i;
    int ret = 1;
    fcs = (struct test *) malloc (sizeof (struct test) * nopcd);
    for (i = 0; i < nopcd; i++)
      {
	  fcs[i].fc = pcd[i].fc;
	  fcs[i].offset = (pos[i + 1] - pos[i]) * 2;
      }

    qsort (fcs, nopcd, sizeof (struct test), compar);

    for (i = 0; i < nopcd - 1; i++)
      {
	  if (fcs[i].fc + fcs[i].offset > fcs[i + 1].fc)
	    {
		wvTrace (("overlap, my guess is 8 bit\n"));
		ret = 0;
		break;
	    }
      }

    free (fcs);
    return (ret);
}*/
//--------End of CLX processing----------



/* The standard SEP is all zeros except as follows:
 bkc           2 (new page)
 dyaPgn        720 twips (equivalent to .5 in)
 dxaPgn        720 twips
 fEndnote      1 (True)
 fEvenlySpaced 1 (True)
 xaPage        12240 twips
 yaPage        15840 twips
 xaPageNUp     12240 twips
 yaPageNUp     15840 twips
 dyaHdrTop     720 twips
 dyaHdrBottom  720 twips
 dmOrientPage  1 (portrait orientation)
 dxaColumns    720 twips
 dyaTop        1440 twips
 dxaLeft       1800 twips
 dyaBottom     1440 twips
 dxaRight      1800 twips
 pgnStart      1
cbSEP (count of bytes of SEP) is 704(decimal), 2C0(hex). */
void wvInitSEP (SEP * item)
{
  memset(item,0,sizeof(*item));

  item->bkc = 2;
  item->fEndNote = 1;
  item->dxaPgn = 720;
  item->dyaPgn = 720;

  wvInitBRC (&item->brcTop);
  wvInitBRC (&item->brcLeft);
  wvInitBRC (&item->brcBottom);
  wvInitBRC (&item->brcRight);

  wvInitDTTM (&item->dttmPropRMark);

  item->pgnStart = 1;
  item->xaPage = 12240;
  item->yaPage = 15840;
  item->xaPageNUp = 12240;
  item->yaPageNUp = 15840;
  item->dxaLeft = 1800;
  item->dxaRight = 1800;
  item->dyaTop = 1440;
  item->dyaBottom = 1440;
  item->dyaHdrTop = 720;
  item->dyaHdrBottom = 720;
  item->fEvenlySpaced = 1;
  item->dxaColumns = 720;
  wvInitOLST (&item->olstAnm);
}


void wvGetSEPX(SEPX * item, FILE * fd)
{
uint16_t i;
  Rd_word(fd,&item->cb);

  if (item->cb)
      item->grpprl = (uint8_t *) malloc (item->cb);
  else
      item->grpprl = NULL;

  for (i = 0; i < item->cb; i++)
      {
      item->grpprl[i] = fgetc(fd);
      wvTrace (("sep is %x\n", item->grpprl[i]));
      }
}


void wvReleaseSEPX (SEPX * item)
{
  free(item->grpprl);
}


int wvAddSEPXFromBucket (SEP * asep, SEPX * item, STSH * stsh)
{
    uint8_t *pointer;
    uint16_t i = 0;
    uint16_t sprm;
    int ret = 0;
    Sprm RetSprm;
#ifdef SPRMTEST
    fprintf (stderr, "\n");
    while (i < item->cb)
      {
	  fprintf (stderr, "%x (%d) ", *(item->grpprl + i),
		   *(item->grpprl + i));
	  i++;
      }
    fprintf (stderr, "\n");
    i = 0;
#endif
    while (i < item->cb - 2)
      {
	  sprm = bread_16ubit (item->grpprl + i, &i);
	  pointer = item->grpprl + i;
	  RetSprm =
	      wvApplySprmFromBucket (8, sprm, NULL, NULL, asep, stsh,
				     pointer, &i, NULL);
	  if (RetSprm.sgc == sgcSep)
	      ret = 1;
      }
    return (ret);
}


int wvAddSEPXFromBucket6 (SEP * asep, SEPX * item, STSH * stsh)
{
    uint8_t *pointer;
    uint16_t i = 0;
    int ret = 0;
    uint8_t sprm8;
    uint16_t sprm;
    Sprm RetSprm;
#ifdef SPRMTEST
    fprintf (stderr, "\n");
    while (i < item->cb)
      {
	  fprintf (stderr, "%x (%d) ", *(item->grpprl + i),
		   *(item->grpprl + i));
	  i++;
      }
    fprintf (stderr, "\n");
    i = 0;
#endif
    while (i < item->cb)
      {
	  sprm8 = bread_8ubit (item->grpprl + i, &i);
#ifdef SPRMTEST
	  wvError (("sep word 6 sprm is %x (%d)\n", sprm8, sprm8));
#endif
	  sprm = (uint16_t) wvGetrgsprmWord6 (sprm8);
#ifdef SPRMTEST
	  wvTrace (("sep word 6 sprm is converted to %x\n", sprm));
#endif
	  pointer = item->grpprl + i;
	  RetSprm =
	      wvApplySprmFromBucket(6, sprm, NULL, NULL, asep, stsh,
				     pointer, &i, NULL);
	  if (RetSprm.sgc == sgcSep)
	      ret = 1;
      }
    return (ret);
}


//--------End of SEP processing----------


static void wvGetSED (SED * item, FILE * fd)
{
  Rd_word(fd,(uint16_t *)&item->fn);
  Rd_dword(fd,(uint32_t *)&item->fcSepx);
  Rd_word(fd,(uint16_t *)&item->fnMpr);
  Rd_dword(fd,&item->fcMpr);
}


int wvGetSED_PLCF (SED ** item, uint32_t ** pos, uint32_t * noitem, uint32_t offset, uint32_t len, FILE * fd)
{
    uint32_t i;
    if (len == 0)
      {
	  *item = NULL;
	  *pos = NULL;
	  *noitem = 0;
      }
    else
      {
	  *noitem = (len - 4) / (cbSED + 4);
	  *pos = (uint32_t *) malloc((*noitem + 1) * sizeof (uint32_t));
	  if (*pos == NULL)
	    {
		//wvError (("NO MEM 1, failed to alloc %d bytes\n",(*noitem + 1) * sizeof (uint32_t)));
		return (1);
	    }

	  *item = (SED *) malloc(*noitem * sizeof (SED));
	  if (*item == NULL)
	    {
		//wvError (("NO MEM 1, failed to alloc %d bytes\n",*noitem * sizeof (SED)));
		free(*pos);
		return (1);
	    }
	  fseek(fd, offset, SEEK_SET);
	  for (i = 0; i <= *noitem; i++)
	       Rd_dword(fd,&(*pos)[i]);
	  for (i = 0; i < *noitem; i++)
	      wvGetSED (&((*item)[i]), fd);
      }
    return (0);
}


//--------End of SED processing----------

static void wvInitSTD (STD * item)
{
  memset(item,0,sizeof(*item));
  item->istdBase = istdNil;
}


static void wvReleaseSTD (STD * item)
{
uint8_t i;
  if (!item) return;
  free(item->xstzName);

  for (i = 0; i < item->cupx; i++)
	{
	if (item->grupxf[i].cbUPX == 0)
	      continue;

	if ((item->cupx == 1) || ((item->cupx == 2) && (i == 1)))
		free(item->grupxf[i].upx.chpx.grpprl);
	else if ((item->cupx == 2) && (i == 0))
		free(item->grupxf[i].upx.papx.grpprl);
	}

  if (item->sgc == sgcChp)
      if (item->grupe)
  wvReleaseCHPX (&(item->grupe[0].chpx));
  free (item->grupxf);
  free (item->grupe);
}


void wvReleaseSTSH (STSH * item)
{
int i;
  for (i = 0; i < item->Stshi.cstd; i++)
     {
     wvTrace (("Releasing %d std\n", i));
     wvReleaseSTD(&(item->std[i]));
     }
  free(item->std);
}

static void wvInitSTSHI(STSHI * item)
{
  memset(item,0,sizeof(*item));
}

void wvInitSTSH(STSH * item)
{
  wvInitSTSHI(&item->Stshi);
  item->std=NULL;
}

/*modify this to handle cbSTSHI < the current size*/
static void wvGetSTSHI (STSHI * item, uint16_t cbSTSHI, FILE * fd)
{
uint16_t temp16;
int i;
uint16_t count = 0;

    wvInitSTSHI (item);		/* zero any new fields that might not exist in the file */

    Rd_word(fd,&item->cstd);
    count += 2;
    wvTrace (("there are %d std\n", item->cstd));
    Rd_word(fd,&item->cbSTDBaseInFile);
    count += 2;
    Rd_word(fd,&temp16);
    count += 2;
    item->fStdStylenamesWritten = temp16 & 0x01;
    item->reserved = (temp16 & 0xfe) >> 1;
    Rd_word(fd,&item->stiMaxWhenSaved);
    count += 2;
    Rd_word(fd,&item->istdMaxFixedWhenSaved);
    count += 2;
    Rd_word(fd,&item->nVerBuiltInNamesWhenSaved);
    count += 2;
    for (i = 0; i < 3; i++)
      {
	  Rd_word(fd,&item->rgftcStandardChpStsh[i]);
	  count += 2;
	  if (count >= cbSTSHI)
		     break;
      }

    while (count < cbSTSHI)
      {
	  fgetc(fd);
	  count++;
      }
}


static int wvGetSTD (STD * item, uint16_t baselen, uint16_t fixedlen, FILE * fd)
{
uint16_t temp16;
uint16_t len, i, j;
int pos;
int ret = 0;
uint16_t count = 0;

    wvInitSTD (item);		/* zero any new fields that might not exist in the file */

    wvTrace (("baselen set to %d fixed part len is %d\n", baselen, fixedlen));

    Rd_word(fd,&temp16);
    count += 2;
    item->sti = temp16 & 0x0fff;
    item->fScratch = (temp16 & 0x1000) >> 12;
    item->fInvalHeight = (temp16 & 0x2000) >> 13;
    item->fHasUpe = (temp16 & 0x4000) >> 14;
    item->fMassCopy = (temp16 & 0x8000) >> 15;
    Rd_word(fd,&temp16);
    count += 2;
    item->sgc = temp16 & 0x000f;
    item->istdBase = (temp16 & 0xfff0) >> 4;
    Rd_word(fd,&temp16);
    count += 2;
    item->cupx = temp16 & 0x000f;
    item->istdNext = (temp16 & 0xfff0) >> 4;
    Rd_word(fd,&item->bchUpe);
    count += 2;
    if (count < baselen)	/* word 6 has only a count of 8 */
      {
	  Rd_word(fd,&temp16);
	  count += 2;
	  item->fAutoRedef = temp16 & 0x0001;
	  item->fHidden = (temp16 & 0x0002) >> 1;
	  item->reserved = (temp16 & 0xfffc) >> 2;

	  while (count < baselen)	/* eat any new fields we might know about ourselves */
	    {
		fgetc(fd);
		count++;
	    }
      }
    wvTrace (("count is %d, baselen is %d\n", count, baselen));


    pos = 10;


    if (count < 10)
      {
	  ret = 1;
	  len = fgetc(fd);
	  pos++;
      }
    else
      {
	  Rd_word(fd,&len);
	  pos += 2;
	  wvTrace (("%x %x %x %x\n", fixedlen, baselen, fixedlen - baselen, len));
	  if (fixedlen - baselen < len)
	    {
//		wvWarning ("The names of the styles are not stored in unicode as is usual for this version, going to 8 bit\n");
		fseek(fd, -2, SEEK_CUR);
		len = fgetc(fd);
		count = 9;	/* to fake the later char reader code */
		pos--;
	    }
      }

    wvTrace (("doing a std, str len is %d\n", len + 1));

    if(len=0xFFFF) len=0xFFFE;	// JFO prevent uint16 overflow.
    item->xstzName = (char *)malloc(((size_t)len + 1) * sizeof (char));

    for(i=0; i<len+1; i++)
      {
	  if (count < 10)
	    {
		item->xstzName[i] = fgetc(fd);
		pos++;
	    }
	  else
	    {
			/* DOM: is this correct? */
		item->xstzName[i] = ( char ) fgetc(fd);
		fgetc(fd);
		pos += 2;
	    }

	  wvTrace (("sample letter is %c\n", item->xstzName[i]));
          if(feof(fd)) break;
      }
    wvTrace (("string ended\n"));


    wvTrace (("cupx is %d\n", item->cupx));
    if (item->cupx == 0)
      {
	  item->grupxf = NULL;
	  item->grupe = NULL;
	  return (0);
      }

    item->grupxf = (UPXF *)malloc(sizeof (UPXF) * item->cupx);
    if (item->grupxf == NULL)
      {
//	  wvError (("Couuldn't alloc %d bytes for UPXF\n", sizeof (UPXF) * item->cupx));
	  return (0);
      }

    item->grupe = (UPE *)malloc(sizeof (UPE) * item->cupx);
    if (item->grupe == NULL)
      {
//	  wvError (("Couuldn't alloc %d bytes for UPE\n", sizeof (UPE) * item->cupx));
	  return (0);
      }

    for (i = 0; i < item->cupx; i++)
      {
	  if ((pos + 1) / 2 != pos / 2)
	    {
		/*eat odd bytes */
		fseek(fd, 1, SEEK_CUR);
		pos++;
	    }

	  Rd_word(fd,&item->grupxf[i].cbUPX);
	  wvTrace (("cbUPX is %d\n", item->grupxf[i].cbUPX));
	  pos += 2;

	  if (item->grupxf[i].cbUPX == 0)
	      continue;

	  if ((item->cupx == 1) || ((item->cupx == 2) && (i == 1)))
	    {
		item->grupxf[i].upx.chpx.grpprl =
		    (uint8_t *)malloc(item->grupxf[i].cbUPX);
		for (j = 0; j < item->grupxf[i].cbUPX; j++)
		  {
		      int ch = fgetc(fd);
		      if(ch<0)			// EOF bailout	fixed by JFO
		      {
			item->grupxf[i].upx.chpx.grpprl[j] = 0;
			item->grupxf[i].cbUPX = j;
		        break;
		      }
		      item->grupxf[i].upx.chpx.grpprl[j] = ch;
		      pos++;
		  }
	    }
	  else if ((item->cupx == 2) && (i == 0))
	    {
		Rd_word(fd,&item->grupxf[i].upx.papx.istd);
		pos += 2;
		if (item->grupxf[i].cbUPX - 2)
		    item->grupxf[i].upx.papx.grpprl =
			(uint8_t *)malloc(item->grupxf[i].cbUPX - 2);
		else
		    item->grupxf[i].upx.papx.grpprl = NULL;
		for (j = 0; j < item->grupxf[i].cbUPX - 2; j++)
		  {
		    int ch = fgetc(fd);
		    if(ch<0)			// EOF
		    {
		      item->grupxf[i].upx.papx.grpprl[j] = 0;
		      item->grupxf[i].cbUPX = j;
		      break;
		    }
		    item->grupxf[i].upx.papx.grpprl[j] = ch;
		    pos++;
		  }
	    }
	  else
	    {
		wvTrace (("Strange cupx option\n"));
		fseek(fd, item->grupxf[i].cbUPX, SEEK_CUR);
		pos += item->grupxf[i].cbUPX;
	    }
      }



    /*eat odd bytes */
    if ((pos + 1) / 2 != pos / 2)
	fseek(fd, 1, SEEK_CUR);
    return (ret);
}


static void wvGenerateStyle (STSH * item, uint16_t i, uint16_t word6)
{
  if (item->std[i].cupx == 0)
    {
	wvTrace (("Empty Slot %d\n", i));
	return;
    }

  switch (item->std[i].sgc)
    {
    case sgcPara:
	wvTrace (("doing paragraph, len is %d\n", item->std[i].grupxf[0].cbUPX));
	wvTrace (("doing paragraph, len is %d\n", item->std[i].grupxf[1].cbUPX));
	wvInitPAPFromIstd (&(item->std[i].grupe[0].apap),
			   (uint16_t) item->std[i].istdBase, item);
	if (word6)
	    wvAddPAPXFromBucket6 (&(item->std[i].grupe[0].apap),
				  &(item->std[i].grupxf[0]), item);
	else
	    wvAddPAPXFromBucket (&(item->std[i].grupe[0].apap),
				 &(item->std[i].grupxf[0]), item, NULL);
	/* data is NULL because HugePAPX cannot occur in this circumstance, according to the
	   docs */

	wvInitCHPFromIstd (&(item->std[i].grupe[1].achp),
			   (uint16_t) item->std[i].istdBase, item);

	wvTrace (("here1\n"));

	if (word6)
	    wvAddCHPXFromBucket6 (&(item->std[i].grupe[1].achp),
				  &(item->std[i].grupxf[1]), item);
	else
	    wvAddCHPXFromBucket (&(item->std[i].grupe[1].achp),
				 &(item->std[i].grupxf[1]), item);

	wvTrace (("here2\n"));

	if (item->std[i].grupe[1].achp.istd != istdNormalChar)
	  {
//	      wvWarning ("chp should have had istd set to istdNormalChar, doing it manually\n");
	      item->std[i].grupe[1].achp.istd = istdNormalChar;
	  }

	break;
    case sgcChp:
	wvInitCHPXFromIstd (&(item->std[i].grupe[0].chpx),
			    (uint16_t) item->std[i].istdBase, item);

	if(word6)
	    wvUpdateCHPXBucket (&(item->std[i].grupxf[0]));

	wvMergeCHPXFromBucket (&(item->std[i].grupe[0].chpx),
			       &(item->std[i].grupxf[0]));
	/* UPE.chpx.istd is set to the style's istd */
	item->std[i].grupe[0].chpx.istd = i;	/*? */
	break;
    default:
//	wvWarning ("New document type\n");
	break;
    }
}


void wvGetSTSH (STSH * item, uint32_t offset, uint32_t len, FILE * fd)
{
uint16_t cbStshi, cbStd, i, word6 = 0, j;
uint16_t *chains1;
uint16_t *chains2;
    if (len == 0)
      {
	  item->Stshi.cstd = 0;
	  item->std = NULL;
	  return;
      }
    wvTrace (("stsh offset len is %x %d\n", offset, len));
    fseek(fd, offset, SEEK_SET);
    Rd_word(fd,&cbStshi);
    wvGetSTSHI (&(item->Stshi), cbStshi, fd);

    if (item->Stshi.cstd == 0)
      {
	  item->std = NULL;
	  return;
      }

    chains1 = (uint16_t *)malloc(sizeof (uint16_t) * item->Stshi.cstd);
    chains2 = (uint16_t *)malloc(sizeof (uint16_t) * item->Stshi.cstd);

    item->std = (STD *)malloc(sizeof (STD) * item->Stshi.cstd);
    if(item->std==NULL || chains1==NULL || chains2==NULL)
      {
          if(chains1) {free(chains1);}
          if(chains2) {free(chains2);}
          if(item->std) {free(item->std);item->std=NULL;}
	  wvError (("No mem for STD list, of size %d\n", sizeof (STD) * item->Stshi.cstd));
	  return;
      }

    for (i = 0; i < item->Stshi.cstd; i++)
	wvInitSTD (&(item->std[i]));

    for (i = 0; i < item->Stshi.cstd; i++)
      {
	  Rd_word(fd,&cbStd);
	  wvTrace (("index is %d,cbStd is %d, should end on %x\n", i, cbStd, ftell(fd) + cbStd));
	  if (cbStd != 0)
	    {
		word6 =
		    wvGetSTD (&(item->std[i]), item->Stshi.cbSTDBaseInFile,
			      cbStd, fd);
		wvTrace ( ("istdBase is %d, type is %d, 6|8 version is %d\n", item->std[i].istdBase, item->std[i].sgc, word6));
	    }
	  wvTrace (("actually ended on %x\n", ftell(fd)));
	  chains1[i] = item->std[i].istdBase;
      }


    /*
       we will do number 10, (standard character style) first if possible,
       some evil word docs attempt illegally to use sprmCBold etc with a
       128 and 129 argument, which is supposedly not allowed, but happens
       anyway. In all examples so far it has been character style no 10 that
       they have attempted to access
     */
    if (item->std[10].istdBase == istdNil)
      {
	  wvTrace (("Generating istd no %d\n", i));
	  wvGenerateStyle (item, 10, word6);
      }
    for (i = 0; i < item->Stshi.cstd; i++)
      {
	  if ((item->std[i].istdBase == istdNil) && (i != 10))
	    {
		wvTrace (("Generating istd no %d\n", i));
		wvGenerateStyle (item, i, word6);
	    }
	  wvTrace (("1: No %d,Base is %d\n", i, chains1[i]));
      }

    j = 0;
    while (j < 11)
      {
	  int finished = 1;
	  for (i = 0; i < item->Stshi.cstd; i++)
	    {
		if ((chains1[i] != istdNil) && 
		     chains1[i] < item->Stshi.cstd &&		// JFO: Checkout overflow - This fix prevents crash.
		    (chains1[chains1[i]] == istdNil))
		  {
		      chains2[i] = istdNil;
		      wvTrace (("Generating istd no %d\n", i));
		      wvGenerateStyle (item, i, word6);
		      finished = 0;
		  }
		else
		    chains2[i] = chains1[i];
	      wvTrace (("%d: No %d, Base is %d\n", j, i, chains2[i]));
	    }
	  for (i = 0; i < item->Stshi.cstd; i++)
	      chains1[i] = chains2[i];
	  if (finished)
	      break;
	  j++;
      }

  free(chains1);
  free(chains2);
}


//--------End of STSH processing----------


static void wvGetBX (BX * item, uint8_t * page, uint16_t * pos)
{
  item->offset = bread_8ubit (&(page[*pos]), pos);
  wvGetPHE (&item->phe, 0, page, pos);
}


static void wvGetBX6 (BX * item, uint8_t * page, uint16_t * pos)
{
  item->offset = bread_8ubit (&(page[*pos]), pos);
  wvGetPHE6 (&item->phe, page, pos);
}


//--------End of BX processing----------


static PAPX_FKP wvPAPX_FKP_previous;
static uint32_t wvPAPX_pn_previous = 0;
static CHPX_FKP wvCHPX_FKP_previous;
static uint32_t wvCHPX_pn_previous = 0;


#define wvReleasePAPX_FKP(X) {}
/*static void wvReleasePAPX_FKP (PAPX_FKP * fkp)
  {return;}*/


void wvInitPAPX_FKP (PAPX_FKP * fkp)
{
  fkp->rgfc = NULL;
  fkp->rgbx = NULL;
  fkp->crun = 0;
  fkp->grppapx = NULL;
}

void wvInitCHPX_FKP (CHPX_FKP * fkp)
{
  fkp->rgfc = NULL;
  fkp->rgb = NULL;
  fkp->crun = 0;
  fkp->grpchpx = NULL;
}


void internal_wvReleasePAPX_FKP (PAPX_FKP * fkp)
{
int i;
  free(fkp->rgfc);
  fkp->rgfc = NULL;
  free(fkp->rgbx);
  fkp->rgbx = NULL;
  for (i = 0; i < fkp->crun; i++)
      wvReleasePAPX (&(fkp->grppapx[i]));
  fkp->crun = 0;
  free(fkp->grppapx);
  fkp->grppapx = NULL;
}



/* At offset 511 is a 1-byte count named crun, which is a count of paragraphs in PAPX
FKPs. Beginning at offset 0 of the FKP is an array of crun+1 FCs, named
rgfc, which records the beginning and limit FCs of crun paragraphs.

immediately following the fkp.rgfc is an array of 13 byte
entries called BXs. This array called the rgbx is in 1-to-1 correspondence
with the rgfc. The first byte of the ith BX entry contains a single byte
field which gives the word offset of the PAPX that belongs to the paragraph
whose beginning in FC space is rgfc[i] and whose limit is rgfc[i+1] in FC
space. The last 12 bytes of the ith BX entry contain a PHE structure that
stores the current paragraph height of the paragraph whose beginning in FC
space is rgfc[i] and whose limit is rgfc[i+1] in FC space. */

/* The first byte of each BX is the word offset of the PAPX recorded for
the paragraph corresponding to this BX. .. If the byte stored is 0,
this represents a 1 line paragraph 15 pixels high with Normal style
(stc == 0) whose column width is 7980 dxas. The last 12 bytes of
the BX is a PHE structure which stores the current paragraph height
for the paragraph corresponding to the BX. If a plcfphe has an entry
that maps to the FC for this paragraph, that entry's PHE overrides the PHE
stored in the FKP.11*fkp.crun+4 unused space. As new runs/paragraphs
are recorded in the FKP, unused space is reduced by 17 if CHPX/PAPX
is already recorded and is reduced by 17+sizeof(PAPX) if property is not
already recorded. */
void wvGetPAPX_FKP (int ver, PAPX_FKP * fkp, uint32_t pn, FILE * fd)
{
    int i;
    uint8_t page[WV_PAGESIZE];
    uint16_t pos = 0;
    /*size_t bytes_read; */

    /* brian.ewins@bt.com */
    /* there seem to be a lot of repeat calls... */
    /* pn=0 is safe because thats the index block, not a PAPX_FKP */
    if (pn != 0 && pn == wvPAPX_pn_previous)
      {
	  memcpy (fkp, &wvPAPX_FKP_previous, sizeof (PAPX_FKP));
	  return;
      }

    wvTrace (("seeking to %x to get crun\n", pn * WV_PAGESIZE + (WV_PAGESIZE - 1)));
    fseek(fd, pn * WV_PAGESIZE, SEEK_SET);
    /*bytes_read= */ fread(page, WV_PAGESIZE, 1, fd);
    fkp->crun = (uint8_t) page[WV_PAGESIZE - 1];
    fkp->rgfc = (uint32_t *)malloc(sizeof (uint32_t) * (fkp->crun + 1));
    fkp->rgbx = (BX *)malloc(sizeof (BX) * (fkp->crun));
    fkp->grppapx = (PAPX *)malloc(sizeof (PAPX) * (fkp->crun));
    for(i=0; i<fkp->crun+1; i++)
      {
	  fkp->rgfc[i] = bread_32ubit (&(page[pos]), &pos);
	  wvTrace (("rgfc is %x\n", fkp->rgfc[i]));
      }

    for (i = 0; i < fkp->crun; i++)
      {
	  if (ver == 8)
	      wvGetBX (&fkp->rgbx[i], page, &pos);
	  else
	      wvGetBX6 (&fkp->rgbx[i], page, &pos);
      }

    for (i = 0; i < fkp->crun; i++)
      {
	  if (fkp->rgbx[i].offset == 0)
	    {
		wvTrace (("i is %d, using clear papx\n", i));
		wvInitPAPX (&(fkp->grppapx[i]));
	    }
	  else
	    {
		wvTrace (("papx index i is %d, offset is %x\n", i, pn * WV_PAGESIZE + fkp->rgbx[i].offset * 2));
		pos = fkp->rgbx[i].offset * 2;
		wvGetPAPX (ver, &(fkp->grppapx[i]), page, &pos);
	    }
      }
    if (wvPAPX_pn_previous != 0)
	internal_wvReleasePAPX_FKP (&wvPAPX_FKP_previous);
    memcpy (&wvPAPX_FKP_previous, fkp, sizeof (PAPX_FKP));
    wvPAPX_pn_previous = pn;
}

#define wvReleaseCHPX_FKP(XX) {}
/*static void wvReleaseCHPX_FKP (CHPX_FKP * fkp)
{
  return;
}*/


void internal_wvReleaseCHPX_FKP (CHPX_FKP * fkp)
{
int i;
    wvTrace (("chpx fkp b freeed\n"));
    free(fkp->rgfc);
    fkp->rgfc = NULL;
    free(fkp->rgb);
    fkp->rgb = NULL;
    for (i = 0; i < fkp->crun; i++)
	wvReleaseCHPX (&(fkp->grpchpx[i]));
    fkp->crun = 0;
    free(fkp->grpchpx);
    fkp->grpchpx = NULL;
    wvTrace (("chpx fkp e freeed\n"));
}



/* Character properties
 * -basically just like PAPX FKPs above
 * however, rather than an array of BX structs in rgbx,
 * there is an array of bytes (giving the word offset to the CHPX) in rgb
 * -JB */
void wvGetCHPX_FKP(CHPX_FKP * fkp, uint32_t pn, FILE * fd)
{
int i;
uint8_t page[WV_PAGESIZE];
uint16_t pos = 0;
    /*size_t bytes_read; */

    /* brian.ewins@bt.com */
    /* there seem to be a lot of repeat calls... */
    /* pn=0 is safe because thats the index block, not a CHPX_FKP */
    if (pn != 0 && pn == wvCHPX_pn_previous)
      {
	  memcpy (fkp, &wvCHPX_FKP_previous, sizeof (CHPX_FKP));
	  return;
      }
    fseek(fd, pn * WV_PAGESIZE, SEEK_SET);
    /*bytes_read= */ fread(page, WV_PAGESIZE, 1, fd);
    fkp->crun = (uint8_t) page[WV_PAGESIZE - 1];
    wvTrace (("chpx fkp gone to %x\n", pn * WV_PAGESIZE + (WV_PAGESIZE - 1)));
    wvTrace (("crun is %d\n", fkp->crun));
    fkp->rgfc = (uint32_t *)malloc(sizeof (uint32_t) * (fkp->crun + 1));
    fkp->rgb = (uint8_t *)malloc(sizeof (uint8_t) * (fkp->crun));
    fkp->grpchpx = (CHPX *)malloc(sizeof(CHPX)*(fkp->crun));
    fseek(fd, pn * WV_PAGESIZE, SEEK_SET);
    wvTrace (("offset is %x\n", pn * WV_PAGESIZE));
    for (i = 0; i < fkp->crun + 1; i++)
      {
	  fkp->rgfc[i] = bread_32ubit (&(page[pos]), &pos);
	  wvTrace (("rgfc is %x\n", fkp->rgfc[i]));
      }

    for (i = 0; i < fkp->crun; i++)
	fkp->rgb[i] = bread_8ubit (&(page[pos]), &pos);

    for (i = 0; i < fkp->crun; i++)
      {
	  if (fkp->rgb[i] == 0)
	    {
		wvTrace (("i is %d, using clear chpx\n", i));
		wvInitCHPX (&(fkp->grpchpx[i]));
	    }
	  else
	    {
		wvTrace (("chpx index i is %d, offset is %x\n", i, (pn * WV_PAGESIZE) + (fkp->rgb[i] * 2)));
		pos = fkp->rgb[i] * 2;
		wvGetCHPX(&(fkp->grpchpx[i]), page, &pos);
	    }
      }
    if (wvCHPX_pn_previous != 0)
	internal_wvReleaseCHPX_FKP (&wvCHPX_FKP_previous);
    memcpy (&wvCHPX_FKP_previous, fkp, sizeof (CHPX_FKP));
    wvCHPX_pn_previous = pn;
}


int wvGetIndexFCInFKP_PAPX (PAPX_FKP * fkp, uint32_t currentfc)
{
uint32_t i = 1;			/*was 0, there is something slightly out of sync in the system */
uint8_t until = fkp->crun + 1;

    while (i < until)
      {
	  wvTrace (("current fc is %x, %x, %x\n", currentfc, wvNormFC (fkp->rgfc[i], NULL), fkp->rgfc[i]));
	  if (wvNormFC (fkp->rgfc[i], NULL) == currentfc)
	      return (i);
	  i++;
      }
    /* basically read
       Algorithm to determine paragraph properties for a paragraph &
       Formatted Disk Page for PAPXs, somehow the currentfc sent in was wrong
       or my understanding is !  */
    wvTrace (("Shite, fix me %x %x\n", currentfc, fkp->rgfc[0]));
    /*return 1 to make things continue on their merry way */
 return (1);
}


/* Using the FC, search the FCs FKP for the largest FC less than the character's FC,
   call it fcTest. */
uint32_t wvSearchNextLargestFCPAPX_FKP (PAPX_FKP * fkp, uint32_t currentfc)
{
uint32_t i = 0;
uint8_t until = fkp->crun + 1;
uint32_t fcTest = 0;

    while (i < until)
      {
	  wvTrace (("searching fkp %x %x\n", currentfc, fkp->rgfc[i]));
	  if ((wvNormFC (fkp->rgfc[i], NULL) < currentfc)
	      && (wvNormFC (fkp->rgfc[i], NULL) > fcTest))
	      fcTest = wvNormFC (fkp->rgfc[i], NULL);
	  else if (wvNormFC (fkp->rgfc[i], NULL) == currentfc)
	      fcTest = currentfc + 1;
	  i++;
      }

    /*for the first paragraph return the current pos as the beginning */
    /*
       if (fcTest == 0)
       fcTest = currentfc+1;
     */

    return (fcTest);
}



/* Using the FC of the character, first search the FKP that describes the
character to find the smallest FC in the rgfc that is larger than the character
FC. */
uint32_t wvSearchNextSmallestFCPAPX_FKP (PAPX_FKP * fkp, uint32_t currentfc)
{
uint32_t i = 0;
uint32_t fcTest = 0xffffffffL;
uint8_t until = fkp->crun + 1;

    while (i < until)
      {
	  wvTrace (
		   ("Smallest %x, %x %x\n", currentfc,
		    wvNormFC (fkp->rgfc[i], NULL), wvNormFC (fkp->rgfc[i],
							     NULL)));
	  if ((wvNormFC (fkp->rgfc[i], NULL) > currentfc)
	      && (wvNormFC (fkp->rgfc[i], NULL) < fcTest))
	      fcTest = wvNormFC (fkp->rgfc[i], NULL);
	  i++;
      }
    return (fcTest);
}




//--------End of FKP processing----------


static void wvInitBTE (BTE * bte)
{
  bte->pn = 0;
  bte->unused = 0;
}


static void wvCopyBTE (BTE * dest, BTE * src)
{
  memcpy (dest, src, sizeof(BTE));
}


int wvGetBTE_FromFC (BTE * bte, uint32_t currentfc, BTE * list, uint32_t * fcs, int nobte)
{
int i = 0;
  if(list==NULL) return 1;

  while (i < nobte)
     {
     if ((currentfc >= wvNormFC (fcs[i], NULL))
	      && (currentfc < wvNormFC (fcs[i + 1], NULL)))
	    {
		wvTrace (("valid\n"));
		wvCopyBTE (bte, &list[i]);
		return (0);
	    }
	  i++;
      }
  wvCopyBTE (bte, &list[i - 1]);
  return (0);
/*  return(1); */
}


int wvGetBTE_PLCF6(BTE ** bte, uint32_t ** pos, uint32_t * nobte, uint32_t offset, uint32_t len, FILE * fd)
{
uint32_t i;
  if (len == 0)
    {
	*bte = NULL;
	*pos = NULL;
	*nobte = 0;
    }
  else
    {
	wvTrace (("offset is %x, len is %d\n", offset, len));
	*nobte = (len - 4) / (cb6BTE + 4);
	wvTrace (("no of bte is %d at %x\n", *nobte, offset));
	*pos = (uint32_t *)malloc((*nobte + 1) * sizeof (uint32_t));
	if (*pos == NULL)
	  {
//      wvError (("NO MEM 1, failed to alloc %d bytes\n",(*nobte + 1) * sizeof (uint32_t)));
	      return (1);
	  }

	*bte = (BTE *)malloc(*nobte * sizeof (BTE));
	if (*bte == NULL)
	  {
//	      wvError (("NO MEM 1, failed to alloc %d bytes\n",*nobte * sizeof (BTE)));
	      free(pos);
	      return (1);
	  }
	fseek(fd, offset, SEEK_SET);
	for (i = 0; i <= *nobte; i++)
	  {
	      Rd_dword(fd,&(*pos)[i]);
	      wvTrace (("pos is %x\n", (*pos)[i]));
	  }
	for (i = 0; i < *nobte; i++)
	  {
	      wvInitBTE (&((*bte)[i]));
	      Rd_dword(fd,&(*bte)[i].pn);
	  }
    }
  return (0);
}


static void wvGetBTE (BTE * bte, FILE * fd)
{
uint32_t temp32;

    Rd_dword(fd,&temp32);
#ifdef PURIFY
    wvInitBTE (bte);
#endif
    bte->pn = temp32 & 0x003fffffL;
    bte->unused = (temp32 & 0xffc00000L) >> 22;
}


int wvGetBTE_PLCF(BTE ** bte, uint32_t ** pos, uint32_t * nobte, uint32_t offset, uint32_t len, FILE * fd)
{
uint32_t i;
  if (len == 0)
    {
	*bte = NULL;
	*pos = NULL;
	*nobte = 0;
    }
  else
    {
	*nobte = (len - 4) / (cbBTE + 4);
	wvTrace (("no of bte is %d at %x\n", *nobte, offset));
	*pos = (uint32_t *)malloc((*nobte + 1) * sizeof (uint32_t));
	if (*pos == NULL)
	  {
//	      wvError ( ("NO MEM 1, failed to alloc %d bytes\n",(*nobte + 1) * sizeof (uint32_t)));
	      return (1);
	  }

	*bte = (BTE *)malloc(*nobte * sizeof (BTE));
	if (*bte == NULL)
	  {
//      wvError (("NO MEM 1, failed to alloc %d bytes\n",*nobte * sizeof (BTE)));
	      free(*pos);
	      return (1);
	  }
	fseek(fd, offset, SEEK_SET);
	for (i = 0; i <= *nobte; i++)
	    Rd_dword(fd,&(*pos)[i]);
	for (i = 0; i < *nobte; i++)
	    wvGetBTE (&((*bte)[i]), fd);
    }
  return (0);
}


//--------End of BTE processing----------
