Line data Source code
1 : /* tr46map.c - implementation of IDNA2008 TR46 functions
2 : Copyright (C) 2016-2017 Tim Rühsen
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 <stdint.h>
32 : #include <stdlib.h> /* bsearch */
33 : #include <string.h> /* memset */
34 :
35 : #include "tr46map.h"
36 : #include "tr46map_data.c"
37 :
38 : #define countof(a) (sizeof(a)/sizeof(*(a)))
39 :
40 : static void
41 78815446 : _fill_map (uint32_t c, const uint8_t *p, IDNAMap *map)
42 : {
43 : uint32_t value;
44 :
45 78815446 : if (c <= 0xFF)
46 : {
47 4632082 : map->cp1 = *p++;
48 4632082 : map->range = *p++;
49 : }
50 74183364 : else if (c <= 0xFFFF)
51 : {
52 12521044 : map->cp1 = (p[0] << 8) | p[1];
53 12521044 : map->range = (p[2] << 8) | p[3];
54 12521044 : p += 4;
55 : }
56 : else
57 : {
58 61662320 : map->cp1 = (p[0] << 16) | (p[1] << 8) | p[2];
59 61662320 : map->range = (p[3] << 8) | p[4];
60 61662320 : p += 5;
61 : }
62 :
63 78815446 : value = (p[0] << 16) | (p[1] << 8) | p[2];
64 :
65 : /* deconstruct value, construction was
66 : * value = (((map->nmappings << 14) | map->offset) << 3) | map->flag_index; */
67 78815446 : map->flag_index = value & 0x7;
68 78815446 : map->offset = (value >> 3) & 0x3FFF;
69 78815446 : map->nmappings = (value >> 17) & 0x1F;
70 78815446 : }
71 :
72 : static int
73 71972555 : _compare_idna_map (const uint32_t *c, const uint8_t *p)
74 : {
75 : IDNAMap map;
76 :
77 71972555 : _fill_map (*c, p, &map);
78 :
79 71972555 : if (*c < map.cp1)
80 20482750 : return -1;
81 51489805 : if (*c > map.cp1 + map.range)
82 44646914 : return 1;
83 6842891 : return 0;
84 : }
85 :
86 : /*
87 : static int
88 : _compare_idna_map(uint32_t *c, IDNAMap *m2)
89 : {
90 : if (*c < m2->cp1)
91 : return -1;
92 : if (*c > m2->cp1 + m2->range)
93 : return 1;
94 : return 0;
95 : }
96 :
97 : IDNAMap
98 : *get_idna_map(uint32_t c)
99 : {
100 : return bsearch(&c, idna_map, countof(idna_map), sizeof(IDNAMap), (int(*)(const void *, const void *))_compare_idna_map);
101 : }
102 : */
103 :
104 : int
105 6842891 : get_idna_map (uint32_t c, IDNAMap *map)
106 : {
107 : uint8_t *p;
108 :
109 6842891 : if (c <= 0xFF)
110 : p =
111 617833 : (uint8_t *) bsearch (&c, idna_map_8, sizeof (idna_map_8) / 5, 5,
112 : (int (*)(const void *, const void *))
113 : _compare_idna_map);
114 6225058 : else if (c <= 0xFFFF)
115 : p =
116 1005902 : (uint8_t *) bsearch (&c, idna_map_16, sizeof (idna_map_16) / 7, 7,
117 : (int (*)(const void *, const void *))
118 : _compare_idna_map);
119 5219156 : else if (c <= 0xFFFFFF)
120 : p =
121 5219156 : (uint8_t *) bsearch (&c, idna_map_24, sizeof (idna_map_24) / 8, 8,
122 : (int (*)(const void *, const void *))
123 : _compare_idna_map);
124 : else
125 0 : p = NULL;
126 :
127 6842891 : if (!p)
128 : {
129 0 : memset (map, 0, sizeof (IDNAMap));
130 0 : return -1;
131 : }
132 :
133 6842891 : _fill_map (c, p, map);
134 6842891 : return 0;
135 : }
136 :
137 : int
138 10617776 : map_is (const IDNAMap *map, unsigned flags)
139 : {
140 10617776 : return (idna_flags[map->flag_index] & flags) == flags;
141 : }
142 :
143 : static int G_GNUC_IDN2_ATTRIBUTE_PURE
144 1023317 : _compare_nfcqc_map (uint32_t *c, NFCQCMap *m2)
145 : {
146 1023317 : if (*c < m2->cp1)
147 224330 : return -1;
148 798987 : if (*c > m2->cp2)
149 798783 : return 1;
150 204 : return 0;
151 : }
152 :
153 : NFCQCMap *
154 153828 : get_nfcqc_map (uint32_t c)
155 : {
156 153828 : return (NFCQCMap *) bsearch (&c, nfcqc_map, countof (nfcqc_map),
157 : sizeof (NFCQCMap),
158 : (int (*)(const void *, const void *))
159 : _compare_nfcqc_map);
160 : }
161 :
162 : /* copy 'n' codepoints from mapdata stream */
163 : int
164 57383 : get_map_data (uint32_t *dst, const IDNAMap *map)
165 : {
166 57383 : int n = map->nmappings;
167 57383 : const uint8_t *src = mapdata + map->offset;
168 :
169 124480 : for (; n > 0; n--)
170 : {
171 67097 : uint32_t cp = 0;
172 : do
173 105096 : cp = (cp << 7) | (*src & 0x7F);
174 105096 : while (*src++ & 0x80);
175 67097 : *dst++ = cp;
176 : }
177 :
178 57383 : return map->nmappings;
179 : }
|