1 /*
2  *******************************************************************************
3  *
4  *   Copyright (C) 1999-2013, International Business Machines
5  *   Corporation and others.  All Rights Reserved.
6  *
7  *******************************************************************************
8  */
9 
10 #include "unicode/utypes.h"
11 #include "unicode/uclean.h"
12 #include "unicode/uchar.h"
13 #include "unicode/unistr.h"
14 #include "unicode/uscript.h"
15 #include "unicode/putil.h"
16 #include "unicode/ctest.h"
17 
18 #include "layout/LETypes.h"
19 #include "layout/LEScripts.h"
20 
21 #include "letsutil.h"
22 #include "letest.h"
23 
24 #include "xmlreader.h"
25 
26 #include "xmlparser.h"
27 
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 
32 //U_NAMESPACE_USE
33 
34 #define CH_COMMA 0x002C
35 
getHexArray(const UnicodeString & numbers,int32_t & arraySize)36 static le_uint32 *getHexArray(const UnicodeString &numbers, int32_t &arraySize)
37 {
38     int32_t offset = -1;
39 
40     arraySize = 1;
41     while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) {
42         arraySize += 1;
43     }
44 
45     le_uint32 *array = NEW_ARRAY(le_uint32, arraySize);
46     char number[16];
47     le_int32 count = 0;
48     le_int32 start = 0, end = 0;
49     le_int32 len = 0;
50 
51     // trim leading whitespace
52     while(u_isUWhiteSpace(numbers[start])) {
53         start += 1;
54     }
55 
56     while((end = numbers.indexOf(CH_COMMA, start)) >= 0) {
57         len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
58         number[len] = '\0';
59         start = end + 1;
60 
61         sscanf(number, "%x", &array[count++]);
62 
63         // trim whitespace following the comma
64         while(u_isUWhiteSpace(numbers[start])) {
65             start += 1;
66         }
67     }
68 
69     // trim trailing whitespace
70     end = numbers.length();
71     while(u_isUWhiteSpace(numbers[end - 1])) {
72         end -= 1;
73     }
74 
75     len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
76     number[len] = '\0';
77     sscanf(number, "%x", &array[count]);
78 
79     return array;
80 }
81 
getFloatArray(const UnicodeString & numbers,int32_t & arraySize)82 static float *getFloatArray(const UnicodeString &numbers, int32_t &arraySize)
83 {
84     int32_t offset = -1;
85 
86     arraySize = 1;
87     while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) {
88         arraySize += 1;
89     }
90 
91     float *array = NEW_ARRAY(float, arraySize);
92     char number[32];
93     le_int32 count = 0;
94     le_int32 start = 0, end = 0;
95     le_int32 len = 0;
96 
97     // trim leading whitespace
98     while(u_isUWhiteSpace(numbers[start])) {
99         start += 1;
100     }
101 
102     while((end = numbers.indexOf(CH_COMMA, start)) >= 0) {
103         len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
104         number[len] = '\0';
105         start = end + 1;
106 
107         sscanf(number, "%f", &array[count++]);
108 
109         // trim whiteapce following the comma
110         while(u_isUWhiteSpace(numbers[start])) {
111             start += 1;
112         }
113     }
114 
115     while(u_isUWhiteSpace(numbers[start])) {
116         start += 1;
117     }
118 
119     // trim trailing whitespace
120     end = numbers.length();
121     while(u_isUWhiteSpace(numbers[end - 1])) {
122         end -= 1;
123     }
124 
125     len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
126     number[len] = '\0';
127     sscanf(number, "%f", &array[count]);
128 
129     return array;
130 }
131 
132 U_CDECL_BEGIN
readTestFile(const char * testFilePath,TestCaseCallback callback)133 void readTestFile(const char *testFilePath, TestCaseCallback callback)
134 {
135 #if !UCONFIG_NO_REGULAR_EXPRESSIONS
136     UErrorCode status = U_ZERO_ERROR;
137     UXMLParser  *parser = UXMLParser::createParser(status);
138     UXMLElement *root   = parser->parseFile(testFilePath, status);
139 
140     if (root == NULL) {
141         log_err("Could not open the test data file: %s\n", testFilePath);
142         delete parser;
143         return;
144     }
145 
146     UnicodeString test_case        = UNICODE_STRING_SIMPLE("test-case");
147     UnicodeString test_text        = UNICODE_STRING_SIMPLE("test-text");
148     UnicodeString test_font        = UNICODE_STRING_SIMPLE("test-font");
149     UnicodeString result_glyphs    = UNICODE_STRING_SIMPLE("result-glyphs");
150     UnicodeString result_indices   = UNICODE_STRING_SIMPLE("result-indices");
151     UnicodeString result_positions = UNICODE_STRING_SIMPLE("result-positions");
152 
153     // test-case attributes
154     UnicodeString id_attr     = UNICODE_STRING_SIMPLE("id");
155     UnicodeString script_attr = UNICODE_STRING_SIMPLE("script");
156     UnicodeString lang_attr   = UNICODE_STRING_SIMPLE("lang");
157 
158     // test-font attributes
159     UnicodeString name_attr   = UNICODE_STRING_SIMPLE("name");
160     UnicodeString ver_attr    = UNICODE_STRING_SIMPLE("version");
161     UnicodeString cksum_attr  = UNICODE_STRING_SIMPLE("checksum");
162 
163     const UXMLElement *testCase;
164     int32_t tc = 0;
165 
166     while((testCase = root->nextChildElement(tc)) != NULL) {
167         if (testCase->getTagName().compare(test_case) == 0) {
168             char *id = getCString(testCase->getAttribute(id_attr));
169             char *script    = getCString(testCase->getAttribute(script_attr));
170             char *lang      = getCString(testCase->getAttribute(lang_attr));
171             char *fontName  = NULL;
172 			char *fontVer   = NULL;
173 			char *fontCksum = NULL;
174             const UXMLElement *element;
175             int32_t ec = 0;
176             int32_t charCount = 0;
177             int32_t typoFlags = 3; // kerning + ligatures...
178             UScriptCode scriptCode;
179             le_int32 languageCode = -1;
180             UnicodeString text, glyphs, indices, positions;
181             int32_t glyphCount = 0, indexCount = 0, positionCount = 0;
182             TestResult expected = {0, NULL, NULL, NULL};
183 
184             uscript_getCode(script, &scriptCode, 1, &status);
185             if (LE_FAILURE(status)) {
186                 log_err("invalid script name: %s.\n", script);
187                 goto free_c_strings;
188             }
189 
190             if (lang != NULL) {
191                 languageCode = getLanguageCode(lang);
192 
193                 if (languageCode < 0) {
194                     log_err("invalid language name: %s.\n", lang);
195                     goto free_c_strings;
196                 }
197             }
198 
199             while((element = testCase->nextChildElement(ec)) != NULL) {
200                 UnicodeString tag = element->getTagName();
201 
202                 // TODO: make sure that each element is only used once.
203                 if (tag.compare(test_font) == 0) {
204                     fontName  = getCString(element->getAttribute(name_attr));
205                     fontVer   = getCString(element->getAttribute(ver_attr));
206                     fontCksum = getCString(element->getAttribute(cksum_attr));
207 
208                 } else if (tag.compare(test_text) == 0) {
209                     text = element->getText(TRUE);
210                     charCount = text.length();
211                 } else if (tag.compare(result_glyphs) == 0) {
212                     glyphs = element->getText(TRUE);
213                 } else if (tag.compare(result_indices) == 0) {
214                     indices = element->getText(TRUE);
215                 } else if (tag.compare(result_positions) == 0) {
216                     positions = element->getText(TRUE);
217                 } else {
218                     // an unknown tag...
219                     char *cTag = getCString(&tag);
220 
221                     log_info("Test %s: unknown element with tag \"%s\"\n", id, cTag);
222                     freeCString(cTag);
223                 }
224             }
225 
226             expected.glyphs    = (LEGlyphID *) getHexArray(glyphs, glyphCount);
227             expected.indices   = (le_int32 *)  getHexArray(indices, indexCount);
228             expected.positions = getFloatArray(positions, positionCount);
229 
230             expected.glyphCount = glyphCount;
231 
232             if (glyphCount < charCount || indexCount != glyphCount || positionCount < glyphCount * 2 + 2) {
233                 log_err("Test %s: inconsistent input data: charCount = %d, glyphCount = %d, indexCount = %d, positionCount = %d\n",
234                     id, charCount, glyphCount, indexCount, positionCount);
235                 goto free_expected;
236             };
237 
238 			(*callback)(id, fontName, fontVer, fontCksum, scriptCode, languageCode, text.getBuffer(), charCount, &expected);
239 
240 free_expected:
241             DELETE_ARRAY(expected.positions);
242             DELETE_ARRAY(expected.indices);
243             DELETE_ARRAY(expected.glyphs);
244 
245 free_c_strings:
246 			freeCString(fontCksum);
247 			freeCString(fontVer);
248 			freeCString(fontName);
249             freeCString(lang);
250             freeCString(script);
251             freeCString(id);
252         }
253     }
254 
255     delete root;
256     delete parser;
257 #endif
258 }
259 U_CDECL_END
260