/******************************************************************************
 * program:     wp2latex                                                      *
 * function:    convert WordPerfect files into LaTeX                          *
 * modul:       pass1_1.cc                                                    *
 * description: This is conversion module for parsing WP 1.x binary files.    *
 * licency:     GPL		                                              *
 ******************************************************************************/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

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

#include "cp_lib/cptran.h"


extern set filter[4];

int set0_10[]={0 ___ 0xFF};		//Everything
int set1_10[]={0 ___ 0xFF}; //Header, Footer, Minipage Text
int set2_10[]={0x20 ___ 0x7F,0xE1};  //Characters Only

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


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

     virtual int Convert_first_pass(void);
     };

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

/*Register translators here*/
TconvertedPass1 *Factory_WP1(void) {return new TconvertedPass1_WP1;}
FFormatTranslator FormatWP1("WP1.x",Factory_WP1);

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


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

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

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

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


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

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

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

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

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

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

       ProcessKey1(cq);
       }

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

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

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


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

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

  Pos = ftell(cq->wpd);

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

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


/*This is main procedure for processing one key. It is recursivelly called.*/
static void ProcessKey1(TconvertedPass1_WP1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#ProcessKey1() ");fflush(cq->log);
#endif
  WORD w;
  DWORD NewPos = 0;
  unsigned char by, subby;

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

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

  /*Guessing end position of the object*/

  if (cq->by >= 0xC0)
      {
      w=ObjWP1SizesC0[cq->by-0xC0];
      if(w>0) NewPos = cq->ActualPos + w;
      }
      
  by = cq->by;
  subby = cq->subby;

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

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

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

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


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

	case 0xBC:AttrOn(cq->attr,5);cq->SubSup|=0x82;		/* Superscript */
		  strcpy(cq->ObjType, "SupScript");
		  break;
	case 0xBD:AttrOn(cq->attr,6);cq->SubSup|=0x81;		/* Subscript */
		  strcpy(cq->ObjType, "SubScript");
		  break;
//	case 0xBE:LineUpDown(cq, 0.5);			break;	/* Advance 1/2 line up */
//	case 0xBF:LineUpDown(cq, -0.5);			break;	/* Advance 1/2 line down */

	case 0xC0:strcpy(cq->ObjType, "!WP1_MARGIN_RESET_GROUP"); goto GROUP_Cx;
	case 0xC1:strcpy(cq->ObjType, "!WP1_SPACING_RESET_GROUP"); goto GROUP_Cx;
	case 0xC2:strcpy(cq->ObjType, "!WP1_MARGIN_RELEASE_GROUP"); goto GROUP_Cx;
	case 0xC3:strcpy(cq->ObjType, "!WP1_CENTER_TEXT_GROUP"); goto GROUP_Cx;
	case 0xC4:strcpy(cq->ObjType, "!WP1_FLUSH_RIGHT_GROUP"); goto GROUP_Cx;

	case 0xC9:strcpy(cq->ObjType, "!WP1_SET_TABS_GROUP"); goto GROUP_Cx;

	case 0xCC:strcpy(cq->ObjType, "!WP1_LEFT_INDENT_GROUP"); goto GROUP_Cx;

	case 0xCE:strcpy(cq->ObjType, "!WP1_TOP_MARGIN_SET_GROUP"); goto GROUP_Cx;
	case 0xCF:strcpy(cq->ObjType, "!WP1_SUPPRESS_PAGE_CHARACTERISTICS_GROUP"); goto GROUP_Cx;
	case 0xD0:strcpy(cq->ObjType, "!WP1_BOTTOM_MARGIN_SET_GROUP"); goto GROUP_Cx;
	case 0xD1:strcpy(cq->ObjType, "!WP1_HEADER_FOOTER_GROUP"); goto GROUP_Cx;

	case 0xE0:strcpy(cq->ObjType, "!WP1_LEFT_RIGHT_INDENT_GROUP"); goto GROUP_Cx;
	case 0xE1:Character1(cq);	break;		/* IBM character WP1_EXTENDED_CHARACTER_GROUP */
	case 0xE2:FootEndNote1(cq, NewPos, w);		break;	/* footnote or endnote */

	case 0xF4:strcpy(cq->ObjType, "!WP1_POINT_SIZE_GROUP"); goto GROUP_Cx;

	case 0xFB:Justification(cq, 1); 	break;

	default:if(by>=0x01 && by<=0x7f)
		     {
		     cq->RequiredFont = FONT_NORMAL;
		     CharacterStr(cq,Ext_chr_str(cq->by,cq,NULL));
                     if(cq->attr.Closed_Depth>0)
			{
			if(cq->SubSup)
			  {
			  AttrOff(cq,5);
			  AttrOff(cq,6);
			  }
			cq->SubSup=0;
			}
		     }
		else if(by>=0xC0)
                  {
GROUP_Cx:         if(NewPos==0)
		    {	//move to the second delimiter, variable size items
	       	    while(!feof(cq->wpd))
		      {
		      by=fgetc(cq->wpd);
		      if(by==cq->by) break;
		      }
		    }
	          }
		break;
	}
  }

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

        fflush(cq->log);
        }
    else if (by >= ' ' && by <= 'z')
	         putc(by, cq->log);
    }


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

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

void InitFilter1(void)
{
 filter[0]=set(set0_10,sizeof(set0_10)/sizeof(int));
 filter[1]=set(set1_10,sizeof(set1_10)/sizeof(int));
 filter[2]=set(set2_10,sizeof(set2_10)/sizeof(int));
 filter[3]=set();
}

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

  LogLevel=1;
  InitFilter1();

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

  UnderlineType = 0;
  SubSup = 0;

  DocumentStart=ftell(wpd);

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

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

      by = 0;
      ProcessKey1(this);
      }

  Finalise_Conversion(this);
  return(1);
}

/*--------------------End of PASS1_1------------------*/

