<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 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/>.
 */

/**
 * $Log$
 * Revision 1.7  2000/02/08 01:16:18  aruna1
 * nodeIterator previous tracking problem solved
 *
 * Revision 1.6  2000/02/06 07:47:33  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.5  2000/02/04 01:49:26  aruna1
 * TreeWalker and NodeIterator changes
 *
 * Revision 1.4  1999/11/30 21:16:25  roddey
 * Changes to add the transcode() method to DOMString, which returns a transcoded
 * version (to local code page) of the DOM string contents. And I changed all of the
 * exception 'throw by pointer' to 'throw by value' style.
 *
 * Revision 1.3  1999/11/23 01:48:16  rahulj
 * Changed 0L to 0. CC under HPUX is happy now.
 *
 * Revision 1.2  1999/11/20 00:56:39  rahulj
 * Source files must end with an un-escaped newline.
 *
 * Revision 1.1.1.1  1999/11/09 01:09:15  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:44:30  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// NodeIteratorImpl.cpp: implementation of the NodeIteratorImpl class.
//
//////////////////////////////////////////////////////////////////////

#include "NodeIteratorImpl.hpp"
#include "DOM_Document.hpp"
#include "DOM_DOMException.hpp"
#include "DocumentImpl.hpp"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

NodeIteratorImpl::NodeIteratorImpl ()
: fDetached(false),
    fNodeFilter(0)
{
}

NodeIteratorImpl::~NodeIteratorImpl ()
{
	fDetached = false;
}

void NodeIteratorImpl::detach ()
{
	fDetached = true;
}

NodeIteratorImpl::NodeIteratorImpl (
                                    DOM_Node root,
                                    unsigned long whatToShow,
                                    DOM_NodeFilter* nodeFilter,
                                    bool expandEntityRef)
:   fDetached(false),
    fRoot(root),
    fCurrentNode(0),
    fWhatToShow(whatToShow),
    fNodeFilter(nodeFilter),
    fForward(true),
    fExpandEntityReferences(expandEntityRef)
{

}

NodeIteratorImpl::NodeIteratorImpl ( const NodeIteratorImpl& toCopy)
    :   fDetached(toCopy.fDetached),
    fRoot(toCopy.fRoot),
    fCurrentNode(toCopy.fCurrentNode),
    fWhatToShow(toCopy.fWhatToShow),
    fNodeFilter(toCopy.fNodeFilter),
    fForward(toCopy.fForward),
    fExpandEntityReferences(toCopy.fExpandEntityReferences)
{
}

NodeIteratorImpl& NodeIteratorImpl::operator= (const NodeIteratorImpl& other) {
    fRoot                   = other.fRoot;
    fCurrentNode            = other.fRoot;
    fWhatToShow             = other.fWhatToShow;
    fNodeFilter             = other.fNodeFilter;
    fForward                = other.fForward;
	fDetached               = other.fDetached;
    fExpandEntityReferences = other.fExpandEntityReferences;
    return *this;
}

// Implementation Note: Note that the iterator looks at whatToShow
// and filter values at each call, and therefore one _could_ add
// setters for these values and alter them while iterating!

/** Return the whatToShow value */

unsigned long NodeIteratorImpl::getWhatToShow () {
    return fWhatToShow;
}

/** Return the filter */

DOM_NodeFilter* NodeIteratorImpl::getFilter () {
    return fNodeFilter;
}

/** Get the expandEntity reference flag. */
bool NodeIteratorImpl::getExpandEntityReferences()
{
    return fExpandEntityReferences;
}

/** Return the next DOM_Node in the Iterator. The node is the next node in
 *  depth-first order which also passes the filter, and whatToShow.
 *  A null return means either that
 */

DOM_Node NodeIteratorImpl::nextNode () {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

	DOM_Node result;

    // if root is null there is no next node.
    if (fRoot.isNull())
			return result;

    DOM_Node aNextNode = fCurrentNode;
    bool accepted = false; // the next node has not been accepted.

    while (!accepted) {

        // if last direction is not forward, repeat node.
        if (!fForward && !aNextNode.isNull()) {
            //System.out.println("nextNode():!fForward:"+fCurrentNode.getNodeName());
            aNextNode = fCurrentNode;
        } else {
        // else get the next node via depth-first
            aNextNode = nextNode(aNextNode, true);
        }

        fForward = true; //REVIST: should direction be set forward before null check?

        // nothing in the list. return null.
        if (aNextNode.isNull())
					return result;

        // does node pass the filters and whatToShow?
        accepted = acceptNode(aNextNode);
        if (accepted) {
            // if so, then the node is the current node.
            fCurrentNode = aNextNode;
            return fCurrentNode;
				}

    }

    // no nodes, or no accepted nodes.
    return result;
}

/** Return the previous Node in the Iterator. The node is the next node in
 *  _backwards_ depth-first order which also passes the filter, and whatToShow.
 */

DOM_Node NodeIteratorImpl::previousNode () {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

	DOM_Node result;

    // if the root is null, or the current node is null, return null.
    if (fRoot.isNull() || fCurrentNode.isNull())
			return result;

    DOM_Node aPreviousNode = fCurrentNode;
    bool accepted = false;

    while (!accepted) {
        // we are going backwards
        fForward = false;

        if (fForward && ! aPreviousNode.isNull()) {
            //repeat last node.
            aPreviousNode = fCurrentNode;
        } else {
            // get previous node in backwards depth first order.
            aPreviousNode = previousNode(aPreviousNode);
        }

        // if the new previous node is null, we're at head or past the root,
        // so return null.
        if (aPreviousNode.isNull())
					return result;

        // check if node passes filters and whatToShow.
        accepted = acceptNode(aPreviousNode);
        if (accepted) {
            // if accepted, update the current node, and return it.
            fCurrentNode = aPreviousNode;
            return fCurrentNode;
        }
    }
    // there are no nodes?
    return result;
}

/** The node is accepted if it passes the whatToShow and the filter. */
bool NodeIteratorImpl::acceptNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    if (fNodeFilter == 0) {
        return ((fWhatToShow & ((1 << node.getNodeType()) - 1)) != 0);
    } else {
        return ((fWhatToShow & ((1 << node.getNodeType()) - 1)) != 0 )
            && fNodeFilter->acceptNode(node) == DOM_NodeFilter::FILTER_ACCEPT;
    }
}

/** Return node, if matches or any parent if matches. */
DOM_Node NodeIteratorImpl::matchNodeOrParent (DOM_Node node) {
		DOM_Node result;

    for (DOM_Node n = node; n != fRoot; n = n.getParentNode()) {
        if (node == n) return n;
    }

    return result;
}

/** The method nextNode(DOM_Node, bool) returns the next node
 *  from the actual DOM tree.
 *
 *  The bool visitChildren determines whether to visit the children.
 *  The result is the nextNode.
 */

DOM_Node NodeIteratorImpl::nextNode (DOM_Node node, bool visitChildren) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    if (node.isNull()) return fRoot;

    DOM_Node result;
    // only check children if we visit children.
    if (visitChildren) {
        //if hasChildren, return 1st child.
        if (node.hasChildNodes()) {
            result = node.getFirstChild();
            return result;
        }
    }

    // if hasSibling, return sibling
    result = node.getNextSibling();
    if (! result.isNull()) return result;

    // return parent's 1st sibling.
    DOM_Node parent = node.getParentNode();
    while (!parent.isNull() && parent != fRoot) {
        result = parent.getNextSibling();
        if (!result.isNull()) {
            return result;
        } else {
            parent = parent.getParentNode();
        }

    } // while (parent != null && parent != fRoot) {

    // end of list, return null
		DOM_Node aNull;
    return aNull;
}

/** The method previousNode(DOM_Node) returns the previous node
 *  from the actual DOM tree.
 */

DOM_Node NodeIteratorImpl::previousNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    DOM_Node result;

    // if we're at the root, return null.
    if (node == fRoot)
			return result;

    // get sibling
    result = node.getPreviousSibling();
    if (result.isNull()) {
        //if 1st sibling, return parent
        result = node.getParentNode();
        return result;
    }

    // if sibling has children, keep getting last child of child.
    if (result.hasChildNodes()) {
        while (result.hasChildNodes()) {
            result = result.getLastChild();
        }
    }

    return result;
}

/** Fix-up the iterator on a remove. Called by DOM or otherwise,
 *  before an actual DOM remove.
 */

void NodeIteratorImpl::removeNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    // Implementation note: Fix-up means setting the current node properly
    // after a remove.

    if (node.isNull())
				return;

    DOM_Node deleted = matchNodeOrParent(node);

    if (deleted.isNull()) return;

    if (fForward) {
        fCurrentNode = previousNode(deleted);
    } else
    // if (!fForward)
    {
        DOM_Node next = nextNode(deleted, false);
        if (! next.isNull()) {
            // normal case: there _are_ nodes following this in the iterator.
            fCurrentNode = next;
        } else {
            // the last node in the iterator is to be removed,
            // so we set the current node to be the previous one.
            fCurrentNode = previousNode(deleted);
            fForward = true;
        }

    }

}

void NodeIteratorImpl::unreferenced()
{
    DOM_Document doc = fRoot.getOwnerDocument();
    DocumentImpl* impl;

    if (! doc.isNull()) {
        impl = (DocumentImpl *) doc.fImpl;
    }
    else
        impl = (DocumentImpl *) fRoot.fImpl;

    if (impl->iterators != 0L) {
        int i;
        int sz = impl->iterators->size();
        for (i = 0; i < sz; i++)
            if (impl->iterators->elementAt(i) == this) {
                impl->iterators->removeElementAt(i);
                break;
            }
    }

    delete this;
}
<commit_msg>NodeIterator problem solved<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 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/>.
 */

/**
 * $Log$
 * Revision 1.8  2000/02/08 20:26:11  aruna1
 * NodeIterator problem solved
 *
 * Revision 1.7  2000/02/08 01:16:18  aruna1
 * nodeIterator previous tracking problem solved
 *
 * Revision 1.6  2000/02/06 07:47:33  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.5  2000/02/04 01:49:26  aruna1
 * TreeWalker and NodeIterator changes
 *
 * Revision 1.4  1999/11/30 21:16:25  roddey
 * Changes to add the transcode() method to DOMString, which returns a transcoded
 * version (to local code page) of the DOM string contents. And I changed all of the
 * exception 'throw by pointer' to 'throw by value' style.
 *
 * Revision 1.3  1999/11/23 01:48:16  rahulj
 * Changed 0L to 0. CC under HPUX is happy now.
 *
 * Revision 1.2  1999/11/20 00:56:39  rahulj
 * Source files must end with an un-escaped newline.
 *
 * Revision 1.1.1.1  1999/11/09 01:09:15  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:44:30  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// NodeIteratorImpl.cpp: implementation of the NodeIteratorImpl class.
//
//////////////////////////////////////////////////////////////////////

#include "NodeIteratorImpl.hpp"
#include "DOM_Document.hpp"
#include "DOM_DOMException.hpp"
#include "DocumentImpl.hpp"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

NodeIteratorImpl::NodeIteratorImpl ()
: fDetached(false),
    fNodeFilter(0)
{
}

NodeIteratorImpl::~NodeIteratorImpl ()
{
	fDetached = false;
}

void NodeIteratorImpl::detach ()
{
	fDetached = true;
}

NodeIteratorImpl::NodeIteratorImpl (
                                    DOM_Node root,
                                    unsigned long whatToShow,
                                    DOM_NodeFilter* nodeFilter,
                                    bool expandEntityRef)
:   fDetached(false),
    fRoot(root),
    fCurrentNode(0),
    fWhatToShow(whatToShow),
    fNodeFilter(nodeFilter),
    fForward(true),
    fExpandEntityReferences(expandEntityRef)
{

}

NodeIteratorImpl::NodeIteratorImpl ( const NodeIteratorImpl& toCopy)
    :   fDetached(toCopy.fDetached),
    fRoot(toCopy.fRoot),
    fCurrentNode(toCopy.fCurrentNode),
    fWhatToShow(toCopy.fWhatToShow),
    fNodeFilter(toCopy.fNodeFilter),
    fForward(toCopy.fForward),
    fExpandEntityReferences(toCopy.fExpandEntityReferences)
{
}

NodeIteratorImpl& NodeIteratorImpl::operator= (const NodeIteratorImpl& other) {
    fRoot                   = other.fRoot;
    fCurrentNode            = other.fRoot;
    fWhatToShow             = other.fWhatToShow;
    fNodeFilter             = other.fNodeFilter;
    fForward                = other.fForward;
	fDetached               = other.fDetached;
    fExpandEntityReferences = other.fExpandEntityReferences;
    return *this;
}

// Implementation Note: Note that the iterator looks at whatToShow
// and filter values at each call, and therefore one _could_ add
// setters for these values and alter them while iterating!

/** Return the whatToShow value */

unsigned long NodeIteratorImpl::getWhatToShow () {
    return fWhatToShow;
}

/** Return the filter */

DOM_NodeFilter* NodeIteratorImpl::getFilter () {
    return fNodeFilter;
}

/** Get the expandEntity reference flag. */
bool NodeIteratorImpl::getExpandEntityReferences()
{
    return fExpandEntityReferences;
}

/** Return the next DOM_Node in the Iterator. The node is the next node in
 *  depth-first order which also passes the filter, and whatToShow.
 *  A null return means either that
 */

DOM_Node NodeIteratorImpl::nextNode () {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

	DOM_Node result;

    // if root is null there is no next node.
    if (fRoot.isNull())
			return result;

    DOM_Node aNextNode = fCurrentNode;
    bool accepted = false; // the next node has not been accepted.

    while (!accepted) {

        // if last direction is not forward, repeat node.
        if (!fForward && !aNextNode.isNull()) {
            //System.out.println("nextNode():!fForward:"+fCurrentNode.getNodeName());
            aNextNode = fCurrentNode;
        } else {
        // else get the next node via depth-first
            aNextNode = nextNode(aNextNode, true);
        }

        fForward = true; //REVIST: should direction be set forward before null check?

        // nothing in the list. return null.
        if (aNextNode.isNull())
					return result;

        // does node pass the filters and whatToShow?
        accepted = acceptNode(aNextNode);
        if (accepted) {
            // if so, then the node is the current node.
            fCurrentNode = aNextNode;
            return fCurrentNode;
				}

    }

    // no nodes, or no accepted nodes.
    return result;
}

/** Return the previous Node in the Iterator. The node is the next node in
 *  _backwards_ depth-first order which also passes the filter, and whatToShow.
 */

DOM_Node NodeIteratorImpl::previousNode () {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

	DOM_Node result;

    // if the root is null, or the current node is null, return null.
    if (fRoot.isNull() || fCurrentNode.isNull())
			return result;

    DOM_Node aPreviousNode = fCurrentNode;
    bool accepted = false;

    while (!accepted) {

        if (fForward && ! aPreviousNode.isNull()) {
            //repeat last node.
            aPreviousNode = fCurrentNode;
        } else {
            // get previous node in backwards depth first order.
            aPreviousNode = previousNode(aPreviousNode);
        }

        // we are going backwards
        fForward = false;

        // if the new previous node is null, we're at head or past the root,
        // so return null.
        if (aPreviousNode.isNull())
					return result;

        // check if node passes filters and whatToShow.
        accepted = acceptNode(aPreviousNode);
        if (accepted) {
            // if accepted, update the current node, and return it.
            fCurrentNode = aPreviousNode;
            return fCurrentNode;
        }
    }
    // there are no nodes?
    return result;
}

/** The node is accepted if it passes the whatToShow and the filter. */
bool NodeIteratorImpl::acceptNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    if (fNodeFilter == 0) {
        return ((fWhatToShow & ((1 << node.getNodeType()) - 1)) != 0);
    } else {
        return ((fWhatToShow & ((1 << node.getNodeType()) - 1)) != 0 )
            && fNodeFilter->acceptNode(node) == DOM_NodeFilter::FILTER_ACCEPT;
    }
}

/** Return node, if matches or any parent if matches. */
DOM_Node NodeIteratorImpl::matchNodeOrParent (DOM_Node node) {
		DOM_Node result;

    for (DOM_Node n = node; n != fRoot; n = n.getParentNode()) {
        if (node == n) return n;
    }

    return result;
}

/** The method nextNode(DOM_Node, bool) returns the next node
 *  from the actual DOM tree.
 *
 *  The bool visitChildren determines whether to visit the children.
 *  The result is the nextNode.
 */

DOM_Node NodeIteratorImpl::nextNode (DOM_Node node, bool visitChildren) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    if (node.isNull()) return fRoot;

    DOM_Node result;
    // only check children if we visit children.
    if (visitChildren) {
        //if hasChildren, return 1st child.
        if (node.hasChildNodes()) {
            result = node.getFirstChild();
            return result;
        }
    }

    // if hasSibling, return sibling
    result = node.getNextSibling();
    if (! result.isNull()) return result;

    // return parent's 1st sibling.
    DOM_Node parent = node.getParentNode();
    while (!parent.isNull() && parent != fRoot) {
        result = parent.getNextSibling();
        if (!result.isNull()) {
            return result;
        } else {
            parent = parent.getParentNode();
        }

    } // while (parent != null && parent != fRoot) {

    // end of list, return null
		DOM_Node aNull;
    return aNull;
}

/** The method previousNode(DOM_Node) returns the previous node
 *  from the actual DOM tree.
 */

DOM_Node NodeIteratorImpl::previousNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    DOM_Node result;

    // if we're at the root, return null.
    if (node == fRoot)
			return result;

    // get sibling
    result = node.getPreviousSibling();
    if (result.isNull()) {
        //if 1st sibling, return parent
        result = node.getParentNode();
        return result;
    }

    // if sibling has children, keep getting last child of child.
    if (result.hasChildNodes()) {
        while (result.hasChildNodes()) {
            result = result.getLastChild();
        }
    }

    return result;
}

/** Fix-up the iterator on a remove. Called by DOM or otherwise,
 *  before an actual DOM remove.
 */

void NodeIteratorImpl::removeNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    // Implementation note: Fix-up means setting the current node properly
    // after a remove.

    if (node.isNull())
				return;

    DOM_Node deleted = matchNodeOrParent(node);

    if (deleted.isNull()) return;

    if (fForward) {
        fCurrentNode = previousNode(deleted);
    } else
    // if (!fForward)
    {
        DOM_Node next = nextNode(deleted, false);
        if (! next.isNull()) {
            // normal case: there _are_ nodes following this in the iterator.
            fCurrentNode = next;
        } else {
            // the last node in the iterator is to be removed,
            // so we set the current node to be the previous one.
            fCurrentNode = previousNode(deleted);
            fForward = true;
        }

    }

}

void NodeIteratorImpl::unreferenced()
{
    DOM_Document doc = fRoot.getOwnerDocument();
    DocumentImpl* impl;

    if (! doc.isNull()) {
        impl = (DocumentImpl *) doc.fImpl;
    }
    else
        impl = (DocumentImpl *) fRoot.fImpl;

    if (impl->iterators != 0L) {
        int i;
        int sz = impl->iterators->size();
        for (i = 0; i < sz; i++)
            if (impl->iterators->elementAt(i) == this) {
                impl->iterators->removeElementAt(i);
                break;
            }
    }

    delete this;
}
<|endoftext|>


<commit_before>/*
===========================================================================

daemon gpl source code
copyright (c) 2013 unvanquished developers

this file is part of the daemon gpl source code (daemon source code).

daemon source code is free software: you can redistribute it and/or modify
it under the terms of the gnu general public license as published by
the free software foundation, either version 3 of the license, or
(at your option) any later version.

daemon source code is distributed in the hope that it will be useful,
but without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.  see the
gnu general public license for more details.

you should have received a copy of the gnu general public license
along with daemon source code.  if not, see <http://www.gnu.org/licenses/>.

===========================================================================
*/

#include "AudioPrivate.h"

namespace Audio {

    // Structures to keep the state of entities we were given
    struct entityData_t {
        vec3_t position;
        vec3_t velocity;
        float occlusion;
    };
    static entityData_t entities[MAX_GENTITIES];
    static int listenerEntity = -1;

    // Keep Entitymitters in an array because there is at most one per entity.
    static std::shared_ptr<Emitter> entityEmitters[MAX_GENTITIES];

    // Position Emitters can be reused so we keep the list of all of them
    // this is not very efficient but we cannot have more position emitters
    // than sounds, that is about 128
    static std::vector<std::shared_ptr<PositionEmitter>> posEmitters;

    // There is a single LocalEmitter
    static std::shared_ptr<Emitter> localEmitter;

    static const vec3_t origin = {0.0f, 0.0f, 0.0f};

    static Cvar::Cvar<bool> useDoppler("audio.doppler", "should the doppler effect be used", Cvar::ARCHIVE, true);
    static Cvar::Modified<Cvar::Cvar<bool>> useReverb("audio.reverb", "should reverb effects be used", Cvar::ARCHIVE, true);
    //TODO use optional once we have it
    static bool removeReverb = false;
    static bool addReverb = false;

    static AL::EffectSlot* globalEffect = nullptr;

    static bool initialized = false;

    void UseDoppler(bool use) {
        float factor = use ? 1.0f : 0.0f;
        AL::SetDopplerExaggerationFactor(factor);
    }

    void InitEmitters() {
        if (initialized) {
            return;
        }

        // This is a temporrary effect to test reverb
        auto preset = AL::GetPresetByName("hangar");

        if (preset) {
            AL::Effect effectParams;
            effectParams.ApplyReverbPreset(*AL::GetPresetByName("hangar"));

            globalEffect = new AL::EffectSlot();
            globalEffect->SetEffect(effectParams);
        } else {
            audioLogs.Warn("Couldn't load the default preset");
        }

        AL::SetInverseDistanceModel();
        AL::SetSpeedOfSound(SPEED_OF_SOUND);
        UseDoppler(useDoppler.Get());

        localEmitter = std::make_shared<LocalEmitter>();

        initialized = true;
    }

    void ShutdownEmitters() {
        if (not initialized) {
            return;
        }

        localEmitter = nullptr;

        for (int i = 0; i < MAX_GENTITIES; i++) {
            if (entityEmitters[i]) {
                entityEmitters[i] = nullptr;
            }
        }

        posEmitters.clear();

        delete globalEffect;
        globalEffect = nullptr;

        initialized = false;
    }

    void UpdateEmitters() {
        localEmitter->Update();

        // Both PositionEmitters and EntityEmitters are ref-counted.
        // If we hold the only reference to them then no sound is still using
        // the Emitter that can be destroyed.
        for (int i = 0; i < MAX_GENTITIES; i++) {
            auto emitter = entityEmitters[i];

            if (not emitter) {
                continue;
            }

            emitter->Update();

            // No sound is using this emitter, destroy it
            if (emitter.unique()) {
                entityEmitters[i] = nullptr;
            }
        }

        for (auto it = posEmitters.begin(); it != posEmitters.end();){
            (*it)->Update();

            // No sound is using this emitter, destroy it
            if ((*it).unique()) {
                it = posEmitters.erase(it);
            } else {
                it ++;
            }
        }

        addReverb = removeReverb = false;
        bool use;
        if (useReverb.GetModifiedValue(use)) {
            if (use) {
                addReverb = true;
            } else {
                removeReverb = true;
            }
        }

        UseDoppler(useDoppler.Get());
    }

    void UpdateListenerEntity(int entityNum, const vec3_t orientation[3]) {
        listenerEntity = entityNum;

        AL::SetListenerPosition(entities[listenerEntity].position);
        AL::SetListenerVelocity(entities[listenerEntity].velocity);
        AL::SetListenerOrientation(orientation);
    }

    std::shared_ptr<Emitter> GetEmitterForEntity(int entityNum) {
        if (not entityEmitters[entityNum]) {
            entityEmitters[entityNum] = std::make_shared<EntityEmitter>(entityNum);
        }

        return entityEmitters[entityNum];
    }

    std::shared_ptr<Emitter> GetEmitterForPosition(const vec3_t position) {
        for (auto emitter : posEmitters) {
            if (Distance(emitter->GetPosition(), position) <= 1.0f) {
                return emitter;
            }
        }
        auto emitter = std::make_shared<PositionEmitter>(position);
        posEmitters.push_back(emitter);
        return emitter;
    }

    std::shared_ptr<Emitter> GetLocalEmitter() {
        return localEmitter;
    }

    void UpdateRegisteredEntityPosition(int entityNum, const vec3_t position) {
        VectorCopy(position, entities[entityNum].position);
    }

    void UpdateRegisteredEntityVelocity(int entityNum, const vec3_t velocity) {
        VectorCopy(velocity, entities[entityNum].velocity);
    }

    // Utility functions for emitters

    // TODO avoid more unnecessary al calls

    void MakeLocal(AL::Source& source) {
        source.SetRelative(true);
        source.SetPosition(origin);
        source.SetVelocity(origin);

        source.DisableEffect(POSITIONAL_EFFECT_SLOT);
    }

    void Make3D(AL::Source& source, const vec3_t position, const vec3_t velocity, bool forceReverb = false) {
        source.SetRelative(false);
        source.SetPosition(position);
        source.SetVelocity(velocity);

        if ((forceReverb and useReverb.Get()) or addReverb) {
            source.EnableEffect(POSITIONAL_EFFECT_SLOT, *globalEffect);
        } else if ((forceReverb and not useReverb.Get()) or removeReverb) {
            source.DisableEffect(POSITIONAL_EFFECT_SLOT);
        }
    }

    // Implementation for Emitter

    Emitter::Emitter() {
    }

    Emitter::~Emitter() {
    }

    void Emitter::SetupSound(Sound& sound) {
        sound.GetSource().SetReferenceDistance(120.0f);
        InternalSetupSound(sound);
        UpdateSound(sound);
    }

    // Implementation of EntityEmitter

    EntityEmitter::EntityEmitter(int entityNum): entityNum(entityNum) {
    }

    EntityEmitter::~EntityEmitter(){
    }

    void EntityEmitter::Update() {
        // TODO
    }

    void EntityEmitter::UpdateSound(Sound& sound) {
        AL::Source& source = sound.GetSource();

        if (entityNum == listenerEntity) {
            MakeLocal(source);
        } else {
            Make3D(source, entities[entityNum].position, entities[entityNum].velocity);
        }
    }

    void EntityEmitter::InternalSetupSound(Sound& sound) {
        AL::Source& source = sound.GetSource();

        Make3D(source, entities[entityNum].position, entities[entityNum].velocity, true);
    }

    // Implementation of PositionEmitter

    PositionEmitter::PositionEmitter(const vec3_t position){
        VectorCopy(position, this->position);
    }

    PositionEmitter::~PositionEmitter() {
    }

    void PositionEmitter::Update() {
        //TODO
    }

    void PositionEmitter::UpdateSound(Sound& sound) {
        AL::Source& source = sound.GetSource();

        Make3D(source, position, origin);
    }

    void PositionEmitter::InternalSetupSound(Sound& sound) {
        AL::Source& source = sound.GetSource();

        Make3D(source, position, origin, true);
    }

    const vec3_t& PositionEmitter::GetPosition() const {
        return position;
    }

    // Implementation of LocalEmitter

    LocalEmitter::LocalEmitter() {
    }

    LocalEmitter::~LocalEmitter() {
    }

    void LocalEmitter::Update() {
    }

    void LocalEmitter::UpdateSound(Sound&) {
    }

    void LocalEmitter::InternalSetupSound(Sound& sound) {
        AL::Source& source = sound.GetSource();

        MakeLocal(source);
    }

    class TestReverbCmd : public Cmd::StaticCmd {
        public:
            TestReverbCmd(): StaticCmd("testReverb", Cmd::AUDIO, N_("Tests a reverb preset.")) {
            }

            virtual void Run(const Cmd::Args& args) const OVERRIDE {
                if (args.Argc() != 2) {
                    PrintUsage(args, "[preset name]", "tests the reverb preset.");
                    return;
                }

                auto preset = AL::GetPresetByName(args.Argv(1));

                if (not preset) {
                    Print("Reverb preset '%s' doesn't exist.", args.Argv(1));
                    return;
                }

                AL::Effect effectParams;
                effectParams.ApplyReverbPreset(*preset);

                globalEffect->SetEffect(effectParams);
            }

            Cmd::CompletionResult Complete(int argNum, const Cmd::Args&, Str::StringRef prefix) const OVERRIDE {
                if (argNum != 1) {
                    return {};
                }
                std::vector<std::string> presets = AL::ListPresetNames();
                std::sort(presets.begin(), presets.end());

                Cmd::CompletionResult res;

                for (auto& name: presets) {
                    if (Str::IsPrefix(prefix, name)) {
                        res.push_back({std::move(name), ""});
                    }
                }

                return res;
            }
    };
    static TestReverbCmd testReverbRegistration;

}
<commit_msg>Audio: Change the default reverb preset to something less extreme<commit_after>/*
===========================================================================

daemon gpl source code
copyright (c) 2013 unvanquished developers

this file is part of the daemon gpl source code (daemon source code).

daemon source code is free software: you can redistribute it and/or modify
it under the terms of the gnu general public license as published by
the free software foundation, either version 3 of the license, or
(at your option) any later version.

daemon source code is distributed in the hope that it will be useful,
but without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.  see the
gnu general public license for more details.

you should have received a copy of the gnu general public license
along with daemon source code.  if not, see <http://www.gnu.org/licenses/>.

===========================================================================
*/

#include "AudioPrivate.h"

namespace Audio {

    // Structures to keep the state of entities we were given
    struct entityData_t {
        vec3_t position;
        vec3_t velocity;
        float occlusion;
    };
    static entityData_t entities[MAX_GENTITIES];
    static int listenerEntity = -1;

    // Keep Entitymitters in an array because there is at most one per entity.
    static std::shared_ptr<Emitter> entityEmitters[MAX_GENTITIES];

    // Position Emitters can be reused so we keep the list of all of them
    // this is not very efficient but we cannot have more position emitters
    // than sounds, that is about 128
    static std::vector<std::shared_ptr<PositionEmitter>> posEmitters;

    // There is a single LocalEmitter
    static std::shared_ptr<Emitter> localEmitter;

    static const vec3_t origin = {0.0f, 0.0f, 0.0f};

    static Cvar::Cvar<bool> useDoppler("audio.doppler", "should the doppler effect be used", Cvar::ARCHIVE, true);
    static Cvar::Modified<Cvar::Cvar<bool>> useReverb("audio.reverb", "should reverb effects be used", Cvar::ARCHIVE, true);
    //TODO use optional once we have it
    static bool removeReverb = false;
    static bool addReverb = false;

    static AL::EffectSlot* globalEffect = nullptr;

    static bool initialized = false;

    void UseDoppler(bool use) {
        float factor = use ? 1.0f : 0.0f;
        AL::SetDopplerExaggerationFactor(factor);
    }

    void InitEmitters() {
        if (initialized) {
            return;
        }

        auto preset = AL::GetPresetByName("generic");
        if (preset) {
            AL::Effect effectParams;
            effectParams.ApplyReverbPreset(*preset);

            globalEffect = new AL::EffectSlot();
            globalEffect->SetEffect(effectParams);
        } else {
            audioLogs.Warn("Couldn't load the default preset");
        }

        AL::SetInverseDistanceModel();
        AL::SetSpeedOfSound(SPEED_OF_SOUND);
        UseDoppler(useDoppler.Get());

        localEmitter = std::make_shared<LocalEmitter>();

        initialized = true;
    }

    void ShutdownEmitters() {
        if (not initialized) {
            return;
        }

        localEmitter = nullptr;

        for (int i = 0; i < MAX_GENTITIES; i++) {
            if (entityEmitters[i]) {
                entityEmitters[i] = nullptr;
            }
        }

        posEmitters.clear();

        delete globalEffect;
        globalEffect = nullptr;

        initialized = false;
    }

    void UpdateEmitters() {
        localEmitter->Update();

        // Both PositionEmitters and EntityEmitters are ref-counted.
        // If we hold the only reference to them then no sound is still using
        // the Emitter that can be destroyed.
        for (int i = 0; i < MAX_GENTITIES; i++) {
            auto emitter = entityEmitters[i];

            if (not emitter) {
                continue;
            }

            emitter->Update();

            // No sound is using this emitter, destroy it
            if (emitter.unique()) {
                entityEmitters[i] = nullptr;
            }
        }

        for (auto it = posEmitters.begin(); it != posEmitters.end();){
            (*it)->Update();

            // No sound is using this emitter, destroy it
            if ((*it).unique()) {
                it = posEmitters.erase(it);
            } else {
                it ++;
            }
        }

        addReverb = removeReverb = false;
        bool use;
        if (useReverb.GetModifiedValue(use)) {
            if (use) {
                addReverb = true;
            } else {
                removeReverb = true;
            }
        }

        UseDoppler(useDoppler.Get());
    }

    void UpdateListenerEntity(int entityNum, const vec3_t orientation[3]) {
        listenerEntity = entityNum;

        AL::SetListenerPosition(entities[listenerEntity].position);
        AL::SetListenerVelocity(entities[listenerEntity].velocity);
        AL::SetListenerOrientation(orientation);
    }

    std::shared_ptr<Emitter> GetEmitterForEntity(int entityNum) {
        if (not entityEmitters[entityNum]) {
            entityEmitters[entityNum] = std::make_shared<EntityEmitter>(entityNum);
        }

        return entityEmitters[entityNum];
    }

    std::shared_ptr<Emitter> GetEmitterForPosition(const vec3_t position) {
        for (auto emitter : posEmitters) {
            if (Distance(emitter->GetPosition(), position) <= 1.0f) {
                return emitter;
            }
        }
        auto emitter = std::make_shared<PositionEmitter>(position);
        posEmitters.push_back(emitter);
        return emitter;
    }

    std::shared_ptr<Emitter> GetLocalEmitter() {
        return localEmitter;
    }

    void UpdateRegisteredEntityPosition(int entityNum, const vec3_t position) {
        VectorCopy(position, entities[entityNum].position);
    }

    void UpdateRegisteredEntityVelocity(int entityNum, const vec3_t velocity) {
        VectorCopy(velocity, entities[entityNum].velocity);
    }

    // Utility functions for emitters

    // TODO avoid more unnecessary al calls

    void MakeLocal(AL::Source& source) {
        source.SetRelative(true);
        source.SetPosition(origin);
        source.SetVelocity(origin);

        source.DisableEffect(POSITIONAL_EFFECT_SLOT);
    }

    void Make3D(AL::Source& source, const vec3_t position, const vec3_t velocity, bool forceReverb = false) {
        source.SetRelative(false);
        source.SetPosition(position);
        source.SetVelocity(velocity);

        if ((forceReverb and useReverb.Get()) or addReverb) {
            source.EnableEffect(POSITIONAL_EFFECT_SLOT, *globalEffect);
        } else if ((forceReverb and not useReverb.Get()) or removeReverb) {
            source.DisableEffect(POSITIONAL_EFFECT_SLOT);
        }
    }

    // Implementation for Emitter

    Emitter::Emitter() {
    }

    Emitter::~Emitter() {
    }

    void Emitter::SetupSound(Sound& sound) {
        sound.GetSource().SetReferenceDistance(120.0f);
        InternalSetupSound(sound);
        UpdateSound(sound);
    }

    // Implementation of EntityEmitter

    EntityEmitter::EntityEmitter(int entityNum): entityNum(entityNum) {
    }

    EntityEmitter::~EntityEmitter(){
    }

    void EntityEmitter::Update() {
        // TODO
    }

    void EntityEmitter::UpdateSound(Sound& sound) {
        AL::Source& source = sound.GetSource();

        if (entityNum == listenerEntity) {
            MakeLocal(source);
        } else {
            Make3D(source, entities[entityNum].position, entities[entityNum].velocity);
        }
    }

    void EntityEmitter::InternalSetupSound(Sound& sound) {
        AL::Source& source = sound.GetSource();

        Make3D(source, entities[entityNum].position, entities[entityNum].velocity, true);
    }

    // Implementation of PositionEmitter

    PositionEmitter::PositionEmitter(const vec3_t position){
        VectorCopy(position, this->position);
    }

    PositionEmitter::~PositionEmitter() {
    }

    void PositionEmitter::Update() {
        //TODO
    }

    void PositionEmitter::UpdateSound(Sound& sound) {
        AL::Source& source = sound.GetSource();

        Make3D(source, position, origin);
    }

    void PositionEmitter::InternalSetupSound(Sound& sound) {
        AL::Source& source = sound.GetSource();

        Make3D(source, position, origin, true);
    }

    const vec3_t& PositionEmitter::GetPosition() const {
        return position;
    }

    // Implementation of LocalEmitter

    LocalEmitter::LocalEmitter() {
    }

    LocalEmitter::~LocalEmitter() {
    }

    void LocalEmitter::Update() {
    }

    void LocalEmitter::UpdateSound(Sound&) {
    }

    void LocalEmitter::InternalSetupSound(Sound& sound) {
        AL::Source& source = sound.GetSource();

        MakeLocal(source);
    }

    class TestReverbCmd : public Cmd::StaticCmd {
        public:
            TestReverbCmd(): StaticCmd("testReverb", Cmd::AUDIO, N_("Tests a reverb preset.")) {
            }

            virtual void Run(const Cmd::Args& args) const OVERRIDE {
                if (args.Argc() != 2) {
                    PrintUsage(args, "[preset name]", "tests the reverb preset.");
                    return;
                }

                auto preset = AL::GetPresetByName(args.Argv(1));

                if (not preset) {
                    Print("Reverb preset '%s' doesn't exist.", args.Argv(1));
                    return;
                }

                AL::Effect effectParams;
                effectParams.ApplyReverbPreset(*preset);

                globalEffect->SetEffect(effectParams);
            }

            Cmd::CompletionResult Complete(int argNum, const Cmd::Args&, Str::StringRef prefix) const OVERRIDE {
                if (argNum != 1) {
                    return {};
                }
                std::vector<std::string> presets = AL::ListPresetNames();
                std::sort(presets.begin(), presets.end());

                Cmd::CompletionResult res;

                for (auto& name: presets) {
                    if (Str::IsPrefix(prefix, name)) {
                        res.push_back({std::move(name), ""});
                    }
                }

                return res;
            }
    };
    static TestReverbCmd testReverbRegistration;

}
<|endoftext|>


<commit_before>#include <bashclass/BArrayUse.h>
#include <bashclass/BElementType.h>

BArrayUse::BArrayUse() {
    m_type = std::make_shared<BElementType>();
}

void BArrayUse::setTypeLexicalToken(std::shared_ptr<ecc::LexicalToken> lexicalToken) {
    m_type->setLexicalToken(lexicalToken);
}

void BArrayUse::castType(std::shared_ptr<BElementType> type) {
    m_type->cast(type);
}<commit_msg>Fixed bug in array use<commit_after>#include <bashclass/BArrayUse.h>

BArrayUse::BArrayUse() {
    m_type = std::make_shared<BElementType>();
}

void BArrayUse::setTypeLexicalToken(std::shared_ptr<ecc::LexicalToken> lexicalToken) {

    // Set the type lexical token
    m_type->setLexicalToken(lexicalToken);

    // Link type
    m_type->linkType();
}

void BArrayUse::castType(std::shared_ptr<BElementType> type) {
    m_type->cast(type);
}<|endoftext|>


<commit_before>/*
 *  This file is part of Poedit (https://poedit.net)
 *
 *  Copyright (C) 2000-2019 Vaclav Slavik
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 *
 */

#include "extractor.h"

#include "extractor_legacy.h"

#include "gexecute.h"

#include <wx/dir.h>
#include <wx/filename.h>

#include <algorithm>

namespace
{

// Path matching with support for wildcards

struct PathToMatch
{
    wxString path;
    bool isWildcard;

    bool MatchesFile(const wxString& fn) const
    {
        if (isWildcard)
            return wxMatchWild(path, fn);
        else
            return fn == path || fn.StartsWith(path + "/");
    }
};

class PathsToMatch
{
public:
    PathsToMatch() {}
    explicit PathsToMatch(const wxArrayString& a)
    {
        paths.reserve(a.size());
        for (auto& p: a)
            paths.push_back({p, wxIsWild(p)});
    }

    bool MatchesFile(const wxString& fn) const
    {
        for (auto& p: paths)
        {
            if (p.MatchesFile(fn))
                return true;
        }
        return false;
    }

private:
    std::vector<PathToMatch> paths;
};

int FindInDir(const wxString& basepath, const wxString& dirname, const PathsToMatch& excludedPaths,
              Extractor::FilesList& output)
{
    if (dirname.empty())
        return 0;

    wxDir dir(basepath + dirname);
    if (!dir.IsOpened())
        return 0;

    bool cont;
    wxString filename;
    int found = 0;

    cont = dir.GetFirst(&filename, wxEmptyString, wxDIR_FILES);
    while (cont)
    {
        const wxString f = (dirname == ".") ? filename : dirname + "/" + filename;
        cont = dir.GetNext(&filename);

        if (excludedPaths.MatchesFile(f))
            continue;

        wxLogTrace("poedit.extractor", "  - %s", f);
        output.push_back(f);
        found++;
    }

    cont = dir.GetFirst(&filename, wxEmptyString, wxDIR_DIRS);
    while (cont)
    {
        const wxString f = (dirname == ".") ? filename : dirname + "/" + filename;
        cont = dir.GetNext(&filename);

        if (excludedPaths.MatchesFile(f))
            continue;

        found += FindInDir(basepath, f, excludedPaths, output);
    }

    return found;
}

} // anonymous namespace

Extractor::FilesList Extractor::CollectAllFiles(const SourceCodeSpec& sources)
{
    // TODO: Only collect files with recognized extensions

    wxLogTrace("poedit.extractor", "collecting files:");

    const auto basepath = sources.BasePath;
    const auto excludedPaths = PathsToMatch(sources.ExcludedPaths);

    FilesList output;

    for (auto& path: sources.SearchPaths)
    {
        if (wxFileName::FileExists(basepath + path))
        {
            if (excludedPaths.MatchesFile(path))
            {
                wxLogTrace("poedit.extractor", "no files found in '%s'", path);
                continue;
            }
            wxLogTrace("poedit.extractor", "  - %s", path);
            output.push_back(path);
        }
        else if (!FindInDir(basepath, path, excludedPaths, output))
        {
            wxLogTrace("poedit.extractor", "no files found in '%s'", path);
        }
    }

    // Sort the filenames in some well-defined order. This is because directory
    // traversal has, generally speaking, undefined order, and the order differs
    // between filesystems. Finally, the order is reflected in the created PO
    // files and it is much better for diffs if it remains consistent.
    std::sort(output.begin(), output.end());

    wxLogTrace("poedit.extractor", "finished collecting %d files", (int)output.size());

    return output;
}

wxString Extractor::ExtractWithAll(TempDirectory& tmpdir,
                                   const SourceCodeSpec& sourceSpec,
                                   const std::vector<wxString>& files_)
{
    auto files = files_;
    wxLogTrace("poedit.extractor", "extracting from %d files", (int)files.size());

    std::vector<wxString> subPots;

    for (auto ex: CreateAllExtractors())
    {
        const auto ex_files = ex->FilterFiles(files);
        if (ex_files.empty())
            continue;

        wxLogTrace("poedit.extractor", " .. using extractor '%s' for %d files", ex->GetId(), (int)ex_files.size());
        auto subPot = ex->Extract(tmpdir, sourceSpec, ex_files);
        if (!subPot.empty())
            subPots.push_back(subPot);

        if (files.size() > ex_files.size())
        {
            FilesList remaining;
            remaining.reserve(files.size() - ex_files.size());
            // Note that this only works because the lists are sorted:
            std::set_difference(files.begin(), files.end(),
                                ex_files.begin(), ex_files.end(),
                                std::inserter(remaining, remaining.begin()));
            std::swap(files, remaining);
        }
        else
        {
            files.clear();
            break; // no more work to do
        }
    }

    wxLogTrace("poedit.extractor", "extraction finished with %d unrecognized files and %d sub-POTs", (int)files.size(), (int)subPots.size());

    if (subPots.empty())
    {
        return "";
    }
    else if (subPots.size() == 1)
    {
        return subPots.front();
    }
    else
    {
        wxLogTrace("poedit.extractor", "merging %d subPOTs", (int)subPots.size());
        return ConcatCatalogs(tmpdir, subPots);
    }
}

Extractor::FilesList Extractor::FilterFiles(const FilesList& files) const
{
    FilesList out;
    for (auto& f: files)
    {
        if (IsFileSupported(f))
            out.push_back(f);
    }
    return out;
}

bool Extractor::IsFileSupported(const wxString& file) const
{
#ifdef __WXMSW__
    auto f = file.Lower();
#else
    auto& f = file;
#endif

    auto ext = f.AfterLast('.');
    if (ext != f && m_extensions.find(ext) != m_extensions.end())
        return true;

    for (auto& w: m_wildcards)
    {
        if (f.Matches(w))
            return true;
    }

    return false;
}

void Extractor::RegisterExtension(const wxString& ext)
{
    if (ext.Contains("."))
    {
        RegisterWildcard("*." + ext);
        return;
    }

#ifdef __WXMSW__
    m_extensions.insert(ext.Lower());
#else
    m_extensions.insert(ext);
#endif
    wxLogTrace("poedit.extractor", "%s handles extension %s", GetId(), ext);
}

void Extractor::RegisterWildcard(const wxString& wildcard)
{
#ifdef __WXMSW__
    m_wildcards.push_back(wildcard.Lower());
#else
    m_wildcards.push_back(wildcard);
#endif
    wxLogTrace("poedit.extractor", "%s handles %s", GetId(), wildcard);
}

wxString Extractor::ConcatCatalogs(TempDirectory& tmpdir, const std::vector<wxString>& files)
{
    if (files.empty())
    {
        return "";
    }
    else if (files.size() == 1)
    {
        return files.front();
    }

    auto outfile = tmpdir.CreateFileName("concatenated.pot");

    wxString list;
    for (auto& f: files)
        list += wxString::Format(" %s", QuoteCmdlineArg(f));

    auto cmd = wxString::Format("msgcat --force-po -o %s %s", QuoteCmdlineArg(outfile), list);
    bool succ = ExecuteGettext(cmd);

    if (!succ)
    {
        wxLogError(_("Failed command: %s"), cmd.c_str());
        wxLogError(_("Failed to merge gettext catalogs."));
        return "";
    }

    return outfile;
}

Extractor::ExtractorsList Extractor::CreateAllExtractors()
{
    ExtractorsList all;

    // User-defined "legacy" extractors take precedence over anything else,
    // to allow customization of the behavior:
    CreateAllLegacyExtractors(all);

    // Standard builtin extractors follow
    CreateGettextExtractors(all);

    return all;
}
<commit_msg>Skip over common VCS directories during extraction<commit_after>/*
 *  This file is part of Poedit (https://poedit.net)
 *
 *  Copyright (C) 2000-2019 Vaclav Slavik
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 *
 */

#include "extractor.h"

#include "extractor_legacy.h"

#include "gexecute.h"

#include <wx/dir.h>
#include <wx/filename.h>

#include <algorithm>

namespace
{

// Path matching with support for wildcards

struct PathToMatch
{
    wxString path;
    bool isWildcard;

    bool MatchesFile(const wxString& fn) const
    {
        if (isWildcard)
            return wxMatchWild(path, fn);
        else
            return fn == path || fn.StartsWith(path + "/");
    }
};

class PathsToMatch
{
public:
    PathsToMatch() {}
    explicit PathsToMatch(const wxArrayString& a)
    {
        paths.reserve(a.size());
        for (auto& p: a)
            paths.push_back({p, wxIsWild(p)});
    }

    bool MatchesFile(const wxString& fn) const
    {
        for (auto& p: paths)
        {
            if (p.MatchesFile(fn))
                return true;
        }
        return false;
    }

private:
    std::vector<PathToMatch> paths;
};

inline bool IsVCSDir(const wxString& d)
{
    return d == ".git" || d == ".svn" || d == ".hg" || d == ".bzr" || d == "CVS";
}

int FindInDir(const wxString& basepath, const wxString& dirname, const PathsToMatch& excludedPaths,
              Extractor::FilesList& output)
{
    if (dirname.empty())
        return 0;

    wxDir dir(basepath + dirname);
    if (!dir.IsOpened())
        return 0;

    bool cont;
    wxString filename;
    int found = 0;

    cont = dir.GetFirst(&filename, wxEmptyString, wxDIR_FILES);
    while (cont)
    {
        const wxString f = (dirname == ".") ? filename : dirname + "/" + filename;
        cont = dir.GetNext(&filename);

        if (excludedPaths.MatchesFile(f))
            continue;

        wxLogTrace("poedit.extractor", "  - %s", f);
        output.push_back(f);
        found++;
    }

    cont = dir.GetFirst(&filename, wxEmptyString, wxDIR_DIRS);
    while (cont)
    {
        const wxString f = (dirname == ".") ? filename : dirname + "/" + filename;
        cont = dir.GetNext(&filename);

        if (IsVCSDir(filename))
            continue;

        if (excludedPaths.MatchesFile(f))
            continue;

        found += FindInDir(basepath, f, excludedPaths, output);
    }

    return found;
}

} // anonymous namespace

Extractor::FilesList Extractor::CollectAllFiles(const SourceCodeSpec& sources)
{
    // TODO: Only collect files with recognized extensions

    wxLogTrace("poedit.extractor", "collecting files:");

    const auto basepath = sources.BasePath;
    const auto excludedPaths = PathsToMatch(sources.ExcludedPaths);

    FilesList output;

    for (auto& path: sources.SearchPaths)
    {
        if (wxFileName::FileExists(basepath + path))
        {
            if (excludedPaths.MatchesFile(path))
            {
                wxLogTrace("poedit.extractor", "no files found in '%s'", path);
                continue;
            }
            wxLogTrace("poedit.extractor", "  - %s", path);
            output.push_back(path);
        }
        else if (!FindInDir(basepath, path, excludedPaths, output))
        {
            wxLogTrace("poedit.extractor", "no files found in '%s'", path);
        }
    }

    // Sort the filenames in some well-defined order. This is because directory
    // traversal has, generally speaking, undefined order, and the order differs
    // between filesystems. Finally, the order is reflected in the created PO
    // files and it is much better for diffs if it remains consistent.
    std::sort(output.begin(), output.end());

    wxLogTrace("poedit.extractor", "finished collecting %d files", (int)output.size());

    return output;
}

wxString Extractor::ExtractWithAll(TempDirectory& tmpdir,
                                   const SourceCodeSpec& sourceSpec,
                                   const std::vector<wxString>& files_)
{
    auto files = files_;
    wxLogTrace("poedit.extractor", "extracting from %d files", (int)files.size());

    std::vector<wxString> subPots;

    for (auto ex: CreateAllExtractors())
    {
        const auto ex_files = ex->FilterFiles(files);
        if (ex_files.empty())
            continue;

        wxLogTrace("poedit.extractor", " .. using extractor '%s' for %d files", ex->GetId(), (int)ex_files.size());
        auto subPot = ex->Extract(tmpdir, sourceSpec, ex_files);
        if (!subPot.empty())
            subPots.push_back(subPot);

        if (files.size() > ex_files.size())
        {
            FilesList remaining;
            remaining.reserve(files.size() - ex_files.size());
            // Note that this only works because the lists are sorted:
            std::set_difference(files.begin(), files.end(),
                                ex_files.begin(), ex_files.end(),
                                std::inserter(remaining, remaining.begin()));
            std::swap(files, remaining);
        }
        else
        {
            files.clear();
            break; // no more work to do
        }
    }

    wxLogTrace("poedit.extractor", "extraction finished with %d unrecognized files and %d sub-POTs", (int)files.size(), (int)subPots.size());

    if (subPots.empty())
    {
        return "";
    }
    else if (subPots.size() == 1)
    {
        return subPots.front();
    }
    else
    {
        wxLogTrace("poedit.extractor", "merging %d subPOTs", (int)subPots.size());
        return ConcatCatalogs(tmpdir, subPots);
    }
}

Extractor::FilesList Extractor::FilterFiles(const FilesList& files) const
{
    FilesList out;
    for (auto& f: files)
    {
        if (IsFileSupported(f))
            out.push_back(f);
    }
    return out;
}

bool Extractor::IsFileSupported(const wxString& file) const
{
#ifdef __WXMSW__
    auto f = file.Lower();
#else
    auto& f = file;
#endif

    auto ext = f.AfterLast('.');
    if (ext != f && m_extensions.find(ext) != m_extensions.end())
        return true;

    for (auto& w: m_wildcards)
    {
        if (f.Matches(w))
            return true;
    }

    return false;
}

void Extractor::RegisterExtension(const wxString& ext)
{
    if (ext.Contains("."))
    {
        RegisterWildcard("*." + ext);
        return;
    }

#ifdef __WXMSW__
    m_extensions.insert(ext.Lower());
#else
    m_extensions.insert(ext);
#endif
    wxLogTrace("poedit.extractor", "%s handles extension %s", GetId(), ext);
}

void Extractor::RegisterWildcard(const wxString& wildcard)
{
#ifdef __WXMSW__
    m_wildcards.push_back(wildcard.Lower());
#else
    m_wildcards.push_back(wildcard);
#endif
    wxLogTrace("poedit.extractor", "%s handles %s", GetId(), wildcard);
}

wxString Extractor::ConcatCatalogs(TempDirectory& tmpdir, const std::vector<wxString>& files)
{
    if (files.empty())
    {
        return "";
    }
    else if (files.size() == 1)
    {
        return files.front();
    }

    auto outfile = tmpdir.CreateFileName("concatenated.pot");

    wxString list;
    for (auto& f: files)
        list += wxString::Format(" %s", QuoteCmdlineArg(f));

    auto cmd = wxString::Format("msgcat --force-po -o %s %s", QuoteCmdlineArg(outfile), list);
    bool succ = ExecuteGettext(cmd);

    if (!succ)
    {
        wxLogError(_("Failed command: %s"), cmd.c_str());
        wxLogError(_("Failed to merge gettext catalogs."));
        return "";
    }

    return outfile;
}

Extractor::ExtractorsList Extractor::CreateAllExtractors()
{
    ExtractorsList all;

    // User-defined "legacy" extractors take precedence over anything else,
    // to allow customization of the behavior:
    CreateAllLegacyExtractors(all);

    // Standard builtin extractors follow
    CreateGettextExtractors(all);

    return all;
}
<|endoftext|>


<commit_before>/**
 * Author: newsworthy39
 * Documentation: http://www.sfml-dev.org/documentation/2.2/
 */

#include <iostream>
#include <SFML/Graphics.hpp>

using namespace std;

int main() {

    sf::ContextSettings settings;
    settings.antialiasingLevel = 8;

    sf::RenderWindow window(sf::VideoMode(1024, 768), "SFML works!",
            sf::Style::Default, settings);

    sf::CircleShape shape(100.f);
    shape.setFillColor(sf::Color::Green);

    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
                // left key is pressed: move our character
                shape.move(1, 0);
            }

            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
                // left key is pressed: move our character
                shape.move(-1, 0);
            }

            if (event.type == sf::Event::Closed)
                window.close();
        }

        window.clear();
        window.draw(shape);
        window.display();
    }

    return 0;
}
<commit_msg>Lets try this<commit_after>/**
 * Author: newsworthy39
 * Documentation: http://www.sfml-dev.org/documentation/2.2/
 */

#include <iostream>
#include <SFML/Graphics.hpp>
#include <cmath>

using namespace std;

int main() {

    sf::ContextSettings settings;
    settings.antialiasingLevel = 8;

    sf::RenderWindow window(sf::VideoMode(640, 480), "SFML works!",
            sf::Style::Default, settings);

    sf::Vertex line[] = {
            sf::Vertex(sf::Vector2f(100,100), sf::Color::White),
            sf::Vertex(sf::Vector2f(100,100), sf::Color::White)
    };

    float degrees = 1.0f;

    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {

            if (event.type == sf::Event::Closed)
                window.close();
        }

        degrees += 0.1f;

        line[1].position.x = 100 + (std::cos((2 * M_PI / 360 ) * degrees)*100);
        line[1].position.y = 100 + (std::sin((2 * M_PI / 360) * degrees)*100);

        window.clear();
        window.draw(line, 2, sf::Lines);
        window.display();
    }

    return 0;
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/debug.hpp>
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/pixel_position.hpp>
#include <mapnik/text/face.hpp>
#include <mapnik/util/fs.hpp>

// boost
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>

// stl
#include <algorithm>
#include <stdexcept>
#include <cstdlib>

// freetype2
extern "C"
{
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_STROKER_H
#include FT_MODULE_H
}

void* _Alloc_Func(FT_Memory memory, long size)
{
    return std::malloc(size);
}

void _Free_Func(FT_Memory memory, void *block)
{
    std::free(block);
}

void* _Realloc_Func(FT_Memory memory, long cur_size, long new_size, void* block)
{
    return std::realloc(block, new_size);
}

namespace mapnik
{

void init_freetype(FT_Memory memory, FT_Library & library)
{
    memory->alloc = _Alloc_Func;
    memory->free = _Free_Func;
    memory->realloc = _Realloc_Func;
    FT_Error error = FT_New_Library(memory, &library );
    if (error) throw std::runtime_error("can not initalise FreeType2 library");
    FT_Add_Default_Modules(library);
}

freetype_engine::freetype_engine() :
    library_(nullptr),
    memory_(new FT_MemoryRec_)

{
    init_freetype(&*memory_, library_);
}

freetype_engine::~freetype_engine()
{
    FT_Done_Library(library_);
}

bool freetype_engine::is_font_file(std::string const& file_name)
{
    // only accept files that will be matched by freetype2's `figurefiletype()`
    std::string fn = file_name;
    std::transform(fn.begin(), fn.end(), fn.begin(), ::tolower);
    return boost::algorithm::ends_with(fn,std::string(".ttf")) ||
        boost::algorithm::ends_with(fn,std::string(".otf")) ||
        boost::algorithm::ends_with(fn,std::string(".ttc")) ||
        boost::algorithm::ends_with(fn,std::string(".pfa")) ||
        boost::algorithm::ends_with(fn,std::string(".pfb")) ||
        boost::algorithm::ends_with(fn,std::string(".ttc")) ||
        boost::algorithm::ends_with(fn,std::string(".woff"))||
        // Plus OSX custom ext
        boost::algorithm::ends_with(fn,std::string(".dfont"));
}

bool freetype_engine::register_font(std::string const& file_name)
{
#ifdef MAPNIK_THREADSAFE
    mapnik::scoped_lock lock(mutex_);
#endif
    std::unique_ptr<FT_MemoryRec_> memory(new FT_MemoryRec_);
    FT_Library library = 0;
    init_freetype(&*memory, library);
    bool result = register_font_impl(file_name, library);
    FT_Done_Library(library);
    return result;
}

bool freetype_engine::register_font_impl(std::string const& file_name, FT_LibraryRec_ * library)
{
    FT_Face face = 0;
    int num_faces = 0;
    bool success = false;
    // some font files have multiple fonts in a file
    // the count is in the 'root' face library[0]
    // see the FT_FaceRec in freetype.h
    for ( int i = 0; face == 0 || i < num_faces; i++ ) {
        // if face is null then this is the first face
        FT_Error error = FT_New_Face (library,file_name.c_str(),i,&face);
        if (error)
        {
            break;
        }
        // store num_faces locally, after FT_Done_Face it can not be accessed any more
        if (!num_faces)
            num_faces = face->num_faces;
        // some fonts can lack names, skip them
        // http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec
        if (face->family_name && face->style_name)
        {
            std::string name = std::string(face->family_name) + " " + std::string(face->style_name);
            // skip fonts with leading . in the name
            if (!boost::algorithm::starts_with(name,"."))
            {
                name2file_.insert(std::make_pair(name, std::make_pair(i,file_name)));
                success = true;
            }
        }
        else
        {
            std::ostringstream s;
            s << "Warning: unable to load font file '" << file_name << "' ";
            if (!face->family_name && !face->style_name)
                s << "which lacks both a family name and style name";
            else if (face->family_name)
                s << "which reports a family name of '" << std::string(face->family_name) << "' and lacks a style name";
            else if (face->style_name)
                s << "which reports a style name of '" << std::string(face->style_name) << "' and lacks a family name";

            MAPNIK_LOG_ERROR(font_engine_freetype) << "register_font: " << s.str();
        }
    }

    if (face) FT_Done_Face(face);

    return success;
}

bool freetype_engine::register_fonts(std::string const& dir, bool recurse)
{
#ifdef MAPNIK_THREADSAFE
    mapnik::scoped_lock lock(mutex_);
#endif
    std::unique_ptr<FT_MemoryRec_> memory(new FT_MemoryRec_);
    FT_Library library = 0;
    init_freetype(&*memory, library);
    bool result = register_fonts_impl(dir, library, recurse);
    FT_Done_Library(library);
    return result;
}

bool freetype_engine::register_fonts_impl(std::string const& dir, FT_LibraryRec_ * library, bool recurse)
{
    if (!mapnik::util::exists(dir))
    {
        return false;
    }
    if (!mapnik::util::is_directory(dir))
    {
        return mapnik::freetype_engine::register_font_impl(dir, library);
    }
    bool success = false;
    try
    {
        boost::filesystem::directory_iterator end_itr;
        for (boost::filesystem::directory_iterator itr(dir); itr != end_itr; ++itr)
        {
#if (BOOST_FILESYSTEM_VERSION == 3)
            std::string file_name = itr->path().string();
#else // v2
            std::string file_name = itr->string();
#endif
            if (boost::filesystem::is_directory(*itr) && recurse)
            {
                if (register_fonts_impl(file_name, library, true))
                {
                    success = true;
                }
            }
            else
            {
#if (BOOST_FILESYSTEM_VERSION == 3)
                std::string base_name = itr->path().filename().string();
#else // v2
                std::string base_name = itr->filename();
#endif
                if (!boost::algorithm::starts_with(base_name,".") &&
                    boost::filesystem::is_regular_file(file_name) &&
                    is_font_file(file_name))
                {
                    if (mapnik::freetype_engine::register_font_impl(file_name, library))
                    {
                        success = true;
                    }
                }
            }
        }
    }
    catch (std::exception const& ex)
    {
        MAPNIK_LOG_ERROR(font_engine_freetype) << "register_fonts: " << ex.what();
    }
    return success;
}

std::vector<std::string> freetype_engine::face_names ()
{
    std::vector<std::string> names;
    std::map<std::string,std::pair<int,std::string> >::const_iterator itr;
    for (itr = name2file_.begin();itr!=name2file_.end();++itr)
    {
        names.push_back(itr->first);
    }
    return names;
}

std::map<std::string,std::pair<int,std::string> > const& freetype_engine::get_mapping()
{
    return name2file_;
}

face_ptr freetype_engine::create_face(std::string const& family_name)
{
    std::map<std::string, std::pair<int,std::string> >::const_iterator itr;
    itr = name2file_.find(family_name);
    if (itr != name2file_.end())
    {
        FT_Face face;

        std::map<std::string,std::string>::const_iterator mem_font_itr = memory_fonts_.find(itr->second.second);

        if (mem_font_itr != memory_fonts_.end()) // memory font
        {
            FT_Error error = FT_New_Memory_Face(library_,
                                                reinterpret_cast<FT_Byte const*>(mem_font_itr->second.c_str()),
                                                static_cast<FT_Long>(mem_font_itr->second.size()), // size
                                                itr->second.first, // face index
                                                &face);

            if (!error) return std::make_shared<font_face>(face);
        }
        else
        {
            // load font into memory
#ifdef MAPNIK_THREADSAFE
            mapnik::scoped_lock lock(mutex_);
#endif
            std::ifstream is(itr->second.second.c_str() , std::ios::binary);
            std::string buffer((std::istreambuf_iterator<char>(is)),
                               std::istreambuf_iterator<char>());
            std::pair<std::map<std::string,std::string>::iterator,bool> result
                = memory_fonts_.insert(std::make_pair(itr->second.second, buffer));

            FT_Error error = FT_New_Memory_Face (library_,
                                                 reinterpret_cast<FT_Byte const*>(result.first->second.c_str()),
                                                 static_cast<FT_Long>(buffer.size()),
                                                 itr->second.first,
                                                 &face);
            if (!error) return std::make_shared<font_face>(face);
            else
            {
                // we can't load font, erase it.
                memory_fonts_.erase(result.first);
            }
        }
    }
    return face_ptr();
}

stroker_ptr freetype_engine::create_stroker()
{
    FT_Stroker s;
    FT_Error error = FT_Stroker_New(library_, &s);
    if (!error)
    {
        return std::make_shared<stroker>(s);
    }
    return stroker_ptr();
}

template <typename T>
face_ptr face_manager<T>::get_face(const std::string &name)
{
    face_ptr_cache_type::iterator itr;
    itr = face_ptr_cache_.find(name);
    if (itr != face_ptr_cache_.end())
    {
        return itr->second;
    }
    else
    {
        face_ptr face = engine_.create_face(name);
        if (face)
        {
            face_ptr_cache_.insert(make_pair(name,face));
        }
        return face;
    }
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(const std::string &name)
{
    face_set_ptr face_set = std::make_shared<font_face_set>();
    if (face_ptr face = get_face(name))
    {
        face_set->add(face);
    }
    return face_set;
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(const font_set &fset)
{
    std::vector<std::string> const& names = fset.get_face_names();
    face_set_ptr face_set = std::make_shared<font_face_set>();
    for (std::vector<std::string>::const_iterator name = names.begin(); name != names.end(); ++name)
    {
        face_ptr face = get_face(*name);
        if (face)
        {
            face_set->add(face);
        }
#ifdef MAPNIK_LOG
        else
        {
            MAPNIK_LOG_DEBUG(font_engine_freetype)
                << "Failed to find face '" << *name
                << "' in font set '" << fset.get_name() << "'\n";
        }
#endif
    }
    return face_set;
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(const std::string &name, boost::optional<font_set> fset)
{
    if (fset && fset->size() > 0)
    {
        return get_face_set(*fset);
    }
    else
    {
        return get_face_set(name);
    }
}

#ifdef MAPNIK_THREADSAFE
std::mutex freetype_engine::mutex_;
#endif
std::map<std::string,std::pair<int,std::string> > freetype_engine::name2file_;
std::map<std::string,std::string> freetype_engine::memory_fonts_;
template class face_manager<freetype_engine>;

}
<commit_msg>mapnik c++ style<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/debug.hpp>
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/pixel_position.hpp>
#include <mapnik/text/face.hpp>
#include <mapnik/util/fs.hpp>

// boost
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>

// stl
#include <algorithm>
#include <stdexcept>
#include <cstdlib>

// freetype2
extern "C"
{
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_STROKER_H
#include FT_MODULE_H
}

void* _Alloc_Func(FT_Memory memory, long size)
{
    return std::malloc(size);
}

void _Free_Func(FT_Memory memory, void *block)
{
    std::free(block);
}

void* _Realloc_Func(FT_Memory memory, long cur_size, long new_size, void* block)
{
    return std::realloc(block, new_size);
}

namespace mapnik
{

void init_freetype(FT_Memory memory, FT_Library & library)
{
    memory->alloc = _Alloc_Func;
    memory->free = _Free_Func;
    memory->realloc = _Realloc_Func;
    FT_Error error = FT_New_Library(memory, &library );
    if (error) throw std::runtime_error("can not initalise FreeType2 library");
    FT_Add_Default_Modules(library);
}

freetype_engine::freetype_engine()
    : library_(nullptr),
      memory_(new FT_MemoryRec_)
{
    init_freetype(&*memory_, library_);
}

freetype_engine::~freetype_engine()
{
    FT_Done_Library(library_);
}

bool freetype_engine::is_font_file(std::string const& file_name)
{
    // only accept files that will be matched by freetype2's `figurefiletype()`
    std::string fn = file_name;
    std::transform(fn.begin(), fn.end(), fn.begin(), ::tolower);
    return boost::algorithm::ends_with(fn,std::string(".ttf")) ||
        boost::algorithm::ends_with(fn,std::string(".otf")) ||
        boost::algorithm::ends_with(fn,std::string(".ttc")) ||
        boost::algorithm::ends_with(fn,std::string(".pfa")) ||
        boost::algorithm::ends_with(fn,std::string(".pfb")) ||
        boost::algorithm::ends_with(fn,std::string(".ttc")) ||
        boost::algorithm::ends_with(fn,std::string(".woff"))||
        // Plus OSX custom ext
        boost::algorithm::ends_with(fn,std::string(".dfont"));
}

bool freetype_engine::register_font(std::string const& file_name)
{
#ifdef MAPNIK_THREADSAFE
    mapnik::scoped_lock lock(mutex_);
#endif
    std::unique_ptr<FT_MemoryRec_> memory(new FT_MemoryRec_);
    FT_Library library = 0;
    init_freetype(&*memory, library);
    bool result = register_font_impl(file_name, library);
    FT_Done_Library(library);
    return result;
}

bool freetype_engine::register_font_impl(std::string const& file_name, FT_LibraryRec_ * library)
{
    FT_Face face = 0;
    int num_faces = 0;
    bool success = false;
    // some font files have multiple fonts in a file
    // the count is in the 'root' face library[0]
    // see the FT_FaceRec in freetype.h
    for ( int i = 0; face == 0 || i < num_faces; i++ ) {
        // if face is null then this is the first face
        FT_Error error = FT_New_Face (library,file_name.c_str(),i,&face);
        if (error)
        {
            break;
        }
        // store num_faces locally, after FT_Done_Face it can not be accessed any more
        if (!num_faces)
            num_faces = face->num_faces;
        // some fonts can lack names, skip them
        // http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec
        if (face->family_name && face->style_name)
        {
            std::string name = std::string(face->family_name) + " " + std::string(face->style_name);
            // skip fonts with leading . in the name
            if (!boost::algorithm::starts_with(name,"."))
            {
                name2file_.insert(std::make_pair(name, std::make_pair(i,file_name)));
                success = true;
            }
        }
        else
        {
            std::ostringstream s;
            s << "Warning: unable to load font file '" << file_name << "' ";
            if (!face->family_name && !face->style_name)
                s << "which lacks both a family name and style name";
            else if (face->family_name)
                s << "which reports a family name of '" << std::string(face->family_name) << "' and lacks a style name";
            else if (face->style_name)
                s << "which reports a style name of '" << std::string(face->style_name) << "' and lacks a family name";

            MAPNIK_LOG_ERROR(font_engine_freetype) << "register_font: " << s.str();
        }
    }

    if (face) FT_Done_Face(face);

    return success;
}

bool freetype_engine::register_fonts(std::string const& dir, bool recurse)
{
#ifdef MAPNIK_THREADSAFE
    mapnik::scoped_lock lock(mutex_);
#endif
    std::unique_ptr<FT_MemoryRec_> memory(new FT_MemoryRec_);
    FT_Library library = 0;
    init_freetype(&*memory, library);
    bool result = register_fonts_impl(dir, library, recurse);
    FT_Done_Library(library);
    return result;
}

bool freetype_engine::register_fonts_impl(std::string const& dir, FT_LibraryRec_ * library, bool recurse)
{
    if (!mapnik::util::exists(dir))
    {
        return false;
    }
    if (!mapnik::util::is_directory(dir))
    {
        return mapnik::freetype_engine::register_font_impl(dir, library);
    }
    bool success = false;
    try
    {
        boost::filesystem::directory_iterator end_itr;
        for (boost::filesystem::directory_iterator itr(dir); itr != end_itr; ++itr)
        {
#if (BOOST_FILESYSTEM_VERSION == 3)
            std::string file_name = itr->path().string();
#else // v2
            std::string file_name = itr->string();
#endif
            if (boost::filesystem::is_directory(*itr) && recurse)
            {
                if (register_fonts_impl(file_name, library, true))
                {
                    success = true;
                }
            }
            else
            {
#if (BOOST_FILESYSTEM_VERSION == 3)
                std::string base_name = itr->path().filename().string();
#else // v2
                std::string base_name = itr->filename();
#endif
                if (!boost::algorithm::starts_with(base_name,".") &&
                    boost::filesystem::is_regular_file(file_name) &&
                    is_font_file(file_name))
                {
                    if (mapnik::freetype_engine::register_font_impl(file_name, library))
                    {
                        success = true;
                    }
                }
            }
        }
    }
    catch (std::exception const& ex)
    {
        MAPNIK_LOG_ERROR(font_engine_freetype) << "register_fonts: " << ex.what();
    }
    return success;
}

std::vector<std::string> freetype_engine::face_names ()
{
    std::vector<std::string> names;
    std::map<std::string,std::pair<int,std::string> >::const_iterator itr;
    for (itr = name2file_.begin();itr!=name2file_.end();++itr)
    {
        names.push_back(itr->first);
    }
    return names;
}

std::map<std::string,std::pair<int,std::string> > const& freetype_engine::get_mapping()
{
    return name2file_;
}

face_ptr freetype_engine::create_face(std::string const& family_name)
{
    std::map<std::string, std::pair<int,std::string> >::const_iterator itr;
    itr = name2file_.find(family_name);
    if (itr != name2file_.end())
    {
        FT_Face face;

        std::map<std::string,std::string>::const_iterator mem_font_itr = memory_fonts_.find(itr->second.second);

        if (mem_font_itr != memory_fonts_.end()) // memory font
        {
            FT_Error error = FT_New_Memory_Face(library_,
                                                reinterpret_cast<FT_Byte const*>(mem_font_itr->second.c_str()),
                                                static_cast<FT_Long>(mem_font_itr->second.size()), // size
                                                itr->second.first, // face index
                                                &face);

            if (!error) return std::make_shared<font_face>(face);
        }
        else
        {
            // load font into memory
#ifdef MAPNIK_THREADSAFE
            mapnik::scoped_lock lock(mutex_);
#endif
            std::ifstream is(itr->second.second.c_str() , std::ios::binary);
            std::string buffer((std::istreambuf_iterator<char>(is)),
                               std::istreambuf_iterator<char>());
            std::pair<std::map<std::string,std::string>::iterator,bool> result
                = memory_fonts_.insert(std::make_pair(itr->second.second, buffer));

            FT_Error error = FT_New_Memory_Face (library_,
                                                 reinterpret_cast<FT_Byte const*>(result.first->second.c_str()),
                                                 static_cast<FT_Long>(buffer.size()),
                                                 itr->second.first,
                                                 &face);
            if (!error) return std::make_shared<font_face>(face);
            else
            {
                // we can't load font, erase it.
                memory_fonts_.erase(result.first);
            }
        }
    }
    return face_ptr();
}

stroker_ptr freetype_engine::create_stroker()
{
    FT_Stroker s;
    FT_Error error = FT_Stroker_New(library_, &s);
    if (!error)
    {
        return std::make_shared<stroker>(s);
    }
    return stroker_ptr();
}

template <typename T>
face_ptr face_manager<T>::get_face(std::string const& name)
{
    auto itr = face_ptr_cache_.find(name);
    if (itr != face_ptr_cache_.end())
    {
        return itr->second;
    }
    else
    {
        face_ptr face = engine_.create_face(name);
        if (face)
        {
            face_ptr_cache_.insert(make_pair(name,face));
        }
        return face;
    }
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(std::string const& name)
{
    face_set_ptr face_set = std::make_shared<font_face_set>();
    if (face_ptr face = get_face(name))
    {
        face_set->add(face);
    }
    return face_set;
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(font_set const& fset)
{
    std::vector<std::string> const& names = fset.get_face_names();
    face_set_ptr face_set = std::make_shared<font_face_set>();
    for (std::vector<std::string>::const_iterator name = names.begin(); name != names.end(); ++name)
    {
        face_ptr face = get_face(*name);
        if (face)
        {
            face_set->add(face);
        }
#ifdef MAPNIK_LOG
        else
        {
            MAPNIK_LOG_DEBUG(font_engine_freetype)
                << "Failed to find face '" << *name
                << "' in font set '" << fset.get_name() << "'\n";
        }
#endif
    }
    return face_set;
}

template <typename T>
face_set_ptr face_manager<T>::get_face_set(const std::string &name, boost::optional<font_set> fset)
{
    if (fset && fset->size() > 0)
    {
        return get_face_set(*fset);
    }
    else
    {
        return get_face_set(name);
    }
}

#ifdef MAPNIK_THREADSAFE
std::mutex freetype_engine::mutex_;
#endif
std::map<std::string,std::pair<int,std::string> > freetype_engine::name2file_;
std::map<std::string,std::string> freetype_engine::memory_fonts_;
template class face_manager<freetype_engine>;

}
<|endoftext|>


<commit_before>
/*
    Copyright 2011 Aevum Software aevum @ aevumlab.com

    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.

    @author Victor Vicente de Carvalho victor.carvalho@aevumlab.com
    @author Ozires Bortolon de Faria ozires@aevumlab.com
*/

#include "Frustum.hpp"

#include "Vector3.hpp"
#include "Matrix4.hpp"
#include "collision/BoundingBox.hpp"

#include <string.h>

using namespace gdx_cpp::math;

Vector3 Frustum::clipSpacePlanePoints[] = { Vector3(-1, -1, -1), Vector3(1, -1, -1),
        Vector3(1, 1, -1), Vector3(-1, 1, -1), // near clip
        Vector3(-1, -1, 1), Vector3(1, -1, 1), Vector3(1, 1, 1), Vector3(-1, 1, 1)}; // far clip

float Frustum::clipSpacePlanePointsArray[8 * 3];

Frustum::Frustum()
{
    for (int i = 0; i < 6; i++) {
        planes[i] = new Plane(Vector3(), 0);
    }
}

void Frustum::update (const Matrix4& inverseProjectionView) {
    memcpy(planePointsArray, clipSpacePlanePointsArray, 24 );

    Matrix4::prj(inverseProjectionView.val, planePointsArray, 0, 8, 3);
    for (int i = 0, j = 0; i < 8; i++) {
        Vector3& v = planePoints[i];
        v.x = planePointsArray[j++];
        v.y = planePointsArray[j++];
        v.z = planePointsArray[j++];
    }

    planes[0]->set(planePoints[1], planePoints[0], planePoints[2]);
    planes[1]->set(planePoints[4], planePoints[5], planePoints[7]);
    planes[2]->set(planePoints[0], planePoints[4], planePoints[3]);
    planes[3]->set(planePoints[5], planePoints[1], planePoints[6]);
    planes[4]->set(planePoints[2], planePoints[3], planePoints[6]);
    planes[5]->set(planePoints[4], planePoints[0], planePoints[1]);
}

bool Frustum::pointInFrustum (const Vector3& point) {
    for (int i = 0; i < 6; i++) {
        Plane::PlaneSide result = planes[i]->testPoint(point);
        if (result == Plane::PlaneSide_Back) return false;
    }

    return true;
}

bool Frustum::sphereInFrustum (const Vector3& center,float radius) {
    for (int i = 0; i < 6; i++)
        if (planes[i]->distance(center) < -radius) return false;

    return true;
}

bool Frustum::sphereInFrustumWithoutNearFar (const Vector3& center,float radius) {
    for (int i = 0; i < 6; i++)
        if (planes[i]->distance(center) < -radius) return false;

    return true;
}

bool Frustum::boundsInFrustum (const gdx_cpp::math::collision::BoundingBox& bounds) {
    const std::vector<Vector3>& corners = bounds.getCorners();
    int len = corners.size();

    for (int i = 0, len2 = 6; i < len2; i++) {
        int out = 0;

        for (int j = 0; j < len; j++)
          if (planes[i]->testPoint(corners[j]) == Plane::PlaneSide_Back) out++;

        if (out == 8) return false;
    }

    return true;
}<commit_msg>Added destructor<commit_after>
/*
    Copyright 2011 Aevum Software aevum @ aevumlab.com

    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.

    @author Victor Vicente de Carvalho victor.carvalho@aevumlab.com
    @author Ozires Bortolon de Faria ozires@aevumlab.com
*/

#include "Frustum.hpp"

#include "Vector3.hpp"
#include "Matrix4.hpp"
#include "collision/BoundingBox.hpp"

#include <string.h>

using namespace gdx_cpp::math;

Vector3 Frustum::clipSpacePlanePoints[] = { Vector3(-1, -1, -1), Vector3(1, -1, -1),
        Vector3(1, 1, -1), Vector3(-1, 1, -1), // near clip
        Vector3(-1, -1, 1), Vector3(1, -1, 1), Vector3(1, 1, 1), Vector3(-1, 1, 1)}; // far clip

float Frustum::clipSpacePlanePointsArray[8 * 3];

Frustum::Frustum()
{
    for (int i = 0; i < 6; i++) {
        planes[i] = new Plane(Vector3(), 0);
    }
}

gdx_cpp::math::Frustum::~Frustum()
{
  for (int i = 0; i < 6; i++) {
    delete planes[i];
  }
}

void Frustum::update (const Matrix4& inverseProjectionView) {
    memcpy(planePointsArray, clipSpacePlanePointsArray, 24 );

    Matrix4::prj(inverseProjectionView.val, planePointsArray, 0, 8, 3);
    for (int i = 0, j = 0; i < 8; i++) {
        Vector3& v = planePoints[i];
        v.x = planePointsArray[j++];
        v.y = planePointsArray[j++];
        v.z = planePointsArray[j++];
    }

    planes[0]->set(planePoints[1], planePoints[0], planePoints[2]);
    planes[1]->set(planePoints[4], planePoints[5], planePoints[7]);
    planes[2]->set(planePoints[0], planePoints[4], planePoints[3]);
    planes[3]->set(planePoints[5], planePoints[1], planePoints[6]);
    planes[4]->set(planePoints[2], planePoints[3], planePoints[6]);
    planes[5]->set(planePoints[4], planePoints[0], planePoints[1]);
}

bool Frustum::pointInFrustum (const Vector3& point) {
    for (int i = 0; i < 6; i++) {
        Plane::PlaneSide result = planes[i]->testPoint(point);
        if (result == Plane::PlaneSide_Back) return false;
    }

    return true;
}

bool Frustum::sphereInFrustum (const Vector3& center,float radius) {
    for (int i = 0; i < 6; i++)
        if (planes[i]->distance(center) < -radius) return false;

    return true;
}

bool Frustum::sphereInFrustumWithoutNearFar (const Vector3& center,float radius) {
    for (int i = 0; i < 6; i++)
        if (planes[i]->distance(center) < -radius) return false;

    return true;
}

bool Frustum::boundsInFrustum (const gdx_cpp::math::collision::BoundingBox& bounds) {
    const std::vector<Vector3>& corners = bounds.getCorners();
    int len = corners.size();

    for (int i = 0, len2 = 6; i < len2; i++) {
        int out = 0;

        for (int j = 0; j < len; j++)
          if (planes[i]->testPoint(corners[j]) == Plane::PlaneSide_Back) out++;

        if (out == 8) return false;
    }

    return true;
}<|endoftext|>