/******************************************************************************
 * program:     wp2latex                                                      *
 * function:    convert WordPerfect files into LaTeX                          *
 * modul:       pass1_4.cc                                                    *
 * description: This is conversion module for parsing WP 4.x binary files.    *
 *              Encrypted WP4.x files are handled by pass1c45 module.         *
 * licency:     GPL		                                              *
 ******************************************************************************/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#include "sets.h"
#include "stringa.h"
#include "lists.h"
#include "struct.h"

#include "wp2latex.h"
#include "cp_lib/cptran.h"


int set0_40[]={0 ___ 0xFF};		//Everything
int set1_40[]={0 ___ 0xBF,0xC0,0xC3,0xC4,0xD1,0xD2,0xD4 ___ 0xFF}; //Header, Footer, Minipage Text
int set2_40[]={0x20 ___ 0x7F,0xE1};  //Characters Only

//0 - object must be handled specialy, size is not defined
extern BYTE ObjWP4SizesC0[];


class TconvertedPass1_WP4: public TconvertedPass1
     {
public:char UnderlineType;
     char SubSup;
     SBYTE DefColumns;
     char LogLevel;

     virtual int Convert_first_pass(void);

protected:
     set filter[4];

     void Comment4(DWORD & NewPos, WORD & w);
     void Character4(void);
     void ColDef4(void);
     bool CheckConzistency4(long NewPos);
     void DefMarkedText4(DWORD & NewPos);
     void FootEndNote(DWORD & NewPos, WORD & w);
     void FootNoteObsolette(DWORD & NewPos, WORD & w);
     void Header_Footer4(DWORD & NewPos, WORD & w);
     void InitFilter4(void);
     void InvisibleChars4(DWORD & NewPos, WORD & w);
     void LineNumbering4(void);
     void LineSpacing4(void);
     void LineUpDown(float offset);
     void MakeIndex4(DWORD & NewPos);
     void Overstrike4(DWORD & NewPos, WORD & w);
     void ProcessKey4(void);     
     void TableOfAuthorities4(DWORD & NewPos);
     void Tabset4(void);
     void UnderlineMode4(void);
     };


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

/*Register translators here*/
TconvertedPass1 *Factory_WP4(void) {return new TconvertedPass1_WP4;}
FFormatTranslator FormatWP4("WP4.x",Factory_WP4);


//Converting wp4.2 units to wp5.x units
#define u2w(x) (120*x)


/// Convert a simple character in WP4
void TconvertedPass1_WP4::Character4(void)
{
#ifdef DEBUG
  fprintf(log,"\n#Character4() ");fflush(log);
#endif

  fread(&subby, 1, 1, wpd);

  CharacterStr(this,Ext_chr_str(subby,this,ConvertCpg));

  sprintf(ObjType, ":%u",(unsigned)subby);
}


void TconvertedPass1_WP4::ColDef4(void)
{
#ifdef DEBUG
  fprintf(log,"\n#ColDef4() ");fflush(log);
#endif

  fseek(wpd, 49L, SEEK_CUR);
  fread(&DefColumns, 1, 1, wpd);   /* new number of columns */

  sprintf(ObjType, "ColDef:%d",(int)DefColumns);
  if(Columns==0 && DefColumns>2) DefColumns=2;
}



void TconvertedPass1_WP4::Comment4(DWORD & NewPos, WORD & w)
{
#ifdef DEBUG
  fprintf(log,"\n#Comment4() ");fflush(log);
#endif
  signed char Old_char_on_line;
  unsigned char OldFlag;
  attribute OldAttr;


  OldFlag = flag;
  OldAttr = attr;
  Old_char_on_line = char_on_line;
  flag = CharsOnly;
  recursion++;
  attr.InitAttr();		//Turn all attributes in the comment off

  fseek(wpd, 4, SEEK_CUR);

  fputc('%',strip);
  NewPos = ActualPos = ftell(wpd);
  while (!feof(wpd))
       {
       fread(&by, 1, 1, wpd);
       if(by==0)	//End of comment text
       		{
                while (!feof(wpd) && !(by==0xF2))
                	fread(&by, 1, 1, wpd);
                }
       if(by==0xF2) break;
       if(by==0xA || by==0xD)	//New comment line
       		{
                line_term = 's';    	//Soft return
		Make_tableentry_envir_extra_end(this);
		fprintf(strip, "\n");
		rownum++;
		Make_tableentry_attr(this);

                fputc('%',strip);
                }

       ProcessKey4();
       continue;
       }
  ActualPos = ftell(wpd);
  w = ActualPos-NewPos+5;
  NewPos = ActualPos;

  line_term = 's';    	//Soft return
  Make_tableentry_envir_extra_end(this);
  fprintf(strip, "\n");
  rownum++;
  Make_tableentry_attr(this);


  recursion--;
  strcpy(ObjType, "Comment");
  attr = OldAttr;
  flag = OldFlag;
  if(Old_char_on_line==true || Old_char_on_line==-1) char_on_line = -1;
	else char_on_line = false;
}


void TconvertedPass1_WP4::FootEndNote(DWORD & NewPos, WORD & w)
{
#ifdef DEBUG
  fprintf(log,"\n#FootEndNote() ");fflush(log);
#endif
  unsigned char OldFlag;
  attribute OldAttr;
  unsigned char NoteType;


  OldFlag = flag;
  OldAttr = attr;
  flag = HeaderText;
  recursion++;
  attr.InitAttr();		//Turn all attributes in the note off

  NewPos = ftell(wpd);
  fread(&NoteType, 1, 1, wpd);
  if(NoteType == 2) {
		  if(!EndNotes) EndNotes=true;		/* set up endnotes */
		  if(EndNotes<0) goto FootNote;		/* endnotes are disabled */
		  fprintf(strip, "\\endnote{");
		  }
	    else {
FootNote:	 fprintf(strip, "\\footnote{");
		 }


  while (!feof(wpd))	// Skip everything to the mark 0xFF
	{
	if(fread(&by, 1, 1, wpd)!=1) goto EmptyNote;
	if(by==0xE2) goto EmptyNote;
	if(by==0xFF) break;	// real start of the note text
	}
  fseek(wpd, 2l, SEEK_CUR);		/* margins */


  ActualPos = ftell(wpd);
  while (!feof(wpd))
       {
       if(fread(&by, 1, 1, wpd)!=1) break;

       if(by==0xE2) break;
       if(by==0) {ActualPos++;continue;}

       ProcessKey4();
       }

EmptyNote:
  ActualPos = ftell(wpd);
  w = ActualPos-NewPos+1;
  NewPos = ActualPos;

  fputc('}',strip);

  recursion--;
  strcpy(ObjType, NoteType==2?"Endnote":"Footnote");
  attr = OldAttr;
  flag = OldFlag;
  char_on_line = true;
}


void TconvertedPass1_WP4::FootNoteObsolette(DWORD & NewPos, WORD & w)
{
#ifdef DEBUG
  fprintf(log,"\n#FootNote() ");fflush(log);
#endif
  unsigned char OldFlag;
  attribute OldAttr;


  OldFlag = flag;
  OldAttr = attr;
  flag = CharsOnly;
  recursion++;
  attr.InitAttr();		//Turn all attributes in the note off

  fseek(wpd, 5L, SEEK_CUR);
  fprintf(strip, "\\footnote{");

  ActualPos = ftell(wpd);
  while (!feof(wpd))
       {
       fread(&by, 1, 1, wpd);

       if(by==0xD2) break;

       ProcessKey4();
       }

  ActualPos = ftell(wpd);
  w = ActualPos-NewPos+1;
  NewPos = ActualPos;

  fputc('}',strip);

  recursion--;
  strcpy(ObjType, "Footnote");
  attr = OldAttr;
  flag = OldFlag;
  char_on_line = true;
}


void TconvertedPass1_WP4::Header_Footer4(DWORD & NewPos, WORD & w)
{
#ifdef DEBUG
  fprintf(log,"\n#Header_Footer4() ");fflush(log);
#endif
  unsigned char OldFlag,OldEnvir;
  attribute OldAttr;
  unsigned char HFtype,HFtype2;
  long PosX;
  char SaveLLevel=LogLevel;

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


  PosX = ftell(wpd) + 6;
  fread(&HFtype, 1, 1, wpd);

  fseek(wpd, PosX, SEEK_SET);
  ActualPos = PosX;
  flag = Nothing;
  LogLevel = 0;		//do not log dummy scan
  while (!feof(wpd))	//This loop scans the header only
       {
       fread(&by, 1, 1, wpd);

       if(by==0xFF)
       		{
                fread(&subby, 1, 1, wpd);
                fread(&HFtype2, 1, 1, wpd);
                fread(&by, 1, 1, wpd);
		if(by!=0xD1) goto EndHeaderFooter; //This object is corrupted
                NewPos = ftell(wpd);
		break;
                }
       if(by==0xD1)
       		{
                HFtype2=HFtype | 4;
                ActualPos = ftell(wpd);
                break;
                }

       ProcessKey4();
       }
  if(feof(wpd)) goto EndHeaderFooter; //This object is corrupted
  w = ActualPos-PosX+6;

// Start a conversion of a Header or Footer
  LogLevel = SaveLLevel;
  attr.InitAttr();		//Turn all attributes in the header/footer off
  recursion++;

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

//	             (HFtype2 & 3) <= 1 ? "\\headtext":"\\foottext"
  InitHeaderFooter(this, HFtype2 & 3, HFtype2 >> 2);

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

  fseek(wpd, PosX, SEEK_SET);
  ActualPos = PosX;
  envir = ' ';
  flag = HeaderText;
  char_on_line = -10;
  while (!feof(wpd))
       {
       fread(&by, 1, 1, wpd);

       if(by==0xFF || by==0xD1) break;

       ProcessKey4();
       }

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

  recursion--;

  attr = OldAttr;
  flag = OldFlag;
  envir= OldEnvir;
  char_on_line = -10;

EndHeaderFooter:
  LogLevel=SaveLLevel;
  strcpy(ObjType, ((HFtype & 3) <= 1)?"Header":"Footer");
}


/** This procedure converts WP4.x Line numbering. */
void TconvertedPass1_WP4::LineNumbering4(void)
{
#ifdef DEBUG
  fprintf(log,"\n#LineNumbering4() ");fflush(log);
#endif
  BYTE LineNumFlag;

  // <F0><Old Interval><Old Position><New Interval><New Position><F0>
  fseek(wpd, 2, SEEK_CUR);
  LineNumFlag = fgetc(wpd);

  LineNumbering(this, LineNumFlag&0x80);
}


/* LineSpacing is called whenever we hit a line-spacing-change command.
 * The argument is the desired line spacing, multiplied by two.
 * So single spacing gets a 2, 1.5 spacing gets a 3, etc.  */
void TconvertedPass1_WP4::LineSpacing4(void)
{
#ifdef DEBUG
  fprintf(log,"\n#LineSpacing4() ");fflush(log);
#endif
WORD CurrentSpacing;
char b;

  b = (WORD)fgetc(wpd) * 64;		   //LastSpacing
  CurrentSpacing=(WORD)fgetc(wpd) * 64;

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

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


void TconvertedPass1_WP4::LineUpDown(float offset)
{
#ifdef DEBUG
  fprintf(log,"\n#LineUpDown(%f) ",offset);fflush(log);
#endif

  fprintf(strip, "\\vspace*{%2.2fex}", offset);

  sprintf(ObjType, "Advance Up/Down %2.2f",offset);
}


void TconvertedPass1_WP4::MakeIndex4(DWORD & NewPos)
{
#ifdef DEBUG
  fprintf(log,"\n#MakeIndex4() ");fflush(log);
#endif
  signed char Old_char_on_line;
  unsigned char OldFlag;
  attribute OldAttr;


  OldFlag = flag;
  OldAttr = attr;
  Old_char_on_line = char_on_line;
  flag = CharsOnly;
  recursion++;
  attr.InitAttr();		//Turn all attributes in the index off


  fprintf(strip, " \\index{");

  NewPos = ActualPos = ftell(wpd);
  while (!feof(wpd))
       {
       fread(&by, 1, 1, wpd);
       if(by==0)	//End of index text
		{
                while (!feof(wpd) && !(by==0xEA))
                	fread(&by, 1, 1, wpd);
                }
       if(by==0xEA) break;
       if(by==0xE1)		//Extended char ?
		{
		fseek(wpd, 2, SEEK_CUR);
		continue;
		}
       if(by==0xA || by==0xD)	//New line -- ignore
       		{
                fprintf(strip,"_nl");
                continue;
                }
       if(by=='\\') {fputs("_bsl", strip); continue;}
       if(by=='$')  {fputs("_dol", strip); continue;}
       if(by=='{')  {fputs("_opb", strip); continue;}
       if(by=='}')  {fputs("_clb", strip); continue;}
       if(by=='_')  {fputs("_und", strip); continue;}

       ProcessKey4();
       }

  ActualPos = ftell(wpd);
//w = ActualPos-NewPos+5;
  NewPos = ActualPos;

  fputc('}',strip);
  Index=true;

  recursion--;
  strcpy(ObjType, "Index");
  attr = OldAttr;
  flag = OldFlag;
  char_on_line = Old_char_on_line;
  char_on_line = true;
}


void TconvertedPass1_WP4::Overstrike4(DWORD & NewPos, WORD & w)
{
#ifdef DEBUG
  fprintf(log,"\n#Overstrike4() ");fflush(log);
#endif
  char OldSubSup,OldMathDepth;

  if(char_on_line<=0)
	{
	strcpy(ObjType, "!Overstrike");
	return;
	}

  ActualPos = ftell(wpd);

  by=fgetc(wpd);
  while( (by>=0x90 && by<=0x97)||(by>=0xB2 && by<=0xBD)) //attributes
	{
	ProcessKey4();
	by=fgetc(wpd);
	}

  if((by>=0x20 && by< 0x80) || by==0xE1)
	{
	Open_All_Attr(attr, strip);
	OldMathDepth=attr.Math_Depth;
	if(attr.Math_Depth>0) attr.Math_Depth=0;//Math might be nested inside \llap
	OldSubSup=SubSup;SubSup=0;
	fprintf(strip, "\\llap{");
	ProcessKey4();
	fputc('}',strip);
	NewPos = ActualPos = ftell(wpd);
	w++;

	attr.Math_Depth=OldMathDepth;
	if(OldSubSup)
	      {
	      AttrOff(this,5);
	      AttrOff(this,6);
	      }
	}
	else fseek(wpd,ActualPos,SEEK_SET); //Overstrike rejected


  char_on_line = true;
  sprintf(ObjType, "Overstrike %c", by);
}


void TconvertedPass1_WP4::InvisibleChars4(DWORD & NewPos, WORD & w)
{
#ifdef DEBUG
  fprintf(log,"\n#InvisibleChars4() ");fflush(log);
#endif
signed char OldCharOnLine;
DWORD OldActualPos;

  OldCharOnLine = char_on_line;
  AttrOn(attr,Hidden_Text);
  recursion++;

  OldActualPos = ActualPos = ftell(wpd);
  by=fgetc(wpd);

  while (!feof(wpd))
       {
       fread(&by, 1, 1, wpd);

       if(by==0xDF) break;

       ProcessKey4();
       }

  NewPos = ActualPos = ftell(wpd);
  w+= ActualPos -OldActualPos;

  recursion--;
  AttrOff(this,Hidden_Text);

  char_on_line = OldCharOnLine;
  strcpy(ObjType, "Ptr Cmnd");
}


void TconvertedPass1_WP4::TableOfAuthorities4(DWORD & NewPos)
{
#ifdef DEBUG
  fprintf(log,"\n#TableOfAuthorities4() ");fflush(log);
#endif
BYTE SectionNumber;
string ShortForm,FullForm;

  SectionNumber = fgetc(wpd);
  by=fgetc(wpd);

  NewPos = ActualPos = ftell(wpd);

  if(by!=0xED)
    while(!feof(wpd))
       {
       by=fgetc(wpd);
       if(by==0) break;
       if(by==0xED) break;
       if(by==0xE1)		//Extended char ?
		{
		fseek(wpd, 2, SEEK_CUR);
		continue;
		}
       else ShortForm+=by;
       }
  if(by!=0xED)
    while(!feof(wpd))
       {
       by=fgetc(wpd);
       if(by==0) break;
       if(by==0xED) break;
       if(by==0xE1)		//Extended char ?
		{
		fseek(wpd, 2, SEEK_CUR);
		continue;
		}
       else FullForm+=by;
       }
  if(by!=0xED) by=fgetc(wpd);

  ActualPos = ftell(wpd);
  NewPos = ActualPos;

  if(length(ShortForm)>sizeof(ObjType)-5)
	ShortForm=copy(ShortForm,0,sizeof(ObjType)-5);
  sprintf(ObjType, "!ToA:%s", ShortForm());	/*not supported yet*/
}


void TconvertedPass1_WP4::DefMarkedText4(DWORD & NewPos)
{
#ifdef DEBUG
  fprintf(log,"\n#DefMarkedText4() ");fflush(log);
#endif

  TableOfContents(this,4);	/*1 byte contains list type as usual for all WP releases*/
  fseek(wpd,5,SEEK_CUR);	/*skip 5 bytes with definition*/

  while(!feof(wpd))
       {
       fread(&by, 1, 1, wpd);
       if(by==0xE9) break;
       }
  NewPos = ActualPos = ftell(wpd);
}



void TconvertedPass1_WP4::Tabset4(void)
{
#ifdef DEBUG
  fprintf(log,"\n#Tabset4() ");fflush(log);
#endif
  int tabpos;
  char ch;
  long pos;


  pos = ftell(wpd);
  fseek(wpd, pos+32l+20l, SEEK_SET);   /* Ga naar TAB-info */

  num_of_tabs = 0;
  ch=0;		//????
  for(tabpos=0;tabpos<256;tabpos++)
	{
	ch <<= 1;
	if(!(tabpos & 7))
		fread(&ch, 1, 1, wpd);

	if(ch & 0x80)
		{
		this->tabpos[num_of_tabs] = u2w(tabpos);
		if(++num_of_tabs > 40) break;
		}
	}


  tabpos=num_of_tabs;
  while(tabpos < 40)
	{
	this->tabpos[tabpos++] = 0xFFFF;
	}

  Make_tableentry_tabset(this);
  strcpy(ObjType, "TabSet");
}


void TconvertedPass1_WP4::UnderlineMode4(void)
{
#ifdef DEBUG
  fprintf(log,"\n#UnderlineMode4() ");fflush(log);
#endif

 fseek(wpd, 1l, SEEK_CUR);
 UnderlineType = fgetc(wpd); /* second byte is a bit field.
		0 = normal underlining
		1 = double underlining
		2 = single underlining continuous
		3 = double continuous */
 sprintf(ObjType, "Und Opt %u", (unsigned)UnderlineType);
}


bool TconvertedPass1_WP4::CheckConzistency4(long NewPos)
{
#ifdef DEBUG
  fprintf(log,"\n#CheckConzistency() ");fflush(log);
#endif

  bool Result = true;
  unsigned char TestedBy;
  long Pos;

  Pos = ftell(wpd);

  fseek(wpd, NewPos-1 , 0);
  fread(&TestedBy, 1, 1, wpd);
  if (TestedBy != by)
  	{
        if (err != NULL)
	  {
	  perc.Hide();
          fprintf(err,
	      _("\nError: Object %lX:%X consistency check failed. Trying to ignore."),Pos,(int)by);
          }
        CorruptedObjects++;
        Result = false;
	/* asm int 3; end;*/
	}

  fseek(wpd, Pos, 0);
  return Result;
}


/** This is main procedure for processing one key. It is recursivelly called. */
void TconvertedPass1_WP4::ProcessKey4(void)
{
#ifdef DEBUG
  fprintf(log,"\n#ProcessKey4() ");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 >= 0xC0)
      {
      w = ObjWP4SizesC0[this->by-0xC0];
      if(w>0) NewPos = ActualPos + w;

      switch(this->by)
	{
	case 0xC4:fread(&this->subby, 1, 1, wpd);  break;
//	case 0xD1:	//header & footer must be analyzed specially
//              verify(0xFF); verify(0xFF);/* separator */ gobble(2);                       /* left and right margin */
//	case 0xDF: gobble_until(0xDF);              /* invisible characters */
//	case 0xE2:  handle note
	}
      }
      
	// Create backup of command and subcommand for the case of recursion.
  by = this->by;
  subby = this->subby;

  if(ExtendedCheck && NewPos != 0)
    if(!CheckConzistency4(NewPos))
      {
      NewPos = 0;
      strcpy(ObjType, "Corrupted!!");
      goto _LObjectError;
      }

  if(filter[flag][by])
     {
     switch(by)
	{
	case 0x02:PageNumber(this);	break;          /* Page number */

	case 0x09:strcpy(ObjType, "!Tab");
		  putc(' ', strip);   break;	/*tabulator (ignored)*/
	case 0x0a:HardReturn(this);break;			// Hard return
	case 0x0b:Terminate_Line(this,'p');strcpy(ObjType, "SRt SoftPg");break;/* Soft page break after a SRt */
	case 0x0c:strcpy(ObjType, "HPg");Terminate_Line(this,'P');break;	// Hard page
	case 0x0d:SoftReturn(this);break;			/* Soft return */

	case 0x20:putc(' ', strip);   break;	/* Soft space ' '*/


	case 0x80:strcpy(ObjType, "NOP");		break;	/* NOP */
	case 0x81:Justification(this, 1 | 0x80);	break;	/* Full justification */
	case 0x82:Justification(this, 0 | 0x80);	break;	/* Left justification - Ragged right */
	case 0x83:if(envir=='c')				/* End centering */
			 Justification(this, 1 + 0x80);
		  strcpy(ObjType, "Center End");	break;
//	case 0x84: leave_environment(0); break;         	/* End aligned text */
//	case 0x85: process0(MathCalc); break;            	/* Begin math calc */
	case 0x86:CenterPage(this);			break;	/* Center page vertically */
	case 0x87:Column(this,DefColumns);  		break;	/* Begin column mode */
	case 0x88:Column(this,1);			break;	/* End column mode */
//	case 0x89: process0(Tab);	 break;			/* Tab after right margin */
	case 0x8A:WidowOrphan(this,3);			break;	/* Widow/orphan protection */
	case 0x8B:WidowOrphan(this,0);			break;	/* Allow widows/orphans */
	case 0x8C:if(char_on_line>=0) Terminate_Line(this,'h'); /* Soft page break after a HRt */
			         else Terminate_Line(this,'s');     // hard return mustn't occur here, fix it
		  strcpy(ObjType, "HRt-SPg");	break;
//      case 0x8D:process0(note_status == eFn ? FNoteNum : ENoteNum);/* Footnote/Endnote number */
	case 0x90:Attr_ON(this,10);			break;	/* Begin redline */
	case 0x91:Attr_OFF(this,10);			break;	/* End redline */
	case 0x92:Attr_ON(this,13);			break;	/* Begin strikeout */
	case 0x93:Attr_OFF(this,13);			break;	/* End strikeout */
	case 0x94:if(UnderlineType & 1) Attr_ON(this,11);	/* Dbl Begin underlining */
				       else Attr_ON(this,14); /* Normal */
		  strcpy(ObjType, "Underline");	break;
	case 0x95:AttrOff(this,14);				/* End underlining */
		  AttrOff(this,11);
		  strcpy(ObjType, "underline");	break;
	case 0x96:Attr_ON(this,17);			break;	/* Begin reverse video */
	case 0x97:Attr_OFF(this,17);			break;	/* End reverse video */
//	case 0x98: 	 break;					/* Table of contents placeholder */
	case 0x99:Overstrike4(NewPos,w);		break;	/* Overstrike */
	case 0x9A:CancelHyph(this);			break;
	case 0x9B:strcpy(ObjType,"!End Gener Text");break;	/* End of generated text */
	case 0x9C:Attr_OFF(this,12);			break;	/* End boldface */
	case 0x9D:Attr_ON(this,12);			break;	/* Begin boldface */
	case 0x9E:Hyphenation(this, false);		break;	/* Forbid hyphenation */
	case 0x9F:Hyphenation(this, true);		break;	/* Allow hyphenation */
	case 0xA0:fputc('~', strip);strcpy(ObjType, " ");
		  break;		    			/* Hard space */
	case 0xA1: strcpy(ObjType, "!Do Subtot");break;		/* Do subtotal - process0(SubTtl); */
//	case 0xA2: process0(IsSubTtl); break;			/* Subtotal entry */
	case 0xA3: strcpy(ObjType, "!Do Total");break;		/* Do total - process0(Ttl); */
//	case 0xA4: process0(IsTtl); break;			/* Total entry */
	case 0xA5: strcpy(ObjType, "!Do Grand Total");break;	/* Do grand total - process0(GrandTtl); */
	case 0xA6: strcpy(ObjType, "!CalcCol");break;		/* Math calc column - process0(MathCalcColumn);*/
//	case 0xA7: process0(Math); break;			/* Begin math mode */
//	case 0xA8: process0(eMath); break;			/* End math mode */
	case 0xA9:                     				/* Normal breakable hyphen */
	case 0xAA:                              		/* Hyphen at end of line */
	case 0xAB:HardHyphen(this);break;			 	/* Hyphen at end of page */
	case 0xAC:SoftHyphen(this);			break;	/* Discretionary hyphen */
	case 0xAD:SoftHyphen(this);			break;	/* Discretionary hyphen at EOLn */
	case 0xAE:SoftHyphen(this);			break;  /* Discretionary hyphen at EOPg */
	case 0xAF:Column(this,false);			break;	/* EOT columns and EOLn */
	case 0xB0:Column(this,false);			break;	/* EOT columns and EOPg */
//	case 0xB1: process0(NegateTotal); break;     /* Negate current total */
	case 0xB2:Attr_ON(this,8);			break;	/* Italic On */
	case 0xB3:Attr_OFF(this,8);			break;	/* Italic Off */
	case 0xB4:Attr_ON(this,9);			break;	/* Shadow On */
	case 0xB5:Attr_OFF(this,9);			break;	/* Shadow Off */
	case 0xB6:Attr_ON(this,7);			break;	/* Outline On */
	case 0xB7:Attr_OFF(this,7);			break;  /* Outline Off */

	case 0xBC:AttrOn(attr,5);SubSup|=0x82;		/* Superscript */
		  strcpy(ObjType, "SupScript");
		  break;
	case 0xBD:AttrOn(attr,6);SubSup|=0x81;		/* Subscript */
		  strcpy(ObjType, "SubScript");
		  break;
	case 0xBE:LineUpDown(0.5);			break;	/* Advance 1/2 line up */
	case 0xBF:LineUpDown(-0.5);			break;	/* Advance 1/2 line down */
	case 0xC0:strcpy(ObjType, "!Margin Reset");	break;  /* Margin change */
	case 0xC1:LineSpacing4();			break;	/* Line spacing */
	case 0xC2:strcpy(ObjType, "!Left Mar Relese");break;/* Margin release */
	case 0xC3:Center(this);				break;	/* Center text */
	case 0xC4:if((subby & 0x7F)==0xA || (subby & 0x7F)==0xC)/* Align or Flush Right */
		     {
		     Flush_right(this, (subby & 0x80)?1:0);
		     }
		  else
		    sprintf(ObjType, "!Align(%d)", (int)subby);
		  break;
//	case 0xC5: gobble(2); c = igetc();               /* Hyphenation zone */
//              process2(HZone, c, igetc()); verify(0xC5); break;
	case 0xC6:Page_number_position(this,4);   	break;	/* Page number position */
	case 0xC7:SetPgNum(this,4);			break;	/* New page number */
//	case 0xC8: gobble(3);                      /* Set Page number column */
//	case 0xC9: gobble(20);                                  /* Set tabs */
	case 0xCA:strcpy(ObjType, "!Cond EOP");     break;  /* Conditional end of page */
	case 0xCB:SetFontSize(this,4);			break;  /* Set pitch or font */
	case 0xCC:Indent(this,4);			break;	/* Indented paragraph */
	case 0xCD:Indent(this,0x14);			break;  /* Indented paragraph (obsolete) */
	case 0xCE:strcpy(ObjType, "!Top Margin");	break;  /* Set top margin */
	case 0xCF:Suppress(this,4);			break;  /* Suppress headers/footers for this page */
	case 0xD0:strcpy(ObjType, "!Form Len");		break;  /* old form length */       /* Set page length */
	case 0xD1:Header_Footer4(NewPos,w);		break;	/* header/footer */
	case 0xD2:FootNoteObsolette(NewPos,w);		break;	/* obsolete footnote */
	case 0xD3:SetFootnoteNum(this, -4);		break;  /* obsolete `set footnote number' */
//	case 0xD4:                            /* Advance to half line number */
//	case 0xD5: gobble(1); process1(LPI, igetc());    /* Set LPI (6 or 8) */
//	case 0xD6:                                      /* set extended tabs */
	      /* next 4 bytes are <old start><old increment>
				  <new start><new increment> */
	case 0xD7:strcpy(ObjType, "!Math Cols");   break;  /* Define math columns */
//	case 0xD8: gobble(1); process1(AlignChar, igetc());        verify(0xD8); break;           /* Set alignment character */
//	case 0xD9: gobble(2);                     /* obsolete margin release */
	case 0xDA:UnderlineMode4();			break;	/* Set underline mode */
//	case 0xDB:                                   /* Set sheet feeder bin */
//	case 0xDC: gobble(7); verify(0xDC); break;      /* End-of-page codes */
//	case 0xDD: gobble(22);                             /* define columns */
	case 0xDE:End_of_indent(this);			break;	/* End indented paragraph */
	case 0xDF:InvisibleChars4(NewPos,w);		break;  /* invisible characters - commands for printer */
//	case 0xE0:                              /* Doubly-indented paragraph */
	case 0xE1:Character4();				break;	/* IBM character */
	case 0xE2:FootEndNote(NewPos, w);		break;	/* footnote or endnote */
//	case 0xE3: gobble(74+74);                     /* footnote attributes */
	case 0xE4:SetFootnoteNum(this,4);			break;	/* set footnote number */
//	case 0xE5:                              /* paragraph numbering style */
//	case 0xE6:                                       /* paragraph number */
	case 0xE7:StartSection(this,4);			break;
	case 0xE8:EndSection(this,4);			break;
	case 0xE9:DefMarkedText4(NewPos);		break;	/* begin marked text */
	case 0xEA:MakeIndex4(NewPos);			break;	/* end marked text */
	case 0xEB:DateCode(this);				break;	/* define marked text */
//	case 0xEC:			break;  /* define index mark */
	case 0xED:TableOfAuthorities4(NewPos);		break;  /* Table of authorities */
	case 0xEE:strcpy(ObjType, "!ParNumDef");	break;  /* paragraph number def */
	case 0xEF:ParagraphNumber(this);		break;	/* paragraph number */
	case 0xF0:LineNumbering4();			break;	/*  Line Numbering */
	case 0xF1:Tabset4();				break;	/* Tab settings */
        case 0xF2:Comment4(NewPos, w);			break;
	case 0xF3:ColDef4();				break;
//	case 0xF4:					/*Point size*/


	default:if(by>=0x01 && by<=0x7f)
		     {
		     RequiredFont = FONT_NORMAL;
		     CharacterStr(this, Ext_chr_str(by,this,NULL));
                     if(attr.Closed_Depth>0)
			{
			if(SubSup)
			  {
			  AttrOff(this,5);
			  AttrOff(this,6);
			  }
			SubSup=0;
			}
                     }
                break;
        }
  }

_LObjectError:
  if (log != NULL && LogLevel>=1)
    {   /**/
    if ((by >= 0x80)||(*ObjType != '\0'))
        {
	fprintf(log, _("\n%*sObject type:%3Xh subtype:%3d length:%4u"),
	                    recursion * 2, "", by, subby, w);
	if (*ObjType != '\0')
	          fprintf(log, " [%s] ", ObjType);
             else fprintf(log, "    ");
        if(*ObjType==0) UnknownObjects++;

        fflush(log);
        }
    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, SEEK_SET);
  ActualPos = NewPos;
  NewPos = 0;

  /*these functions has fixed size - see table SizesC0*/
}


void TconvertedPass1_WP4::InitFilter4(void)
{
 filter[0]=set(set0_40,sizeof(set0_40)/sizeof(int));
 filter[1]=set(set1_40,sizeof(set1_40)/sizeof(int));
 filter[2]=set(set2_40,sizeof(set2_40)/sizeof(int));
 filter[3]=set();
}


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

  LogLevel=1;
  InitFilter4();

  ConvertCpg = GetTranslator("wp4aTOinternal");
  DefColumns=2;

  UnderlineType = 0;
  SubSup = 0;

  DocumentStart=ftell(wpd);

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

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

      by = 0;
      ProcessKey4();
      }

  Finalise_Conversion(this);
  return(1);
}

/*--------------------End of PASS1_4------------------*/

