/******************************************************************************
 * program:     wp2latex                                                      *
 * function:    Convert WordPerfect 5.x files into LaTeX		      *
 * modul:       pass1_5.cc                                                    *
 * description: This is conversion module for parsing WP 5.x binary files.    *
 *              Encrypted WP5.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 "lists.h"
#include "stringa.h"
#include "struct.h"

#include "raster.h"
#include "wp2latex.h"
#include "cp_lib/cptran.h"
#include "images/image.h"


extern list UserLists;
extern RGB_Record WPG_Palette[256];

static int set0[]={0 ___ 0xFF};		//Everything
static int set1[]={0 ___ 0xB,0xD ___ 0xBF,0xC0,0xC1,0xC3,0xC4,0xD0,0xD1,0xD2,0xD4 ___ 0xFF}; //Header, Footer, Minipage Text
static int set2[]={0x20 ___ 0x7F,0xA0,0xA9,0xC0};  //Characters Only


/*(3,8,10,2,2,4,5,6,0,0,0,0,0,0,0,0);*/
static const unsigned char SizesC0[0x10] = {
  4, 9, 11, 3, 3, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0
  };

typedef struct
	{
	uint16_t   PacketType;
	uint32_t  Length;
	uint32_t  DataPointer;
	} NestedPacket;


class TconvertedPass1_WP5: public TconvertedPass1
     {
public:
     TconvertedPass1_WP5(void): ResourceStart(0),FontNames(0),FontList(0)
		{Images.Length=0; Images.DataPointer=0; ImageCounter=0;}

     uint32_t ResourceStart;
     uint16_t ImageCounter;
     int8_t DefColumns;
     NestedPacket Images;
     uint32_t FontNames;		//offset of packet with font names
     uint32_t FontList;

     virtual int Convert_first_pass(void);
     virtual int Dispatch(int FuncNo, const void *arg);

     virtual void ProcessKey(void);
     bool CheckConzistency(long NewPos);

protected:
     set filter[4];

     void Advance(void);
     void DocumentSummary(uint32_t length);
     void WalkResources(void);
     void TableStart5(unsigned short len, uint32_t & NewPos);
     void NonEditable5(uint32_t end_of_code);
     void SetFont5(void);
     void FinishSummaryItem(int ItemNo);
     void ReadFormulaStr(string & StrBeg, uint32_t end_of_code);
     void AnyBox(uint32_t end_of_code);
     void ExtendedCharacter(void);
     uint32_t SelectImageResource(int GraphicsNo);
     void LabelInside(uint32_t end_of_code);
     void MakeIndex(uint32_t end_of_code);
     void MakeLabel(uint32_t end_of_code);
     void MakeRef(uint32_t end_of_code);
     void InitFilter5(void);
     void LineNumbering5(void);
     void ColDef5(void);
     void Comment5(uint32_t end_of_code);
     void Endnote(uint32_t end_of_code);
     void Footnote(uint32_t end_of_code);
     void Header_Footer(uint32_t end_of_code);
     void MarkedTextBegin(uint32_t & NewPos);
     void Overstrike(uint32_t end_of_code);
     void ExtractCaptionLabel5(const TBox *Box);
     void DoCaption5(unsigned short CaptionSize);
     };


/*Register translators here*/
TconvertedPass1 *Factory_WP5(void) {return new TconvertedPass1_WP5;}
FFormatTranslator FormatWP5("WP5.x",&Factory_WP5);


typedef struct
	{
	uint16_t  HeadPacketType;
	uint16_t  NoIndexes;
	uint16_t  IndexBlkSize;
	uint32_t NextBlock;
	} Resource5;


void TconvertedPass1_WP5::FinishSummaryItem(int ItemNo)
{
#ifdef DEBUG
 fprintf(log,"\n#FinishSummaryItem() ");fflush(log);
#endif

 switch(ItemNo)
	{
	case 0:
	case 1:fprintf(strip,"}");		break;
	case 2:break;
	case 3:break;
	case 4:fprintf(strip,"}");		break;
	case 5:break;
	case 6:NewLine(this);
	       fprintf(strip,"\\end{abstract}");
	       break;
	}
 NewLine(this);
}


/** This procedure reads a document summary packet. */
void TconvertedPass1_WP5::DocumentSummary(uint32_t length)
{
#ifdef DEBUG
  fprintf(log,"\n#DocumentSummary(%lu) ",(unsigned long)length);fflush(log);
#endif
uint32_t SummaryEnd,SummaryStart;
int SummaryItem=0;
unsigned SummaryChars;
unsigned TotalSummary=0;
unsigned spaces=0;
unsigned char OldFlag;

SummaryStart=ActualPos;
SummaryEnd=ActualPos+length;
//ActualPos+=26;
fseek(wpd,ActualPos,SEEK_SET);

OldFlag=flag;
flag = HeaderText;
attr.InitAttr();
SummaryChars=0;

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

   if(ActualPos>=SummaryStart+26 && SummaryItem==0)	//End of first item
	{
	if(SummaryChars>0) FinishSummaryItem(SummaryItem);
	SummaryItem=1;
	SummaryChars=0;
	}
   if(ActualPos>=SummaryStart+26+68 && SummaryItem==1)//End of second item
	{
	if(SummaryChars>0) FinishSummaryItem(SummaryItem);
	SummaryItem++;
	SummaryChars=0;
	}
   if(by == 0)			//End of null terminated items
	{
	if(SummaryChars>0) FinishSummaryItem(SummaryItem);
	SummaryItem++;
	SummaryChars=0;
	ActualPos++;
	continue;
	}
   if(by==0xFF) break;		//End of all items in summary


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

   if(isalnum(by) || by==0xC0)
	{
	if(SummaryChars==0)
	   {
	   switch(SummaryItem)
		{
		case 0:fprintf(strip,"\\date{");
		       TotalSummary|=4;				break;
		case 1:fprintf(strip,"\\title{");
		       TotalSummary|=4;                         break;
		case 2:fprintf(strip,"%%Type: ");
		       TotalSummary|=1;				break;
		case 3:fprintf(strip,"%%Subject: ");
		       TotalSummary|=1;				break;
		case 4:fprintf(strip,"\\author{");
		       TotalSummary|=4;				break;
		case 5:fprintf(strip,"%%Typist: ");
		       TotalSummary|=1;				break;
		case 6:if(TotalSummary>=4 && TotalSummary<8)
				{
				NewLine(this);
				fprintf(strip,"\\maketitle");
				NewLine(this);
				TotalSummary|=8;
				}
		       fprintf(strip,"\\begin{abstract}");
		       TotalSummary|=2;
		       NewLine(this);
		       break;
		case 7:fprintf(strip,"%%Account: ");
		       TotalSummary|=1;				break;
		case 8:fprintf(strip,"%%Key Words: ");
		       TotalSummary|=1;				break;
		}
	   spaces=0;
	   }
	SummaryChars++;
	flag = HeaderText;
	}
   else {
	if(SummaryChars==0) flag = Nothing;
	}

   if(by==' ') /*Fix useless spaces at the end of the item*/
	{
	spaces++;
	ActualPos++;
	continue;
	}
   else {
	if(spaces)
	  {
	  fprintf(strip,"%*c",spaces,' '); /*spaces must be printed*/
	  spaces=0;
	  }
	}
   ProcessKey();
   }
if(SummaryChars>0) FinishSummaryItem(SummaryItem);

if(TotalSummary>=4 && TotalSummary<8)
	{
	NewLine(this);
	fprintf(strip,"\\maketitle");
	NewLine(this);
	}
if(TotalSummary>0) NewLine(this);
flag = OldFlag;
}


/** This procedure scans resources stored in the packet area. */
void TconvertedPass1_WP5::WalkResources(void)
{
#ifdef DEBUG
  fprintf(log,"\n#WalkResources() ");fflush(log);
#endif
uint32_t pos1;
Resource5 res;
NestedPacket packet;
int i;
int BlockCounter=0;

pos1=16;
while(pos1>=16 && pos1<=DocumentStart)
	{
	BlockCounter++;
	fseek(wpd,pos1,SEEK_SET);
	if(feof(wpd)) return;

	Rd_word(wpd, &res.HeadPacketType);
	if(res.HeadPacketType==0) break;		//End of prefix

	Rd_word(wpd, &res.NoIndexes);
	Rd_word(wpd, &res.IndexBlkSize);
	Rd_dword(wpd, &res.NextBlock);

	if( (res.NextBlock<=pos1 && res.NextBlock!=0) || res.NextBlock>=DocumentStart)
	   {
	   if(err != NULL)
	     fprintf(err,_("\nError: WP prefix area is corrupted (block #%d), attempting to ignore!"),BlockCounter);
	   return;
	   }

	if(res.IndexBlkSize != 10*res.NoIndexes)
	   {
	   if(err != NULL)
	     fprintf(err,_("\nWarning: Suspicious size of packet descriptors, skipping packet block %d!"),BlockCounter);
	   goto NextBlock;
	   }

	if(res.HeadPacketType==0xFFFB)	//valid block
	   {
	   for(i=0;i<res.NoIndexes;i++)
	      {
	      Rd_word(wpd,  &packet.PacketType);
	      Rd_dword(wpd, &packet.Length);
	      Rd_dword(wpd, &packet.DataPointer);

	      if((packet.DataPointer>=res.NextBlock && res.NextBlock!=0) ||
		 (packet.DataPointer<=pos1 && pos1>=16) )
		 {
		 if(packet.PacketType==0 || packet.PacketType>=256 || packet.DataPointer==0xFFFFFFFF ||
		    packet.Length==0 ) continue;
		 if(err!=NULL && Verbosing>0)
		   fprintf(err,_("\nWarning: Packet #%d inside block #%d has an invalid data pointer!"),i,BlockCounter);
		 continue;
		 }

	      switch(packet.PacketType)
		   {
		   case 1:pos1 = ftell(wpd);
			  ActualPos = packet.DataPointer;
			  fseek(wpd,packet.DataPointer,SEEK_SET);
			  DocumentSummary(packet.Length);
			  fseek(wpd,pos1,SEEK_SET);
			  break;
		   case 7:FontNames=packet.DataPointer;	//Font Name Pool
			  break;
		   case 8:ResourceStart=packet.DataPointer; //Graphics Information
			  Images=packet;
			  break;
		   case 15:FontList=packet.DataPointer;	//List of Fonts
			  break;
		   }
	      }

	   }
NextBlock:
	pos1=res.NextBlock;
	}
}


/** This function traverses packet type 8 that contains a table of graphics images. */
uint32_t TconvertedPass1_WP5::SelectImageResource(int GraphicsNo)
{
#ifdef DEBUG
  fprintf(log,"\n#SelectImageResource(%d) ",GraphicsNo);fflush(log);
#endif
uint16_t Resources;
int i;
uint32_t StartResource, ResourceSize;

StartResource = ResourceStart;	// This is start of packet type 8
if(ResourceStart==0) goto ResErr;

fseek(wpd,ResourceStart,SEEK_SET);
Rd_word(wpd, &Resources);		// Count of Graphics images
if(GraphicsNo >= Resources) goto ResErr;

StartResource+=(uint32_t)4 * Resources + 2l;

Rd_dword(wpd, &ResourceSize);
i = GraphicsNo;
while(i>0)		//walk through a table of resource lengths
	{
	StartResource += ResourceSize;
	i--;
	Rd_dword(wpd, &ResourceSize);
	}

if(GraphicsNo+1==Resources) // The size of last resource must be computed
	{		    // because it is not written in the table
	ResourceSize=DocumentStart-StartResource-1;
	}

if(StartResource+ResourceSize>=DocumentStart)
	{
ResErr:	perc.Hide();
	fprintf(err, _("\nError: Graphics object #%d cannot be read!"),(int)GraphicsNo);
	fflush(stdout);
	return(0);
	}
fseek(wpd,StartResource,SEEK_SET);
return(ResourceSize);
}


void TconvertedPass1_WP5::NonEditable5(uint32_t end_of_code)
{
#ifdef DEBUG
  fprintf(log,"\n#NonEditable5() ");fflush(log);
#endif
  end_of_code -= 4;

  ActualPos = ftell(wpd);
  ActualPos += 2;
  fseek(wpd, ActualPos, SEEK_SET);
  
  recursion++;
  while(ActualPos < end_of_code)
	{
	if(fread(&by, 1, 1, wpd) !=1 ) break; /*Error during read*/
	ProcessKey();
	}
  recursion--;

  strcpy(ObjType,"Non editable disp");
}


void TconvertedPass1_WP5::DoCaption5(unsigned short CaptionSize)
{
#ifdef DEBUG
  fprintf(log,"\n#DoCaption5() ");fflush(log);
#endif

  uint32_t 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]
	if(by==0xD7 && subby==8)
		{
		fread(&subby, 1, 1, wpd);
		fseek(wpd,-1,SEEK_CUR);
		if(subby==8)	//Ignore \label{} in caption
			{
			flag = Nothing;
			ProcessKey();
			flag = HeaderText;
			continue;
			}
		}

	if(isalnum(by)) CaptionChars++;

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


/** This is hook callback from formula parser, that parses WP5 text. */
void TconvertedPass1_WP5::ExtractCaptionLabel5(const TBox *Box)
{
#ifdef DEBUG
  fprintf(log,"\n#ExtractCaptionLabel5() ");fflush(log);
#endif
uint32_t 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*/

	if(by==0xD7)
		{
		if(fread(&subby, 1, 1, wpd)!=1) break;
		fseek(wpd,-1,SEEK_CUR);
		if(subby==8)	//convert \label{} only
			{
			flag = HeaderText; // label start has been found, enable text conversion from this point.
			ProcessKey();
			NewLine(this);
			break;
			}
		}
	ProcessKey();
	}

  recursion--;
  flag = OldFlag;
}


void TconvertedPass1_WP5::ReadFormulaStr(string & StrBeg, uint32_t end_of_code)
{
#ifdef DEBUG
  fprintf(log,"\n#ReadFormulaStr() ");fflush(log);
#endif
uint16_t 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=='$' || 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);

	    StrEnd = Ext_chr_str(wchr_code, this, ConvertCpg);
	    StrBeg += FixFormulaStrFromTeX(StrEnd, wchr_code>>8);
	    StrEnd.erase();

	    sprintf(ObjType, "%u,%u", wchr_code & 0xFF, wchr_code>>8);
	    }

      ProcessKey();
      }
}


static const char *BoxNames[6]={"Figure","Table Box","Text Box","Usr Box","Equation","!Box?"};

void TconvertedPass1_WP5::AnyBox(uint32_t end_of_code)
{
#ifdef DEBUG
 fprintf(log,"\n#AnyBox() ");fflush(log);
#endif
char OldEnvir;
string StrBeg, ImageName;
uint16_t EquLen;
uint8_t OldFlag;
TBox Box;
attribute OldAttr;
int i;
char ch;
bool AllowCaption;
char BoxType;
  // CrackObject(cq, end_of_code); //

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

  ActualPos = ftell(wpd);
  fseek(wpd, ActualPos+2L, SEEK_SET);	// Pos and type flags Offset 6-4
  fread(&Box.AnchorType, 1, 1, wpd);
  Box.AnchorType &= 0x3;   /*0-Paragraph, 1-Page, 2-Character*/
  fread(&Box.HorizontalPos, 1, 1, wpd);
  Box.HorizontalPos &= 3;  /*0-Left, 1-Right, 2-Center, 3-Full */
  Rd_word(wpd,&EquLen); Box.Width = EquLen/47.0f;

  fseek(wpd, ActualPos+48L, SEEK_SET);
  fread(&Box.Contents, 1, 1, wpd);

  fread(&ch, 1, 1, wpd);
  while(ch>=' ')
  	{
        ImageName+=ch;
        fread(&ch, 1, 1, wpd);
	}
  ImageName.trim();

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

  switch(Box.Contents)
    {
    case 0:sprintf(ObjType,"%s:Empty",BoxNames[BoxType]);
	   goto UnknownEquType;
    case 0x08:Box.Contents = 4;	  //Content equation
	      fseek(wpd, ActualPos+115L, SEEK_SET);
	      Rd_word(wpd, &Box.CaptionSize);   /*total length of caption*/
	      Box.CaptionPos = ftell(wpd);

              fseek(wpd, Box.CaptionSize+10L, SEEK_CUR);
              Rd_word(wpd, &EquLen);   /*total length of equation*/
	      StrBeg.erase();

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

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

	      ReadFormulaStr(StrBeg, end_of_code);

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

	      attr = OldAttr;	      

	      PutFormula(this,StrBeg(),Box);
              if(StrBeg.length()>0)
              {
                if(OldEnvir=='B' && char_on_line==false) 
	            char_on_line = -1;		// This will force newline in tabbing environment.
              }	      

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

    case 0x10:Box.Contents = 1;		//Content text
	      fseek(wpd, ActualPos+115L, SEEK_SET);
	      Rd_word(wpd, &Box.CaptionSize);   /*total length of caption*/
	      Box.CaptionPos = ftell(wpd);

	      fseek(wpd, Box.CaptionSize, SEEK_CUR);
	      ActualPos = ftell(wpd);
	      end_of_code -= 4;

	      if(Box.HorizontalPos!=3)
		 if(Box.Width<=1 && err != NULL)
			  fprintf(err, _("\nWarning: The width of the Box is %f, are you sure?"),Box.Width);

	      if(char_on_line == LEAVE_ONE_EMPTY_LINE) // Left one empty line for new enviroment.
		  {
		  fputc('%', table);
		  fputc('%', strip);
		  NewLine(this);
		  char_on_line = true;
		  }
	      if(char_on_line==CHAR_PRESENT)     /* make new line for leader of minipage */
		  {
                  NewLine(this);
		  }

	      AllowCaption = BoxTexHeader(this,Box);
	      envir='!';			//Ignore enviroments Before
	      NewLine(this);

              char_on_line = FIRST_CHAR_MINIPAGE;
              envir = ' ';
	      while(ActualPos < end_of_code)
		  {
		  fread(&by, 1, 1, wpd);
                  ProcessKey();
		  }
               
	      Close_All_Attr(attr,strip);

              envir=' ';
              if (char_on_line==CHAR_PRESENT)
		   {
                   NewLine(this);
		   }
              if(AllowCaption)
                      {
                      fseek(wpd, Box.CaptionPos, SEEK_SET);
		      DoCaption5(Box.CaptionSize);
                      }
	      BoxTexFoot(this, Box);

              envir='^';		//Ignore enviroments after minipage
	      NewLine(this);
	      break;
    case 0x02:Box.Image_type=0; //Image on disk
	      goto DiskImage;
    case 0x80:			//WPG format (Image in resource)
    case 0x82:			//TIFF format (Image in resource)
    case 0x83:			//PCX format (Image in resource)
    case 0x8A:			//HPG format (Image in resource)
    case 0x8F:			//Encapsulated PostScript
    case 0x90:			//PostScript
	      Box.Image_type=0;
	      fseek(wpd, ActualPos+38L, SEEK_SET);  // image orientation, offset 42-4.
	      Rd_word(wpd, &Box.RotAngle);
	      if(Box.RotAngle & 0x8000) Box.HScale=-Box.HScale;
	      Box.RotAngle &= 0xFFF;
	      //fseek(wpd, ActualPos+109L, SEEK_SET); // Image index in graphics temp file, offset 113-4, an image resource No
	      //Rd_word(wpd, &WPGResourceNo);	      // I am lost here, it seems that images are not indexed but only plain image counter is used.
	      if((Box.Image_size=SelectImageResource(ImageCounter++))>0)
		{
		Box.Image_offset = ftell(wpd);
		Box.Image_type = 1;
		}
DiskImage:
	      Box.Contents = 3; // content image - every images are internally converted into WPG
	      end_of_code -= 4;
	      Box.CaptionPos = ActualPos+117L;
	      i=(end_of_code<Box.CaptionPos)?0:(uint16_t)(end_of_code-Box.CaptionPos);
	      fseek(wpd, ActualPos+115L, SEEK_SET); // receive a caption size
	      Rd_word(wpd,&Box.CaptionSize);
	      if(Box.CaptionSize>i) Box.CaptionSize=i;
	      ImageWP(this,ImageName,Box);
	      break;

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


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


/** This procedure expands extended WP5.x characters into LaTeX string */
void TconvertedPass1_WP5::ExtendedCharacter(void)
{
#ifdef DEBUG
  fprintf(log,"\n#ExtendedCharacter() ");fflush(log);
#endif
uint16_t WChar;

  Rd_word(wpd, &WChar);
  sprintf(ObjType, "%u,%u", (unsigned)WChar>>8, (unsigned)WChar&0xFF);
  CharacterStr(this, Ext_chr_str(WChar, this, ConvertCpg));
}


/** Internal loop for translating text for labels and references. */
void TconvertedPass1_WP5::LabelInside(uint32_t end_of_code)
{
#ifdef DEBUG
  fprintf(log,"\n#LabelInside(%u) ",end_of_code);fflush(log);
#endif
const char *characterStr;
char str2[2];
uint16_t wchr_code;
const unsigned short BkCodePage = OutCodePage;

 OutCodePage = 0;		// Disable any output codepage in Label contents.
 str2[1] = 0;
 while (ActualPos < end_of_code)
       {
       fread(&by, sizeof(unsigned char), 1, wpd);
       if(by == 0) break;
       if(by >= 0x20 && by <= 0x7f)
	   {
	   str2[0] = by;		/* Normal_char  */
	   characterStr = str2;
	   ActualPos++;
	   goto ProcessCharacterSTR;
	   }
       if(by == 0xC0)       /*extended character*/
	   {			 /*Special Caracters cannot be used in labels*/
	   Rd_word(wpd, &wchr_code);

	   characterStr = Ext_chr_str(wchr_code, this, ConvertCpg);

	   fread(&by, 1, 1, wpd);
	   ActualPos+=4;

ProcessCharacterSTR:
           FixLabelText(characterStr,strip);
	   continue;
	   }

       ProcessKey();
       }
  OutCodePage = BkCodePage;
}


/** This procedure converts WP5.x Line numbering. */
void TconvertedPass1_WP5::LineNumbering5(void)
{
#ifdef DEBUG
  fprintf(log,"\n#LineNumbering5() ");fflush(log);
#endif
  uint8_t LineNumFlag;

  fseek(wpd, 1+2+2, SEEK_CUR);
  LineNumFlag = fgetc(wpd);

  LineNumbering(this, LineNumFlag&0x80);
}


void TconvertedPass1_WP5::MakeIndex(uint32_t end_of_code)
{
#ifdef DEBUG
  fprintf(log,"\n#MakeIndex() ");fflush(log);
#endif
  unsigned char OldFlag;

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

  ActualPos = ftell(wpd);
  fprintf(strip, "\\index{");
  LabelInside(end_of_code);
  putc('}', strip);
  Index=true;

  flag = OldFlag;
  char_on_line = true;
  strcpy(ObjType, "Index");
}



void TconvertedPass1_WP5::MakeLabel(uint32_t end_of_code)
{
#ifdef DEBUG
  fprintf(log,"\n#MakeLabel() ");fflush(log);
#endif
  unsigned char OldFlag;

  OldFlag = flag;
  flag = CharsOnly;
  end_of_code -= 4;

  ActualPos = ftell(wpd);
  fprintf(strip, "%s\\label{",char_on_line>0?" ":"");
  LabelInside(end_of_code);
  putc('}', strip);

  flag = OldFlag;
  if(char_on_line == false)
	char_on_line = -1;
  strcpy(ObjType, "Label");
}


void TconvertedPass1_WP5::MakeRef(uint32_t end_of_code)
{
#ifdef DEBUG
  fprintf(log,"\n#MakeRef() ");fflush(log);
#endif
  unsigned char OldFlag, TypeRef;

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

  fread(&TypeRef, 1, 1, wpd);   /*Type of reference*/

  ActualPos = ftell(wpd);
  if(TypeRef==0) fprintf(strip, " \\pageref{");
  	    else fprintf(strip, " \\ref{");
  LabelInside(end_of_code);
  putc('}', strip);

  flag = OldFlag;
  char_on_line = true;
  strcpy(ObjType, "Reference");
}



//***********************************************************************//
//*** Alphabetically ordered functions for translating WP5.x features ***//
//***********************************************************************//

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

 int16_t w;
 unsigned char b;
 const char *what;

 fread(&b, sizeof(unsigned char), 1, wpd);
 fseek(wpd, 2L, SEEK_CUR);
 Rd_word(wpd, (uint16_t *)&w);

 what="";
 if(b == 0)	/*Up/Down*/
	{
        if(w>0) what="Up";
        if(w<0) what="Down";
	fprintf(strip, "\\vspace{%2.2fcm}", float(w)/470.0);
        }
 if(b == 2)	/*Left/Right*/
	{
	if(w>0) what="Right";
        if(w<0) what="Left";
    	fprintf(strip, "{\\hskip %2.2fcm}", float(w)/470.0);
        }
 sprintf(ObjType, "Advance %s %2.2fcm",what,float(w)/470.0);
}


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

/*TabType = 0-Left, 1-Full, 2-Center, 3-Right, 4-Aligned */
  switch(cq->tab_type)
	{
	case 4:Close_All_Attr(cq->attr,cq->strip);	//aligned
	       fputs("\\'",cq->strip);
	       cq->tab_type = 0;
	       Open_All_Attr(cq->attr,cq->strip);
	       break;

	case 3:Close_All_Attr(cq->attr,cq->strip);	//right
	       fprintf(cq->strip, "\\'");
	       cq->tab_type = 0;
	       Open_All_Attr(cq->attr,cq->strip);
	       break;

	case 2:Close_All_Attr(cq->attr,cq->strip);	//center
	       putc('}', cq->strip);
	       cq->tab_type = 0;
	       Open_All_Attr(cq->attr,cq->strip);
	       break;
	}

strcpy(cq->ObjType, "End Align");
}


/** This function converts changing of number of column (like newspaper). */
void TconvertedPass1_WP5::ColDef5(void)
{
#ifdef DEBUG
  fprintf(log,"\n#ColDef5() ");fflush(log);
#endif

  fseek(wpd, 97L, SEEK_CUR);
  fread(&DefColumns, 1, 1, wpd);   /* new number of columns */
  DefColumns&=0x1F;			   /*bits:0-4 #cols; 6:paralel col; 7:block protected par col*/

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


/** This function converts commented text to proper LaTeX comment. */
void TconvertedPass1_WP5::Comment5(uint32_t end_of_code)
{
#ifdef DEBUG
  fprintf(log,"\n#Comment5() ");fflush(log);
#endif
  signed char Old_char_on_line;
  unsigned char OldFlag;
  uint16_t something;
  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
  end_of_code -= 4;

  Rd_word(wpd, &something);


  fputc('%',strip);
  ActualPos = ftell(wpd);
  while (ActualPos < end_of_code)
       {
       fread(&by, sizeof(unsigned char), 1, wpd);
       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);
                }

       ProcessKey();
       continue;
       }

  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==CHAR_PRESENT || Old_char_on_line==-1) char_on_line = -1;
	else char_on_line = false;
}


void TconvertedPass1_WP5::Endnote(uint32_t end_of_code)
{
#ifdef DEBUG
  fprintf(log,"\n#Endnote() ");fflush(log);
#endif
  attribute OldAttr;
  unsigned char OldFlag;

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

  fseek(wpd, 7, SEEK_CUR);

  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: ProcessKey();
	              break;
             }

           ActualPos = ftell(wpd);
	   }


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

  attr=OldAttr;
  Open_All_Attr(attr,strip);

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


void TconvertedPass1_WP5::Footnote(uint32_t end_of_code)
{
#ifdef DEBUG
  fprintf(log,"\n#Footnote() ");fflush(log);
#endif
  attribute OldAttr;
  unsigned char flags, num_of_pages;
  char BkEnvir;
  uint16_t fn_num;
  unsigned char OldFlag;

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

  fread(&flags, sizeof(unsigned char), 1, wpd);

  Rd_word(wpd, &fn_num);

  fread(&num_of_pages, sizeof(unsigned char), 1, wpd);   /* Skip all the shit */
  fseek(wpd, (num_of_pages + 1L) * 2 + 9, SEEK_CUR);

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

  BkEnvir = envir;
  if(BkEnvir=='L' || BkEnvir=='B') // || BkEnvir=='i')
  {
    envir = '!';  		//Ignore enviroments Before
    NewLine(this);
    envir = ' ';
  }
  //envir = ' ';

  fprintf(strip, "\\footnote" );
  if(ExactFnNumbers) fprintf(strip, "[%u]", fn_num);
  fputc('{',strip);
  char_on_line = true;

  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: ProcessKey();
		      break;
	     }

	   ActualPos = ftell(wpd);
	   }


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

  if(envir != ' ') NewLine(this);

  putc('}', strip);

  if(envir != ' ')
    {
    envir = ' ';
    NewLine(this);
    }

  if(BkEnvir=='L' || BkEnvir=='B') // || BkEnvir=='i')
  {
    envir = '^';		//Ignore enviroments Before
    NewLine(this);
    char_on_line = JUNK_CHARS;
  }
  envir = BkEnvir;

  attr = OldAttr;

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


void TconvertedPass1_WP5::Header_Footer(uint32_t end_of_code)
{
#ifdef DEBUG
  fprintf(log,"\n#Header_Footer() "); fflush(log);
#endif
unsigned char occurance;
attribute OldAttr;
string s;
unsigned char OldFlag, OldEnvir, OldFont;
int i;

  if(end_of_code - ftell(wpd) <= 18) goto ExitHeaderFooter;

  OldFlag = flag;
  OldFont = Font;
  OldEnvir= envir;

  recursion++;
  end_of_code -= 4;

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

  fseek(wpd, 7L, SEEK_CUR);
  fread(&occurance, 1, 1, wpd);

  fseek(wpd, 10L, SEEK_CUR);

  Close_All_Attr(attr,strip);
  OldAttr = attr;			/* Backup all attributes */
  if(Font>=FONT_CYRILLIC && Font<=FONT_ARABIC)
      {
      Font = FONT_NORMAL;
      }

  				/* 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,occurance);
  occurance=(occurance << 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 = FIRST_CHAR_MINIPAGE;
  while(ActualPos < end_of_code)
        {
        fread(&by, 1, 1, wpd);

        ProcessKey();
        }

  Close_All_Attr(attr,strip);
  if(char_on_line==CHAR_PRESENT)
     {
     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 backuped attributes */
  flag = OldFlag;
  envir = OldEnvir;
  Font = OldFont;
  char_on_line = FIRST_CHAR_MINIPAGE;	// stronger false;
  recursion--;

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


static void LineSpacing(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#LineSpacing() ");fflush(cq->log);
#endif
uint16_t LastSpacing;
uint16_t CurrentSpacing;
char b;

  Rd_word(cq->wpd,&LastSpacing);
  Rd_word(cq->wpd,&CurrentSpacing);

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

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


void TconvertedPass1_WP5::MarkedTextBegin(uint32_t & NewPos)
{
#ifdef DEBUG
  fprintf(log,"\n#MarkedTextBegin() ");fflush(log);
#endif
  signed char b;
  string ListName;


  fread(&b, sizeof(unsigned char), 1, wpd);   /* read flags */
  if(b<0x10)	//This is a MarkToContents
	{
	StartSection(this, -b);
	return;
	}

  sprintf(ObjType, "Start MarkToL:%d",(int)(b&0xDF) + 1);
  if(!(b&0x20)) return;


  ListName=_("List ");
  ListName+=ObjType+14;
  b=ListName() IN UserLists;
  if(b) b--;
   else b=UserLists+=ListName();

  fprintf(strip, "\\UserList{l%c}{",b+'a');
  fseek(wpd,ActualPos=NewPos,SEEK_SET);
  by = fgetc(wpd);
  recursion++;
  while(filter[CharsOnly][by])
	{
	ProcessKey();
	NewPos=ActualPos;
	by=fgetc(wpd);
	}
  fputc('}',strip);
  recursion--;
}


/** This function converts overstriked characters. */
void TconvertedPass1_WP5::Overstrike(uint32_t end_of_code)
{
#ifdef DEBUG
  fprintf(log,"\n#Overstrike() ");fflush(log);
#endif
  bool first_char_os = true;
  uint16_t char_width_os;
  attribute OldAttr;
  string s;

  unsigned char OldFlag;

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

  Rd_word(wpd, &char_width_os);

  OldAttr=attr;
  ActualPos = ftell(wpd);
  while(ActualPos < end_of_code)
       {
       fread(&by, 1, 1, wpd);

       if (by == 0xC3 || by == 0xC4)
	  {
	  flag = OldFlag;
	  ProcessKey();
	  flag = CharsOnly;
	  continue;
	  }

       if (by != 0xC0 && by != 0xa9 && (by < 0x20 || by > 0x7f))
          {
          ProcessKey();
          continue;
          }

      if (first_char_os)
	 {
	 ProcessKey();
         first_char_os = false;
         }
      else {
	   Open_All_Attr(attr, strip);
	   if(attr.Math_Depth>0) attr.Math_Depth=0;//Math might be nested inside \llap
           fprintf(strip, "\\llap{");
           ProcessKey();
           putc('}', strip);
           }
      }

  AttrFit(attr,OldAttr,s);
  if(!s.isEmpty()) fputs(s(),strip);

  recursion--;
  strcpy(ObjType, "Overstrike");
  flag = OldFlag;
  char_on_line = true;
}


void TconvertedPass1_WP5::SetFont5(void)
{
#ifdef DEBUG
  fprintf(log,"\n#SetFont5() ");fflush(log);
#endif
uint16_t PointSize;
uint16_t NamePtr;
const char *ig="!";
string FontName;
uint8_t FontNo;
char ch;

  fseek(wpd, 25l, SEEK_CUR);
  FontNo = fgetc(wpd);

  fseek(wpd, 2l, SEEK_CUR);
  Rd_word(wpd,&PointSize);

  if(FontList>0 && FontNames>0)
    {
    fseek(wpd, FontList + (long)FontNo*86 + 18, SEEK_SET);
    Rd_word(wpd,&NamePtr);
    fseek(wpd, FontNames + NamePtr, SEEK_SET);
    ch=fgetc(wpd);
    while(ch!=0 && !feof(wpd))
	{
	FontName+=ch;
	ch=fgetc(wpd);
	}
    }

  SetFont(this,PointSize,FontName());
  if(NFSS) ig="";

#ifdef HAVE_snprintf
  snprintf(ObjType, sizeof(ObjType), "%sFont %2.2f%s", ig, float(PointSize)/50, chk(FontName()));
#else
  sprintf(ObjType, "%sFont %2.2f%.20s", ig, float(PointSize)/50, chk(FontName()));
#endif
}



typedef struct WPTab {
  uint16_t len;
  uint16_t attribute;
  uint8_t alignment;
} WPTab;

void TconvertedPass1_WP5::TableStart5(unsigned short len, uint32_t & NewPos)
{
#ifdef DEBUG
  fprintf(log,"\n#TableStart5(%d) ",(int)len);fflush(log);
#endif
  short columns = 0;
  uint16_t i;
  unsigned char b;
  WPTab Atbl[100];
  string TexAttrib;
  unsigned char OldFlag;
  char OldEnvir;
  uint8_t PosFlag;
  attribute OldAttr;

  if(log) fprintf(log, _("\n%*sStart Table"), recursion * 2, "");

  fseek(wpd, 2L, SEEK_CUR);		//OldFlag + OldShading
  fread(&b, 1, 1, wpd);		//OldColumns

  fseek(wpd, 24L + b*5 - 3L, SEEK_CUR);
  fread(&PosFlag, 1, 1, wpd);	//NewTableFlag

  fseek(wpd, 24L - 1L, SEEK_CUR);

  i = b*5 + 48;
  i++;
  if(b & 1) i += 5;
  columns = (len - i) / 5;
  if((len - i) % 5 != 0) goto FAIL;
  if(columns > 100 || columns <= 0)
	{
FAIL:	strcpy(ObjType, "!Table Start"); return;
	}

  for(i = 0; i <= columns - 1; i++)
	Rd_word(wpd, &Atbl[i].len);
  for(i = 0; i <= columns - 1; i++)
	Rd_word(wpd, &Atbl[i].attribute);
  for(i = 0; i <= columns - 1; i++)
	fread(&Atbl[i].alignment, 1, 1, wpd);

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

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

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

  OldAttr = attr;
  attr.InitAttr();

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

  envir = 'B';

  fprintf(strip, "{|");
  for (i = 0; i <= columns - 1; i++)
    {
    TexAttrib = Attributes2String(Atbl[i].attribute); //Solve attributes for columns

    if(!TexAttrib.isEmpty())
	{
	fprintf(strip,"@{%s}",TexAttrib());
	}

    switch (Atbl[i].alignment & 0xf)
      {
      case 0:fprintf(strip, "l|");   /*left*/
	     break;
      case 1:fprintf(strip, "c|");   /*full*/
	     break;
      case 2:fprintf(strip, "c|");   /*center*/
	     break;
      case 3:fprintf(strip, "r|");   /*right*/
	     break;

      default:fprintf(strip, "c|");   /*I don`t know*/
	      break;
      }
  }
  putc('}', strip);
  NewLine(this);		// write cell contents on a new line

  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);
  while(!feof(wpd))
	{
	if((by==0xDC || by==0xDD) && envir!='B')
		{
		envir='B';
		}
	ProcessKey();
	NewPos=ActualPos;
	if(by==0xDC && subby==0x2) break; /*End of table*/
        if(by==0xDD && subby==0x2) break; /*End of table on EOP*/

	by = fgetc(wpd);
	}
  Close_All_Attr(attr,strip);

  if(char_on_line <= FIRST_CHAR_MINIPAGE)  // Left one empty line for ending enviroment.
	{
	fputc('%', table);fputc('%', strip);
	NewLine(this);
	}

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

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

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

  strcpy(ObjType, "Table Start");
}


static void Tabset(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Tabset() ");fflush(cq->log);
#endif
  int j,SideMargin;
  uint16_t w,Absolute;
  long pos;


  pos = ftell(cq->wpd);
  fseek(cq->wpd, pos+202L, SEEK_SET);   /* Ga naar TAB-info */
  Rd_word(cq->wpd, &Absolute);
  if(Absolute!=0xFFFF)
	{
	SideMargin=Absolute+cq->WP_sidemargin-cq->Lmar;//Relative Tab
	}
	else SideMargin=cq->WP_sidemargin;	//Absolute Tab

  fseek(cq->wpd, pos+100L, SEEK_SET);   /* Ga naar TAB-info */
  cq->num_of_tabs = 0;

  for(j = 1; j <= 40; j++)
      {
      Rd_word(cq->wpd, &w);
      if (w > cq->WP_sidemargin && w != 0xffffL)
	    {
	    cq->num_of_tabs++;
	    cq->tabpos[cq->num_of_tabs - 1] = w - SideMargin;
	    }
      }

  Make_tableentry_tabset(cq);
  sprintf(cq->ObjType, "TabSet:%s",Absolute==0xFFFFL?"Abs":"Rel");
}


static void LRMargin(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#LRMargin() ");fflush(cq->log);
#endif
  uint16_t w;

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

  Rd_word(cq->wpd, &w);
  cq->Lmar=w;
  Rd_word(cq->wpd, &w);
  cq->Rmar=w;

  strcpy(cq->ObjType, "L/R Mar");
}



////////////////////////////////////////////////////////////////
bool TconvertedPass1_WP5::CheckConzistency(long NewPos)
{
#ifdef DEBUG
  fprintf(log,"\n#CheckConzistency(%X,%X) ",(int)by,(int)subby);fflush(log);
#endif

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

  Pos = ftell(wpd);

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

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


/** This is main procedure for processing one key. It can be recursivelly called. */
void TconvertedPass1_WP5::ProcessKey(void)
{
#ifdef DEBUG
  fprintf(log,"\n#ProcessKey() ");fflush(log);
#endif
  uint16_t w;
  uint32_t NewPos = 0;
  unsigned char loc_by, loc_subby;

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

  *ObjType = '\0';
  w = 1;
  subby=0;

	  /*Guessing end position of the object*/
  if (by > 0xbf)
      {
      if (by >= 0xC0 && by <= 0xcf)
	  {	/*these functions has fixed size - see table SizesC0*/
	  if (SizesC0[by - 0xC0] != 0)
		NewPos = SizesC0[by - 0xC0] + ActualPos;
	  subby = 0xff;   /*ignored subcommand*/
          }
      else if (by >= 0xd0)
         {
	 fread(&subby, 1, 1, wpd);
         Rd_word(wpd, &w);
         NewPos = ActualPos + w + 4;
         Linebegin = false;
	 }
      }		/* Other functions has size only 1 byte - all OK. */
      
  loc_by = by;
  loc_subby = subby;

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

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

  if(filter[flag][by])
     {
     switch (by)
	{
	case 0x02:PageNumber(this);			break;	//^B
	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: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:End_Align(this);			break;
//	case 0x84:break;					// Reserved
	case 0x85:strcpy(ObjType, "Temp");		break;  // Place Saver
	case 0x86:CenterPage(this);			break;  // Center page top to bottom
	case 0x87:Column(this,DefColumns);		break;	// Col On
	case 0x88:Column(this,1);			break;	// Col Off
//	case 0x89:break;					// Reserved
	case 0x8A:WidowOrphan(this,3);			break;	// Widow/Orphan ON
	case 0x8B:WidowOrphan(this,0);			break;	// Widow/Orphan OFF
	case 0x8C:if(char_on_line>=0) Terminate_Line(this,'h');	/* Hard return */
				     else Terminate_Line(this,'s');   // hard return mustn't occur here, fix it
                  strcpy(ObjType, "HRT");
		  break;
	case 0x8D:strcpy(ObjType, "!Note Num");		break;	// Footnote/Endnote# - inside footnote
	case 0x8E:strcpy(ObjType, "!Fig Num");		break;	// Figure #
	case 0x8F:if(toupper(envir)=='C') Justification(this, 0x83);    // Hard end of center/align
		  strcpy(ObjType, "~Center");
                  break;
        case 0x90:if(envir != 'B')		// Omit dormant Srt in tabbing environment
		      SoftReturn(this);
                  strcpy(ObjType, "DSRt");			// Deletable return at end of the line.
		  break;					
        case 0x91:putc(' ', strip);
		  strcpy(ObjType, "DSPg");		break;	// Deletable return at end of the page.
	case 0x92:strcpy(ObjType, "Deleted EOPg");	break;	// Deleted EOPg
	case 0x93:InvisibleSoftReturn(this);		break;
//	case 0x94:						// Invisible return at EOL
//	case 0x95:						// Invisible return at EOP
	case 0x96:strcpy(ObjType, "!Block On");		break;
	case 0x97:strcpy(ObjType, "!Block Off");	break;
//	case 0x98:						// Table of contents page #
	case 0x99:if(envir != 'B' && char_on_line > 0)	// Dormant Hard return
		       Terminate_Line(this,'h');
		  else fputc(' ', strip);
		  strcpy(ObjType, "Dorm HRt");
		  break;
	case 0x9A:CancelHyph(this);			break;
	case 0x9B:strcpy(ObjType, "End Def");		break;	// End of automatically generated definition
//	case 0x9C:						// Reserved
//	case 0x9D:						// Reserved
	case 0x9E:Hyphenation(this,false);		break;
	case 0x9F:Hyphenation(this,true);		break;
	case 0xA0:fputc('~', strip);strcpy(ObjType, " ");	// Hard space
		  break;
        case 0xA1:strcpy(ObjType, "!Subtotal do");	break;
        case 0xA2:strcpy(ObjType, "!Subtotal entry");	break;
        case 0xA3:strcpy(ObjType, "!Total do");		break;
        case 0xA4:strcpy(ObjType, "!Total entry");	break;
        case 0xA5:strcpy(ObjType, "!GrangTotal do");	break;
        case 0xA6:strcpy(ObjType, "!GrangTotal entry");	break;
        case 0xA7:strcpy(ObjType, "!Math On");		break;
        case 0xA8:strcpy(ObjType, "!Math Off");		break;
	case 0xA9:						// Hard hyphen in line
	case 0xAA:                                      	// Hard hyphen EOL
	case 0xAB:HardHyphen(this);			break;	// Hyphen EOP
	case 0xAC:						// Soft hyphen in line
	case 0xAD:                                      	// Soft hyphen EOL
	case 0xAE:SoftHyphen(this);	  		break;	// Soft hyphen EOP
	case 0xAF:Column(this,false);			break;	// Col off at EOL
	case 0xB0:Column(this,false);			break;	// Col off at EOP
        case 0xB1:strcpy(ObjType, "!Math negate");	break;
        case 0xB2:strcpy(ObjType, "!Outline Off");	break;
	case 0xB3:strcpy(ObjType, "!Rev Dir On");	break;
	case 0xB4:strcpy(ObjType, "!Rev Dir Off");	break;
	// B5h - BCh reserved
        case 0xBD:strcpy(ObjType, "!Auto cod On");	break;
	case 0xBE:strcpy(ObjType, "!Auto cod Off");	break;
        // BF - unknown

	case 0xC0:ExtendedCharacter();			break;	/* Special character */
	case 0xC1:fread(&subby, sizeof(unsigned char), 1, wpd);
		  switch (subby & 0xE8)
		       {
		       case 0:
		       case 0xc8:
		       case 0x48:
		       case 0x40:Tab(this,5);		break;
		       case 0x60:if(subby!=0x70) Flush_right(this,0);
						else Flush_right(this,1);
				 break;
		       case 0xe0:Center(this);		break;
		       }
		  break;

	case 0xC2:Indent(this,5);			break;
	case 0xC3:Attr_ON(this);			break;
	case 0xC4:Attr_OFF(this);			break;
	case 0xC5:strcpy(ObjType, "!Blk protect");	break;	// block protect
	case 0xC6:End_of_indent(this);			break;
//	C8 - CF reserved

	case 0xD0:switch (subby)
		    {
		    case 0x01:LRMargin(this);		break;
		    case 0x02:LineSpacing(this);	break;
		    case 0x04:Tabset(this);		break;
		    case 0x06:Justification(this,5);	break;
		    case 0x07:Suppress(this,5);		break;
		    case 0x08:Page_number_position(this,5);break;
		    }
		  break;
	case 0xD1:switch (subby)
		    {
                    case 0: Color(this,5); break;
		    case 1: SetFont5(); break;
		    case 2: fseek(wpd,1,SEEK_CUR);
			    fread(&subby, 1, 1, wpd);
			    RGBQuad q;
			    q.R = WPG_Palette[subby].Red;
			    q.G = WPG_Palette[subby].Green;
			    q.B = WPG_Palette[subby].Blue;
			    Color(this,5,&q);
			    break;
                    }
		  break;
	case 0xD2:if(subby == 1) ColDef5();
		  if(subby == 0xb) TableStart5(w, NewPos);
		  break;
	case 0xD3:switch (subby)
		    {
		    case 0x02:SetFootnoteNum(this,5);	break;
		    case 0x03:SetEndnoteNum(this,5);	break;
		    case 0x04:SetPgNum(this,5);		break;
		    case 0x05:LineNumbering5();		break;
		    case 0x06:Advance();		break;
		    case 0x0A:strcpy(ObjType,"!Space Width"); break;
		    case 0x0B:strcpy(ObjType,"!Space Exp"); break;
                    case 0x0C:strcpy(ObjType,"!GrBox Num Fig"); break;
                    case 0x0D:strcpy(ObjType,"!GrBox Num Tab"); break;
                    case 0x0E:strcpy(ObjType,"!GrBox Num TXT"); break;
                    case 0x0F:strcpy(ObjType,"!GrBox Num UsrBox"); break;
                    case 0x10:strcpy(ObjType,"!GrBox Num Equ"); break;
		    case 0x11:Language(this,5);		break;
                    case 0x12:strcpy(ObjType,"!PgNumStyle"); break;
                    case 0x13:strcpy(ObjType,"!SetDirection"); break;
		    }
		  break;
	case 0xD4:switch (subby)
		    {
                    case 0: strcpy(ObjType,"!EOP internal"); break;
                    case 1: strcpy(ObjType,"!BOL internal"); break;
                    case 2: strcpy(ObjType,"!Gr Box Info"); break;
                    case 3: strcpy(ObjType,"!Repositioning Marker"); break;
                    case 4: NonEditable5(NewPos); break;
                    }
		  break;
	case 0xD5:Header_Footer(NewPos);		   break;
	case 0xD6:switch(subby)
		     {
		     case 0: Footnote(NewPos); break;
		     case 1: Endnote(NewPos); break;
		     }
		  break;

	case 0xD7: switch(subby)
		      {
		      case 0:   MarkedTextBegin(NewPos);break;
		      case 0x1: EndSection(this,5);	   break;
		      case 0x2: TableOfContents(this,5);	   break;
		      case 0x3: MakeIndex(NewPos);	   break;
		      case 0x5: PlaceEndnotes(this);	   break;
		      case 0x7: MakeRef(NewPos);       break;
		      case 0x8: MakeLabel(NewPos);	   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 0x2: Overstrike(NewPos); break;
		    case 0x3: PageNumber(this); break;
		    }
		  break;

	case 0xD9:// 0 Printer command
		  // 1 Conditional EOP
		  if(subby == 2) Comment5(NewPos);
		  // 3 Kerning
		  // 4 Outline
		  // 5 Leading adjustment
		  // 6 Kerning graphics
		  // 7 Hide function
		  // 8 Macro
		  break;


	case 0xDA:if (subby <= 4) AnyBox(NewPos);
		  if (subby == 5) HLine(this,5);
		  if (subby == 6) strcpy(ObjType, "!VLine");
		  break;

	/*      $DB:if subby=0 then StyleInsides(this,NewPos);*/
	case 0xDC:switch (subby)	/* Normal table items */
		   {
		   case   0:CellTable(this);	break;
		   case 0x1:RowTable(this);	break;
		   case 0x2:EndTable(this);	break;
		   }
		 break;

	case 0xDD:switch (subby)	/* Table items on soft page break */
		   {
		   case 0x1:RowTable(this);      break;
		   case 0x2:EndTable(this);      break;
		   }
		 break;

	default:if(by>=0x01 && by<=0x7f)
		     {
		     if(NativeCpg != NULL)
		       {
	               CharacterStr(this,Ext_chr_str(by,this,NativeCpg));
		       }
		     else
                       {
		       if(RequiredFont==FONT_HEBREW)
		         {
		         if(by=='.')
                            {CharacterStr(this,"\\textrm{.}");break;}
                         if(by==',')
                            {CharacterStr(this,"\\textrm{,}");break;}
		         if(by==':')
                            {CharacterStr(this,"\\textrm{:}");break;}
                         if(by==';')
                            {CharacterStr(this,"\\textrm{;}");break;}
                         }
		       RequiredFont = FONT_NORMAL;
     		       CharacterStr(this,Ext_chr_str(by,this,ConvertCpg));   /* Normal_char */
                       }
		     }
		break;
	}
  }

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

  if(NewPos == 0)
	{
	if(loc_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;
  NewPos = 0;
}


void TconvertedPass1_WP5::InitFilter5(void)
{
 filter[0]=set(set0,sizeof(set0)/sizeof(int));
 filter[1]=set(set1,sizeof(set1)/sizeof(int));
 filter[2]=set(set2,sizeof(set2)/sizeof(int));
 filter[3]=set();
}


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

 switch(FuncNo)
   {
   case DISP_PROCESSKEY:         
	 ProcessKey();
	 return 0;

   case DISP_EXTRACT_LABEL:
         {         
         ExtractCaptionLabel5((const TBox*)arg);
         return 0;
         }

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

return(-1);
}


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

  InitFilter5();

  if(WPcharset==2) ConvertCpg=GetTranslator("wp5_czTOinternal");
              else ConvertCpg=GetTranslator("wp5TOinternal");
  DefColumns=2;

  DocumentStart=ftell(wpd);

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

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

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

      by = 0;
      ProcessKey();
      }

  Finalise_Conversion(this);
  return(1);
}


/*******************************************************************/
class TconvertedPass1WP5FarEast: public TconvertedPass1_WP5
{
public:
    virtual void ProcessKey(void);
};


/*Register translators here*/
TconvertedPass1 *Factory_WP5FarEast(void) {return new TconvertedPass1WP5FarEast;}
FFormatTranslator FormatWP5FarEast("WP5.FarEast",&Factory_WP5FarEast);


/** This is main procedure for processing one key. It can be recursivelly called. */
void TconvertedPass1WP5FarEast::ProcessKey(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1WP5FarEast::ProcessKey() ");fflush(log);
#endif

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

  if(by=='!')
    {
      ActualPos++;
      by = 0;
      TconvertedPass1_WP5::ProcessKey();
      return;
    }
  if(by=='"')
    {
      fread(&by, 1, 1, wpd);
      CharacterStr(this, Ext_chr_str('!'+(0xB00|by), this, ConvertCpg));
      ActualPos += 2;
      return;
    }

  TconvertedPass1_WP5::ProcessKey();
}



/*--------------------End of PASS1 WP 5.x-----------------*/
