/******************************************************************************
 * program:     wp2latex                                                      *
 * function:    convert Macintosh WordPerfect 3.x & 4.x files into LaTeX      *
 * modul:       pass1_3.cc                                                    *
 * description: This modul contains functions for first pass. In the first    *
 *              pass information of the WP binary file will splitted in two   *
 *              parts:                                                        *
 *              1) A text file containing the whole text. The special WP      *
 *                 characters are translated.                                 *
 *              2) A binary file which contains information about             *
 *                 environments, tabbings, line endings                       *
 * licency:     GPL		                                              *
 ******************************************************************************/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include <ctype.h>

#include <sets.h>
#include <lists.h>
#include <strings.h>
#include <stacks.h>
#include "wp2latex.h"

#ifdef __UNIX__
 #include <unistd.h>
#endif

#include "cp_lib/cptran.h"
#include "cp_lib/macroman.trn"


typedef struct
	{
	DWORD  ResDataOffset;
	DWORD  ResMapOffset;
	DWORD  ResDataSize;
	DWORD  ResMapSize;
	} ResourceHdr3;

class TconvertedPass1_WP3: public TconvertedPass1
     {
public:
     CpTranslator *MacRoman;
     WORD ResIDCount;
     DWORD ResIdArea;
     ResourceHdr3 res;

     virtual int Convert_first_pass(void);

     stack UndoRedo;
     };


/** Register translators here. */
TconvertedPass1 *Factory_WP3(void) {return new TconvertedPass1_WP3;}
FFormatTranslator FormatWP3("WP3.x",Factory_WP3);


#ifndef FINAL
void CrackObject(TconvertedPass1 *cq, DWORD end_of_code);
#endif

static void ProcessKeyWP3(TconvertedPass1_WP3 *cq);
static const char *ExtendedCharacter3(TconvertedPass1_WP3 *cq);

extern list UserLists;

extern set filter[4];
int set0_3[]={0 ___ 0xFF};	//Everything
int set1_3[]={0 ___ 0xFF};	//Header, Footer, Minipage Text
int set2_3[]={0 ___ 0x7F};	//Characters Only


static const unsigned char SizesC0[0x10] = {
  5, 8, 7, 4, 4, 7,10, 7, 4, 5, 6, 6, 7, 9, 7, 4
  };


static void Attribute3(TconvertedPass1 *cq)
{
BYTE Attribute, State;
static const signed char ConvertAttr[32] =
   {12, /* boldface */	  8,	/* italic */
    14,	/* underline */   7, 	/* outline */
     9,	/* shadow */
    -1,-1,-1,
    10, /* red line */		 13,	/* strike out */
     6, /* Subscript */ 	  5,	/* Superscript */
    11, /* Double underline */	  0,	/* Extra large  */
     1, /* Very large */	  2,	/* Large */
     3, /* Small */		  4,    /* Fine */
    15, /* Small caps */
    -1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1};

  Attribute=fgetc(cq->wpd);
  State=fgetc(cq->wpd);

  if(Attribute>=32) return;
  if(ConvertAttr[Attribute]<0) return;	//unsupported attribute

  if(State==0x80) Attr_OFF(cq,ConvertAttr[Attribute]);
  if(State==0x01) Attr_ON(cq,ConvertAttr[Attribute]);
}


static DWORD SelectImageResource3(TconvertedPass1_WP3 *cq, int ResourceNo)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#SelectImageResource3(%d) ",ResourceNo);fflush(cq->log);
#endif
int ResCounter=0;

 if(cq->ResIdArea!=0)
   {
   if(fseek(cq->wpd,cq->ResIdArea,SEEK_SET)!=0) goto ResErr;

   for(ResCounter=0; ResCounter<cq->ResIDCount; ResCounter++)
     {
     WORD ResID;
     WORD ResNameOffset;
     DWORD ResAttrDataOffs;
     DWORD ResReserved;		//4 bytes 0 (reserved for handle to resource)

     RdWORD_HiEnd(&ResID, cq->wpd);
     RdWORD_HiEnd(&ResNameOffset, cq->wpd);
     RdDWORD_HiEnd(&ResAttrDataOffs, cq->wpd);
     RdDWORD_HiEnd(&ResReserved, cq->wpd);

     if(ResID==ResourceNo)
       {
       DWORD ResourceSize;
       fseek(cq->wpd, (ResAttrDataOffs&0xFFFFFF) + cq->res.ResDataOffset + 16,
	     SEEK_SET);
       if(feof(cq->wpd)) break;
       RdDWORD_HiEnd(&ResourceSize, cq->wpd);
       return ResourceSize;
       }
     }
  }

ResErr:
 cq->perc.Hide();
 fprintf(cq->err, _("\nError: Resource #%d cannot be read!"),(int)ResourceNo);
 fflush(stdout);
 return(0);
}


/**This procedure scans resources stored in the packet area*/
static void WalkResources3(TconvertedPass1_WP3 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#WalkResources3() ");fflush(cq->log);
#endif
DWORD pos1;
DWORD resLen;
WORD resTypes;
int ResCounter=0;

 cq->ResIDCount = 0;
 cq->ResIdArea = 0;

 fseek(cq->wpd,16,SEEK_SET);
 RdDWORD_HiEnd(&cq->res.ResDataOffset, cq->wpd);
 RdDWORD_HiEnd(&cq->res.ResMapOffset, cq->wpd);
 RdDWORD_HiEnd(&cq->res.ResDataSize, cq->wpd);
 RdDWORD_HiEnd(&cq->res.ResMapSize, cq->wpd);

 if(cq->log)
   fprintf(cq->log, "\nResource DataStart:%4lXh, DataSize:%4lXh, MapStart:%4lXh, MapSize:%4lXh ",
	(unsigned long)cq->res.ResDataOffset, (unsigned long)cq->res.ResDataSize, 
        (unsigned long)cq->res.ResMapOffset, (unsigned long)cq->res.ResMapSize);

 if(cq->res.ResDataOffset > cq->DocumentStart)
   {
   fprintf(cq->err, _("\nWrong resource start offset %d >= document start %d."),
      cq->res.ResDataOffset, cq->DocumentStart);
   cq->res.ResDataSize = 0;
   return;
   }

 if(cq->res.ResDataOffset+cq->res.ResDataSize > cq->DocumentStart)
   {
   fprintf(cq->err, _("\nWrong resource data size %d."),
      cq->res.ResDataSize);
   cq->res.ResDataSize = 0;
   return;
   }
  
 pos1 = cq->res.ResDataOffset + 16;
 while(pos1 >= cq->res.ResDataOffset && pos1<=(cq->res.ResDataOffset+cq->res.ResDataSize))
   {
   fseek(cq->wpd,pos1,SEEK_SET);
   if(feof(cq->wpd)) return;

   RdDWORD_HiEnd(&resLen, cq->wpd);

   if(cq->log)
     fprintf(cq->log, "\nResource #%d - ResourceStart:%4lXh(%4lXh), ResourceSize:%4lXh",
        ResCounter, (unsigned long)(pos1-cq->res.ResDataOffset-16),
        (unsigned long)pos1, (unsigned long)resLen);

   ResCounter++;
   pos1 += 4 + resLen;
  }

 if(cq->res.ResMapOffset > cq->DocumentStart)
   {
   fprintf(cq->err, _("\nWrong resource map start offset %d >= document start %d."),
      cq->res.ResMapOffset, cq->DocumentStart);
   cq->res.ResMapSize = 0;
   return;
   }
 if(cq->res.ResMapOffset+cq->res.ResMapSize > cq->DocumentStart)
   {
   fprintf(cq->err, _("\nWrong resource map data size %d."),
      cq->res.ResMapSize);
   cq->res.ResMapSize = 0;
   return;
   }

 fseek(cq->wpd,16+cq->res.ResMapOffset+16+4+2+2,SEEK_SET);
 RdWORD_HiEnd(&resTypes, cq->wpd);	// type list offset
 if(cq->log) fprintf(cq->log, "\nResTypes offset %d ", resTypes);

 pos1 = 16 + cq->res.ResMapOffset + resTypes;
 fseek(cq->wpd,pos1,SEEK_SET);		// resource type list
 RdWORD_HiEnd(&resTypes, cq->wpd);
 pos1 += 2;
 if(cq->log) fprintf(cq->log, " resTypes count %d ", resTypes+1);

 for(ResCounter=0; ResCounter<=resTypes; ResCounter++)
   {
   char ResType[5];
   WORD ResTypeCount;
   WORD ResTypeOffset;

   fread(ResType,1,4,cq->wpd); ResType[4]=0;
   RdWORD_HiEnd(&ResTypeCount, cq->wpd);
   RdWORD_HiEnd(&ResTypeOffset, cq->wpd);
   pos1 += 4+2+2;

   if(cq->log)
     fprintf(cq->log, "\nResource type #%d - ResType:%s, ResTypeCount:%4Xh, ResTypeOffset:%4Xh",
        ResCounter, ResType, ResTypeCount, ResTypeOffset);

   if(pos1>cq->DocumentStart) return;

   cq->ResIDCount += 1 + ResTypeCount;
   }

 cq->ResIdArea = ftell(cq->wpd);
 for(ResCounter=0; ResCounter<cq->ResIDCount; ResCounter++)
   {
   WORD ResID;
   WORD ResNameOffset;
   DWORD ResAttrDataOffs;
   DWORD ResReserved;		//4 bytes 0 (reserved for handle to resource)

   RdWORD_HiEnd(&ResID, cq->wpd);
   RdWORD_HiEnd(&ResNameOffset, cq->wpd);
   RdDWORD_HiEnd(&ResAttrDataOffs, cq->wpd);
   RdDWORD_HiEnd(&ResReserved, cq->wpd);
   pos1 += 2+2+4+4;

   if(cq->log)
     fprintf(cq->log, "\nResource ID:%d ResNameOffset:%Xh, ResAttr:%d, ResAttrDataOffs:%4Xh",
        ResID, ResNameOffset, ResAttrDataOffs>>24, ResAttrDataOffs&0xFFFFFF);

   if(pos1>cq->DocumentStart) return;
   }
}


void ExtractCaptionLabel3(TconvertedPass1 *_cq,const TBox & Box)
{
#ifdef DEBUG
  fprintf(_cq->log,"\n#ExtractCaptionLabel3() ");fflush(_cq->log);
#endif
TconvertedPass1_WP3 *cq;
DWORD end_of_code;
unsigned char OldFlag;

  if (Box.CaptionSize == 0) return;

  cq = (TconvertedPass1_WP3 *)_cq;
  fseek(cq->wpd, Box.CaptionPos, SEEK_SET);
  cq->ActualPos = Box.CaptionPos;
  end_of_code = cq->ActualPos + Box.CaptionSize;
  OldFlag = cq->flag;
  cq->recursion++;

  cq->flag = Nothing;
  InitAttr(cq->attr);

  while (cq->ActualPos < end_of_code)
	{
	if(fread(&cq->by, 1, 1, cq->wpd) !=1 ) break; /*Error during read*/

/*  \todo fix for referrence
	if(cq->by==0xD7)	// reference
		{
		if(fread(&cq->subby, 1, 1, cq->wpd)!=1) break;
		fseek(cq->wpd,-1,SEEK_CUR);
		if(cq->subby==8)	//convert \label{} only
			{
			cq->flag = HeaderText;
			ProcessKeyWP3(cq);
			NewLine(cq);
			FoundLabel=true;
			break;
			}
		}
*/

	ProcessKeyWP3(cq);
	}

  cq->recursion--;
  cq->flag = OldFlag;
}


void DoCaption3(TconvertedPass1 *_cq,unsigned short CaptionSize)
{
#ifdef DEBUG
  fprintf(_cq->log,"\n#DoCaption3() ");fflush(_cq->log);
#endif

  TconvertedPass1_WP3 *cq;
  DWORD end_of_code;
  unsigned char OldFlag;
  char OldEnvir;
  attribute OldAttr;
  int CaptionChars;

  if (CaptionSize == 0)
    return;

  cq = (TconvertedPass1_WP3 *)_cq;
  cq->ActualPos = ftell(cq->wpd);
  end_of_code = cq->ActualPos + CaptionSize;
  OldFlag = cq->flag;
  OldEnvir = cq->envir;
  cq->recursion++;

  OldAttr = cq->attr;
  InitAttr(cq->attr);

  cq->flag = HeaderText;
  CaptionChars=0;

  fprintf(cq->strip, "\\caption{");
  while (cq->ActualPos < end_of_code)
    {
    if(fread(&cq->by, 1, 1, cq->wpd) !=1 ) break; /*Error during read*/

    if(CaptionChars==0)
	{			// Rule out return before any character
	if((cq->by==0x0A)||(cq->by==0x0D)) cq->by=' ';
	}
    if(cq->by==0x0A) cq->by=0x0D; // Replace [HRt] by [SRt]

/* \todo fix for referrence
    if(cq->by==0xD7 && cq->subby==8)
		{
		fread(&cq->subby, 1, 1, cq->wpd);
		fseek(cq->wpd,-1,SEEK_CUR);
		if(cq->subby==8)	//Ignore \label{} in caption
			{
			cq->flag = Nothing;
			ProcessKeyWP3(cq);
			cq->flag = HeaderText;
			continue;
			}
		}
*/

    if(isalnum(cq->by)) CaptionChars++;

    ProcessKeyWP3(cq);
    }
  Close_All_Attr(cq->attr,cq->strip);
  fprintf(cq->strip, "}\n");

  cq->line_term = 's';   /* Soft return */
  Make_tableentry_envir_extra_end(cq);

  cq->recursion--;
  cq->flag = OldFlag;
  cq->envir = OldEnvir;
  cq->attr = OldAttr;
  cq->char_on_line = false;
  cq->nomore_valid_tabs = false;
  cq->rownum++;
  Make_tableentry_attr(cq);
  cq->latex_tabpos = 0;
}


/** Extract WP3.x formula string from object. */
static void ReadFormulaStr3(TconvertedPass1_WP3 *cq, string & StrBeg, DWORD end_of_code)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#ReadFormulaStr3() ");fflush(cq->log);
#endif
WORD wchr_code;
string StrEnd;

while (cq->ActualPos < end_of_code)
      {
      fread(&cq->by, 1, 1, cq->wpd);
      if (cq->by <= '\005' || cq->by == 0xEA) break;

      if (cq->by == 169) cq->by = '-';
      if (cq->by == '\n' || cq->by == '\015' || cq->by == '&' || cq->by == '~' ||
	  cq->by == '(' || cq->by == ')' || cq->by == '}' || cq->by == '{' ||
	  cq->by == '|' ||
	  (cq->by >= ' ' && cq->by <= 'z'))
	     {
	     if (cq->by == 10 || cq->by == 13) cq->by = ' ';
	     if (cq->by == '$') StrBeg += '\\';	 // $ is transformed to \$

	     StrBeg += char(cq->by);
	     if(cq->log==NULL)
		{		//small speedup
		cq->ActualPos++;
		continue;
		}
	     }
      if(cq->by == '\\')
	      {
	      StrBeg += (char)1;	//Fix \\ to inactive symbol 1
	      cq->ActualPos++;
	      continue;
	      }

      if (cq->by == 0xC0)       /*extended character*/
	    {			/*why special wp characters are in equations?*/
            Rd_word(cq->wpd, &wchr_code);
	    if((wchr_code&0xFF00) == 0x2000)
	      StrEnd = Ext_chr_str(wchr_code & 0xFF, cq, cq->MacRoman);
            else
	      StrEnd = Ext_chr_str(wchr_code, cq, cq->ConvertCpg);
	    StrBeg+=FixFormulaStrFromTeX(StrEnd, wchr_code>>8);
	    StrEnd="";

	    sprintf(cq->ObjType, "%d,%d",wchr_code & 0xFF,wchr_code>>8);
	    cq->ActualPos+=4;	//And sized only 2 (4) BYTES??

	    fread(&cq->by, 1, 1, cq->wpd);
	    if(cq->by!=0xC0)
	      {
	      cq->ActualPos--;
              if(cq->err!=NULL)
	 	{
	 	cq->perc.Hide();
	 	fprintf(cq->err,
			_("\nError: 0xC0 is not closed by its counterpart! File position=0x%X"),cq->ActualPos);
	 	}
	      }
	    continue;
	    }

      ProcessKeyWP3(cq);
      }
}


static const char *BoxNames[6]={"Figure","Table Box","Text Box","Usr Box","Equation","HTML Box"};
static void AnyBox3(TconvertedPass1_WP3 *cq, DWORD end_of_code)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#AnyBox3() ");fflush(cq->log);
#endif
typedef struct
  {
  WORD hor_position:2;	//0=Left; 1=Right; 2=Centered; 3=Left/right justified
  WORD margin:2;	//0=Relative to margins; 1=Relative to column margins; 2=Absolute
  WORD scale_width:1;	//0=scale to figure widthwise; 1=fixed width
  WORD scale_height:1;	//0=scale to figure heightwise; 1=fixed height
  WORD unknown:1;
  WORD wrap:1;		//0=Wrap text around box; 1=No text wrap around box
  WORD anchor:2;	//0=Paragraph; 1=Page; 2=Character
  WORD positioning:3;	//0=Full page; 1=Top; 2=Middle; 3=Bottom; 4=Absolute
  WORD unknown2:1;
  WORD dumping:1;	//1=Checked for dumping soft (internal use only)
  WORD BW_Color:1;	//0=B/W Pic conversion; 1=Color Pic conversion
  } FIGURE_FLAGS;

char OldEnvir;
string StrBeg,ImageName;
WORD EquLen;
BYTE OldFlag;
TBox Box;
attribute OldAttr;
int i;
//boolean AllowCaption;
char BoxType;
WORD WPGResourceNo;
FIGURE_FLAGS FF;
WORD count_xx;

  //CrackObject(cq, end_of_code); //

  initBox(Box);
  BoxType=cq->subby;
  if(BoxType>=6) {		/* Unknown Box */
		 sprintf(cq->ObjType, "!Box %d", BoxType);
		 return;
		 }
  if(BoxType==4) FormulaNo++;
  Box.Type=BoxType;

  cq->ActualPos = ftell(cq->wpd);

  fseek(cq->wpd, cq->ActualPos+14L, SEEK_SET);
  RdWORD_HiEnd((WORD *)&FF, cq->wpd);
  Box.AnchorType = FF.anchor;		/*0-Paragraph, 1-Page, 2-Character*/
  Box.HorizontalPos = FF.hor_position;	/*0-Left, 1-Right, 2-Center, 3-Full */

  //  Rd_word(cq->wpd,&EquLen);Box.Width=EquLen/47.0;

  fseek(cq->wpd, cq->ActualPos+50L, SEEK_SET);
  RdWORD_HiEnd(&WPGResourceNo, cq->wpd);

  fseek(cq->wpd, cq->ActualPos+77L, SEEK_SET);
  count_xx = fgetc(cq->wpd);		//#of subrectangles
  if(cq->ActualPos+1+count_xx*8>end_of_code)
    {
    Box.CaptionSize = 0;
    sprintf(cq->ObjType,"!%s",BoxNames[BoxType]);
    return;
    }
  else
    {
    fseek(cq->wpd, count_xx*8, SEEK_CUR);

    RdWORD_HiEnd(&count_xx, cq->wpd);	//caption length
    Box.CaptionPos = ftell(cq->wpd);

    if(count_xx+Box.CaptionPos >  end_of_code)
         Box.CaptionSize = end_of_code-Box.CaptionPos;
    else Box.CaptionSize = count_xx;

    fseek(cq->wpd, count_xx, SEEK_CUR);  // skip caption?
    }
  //printf("Box.CaptionSize:%d        ",Box.CaptionSize);


  				/* Any of section's attr cannot be opened */
  for(i=First_com_section;i<=Last_com_section;i++)
		     AttrOff(cq,i);

  OldEnvir = cq->envir;
  OldFlag = cq->flag;
  OldAttr = cq->attr;
  cq->recursion++;

//printf("\nWPG res no: %X %d       ", WPGResourceNo,(int)cq->subby);

  switch(cq->subby)
    {
    case 0: Box.Image_type=0;
	    fseek(cq->wpd, cq->ActualPos+36L, SEEK_SET);	// image orientation
	    RdWORD_HiEnd(&Box.RotAngle,cq->wpd);
	    if(Box.RotAngle & 0x8000) Box.HScale=-Box.HScale;
	    Box.RotAngle&=0xFFF;

	    if((Box.Image_size = SelectImageResource3(cq,WPGResourceNo))>0)
		{
		Box.Image_offset = ftell(cq->wpd);
	        Box.Image_type = 2;	// full file embedded
		}

//DiskImage:
	    Box.Contents = 3; // content image - every images are internally converted into WPG
	    end_of_code -= 4;

	    fseek(cq->wpd, Box.CaptionPos, SEEK_SET); // receive a caption size
	    ImageWP(cq,ImageName,Box,DoCaption3);
	    break;

    case 4: Box.Contents = 4;	  //Content equation

	    RdWORD_HiEnd(&EquLen, cq->wpd);	//text length
            StrBeg = "";

	    cq->flag = Nothing;
	    end_of_code -= 4;
            cq->ActualPos = ftell(cq->wpd);

            if (end_of_code > cq->ActualPos + EquLen)
                  end_of_code = cq->ActualPos + EquLen;

	    ReadFormulaStr3(cq, StrBeg, end_of_code);

	    InitAttr(cq->attr);
	    i = OptimizeFormulaStr(cq,StrBeg);
	    if(StrBeg=="") goto LEqEmpty;
	    if(i!=0 && Box.AnchorType==2) StrBeg+='\n';

	    cq->attr = OldAttr;

	    PutFormula(cq,StrBeg(),Box,DoCaption3,ExtractCaptionLabel3);

  /*	    if(CaptionLen>0) then
		begin
		seek(cq.wpd^,CaptionPos);
		DoCaption(cq,CaptionLen);
		end;*/
	    break;

    default:sprintf(cq->ObjType,"!%s",BoxNames[BoxType]);
	    goto UnknownEquType;
    }


LEqEmpty:
  strcpy(cq->ObjType, BoxNames[BoxType]);
UnknownEquType:
  cq->recursion--;
  if(cq->envir=='^') cq->char_on_line = -10;		// stronger false;
  cq->flag = OldFlag;
  cq->envir = OldEnvir;
  cq->attr = OldAttr;
}


static void Column3(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Column3() ");fflush(cq->log);
#endif
BYTE NoColumns;

fseek(cq->wpd, 2L, SEEK_CUR);	//skip <flags>,[non del size]
NoColumns=getc(cq->wpd);

Column(cq,NoColumns);

sprintf(cq->ObjType, "Col Def:%d",(int)NoColumns);
}



static const char *ExtendedCharacter3(TconvertedPass1_WP3 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#ExtendedCharacter3() ");fflush(cq->log);
#endif
BYTE MacChar;
BYTE WpCharSet;
BYTE Char;
const char *RetCharStr=NULL;

  MacChar = fgetc(cq->wpd);
  WpCharSet = fgetc(cq->wpd);
  Char = fgetc(cq->wpd);

  sprintf(cq->ObjType, "%d %d,%d",MacChar,WpCharSet,Char);
  if(WpCharSet<12)
    {
    RetCharStr = Ext_chr_str((WORD)WpCharSet*256 + Char, cq, cq->ConvertCpg);
    }
  if(RetCharStr==NULL)
    {
    RetCharStr = Ext_chr_str(MacChar, cq, cq->MacRoman);
    }
  return RetCharStr;
}


static void Endnote3(TconvertedPass1_WP3 *cq, DWORD end_of_code)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Endnote3() ");fflush(cq->log);
#endif
attribute OldAttr;
unsigned char flags;
WORD x_num;
unsigned char OldFlag;
  //CrackObject(cq, end_of_code); //

  end_of_code -= 4;
  OldFlag = cq->flag;
  cq->flag = HeaderText;
  cq->recursion++;

  fread(&flags, sizeof(unsigned char), 1, cq->wpd);
  fseek(cq->wpd, 26L, SEEK_CUR);	/* Skip all the shit */

  RdWORD_HiEnd(&x_num, cq->wpd);	//# of breaks
  fseek(cq->wpd, 6L*x_num, SEEK_CUR);	//skip all 6byte entries

  Close_All_Attr(cq->attr,cq->strip);
  OldAttr=cq->attr;
  InitAttr(cq->attr);

  if(!EndNotes) EndNotes=true;		/* set up endnotes */
  if(EndNotes==-1) EndNotes=-2;		/* endnote is replaced by \footnote */
  fprintf(cq->strip, "\\endnote{");

  cq->ActualPos = ftell(cq->wpd);

  while (cq->ActualPos < end_of_code)
	{
	fread(&cq->by, sizeof(unsigned char), 1, cq->wpd);

	switch(cq->by)
	     {
	     case 0xA:
	     case 0xC:fprintf(cq->strip, "\\\\ ");
		      break;

	     case 0xB:
	     case 0xD:putc(' ', cq->strip);
		      break;

	     default: ProcessKeyWP3(cq);
		      break;
	     }

	   cq->ActualPos = ftell(cq->wpd);
	   }

  Close_All_Attr(cq->attr,cq->strip);   /* Echt nodig ? */
  putc('}', cq->strip);

  cq->attr=OldAttr;

  cq->recursion--;
  strcpy(cq->ObjType, "Endnote");
  cq->flag = OldFlag;
}


static void Footnote3(TconvertedPass1_WP3 *cq, DWORD end_of_code)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Footnote3() ");fflush(cq->log);
#endif
attribute OldAttr;
unsigned char flags;
WORD x_num;
unsigned char OldFlag;
  //CrackObject(cq, end_of_code); //

  end_of_code -= 4;
  OldFlag = cq->flag;
  cq->flag = HeaderText;
  cq->recursion++;

  fread(&flags, sizeof(unsigned char), 1, cq->wpd);
  fseek(cq->wpd, 24L, SEEK_CUR);	/* Skip all the shit */

  RdWORD_HiEnd(&x_num, cq->wpd);	//# of footnote pages
  fseek(cq->wpd, 4L*x_num, SEEK_CUR);	//skip all 4byte pages

  RdWORD_HiEnd(&x_num, cq->wpd);	//# of table entries
  fseek(cq->wpd, 6L*x_num, SEEK_CUR);	//skip all 6byte entries


  Close_All_Attr(cq->attr,cq->strip);
  OldAttr=cq->attr;
  InitAttr(cq->attr);

  fprintf(cq->strip, "\\footnote" );
  if(ExactFnNumbers) fprintf(cq->strip, "[%u]", x_num);
  fputc('{',cq->strip);

  cq->ActualPos = ftell(cq->wpd);
  while (cq->ActualPos < end_of_code)
	{
	fread(&cq->by, sizeof(unsigned char), 1, cq->wpd);

	switch(cq->by)
	     {
	     case 0xa:
	     case 0xc:fprintf(cq->strip, "\\\\ ");
		      break;

	     case 0xb:
	     case 0xd:putc(' ', cq->strip);
		      break;

	     default: ProcessKeyWP3(cq);
		      break;
	     }

	   cq->ActualPos = ftell(cq->wpd);
	   }

  Close_All_Attr(cq->attr,cq->strip);   /* Echt nodig ? */
  putc('}', cq->strip);

  cq->attr=OldAttr;

  cq->recursion--;
  strcpy(cq->ObjType, "Footnote");
  cq->flag = OldFlag;
}


static void Header_Footer3(TconvertedPass1_WP3 *cq, DWORD end_of_code)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Header_Footer3() ");fflush(cq->log);
#endif
//BYTE FormatFlags;
BYTE Defs;
attribute OldAttr;
string s;
unsigned char OldFlag,OldEnvir;
WORD OldLen;
int i;
const BYTE TranslateOccurance[4] = {0,4,2,1};

//CrackObject(cq, end_of_code); 

  if(end_of_code - ftell(cq->wpd) <= 18)
	{Defs=0;goto ExitHeaderFooter;}

  OldFlag = cq->flag;
  OldEnvir= cq->envir;

  cq->recursion++;
  end_of_code -= 4;	//stop before this object ends

  cq->line_term = 's';    	//Soft return
  if(cq->char_on_line == -20)    /* Left one enpty line for new enviroment */
      {
      fputc('%', cq->table);
      fputc('%', cq->strip);
      NewLine(cq);
      }
  if(cq->char_on_line==true)
      {
      NewLine(cq);
      }

  i = fgetc(cq->wpd);		//FormatFlags
  fseek(cq->wpd, 13L, SEEK_CUR);
  RdWORD_HiEnd(&OldLen,cq->wpd);

  fseek(cq->wpd, OldLen, SEEK_CUR);
  Defs = fgetc(cq->wpd);

  if(cq->ActualPos+1L+13L+2L+OldLen+6L > end_of_code)
	goto ExitHeaderFooter;		//invalid length

  fseek(cq->wpd, 6L, SEEK_CUR);

  Close_All_Attr(cq->attr,cq->strip);
  OldAttr=cq->attr;			/* Backup all attributes */

				/* Any of section's attr cannot be opened */
  for(i=First_com_section;i<=Last_com_section;i++)
		  _AttrOff(cq->attr,i,s); // !!!!!! toto predelat!

  InitHeaderFooter(cq, cq->subby, TranslateOccurance[Defs&3]);
  Defs=(Defs << 4) | (cq->subby & 0xF);

  cq->envir='!';		//Ignore enviroments after header/footer
  NewLine(cq);

  InitAttr(cq->attr);		//Turn all attributes in the header/footer off

  cq->flag = HeaderText;
  cq->envir = ' ';
  cq->ActualPos = ftell(cq->wpd);
  cq->char_on_line = -10;
  while (cq->ActualPos < end_of_code)
	{
	fread(&cq->by, 1, 1, cq->wpd);

	ProcessKeyWP3(cq);
	}

  Close_All_Attr(cq->attr,cq->strip);
  if(cq->char_on_line==true)
     {
     cq->line_term = 's';    	//Soft return
     NewLine(cq);
     }
  putc('}', cq->strip);

  cq->line_term = 's';    	//Soft return
  cq->envir='^';		//Ignore enviroments after header/footer
  NewLine(cq);

  cq->attr=OldAttr;		/* Restore attributes backed up */
  cq->flag = OldFlag;
  cq->envir = OldEnvir;
  cq->char_on_line = -10;	// stronger false;
  cq->recursion--;

ExitHeaderFooter:
  strcpy(cq->ObjType,(Defs & 3)<=1?"Header":"Footer");
}


typedef struct WP3Tab {
  BYTE Mode;
  BYTE NumFormat;
  DWORD Width;
  DWORD RightOffset;
} WPTab;

const char *TableDelimiter(char Mode)
{
  switch(Mode)
    {
    case 0:  break; 		// None
    case 1:			// Hairline
    case 2:                    	// Single
    case 3:			// Thick
    case 4:		 	// Extra Thick
    case 5:			// Dashed
    case 6: return "|";		// Dotted
    case 7: 			// Double
    case 8: return "||";	// Double Thick
    }
return "";
}

static void TableStart3(TconvertedPass1_WP3 *cq, DWORD & NewPos)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#TableStart3(%d) ",(int)NewPos);fflush(cq->log);
#endif
BYTE columns = 0;
WORD i;
WP3Tab Atbl[100];
unsigned char OldFlag;
char OldEnvir;
BYTE TableMode;
BYTE TableStatus;
BYTE OutsideBorder[4];
BYTE CellBorder[4];

  //CrackObject(cq, NewPos); //!!
  if(cq->log) fprintf(cq->log, _("\n%*sStart Table"), cq->recursion*2, "");

  fseek(cq->wpd, 8L, SEEK_CUR);			// outside border
  fread(&OutsideBorder, 1, 4, cq->wpd);

  fseek(cq->wpd, 36L-(8L+4L), SEEK_CUR);	// cell border
  fread(&CellBorder, 1, 4, cq->wpd);

  fseek(cq->wpd, 71L-(36L+4L), SEEK_CUR);	// table mode
  fread(&TableMode, 1, 1, cq->wpd);

  fseek(cq->wpd, 95L-(71L+1L), SEEK_CUR);	// #of columns
  fread(&columns, 1, 1, cq->wpd);

  if(columns>100 || columns<=0)
	{strcpy(cq->ObjType, "!Table Start"); return;}

  for(i=0; i<=columns-1; i++)
    {
    fread(&Atbl[i].Mode, 1, 1, cq->wpd);
    fread(&Atbl[i].NumFormat, 1, 1, cq->wpd);
    RdDWORD_HiEnd(&Atbl[i].Width, cq->wpd);
    RdDWORD_HiEnd(&Atbl[i].RightOffset, cq->wpd);
    }

  cq->line_term = 's';   /* Soft return */
  OldFlag = cq->flag;
  OldEnvir= cq->envir;
  cq->recursion++;

  if(cq->char_on_line == -20)    /* Left one enpty line for new enviroment */
      {
      fputc('%', cq->table);fputc('%', cq->strip);
      NewLine(cq);
      }
  if(cq->char_on_line>=true) //  if(cq->char_on_line>=-1)
      {
      NewLine(cq);
      }

  switch(TableMode & 7)		// Apply table position flag
    {
    case 2:if(OldEnvir!='R')
		{fprintf(cq->strip, "\\begin{flushright}"); NewLine(cq);}
	   break;
    case 1:if(OldEnvir!='C')
		{fprintf(cq->strip, "\\begin{center}"); NewLine(cq);}
	   break;
    }

  cq->envir='!';
  fputc('%', cq->table);fputc('%', cq->strip);
  NewLine(cq);

  cq->envir = 'B';

  fprintf(cq->strip, "{%s", TableDelimiter(OutsideBorder[1]));
  for(i=0; i<=columns-1; i++)
    {
    switch(TableMode & 0x7)
      {
      case 0:fprintf(cq->strip, "l"); break;  // left	     
      case 1:fprintf(cq->strip, "c"); break;  // center
      case 2:fprintf(cq->strip, "r"); break;  // right
      //case 3: break;			       // margin fit??
      case 4: fprintf(cq->strip, "l"); break; // absolute offset from left edge
      default:fprintf(cq->strip, "c");   //I don`t know
	      break;
      }
    fprintf(cq->strip, "%s", 
	TableDelimiter((i>=columns-1)?OutsideBorder[3]:CellBorder[3]));
  }
  putc('}', cq->strip);
  NewLine(cq);

  cq->char_on_line = false;
  cq->nomore_valid_tabs = false;
  cq->rownum++;
  Make_tableentry_attr(cq);
  cq->latex_tabpos = 0;

	/* Process all content of the table. */
  fseek(cq->wpd,cq->ActualPos=NewPos,SEEK_SET);
  cq->by = fgetc(cq->wpd);
  TableStatus = 0;		// No character in a table
  while(!feof(cq->wpd))
	{
	if(cq->by==0xDC && cq->envir!='B')
		{
		cq->envir='B';
		}
        if(TableStatus==0)	// 1st row fix
		{
		if(cq->by==0xDC)
		  {
	            cq->subby = fgetc(cq->wpd);
		    fseek(cq->wpd,-1,SEEK_CUR);
		    if(cq->subby!=0x18) TableStatus=0xFF;
		  }
	        else
		  TableStatus = 0xFF;
	        if(TableStatus==0xFF) RowTable(cq,OutsideBorder[0]); // create false row
		TableStatus = 1;
		}
	ProcessKeyWP3(cq);
	NewPos = cq->ActualPos;
	if(cq->by==0xDC && 
	     (cq->subby==0x1A||cq->subby==0x1B) ) break; /*End of table*/

	cq->by=fgetc(cq->wpd);
	}
  if(cq->char_on_line <= -10)    /* Left one empty line for ending enviroment */
	{
	fputc('%', cq->table);fputc('%', cq->strip);
	NewLine(cq);
	}

  switch(TableMode & 7)		// Apply table position flag
    {
    case 2:if(OldEnvir!='R')
		{fprintf(cq->strip, "\\end{flushright}"); NewLine(cq);}
	   break;
    case 1:if(OldEnvir!='C')
		{fprintf(cq->strip, "\\end{center}"); NewLine(cq);}
	   break;
    }

  cq->envir='^';		//Ignore enviroments after table
  fputc('%', cq->table);
  NewLine(cq);
  cq->char_on_line = -10;		// stronger false;

  cq->recursion--;
  cq->flag=OldFlag;
  cq->envir=OldEnvir;

  strcpy(cq->ObjType, "Table Start");
}


static void Undo3(TconvertedPass1_WP3 *cq, DWORD & NewPos)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Undo() ");fflush(cq->log);
#endif
unsigned char OldFlag;
attribute OldAttr;
WORD Level;
SWORD SubLevel;
const char *UndoType;
BYTE Type;

  cq->subby = fgetc(cq->wpd);
  Rd_word(cq->wpd, &Level);
  if(!UndoRedo) goto SkipUndoStuff;

  fseek(cq->wpd, NewPos, SEEK_SET);

  if(cq->subby==0 && EmptyCheck(cq->UndoRedo))
    {
    cq->UndoRedo.push(-(int)Level);
    if(cq->log)
      fprintf(cq->log,_("\n%*sIgnored from undo %d:"), cq->recursion*2, "", Level);

    OldFlag = cq->flag;
    OldAttr = cq->attr;

    cq->flag = Nothing;

    fseek(cq->wpd, NewPos, SEEK_SET);
    cq->ActualPos=NewPos;

    cq->recursion++;
    while(!feof(cq->wpd))
	{
	if(fread(&cq->by, 1, 1, cq->wpd)<1) break;

	if(cq->by==0xF1) //next Undo command
		{
		NewPos=cq->ActualPos; //Everything is OK
		Type=fgetc(cq->wpd);
		Rd_word(cq->wpd, (WORD *)&SubLevel);
		fseek(cq->wpd,cq->ActualPos+1,SEEK_SET);

		switch(Type)
		  {
		  case 0:cq->UndoRedo.push(-(int)SubLevel); break;
		  case 2:cq->UndoRedo.push((int)SubLevel);  break;

		  case 1:SubLevel=-SubLevel;  	//continuing on label 3:
		  case 3:while(cq->UndoRedo.pop()!=(int)SubLevel && !EmptyCheck(cq->UndoRedo))
			   {
			   if(cq->err!=NULL)
	 		     {
	 		     cq->perc.Hide();
	 		     fprintf(cq->err,
			       _("\nError: Undo/Redo stack is corrupted, Type=%d!"),Type);
	 		     }
                           }
                  }
		if(EmptyCheck(cq->UndoRedo))
                  {
		  ProcessKeyWP3(cq);
		  NewPos=cq->ActualPos; //Everything is OK
                  break;}
		}
	ProcessKeyWP3(cq);
	}

     cq->recursion--;
     cq->attr = OldAttr;
     cq->flag = OldFlag;

     Type=0;
     }

SkipUndoStuff:
 switch(cq->subby)
   {
   case 0:UndoType="Invalid Start";	break;
   case 1:UndoType="Invalid End";	break;
   case 2:UndoType="Valid Start";	break;
   case 3:UndoType="Valid End";		break;
   default:if (cq->err != NULL)
		{
		cq->perc.Hide();
		fprintf(cq->err, _("\nWarning: Strange Undo type:%d !"),(int)cq->subby);
		}
	   sprintf(cq->ObjType, "!Undo (?%d:%d)"+(UndoRedo?1:0),cq->subby,(int)Level);
	   return;
   }

  sprintf(cq->ObjType, "!Undo (%s:%d)"+(UndoRedo?1:0), UndoType,(int)Level);
}


/////////////////////////////////////////////////////////////////////

static boolean CheckConzistency3(TconvertedPass1 *cq, long NewPos)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#CheckConzistency() ");fflush(cq->log);
#endif

  boolean Result = true;
  unsigned char TestedBy,TestedSubBy;
  long Pos;

  Pos = ftell(cq->wpd);

  TestedSubBy=cq->subby;
  if (cq->by>=0xd0 && cq->by<0xF0)
		 {                              //subby will be also tested
                 fseek(cq->wpd, NewPos-2 , 0);
		 fread(&TestedSubBy, 1, 1, cq->wpd);
		 }
	    else fseek(cq->wpd, NewPos-1 , 0);
  fread(&TestedBy, 1, 1, cq->wpd);
  if ((TestedBy != cq->by)||(TestedSubBy != cq->subby))
  	{
        if (cq->err != NULL)
          {
//        if(CorruptedObjects<19)
	    cq->perc.Hide();
            fprintf(cq->err,
	      _("\nError: Object %lX:%X consistency check failed. Trying to ignore."),cq->ActualPos,(int)cq->by);
/*        if(CorruptedObjects==19)
	    fprintf(cq->err,
	      _("\nError: Overwhelmed by too many currupted objects, switching to the silent mode.);*/
          }
        CorruptedObjects++;
        Result = false;
	}

  fseek(cq->wpd, Pos, 0);
  return Result;
}



/*This is main procedure for processing one key. It is recursivelly called.*/
static void ProcessKeyWP3(TconvertedPass1_WP3 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#ProcessKey() ");fflush(cq->log);
#endif
  WORD w;
  DWORD NewPos = 0;
  unsigned char by, subby;

  if (cq->by == 0)
    fread(&cq->by, 1, 1, cq->wpd);

  *cq->ObjType = '\0';
  w=1;
  cq->subby=0;


  /*Guessing end position of the object*/

  if (cq->by > 0xbf)
      {
      if (cq->by >= 0xC0 && cq->by <= 0xCF)
	  {	/*these functions has fixed size - see table SizesC0*/
	  if (SizesC0[cq->by - 0xc0] != 0)
		{
		w=SizesC0[cq->by- 0xc0];
		NewPos = w + cq->ActualPos;
		}
//	  else printf("!!%d",cq->by - 0xc0);
	  if(cq->by==0xC1 || cq->by==0xC2)
	    fread(&cq->subby, 1, 1, cq->wpd);
          else
	    cq->subby = 0xff;   /*ignored subcommand*/
	  }
      else if (cq->by >= 0xD0)
	 {
	 fread(&cq->subby, 1, 1, cq->wpd);
	 RdWORD_HiEnd(&w,cq->wpd);
	 NewPos = cq->ActualPos + w + 4;
	 cq->Linebegin = false;
	 }
      }	/*other functions has size only 1 byte - all OK*/
      
  by = cq->by;
  subby = cq->subby;

  if (ExtendedCheck && NewPos != 0)
    if (!CheckConzistency3(cq, NewPos))
      {
      NewPos = cq->ActualPos+1;
      strcpy(cq->ObjType, "Corrupted!!");
      goto _LObjectError;
      }

/*  if((by==0xd2)&&(subby==0xb))
               fprintf(cq->strip, " ****Start Of Table:%d****",cq->flag);*//**/

  if( filter[cq->flag][cq->by] )
     {
     switch (by)
	{
	case 0x0a: HardReturn(cq); break;		// Hard return
	case 0x0b: Terminate_Line(cq,'p');strcpy(cq->ObjType, "SRt SoftPg");break;// Soft page
	case 0x0c: HardPage(cq); break;			// Hard page
	case 0x0d: SoftReturn(cq); break;		// Soft return
	case 0x20: putc(' ', cq->strip); break;		/*soft space ' '*/

	case 0x80: HardReturn(cq); break;			//Condensed Hard Return
	case 0x81: HardPage(cq); break;				//Condensed Hard Page
	case 0x82: strcpy(cq->ObjType,"!Cond Tab"); break;	//Condensed Tab
	case 0x83: strcpy(cq->ObjType,"!Cond BK Tab"); break;	//Condensed Back Tab
	case 0x84: strcpy(cq->ObjType,"!Cond Ind"); break;	//Condensed Indent
	case 0x85: strcpy(cq->ObjType,"!Cond Left/Right Ind"); break;	//Condensed Left/Right Indent
	   //Reserved
	case 0x8A: strcpy(cq->ObjType,"!Highlite Off"); break;	//Highlite Off
	case 0x8B: strcpy(cq->ObjType,"!Cursor Position"); break;	//Cursor Position
	case 0x8C: strcpy(cq->ObjType,"!Raw Text Range"); break;	//Raw Text Range
	case 0x8D: strcpy(cq->ObjType,"!Sel Raw Text Range"); break;	//Selected Raw Text Range
	case 0x8E: strcpy(cq->ObjType,"!Conv Text Range"); break;	//Converted Text Range
	case 0x8F: strcpy(cq->ObjType,"!Sel Conv Text Range"); break;	//Select Converted Text Range
	case 0x90: strcpy(cq->ObjType,"!End of Bookmark"); break;	//End of Bookmark
	case 0x91: strcpy(cq->ObjType,"!End of Hyperlink Text"); break;	//End of Hyperlink Text
	case 0x92: strcpy(cq->ObjType,"!Turn Disp Off"); break;		//Turn Display Off
	case 0x93: strcpy(cq->ObjType,"!Turn Disp On"); break;		//Turn Display On
	case 0x94: strcpy(cq->ObjType,"!End Center/Align"); break;	//End Center/Align
	case 0x95: strcpy(cq->ObjType,"!Begin Character Subst"); break;	//Begin Character Substitution

        case 0x96: HardHyphen(cq); break;				//Hard Hyphen In Line
	case 0x97: SoftHyphen(cq); break;				//Soft Hyphen In Line

	case 0x98: strcpy(cq->ObjType,"!Auto Hyphen In Line"); break;	//Auto Hyphen In Line
	   //0x99 reserved

	case 0x9A: CancelHyph(cq); break;				//Cancel Hyphenation of Word

	case 0x9C: strcpy(cq->ObjType,"!Box Number"); break;		//Box Number
	case 0x9D: strcpy(cq->ObjType,"!Chapter Number"); break;	//Chapter Number
	case 0x9E: strcpy(cq->ObjType,"!Hide Functions ON"); break;	//Hide Functions ON
	case 0x9F: strcpy(cq->ObjType,"!Hide Functions OFF"); break;	//Hide Functions OFF

	case 0xA0: fputc('~', cq->strip);strcpy(cq->ObjType, " ");	//Hard space
		   break;
	case 0xA1: PageNumber(cq); break;				//Page Number
	case 0xA2: strcpy(cq->ObjType,"!Footnote Number"); break;	//Footnote Number
	case 0xA3: strcpy(cq->ObjType,"!Table of Contents Placeholder"); break;	//Table of Contents Placeholder
	case 0xA4: strcpy(cq->ObjType,"!Endnote Number"); break;	//Endnote Number
	case 0xA5: strcpy(cq->ObjType,"!Start of Subtitle Text"); break;	//Start of Subtitle Text
	case 0xA6: strcpy(cq->ObjType,"!End of Centered/Aligned Text"); break;	//End of Centered/Aligned Text
	case 0xA7: strcpy(cq->ObjType,"!End of Generated Text"); break;	//End of Generated Text
	case 0xA8: CenterPage(cq); break;				//Center Page Top to Bottom

	case 0xAA: strcpy(cq->ObjType,"!Beg Par ON"); break;	//Beginning of Paragraph ON
	case 0xAB: strcpy(cq->ObjType,"!Beg Par OFF"); break;	//Beginning of Paragraph OFF
	case 0xAC: strcpy(cq->ObjType,"!Begin Enc Grp"); break;	//Begin Encased Grouping
	case 0xAD: strcpy(cq->ObjType,"!End Enc Grp"); break;	//End Encased Grouping
	case 0xAE: strcpy(cq->ObjType,"!Start TAB HdR"); break;	//Start Table Header
	case 0xAF: strcpy(cq->ObjType,"!End TAB Hdr"); break;	//End Table Header

	case 0xB0: WidowOrphan(cq,3); break;			//Turn Widow/Orphan On
	case 0xB1: WidowOrphan(cq,0); break;			//Turn Widow/Orphan Off

	case 0xB2: strcpy(cq->ObjType,"!Blk ON"); break;	//Block ON
	case 0xB3: strcpy(cq->ObjType,"!Blk OFF"); break;	//Block OFF

	case 0xB4: Hyphenation(cq,true); break;			//Turn Hyphenation On
	case 0xB5: Hyphenation(cq,false); break;		//Turn Hyphenation Off

	case 0xB6: strcpy(cq->ObjType,"!Rev Video ON"); break;	//Reverse Video ON
	case 0xB7: strcpy(cq->ObjType,"!Rev Video OFF"); break;	//Reverse Video OFF
	case 0xB8: strcpy(cq->ObjType,"!Gen Mark #1"); break;	//Generate Marker #1
	case 0xB9: strcpy(cq->ObjType,"!Gen Mark #2"); break;	//Generate Marker #2
	case 0xBA: strcpy(cq->ObjType,"!Srch Mark #1"); break;	//Search Marker #1
	case 0xBB: strcpy(cq->ObjType,"!Srch Mark #2"); break;	//Search Marker #2
	case 0xBC: strcpy(cq->ObjType,"!Form EOL/EOP/EOC"); break; //Format to EOL/EOP/EOC
	case 0xBD: strcpy(cq->ObjType,"!Misc Form Mark"); break; //Misc Formatter Marker
	case 0xBE: strcpy(cq->ObjType,"!Reform Line Mark"); break; //Reformat Line Marker
	case 0xBF: strcpy(cq->ObjType,"NOP"); break;		//No Operation

	case 0xC0:CharacterStr(cq,ExtendedCharacter3(cq)); break;
	case 0xC1: switch(subby)
		     {
		     case 0: if(cq->char_on_line<true) Tab(cq,3);
			     else Tab(cq,127);  //Ignore tab
			     break;		
		     case 1: Center(cq);	break;
                     case 2: Flush_right(cq,0);	break;

		     case 3: strcpy(cq->ObjType,"!Bk Tab"); break;
		     case 4: strcpy(cq->ObjType,"!Chr Kern"); break;
		     case 5: strcpy(cq->ObjType,"!Tab w/Vertical Line"); break;
		     case 6: strcpy(cq->ObjType,"!Fix Tab"); break;
		     }
	           break;
	case 0xC2:switch(subby)
		     {
		     case 0: strcpy(cq->ObjType,"!Left Indent"); break; //Left Indent
		     case 1: strcpy(cq->ObjType,"!L/R Indent"); break;	//Left/Right Indent
		     }
	           break;
	case 0xC3: Attribute3(cq); break;
	case 0xC4: strcpy(cq->ObjType,"!Emphasis Char"); break; //Emphasis Character
        case 0xC5: strcpy(cq->ObjType,"!Block Protect"); break; //Block Protect
	case 0xC6: End_of_indent(cq);     break;

	case 0xC8: strcpy(cq->ObjType,"!Dbl Byte Script Char"); break; //Double Byte Script Character

        case 0xCC: sprintf(cq->ObjType,"!Tmp Marker %d",subby); break;
	case 0xCD: Undo3(cq,NewPos);  break;
	case 0xCE: if(subby==0) sprintf(cq->ObjType,"!Tmp Ch Spc");    // Temp Character Space Function
		   if(subby==1) sprintf(cq->ObjType,"!Tmp Ch SpcExt"); // Temp Space-Extra Function 
		   if(subby==0xFF) sprintf(cq->ObjType,"!Tmp Ch Ext"); //Temp Char-Extra Function 
		   break;

	case 0xD0: if(subby == 1) sprintf(cq->ObjType,"!Set Hor Margin");
	           if(subby == 6) Justification(cq,3);
		   if(subby == 0xD)
			{
			fseek(cq->wpd, 1L, SEEK_CUR);	//skip Old Mode
			WidowOrphan(cq,fgetc(cq->wpd)&3);
			}
		   break;

	case 0xD1: if(subby == 0) Color(cq,3);
		   if(subby == 1) strcpy(cq->ObjType,"!Font");
		   if(subby == 2) strcpy(cq->ObjType,"!Font Size");
		   break;

	case 0xD2: if(subby == 1) Column3(cq);
		   if(subby == 0xA) strcpy(cq->ObjType,"!Def Sub/Sup Opt");
		   break;

        case 0xD3:switch (subby)
		    {
		    case 0x01:strcpy(cq->ObjType,"!Underline mode");	break;

		    case 0x02:SetFootnoteNum(cq,3);	break;
		    case 0x03:SetEndnoteNum(cq,3);	break;
		    case 0x04:SetPgNum(cq,3);		break;
	            }
		  break;

	case 0xD5: Header_Footer3(cq,NewPos);		break;

	case 0xD6: if(subby == 0) Footnote3(cq,NewPos);
		   if(subby == 1) Endnote3(cq,NewPos);
		   break;

	case 0xD7: switch (subby)
		     {
		     case 0:   StartSection(cq,3);	break;
		     case 0x1: EndSection(cq,3);	break;

		     case 0x5: PlaceEndnotes(cq);	break; 	
//		     case 0xA: Start Included SubDocument
//		     case 0xB: End Included SubDocument	    
		     }
		   break;

	case 0xD8:switch (subby)
                    {
		    case 0x0: DateCode(cq);		break;
		    case 0x1: ParagraphNumber(cq);	break;

		    case 0x6: PageNumber(cq);	   	break;
		    }
		  break;

	case 0xDA:if(subby<=5) {AnyBox3(cq,NewPos); break;}
		  break;

	case 0xDB:switch (subby)
                    {
		    case 0x0: strcpy(cq->ObjType, "!Endr Style Def");	break;
		    case 0x1: strcpy(cq->ObjType, "!Beg Par Style Def");break;
		    case 0x2: strcpy(cq->ObjType, "!Beg EOP Style");	break; // Begin End Paragraph Style Definition
		    case 0x3: strcpy(cq->ObjType, "!Beg DOC Style");	break;
		    //case 0x4:		// Begin Formatter Style Definition
		    //case 0x5:		// Begin Start Character Style Definition
		    //case 0x6: 	// Begin End Character Style Definition
		    }
		  break;

	case 0xDC: switch(subby)
		     {
		     case 0: SoftReturn(cq);		break;
		     case 1: strcpy(cq->ObjType, "SPg");break;	// Soft end of page
		     case 2: HardReturn(cq);		break;
		     case 3: Terminate_Line(cq, 'p');	// Soft page
			     strcpy(cq->ObjType, "HRt-SPg");
			     break;
		     //case 4: 				//Temporary end of line 
		     //case 5:				//Temporary end of page/column 
		     case 6: Terminate_Line(cq, 'h');	/* Dormant Hard Return */
		  	     strcpy(cq->ObjType, "Dorm HRt");
		             break;
		     case 7: HardPage(cq);		break;	// Hard page
		     //case 8: 				//Hard end of column
		     //case 9: 				//Hard end of column/Soft end of page
		     //case 0xA:			break;	// Hard end of line (HardEOC_ not in columns)
                     case 0xB:HardPage(cq);		break;	// Hard page
		     case 0xC:					// Hard hyphen at end of line
		     case 0xD:HardHyphen(cq);		break;  // Hard hyphen at end of page/col
		     case 0xE:					// Soft hyphen at EOL
		     case 0xF:SoftHyphen(cq);	 	break;	// Soft hyphen at EOP/COL
		     //case 0x10:				// Auto hyphen at end of line
		     //case 0x11:				// Auto hyphen at end of page/column

		     //case 0x13:			break; // Hard beginning of file
		     //case 0x14:			       //Temporary Hard end of column
		     //case 0x15:			       // Hard EOC/Soft EOP
		     case 0x16: if(cq->envir=='B') cq->char_on_line=true;
				CellTable(cq);		break; // Hard end of table cell

		     case 0x18:				       // Hard end of table row/cell
		     case 0x19: RowTable(cq);		break; // Hard end of table row/cell/soft end of page
                     case 0x1A:				       // Hard end of table row/end of table
		     case 0x1B: EndTable(cq);		break; // Hard end of table row/end of table/soft EOP
		     //case 0x1C:			       // Hard end of table row/cell/end of header
		     //case 0x1D:			       // Hard end of table row/cell/soft EOP/start of header
		     }
		   break;

	case 0xDF:switch (subby)
                    {
		    case 0x1: strcpy(cq->ObjType, "!Par Border On/Off"); break;

		    case 0x6: strcpy(cq->ObjType, "!Txt Box Border On/Off"); break;
		    case 0x7: strcpy(cq->ObjType, "!Usr Box Border On/Off"); break;
		    case 0x8: strcpy(cq->ObjType, "!Equ Box Border On/Off"); break;
		    }
		  break;

        case 0xE2: if(subby == 1) TableStart3(cq,NewPos);
                   break;

	default:if(by >= 0x03 && by <= 0x7f)
		    {
		    cq->RequiredFont = FONT_NORMAL;
		    CharacterStr(cq,Ext_chr_str(cq->by,cq,NULL));  /* Normal_char */
		    }
		break;
	}
  }

_LObjectError:
  if (cq->log != NULL)
    {   /**/
    if (by==0xC0) fprintf(cq->log, " [ExtChr %s] ", cq->ObjType);
    else if ((by > 0x80)||(*cq->ObjType != '\0'))
	{
	fprintf(cq->log, _("\n%*sObject type:%3Xh subtype:%3X length:%4u %c"),
		  cq->recursion * 2, "", by, subby, w, cq->envir);
	if (*cq->ObjType != '\0')
		  fprintf(cq->log, " [%s] ", cq->ObjType);
	     else fprintf(cq->log, "    ");
	if(*cq->ObjType==0) UnknownObjects++;
	}
    else if (by >= ' ' && by <= 'z')
		 putc(by, cq->log);
    }

  if (NewPos == 0)
	{
	if(by<0xC0) cq->ActualPos++;	//Only one byte read - simple guess of new position
	       else cq->ActualPos = ftell(cq->wpd);
	return;
	}
  cq->ActualPos = ftell(cq->wpd);
  if (NewPos == cq->ActualPos) return;
  fseek(cq->wpd, NewPos, 0);
  cq->ActualPos = NewPos;
}


static void InitFilter3(void)
{
 filter[0]=set(set0_3,sizeof(set0_3)/sizeof(int));
 filter[1]=set(set1_3,sizeof(set1_3)/sizeof(int));
 filter[2]=set(set2_3,sizeof(set2_3)/sizeof(int));
 filter[3]=set();
}


/*******************************************************************/
/* This procedure provides all needed processing for the first pass*/
int TconvertedPass1_WP3::Convert_first_pass(void)
{
#ifdef DEBUG
  fprintf(log,"\n#Convert_pass1_WP3() ");fflush(log);
#endif
DWORD fsize;

  InitFilter3();
  ConvertCpg=GetTranslator("wp5TOinternal");  // WP3 MAC uses a same character set as WP5.x
  MacRoman = GetTranslator("MacRomanTOinternal");

  DocumentStart=ftell(wpd);

  fsize=filesize(wpd);
  perc.Init(ftell(wpd), fsize,_("First pass WP MAC 3.x:") );

  if(DocumentStart>0x10)	//This can be omitted
    {
    WalkResources3(this);
    fseek(wpd,DocumentStart,SEEK_SET);
    }  

  ActualPos = ftell(wpd);
  while (ActualPos < fsize)
    {
    if(Verbosing >= 1)		//actualise a procentage counter
	      perc.Actualise(ActualPos);

    by = 0;
    ProcessKeyWP3(this);
    }

  Finalise_Conversion(this);
  return(1);
}


/*--------------------End of PASS1_WP3--------------------*/
