159d709d503bab6e2b61931737e662dd293b40578ccornelius/*
259d709d503bab6e2b61931737e662dd293b40578ccornelius *******************************************************************************
359d709d503bab6e2b61931737e662dd293b40578ccornelius *
40596faeddefbf198de137d5e893708495ab1584cFredrik Roubert *   © 2016 and later: Unicode, Inc. and others.
564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert *   License & terms of use: http://www.unicode.org/copyright.html#License
664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert *
764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert *******************************************************************************
864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert *******************************************************************************
964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert *
1059d709d503bab6e2b61931737e662dd293b40578ccornelius *   Copyright (C) 1999-2013, International Business Machines
1159d709d503bab6e2b61931737e662dd293b40578ccornelius *   Corporation and others.  All Rights Reserved.
1259d709d503bab6e2b61931737e662dd293b40578ccornelius *
1359d709d503bab6e2b61931737e662dd293b40578ccornelius *******************************************************************************
1459d709d503bab6e2b61931737e662dd293b40578ccornelius */
1559d709d503bab6e2b61931737e662dd293b40578ccornelius
1659d709d503bab6e2b61931737e662dd293b40578ccornelius#include "unicode/utypes.h"
1759d709d503bab6e2b61931737e662dd293b40578ccornelius#include "unicode/uclean.h"
1859d709d503bab6e2b61931737e662dd293b40578ccornelius#include "unicode/uchar.h"
1959d709d503bab6e2b61931737e662dd293b40578ccornelius#include "unicode/unistr.h"
2059d709d503bab6e2b61931737e662dd293b40578ccornelius#include "unicode/uscript.h"
2159d709d503bab6e2b61931737e662dd293b40578ccornelius#include "unicode/putil.h"
2259d709d503bab6e2b61931737e662dd293b40578ccornelius#include "unicode/ctest.h"
2359d709d503bab6e2b61931737e662dd293b40578ccornelius
2459d709d503bab6e2b61931737e662dd293b40578ccornelius#include "layout/LETypes.h"
2559d709d503bab6e2b61931737e662dd293b40578ccornelius#include "layout/LEScripts.h"
2659d709d503bab6e2b61931737e662dd293b40578ccornelius
2759d709d503bab6e2b61931737e662dd293b40578ccornelius#include "letsutil.h"
2859d709d503bab6e2b61931737e662dd293b40578ccornelius#include "letest.h"
2959d709d503bab6e2b61931737e662dd293b40578ccornelius
3059d709d503bab6e2b61931737e662dd293b40578ccornelius#include "xmlreader.h"
3159d709d503bab6e2b61931737e662dd293b40578ccornelius
3259d709d503bab6e2b61931737e662dd293b40578ccornelius#include "xmlparser.h"
3359d709d503bab6e2b61931737e662dd293b40578ccornelius
3459d709d503bab6e2b61931737e662dd293b40578ccornelius#include <stdlib.h>
3559d709d503bab6e2b61931737e662dd293b40578ccornelius#include <stdio.h>
3659d709d503bab6e2b61931737e662dd293b40578ccornelius#include <string.h>
3759d709d503bab6e2b61931737e662dd293b40578ccornelius
3859d709d503bab6e2b61931737e662dd293b40578ccornelius//U_NAMESPACE_USE
3959d709d503bab6e2b61931737e662dd293b40578ccornelius
4059d709d503bab6e2b61931737e662dd293b40578ccornelius#define CH_COMMA 0x002C
4159d709d503bab6e2b61931737e662dd293b40578ccornelius
4259d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic le_uint32 *getHexArray(const UnicodeString &numbers, int32_t &arraySize)
4359d709d503bab6e2b61931737e662dd293b40578ccornelius{
4459d709d503bab6e2b61931737e662dd293b40578ccornelius    int32_t offset = -1;
4559d709d503bab6e2b61931737e662dd293b40578ccornelius
4659d709d503bab6e2b61931737e662dd293b40578ccornelius    arraySize = 1;
4759d709d503bab6e2b61931737e662dd293b40578ccornelius    while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) {
4859d709d503bab6e2b61931737e662dd293b40578ccornelius        arraySize += 1;
4959d709d503bab6e2b61931737e662dd293b40578ccornelius    }
5059d709d503bab6e2b61931737e662dd293b40578ccornelius
5159d709d503bab6e2b61931737e662dd293b40578ccornelius    le_uint32 *array = NEW_ARRAY(le_uint32, arraySize);
5259d709d503bab6e2b61931737e662dd293b40578ccornelius    char number[16];
5359d709d503bab6e2b61931737e662dd293b40578ccornelius    le_int32 count = 0;
5459d709d503bab6e2b61931737e662dd293b40578ccornelius    le_int32 start = 0, end = 0;
5559d709d503bab6e2b61931737e662dd293b40578ccornelius    le_int32 len = 0;
5659d709d503bab6e2b61931737e662dd293b40578ccornelius
5759d709d503bab6e2b61931737e662dd293b40578ccornelius    // trim leading whitespace
5859d709d503bab6e2b61931737e662dd293b40578ccornelius    while(u_isUWhiteSpace(numbers[start])) {
5959d709d503bab6e2b61931737e662dd293b40578ccornelius        start += 1;
6059d709d503bab6e2b61931737e662dd293b40578ccornelius    }
6159d709d503bab6e2b61931737e662dd293b40578ccornelius
6259d709d503bab6e2b61931737e662dd293b40578ccornelius    while((end = numbers.indexOf(CH_COMMA, start)) >= 0) {
6359d709d503bab6e2b61931737e662dd293b40578ccornelius        len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
6459d709d503bab6e2b61931737e662dd293b40578ccornelius        number[len] = '\0';
6559d709d503bab6e2b61931737e662dd293b40578ccornelius        start = end + 1;
6659d709d503bab6e2b61931737e662dd293b40578ccornelius
6759d709d503bab6e2b61931737e662dd293b40578ccornelius        sscanf(number, "%x", &array[count++]);
6859d709d503bab6e2b61931737e662dd293b40578ccornelius
6959d709d503bab6e2b61931737e662dd293b40578ccornelius        // trim whitespace following the comma
7059d709d503bab6e2b61931737e662dd293b40578ccornelius        while(u_isUWhiteSpace(numbers[start])) {
7159d709d503bab6e2b61931737e662dd293b40578ccornelius            start += 1;
7259d709d503bab6e2b61931737e662dd293b40578ccornelius        }
7359d709d503bab6e2b61931737e662dd293b40578ccornelius    }
7459d709d503bab6e2b61931737e662dd293b40578ccornelius
7559d709d503bab6e2b61931737e662dd293b40578ccornelius    // trim trailing whitespace
7659d709d503bab6e2b61931737e662dd293b40578ccornelius    end = numbers.length();
7759d709d503bab6e2b61931737e662dd293b40578ccornelius    while(u_isUWhiteSpace(numbers[end - 1])) {
7859d709d503bab6e2b61931737e662dd293b40578ccornelius        end -= 1;
7959d709d503bab6e2b61931737e662dd293b40578ccornelius    }
8059d709d503bab6e2b61931737e662dd293b40578ccornelius
8159d709d503bab6e2b61931737e662dd293b40578ccornelius    len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
8259d709d503bab6e2b61931737e662dd293b40578ccornelius    number[len] = '\0';
8359d709d503bab6e2b61931737e662dd293b40578ccornelius    sscanf(number, "%x", &array[count]);
8459d709d503bab6e2b61931737e662dd293b40578ccornelius
8559d709d503bab6e2b61931737e662dd293b40578ccornelius    return array;
8659d709d503bab6e2b61931737e662dd293b40578ccornelius}
8759d709d503bab6e2b61931737e662dd293b40578ccornelius
8859d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic float *getFloatArray(const UnicodeString &numbers, int32_t &arraySize)
8959d709d503bab6e2b61931737e662dd293b40578ccornelius{
9059d709d503bab6e2b61931737e662dd293b40578ccornelius    int32_t offset = -1;
9159d709d503bab6e2b61931737e662dd293b40578ccornelius
9259d709d503bab6e2b61931737e662dd293b40578ccornelius    arraySize = 1;
9359d709d503bab6e2b61931737e662dd293b40578ccornelius    while((offset = numbers.indexOf(CH_COMMA, offset + 1)) >= 0) {
9459d709d503bab6e2b61931737e662dd293b40578ccornelius        arraySize += 1;
9559d709d503bab6e2b61931737e662dd293b40578ccornelius    }
9659d709d503bab6e2b61931737e662dd293b40578ccornelius
9759d709d503bab6e2b61931737e662dd293b40578ccornelius    float *array = NEW_ARRAY(float, arraySize);
9859d709d503bab6e2b61931737e662dd293b40578ccornelius    char number[32];
9959d709d503bab6e2b61931737e662dd293b40578ccornelius    le_int32 count = 0;
10059d709d503bab6e2b61931737e662dd293b40578ccornelius    le_int32 start = 0, end = 0;
10159d709d503bab6e2b61931737e662dd293b40578ccornelius    le_int32 len = 0;
10259d709d503bab6e2b61931737e662dd293b40578ccornelius
10359d709d503bab6e2b61931737e662dd293b40578ccornelius    // trim leading whitespace
10459d709d503bab6e2b61931737e662dd293b40578ccornelius    while(u_isUWhiteSpace(numbers[start])) {
10559d709d503bab6e2b61931737e662dd293b40578ccornelius        start += 1;
10659d709d503bab6e2b61931737e662dd293b40578ccornelius    }
10759d709d503bab6e2b61931737e662dd293b40578ccornelius
10859d709d503bab6e2b61931737e662dd293b40578ccornelius    while((end = numbers.indexOf(CH_COMMA, start)) >= 0) {
10959d709d503bab6e2b61931737e662dd293b40578ccornelius        len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
11059d709d503bab6e2b61931737e662dd293b40578ccornelius        number[len] = '\0';
11159d709d503bab6e2b61931737e662dd293b40578ccornelius        start = end + 1;
11259d709d503bab6e2b61931737e662dd293b40578ccornelius
11359d709d503bab6e2b61931737e662dd293b40578ccornelius        sscanf(number, "%f", &array[count++]);
11459d709d503bab6e2b61931737e662dd293b40578ccornelius
11559d709d503bab6e2b61931737e662dd293b40578ccornelius        // trim whiteapce following the comma
11659d709d503bab6e2b61931737e662dd293b40578ccornelius        while(u_isUWhiteSpace(numbers[start])) {
11759d709d503bab6e2b61931737e662dd293b40578ccornelius            start += 1;
11859d709d503bab6e2b61931737e662dd293b40578ccornelius        }
11959d709d503bab6e2b61931737e662dd293b40578ccornelius    }
12059d709d503bab6e2b61931737e662dd293b40578ccornelius
12159d709d503bab6e2b61931737e662dd293b40578ccornelius    while(u_isUWhiteSpace(numbers[start])) {
12259d709d503bab6e2b61931737e662dd293b40578ccornelius        start += 1;
12359d709d503bab6e2b61931737e662dd293b40578ccornelius    }
12459d709d503bab6e2b61931737e662dd293b40578ccornelius
12559d709d503bab6e2b61931737e662dd293b40578ccornelius    // trim trailing whitespace
12659d709d503bab6e2b61931737e662dd293b40578ccornelius    end = numbers.length();
12759d709d503bab6e2b61931737e662dd293b40578ccornelius    while(u_isUWhiteSpace(numbers[end - 1])) {
12859d709d503bab6e2b61931737e662dd293b40578ccornelius        end -= 1;
12959d709d503bab6e2b61931737e662dd293b40578ccornelius    }
13059d709d503bab6e2b61931737e662dd293b40578ccornelius
13159d709d503bab6e2b61931737e662dd293b40578ccornelius    len = numbers.extract(start, end - start, number, ARRAY_SIZE(number), US_INV);
13259d709d503bab6e2b61931737e662dd293b40578ccornelius    number[len] = '\0';
13359d709d503bab6e2b61931737e662dd293b40578ccornelius    sscanf(number, "%f", &array[count]);
13459d709d503bab6e2b61931737e662dd293b40578ccornelius
13559d709d503bab6e2b61931737e662dd293b40578ccornelius    return array;
13659d709d503bab6e2b61931737e662dd293b40578ccornelius}
13759d709d503bab6e2b61931737e662dd293b40578ccornelius
13859d709d503bab6e2b61931737e662dd293b40578ccorneliusU_CDECL_BEGIN
13959d709d503bab6e2b61931737e662dd293b40578ccorneliusvoid readTestFile(const char *testFilePath, TestCaseCallback callback)
14059d709d503bab6e2b61931737e662dd293b40578ccornelius{
14159d709d503bab6e2b61931737e662dd293b40578ccornelius#if !UCONFIG_NO_REGULAR_EXPRESSIONS
14259d709d503bab6e2b61931737e662dd293b40578ccornelius    UErrorCode status = U_ZERO_ERROR;
14359d709d503bab6e2b61931737e662dd293b40578ccornelius    UXMLParser  *parser = UXMLParser::createParser(status);
14459d709d503bab6e2b61931737e662dd293b40578ccornelius    UXMLElement *root   = parser->parseFile(testFilePath, status);
14559d709d503bab6e2b61931737e662dd293b40578ccornelius
14659d709d503bab6e2b61931737e662dd293b40578ccornelius    if (root == NULL) {
14759d709d503bab6e2b61931737e662dd293b40578ccornelius        log_err("Could not open the test data file: %s\n", testFilePath);
14859d709d503bab6e2b61931737e662dd293b40578ccornelius        delete parser;
14959d709d503bab6e2b61931737e662dd293b40578ccornelius        return;
15059d709d503bab6e2b61931737e662dd293b40578ccornelius    }
15159d709d503bab6e2b61931737e662dd293b40578ccornelius
15259d709d503bab6e2b61931737e662dd293b40578ccornelius    UnicodeString test_case        = UNICODE_STRING_SIMPLE("test-case");
15359d709d503bab6e2b61931737e662dd293b40578ccornelius    UnicodeString test_text        = UNICODE_STRING_SIMPLE("test-text");
15459d709d503bab6e2b61931737e662dd293b40578ccornelius    UnicodeString test_font        = UNICODE_STRING_SIMPLE("test-font");
15559d709d503bab6e2b61931737e662dd293b40578ccornelius    UnicodeString result_glyphs    = UNICODE_STRING_SIMPLE("result-glyphs");
15659d709d503bab6e2b61931737e662dd293b40578ccornelius    UnicodeString result_indices   = UNICODE_STRING_SIMPLE("result-indices");
15759d709d503bab6e2b61931737e662dd293b40578ccornelius    UnicodeString result_positions = UNICODE_STRING_SIMPLE("result-positions");
15859d709d503bab6e2b61931737e662dd293b40578ccornelius
15959d709d503bab6e2b61931737e662dd293b40578ccornelius    // test-case attributes
16059d709d503bab6e2b61931737e662dd293b40578ccornelius    UnicodeString id_attr     = UNICODE_STRING_SIMPLE("id");
16159d709d503bab6e2b61931737e662dd293b40578ccornelius    UnicodeString script_attr = UNICODE_STRING_SIMPLE("script");
16259d709d503bab6e2b61931737e662dd293b40578ccornelius    UnicodeString lang_attr   = UNICODE_STRING_SIMPLE("lang");
16359d709d503bab6e2b61931737e662dd293b40578ccornelius
16459d709d503bab6e2b61931737e662dd293b40578ccornelius    // test-font attributes
16559d709d503bab6e2b61931737e662dd293b40578ccornelius    UnicodeString name_attr   = UNICODE_STRING_SIMPLE("name");
16659d709d503bab6e2b61931737e662dd293b40578ccornelius    UnicodeString ver_attr    = UNICODE_STRING_SIMPLE("version");
16759d709d503bab6e2b61931737e662dd293b40578ccornelius    UnicodeString cksum_attr  = UNICODE_STRING_SIMPLE("checksum");
16859d709d503bab6e2b61931737e662dd293b40578ccornelius
16959d709d503bab6e2b61931737e662dd293b40578ccornelius    const UXMLElement *testCase;
17059d709d503bab6e2b61931737e662dd293b40578ccornelius    int32_t tc = 0;
17159d709d503bab6e2b61931737e662dd293b40578ccornelius
17259d709d503bab6e2b61931737e662dd293b40578ccornelius    while((testCase = root->nextChildElement(tc)) != NULL) {
17359d709d503bab6e2b61931737e662dd293b40578ccornelius        if (testCase->getTagName().compare(test_case) == 0) {
17459d709d503bab6e2b61931737e662dd293b40578ccornelius            char *id = getCString(testCase->getAttribute(id_attr));
17559d709d503bab6e2b61931737e662dd293b40578ccornelius            char *script    = getCString(testCase->getAttribute(script_attr));
17659d709d503bab6e2b61931737e662dd293b40578ccornelius            char *lang      = getCString(testCase->getAttribute(lang_attr));
17759d709d503bab6e2b61931737e662dd293b40578ccornelius            char *fontName  = NULL;
17859d709d503bab6e2b61931737e662dd293b40578ccornelius			char *fontVer   = NULL;
17959d709d503bab6e2b61931737e662dd293b40578ccornelius			char *fontCksum = NULL;
18059d709d503bab6e2b61931737e662dd293b40578ccornelius            const UXMLElement *element;
18159d709d503bab6e2b61931737e662dd293b40578ccornelius            int32_t ec = 0;
18259d709d503bab6e2b61931737e662dd293b40578ccornelius            int32_t charCount = 0;
18359d709d503bab6e2b61931737e662dd293b40578ccornelius            int32_t typoFlags = 3; // kerning + ligatures...
18459d709d503bab6e2b61931737e662dd293b40578ccornelius            UScriptCode scriptCode;
18559d709d503bab6e2b61931737e662dd293b40578ccornelius            le_int32 languageCode = -1;
18659d709d503bab6e2b61931737e662dd293b40578ccornelius            UnicodeString text, glyphs, indices, positions;
18759d709d503bab6e2b61931737e662dd293b40578ccornelius            int32_t glyphCount = 0, indexCount = 0, positionCount = 0;
18859d709d503bab6e2b61931737e662dd293b40578ccornelius            TestResult expected = {0, NULL, NULL, NULL};
18959d709d503bab6e2b61931737e662dd293b40578ccornelius
19059d709d503bab6e2b61931737e662dd293b40578ccornelius            uscript_getCode(script, &scriptCode, 1, &status);
19159d709d503bab6e2b61931737e662dd293b40578ccornelius            if (LE_FAILURE(status)) {
19259d709d503bab6e2b61931737e662dd293b40578ccornelius                log_err("invalid script name: %s.\n", script);
19359d709d503bab6e2b61931737e662dd293b40578ccornelius                goto free_c_strings;
19459d709d503bab6e2b61931737e662dd293b40578ccornelius            }
19559d709d503bab6e2b61931737e662dd293b40578ccornelius
19659d709d503bab6e2b61931737e662dd293b40578ccornelius            if (lang != NULL) {
19759d709d503bab6e2b61931737e662dd293b40578ccornelius                languageCode = getLanguageCode(lang);
19859d709d503bab6e2b61931737e662dd293b40578ccornelius
19959d709d503bab6e2b61931737e662dd293b40578ccornelius                if (languageCode < 0) {
20059d709d503bab6e2b61931737e662dd293b40578ccornelius                    log_err("invalid language name: %s.\n", lang);
20159d709d503bab6e2b61931737e662dd293b40578ccornelius                    goto free_c_strings;
20259d709d503bab6e2b61931737e662dd293b40578ccornelius                }
20359d709d503bab6e2b61931737e662dd293b40578ccornelius            }
20459d709d503bab6e2b61931737e662dd293b40578ccornelius
20559d709d503bab6e2b61931737e662dd293b40578ccornelius            while((element = testCase->nextChildElement(ec)) != NULL) {
20659d709d503bab6e2b61931737e662dd293b40578ccornelius                UnicodeString tag = element->getTagName();
20759d709d503bab6e2b61931737e662dd293b40578ccornelius
20859d709d503bab6e2b61931737e662dd293b40578ccornelius                // TODO: make sure that each element is only used once.
20959d709d503bab6e2b61931737e662dd293b40578ccornelius                if (tag.compare(test_font) == 0) {
21059d709d503bab6e2b61931737e662dd293b40578ccornelius                    fontName  = getCString(element->getAttribute(name_attr));
21159d709d503bab6e2b61931737e662dd293b40578ccornelius                    fontVer   = getCString(element->getAttribute(ver_attr));
21259d709d503bab6e2b61931737e662dd293b40578ccornelius                    fontCksum = getCString(element->getAttribute(cksum_attr));
21359d709d503bab6e2b61931737e662dd293b40578ccornelius
21459d709d503bab6e2b61931737e662dd293b40578ccornelius                } else if (tag.compare(test_text) == 0) {
21559d709d503bab6e2b61931737e662dd293b40578ccornelius                    text = element->getText(TRUE);
21659d709d503bab6e2b61931737e662dd293b40578ccornelius                    charCount = text.length();
21759d709d503bab6e2b61931737e662dd293b40578ccornelius                } else if (tag.compare(result_glyphs) == 0) {
21859d709d503bab6e2b61931737e662dd293b40578ccornelius                    glyphs = element->getText(TRUE);
21959d709d503bab6e2b61931737e662dd293b40578ccornelius                } else if (tag.compare(result_indices) == 0) {
22059d709d503bab6e2b61931737e662dd293b40578ccornelius                    indices = element->getText(TRUE);
22159d709d503bab6e2b61931737e662dd293b40578ccornelius                } else if (tag.compare(result_positions) == 0) {
22259d709d503bab6e2b61931737e662dd293b40578ccornelius                    positions = element->getText(TRUE);
22359d709d503bab6e2b61931737e662dd293b40578ccornelius                } else {
22459d709d503bab6e2b61931737e662dd293b40578ccornelius                    // an unknown tag...
22559d709d503bab6e2b61931737e662dd293b40578ccornelius                    char *cTag = getCString(&tag);
22659d709d503bab6e2b61931737e662dd293b40578ccornelius
22759d709d503bab6e2b61931737e662dd293b40578ccornelius                    log_info("Test %s: unknown element with tag \"%s\"\n", id, cTag);
22859d709d503bab6e2b61931737e662dd293b40578ccornelius                    freeCString(cTag);
22959d709d503bab6e2b61931737e662dd293b40578ccornelius                }
23059d709d503bab6e2b61931737e662dd293b40578ccornelius            }
23159d709d503bab6e2b61931737e662dd293b40578ccornelius
23259d709d503bab6e2b61931737e662dd293b40578ccornelius            expected.glyphs    = (LEGlyphID *) getHexArray(glyphs, glyphCount);
23359d709d503bab6e2b61931737e662dd293b40578ccornelius            expected.indices   = (le_int32 *)  getHexArray(indices, indexCount);
23459d709d503bab6e2b61931737e662dd293b40578ccornelius            expected.positions = getFloatArray(positions, positionCount);
23559d709d503bab6e2b61931737e662dd293b40578ccornelius
23659d709d503bab6e2b61931737e662dd293b40578ccornelius            expected.glyphCount = glyphCount;
23759d709d503bab6e2b61931737e662dd293b40578ccornelius
23859d709d503bab6e2b61931737e662dd293b40578ccornelius            if (glyphCount < charCount || indexCount != glyphCount || positionCount < glyphCount * 2 + 2) {
23959d709d503bab6e2b61931737e662dd293b40578ccornelius                log_err("Test %s: inconsistent input data: charCount = %d, glyphCount = %d, indexCount = %d, positionCount = %d\n",
24059d709d503bab6e2b61931737e662dd293b40578ccornelius                    id, charCount, glyphCount, indexCount, positionCount);
24159d709d503bab6e2b61931737e662dd293b40578ccornelius                goto free_expected;
24259d709d503bab6e2b61931737e662dd293b40578ccornelius            };
24359d709d503bab6e2b61931737e662dd293b40578ccornelius
24459d709d503bab6e2b61931737e662dd293b40578ccornelius			(*callback)(id, fontName, fontVer, fontCksum, scriptCode, languageCode, text.getBuffer(), charCount, &expected);
24559d709d503bab6e2b61931737e662dd293b40578ccornelius
24659d709d503bab6e2b61931737e662dd293b40578ccorneliusfree_expected:
24759d709d503bab6e2b61931737e662dd293b40578ccornelius            DELETE_ARRAY(expected.positions);
24859d709d503bab6e2b61931737e662dd293b40578ccornelius            DELETE_ARRAY(expected.indices);
24959d709d503bab6e2b61931737e662dd293b40578ccornelius            DELETE_ARRAY(expected.glyphs);
25059d709d503bab6e2b61931737e662dd293b40578ccornelius
25159d709d503bab6e2b61931737e662dd293b40578ccorneliusfree_c_strings:
25259d709d503bab6e2b61931737e662dd293b40578ccornelius			freeCString(fontCksum);
25359d709d503bab6e2b61931737e662dd293b40578ccornelius			freeCString(fontVer);
25459d709d503bab6e2b61931737e662dd293b40578ccornelius			freeCString(fontName);
25559d709d503bab6e2b61931737e662dd293b40578ccornelius            freeCString(lang);
25659d709d503bab6e2b61931737e662dd293b40578ccornelius            freeCString(script);
25759d709d503bab6e2b61931737e662dd293b40578ccornelius            freeCString(id);
25859d709d503bab6e2b61931737e662dd293b40578ccornelius        }
25959d709d503bab6e2b61931737e662dd293b40578ccornelius    }
26059d709d503bab6e2b61931737e662dd293b40578ccornelius
26159d709d503bab6e2b61931737e662dd293b40578ccornelius    delete root;
26259d709d503bab6e2b61931737e662dd293b40578ccornelius    delete parser;
26359d709d503bab6e2b61931737e662dd293b40578ccornelius#endif
26459d709d503bab6e2b61931737e662dd293b40578ccornelius}
26559d709d503bab6e2b61931737e662dd293b40578ccorneliusU_CDECL_END
266