;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;   Compile with FASM 1.60 or above
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SIZE_QRDATA = 32
SIZE_QRECC  = 16

macro pushext {
  push rbx
  push rbp
  push rsi
  push rdi
}

macro popext {
  pop rdi
  pop rsi
  pop rbp
  pop rbx
}


use64

    org   0x0

    db    'MENUET64'              ; Header identifier
    dq    0x01                    ; Version
    dq    START                   ; Start of code
    dq    image_end               ; Size of image
    dq    0x100000                ; Memory for app
    dq    0xffff0                 ; Rsp
    dq    0x00                    ; Prm 
    dq    0x00                    ; Icon

include "textbox.inc"

    rs_init_gf:   ; ecx = poly
 pushext

 mov ebx, 1  ; ebx = b = 1
 xor eax, eax ; eax = m
 mov edx, ebx ; edx = 1
      .L1:
 cmp ebx, ecx ; if b > poly then
 jg @f  ;   break the loop
 inc eax  ; Inc (m)
 shl ebx, 1  ; b = b shl 1
 jmp .L1
      @@:
    ; since there are no calls in this subroutine,
    ; it's possible to use the stack directly

 mov [rsp-4], ecx ; save ecx on stack
 dec eax  ; Dec (m)
 shr ebx, 1  ; b = b shr 1

 mov ecx, eax ; ecx = m
 shl edx, cl  ; edx = (1 shl m)
 mov ecx, [rsp-4] ; restore ecx
 dec edx  ; edx = logmod = (1 shl m) - 1
 mov [rsp-4], ebx ; save b
 mov eax, 1  ; eax = p
 mov [logmod], edx ; store global variable
 xor ebx, ebx ; ebx = v
 mov esi, logt
 mov edi, alog

      .L2:
 cmp ebx, edx  ; if v >= logmod then
 jge .L9   ;   return
 mov [edi+4*ebx], eax ; alog[v] = p
 mov [esi+4*eax], ebx ; logt[p] = v
 shl eax, 1   ; p = p shl 1
 mov rbp, [rsp-4]  ; load b from stack
 and rbp, rax  ; if (p and b) = 0 then
 jz  @f   ;   do nothing
 xor eax, ecx  ; else p:=p xor poly
      @@:
 inc ebx   ; Inc (v)
 jmp .L2

      .L9:
 popext
 ret


    rs_init_code:  ; ecx = nsym, edx = index
 pushext
 mov esi, 1   ; esi = i
 mov [rsp-4], ecx  ; save nsym
 mov [rsp-8], edx  ; save index
 mov edi, rspoly
 mov [rlen], ecx  ; store global variable
 mov dword [edi], 1  ; rspoly[0] = 1

      .L1:
 cmp esi, [rsp-4]  ; if i > nsym then
 jg .L9                     ;   return
 mov dword [edi+4*esi], 1 ; rspoly[i] = 1
 lea ebx, [esi-1]  ; ebx = k = i - 1
      .L2:
 cmp ebx, 0   ; if k <= 0 then
 jle .L4   ;   break the loop
 mov ecx, [edi+4*ebx] ; ecx = rspoly[k]
 cmp ecx, 0
 jz @f   ; if rspoly[k]=0 then jump

 mov eax, [logt+4*ecx] ; eax = logt[rspoly[k]]
 xor edx, edx  ; prepare edx for division
 add eax, [rsp-8]  ; eax = eax + index
 idiv dword [logmod]
 mov eax, [alog+4*edx] ; eax = alog [ ... ]
 mov [edi+4*ebx], eax ; rspoly[k] = eax

      @@:
 mov eax, [edi+4*ebx-4] ; eax = rspoly[k - 1]
 xor eax, [edi+4*ebx] ; eax = eax xor rspoly[k]
 mov [edi+4*ebx], eax        ; rspoly[k] = eax
 dec ebx   ; Dec (k)
 jmp .L2

      .L4:
 mov ecx, [edi]  ; ecx = rspoly[0]
 mov eax, [logt+4*ecx] ; eax = logt[rspoly[0]]
 xor edx, edx  ; prepare edx for division
 add eax, [rsp-8]  ; eax = eax + index
 idiv dword [logmod]  
 inc dword [rsp-8]           ; Inc (index)
 mov eax, [alog+4*edx] ; eax = alog [ ... ]
 inc esi   ; Inc (i)
 mov [edi], eax  ; rspoly[0] = eax
 jmp .L1

      .L9:
 popext
 ret


    rs_encode:   ; ecx = len, edx = data, eax = res
 pushext
 mov [rsp-4], ecx  ; save len
 mov [rsp-8], edx  ; save data
 mov esi, eax  ; esi = res
 xor edi, edi  ; edi = i = 0

      .L1:
 or ebx, -1   ; same as "mov ebx, -1" but shorter
 cmp edi, [rsp-4]  ; if i >= len then
 jge .L9   ;   return
 xor eax, eax  ; going to use eax and al simultaneously, so must clear it first
 mov edx, [rsp-8]  ; edx = data
 add ebx, [rlen]  ; ebx = k = rlen - 1
 mov al, [edx+edi]  ; al = data[i]
 xor al, [esi+ebx]  ; al = al xor res[k]
 mov ebp, eax  ; ebp = m

      .L2:
 cmp ebx, 0   ; if k <= 0 then
 jle .L6   ;   break the loop
 xor eax, eax  ; using carry flag to test ((m<>0) and (rspoly[k]<>0))
 mov ecx, [rspoly+4*ebx]
 cmp ebp, 1   ; set carry flag if m=0
 adc eax, 0   ; inc eax if m=0
 cmp ecx, 1                  ; set carry flag if rspoly[k]=0
 adc eax, 0   ; inc eax if rspoly[k]=0
 jnz @f

 mov eax, [logt+4*ebp]
 xor edx, edx  ; prepare edx for division
 add eax, [logt+4*ecx]
 idiv dword [logmod]
 mov eax, [alog+4*edx]
 xor al, [esi+ebx-1]
 jmp .L4

      @@:
 mov al, [esi+ebx-1]

      .L4:
 mov [esi+ebx], al
 dec ebx   ; Dec (k)
 jmp .L2

      .L6:
 xor eax, eax  ; using carry flag to test ((m<>0) and (rspoly[0]<>0))
 mov ecx, [rspoly]
 cmp ebp, 1
 adc eax, 0
 cmp ecx, 1
 adc eax, 0
 jnz @f

 mov eax, [logt+4*ebp]
 xor edx, edx  ; prepare edx for division
 add eax, [logt+4*ecx]
 idiv dword [logmod]
 mov eax, [alog+4*edx]
 jmp .L8

      @@:
 xor eax, eax
      .L8:
 mov [esi], al
 inc edi   ; Inc (i)
 jmp .L1

      .L9:
 popext
 ret


    bit:    ; al = char, edx = table
 pushext
 mov esi, edx  ; esi = table
 xor edx, edx  ; edx = i-1

      .L1:
 mov cl, byte [esi]  ; cl = vert
 xor ebx, ebx
 and cl, 1
 or bl, cl
 mov cl, byte [esi+2] ; cl = up
 shl bl, 1
 and cl, 1
 or bl, cl   ; 4 possible combinations of vert and up
 mov edi, [vu_case+4*ebx] ; select the right one from a table

 mov ebx, 1   ; bl = (Byte(c) and (1 shl i)) shr i
 mov ecx, edx
 shl bl, cl
 and bl, al
 shr bl, cl
 xor ebp, ebp

      .L4:    ; if i in [ ... ] then
 cmp dl, [edi+ebp]
 jnz @f
 xor bl, 1   ; flip the bit
      @@:
 inc ebp
 cmp ebp, 4   ; 4 entries in vu_xx tables
 jl .L4
 
 lea ecx, [edx+2]  ; ecx = edx + 2
 mov cx, word [esi+2*ecx] ; get position
 mov [qr_image+ecx-2], bl ; modify appropriate pixel in qr_image
 inc edx
 cmp edx, 8
 jl .L1

 popext
 ret
 

START:
    sub rsp, 8
        
    mov   rax , 141         ; Enable system font
    mov   rbx , 1
    mov   rcx , 1
    mov   rdx , 5 shl 32 + 5
    mov   r8  , 9 shl 32 + 12
    int   0x60

    call  draw_window       ; At first, draw the window

still:

    mov   rax , 10          ; Wait here for event
    int   0x60

    test  rax , 1           ; Window redraw
    jnz   window_event
    test  rax , 2           ; Keyboard press
    jnz   key_event
    test  rax , 4           ; Button press
    jnz   button_event

    jmp   still

window_event:

    call  draw_window
    jmp   still

key_event:

    mov   rax , 2          ; Read the key and ignore
    int   0x60

    jmp   still

button_event:

    mov   rax , 17
    int   0x60

    ; rax = status
    ; rbx = button id
    
    cmp   rbx , 11
    jne   no_textbox1
    mov   r14 , textbox1
    call  read_textbox
    jmp   still
  no_textbox1:    

    cmp   rbx , 0x10000001  ; Button - Close application
    jne   no_application_terminate_button
    add   rsp,8
    mov   rax , 0x200       ; Terminate process
    int   0x60
        
  no_application_terminate_button:

    cmp   rbx, 20
    jne   no_clickme
    call  generate_qr
    jmp   still
    
 no_clickme:
    ;cmp   rbx , 0x106       ; Menu - Close application
    ;jne   no_application_terminate_menu
    ;mov   rax , 0x200       ; Terminate process
    ;int   0x60
  no_application_terminate_menu:

    jmp   still

generate_qr:
    push  rax rbx rcx rdx rsi r9 r10 r8 r14
                 
   ;jmp .save_bmp

    mov   r14, textbox1
    movups xmm1,[r14+48]   ; SSE extension copy 16 bytes 
    lea   rsi, [string]
    movups [rsi],xmm1

    ;mov rbx, string
    ;mov rcx, 20
    ;mov rdx, 60
    ;xor rsi,rsi
    ;mov r9, 3*65535
    ;mov rax, 4
    ;int 0x60

    lea rsi,[qrdata]
    xorps xmm1,xmm1
    movups [rsi],xmm1
    movups [rsi+16],xmm1
    lea rsi,[qrecc]
    movups [rsi],xmm1
    
    mov ecx, 285
 call rs_init_gf
 mov ecx, 7
 mov edx, 0
 call rs_init_code

 mov [qrdata], 0x40  ; qrdata and qrecc are already zeroed
 mov [qrdata+1], 0xE0 ; = 14 shl 4
 xor ecx, ecx

      .init_qrdata:
 mov al, byte [string+ecx]
 cmp al, 0
 jz .encode
 mov dl, al
 shr al, 4
 shl dl, 4
 or byte [qrdata+ecx+1], al
 mov byte [qrdata+ecx+2], dl
  inc ecx
 jmp .init_qrdata

      .encode:
 mov ecx, 19
 mov edx, qrdata
 mov eax, qrecc
 call rs_encode

      .bit_length: 
 mov al, 14
 mov edx, qr_tbl00
 call bit

 xor eax, eax
 
      .bit_string:
 mov [rsp], eax
 mov ecx, eax
 imul eax, 2*10
 lea edx, [qr_tbl01+eax]
 mov al, [string+ecx]
 call bit
 mov eax, [rsp]
 inc eax
 cmp eax, 14
 jl .bit_string

 mov eax, 6 
      .bit_ecc:
 mov [rsp], eax
 mov ecx, eax
 imul eax, 2*10
 lea edx, [qr_tble0+eax]
 mov al, [qrecc+ecx]
 call bit
 mov eax, [rsp]
 dec eax
 jns .bit_ecc
 
      .save_bmp:
    
MAG = 5         ; 500% magnification

    xor r9, r9          ; r9 = y
    xor r10, r10        ; r10 = x
    mov r8, qr_image
redo:
    mov  rcx, r9
    imul rcx, 24
    add  rcx, r10
    cmp byte [r8+rcx], 1
    jnz is_white
    mov rdx, 0x000000
    jmp show_pixel 
is_white:
    mov rdx, 0xFFFFFF
show_pixel:
    push r9
    push r10
    imul r9, MAG
    imul r10, MAG
    xor  rbx, rbx
    xor  rcx, rcx
c2:
    push rbx
    push rcx
    push rdx
    add rbx, r10        ; rbx = x
    add rcx, r9         ; rcx = y
    add rbx, 20
    add rcx, 80
    mov rax, 1
    int 0x60            ; must keep r8, r9 and r10
    pop rdx
    pop rcx
    pop rbx
    inc rbx
    cmp rbx, MAG
    jb  c2
    inc rcx
    xor rbx, rbx
    cmp rcx, MAG
    jb  c2
c1:
    pop r10
    pop r9
    inc r10
    cmp r10, 24
    jb  redo
    xor r10, r10
    inc r9
    cmp r9, 23
    jb  redo    
    


;      7 - Display image
;         In : rbx - X start shl 32 & x size
;              rcx - Y start shl 32 & y size
;              rdx - Pointer to first pixel (rrggbb) to display
;              r8  - Scanline difference (0 for continuous picture data)
;              r9  - Transparency color (0x1000000 for no transparency)
;              r10 - Pixel alignment (3 for RRggbbRRggbb)
;         Out: -

  ;  mov   rax, 7        ; Display image
  ;  mov   rbx , 20 shl 32 + 24     ; X start & size
  ;  mov   rcx , 70 shl 32 + 23     ; Y start & size
  ;  mov   rdx , qr_image
  ;  xor   r8, r8
  ;  mov   r9, 0x1000000
  ;  mov   r10, 3    
  ;  int   0x60

    pop   r14 r8 r10 r9 rsi rdx rcx rbx rax

    ret

draw_window:    

    mov   rax , 12                           ; Beginning of window draw
    mov   rbx , 1
    int   0x60

    mov   rax , 0                            ; Draw window
    mov   rbx , 256 shl 32 + 300             ; X start & size
    mov   rcx , 128 shl 32 + 250             ; Y start & size
    mov   rdx , 0x4000000000FFFFFF           ; Type    & border color  (no resizing)
    mov   r8  , 0x0000000000000001           ; Flags (set as 1)
    mov   r9  , window_label                 ; 0 or label - asciiz
    mov   r10 , 0                            ; 0 or pointer to menu struct
    int   0x60

    ;mov   rax , 4                            ; Display text
    ;mov   rbx , text                         ; Pointer to text
    ;mov   rcx , 32                           ; X position
    ;mov   rdx , 64                           ; Y position
    ;mov   rsi , 0x000000                     ; Color
    ;mov   r9  , 1                            ; Font
    ;int   0x60

    ; Define button

    mov   rax , 8
    mov   rbx , 180 shl 32 + 65              ; X start & size
    mov   rcx , 40 shl 32 + 20               ; Y start & size
    mov   rdx , 20  
    mov   r8  , 0
    mov   r9  , button_text
    int   0x60

    mov   r14 , textbox1
    call  draw_textbox

    mov   rax , 12                           ; End of window draw
    mov   rbx , 2
    int   0x60

    ret

; Data area

window_label:

    db    'QR CODE GENERATOR',0     ; Window label
    
textbox1:

    dq    0x40000   ; Type0
                    ; bit 16 - clear at doubleclick
                    ; bit 17 - set edit position according to mouse
                    ; bit 18 - enable utf8 (max 4 byte/char)
    dq    20        ; X position
    dq    140       ; X size
    dq    40        ; Y position
    dq    11        ; Button ID
    dq    0         ; Current text length
    db    'Hello World !',0   
    times 82 db 0   ; Text    
    
button_text:               ; Button text

    db    'Generate',0
    
  logmod   dd 0
  rlen     dd 0

  string   rb 16
  times    16-($-string) db 0  ; fill the rest of the string with null bytes

  image    db 'qrcli.bmp',0

  vu_case  dd vu_ff, vu_ft, vu_tf, vu_tt
  vu_tt    db 2,3,6,7
  vu_tf    db 0,1,4,5
  vu_ft    db 2,3,4,5
  vu_ff    db 0,1,6,7

  qr_tbl00 dw  1,  1, 24*17-2, 24*17-1, 24*18-2, 24*18-1, 24*19-2, 24*19-1, 24*20-2, 24*20-1
  qr_tbl01 dw  1,  1, 24*13-2, 24*13-1, 24*14-2, 24*14-1, 24*15-2, 24*15-1, 24*16-2, 24*16-1
  qr_tbl02 dw 0, 0, 24*12-4, 24*12-3, 24*11-4, 24*11-3, 24*11-2, 24*11-1, 24*12-2, 24*12-1
  qr_tbl03 dw  1, 0, 24*16-4, 24*16-3, 24*15-4, 24*15-3, 24*14-4, 24*14-3, 24*13-4, 24*13-3
  qr_tbl04 dw  1, 0, 24*20-4, 24*20-3, 24*19-4, 24*19-3, 24*18-4, 24*18-3, 24*17-4, 24*17-3
  qr_tbl05 dw 0,  1, 24*21-6, 24*21-5, 24*22-6, 24*22-5, 24*22-4, 24*22-3, 24*21-4, 24*21-3
  qr_tbl06 dw  1,  1, 24*17-6, 24*17-5, 24*18-6, 24*18-5, 24*19-6, 24*19-5, 24*20-6, 24*20-5
  qr_tbl07 dw  1,  1, 24*13-6, 24*13-5, 24*14-6, 24*14-5, 24*15-6, 24*15-5, 24*16-6, 24*16-5
  qr_tbl08 dw 0, 0, 24*12-8, 24*12-7, 24*11-8, 24*11-7, 24*11-6, 24*11-5, 24*12-6, 24*12-5
  qr_tbl09 dw  1, 0, 24*16-8, 24*16-7, 24*15-8, 24*15-7, 24*14-8, 24*14-7, 24*13-8, 24*13-7
  qr_tbl10 dw  1, 0, 24*20-8, 24*20-7, 24*19-8, 24*19-7, 24*18-8, 24*18-7, 24*17-8, 24*17-7
  qr_tbl11 dw 0,  1, 24*21-10, 24*21-9, 24*22-10, 24*22-9, 24*22-8, 24*22-7, 24*21-8, 24*21-7
  qr_tbl12 dw  1,  1, 24*17-10, 24*17-9, 24*18-10, 24*18-9, 24*19-10, 24*19-9, 24*20-10, 24*20-9
  qr_tbl13 dw  1,  1, 24*13-10, 24*13-9, 24*14-10, 24*14-9, 24*15-10, 24*15-9, 24*16-10, 24*16-9
  qr_tbl14 dw  1,  1, 24*9-10, 24*9-9, 24*10-10, 24*10-9, 24*11-10, 24*11-9, 24*12-10, 24*12-9
  qr_tble0 dw  1, 0, 24*14-21, 24*14-20, 24*13-21, 24*13-20, 24*12-21, 24*12-20, 24*11-21, 24*11-20
  qr_tble1 dw  1,  1, 24*11-19, 24*11-18, 24*12-19, 24*12-18, 24*13-19, 24*13-18, 24*14-19, 24*14-18
  qr_tble2 dw  1, 0, 24*14-17, 24*14-16, 24*13-17, 24*13-16, 24*12-17, 24*12-16, 24*11-17, 24*11-16
  qr_tble3 dw  1,  1, 24*11-14, 24*11-13, 24*12-14, 24*12-13, 24*13-14, 24*13-13, 24*14-14, 24*14-13
  qr_tble4 dw  1, 0, 24*22-12, 24*22-11, 24*21-12, 24*21-11, 24*20-12, 24*20-11, 24*19-12, 24*19-11
  qr_tble5 dw  1, 0, 24*18-12, 24*18-11, 24*17-12, 24*17-11, 24*16-12, 24*16-11, 24*15-12, 24*15-11
  qr_tble6 dw  1, 0, 24*14-12, 24*14-11, 24*13-12, 24*13-11, 24*12-12, 24*12-11, 24*11-12, 24*11-11

  qr_bmp db 'BM'  ; bmp header
  dd size_qr_bmp
  dd 0
  dd 14+40+4*256
  dd 40
  dd 23  ; image width
  dd -23  ; image height is negative in order to draw the image from top to bottom
  dw 1
  dw 8  ; 8 bits per pixel
  dd 0
  dd 24*23
  dd 0
  dd 0
  dd 2
  dd 2
  ; palette entries
  db 0xFF, 0xFF, 0xFF, 0x00 ; white
  db 0x00, 0x00, 0x00, 0x00 ; green --> black  ***** Modifed *****
  times 254 dd 0

  ; in fact the image is 24x23 pixels, because bmp format requires padding
  qr_image      db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
     0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,\
     0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,\
     0,1,0,1,1,1,0,1,0,0,1,1,1,1,0,1,0,1,1,1,0,1,0,0,\
     0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,0,\
     0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,0,\
     0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,\
     0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,0,\
     0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
     0,1,1,1,0,0,1,1,0,1,1,1,0,0,1,1,1,1,0,0,1,1,0,0,\
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
     0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
     0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
     0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
     0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
     0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
     0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
     0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
     0,1,0,1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
     0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
     0,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,\
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

  size_qr_bmp = $ - qr_bmp 

  alog     rd 512  ; reserve 2 KB
  logt    rd 512
  rspoly   rd 32
  qrdata   rb SIZE_QRDATA
  qrecc    rb SIZE_QRECC    
    
image_end:

