OLD | NEW |
| (Empty) |
1 /* | |
2 ******************************************************************************* | |
3 * | |
4 * Copyright (C) 1999-2013, International Business Machines | |
5 * Corporation and others. All Rights Reserved. | |
6 * | |
7 ******************************************************************************* | |
8 * file name: gendata.cpp | |
9 * | |
10 * created on: 11/03/2000 | |
11 * created by: Eric R. Mader | |
12 */ | |
13 | |
14 #include <stdio.h> | |
15 #include <string.h> | |
16 #include <time.h> | |
17 | |
18 #include "unicode/utypes.h" | |
19 #include "unicode/unistr.h" | |
20 #include "unicode/uscript.h" | |
21 #include "unicode/ubidi.h" | |
22 #include "unicode/ustring.h" | |
23 | |
24 #include "layout/LETypes.h" | |
25 #include "layout/LEScripts.h" | |
26 #include "layout/LayoutEngine.h" | |
27 | |
28 #include "PortableFontInstance.h" | |
29 #include "SimpleFontInstance.h" | |
30 | |
31 #include "xmlparser.h" | |
32 | |
33 #include "letsutil.h" | |
34 #include "letest.h" | |
35 | |
36 U_NAMESPACE_USE | |
37 | |
38 static LEErrorCode overallStatus = LE_NO_ERROR; | |
39 struct TestInput | |
40 { | |
41 const char *fontName; | |
42 LEUnicode *text; | |
43 le_int32 textLength; | |
44 le_int32 scriptCode; | |
45 le_bool rightToLeft; | |
46 }; | |
47 | |
48 /* Returns the path to icu/source/test/testdata/ */ | |
49 const char *getSourceTestData() { | |
50 const char *srcDataDir = NULL; | |
51 #ifdef U_TOPSRCDIR | |
52 srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testd
ata" U_FILE_SEP_STRING; | |
53 #else | |
54 srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRI
NG"testdata"U_FILE_SEP_STRING; | |
55 FILE *f = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_S
TRING"testdata"U_FILE_SEP_STRING"rbbitst.txt", "r"); | |
56 | |
57 if (f != NULL) { | |
58 /* We're in icu/source/test/letest/ */ | |
59 fclose(f); | |
60 } else { | |
61 /* We're in icu/source/test/letest/(Debug|Release) */ | |
62 srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_ST
RING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING; | |
63 } | |
64 #endif | |
65 | |
66 return srcDataDir; | |
67 } | |
68 | |
69 const char *getPath(char buffer[2048], const char *filename) { | |
70 const char *testDataDirectory = getSourceTestData(); | |
71 | |
72 strcpy(buffer, testDataDirectory); | |
73 strcat(buffer, filename); | |
74 | |
75 return buffer; | |
76 } | |
77 | |
78 /* | |
79 * FIXME: should use the output file name and the current date. | |
80 */ | |
81 const char *header = | |
82 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" | |
83 "\n" | |
84 "<!--\n" | |
85 " Copyright (c) 1999-%4.4d International Business Machines\n" | |
86 " Corporation and others. All rights reserved.\n" | |
87 "\n" | |
88 " WARNING: THIS FILE IS MACHINE GENERATED. DO NOT HAND EDIT IT\n" | |
89 " UNLESS YOU REALLY KNOW WHAT YOU'RE DOING.\n" | |
90 "\n" | |
91 " file name: letest.xml\n" | |
92 " generated on: %s\n" | |
93 " generated by: gendata.cpp\n" | |
94 "-->\n" | |
95 "\n" | |
96 "<layout-tests>\n"; | |
97 | |
98 void dumpLongs(FILE *file, const char *tag, le_int32 *longs, le_int32 count) { | |
99 char lineBuffer[8 * 12 + 2]; | |
100 le_int32 bufp = 0; | |
101 | |
102 fprintf(file, " <%s>\n", tag); | |
103 | |
104 for (int i = 0; i < count; i += 1) { | |
105 if (i % 8 == 0 && bufp != 0) { | |
106 fprintf(file, " %s\n", lineBuffer); | |
107 bufp = 0; | |
108 } | |
109 | |
110 bufp += sprintf(&lineBuffer[bufp], "0x%8.8X, ", longs[i]); | |
111 } | |
112 | |
113 if (bufp != 0) { | |
114 lineBuffer[bufp - 2] = '\0'; | |
115 fprintf(file, " %s\n", lineBuffer); | |
116 } | |
117 | |
118 fprintf(file, " </%s>\n\n", tag); | |
119 } | |
120 | |
121 void dumpFloats(FILE *file, const char *tag, float *floats, le_int32 count) { | |
122 char lineBuffer[8 * 16 + 2]; | |
123 le_int32 bufp = 0; | |
124 | |
125 fprintf(file, " <%s>\n", tag); | |
126 | |
127 for (int i = 0; i < count; i += 1) { | |
128 if (i % 8 == 0 && bufp != 0) { | |
129 fprintf(file, " %s\n", lineBuffer); | |
130 bufp = 0; | |
131 } | |
132 | |
133 bufp += sprintf(&lineBuffer[bufp], "%f, ", floats[i]); | |
134 } | |
135 | |
136 if (bufp != 0) { | |
137 lineBuffer[bufp - 2] = '\0'; | |
138 fprintf(file, " %s\n", lineBuffer); | |
139 } | |
140 | |
141 fprintf(file, " </%s>\n", tag); | |
142 } | |
143 | |
144 int main(int argc, char *argv[]) | |
145 { | |
146 UErrorCode status = U_ZERO_ERROR; | |
147 const char *gendataFile = "gendata.xml"; | |
148 FILE *outputFile = fopen(argv[1], "w"); | |
149 if(argc>2) { | |
150 gendataFile = argv[2]; | |
151 } | |
152 time_t now = time(NULL); | |
153 struct tm *local = localtime(&now); | |
154 const char *tmFormat = "%m/%d/%Y %I:%M:%S %p %Z"; | |
155 char tmString[64]; | |
156 le_uint32 count = 0; | |
157 strftime(tmString, 64, tmFormat, local); | |
158 fprintf(outputFile, header, local->tm_year + 1900, tmString); | |
159 | |
160 UXMLParser *parser = UXMLParser::createParser(status); | |
161 UXMLElement *root = parser->parseFile(gendataFile, status); | |
162 | |
163 if (root == NULL) { | |
164 printf("Error: Could not open %s\n", gendataFile); | |
165 delete parser; | |
166 return -1; | |
167 } else if(U_FAILURE(status)) { | |
168 printf("Error reading %s: %s\n", gendataFile, u_errorName(status)); | |
169 return -2; | |
170 } else { | |
171 printf("Reading %s\n", gendataFile); | |
172 } | |
173 | |
174 UnicodeString test_case = UNICODE_STRING_SIMPLE("test-case"); | |
175 UnicodeString test_text = UNICODE_STRING_SIMPLE("test-text"); | |
176 UnicodeString test_font = UNICODE_STRING_SIMPLE("test-font"); | |
177 | |
178 // test-case attributes | |
179 UnicodeString id_attr = UNICODE_STRING_SIMPLE("id"); | |
180 UnicodeString script_attr = UNICODE_STRING_SIMPLE("script"); | |
181 UnicodeString lang_attr = UNICODE_STRING_SIMPLE("lang"); | |
182 | |
183 // test-font attributes | |
184 UnicodeString name_attr = UNICODE_STRING_SIMPLE("name"); | |
185 | |
186 const UXMLElement *testCase; | |
187 int32_t tc = 0; | |
188 | |
189 while((testCase = root->nextChildElement(tc)) != NULL) { | |
190 if (testCase->getTagName().compare(test_case) == 0) { | |
191 char *id = getCString(testCase->getAttribute(id_attr)); | |
192 char *script = getCString(testCase->getAttribute(script_attr)); | |
193 char *lang = getCString(testCase->getAttribute(lang_attr)); | |
194 ++count; | |
195 printf("\n ID %s\n", id); | |
196 LEFontInstance *font = NULL; | |
197 const UXMLElement *element; | |
198 int32_t ec = 0; | |
199 int32_t charCount = 0; | |
200 int32_t typoFlags = LayoutEngine::kTypoFlagKern | LayoutEngine::kTyp
oFlagLiga; // kerning + ligatures... | |
201 UScriptCode scriptCode; | |
202 le_int32 languageCode = -1; | |
203 UnicodeString text; | |
204 int32_t glyphCount = 0; | |
205 LEErrorCode leStatus = LE_NO_ERROR; | |
206 LayoutEngine *engine = NULL; | |
207 LEGlyphID *glyphs = NULL; | |
208 le_int32 *indices = NULL; | |
209 float *positions = NULL; | |
210 | |
211 uscript_getCode(script, &scriptCode, 1, &status); | |
212 if (LE_FAILURE(status)) { | |
213 printf("Error: invalid script name: %s.\n", script); | |
214 goto free_c_strings; | |
215 } | |
216 | |
217 if (lang != NULL) { | |
218 languageCode = getLanguageCode(lang); | |
219 | |
220 if (languageCode < 0) { | |
221 printf("Error: invalid language name: %s.\n", lang); | |
222 goto free_c_strings; | |
223 } | |
224 | |
225 fprintf(outputFile, " <test-case id=\"%s\" script=\"%s\" lang
=\"%s\">\n", id, script, lang); | |
226 } else { | |
227 fprintf(outputFile, " <test-case id=\"%s\" script=\"%s\">\n",
id, script); | |
228 } | |
229 | |
230 while((element = testCase->nextChildElement(ec)) != NULL) { | |
231 UnicodeString tag = element->getTagName(); | |
232 | |
233 // TODO: make sure that each element is only used once. | |
234 if (tag.compare(test_font) == 0) { | |
235 char *fontName = getCString(element->getAttribute(name_attr
)); | |
236 const char *version = NULL; | |
237 char buf[2048]; | |
238 PortableFontInstance *pfi = new PortableFontInstance(getPath
(buf,fontName), 12, leStatus); | |
239 | |
240 if (LE_FAILURE(leStatus)) { | |
241 printf("Error: could not open font: %s (path: %s)\n", font
Name, buf); | |
242 freeCString(fontName); | |
243 goto free_c_strings; | |
244 } | |
245 | |
246 printf(" Generating: %s, %s, %s, %s\n", id, script, lang, fo
ntName); | |
247 | |
248 version = pfi->getNameString(NAME_VERSION_STRING, PLATFORM_M
ACINTOSH, MACINTOSH_ROMAN, MACINTOSH_ENGLISH); | |
249 | |
250 // The standard recommends that the Macintosh Roman/English
name string be present, but | |
251 // if it's not, try the Microsoft Unicode/English string. | |
252 if (version == NULL) { | |
253 const LEUnicode16 *uversion = pfi->getUnicodeNameString(
NAME_VERSION_STRING, PLATFORM_MICROSOFT, MICROSOFT_UNICODE_BMP, MICROSOFT_ENGLIS
H); | |
254 | |
255 if (uversion != NULL) { | |
256 char uversion_utf8[300]; | |
257 UErrorCode status2 = U_ZERO_ERROR; | |
258 u_strToUTF8(uversion_utf8, 300, NULL, uversion, -1, &s
tatus2); | |
259 if(U_FAILURE(status2)) { | |
260 uversion_utf8[0]=0; | |
261 } | |
262 fprintf(outputFile, " <test-font name=\"%s\"
version=\"%s\" checksum=\"0x%8.8X\" rchecksum=\"0x%8.8X\"/>\n\n", | |
263 fontName, uversion_utf8, pfi->getFontChecksu
m(), pfi->getRawChecksum()); | |
264 | |
265 pfi->deleteNameString(uversion); | |
266 } else { | |
267 fprintf(outputFile, " <test-font name=\"%s\" ve
rsion=\"unknown-0x%8.8X\" checksum=\"0x%8.8X\" rchecksum=\"0x%8.8X\"/>\n\n", | |
268 fontName, pfi->getFontChecksum(), pfi->getFont
Checksum(), pfi->getRawChecksum()); | |
269 } | |
270 } else { | |
271 fprintf(outputFile, " <test-font name=\"%s\" vers
ion=\"%s\" checksum=\"0x%8.8X\" rchecksum=\"0x%8.8X\"/>\n\n", | |
272 fontName, version, pfi->getFontChecksum(), pfi->
getRawChecksum()); | |
273 | |
274 pfi->deleteNameString(version); | |
275 } | |
276 fflush(outputFile); | |
277 | |
278 freeCString(fontName); | |
279 | |
280 font = pfi; | |
281 } else if (tag.compare(test_text) == 0) { | |
282 char *utf8 = NULL; | |
283 | |
284 text = element->getText(TRUE); | |
285 charCount = text.length(); | |
286 | |
287 utf8 = getUTF8String(&text); | |
288 fprintf(outputFile, " <test-text>%s</test-text>\n\n",
utf8); | |
289 fflush(outputFile); | |
290 freeCString(utf8); | |
291 } else { | |
292 // an unknown tag... | |
293 char *cTag = getCString(&tag); | |
294 | |
295 printf("Test %s: unknown element with tag \"%s\"\n", id, cTa
g); | |
296 freeCString(cTag); | |
297 } | |
298 } | |
299 | |
300 if (font == NULL) { | |
301 LEErrorCode fontStatus = LE_NO_ERROR; | |
302 | |
303 font = new SimpleFontInstance(12, fontStatus); | |
304 typoFlags |= 0x80000000L; // use CharSubstitutionFilter... | |
305 } | |
306 | |
307 engine = LayoutEngine::layoutEngineFactory(font, scriptCode, languag
eCode, typoFlags, leStatus); | |
308 | |
309 if (LE_FAILURE(leStatus)) { | |
310 printf("Error for test %s: could not create a LayoutEngine.\n",
id); | |
311 goto delete_font; | |
312 } | |
313 | |
314 glyphCount = engine->layoutChars(text.getBuffer(), 0, charCount, cha
rCount, getRTL(text), 0, 0, leStatus); | |
315 | |
316 glyphs = NEW_ARRAY(LEGlyphID, glyphCount); | |
317 indices = NEW_ARRAY(le_int32, glyphCount); | |
318 positions = NEW_ARRAY(float, glyphCount * 2 + 2); | |
319 | |
320 engine->getGlyphs(glyphs, leStatus); | |
321 engine->getCharIndices(indices, leStatus); | |
322 engine->getGlyphPositions(positions, leStatus); | |
323 | |
324 if(LE_FAILURE(leStatus)) { | |
325 fprintf(stderr,"ERROR: LO returned error: %s\n", u_errorName((UErr
orCode)leStatus)); | |
326 overallStatus = leStatus; | |
327 fprintf(outputFile, "<!-- ERROR: %d -->\n", leStatus); | |
328 fflush(outputFile); | |
329 leStatus = LE_NO_ERROR; | |
330 } else { | |
331 dumpLongs(outputFile, "result-glyphs", (le_int32 *) glyphs, glyphC
ount); | |
332 | |
333 dumpLongs(outputFile, "result-indices", indices, glyphCount); | |
334 | |
335 dumpFloats(outputFile, "result-positions", positions, glyphCount *
2 + 2); | |
336 fflush(outputFile); | |
337 | |
338 } | |
339 | |
340 DELETE_ARRAY(positions); | |
341 DELETE_ARRAY(indices); | |
342 DELETE_ARRAY(glyphs); | |
343 | |
344 delete engine; | |
345 | |
346 delete_font: | |
347 fprintf(outputFile, " </test-case>\n\n"); | |
348 fflush(outputFile); | |
349 | |
350 delete font; | |
351 | |
352 free_c_strings: | |
353 freeCString(lang); | |
354 freeCString(script); | |
355 freeCString(id); | |
356 } | |
357 } | |
358 | |
359 delete root; | |
360 delete parser; | |
361 | |
362 fprintf(outputFile, "</layout-tests>\n"); | |
363 | |
364 if(count==0) { | |
365 fprintf(stderr, "No cases processed!\n"); | |
366 return 1; | |
367 } | |
368 | |
369 | |
370 if(LE_FAILURE(overallStatus)) { | |
371 fprintf(outputFile, "<!-- !!! FAILED. %d -->\n", overallStatus); | |
372 fprintf(stderr, "!!! FAILED. %d\n", overallStatus); | |
373 fclose(outputFile); | |
374 return 0; | |
375 // return 1; | |
376 } else { | |
377 printf("Generated.\n"); | |
378 fclose(outputFile); | |
379 return 0; | |
380 } | |
381 } | |
OLD | NEW |