<commit_before>/*
 * Copyright (C) 2016 Muhammad Tayyab Akram
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <cstdint>
#include <cstring>
#include <iostream>
#include <list>
#include <memory>
#include <set>
#include <tuple>
#include <utility>
#include <vector>

extern "C" {
#include <Source/SFAlbum.h>
#include <Source/SFAssert.h>
}

#include "OpenType/Builder.h"
#include "OpenType/GSUB.h"
#include "TextProcessorTester.h"

using namespace std;
using namespace SheenFigure::Tester;
using namespace SheenFigure::Tester::OpenType;

void TextProcessorTester::testSingleSubstitution()
{
    Builder builder;

    /* Test the first format. */
    {
        /* Test with unmatching glyph. */
        testSubstitution(builder.createSingleSubst({ 0 }, 0), { 1 }, { 1 });
        /* Test with zero delta. */
        testSubstitution(builder.createSingleSubst({ 1 }, 0), { 1 }, { 1 });
        /* Test with positive delta. */
        testSubstitution(builder.createSingleSubst({ 1 }, 99), { 1 }, { 100 });
        /* Test with negative delta. */
        testSubstitution(builder.createSingleSubst({ 100 }, -99), { 100 }, { 1 });
        /* Test with opposite delta. */
        testSubstitution(builder.createSingleSubst({ 1 }, -1), { 1 }, { 0 });
    }

    /* Test the second format. */
    {
        /* Test with unmatching glyph. */
        testSubstitution(builder.createSingleSubst({ {0, 0} }), { 1 }, { 1 });
        /* Test with zero glyph. */
        testSubstitution(builder.createSingleSubst({ {0, 1} }), { 0 }, { 1 });
        /* Test with zero substitution. */
        testSubstitution(builder.createSingleSubst({ {1, 0} }), { 1 }, { 0 });
        /* Test with same substitution. */
        testSubstitution(builder.createSingleSubst({ {1, 1} }), { 1 }, { 1 });
        /* Test with a different substitution. */
        testSubstitution(builder.createSingleSubst({ {1, 100} }), { 1 }, { 100 });
    }
}

void TextProcessorTester::testMultipleSubstitution()
{
    Builder builder;

    /* Test with unmatching glyph. */
    testSubstitution(builder.createMultipleSubst({ {0, { 1, 2, 3 }} }), { 1 }, { 1 });
    /* Test with no glyph. */
    testSubstitution(builder.createMultipleSubst({ {1, { }} }), { 1 }, { 1 });
    /* Test with zero glyph. */
    testSubstitution(builder.createMultipleSubst({ {0, { 1 }} }), { 0 }, { 1 });
    /* Test with zero substitution. */
    testSubstitution(builder.createMultipleSubst({ {1, { 0 }} }), { 1 }, { 0 });
    /* Test with same substitution. */
    testSubstitution(builder.createMultipleSubst({ {1, { 1 }} }), { 1 }, { 1 });
    /* Test with different single substitution. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100 }} }), { 1 }, { 100 });
    /* Test with different two substitutions. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 200 }} }), { 1 }, { 100, 200 });
    /* Test with different multiple substitutions. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 200, 300 }} }), { 1 }, { 100, 200, 300 });
    /* Test with multiple substitutions having input glyph at the start. */
    testSubstitution(builder.createMultipleSubst({ {1, { 1, 200, 300 }} }), { 1 }, { 1, 200, 300 });
    /* Test with multiple substitutions having input glyph at the middle. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 1, 300 }} }), { 1 }, { 100, 1, 300 });
    /* Test with multiple substitutions having input glyph at the end. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 200, 1 }} }), { 1 }, { 100, 200, 1 });
    /* Test with multiple substitutions having input glyph everywhere. */
    testSubstitution(builder.createMultipleSubst({ {1, { 1, 1, 1 }} }), { 1 }, { 1, 1, 1 });
    /* Test with multiple repeating substitutions. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 100, 100 }} }), { 1 }, { 100, 100, 100 });
    /* Test with multiple zero substitutions. */
    testSubstitution(builder.createMultipleSubst({ {1, { 0, 0, 0 }} }), { 1 }, { 0, 0, 0 });
}

void TextProcessorTester::testLigatureSubstitution()
{
    Builder builder;

    /* Test with unmatching glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 0} }), { 1 }, { 1 });
    /* Test with zero glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 0 }, 1} }), { 0 }, { 1 });
    /* Test with zero substitution. */
    testSubstitution(builder.createLigatureSubst({ {{ 1 }, 0} }), { 1 }, { 0 });
    /* Test with same substitution. */
    testSubstitution(builder.createLigatureSubst({ {{ 1 }, 1} }), { 1 }, { 1 });
    /* Test with different substitution. */
    testSubstitution(builder.createLigatureSubst({ {{ 1 }, 100} }), { 1 }, { 100 });
    /* Test with two different glyphs. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2 }, 100} }), { 1, 2 }, { 100 });
    /* Test with multiple different glyphs. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 100} }), { 1, 2, 3 }, { 100 });
    /* Test with multiple glyphs translating to first input glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 1} }), { 1, 2, 3 }, { 1 });
    /* Test with multiple glyphs translating to middle input glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 2} }), { 1, 2, 3 }, { 2 });
    /* Test with multiple glyphs translating to last input glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 3} }), { 1, 2, 3 }, { 3 });
    /* Test with multiple same glyphs translating to itself. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 1, 1 }, 1} }), { 1, 1, 1 }, { 1 });
    /* Test with multiple same glyphs translating to a different glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 1, 1 }, 100} }), { 1, 1, 1 }, { 100 });
    /* Test with multiple zero glyphs. */
    testSubstitution(builder.createLigatureSubst({ {{ 0, 0, 0 }, 100} }), { 0, 0, 0 }, { 100 });
}

void TextProcessorTester::testChainContextSubstitution()
{
    Builder builder;

    /* Test the format 1. */
    {
        /* Test with simple substitution. */
        {
            vector<LookupSubtable *> referrals = {
                &builder.createSingleSubst({ 2 }, 1)
            };
            ChainContextSubtable &subtable = builder.createChainContext({
                rule_chain_context {
                    { 1, 1, 1 },
                    { 1, 2, 3 },
                    { 3, 3, 3 },
                    { { 1, 1 } }
                }
            });
            testSubstitution(subtable,
                             { 1, 1, 1, 1, 2, 3, 3, 3, 3 }, { 1, 1, 1, 1, 3, 3, 3, 3, 3 },
                             referrals.data(), referrals.size());
        }

        /* Test with complex substitutions. */
        {
            vector<LookupSubtable *> referrals = {
                &builder.createSingleSubst({ 1, 2, 3, 4, 5, 6 }, 1),
                &builder.createMultipleSubst({ {2, { 4, 5, 6 }} }),
                &builder.createLigatureSubst({ {{ 1, 4 }, 10}, {{ 6, 4 }, 20} })
            };
            ChainContextSubtable &subtable = builder.createChainContext({
                rule_chain_context {
                    { 1, 1, 1 },
                    { 1, 2, 3 },
                    { 3, 3, 3 },
                    { { 2, 1 }, { 1, 2 }, { 3, 3 }, { 0, 3 }, { 1, 1 } }
                }
            });
            testSubstitution(subtable,
                             {  1, 1, 1, 1, 2, 3, 3, 3, 3 }, { 1, 1, 1, 10, 6, 20, 3, 3, 3 },
                             referrals.data(), referrals.size());
        }
    }

    /* Test the format 3. */
    {
        /* Test with simple substitution. */
        {
            vector<LookupSubtable *> referrals = {
                &builder.createSingleSubst({ 2 }, 1)
            };
            ChainContextSubtable &subtable = builder.createChainContext(
                { { 1 }, { 1 }, { 1 } },
                { { 1 }, { 2 }, { 3 } },
                { { 3 }, { 3 }, { 3 } },
                { { 1, 1 } }
            );
            testSubstitution(subtable,
                             { 1, 1, 1, 1, 2, 3, 3, 3, 3 }, { 1, 1, 1, 1, 3, 3, 3, 3, 3 },
                             referrals.data(), referrals.size());
        }

        /* Test with complex substitutions. */
        {
            vector<LookupSubtable *> referrals = {
                &builder.createSingleSubst({ 1, 2, 3, 4, 5, 6 }, 1),
                &builder.createMultipleSubst({ {2, { 4, 5, 6 }} }),
                &builder.createLigatureSubst({ {{ 1, 4 }, 10}, {{ 6, 4 }, 20} })
            };
            ChainContextSubtable &subtable = builder.createChainContext(
                { { 1 }, { 1 }, { 1 } },
                { { 1 }, { 2 }, { 3 } },
                { { 3 }, { 3 }, { 3 } },
                { { 2, 1 }, { 1, 2 }, { 3, 3 }, { 0, 3 }, { 1, 1 } }
            );
            testSubstitution(subtable,
                             {  1, 1, 1, 1, 2, 3, 3, 3, 3 }, { 1, 1, 1, 10, 6, 20, 3, 3, 3 },
                             referrals.data(), referrals.size());
        }
    }
}
<commit_msg>Added test cases for chain context format 2...<commit_after>/*
 * Copyright (C) 2016 Muhammad Tayyab Akram
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <cstdint>
#include <cstring>
#include <iostream>
#include <list>
#include <memory>
#include <set>
#include <tuple>
#include <utility>
#include <vector>

extern "C" {
#include <Source/SFAlbum.h>
#include <Source/SFAssert.h>
}

#include "OpenType/Builder.h"
#include "OpenType/GSUB.h"
#include "TextProcessorTester.h"

using namespace std;
using namespace SheenFigure::Tester;
using namespace SheenFigure::Tester::OpenType;

void TextProcessorTester::testSingleSubstitution()
{
    Builder builder;

    /* Test the first format. */
    {
        /* Test with unmatching glyph. */
        testSubstitution(builder.createSingleSubst({ 0 }, 0), { 1 }, { 1 });
        /* Test with zero delta. */
        testSubstitution(builder.createSingleSubst({ 1 }, 0), { 1 }, { 1 });
        /* Test with positive delta. */
        testSubstitution(builder.createSingleSubst({ 1 }, 99), { 1 }, { 100 });
        /* Test with negative delta. */
        testSubstitution(builder.createSingleSubst({ 100 }, -99), { 100 }, { 1 });
        /* Test with opposite delta. */
        testSubstitution(builder.createSingleSubst({ 1 }, -1), { 1 }, { 0 });
    }

    /* Test the second format. */
    {
        /* Test with unmatching glyph. */
        testSubstitution(builder.createSingleSubst({ {0, 0} }), { 1 }, { 1 });
        /* Test with zero glyph. */
        testSubstitution(builder.createSingleSubst({ {0, 1} }), { 0 }, { 1 });
        /* Test with zero substitution. */
        testSubstitution(builder.createSingleSubst({ {1, 0} }), { 1 }, { 0 });
        /* Test with same substitution. */
        testSubstitution(builder.createSingleSubst({ {1, 1} }), { 1 }, { 1 });
        /* Test with a different substitution. */
        testSubstitution(builder.createSingleSubst({ {1, 100} }), { 1 }, { 100 });
    }
}

void TextProcessorTester::testMultipleSubstitution()
{
    Builder builder;

    /* Test with unmatching glyph. */
    testSubstitution(builder.createMultipleSubst({ {0, { 1, 2, 3 }} }), { 1 }, { 1 });
    /* Test with no glyph. */
    testSubstitution(builder.createMultipleSubst({ {1, { }} }), { 1 }, { 1 });
    /* Test with zero glyph. */
    testSubstitution(builder.createMultipleSubst({ {0, { 1 }} }), { 0 }, { 1 });
    /* Test with zero substitution. */
    testSubstitution(builder.createMultipleSubst({ {1, { 0 }} }), { 1 }, { 0 });
    /* Test with same substitution. */
    testSubstitution(builder.createMultipleSubst({ {1, { 1 }} }), { 1 }, { 1 });
    /* Test with different single substitution. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100 }} }), { 1 }, { 100 });
    /* Test with different two substitutions. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 200 }} }), { 1 }, { 100, 200 });
    /* Test with different multiple substitutions. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 200, 300 }} }), { 1 }, { 100, 200, 300 });
    /* Test with multiple substitutions having input glyph at the start. */
    testSubstitution(builder.createMultipleSubst({ {1, { 1, 200, 300 }} }), { 1 }, { 1, 200, 300 });
    /* Test with multiple substitutions having input glyph at the middle. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 1, 300 }} }), { 1 }, { 100, 1, 300 });
    /* Test with multiple substitutions having input glyph at the end. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 200, 1 }} }), { 1 }, { 100, 200, 1 });
    /* Test with multiple substitutions having input glyph everywhere. */
    testSubstitution(builder.createMultipleSubst({ {1, { 1, 1, 1 }} }), { 1 }, { 1, 1, 1 });
    /* Test with multiple repeating substitutions. */
    testSubstitution(builder.createMultipleSubst({ {1, { 100, 100, 100 }} }), { 1 }, { 100, 100, 100 });
    /* Test with multiple zero substitutions. */
    testSubstitution(builder.createMultipleSubst({ {1, { 0, 0, 0 }} }), { 1 }, { 0, 0, 0 });
}

void TextProcessorTester::testLigatureSubstitution()
{
    Builder builder;

    /* Test with unmatching glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 0} }), { 1 }, { 1 });
    /* Test with zero glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 0 }, 1} }), { 0 }, { 1 });
    /* Test with zero substitution. */
    testSubstitution(builder.createLigatureSubst({ {{ 1 }, 0} }), { 1 }, { 0 });
    /* Test with same substitution. */
    testSubstitution(builder.createLigatureSubst({ {{ 1 }, 1} }), { 1 }, { 1 });
    /* Test with different substitution. */
    testSubstitution(builder.createLigatureSubst({ {{ 1 }, 100} }), { 1 }, { 100 });
    /* Test with two different glyphs. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2 }, 100} }), { 1, 2 }, { 100 });
    /* Test with multiple different glyphs. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 100} }), { 1, 2, 3 }, { 100 });
    /* Test with multiple glyphs translating to first input glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 1} }), { 1, 2, 3 }, { 1 });
    /* Test with multiple glyphs translating to middle input glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 2} }), { 1, 2, 3 }, { 2 });
    /* Test with multiple glyphs translating to last input glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 2, 3 }, 3} }), { 1, 2, 3 }, { 3 });
    /* Test with multiple same glyphs translating to itself. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 1, 1 }, 1} }), { 1, 1, 1 }, { 1 });
    /* Test with multiple same glyphs translating to a different glyph. */
    testSubstitution(builder.createLigatureSubst({ {{ 1, 1, 1 }, 100} }), { 1, 1, 1 }, { 100 });
    /* Test with multiple zero glyphs. */
    testSubstitution(builder.createLigatureSubst({ {{ 0, 0, 0 }, 100} }), { 0, 0, 0 }, { 100 });
}

void TextProcessorTester::testChainContextSubstitution()
{
    Builder builder;

    /* Test the format 1. */
    {
        /* Test with simple substitution. */
        {
            vector<LookupSubtable *> referrals = {
                &builder.createSingleSubst({ 2 }, 1)
            };
            ChainContextSubtable &subtable = builder.createChainContext({
                rule_chain_context {
                    { 1, 1, 1 },
                    { 1, 2, 3 },
                    { 3, 3, 3 },
                    { { 1, 1 } }
                }
            });
            testSubstitution(subtable,
                             { 1, 1, 1, 1, 2, 3, 3, 3, 3 }, { 1, 1, 1, 1, 3, 3, 3, 3, 3 },
                             referrals.data(), referrals.size());
        }

        /* Test with complex substitutions. */
        {
            vector<LookupSubtable *> referrals = {
                &builder.createSingleSubst({ 1, 2, 3, 4, 5, 6 }, 1),
                &builder.createMultipleSubst({ {2, { 4, 5, 6 }} }),
                &builder.createLigatureSubst({ {{ 1, 4 }, 10}, {{ 6, 4 }, 20} })
            };
            ChainContextSubtable &subtable = builder.createChainContext({
                rule_chain_context {
                    { 1, 1, 1 },
                    { 1, 2, 3 },
                    { 3, 3, 3 },
                    { { 2, 1 }, { 1, 2 }, { 3, 3 }, { 0, 3 }, { 1, 1 } }
                }
            });
            testSubstitution(subtable,
                             {  1, 1, 1, 1, 2, 3, 3, 3, 3 }, { 1, 1, 1, 10, 6, 20, 3, 3, 3 },
                             referrals.data(), referrals.size());
        }
    }

    /* Test the format 2. */
    {
        array<ClassDefTable *, 3> classDefs = {
            &builder.createClassDef({ { 1, 10, 1 } }),
            &builder.createClassDef({ { 1, 10, 1 } }),
            &builder.createClassDef({ { 1, 10, 1 } }),
        };

        /* Test with simple substitution. */
        {
            vector<LookupSubtable *> referrals = {
                &builder.createSingleSubst({ 2 }, 1)
            };
            ChainContextSubtable &subtable = builder.createChainContext({
                rule_chain_context {
                    { 1, 1, 1 },
                    { 1, 1, 1 },
                    { 1, 1, 1 },
                    { { 1, 1 } }
                }
            }, classDefs);
            testSubstitution(subtable,
                             { 1, 1, 1, 1, 2, 3, 3, 3, 3 }, { 1, 1, 1, 1, 3, 3, 3, 3, 3 },
                             referrals.data(), referrals.size());
        }

        /* Test with complex substitutions. */
        {
            vector<LookupSubtable *> referrals = {
                &builder.createSingleSubst({ 1, 2, 3, 4, 5, 6 }, 1),
                &builder.createMultipleSubst({ {2, { 4, 5, 6 }} }),
                &builder.createLigatureSubst({ {{ 1, 4 }, 10}, {{ 6, 4 }, 20} })
            };
            ChainContextSubtable &subtable = builder.createChainContext({
                rule_chain_context {
                    { 1, 1, 1 },
                    { 1, 1, 1 },
                    { 1, 1, 1 },
                    { { 2, 1 }, { 1, 2 }, { 3, 3 }, { 0, 3 }, { 1, 1 } }
                }
            }, classDefs);
            testSubstitution(subtable,
                             {  1, 1, 1, 1, 2, 3, 3, 3, 3 }, { 1, 1, 1, 10, 6, 20, 3, 3, 3 },
                             referrals.data(), referrals.size());
        }
    }

    /* Test the format 3. */
    {
        /* Test with simple substitution. */
        {
            vector<LookupSubtable *> referrals = {
                &builder.createSingleSubst({ 2 }, 1)
            };
            ChainContextSubtable &subtable = builder.createChainContext(
                { { 1 }, { 1 }, { 1 } },
                { { 1 }, { 2 }, { 3 } },
                { { 3 }, { 3 }, { 3 } },
                { { 1, 1 } }
            );
            testSubstitution(subtable,
                             { 1, 1, 1, 1, 2, 3, 3, 3, 3 }, { 1, 1, 1, 1, 3, 3, 3, 3, 3 },
                             referrals.data(), referrals.size());
        }

        /* Test with complex substitutions. */
        {
            vector<LookupSubtable *> referrals = {
                &builder.createSingleSubst({ 1, 2, 3, 4, 5, 6 }, 1),
                &builder.createMultipleSubst({ {2, { 4, 5, 6 }} }),
                &builder.createLigatureSubst({ {{ 1, 4 }, 10}, {{ 6, 4 }, 20} })
            };
            ChainContextSubtable &subtable = builder.createChainContext(
                { { 1 }, { 1 }, { 1 } },
                { { 1 }, { 2 }, { 3 } },
                { { 3 }, { 3 }, { 3 } },
                { { 2, 1 }, { 1, 2 }, { 3, 3 }, { 0, 3 }, { 1, 1 } }
            );
            testSubstitution(subtable,
                             {  1, 1, 1, 1, 2, 3, 3, 3, 3 }, { 1, 1, 1, 10, 6, 20, 3, 3, 3 },
                             referrals.data(), referrals.size());
        }
    }
}
<|endoftext|>


<commit_before>#ifndef LM_HH
#define LM_HH

#include <float.h>
#include "misc/types.hh"
#include "FixedArray.hh"

namespace fsalm {

  class Semiring {
  public:
    Semiring() : one(0), zero(-1e30) { }
    virtual ~Semiring() { }
    virtual float plus(float a, float b) = 0;
    virtual float times(float a, float b) = 0;
    virtual float divide(float a, float b) = 0;
    virtual bool equal(float a, float b) = 0;
    float one;
    float zero;
  };

  class MaxPlusSemiring : public Semiring {
  public:
    virtual ~MaxPlusSemiring() { }
    virtual float plus(float a, float b) { return a < b ? b : a; }
    virtual float times(float a, float b) { return a + b; }
    virtual float divide(float a, float b) { return a - b; }
    virtual bool equal(float a, float b) { return a == b; }
  };

  /** Class for storing ngram language model in a fst format with
   * backoff arcs.
   *
   * INVARIANTS:
   *
   * - before trim() there may be nodes without children and bt=0
   *
   * - after trim() only final node has bt=0 and has zero children
   *
   * - node n has zero children if limit[n-1] == limit[n] or limit[n] == 0
   *
   * IMPLEMENTATION NOTES:
   *
   * - Backoff information is stored in the nodes instead of normal
   * arcs.  Otherwise, creating the arcs in proper order would be
   * troublesome from ARPA format.
   *
   * ASSUMES:
   * - children of a context are inserted in sorted chunk
   * - lower order is inserted before higher order
   */
  class LM {
  public:

    typedef FixedArray<int> Array;
    typedef FixedArray<float> FloatArray;

    Str start_str;
    Str end_str;
    Semiring *semiring;

    LM();
    void reset();
    const SymbolMap &symbol_map() const { return m_symbol_map; }
    int start_symbol() const { return m_start_symbol; }
    int end_symbol() const { return m_end_symbol; }
    int final_node_id() const { return m_final_node_id; }
    int empty_node_id() const { return m_empty_node_id; }
    int initial_node_id() const { return m_initial_node_id; }
    int order() const { return m_order; }
    int num_arcs() const { return m_arcs.symbol.num_elems(); }
    int num_nodes() const { return m_nodes.bo_target.num_elems(); }
    float final_score() const { return m_final_score; }

    /** Return the number of explicit children of node. */
    int num_children(int node_id) const;

    /** String describing a vector of symbol indices. */
    Str str(const IntVec &vec) const;

    /** Find context node for given backoff vector by backoffing
     * further if necessary.
     *
     * \note Throws exception if given ngram ends in sentence end
     * symbol.
     *
     * \param vec = candidate context for the backoff
     * \return node index corresponding to backoff context
     */
    int find_backoff(IntVec vec) const;

    /** Move to next node through given symbol but do not backoff.
     *
     * Finds the arc that starts from given node and has the given
     * symbol assigned, then returns its target node.
     *
     * \param node_id = the node to start from (final node not allowed)
     * \param symbol = the symbol to search
     * \param score = float pointer to which the possible score of the arc is ADDED
     * \return the resulting node (or -1 if explicit arc with symbol not found)
     */
    int walk_no_bo(int node_id, int symbol, float *score = NULL) const;
    int walk_no_bo(int node_id, const IntVec &vec, float *score = NULL) const;

    /** Move to next node through given symbols without backoffing.
     * Same as above, but returns node indices for each symbol in a
     * vector. */
    IntVec walk_no_bo_vec(int node_id, const IntVec &vec,
                          float *score = NULL) const;

    /** Move to next node through given symbol by backoffing if necessary.
     *
     * \param node_id = the node to start from (final node not allowed)
     * \param symbol = the symbol to traverse through
     * \param score = float pointer to which the score is ADDED
     * \return the resulting node
     */
    int walk(int node_id, int symbol, float *score = NULL) const;
    int walk(int node_id, const IntVec &vec, float *score = NULL) const;

    void new_arc(int src_node_id, int symbol, int tgt_node_id, float score);
    void new_ngram(const IntVec &vec, float score, float bo_score);
    int new_node();
    void set_arc(int arc_id, int symbol, int target, float score);
    void trim();
    void quantize(int bits);

    /** Compute potential of each node (used by push). */
    void compute_potential(FloatVec &d);

    /** Push scores as early as possible. */
    void push();

    /** Reads the language model in ARPA format. */
    void read_arpa(FILE *file, bool show_progress = false);
    /** Reads the language model in a non-standard format. */
    void read(FILE *file);
    /** Writes the language model in a non-standard format. */
    void write(FILE *file) const;

    /** Write the language model in MIT fst format. */
    void write_fst(FILE *file, Str bo_symbol = "<B>") const;

    /** Write the language model in ATT fsmt format. */
    void write_fsmt(FILE *file, Str bo_symbol = "<B>") const;
    void write_fsmt_node(FILE *file, int n, Str bo_symbol) const;

    /** Fetch probabilities for all symbols (ignoring non-events). */
    void fetch_probs(int node_id, FloatVec &vec);

    Str debug_str() const;
    bool debug_check_sum(int node_id) const;
    bool debug_check_sums() const;
    bool debug_check_zero_bo() const;

  private:

    /** Incoming arc used temporarily by compute_potential() */
    struct InArc {
      InArc() : source(-1), arc_id(-1) { }
      InArc(int source, int arc_id) : source(source), arc_id(arc_id) { }
      int source;
      int arc_id;
    };

    /** Node information */
    struct {
      FloatArray bo_score;
      Array bo_target;
      Array limit_arc;  //!< Index to one past the last arc that starts from this node.
    } m_nodes;

    /** Arc information */
    struct {
      Array symbol;  //!< The symbol assigned to the arc.
      Array target;  //!< The target node.
      FloatArray score;  //!< Possible score of the arc.
    } m_arcs;

    /** Cache containing information about the last ngram inserted in
     * the strucure. */
    struct {
      IntVec ctx_vec;  //!< Context vector, i.e. all but the last symbol.
      int ctx_node_id;
    } m_cache;

    /** Mapping between language model symbols and indices. */
    SymbolMap m_symbol_map;

    /** Bit array defining non-event symbols. */
    BoolVec m_non_event;

    int m_order;
    int m_empty_node_id;
    int m_initial_node_id;
    int m_final_node_id;
    int m_start_symbol;
    int m_end_symbol;
    float m_final_score;
  };

};

#endif /* LM_HH */
<commit_msg>Added some Doxygen comments.<commit_after>#ifndef LM_HH
#define LM_HH

#include <float.h>
#include "misc/types.hh"
#include "FixedArray.hh"

namespace fsalm {

  class Semiring {
  public:
    Semiring() : one(0), zero(-1e30) { }
    virtual ~Semiring() { }
    virtual float plus(float a, float b) = 0;
    virtual float times(float a, float b) = 0;
    virtual float divide(float a, float b) = 0;
    virtual bool equal(float a, float b) = 0;
    float one;
    float zero;
  };

  class MaxPlusSemiring : public Semiring {
  public:
    virtual ~MaxPlusSemiring() { }
    virtual float plus(float a, float b) { return a < b ? b : a; }
    virtual float times(float a, float b) { return a + b; }
    virtual float divide(float a, float b) { return a - b; }
    virtual bool equal(float a, float b) { return a == b; }
  };

  /** Class for storing ngram language model in a fst format with
   * backoff arcs.
   *
   * INVARIANTS:
   *
   * - before trim() there may be nodes without children and bt=0
   *
   * - after trim() only final node has bt=0 and has zero children
   *
   * - node n has zero children if limit[n-1] == limit[n] or limit[n] == 0
   *
   * IMPLEMENTATION NOTES:
   *
   * - Backoff information is stored in the nodes instead of normal
   * arcs.  Otherwise, creating the arcs in proper order would be
   * troublesome from ARPA format.
   *
   * ASSUMES:
   * - children of a context are inserted in sorted chunk
   * - lower order is inserted before higher order
   */
  class LM {
  public:

    typedef FixedArray<int> Array;
    typedef FixedArray<float> FloatArray;

    Str start_str;
    Str end_str;
    Semiring *semiring;

    LM();
    void reset();
    const SymbolMap &symbol_map() const { return m_symbol_map; }
    int start_symbol() const { return m_start_symbol; }
    int end_symbol() const { return m_end_symbol; }
    int final_node_id() const { return m_final_node_id; }
    int empty_node_id() const { return m_empty_node_id; }
    int initial_node_id() const { return m_initial_node_id; }
    int order() const { return m_order; }
    int num_arcs() const { return m_arcs.symbol.num_elems(); }
    int num_nodes() const { return m_nodes.bo_target.num_elems(); }
    float final_score() const { return m_final_score; }

    /** Return the number of explicit children of node. */
    int num_children(int node_id) const;

    /** String describing a vector of symbol indices. */
    Str str(const IntVec &vec) const;

    /** Find context node for given backoff vector by backoffing
     * further if necessary.
     *
     * \note Throws exception if given ngram ends in sentence end
     * symbol.
     *
     * \param vec = candidate context for the backoff
     * \return node index corresponding to backoff context
     */
    int find_backoff(IntVec vec) const;

    /** Move to next node through given symbol but do not backoff.
     *
     * Finds the arc that starts from given node and has the given
     * symbol assigned, then returns its target node.
     *
     * \param node_id The node to start from (final node not allowed), or
     * empty_node_id() to search every node(?)
     * \param symbol The symbol to search for.
     * \param score Float pointer to which the possible score of the arc is ADDED
     * \return The resulting node (or -1 if explicit arc with symbol not found).
     */
    int walk_no_bo(int node_id, int symbol, float *score = NULL) const;

    /** Walks through a list of symbols but does not backoff.
     *
     * Finds a path that starts from given node and has the list of symbols
     * assigned in given order, then returns the target node of the last arc.
     *
     * \param node_id The node to start from (final node not allowed), or
     * empty_node_id() to search every node(?)
     * \param vec The list of symbols to traverse.
     * \param score Float pointer to which the possible score of the arc is ADDED
     * \return The resulting node (or -1 if explicit arc with symbol not found).
     */
    int walk_no_bo(int node_id, const IntVec &vec, float *score = NULL) const;

    /** Move to next node through given symbols without backoffing.
     * Same as above, but returns node indices for each symbol in a
     * vector. */
    IntVec walk_no_bo_vec(int node_id, const IntVec &vec,
                          float *score = NULL) const;

    /** Move to next node through given symbol by backoffing if necessary.
     *
     * \param node_id = the node to start from (final node not allowed)
     * \param symbol = the symbol to traverse through
     * \param score = float pointer to which the score is ADDED
     * \return the resulting node
     */
    int walk(int node_id, int symbol, float *score = NULL) const;
    int walk(int node_id, const IntVec &vec, float *score = NULL) const;

    void new_arc(int src_node_id, int symbol, int tgt_node_id, float score);
    void new_ngram(const IntVec &vec, float score, float bo_score);
    int new_node();
    void set_arc(int arc_id, int symbol, int target, float score);
    void trim();
    void quantize(int bits);

    /** Compute potential of each node (used by push). */
    void compute_potential(FloatVec &d);

    /** Push scores as early as possible. */
    void push();

    /** Reads the language model in ARPA format. */
    void read_arpa(FILE *file, bool show_progress = false);
    /** Reads the language model in a non-standard format. */
    void read(FILE *file);
    /** Writes the language model in a non-standard format. */
    void write(FILE *file) const;

    /** Write the language model in MIT fst format. */
    void write_fst(FILE *file, Str bo_symbol = "<B>") const;

    /** Write the language model in ATT fsmt format. */
    void write_fsmt(FILE *file, Str bo_symbol = "<B>") const;
    void write_fsmt_node(FILE *file, int n, Str bo_symbol) const;

    /** Fetch probabilities for all symbols (ignoring non-events). */
    void fetch_probs(int node_id, FloatVec &vec);

    Str debug_str() const;
    bool debug_check_sum(int node_id) const;
    bool debug_check_sums() const;
    bool debug_check_zero_bo() const;

  private:

    /** Incoming arc used temporarily by compute_potential() */
    struct InArc {
      InArc() : source(-1), arc_id(-1) { }
      InArc(int source, int arc_id) : source(source), arc_id(arc_id) { }
      int source;
      int arc_id;
    };

    /** Node information */
    struct {
      FloatArray bo_score;
      Array bo_target;
      Array limit_arc;  //!< Index to one past the last arc that starts from this node.
    } m_nodes;

    /** Arc information */
    struct {
      Array symbol;  //!< The symbol assigned to the arc.
      Array target;  //!< The target node.
      FloatArray score;  //!< Possible score of the arc.
    } m_arcs;

    /** Cache containing information about the last ngram inserted in
     * the strucure. */
    struct {
      IntVec ctx_vec;  //!< Context vector, i.e. all but the last symbol.
      int ctx_node_id;
    } m_cache;

    /** Mapping between language model symbols and indices. */
    SymbolMap m_symbol_map;

    /** Bit array defining non-event symbols. */
    BoolVec m_non_event;

    int m_order;
    int m_empty_node_id;
    int m_initial_node_id;
    int m_final_node_id;
    int m_start_symbol;
    int m_end_symbol;
    float m_final_score;
  };

};

#endif /* LM_HH */
<|endoftext|>


<commit_before>#include "Camera3D.h"

edk::Camera3D::Camera3D(){
    //
    this->start();
    this->perspective = false;
    this->firstPerson=false;
}
edk::Camera3D::Camera3D(edk::vec3f32 position,edk::vec3f32 lookAt){
    this->start();
    this->position = position;
    this->lookAt = lookAt;
    this->perspective = false;
    this->firstPerson=false;
}
edk::Camera3D::Camera3D(edk::float32 pX,edk::float32 pY,edk::float32 pZ,edk::float32 lookX,edk::float32 lookY,edk::float32 lookZ){
    this->start();
    this->position = edk::vec3f32(pX,pY,pZ);
    this->lookAt = edk::vec3f32(lookX,lookY,lookZ);
    this->perspective = false;
    this->firstPerson=false;
}
edk::Camera3D::~Camera3D(){
    //
}
void edk::Camera3D::start(){
    //
    this->position = edk::vec3f32(0.f,0.f,-1.f);
    this->lookAt = edk::vec3f32(0.f,0.f,0.f);

    this->up = edk::vec3f32(0.f,1.f,0.f);
    this->size = edk::size2f32(1.f,1.f);
    this->sizePercent = this->size.width/this->size.height;
    this->near = 0.0001f;
    this->far = 1.f;
}

//Sset witch camera type its using
void edk::Camera3D::usePerspective(){
    this->perspective=true;
}
void edk::Camera3D::useOrtho(){
    this->perspective=false;
}

//set the size
void edk::Camera3D::setSize(edk::size2f32 size){
    //
    this->size=size*0.5f;
    this->sizePercent = this->size.width/this->size.height;
}
void edk::Camera3D::setSize(edk::float32 sizeW,edk::float32 sizeH){
    //
    return this->setSize(edk::size2f32(sizeW,sizeH));
}
void edk::Camera3D::setSizeW(edk::float32 width){
    this->size.width = width*0.5f;
    this->sizePercent = this->size.width/this->size.height;
}
void edk::Camera3D::setSizeH(edk::float32 height){
    this->size.height = height*0.5f;
    this->sizePercent = this->size.width/this->size.height;
}
//return the size
edk::float32 edk::Camera3D::getWidth(){
    return this->size.width * 2.f;
}
edk::float32 edk::Camera3D::getHeight(){
    return this->size.height * 2.f;
}

//set near and far
void edk::Camera3D::setNearFar(edk::float32 near,edk::float32 far){
    if(far>near){
        this->near = near;
        this->far = far;
    }
    else{
        this->near = far;
        this->far = near;
    }
}
void edk::Camera3D::setFar(edk::float32 far){
    this->setNearFar(0.0001f,far);
}
//Get near and far
edk::float32 edk::Camera3D::getNear(){
    return this->near;
}
edk::float32 edk::Camera3D::getFar(){
    return this->far;
}

//Distance
edk::float32 edk::Camera3D::getDistance(){
    //
    return edk::Math::pythagoras3f(this->lookAt.x - this->position.x,
                                   this->lookAt.y - this->position.y,
                                   this->lookAt.y - this->position.z
                                   );
}
//set the distance
bool edk::Camera3D::setDistance(edk::float32 distance){
    if(distance>0.f){
        edk::float32 percent = distance / this->getDistance();
        //set the distance
        if(this->firstPerson){
            //
            this->lookAt.x = this->position.x + ((this->lookAt.x-this->position.x) * percent);
            this->lookAt.y = this->position.y + ((this->lookAt.y-this->position.y) * percent);
            this->lookAt.z = this->position.z + ((this->lookAt.z-this->position.z) * percent);
        }
        else{
            //
            this->position.x = this->lookAt.x + ((this->position.x-this->lookAt.x) * percent);
            this->position.y = this->lookAt.y + ((this->position.y-this->lookAt.y) * percent);
            this->position.z = this->lookAt.z + ((this->position.z-this->lookAt.z) * percent);
        }
        return true;
    }
    return false;
}
//move the distance
bool edk::Camera3D::moveDistance(edk::float32 distance){
    return this->setDistance(this->getDistance()+distance);
}

//return the angle width and height
edk::float32 edk::Camera3D::getAngleX(){
    if(this->firstPerson){
        return edk::Math::getAngle2f(this->lookAt.x-this->position.x,this->lookAt.z-this->position.z);
    }
    return edk::Math::getAngle2f(this->position.x-this->lookAt.x,this->position.z-this->lookAt.z);
}
edk::float32 edk::Camera3D::getAngleY(){
    if(this->firstPerson){
        return edk::Math::getAngle2f(edk::Math::pythagoras2f(this->lookAt.x-this->position.x,this->lookAt.z-this->position.z),this->lookAt.y-this->position.y);
    }
    return edk::Math::getAngle2f(edk::Math::pythagoras2f(this->position.x-this->lookAt.x,this->position.z-this->lookAt.z),this->position.y-this->lookAt.y);
}
//set the angles
void edk::Camera3D::setAngleX(edk::float32 angle){
    if(this->firstPerson){
        edk::float32 distance = edk::Math::pythagoras2f(this->lookAt.x - this->position.x,this->lookAt.z - this->position.z);
        this->lookAt.x = edk::Math::rotateXFloat(distance,angle) + this->position.x;
        this->lookAt.z = edk::Math::rotateYFloat(distance,angle) + this->position.z;
    }
    else{
        edk::float32 distance = edk::Math::pythagoras2f(this->position.x - this->lookAt.x,this->position.z - this->lookAt.z);
        this->position.x = edk::Math::rotateXFloat(distance,angle) + this->lookAt.x;
        this->position.z = edk::Math::rotateYFloat(distance,angle) + this->lookAt.z;
    }
}
void edk::Camera3D::setAngleY(edk::float32 angle){
    if(this->firstPerson){
        edk::float32 angleX = this->getAngleX();
        edk::float32 distanceX = edk::Math::pythagoras2f(this->lookAt.x - this->position.x,this->lookAt.z - this->position.z);
        edk::float32 distanceY = edk::Math::pythagoras2f(distanceX,this->lookAt.y - this->position.y);
        //
        distanceX = edk::Math::rotateXFloat(distanceY,angle) + this->position.x;
        this->lookAt.y = edk::Math::rotateYFloat(distanceY,angle) + this->position.z;
        //
        this->lookAt.x = edk::Math::rotateXFloat(distanceX,angleX) + this->position.x;
        this->lookAt.z = edk::Math::rotateYFloat(distanceX,angleX) + this->position.z;
    }
    else{
        edk::float32 angleX = this->getAngleX();
        edk::float32 distanceX = edk::Math::pythagoras2f(this->position.x - this->lookAt.x,this->position.z - this->lookAt.z);
        edk::float32 distanceY = edk::Math::pythagoras2f(distanceX,this->position.y - this->lookAt.y);
        //
        distanceX = edk::Math::rotateXFloat(distanceY,angle) + this->lookAt.x;
        this->position.y = edk::Math::rotateYFloat(distanceY,angle) + this->lookAt.z;
        //
        this->position.x = edk::Math::rotateXFloat(distanceX,angleX) + this->lookAt.x;
        this->position.z = edk::Math::rotateYFloat(distanceX,angleX) + this->lookAt.z;
    }
}
//move the angles
void edk::Camera3D::moveAngleX(edk::float32 angle){
    this->setAngleX(angle + this->getAngleX());
}
void edk::Camera3D::moveAngleY(edk::float32 angle){
    this->setAngleY(angle + this->getAngleY());
}

//draw the camera
void edk::Camera3D::draw(){
    //
    //test if are NOT using GUmodelview
    if(!edk::GU::guUsingMatrix(GU_PROJECTION))
        //then set to use modelView
        edk::GU::guUseMatrix(GU_PROJECTION);
    edk::GU::guLoadIdentity();
    //
    edk::Camera3D::drawAxisOnly();
}
void edk::Camera3D::drawAxisOnly(){
    if(this->perspective){
        edk::GU::guUsePerspective(this->size.height*2.f,this->sizePercent,this->near,this->far);
    }
    else{
        edk::GU::guUseOrtho(-this->size.width,
                            this->size.width,
                            -this->size.height,
                            this->size.height,
                            this->near,//nea
                            this->far//far
                            );
    }
    /*
    //update the shaking animations
    this->animAngle.updateClockAnimation();
    if(this->animAngle.isPlaying()){
        //calculate the angle of shaking
        this->up = edk::Math::rotate2f(edk::vec2f32(1,0),(((this->angle + this->animAngle.getClockX())*-1)+360.f)+90);
    }
    else{
        this->up = edk::Math::rotate2f(edk::vec2f32(1,0),((this->angle*-1)+360.f)+90);
    }
*/

    //shake position
    /*
    this->animPosition.updateClockAnimation();
    if(this->animPosition.isPlaying()){
        this->tempPosition.x = this->position.x+this->animPosition.getClockX();
        this->tempPosition.y = this->position.y+this->animPosition.getClockY();
        edk::GU::guLookAt(this->tempPosition.x,this->tempPosition.y,1.f,
                          this->tempPosition.x,this->tempPosition.y,0.f,
                          this->up.x,this->up.y,0.f
                          );
    }
    else{
        edk::GU::guLookAt(this->position.x,this->position.y,1.f,
                          this->position.x,this->position.y,0.f,
                          this->up.x,this->up.y,0.f
                          );
    }
    */
    edk::GU::guLookAt(this->position.x,this->position.y,this->position.z,
                      this->lookAt.x,this->lookAt.y,this->lookAt.z,
                      this->up.x,this->up.y,this->up.z
                      );
}
void edk::Camera3D::drawAxisOnly(edk::float32 seconds){
    //
}

//operator to copy the cameras
bool edk::Camera3D::cloneFrom(edk::Camera3D* cam){
    //
    ///TODO
    return false;
}
<commit_msg>edk/Camera3D:  - Implement the function cloneFrom for clone the camera into another camera.<commit_after>#include "Camera3D.h"

edk::Camera3D::Camera3D(){
    //
    this->start();
    this->perspective = false;
    this->firstPerson=false;
}
edk::Camera3D::Camera3D(edk::vec3f32 position,edk::vec3f32 lookAt){
    this->start();
    this->position = position;
    this->lookAt = lookAt;
    this->perspective = false;
    this->firstPerson=false;
}
edk::Camera3D::Camera3D(edk::float32 pX,edk::float32 pY,edk::float32 pZ,edk::float32 lookX,edk::float32 lookY,edk::float32 lookZ){
    this->start();
    this->position = edk::vec3f32(pX,pY,pZ);
    this->lookAt = edk::vec3f32(lookX,lookY,lookZ);
    this->perspective = false;
    this->firstPerson=false;
}
edk::Camera3D::~Camera3D(){
    //
}
void edk::Camera3D::start(){
    //
    this->position = edk::vec3f32(0.f,0.f,-1.f);
    this->lookAt = edk::vec3f32(0.f,0.f,0.f);

    this->up = edk::vec3f32(0.f,1.f,0.f);
    this->size = edk::size2f32(1.f,1.f);
    this->sizePercent = this->size.width/this->size.height;
    this->near = 0.0001f;
    this->far = 1.f;
}

//Sset witch camera type its using
void edk::Camera3D::usePerspective(){
    this->perspective=true;
}
void edk::Camera3D::useOrtho(){
    this->perspective=false;
}

//set the size
void edk::Camera3D::setSize(edk::size2f32 size){
    //
    this->size=size*0.5f;
    this->sizePercent = this->size.width/this->size.height;
}
void edk::Camera3D::setSize(edk::float32 sizeW,edk::float32 sizeH){
    //
    return this->setSize(edk::size2f32(sizeW,sizeH));
}
void edk::Camera3D::setSizeW(edk::float32 width){
    this->size.width = width*0.5f;
    this->sizePercent = this->size.width/this->size.height;
}
void edk::Camera3D::setSizeH(edk::float32 height){
    this->size.height = height*0.5f;
    this->sizePercent = this->size.width/this->size.height;
}
//return the size
edk::float32 edk::Camera3D::getWidth(){
    return this->size.width * 2.f;
}
edk::float32 edk::Camera3D::getHeight(){
    return this->size.height * 2.f;
}

//set near and far
void edk::Camera3D::setNearFar(edk::float32 near,edk::float32 far){
    if(far>near){
        this->near = near;
        this->far = far;
    }
    else{
        this->near = far;
        this->far = near;
    }
}
void edk::Camera3D::setFar(edk::float32 far){
    this->setNearFar(0.0001f,far);
}
//Get near and far
edk::float32 edk::Camera3D::getNear(){
    return this->near;
}
edk::float32 edk::Camera3D::getFar(){
    return this->far;
}

//Distance
edk::float32 edk::Camera3D::getDistance(){
    //
    return edk::Math::pythagoras3f(this->lookAt.x - this->position.x,
                                   this->lookAt.y - this->position.y,
                                   this->lookAt.y - this->position.z
                                   );
}
//set the distance
bool edk::Camera3D::setDistance(edk::float32 distance){
    if(distance>0.f){
        edk::float32 percent = distance / this->getDistance();
        //set the distance
        if(this->firstPerson){
            //
            this->lookAt.x = this->position.x + ((this->lookAt.x-this->position.x) * percent);
            this->lookAt.y = this->position.y + ((this->lookAt.y-this->position.y) * percent);
            this->lookAt.z = this->position.z + ((this->lookAt.z-this->position.z) * percent);
        }
        else{
            //
            this->position.x = this->lookAt.x + ((this->position.x-this->lookAt.x) * percent);
            this->position.y = this->lookAt.y + ((this->position.y-this->lookAt.y) * percent);
            this->position.z = this->lookAt.z + ((this->position.z-this->lookAt.z) * percent);
        }
        return true;
    }
    return false;
}
//move the distance
bool edk::Camera3D::moveDistance(edk::float32 distance){
    return this->setDistance(this->getDistance()+distance);
}

//return the angle width and height
edk::float32 edk::Camera3D::getAngleX(){
    if(this->firstPerson){
        return edk::Math::getAngle2f(this->lookAt.x-this->position.x,this->lookAt.z-this->position.z);
    }
    return edk::Math::getAngle2f(this->position.x-this->lookAt.x,this->position.z-this->lookAt.z);
}
edk::float32 edk::Camera3D::getAngleY(){
    if(this->firstPerson){
        return edk::Math::getAngle2f(edk::Math::pythagoras2f(this->lookAt.x-this->position.x,this->lookAt.z-this->position.z),this->lookAt.y-this->position.y);
    }
    return edk::Math::getAngle2f(edk::Math::pythagoras2f(this->position.x-this->lookAt.x,this->position.z-this->lookAt.z),this->position.y-this->lookAt.y);
}
//set the angles
void edk::Camera3D::setAngleX(edk::float32 angle){
    if(this->firstPerson){
        edk::float32 distance = edk::Math::pythagoras2f(this->lookAt.x - this->position.x,this->lookAt.z - this->position.z);
        this->lookAt.x = edk::Math::rotateXFloat(distance,angle) + this->position.x;
        this->lookAt.z = edk::Math::rotateYFloat(distance,angle) + this->position.z;
    }
    else{
        edk::float32 distance = edk::Math::pythagoras2f(this->position.x - this->lookAt.x,this->position.z - this->lookAt.z);
        this->position.x = edk::Math::rotateXFloat(distance,angle) + this->lookAt.x;
        this->position.z = edk::Math::rotateYFloat(distance,angle) + this->lookAt.z;
    }
}
void edk::Camera3D::setAngleY(edk::float32 angle){
    if(this->firstPerson){
        edk::float32 angleX = this->getAngleX();
        edk::float32 distanceX = edk::Math::pythagoras2f(this->lookAt.x - this->position.x,this->lookAt.z - this->position.z);
        edk::float32 distanceY = edk::Math::pythagoras2f(distanceX,this->lookAt.y - this->position.y);
        //
        distanceX = edk::Math::rotateXFloat(distanceY,angle) + this->position.x;
        this->lookAt.y = edk::Math::rotateYFloat(distanceY,angle) + this->position.z;
        //
        this->lookAt.x = edk::Math::rotateXFloat(distanceX,angleX) + this->position.x;
        this->lookAt.z = edk::Math::rotateYFloat(distanceX,angleX) + this->position.z;
    }
    else{
        edk::float32 angleX = this->getAngleX();
        edk::float32 distanceX = edk::Math::pythagoras2f(this->position.x - this->lookAt.x,this->position.z - this->lookAt.z);
        edk::float32 distanceY = edk::Math::pythagoras2f(distanceX,this->position.y - this->lookAt.y);
        //
        distanceX = edk::Math::rotateXFloat(distanceY,angle) + this->lookAt.x;
        this->position.y = edk::Math::rotateYFloat(distanceY,angle) + this->lookAt.z;
        //
        this->position.x = edk::Math::rotateXFloat(distanceX,angleX) + this->lookAt.x;
        this->position.z = edk::Math::rotateYFloat(distanceX,angleX) + this->lookAt.z;
    }
}
//move the angles
void edk::Camera3D::moveAngleX(edk::float32 angle){
    this->setAngleX(angle + this->getAngleX());
}
void edk::Camera3D::moveAngleY(edk::float32 angle){
    this->setAngleY(angle + this->getAngleY());
}

//draw the camera
void edk::Camera3D::draw(){
    //
    //test if are NOT using GUmodelview
    if(!edk::GU::guUsingMatrix(GU_PROJECTION))
        //then set to use modelView
        edk::GU::guUseMatrix(GU_PROJECTION);
    edk::GU::guLoadIdentity();
    //
    edk::Camera3D::drawAxisOnly();
}
void edk::Camera3D::drawAxisOnly(){
    if(this->perspective){
        edk::GU::guUsePerspective(this->size.height*2.f,this->sizePercent,this->near,this->far);
    }
    else{
        edk::GU::guUseOrtho(-this->size.width,
                            this->size.width,
                            -this->size.height,
                            this->size.height,
                            this->near,//nea
                            this->far//far
                            );
    }
    /*
    //update the shaking animations
    this->animAngle.updateClockAnimation();
    if(this->animAngle.isPlaying()){
        //calculate the angle of shaking
        this->up = edk::Math::rotate2f(edk::vec2f32(1,0),(((this->angle + this->animAngle.getClockX())*-1)+360.f)+90);
    }
    else{
        this->up = edk::Math::rotate2f(edk::vec2f32(1,0),((this->angle*-1)+360.f)+90);
    }
*/

    //shake position
    /*
    this->animPosition.updateClockAnimation();
    if(this->animPosition.isPlaying()){
        this->tempPosition.x = this->position.x+this->animPosition.getClockX();
        this->tempPosition.y = this->position.y+this->animPosition.getClockY();
        edk::GU::guLookAt(this->tempPosition.x,this->tempPosition.y,1.f,
                          this->tempPosition.x,this->tempPosition.y,0.f,
                          this->up.x,this->up.y,0.f
                          );
    }
    else{
        edk::GU::guLookAt(this->position.x,this->position.y,1.f,
                          this->position.x,this->position.y,0.f,
                          this->up.x,this->up.y,0.f
                          );
    }
    */
    edk::GU::guLookAt(this->position.x,this->position.y,this->position.z,
                      this->lookAt.x,this->lookAt.y,this->lookAt.z,
                      this->up.x,this->up.y,this->up.z
                      );
}
void edk::Camera3D::drawAxisOnly(edk::float32 seconds){
    //
}

//operator to copy the cameras
bool edk::Camera3D::cloneFrom(edk::Camera3D* cam){
    if(cam){
        this->position = cam->position;
        this->lookAt = cam->lookAt;
        this->perspective = cam->perspective;
        this->up = cam->up;
        this->size = cam->size;
        this->sizePercent = cam->sizePercent;
        this->near = cam->near;
        this->far = cam->far;
        this->firstPerson = cam->firstPerson;
        return true;
    }
    return false;
}
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/parsers/AbstractDOMParser.hpp>
#include <xercesc/dom/DOMImplementation.hpp>
#include <xercesc/dom/DOMImplementationLS.hpp>
#include <xercesc/dom/DOMImplementationRegistry.hpp>
#include <xercesc/dom/DOMBuilder.hpp>
#include <xercesc/dom/DOMException.hpp>
#include <xercesc/dom/DOMDocument.hpp>
#include <xercesc/dom/DOMNodeList.hpp>
#include <xercesc/dom/DOMError.hpp>
#include <xercesc/dom/DOMLocator.hpp>
#include "DOMCount.hpp"
#include <string.h>
#include <stdlib.h>
#include <fstream.h>

// ---------------------------------------------------------------------------
//  This is a simple program which invokes the DOMParser to build a DOM
//  tree for the specified input file. It then walks the tree and counts
//  the number of elements. The element count is then printed.
// ---------------------------------------------------------------------------
static void usage()
{
    cout << "\nUsage:\n"
            "    DOMCount [options] <XML file | List file>\n\n"
            "This program invokes the DOMBuilder, builds the DOM tree,\n"
            "and then prints the number of elements found in each XML file.\n\n"
            "Options:\n"
            "    -l          Indicate the input file is a List File that has a list of xml files.\n"
            "                Default to off (Input file is an XML file).\n"
            "    -v=xxx      Validation scheme [always | never | auto*].\n"
            "    -n          Enable namespace processing. Defaults to off.\n"
            "    -s          Enable schema processing. Defaults to off.\n"
            "    -f          Enable full schema constraint checking. Defaults to off.\n"
            "    -locale=ll_CC specify the locale, default: en_US.\n"
		    "    -?          Show this help.\n\n"
            "  * = Default if not provided explicitly.\n"
         << endl;
}

// ---------------------------------------------------------------------------
//
//  Recursively Count up the total number of child Elements under the specified Node.
//
// ---------------------------------------------------------------------------
static int countChildElements(DOMNode *n)
{
    DOMNode *child;
    int count = 0;
    if (n) {
        if (n->getNodeType() == DOMNode::ELEMENT_NODE)
            count++;
        for (child = n->getFirstChild(); child != 0; child=child->getNextSibling())
            count += countChildElements(child);
    }
    return count;
}

// ---------------------------------------------------------------------------
//
//   main
//
// ---------------------------------------------------------------------------
int main(int argC, char* argV[])
{

    // Check command line and extract arguments.
    if (argC < 2)
    {
        usage();
        return 1;
    }

    const char*                xmlFile = 0;
    AbstractDOMParser::ValSchemes valScheme = AbstractDOMParser::Val_Auto;
    bool                       doNamespaces       = false;
    bool                       doSchema           = false;
    bool                       schemaFullChecking = false;
    bool                       doList = false;
    bool                       errorOccurred = false;
    bool                       recognizeNEL = false;
    char                       localeStr[64];
    memset(localeStr, 0, sizeof localeStr);

    int argInd;
    for (argInd = 1; argInd < argC; argInd++)
    {
        // Break out on first parm not starting with a dash
        if (argV[argInd][0] != '-')
            break;

        // Watch for special case help request
        if (!strcmp(argV[argInd], "-?"))
        {
            usage();
            return 2;
        }
         else if (!strncmp(argV[argInd], "-v=", 3)
              ||  !strncmp(argV[argInd], "-V=", 3))
        {
            const char* const parm = &argV[argInd][3];

            if (!strcmp(parm, "never"))
                valScheme = AbstractDOMParser::Val_Never;
            else if (!strcmp(parm, "auto"))
                valScheme = AbstractDOMParser::Val_Auto;
            else if (!strcmp(parm, "always"))
                valScheme = AbstractDOMParser::Val_Always;
            else
            {
                cerr << "Unknown -v= value: " << parm << endl;
                return 2;
            }
        }
         else if (!strcmp(argV[argInd], "-n")
              ||  !strcmp(argV[argInd], "-N"))
        {
            doNamespaces = true;
        }
         else if (!strcmp(argV[argInd], "-s")
              ||  !strcmp(argV[argInd], "-S"))
        {
            doSchema = true;
        }
         else if (!strcmp(argV[argInd], "-f")
              ||  !strcmp(argV[argInd], "-F"))
        {
            schemaFullChecking = true;
        }
         else if (!strcmp(argV[argInd], "-l")
              ||  !strcmp(argV[argInd], "-L"))
        {
            doList = true;
        }
         else if (!strcmp(argV[argInd], "-special:nel"))
        {
            // turning this on will lead to non-standard compliance behaviour
            // it will recognize the unicode character 0x85 as new line character
            // instead of regular character as specified in XML 1.0
            // do not turn this on unless really necessary

             recognizeNEL = true;
        }
         else if (!strncmp(argV[argInd], "-locale=", 8))
        {
             // Get out the end of line
             strcpy(localeStr, &(argV[argInd][8]));
        }
         else
        {
            cerr << "Unknown option '" << argV[argInd]
                 << "', ignoring it\n" << endl;
        }
    }

    //
    //  There should be only one and only one parameter left, and that
    //  should be the file name.
    //
    if (argInd != argC - 1)
    {
        usage();
        return 1;
    }

    // Initialize the XML4C system
    try
    {
        if (strlen(localeStr))
        {
            XMLPlatformUtils::Initialize(localeStr);
        }
        else
        {
            XMLPlatformUtils::Initialize();
        }

        if (recognizeNEL)
        {
            XMLPlatformUtils::recognizeNEL(recognizeNEL);
        }
    }

    catch (const XMLException& toCatch)
    {
         cerr << "Error during initialization! :\n"
              << StrX(toCatch.getMessage()) << endl;
         return 1;
    }

    // Instantiate the DOM parser.
    static const XMLCh gLS[] = { chLatin_L, chLatin_S, chNull };
    DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(gLS);
    DOMBuilder        *parser = ((DOMImplementationLS*)impl)->createDOMBuilder(DOMImplementationLS::MODE_SYNCHRONOUS, 0);

    parser->setFeature(XMLUni::fgDOMNamespaces, doNamespaces);
    parser->setFeature(XMLUni::fgXercesSchema, doSchema);
    parser->setFeature(XMLUni::fgXercesSchemaFullChecking, schemaFullChecking);

    if (valScheme == AbstractDOMParser::Val_Auto)
    {
        parser->setFeature(XMLUni::fgDOMValidateIfSchema, true);
    }
    else if (valScheme == AbstractDOMParser::Val_Never)
    {
        parser->setFeature(XMLUni::fgDOMValidation, false);
    }
    else if (valScheme == AbstractDOMParser::Val_Always)
    {
        parser->setFeature(XMLUni::fgDOMValidation, true);
    }

    // enable datatype normalization - default is off
    parser->setFeature(XMLUni::fgDOMDatatypeNormalization, true);

    // And create our error handler and install it
    DOMCountErrorHandler errorHandler;
    parser->setErrorHandler(&errorHandler);

    //
    //  Get the starting time and kick off the parse of the indicated
    //  file. Catch any exceptions that might propogate out of it.
    //
    unsigned long duration;

    bool more = true;
    ifstream fin;

    // the input is a list file
    if (doList)
        fin.open(argV[argInd]);

    if (fin.fail()) {
        cerr <<"Cannot open the list file: " << argV[argInd] << endl;
        return 2;
    }

    while (more)
    {
        char fURI[1000];
        //initialize the array to zeros
        memset(fURI,0,sizeof(fURI));

        if (doList) {
            if (! fin.eof() ) {
                fin.getline (fURI, sizeof(fURI));
                if (!*fURI)
                    continue;
                else {
                    xmlFile = fURI;
                    cerr << "==Parsing== " << xmlFile << endl;
                }
            }
            else
                break;
        }
        else {
            xmlFile = argV[argInd];
            more = false;
        }

        //reset error count first
        errorHandler.resetErrors();

        DOMDocument *doc = 0;

        try
        {
            // reset document pool
            parser->resetDocumentPool();

            const unsigned long startMillis = XMLPlatformUtils::getCurrentMillis();
            doc = parser->parseURI(xmlFile);
            const unsigned long endMillis = XMLPlatformUtils::getCurrentMillis();
            duration = endMillis - startMillis;
        }

        catch (const XMLException& toCatch)
        {
            cerr << "\nError during parsing: '" << xmlFile << "'\n"
                 << "Exception message is:  \n"
                 << StrX(toCatch.getMessage()) << "\n" << endl;
            errorOccurred = true;
            continue;
        }
        catch (const DOMException& toCatch)
        {
            const unsigned int maxChars = 2047;
            XMLCh errText[maxChars + 1];

            cerr << "\nDOM Error during parsing: '" << xmlFile << "'\n"
                 << "DOMException code is:  " << toCatch.code << endl;

            if (DOMImplementation::loadDOMExceptionMsg(toCatch.code, errText, maxChars))
                 cerr << "Message is: " << StrX(errText) << endl;

            errorOccurred = true;
            continue;
        }
        catch (...)
        {
            cerr << "\nUnexpected exception during parsing: '" << xmlFile << "'\n";
            errorOccurred = true;
            continue;
        }

        //
        //  Extract the DOM tree, get the list of all the elements and report the
        //  length as the count of elements.
        //
        if (errorHandler.getSawErrors())
        {
            cout << "\nErrors occurred, no output available\n" << endl;
            errorOccurred = true;
        }
         else
        {
            unsigned int elementCount = 0;
            if (doc) {
                elementCount = countChildElements((DOMNode*)doc->getDocumentElement());
                // test getElementsByTagName and getLength
                XMLCh xa[] = {chAsterisk, chNull};
                if (elementCount != doc->getElementsByTagName(xa)->getLength()) {
                    cout << "\nErrors occurred, element count is wrong\n" << endl;
                    errorOccurred = true;
                }
            }

            // Print out the stats that we collected and time taken.
            cout << xmlFile << ": " << duration << " ms ("
                 << elementCount << " elems)." << endl;
        }
    }

    //
    //  Delete the parser itself.  Must be done prior to calling Terminate, below.
    //
    parser->release();

    // And call the termination method
    XMLPlatformUtils::Terminate();

    if (doList)
        fin.close();

    if (errorOccurred)
        return 4;
    else
        return 0;
}

DOMCountErrorHandler::DOMCountErrorHandler() :

    fSawErrors(false)
{
}

DOMCountErrorHandler::~DOMCountErrorHandler()
{
}

// ---------------------------------------------------------------------------
//  DOMCountHandlers: Overrides of the DOM ErrorHandler interface
// ---------------------------------------------------------------------------
bool DOMCountErrorHandler::handleError(const DOMError& domError)
{
    fSawErrors = true;
    if (domError.getSeverity() == DOMError::DOM_SEVERITY_WARNING)
        cerr << "\nWarning at file ";
    else if (domError.getSeverity() == DOMError::DOM_SEVERITY_ERROR)
        cerr << "\nError at file ";
    else
        cerr << "\nFatal Error at file ";

    cerr << StrX(domError.getLocation()->getURI())
         << ", line " << domError.getLocation()->getLineNumber()
         << ", char " << domError.getLocation()->getColumnNumber()
         << "\n  Message: " << StrX(domError.getMessage()) << endl;

    return false;
}

void DOMCountErrorHandler::resetErrors()
{
    fSawErrors = false;
}
<commit_msg>[Bug 14955] error validating parser<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/parsers/AbstractDOMParser.hpp>
#include <xercesc/dom/DOMImplementation.hpp>
#include <xercesc/dom/DOMImplementationLS.hpp>
#include <xercesc/dom/DOMImplementationRegistry.hpp>
#include <xercesc/dom/DOMBuilder.hpp>
#include <xercesc/dom/DOMException.hpp>
#include <xercesc/dom/DOMDocument.hpp>
#include <xercesc/dom/DOMNodeList.hpp>
#include <xercesc/dom/DOMError.hpp>
#include <xercesc/dom/DOMLocator.hpp>
#include "DOMCount.hpp"
#include <string.h>
#include <stdlib.h>
#include <fstream.h>

// ---------------------------------------------------------------------------
//  This is a simple program which invokes the DOMParser to build a DOM
//  tree for the specified input file. It then walks the tree and counts
//  the number of elements. The element count is then printed.
// ---------------------------------------------------------------------------
static void usage()
{
    cout << "\nUsage:\n"
            "    DOMCount [options] <XML file | List file>\n\n"
            "This program invokes the DOMBuilder, builds the DOM tree,\n"
            "and then prints the number of elements found in each XML file.\n\n"
            "Options:\n"
            "    -l          Indicate the input file is a List File that has a list of xml files.\n"
            "                Default to off (Input file is an XML file).\n"
            "    -v=xxx      Validation scheme [always | never | auto*].\n"
            "    -n          Enable namespace processing. Defaults to off.\n"
            "    -s          Enable schema processing. Defaults to off.\n"
            "    -f          Enable full schema constraint checking. Defaults to off.\n"
            "    -locale=ll_CC specify the locale, default: en_US.\n"
		    "    -?          Show this help.\n\n"
            "  * = Default if not provided explicitly.\n"
         << endl;
}

// ---------------------------------------------------------------------------
//
//  Recursively Count up the total number of child Elements under the specified Node.
//
// ---------------------------------------------------------------------------
static int countChildElements(DOMNode *n)
{
    DOMNode *child;
    int count = 0;
    if (n) {
        if (n->getNodeType() == DOMNode::ELEMENT_NODE)
            count++;
        for (child = n->getFirstChild(); child != 0; child=child->getNextSibling())
            count += countChildElements(child);
    }
    return count;
}

// ---------------------------------------------------------------------------
//
//   main
//
// ---------------------------------------------------------------------------
int main(int argC, char* argV[])
{

    // Check command line and extract arguments.
    if (argC < 2)
    {
        usage();
        return 1;
    }

    const char*                xmlFile = 0;
    AbstractDOMParser::ValSchemes valScheme = AbstractDOMParser::Val_Auto;
    bool                       doNamespaces       = false;
    bool                       doSchema           = false;
    bool                       schemaFullChecking = false;
    bool                       doList = false;
    bool                       errorOccurred = false;
    bool                       recognizeNEL = false;
    char                       localeStr[64];
    memset(localeStr, 0, sizeof localeStr);

    int argInd;
    for (argInd = 1; argInd < argC; argInd++)
    {
        // Break out on first parm not starting with a dash
        if (argV[argInd][0] != '-')
            break;

        // Watch for special case help request
        if (!strcmp(argV[argInd], "-?"))
        {
            usage();
            return 2;
        }
         else if (!strncmp(argV[argInd], "-v=", 3)
              ||  !strncmp(argV[argInd], "-V=", 3))
        {
            const char* const parm = &argV[argInd][3];

            if (!strcmp(parm, "never"))
                valScheme = AbstractDOMParser::Val_Never;
            else if (!strcmp(parm, "auto"))
                valScheme = AbstractDOMParser::Val_Auto;
            else if (!strcmp(parm, "always"))
                valScheme = AbstractDOMParser::Val_Always;
            else
            {
                cerr << "Unknown -v= value: " << parm << endl;
                return 2;
            }
        }
         else if (!strcmp(argV[argInd], "-n")
              ||  !strcmp(argV[argInd], "-N"))
        {
            doNamespaces = true;
        }
         else if (!strcmp(argV[argInd], "-s")
              ||  !strcmp(argV[argInd], "-S"))
        {
            doSchema = true;
        }
         else if (!strcmp(argV[argInd], "-f")
              ||  !strcmp(argV[argInd], "-F"))
        {
            schemaFullChecking = true;
        }
         else if (!strcmp(argV[argInd], "-l")
              ||  !strcmp(argV[argInd], "-L"))
        {
            doList = true;
        }
         else if (!strcmp(argV[argInd], "-special:nel"))
        {
            // turning this on will lead to non-standard compliance behaviour
            // it will recognize the unicode character 0x85 as new line character
            // instead of regular character as specified in XML 1.0
            // do not turn this on unless really necessary

             recognizeNEL = true;
        }
         else if (!strncmp(argV[argInd], "-locale=", 8))
        {
             // Get out the end of line
             strcpy(localeStr, &(argV[argInd][8]));
        }
         else
        {
            cerr << "Unknown option '" << argV[argInd]
                 << "', ignoring it\n" << endl;
        }
    }

    //
    //  There should be only one and only one parameter left, and that
    //  should be the file name.
    //
    if (argInd != argC - 1)
    {
        usage();
        return 1;
    }

    // Initialize the XML4C system
    try
    {
        if (strlen(localeStr))
        {
            XMLPlatformUtils::Initialize(localeStr);
        }
        else
        {
            XMLPlatformUtils::Initialize();
        }

        if (recognizeNEL)
        {
            XMLPlatformUtils::recognizeNEL(recognizeNEL);
        }
    }

    catch (const XMLException& toCatch)
    {
         cerr << "Error during initialization! :\n"
              << StrX(toCatch.getMessage()) << endl;
         return 1;
    }

    // Instantiate the DOM parser.
    static const XMLCh gLS[] = { chLatin_L, chLatin_S, chNull };
    DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(gLS);
    DOMBuilder        *parser = ((DOMImplementationLS*)impl)->createDOMBuilder(DOMImplementationLS::MODE_SYNCHRONOUS, 0);

    parser->setFeature(XMLUni::fgDOMNamespaces, doNamespaces);
    parser->setFeature(XMLUni::fgXercesSchema, doSchema);
    parser->setFeature(XMLUni::fgXercesSchemaFullChecking, schemaFullChecking);

    if (valScheme == AbstractDOMParser::Val_Auto)
    {
        parser->setFeature(XMLUni::fgDOMValidateIfSchema, true);
    }
    else if (valScheme == AbstractDOMParser::Val_Never)
    {
        parser->setFeature(XMLUni::fgDOMValidation, false);
    }
    else if (valScheme == AbstractDOMParser::Val_Always)
    {
        parser->setFeature(XMLUni::fgDOMValidation, true);
    }

    // enable datatype normalization - default is off
    parser->setFeature(XMLUni::fgDOMDatatypeNormalization, true);

    // And create our error handler and install it
    DOMCountErrorHandler errorHandler;
    parser->setErrorHandler(&errorHandler);

    //
    //  Get the starting time and kick off the parse of the indicated
    //  file. Catch any exceptions that might propogate out of it.
    //
    unsigned long duration;

    bool more = true;
    ifstream fin;

    // the input is a list file
    if (doList)
        fin.open(argV[argInd]);

    if (fin.fail()) {
        cerr <<"Cannot open the list file: " << argV[argInd] << endl;
        return 2;
    }

    while (more)
    {
        char fURI[1000];
        //initialize the array to zeros
        memset(fURI,0,sizeof(fURI));

        if (doList) {
            if (! fin.eof() ) {
                fin.getline (fURI, sizeof(fURI));
                if (!*fURI)
                    continue;
                else {
                    xmlFile = fURI;
                    cerr << "==Parsing== " << xmlFile << endl;
                }
            }
            else
                break;
        }
        else {
            xmlFile = argV[argInd];
            more = false;
        }

        //reset error count first
        errorHandler.resetErrors();

        DOMDocument *doc = 0;

        try
        {
            // reset document pool
            parser->resetDocumentPool();

            const unsigned long startMillis = XMLPlatformUtils::getCurrentMillis();
            doc = parser->parseURI(xmlFile);
            const unsigned long endMillis = XMLPlatformUtils::getCurrentMillis();
            duration = endMillis - startMillis;
        }

        catch (const XMLException& toCatch)
        {
            cerr << "\nError during parsing: '" << xmlFile << "'\n"
                 << "Exception message is:  \n"
                 << StrX(toCatch.getMessage()) << "\n" << endl;
            errorOccurred = true;
            continue;
        }
        catch (const DOMException& toCatch)
        {
            const unsigned int maxChars = 2047;
            XMLCh errText[maxChars + 1];

            cerr << "\nDOM Error during parsing: '" << xmlFile << "'\n"
                 << "DOMException code is:  " << toCatch.code << endl;

            if (DOMImplementation::loadDOMExceptionMsg(toCatch.code, errText, maxChars))
                 cerr << "Message is: " << StrX(errText) << endl;

            errorOccurred = true;
            continue;
        }
        catch (...)
        {
            cerr << "\nUnexpected exception during parsing: '" << xmlFile << "'\n";
            errorOccurred = true;
            continue;
        }

        //
        //  Extract the DOM tree, get the list of all the elements and report the
        //  length as the count of elements.
        //
        if (errorHandler.getSawErrors())
        {
            cout << "\nErrors occurred, no output available\n" << endl;
            errorOccurred = true;
        }
         else
        {
            unsigned int elementCount = 0;
            if (doc) {
                elementCount = countChildElements((DOMNode*)doc->getDocumentElement());
                // test getElementsByTagName and getLength
                XMLCh xa[] = {chAsterisk, chNull};
                if (elementCount != doc->getElementsByTagName(xa)->getLength()) {
                    cout << "\nErrors occurred, element count is wrong\n" << endl;
                    errorOccurred = true;
                }
            }

            // Print out the stats that we collected and time taken.
            cout << xmlFile << ": " << duration << " ms ("
                 << elementCount << " elems)." << endl;
        }
    }

    //
    //  Delete the parser itself.  Must be done prior to calling Terminate, below.
    //
    parser->release();

    // And call the termination method
    XMLPlatformUtils::Terminate();

    if (doList)
        fin.close();

    if (errorOccurred)
        return 4;
    else
        return 0;
}

DOMCountErrorHandler::DOMCountErrorHandler() :

    fSawErrors(false)
{
}

DOMCountErrorHandler::~DOMCountErrorHandler()
{
}

// ---------------------------------------------------------------------------
//  DOMCountHandlers: Overrides of the DOM ErrorHandler interface
// ---------------------------------------------------------------------------
bool DOMCountErrorHandler::handleError(const DOMError& domError)
{
    fSawErrors = true;
    if (domError.getSeverity() == DOMError::DOM_SEVERITY_WARNING)
        cerr << "\nWarning at file ";
    else if (domError.getSeverity() == DOMError::DOM_SEVERITY_ERROR)
        cerr << "\nError at file ";
    else
        cerr << "\nFatal Error at file ";

    cerr << StrX(domError.getLocation()->getURI())
         << ", line " << domError.getLocation()->getLineNumber()
         << ", char " << domError.getLocation()->getColumnNumber()
         << "\n  Message: " << StrX(domError.getMessage()) << endl;

    return true;
}

void DOMCountErrorHandler::resetErrors()
{
    fSawErrors = false;
}
<|endoftext|>


<commit_before>#include "ActorManager.h"

#include "../components/MeshComponent.h"
#include "../components/RenderComponent.h"
#include "../components/TransformComponent.h"

ActorManager::ActorManager() :
	nextActorID(0),
	actorXML(nullptr)
{
	this->componentFactory.registerType<MeshComponent>(MeshComponent::componentName);
	this->componentFactory.registerType<RenderComponent>(RenderComponent::componentName);
	this->componentFactory.registerType<TransformComponent>(TransformComponent::componentName);
}

int ActorManager::createActor(const std::string actorPath)
{
	if (!this->actorXML)
	{
		this->actorXML = new XMLDocument();
	}
	else
	{
		assert("How did we come here?" || false);
		this->actorXML->Clear();
	}

	this->actorXML->LoadFile(actorPath.c_str());

	XMLElement* actorDescription = actorXML->RootElement();

	if (actorDescription == nullptr)
	{
		printf("Could not find resource: %s\n", actorPath);
	}

	return createActor(actorDescription);
}

int ActorManager::createActor(XMLElement* actorDescriptionRoot)
{
	std::shared_ptr<Actor> actor = std::make_shared<Actor>(this->getNextActorID());

	const char* type = actorDescriptionRoot->Attribute("type");
	if (!type)
	{
		printf("Actor type not specified: Abort actor creation!\n");
		return 0;
	}

	actor->setActorName(type);

	// Add components from xml (if it exists a constructor for it)
	for (XMLElement* node = actorDescriptionRoot->FirstChildElement(); node; node = node->NextSiblingElement())
	{
		std::string name = node->Value();
		std::shared_ptr<ActorComponent> component = this->componentFactory.createComponent(name);

		if (component)
		{
			// Add component and set ownership, if it successfully initializes
			if (component->preInit(node))
			{
				actor->addComponent(name, component);
				component->owner = actor;
			}
			else
			{
				printf("ActorComponent \"%s\" in \"%s\" failed to do pre-initialization, and will not be added.\n", name.c_str(), type);
			}
		}
		else
		{
			printf("ActorComponent \"%s\" not loaded in Actor \"%s\".\n", name.c_str(), type);
		}
	}

	// execute dependancy injection (let components get pointers to other components)
	for (auto& component : actor->components)
	{
		if (component.second->dependancyInjection() == false)
		{
			printf("Dependancy injection failed for %s. Actor creation aborted!\n", type);
			return 0;
		}
	}

	// now all components should be ready, so we can initialize them
	for (auto& component : actor->components)
	{
		component.second->init();
	}

	// now we are finished with the XMLDocument and can safely delete it
	delete this->actorXML;

	return 0;
}

const int ActorManager::getNextActorID()
{
	int id = this->nextActorID;
	this->nextActorID += 1;
	return id;
}<commit_msg>Fixed a bug where the member variable actorXML was deleted but not set to nullptr. Caused unwanted behaviour.<commit_after>#include "ActorManager.h"

#include "../components/MeshComponent.h"
#include "../components/RenderComponent.h"
#include "../components/TransformComponent.h"

ActorManager::ActorManager() :
	nextActorID(0),
	actorXML(nullptr)
{
	this->componentFactory.registerType<MeshComponent>(MeshComponent::componentName);
	this->componentFactory.registerType<RenderComponent>(RenderComponent::componentName);
	this->componentFactory.registerType<TransformComponent>(TransformComponent::componentName);
}

int ActorManager::createActor(const std::string actorPath)
{
	if (!this->actorXML)
	{
		this->actorXML = new XMLDocument();
	}
	else
	{
		assert("How did we come here?" || false);
		this->actorXML->Clear();
	}

	this->actorXML->LoadFile(actorPath.c_str());

	XMLElement* actorDescription = actorXML->RootElement();

	if (actorDescription == nullptr)
	{
		printf("Could not find resource: %s\n", actorPath);
	}

	return createActor(actorDescription);
}

int ActorManager::createActor(XMLElement* actorDescriptionRoot)
{
	std::shared_ptr<Actor> actor = std::make_shared<Actor>(this->getNextActorID());

	const char* type = actorDescriptionRoot->Attribute("type");
	if (!type)
	{
		printf("Actor type not specified: Abort actor creation!\n");
		return 0;
	}

	actor->setActorName(type);

	// Add components from xml (if it exists a constructor for it)
	for (XMLElement* node = actorDescriptionRoot->FirstChildElement(); node; node = node->NextSiblingElement())
	{
		std::string name = node->Value();
		std::shared_ptr<ActorComponent> component = this->componentFactory.createComponent(name);

		if (component)
		{
			// Add component and set ownership, if it successfully initializes
			if (component->preInit(node))
			{
				actor->addComponent(name, component);
				component->owner = actor;
			}
			else
			{
				printf("ActorComponent \"%s\" in \"%s\" failed to do pre-initialization, and will not be added.\n", name.c_str(), type);
			}
		}
		else
		{
			printf("ActorComponent \"%s\" not loaded in Actor \"%s\".\n", name.c_str(), type);
		}
	}

	// execute dependancy injection (let components get pointers to other components)
	for (auto& component : actor->components)
	{
		if (component.second->dependancyInjection() == false)
		{
			printf("Dependancy injection failed for %s. Actor creation aborted!\n", type);
			return 0;
		}
	}

	// now all components should be ready, so we can initialize them
	for (auto& component : actor->components)
	{
		component.second->init();
	}

	// now we are finished with the XMLDocument and can safely delete it
	delete this->actorXML;
	this->actorXML = nullptr;

	return 0;
}

const int ActorManager::getNextActorID()
{
	int id = this->nextActorID;
	this->nextActorID += 1;
	return id;
}<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2013-2014 Baptiste Wicht.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <numeric>
#include <unordered_map>
#include <unordered_set>

#include "cpp_utils/assert.hpp"

#include "summary.hpp"
#include "console.hpp"
#include "accounts.hpp"
#include "compute.hpp"
#include "expenses.hpp"
#include "earnings.hpp"
#include "budget_exception.hpp"
#include "config.hpp"

using namespace budget;

namespace {

void month_overview(budget::month month, budget::year year) {
    // First display overview of the accounts

    std::vector<std::string> columns;
    std::vector<std::vector<std::string>> contents;

    auto sm = start_month(year);

    columns.push_back("Account");
    columns.push_back("Expenses");
    columns.push_back("Earnings");
    columns.push_back("Balance");
    columns.push_back("Local");

    std::unordered_map<std::string, budget::money> account_previous;

    //Fill the table

    budget::money tot_expenses;
    budget::money tot_earnings;
    budget::money tot_balance;
    budget::money tot_local;

    for (unsigned short i = sm; i <= month; ++i) {
        budget::month m = i;

        for (auto& account : all_accounts(year, m)) {
            auto total_expenses = accumulate_amount_if(all_expenses(), [account, year, m](budget::expense& e) { return e.account == account.id && e.date.year() == year && e.date.month() == m; });
            auto total_earnings = accumulate_amount_if(all_earnings(), [account, year, m](budget::earning& e) { return e.account == account.id && e.date.year() == year && e.date.month() == m; });

            auto balance       = account_previous[account.name] + account.amount - total_expenses + total_earnings;
            auto local_balance = account.amount - total_expenses + total_earnings;

            if (i == month) {
                contents.push_back({account.name});

                contents.back().push_back(format_money(total_expenses));
                contents.back().push_back(format_money(total_earnings));
                contents.back().push_back(format_money(balance));
                contents.back().push_back(format_money(local_balance));

                tot_expenses += total_expenses;
                tot_earnings += total_earnings;
                tot_balance += balance;
                tot_expenses += local_balance;
            }

            account_previous[account.name] = balance;
        }
    }

    display_table(columns, contents);
}

void month_overview(budget::month m) {
    month_overview(m, local_day().year());
}

void month_overview() {
    month_overview(local_day().month(), local_day().year());
}

} // end of anonymous namespace

constexpr const std::array<std::pair<const char*, const char*>, 1> budget::module_traits<budget::summary_module>::aliases;

void budget::summary_module::load() {
    load_accounts();
    load_expenses();
    load_earnings();
}

void budget::summary_module::handle(std::vector<std::string>& args) {
    if (all_accounts().empty()) {
        throw budget_exception("No accounts defined, you should start by defining some of them");
    }

    if (args.empty() || args.size() == 1) {
        month_overview();
    } else {
        auto& subcommand = args[1];

        if (subcommand == "month") {
            auto today = local_day();

            if (args.size() == 2) {
                month_overview();
            } else if (args.size() == 3) {
                auto m = budget::month(to_number<unsigned short>(args[2]));

                if (m > today.month()) {
                    throw budget_exception("Cannot compute the summary of the future");
                }

                month_overview(m);
            } else if (args.size() == 4) {
                auto m = budget::month(to_number<unsigned short>(args[2]));
                auto y = budget::year(to_number<unsigned short>(args[3]));

                if (y > today.year()) {
                    throw budget_exception("Cannot compute the summary of the future");
                }

                if (y == today.year() && m > today.month()) {
                    throw budget_exception("Cannot compute the summary of the future");
                }

                month_overview(m, y);
            } else {
                throw budget_exception("Too many arguments to overview month");
            }
        } else {
            throw budget_exception("Invalid subcommand \"" + subcommand + "\"");
        }
    }
}
<commit_msg>Refactor<commit_after>//=======================================================================
// Copyright (c) 2013-2014 Baptiste Wicht.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <numeric>
#include <unordered_map>
#include <unordered_set>

#include "cpp_utils/assert.hpp"

#include "summary.hpp"
#include "console.hpp"
#include "accounts.hpp"
#include "compute.hpp"
#include "expenses.hpp"
#include "earnings.hpp"
#include "budget_exception.hpp"
#include "config.hpp"

using namespace budget;

namespace {

std::string account_summary(budget::month month, budget::year year){
    std::vector<std::string> columns;
    std::vector<std::vector<std::string>> contents;

    auto sm = start_month(year);

    columns.push_back("Account");
    columns.push_back("Expenses");
    columns.push_back("Earnings");
    columns.push_back("Balance");
    columns.push_back("Local");

    std::unordered_map<std::string, budget::money> account_previous;

    //Fill the table

    budget::money tot_expenses;
    budget::money tot_earnings;
    budget::money tot_balance;
    budget::money tot_local;

    for (unsigned short i = sm; i <= month; ++i) {
        budget::month m = i;

        for (auto& account : all_accounts(year, m)) {
            auto total_expenses = accumulate_amount_if(all_expenses(), [account, year, m](budget::expense& e) { return e.account == account.id && e.date.year() == year && e.date.month() == m; });
            auto total_earnings = accumulate_amount_if(all_earnings(), [account, year, m](budget::earning& e) { return e.account == account.id && e.date.year() == year && e.date.month() == m; });

            auto balance       = account_previous[account.name] + account.amount - total_expenses + total_earnings;
            auto local_balance = account.amount - total_expenses + total_earnings;

            if (i == month) {
                contents.push_back({account.name});

                contents.back().push_back(format_money(total_expenses));
                contents.back().push_back(format_money(total_earnings));
                contents.back().push_back(format_money(balance));
                contents.back().push_back(format_money(local_balance));

                tot_expenses += total_expenses;
                tot_earnings += total_earnings;
                tot_balance += balance;
                tot_expenses += local_balance;
            }

            account_previous[account.name] = balance;
        }
    }

    std::stringstream ss;
    display_table(ss, columns, contents);
    return ss.str();
}

void month_overview(budget::month month, budget::year year) {
    // First display overview of the accounts
    auto m_summary = account_summary(month, year);

    std::cout << m_summary;
}

void month_overview(budget::month m) {
    month_overview(m, local_day().year());
}

void month_overview() {
    month_overview(local_day().month(), local_day().year());
}

} // end of anonymous namespace

constexpr const std::array<std::pair<const char*, const char*>, 1> budget::module_traits<budget::summary_module>::aliases;

void budget::summary_module::load() {
    load_accounts();
    load_expenses();
    load_earnings();
}

void budget::summary_module::handle(std::vector<std::string>& args) {
    if (all_accounts().empty()) {
        throw budget_exception("No accounts defined, you should start by defining some of them");
    }

    if (args.empty() || args.size() == 1) {
        month_overview();
    } else {
        auto& subcommand = args[1];

        if (subcommand == "month") {
            auto today = local_day();

            if (args.size() == 2) {
                month_overview();
            } else if (args.size() == 3) {
                auto m = budget::month(to_number<unsigned short>(args[2]));

                if (m > today.month()) {
                    throw budget_exception("Cannot compute the summary of the future");
                }

                month_overview(m);
            } else if (args.size() == 4) {
                auto m = budget::month(to_number<unsigned short>(args[2]));
                auto y = budget::year(to_number<unsigned short>(args[3]));

                if (y > today.year()) {
                    throw budget_exception("Cannot compute the summary of the future");
                }

                if (y == today.year() && m > today.month()) {
                    throw budget_exception("Cannot compute the summary of the future");
                }

                month_overview(m, y);
            } else {
                throw budget_exception("Too many arguments to overview month");
            }
        } else {
            throw budget_exception("Invalid subcommand \"" + subcommand + "\"");
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Fixed bug with point lights using shadows.<commit_after><|endoftext|>