/* voir le fichier qrcodes.h pour des commentaires sur l'utilisation des * fonctions */ #include "./qrcodes.h" /******************************************* * parties fixes d'un QR code de version 1 * *******************************************/ /* renvoie le nombre de pixels fixes incorrects */ int check_fixed_bits_version1(QRCode qr) { /* 1 pour noir ; 0 pour blanc ; 2 pour les bits non-constants */ char FIXED[21][21] = { {1,1,1,1,1,1,1,0,2,2,2,2,2,0,1,1,1,1,1,1,1}, {1,0,0,0,0,0,1,0,2,2,2,2,2,0,1,0,0,0,0,0,1}, {1,0,1,1,1,0,1,0,2,2,2,2,2,0,1,0,1,1,1,0,1}, {1,0,1,1,1,0,1,0,2,2,2,2,2,0,1,0,1,1,1,0,1}, {1,0,1,1,1,0,1,0,2,2,2,2,2,0,1,0,1,1,1,0,1}, {1,0,0,0,0,0,1,0,2,2,2,2,2,0,1,0,0,0,0,0,1}, {1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1}, {0,0,0,0,0,0,0,0,2,2,2,2,2,0,0,0,0,0,0,0,0}, {2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, {2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, {2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, {2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, {2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2}, {0,0,0,0,0,0,0,0,1,2,2,2,2,2,2,2,2,2,2,2,2}, {1,1,1,1,1,1,1,0,2,2,2,2,2,2,2,2,2,2,2,2,2}, {1,0,0,0,0,0,1,0,2,2,2,2,2,2,2,2,2,2,2,2,2}, {1,0,1,1,1,0,1,0,2,2,2,2,2,2,2,2,2,2,2,2,2}, {1,0,1,1,1,0,1,0,2,2,2,2,2,2,2,2,2,2,2,2,2}, {1,0,1,1,1,0,1,0,2,2,2,2,2,2,2,2,2,2,2,2,2}, {1,0,0,0,0,0,1,0,2,2,2,2,2,2,2,2,2,2,2,2,2}, {1,1,1,1,1,1,1,0,2,2,2,2,2,2,2,2,2,2,2,2,2} }; int nb_errors = 0; int i,j; for (i=0; i<21; i++) { for (j=0; j<21; j++) { if (FIXED[i][j] != 2 && qr[i][j] != FIXED[i][j]) nb_errors++; } } return nb_errors; } /********************* * format du QR code * *********************/ /* récupère les 15 bits de format, aux deux endroits * sans appliquer le masque */ void get_raw_format_bits(QRCode qr, bit format[2][15]) { int i; for (i=0; i<6; i++) format[0][i] = qr[8][i]; format[0][6] = qr[8][7]; format[0][7] = qr[8][8]; format[0][8] = qr[7][8]; for (i=9; i<15; i++) format[0][i] = qr[14-i][8]; for (i=0; i<7; i++) format[1][i] = qr[SIZE_V1-1-i][8]; for (i=7; i<15; i++) format[1][i] = qr[8][SIZE_V1-15+i]; } /* récupère les 15 bits de format, aux deux endroits * en appliquant le masque */ void get_format_bits(QRCode qr, bit format[2][15]) { int i; bit MASK[15] = { 1,0,1,0,1,0,0,0,0,0,1,0,0,1,0 }; get_raw_format_bits(qr, format); /* on applique le masque (constant) aux bits du format */ for (i=0; i<15; i++) { format[0][i] ^= MASK[i]; format[1][i] ^= MASK[i]; } } /* récupère les 5 bits de format dans "format". * S'il avait des erreurs qu'on n'a pas pu corriger, la valeur de retour est * -1, sinon c'est 0. */ int get_format(QRCode qr, int *correction_level, int *mask) { bit format_bits[2][15]; bit syndrome[2][10]; int s0,s1; int e0,e1; int i; get_format_bits(qr, format_bits); format_syndrome(format_bits[0],syndrome[0]); format_syndrome(format_bits[1],syndrome[1]); s0 = 0; for (i=0; i<10; i++) if (syndrome[0][i] != 0) s0++; s1 = 0; for (i=0; i<10; i++) if (syndrome[1][i] != 0) s1++; /* si un des formats est correct, on le garde */ if (s0 == 0) { *correction_level = 0; *correction_level |= format_bits[0][1]; *correction_level |= format_bits[0][0]<<1; *mask = 0; *mask |= format_bits[0][4]; *mask |= format_bits[0][3]<<1; *mask |= format_bits[0][2]<<2; return(0); } if (s1 == 0) { *correction_level = 0; *correction_level |= format_bits[1][1]; *correction_level |= format_bits[1][0]<<1; *mask = 0; *mask |= format_bits[1][4]; *mask |= format_bits[1][3]<<1; *mask |= format_bits[1][2]<<2; return(0); } /* si les deux résultats sont incorrect, on ne peut rien faire */ return(-1); } /********************** * données du QR code * **********************/ static void data_mask0(QRCode qr) { int i,j; for (i=0; i<21; i++) { for (j=0; j<21; j++) { if (0 == (i+j)%2) qr[i][j] ^= 1; } } } static void data_mask1(QRCode qr) { int i,j; for (i=0; i<21; i++) { for (j=0; j<21; j++) { if (0 == i%2) qr[i][j] ^= 1; } } } static void data_mask2(QRCode qr) { int i,j; for (i=0; i<21; i++) { for (j=0; j<21; j++) { if (0 == j%3) qr[i][j] ^= 1; } } } static void data_mask3(QRCode qr) { int i,j; for (i=0; i<21; i++) { for (j=0; j<21; j++) { if (0 == (i+j)%3) qr[i][j] ^= 1; } } } static void data_mask4(QRCode qr) { int i,j; for (i=0; i<21; i++) { for (j=0; j<21; j++) { if (0 == (i/2+j/3)%2) qr[i][j] ^= 1; } } } static void data_mask5(QRCode qr) { int i,j; for (i=0; i<21; i++) { for (j=0; j<21; j++) { if (0 == (i*j)%2 + (i*j)%3) qr[i][j] ^= 1; } } } static void data_mask6(QRCode qr) { int i,j; for (i=0; i<21; i++) { for (j=0; j<21; j++) { if (0 == ((i*j)%3 + i*j)%2) qr[i][j] ^= 1; } } } static void data_mask7(QRCode qr) { int i,j; for (i=0; i<21; i++) { for (j=0; j<21; j++) { if (0 == ((i*j)%3 + i+j)%2) qr[i][j] ^= 1; } } } /* applique le masque numéro m au qrcode : voir * http://en.wikiversity.org/wiki/Reed%E2%80%93Solomon_codes_for_coders#Masking * pour la liste des masques */ void data_mask(QRCode qr, int mask) { if (0 == mask) {data_mask0(qr); return; } if (1 == mask) {data_mask1(qr); return; } if (2 == mask) {data_mask2(qr); return; } if (3 == mask) {data_mask3(qr); return; } if (4 == mask) {data_mask4(qr); return; } if (5 == mask) {data_mask5(qr); return; } if (6 == mask) {data_mask6(qr); return; } if (7 == mask) {data_mask7(qr); return; } printf("Unknow mask...\n"); printf("Aborting.\n"); exit(-1); } typedef struct { int i; int j; } module; /* vérifie si un module est un module de données / redondance (et renvoie 0 * dans ce cas) ou s'il s'agit d'un autre module (fixe, format, version) */ int is_data(module ij) { if (ij.i == 6) return -1; /* timing pattern */ if (ij.j == 6) return -1; /* timing pattern */ if (ij.i<9 && ij.j<9) return -1; /* upper left corner, with format */ if (ij.i>SIZE_V1-9 && ij.j<9) return -1; /* lower left corner, with format */ if (ij.i<9 && ij.j>SIZE_V1-9) return -1; /* upper right corner, with format */ /* TODO: "alignment patterns" pour les versions supérieures à 1 */ return 0; } /* calcule les coordonnées du module suivant avec les parcours en Z */ module next_module(module ij) { /* quand on est à gauche du "timing pattern" vertical, il faut décaler le * numéro de colone vers la gauche pour faire les calculs... */ int delta = (ij.j<6)?1:0; module r; /* on peut décider ce qu'il faut faire en regardant le numéro de colonne */ switch ((ij.j+delta)%4) { case 0: r.i=ij.i; r.j=ij.j-1; break; case 3: if (ij.i == 0) { if (ij.j == 7) { /* cas particulier, il faut éviter le "timing pattern" vertical */ r.i=0; r.j=5; } else { r.i=0; r.j=ij.j-1; } } else { r.i=ij.i-1; r.j=ij.j+1; } break; case 2: r.i=ij.i; r.j=ij.j-1; break; case 1: if (ij.i == SIZE_V1-1) { r.i=ij.i; r.j=ij.j-1; } else { r.i=ij.i+1; r.j=ij.j+1; } break; default: fprintf(stderr, "Unexpected result... Aborting.\n"); exit(-1); break; } return r; } /* récupère l'octet qui commence aux coordonnées i,j */ byte get_byte(QRCode qr, module *ij) { byte b = 0x00; for (int k=7; k>=0; k--) { while (1) { if (0 == is_data(*ij)) { b |= qr[ij->i][ij->j]<>%u<<\n", r); return(r); } /* récupère les 4 bits du mode à un offset donné */ int get_mode(const byte *data, int offset) { return(get_bits(data, offset,4)); } /* récupère le nombre de symboles suivant un mode */ int get_length(const byte *data, int offset, int mode) { switch (mode) { case NUMERIC_MODE: return(get_bits(data,offset+4,10)); break; case ALPHANUMERIC_MODE: return(get_bits(data,offset+4,9)); break; case BYTE_MODE: return(get_bits(data,offset+4,8)); break; case KANJI_MODE: return(get_bits(data,offset+4,8)); break; default: fprintf(stderr, "Unknown mode (%u)! Aborting...\n", mode); exit(-1); } } /* les fonctions de décodages des différents modes. La chaine result * doit déjà être allouée... * Elles renvoient le nombre de bits qu'elles ont lus dans le tableau des * données.*/ int decode_bytes(const byte *data, int offset, int nb, char *result) { for (int i=0; i