/******************************************************************************
 * 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 <stdarg.h>

#include <ctype.h>

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

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


extern list UserLists;
extern RGB_Record WPG_Palette[256];

extern set filter[4];
int set0[]={0 ___ 0xFF};		//Everything
int set1[]={0 ___ 0xB,0xD ___ 0xBF,0xC0,0xC1,0xC3,0xC4,0xD0,0xD1,0xD2,0xD4 ___ 0xFF}; //Header, Footer, Minipage Text
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
	{
	WORD   PacketType;
	DWORD  Length;
	DWORD  DataPointer;
	} NestedPacket;


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

     DWORD ResourceStart;
     SBYTE DefColumns;
     NestedPacket Images;
     DWORD FontNames;		//offset of packet with font names
     DWORD FontList;

     virtual int Convert_first_pass(void);
     virtual int Dispatch(int FuncNo, ...);
     };

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


static void ProcessKey(TconvertedPass1_WP5 *cq);

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


typedef struct
	{
	WORD  HeadPacketType;
	WORD  NoIndexes;
	WORD  IndexBlkSize;
	DWORD NextBlock;
	} Resource5;


static void FinishSummaryItem(TconvertedPass1_WP5 *cq,int ItemNo)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#FinishSummaryItem() ");fflush(cq->log);
#endif

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


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

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

OldFlag=cq->flag;
cq->flag = HeaderText;
InitAttr(cq->attr);
SummaryChars=0;

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

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


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

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

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

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


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

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

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

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

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

	if(res.IndexBlkSize != 10*res.NoIndexes)
	   {
	   if(cq->err != NULL)
	     fprintf(cq->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(cq->wpd,  &packet.PacketType);
	      Rd_dword(cq->wpd, &packet.Length);
	      Rd_dword(cq->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(cq->err!=NULL && Verbosing>0)
		   fprintf(cq->err,_("\nWarning: Packet #%d inside block #%d has an invalid data pointer!"),i,BlockCounter);
		 continue;
		 }

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

	   }
NextBlock:
	pos1=res.NextBlock;
	}
}


static DWORD SelectImageResource(TconvertedPass1_WP5 *cq, int ResourceNo)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#SelectImageResource(%d) ",ResourceNo);fflush(cq->log);
#endif
WORD Resources;
int i;
DWORD StartResource,ResourceSize;

StartResource=cq->ResourceStart;
if(cq->ResourceStart==0) goto ResErr;

fseek(cq->wpd,cq->ResourceStart,SEEK_SET);
Rd_word(cq->wpd, &Resources);
if(ResourceNo >= Resources) goto ResErr;

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

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

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

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


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

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

  if (CaptionSize == 0)
    return;

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

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

  cq->flag = HeaderText;
  CaptionChars=0;

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

	if(CaptionChars==0)
	  {			// Rule out return before any character
	  if((cq->by==0x0A)||(cq->by==0x0D)) cq->by=' ';
	  }
	if(cq->by==0x0A) cq->by=0x0D; // Replace [HRt] by [SRt]
	if(cq->by==0xD7 && cq->subby==8)
		{
		fread(&cq->subby, 1, 1, cq->wpd);
		fseek(cq->wpd,-1,SEEK_CUR);
		if(cq->subby==8)	//Ignore \label{} in caption
			{
			cq->flag = Nothing;
			ProcessKey(cq);
			cq->flag = HeaderText;
			continue;
			}
		}

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

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

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

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


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

  if (Box.CaptionSize == 0) return;

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

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

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

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

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



static void ReadFormulaStr(TconvertedPass1_WP5 *cq, string & StrBeg, DWORD end_of_code)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#ReadFormulaStr() ");fflush(cq->log);
#endif
WORD wchr_code;
string StrEnd;

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

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

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

      if (cq->by == 0xC0)       /*extended character*/
	    {			/*why special wp characters are in equations?*/
	    Rd_word(cq->wpd, &wchr_code);

	    StrEnd = Ext_chr_str(wchr_code, cq, cq->ConvertCpg);
	    StrBeg+=FixFormulaStrFromTeX(StrEnd, wchr_code>>8);
	    StrEnd="";

	    sprintf(cq->ObjType, "%d,%d",wchr_code & 0xFF,wchr_code>>8);
	    }

      ProcessKey(cq);
      }
}


static const char *BoxNames[6]={"Figure","Table Box","Text Box","Usr Box","Equation","!Box?"};
static void AnyBox(TconvertedPass1_WP5 *cq, DWORD end_of_code)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#AnyBox() ");fflush(cq->log);
#endif
char OldEnvir;
string StrBeg,ImageName;
WORD EquLen;
BYTE OldFlag;
TBox Box;
attribute OldAttr;
int i;
char ch;
boolean AllowCaption;
char BoxType;
WORD WPGResourceNo;
//      CrackObject(cq, end_of_code); //

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

  cq->ActualPos = ftell(cq->wpd);
  fseek(cq->wpd, cq->ActualPos+2L, SEEK_SET);
  fread(&Box.AnchorType, 1, 1, cq->wpd);
  Box.AnchorType &= 0x3;   /*0-Paragraph, 1-Page, 2-Character*/
  fread(&Box.HorizontalPos, 1, 1, cq->wpd);
  Box.HorizontalPos&=3;	   /*0-Left, 1-Right, 2-Center, 3-Full */
  Rd_word(cq->wpd,&EquLen); Box.Width=EquLen/47.0;

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

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

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

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

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

              fseek(cq->wpd, Box.CaptionSize + 10L, SEEK_CUR);
              Rd_word(cq->wpd, &EquLen);   /*total length of equation*/
              StrBeg = "";

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

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

	      ReadFormulaStr(cq, StrBeg, end_of_code);

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

	      cq->attr = OldAttr;

	      PutFormula(cq,StrBeg(),Box,DoCaption5,ExtractCaptionLabel5);

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

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

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

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

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

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

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

              cq->envir=' ';
              if (cq->char_on_line==true)
                   {
                   NewLine(cq);
		   }
              if(AllowCaption)
                      {
                      fseek(cq->wpd, Box.CaptionPos, SEEK_SET);
		      DoCaption5(cq, Box.CaptionSize);
                      }
	      BoxTexFoot(cq, Box);

              cq->envir='^';		//Ignore enviroments after minipage
	      NewLine(cq);
	      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(cq->wpd, cq->ActualPos+38L, SEEK_SET);  // image orientation
	      Rd_word(cq->wpd,&Box.RotAngle);
	      if(Box.RotAngle & 0x8000) Box.HScale=-Box.HScale;
	      Box.RotAngle&=0xFFF;
	      fseek(cq->wpd, cq->ActualPos+109L, SEEK_SET); // receive an image resource No
	      Rd_word(cq->wpd,&WPGResourceNo);
	      if((Box.Image_size=SelectImageResource(cq,WPGResourceNo))>0)
		{
		Box.Image_offset=ftell(cq->wpd);
		Box.Image_type=1;
		}
DiskImage:
	      Box.Contents = 3; // content image - every images are internally converted into WPG
	      end_of_code -= 4;
	      Box.CaptionPos=cq->ActualPos+117L;
	      i=(end_of_code<Box.CaptionPos)?0:(WORD)(end_of_code-Box.CaptionPos);
	      fseek(cq->wpd, cq->ActualPos+115L, SEEK_SET); // receive a caption size
	      Rd_word(cq->wpd,&Box.CaptionSize);
	      if(Box.CaptionSize>i) Box.CaptionSize=i;
	      ImageWP(cq,ImageName,Box,DoCaption5);
	      break;

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


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


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

  Rd_word(cq->wpd, &WChar);
  sprintf(cq->ObjType, "%d,%d",WChar>>8,WChar & 0xFF);
  CharacterStr(cq, Ext_chr_str(WChar, cq, cq->ConvertCpg));
}


/* Internal loop for translating text for labels and references */
static void LabelInside(TconvertedPass1_WP5 *cq, DWORD end_of_code)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#LabelInside(%ld) ",end_of_code);fflush(cq->log);
#endif
const char *characterStr;
char str2[2];
WORD wchr_code;

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

	    characterStr = Ext_chr_str(wchr_code, cq, cq->ConvertCpg);

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

ProcessCharacterSTR:
            FixLabelText(characterStr,cq->strip);
	    continue;
	    }

       ProcessKey(cq);
       }
}


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

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

  LineNumbering(cq, LineNumFlag&0x80);
}


static void MakeIndex(TconvertedPass1_WP5 *cq, DWORD end_of_code)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#MakeIndex() ");fflush(cq->log);
#endif
  unsigned char OldFlag;

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

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

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



static void MakeLabel(TconvertedPass1_WP5 *cq, DWORD end_of_code)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#MakeLabel() ");fflush(cq->log);
#endif
  unsigned char OldFlag;

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

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

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


static void MakeRef(TconvertedPass1_WP5 *cq, DWORD end_of_code)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#MakeRef() ");fflush(cq->log);
#endif
  unsigned char OldFlag, TypeRef;

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

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

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

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



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

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

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

 fread(&b, sizeof(unsigned char), 1, cq->wpd);
 fseek(cq->wpd, 2L, SEEK_CUR);
 Rd_word(cq->wpd, (WORD *)&w);

 what="";
 if(b == 0)	/*Up/Down*/
	{
        if(w>0) what="Up";
        if(w<0) what="Down";
	fprintf(cq->strip, "\\vspace{%2.2fcm}", float(w)/470.0);
        }
 if(b == 2)	/*Left/Right*/
	{
	if(w>0) what="Right";
        if(w<0) what="Left";
    	fprintf(cq->strip, "{\\hskip %2.2fcm}", float(w)/470.0);
        }
 sprintf(cq->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).*/
static void ColDef5(TconvertedPass1_WP5 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#ColDef5() ");fflush(cq->log);
#endif

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

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


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

  Rd_word(cq->wpd, &something);


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

       ProcessKey(cq);
       continue;
       }

  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 Endnote(TconvertedPass1_WP5 *cq, DWORD end_of_code)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Endnote() ");fflush(cq->log);
#endif
  attribute OldAttr;
  unsigned char OldFlag;


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

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

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

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

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

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

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

             default: ProcessKey(cq);
	              break;
             }

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


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

  cq->attr=OldAttr;
  Open_All_Attr(cq->attr,cq->strip);

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


static void Footnote(TconvertedPass1_WP5 *cq, DWORD end_of_code)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Footnote() ");fflush(cq->log);
#endif
  attribute OldAttr;
  unsigned char flags, num_of_pages;
  WORD fn_num;
  unsigned char OldFlag;


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


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

  Rd_word(cq->wpd, &fn_num);

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

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


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

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

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

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

	     default: ProcessKey(cq);
		      break;
	     }

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


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

  cq->attr=OldAttr;

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


static void Header_Footer(TconvertedPass1_WP5 *cq,DWORD end_of_code)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Header_Footer() "); fflush(cq->log);
#endif
unsigned char occurance;
attribute OldAttr;
string s;
unsigned char OldFlag,OldEnvir;
int i;

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

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

  cq->recursion++;
  end_of_code -= 4;

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

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

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

  Close_All_Attr(cq->attr,cq->strip);
  OldAttr = cq->attr;			/* Backup all attributes */
  if(cq->Font==FONT_HEBREW || cq->Font==FONT_CYRILLIC)
      {
      cq->Font = FONT_NORMAL;
      }

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

  InitHeaderFooter(cq,cq->subby,occurance);
  occurance=(occurance << 4) | (cq->subby & 0xF);


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

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

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

        ProcessKey(cq);
        }

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

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

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

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


static void LineSpacing(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#LineSpacing() ");fflush(cq->log);
#endif
WORD LastSpacing;
WORD 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);
}


static void MarkedTextBegin(TconvertedPass1_WP5 *cq,DWORD & NewPos)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#MarkedTextBegin() ");fflush(cq->log);
#endif
  signed char b;
  string ListName;


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

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


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

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


/*This function converts overstriked characters.*/
static void Overstrike(TconvertedPass1_WP5 *cq, DWORD end_of_code)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Overstrike() ");fflush(cq->log);
#endif
  boolean first_char_os = true;
  WORD char_width_os;
  attribute OldAttr;
  string s;

  unsigned char OldFlag;

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

  Rd_word(cq->wpd, &char_width_os);

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

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

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

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

  AttrFit(cq->attr,OldAttr,s);
  if(s!="") fputs(s(),cq->strip);

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


static void SetFont5(TconvertedPass1_WP5 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#SetFont5() ");fflush(cq->log);
#endif
WORD PointSize;
WORD NamePtr;
const char *ig="!";
string FontName;
BYTE FontNo;
char ch;

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

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

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

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

  sprintf(cq->ObjType, "%sFont %2.2f%.20s",ig,float(PointSize)/50,FontName());
}



typedef struct WPTab {
  WORD len;
  WORD attribute;
  BYTE alignment;
} WPTab;

static void TableStart5(TconvertedPass1_WP5 *cq, unsigned short len, DWORD & NewPos)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#TableStart5(%d) ",(int)len);fflush(cq->log);
#endif
  short columns = 0;
  WORD i;
  unsigned char b;
  WPTab Atbl[100];
  string TexAttrib;
  unsigned char OldFlag;
  char OldEnvir;
  BYTE PosFlag;

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

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

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

  fseek(cq->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(cq->ObjType, "!Table Start"); return;
	}

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

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

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

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

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

  cq->envir = 'B';

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

    if(TexAttrib != "")
	{
	fprintf(cq->strip,"@{%s}",TexAttrib());
	}

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

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

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

	/*Process all content of the table */
  fseek(cq->wpd,cq->ActualPos=NewPos,SEEK_SET);
  cq->by = fgetc(cq->wpd);
  while(!feof(cq->wpd))
	{
	if((cq->by==0xDC || cq->by==0xDD) && cq->envir!='B')
		{
		cq->envir='B';
		}
	ProcessKey(cq);
	NewPos=cq->ActualPos;
	if(cq->by==0xDC && cq->subby==0x2) break; /*End of table*/
        if(cq->by==0xDD && cq->subby==0x2) break; /*End of table on EOP*/

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

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

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

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

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


static void Tabset(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Tabset() ");fflush(cq->log);
#endif
  int j,SideMargin;
  WORD 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
  WORD 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");
}



////////////////////////////////////////////////////////////////
static boolean CheckConzistency(TconvertedPass1 *cq, long NewPos)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#CheckConzistency(%X,%X) ",(int)cq->by,(int)cq->subby);fflush(cq->log);
#endif

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

  Pos = ftell(cq->wpd);

  TestedSubBy=cq->subby;
  if (cq->by >= 0xd0)			//subby will be also tested
  		 {
                 fseek(cq->wpd, NewPos-2 , 0);
		 fread(&TestedSubBy, 1, 1, cq->wpd);
		 }
  	    else fseek(cq->wpd, NewPos-1 , 0);
  fread(&TestedBy, 1, 1, cq->wpd);
  if ((TestedBy != cq->by)||(TestedSubBy != cq->subby))
  	{
        if (cq->err != NULL)
          {
//        if(CorruptedObjects<19)
	    cq->perc.Hide();
            fprintf(cq->err,
              _("\nError: Object %lX:%X consistency check failed. Trying to ignore."),Pos,(int)cq->by);
/*        if(CorruptedObjects==19)
	    fprintf(cq->err,
	      _("\nError: Overwhelmed by too many currupted objects, switching to the silent mode.);*/
          }
	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 ProcessKey(TconvertedPass1_WP5 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#ProcessKey() ");fflush(cq->log);
#endif
  WORD w;
  DWORD NewPos = 0;
  unsigned char by, subby;

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

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

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

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

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

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

	case 0x80: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:End_Align(cq);			  break;
//	case 0x84:break;						/* Reserved */
//	case 0x85:break;						/* Place Saver */
	case 0x86:CenterPage(cq);			  break;
	case 0x87:Column(cq,cq->DefColumns);		  break;	/* Col On */
	case 0x88:Column(cq,1);				  break;	/* Col Off */
//	case 0x89:break;						/* Reserved */
	case 0x8A:WidowOrphan(cq,3);			  break;
	case 0x8B:WidowOrphan(cq,0);			  break;
	case 0x8C:if(cq->char_on_line>=0) Terminate_Line(cq,'h');	/* Hard return */
				     else Terminate_Line(cq,'s');   // hard return mustn't occur here, fix it
		  break;
	case 0x8D:strcpy(cq->ObjType, "!Note Num");	  break;
	case 0x8E:strcpy(cq->ObjType, "!Fig Num");	  break;
	case 0x8F:if(toupper(cq->envir)=='C') Justification(cq, 0x83);
		  strcpy(cq->ObjType, "~Center");	  break;

	case 0x93:InvisibleSoftReturn(cq);		  break;

	case 0x96:strcpy(cq->ObjType, "!Block On");	  break;
	case 0x97:strcpy(cq->ObjType, "!Block Off");	  break;

	case 0x99:if(cq->envir != 'B' && cq->char_on_line > 0)	// Dormant Hard return
			     Terminate_Line(cq,'h');
			else fputc(' ', cq->strip);
		  strcpy(cq->ObjType, "Dorm HRt");
		  break;
	case 0x9A:CancelHyph(cq);			break;
	case 0x9B:strcpy(cq->ObjType, "End Def");	break; //End of automatically generated definition
	case 0x9E:Hyphenation(cq,false);		break;
	case 0x9F:Hyphenation(cq,true);			break;
	case 0xA0:fputc('~', cq->strip);strcpy(cq->ObjType, " ");
		  break;

	case 0xA9:
	case 0xAA:
	case 0xAB:HardHyphen(cq);			break;	/*Hyphen*/
	case 0xAC:
	case 0xAD:
	case 0xAE:SoftHyphen(cq);	  		break;
	case 0xAF:Column(cq,false);			break;
	case 0xB0:Column(cq,false);			break;

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

	case 0xC2:Indent(cq,5);		 break;
	case 0xC3:Attr_ON(cq);           break;
	case 0xC4:Attr_OFF(cq);          break;
	case 0xC6:End_of_indent(cq);     break;

	case 0xD0:switch (subby)
		    {
		    case 0x01:LRMargin(cq);		break;
		    case 0x02:LineSpacing(cq);		break;
		    case 0x04:Tabset(cq);		break;
		    case 0x06:Justification(cq,5);	break;
		    case 0x07:Suppress(cq,5);		break;
		    case 0x08:Page_number_position(cq,5);break;
		    }
		  break;
	case 0xD1:switch (subby)
		    {
                    case 0: Color(cq,5); break;
		    case 1: SetFont5(cq); break;		    
		    case 2: fseek(cq->wpd,1,SEEK_CUR);
                            fread(&subby, 1, 1, cq->wpd);
			    RGBQuad q;
			    q.R = WPG_Palette[subby].Red;
			    q.G = WPG_Palette[subby].Green;
			    q.B = WPG_Palette[subby].Blue;
			    Color(cq,5,&q);
			    break;
                    } 
		  break;
	case 0xD2:if(subby == 1) ColDef5(cq);
		  if(subby == 0xb) TableStart5(cq, w, NewPos);
		  break;
	case 0xD3:switch (subby)
		    {
		    case 0x02:SetFootnoteNum(cq,5);	break;
		    case 0x03:SetEndnoteNum(cq,5);	break;
		    case 0x04:SetPgNum(cq,5);		break;
		    case 0x05:LineNumbering5(cq);	break;
		    case 0x06:Advance(cq);		break;
		    case 0x11:Language(cq,5);		break;
		    }
		  break;
	case 0xD4:if(cq->subby==3) strcpy(cq->ObjType,"!Repositioning Marker");
		  break;
	case 0xD5:Header_Footer(cq, NewPos);
		  break;
	case 0xD6:switch(subby)
		     {
		     case 0: Footnote(cq, NewPos);         break;
		     case 1: Endnote(cq, NewPos);          break;
		     }
		  break;

	case 0xD7: switch(subby)
		      {
		      case 0:   MarkedTextBegin(cq,NewPos);break;
		      case 0x1: EndSection(cq,5);	   break;
		      case 0x2: TableOfContents(cq,5);	   break;
		      case 0x3: MakeIndex(cq, NewPos);	   break;
		      case 0x5: PlaceEndnotes(cq);	   break;
		      case 0x7: MakeRef(cq, NewPos);       break;
		      case 0x8: MakeLabel(cq, NewPos);	   break;
//		      case 0xA: Start Included SubDocument
//		      case 0xB: End Included SubDocument
                      }
                   break;

	case 0xD8:switch (subby)
                    {
		    case 0x0: DateCode(cq);                break;
		    case 0x1: ParagraphNumber(cq);	   break;
		    case 0x2: Overstrike(cq, NewPos);      break;
		    case 0x3: PageNumber(cq);		   break;
		    }
		  break;

	case 0xD9:if (subby == 2) Comment5(cq, NewPos);
		  break;


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

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

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

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

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


static void 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, ...)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WP5::Dispatch(%d) ",FuncNo);fflush(log);
#endif
va_list ap;

 va_start(ap, FuncNo);
 switch(FuncNo)
   {
   case DISP_PROCESSKEY:
	 ProcessKey(this);
	 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
DWORD 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(this);
    fseek(wpd,DocumentStart,SEEK_SET);
    }

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

      by = 0;
      ProcessKey(this);
      }

  Finalise_Conversion(this);
  return(1);
}

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


