diff options
Diffstat (limited to 'src/reducer/validation_ES_DNI.c')
-rw-r--r-- | src/reducer/validation_ES_DNI.c | 147 |
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 | */ | ||
34 | static bool | ||
35 | validate_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; |