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 "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 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::kTypoFlagLiga; // 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", fontName, buf); 242 freeCString(fontName); 243 goto free_c_strings; 244 } 245 246 printf(" Generating: %s, %s, %s, %s\n", id, script, lang, fontName); 247 248 version = pfi->getNameString(NAME_VERSION_STRING, PLATFORM_MACINTOSH, 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_ENGLISH); 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, &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()); 264 265 pfi->deleteNameString(uversion); 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()); 269 } 270 } else { 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()); 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, 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 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); 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 } 382