| 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 |