]>
Commit | Line | Data |
---|---|---|
b75a7d8f A |
1 | /* |
2 | ******************************************************************************* | |
3 | * | |
57a6839d | 4 | * Copyright (C) 1999-2013, International Business Machines |
b75a7d8f A |
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> | |
73c04bcf A |
15 | #include <string.h> |
16 | #include <time.h> | |
b75a7d8f | 17 | |
73c04bcf A |
18 | #include "unicode/utypes.h" |
19 | #include "unicode/unistr.h" | |
20 | #include "unicode/uscript.h" | |
21 | #include "unicode/ubidi.h" | |
57a6839d | 22 | #include "unicode/ustring.h" |
73c04bcf A |
23 | |
24 | #include "layout/LETypes.h" | |
25 | #include "layout/LEScripts.h" | |
26 | #include "layout/LayoutEngine.h" | |
b75a7d8f A |
27 | |
28 | #include "PortableFontInstance.h" | |
73c04bcf | 29 | #include "SimpleFontInstance.h" |
b75a7d8f | 30 | |
73c04bcf | 31 | #include "xmlparser.h" |
b75a7d8f | 32 | |
73c04bcf A |
33 | #include "letsutil.h" |
34 | #include "letest.h" | |
b75a7d8f | 35 | |
73c04bcf | 36 | U_NAMESPACE_USE |
b75a7d8f | 37 | |
57a6839d | 38 | static LEErrorCode overallStatus = LE_NO_ERROR; |
b75a7d8f A |
39 | struct TestInput |
40 | { | |
73c04bcf A |
41 | const char *fontName; |
42 | LEUnicode *text; | |
43 | le_int32 textLength; | |
44 | le_int32 scriptCode; | |
45 | le_bool rightToLeft; | |
b75a7d8f A |
46 | }; |
47 | ||
57a6839d A |
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 "testdata" U_FILE_SEP_STRING; | |
53 | #else | |
54 | srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING; | |
55 | FILE *f = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"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_STRING"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 | ||
b75a7d8f A |
78 | /* |
79 | * FIXME: should use the output file name and the current date. | |
80 | */ | |
73c04bcf A |
81 | const char *header = |
82 | "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" | |
b75a7d8f | 83 | "\n" |
73c04bcf A |
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"; | |
b75a7d8f | 97 | |
73c04bcf | 98 | void dumpLongs(FILE *file, const char *tag, le_int32 *longs, le_int32 count) { |
b75a7d8f A |
99 | char lineBuffer[8 * 12 + 2]; |
100 | le_int32 bufp = 0; | |
101 | ||
73c04bcf | 102 | fprintf(file, " <%s>\n", tag); |
b75a7d8f A |
103 | |
104 | for (int i = 0; i < count; i += 1) { | |
105 | if (i % 8 == 0 && bufp != 0) { | |
73c04bcf | 106 | fprintf(file, " %s\n", lineBuffer); |
b75a7d8f A |
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'; | |
73c04bcf | 115 | fprintf(file, " %s\n", lineBuffer); |
b75a7d8f A |
116 | } |
117 | ||
73c04bcf | 118 | fprintf(file, " </%s>\n\n", tag); |
b75a7d8f A |
119 | } |
120 | ||
73c04bcf | 121 | void dumpFloats(FILE *file, const char *tag, float *floats, le_int32 count) { |
b75a7d8f A |
122 | char lineBuffer[8 * 16 + 2]; |
123 | le_int32 bufp = 0; | |
124 | ||
73c04bcf | 125 | fprintf(file, " <%s>\n", tag); |
b75a7d8f A |
126 | |
127 | for (int i = 0; i < count; i += 1) { | |
128 | if (i % 8 == 0 && bufp != 0) { | |
73c04bcf | 129 | fprintf(file, " %s\n", lineBuffer); |
b75a7d8f A |
130 | bufp = 0; |
131 | } | |
132 | ||
73c04bcf | 133 | bufp += sprintf(&lineBuffer[bufp], "%f, ", floats[i]); |
b75a7d8f A |
134 | } |
135 | ||
136 | if (bufp != 0) { | |
137 | lineBuffer[bufp - 2] = '\0'; | |
73c04bcf | 138 | fprintf(file, " %s\n", lineBuffer); |
b75a7d8f A |
139 | } |
140 | ||
73c04bcf | 141 | fprintf(file, " </%s>\n", tag); |
b75a7d8f A |
142 | } |
143 | ||
57a6839d | 144 | int main(int argc, char *argv[]) |
b75a7d8f | 145 | { |
73c04bcf | 146 | UErrorCode status = U_ZERO_ERROR; |
57a6839d | 147 | const char *gendataFile = "gendata.xml"; |
b75a7d8f | 148 | FILE *outputFile = fopen(argv[1], "w"); |
57a6839d A |
149 | if(argc>2) { |
150 | gendataFile = argv[2]; | |
151 | } | |
73c04bcf A |
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]; | |
57a6839d | 156 | le_uint32 count = 0; |
73c04bcf A |
157 | strftime(tmString, 64, tmFormat, local); |
158 | fprintf(outputFile, header, local->tm_year + 1900, tmString); | |
b75a7d8f | 159 | |
73c04bcf | 160 | UXMLParser *parser = UXMLParser::createParser(status); |
57a6839d | 161 | UXMLElement *root = parser->parseFile(gendataFile, status); |
b75a7d8f | 162 | |
73c04bcf | 163 | if (root == NULL) { |
57a6839d | 164 | printf("Error: Could not open %s\n", gendataFile); |
73c04bcf A |
165 | delete parser; |
166 | return -1; | |
57a6839d A |
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); | |
b75a7d8f A |
172 | } |
173 | ||
73c04bcf A |
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)); | |
57a6839d A |
194 | ++count; |
195 | printf("\n ID %s\n", id); | |
73c04bcf A |
196 | LEFontInstance *font = NULL; |
197 | const UXMLElement *element; | |
198 | int32_t ec = 0; | |
199 | int32_t charCount = 0; | |
57a6839d | 200 | int32_t typoFlags = LayoutEngine::kTypoFlagKern | LayoutEngine::kTypoFlagLiga; // kerning + ligatures... |
73c04bcf A |
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; | |
57a6839d A |
237 | char buf[2048]; |
238 | PortableFontInstance *pfi = new PortableFontInstance(getPath(buf,fontName), 12, leStatus); | |
73c04bcf A |
239 | |
240 | if (LE_FAILURE(leStatus)) { | |
57a6839d | 241 | printf("Error: could not open font: %s (path: %s)\n", fontName, buf); |
73c04bcf A |
242 | freeCString(fontName); |
243 | goto free_c_strings; | |
244 | } | |
245 | ||
57a6839d A |
246 | printf(" Generating: %s, %s, %s, %s\n", id, script, lang, fontName); |
247 | ||
73c04bcf A |
248 | version = pfi->getNameString(NAME_VERSION_STRING, PLATFORM_MACINTOSH, MACINTOSH_ROMAN, MACINTOSH_ENGLISH); |
249 | ||
46f4442e A |
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_ENGLISH); | |
254 | ||
255 | if (uversion != NULL) { | |
57a6839d A |
256 | char uversion_utf8[300]; |
257 | UErrorCode status2 = U_ZERO_ERROR; | |
258 | u_strToUTF8(uversion_utf8, 300, NULL, uversion, -1, &status2); | |
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->getFontChecksum(), pfi->getRawChecksum()); | |
46f4442e A |
264 | |
265 | pfi->deleteNameString(uversion); | |
57a6839d A |
266 | } else { |
267 | fprintf(outputFile, " <test-font name=\"%s\" version=\"unknown-0x%8.8X\" checksum=\"0x%8.8X\" rchecksum=\"0x%8.8X\"/>\n\n", | |
268 | fontName, pfi->getFontChecksum(), pfi->getFontChecksum(), pfi->getRawChecksum()); | |
46f4442e A |
269 | } |
270 | } else { | |
57a6839d A |
271 | fprintf(outputFile, " <test-font name=\"%s\" version=\"%s\" checksum=\"0x%8.8X\" rchecksum=\"0x%8.8X\"/>\n\n", |
272 | fontName, version, pfi->getFontChecksum(), pfi->getRawChecksum()); | |
46f4442e A |
273 | |
274 | pfi->deleteNameString(version); | |
275 | } | |
57a6839d | 276 | fflush(outputFile); |
73c04bcf | 277 | |
73c04bcf | 278 | freeCString(fontName); |
46f4442e | 279 | |
73c04bcf A |
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); | |
57a6839d | 289 | fflush(outputFile); |
73c04bcf A |
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, cTag); | |
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, languageCode, 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, charCount, 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 | ||
57a6839d A |
324 | if(LE_FAILURE(leStatus)) { |
325 | fprintf(stderr,"ERROR: LO returned error: %s\n", u_errorName((UErrorCode)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, glyphCount); | |
332 | ||
333 | dumpLongs(outputFile, "result-indices", indices, glyphCount); | |
334 | ||
335 | dumpFloats(outputFile, "result-positions", positions, glyphCount * 2 + 2); | |
336 | fflush(outputFile); | |
73c04bcf | 337 | |
57a6839d | 338 | } |
73c04bcf A |
339 | |
340 | DELETE_ARRAY(positions); | |
341 | DELETE_ARRAY(indices); | |
342 | DELETE_ARRAY(glyphs); | |
b75a7d8f | 343 | |
73c04bcf | 344 | delete engine; |
b75a7d8f | 345 | |
73c04bcf | 346 | delete_font: |
57a6839d A |
347 | fprintf(outputFile, " </test-case>\n\n"); |
348 | fflush(outputFile); | |
349 | ||
73c04bcf | 350 | delete font; |
b75a7d8f | 351 | |
73c04bcf A |
352 | free_c_strings: |
353 | freeCString(lang); | |
354 | freeCString(script); | |
355 | freeCString(id); | |
356 | } | |
b75a7d8f A |
357 | } |
358 | ||
73c04bcf A |
359 | delete root; |
360 | delete parser; | |
361 | ||
362 | fprintf(outputFile, "</layout-tests>\n"); | |
b75a7d8f | 363 | |
57a6839d A |
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 | } | |
b75a7d8f | 381 | } |