/******************************************************************************
 * 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 "stringa.h"
#include "stacks.h"
#include "struct.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);
     virtual int Dispatch(int FuncNo, const void *arg);
     void ProcessKeyWP3(void);

     void AnyBox3(DWORD end_of_code);
     void Attribute3(void);
     void Column3(void);
     void Endnote3(DWORD end_of_code);
     void Footnote3(DWORD end_of_code);
     void Header_Footer3(DWORD end_of_code);
     void LineSpacing3(void);
     void ReadFormulaStr3(string & StrBeg, DWORD end_of_code);
     DWORD SelectImageResource3(int ResourceNo);
     void TableStart3(DWORD & NewPos);
     void Undo3(DWORD & NewPos);
     void WalkResources3(void);
     const char *ExtendedCharacter3();

     stack UndoRedo;

protected:
     set filter[4];

     void ExtractCaptionLabel3(const TBox *Box);
     void DoCaption3(unsigned short CaptionSize);
     void InitFilter3(void);     
     };


/** 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


extern list UserLists;

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
  };


void TconvertedPass1_WP3::Attribute3(void)
{
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(wpd);
  State = fgetc(wpd);

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

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


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

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

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

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

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

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


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

 ResIDCount = 0;
 ResIdArea = 0;

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

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

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

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

   RdDWORD_HiEnd(&resLen, wpd);

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

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

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

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

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

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

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

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

   if(pos1>DocumentStart) return;

   ResIDCount += 1 + ResTypeCount;
   }

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

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

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

   if(pos1>DocumentStart) return;
   }
}


void TconvertedPass1_WP3::ExtractCaptionLabel3(const TBox *Box)
{
#ifdef DEBUG
  fprintf(log,"\n#ExtractCaptionLabel3() ");fflush(log);
#endif
DWORD end_of_code;
unsigned char OldFlag;

  if(Box==NULL) return;
  if(Box->CaptionSize == 0) return;

  fseek(wpd, Box->CaptionPos, SEEK_SET);
  ActualPos = Box->CaptionPos;
  end_of_code = ActualPos + Box->CaptionSize;
  OldFlag = flag;
  recursion++;

  flag = Nothing;
  attr.InitAttr();

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

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

	ProcessKeyWP3();
	}

  recursion--;
  flag = OldFlag;
}


void TconvertedPass1_WP3::DoCaption3(unsigned short CaptionSize)
{
#ifdef DEBUG
  fprintf(log,"\n#DoCaption3() ");fflush(log);
#endif
  
  DWORD end_of_code;
  unsigned char OldFlag;
  char OldEnvir;
  attribute OldAttr;
  int CaptionChars;

  if(CaptionSize == 0) return;

  ActualPos = ftell(wpd);
  end_of_code = ActualPos + CaptionSize;
  OldFlag = flag;
  OldEnvir = envir;
  recursion++;

  OldAttr = attr;
  attr.InitAttr();

  flag = HeaderText;
  CaptionChars=0;

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

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

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

    if(isalnum(by)) CaptionChars++;

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

  line_term = 's';   /* Soft return */
  Make_tableentry_envir_extra_end(this);

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


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

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

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

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

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

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

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

      ProcessKeyWP3();
      }
}


static const char *BoxNames[6]={"Figure","Table Box","Text Box","Usr Box","Equation","HTML Box"};
void TconvertedPass1_WP3::AnyBox3(DWORD end_of_code)
{
#ifdef DEBUG
  fprintf(log,"\n#AnyBox3() ");fflush(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;
//bool AllowCaption;
char BoxType;
WORD WPGResourceNo;
FIGURE_FLAGS FF;
WORD count_xx;

  //CrackObject(cq, end_of_code); //

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

  ActualPos = ftell(wpd);

  fseek(wpd, ActualPos+14L, SEEK_SET);
  RdWORD_HiEnd((WORD *)&FF, 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(wpd,&EquLen);Box.Width=EquLen/47.0;

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

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

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

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

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

  AttrOff(this,14);  		// ulem
  AttrOff(this,11);		// uulem
  for(i=First_com_section;i<=Last_com_section;i++)
      AttrOff(this,i);		// Any of section's attr cannot be opened.

  OldEnvir = envir;
  OldFlag = flag;
  OldAttr = attr;
  recursion++;

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

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

	    if((Box.Image_size = SelectImageResource3(WPGResourceNo))>0)
		{
		Box.Image_offset = ftell(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(wpd, Box.CaptionPos, SEEK_SET); // receive a caption size
	    ImageWP(this,ImageName,Box);
	    break;

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

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

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

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

	    ReadFormulaStr3(StrBeg, end_of_code);

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

	    attr = OldAttr;

	    PutFormula(this,StrBeg(),Box);

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

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


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


void TconvertedPass1_WP3::Column3(void)
{
#ifdef DEBUG
  fprintf(log,"\n#Column3() ");fflush(log);
#endif
BYTE NoColumns;

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

Column(this,NoColumns);

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


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

  MacChar = fgetc(wpd);
  WpCharSet = fgetc(wpd);
  Char = fgetc(wpd);

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

  if(Verbosing>1 && log!=NULL)
    fprintf(log, " \"%s\"", RetCharStr);

  return RetCharStr;
}


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

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

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

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

  Close_All_Attr(attr,strip);
  OldAttr=attr;
  attr.InitAttr();

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

  ActualPos = ftell(wpd);

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

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

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

	     default: ProcessKeyWP3();
		      break;
	     }

	   ActualPos = ftell(wpd);
	   }

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

  attr=OldAttr;

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


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

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

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

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

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


  Close_All_Attr(attr,strip);
  OldAttr=attr;
  attr.InitAttr();

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

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

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

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

	     default: ProcessKeyWP3();
		      break;
	     }

	   ActualPos = ftell(wpd);
	   }

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

  attr=OldAttr;

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


void TconvertedPass1_WP3::Header_Footer3(DWORD end_of_code)
{
#ifdef DEBUG
  fprintf(log,"\n#Header_Footer3() ");fflush(log);
#endif
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(wpd) <= 18)
	{Defs=0;goto ExitHeaderFooter;}

  OldFlag = flag;
  OldEnvir= envir;

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

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

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

  fseek(wpd, OldLen, SEEK_CUR);
  Defs = fgetc(wpd);

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

  fseek(wpd, 6L, SEEK_CUR);

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

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

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

  envir='!';		//Ignore enviroments after header/footer
  NewLine(this);

  attr.InitAttr();		//Turn all attributes in the header/footer off

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

	ProcessKeyWP3();
	}

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

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

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

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


void TconvertedPass1_WP3::LineSpacing3(void)
{
#ifdef DEBUG
  fprintf(log,"\n#LineSpacing3() ");fflush(log);
#endif
DWORD LastSpacing;
DWORD CurrentSpacing;
char b;

  RdDWORD_HiEnd(&LastSpacing,wpd);
  RdDWORD_HiEnd(&CurrentSpacing,wpd);

  b = 'l';
  fwrite(&b, 1, 1, table);
  Wr_word(table,CurrentSpacing);

  sprintf(ObjType, "Line Spacing %2.2f",float(CurrentSpacing)/128);
}


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 "";
}

void TconvertedPass1_WP3::TableStart3(DWORD & NewPos)
{
#ifdef DEBUG
  fprintf(log,"\n#TableStart3(%d) ",(int)NewPos);fflush(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(log) fprintf(log, _("\n%*sStart Table"), recursion*2, "");

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

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

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

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

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

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

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

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

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

  envir='!';
  fputc('%', table);fputc('%', strip);
  NewLine(this);

  envir = 'B';

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

  char_on_line = false;
  nomore_valid_tabs = false;
  rownum++;
  Make_tableentry_attr(this);
  latex_tabpos = 0;

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

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

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

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

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

  strcpy(ObjType, "Table Start");
}


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

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

  fseek(wpd, NewPos, SEEK_SET);

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

    OldFlag = flag;
    OldAttr = attr;

    flag = Nothing;

    fseek(wpd, NewPos, SEEK_SET);
    ActualPos=NewPos;

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

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

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

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

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

     Type=0;
     }

SkipUndoStuff:
 switch(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 (err != NULL)
		{
		perc.Hide();
		fprintf(err, _("\nWarning: Strange Undo type:%d!"),(int)subby);
		}
	   sprintf(ObjType, "!Undo (?%d:%d)"+(::UndoRedo?1:0),subby,(int)Level);
	   return;
   }

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


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

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

  bool 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."), (long)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. */
void TconvertedPass1_WP3::ProcessKeyWP3(void)
{
#ifdef DEBUG
  fprintf(log,"\n#ProcessKeyWP3() ");fflush(log);
#endif
  WORD w;
  DWORD NewPos = 0;
  unsigned char by, subby;

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

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


  /*Guessing end position of the object*/

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

  by = this->by;
  subby = this->subby;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	case 0xD0:switch(subby)
                    {
                    case 0x01: sprintf(ObjType,"!Set Hor Margin"); break;
                    case 0x02: LineSpacing3(); break;
	            case 0x06: Justification(this,3); break;
                    case 0x07: Suppress(this,3); break;
                    case 0x08: Page_number_position(this,3);break;
		    case 0x0D: fseek(wpd, 1L, SEEK_CUR);	//skip Old Mode
			    WidowOrphan(this,fgetc(wpd)&3);
                            break;
		    }
		  break;

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

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

        case 0xD3:switch(subby)
		    {
		    case 0x01:strcpy(ObjType,"!Underline mode"); break;
		    case 0x02:SetFootnoteNum(this,3);  break;
		    case 0x03:SetEndnoteNum(this,3);  break;
		    case 0x04:SetPgNum(this,3); break;
                    case 0x11:Language(this,3); break;
	            }
		  break;

	case 0xD5: Header_Footer3(NewPos);		break;

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

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

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

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

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

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

	case 0xDB:switch (subby)
                    {
		    case 0x0: strcpy(ObjType, "!Endr Style Def");	break;
		    case 0x1: strcpy(ObjType, "!Beg Par Style Def");break;
		    case 0x2: strcpy(ObjType, "!Beg EOP Style");	break; // Begin End Paragraph Style Definition
		    case 0x3: strcpy(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(this);		break;
		     case 1: strcpy(ObjType, "!SPg");break;	// Soft end of page
		     case 2: HardReturn(this);		break;
		     case 3: Terminate_Line(this, 'p');	// Soft page
			     strcpy(ObjType, "HRt-SPg");
			     break;
		     //case 4: 				//Temporary end of line
		     //case 5:				//Temporary end of page/column
		     case 6: Terminate_Line(this, 'h');	/* Dormant Hard Return */
		  	     strcpy(ObjType, "Dorm HRt");
		             break;
		     case 7: HardPage(this);		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(this);		break;	// Hard page
		     case 0xC:					// Hard hyphen at end of line
		     case 0xD:HardHyphen(this);		break;  // Hard hyphen at end of page/col
		     case 0xE:					// Soft hyphen at EOL
		     case 0xF:SoftHyphen(this);	 	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:strcpy(ObjType, "!BOF"); break; // Hard beginning of file
		     //case 0x14:			       //Temporary Hard end of column
		     //case 0x15:			       // Hard EOC/Soft EOP
		     case 0x16: if(envir=='B') char_on_line=true;
				CellTable(this);		break; // Hard end of table cell

		     case 0x18:				       // Hard end of table row/cell
		     case 0x19: RowTable(this);		break; // Hard end of table row/cell/soft end of page
                     case 0x1A:				       // Hard end of table row/end of table
		     case 0x1B: EndTable(this);		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(ObjType, "!Par Border On/Off"); break;

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

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

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

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

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


void TconvertedPass1_WP3::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();
}


/*******************************************************************/

int TconvertedPass1_WP3::Dispatch(int FuncNo, const void *arg)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WP3::Dispatch(%d) ",FuncNo);fflush(log);
#endif

 switch(FuncNo)
   {   
   case DISP_EXTRACT_LABEL:
         {         
         ExtractCaptionLabel3((const TBox *)arg);
         return 0;
         }

   case DISP_DO_CAPTION:
         {         
         DoCaption3((arg==NULL)?0:*(unsigned short*)arg);
         return 0;
         }
   }

return(-1);
}


/* 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();
    fseek(wpd,DocumentStart,SEEK_SET);
    }  

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

    by = 0;
    ProcessKeyWP3();
    }

  Finalise_Conversion(this);
  return(1);
}


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