119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)/*
219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * Copyright (C) 2013 Google Inc. All rights reserved.
319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) *
419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * Redistribution and use in source and binary forms, with or without
519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * modification, are permitted provided that the following conditions are
619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * met:
719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) *
819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) *     * Redistributions of source code must retain the above copyright
919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * notice, this list of conditions and the following disclaimer.
1019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) *     * Redistributions in binary form must reproduce the above
1119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer
1219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * in the documentation and/or other materials provided with the
1319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * distribution.
1419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) *     * Neither the name of Google Inc. nor the names of its
1519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * contributors may be used to endorse or promote products derived from
1619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * this software without specific prior written permission.
1719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) *
1819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) */
3019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
3119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)#ifndef BidiTestHarness_h
3219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)#define BidiTestHarness_h
3319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
3419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)#include <istream>
3519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)#include <map>
3619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)#include <stdio.h>
3719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)#include <string>
3819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)#include <vector>
3919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
4019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)// FIXME: We don't have any business owning this code. We should try to
4119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)// upstream this to unicode.org if possible (for other implementations to use).
4219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)// Unicode.org provides a reference implmentation, including parser:
4319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)// http://www.unicode.org/Public/PROGRAMS/BidiReferenceC/6.3.0/source/brtest.c
4419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)// But it, like the other implementations I've found, is rather tied to
4519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)// the algorithms it is testing. This file seeks to only implement the parser bits.
4619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
4719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)// Other C/C++ implementations of this parser:
4819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)// https://github.com/googlei18n/fribidi-vs-unicode/blob/master/test.c
4919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)// http://source.icu-project.org/repos/icu/icu/trunk/source/test/intltest/bidiconf.cpp
5019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)// Both of those are too tied to their respective projects to be use to Blink.
5119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
5219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)// There are non-C implmentations to parse BidiTest.txt as well, including:
5319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)// https://github.com/twitter/twitter-cldr-rb/blob/master/spec/bidi/bidi_spec.rb
5419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
5519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)// NOTE: None of this file is currently written to be thread-safe.
5619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
5719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)namespace bidi_test {
5819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
5919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)enum ParagraphDirection {
6019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    DirectionAutoLTR = 1,
6119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    DirectionLTR = 2,
6219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    DirectionRTL = 4,
6319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)};
6419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)const int kMaxParagraphDirection = DirectionAutoLTR | DirectionLTR | DirectionRTL;
6519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
6619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)// For error printing:
6719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)std::string nameFromParagraphDirection(ParagraphDirection paragraphDirection)
6819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles){
6919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    switch (paragraphDirection) {
7019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    case bidi_test::DirectionAutoLTR:
7119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        return "Auto-LTR";
7219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    case bidi_test::DirectionLTR:
7319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        return "LTR";
7419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    case bidi_test::DirectionRTL:
7519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        return "RTL";
7619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    }
7719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    // This should never be reached.
7819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    return "";
7919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)}
8019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
8119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)template<class Runner>
8219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)class Harness {
8319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)public:
8419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    Harness(Runner& runner)
8519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        : m_runner(runner)
8619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    {
8719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    }
8819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    void parse(std::istream& bidiTestFile);
8919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
9019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)private:
9119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    Runner& m_runner;
9219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)};
9319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
9419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)// We could use boost::trim, but no other part of Blink uses boost yet.
9519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)inline void ltrim(std::string& s)
9619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles){
9719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    static const std::string separators(" \t");
9819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    s.erase(0, s.find_first_not_of(separators));
9919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)}
10019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
10119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)inline void rtrim(std::string& s)
10219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles){
10319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    static const std::string separators(" \t");
10419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    size_t lastNonSpace = s.find_last_not_of(separators);
10519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    if (lastNonSpace == std::string::npos) {
10619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        s.erase();
10719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        return;
10819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    }
10919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    size_t firstSpaceAtEndOfString = lastNonSpace + 1;
11019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    if (firstSpaceAtEndOfString >= s.size())
11119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        return; // lastNonSpace was the last char.
11219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    s.erase(firstSpaceAtEndOfString, std::string::npos); // erase to the end of the string.
11319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)}
11419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
11519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)inline void trim(std::string& s)
11619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles){
11719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    rtrim(s);
11819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    ltrim(s);
11919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)}
12019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
12119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)static std::vector<std::string> parseStringList(const std::string& str)
12219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles){
12319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    std::vector<std::string> strings;
12419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    static const std::string separators(" \t");
12519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    size_t lastPos = str.find_first_not_of(separators); // skip leading spaces
12619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    size_t pos = str.find_first_of(separators, lastPos); // find next space
12719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
12819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    while (std::string::npos != pos || std::string::npos != lastPos) {
12919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        strings.push_back(str.substr(lastPos, pos - lastPos));
13019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        lastPos = str.find_first_not_of(separators, pos);
13119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        pos = str.find_first_of(separators, lastPos);
13219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    }
13319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    return strings;
13419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)}
13519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
13619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)static std::vector<int> parseIntList(const std::string& str)
13719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles){
13819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    std::vector<int> ints;
13919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    std::vector<std::string> strings = parseStringList(str);
14019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    for (size_t x = 0; x < strings.size(); x++) {
14119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        int i = atoi(strings[x].c_str());
14219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        ints.push_back(i);
14319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    }
14419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    return ints;
14519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)}
14619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
14719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)static std::vector<int> parseLevels(const std::string& line)
14819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles){
14919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    std::vector<int> levels;
15019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    std::vector<std::string> strings = parseStringList(line);
15119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    for (size_t x = 0; x < strings.size(); x++) {
15219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        const std::string& levelString = strings[x];
15319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        int i;
15419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        if (levelString == "x")
15519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            i = -1;
15619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        else
15719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            i = atoi(levelString.c_str());
15819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        levels.push_back(i);
15919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    }
16019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    return levels;
16119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)}
16219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
16319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)// This is not thread-safe as written.
16419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)static std::basic_string<UChar> parseTestString(const std::string& line)
16519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles){
16619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    std::basic_string<UChar> testString;
16719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    static std::map<std::string, UChar> charClassExamples;
16819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    if (charClassExamples.empty()) {
16919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        // FIXME: Explicit make_pair is ugly, but required for C++98 compat.
17019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("L", 0x6c)); // 'l' for L
17119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("R", 0x05D0)); // HEBREW ALEF
17219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("EN", 0x33)); // '3' for EN
17319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("ES", 0x2d)); // '-' for ES
17419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("ET", 0x25)); // '%' for ET
17519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("AN", 0x0660)); // arabic 0
17619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("CS", 0x2c)); // ',' for CS
17719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("B", 0x0A)); // <control-000A>
17819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("S", 0x09)); // <control-0009>
17919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("WS", 0x20)); // ' ' for WS
18019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("ON", 0x3d)); // '=' for ON
18119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("NSM", 0x05BF)); // HEBREW POINT RAFE
18219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("AL", 0x0608)); // ARABIC RAY
18319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("BN", 0x00AD)); // SOFT HYPHEN
18419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("LRE", 0x202A));
18519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("RLE", 0x202B));
18619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("PDF", 0x202C));
18719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("LRO", 0x202D));
18819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("RLO", 0x202E));
18919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("LRI", 0x2066));
19019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("RLI", 0x2067));
19119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("FSI", 0x2068));
19219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        charClassExamples.insert(std::make_pair("PDI", 0x2069));
19319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    }
19419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
19519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    std::vector<std::string> charClasses = parseStringList(line);
19619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    for (size_t i = 0; i < charClasses.size(); i++) {
19719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        // FIXME: If the lookup failed we could return false for a parse error.
19819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        testString.push_back(charClassExamples.find(charClasses[i])->second);
19919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    }
20019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    return testString;
20119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)}
20219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
20319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)static bool parseParagraphDirectionMask(const std::string& line, int& modeMask)
20419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles){
20519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    modeMask = atoi(line.c_str());
20619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    return modeMask >= 1 && modeMask <= kMaxParagraphDirection;
20719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)}
20819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
20919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)static void parseError(const std::string& line, size_t lineNumber)
21019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles){
21119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    // Use printf to avoid the expense of std::cout.
21219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    printf("Parse error, line %zu : %s\n", lineNumber, line.c_str());
21319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)}
21419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
21519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)template<class Runner>
21619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)void Harness<Runner>::parse(std::istream& bidiTestFile)
21719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles){
21819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    static const std::string levelsPrefix("@Levels");
21919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    static const std::string reorderPrefix("@Reorder");
22019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
22119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    // FIXME: UChar is an ICU type and cheating a bit to use here.
22219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    // uint16_t might be more portable.
22319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    std::basic_string<UChar> testString;
22419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    std::vector<int> levels;
22519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    std::vector<int> reorder;
22619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    int paragraphDirectionMask;
22719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
22819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    std::string line;
22919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    size_t lineNumber = 0;
23019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    while (std::getline(bidiTestFile, line)) {
23119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        lineNumber++;
23219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        const std::string originalLine = line;
23319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        size_t commentStart = line.find_first_of('#');
23419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        if (commentStart != std::string::npos)
23519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            line = line.substr(0, commentStart);
23619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        trim(line);
23719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        if (line.empty())
23819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            continue;
23919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        if (line[0] == '@') {
24019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            if (!line.find(levelsPrefix)) {
24119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)                levels = parseLevels(line.substr(levelsPrefix.length() + 1));
24219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)                continue;
24319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            }
24419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            if (!line.find(reorderPrefix)) {
24519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)                reorder = parseIntList(line.substr(reorderPrefix.length() + 1));
24619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)                continue;
24719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            }
24819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        } else {
24919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            // Assume it's a data line.
25019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            size_t seperatorIndex = line.find_first_of(';');
25119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            if (seperatorIndex == std::string::npos) {
25219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)                parseError(originalLine, lineNumber);
25319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)                continue;
25419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            }
25519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            testString = parseTestString(line.substr(0, seperatorIndex));
25619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            if (!parseParagraphDirectionMask(line.substr(seperatorIndex + 1), paragraphDirectionMask)) {
25719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)                parseError(originalLine, lineNumber);
25819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)                continue;
25919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            }
26019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
26119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            if (paragraphDirectionMask & DirectionAutoLTR)
26219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)                m_runner.runTest(testString, reorder, levels, DirectionAutoLTR, originalLine, lineNumber);
26319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            if (paragraphDirectionMask & DirectionLTR)
26419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)                m_runner.runTest(testString, reorder, levels, DirectionLTR, originalLine, lineNumber);
26519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)            if (paragraphDirectionMask & DirectionRTL)
26619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)                m_runner.runTest(testString, reorder, levels, DirectionRTL, originalLine, lineNumber);
26719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)        }
26819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)    }
26919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)}
27019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
27119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)} // namespace bidi_test
27219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)
27319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)#endif // BidiTestHarness_h
274