aboutsummaryrefslogtreecommitdiff
path: root/src/reducer/validation_ES_DNI.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/reducer/validation_ES_DNI.c')
-rw-r--r--src/reducer/validation_ES_DNI.c147
1 files changed, 128 insertions, 19 deletions
diff --git a/src/reducer/validation_ES_DNI.c b/src/reducer/validation_ES_DNI.c
index 06bf143..6679f45 100644
--- a/src/reducer/validation_ES_DNI.c
+++ b/src/reducer/validation_ES_DNI.c
@@ -17,9 +17,75 @@
17 * @file reducer/validation_ES_DNI.c 17 * @file reducer/validation_ES_DNI.c
18 * @brief validation logic for Spanish Documento Nacional de Identidad numbers, and Número de Identificación de Extranjeros 18 * @brief validation logic for Spanish Documento Nacional de Identidad numbers, and Número de Identificación de Extranjeros
19 * @author Christian Grothoff 19 * @author Christian Grothoff
20 *
21 * Examples:
22 * 12345678Z, 39740191D, 14741806W, X8095495R
20 */ 23 */
21#include <string.h> 24#include <string.h>
22#include <stdbool.h> 25#include <stdbool.h>
26#include <stdio.h>
27
28/**
29 * Function to validate a Spanish CIF number.
30 *
31 * @param civ number to validate
32 * @return true if validation passed, else false
33 */
34static bool
35validate_cif (const char *cif)
36{
37 size_t slen = strlen (cif);
38 char letter = cif[0];
39 const char *number = &cif[1];
40 char control = cif[slen - 1];
41 unsigned int sum = 0;
42
43 if (9 != slen)
44 return false;
45
46 for (unsigned int i = 0; i < slen - 2; i++)
47 {
48 unsigned int n = number[i] - '0';
49
50 if (n >= 10)
51 return false;
52 if (0 == (i % 2))
53 {
54 n *= 2;
55 sum += n < 10 ? n : n - 9;
56 }
57 else
58 {
59 sum += n;
60 }
61 }
62 sum %= 10;
63 if (0 != sum)
64 sum = 10 - sum;
65 {
66 char control_digit = "0123456789"[sum];
67 char control_letter = "JABCDEFGHI"[sum];
68
69 switch (letter)
70 {
71 case 'A':
72 case 'B':
73 case 'E':
74 case 'H':
75 return control == control_digit;
76 case 'N':
77 case 'P':
78 case 'Q':
79 case 'R':
80 case 'S':
81 case 'W':
82 return control == control_letter;
83 default:
84 return (control == control_letter) ||
85 (control == control_digit);
86 }
87 }
88}
23 89
24 90
25/** 91/**
@@ -43,32 +109,75 @@ ES_DNI_check (const char *dni_number)
43 return false; 109 return false;
44 switch (dni_number[0]) 110 switch (dni_number[0])
45 { 111 {
112 case 'A':
113 case 'B':
114 case 'C':
115 case 'D':
116 case 'E':
117 case 'F':
118 case 'G':
119 case 'H':
120 case 'I':
121 case 'J':
122 case 'K':
123 case 'L':
124 case 'N':
125 case 'O':
126 case 'P':
127 case 'Q':
128 case 'R':
129 case 'S':
130 case 'T':
131 case 'U':
132 case 'V':
133 case 'W':
134 /* CIF: [A-W]\d{7}[0-9A-J] */
135 /* CIF is for companies, we only take those
136 of individuals here! */
137 return false; /* CIV is not allowed! */
138 case 'M':
139 /* special NIE, with CIF validation (?),
140 but for individuals, see
141 https://www.strongabogados.com/tax-id-spain.php */
142 return validate_cif (dni_number);
46 case 'X': 143 case 'X':
47 fact = 0;
48 dni_number++;
49 break;
50 case 'Y': 144 case 'Y':
51 fact = 10000000;
52 dni_number++;
53 break;
54 case 'Z': 145 case 'Z':
55 fact = 20000000; 146 /* NIE */
56 dni_number++; 147 fact = dni_number[0] - 'X';
148 /* 7 or 8 digits */
149 if (2 == sscanf (&dni_number[1],
150 "%8u%c%c",
151 &num,
152 &chksum,
153 &dummy))
154 {
155 num += fact * 100000000;
156 }
157 else if (2 == sscanf (&dni_number[1],
158 "%7u%c%c",
159 &num,
160 &chksum,
161 &dummy))
162 {
163 num += fact * 10000000;
164 }
165 else
166 {
167 return false;
168 }
57 break; 169 break;
58 default: 170 default:
59 fact = 0; 171 fact = 0;
60 /* domestic */ 172 /* DNI */
173 if (2 != sscanf (dni_number,
174 "%8u%c%c",
175 &num,
176 &chksum,
177 &dummy))
178 return false;
179 break;
61 } 180 }
62
63 if (2 != sscanf (dni_number,
64 "%7u%c%c"
65 & num,
66 &chksum,
67 &dummy))
68 return false;
69 num += fact;
70 if (map[num % 23] != chksum)
71 return false;
72 if (map[num % 23] != chksum) 181 if (map[num % 23] != chksum)
73 return false; 182 return false;
74 return true; 183 return true;