; QR-Code generator, module FORTH
; Guillaume Tello
; guillaume.tello@orange.fr
; octobre/novembre 2025

LDV equ 1		; 1 pour fichier OBJ pour LDV
					; 0 pour module FORTH

	opt P=68000
	
	if LDV=1
		opt L1,D-
		export QRinfo,QRcode
	endif
	
GEMDOS MACRO    ; fn,pile
   move #\1,-(sp)
   trap #1
   if \2<=8
      addq.l #\2,sp
   else
      add.w #\2,sp
   endif
   ENDM

		section	text

	if LDV=1

	; ************ ici LDV ************
	
	dcb.b 34,0
debut:

	; ************ ici FOM ************

	else

debut:	
	dc.b "READ_FOM"	; identifiant module g‚n‚ral FORTH
	dc.b "QR-C"			; objets support‚s
	dc.w 0				; pas de multiples appels modexe
	dc.b "QR-CODEG"	; nom court
	dc.w 100				; version 1.00
	dc.b "QR-Code Generator 2025 G.Tello",0 ; long name (30 caractŠres + z‚ro)
	dc.b 16+2+1			; 16 si mfdbs pr‚f‚r‚ … sndb, 2 si mots red‚finis, 1 si do_param pr‚sent
	bra QRinfo
	bra QRcode
	bra QRsave
	bra do_param		; si bit #0
	
	; ici, red‚finition des mots modinfo, modpal, modexe si bit #1
	
	dc.b "QRinfo",0	; si l'un des mots n'est pas red‚fini,
	dc.b "QRcode",0	; on met simplement dc.b 0
	dc.b "QRsave",0
	even					; assure la parit‚

	endif ; *************** fin LDV FOM ***********

	; ********* mode LDV **********
	; l'appel est fait au premier appel de QRinfo
	
	; ********* mode FOM **********
	; l'appel est automatique lors du chargement
		
	; ici l'initialisation consiste …:
	; cr‚er les tables GF(256) de log/exp
	; renvoie toujours 0

do_param:
	if LDV=1
		movem.l a0/d0,-(sp)
	endif
	lea expn(pc),a0
	lea logn(pc),a1
	moveq #0,d0				; premier n
	moveq #1,d1				; et 2^n
.lb0:
	move.b d1,0(a0,d0.l)	; dit que d1 vaut 2^d0
	move.b d0,0(a1,d1.l)	; et que d0 vaut log2(d1)
	addq.b #1,d0
	beq.s .fin				; si fin, c'est 0 (256)
	add d1,d1				; multiplie par 2
	cmp #256,d1
	bmi.s .lb0				; moins de 256, on garde
	eor #285,d1				; sinon, xor 285, on retombe sous 256
	bra.s .lb0
.fin:
	lea logn(pc),a1
	st (a1)+					; 255 ici comme marqueur de 0
	sf (a1)					; et l… 0 au lieu du 255
	if LDV=1
		movem.l (sp)+,a0/d0
	else
		moveq #0,d0
	endif
	rts


	; *********** en mode LDV **********
	; QRinfo(texte, ecc, retour)
	; A0 = pointeur sur texte
	; D0 = ecc
	; A1 = pointeur sur bloc retour
	;
	; renvoie dans retour
	; +0	taille bloc … r‚server
	; +4	version
	; +6	largeur image
	; +8	hauteur image

	; *********** en mode FOM **********
	; " message" level QRinfo	; level est le niveau de correction d'erreur 0-3
	; en 4(SP)on trouve mfdbs
	; sur A6 la pile FORTH
	
	; renvoie dans mfdbs:
	;  0  taille buffer … r‚server
	;	+4 version choisie (1-40)
	;  +6 mode (NUME, ALPH, BYTE, KENJ)
	;  +10  mode d'‚criture (1 num, 2 alp, 3 byt, 4 ken)
	;  +12 level erreur retenu

	; *********** mode FOM/LDV *********
	; renvoie 2 = OK (renvoi 0 si LDV)
	; renvoie -1 = message trop long/ou nul 
	; renvoie -2 = level incorrect
	
	; avant le module on a
	; -2 WORD level 0-3
	; -6 LONG adresse message
	; -8 WORD mode 0-3
	; -10 WORD taille message
	; -12 WORD version 1-40
	; -16 LONG pointeur des data du mode/version
	
QRinfo:
	if LDV=1
		movem.l d2-d7/a2-a3,-(sp)
		move.l a1,a3	; bloc retour, idem mfdbs
		move.l expn(pc),d1	; regarde le debut de la table
		bne.s .deja		; d‚j… remplie
		bsr do_param	; sinon, premier appel, on calcule log+exp
	.deja:
		lea debut(pc),a1	; zone 34 octets avant le module
		move.l d0,d6	; level
	else
		lea debut(pc),a1	; zone 32 octets avant le module
		move.l 4(sp),a3	; mfdbs
		move.l (a6)+,d6	; level
	endif
	bmi.s .err_level
	moveq #4,d0
	cmp.l d0,d6
	bpl.s .err_level
	if LDV=0
		move d6,12(a3)		; conserve level
	endif
	move d6,-(a1)
	lsl.l #4,d6			; *16 pour l'offset
	if LDV=1
		move.l a0,a2	; le message
	else
		move.l (a6),a2		; le message
	endif
	move.l a2,-(a1)
	; ici analyse pour trouver le bon encodage (num, alph, byte)
	moveq #0,d0			; le mode par d‚faut, num‚rique
	moveq #0,d1			; taille
	moveq #0,d2			; l'octet lu
.analyse:
	move.b (a2)+,d2
	beq _fin_an
	bpl.s .lb0
	bset #1,d0			; si un >128, mode byte
	bra.s .analyse
.lb0:
	or.b table(pc,d2.l),d0	; ajoute le mode du caractŠre
	bra.s .analyse
.err_level:
	if LDV=0
		addq.l #4,a6
	else
		movem.l (sp)+,d2-d7/a2-a3
	endif
	moveq #-2,d0
	rts
	
	; 0 pour mode NUM, 1 pour ALPHA et 2 pour BYTE
table:
	dcb.b 32,2			; octets 0-31, bit1 (mode byte)
	dc.b 1				; espace, mode alpha
	dcb.b 3,2
	dc.b 1,1				; $ % (mode alpha)
	dcb.b 4,2
	dc.b 1,1				; * +
	dc.b 2
	dcb.b 3,1			; - . /
	dcb.b 10,0			; 0 1 2 3 4 5 6 7 8 9
	dc.b 1				; :
	dcb.b 6,2
	dcb.b 26,1			; A - Z
	dcb.b 37,2

modes:
	dc.b "NUMEALPHBYTEKENJ"
	
_fin_an:
	moveq #3,d2			; teste les bits de 0 … 3
.find_mode:
	btst d2,d0
	bne.s .found
	dbf d2,.find_mode
	bra.s .lb1			; z‚ro, on le garde
.found:
	moveq #0,d0
	bset d2,d0			; ne conserve que le bit le plus haut
.lb1:	
	move d0,d2
	addq #1,d2
	if LDV=0
		move d2,10(a3)		; le mode 1-4
	endif
	move d2,-(a1)
	move d0,d2
	lsl.l #2,d2
	if LDV=0
		move.l modes(pc,d2.l),6(a3)	; le mode en alpha
	endif
	if LDV=1
		sub.l debut-6(pc),a2
	else
		sub.l (a6),a2
	endif
	subq.l #1,a2		;	taille du message
	move.l a2,d2
	move d2,-(a1)		; taille message
	beq.s .err_len
	lea data_version(pc),a2	
	add.l d6,a2			; et pointe sur le bon niveau d'erreur
	add.l d0,a2			; pointe sur la bonne colonne selon le mode
	add.l d0,a2			; car ce sont des mots
	moveq #39,d1
.find_ver:
	cmp (a2),d2
	bmi.s .ok
	lea 64(a2),a2
	dbf d1,.find_ver
.err_len:
	if LDV=0
		addq.l #4,a6
	else
		movem.l (sp)+,d2-d7/a2-a3
	endif
	moveq	#-1,d0
	rts
.ok:
	if LDV=0
		addq.l #4,a6	; corrige pile FORTH
	endif
	moveq #40,d0
	sub.l d1,d0			; ici version choisie (1-40)
	move d0,4(a3)		; la range
	move d0,-(a1)
	subq.l #1,d0		; (0-39)
	lsl.l #6,d0			; *64 par version
	lea data_version(pc),a2
	add.l d0,a2			; sur la bonne version
	add.l d6,a2			; et le bon niveau d'erreur
	move.l a2,-(a1)
	moveq #0,d0
	move.b 11(a2),d0	; combien de blocs groupe 1
	moveq #0,d1
	move.b 13(a2),d1	; et groupe 2
	add d1,d0			; total blocs
	move.b 10(a2),d1	; valeurs EC par bloc
	muls d1,d0			; total de valeurs EC
	move 8(a2),d1		; les valeurs code
	add.l d1,d0			; total valeurs code+ec
	lsl.l #3,d0			; taille buffer en octet=1 bit
	
	move 4(a3),d1		; version
	lsl #2,d1			; 4v
	add #17,d1			; 4v+17 = cot‚ du carr‚ QR-Code
	addq #2,d1			; pour la bordure
	if LDV=1
		move d1,d2		; 4V+19 nombre de blocs
		lsl #2,d2		; en pixels (4 par bloc)
		move d2,6(a3)	; l renvoy‚ pour le LDV
		move d2,8(a3)	; h idem
	endif
	moveq #15,d2		; pour l'alignement sur 16bits
	add d1,d2
	muls d2,d1			; taille d'un QR-Code en pixels
	add.l #180,d1		; pour laisser une ligne libre
	
	cmp.l d1,d0			; on prend la taille max (soit les valeurs, soit le qr-code)
	bpl.s .lb2
	move.l d1,d0
.lb2:
	addq.l #1,d0
	bclr #0,d0			; rend le demi bloc pair
	move.l d0,-8(a1)	; demi buffer en debut-24
	add.l d0,d0			; en double
	move.l d0,(a3)		; renvoie taille
	if LDV=1
		movem.l (sp)+,d2-d7/a2-a3
		moveq #0,d0		; 0 pas d'erreur
	else
		moveq #2,d0			; Ok pas d'erreur
	endif
	rts

	; *********** mode LDV ***********
	; QRcode(buffer,mfdbs)
	; A0 = adresse du buffer
	; A1 = adresse du mfdbs
	
	; *********** mode FOM ***********
	; buffer QRcode
	; si buffer+0 contient LONG 'ICON'
	; alors buffer+4 contient l'adresse d'une stucture Iconblk
	; qu'on doit m‚langer … l'image
	
	; *********** mode FOM/LDV *******
	;	 fais l'encodage et remplis mfdbs comme source monochrome 1 pixel=1bit
	
	; renvoie 2 OK
	;			-1 mode non support‚
	

	; avant le module on a
	; -2 WORD level 0-3
	; -6 LONG adresse message
	; -8 WORD mode 0-3
	; -10 WORD taille message
	; -12 WORD version 1-40
	; -16 LONG pointeur des data du mode/version	
	; -20 LONG le buffer re‡u
	; -24 LONG taille du demi buffer (pour les deux zones de travail)
	; -28 LONG taille en octets des donn‚es
	; -30 WORD le masque choisi	
	; ******* mode LDV only ******* -34 LONG mfdbs
	; ******* mode FOM only ******* icone LONG adresse icon ou z‚ro
	
QRcode:
	if LDV=1
		movem.l d2-d7/a2-a3,-(sp)
		move.l a0,a3	; l… ou placer les codes
		lea debut(pc),a0
		move.l a1,-34(a0)	; sauve le mfdbs
	else
		move.l (a6)+,a3	; l… ou placer les codes
		moveq #0,d0
		cmp.l #'ICON',(a3)
		bne.s .noicon
		move.l 4(a3),d0	; adresse Iconblock
	.noicon:
		lea icone(pc),a0
		move.l d0,(a0)		; sauve 0 ou adresse icone
		lea debut(pc),a0
	endif
	move.l a3,-20(a0)	; conserve le buffer
	move.l -6(a0),a2	; le message
	move.l -16(a0),a1	; le tableau des data
	move -8(a0),d2		; le mode 1-4
	moveq #-128,d0
	rol.b d2,d0					; devient 1,2,8,16
	moveq #4,d1
	bsr add_bits				; ajoute le mode
	move debut-10(pc),d0		; taille des donn‚es
	
	lea count_len(pc),a0		; table pour d‚terminer combien de bits pour encoder la taille
	moveq #0,d1
	move debut-12(pc),d1		; selon la version
.cl1:
	cmp.b (a0),d1				; cherche la bonne partie du tableau selon la version
	bls.s .cl0					; trouv‚
	addq.l #5,a0				; suite
	bra.s .cl1
.cl0:
	move.b 0(a0,d2.w),d1		; nombre de bits selon le mode D2
	bsr add_bits
	subq #1,d2
	bne.s .lba
	; ici mode num‚rique !
	moveq #0,d2
.num:
	moveq #0,d0
	move.b (a2),d0
	beq .fin_code				; fin de chaine
	sub #'0',d0
	moveq #4,d1
	addq.l #1,a2
	move.b (a2),d2
	beq.s .num1					; si fin de chaine aprŠs 1 octets, encoder sur 4 bits
	muls #10,d0
	sub #'0',d2
	add d2,d0
	addq.l #1,a2
	moveq #7,d1
	move.b (a2),d2
	beq.s .num1					; si fin aprŠs 2 octets, encoder sur 7 bits
	muls #10,d0
	sub #'0',d2
	add d2,d0
	addq.l #1,a2
	moveq #10,d1				; sinon encoder les 3 octets sur 10 bits 000-999 dans 0-1023
.num1:
	bsr add_bits
	bra.s .num
.lba:
	subq #1,d2
	bne.s .lbb
	; ici mode ALPHA
.alpha:
	move.b (a2),d2
	beq .fin_code
	bsr get_alpha				; renvoie le code dans d0.w
	moveq #6,d1
	addq.l #1,a2
	move.b (a2),d2
	beq.s .alpha1
	moveq #45,d1
	addq.l #1,a2
	muls d0,d1
	bsr get_alpha
	add d1,d0
	moveq #11,d1
.alpha1:
	bsr add_bits
	bra.s .alpha
.lbb:
	subq #1,d2
	bne.s .lbc
	; ici mode BYTE
.byte:
	lea vers_ibm(pc),a1
	moveq #0,d0
.bb0:
	move.b (a2)+,d0
	beq .fin_code
	bpl.s .bb1					; code 0-127 on garde
	move.b -128(a1,d0.l),d0	; code 128-255 on transforme
.bb1:
	moveq #8,d1
	bsr add_bits				; ici chaque octet encod‚ sur 8 bits
	bra.s .bb0
.lbc:
	if LDV=1
		movem.l (sp)+,d2-d7/a2-a3
	endif
	moveq #-1,d0
	rts
.fin_code:
	move.l a3,d6
	sub.l debut-20(pc),d6	; d0=taille des donn‚es en bits
	move.l debut-16(pc),a1	; les data
	move 8(a1),d7
	lsl #3,d7					; nombre de bits requis
	moveq #3,d2					; maxi 4 0 en terminateur
.terminator:
	cmp d6,d7					; ici ajoute 4 z‚ro sauf si on atteint le total
	beq.s .mul8
	addq #1,d6
	clr.b (a3)+
	dbf d2,.terminator
.mul8:							; ici ajoute des z‚ros jusqu'… un multiple de 8
	move d6,d2
	and #7,d2
	beq.s .pad
	addq #1,d6
	clr.b (a3)+
	bra.s .mul8
.pad:								; ici ajoute en s‚quence 236 et 17 jusqu'… atteindre le total de bits
	cmp d6,d7
	beq.s .pad_end
	move #236,d0
	moveq #8,d1
	add d1,d6
	bsr add_bits
	cmp d6,d7
	beq.s .pad_end
	moveq #17,d0
	moveq #8,d1
	add d1,d6
	bsr add_bits
	bra.s .pad
.pad_end:
	move.l debut-20(pc),a3	; retour au d‚but
	move.l a3,a0
.pack:							; ici retransforme les octets FF, 00 en bits
	moveq #7,d1
.8bits:
	add d0,d0
	tst.b (a3)+
	beq.s .skip
	addq #1,d0
.skip:
	dbf d1,.8bits
	move.b d0,(a0)+
	subq #8,d6
	bne.s .pack
	move.l a0,a3				; nouveau pointeur de fin de donn‚es
	move.l debut-16(pc),a1	; les data
	moveq #0,d7
	move.b 10(a1),d7			; degr‚ du polynome … g‚n‚rer
	bsr generate_poly
	move.l a4,-(sp)			; on en aura besoin !
	move.l debut-20(pc),a4	; pointe sur les donn‚es
	move.l debut-16(pc),a1	; les data
	moveq #0,d5
	move.b 11(a1),d5			; nombre de blocs dans le groupe 1
	moveq #0,d6
	move.b 12(a1),d6			; taille de chaque bloc
	bra.s .lb0
.groupe1:
	bsr error_codes			; divise les polynomes et range les codes d'erreur
.lb0:
	dbf d5,.groupe1
	move.l debut-16(pc),a1	; les data
	moveq #0,d5
	move.b 13(a1),d5			; nombre de blocs dans le groupe 2
;	moveq #0,d6
;	move.b 14(a1),d6			; taille de chaque bloc
	addq.b #1,d6				; quand il y a un groupe 2, c'est une donn‚e de plus
	bra.s .lb1
.groupe2:
	bsr error_codes			; divise les polynomes et range les codes d'erreur
.lb1:
	dbf d5,.groupe2
	move.l (sp)+,a4
	
	bsr entrelace
	
	sub.l debut-20(pc),a3	; -buffer
	sub.l debut-24(pc),a3	; - 1/2 buffer = taille des donn‚es !
	if LDV=1
		move.l debut-34(pc),a1	; mfdbs
	else
		move.l 4(sp),a1			; mfdbs
	endif
	move.l a3,(a1)				; renvoie taille en octets
	lea debut-28(pc),a1
	move.l a3,(a1)				; et aussi l… !
	
	bsr grille
	if LDV=1
		move.l debut-34(pc),a2	; mfdbs
		bsr format_ecran
	else
		move.l 4(sp),a2			; mfdbs
		bsr format_ecran
		move.l 4(sp),a2
		bsr ajoute_icone			; ‚ventuellement
	endif
	if LDV=1
		movem.l (sp)+,d2-d7/a2-a3
		moveq #0,d0					; 0 Ok pour LDV
	else
		moveq #2,d0					; 2 Ok pour FOM
	endif	
	rts	
	
	
	; d0 = valeur, d1=nombre de bits
	; ajoute les bits sous forme de FF, 00 dans A3
	
add_bits:
	bra.s .loop
.lb0:
	btst d1,d0
	sne (a3)+		; octet FF … chaque "1"
.loop:
	dbf d1,.lb0	
	rts	

	; transforme un ASCII en 0-44 du mode alpha
	
get_alpha:
	moveq #0,d0
	lea table_alpha(pc),a0
	move.b d2,45(a0)			; pour s'assurer de l'arrˆt
.lb0:
	cmp.b (a0)+,d2
	beq.s .exit
	addq #1,d0
	bra.s .lb0
.exit:
	cmp.b #45,d0				; si pas trouv‚... (pas normal)
	bne.s .fin
	moveq #0,d0					; remplace par z‚ro
.fin:
	rts	
table_alpha:
	dc.b "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"
	dc.b 0
	even
	
	; d7 degr‚ du polynome … g‚n‚rer, d7>0
	; renvoie les coeffs dans poly

generate_poly:
	lea poly(pc),a0
	move #$0101,(a0)		; initialise … 1x+1
	moveq #1,d6				; ce qui correspond … n=1
	moveq #1,d5				; et donc 2^(n-1)=1, le coeff
	moveq #0,d4
	moveq #0,d3
	moveq #0,d2
	moveq #0,d1
	lea expn(pc),a1
	lea logn(pc),a2
.loop:
	cmp d6,d7
	bne.s .suite
	rts
.suite:
	addq.l #1,d6
	move.b -1(a1,d6.l),d5	; 2^(n-1) comme coeff
	move.b 0(a2,d5.l),d5		; seul son log nous int‚resse
	lea poly(pc),a0
	clr.b 0(a0,d6.l)			; ajoute un dernier coeff nul
	move.b (a0)+,d4			; le premiere valeur
	move.l d6,d0				; pour la boucle
	bra.s .lb0
.multiplie:	
	move.b 0(a2,d4.l),d3		; log de la valeur
	add.b d5,d3					; ajoute le log du coeff (on a multipl‚)
	bcc.s .lb1					; d‚passement de 255 ?
	addq.b #1,d3				; si oui, on corrige l'exposant
.lb1:	
	move.b (a0),d4				; sauvegarde la valeur actuelle pour la suite
	move.b 0(a1,d3.l),d3		; reprend la valeur
	eor.b d3,(a0)+				; fait l'addition en XOR
.lb0:	
	dbf d0,.multiplie
	bra.s .loop

	; a4 pointe sur les donn‚es … r‚cup‚rer
	; d6 nombre de donn‚es du groupe
	; d7 degr‚ du polynome de r‚f‚rence
	; a3 o— on stockera les codes
			
error_codes:
	lea dividende(pc),a0
	moveq #63,d0
.lb0:
	clr.l (a0)+					; efface la zone du dividende
	dbf d0,.lb0
	lea dividende(pc),a0
	move.l a3,-(sp)			; on sauve !
	lea expn(pc),a1
	lea logn(pc),a2			; les tables
	
	moveq #0,d4
	moveq #0,d0
	
	lea dividende(pc),a0
	move d6,d2					; taille polynome comme nombre de divisions
	bra.s .lb6
.lb7:
	move.b (a0)+,d3
	move.b (a4)+,d4			; valeur dividende
	eor.b d3,d4
	move.l a0,d3				; pour la suite
	move.b 0(a2,d4.l),d4		; son log nous int‚resse
	lea poly+1(pc),a3
	move d7,d1					; degr‚ polynome comme compteur
	cmp.b #255,d4				; cas particulier facteur nul?
	beq.s .skip					; oui, rien … faire
	bra.s .lb4					; non, boucle normale
.lb5:
	move.b (a3)+,d0			; un coeff du diviseur
	move.b 0(a2,d0.l),d0		; son log
	add.b d4,d0					; multiplie
	bcc.s .lb3
	addq.b #1,d0				; si d‚passement, corrige
.lb3:
	move.b 0(a1,d0.l),d0		; retrouve la valeur
	eor.b d0,(a0)+				; stocke
.lb4:
	dbf d1,.lb5	
.skip:
	move.l d3,a0				; revient l… o— on doit travailler
.lb6:
	dbf d2,.lb7					; compteur de divisions … r‚aliser
	move d7,d0					; les "d7" coeffs restants sont les error codes
	move.l (sp)+,a3
	bra.s .lb8
.add_code:
	move.b (a0)+,(a3)+		; on les ajoute … la suite du message
.lb8:
	dbf d0,.add_code	
	rts
	
	if LDV=0

	; *************** mode FOM uniquement ****************
	; " chemin\fichier" n QRsave
	; sauve l'image d‚crite dans mfdbs selon n (0=X-IMG, 1=BMP)
		
	; pile 4(SP): mfdbs (et pas sndb)

QRsave:
	move.l a4,-(sp)
	move.l (a6)+,d5			; type demand‚
	move.l (a6)+,a3			; nom du fichier
	tst.l d5
	bpl.s .ok
.bugtype:
	move.l (sp)+,a4
	moveq #-1,d0				; erreur, type non support‚
	rts	
.bugfile:
	move.l (sp)+,a4
	moveq #-2,d0
	rts
.ok:
	cmp.l #1,d5
	bhi.s .bugtype
	clr -(sp)
	pea (a3)
	GEMDOS 60,8					; fcreate
	move.l d0,d4				; handle
	bmi.s .bugfile
	move.l 8(sp),a4			; mfdbs
	move.l debut-20(pc),a3	; le buffer, on a 180 octets libres
	tst.l d5
	bne.s .sauve_bmp
	; ici on sauve un IMG monochrome
	move.l #$00010008,(a3)+	; version et 8 octets d'en-tete
	move.l #$00010002,(a3)+	; plans et pattern
	move.l #$01740174,(a3)+	; tailles en micron
	move.l 4(a4),(a3)+		; largeur et hauteur
	bsr.s .ecris				; et remet a3 au d‚but
	bmi.s .bugfile
	move 8(a4),d5				; taille en words d'une ligne
	move 6(a4),d6				; hauteur en lignes
	
	move.l #$0000FF04,(a3)+	; r‚p‚ter 4 fois
	move d5,d0
	add.b d0,d0					; taille d'une ligne en octets
	move d0,d7
	bset #15,d0
	move d0,(a3)+				; 80nn nombre d'octets d'une ligne
	
	move.l (a4),a4				; adresse du bloc de pixels
	muls #3,d7					; pour sauter 3 lignes !
.lb2:	
	move d5,d0
	bra.s .lb0
.lb1:
	move (a4)+,(a3)+			; copie une ligne vers le buffer d'‚criture
.lb0:
	dbf d0,.lb1
	bsr.s .ecris
	bmi.s .bugfile
	add.l d7,a4					; saute 3 lignes identiques
	addq.l #6,a3				; saute le petit header toujours pareil
	subq #4,d6
	bne.s .lb2
	bra .fermer
.ecris:
	move.l debut-20(pc),a0
	pea (a0)						; buffer
	exg.l a0,a3
	sub.l a3,a0					; taille
	move.l a0,-(sp)
	move d4,-(sp)
	GEMDOS 64,12				; fwrite
	tst.l d0
	rts
.sauve_bmp:
	move #'BM',(a3)+
	moveq #0,d6
	move 6(a4),d6				; hauteur en pixels
	move 8(a4),d5				; largeur en words
	move d5,d0
	addq #1,d0
	bclr #0,d0					; nombre pair pour aligner sur des LONGS
	move d0,d1
	sub d5,d0					; 1 s'il faut ajouter un word
	beq.s .sb0
	bset #31,d6					; bit 31 mis si on doit ajouter un word
.sb0:
	add d1,d1					; une ligne en bytes
	muls d6,d1					; image totale en bytes destination BMP
	add.l #62,d1				; plus header
	ror #8,d1
	swap d1
	ror #8,d1					; en INTEL
	move.l d1,(a3)+
	clr.l (a3)+					; r‚serv‚
	move.l #$3E000000,(a3)+	; offset vers data (62)
	move.l #$28000000,(a3)+	; taille infos (40)
	moveq #0,d1
	move 4(a4),d1
	ror #8,d1
	swap d1
	move.l d1,(a3)+			; largeur
	moveq #0,d1
	move d6,d1
	ror #8,d1
	swap d1
	move.l d1,(a3)+			; hauteur
	move.l #$01000100,(a3)+	; 1 plan, 1 bit/pixel
	clr.l (a3)+
	clr.l (a3)+					; pas de compression
	move.l #$34070000,(a3)+
	move.l #$34070000,(a3)+	; les pixels par metre
	move.l #$02000000,(a3)+	; nombre de couleurs
	clr.l (a3)+					; toutes importantes
	move.l #$FFFFFF00,(a3)+	; blanc
	clr.l (a3)+					; noir
	bsr .ecris
	move.l (a4),a4				; donn‚es de l'image
	move d5,d7
	add d7,d7					; une ligne en octets
	move d7,d0
	muls d6,d0					; taille totale source
	add.l d0,a4					; fin de l'image
	bra.s .sb4
.sb5:
	sub d7,a4					; debut de nouvelle ligne
	move d5,d0
	bra.s .sb1
.sb2:
	move (a4)+,(a3)+
.sb1:
	dbf d0,.sb2
	tst.l d6
	bpl.s .sb3
	clr (a3)+					; un word de plus
.sb3:
	bsr .ecris
	sub d7,a4
.sb4:
	dbf d6,.sb5
.fermer:
	move d4,-(sp)
	GEMDOS 62,4
	move.l (sp)+,a4
	moveq #2,d0					; tout va bien !
	rts		
	
	endif		; ****************** fin de QRsave *******************


	; entrelace les groupes et les codes d'erreur
	; passe du buffer au 1/2 buffer sup‚rieur
	
entrelace:
	lea debut-16(pc),a0
	move.l (a0),a1			; data
	move.l -(a0),a2		; buffer source
	move.l -(a0),d0
	lea 0(a2,d0.l),a3		; 1/2 buffer sup‚rieur, destination
	moveq #0,d5
	moveq #0,d6
	moveq #0,d7
	move.b 11(a1),d5		; nombre de blocs groupe 1
	move.b 13(a1),d6		; nombre de blocs groupe 2
	move.b 12(a1),d7		; taille d'un bloc groupe 1
	
	; on entrelace d'abord les donn‚es du message
	
	move d7,d4				; boucle pricipale
	bra.s .lb4
.donnees:	
	move.l a2,a0			; source
	move d5,d3				; traite le groupe 1
	bra.s .lb0
.lb1:
	move.b (a0),(a3)+		; une donn‚e
	add.l d7,a0				; bloc suivant
.lb0:
	dbf d3,.lb1
	move d6,d3				; traite le groupe 2
	bra.s .lb3
.lb2:
	move.b (a0),(a3)+		; une donn‚e
	lea 1(a0,d7.l),a0		; bloc suivant (une donn‚es de plus en bloc 2)
.lb3:
	dbf d3,.lb2
	addq.l #1,a2			; avance dans la source
.lb4:
	dbf d4,.donnees
	move.l a0,a2
	sub.l d7,a2
	addq.l #1,a2			; nouveau pointeur sur les codes d'erreur
	add.l d6,a3				; en cas de groupe 2, il y a un reste
	lea -1(a2),a0			; pointe sur ce reste
	move d6,d3
	bra.s .lb5
.lb6:
	move.b (a0),-(a3)		; ajoute le reste … reculons
	sub.l d7,a0
	subq.l #1,a0
.lb5:
	dbf d3,.lb6
	add.l d6,a3				; puis revient au bout des donn‚es
	
	; ensuite on entrelace les codes d'erreur (plus faciles!)
	
	add d6,d5				; total bloc d'erreurs
	move.b 10(a1),d7		; et taille d'un bloc
	move.l d7,d4
	bra.s .lb14	
.erreurs:	
	move.l a2,a0			; source
	move d5,d3				; traite groupe
	bra.s .lb10
.lb11:
	move.b (a0),(a3)+		; une donn‚e
	add.l d7,a0				; bloc suivant
.lb10:
	dbf d3,.lb11
	addq.l #1,a2			; avance dans la source
.lb14:
	dbf d4,.erreurs
	rts


	; ici g‚nŠre la grille
grille:
	moveq #0,d7
	move debut-12(pc),d7		; version
	move.l debut-20(pc),a3	; buffer
	lsl.l #2,d7
	add.w #19,d7				; 4v+19 = longueur d'une ligne !
	bsr efface_tout
	move.l a3,a2				; position 0,0
	bsr finder
	lea -9(a3,d7.l),a2		; position (l-9 ; 0)
	bsr finder
	moveq #-9,d0
	add.l d7,d0
	muls d7,d0
	lea 0(a3,d0.l),a2			; position (0 ; l-9)
	lea 9(a2),a1				; pour black spot et r‚serve vertical 3e finder
	bsr finder
	bsr bordures				; un grand cadre pour marquer la fin
	bsr reserve					; les zones codant les caract‚ristiques du QR Code
	bsr alignements			; les modules d'alignement
	bsr timing					; deux ligne de pointill‚s "timing pattern"
	bsr remplir					; ajoute tous les codes !
	bsr masques					; applique les masques et choisit le meilleur
	bsr informations			; ajoute les bits d'information
	rts
	
	; a3 = buffer
	; d7 = longueur ligne
	; remplit le buffer de z‚ros
	
efface_tout:
	move.l a3,a0
	move d7,d0
	muls d7,d0					; nombre de bytes
	move d0,d2
	lsr #2,d2					; par paquets de 4
	moveq #0,d1
	bra.s .lb0
.lb1:
	move.l d1,(a0)+
.lb0:
	dbf d2,.lb1
	and #3,d0					; le reste (0-3)
	bra.s .lb2
.lb3:
	sf (a0)+
.lb2:
	dbf d0,.lb3
	rts
	
	; a2 = adresse du premier byte (normalement paire!)
	; d7 = taille ligne
	; dessine un finder 
	; .........		. = 02
	; .*******.		* = FE
	; .*.....*.
	; .*.***.*.
	; .*.***.*.
	; .*.***.*.
	; .*.....*.
	; .*******.
	; .........

finder:
	move.l #$02020202,d0		; pour les blancs
	move.l #$FEFEFEFE,d1		; pour les noirs
	move.l #$02FE02FE,d2		; blanc noir
	move.l #$FE02FE02,d3		; noir blanc
	bsr.s .f3						; ......... sur ligne paire
	bsr.s .f2						; .*******. sur ligne impaire
	bsr.s .f1						; .*.....*. sur ligne paire
	bsr.s .f0						; .*.***.*. sur ligne impaire
	; paire
	move.l d2,(a2)+
	move.w d1,(a2)+
	move.w d2,(a2)+
	move.b d0,(a2)+			; .*.***.*
	lea -9(a2,d7.l),a2		; ligne suivante
	bsr.s .f0						; .*.***.*. sur ligne impaire
	bsr.s .f1						; .*.....*. sur ligne paire
	bsr.s .f2						; .*******. sur ligne impaire
	bsr.s .f3						; ......... sur ligne paire
	rts
.f0:
	; impaire
	move.b d0,(a2)+
	move.w d3,(a2)+
	move.w d1,(a2)+
	move.l d3,(a2)+			; .*.***.*.
	lea -9(a2,d7.l),a2		; ligne suivante
	rts
.f1:
	; paire
	move.w d2,(a2)+
	move.l d0,(a2)+
	move.w d2,(a2)+
	move.b d0,(a2)+			; .*.....*.
	lea -9(a2,d7.l),a2		; ligne suivante
	rts
.f2:
	; impaire
	move.b d0,(a2)+
	move.l d1,(a2)+
	move.w d1,(a2)+
	move.w d3,(a2)+			; .*******.
	lea -9(a2,d7.l),a2		; ligne suivante
	rts
.f3:
	; paire
	move.l d0,(a2)+
	move.l d0,(a2)+
	move.b d0,(a2)+			; .........
	lea -9(a2,d7.l),a2		; ligne suivante	
	rts

	; a3 = buffer
	; d7 = longueur ligne
	; ajoute des 03 sur tout le cadre (changement de direction)
	
bordures:
	move.l a3,a2
	moveq #3,d1
	bsr.s .une_ligne
	move d7,d0
	subq #3,d0				; pour l-2 fois
.loop:
	move.b d1,-1(a2)		; fin de ligne pr‚c‚dente
	move.b d1,(a2)			; d‚but de ligne actuelle
	add.l d7,a2				; suivante
	dbf d0,.loop
	move.b d1,-1(a2)
	bsr.s .une_ligne
	rts
.une_ligne:
	move d7,d0
	bra.s .ul1
.ul0:
	move.b d1,(a2)+
.ul1:
	dbf d0,.ul0
	rts	

reserve:
	lea 9(a3,d7.l),a2		; partie verticale le long du 1er finder
	move.l a1,a0			; idem 3e finder	
	move.l #$02020202,d1
	moveq #7,d0
.lb0:
	move.b d1,(a2)
	move.b d1,(a0)
	add.l d7,a2
	add.l d7,a0
	dbf d0,.lb0
	move.b #$FE,(a1)		; le black spot
	move.b d1,(a2)			; l'angle des deux zones de r‚serve
	moveq #7,d0
.lb1:
	move.b d1,-(a2)		; ici les 2 parties horizontales
	move.b d1,-10(a2,d7.l)	; sous les finders 1 et 2
	dbf d0,.lb1
	cmp #47,d7				; version 7+ ?
	bmi.s .fin				; non, donc pas de zone suppl‚mentaire
	lea -12(a3,d7.l),a2	; position l-12 prŠs du 2e finder
	moveq #5,d0
	add.l d7,a2				; on commence par ajouter (passer la bordure la 1e fois)
.lb2:
	move.b d1,(a2)+		; ici zone 3x6 prŠs du finder 2
	move.b d1,(a2)+
	move.b d1,(a2)+
	lea -3(a2,d7.l),a2
	dbf d0,.lb2
	lea -8(a1),a2
	moveq #6,d2
	sub.l d7,d2
	moveq #2,d0
.lb3:
	add.l d2,a2
	move.b d1,-(a2)		; ici zone 6x3 dessus le finder 3
	move.b d1,-(a2)
	move.b d1,-(a2)
	move.b d1,-(a2)
	move.b d1,-(a2)
	move.b d1,-(a2)
	dbf d0,.lb3
.fin:
	rts

	; a3 = buffer
	; d7 = ligne
	
alignements:
	lea align_table(pc),a0
	move debut-12(pc),d0	; version
	subq #1,d0
	bra.s .lb0
.lb1:
	tst.b (a0)+			; avance jusqu'… la zone
	bne.s .lb1			; de ma version
.lb0:
	dbf d0,.lb1
	move.l a0,d6		; conserve le pointeur
.loop:
	moveq #0,d5
	move.b (a0)+,d5
	beq.s .fin			; fin de liste, tout est trait‚
	subq #1,d5			; pour le coin du haut
	muls d7,d5			; en nombre de lignes
	subq.l #1,d5		; le coin gauche coordonn‚e z‚ro
	add.l a3,d5			; conserve l'adresse
	move.l d6,a1		; pour parcourir la liste … nouveau
.ligne:
	moveq #0,d0
	move.b (a1)+,d0
	beq.s .loop			; liste finie
	move.l d5,a2
	add.l d0,a2			; coin gauche du module
	tst.b (a2)			; occup‚?
	bne.s .ligne		; oui, on passe
	tst.b 4(a2)
	bne.s .ligne
	move.l d7,d0
	lsl.l #2,d0
	tst.b 0(a2,d0.l)	; idem
	bne.s .ligne
	tst.b 5(a2,d0.l)	; idem
	bne.s .ligne
	; ici les 4 coins sont libres, on dessine un module !
	; l'adresse de d‚but est toujours paire (normalement...)
	move.l #$FEFEFEFE,(a2)+
	move.b #$FE,(a2)+			; ligne *****
	lea -5(a2,d7.l),a2
	move.b #$FE,(a2)+
	move.l #$020202FE,(a2)+ ; ligne *   *
	lea -5(a2,d7.l),a2
	move.l #$FE02FE02,(a2)+
	move.b #$FE,(a2)+			; ligne * * *
	lea -5(a2,d7.l),a2
	move.b #$FE,(a2)+
	move.l #$020202FE,(a2)+ ; ligne *   *
	lea -5(a2,d7.l),a2	
	move.l #$FEFEFEFE,(a2)+
	move.b #$FE,(a2)+			; ligne *****
	bra.s .ligne
.fin:
	rts	


	; ajoute deux lignes de pointill‚s
timing:	
	move.l d7,d0
	muls #7,d0
	lea 9(a3,d0.l),a2			; pointeur ligne horizontale pair au d‚but
	lea -2(a2,d7.l),a1
	add.l d7,a1					; pointeur ligne verticale
	moveq #-18,d0
	add.l d7,d0					; l-18 nombre de pixels … tracer
	lsr.l d0						; par deux
	moveq #-2,d1				; octet FE
	bra.s .lb1
.lb0:
	move #$FE02,(a2)+			; noir + blanc horizontal
	move.b d1,(a1)				; noir
	add.l d7,a1
	move.b #$02,(a1)			; + blanc vertical
	add.l d7,a1
.lb1:
	dbf d0,.lb0
	move.b d1,(a2)				; et le dernier point
	move.b d1,(a1)
	rts
	
	; ici remplit la grille avec les donn‚es
	; a3 = buffer
	; d7 = longueur ligne
	; debut-24 = taille demi buffer (vers donn‚es)
	; debut-28 = taille donn‚es

remplir:
	move.l d7,d0
	subq.l #1,d0
	muls d7,d0		; l*(l-1)
	lea -2(a3,d0.l),a2	; pointeur sur le premier bit
	moveq #-1,d3
	add d7,d3				; l-1
	neg d3					; -(l-1)
	swap d3					; d3 vaut "-(l-1)" et "-1" les deux directions … alterner
								; gauche et haut
	moveq #-1,d1
	sub d7,d1				; -(l+1)
	neg d1					; l+1
	swap d1					; d1 vaut "l+1" et "-1" pour bas et gauche
	
	move.l debut-24(pc),a1
	add.l a3,a1				; pointe sur les donn‚es
	move.l debut-28(pc),d6	; taille des donn‚es
	moveq #-9,d2
	add.l d7,d2				; pour d‚tecter la colonne du timing vertical
	bra.s .loop
.un_octet:
	move.b (a1)+,d5		; nouvel octet
	moveq #7,d4				; compteur de bits
.lb1:
	move.b (a2),d0			; emplacement actuel
	beq.s .libre
	cmp.b #3,d0				; changement de direction?
	bne.s .lb0
	swap d3
	sub d3,a2				; on recule de la bordure
	swap d3
	exg.l d1,d3				; valeurs pour colonne invers‚e
	subq.l #1,a2			; colonne suivante
	subq #2,d2				; colonne du timing?
	bne.s .lb1
	subq.l #1,a2			; si oui, on saute cette colonne
	bra.s .lb1
.lb0:
	add d3,a2				; pas de changment, case contigue
	swap d3				
	bra.s .lb1
.libre:
	btst d4,d5				; teste un bit
	beq.s .skip				; si nul, on ne met rien
	st (a2)					; si 1, on met FF
.skip:
	add d3,a2				; et on avance
	swap d3
	dbf d4,.lb1
.loop:
	dbf d6,.un_octet
	rts


	; applique les masques et calcule la note de chacun, conserve le meilleur
	; D4 HIGH = index du dernier masque appliqu‚, low note du masque en cours
	; D5 HIGH = offset routine LOW note du meilleur pasque
	; A3 buffer (modifi‚ vers buffer du haut, puis remis … buffer du bas)
	; d6 = (-offset buffers)
	; d7 = longueur ligne
	
masques:
	add.l debut-24(pc),a3	; bascule sur le 1/2 buffer du haut
	bsr efface_tout			; remplit de z‚ros
	bsr bordures				; ajoute les 03 tout autour
	move.l debut-24(pc),d6	; offset des deux buffers
	neg.l d6						; on pointera du haut vers le bas
	move.l #$7fff,d5			; note du meilleur masque, ici le pire, et dans D5 (high word), num‚ro du masque
	lea base(pc),a0
.parse_mask:
	move (a0)+,d0				; offset routine
	beq.s .fin_liste			; tous les masques appliqu‚s
	bsr applique_masque
	bsr calcule_note			; renvoy‚e dans d4.W le haut est r‚serv‚
	cmp d4,d5
	bls.s .parse_mask			; on a d‚j… plus bas
	move d4,d5					; sinon meilleure note
	swap d5
	move -2(a0),d5				; et conserve l'offset "base" de la routine
	swap d5
	bra.s .parse_mask
.fin_liste:
	swap d5
	move d5,d0					; l'offset
	moveq #0,d6					; transformation sur place
	move.l debut-20(pc),a3	; et sur le premier bloc
	bsr applique_masque
	swap d4
	lea debut-30(pc),a0
	move d4,(a0)				; renvoie le numero de masque
	rts	
	
applique_masque:
	lea base(pc),a1
	add.w d0,a1					; routine d'initialisation du masque
	lea 1(a3,d7.l),a2			; buffer du haut
	jsr (a1)						; initialise le masque
.m0:	
	moveq #0,d0
	move.b 0(a2,d6.l),d0		; octet source
.lb2:
	beq.s .lb0					; z‚ro, rien … ajouter
	bmi.s .noir
	cmp.b #3,d0					; une bordure?
	bne.s .lb1					; non, c'est un 02 = blanc r‚serv‚
	addq.l #2,a2				; passe … la ligne suivante
	bset #31,d0					; marque le changement de ligne
	move.b 0(a2,d6.l),d0		; reprend la nouvelle source
	cmp.b #3,d0					; encore une bordure?
	beq.s .fin_masque
	tst.b d0
	bra.s .lb2
.noir:
	btst #0,d0
	bne.s .lb0					; FF noir normal
	st d0							; sinon transforme FE en FF
	bra.s .lb3					; c'est un noir r‚serv‚
.lb1:
	sf d0							; blanc
.lb3:
	bset #15,d0					; et r‚serv‚	
.lb0:
	jsr (a1)						; applique le masque
	move.b d0,(a2)+			; copie l'octet (modifi‚ ou non)	
	bra.s .m0
.fin_masque:
	rts
	
calcule_note:
	clr d4						; ne pas modifier le HIGH
	lea 1(a3,d7.l),a2			; pointe sur le premier pixel, on est d‚j… dans le buffer du haut
	move.l a2,-(sp)
	bsr eval_lignes
	move.l (sp),a2
	bsr eval_colonnes
	move.l (sp),a2
	bsr eval_blocks
	move.l (sp)+,a2
	bsr eval_blacknwhite
	rts
	
	; compte les alignements de 5+ cons‚cultifs
	; v‚rifie les patterns  ----*-***-* ou *-***-*----
	
eval_lignes:
	move.b #22,d2	; valeur dum
	moveq #0,d1		; taille block dum
.lb0:
	move.b (a2)+,d0
	cmp.b d0,d2		; encore la mˆme?
	bne.s .lb1
	addq #1,d1		; oui, on compte
	bra.s .lb0
.lb1:					; non, on regarde la taille
	bsr .finders	; regarde le pattern finder
	subq #5,d1
	bmi.s .lb3		; pas de p‚nalit‚ si moins de 5
	addq #3,d1		; p‚nalit‚ (5=3, 6=4...)
	add d1,d4
.lb3:
	cmp.b #3,d0		; une bordure?
	beq.s .lb4		; oui, changer de ligne
	move.b d0,d2	; sinon, nouveau modŠle
	moveq #1,d1		; et on recompte … 1
	bra.s .lb0
.lb4:
	addq.l #1,a2	; saute la bordure
	cmp.b #3,(a2)	; encore? (c'est qu'on est sur la ligne de fond)
	bne.s eval_lignes
	rts
.finders:
	cmp.b #4,d1
	bmi.s .lb6		; moins de 4
	tst.b d2
	bne.s .lb6		; c'‚taient de FF...
	; donc ici au moins 4 blancs cons‚cutifs
	tst.b d0			; suivi d'un FF?
	bpl.s .lb5		; non bordure
	move.l a2,a1
	tst.b (a1)+		; et un 00
	bne.s .lb5		
	tst.b (a1)+		; et trois FF ?
	bpl.s .lb5
	tst.b (a1)+
	bpl.s .lb5
	tst.b (a1)+
	bpl.s .lb5	
	tst.b (a1)+		; et un 00
	bne.s .lb5		
	tst.b (a1)+		; et un FF ?
	bpl.s .lb5
	add.w #40,d4	; si tout est bon... p‚nalit‚ !
.lb5:
	lea -1(a2),a1
	sub d1,a1		; revient avant la zone blanche
	tst.b -(a1)		; pr‚c‚d‚e d'un FF?
	bpl.s .lb6		; non bordure
	tst.b -(a1)		; et un 00
	bne.s .lb6		
	tst.b -(a1)		; et trois FF ?
	bpl.s .lb6
	tst.b -(a1)
	bpl.s .lb6
	tst.b -(a1)
	bpl.s .lb6	
	tst.b -(a1)		; et un 00
	bne.s .lb6		
	tst.b -(a1)		; et un FF ?
	bpl.s .lb6
	add.w #40,d4	; si tout est bon... p‚nalit‚ !	
.lb6:
	rts
	
	; compte les alignements de 5+ cons‚cultifs
	; et les patterns findes ----*-***-* ou *-***-*----
eval_colonnes:
	move.l a0,-(sp)
.encore:
	lea 1(a2),a0	; colonne suivante
	move.b #22,d2	; valeur dum
	moveq #0,d1		; taille block dum
.lb0:
	move.b (a2),d0
	add.l d7,a2
	cmp.b d0,d2		; encore la mˆme?
	bne.s .lb1
	addq #1,d1		; oui, on compte
	bra.s .lb0
.lb1:					; non, on regarde la taille
	bsr.s .finders	; regarde la motif finders
	subq #5,d1
	bmi.s .lb3		; pas de p‚nalit‚ si moins de 5
	addq #3,d1		; p‚nalit‚ (5=3, 6=4...)
	add d1,d4
.lb3:
	cmp.b #3,d0		; une bordure?
	beq.s .lb4		; oui, changer de colonne
	move.b d0,d2	; sinon, nouveau modŠle
	moveq #1,d1		; et on recompte … 1
	bra.s .lb0
.lb4:
	move.l a0,a2	; colonne suivante
	cmp.b #3,(a2)	; encore? (c'est qu'on est sur la colonne de droite)
	bne.s .encore
	move.l (sp)+,a0
	rts
.finders:
	cmp.b #4,d1
	bmi.s .lb6		; moins de 4
	tst.b d2
	bne.s .lb6		; c'‚taient de FF...
	; donc ici au moins 4 blancs cons‚cutifs
	tst.b d0			; suivi d'un FF?
	bpl.s .lb5		; non bordure
	lea 0(a2,d7.l),a1
	tst.b (a1)		; et un 00
	bne.s .lb5
	add.l d7,a1		
	tst.b (a1)		; et trois FF ?
	bpl.s .lb5
	add.l d7,a1		
	tst.b (a1)
	bpl.s .lb5
	add.l d7,a1		
	tst.b (a1)
	bpl.s .lb5	
	add.l d7,a1		
	tst.b (a1)		; et un 00
	bne.s .lb5		
	add.l d7,a1		
	tst.b (a1)		; et un FF ?
	bpl.s .lb5
	add.w #40,d4	; si tout est bon... p‚nalit‚ !
.lb5:
	moveq #-1,d3
	sub d1,d3
	muls d7,d3
	lea 0(a2,d3.l),a1	; retour au d‚but de la zone blanche
	tst.b (a1)		; pr‚c‚d‚e d'un FF?
	bpl.s .lb6		; non bordure
	sub.l d7,a1
	tst.b (a1)		; et un 00
	bne.s .lb6		
	sub.l d7,a1
	tst.b (a1)		; et trois FF ?
	bpl.s .lb6
	sub.l d7,a1
	tst.b (a1)
	bpl.s .lb6
	sub.l d7,a1
	tst.b (a1)
	bpl.s .lb6	
	sub.l d7,a1
	tst.b (a1)		; et un 00
	bne.s .lb6		
	sub.l d7,a1
	tst.b (a1)		; et un FF ?
	bpl.s .lb6
	add.w #40,d4	; si tout est bon... p‚nalit‚ !	
.lb6:
	rts	


	; compte les blocs 2x2
	
eval_blocks:
	move.l d7,d2	
	subq.l #4,d2	; boucle verticale	
.lb2:
	move.l d7,d1	
	subq.l #4,d1	; pour la boucle horizontale
.lb1:
	move.b (a2)+,d0
	cmp.b (a2),d0
	bne.s .lb0		; les 2 premiers diff‚rents... on saute
	cmp.b 0(a2,d7.l),d0
	bne.s .lb0		; pas ‚gal … dessous-droite... on saute
	cmp.b -1(a2,d7.l),d0
	bne.s .lb0		; pas ‚gal … dessous-gauche... on saute
	addq #3,d4		; sinon, p‚nalit‚
.lb0:
	dbf d1,.lb1
	addq.l #3,a2	; saute la bordure
	dbf d2,.lb2
	rts
	
	; compte l'‚cart proportion noir/blancs par rapport … 50-50
eval_blacknwhite:
	move.l d7,d2
	subq.l #3,d2
	moveq #0,d1		; nombre de noirs
.lb0:
	move.l d7,d0
	subq.l #3,d0
.lb1:
	tst.b (a2)+
	beq.s .lb2
	addq.l #1,d1	; un noir de plus
.lb2:
	dbf d0,.lb1
	addq.l #2,a2	; saute la bordure
	dbf d2,.lb0		; ligne suivante
	muls #100,d1	; 100*noirs
	move.l d7,d0
	subq #2,d0
	muls d0,d0		; total des cases
	divu d0,d1		; d1 = pourcentage de noir
	ext.l d1
	divu #5,d1		; puis en multiple de 5
	bpl.s .lb3
	addq #1,d1
	neg d1
.lb3:
	muls #10,d1
	add d1,d4		; p‚nalit‚
	rts
	
	; initialisation du masque
	; *-*-*-* ...
	; -*-*-*- ...
	
damier:
	moveq #0,d3					; compteur de parit‚ initialis‚
	moveq #0,d4					; HIGH = 0, code du masque damier
	lea _damier(pc),a1
	rts
	
_damier:
	not d3
	beq.s .lb0					; si z‚ro, rien … changer
	tst d0
	bmi.s .lb0					; si octet r‚serv‚, rien … changer
	not d0						; sinon, inverse le pixel
.lb0:
	rts

	; initialisation du masque
	; ******* ...
	; ------- ...	

ligne:
	moveq #0,d3					; compteur de parit‚ lignes
	moveq #1,d4
	swap d4						; num‚ro de masque
	lea _ligne(pc),a1
	rts
	
_ligne:
	tst.l d0						; une nouvelle ligne?
	bpl.s .lb0				
	not d3						; si oui, bascule 00 en FF
.lb0:
	tst d0
	bmi.s .lb1					; si r‚serv‚, rien … changer
	tst.b d3
	bne.s .lb1					; rien … faire sur les lignes 00
	not.b d0						; sinon inverser
.lb1:
	rts	

	; initialisation masque 
	; *--*--*--
	; *--*--*--
	
colonne:
	moveq #0,d3					; compteur 2-1-0
	moveq #2,d4
	swap d4						; num‚ro de masque
	lea _colonne(pc),a1
	rts
	
_colonne:
	tst.l d0
	bpl.s .lb0
	moveq #0,d3					; nouvelle ligne, remis … z‚ro
.lb0:
	tst d0
	bmi.s .lb1					; r‚serv‚, on saute
	tst.b d3
	bne.s .lb1					; pas z‚ro? on saute
	not.b d0						; sinon, inverse
.lb1:
	subq #1,d3
	bpl.s .lb2					; si encore positif, on garde
	moveq #2,d3					; sinon, retour … 2
.lb2:
	rts

	; motif
	; *--*--
	; --*--*
	; -*--*-
	; *--*--
	
diagonale:
	moveq #0,d3					; compteur 2-1-0 ligne
	moveq #0,d2					; compteur 2-1-0 colonne
	moveq #3,d4
	swap d4						; num‚ro de masque
	lea _diagonale(pc),a1
	rts
	
_diagonale:
	tst.l d0
	bpl.s .lb0
	subq #1,d2					; nouvelle ligne, donc nouveau d‚calage
	bpl.s .lb3
	moveq #2,d2
.lb3:
	move d2,d3					; nouvelle ligne, remis … z‚ro
.lb0:
	tst d0
	bmi.s .lb1					; r‚serv‚, on saute
	tst.b d3
	bne.s .lb1					; pas z‚ro? on saute
	not.b d0						; sinon, inverse
.lb1:
	subq #1,d3
	bpl.s .lb2					; si encore positif, on garde
	moveq #2,d3					; sinon, retour … 2
.lb2:
	rts

motif4:
	moveq #4,d4
	moveq #5,d2					; motif de 4 de haut
	lea .motif(pc),a1
	bra.s _motif_comm
.motif:
	dc.b %111000
	dc.b %111000
	dc.b %000111
	dc.b %000111
	dc.w 0
	
motif5:	
	moveq #5,d4
	moveq #7,d2					; motif de 6 de haut
	lea .motif(pc),a1
	bra.s _motif_comm
.motif:
	dc.b %111111
	dc.b %100000
	dc.b %100100
	dc.b %101010
	dc.b %100100
	dc.b %100000
	dc.w 0

_motif_comm:
	swap d4
	swap d2
	moveq #5,d3			; bit count
	move.b (a1)+,d2	; mask
	move.l a1,d1		; conserve pointeur
	lea _motif(pc),a1
	rts
	
motif6:
	moveq #6,d4
	moveq #7,d2					; motif de 6 de haut
	lea .motif(pc),a1
	bra.s _motif_comm
.motif:
	dc.b %111111
	dc.b %111000
	dc.b %110110
	dc.b %101010
	dc.b %101101
	dc.b %100011
	dc.w 0
	
motif7:
	moveq #7,d4
	moveq #7,d2					; motif de 6 de haut
	lea .motif(pc),a1
	bra.s _motif_comm
.motif:
	dc.b %101010
	dc.b %000111
	dc.b %100011
	dc.b %010101
	dc.b %111000
	dc.b %011100
	dc.w 0
	
_motif:
	tst.l d0			; nouvelle ligne?
	bpl.s .lb0
	move.l d1,a1	; r‚cupŠre pointeur
	moveq #5,d3			; retour au d‚but
	move.b (a1)+,d2	; et nouveau masque
	bne.s .lb1			; correct
	swap d2
	sub.w d2,a1			; si 0, retour au d‚but de la liste	
	swap d2
	move.b (a1)+,d2
.lb1:
	move.l a1,d1
	lea _motif(pc),a1
.lb0:
	tst.w d0				; r‚serv‚?
	bmi.s .lb2			; oui, on saute
	btst d3,d2
	beq.s .lb2			; pas de changement
	not.b d0				; sinon on inverse
.lb2:
	subq #1,d3			; bit suivant
	bpl.s .lb3
	moveq #5,d3			; retour en haut
.lb3:
	rts
	

	
	; la routine initialise et modifie a1 pour la suite, renvoie dans D4 HIGH le code du masque (0-7)
	; peut utiliser d1-d2-d3
	; elle recoit d0 = L--- ---- ---- ---- R--- ---- VVVV VVVV
	; L = 1 si nouvelle ligne
	; R = 1 si octet r‚serv‚
	; VVVV VVVV = FF ou 00 pour noir/blanc
	
base:
;	dc.w damier-base,0
	dc.w damier-base,ligne-base,colonne-base,diagonale-base
	dc.w motif4-base,motif5-base,motif6-base,motif7-base
	dc.w 0
	
	
	; a3 = buffer
	; d7 = taille ligne
	; d4 = LOW (modŠle masque) d‚j… swapp‚ dans "masques"
	
informations:
	lea info_level_mask(pc),a0
	add d4,d4						; mask*2
	move debut-2(pc),d1			; level 
	lsl #4,d1
	add d4,d1						; level*16 + mask*2 = offset!
	move 0(a0,d1),d4				; D4 = 15 bits d'informations (bits 0 … 14)
	move.l d7,d0
	subq.l #2,d0
	muls d7,d0
	lea 9(a3,d0.l),a0				; zone info prŠs de finder 3
	moveq #9,d0
	muls d7,d0
	lea 1(a3,d0.l),a1				; zone info sous le finder 1
	moveq #14,d0					; compteur de bits
.lb0:
	tst.b (a1)						; s'il y a d‚j… un noir sur finder 1
	beq.s .lb1
	addq.l #1,a1					; alors on le passe (c'est la timing zone)
.lb1:
	btst d0,d4
	sne (a0)							; 00 ou FF sur finder 3
	sne (a1)+						; idem sur finder 1
	sub.l d7,a0
	subq #1,d0
	cmp #7,d0						; … partir du bit 7, on change de zone !
	bne.s .lb0
	lea -18(a1),a0
	add.l d7,a0						; zone info sous finder 2
.lb3:
	tst.b (a1)						; s'il y a d‚j… un noir sur finder 1
	beq.s .lb4
	sub.l d7,a1						; on le passe (timing zone)
.lb4:	
	btst d0,d4
	sne (a0)+						; finder 2
	sne (a1)							; finder 1
	sub.l d7,a1
	dbf d0,.lb3	
	move debut-12(pc),d4			; version
	subq #7,d4
	bmi.s .out						; version < 7, pas d'info en plus
	lsl #2,d4						; *4 pour des longs
	lea version7plus(pc),a0
	move.l 0(a0,d4.w),d4			; les 18 bits d'info
	lea -12(a3,d7.l),a2
	add.l d7,a2						; position l-12 prŠs du 2e finder
	moveq #0,d0				; bit counter
.lb7:
	moveq #2,d1				; line counter
.lb5:
	btst d0,d4
	sne (a2)+
	addq #1,d0
	dbf d1,.lb5
	cmp #18,d0				; fin?
	beq.s .lb6
	lea -3(a2,d7.l),a2
	bra.s .lb7
.lb6:
	moveq #-12,d0
	add d7,d0
	muls d7,d0
	lea 1(a3,d0.l),a2		; position l-12 prŠs du 3e finder
	moveq #0,d0				; bit counter
.lb8:	
	btst d0,d4
	sne (a2)+
	addq #3,d0
	cmp #18,d0
	bmi.s .lb8
	sub #17,d0
	lea -6(a2,d7.l),a2	; ligne suivante
	cmp.b #3,d0
	bne.s .lb8
.out:
	rts	

	if LDV=0		; *********** ajout d'icone seulement dans le FOM
	; a2 = mfdbs
	; icone = iconblk
	
ajoute_icone:
	move.l icone(pc),d0		; si adresse nulle...
	bne.s .ok
	rts							; ... alors retour, rien … faire.
.ok:
	move.l d0,a3				; iconblk
	move 6(a2),d0				; hq
	move 24(a3),d4				; hi
	sub d4,d0					; hq-hi
	move 8(a2),d1				; lq.w
	move d1,d3
	add d3,d3					; taille d'une ligne en octets
	muls d1,d0
	move 22(a3),d2				; li
	lsr #4,d2					; li.w
	sub d2,d1					; lq.w-li.w
	add d1,d0					; offset 1er octet dans QRcode sous l'icone
	move.l (a2),a0
	add d0,a0					; adresse 1er octet icone
	move.l (a3)+,a1			; le masque
	move.l (a3)+,a2			; les donn‚es
	add d2,d2					; li en octets
	subq #1,d2					; pour les boucles
	bra.s .lb2
.lb1:
	move.l a0,a3
	move d2,d5
.lb0;	
	move.b (a0),d0				; un octet du QRcode
	move.b (a1)+,d1			; le masque
	not.b d1
	and.b d1,d0					; applique le masque
	or.b (a2)+,d0				; puis l'icone
	move.b d0,(a0)+
	dbf d5,.lb0
	lea 0(a3,d3.w),a0			; d‚but nouvelle ligne
.lb2:
	dbf d4,.lb1
	rts
	
	endif			; ************* fin d'ajout d'icone FOM

	; a2 le mfdbs … remplir
	; a3 buffer
	; d7 taille ligne
	
format_ecran:
	move.l a4,-(sp)
	lea 180(a3),a0		; l… ou commencera les bloc pixels
	move.l a0,(a2)+	; mfdbs ADDR
	move.l d7,d6
	lsl.l #2,d6			; *4 pixels
	add #15,d6
	and.b #$F0,d6		; largeur arrondie au bloc de 16
	move d6,(a2)+		; mfdbs L
	move d7,d0
	lsl #2,d0
	move d0,(a2)+		; mfdbs H
	lsr.l #4,d6
	move d6,(a2)+		; mfdbs L en mots
	moveq #1,d1
	move.l d1,(a2)+	; mfdbs format 0 et 1 plan
	add.l d6,d6			; largeur image en octets
	muls d6,d0			; taille totale en octets de l'image
	add.l d0,a0			; pointe sur la fin de l'image.
	move d7,d0
	muls d7,d0			; taille totale des octets FF/00
	add.l d0,a3			; pointe sur la fin des donn‚es
	move d7,d5
	addq #3,d5
	and.b #$FC,d5		; d5=longueur arrondie au 4 sup‚rieur
	sub d7,d5			; d5 = pixels vides … ajouter … chaque ligne
	move d7,d2
	bra.s .lb6
.lb7:	
	neg.l d6
	lea 0(a0,d6.l),a1
	lea 0(a1,d6.l),a2
	lea 0(a2,d6.l),a4
	neg.l d6
	move d5,d0
	bra.s .lb0
.lb1:
	clr.b (a3)+			; ajoute des pixels vides pour aligner sur 16
.lb0:
	dbf d0,.lb1
	move d6,d0
	bra.s .lb2
.lb3:
	moveq #0,d1
	tst.b -(a3)
	bpl.s .lb4
	or.b #$F,d1
.lb4:
	tst.b -(a3)
	bpl.s .lb5
	or.b #$F0,d1
.lb5:
	move.b d1,-(a0)
	move.b d1,-(a1)
	move.b d1,-(a2)
	move.b d1,-(a4)
.lb2:
	dbf d0,.lb3
	move.l a4,a0		; le pointeur le plus bas est notre nouvelle ref
.lb6:
	dbf d2,.lb7	
	move.l (sp)+,a4
	rts	

	if LDV=0	
	data
	endif

	; tableau du nombre de bits pour encoder la taille des donn‚es
	; dc.b v,n,a,b,k
	; v = jusqu'… version v
	; n = nombre de bits en mode NUM
	; puis mode ALPH, BIN, KEN
	
count_len:
	dc.b 9,10,9,8,8
	dc.b 26,12,11,16,10
	dc.b 40,14,13,16,12
	even

	; pour chaque version: 4 fois deux lignes pour les 4 niveaux de correction d'erreur L,M,Q,H
	; premiŠre ligne (mots)  :
	; +0 nombre max de caractŠres en mode Num‚rique
	; +2 idem mode alpha
	; +4 idem mode byte
	; +6 idem mode kenjii
	; +8 total octets + EC (error codes)
	
	; deuxiŠme ligne (octets):
	; +10 nombre d'octets EC par bloc
	; +11 nombre de groupes dans le bloc 1
	; +12 nombre de codes par groupe 1
	; +13 nombre de groupes dans le bloc 2
	; +14 nombre de codes par groupe 2
	; +15 valeur dum pour compl‚ter … 16

data_version:
   ; version 1
   dc.w 41,25,17,10,19
   dc.b 7,1,19,0,0,10
   dc.w 34,20,14,8,16
   dc.b 10,1,16,0,0,9
   dc.w 27,16,11,7,13
   dc.b 13,1,13,0,0,8
   dc.w 17,10,7,4,9
   dc.b 17,1,9,0,0,8
   ; version 2
   dc.w 77,47,32,20,34
   dc.b 10,1,34,0,0,10
   dc.w 63,38,26,16,28
   dc.b 16,1,28,0,0,9
   dc.w 48,29,20,12,22
   dc.b 22,1,22,0,0,8
   dc.w 34,20,14,8,16
   dc.b 28,1,16,0,0,8
   ; version 3
   dc.w 127,77,53,32,55
   dc.b 15,1,55,0,0,10
   dc.w 101,61,42,26,44
   dc.b 26,1,44,0,0,9
   dc.w 77,47,32,20,34
   dc.b 18,2,17,0,0,8
   dc.w 58,35,24,15,26
   dc.b 22,2,13,0,0,8
   ; version 4
   dc.w 187,114,78,48,80
   dc.b 20,1,80,0,0,10
   dc.w 149,90,62,38,64
   dc.b 18,2,32,0,0,9
   dc.w 111,67,46,28,48
   dc.b 26,2,24,0,0,8
   dc.w 82,50,34,21,36
   dc.b 16,4,9,0,0,8
   ; version 5
   dc.w 255,154,106,65,108
   dc.b 26,1,108,0,0,10
   dc.w 202,122,84,52,86
   dc.b 24,2,43,0,0,9
   dc.w 144,87,60,37,62
   dc.b 18,2,15,2,16,8
   dc.w 106,64,44,27,46
   dc.b 22,2,11,2,12,8
   ; version 6
   dc.w 322,195,134,82,136
   dc.b 18,2,68,0,0,10
   dc.w 255,154,106,65,108
   dc.b 16,4,27,0,0,9
   dc.w 178,108,74,45,76
   dc.b 24,4,19,0,0,8
   dc.w 139,84,58,36,60
   dc.b 28,4,15,0,0,8
   ; version 7
   dc.w 370,224,154,95,156
   dc.b 20,2,78,0,0,10
   dc.w 293,178,122,75,124
   dc.b 18,4,31,0,0,9
   dc.w 207,125,86,53,88
   dc.b 18,2,14,4,15,8
   dc.w 154,93,64,39,66
   dc.b 26,4,13,1,14,8
   ; version 8
   dc.w 461,279,192,118,194
   dc.b 24,2,97,0,0,10
   dc.w 365,221,152,93,154
   dc.b 22,2,38,2,39,9
   dc.w 259,157,108,66,110
   dc.b 22,4,18,2,19,8
   dc.w 202,122,84,52,86
   dc.b 26,4,14,2,15,8
   ; version 9
   dc.w 552,335,230,141,232
   dc.b 30,2,116,0,0,10
   dc.w 432,262,180,111,182
   dc.b 22,3,36,2,37,9
   dc.w 312,189,130,80,132
   dc.b 20,4,16,4,17,8
   dc.w 235,143,98,60,100
   dc.b 24,4,12,4,13,8
   ; version 10
   dc.w 652,395,271,167,274
   dc.b 18,2,68,2,69,12
   dc.w 513,311,213,131,216
   dc.b 26,4,43,1,44,11
   dc.w 364,221,151,93,154
   dc.b 24,6,19,2,20,16
   dc.w 288,174,119,74,122
   dc.b 28,6,15,2,16,10
   ; version 11
   dc.w 772,468,321,198,324
   dc.b 20,4,81,0,0,12
   dc.w 604,366,251,155,254
   dc.b 30,1,50,4,51,11
   dc.w 427,259,177,109,180
   dc.b 28,4,22,4,23,16
   dc.w 331,200,137,85,140
   dc.b 24,3,12,8,13,10
   ; version 12
   dc.w 883,535,367,226,370
   dc.b 24,2,92,2,93,12
   dc.w 691,419,287,177,290
   dc.b 22,6,36,2,37,11
   dc.w 489,296,203,125,206
   dc.b 26,4,20,6,21,16
   dc.w 374,227,155,96,158
   dc.b 28,7,14,4,15,10
   ; version 13
   dc.w 1022,619,425,262,428
   dc.b 26,4,107,0,0,12
   dc.w 796,483,331,204,334
   dc.b 22,8,37,1,38,11
   dc.w 580,352,241,149,244
   dc.b 24,8,20,4,21,16
   dc.w 427,259,177,109,180
   dc.b 22,12,11,4,12,10
   ; version 14
   dc.w 1101,667,458,282,461
   dc.b 30,3,115,1,116,12
   dc.w 871,528,362,223,365
   dc.b 24,4,40,5,41,11
   dc.w 621,376,258,159,261
   dc.b 20,11,16,5,17,16
   dc.w 468,283,194,120,197
   dc.b 24,11,12,5,13,10
   ; version 15
   dc.w 1250,758,520,320,523
   dc.b 22,5,87,1,88,12
   dc.w 991,600,412,254,415
   dc.b 24,5,41,5,42,11
   dc.w 703,426,292,180,295
   dc.b 30,5,24,7,25,16
   dc.w 530,321,220,136,223
   dc.b 24,11,12,7,13,10
   ; version 16
   dc.w 1408,854,586,361,589
   dc.b 24,5,98,1,99,12
   dc.w 1082,656,450,277,453
   dc.b 28,7,45,3,46,11
   dc.w 775,470,322,198,325
   dc.b 24,15,19,2,20,16
   dc.w 602,365,250,154,253
   dc.b 30,3,15,13,16,10
   ; version 17
   dc.w 1548,938,644,397,647
   dc.b 28,1,107,5,108,12
   dc.w 1212,734,504,310,507
   dc.b 28,10,46,1,47,11
   dc.w 876,531,364,224,367
   dc.b 28,1,22,15,23,16
   dc.w 674,408,280,173,283
   dc.b 28,2,14,17,15,10
   ; version 18
   dc.w 1725,1046,718,442,721
   dc.b 30,5,120,1,121,12
   dc.w 1346,816,560,345,563
   dc.b 26,9,43,4,44,11
   dc.w 948,574,394,243,397
   dc.b 28,17,22,1,23,16
   dc.w 746,452,310,191,313
   dc.b 28,2,14,19,15,10
   ; version 19
   dc.w 1903,1153,792,488,795
   dc.b 28,3,113,4,114,12
   dc.w 1500,909,624,384,627
   dc.b 26,3,44,11,45,11
   dc.w 1063,644,442,272,445
   dc.b 26,17,21,4,22,16
   dc.w 813,493,338,208,341
   dc.b 26,9,13,16,14,10
   ; version 20
   dc.w 2061,1249,858,528,861
   dc.b 28,3,107,5,108,12
   dc.w 1600,970,666,410,669
   dc.b 26,3,41,13,42,11
   dc.w 1159,702,482,297,485
   dc.b 30,15,24,5,25,16
   dc.w 919,557,382,235,385
   dc.b 28,15,15,10,16,10
   ; version 21
   dc.w 2232,1352,929,572,932
   dc.b 28,4,116,4,117,12
   dc.w 1708,1035,711,438,714
   dc.b 26,17,42,0,0,11
   dc.w 1224,742,509,314,512
   dc.b 28,17,22,6,23,16
   dc.w 969,587,403,248,406
   dc.b 30,19,16,6,17,10
   ; version 22
   dc.w 2409,1460,1003,618,1006
   dc.b 28,2,111,7,112,12
   dc.w 1872,1134,779,480,782
   dc.b 28,17,46,0,0,11
   dc.w 1358,823,565,348,568
   dc.b 30,7,24,16,25,16
   dc.w 1056,640,439,270,442
   dc.b 24,34,13,0,0,10
   ; version 23
   dc.w 2620,1588,1091,672,1094
   dc.b 30,4,121,5,122,12
   dc.w 2059,1248,857,528,860
   dc.b 28,4,47,14,48,11
   dc.w 1468,890,611,376,614
   dc.b 30,11,24,14,25,16
   dc.w 1108,672,461,284,464
   dc.b 30,16,15,14,16,10
   ; version 24
   dc.w 2812,1704,1171,721,1174
   dc.b 30,6,117,4,118,12
   dc.w 2188,1326,911,561,914
   dc.b 28,6,45,14,46,11
   dc.w 1588,963,661,407,664
   dc.b 30,11,24,16,25,16
   dc.w 1228,744,511,315,514
   dc.b 30,30,16,2,17,10
   ; version 25
   dc.w 3057,1853,1273,784,1276
   dc.b 26,8,106,4,107,12
   dc.w 2395,1451,997,614,1000
   dc.b 28,8,47,13,48,11
   dc.w 1718,1041,715,440,718
   dc.b 30,7,24,22,25,16
   dc.w 1286,779,535,330,538
   dc.b 30,22,15,13,16,10
   ; version 26
   dc.w 3283,1990,1367,842,1370
   dc.b 28,10,114,2,115,12
   dc.w 2544,1542,1059,652,1062
   dc.b 28,19,46,4,47,11
   dc.w 1804,1094,751,462,754
   dc.b 28,28,22,6,23,16
   dc.w 1425,864,593,365,596
   dc.b 30,33,16,4,17,10
   ; version 27
   dc.w 3517,2132,1465,902,1468
   dc.b 30,8,122,4,123,14
   dc.w 2701,1637,1125,692,1128
   dc.b 28,22,45,3,46,13
   dc.w 1933,1172,805,496,808
   dc.b 30,8,23,26,24,16
   dc.w 1501,910,625,385,628
   dc.b 30,12,15,28,16,12
   ; version 28
   dc.w 3669,2223,1528,940,1531
   dc.b 30,3,117,10,118,14
   dc.w 2857,1732,1190,732,1193
   dc.b 28,3,45,23,46,13
   dc.w 2085,1263,868,534,871
   dc.b 30,4,24,31,25,16
   dc.w 1581,958,658,405,661
   dc.b 30,11,15,31,16,12
   ; version 29
   dc.w 3909,2369,1628,1002,1631
   dc.b 30,7,116,7,117,14
   dc.w 3035,1839,1264,778,1267
   dc.b 28,21,45,7,46,13
   dc.w 2181,1322,908,559,911
   dc.b 30,1,23,37,24,16
   dc.w 1677,1016,698,430,701
   dc.b 30,19,15,26,16,12
   ; version 30
   dc.w 4158,2520,1732,1066,1735
   dc.b 30,5,115,10,116,14
   dc.w 3289,1994,1370,843,1373
   dc.b 28,19,47,10,48,13
   dc.w 2358,1429,982,604,985
   dc.b 30,15,24,25,25,16
   dc.w 1782,1080,742,457,745
   dc.b 30,23,15,25,16,12
   ; version 31
   dc.w 4417,2677,1840,1132,1843
   dc.b 30,13,115,3,116,14
   dc.w 3486,2113,1452,894,1455
   dc.b 28,2,46,29,47,13
   dc.w 2473,1499,1030,634,1033
   dc.b 30,42,24,1,25,16
   dc.w 1897,1150,790,486,793
   dc.b 30,23,15,28,16,12
   ; version 32
   dc.w 4686,2840,1952,1201,1955
   dc.b 30,17,115,0,0,14
   dc.w 3693,2238,1538,947,1541
   dc.b 28,10,46,23,47,13
   dc.w 2670,1618,1112,684,1115
   dc.b 30,10,24,35,25,16
   dc.w 2022,1226,842,518,845
   dc.b 30,19,15,35,16,12
   ; version 33
   dc.w 4965,3009,2068,1273,2071
   dc.b 30,17,115,1,116,14
   dc.w 3909,2369,1628,1002,1631
   dc.b 28,14,46,21,47,13
   dc.w 2805,1700,1168,719,1171
   dc.b 30,29,24,19,25,16
   dc.w 2157,1307,898,553,901
   dc.b 30,11,15,46,16,12
   ; version 34
   dc.w 5253,3183,2188,1347,2191
   dc.b 30,13,115,6,116,14
   dc.w 4134,2506,1722,1060,1725
   dc.b 28,14,46,23,47,13
   dc.w 2949,1787,1228,756,1231
   dc.b 30,44,24,7,25,16
   dc.w 2301,1394,958,590,961
   dc.b 30,59,16,1,17,12
   ; version 35
   dc.w 5529,3351,2303,1417,2306
   dc.b 30,12,121,7,122,14
   dc.w 4343,2632,1809,1113,1812
   dc.b 28,12,47,26,48,13
   dc.w 3081,1867,1283,790,1286
   dc.b 30,39,24,14,25,16
   dc.w 2361,1431,983,605,986
   dc.b 30,22,15,41,16,12
   ; version 36
   dc.w 5836,3537,2431,1496,2434
   dc.b 30,6,121,14,122,14
   dc.w 4588,2780,1911,1176,1914
   dc.b 28,6,47,34,48,13
   dc.w 3244,1966,1351,832,1354
   dc.b 30,46,24,10,25,16
   dc.w 2524,1530,1051,647,1054
   dc.b 30,2,15,64,16,12
   ; version 37
   dc.w 6153,3729,2563,1577,2566
   dc.b 30,17,122,4,123,14
   dc.w 4775,2894,1989,1224,1992
   dc.b 28,29,46,14,47,13
   dc.w 3417,2071,1423,876,1426
   dc.b 30,49,24,10,25,16
   dc.w 2625,1591,1093,673,1096
   dc.b 30,24,15,46,16,12
   ; version 38
   dc.w 6479,3927,2699,1661,2702
   dc.b 30,4,122,18,123,14
   dc.w 5039,3054,2099,1292,2102
   dc.b 28,13,46,32,47,13
   dc.w 3599,2181,1499,923,1502
   dc.b 30,48,24,14,25,16
   dc.w 2735,1658,1139,701,1142
   dc.b 30,42,15,32,16,12
   ; version 39
   dc.w 6743,4087,2809,1729,2812
   dc.b 30,20,117,4,118,14
   dc.w 5313,3220,2213,1362,2216
   dc.b 28,40,47,7,48,13
   dc.w 3791,2298,1579,972,1582
   dc.b 30,43,24,22,25,16
   dc.w 2927,1774,1219,750,1222
   dc.b 30,10,15,67,16,12
   ; version 40
   dc.w 7089,4296,2953,1817,2956
   dc.b 30,19,118,6,119,14
   dc.w 5596,3391,2331,1435,2334
   dc.b 28,18,47,31,48,13
   dc.w 3993,2420,1663,1024,1666
   dc.b 30,34,24,34,25,16
   dc.w 3057,1852,1273,784,1276
   dc.b 30,20,15,61,16,12
   
   ; table des coordonn‚es des alignements selon la version

align_table:   
   dc.b 0		; version 1, pas d'alignement
   dc.b 6,18,0		; version 2 (6,6) (6,18) (18,6) et (18,18)
   dc.b 6,22,0
   dc.b 6,26,0
   dc.b 6,30,0
   dc.b 6,34,0
   dc.b 6,22,38,0
   dc.b 6,24,42,0
   dc.b 6,26,46,0
   dc.b 6,28,50,0	; version 10
   dc.b 6,30,54,0
   dc.b 6,32,58,0
   dc.b 6,34,62,0
   dc.b 6,26,46,66,0
   dc.b 6,26,48,70,0
   dc.b 6,26,50,74,0
   dc.b 6,30,54,78,0
   dc.b 6,30,56,82,0
   dc.b 6,30,58,86,0
   dc.b 6,34,62,90,0	; version 20
   dc.b 6,28,50,72,94,0
   dc.b 6,26,50,74,98,0
   dc.b 6,30,54,78,102,0
   dc.b 6,28,54,80,106,0
   dc.b 6,32,58,84,110,0
   dc.b 6,30,58,86,114,0
   dc.b 6,34,62,90,118,0
   dc.b 6,26,50,74,98,122,0
   dc.b 6,30,54,78,102,126,0
   dc.b 6,26,52,78,104,130,0	; version 30
   dc.b 6,30,56,82,108,134,0
   dc.b 6,34,60,86,112,138,0
   dc.b 6,30,58,86,114,142,0
   dc.b 6,34,62,90,118,146,0
   dc.b 6,30,54,78,102,126,150,0
   dc.b 6,24,50,76,102,128,154,0
   dc.b 6,28,54,80,106,132,158,0
   dc.b 6,32,58,84,110,136,162,0
   dc.b 6,26,54,82,110,138,166,0
   dc.b 6,30,58,86,114,142,170,0	; version 40

	even

	; Table des 18 bits selon la version de 7   40
	
version7plus:
   dc.l %000111110010010100	; VERSION 7
   dc.l %001000010110111100
   dc.l %001001101010011001
   dc.l %001010010011010011
   dc.l %001011101111110110
   dc.l %001100011101100010
   dc.l %001101100001000111
   dc.l %001110011000001101
   dc.l %001111100100101000
   dc.l %010000101101111000
   dc.l %010001010001011101
   dc.l %010010101000010111
   dc.l %010011010100110010
   dc.l %010100100110100110
   dc.l %010101011010000011
   dc.l %010110100011001001
   dc.l %010111011111101100
   dc.l %011000111011000100
   dc.l %011001000111100001
   dc.l %011010111110101011
   dc.l %011011000010001110
   dc.l %011100110000011010
   dc.l %011101001100111111
   dc.l %011110110101110101
   dc.l %011111001001010000
   dc.l %100000100111010101
   dc.l %100001011011110000
   dc.l %100010100010111010
   dc.l %100011011110011111
   dc.l %100100101100001011
   dc.l %100101010000101110
   dc.l %100110101001100100
   dc.l %100111010101000001
   dc.l %101000110001101001	; VERSION 40

	; table des 15 bits selon niveau de correction et masque

info_level_mask:
   dc.w %111011111000100	;L	0
   dc.w %111001011110011	;L	1
   dc.w %111110110101010	;L	2
   dc.w %111100010011101	;L	3
   dc.w %110011000101111	;L	4
   dc.w %110001100011000	;L	5
   dc.w %110110001000001	;L	6
   dc.w %110100101110110	;L	7
   dc.w %101010000010010	;M	0
   dc.w %101000100100101	;M	1
   dc.w %101111001111100	;M	2
   dc.w %101101101001011	;M	3
   dc.w %100010111111001	;M	4
   dc.w %100000011001110	;M	5
   dc.w %100111110010111	;M	6
   dc.w %100101010100000	;M	7
   dc.w %011010101011111	;Q	0
   dc.w %011000001101000	;Q	1
   dc.w %011111100110001	;Q	2
   dc.w %011101000000110	;Q	3
   dc.w %010010010110100	;Q	4
   dc.w %010000110000011	;Q	5
   dc.w %010111011011010	;Q	6
   dc.w %010101111101101	;Q	7
   dc.w %001011010001001	;H	0
   dc.w %001001110111110	;H	1
   dc.w %001110011100111	;H	2
   dc.w %001100111010000	;H	3
   dc.w %000011101100010	;H	4
   dc.w %000011001010101	;H	5
   dc.w %000110100001100	;H	6
   dc.w %000100000111011	;H	7

vers_ibm: dc.b $c7,$fc,$e9,$e2,$e4,$e0,$e5,$e7	; 128 … 135
			 dc.b $ea,$eb,$e8,$ef,$ee,$ec,$c4,$c5	; 136 … 143
			 dc.b $c9,$e6,$c6,$f4,$f6,$f2,$fb,$f9	; 144 … 151
			 dc.b $ff,$d6,$dc,$f8,$a3,$d8,$d7,$83	; 152 … 159
			 dc.b $e1,$ed,$f3,$fa,$f1,$d1,$aa,$ba	; 160 … 167
			 dc.b $bf,$ae,$ac,$bd,$bc,$a1,$ab,$bb	; 168 … 175
			 dc.b $b0,$b1,$b2,$b3,$b4,$c1,$c2,$c0	; 176 … 183
			 dc.b $a9,$b9,$ba,$bb,$bc,$a2,$a5,$bf	; 184 … 191
			 dc.b $c0,$c1,$c2,$c3,$c4,$c5,$e3,$c3	; 192 … 199
			 dc.b $c8,$c9,$ca,$cb,$cc,$cd,$ce,$a4	; 200 … 207
			 dc.b $f0,$d0,$ca,$cb,$c8,$d5,$cd,$ce  ; 208 … 215
			 dc.b $cf,$d9,$da,$db,$dc,$a6,$cc,$df	; 216 … 223
			 dc.b $d3,$df,$d4,$d2,$f5,$d5,$b5,$fe	; 224 … 231
			 dc.b $de,$da,$db,$d9,$fd,$dd,$af,$b4	; 232 … 239
			 dc.b $f0,$b1,$f2,$be,$b6,$a7,$f7,$b8	; 240 … 247
			 dc.b $b0,$a8,$b7,$b9,$b3,$b2,$fe,$ff	; 248 … 255

	if LDV=1
expn: dcb.b 256,0	; 2^n en GF(256)
logn: dcb.b 256,0	; log2(n) en GF(256)
poly: dcb.b 32,0	; coeffs du polynome de r‚f‚rence (diviseur) degr‚ 30 maxi.
dividende: dcb.b 256,0	; a priori pas plus de 123... mais...	
	
	else
		
	bss
expn: ds.b 256	; 2^n en GF(256)
logn: ds.b 256	; log2(n) en GF(256)
poly: ds.b 32	; coeffs du polynome de r‚f‚rence (diviseur) degr‚ 30 maxi.
dividende: ds.b 256	; a priori pas plus de 123... mais...
icone: ds.l 1	; adresse idone ou 0 si absente

	endif
	
	end