files
kolibrios/kernel/trunk/qrcode.inc

2153 lines
56 KiB
PHP

iglobal
places db 6,0,0,0,0,0,0
dark dd 0
lite dd 0ffffffH
unus dd 02H
ddat dd 01H
ldat dd 0fffffeH
resr dd 0fffffdH
endg
uglobal
version DD 1 DUP (?)
mode DD 1 DUP (?)
maxcodewords DD 1 DUP (?)
eclevel DD 1 DUP (?)
maskpattern DD 1 DUP (?)
size DD 1 DUP (?)
size2 DD 1 DUP (?)
genpoly DB 32 DUP (?)
versionstring DD 18 DUP (?)
formatstring DD 16 DUP (?)
message DB 154 DUP (?)
datcodewords DB 0e84H DUP (?)
ileaveddata DB 0e84H DUP (?)
matrix DD 31330 DUP (?)
endg
;system function 78: prepare QR code
;input: eax = 78
; ebx = pointer to payload data
; ecx = length of payload data
; edx = pointer to buffer at least (31330 * 3) bytes long
; to hold the QR code as a 24-bit RGB bitmap
;output: if QR code generation failed:
; eax = -1
; otherwise:
; eax = number of pixels per side of QR code
; bitmap is copied to buffer starting at [edx]
syscall_qrcode:
stdcall is_region_userspace, edx, 31330 * 3
jnz .error
push edx
push -1
push -1
push ecx
push ebx
call makeQR
cmp eax, -1
je .error
push eax
call reducematrix
mov eax, [esp]
imul eax, eax
imul eax, eax, 3
mov ecx, eax
mov esi, matrix
mov edi, [esp + 4]
rep movsb
pop eax
pop edx
mov [esp + SYSCALL_STACK.eax], eax
ret
.error:
mov [esp + SYSCALL_STACK.eax], -1
ret
DARK equ 0
CMSK equ 0FFFF00H
makeQR:
;input: 4 dwords in the stack
; top argument is pointer to input data
; 2nd argument is length of input data, as number of bytes
; 3rd argument indicates extended channel interpretation mode
; -1 - no ECI
; 22 - windows-1251
; 26 - utf8
; (see list of ECI indicators at the bottom of this file)
; note: there is no ECI indicator for code page 866
; 4th argument is not used currently
; planned to use it to indicate if negative
; (white on black) QR code is desired
;output: if QR code could not be made, eax = -1
; otherwise, eax = size of QR code, as number of pixels per side
; matrix variable contains QR code as RGBA bitmap
;---------local variable declarations----------
_ecwords EQU [ebp]
_bytechars1 EQU [ebp + 4]
_alphachars2 EQU [ebp + 8]
_numchars3 EQU [ebp + 12]
_leadalpha21 EQU [ebp + 16]
_totalblocks EQU [ebp + 20]
_g1b EQU [ebp + 24] ;number of group 1 blocks
_g1dc EQU [ebp + 28] ;data codewords per block
_g2b EQU [ebp + 32] ;number of group 2 blocks
_g2dc EQU [ebp + 36] ;data codewords per block
_wordssofar EQU [ebp + 40]
_requiredbitslength EQU [ebp + 44]
_charcountlength EQU [ebp + 48]
_thisblockwords10 EQU [ebp + 52]
_thisblock12 EQU [ebp + 56] ;block counter
_unusedbits EQU [ebp + 60]
_ord20 EQU [ebp + 64] ;polynomial division cycle counter
;caller's ebp here 68
;return address here 72
_theinput EQU [ebp + 76] ;address of input data
_theinputlength EQU [ebp + 80]
_theecimode EQU [ebp + 84]
_makenegative EQU [ebp + 88] ;not used
;---------end of local variable declarations----------
EBPNUMBER EQU 68
push ebp
lea ebp, dword [esp - EBPNUMBER]
sub esp, EBPNUMBER - 4
push esi
and dword _requiredbitslength, 0
;return -1 if input length is more than absolute maximum
or eax, - 1
cmp dword _theinputlength, 7089
ja makeQR_end
;------------------
;figure out if input is numeric, alphanumeric, or
;binary, and set [mode] variable accordingly
and dword [mode], 0
mov ebx, dword _theinputlength
dec ebx
cld
mov esi, dword _theinput
findmodeloop:
lodsb
push eax
call alphaindex
cmp eax, 9
jle @f
mov dword [mode], 1
cmp eax, 46
jl @f
mov dword [mode], 2
jmp findmodeloopend
@@:
dec ebx
jns findmodeloop
findmodeloopend:
;------------------
;backslashes (\) need escaping in QR code,
;so they count double towards input length
cmp dword _theecimode, -1
je countslashloopend
mov ebx, dword _theinputlength
cld
mov esi, dword _theinput
countslashloop:
lodsb
cmp al, 92
jne @f
inc dword _theinputlength
@@:
dec ebx
jns countslashloop
countslashloopend:
;------------------
;return -1 if mode is 1 or 2 and input
;length is more than respective maxima
or eax, -1
cmp dword [mode], 1
jne @f
cmp dword _theinputlength, 4296
ja makeQR_end
@@:
cmp dword [mode], 2
jne @f
cmp dword _theinputlength, 2953
ja makeQR_end
@@:
;------------------
and dword _unusedbits, 0
and dword _charcountlength, 0
mov dword [version], 1
findversionloop:
mov dword [eclevel], 3
findeclevelloop:
mov eax, dword [version]
;same as eax = 21 + (version - 1) * 4
lea eax, dword [eax * 4 + 17]
mov dword [size], eax
imul eax, eax
mov dword [size2], eax
;fill matrix with unused pixels
mov ecx, eax ; 31330
mov eax, dword [unus]
mov edi, matrix
cld
rep stosd
;--------------
call reserveareas
call drawversion
call drawfinders
call drawtiming
call drawalign
call drawdarkmodule
;--------------
;count unused pixels in matrix; these are
;the pixels which will carry input and EC data
xor ecx, ecx
mov eax, dword [size2]
countunusedloop:
mov ebx, dword [matrix + eax * 4]
cmp ebx, dword [unus]
jne @f
inc ecx
@@:
dec eax
jns countunusedloop
mov dword _unusedbits, ecx
;-------------
;mov ecx, dword _unusedbits
shr ecx, 3
mov dword [maxcodewords], ecx
call getcharcountlength
movzx eax, al
mov dword _charcountlength, eax
call numdatacodewords
movzx eax, ax
shl eax, 3
mov dword _requiredbitslength, eax
;-------------
;begin computing capacity of current QR code
;mov ebx, dword _requiredbitslength
mov ebx, eax
sub ebx, 4
cmp dword _theecimode, -1
je @f
sub ebx, 12
@@:
sub ebx, dword _charcountlength
;mov dword _avail ableb its5, ebx
push ebx
mov eax, ebx
add eax, ebx
add eax, ebx
cdq
mov ecx, 10
idiv ecx
;calculated maximum number of characters this
;QR code can contain, if it is numeric
mov dword _numchars3, eax
mov eax, [esp]
add eax, eax
cdq
mov ecx, 11
idiv ecx
;calculated maximum number of characters this
;QR code can contain, if it is alphanumeric
mov dword _alphachars2, eax
pop eax
sar eax, 3
;calculated maximum number of bytes this
;QR code can contain, if it is binary
mov dword _bytechars1, eax
;it is possible to pre compute and look up the
;three previous results, which only depend on
;version and error correction level, however I
;prefer to calculate them explicitly
;break out of the loop if current version and
;EC level are sufficient to contain the input
cmp dword [mode], 0
jne @f
mov eax, dword _numchars3
cmp eax, dword _theinputlength
jge Loopfinished
@@:
cmp dword [mode], 1
jne @f
mov eax, dword _alphachars2
cmp eax, dword _theinputlength
jge Loopfinished
@@:
cmp dword [mode], 2
jne @f
mov eax, dword _bytechars1
cmp eax, dword _theinputlength
jge Loopfinished
@@:
dec dword [eclevel]
cmp dword [eclevel], 0
jnl findeclevelloop
inc dword [version]
cmp dword [version], 40
jng findversionloop
Loopfinished:
;--------------
;return -1 if version is greater than 40, which is
;the maximum for QR codes
;this should never happen, because of the prior checks
;regarding input length
or eax, - 1
cmp dword [version], 40
ja makeQR_end
;--------------
;reset data structures in case
;they have been used previously
cld
mov ecx, 5 ; 929
xor eax, eax
mov edi, datcodewords
rep stosd
mov ecx, 5 ; 929
mov edi, ileaveddata
rep stosd
;---------------
;add ECI mode indicator if necessary
;see page 24 of ISO/IEC 18004:2015
cmp dword _theecimode, 999999
jng @f
mov dword _theecimode, -1
@@:
cmp dword _theecimode, -1
je eciskip
push dword 4
push dword 7
push datcodewords
call appendtobitset
mov eax, dword _theecimode
cmp eax, 127
jg @f
push 8
and eax, 127
jmp addeci
@@:
cmp eax, 16383
jg @f
push 16
and eax, 16383
or eax, 32768
jmp addeci
@@:
push 24
and eax, 2097151
or eax, 12582912
addeci:
push eax
push datcodewords
call appendtobitset
eciskip:
;-----------------
;add mode indicator
mov eax, dword [mode]
movzx eax, byte [modeindicators + eax]
push 4
push eax
push datcodewords
call appendtobitset
;add length-of-input marker
push dword _charcountlength
push dword _theinputlength
push datcodewords
call appendtobitset
;-------------------
;prepare registers for data acquisition
cld
mov esi, dword _theinput
mov edi, esi
add edi, dword _theinputlength
;-------------------
;mode 0: acquire numeric data
cmp dword [mode], 0
jne mode0loopend
;cld
;mov esi, dword _theinput
;mov edi, esi
;add edi, dword _theinputlength
mode0loop:
mov ebx, edi
sub ebx, esi
lodsb
sub al, 48
cmp ebx, 1
jne @f
push 4
jmp mode0next
@@:
cmp ebx, 2
jne @f
imul eax, eax, 10
mov ebx, eax
lodsb
sub al, 48
add eax, ebx
push 7
jmp mode0next
@@:
cmp ebx, 3
jl mode0next
imul eax, eax, 100
mov ebx, eax
lodsb
sub al, 48
imul eax, eax, 10
add ebx,eax
lodsb
sub al, 48
add eax, ebx
push 10
mode0next:
push eax
push datcodewords
call appendtobitset
cmp esi, edi
jnge mode0loop
mode0loopend:
;-------------------
;mode 1: acquire alphanumeric data
cmp dword [mode], 1
jne skipmode1
;cld
;mov esi, dword _theinput
;mov edi, esi
;add edi, dword _theinputlength
mode1loop:
mov ebx, edi
sub ebx, esi
lodsb
push eax
call alphaindex
cmp ebx, 2
jnae @f
imul eax, 45
mov edx, eax
lodsb
push eax
call alphaindex
add eax, edx
push dword 11
jmp mode1next
@@:
push dword 6
mode1next:
push eax
push dword datcodewords
call appendtobitset
cmp esi, edi
jb mode1loop
skipmode1:
;-------------------
;mode 2: acquire binary data
cmp dword [mode], 2
jne skipmode2
;cld
;mov esi, dword _theinput
;mov edi, esi
;add edi, dword _theinputlength
mode2loop:
lodsb
push dword 8
push eax
push datcodewords
;if ECI mode is not default and input contains a
;backslash, escape it in the QR code by doubling it up
cmp dword _theecimode, -1
je @f
cmp eax, 92
jne @f
push dword 8
push eax
push dword datcodewords
call appendtobitset
@@:
call appendtobitset
cmp esi, edi
jb mode2loop
skipmode2:
;----------------
;if number of payload bits so far is less than capacity,
;!!! append four 0s to terminate !!! (emphasis intentional)
;or append 0s up to full capacity, whichever happens first
mov eax, dword _requiredbitslength
sub eax, dword [datcodewords + 4]
cmp eax, 4
jle @f
mov al, 4
@@:
push eax
push 0
push datcodewords
call appendtobitset
;if number of payload bits so far is not multiple of 8,
;append 0s until it is
mov al, 8
sub al, byte [datcodewords + 8]
and eax, 7
jz @f
push eax
push 0
push datcodewords
call appendtobitset
@@:
;-------------
;add repeating padding {236, 17} if necessary to fill capacity
mov esi, 236
mov edi, 17
push ebp
mov ebp, dword _requiredbitslength
sar ebp, 3
sub ebp, dword [datcodewords]
paddingloop:
cmp ebp, 0
jng paddingloopend
push 8
push esi
push datcodewords
call appendtobitset
xchg esi, edi
dec ebp
jmp paddingloop
paddingloopend:
pop ebp
;---------------------
;prepare some local variables
call numblocksingroup2; movzx eax, al
mov dword _g2b, eax
call numblocksingroup1; movzx eax, al
mov dword _g1b, eax
mov eax, dword _g1b
add eax, dword _g2b
mov dword _totalblocks, eax
call group1datacodewords; movzx eax, al
mov dword _g1dc, eax
call group2datacodewords; movzx eax, al
mov dword _g2dc, eax
call eccodewordsperblock
mov dword _ecwords, eax
and dword _wordssofar, 0
push dword _ecwords
call makeECgenerator
and dword _thisblock12, 0
processblockloop:
mov ebx, dword _g1dc
mov eax, dword _thisblock12
cmp eax, dword _g1b
jl @f
mov ebx, dword _g2dc
@@:
;determined how many codewords this block must contain
mov dword _thisblockwords10, ebx
;clear the array that is used to
;calculate error correction codewords
cld
mov ecx, 76 ; 154
xor eax, eax
mov edi, message
rep stosw
;copy this block's data to the array in reverse order
;with leading 0s required for next computation
mov edi, message
add edi, dword _ecwords
mov ecx, dword _thisblockwords10
mov esi, datcodewords + 9
add esi, dword _wordssofar
;also increase the counter of codewords processed so far
add dword _wordssofar, ecx
dec ecx
add esi, ecx
@@:
movsb
dec esi
dec esi
dec ecx
jns @b
;----------------
mov eax, dword _thisblockwords10
mov ecx, dword _ecwords
lea eax, dword [ecx + eax - 1]
mov dword _ord20, eax
errorcorrectionloop:
mov eax, dword _ord20
movzx eax, byte [message + eax]
test eax, eax
;if lead exponent is 0, skip this polynomial division cycle
jz errorcorrectionnext
;calculate lead value for this polynomial division cycle
mov eax, dword _ord20
movzx eax, byte [message + eax]
mov al, byte [mod285antilogs + eax]
mov byte _leadalpha21, al
;perform one cycle of dividing this block's codewords by the
;EC generator polynomial, using Galois Field 256 arithmetic
mov ecx, dword _ord20
mov edi, dword _ecwords
sub ecx, edi
polydivisionloop:
movzx eax, byte [genpoly + edi]
movzx edx, byte _leadalpha21
add eax, edx
cdq
mov esi, 255
idiv esi
movzx eax, byte [mod285logs + edx]
mov edx, edi
movzx ebx, byte [message + edx + ecx]
xor ebx, eax
mov byte [message + edi + ecx], bl
dec edi
jns polydivisionloop
;------------------
errorcorrectionnext:
dec dword _ord20
mov eax, dword _ord20
cmp eax, dword _ecwords
jnl errorcorrectionloop
;store error correction data
mov edi, dword _ecwords
mov esi, dword message
dec edi
add esi, edi
std
@@:
lodsb
push 8
push eax
push datcodewords
call appendtobitset
dec edi
jns @b
cld
;------------
inc dword _thisblock12
mov eax, dword _thisblock12
cmp eax, dword _totalblocks
jnge processblockloop
;------------
;interleave data
xor esi, esi
ileavegroup1loop:
xor edi, edi
ileavegroup1_innerloop:
mov ecx, edi
sub ecx, dword _g1b
cmp edi, dword _g1b
jnle @f
xor ecx, ecx
@@:
mov eax, edi
imul eax, dword _g1dc
add eax, esi
movzx eax, byte [datcodewords + eax + ecx + 9]
push 8
push eax
push ileaveddata
call appendtobitset
inc edi
cmp edi, dword _totalblocks
jnge ileavegroup1_innerloop
inc esi
cmp esi, dword _g1dc
jnge ileavegroup1loop
cmp dword _g2dc, 0
jle skipgroup2
;interleave data from group 2
mov esi, 1
group2loop:
mov ecx, esi
mov eax, dword _g1dc
imul eax, dword _g1b
imul ecx, dword _g2dc
movzx eax, byte [datcodewords + eax + ecx + 8]
push 8
push eax
push ileaveddata
call appendtobitset
inc esi
cmp esi, dword _g2b
jng group2loop
skipgroup2:
;interleave error correction data
mov eax, dword _g1b
mov ecx, dword _g2b
imul eax, dword _g1dc
imul ecx, dword _g2dc
add eax, ecx
push eax; startecwords
call eccodewordsperblock
push eax; bk
push 0; n
push 0; i
ix EQU dword [esp]
jx EQU dword [esp + 4]
bk EQU [esp + 8]
startecwords EQU [esp + 12]
ileaveloop2:
mov ix, 0
ileaveloop1:
xor edx,edx
mov eax, ix
imul dword bk
add eax, startecwords
mov ecx, jx
movzx eax, byte [datcodewords + 9 + eax + ecx]
push 8
push eax
push ileaveddata
call appendtobitset
inc ix
mov eax, ix
cmp eax, dword _totalblocks
jnge ileaveloop1
inc jx
mov eax, jx
cmp eax, bk
jnge ileaveloop2
sub esp, 16 ; discard last 4 local variables
;------------------
;if there are any unused pixels left over,
;fill the corresponding data with 0s
mov eax, dword _unusedbits
sub eax, dword [ileaveddata + 4]
cmp eax, 0
jle @f
push dword eax
push dword 0
push ileaveddata
call appendtobitset
@@:
;-----------------
;draw interleaved data,
;find which mask pattern minimizes penalty score,
;apply mask,
;return size of QR code
call drawdata
call minimalpenaltymask
mov dword [maskpattern], eax
push dword eax
call mask
mov eax, dword [size]
makeQR_end:
pop esi
add ebp, EBPNUMBER
leave
ret 16
drawdata:
;input: nothing
;output: matrix is modified
col EQU edx
row EQU ebx
ix EQU ecx
godown EQU edi
oddcol EQU ebp
push ebp
xor godown, godown
xor ix, ix
mov col, dword [size]
dec col
mov row, col
drawdataloop:
mov eax, row
mul byte [size]
add eax, col
mov esi, dword [matrix + eax * 4]
cmp esi, dword [unus]
jne skipdraw
push ebx
push ecx
push eax
mov eax, ix
call getdrawbit
pop ecx
mov dword [matrix + ecx * 4], eax
pop ecx
pop ebx
inc ix
skipdraw:
mov oddcol,col
and oddcol,1
cmp col, 6
jge @f
xor oddcol, 1
@@:
cmp oddcol, 1
je isoddcol
dec col
jmp testrow0
isoddcol:
inc col
and godown, 1
jz @f
inc row
jmp testrow0
@@:
dec row
testrow0:
cmp row, 0
jge testrowsize
or godown, 1
xor row, row
cmp col, 8
jne @f
dec col
@@:
dec col
dec col
testrowsize:
cmp row, dword [size]
jnae drawdataloopend
xor godown, godown
mov row, dword [size]
dec row
dec col
dec col
cmp col, 5
jne @f
dec col
@@:
cmp col, 6
jne drawdataloopend
dec col
dec col
drawdataloopend:
cmp ix, dword [datcodewords + 4]
jnae drawdataloop
pop ebp
ret
mask:
;input: eax = mask type
;output: matrix is modified
pop ecx
pop eax
push ecx
;remove the above to change calling convention
col EQU ecx
row EQU edx
push eax
push 0
push eax
call drawformat
xor col, col
maskloopcol:
xor row, row
masklooprow:
mov eax, row
mul cl
push eax ;save result: row * column
push edx
cdq
mov ebx, 3
idiv ebx
mov eax, edx
pop edx
push eax; save result: (row * column) mod 3
mov eax, dword [esp + 12]
cmp al, 7
jg @f
jmp dword [maskbjumps + eax * 4]
@@:
pop ebx
jmp endmasks
bmask0:
mov ebx, row
add ebx, col
and bl, 1
xor ebx, 1
jmp bmaskdone
bmask1:
mov ebx, row
and bl, 1
xor ebx, 1
jmp bmaskdone
bmask2:
mov eax, col
mov bl, 3
div bl
xor ebx, ebx
cmp ah, 0
setz bl
jmp bmaskdone
bmask3:
mov eax, col
add eax, row
mov bl, 3
div bl
xor ebx, ebx
cmp ah, 0
setz bl
jmp bmaskdone
bmask4:
mov eax, col
mov ebx, 3
div bl
mov ebx, row
shr ebx, 1
add bl, al
and bl, 1
xor ebx, 1
jmp bmaskdone
bmask5:
mov eax, dword [esp]
mov ebx, dword [esp+4]
and ebx, 1
add ebx, eax
setz bl
jmp bmaskdone
bmask6:
mov eax, dword [esp]
mov ebx, dword [esp+4]
and ebx, 1
add ebx, eax
and ebx, 1
setz bl
jmp bmaskdone
bmask7:
mov eax, dword [esp]
mov ebx, row
add ebx, col
and ebx, 1
add ebx, eax
and ebx, 1
setz bl
bmaskdone:
pop eax ;discard result
pop eax ;discard result
mov dword [esp], ebx
mov eax, row
imul byte [size]
add eax, col
mov ebx, eax
mov eax, dword [matrix + ebx * 4]
cmp eax, dword [unus]
jne @f
mov eax, dword [ldat]
@@:
and dword [esp], 1
jz endflip
cmp eax, dword [ddat]
jne @f
mov eax, dword [ldat]
jmp endflip
@@:
cmp eax, dword [ldat]
jne endflip
mov eax, dword [ddat]
endflip:
mov dword [matrix + ebx * 4], eax
inc row
cmp row, dword [size]
jnge masklooprow
inc col
cmp col, dword [size]
jnge maskloopcol
endmasks:
pop eax
pop eax
ret
maskbjumps:
dd bmask0
dd bmask1
dd bmask2
dd bmask3
dd bmask4
dd bmask5
dd bmask6
dd bmask7
getratiopenalty:
;input: nothing
;output: eax = penalty score from B/W ratio of QR code
darks EQU ebx
xor darks, darks
mov ecx, dword [size2]
countdarksloop:
mov eax, dword [matrix + ix * 4]
and eax, CMSK
jnz @f
inc darks
@@:
dec ecx
jns countdarksloop
imul eax, darks, 100
mov ecx, DWORD [size2]
cdq
idiv ecx
sub eax, 50
jns @f
neg eax
@@:
xor ecx, ecx
cmp eax, 5
jle @f
ratioloop:
inc ecx
sub eax, 5
cmp eax, 5
jg ratioloop
@@:
imul eax, ecx, 10
ret
gettotalpenalty:
;input: nothing
;output: eax = total penalty score of QR code
call getblockpenalty
push eax
call getstraightpenalty
push eax
call getsequencepenalty
push eax
call getratiopenalty
pop ebx
add eax, ebx
pop ebx
add eax, ebx
pop ebx
add eax, ebx
ret
getsequencepenalty:
;input: nothing
;output: eax = penalty score for rule 3 of current QR code
ix EQU ebx
penalty EQU esi
col EQU dword [esp]
row EQU dword [esp + 4]
xor penalty, penalty
push 0
push 0
seqloopA:
mov col, 10
seqloopB:
xor edi, edi
xor ix, ix
seqloopC:
mov eax, col
sub eax, ix
mov ecx, row
imul ecx, dword [size]
add eax, ecx
mov eax, dword [matrix + eax * 4]
and eax, CMSK
cmp eax, dword [sequence + ix * 4]
jne @f
inc edi
@@:
cmp eax, dword [sequence + ix * 4 + 16]
jne @f
add edi, 16
@@:
mov eax, col
sub eax, ix
imul eax, dword [size]
add eax, row
mov eax, dword [matrix + eax * 4]
and eax, CMSK
cmp eax, dword [sequence + ix * 4]
jne @f
add edi, 256
@@:
cmp eax, dword [sequence + ix * 4 + 16]
jne @f
add edi, 4096
@@:
inc ix
cmp ix, 10
jng seqloopC
push ecx
xor ecx, ecx
incpenaltyloop:
mov eax, edi
shr eax, cl
and eax, 15
cmp eax, 11
jl @f
inc penalty
@@:
add cl, 4
cmp cl, 12
jle incpenaltyloop
pop ecx
inc col
mov eax, col
cmp eax, dword [size]
jnge seqloopB
inc row
mov eax, row
cmp eax, dword [size]
jnge seqloopA
pop eax
pop eax
imul eax, penalty, 40
ret
minimalpenaltymask:
;input: nothing
;output: al = number of mask pattern that minimizes
; penalty score for current QR code
mov ecx,0
sub esp, 8
mpmloop:
push ecx
mov eax, ecx
push eax
call mask
call gettotalpenalty
pop ecx
cmp ecx, 0
jne @f
mov dword [esp], ecx
mov dword [esp + 4], eax
@@:
mov edx, dword [esp + 4]
cmp eax, edx
jge @f
mov dword [esp + 4], eax
mov dword [esp], ecx
@@:
push ecx
mov eax, ecx
push eax
call mask
pop ecx
inc ecx
cmp ecx, 8
jl mpmloop
pop eax
pop edx
ret
reserveareas:
;input: nothing
;output: some parts of matrix are marked as reserved
; so the data drawing algorithm will skip them
push dword [resr]
push 9
push 0
push 0
call fillbox
push dword [resr]
push 8
mov eax, dword [size]
sub eax, 8
push eax
push 1
call fillbox
push dword [resr]
push 8
push 1
mov eax, dword [size]
sub eax, 8
push eax
call fillbox
cmp dword [version], 7
jl @f
push dword [resr]
push 3
mov eax, dword [size]
sub eax, 11
push eax
push 0
call fillbox
push dword [resr]
push 3
mov eax, dword [size]
sub eax, 11
push eax
push 3
call fillbox
push dword [resr]
push 3
push 0
mov eax, dword [size]
sub eax, 11
push eax
call fillbox
push dword [resr]
push 3
push 3
mov eax, dword [size]
sub eax, 11
push eax
call fillbox
@@:
ret
drawformat:
;input: eax = type of mask
;output: formatstring array is modified
; format info is drawn in matrix
;uses eax ebx ecx edx esi
pop ecx
pop eax
push ecx
ix EQU ecx
xor ix, ix
mov ebx, dword [eclevel]
shl ebx, 3
add eax, ebx
dfloop1:
mov ebx, 1
shl ebx, cl
movzx edx, word [formatstrings + eax * 2]
mov esi, dword [dark]
and ebx, edx
jnz @f
mov esi, dword [lite]
@@:
mov ebx, 14
sub ebx, ix
mov dword [formatstring + ebx * 4], esi
inc ix
cmp ix, 14
jle dfloop1
row EQU edx
xor ix, ix
mov row, dword [size]
dfloop2:
dec row
mov eax, row
imul byte [size]
mov ebx, dword [formatstring + ix * 4]
inc ix
mov dword [matrix + 32 + eax * 4], ebx
cmp row, 7
jne @f
dec row
@@:
mov ebx, dword [size]
sub ebx, 7
cmp row, ebx
jne @f
mov row, 9
@@:
cmp row, 0
jge dfloop2
col EQU edx
xor ix, ix
xor col, col
mov eax, dword [size]
shl eax, 5
dfloop3:
mov ebx, dword [formatstring + ix * 4]
inc ix
mov dword [matrix + eax + col * 4], ebx
cmp col, 5
jne @f
inc col
@@:
cmp col, 7
jne @f
mov col, dword [size]
sub col, 9
@@:
inc col
cmp col, dword [size]
jnge dfloop3
ret
drawtiming:
;input: nothing
;output: timing pattern is drawn in matrix
mov eax, 8
mov ebx, dword [size]
mov esi, ebx
sub ebx, eax
dtloop:
mov ecx, dword [dark]
test eax, 1
jz @f
mov ecx, dword [lite]
@@:
mov edx, 6
imul edx, esi
add edx, eax
mov [matrix + edx * 4], ecx
mov edx, eax
imul edx, esi
add edx, 6
mov [matrix + edx * 4], ecx
inc eax
cmp eax, ebx
jl dtloop
ret
fillbox:
;input: 4 dwords in the stack: startx, starty, boxsize, content
;output: a filled box is drawn in matrix
pop esi; return address
pop edi
pop eax
pop ecx
pop edx
push esi; save return address
push ebp; save previous base pointer
mov ebp, edi
shl ebp, 2
mov esi, eax
add edi, ecx
shl edi, 2
add esi, ecx
movzx ecx, byte [size]
mul cl
imul esi, ecx
fbloop:
mov ebx, ebp
@@:
mov [matrix + ebx + eax * 4], edx
add ebx, 4
cmp edi, ebx
jg @b
add eax, ecx
cmp esi, eax
jg fbloop
pop ebp; restore previous base pointer
ret
numblocksingroup2:
;input: nothing
;output: eax = number of blocks in group 2 of QR code
mov edx, 2
jmp lbt
group1datacodewords:
;input: nothing
;output: eax = number of data codewords in group 1 of QR code
mov edx, 1
jmp lbt
numblocksingroup1:
;input: nothing
;output: eax = number of blocks in group 1 of QR code
mov edx, 0
lbt:
mov eax, dword [version]
dec eax
imul eax, eax, 12
imul ecx, dword [eclevel], 3
add eax, edx
movzx eax, byte [bigtable + ecx + eax]
ret
group2datacodewords:
;input: nothing
;output: eax = number of data codewords in group 2 of QR code
call numblocksingroup2
test eax, eax
jz @f
call group1datacodewords
inc eax
@@:
ret
eccodewordsperblock:
;input: nothing
;output: eax = number of EC codewords per block
call numdatacodewords
mov esi, DWORD [maxcodewords]
sub esi, eax
call numblocksingroup1
mov edi, eax
call numblocksingroup2
add edi, eax
mov eax, esi
cdq
idiv edi
ret
numdatacodewords:
;input: nothing
;output: eax = number of data codewords in QR code
call group1datacodewords
mov esi, eax
call numblocksingroup1
imul esi, eax
call group2datacodewords
mov edi, eax
call numblocksingroup2
imul edi, eax
add esi, edi
mov eax, esi
ret
alphaindex:
;input: al
;output: eax = index of input in alphamode table, or 46 if not found
pop ecx
pop eax
push ecx
xor ecx, ecx
@@:
cmp [alphamode + ecx], al
je @f
inc cl
cmp cl, 46
jl @b
@@:
mov eax, ecx
ret
mem7 db 7
drawalign:
;input: nothing
;output: alignment patterns (small squares) are drawn in matrix
mov eax, dword [version]
cmp al, 1
jle drawalign_end
push eax
shl al, 2
add al, 10
mov byte [places + 1], al
pop eax
mov ebx, eax
idiv byte [mem7]
and eax, 255
cmp al, 0
je startloop
cmp al, 1
jg case2
inc bl
jmp @f
case2:
cmp al, 2
jg case3
sub bl, 4
jmp @f
case3:
cmp al, 3
jg case4
sub bl, 10
@@:
shl bl, 1
jmp da_endcases
case4:
cmp al, 4
jg case5
sub bl, 28
jmp @f
case5:
sub bl, 34
@@:
mov bl, byte [diffs + ebx]
da_endcases:
mov ecx, 1
@@:
mov dl, byte [places + ecx]
sub dl, bl
mov byte [places + 1 + ecx], dl
inc ecx
cmp ecx, eax
jle @b
startloop:
xor ecx, ecx
da_loop1:
xor edx, edx
da_loop2:
cmp cl, 0
jne @f
cmp dl, 1
jle da_continue
@@:
cmp cl, 1
jne @f
cmp dl, 0
je da_continue
@@:
push edx
push ecx
push dword [dark]
push 1
movzx edx, byte [places + edx]
push edx
movzx ecx, byte [places + ecx]
push ecx
dec edx
dec ecx
push dword [lite]
push 3
push edx
push ecx
dec ecx
dec edx
push dword [dark]
push 5
push edx
push ecx
call fillbox
call fillbox
call fillbox
pop ecx
pop edx
da_continue:
inc dl
cmp dl, 7
jge @f
cmp byte [places + edx], 0
je @f
jmp da_loop2
@@:
inc cl
cmp cl, 7
jge @f
cmp byte [places + ecx], 0
je @f
jmp da_loop1
@@:
drawalign_end:
ret
drawdarkmodule:
;input: nothing
;output: fixed dark module is drawn in matrix
push dword [dark]
push dword 1
mov eax, dword [size]
sub eax, 8
push eax
push dword 8
call fillbox
ret
getcharcountlength:
;input: nothing
;output: eax = length of character count marker, in bits
mov eax, [mode]
xor ebx, ebx
cmp [version], 9
setg bl
cmp [version], 26
setg cl
add bl, cl
shl bl, 2
add ebx, charcountlengths
xlatb
ret
appendtobitset:
;input: ebx = pointer to bitset
; eax = data to add
; ecx = number of low-order bits from eax to add
;output: bitset is modified
pop ecx
pop ebx
pop eax
xchg ecx, dword [esp]
;remove the above to change calling convention
mbs EQU ebx
numbits EQu ecx
push ebp
dec numbits
appendloop:
mov edx, eax
shr edx, cl
push numbits
mov ecx, 7
sub cl, byte [mbs + 8]
mov ebp, 1
shl ebp, cl
mov ecx, dword [mbs]
add ecx, 9
xchg ebp, ecx
and edx, 1
jz @f
or byte [mbs + ebp], cl
jmp appenddone
@@:
not ecx
and byte [mbs + ebp], cl
appenddone:
pop numbits
inc dword [mbs + 4]
inc byte [mbs + 8]
and byte [mbs + 8], 7
jnz @f
inc dword [mbs]
@@:
dec numbits
cmp numbits, 0
jge appendloop
pop ebp
ret
drawfinders:
;input: nothing
;output: finder patterns (large squares) are drawn in matrix
push dword [lite]
push 8
push 0
push 0
call fillbox
push dword [dark]
push 7
push 0
push 0
call fillbox
push dword [lite]
push 5
push 1
push 1
call fillbox
push dword [dark]
push 3
push 2
push 2
call fillbox
push dword [lite]
push 8
mov eax, dword [size]
sub eax, 8
push eax
push 0
call fillbox
push dword [dark]
push 7
mov eax, dword [size]
sub eax, 7
push eax
push 0
call fillbox
push dword [lite]
push 5
mov eax, dword [size]
sub eax, 6
push eax
push 1
call fillbox
push dword [dark]
push 3
mov eax, dword [size]
sub eax, 5
push eax
push 2
call fillbox
push dword [lite]
push 8
push 0
mov eax, dword [size]
sub eax, 8
push eax
call fillbox
push dword [dark]
push 7
push 0
mov eax, dword [size]
sub eax, 7
push eax
call fillbox
push dword [lite]
push 5
push 1
mov eax, dword [size]
sub eax, 6
push eax
call fillbox
push dword [dark]
push 3
push 2
mov eax, dword [size]
sub eax, 5
push eax
call fillbox
ret
getdrawbit:
;input: eax = index of desired bit from ileaveddata
;output: eax = [ddat] if bit is 1, [ldat] otherwise
;pop ebx
;pop eax
;pop eax
;push ebx
;remove the above to change calling convention
mov ebx, eax
shr eax, 3
and ebx, 7
mov ecx, 7
sub ecx, ebx
mov bl, byte [ileaveddata + 9 + eax]
shr bx, cl
mov eax, dword [ddat]
and ebx, 1
jnz @f
mov eax, dword [ldat]
@@:
ret
drawversion:
;input: nothing
;output: version info is drawn in matrix
mov ebx, dword [version]
cmp bx, 7
jnge drawversion_end
sub bx, 7
mov ebx, dword [versionstrings + ebx * 4]
xor ecx, ecx
drawverloop:
mov eax, 1
shl ax, cl
and ax, bx
mov eax, dword [dark]
jnz @f
mov eax, dword [lite]
@@:
mov dword [versionstring + ecx * 4], eax
inc ecx
cmp ecx, 17
jng drawverloop
xor ecx, ecx
xor ebx, ebx ;col
mov edx, dword [size]
sub dl, 8
push edx
putversion1:
mov edx, dword [size]
sub edx, 11 ;row
putversion2:
mov eax, edx
mul byte [size]
add eax, ebx
push ebx
mov ebx, dword [versionstring + ecx * 4]
mov dword [matrix + eax * 4], ebx
pop ebx
push edx
mov eax, ebx
mul byte [size]
add eax, edx
mov edx, dword [versionstring + ecx * 4]
mov dword [matrix + eax * 4], edx
inc cx
pop edx
inc edx
cmp edx, dword [esp]
jl putversion2
inc bx
cmp bx, 6
jl putversion1
pop edx
drawversion_end:
ret
makeECgenerator:
;input: eax = desired order of EC generator polynomial
;output: genpoly array is modified
pop ecx
pop eax
push ecx
;remove the above to change calling convention
mov [genpoly], 0
push eax
cld
mov ecx, 31
mov edi, genpoly
xor eax, eax
rep stosb
mov ecx, 2
ecgenloop:
push ecx
mov eax, ecx
dec eax
push eax
std
mov esi, genpoly - 1
add esi, ecx
mov edi, esi
inc edi
rep movsb
mov al, [genpoly]
add eax, [esp]
cmp eax, 255
jnge @f
sub eax, 255
cmp eax, 255
jnge @f
sub eax, 255
@@:
mov [genpoly], al
inc cl
xorloop:
mov ebx, genpoly
mov eax, ecx
xlatb
mov dh, al
mov al, cl
inc eax
xlatb
add eax, [esp]
cmp eax, 255
jnge @f
sub eax, 255
cmp eax, 255
jnge @f
sub eax, 255
@@:
mov ebx, mod285logs
xlatb
mov dl, al
mov al, dh
xlatb
xor al, dl
mov ebx, mod285antilogs
xlatb
mov byte [genpoly + ecx], al
inc cl
cmp ecx, dword [esp + 4]
jl xorloop
pop ecx
pop ecx
inc cl
cmp cl, byte [esp]
jle ecgenloop
pop eax
end2:
cld
ret
getblockpenalty:
;input: nothing
;output: eax = penalty score from squares
mov esi, 0
mov ebx, [size]
dec bl
dec bl
sqloop2:
mov ecx, [size]
dec cl
dec cl
sqloop:
mov eax, ecx
imul byte [size]
add eax, ebx
mov edx, [matrix + eax * 4]
and edx, CMSK
mov edi, edx
mov edx, [matrix + 4 + eax * 4]
and edx, CMSK
cmp edx, edi
jne @f
add eax, [size]
mov edx, [matrix + eax * 4]
and edx, CMSK
cmp edx, edi
jne @f
mov edx, [matrix + 4 + eax * 4]
and edx, CMSK
cmp edx, edi
jne @f
add esi, 3
@@:
dec ecx
cmp ecx, 0
jge sqloop
dec ebx
cmp ebx, 0
jge sqloop2
mov eax, esi
ret
getstraightpenalty:
;input: nothing
;output: eax = penalty score of qr code for
; straight runs of identical pixels
mov esi, 0 ; penalty
mov edi, 3 ; flags 1=new row, 2= new column
mov ecx, dword [size]
sub ecx, 5
gsploop2:
mov ebx, dword [size]
sub ebx, 5
gsploop1:
mov eax, ecx
imul byte [size]
add eax, ebx
push ecx
mov edx, dword [matrix + eax * 4]
and edx, CMSK
mov ecx, dword [matrix + 4 + eax * 4]
and ecx, CMSK
cmp edx, ecx
jne nostraightrow
mov ecx, dword [matrix + 8 + eax * 4]
and ecx, CMSK
cmp edx, ecx
jne nostraightrow
mov ecx, dword [matrix + 12 + eax * 4]
and ecx, CMSK
cmp edx, ecx
jne nostraightrow
mov ecx, dword [matrix + 16 + eax * 4]
and ecx, CMSK
cmp edx, ecx
jne nostraightrow
inc esi
test edi, 1
jz @f
inc esi
inc esi
@@:
and edi, 2
jmp @f
nostraightrow:
or edi, 1
@@:
pop ecx
mov eax, ebx
imul byte [size]
add eax, ecx
push ecx
mov edx, dword [matrix + eax * 4]
and edx, CMSK
add eax, dword [size]
mov ecx, dword [matrix + eax * 4]
and ecx, CMSK
cmp edx, ecx
jne nostraightcol
add eax, dword [size]
mov ecx, dword [matrix + eax * 4]
and ecx, CMSK
cmp edx, ecx
jne nostraightcol
add eax, dword [size]
mov ecx, dword [matrix + eax * 4]
and ecx, CMSK
cmp edx, ecx
jne nostraightcol
add eax, dword [size]
mov ecx, dword [matrix + eax * 4]
and ecx, CMSK
cmp edx, ecx
jne nostraightcol
inc esi
test edi, 2
jz @f
inc esi
inc esi
@@:
and edi, 1
jmp @f
nostraightcol:
or edi, 2
@@:
pop ecx
dec ebx
cmp ebx, 0
jge gsploop1
mov edi, 3
dec ecx
cmp ecx, 0
jge gsploop2
mov eax, esi
ret
;kolibrios_drawtowindow:
;;input: nothing
; call reducematrix
; mov eax, 7
; mov ebx, matrix
; mov ecx, [size]
; shl ecx, 16
; add ecx, [size]
; mov edx, 40
; shl edx, 16
; add edx, 80
; int 0x40
; ret
reducematrix:
;input: nothing
;reduces matrix from rgba to 3-byte rgb
;for use in KolibriOS system function 7
mov ecx, [size2]
dec ecx
mov esi, matrix
mov edi, esi
redloop:
lodsd
mov bx, 0
cmp al, 5
jb @f
mov bx, 0xffff
@@:
xchg ax, bx
stosw
stosb
dec ecx
jns redloop
ret
iglobal
versionstrings dd 0x7C94, 0x85BC, 0x9A99, 0xA4D3, 0xBBF6
dd 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78, 0x1145D
dd 0x12A17, 0x13532, 0x149A6, 0x15683, 0x168C9, 0x177EC
dd 0x18EC4, 0x191E1, 0x1AFAB, 0x1B08E, 0x1CC1A, 0x1D33F
dd 0x1ED75, 0x1F250, 0x209D5, 0x216F0, 0x228BA, 0x2379F
dd 0x24B0B, 0x2542E, 0x26A64, 0x27541, 0x28C69
formatstrings dw 0x77C4, 0x72F3, 0x7DAA, 0x789D, 0x662F
dw 0x6318, 0x6C41, 0x6976, 0x5412, 0x5125, 0x5E7C
dw 0x5B4B, 0x45F9, 0x40CE, 0x4F97, 0x4AA0, 0x355F
dw 0x3068, 0x3F31, 0x3A06, 0x24B4, 0x2183, 0x2EDA
dw 0x2BED, 0x1689, 0x13BE, 0x1CE7, 0x19D0, 0x762
dw 0x255, 0xD0C, 0x83B
mod285logs db 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232
db 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201
db 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37
db 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35
db 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210
db 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94
db 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231
db 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91
db 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13
db 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248
db 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204
db 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66
db 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 170
db 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191
db 99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246
db 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149
db 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200
db 141, 7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 81
db 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86
db 172, 69, 138, 9, 18, 36, 72, 144, 61, 122, 244, 245
db 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125
db 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1
mod285antilogs db 0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238
db 27, 104, 199, 75, 4, 100, 224, 14, 52
db 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5
db 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240
db 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201
db 154, 9, 120, 77, 228, 114, 166, 6, 191, 139, 98, 102, 221
db 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208
db 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56
db 70, 64, 30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40
db 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121
db 43, 78, 212, 229, 172, 115, 243, 167, 87, 7, 112, 192
db 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24
db 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217
db 35, 32, 137, 46, 55, 63, 209, 91, 149, 188, 207, 205, 144
db 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20
db 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31, 45, 67
db 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111
db 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177
db 187, 204, 62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11
db 245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230
db 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175
;bigtable (blocks by version and ec level)
;rowmajor - version
;rowminor - eclevel
;columns: number of blocks in group 1,
; number of data codewords in each of group 1's blocks,
; number of blocks in group 2,
bigtable db 1,19,0,1,16,0,1,13,0,1,9,0,1,34,0,1,28,0,1,22,0
db 1,16,0,1,55,0,1,44,0,2,17,0,2,13,0,1,80
db 0,2,32,0,2,24,0,4,9,0,1,108,0,2,43,0,2,15,2,2,11
db 2,2,68,0,4,27,0,4,19,0,4,15,0,2,78,0,4
db 31,0,2,14,4,4,13,1,2,97,0,2,38,2,4,18,2,4,14,2,2
db 116,0,3,36,2,4,16,4,4,12,4,2,68,2,4,43
db 1,6,19,2,6,15,2,4,81,0,1,50,4,4,22,4,3,12,8,2,92
db 2,6,36,2,4,20,6,7,14,4,4,107,0,8,37,1,8
db 20,4,12,11,4,3,115,1,4,40,5,11,16,5,11,12,5,5,87
db 1,5,41,5,5,24,7,11,12,7,5,98,1,7,45,3
db 15,19,2,3,15,13,1,107,5,10,46,1,1,22,15,2,14,17
db 5,120,1,9,43,4,17,22,1,2,14,19,3,113,4,3
db 44,11,17,21,4,9,13,16,3,107,5,3,41,13,15,24,5,15
db 15,10,4,116,4,17,42,0,17,22,6,19,16,6,2
db 111,7,17,46,0,7,24,16,34,13,0,4,121,5,4,47,14,11
db 24,14,16,15,14,6,117,4,6,45,14,11,24,16
db 30,16,2,8,106,4,8,47,13,7,24,22,22,15,13,10,114
db 2,19,46,4,28,22,6,33,16,4,8,122,4,22,45
db 3,8,23,26,12,15,28,3,117,10,3,45,23,4,24,31,11
db 15,31,7,116,7,21,45,7,1,23,37,19,15,26,5
db 115,10,19,47,10,15,24,25,23,15,25,13,115,3,2,46
db 29,42,24,1,23,15,28,17,115,0,10,46,23,10
db 24,35,19,15,35,17,115,1,14,46,21,29,24,19,11,15
db 46,13,115,6,14,46,23,44,24,7,59,16,1,12
db 121,7,12,47,26,39,24,14,22,15,41,6,121,14,6,47
db 34,46,24,10,2,15,64,17,122,4,29,46,14,49
db 24,10,24,15,46,4,122,18,13,46,32,48,24,14,42,15
db 32,20,117,4,40,47,7,43,24,22,10,15,67,19
db 118,6,18,47,31,34,24,34,20,15,61
charcountlengths db 10,9,8,8,12,11,16,10,14,13,16,12
modeindicators db 1,2,4,8,7
diffs db 24,24,26,26,26,28,28
alphamode db '0123456789ABCDEFGHIJKL'
db 'MNOPQRSTUVWXYZ $%*+-./:', 0
DARK equ 0
CMSK equ 0FFFF00H
;1 dark, 1 light, 3 dark, 1 light, 1 dark
;preceded or followed by 4 light
sequence dd CMSK, CMSK, CMSK, CMSK
dd DARK, CMSK, DARK, DARK, DARK, DARK
dd CMSK, DARK, CMSK, CMSK, CMSK, CMSK
endg