;workarea:    <- RTF_work
;  listptr dd savelist    0
;  szKeyword rb 31        4
;  szParameter rb 21      35

include 'rtftype.inc'
include 'rtfactn.inc'

read_next_block:
  inc  [cur_block]
read_block:
  mov  esi,I_END
  pusha
  mov  ecx,[cur_block]
  mov  ebx,fileinfo
  mov  eax,ecx
  shl  eax,16
  mov  [ebx+4],eax
;  mov  [ebx+12],esi
  mcall 70
if DEBUG_BLOCK eq 1
;  dps  'B='
;  dpd  ecx
;  dps  <13,10>
end if
  cmp  ecx,[max_block]
  je   .last
  mov  ebx,I_END+RTFSIZE
  jmp  .add
.last:
  mov  ebx,[tail]
;  dpd  ebx
.add:
;  dpd  ebx
  mov  [block_end],ebx
  popa
;  dpd  esi
;  dps  <13,10>
  ret
;
; %%Function: ecRtfParse
;
; Step 1:
; Isolate RTF keywords and send them to ecParseRtfKeyword;
; Push and pop state at the start and end of RTF groups;
; Send text to ecParseChar for further processing.
;
macro CopySave _src,_dest
{
    pusha
    mov  ecx,SIZE_save
    mov  esi,_src
    mov  edi,_dest
    rep  movsb
    popa
}

RtfParse:

 if BENCH eq 1
    mcall 26,9
    mov  [bench],eax
 end if
    mov  [RetroPtr],esi
    CopySave Chp,RetroSave
    push dword[Free+4]
    pop  dword[RetroXY]
    xor  eax,eax
    mov  [cur_block],eax
    mov  [RetroBlock],eax
    push [cGroup]
    pop  [RetroGroup]
    and  [mode],not RTF_BLIND
    mov  [listptr],save_stack
    mov  [fileinfo.size],128*512
;    test ebp,RTF_HELP
    test [mode],RTF_HELP
    jne  .noread
    call read_block
  .noread:
    mov  [RetroPtr],esi
  .nib2:
    mov  [nibble],2
    and  [b],al
  .getc:
    xor  eax,eax
    lods_block
    cmp  [cGroup],0
    jge  .ok1
    Return ecStackUnderflow
  .ok1:
    cmp  [ris],risBin
    jne  .nobin
    RetError ecParseChar
  .nobin:
    cmp  al,'{'
    jne  .nobr1
    RetError ecPushRtfState
  .nobr1:
    cmp  al,'}'
    jne  .nobr2
    RetError ecPopRtfState
  .nobr2:
    cmp  al,'\'
    jne  .noslash
    RetError ecParseRtfKeyword
  .noslash:
    cmp  al,0xd
    je   .getc
    cmp  al,0xa
    je   .getc
  .nouc:
    cmp  [ris],risNorm
    jne  .nonorm
    call ecParseChar
    cmp  eax,ecOutOfWindow
    je   .__ex
    test eax,eax
    je   .getc
    jmp  .__ex
  .nonorm:
    cmp  [ris],risHex
    je   .noassert
    Return ecAssertion
  .noassert:
    shl  [b],4
    isdigit al, .nodig
    sub  al,'0'
    add  [b],al
    jmp  .nibble
  .nodig:
    islower al, .nolow
    cmp  al,'a'
    jb   .inval
    cmp  al,'f'
    ja   .inval
    sub  al,'a'-10
    jmp  .nib0
  .inval:
  if INVALHEX eq 0
    jmp  .getc
  else
;    sub  esi,I_END+1
;    dpd  esi
;    movzx eax,al
;    dpd  eax
;    movzx eax,[b]
;    dpd  eax
    Return ecInvalidHex
  end if
  .nolow:
    cmp  al,'A'
    jb   .inval
    cmp  al,'F'
    ja   .inval
    sub  al,'A'-10
  .nib0:
    add  [b],al
  .nibble:
    dec  [nibble]
    cmp  [nibble],0
    jnz  .getc
    movzx eax,[b]
    mov  [ris],risNorm
    call ecParseChar
    test eax,eax
    jnz  .__ex
;    mov  [ris],risNorm
    jmp  .nib2
  .eof:
    xor  eax,eax
    cmp  eax,[cGroup]
    je   .__ex
    jg   .unbr
    Return ecStackUnderflow
  .unbr:
    mov  eax,ecUnmatchedBrace
  .__ex:
    ret
nibble db 2
b      db 0
RTF_maxlist dd ?
;
; %%Function: ecParseRtfKeyword
;
; Step 2:
; get a control word (and its associated value) and
; call ecTranslateKeyword to dispatch the control.
;

ecParseRtfKeyword:
; ch-al,bl-fParam, bh-fNeg
    mov  [ris],risNorm
    xor  eax,eax
    xor  ebx,ebx
    push edx
    mov  [szKeyword],al
    mov  [szParameter],al
    lods_block
    isalpha al,.ctrl
    jmp  .alph
  .ctrl:
    push esi
    mov  esi,szKeyword
    inc  byte[esi]
    mov  [esi+1],al
    mov  eax,ebx
    xor  ebx,ebx
    call ecTranslateKeyword
    pop  esi
    jmp  .__ex
  .alph:
    push edi
    mov  edi,szKeyword+1
  .loop1:
    stosb
    inc  [szKeyword]
    lods_block
    isalpha al,.outloop1
    jmp  .loop1
  .outloop1:
    pop  edi
    cmp  al,'-'
    jne  .noneg
    not  bh
    lods_block
  .noneg:
    isdigit al,.nodig
    not  bl
    push edi
    mov  edi,szParameter+1
  .loop2:
    stosb
    inc  [szParameter]
    lods_block
    isdigit al,.outloop2
    jmp  .loop2
  .outloop2:
    pop  edi
    push eax esi
    mov  esi,szParameter
    atoi
    pop  esi
    mov  edx,eax
    pop  eax
    mov  [lParam],edx
    test bh,bh
    jz   .nodig
    neg  edx
  .nodig:
    cmp  al,' '
    je   .space
    cmp  esi,I_END
    jne  .ok_block
    dec  [cur_block]
    call read_block
    mov  esi,[block_end]
  .ok_block:
    dec  esi
  .space:
    mov eax,ebx
    mov ebx,edx
    push esi
    mov  esi,szKeyword
    call ecTranslateKeyword
    pop  esi
  .__ex:
    pop  edx
    ret

;
; %%Function: ecParseChar
;
; Route the character to the appropriate destination stream.
;

ecParseChar:
;in: ch-al, esi->rtf
   cmp  [ris],risBin
   jne  .nobin
   dec  [cbBin]
   cmp  [cbBin],0
   jg   .nobin
   mov  [ris],risNorm
 .nobin:
   cmp  [rds],rdsColor
   jne  .nodelim
   cmp  al,';'
   jne  .non
   mov  eax,[colorptr]
   cmp  eax,ct_end-4
   jae  .non
   add  [colorptr],4
   jmp  .non
 .nodelim:
   cmp  [rds],rdsSkip
   je  .non
   cmp  [rds],rdsNorm
   je   ecPrintChar
;   ret
 .non:
   mov  eax,ecOK
   ret

macro PrintTrap _char
{
local .notrap
    cmp  byte[esi],_char
    jne  .notrap
    sub  esi,I_END
    dps  'Trapped at '
    dpd  esi
    dps  <13,10>
    ud2
  .notrap:
}
;
; %%Function: ecPrintChar
;
; Send a character to the output file.
;

ecPrintChar:
; in:ch-al, esi - rtf pointer
;    stosb
;    jmp  .nowrap
    mov  ebp,[mode]
    cmp  al,0xa
    jne   .nopar
;    and  ebp,not RTF_NO1STLINE
    and  [mode],not RTF_NO1STLINE
    jmp  .par
  .nopar:
    cmp  al,0x9
    jne  .notab
    add  word[Free+6],CHARW*3
    jmp  .chkwrap
  .notab:
    xor  ebx,ebx
  if ~ RENDER eq FREE
    cmp  word[Free+4],TOP
    jl   .nodraw
  end if
    ansi2oem
    mov  [char],al
;    PrintTrap '/'
    pusha
    xor   eax,eax
;    test  [mode],RTF_BLIND
    test  ebp,RTF_BLIND
    je   .rend
;    test  [mode],RTF_COLORLESS
    test  ebp,RTF_COLORLESS
    jz    .setcolor
    mov   ecx,DEFCOLOR
    jmp   .rend
  .setcolor:
    movzx ecx,byte[Chp+3]
    mov   ecx,[colortbl+ecx*4]
  .rend:
  if RENDER eq FREE
    mov   ebx,Free
    mov   dword[ebx+32],eax
    mov   [ebx+28],ecx
;    test  [mode], RTF_BOTTOM
    test  ebp, RTF_BOTTOM
    jne   .nodraw2
    cmp  word[Free+4],TOP
    jl   .nodraw2
    cmp   byte[Chp],fTrue
    jne   .nobold
    or    dword[ebx+32],BGI_BOLD
  .nobold:
;    test  [mode], RTF_BLIND
    test  ebp, RTF_BLIND
    jne   .freet
  .nodraw2:
    or    dword[ebx+32],BGI_NODRAW
  .freet:
    BGIfont_Freetext

    mov  [Free+4],eax
    test [mode],RTF_BLIND
;    jmp  .nohei
    jne  .nohei
    fild word[BGIheight]
    fmul dword[Free+12]
;    fistp word[curheight]
    fistp word[maxheight]
;    movzx eax,[curheight]
;    dpd  eax
;    cmp  ax,[maxheight]
;    jae  .nohei
;    mov  [maxheight],ax
;    dps 'M'
;    dpd  eax

;    dps <13,10>
  .nohei:
  else
    and   ecx,0xffffff
    mov   ebx,[Free+4]
    mov   edx,char
    mov   esi,1
  end if

  if RENDER eq BGI
    add   ecx,0x44000000
    cmp   byte[Chp],fTrue
    jne   .nobold
    or    esi,BGI_BOLD
  .nobold:
    test  ebp,RTF_BLIND
;    test  [mode],RTF_BLIND
    jne    .freet
    or    esi,BGI_NODRAW
  .freet:
    BGIfont_Outtext
    mov   [Free+4],eax
  end if

  if RENDER eq PIX
;    test  [mode],RTF_TOEOF
;    jne   .blind
;    test  [mode],RTF_BOTTOM
    test  ebp,RTF_BOTTOM
    jne   .nobold
  .blind:
;    test  [mode],RTF_BLIND
    test  ebp,RTF_BLIND
    je    .nobold
    mcall 4
    cmp   byte[Chp],fTrue
    jne   .nobold
    add   ebx,1 shl 16
    mcall
  .nobold:
  end if
    popa
  .nodraw:
  if  RENDER eq PIX
    add  word[Free+6],CHARW
  end if
    movsx eax,[pitch]
    add  word[Free+6],ax
  .chkwrap:
    mov  eax,dword[prcinfo+42]
    cmp  ax,word[Free+6]
    ja   .nowrap
;    or   ebp,RTF_NO1STLINE
    or   [mode],RTF_NO1STLINE
  .par:
    xor  [mode],RTF_BLIND
;    not  [blind]
    test [mode] ,RTF_BLIND
    je   .makewrap
    ; [blind]=false
    movzx eax,word[Free+6]
    sub  ax,word[RetroXY+2]
    push dword[RetroXY]
    pop  dword[Free+4]
    mov  [mark],0xff0000
    test [mode],RTF_ALIGNLESS
    jnz  .letsdraw
    cmp  byte[Pap+12],justR
    jb   .letsdraw
    mov  [mark],0xff
    mov  ebx,dword[prcinfo+42] ; wnd width
    sub  ebx,eax
    cmp  byte[Pap+12],justC
    jne  .nocenter
    shr  ebx,1
    mov  [mark],0x00ff00
  .nocenter:
    mov  word[Free+6],bx
  .letsdraw:
;    test [mode],RTF_NO1STLINE
;    jnz  .no1st
;    add  word[Free+6],60
  .no1st:
  if STEPBYSTEP eq 1
;    movzx eax,[mode]
;    dph  eax
;    test [mode],RTF_NO1STLINE
;    jnz  .no1st
;    mcall 4,[RetroXY],[mark],sym,1
;    dps  '1st '
;  .no1st:
    dps  <'false ',13,10>
;    dpd  eax
;    dpd  ebx
  end if
  if SHOWALIGN eq 1
    mcall 4,[RetroXY],[mark],sym,1
  end if
  if STEPBYSTEP eq 1
    mcall 10
    mcall 2
  end if
    mov  eax,[RetroBlock]
    cmp  eax,[cur_block]
    je   .norblock
    mov  [cur_block],eax
    call read_block
  .norblock:
    mov  esi,[RetroPtr]
    push [RetroGroup]
    pop  [cGroup]
    CopySave RetroSave,Chp
    jmp  .nowrap
  .makewrap:       ; second pass preparing
    ; [blind]=true
  if STEPBYSTEP eq 1
    dps  'true '
    mcall 10
    mcall 2
  end if
    mov  word[Free+6],LMARGIN
  if RENDER eq FREE
    fld [line_space]
    fimul [maxheight]
    fistp [maxheight]
    movzx eax,[maxheight]
    add  word[Free+4],ax
;    and  [maxheight],0
;    add  word[Free+4],CHARH
  else
    mov  eax,CHARH
    add  word[Free+4],ax
  end if
    test [mode],RTF_TOEOF
    je   .nohdoc
    add  [HDoc],eax
    inc  [line_count]
  .nohdoc:
    test [mode],RTF_BOTTOM
    jne  .text
;    dps  '1'
    mov  ebx,dword[prcinfo+46]
    cmp  bx,word[Free+4]
    jge   .text
    or   [mode],RTF_BOTTOM
    dps  <'btm',13,10>
    test [mode],RTF_TOEOF
    jne  .text
    mov  eax,ecOutOfWindow
    ret
;  end if
  .text:
    push dword[Free+4]
    pop  dword[RetroXY]
    mov  word[RetroXY+2],LMARGIN
    mov  [RetroPtr],esi
    push [cur_block]
    pop  [RetroBlock]
    CopySave Chp,RetroSave
    push [cGroup]
    pop  [RetroGroup]
;  if STEPBYSTEP eq 1
;    mcall 10
;    mcall 2
;  end if
  .nowrap:
    mov  eax,ecOK
    ret
mark dd ?
sym db 0x10
line_space dd 1.6
;
; %%Function: ecPushRtfState
;
; Save relevant info on a linked list of SAVE structures.
;

ecPushRtfState:
    pusha
    mov  edi,[listptr]
    mov  eax,edi
    mov  ecx,SIZE_save
    add  eax,ecx
    cmp  eax,save_limit
    jb   .malloc
    Return ecStackOverflow
  .malloc:
    mov  esi,Chp
    rep  movsb
    mov  [listptr],edi
    mov  [ris],risNorm
    inc  [cGroup]
    xor  eax,eax
    Epilog

; %%Function: ecPopRtfState
;
; If we're ending a destination (that is, the destination is changing),
; call ecEndGroupAction.
; Always restore relevant info from the top of the SAVE list.

ecPopRtfState:
    pusha
    mov  esi,[listptr]
    cmp  esi,save_stack
    ja  .okpop
    Return ecStackUnderflow
  .okpop:
    movzx eax,[rds]
    cmp  al,[esi-2]
    je   .noega
    RetError ecEndGroupAction, .noega
  .noega:
    mov  ecx,SIZE_save
    sub  esi,ecx
    mov  [listptr],esi
    mov  edi,Chp
    rep  movsb
    dec  [cGroup]
    xor  eax,eax
    Epilog

ansitbl:
    db 0xaa,0xba,0xbf,0xaf
    db 0xa7,0xa8,0xa1,0xab,0xb0,0xb2,0xb3,0xb6,0xb7,0xb8,0xb9
    db 0xa2,0xbb,0x93,0x94,0x85
oematbl:
 if RENDER eq PIX
    db 0xf2,0xf3,0xf5,0xf4
 else
    db 0x85,0xa5,0x69,0x49
 end if
    db 0x15,0xf0,0xf6,0x22,0x1d,0x49,0x69,0x14,0x1c,0xf1,0x23
    db 0xf7,0x22,0x22,0x22,0x16
uctbl:
    dw 0x451
oemutbl:
    db 0xb8
