• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *******************************************************************************
3  *
4  *   Copyright (C) 2005-2009, International Business Machines
5  *   Corporation and others.  All Rights Reserved.
6  *
7  *******************************************************************************
8  *
9  *   created on: 2005jun15
10  *   created by: Raymond Yang
11  */
12 
13 #if !UCONFIG_NO_IDNA
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include "unicode/utypes.h"
19 #include "unicode/ucnv.h"
20 #include "unicode/ustring.h"
21 #include "unicode/uidna.h"
22 
23 #include "idnaconf.h"
24 
25 static const UChar C_TAG[] = {0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0}; // =====
26 static const UChar C_NAMEZONE[] = {0x6E, 0x61, 0x6D, 0x65, 0x7A, 0x6F, 0x6E, 0x65, 0}; // namezone
27 static const UChar C_NAMEBASE[] = {0x6E, 0x61, 0x6D, 0x65, 0x62, 0x61, 0x73, 0x65, 0}; // namebase
28 static const UChar C_NAMEUTF8[] = {0x6E, 0x61, 0x6D, 0x65, 0x75, 0x74, 0x66, 0x38, 0}; // nameutf8
29 
30 static const UChar C_TYPE[] = {0x74, 0x79, 0x70, 0x65, 0}; // type
31 static const UChar C_TOASCII[]  =  {0x74, 0x6F, 0x61, 0x73, 0x63, 0x69, 0x69, 0};       // toascii
32 static const UChar C_TOUNICODE[] = {0x74, 0x6F, 0x75, 0x6E, 0x69, 0x63, 0x6F, 0x64, 0x65, 0}; // tounicode
33 
34 static const UChar C_PASSFAIL[] = {0x70, 0x61, 0x73, 0x73, 0x66, 0x61, 0x69, 0x6C, 0}; // passfail
35 static const UChar C_PASS[] = {0x70, 0x61, 0x73, 0x73, 0}; // pass
36 static const UChar C_FAIL[] = {0x66, 0x61, 0x69, 0x6C, 0}; // fail
37 
38 static const UChar C_DESC[] = {0x64, 0x65, 0x73, 0x63, 0}; // desc
39 static const UChar C_USESTD3ASCIIRULES[] = {0x55, 0x73, 0x65, 0x53, 0x54, 0x44,
40        0x33, 0x41, 0x53, 0x43, 0x49, 0x49, 0x52, 0x75, 0x6C, 0x65, 0x73, 0}; // UseSTD3ASCIIRules
41 
IdnaConfTest()42 IdnaConfTest::IdnaConfTest(){
43     base = NULL;
44     len = 0;
45     curOffset = 0;
46 
47     type = option = passfail = -1;
48     namebase.setToBogus();
49     namezone.setToBogus();
50 }
~IdnaConfTest()51 IdnaConfTest::~IdnaConfTest(){
52     delete [] base;
53 }
54 
55 #if !UCONFIG_NO_IDNA
56 /* this function is modified from RBBITest::ReadAndConvertFile()
57  *
58  */
ReadAndConvertFile()59 UBool IdnaConfTest::ReadAndConvertFile(){
60 
61     char * source = NULL;
62     size_t source_len;
63 
64     // read the test data file to memory
65     FILE* f    = NULL;
66     UErrorCode  status  = U_ZERO_ERROR;
67 
68     const char *path = IntlTest::getSourceTestData(status);
69     if (U_FAILURE(status)) {
70         errln("%s", u_errorName(status));
71         return FALSE;
72     }
73 
74     const char* name = "idna_conf.txt";     // test data file
75     int t = strlen(path) + strlen(name) + 1;
76     char* absolute_name = new char[t];
77     strcpy(absolute_name, path);
78     strcat(absolute_name, name);
79     f = fopen(absolute_name, "rb");
80     delete [] absolute_name;
81 
82     if (f == NULL){
83         dataerrln("fopen error on %s", name);
84         return FALSE;
85     }
86 
87     fseek( f, 0, SEEK_END);
88     if ((source_len = ftell(f)) <= 0){
89         errln("Error reading test data file.");
90         fclose(f);
91         return FALSE;
92     }
93 
94     source = new char[source_len];
95     fseek(f, 0, SEEK_SET);
96     if (fread(source, 1, source_len, f) != source_len) {
97         errln("Error reading test data file.");
98         delete [] source;
99         fclose(f);
100         return FALSE;
101     }
102     fclose(f);
103 
104     // convert the UTF-8 encoded stream to UTF-16 stream
105     UConverter* conv = ucnv_open("utf-8", &status);
106     int dest_len = ucnv_toUChars(conv,
107                                 NULL,           //  dest,
108                                 0,              //  destCapacity,
109                                 source,
110                                 source_len,
111                                 &status);
112     if (status == U_BUFFER_OVERFLOW_ERROR) {
113         // Buffer Overflow is expected from the preflight operation.
114         status = U_ZERO_ERROR;
115         UChar * dest = NULL;
116         dest = new UChar[ dest_len + 1];
117         ucnv_toUChars(conv, dest, dest_len + 1, source, source_len, &status);
118         // Do not know the "if possible" behavior of ucnv_toUChars()
119         // Do it by ourself.
120         dest[dest_len] = 0;
121         len = dest_len;
122         base = dest;
123         delete [] source;
124         ucnv_close(conv);
125         return TRUE;    // The buffer will owned by caller.
126     }
127     errln("UConverter error: %s", u_errorName(status));
128     delete [] source;
129     ucnv_close(conv);
130     return FALSE;
131 }
132 
isNewlineMark()133 int IdnaConfTest::isNewlineMark(){
134     static const UChar LF        = 0x0a;
135     static const UChar CR        = 0x0d;
136     UChar c = base[curOffset];
137     // CR LF
138     if ( c == CR && curOffset + 1 < len && base[curOffset + 1] == LF){
139         return 2;
140     }
141 
142     // CR or LF
143     if ( c == CR || c == LF) {
144         return 1;
145     }
146 
147     return 0;
148 }
149 
150 /* Read a logical line.
151  *
152  * All lines ending in a backslash (\) and immediately followed by a newline
153  * character are joined with the next line in the source file forming logical
154  * lines from the physical lines.
155  *
156  */
ReadOneLine(UnicodeString & buf)157 UBool IdnaConfTest::ReadOneLine(UnicodeString& buf){
158     if ( !(curOffset < len) ) return FALSE; // stream end
159 
160     static const UChar BACKSLASH = 0x5c;
161     buf.remove();
162     int t = 0;
163     while (curOffset < len){
164         if ((t = isNewlineMark())) {  // end of line
165             curOffset += t;
166             break;
167         }
168         UChar c = base[curOffset];
169         if (c == BACKSLASH && curOffset < len -1){  // escaped new line mark
170             if ((t = isNewlineMark())){
171                 curOffset += 1 + t;  // BACKSLAH and NewlineMark
172                 continue;
173             }
174         };
175         buf.append(c);
176         curOffset++;
177     }
178     return TRUE;
179 }
180 
181 //
182 //===============================================================
183 //
184 
185 /* Explain <xxxxx> tag to a native value
186  *
187  * Since <xxxxx> is always larger than the native value,
188  * the operation will replace the tag directly in the buffer,
189  * and, of course, will shift tail elements.
190  */
ExplainCodePointTag(UnicodeString & buf)191 void IdnaConfTest::ExplainCodePointTag(UnicodeString& buf){
192     buf.append((UChar)0);    // add a terminal NULL
193     UChar* bufBase = buf.getBuffer(buf.length());
194     UChar* p = bufBase;
195     while (*p != 0){
196         if ( *p != 0x3C){    // <
197             *bufBase++ = *p++;
198         } else {
199             p++;    // skip <
200             UChar32 cp = 0;
201             for ( ;*p != 0x3E; p++){   // >
202                 if (0x30 <= *p && *p <= 0x39){        // 0-9
203                     cp = (cp * 16) + (*p - 0x30);
204                 } else if (0x61 <= *p && *p <= 0x66){ // a-f
205                     cp = (cp * 16) + (*p - 0x61) + 10;
206                 } else if (0x41 <= *p && *p <= 0x46) {// A-F
207                     cp = (cp * 16) + (*p - 0x41) + 10;
208                 }
209                 // no else. hope everything is good.
210             }
211             p++;    // skip >
212             if (U_IS_BMP(cp)){
213                 *bufBase++ = cp;
214             } else {
215                 *bufBase++ = U16_LEAD(cp);
216                 *bufBase++ = U16_TRAIL(cp);
217             }
218         }
219     }
220     *bufBase = 0;  // close our buffer
221     buf.releaseBuffer();
222 }
223 
Call()224 void IdnaConfTest::Call(){
225     if (type == -1 || option == -1 || passfail == -1 || namebase.isBogus() || namezone.isBogus()){
226         errln("Incomplete record");
227     } else {
228         UErrorCode status = U_ZERO_ERROR;
229         UChar result[200] = {0,};   // simple life
230         const UChar *p = namebase.getTerminatedBuffer();
231         const int p_len = namebase.length();
232 
233         if (type == 0 && option == 0){
234             uidna_IDNToASCII(p, p_len, result, 200, UIDNA_USE_STD3_RULES, NULL, &status);
235         } else if (type == 0 && option == 1){
236             uidna_IDNToASCII(p, p_len, result, 200, UIDNA_ALLOW_UNASSIGNED, NULL, &status);
237         } else if (type == 1 && option == 0){
238             uidna_IDNToUnicode(p, p_len, result, 200, UIDNA_USE_STD3_RULES, NULL, &status);
239         } else if (type == 1 && option == 1){
240             uidna_IDNToUnicode(p, p_len, result, 200, UIDNA_ALLOW_UNASSIGNED, NULL, &status);
241         }
242         if (passfail == 0){
243             if (U_FAILURE(status)){
244                 id.append(" should pass, but failed. - ");
245                 id.append(u_errorName(status));
246                 errcheckln(status, id);
247             } else{
248                 if (namezone.compare(result, -1) == 0){
249                     // expected
250                     logln(UnicodeString("namebase: ") + prettify(namebase) + UnicodeString(" result: ") + prettify(result));
251                 } else {
252                     id.append(" no error, but result is not as expected.");
253                     errln(id);
254                 }
255             }
256         } else if (passfail == 1){
257             if (U_FAILURE(status)){
258                 // expected
259                 // TODO: Uncomment this when U_IDNA_ZERO_LENGTH_LABEL_ERROR is added to u_errorName
260                 //logln("Got the expected error: " + UnicodeString(u_errorName(status)));
261             } else{
262                 if (namebase.compare(result, -1) == 0){
263                     // garbage in -> garbage out
264                     logln(UnicodeString("ICU will not recognize malformed ACE-Prefixes or incorrect ACE-Prefixes. ") + UnicodeString("namebase: ") + prettify(namebase) + UnicodeString(" result: ") + prettify(result));
265                 } else {
266                     id.append(" should fail, but not failed. ");
267                     id.append(u_errorName(status));
268                     errln(id);
269                 }
270             }
271         }
272     }
273     type = option = passfail = -1;
274     namebase.setToBogus();
275     namezone.setToBogus();
276     id.remove();
277     return;
278 }
279 
Test(void)280 void IdnaConfTest::Test(void){
281     if (!ReadAndConvertFile())return;
282 
283     UnicodeString s;
284     UnicodeString key;
285     UnicodeString value;
286 
287     // skip everything before the first "=====" and "=====" itself
288     do {
289         if (!ReadOneLine(s)) {
290             errln("End of file prematurely found");
291             break;
292         }
293     }
294     while (s.compare(C_TAG, -1) != 0);   //"====="
295 
296     while(ReadOneLine(s)){
297         s.trim();
298         key.remove();
299         value.remove();
300         if (s.compare(C_TAG, -1) == 0){   //"====="
301             Call();
302        } else {
303             // explain      key:value
304             int p = s.indexOf((UChar)0x3A);    // :
305             key.setTo(s,0,p).trim();
306             value.setTo(s,p+1).trim();
307             if (key.compare(C_TYPE, -1) == 0){
308                 if (value.compare(C_TOASCII, -1) == 0) {
309                     type = 0;
310                 } else if (value.compare(C_TOUNICODE, -1) == 0){
311                     type = 1;
312                 }
313             } else if (key.compare(C_PASSFAIL, -1) == 0){
314                 if (value.compare(C_PASS, -1) == 0){
315                     passfail = 0;
316                 } else if (value.compare(C_FAIL, -1) == 0){
317                     passfail = 1;
318                 }
319             } else if (key.compare(C_DESC, -1) == 0){
320                 if (value.indexOf(C_USESTD3ASCIIRULES, u_strlen(C_USESTD3ASCIIRULES), 0) == -1){
321                     option = 1; // not found
322                 } else {
323                     option = 0;
324                 }
325                 id.setTo(value, 0, value.indexOf((UChar)0x20));    // space
326             } else if (key.compare(C_NAMEZONE, -1) == 0){
327                 ExplainCodePointTag(value);
328                 namezone.setTo(value);
329             } else if (key.compare(C_NAMEBASE, -1) == 0){
330                 ExplainCodePointTag(value);
331                 namebase.setTo(value);
332             }
333             // just skip other lines
334         }
335     }
336 
337     Call(); // for last record
338 }
339 #else
Test(void)340 void IdnaConfTest::Test(void)
341 {
342   // test nothing...
343 }
344 #endif
345 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)346 void IdnaConfTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/){
347     switch (index) {
348         TESTCASE(0,Test);
349         default: name = ""; break;
350     }
351 }
352 
353 #endif
354