1 /*
2 *******************************************************************************
3 *
4 * Copyright (C) 1999-2014, 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