/******************************************************************************
 * 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 <strings.h>
#include <lists.h>
#include "wp2latex.h"

#include "cp_lib/cptran.h"


extern set filter[4];

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

static void ProcessKey4(TconvertedPass1_WP4 *cq);
#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)

static void Character4(TconvertedPass1_WP4 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Character4() ");fflush(cq->log);
#endif

  fread(&cq->subby, 1, 1, cq->wpd);

  CharacterStr(cq,Ext_chr_str(cq->subby,cq,cq->ConvertCpg));

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


static void ColDef4(TconvertedPass1_WP4 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#ColDef4() ");fflush(cq->log);
#endif

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

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



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


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

  fseek(cq->wpd, 4, SEEK_CUR);

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

                fputc('%',cq->strip);
                }

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

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


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


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


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

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


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


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

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

       ProcessKey4(cq);
       }

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

  fputc('}',cq->strip);

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


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


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

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

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

       if(cq->by==0xD2) break;

       ProcessKey4(cq);
       }

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

  fputc('}',cq->strip);

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


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

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


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

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

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

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

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

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

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

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

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

       if(cq->by==0xFF || cq->by==0xD1) break;

       ProcessKey4(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->recursion--;

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

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


/* 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.  */
static void LineSpacing4(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#LineSpacing4() ");fflush(cq->log);
#endif
WORD CurrentSpacing;
char b;

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

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

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


static void LineUpDown(TconvertedPass1_WP4 *cq, float offset)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#LineUpDown(%f) ",offset);fflush(cq->log);
#endif

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

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


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


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


  fprintf(cq->strip, " \\index{");

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

       ProcessKey4(cq);
       }

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

  fputc('}',cq->strip);
  Index=true;

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


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

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

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

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

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

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


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


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

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

  OldActualPos = cq->ActualPos = ftell(cq->wpd);
  cq->by=fgetc(cq->wpd);

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

       if(cq->by==0xDF) break;

       ProcessKey4(cq);
       }

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

  cq->recursion--;
  AttrOff(cq,Hidden_Text);

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


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

  SectionNumber=fgetc(cq->wpd);
  cq->by=fgetc(cq->wpd);

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

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

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

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


static void DefMarkedText4(TconvertedPass1_WP4 *cq, DWORD & NewPos)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#DefMarkedText4() ");fflush(cq->log);
#endif

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

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



static void Tabset4(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Tabset4() ");fflush(cq->log);
#endif
  int tabpos;
  char ch;
  long pos;


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

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

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


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

  Make_tableentry_tabset(cq);
  sprintf(cq->ObjType, "TabSet");
}



static void UnderlineMode4(TconvertedPass1_WP4 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#UnderlineMode4() ");fflush(cq->log);
#endif

 fseek(cq->wpd, 1l, SEEK_CUR);
 cq->UnderlineType=fgetc(cq->wpd); /* second byte is a bit field.
			*       1 = double-underline (default single),
			*       2 = underline spaces (default don't)  */

 strcpy(cq->ObjType, "Und Opt");
}



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

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

  Pos = ftell(cq->wpd);

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

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


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

      switch (cq->by)
	{
	case 0xC4:fread(&cq->subby, 1, 1, cq->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
	}
      }
      
  by = cq->by;
  subby = cq->subby;

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

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

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

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


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

	case 0xBC:AttrOn(cq->attr,5);cq->SubSup|=0x82;		/* Superscript */
		  strcpy(cq->ObjType, "SupScript");
		  break;
	case 0xBD:AttrOn(cq->attr,6);cq->SubSup|=0x81;		/* Subscript */
		  strcpy(cq->ObjType, "SubScript");
		  break;
	case 0xBE:LineUpDown(cq, 0.5);			break;	/* Advance 1/2 line up */
	case 0xBF:LineUpDown(cq, -0.5);			break;	/* Advance 1/2 line down */
	case 0xC0:strcpy(cq->ObjType, "!Margin Reset"); break;  /* Margin change */
	case 0xC1:LineSpacing4(cq);			break;	/* Line spacing */
	case 0xC2:strcpy(cq->ObjType, "!Left Mar Relese");break;/* Margin release */
	case 0xC3:Center(cq);				break;	/* Center text */
	case 0xC4:if((subby & 0x7F)==0xA || (subby & 0x7F)==0xC)/* Align or Flush Right */
		     {
		     Flush_right(cq,(subby & 0x80)?1:0);
		     }
		  else
		    sprintf(cq->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(cq,4);   	break;	/* Page number position */
	case 0xC7:SetPgNum(cq,4);			break;	/* New page number */
//	case 0xC8: gobble(3);                      /* Set Page number column */
//	case 0xC9: gobble(20);                                  /* Set tabs */
	case 0xCA:strcpy(cq->ObjType, "!Cond EOP");     break;  /* Conditional end of page */
	case 0xCB:SetFontSize(cq,4);			break;  /* Set pitch or font */
	case 0xCC:Indent(cq,4);				break;	/* Indented paragraph */
	case 0xCD:Indent(cq,0x14);			break;  /* Indented paragraph (obsolete) */
	case 0xCE:strcpy(cq->ObjType, "!Top Margin");   break;  /* Set top margin */
	case 0xCF:Suppress(cq,4);			break;  /* Suppress headers/footers for this page */
	case 0xD0:strcpy(cq->ObjType, "!Form Len");     break;  /* old form length */       /* Set page length */
	case 0xD1:Header_Footer4(cq,NewPos,w);		break;	/* header/footer */
	case 0xD2:FootNoteObsolette(cq,NewPos,w);	break;	/* obsolete footnote */
	case 0xD3:SetFootnoteNum(cq, -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(cq->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(cq);			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(cq);			break;	/* End indented paragraph */
	case 0xDF:InvisibleChars4(cq,NewPos,w);		break;  /* invisible characters - commands for printer */
//	case 0xE0:                              /* Doubly-indented paragraph */
	case 0xE1:Character4(cq);			break;	/* IBM character */
	case 0xE2:FootEndNote(cq, NewPos, w);		break;	/* footnote or endnote */
//	case 0xE3: gobble(74+74);                     /* footnote attributes */
	case 0xE4:SetFootnoteNum(cq,4);			break;	/* set footnote number */
//	case 0xE5:                              /* paragraph numbering style */
//	case 0xE6:                                       /* paragraph number */
	case 0xE7:StartSection(cq,4);			break;
	case 0xE8:EndSection(cq,4);			break;
	case 0xE9:DefMarkedText4(cq, NewPos);		break;	/* begin marked text */
	case 0xEA:MakeIndex4(cq, NewPos);		break;	/* end marked text */
	case 0xEB:DateCode(cq);				break;	/* define marked text */
//	case 0xEC:			break;  /* define index mark */
	case 0xED:TableOfAuthorities4(cq, NewPos);	break;  /* Table of authorities */
	case 0xEE:strcpy(cq->ObjType, "!ParNumDef");    break;  /* paragraph number def */
	case 0xEF:ParagraphNumber(cq);			break;	/* paragraph number */
//	case 0xF0:					/*  Line Numbering */
	case 0xF1:Tabset4(cq);				break;	/* Tab settings */
        case 0xF2:Comment4(cq, NewPos, w);		break;
	case 0xF3:ColDef4(cq);				break;
//	case 0xF4:					/*Point size*/


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

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

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

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

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

  Finalise_Conversion(this);
  return(1);
}

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

