Line data Source code
1 : /* context.c - check contextual rule on label 2 : Copyright (C) 2011-2024 Simon Josefsson 3 : 4 : Libidn2 is free software: you can redistribute it and/or modify it 5 : under the terms of either: 6 : 7 : * the GNU Lesser General Public License as published by the Free 8 : Software Foundation; either version 3 of the License, or (at 9 : your option) any later version. 10 : 11 : or 12 : 13 : * the GNU General Public License as published by the Free 14 : Software Foundation; either version 2 of the License, or (at 15 : your option) any later version. 16 : 17 : or both in parallel, as here. 18 : 19 : This program is distributed in the hope that it will be useful, 20 : but WITHOUT ANY WARRANTY; without even the implied warranty of 21 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 : GNU General Public License for more details. 23 : 24 : You should have received copies of the GNU General Public License and 25 : the GNU Lesser General Public License along with this program. If 26 : not, see <http://www.gnu.org/licenses/>. 27 : */ 28 : 29 : #include <config.h> 30 : 31 : #include "idn2.h" 32 : #include "tables.h" 33 : #include <unictype.h> /* uc_combining_class, UC_CCC_VR */ 34 : #include "context.h" 35 : 36 : int 37 1409907 : _idn2_contextj_rule (const uint32_t *label, size_t llen, size_t pos) 38 : { 39 : uint32_t cp; 40 : 41 1409907 : if (llen == 0) 42 0 : return IDN2_OK; 43 : 44 1409907 : cp = label[pos]; 45 : 46 1409907 : if (!_idn2_contextj_p (cp)) 47 1408342 : return IDN2_OK; 48 : 49 1565 : switch (cp) 50 : { 51 988 : case 0x200C: /* ZERO WIDTH NON-JOINER */ 52 988 : if (pos > 0) 53 : { 54 : /* If Canonical_Combining_Class(Before(cp)) .eq. Virama Then True; */ 55 843 : uint32_t before_cp = label[pos - 1]; 56 843 : int cc = uc_combining_class (before_cp); 57 843 : if (cc == UC_CCC_VR) 58 252 : return IDN2_OK; 59 : } 60 : 61 : /* See http://permalink.gmane.org/gmane.ietf.idnabis/6980 for 62 : clarified rule. */ 63 : 64 736 : if (pos == 0 || pos == llen - 1) 65 177 : return IDN2_CONTEXTJ; 66 : 67 : { 68 : int jt; 69 : size_t tmp; 70 : 71 : /* Search backwards. */ 72 559 : for (tmp = pos - 1;; tmp--) 73 : { 74 352 : jt = uc_joining_type (label[tmp]); 75 911 : if (jt == UC_JOINING_TYPE_L || jt == UC_JOINING_TYPE_D) 76 : break; 77 490 : if (tmp == 0) 78 58 : return IDN2_CONTEXTJ; 79 432 : if (jt == UC_JOINING_TYPE_T) 80 352 : continue; 81 80 : return IDN2_CONTEXTJ; 82 : } 83 : 84 : /* Search forward. */ 85 685 : for (tmp = pos + 1; tmp < llen; tmp++) 86 : { 87 685 : jt = uc_joining_type (label[tmp]); 88 685 : if (jt == UC_JOINING_TYPE_R || jt == UC_JOINING_TYPE_D) 89 : break; 90 337 : if (tmp == llen - 1) 91 64 : return IDN2_CONTEXTJ; 92 273 : if (jt == UC_JOINING_TYPE_T) 93 264 : continue; 94 9 : return IDN2_CONTEXTJ; 95 : } 96 : } 97 : 98 348 : return IDN2_OK; 99 : break; 100 : 101 577 : case 0x200D: /* ZERO WIDTH JOINER */ 102 577 : if (pos > 0) 103 : { 104 433 : uint32_t before_cp = label[pos - 1]; 105 433 : int cc = uc_combining_class (before_cp); 106 433 : if (cc == UC_CCC_VR) 107 346 : return IDN2_OK; 108 : } 109 231 : return IDN2_CONTEXTJ; 110 : } 111 : 112 0 : return IDN2_CONTEXTJ_NO_RULE; 113 : } 114 : 115 : static const char * 116 2038 : _uc_script_name (ucs4_t uc) 117 : { 118 2038 : const uc_script_t *ucs = uc_script (uc); 119 : 120 2038 : if (!ucs) 121 252 : return ""; 122 : 123 1786 : return ucs->name; 124 : } 125 : 126 : int 127 4918 : _idn2_contexto_rule (const uint32_t *label, size_t llen, size_t pos) 128 : { 129 4918 : uint32_t cp = label[pos]; 130 : 131 4918 : if (!_idn2_contexto_p (cp)) 132 2266 : return IDN2_OK; 133 : 134 2652 : switch (cp) 135 : { 136 12 : case 0x00B7: 137 : /* MIDDLE DOT */ 138 12 : if (llen < 3) 139 4 : return IDN2_CONTEXTO; 140 8 : if (pos == 0 || pos == llen - 1) 141 0 : return IDN2_CONTEXTO; 142 8 : if (label[pos - 1] == 0x006C && label[pos + 1] == 0x006C) 143 5 : return IDN2_OK; 144 3 : return IDN2_CONTEXTO; 145 : break; 146 : 147 44 : case 0x0375: 148 : /* GREEK LOWER NUMERAL SIGN (KERAIA) */ 149 44 : if (pos == llen - 1) 150 2 : return IDN2_CONTEXTO; 151 42 : if (strcmp (_uc_script_name (label[pos + 1]), "Greek") == 0) 152 33 : return IDN2_OK; 153 9 : return IDN2_CONTEXTO; 154 : break; 155 : 156 189 : case 0x05F3: 157 : /* HEBREW PUNCTUATION GERESH */ 158 : case 0x05F4: 159 : /* HEBREW PUNCTUATION GERSHAYIM */ 160 189 : if (pos == 0) 161 4 : return IDN2_CONTEXTO; 162 185 : if (strcmp (_uc_script_name (label[pos - 1]), "Hebrew") == 0) 163 172 : return IDN2_OK; 164 13 : return IDN2_CONTEXTO; 165 : break; 166 : 167 1044 : case 0x0660: 168 : case 0x0661: 169 : case 0x0662: 170 : case 0x0663: 171 : case 0x0664: 172 : case 0x0665: 173 : case 0x0666: 174 : case 0x0667: 175 : case 0x0668: 176 : case 0x0669: 177 : { 178 : /* ARABIC-INDIC DIGITS */ 179 : size_t i; 180 28157 : for (i = 0; i < llen; i++) 181 27121 : if (label[i] >= 0x6F0 && label[i] <= 0x06F9) 182 8 : return IDN2_CONTEXTO; 183 1036 : return IDN2_OK; 184 : break; 185 : } 186 : 187 1135 : case 0x06F0: 188 : case 0x06F1: 189 : case 0x06F2: 190 : case 0x06F3: 191 : case 0x06F4: 192 : case 0x06F5: 193 : case 0x06F6: 194 : case 0x06F7: 195 : case 0x06F8: 196 : case 0x06F9: 197 : { 198 : /* EXTENDED ARABIC-INDIC DIGITS */ 199 : size_t i; 200 33383 : for (i = 0; i < llen; i++) 201 32252 : if (label[i] >= 0x660 && label[i] <= 0x0669) 202 4 : return IDN2_CONTEXTO; 203 1131 : return IDN2_OK; 204 : break; 205 : } 206 228 : case 0x30FB: 207 : { 208 : /* KATAKANA MIDDLE DOT */ 209 : size_t i; 210 228 : bool script_ok = false; 211 : 212 914 : for (i = 0; !script_ok && i < llen; i++) 213 686 : if (strcmp (_uc_script_name (label[i]), "Hiragana") == 0 214 619 : || strcmp (_uc_script_name (label[i]), "Katakana") == 0 215 506 : || strcmp (_uc_script_name (label[i]), "Han") == 0) 216 224 : script_ok = true; 217 : 218 228 : if (script_ok) 219 224 : return IDN2_OK; 220 4 : return IDN2_CONTEXTO; 221 : break; 222 : } 223 : } 224 : 225 0 : return IDN2_CONTEXTO_NO_RULE; 226 : } 227 : 228 : bool 229 6468 : _idn2_contexto_with_rule (uint32_t cp) 230 : { 231 6468 : switch (cp) 232 : { 233 6468 : case 0x00B7: 234 : /* MIDDLE DOT */ 235 : case 0x0375: 236 : /* GREEK LOWER NUMERAL SIGN (KERAIA) */ 237 : case 0x05F3: 238 : /* HEBREW PUNCTUATION GERESH */ 239 : case 0x05F4: 240 : /* HEBREW PUNCTUATION GERSHAYIM */ 241 : case 0x0660: 242 : case 0x0661: 243 : case 0x0662: 244 : case 0x0663: 245 : case 0x0664: 246 : case 0x0665: 247 : case 0x0666: 248 : case 0x0667: 249 : case 0x0668: 250 : case 0x0669: 251 : /* ARABIC-INDIC DIGITS */ 252 : case 0x06F0: 253 : case 0x06F1: 254 : case 0x06F2: 255 : case 0x06F3: 256 : case 0x06F4: 257 : case 0x06F5: 258 : case 0x06F6: 259 : case 0x06F7: 260 : case 0x06F8: 261 : case 0x06F9: 262 : /* EXTENDED ARABIC-INDIC DIGITS */ 263 : case 0x30FB: 264 : /* KATAKANA MIDDLE DOT */ 265 6468 : return true; 266 : break; 267 : } 268 : 269 0 : return false; 270 : }