Line data Source code
1 : /* context.c - check contextual rule on label 2 : Copyright (C) 2011-2025 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 29750 : _idn2_contextj_rule (const uint32_t *label, size_t llen, size_t pos) 38 : { 39 : uint32_t cp; 40 : 41 29750 : if (llen == 0) 42 0 : return IDN2_OK; 43 : 44 29750 : cp = label[pos]; 45 : 46 29750 : if (!_idn2_contextj_p (cp)) 47 28557 : return IDN2_OK; 48 : 49 1193 : switch (cp) 50 : { 51 804 : case 0x200C: /* ZERO WIDTH NON-JOINER */ 52 804 : if (pos > 0) 53 : { 54 : /* If Canonical_Combining_Class(Before(cp)) .eq. Virama Then True; */ 55 758 : uint32_t before_cp = label[pos - 1]; 56 758 : int cc = uc_combining_class (before_cp); 57 758 : if (cc == UC_CCC_VR) 58 246 : return IDN2_OK; 59 : } 60 : 61 : /* See http://permalink.gmane.org/gmane.ietf.idnabis/6980 for 62 : clarified rule. */ 63 : 64 558 : if (pos == 0 || pos == llen - 1) 65 66 : return IDN2_CONTEXTJ; 66 : 67 : { 68 : int jt; 69 : size_t tmp; 70 : 71 : /* Search backwards. */ 72 492 : for (tmp = pos - 1;; tmp--) 73 : { 74 323 : jt = uc_joining_type (label[tmp]); 75 815 : if (jt == UC_JOINING_TYPE_L || jt == UC_JOINING_TYPE_D) 76 : break; 77 429 : if (tmp == 0) 78 44 : return IDN2_CONTEXTJ; 79 385 : if (jt == UC_JOINING_TYPE_T) 80 323 : continue; 81 62 : return IDN2_CONTEXTJ; 82 : } 83 : 84 : /* Search forward. */ 85 633 : for (tmp = pos + 1; tmp < llen; tmp++) 86 : { 87 633 : jt = uc_joining_type (label[tmp]); 88 633 : if (jt == UC_JOINING_TYPE_R || jt == UC_JOINING_TYPE_D) 89 : break; 90 312 : if (tmp == llen - 1) 91 56 : return IDN2_CONTEXTJ; 92 256 : if (jt == UC_JOINING_TYPE_T) 93 247 : continue; 94 9 : return IDN2_CONTEXTJ; 95 : } 96 : } 97 : 98 321 : return IDN2_OK; 99 : break; 100 : 101 389 : case 0x200D: /* ZERO WIDTH JOINER */ 102 389 : if (pos > 0) 103 : { 104 340 : uint32_t before_cp = label[pos - 1]; 105 340 : int cc = uc_combining_class (before_cp); 106 340 : if (cc == UC_CCC_VR) 107 316 : return IDN2_OK; 108 : } 109 73 : return IDN2_CONTEXTJ; 110 : } 111 : 112 0 : return IDN2_CONTEXTJ_NO_RULE; 113 : } 114 : 115 : static const char * 116 1868 : _uc_script_name (ucs4_t uc) 117 : { 118 1868 : const uc_script_t *ucs = uc_script (uc); 119 : 120 1868 : if (!ucs) 121 252 : return ""; 122 : 123 1616 : return ucs->name; 124 : } 125 : 126 : int 127 4695 : _idn2_contexto_rule (const uint32_t *label, size_t llen, size_t pos) 128 : { 129 4695 : uint32_t cp = label[pos]; 130 : 131 4695 : if (!_idn2_contexto_p (cp)) 132 2085 : return IDN2_OK; 133 : 134 2610 : switch (cp) 135 : { 136 6 : case 0x00B7: 137 : /* MIDDLE DOT */ 138 6 : if (llen < 3) 139 1 : return IDN2_CONTEXTO; 140 5 : if (pos == 0 || pos == llen - 1) 141 0 : return IDN2_CONTEXTO; 142 5 : if (label[pos - 1] == 0x006C && label[pos + 1] == 0x006C) 143 3 : return IDN2_OK; 144 2 : return IDN2_CONTEXTO; 145 : break; 146 : 147 36 : case 0x0375: 148 : /* GREEK LOWER NUMERAL SIGN (KERAIA) */ 149 36 : if (pos == llen - 1) 150 1 : return IDN2_CONTEXTO; 151 35 : if (strcmp (_uc_script_name (label[pos + 1]), "Greek") == 0) 152 29 : return IDN2_OK; 153 6 : return IDN2_CONTEXTO; 154 : break; 155 : 156 177 : case 0x05F3: 157 : /* HEBREW PUNCTUATION GERESH */ 158 : case 0x05F4: 159 : /* HEBREW PUNCTUATION GERSHAYIM */ 160 177 : if (pos == 0) 161 2 : return IDN2_CONTEXTO; 162 175 : if (strcmp (_uc_script_name (label[pos - 1]), "Hebrew") == 0) 163 167 : return IDN2_OK; 164 8 : return IDN2_CONTEXTO; 165 : break; 166 : 167 1038 : 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 28136 : for (i = 0; i < llen; i++) 181 27103 : if (label[i] >= 0x6F0 && label[i] <= 0x06F9) 182 5 : return IDN2_CONTEXTO; 183 1033 : return IDN2_OK; 184 : break; 185 : } 186 : 187 1133 : 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 33375 : for (i = 0; i < llen; i++) 201 32245 : if (label[i] >= 0x660 && label[i] <= 0x0669) 202 3 : return IDN2_CONTEXTO; 203 1130 : return IDN2_OK; 204 : break; 205 : } 206 220 : case 0x30FB: 207 : { 208 : /* KATAKANA MIDDLE DOT */ 209 : size_t i; 210 220 : bool script_ok = false; 211 : 212 854 : for (i = 0; !script_ok && i < llen; i++) 213 634 : if (strcmp (_uc_script_name (label[i]), "Hiragana") == 0 214 568 : || strcmp (_uc_script_name (label[i]), "Katakana") == 0 215 456 : || strcmp (_uc_script_name (label[i]), "Han") == 0) 216 219 : script_ok = true; 217 : 218 220 : if (script_ok) 219 219 : return IDN2_OK; 220 1 : return IDN2_CONTEXTO; 221 : break; 222 : } 223 : } 224 : 225 0 : return IDN2_CONTEXTO_NO_RULE; 226 : } 227 : 228 : bool 229 6269 : _idn2_contexto_with_rule (uint32_t cp) 230 : { 231 6269 : switch (cp) 232 : { 233 6269 : 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 6269 : return true; 266 : break; 267 : } 268 : 269 0 : return false; 270 : }