|
1 /* |
|
2 * Copyright (c) 2000,2001,2002 Japan Network Information Center. |
|
3 * All rights reserved. |
|
4 * |
|
5 * By using this file, you agree to the terms and conditions set forth bellow. |
|
6 * |
|
7 * LICENSE TERMS AND CONDITIONS |
|
8 * |
|
9 * The following License Terms and Conditions apply, unless a different |
|
10 * license is obtained from Japan Network Information Center ("JPNIC"), |
|
11 * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda, |
|
12 * Chiyoda-ku, Tokyo 101-0047, Japan. |
|
13 * |
|
14 * 1. Use, Modification and Redistribution (including distribution of any |
|
15 * modified or derived work) in source and/or binary forms is permitted |
|
16 * under this License Terms and Conditions. |
|
17 * |
|
18 * 2. Redistribution of source code must retain the copyright notices as they |
|
19 * appear in each source code file, this License Terms and Conditions. |
|
20 * |
|
21 * 3. Redistribution in binary form must reproduce the Copyright Notice, |
|
22 * this License Terms and Conditions, in the documentation and/or other |
|
23 * materials provided with the distribution. For the purposes of binary |
|
24 * distribution the "Copyright Notice" refers to the following language: |
|
25 * "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved." |
|
26 * |
|
27 * 4. The name of JPNIC may not be used to endorse or promote products |
|
28 * derived from this Software without specific prior written approval of |
|
29 * JPNIC. |
|
30 * |
|
31 * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC |
|
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
|
34 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE |
|
35 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
36 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
37 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
|
38 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
|
39 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
|
40 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
|
41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. |
|
42 */ |
|
43 |
|
44 |
|
45 #include <stddef.h> |
|
46 #include <stdlib.h> |
|
47 #include <string.h> |
|
48 |
|
49 #include "nsIDNKitInterface.h" |
|
50 |
|
51 |
|
52 #define RACE_2OCTET_MODE 0xd8 |
|
53 #define RACE_ESCAPE 0xff |
|
54 #define RACE_ESCAPE_2ND 0x99 |
|
55 |
|
56 /* |
|
57 * Compression type. |
|
58 */ |
|
59 enum { |
|
60 compress_one, /* all characters are in a single row */ |
|
61 compress_two, /* row 0 and another row */ |
|
62 compress_none /* nope */ |
|
63 }; |
|
64 |
|
65 |
|
66 idn_result_t |
|
67 race_decode_decompress(const char *from, uint16_t *buf, size_t buflen) |
|
68 { |
|
69 uint16_t *p = buf; |
|
70 unsigned int bitbuf = 0; |
|
71 int bitlen = 0; |
|
72 unsigned int i, j; |
|
73 size_t len; |
|
74 |
|
75 while (*from != '\0') { |
|
76 int c = *from++; |
|
77 int x; |
|
78 |
|
79 if ('a' <= c && c <= 'z') |
|
80 x = c - 'a'; |
|
81 else if ('A' <= c && c <= 'Z') |
|
82 x = c - 'A'; |
|
83 else if ('2' <= c && c <= '7') |
|
84 x = c - '2' + 26; |
|
85 else |
|
86 return (idn_invalid_encoding); |
|
87 |
|
88 bitbuf = (bitbuf << 5) + x; |
|
89 bitlen += 5; |
|
90 if (bitlen >= 8) { |
|
91 *p++ = (bitbuf >> (bitlen - 8)) & 0xff; |
|
92 bitlen -= 8; |
|
93 } |
|
94 } |
|
95 len = p - buf; |
|
96 |
|
97 /* |
|
98 * Now 'buf' holds the decoded string. |
|
99 */ |
|
100 |
|
101 /* |
|
102 * Decompress. |
|
103 */ |
|
104 if (buf[0] == RACE_2OCTET_MODE) { |
|
105 if ((len - 1) % 2 != 0) |
|
106 return (idn_invalid_encoding); |
|
107 for (i = 1, j = 0; i < len; i += 2, j++) |
|
108 buf[j] = (buf[i] << 8) + buf[i + 1]; |
|
109 len = j; |
|
110 } else { |
|
111 uint16_t c = buf[0] << 8; /* higher octet */ |
|
112 |
|
113 for (i = 1, j = 0; i < len; j++) { |
|
114 if (buf[i] == RACE_ESCAPE) { |
|
115 if (i + 1 >= len) |
|
116 return (idn_invalid_encoding); |
|
117 else if (buf[i + 1] == RACE_ESCAPE_2ND) |
|
118 buf[j] = c | 0xff; |
|
119 else |
|
120 buf[j] = buf[i + 1]; |
|
121 i += 2; |
|
122 |
|
123 } else if (buf[i] == 0x99 && c == 0x00) { |
|
124 /* |
|
125 * The RACE specification says this is error. |
|
126 */ |
|
127 return (idn_invalid_encoding); |
|
128 |
|
129 } else { |
|
130 buf[j] = c | buf[i++]; |
|
131 } |
|
132 } |
|
133 len = j; |
|
134 } |
|
135 buf[len] = '\0'; |
|
136 |
|
137 return (idn_success); |
|
138 } |
|
139 |
|
140 idn_result_t |
|
141 race_compress_encode(const uint16_t *p, int compress_mode, |
|
142 char *to, size_t tolen) |
|
143 { |
|
144 uint32_t bitbuf = *p++; /* bit stream buffer */ |
|
145 int bitlen = 8; /* # of bits in 'bitbuf' */ |
|
146 |
|
147 while (*p != '\0' || bitlen > 0) { |
|
148 unsigned int c = *p; |
|
149 |
|
150 if (c == '\0') { |
|
151 /* End of data. Flush. */ |
|
152 bitbuf <<= (5 - bitlen); |
|
153 bitlen = 5; |
|
154 } else if (compress_mode == compress_none) { |
|
155 /* Push 16 bit data. */ |
|
156 bitbuf = (bitbuf << 16) | c; |
|
157 bitlen += 16; |
|
158 p++; |
|
159 } else {/* compress_mode == compress_one/compress_two */ |
|
160 /* Push 8 or 16 bit data. */ |
|
161 if (compress_mode == compress_two && |
|
162 (c & 0xff00) == 0) { |
|
163 /* Upper octet is zero (and not U1). */ |
|
164 bitbuf = (bitbuf << 16) | 0xff00 | c; |
|
165 bitlen += 16; |
|
166 } else if ((c & 0xff) == 0xff) { |
|
167 /* Lower octet is 0xff. */ |
|
168 bitbuf = (bitbuf << 16) | |
|
169 (RACE_ESCAPE << 8) | RACE_ESCAPE_2ND; |
|
170 bitlen += 16; |
|
171 } else { |
|
172 /* Just output lower octet. */ |
|
173 bitbuf = (bitbuf << 8) | (c & 0xff); |
|
174 bitlen += 8; |
|
175 } |
|
176 p++; |
|
177 } |
|
178 |
|
179 /* |
|
180 * Output bits in 'bitbuf' in 5-bit unit. |
|
181 */ |
|
182 while (bitlen >= 5) { |
|
183 int x; |
|
184 |
|
185 /* Get top 5 bits. */ |
|
186 x = (bitbuf >> (bitlen - 5)) & 0x1f; |
|
187 bitlen -= 5; |
|
188 |
|
189 /* Encode. */ |
|
190 if (x < 26) |
|
191 x += 'a'; |
|
192 else |
|
193 x = (x - 26) + '2'; |
|
194 |
|
195 if (tolen < 1) |
|
196 return (idn_buffer_overflow); |
|
197 |
|
198 *to++ = x; |
|
199 tolen--; |
|
200 } |
|
201 } |
|
202 |
|
203 if (tolen <= 0) |
|
204 return (idn_buffer_overflow); |
|
205 |
|
206 *to = '\0'; |
|
207 return (idn_success); |
|
208 } |
|
209 |
|
210 int |
|
211 get_compress_mode(uint16_t *p) { |
|
212 int zero = 0; |
|
213 unsigned int upper = 0; |
|
214 uint16_t *modepos = p - 1; |
|
215 |
|
216 while (*p != '\0') { |
|
217 unsigned int hi = *p++ & 0xff00; |
|
218 |
|
219 if (hi == 0) { |
|
220 zero++; |
|
221 } else if (hi == upper) { |
|
222 ; |
|
223 } else if (upper == 0) { |
|
224 upper = hi; |
|
225 } else { |
|
226 *modepos = RACE_2OCTET_MODE; |
|
227 return (compress_none); |
|
228 } |
|
229 } |
|
230 *modepos = upper >> 8; |
|
231 if (upper > 0 && zero > 0) |
|
232 return (compress_two); |
|
233 else |
|
234 return (compress_one); |
|
235 } |