1/* 2 ******************************************************************************* 3 * 4 * Copyright (C) 1999-2007, 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 36static 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 82static 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 132U_CDECL_BEGIN 133void 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 240free_expected: 241 DELETE_ARRAY(expected.positions); 242 DELETE_ARRAY(expected.indices); 243 DELETE_ARRAY(expected.glyphs); 244 245free_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} 259U_CDECL_END 260