<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: optiongrouplayouter.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 19:33:06 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _EXTENSIONS_DBP_OPTIONGROUPLAYOUTER_HXX_
#define _EXTENSIONS_DBP_OPTIONGROUPLAYOUTER_HXX_

#ifndef _COM_SUN_STAR_DRAWING_XDRAWPAGE_HPP_
#include <com/sun/star/drawing/XDrawPage.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_DRAWING_XCONTROLSHAPE_HPP_
#include <com/sun/star/drawing/XControlShape.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XMODEL_HPP_
#include <com/sun/star/frame/XModel.hpp>
#endif
#ifndef _EXTENSIONS_DBP_DBPTYPES_HXX_
#include "dbptypes.hxx"
#endif

//.........................................................................
namespace dbp
{
//.........................................................................

    struct OControlWizardContext;
    struct OOptionGroupSettings;
    //=====================================================================
    //= OOptionGroupLayouter
    //=====================================================================
    class OOptionGroupLayouter
    {
        ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
                    m_xORB;

    public:
        OOptionGroupLayouter(
            const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxORB
            );

    public:
        void    doLayout(
            const OControlWizardContext& _rContext,
            const OOptionGroupSettings& _rSettings
        );

    protected:
        void    implAnchorShape(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxShapeProps
            );
    };

//.........................................................................
}   // namespace dbp
//.........................................................................

#endif // _EXTENSIONS_DBP_OPTIONGROUPLAYOUTER_HXX_

<commit_msg>INTEGRATION: CWS changefileheader (1.5.472); FILE MERGED 2008/04/01 12:29:44 thb 1.5.472.2: #i85898# Stripping all external header guards 2008/03/31 12:31:28 rt 1.5.472.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: optiongrouplayouter.hxx,v $
 * $Revision: 1.6 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _EXTENSIONS_DBP_OPTIONGROUPLAYOUTER_HXX_
#define _EXTENSIONS_DBP_OPTIONGROUPLAYOUTER_HXX_

#include <com/sun/star/drawing/XDrawPage.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/drawing/XControlShape.hpp>
#include <com/sun/star/frame/XModel.hpp>
#include "dbptypes.hxx"

//.........................................................................
namespace dbp
{
//.........................................................................

    struct OControlWizardContext;
    struct OOptionGroupSettings;
    //=====================================================================
    //= OOptionGroupLayouter
    //=====================================================================
    class OOptionGroupLayouter
    {
        ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
                    m_xORB;

    public:
        OOptionGroupLayouter(
            const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxORB
            );

    public:
        void    doLayout(
            const OControlWizardContext& _rContext,
            const OOptionGroupSettings& _rSettings
        );

    protected:
        void    implAnchorShape(
            const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxShapeProps
            );
    };

//.........................................................................
}   // namespace dbp
//.........................................................................

#endif // _EXTENSIONS_DBP_OPTIONGROUPLAYOUTER_HXX_

<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you 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 .
 */

#include <cppuhelper/bootstrap.hxx>
#include <com/sun/star/bridge/XUnoUrlResolver.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>

#include <vcl/svapp.hxx>

#include <toolkit/awt/Vclxwindow.hxx>

#ifndef _SV_SYSDATA_HXX
#if defined( WIN ) || defined( WNT ) || defined( OS2 )
typedef sal_Int32 HWND;
#endif
#endif
#include "AccEventListener.hxx"
#include "AccObjectManagerAgent.hxx"
#include "unomsaaevent.hxx"

#include <com/sun/star/accessibility/XAccessible.hpp>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
#include <com/sun/star/accessibility/XAccessibleComponent.hpp>

#include <stdio.h>

using namespace com::sun::star::uno;
using namespace com::sun::star::accessibility;
using namespace rtl;
using namespace cppu;

AccEventListener::AccEventListener(com::sun::star::accessibility::XAccessible* pAcc,
                                   AccObjectManagerAgent* Agent)
    : pAccessible(pAcc)
    , pAgent(Agent)
    , m_isDisposed(false)
{}

AccEventListener::~AccEventListener()
{
}

/**
 *  Uno's event notifier when event is captured
 *  @param AccessibleEventObject    the event object which contains information about event
 */
void  AccEventListener::notifyEvent( const ::com::sun::star::accessibility::AccessibleEventObject& aEvent )
throw (::com::sun::star::uno::RuntimeException)
{
    SolarMutexGuard g;

    switch (aEvent.EventId)
    {
    case AccessibleEventId::NAME_CHANGED:
        HandleNameChangedEvent(aEvent.NewValue);
        break;
    case AccessibleEventId::DESCRIPTION_CHANGED:
        HandleDescriptionChangedEvent(aEvent.NewValue);
        break;
    case AccessibleEventId::STATE_CHANGED:
        HandleStateChangedEvent(aEvent.OldValue, aEvent.NewValue);
        break;
    default:
        break;
    }
}

/**
 *  handle the NAME_CHANGED event
 *  @param  name        the new name with changed.
 */
void AccEventListener::HandleNameChangedEvent(Any name)
{
    if ( pAgent->IsTopWinAcc( pAccessible ) )
    {
        XAccessible* pAccDoc = pAgent->GetAccDocByAccTopWin( pAccessible );
        if ( pAccDoc )
        {
            pAgent->UpdateAccName(pAccDoc);
            pAgent->NotifyAccEvent(UM_EVENT_OBJECT_NAMECHANGE, pAccDoc);
        }
    }

    pAgent->UpdateAccName(pAccessible, name);
    pAgent->NotifyAccEvent(UM_EVENT_OBJECT_NAMECHANGE, pAccessible);
}

/**
 *  handle the DESCRIPTION_CHANGED event
 *  @param  desc        the new description
 */
void AccEventListener::HandleDescriptionChangedEvent(Any desc)
{
    pAgent->UpdateDescription(pAccessible, desc);
    pAgent->NotifyAccEvent(UM_EVENT_OBJECT_DESCRIPTIONCHANGE, pAccessible);
}

/**
 *  handle the BOUNDRECT_CHANGED event
 */
void AccEventListener::HandleBoundrectChangedEvent()
{
    pAgent->UpdateLocation(pAccessible);
    pAgent->NotifyAccEvent(UM_EVENT_BOUNDRECT_CHANGED, pAccessible);
}

/**
 *  handle the VISIBLE_DATA_CHANGED event
 */
void AccEventListener::HandleVisibleDataChangedEvent()
{
    pAgent->UpdateValue(pAccessible);
    pAgent->NotifyAccEvent(UM_EVENT_VISIBLE_DATA_CHANGED, pAccessible);
}

/**
 *  handle the STATE_CHANGED event
 *  @param  oldValue    the old state of the source of event
 *  @param  newValue    the new state of the source of event
 */
void AccEventListener::HandleStateChangedEvent(Any oldValue, Any newValue)
{
    short newV, oldV;
    if( newValue >>= newV)
    {
        SetComponentState(newV, true);
    }
    else if (oldValue >>= oldV)
    {
        SetComponentState(oldV, false);
    }
}

/**
 *  set the new state and fire the MSAA event
 *  @param  state       new state id
 *  @param  enable      true if state is set, false if state is unset
 */
void AccEventListener::SetComponentState(short state, bool enable )
{
    switch (state)
    {
    case AccessibleStateType::FOCUSED:
        FireStateFocusedChange(enable);
        break;
    default:
        FireStatePropertyChange(state, enable);
        break;
    }
}

/**
 *  handle the focused event
 *  @param enable   true if get focus, false if lose focus
 */
void AccEventListener::FireStateFocusedChange(bool enable)
{
    if(enable)
    {
        pAgent->IncreaseState( pAccessible, AccessibleStateType::FOCUSED);
        pAgent->NotifyAccEvent(UM_EVENT_STATE_FOCUSED, pAccessible);
    }
    else
    {
        // no focus lost event in MSAA
    }
}

/**
 *  fire the MSAA state changed event
 *  @param state    the state id
 *  @param set      true if state is set, false if state is unset
 */
void AccEventListener::FireStatePropertyChange(short /*state*/, bool set )
{
    if( set )
    {
        //get new state
    }
    else
    {
        //lose old state
    }
}

/**
 *  get the role of accessible object which is observed
 */
short AccEventListener::GetRole()
{
    Reference<com::sun::star::accessibility::XAccessibleContext> xContext(pAccessible->getAccessibleContext(),UNO_QUERY);
    if(xContext.is())
    {
        return xContext->getAccessibleRole();
    }
    return -1;
}

/**
 *  get the role of accessible parent object which is observed
 */
short AccEventListener::GetParentRole()
{
    if(pAccessible)
    {
        return pAgent->GetParentRole(pAccessible);
    }
    return -1;
}
/**
 *  remove the listener from accessible object
 */
void AccEventListener::RemoveMeFromBroadcaster()
{
    try
    {
        if(m_isDisposed)
            return;
        //get accessible context
        Reference< XAccessibleContext > pRContext;
        XAccessibleContext* pContext =NULL;

        if( pAccessible == NULL)
        {
            return;
        }
        pRContext = pAccessible->getAccessibleContext();
        if( !pRContext.is() )
        {
            return;
        }

        //get broadcaster from accessible component
        Reference<XAccessibleComponent> xComponent(pRContext,UNO_QUERY);
        if(!xComponent.is())
        {
            return;
        }
        Reference<XAccessibleEventBroadcaster> broadcaster(xComponent,UNO_QUERY);
        XAccessibleEventBroadcaster* pBroadcaster = broadcaster.get();
        if (pBroadcaster != NULL)
        {
            //remove the lister from accessible object
            pBroadcaster->removeAccessibleEventListener(this);
            m_isDisposed = true;
            pAgent->NotifyDestroy(pAccessible);
        }
    }
    catch(...)
    {
        return;
    }

}

/**
 *  this method is invoked before listener is disposed
 */
void AccEventListener::disposing( const ::com::sun::star::lang::EventObject& /*Source*/ )
throw (::com::sun::star::uno::RuntimeException)
{
    SolarMutexGuard g;

    RemoveMeFromBroadcaster();
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>winaccessibility: "typedef sal_Int32 HWND;" - sigh...<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you 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 .
 */

#include <cppuhelper/bootstrap.hxx>
#include <com/sun/star/bridge/XUnoUrlResolver.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>

#include <vcl/svapp.hxx>

#include <toolkit/awt/Vclxwindow.hxx>

#include "AccEventListener.hxx"
#include "AccObjectManagerAgent.hxx"
#include "unomsaaevent.hxx"

#include <com/sun/star/accessibility/XAccessible.hpp>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
#include <com/sun/star/accessibility/XAccessibleComponent.hpp>

#include <stdio.h>

using namespace com::sun::star::uno;
using namespace com::sun::star::accessibility;
using namespace rtl;
using namespace cppu;

AccEventListener::AccEventListener(com::sun::star::accessibility::XAccessible* pAcc,
                                   AccObjectManagerAgent* Agent)
    : pAccessible(pAcc)
    , pAgent(Agent)
    , m_isDisposed(false)
{}

AccEventListener::~AccEventListener()
{
}

/**
 *  Uno's event notifier when event is captured
 *  @param AccessibleEventObject    the event object which contains information about event
 */
void  AccEventListener::notifyEvent( const ::com::sun::star::accessibility::AccessibleEventObject& aEvent )
throw (::com::sun::star::uno::RuntimeException)
{
    SolarMutexGuard g;

    switch (aEvent.EventId)
    {
    case AccessibleEventId::NAME_CHANGED:
        HandleNameChangedEvent(aEvent.NewValue);
        break;
    case AccessibleEventId::DESCRIPTION_CHANGED:
        HandleDescriptionChangedEvent(aEvent.NewValue);
        break;
    case AccessibleEventId::STATE_CHANGED:
        HandleStateChangedEvent(aEvent.OldValue, aEvent.NewValue);
        break;
    default:
        break;
    }
}

/**
 *  handle the NAME_CHANGED event
 *  @param  name        the new name with changed.
 */
void AccEventListener::HandleNameChangedEvent(Any name)
{
    if ( pAgent->IsTopWinAcc( pAccessible ) )
    {
        XAccessible* pAccDoc = pAgent->GetAccDocByAccTopWin( pAccessible );
        if ( pAccDoc )
        {
            pAgent->UpdateAccName(pAccDoc);
            pAgent->NotifyAccEvent(UM_EVENT_OBJECT_NAMECHANGE, pAccDoc);
        }
    }

    pAgent->UpdateAccName(pAccessible, name);
    pAgent->NotifyAccEvent(UM_EVENT_OBJECT_NAMECHANGE, pAccessible);
}

/**
 *  handle the DESCRIPTION_CHANGED event
 *  @param  desc        the new description
 */
void AccEventListener::HandleDescriptionChangedEvent(Any desc)
{
    pAgent->UpdateDescription(pAccessible, desc);
    pAgent->NotifyAccEvent(UM_EVENT_OBJECT_DESCRIPTIONCHANGE, pAccessible);
}

/**
 *  handle the BOUNDRECT_CHANGED event
 */
void AccEventListener::HandleBoundrectChangedEvent()
{
    pAgent->UpdateLocation(pAccessible);
    pAgent->NotifyAccEvent(UM_EVENT_BOUNDRECT_CHANGED, pAccessible);
}

/**
 *  handle the VISIBLE_DATA_CHANGED event
 */
void AccEventListener::HandleVisibleDataChangedEvent()
{
    pAgent->UpdateValue(pAccessible);
    pAgent->NotifyAccEvent(UM_EVENT_VISIBLE_DATA_CHANGED, pAccessible);
}

/**
 *  handle the STATE_CHANGED event
 *  @param  oldValue    the old state of the source of event
 *  @param  newValue    the new state of the source of event
 */
void AccEventListener::HandleStateChangedEvent(Any oldValue, Any newValue)
{
    short newV, oldV;
    if( newValue >>= newV)
    {
        SetComponentState(newV, true);
    }
    else if (oldValue >>= oldV)
    {
        SetComponentState(oldV, false);
    }
}

/**
 *  set the new state and fire the MSAA event
 *  @param  state       new state id
 *  @param  enable      true if state is set, false if state is unset
 */
void AccEventListener::SetComponentState(short state, bool enable )
{
    switch (state)
    {
    case AccessibleStateType::FOCUSED:
        FireStateFocusedChange(enable);
        break;
    default:
        FireStatePropertyChange(state, enable);
        break;
    }
}

/**
 *  handle the focused event
 *  @param enable   true if get focus, false if lose focus
 */
void AccEventListener::FireStateFocusedChange(bool enable)
{
    if(enable)
    {
        pAgent->IncreaseState( pAccessible, AccessibleStateType::FOCUSED);
        pAgent->NotifyAccEvent(UM_EVENT_STATE_FOCUSED, pAccessible);
    }
    else
    {
        // no focus lost event in MSAA
    }
}

/**
 *  fire the MSAA state changed event
 *  @param state    the state id
 *  @param set      true if state is set, false if state is unset
 */
void AccEventListener::FireStatePropertyChange(short /*state*/, bool set )
{
    if( set )
    {
        //get new state
    }
    else
    {
        //lose old state
    }
}

/**
 *  get the role of accessible object which is observed
 */
short AccEventListener::GetRole()
{
    Reference<com::sun::star::accessibility::XAccessibleContext> xContext(pAccessible->getAccessibleContext(),UNO_QUERY);
    if(xContext.is())
    {
        return xContext->getAccessibleRole();
    }
    return -1;
}

/**
 *  get the role of accessible parent object which is observed
 */
short AccEventListener::GetParentRole()
{
    if(pAccessible)
    {
        return pAgent->GetParentRole(pAccessible);
    }
    return -1;
}
/**
 *  remove the listener from accessible object
 */
void AccEventListener::RemoveMeFromBroadcaster()
{
    try
    {
        if(m_isDisposed)
            return;
        //get accessible context
        Reference< XAccessibleContext > pRContext;
        XAccessibleContext* pContext =NULL;

        if( pAccessible == NULL)
        {
            return;
        }
        pRContext = pAccessible->getAccessibleContext();
        if( !pRContext.is() )
        {
            return;
        }

        //get broadcaster from accessible component
        Reference<XAccessibleComponent> xComponent(pRContext,UNO_QUERY);
        if(!xComponent.is())
        {
            return;
        }
        Reference<XAccessibleEventBroadcaster> broadcaster(xComponent,UNO_QUERY);
        XAccessibleEventBroadcaster* pBroadcaster = broadcaster.get();
        if (pBroadcaster != NULL)
        {
            //remove the lister from accessible object
            pBroadcaster->removeAccessibleEventListener(this);
            m_isDisposed = true;
            pAgent->NotifyDestroy(pAccessible);
        }
    }
    catch(...)
    {
        return;
    }

}

/**
 *  this method is invoked before listener is disposed
 */
void AccEventListener::disposing( const ::com::sun::star::lang::EventObject& /*Source*/ )
throw (::com::sun::star::uno::RuntimeException)
{
    SolarMutexGuard g;

    RemoveMeFromBroadcaster();
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/*  Sirikata
 *  Meshdata.hpp
 *
 *  Copyright (c) 2010, Daniel B. Miller
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * 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.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS 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 COPYRIGHT OWNER
 * OR 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.
 */

#ifndef _SIRIKATA_MESH_MESHDATA_HPP_
#define _SIRIKATA_MESH_MESHDATA_HPP_

#include <sirikata/mesh/Platform.hpp>
#include <sirikata/core/util/Sha256.hpp>
#include "LightInfo.hpp"
#include <sirikata/core/util/UUID.hpp>
#include <stack>

namespace Sirikata {
namespace Mesh {

// Typedefs for NodeIndices, which refer to scene graph nodes in the model
typedef int32 NodeIndex;
extern NodeIndex NullNodeIndex;
typedef std::vector<NodeIndex> NodeIndexList;

typedef std::vector<LightInfo> LightInfoList;
typedef std::vector<std::string> TextureList;

struct SIRIKATA_MESH_EXPORT Meshdata;
typedef std::tr1::shared_ptr<Meshdata> MeshdataPtr;

/** Represents a skinned animation. A skinned animation is directly associated
 *  with a SubMeshGeometry.
 */
struct SIRIKATA_MESH_EXPORT SkinController {
    // Joints for this controls Indexes into the Meshdata.joints array
    // (which indexes into Meshdata.nodes).
    std::vector<uint32> joints;

    Matrix4x4f bindShapeMatrix;
    ///n+1 elements where n is the number of vertices, so that we can do simple subtraction to find out how many joints influence each vertex
    std::vector<unsigned int> weightStartIndices;
    std::vector<float> weights;
    std::vector<unsigned int>jointIndices;
    std::vector<Matrix4x4f> inverseBindMatrices;
};
typedef std::vector<SkinController> SkinControllerList;

struct SIRIKATA_MESH_EXPORT SubMeshGeometry {
    std::string name;
    std::vector<Sirikata::Vector3f> positions;

    std::vector<Sirikata::Vector3f> normals;
    std::vector<Sirikata::Vector3f> tangents;
    std::vector<Sirikata::Vector4f> colors;
    std::vector<unsigned int> influenceStartIndex;//a list of where a given position's joint weights start
    std::vector<unsigned int> jointindices;
    std::vector<float> weights;

    std::vector<Sirikata::Matrix4x4f> inverseBindMatrices;

    struct TextureSet {
        unsigned int stride;
        std::vector<float> uvs;
    };
    std::vector<TextureSet>texUVs;
    struct Primitive {
        std::vector<unsigned short> indices;

        enum PrimitiveType {
            TRIANGLES,
            LINES,
            POINTS,
            LINESTRIPS,
            TRISTRIPS,
            TRIFANS
        }primitiveType;
        typedef size_t MaterialId;
        MaterialId materialId;
    };
    std::vector<Primitive> primitives;

    BoundingBox3f3f aabb;
    double radius;
    void recomputeBounds();

    SkinControllerList skinControllers;

    //used only during simplification
    std::vector< Matrix4x4f  > positionQs;
    uint32 numInstances;
    std::tr1::unordered_map<uint32, std::vector< std::pair<uint32, uint32> > > neighborPrimitives; // maps positionIdx to list of primitiveIdxes
    /////////////////////////////////

    /** Append the given SubMeshGeometry to the end of this one. Use the given
     *  transformation to transform the geometry before adding it.  This is a
     *  useful primitive when trying to merge/simplify geometry.
     */
    void append(const SubMeshGeometry& rhs, const Matrix4x4f& xform);
};
typedef std::vector<SubMeshGeometry> SubMeshGeometryList;

struct SIRIKATA_MESH_EXPORT GeometryInstance {
    typedef std::map<SubMeshGeometry::Primitive::MaterialId,size_t> MaterialBindingMap;
    MaterialBindingMap materialBindingMap;//maps materialIndex to offset in Meshdata's materials
    unsigned int geometryIndex; // Index in SubMeshGeometryList
    NodeIndex parentNode; // Index of node holding this instance

    /** Compute the bounds of this instance with the given transform. This is
     * more precise, and much more expensive, than transforming the
     * SubMeshGeometry's bounds.
     */
    BoundingBox3f3f computeTransformedBounds(MeshdataPtr parent, const Matrix4x4f& xform) const;
    BoundingBox3f3f computeTransformedBounds(const Meshdata& parent, const Matrix4x4f& xform) const;
    void computeTransformedBounds(MeshdataPtr parent, const Matrix4x4f& xform, BoundingBox3f3f* bounds_out, double* radius_out) const;
    void computeTransformedBounds(const Meshdata& parent, const Matrix4x4f& xform, BoundingBox3f3f* bounds_out, double* radius_out) const;
};
typedef std::vector<GeometryInstance> GeometryInstanceList;

struct SIRIKATA_MESH_EXPORT LightInstance {
    int lightIndex; // Index in LightInfoList
    NodeIndex parentNode; // Index of node holding this instance
};
typedef std::vector<LightInstance> LightInstanceList;

struct SIRIKATA_MESH_EXPORT MaterialEffectInfo {
    struct Texture {
        std::string uri;
        Vector4f color;//color while the texture is pulled in, or if the texture is 404'd
        size_t texCoord;
        enum Affecting {
            DIFFUSE,
            SPECULAR,
            EMISSION,
            AMBIENT,
            REFLECTIVE,
            OPACITY,

        }affecting;
        enum SamplerType
        {
			SAMPLER_TYPE_UNSPECIFIED,
			SAMPLER_TYPE_1D,
			SAMPLER_TYPE_2D,
			SAMPLER_TYPE_3D,
			SAMPLER_TYPE_CUBE,
			SAMPLER_TYPE_RECT,
			SAMPLER_TYPE_DEPTH,
			SAMPLER_TYPE_STATE
		} samplerType;
		enum SamplerFilter
		{
			SAMPLER_FILTER_UNSPECIFIED,
			SAMPLER_FILTER_NONE,
			SAMPLER_FILTER_NEAREST,
			SAMPLER_FILTER_LINEAR,
			SAMPLER_FILTER_NEAREST_MIPMAP_NEAREST,
			SAMPLER_FILTER_LINEAR_MIPMAP_NEAREST,
			SAMPLER_FILTER_NEAREST_MIPMAP_LINEAR,
			SAMPLER_FILTER_LINEAR_MIPMAP_LINEAR
		};
        SamplerFilter minFilter;
        SamplerFilter magFilter;
		enum WrapMode
		{
			WRAP_MODE_UNSPECIFIED=0,
			// NONE == GL_CLAMP_TO BORDER The defined behavior for NONE is
			// consistent with decal texturing where the border is black.
			// Mapping this calculation to GL_CLAMP_TO_BORDER is the best
			// approximation of this.
			WRAP_MODE_NONE,
 			// WRAP == GL_REPEAT Ignores the integer part of texture coordinates,
			// using only the fractional part.
			WRAP_MODE_WRAP,
			// MIRROR == GL_MIRRORED_REPEAT First mirrors the texture coordinate.
			// The mirrored coordinate is then clamped as described for CLAMP_TO_EDGE.
			WRAP_MODE_MIRROR,
			// CLAMP == GL_CLAMP_TO_EDGE Clamps texture coordinates at all
			// mipmap levels such that the texture filter never samples a
			// border texel. Note: GL_CLAMP takes any texels beyond the
			// sampling border and substitutes those texels with the border
			// color. So CLAMP_TO_EDGE is more appropriate. This also works
			// much better with OpenGL ES where the GL_CLAMP symbol was removed
			// from the OpenGL ES specification.
			WRAP_MODE_CLAMP,
			// BORDER GL_CLAMP_TO_BORDER Clamps texture coordinates at all
			// MIPmaps such that the texture filter always samples border
			// texels for fragments whose corresponding texture coordinate
			// is sufficiently far outside the range [0, 1].
			WRAP_MODE_BORDER
		};
        WrapMode wrapS,wrapT,wrapU;
        unsigned int maxMipLevel;
        float mipBias;

        bool operator==(const Texture& rhs) const;
        bool operator!=(const Texture& rhs) const;
    };
    typedef std::vector<Texture> TextureList;
    TextureList textures;
    float shininess;
    float reflectivity;

    bool operator==(const MaterialEffectInfo& rhs) const;
    bool operator!=(const MaterialEffectInfo& rhs) const;
};
typedef std::vector<MaterialEffectInfo> MaterialEffectInfoList;

struct  SIRIKATA_MESH_EXPORT InstanceSkinAnimation {
};

// A scene graph node. Contains a transformation, set of children nodes,
// camera instances, geometry instances, skin controller instances, light
// instances, and instances of other nodes.
struct SIRIKATA_MESH_EXPORT Node {
    Node();
    Node(NodeIndex par, const Matrix4x4f& xform);
    Node(const Matrix4x4f& xform);

    // Parent node in the actual hierarchy (not instantiated).
    NodeIndex parent;
    // Transformation to apply when traversing this node.
    Matrix4x4f transform;
    // Direct children, i.e. they are contained by this node directly and their
    // parent NodeIndex will reflect that.
    NodeIndexList children;
    // Instantiations of other nodes (and their children) into this
    // subtree. Because they are instantiations, their
    // instanceChildren[i]->parent != this node's index.
    NodeIndexList instanceChildren;
};
typedef std::vector<Node> NodeList;

struct SIRIKATA_MESH_EXPORT Meshdata {
    SubMeshGeometryList geometry;
    TextureList textures;
    LightInfoList lights;
    MaterialEffectInfoList materials;

    std::string uri;
    SHA256 hash;
    long id;

    GeometryInstanceList instances;
    LightInstanceList lightInstances;

    // The global transform should be applied to all nodes and instances
    Matrix4x4f globalTransform;
    // We track two sets of nodes: roots and the full list. (Obviously the roots
    // are a subset of the full list). The node list is just the full set,
    // usually only used to look up children/parents.  The roots list is just a
    // set of indices into the full list.
    NodeList nodes;
    NodeIndexList rootNodes;

    // Joints are tracked as indices of the nodes they are associated with.
    NodeIndexList joints;

    // Be careful using these methods. Since there are no "parent" links for
    // instance nodes (and even if there were, there could be more than one),
    // these methods cannot correctly compute the transform when instance_nodes
    // are involved.
    Matrix4x4f getTransform(NodeIndex index) const;

  private:

    // A stack of NodeState is used to track the current traversal state for
    // instance iterators
    struct NodeState {
        enum Step {
            Nodes,
            InstanceNodes,
            InstanceGeometries,
            InstanceLights,
            Done
        };

        NodeIndex index;
        Matrix4x4f transform;
        Step step;
        int32 currentChild;
    };

  public:

    // Allows you to generate a list of GeometryInstances with their transformations.
    class GeometryInstanceIterator {
    public:
        GeometryInstanceIterator(const Meshdata* const mesh);
        // Get the next GeometryInstance and its transform. Returns true if
        // values were set, false if there were no more instances. The index
        // returned is of the geometry instance.
        bool next(uint32* geoinst_idx, Matrix4x4f* xform);
    private:
        const Meshdata* mMesh;

        int32 mRoot;
        std::stack<NodeState> mStack;
    };
    GeometryInstanceIterator getGeometryInstanceIterator() const;
    /** Get count of instanced geometry. This can differ from instances.size()
     * because many nodes may refer to the same InstanceGeometry.
     */
    uint32 getInstancedGeometryCount() const;

    // Allows you to generate a list of GeometryInstances with their transformations.
    class LightInstanceIterator {
    public:
        LightInstanceIterator(const Meshdata* const mesh);
        // Get the next LightInstance and its transform. Returns true if
        // values were set, false if there were no more instances. The index
        // returned is of the light instance.
        bool next(uint32* lightinst_idx, Matrix4x4f* xform);
    private:
        const Meshdata* mMesh;

        int32 mRoot;
        std::stack<NodeState> mStack;
    };
    LightInstanceIterator getLightInstanceIterator() const;
    /** Get count of instanced lights. This can differ from
     * lightInstances.size() because many nodes may refer to the same
     * InstanceLight.
     */
    uint32 getInstancedLightCount() const;
};

} // namespace Mesh
} // namespace Sirikata

#endif //_SIRIKATA_MESH_MESHDATA_HPP_
<commit_msg>Fixed linker error on mac.<commit_after>/*  Sirikata
 *  Meshdata.hpp
 *
 *  Copyright (c) 2010, Daniel B. Miller
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * 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.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS 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 COPYRIGHT OWNER
 * OR 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.
 */

#ifndef _SIRIKATA_MESH_MESHDATA_HPP_
#define _SIRIKATA_MESH_MESHDATA_HPP_

#include <sirikata/mesh/Platform.hpp>
#include <sirikata/core/util/Sha256.hpp>
#include "LightInfo.hpp"
#include <sirikata/core/util/UUID.hpp>
#include <stack>

namespace Sirikata {
namespace Mesh {

// Typedefs for NodeIndices, which refer to scene graph nodes in the model
typedef int32 NodeIndex;
extern NodeIndex NullNodeIndex;
typedef std::vector<NodeIndex> NodeIndexList;

typedef std::vector<LightInfo> LightInfoList;
typedef std::vector<std::string> TextureList;

struct SIRIKATA_MESH_EXPORT Meshdata;
typedef std::tr1::shared_ptr<Meshdata> MeshdataPtr;

/** Represents a skinned animation. A skinned animation is directly associated
 *  with a SubMeshGeometry.
 */
struct SIRIKATA_MESH_EXPORT SkinController {
    // Joints for this controls Indexes into the Meshdata.joints array
    // (which indexes into Meshdata.nodes).
    std::vector<uint32> joints;

    Matrix4x4f bindShapeMatrix;
    ///n+1 elements where n is the number of vertices, so that we can do simple subtraction to find out how many joints influence each vertex
    std::vector<unsigned int> weightStartIndices;
    std::vector<float> weights;
    std::vector<unsigned int>jointIndices;
    std::vector<Matrix4x4f> inverseBindMatrices;
};
typedef std::vector<SkinController> SkinControllerList;

struct SIRIKATA_MESH_EXPORT SubMeshGeometry {
    std::string name;
    std::vector<Sirikata::Vector3f> positions;

    std::vector<Sirikata::Vector3f> normals;
    std::vector<Sirikata::Vector3f> tangents;
    std::vector<Sirikata::Vector4f> colors;
    std::vector<unsigned int> influenceStartIndex;//a list of where a given position's joint weights start
    std::vector<unsigned int> jointindices;
    std::vector<float> weights;

    std::vector<Sirikata::Matrix4x4f> inverseBindMatrices;

    struct TextureSet {
        unsigned int stride;
        std::vector<float> uvs;
    };
    std::vector<TextureSet>texUVs;
    struct Primitive {
        std::vector<unsigned short> indices;

        enum PrimitiveType {
            TRIANGLES,
            LINES,
            POINTS,
            LINESTRIPS,
            TRISTRIPS,
            TRIFANS
        }primitiveType;
        typedef size_t MaterialId;
        MaterialId materialId;
    };
    std::vector<Primitive> primitives;

    BoundingBox3f3f aabb;
    double radius;
    void recomputeBounds();

    SkinControllerList skinControllers;

    //used only during simplification
    std::vector< Matrix4x4f  > positionQs;
    uint32 numInstances;
    std::tr1::unordered_map<uint32, std::vector< std::pair<uint32, uint32> > > neighborPrimitives; // maps positionIdx to list of primitiveIdxes
    /////////////////////////////////

    /** Append the given SubMeshGeometry to the end of this one. Use the given
     *  transformation to transform the geometry before adding it.  This is a
     *  useful primitive when trying to merge/simplify geometry.
     */
    void append(const SubMeshGeometry& rhs, const Matrix4x4f& xform);
};
typedef std::vector<SubMeshGeometry> SubMeshGeometryList;

struct SIRIKATA_MESH_EXPORT GeometryInstance {
    typedef std::map<SubMeshGeometry::Primitive::MaterialId,size_t> MaterialBindingMap;
    MaterialBindingMap materialBindingMap;//maps materialIndex to offset in Meshdata's materials
    unsigned int geometryIndex; // Index in SubMeshGeometryList
    NodeIndex parentNode; // Index of node holding this instance

    /** Compute the bounds of this instance with the given transform. This is
     * more precise, and much more expensive, than transforming the
     * SubMeshGeometry's bounds.
     */
    BoundingBox3f3f computeTransformedBounds(MeshdataPtr parent, const Matrix4x4f& xform) const;
    BoundingBox3f3f computeTransformedBounds(const Meshdata& parent, const Matrix4x4f& xform) const;
    void computeTransformedBounds(MeshdataPtr parent, const Matrix4x4f& xform, BoundingBox3f3f* bounds_out, double* radius_out) const;
    void computeTransformedBounds(const Meshdata& parent, const Matrix4x4f& xform, BoundingBox3f3f* bounds_out, double* radius_out) const;
};
typedef std::vector<GeometryInstance> GeometryInstanceList;

struct SIRIKATA_MESH_EXPORT LightInstance {
    int lightIndex; // Index in LightInfoList
    NodeIndex parentNode; // Index of node holding this instance
};
typedef std::vector<LightInstance> LightInstanceList;

struct SIRIKATA_MESH_EXPORT MaterialEffectInfo {
    struct Texture {
        std::string uri;
        Vector4f color;//color while the texture is pulled in, or if the texture is 404'd
        size_t texCoord;
        enum Affecting {
            DIFFUSE,
            SPECULAR,
            EMISSION,
            AMBIENT,
            REFLECTIVE,
            OPACITY,

        }affecting;
        enum SamplerType
        {
			SAMPLER_TYPE_UNSPECIFIED,
			SAMPLER_TYPE_1D,
			SAMPLER_TYPE_2D,
			SAMPLER_TYPE_3D,
			SAMPLER_TYPE_CUBE,
			SAMPLER_TYPE_RECT,
			SAMPLER_TYPE_DEPTH,
			SAMPLER_TYPE_STATE
		} samplerType;
		enum SamplerFilter
		{
			SAMPLER_FILTER_UNSPECIFIED,
			SAMPLER_FILTER_NONE,
			SAMPLER_FILTER_NEAREST,
			SAMPLER_FILTER_LINEAR,
			SAMPLER_FILTER_NEAREST_MIPMAP_NEAREST,
			SAMPLER_FILTER_LINEAR_MIPMAP_NEAREST,
			SAMPLER_FILTER_NEAREST_MIPMAP_LINEAR,
			SAMPLER_FILTER_LINEAR_MIPMAP_LINEAR
		};
        SamplerFilter minFilter;
        SamplerFilter magFilter;
		enum WrapMode
		{
			WRAP_MODE_UNSPECIFIED=0,
			// NONE == GL_CLAMP_TO BORDER The defined behavior for NONE is
			// consistent with decal texturing where the border is black.
			// Mapping this calculation to GL_CLAMP_TO_BORDER is the best
			// approximation of this.
			WRAP_MODE_NONE,
 			// WRAP == GL_REPEAT Ignores the integer part of texture coordinates,
			// using only the fractional part.
			WRAP_MODE_WRAP,
			// MIRROR == GL_MIRRORED_REPEAT First mirrors the texture coordinate.
			// The mirrored coordinate is then clamped as described for CLAMP_TO_EDGE.
			WRAP_MODE_MIRROR,
			// CLAMP == GL_CLAMP_TO_EDGE Clamps texture coordinates at all
			// mipmap levels such that the texture filter never samples a
			// border texel. Note: GL_CLAMP takes any texels beyond the
			// sampling border and substitutes those texels with the border
			// color. So CLAMP_TO_EDGE is more appropriate. This also works
			// much better with OpenGL ES where the GL_CLAMP symbol was removed
			// from the OpenGL ES specification.
			WRAP_MODE_CLAMP,
			// BORDER GL_CLAMP_TO_BORDER Clamps texture coordinates at all
			// MIPmaps such that the texture filter always samples border
			// texels for fragments whose corresponding texture coordinate
			// is sufficiently far outside the range [0, 1].
			WRAP_MODE_BORDER
		};
        WrapMode wrapS,wrapT,wrapU;
        unsigned int maxMipLevel;
        float mipBias;

        bool operator==(const Texture& rhs) const;
        bool operator!=(const Texture& rhs) const;
    };
    typedef std::vector<Texture> TextureList;
    TextureList textures;
    float shininess;
    float reflectivity;

    bool operator==(const MaterialEffectInfo& rhs) const;
    bool operator!=(const MaterialEffectInfo& rhs) const;
};
typedef std::vector<MaterialEffectInfo> MaterialEffectInfoList;

struct  SIRIKATA_MESH_EXPORT InstanceSkinAnimation {
};

// A scene graph node. Contains a transformation, set of children nodes,
// camera instances, geometry instances, skin controller instances, light
// instances, and instances of other nodes.
struct SIRIKATA_MESH_EXPORT Node {
    Node();
    Node(NodeIndex par, const Matrix4x4f& xform);
    Node(const Matrix4x4f& xform);

    // Parent node in the actual hierarchy (not instantiated).
    NodeIndex parent;
    // Transformation to apply when traversing this node.
    Matrix4x4f transform;
    // Direct children, i.e. they are contained by this node directly and their
    // parent NodeIndex will reflect that.
    NodeIndexList children;
    // Instantiations of other nodes (and their children) into this
    // subtree. Because they are instantiations, their
    // instanceChildren[i]->parent != this node's index.
    NodeIndexList instanceChildren;
};
typedef std::vector<Node> NodeList;

struct SIRIKATA_MESH_EXPORT Meshdata {
    SubMeshGeometryList geometry;
    TextureList textures;
    LightInfoList lights;
    MaterialEffectInfoList materials;

    std::string uri;
    SHA256 hash;
    long id;

    GeometryInstanceList instances;
    LightInstanceList lightInstances;

    // The global transform should be applied to all nodes and instances
    Matrix4x4f globalTransform;
    // We track two sets of nodes: roots and the full list. (Obviously the roots
    // are a subset of the full list). The node list is just the full set,
    // usually only used to look up children/parents.  The roots list is just a
    // set of indices into the full list.
    NodeList nodes;
    NodeIndexList rootNodes;

    // Joints are tracked as indices of the nodes they are associated with.
    NodeIndexList joints;

    // Be careful using these methods. Since there are no "parent" links for
    // instance nodes (and even if there were, there could be more than one),
    // these methods cannot correctly compute the transform when instance_nodes
    // are involved.
    Matrix4x4f getTransform(NodeIndex index) const;

  private:

    // A stack of NodeState is used to track the current traversal state for
    // instance iterators
    struct SIRIKATA_MESH_EXPORT NodeState {
        enum Step {
            Nodes,
            InstanceNodes,
            InstanceGeometries,
            InstanceLights,
            Done
        };

        NodeIndex index;
        Matrix4x4f transform;
        Step step;
        int32 currentChild;
    };

  public:

    // Allows you to generate a list of GeometryInstances with their transformations.
    class SIRIKATA_MESH_EXPORT GeometryInstanceIterator {
    public:
        GeometryInstanceIterator(const Meshdata* const mesh);
        // Get the next GeometryInstance and its transform. Returns true if
        // values were set, false if there were no more instances. The index
        // returned is of the geometry instance.
        bool next(uint32* geoinst_idx, Matrix4x4f* xform);
    private:
        const Meshdata* mMesh;

        int32 mRoot;
        std::stack<NodeState> mStack;
    };
    GeometryInstanceIterator getGeometryInstanceIterator() const;
    /** Get count of instanced geometry. This can differ from instances.size()
     * because many nodes may refer to the same InstanceGeometry.
     */
    uint32 getInstancedGeometryCount() const;

    // Allows you to generate a list of GeometryInstances with their transformations.
    class SIRIKATA_MESH_EXPORT LightInstanceIterator {
    public:
        LightInstanceIterator(const Meshdata* const mesh);
        // Get the next LightInstance and its transform. Returns true if
        // values were set, false if there were no more instances. The index
        // returned is of the light instance.
        bool next(uint32* lightinst_idx, Matrix4x4f* xform);
    private:
        const Meshdata* mMesh;

        int32 mRoot;
        std::stack<NodeState> mStack;
    };
    LightInstanceIterator getLightInstanceIterator() const;
    /** Get count of instanced lights. This can differ from
     * lightInstances.size() because many nodes may refer to the same
     * InstanceLight.
     */
    uint32 getInstancedLightCount() const;
};

} // namespace Mesh
} // namespace Sirikata

#endif //_SIRIKATA_MESH_MESHDATA_HPP_
<|endoftext|>


<commit_before>/*
  Parsing.cpp - HTTP request parsing.

  Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.

  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
  Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
*/

#include <Arduino.h>
#include "WiFiServer.h"
#include "WiFiClient.h"
#include "ESP8266WebServer.h"

// #define DEBUG
#define DEBUG_OUTPUT Serial1

bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
  // Read the first line of HTTP request
  String req = client.readStringUntil('\r');
  client.readStringUntil('\n');

  // First line of HTTP request looks like "GET /path HTTP/1.1"
  // Retrieve the "/path" part by finding the spaces
  int addr_start = req.indexOf(' ');
  int addr_end = req.indexOf(' ', addr_start + 1);
  if (addr_start == -1 || addr_end == -1) {
#ifdef DEBUG
    DEBUG_OUTPUT.print("Invalid request: ");
    DEBUG_OUTPUT.println(req);
#endif
    return false;
  }

  String methodStr = req.substring(0, addr_start);
  String url = req.substring(addr_start + 1, addr_end);
  String searchStr = "";
  int hasSearch = url.indexOf('?');
  if (hasSearch != -1){
    searchStr = url.substring(hasSearch + 1);
    url = url.substring(0, hasSearch);
  }
  _currentUri = url;

  HTTPMethod method = HTTP_GET;
  if (methodStr == "POST") {
    method = HTTP_POST;
  } else if (methodStr == "DELETE") {
    method = HTTP_DELETE;
  } else if (methodStr == "PUT") {
    method = HTTP_PUT;
  } else if (methodStr == "PATCH") {
    method = HTTP_PATCH;
  }
  _currentMethod = method;

#ifdef DEBUG
  DEBUG_OUTPUT.print("method: ");
  DEBUG_OUTPUT.print(methodStr);
  DEBUG_OUTPUT.print(" url: ");
  DEBUG_OUTPUT.print(url);
  DEBUG_OUTPUT.print(" search: ");
  DEBUG_OUTPUT.println(searchStr);
#endif

  String formData;
  // below is needed only when POST type request
  if (method == HTTP_POST || method == HTTP_PUT || method == HTTP_PATCH || method == HTTP_DELETE){
    String boundaryStr;
    String headerName;
    String headerValue;
    bool isForm = false;
    uint32_t contentLength = 0;
    //parse headers
    while(1){
      req = client.readStringUntil('\r');
      client.readStringUntil('\n');
      if (req == "") break;//no moar headers
      int headerDiv = req.indexOf(':');
      if (headerDiv == -1){
        break;
      }
      headerName = req.substring(0, headerDiv);
      headerValue = req.substring(headerDiv + 2);
      if (headerName == "Content-Type"){
        if (headerValue.startsWith("text/plain")){
          isForm = false;
        } else if (headerValue.startsWith("multipart/form-data")){
          boundaryStr = headerValue.substring(headerValue.indexOf('=')+1);
          isForm = true;
        }
      } else if (headerName == "Content-Length"){
        contentLength = headerValue.toInt();
      }
    }

    if (!isForm){
      if (searchStr != "") searchStr += '&';
      String bodyLine = client.readStringUntil('\r');
#ifdef DEBUG
      DEBUG_OUTPUT.print("Plain: ");
      DEBUG_OUTPUT.println(bodyLine);
#endif
      if(bodyLine.startsWith("{") || bodyLine.startsWith("[") || bodyLine.indexOf('=') == -1){
        //plain post json or other data
        searchStr += "plain=";
        searchStr += bodyLine;
        searchStr += client.readString();
      } else {
        searchStr += bodyLine;
        client.readStringUntil('\n');
      }
    }
    _parseArguments(searchStr);
    if (isForm){
      _parseForm(client, boundaryStr, contentLength);
    }
  } else {
    _parseArguments(searchStr);
  }
  client.flush();

#ifdef DEBUG
  DEBUG_OUTPUT.print("Request: ");
  DEBUG_OUTPUT.println(url);
  DEBUG_OUTPUT.print(" Arguments: ");
  DEBUG_OUTPUT.println(searchStr);
#endif

  return true;
}

void ESP8266WebServer::_parseArguments(String data) {
#ifdef DEBUG
  DEBUG_OUTPUT.print("args: ");
  DEBUG_OUTPUT.println(data);
#endif
  if (_currentArgs)
    delete[] _currentArgs;
  _currentArgs = 0;
  if (data.length() == 0) {
    _currentArgCount = 0;
    return;
  }
  _currentArgCount = 1;

  for (int i = 0; i < data.length(); ) {
    i = data.indexOf('&', i);
    if (i == -1)
      break;
    ++i;
    ++_currentArgCount;
  }
#ifdef DEBUG
  DEBUG_OUTPUT.print("args count: ");
  DEBUG_OUTPUT.println(_currentArgCount);
#endif

  _currentArgs = new RequestArgument[_currentArgCount];
  int pos = 0;
  int iarg;
  for (iarg = 0; iarg < _currentArgCount;) {
    int equal_sign_index = data.indexOf('=', pos);
    int next_arg_index = data.indexOf('&', pos);
#ifdef DEBUG
    DEBUG_OUTPUT.print("pos ");
    DEBUG_OUTPUT.print(pos);
    DEBUG_OUTPUT.print("=@ ");
    DEBUG_OUTPUT.print(equal_sign_index);
    DEBUG_OUTPUT.print(" &@ ");
    DEBUG_OUTPUT.println(next_arg_index);
#endif
    if ((equal_sign_index == -1) || ((equal_sign_index > next_arg_index) && (next_arg_index != -1))) {
#ifdef DEBUG
      DEBUG_OUTPUT.print("arg missing value: ");
      DEBUG_OUTPUT.println(iarg);
#endif
      if (next_arg_index == -1)
        break;
      pos = next_arg_index + 1;
      continue;
    }
    RequestArgument& arg = _currentArgs[iarg];
    arg.key = data.substring(pos, equal_sign_index);
    arg.value = data.substring(equal_sign_index + 1, next_arg_index);
#ifdef DEBUG
    DEBUG_OUTPUT.print("arg ");
    DEBUG_OUTPUT.print(iarg);
    DEBUG_OUTPUT.print(" key: ");
    DEBUG_OUTPUT.print(arg.key);
    DEBUG_OUTPUT.print(" value: ");
    DEBUG_OUTPUT.println(arg.value);
#endif
    ++iarg;
    if (next_arg_index == -1)
      break;
    pos = next_arg_index + 1;
  }
  _currentArgCount = iarg;
#ifdef DEBUG
  DEBUG_OUTPUT.print("args count: ");
  DEBUG_OUTPUT.println(_currentArgCount);
#endif

}

void ESP8266WebServer::_uploadWriteByte(uint8_t b){
  if (_currentUpload.currentSize == HTTP_UPLOAD_BUFLEN){
    if (_fileUploadHandler) _fileUploadHandler();
    _currentUpload.totalSize += _currentUpload.currentSize;
    _currentUpload.currentSize = 0;
  }
  _currentUpload.buf[_currentUpload.currentSize++] = b;
}

uint8_t ESP8266WebServer::_uploadReadByte(WiFiClient& client){
  int res = client.read();
  if(res == -1){
    while(!client.available())
      yield();
    res = client.read();
  }
  return (uint8_t)res;
}

void ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){

#ifdef DEBUG
  DEBUG_OUTPUT.print("Parse Form: Boundary: ");
  DEBUG_OUTPUT.print(boundary);
  DEBUG_OUTPUT.print(" Length: ");
  DEBUG_OUTPUT.println(len);
#endif
  String line;
  line = client.readStringUntil('\r');
  client.readStringUntil('\n');
  //start reading the form
  if (line == ("--"+boundary)){
    RequestArgument* postArgs = new RequestArgument[32];
    int postArgsLen = 0;
    while(1){
      String argName;
      String argValue;
      String argType;
      String argFilename;
      bool argIsFile = false;

      line = client.readStringUntil('\r');
      client.readStringUntil('\n');
      if (line.startsWith("Content-Disposition")){
        int nameStart = line.indexOf('=');
        if (nameStart != -1){
          argName = line.substring(nameStart+2);
          nameStart = argName.indexOf('=');
          if (nameStart == -1){
            argName = argName.substring(0, argName.length() - 1);
          } else {
            argFilename = argName.substring(nameStart+2, argName.length() - 1);
            argName = argName.substring(0, argName.indexOf('"'));
            argIsFile = true;
#ifdef DEBUG
            DEBUG_OUTPUT.print("PostArg FileName: ");
            DEBUG_OUTPUT.println(argFilename);
#endif
            //use GET to set the filename if uploading using blob
            if (argFilename == "blob" && hasArg("filename")) argFilename = arg("filename");
          }
#ifdef DEBUG
          DEBUG_OUTPUT.print("PostArg Name: ");
          DEBUG_OUTPUT.println(argName);
#endif
          argType = "text/plain";
          line = client.readStringUntil('\r');
          client.readStringUntil('\n');
          if (line.startsWith("Content-Type")){
            argType = line.substring(line.indexOf(':')+2);
            //skip next line
            client.readStringUntil('\r');
            client.readStringUntil('\n');
          }
#ifdef DEBUG
          DEBUG_OUTPUT.print("PostArg Type: ");
          DEBUG_OUTPUT.println(argType);
#endif
          if (!argIsFile){
            while(1){
              line = client.readStringUntil('\r');
              client.readStringUntil('\n');
              if (line.startsWith("--"+boundary)) break;
              if (argValue.length() > 0) argValue += "\n";
              argValue += line;
            }
#ifdef DEBUG
            DEBUG_OUTPUT.print("PostArg Value: ");
            DEBUG_OUTPUT.println(argValue);
            DEBUG_OUTPUT.println();
#endif

            RequestArgument& arg = postArgs[postArgsLen++];
            arg.key = argName;
            arg.value = argValue;

            if (line == ("--"+boundary+"--")){
#ifdef DEBUG
              DEBUG_OUTPUT.println("Done Parsing POST");
#endif
              break;
            }
          } else {
            _currentUpload.status = UPLOAD_FILE_START;
            _currentUpload.name = argName;
            _currentUpload.filename = argFilename;
            _currentUpload.type = argType;
            _currentUpload.totalSize = 0;
            _currentUpload.currentSize = 0;
#ifdef DEBUG
            DEBUG_OUTPUT.print("Start File: ");
            DEBUG_OUTPUT.print(_currentUpload.filename);
            DEBUG_OUTPUT.print(" Type: ");
            DEBUG_OUTPUT.println(_currentUpload.type);
#endif
            if (_fileUploadHandler) _fileUploadHandler();
            _currentUpload.status = UPLOAD_FILE_WRITE;
            uint8_t argByte = _uploadReadByte(client);
readfile:
            while(argByte != 0x0D){
              _uploadWriteByte(argByte);
              argByte = _uploadReadByte(client);
            }

            argByte = _uploadReadByte(client);
            if (argByte == 0x0A){
              argByte = _uploadReadByte(client);
              if ((char)argByte != '-'){
                //continue reading the file
                _uploadWriteByte(0x0D);
                _uploadWriteByte(0x0A);
                goto readfile;
              } else {
                argByte = _uploadReadByte(client);
                if ((char)argByte != '-'){
                  //continue reading the file
                  _uploadWriteByte(0x0D);
                  _uploadWriteByte(0x0A);
                  _uploadWriteByte((uint8_t)('-'));
                  goto readfile;
                }
              }

              uint8_t endBuf[boundary.length()];
              client.readBytes(endBuf, boundary.length());

              if (strstr((const char*)endBuf, boundary.c_str()) != NULL){
                if (_fileUploadHandler) _fileUploadHandler();
                _currentUpload.totalSize += _currentUpload.currentSize;
                _currentUpload.status = UPLOAD_FILE_END;
                if (_fileUploadHandler) _fileUploadHandler();
#ifdef DEBUG
                DEBUG_OUTPUT.print("End File: ");
                DEBUG_OUTPUT.print(_currentUpload.filename);
                DEBUG_OUTPUT.print(" Type: ");
                DEBUG_OUTPUT.print(_currentUpload.type);
                DEBUG_OUTPUT.print(" Size: ");
                DEBUG_OUTPUT.println(_currentUpload.totalSize);
#endif
                line = client.readStringUntil(0x0D);
                client.readStringUntil(0x0A);
                if (line == "--"){
#ifdef DEBUG
                  DEBUG_OUTPUT.println("Done Parsing POST");
#endif
                  break;
                }
                continue;
              } else {
                _uploadWriteByte(0x0D);
                _uploadWriteByte(0x0A);
                _uploadWriteByte((uint8_t)('-'));
                _uploadWriteByte((uint8_t)('-'));
                uint32_t i = 0;
                while(i < boundary.length()){
                  _uploadWriteByte(endBuf[i++]);
                }
                argByte = _uploadReadByte(client);
                goto readfile;
              }
            } else {
              _uploadWriteByte(0x0D);
              goto readfile;
            }
            break;
          }
        }
      }
    }

    int iarg;
    int totalArgs = ((32 - postArgsLen) < _currentArgCount)?(32 - postArgsLen):_currentArgCount;
    for (iarg = 0; iarg < totalArgs; iarg++){
      RequestArgument& arg = postArgs[postArgsLen++];
      arg.key = _currentArgs[iarg].key;
      arg.value = _currentArgs[iarg].value;
    }
    if (_currentArgs) delete[] _currentArgs;
    _currentArgs = new RequestArgument[postArgsLen];
    for (iarg = 0; iarg < postArgsLen; iarg++){
      RequestArgument& arg = _currentArgs[iarg];
      arg.key = postArgs[iarg].key;
      arg.value = postArgs[iarg].value;
    }
    _currentArgCount = iarg;
    if (postArgs) delete[] postArgs;
  }
}

<commit_msg>fix  plain post slowdown<commit_after>/*
  Parsing.cpp - HTTP request parsing.

  Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.

  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
  Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
*/

#include <Arduino.h>
#include "WiFiServer.h"
#include "WiFiClient.h"
#include "ESP8266WebServer.h"

// #define DEBUG
#define DEBUG_OUTPUT Serial1

bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
  // Read the first line of HTTP request
  String req = client.readStringUntil('\r');
  client.readStringUntil('\n');

  // First line of HTTP request looks like "GET /path HTTP/1.1"
  // Retrieve the "/path" part by finding the spaces
  int addr_start = req.indexOf(' ');
  int addr_end = req.indexOf(' ', addr_start + 1);
  if (addr_start == -1 || addr_end == -1) {
#ifdef DEBUG
    DEBUG_OUTPUT.print("Invalid request: ");
    DEBUG_OUTPUT.println(req);
#endif
    return false;
  }

  String methodStr = req.substring(0, addr_start);
  String url = req.substring(addr_start + 1, addr_end);
  String searchStr = "";
  int hasSearch = url.indexOf('?');
  if (hasSearch != -1){
    searchStr = url.substring(hasSearch + 1);
    url = url.substring(0, hasSearch);
  }
  _currentUri = url;

  HTTPMethod method = HTTP_GET;
  if (methodStr == "POST") {
    method = HTTP_POST;
  } else if (methodStr == "DELETE") {
    method = HTTP_DELETE;
  } else if (methodStr == "PUT") {
    method = HTTP_PUT;
  } else if (methodStr == "PATCH") {
    method = HTTP_PATCH;
  }
  _currentMethod = method;

#ifdef DEBUG
  DEBUG_OUTPUT.print("method: ");
  DEBUG_OUTPUT.print(methodStr);
  DEBUG_OUTPUT.print(" url: ");
  DEBUG_OUTPUT.print(url);
  DEBUG_OUTPUT.print(" search: ");
  DEBUG_OUTPUT.println(searchStr);
#endif

  String formData;
  // below is needed only when POST type request
  if (method == HTTP_POST || method == HTTP_PUT || method == HTTP_PATCH || method == HTTP_DELETE){
    String boundaryStr;
    String headerName;
    String headerValue;
    bool isForm = false;
    uint32_t contentLength = 0;
    //parse headers
    while(1){
      req = client.readStringUntil('\r');
      client.readStringUntil('\n');
      if (req == "") break;//no moar headers
      int headerDiv = req.indexOf(':');
      if (headerDiv == -1){
        break;
      }
      headerName = req.substring(0, headerDiv);
      headerValue = req.substring(headerDiv + 2);
      if (headerName == "Content-Type"){
        if (headerValue.startsWith("text/plain")){
          isForm = false;
        } else if (headerValue.startsWith("multipart/form-data")){
          boundaryStr = headerValue.substring(headerValue.indexOf('=')+1);
          isForm = true;
        }
      } else if (headerName == "Content-Length"){
        contentLength = headerValue.toInt();
      }
    }

    if (!isForm){
      if (searchStr != "") searchStr += '&';
      size_t plainLen = client.available();
      char *plainBuf = (char*)malloc(plainLen+1);
      client.readBytes(plainBuf, plainLen);
      plainBuf[plainLen] = '\0';
#ifdef DEBUG
      DEBUG_OUTPUT.print("Plain: ");
      DEBUG_OUTPUT.println(plainBuf);
#endif
      if(plainBuf[0] == '{' || plainBuf[0] == '[' || strstr(plainBuf, "=") == NULL){
        //plain post json or other data
        searchStr += "plain=";
        searchStr += plainBuf;
      } else {
        searchStr += plainBuf;
      }
      free(plainBuf);
    }
    _parseArguments(searchStr);
    if (isForm){
      _parseForm(client, boundaryStr, contentLength);
    }
  } else {
    _parseArguments(searchStr);
  }
  client.flush();

#ifdef DEBUG
  DEBUG_OUTPUT.print("Request: ");
  DEBUG_OUTPUT.println(url);
  DEBUG_OUTPUT.print(" Arguments: ");
  DEBUG_OUTPUT.println(searchStr);
#endif

  return true;
}

void ESP8266WebServer::_parseArguments(String data) {
#ifdef DEBUG
  DEBUG_OUTPUT.print("args: ");
  DEBUG_OUTPUT.println(data);
#endif
  if (_currentArgs)
    delete[] _currentArgs;
  _currentArgs = 0;
  if (data.length() == 0) {
    _currentArgCount = 0;
    return;
  }
  _currentArgCount = 1;

  for (int i = 0; i < data.length(); ) {
    i = data.indexOf('&', i);
    if (i == -1)
      break;
    ++i;
    ++_currentArgCount;
  }
#ifdef DEBUG
  DEBUG_OUTPUT.print("args count: ");
  DEBUG_OUTPUT.println(_currentArgCount);
#endif

  _currentArgs = new RequestArgument[_currentArgCount];
  int pos = 0;
  int iarg;
  for (iarg = 0; iarg < _currentArgCount;) {
    int equal_sign_index = data.indexOf('=', pos);
    int next_arg_index = data.indexOf('&', pos);
#ifdef DEBUG
    DEBUG_OUTPUT.print("pos ");
    DEBUG_OUTPUT.print(pos);
    DEBUG_OUTPUT.print("=@ ");
    DEBUG_OUTPUT.print(equal_sign_index);
    DEBUG_OUTPUT.print(" &@ ");
    DEBUG_OUTPUT.println(next_arg_index);
#endif
    if ((equal_sign_index == -1) || ((equal_sign_index > next_arg_index) && (next_arg_index != -1))) {
#ifdef DEBUG
      DEBUG_OUTPUT.print("arg missing value: ");
      DEBUG_OUTPUT.println(iarg);
#endif
      if (next_arg_index == -1)
        break;
      pos = next_arg_index + 1;
      continue;
    }
    RequestArgument& arg = _currentArgs[iarg];
    arg.key = data.substring(pos, equal_sign_index);
    arg.value = data.substring(equal_sign_index + 1, next_arg_index);
#ifdef DEBUG
    DEBUG_OUTPUT.print("arg ");
    DEBUG_OUTPUT.print(iarg);
    DEBUG_OUTPUT.print(" key: ");
    DEBUG_OUTPUT.print(arg.key);
    DEBUG_OUTPUT.print(" value: ");
    DEBUG_OUTPUT.println(arg.value);
#endif
    ++iarg;
    if (next_arg_index == -1)
      break;
    pos = next_arg_index + 1;
  }
  _currentArgCount = iarg;
#ifdef DEBUG
  DEBUG_OUTPUT.print("args count: ");
  DEBUG_OUTPUT.println(_currentArgCount);
#endif

}

void ESP8266WebServer::_uploadWriteByte(uint8_t b){
  if (_currentUpload.currentSize == HTTP_UPLOAD_BUFLEN){
    if (_fileUploadHandler) _fileUploadHandler();
    _currentUpload.totalSize += _currentUpload.currentSize;
    _currentUpload.currentSize = 0;
  }
  _currentUpload.buf[_currentUpload.currentSize++] = b;
}

uint8_t ESP8266WebServer::_uploadReadByte(WiFiClient& client){
  int res = client.read();
  if(res == -1){
    while(!client.available())
      yield();
    res = client.read();
  }
  return (uint8_t)res;
}

void ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){

#ifdef DEBUG
  DEBUG_OUTPUT.print("Parse Form: Boundary: ");
  DEBUG_OUTPUT.print(boundary);
  DEBUG_OUTPUT.print(" Length: ");
  DEBUG_OUTPUT.println(len);
#endif
  String line;
  line = client.readStringUntil('\r');
  client.readStringUntil('\n');
  //start reading the form
  if (line == ("--"+boundary)){
    RequestArgument* postArgs = new RequestArgument[32];
    int postArgsLen = 0;
    while(1){
      String argName;
      String argValue;
      String argType;
      String argFilename;
      bool argIsFile = false;

      line = client.readStringUntil('\r');
      client.readStringUntil('\n');
      if (line.startsWith("Content-Disposition")){
        int nameStart = line.indexOf('=');
        if (nameStart != -1){
          argName = line.substring(nameStart+2);
          nameStart = argName.indexOf('=');
          if (nameStart == -1){
            argName = argName.substring(0, argName.length() - 1);
          } else {
            argFilename = argName.substring(nameStart+2, argName.length() - 1);
            argName = argName.substring(0, argName.indexOf('"'));
            argIsFile = true;
#ifdef DEBUG
            DEBUG_OUTPUT.print("PostArg FileName: ");
            DEBUG_OUTPUT.println(argFilename);
#endif
            //use GET to set the filename if uploading using blob
            if (argFilename == "blob" && hasArg("filename")) argFilename = arg("filename");
          }
#ifdef DEBUG
          DEBUG_OUTPUT.print("PostArg Name: ");
          DEBUG_OUTPUT.println(argName);
#endif
          argType = "text/plain";
          line = client.readStringUntil('\r');
          client.readStringUntil('\n');
          if (line.startsWith("Content-Type")){
            argType = line.substring(line.indexOf(':')+2);
            //skip next line
            client.readStringUntil('\r');
            client.readStringUntil('\n');
          }
#ifdef DEBUG
          DEBUG_OUTPUT.print("PostArg Type: ");
          DEBUG_OUTPUT.println(argType);
#endif
          if (!argIsFile){
            while(1){
              line = client.readStringUntil('\r');
              client.readStringUntil('\n');
              if (line.startsWith("--"+boundary)) break;
              if (argValue.length() > 0) argValue += "\n";
              argValue += line;
            }
#ifdef DEBUG
            DEBUG_OUTPUT.print("PostArg Value: ");
            DEBUG_OUTPUT.println(argValue);
            DEBUG_OUTPUT.println();
#endif

            RequestArgument& arg = postArgs[postArgsLen++];
            arg.key = argName;
            arg.value = argValue;

            if (line == ("--"+boundary+"--")){
#ifdef DEBUG
              DEBUG_OUTPUT.println("Done Parsing POST");
#endif
              break;
            }
          } else {
            _currentUpload.status = UPLOAD_FILE_START;
            _currentUpload.name = argName;
            _currentUpload.filename = argFilename;
            _currentUpload.type = argType;
            _currentUpload.totalSize = 0;
            _currentUpload.currentSize = 0;
#ifdef DEBUG
            DEBUG_OUTPUT.print("Start File: ");
            DEBUG_OUTPUT.print(_currentUpload.filename);
            DEBUG_OUTPUT.print(" Type: ");
            DEBUG_OUTPUT.println(_currentUpload.type);
#endif
            if (_fileUploadHandler) _fileUploadHandler();
            _currentUpload.status = UPLOAD_FILE_WRITE;
            uint8_t argByte = _uploadReadByte(client);
readfile:
            while(argByte != 0x0D){
              _uploadWriteByte(argByte);
              argByte = _uploadReadByte(client);
            }

            argByte = _uploadReadByte(client);
            if (argByte == 0x0A){
              argByte = _uploadReadByte(client);
              if ((char)argByte != '-'){
                //continue reading the file
                _uploadWriteByte(0x0D);
                _uploadWriteByte(0x0A);
                goto readfile;
              } else {
                argByte = _uploadReadByte(client);
                if ((char)argByte != '-'){
                  //continue reading the file
                  _uploadWriteByte(0x0D);
                  _uploadWriteByte(0x0A);
                  _uploadWriteByte((uint8_t)('-'));
                  goto readfile;
                }
              }

              uint8_t endBuf[boundary.length()];
              client.readBytes(endBuf, boundary.length());

              if (strstr((const char*)endBuf, boundary.c_str()) != NULL){
                if (_fileUploadHandler) _fileUploadHandler();
                _currentUpload.totalSize += _currentUpload.currentSize;
                _currentUpload.status = UPLOAD_FILE_END;
                if (_fileUploadHandler) _fileUploadHandler();
#ifdef DEBUG
                DEBUG_OUTPUT.print("End File: ");
                DEBUG_OUTPUT.print(_currentUpload.filename);
                DEBUG_OUTPUT.print(" Type: ");
                DEBUG_OUTPUT.print(_currentUpload.type);
                DEBUG_OUTPUT.print(" Size: ");
                DEBUG_OUTPUT.println(_currentUpload.totalSize);
#endif
                line = client.readStringUntil(0x0D);
                client.readStringUntil(0x0A);
                if (line == "--"){
#ifdef DEBUG
                  DEBUG_OUTPUT.println("Done Parsing POST");
#endif
                  break;
                }
                continue;
              } else {
                _uploadWriteByte(0x0D);
                _uploadWriteByte(0x0A);
                _uploadWriteByte((uint8_t)('-'));
                _uploadWriteByte((uint8_t)('-'));
                uint32_t i = 0;
                while(i < boundary.length()){
                  _uploadWriteByte(endBuf[i++]);
                }
                argByte = _uploadReadByte(client);
                goto readfile;
              }
            } else {
              _uploadWriteByte(0x0D);
              goto readfile;
            }
            break;
          }
        }
      }
    }

    int iarg;
    int totalArgs = ((32 - postArgsLen) < _currentArgCount)?(32 - postArgsLen):_currentArgCount;
    for (iarg = 0; iarg < totalArgs; iarg++){
      RequestArgument& arg = postArgs[postArgsLen++];
      arg.key = _currentArgs[iarg].key;
      arg.value = _currentArgs[iarg].value;
    }
    if (_currentArgs) delete[] _currentArgs;
    _currentArgs = new RequestArgument[postArgsLen];
    for (iarg = 0; iarg < postArgsLen; iarg++){
      RequestArgument& arg = _currentArgs[iarg];
      arg.key = postArgs[iarg].key;
      arg.value = postArgs[iarg].value;
    }
    _currentArgCount = iarg;
    if (postArgs) delete[] postArgs;
  }
}

<|endoftext|>


<commit_before>#include "ParserUtils.h"
#include "ValueParser.h"
#include "ExpressionParser.h"
#include "TransformParser.h"
#include "ColorParser.h"

#include <sstream>
#include <utility>
#include <unordered_map>
#include <mutex>

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

namespace carto { namespace mvt {
    vt::Color parseColor(const std::string& str) {
        std::string::const_iterator it = str.begin();
        std::string::const_iterator end = str.end();
        colorparserimpl::encoding::space_type space;
        unsigned int color = 0;
        bool result = boost::spirit::qi::phrase_parse(it, end, ColorParser<std::string::const_iterator>(), space, color);
        if (!result) {
            throw ParserException("Color parsing failed", str);
        }
        if (it != str.end()) {
            throw ParserException("Could not parse to the end of color, error at position " + boost::lexical_cast<std::string>(it - str.begin()), str);
        }
        return vt::Color(color);
    }

    vt::CompOp parseCompOp(const std::string& str) {
        static const std::unordered_map<std::string, vt::CompOp> compOpTable = {
            { "src",      vt::CompOp::SRC },
            { "src-over", vt::CompOp::SRC_OVER },
            { "src-in",   vt::CompOp::SRC_IN },
            { "src-atop", vt::CompOp::SRC_ATOP },
            { "dst",      vt::CompOp::DST },
            { "dst-over", vt::CompOp::DST_OVER },
            { "dst-in",   vt::CompOp::DST_IN },
            { "dst-atop", vt::CompOp::DST_ATOP },
            { "zero",     vt::CompOp::ZERO },
            { "plus",     vt::CompOp::PLUS },
            { "minus",    vt::CompOp::MINUS },
            { "multiply", vt::CompOp::MULTIPLY },
            { "darken",   vt::CompOp::DARKEN },
            { "lighten",  vt::CompOp::LIGHTEN }
        };

        auto it = compOpTable.find(str);
        if (it == compOpTable.end()) {
            throw ParserException("CompOp parsing failed", str);
        }
        return it->second;
    }

    vt::LabelOrientation parseLabelOrientation(const std::string& str) {
        static const std::unordered_map<std::string, vt::LabelOrientation> labelOrientationTable = {
            { "point",         vt::LabelOrientation::BILLBOARD2D },
            { "nutibillboard", vt::LabelOrientation::BILLBOARD3D },
            { "nutipoint",     vt::LabelOrientation::POINT },
            { "line",          vt::LabelOrientation::LINE }
        };

        auto it = labelOrientationTable.find(str);
        if (it == labelOrientationTable.end()) {
            throw ParserException("LabelOrientation parsing failed", str);
        }
        return it->second;
    }

    Value parseValue(const std::string& str) {
        std::string::const_iterator it = str.begin();
        std::string::const_iterator end = str.end();
        valparserimpl::encoding::space_type space;
        Value val;
        bool result = boost::spirit::qi::phrase_parse(it, end, ValueParser<std::string::const_iterator>(), space, val);
        if (!result) {
            throw ParserException("Value parsing failed", str);
        }
        if (it != str.end()) {
            throw ParserException("Could not parse to the end of value, error at position " + boost::lexical_cast<std::string>(it - str.begin()), str);
        }
        return val;
    }

    std::shared_ptr<Expression> parseExpression(const std::string& str) {
        static std::mutex exprCacheMutex;
        static std::unordered_map<std::string, std::shared_ptr<Expression>> exprCache;

        std::lock_guard<std::mutex> lock(exprCacheMutex);
        auto exprIt = exprCache.find(str);
        if (exprIt != exprCache.end()) {
            return exprIt->second;
        }

        std::string::const_iterator it = str.begin();
        std::string::const_iterator end = str.end();
        exprparserimpl::encoding::space_type space;
        std::shared_ptr<Expression> expr;
        bool result = boost::spirit::qi::phrase_parse(it, end, ExpressionParser<std::string::const_iterator>(), space, expr);
        if (!result) {
            throw ParserException("Expression parsing failed", str);
        }
        if (it != str.end()) {
            throw ParserException("Could not parse to the end of expression, error at position " + boost::lexical_cast<std::string>(it - str.begin()), str);
        }

        exprCache[str] = expr;
        return expr;
    }

    std::shared_ptr<Expression> parseStringExpression(const std::string& str) {
        static std::mutex exprCacheMutex;
        static std::unordered_map<std::string, std::shared_ptr<Expression>> exprCache;

        std::lock_guard<std::mutex> lock(exprCacheMutex);
        auto exprIt = exprCache.find(str);
        if (exprIt != exprCache.end()) {
            return exprIt->second;
        }

        std::string::const_iterator it = str.begin();
        std::string::const_iterator end = str.end();
        exprparserimpl::encoding::space_type space;
        std::shared_ptr<Expression> expr;
        bool result = boost::spirit::qi::phrase_parse(it, end, StringExpressionParser<std::string::const_iterator>(), space, expr);
        if (!result) {
            throw ParserException("String expression parsing failed", str);
        }
        if (it != str.end()) {
            throw ParserException("Could not parse to the end of string expression, error at position " + boost::lexical_cast<std::string>(it - str.begin()), str);
        }

        exprCache[str] = expr;
        return expr;
    }

    std::vector<std::shared_ptr<Transform> > parseTransformList(const std::string& str) {
        std::string::const_iterator it = str.begin();
        std::string::const_iterator end = str.end();
        transparserimpl::encoding::space_type space;
        std::vector<std::shared_ptr<Transform>> transforms;
        bool result = boost::spirit::qi::phrase_parse(it, end, TransformParser<std::string::const_iterator>() % ',', space, transforms);
        if (!result) {
            throw ParserException("Transform parsing failed", str);
        }
        if (it != str.end()) {
            throw ParserException("Could not parse to the end of transform, error at position " + boost::lexical_cast<std::string>(it - str.begin()), str);
        }
        return transforms;
    }
} }
<commit_msg>Forgot to push<commit_after>#include "ParserUtils.h"
#include "ValueParser.h"
#include "ExpressionParser.h"
#include "TransformParser.h"
#include "ColorParser.h"

#include <sstream>
#include <utility>
#include <unordered_map>
#include <mutex>

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

namespace carto { namespace mvt {
    vt::Color parseColor(const std::string& str) {
        std::string::const_iterator it = str.begin();
        std::string::const_iterator end = str.end();
        colorparserimpl::encoding::space_type space;
        unsigned int color = 0;
        bool result = boost::spirit::qi::phrase_parse(it, end, ColorParser<std::string::const_iterator>(), space, color);
        if (!result) {
            throw ParserException("Color parsing failed", str);
        }
        if (it != str.end()) {
            throw ParserException("Could not parse to the end of color, error at position " + boost::lexical_cast<std::string>(it - str.begin()), str);
        }
        return vt::Color(color);
    }

    vt::CompOp parseCompOp(const std::string& str) {
        static const std::unordered_map<std::string, vt::CompOp> compOpTable = {
            { "src",      vt::CompOp::SRC },
            { "src-over", vt::CompOp::SRC_OVER },
            { "src-in",   vt::CompOp::SRC_IN },
            { "src-atop", vt::CompOp::SRC_ATOP },
            { "dst",      vt::CompOp::DST },
            { "dst-over", vt::CompOp::DST_OVER },
            { "dst-in",   vt::CompOp::DST_IN },
            { "dst-atop", vt::CompOp::DST_ATOP },
            { "zero",     vt::CompOp::ZERO },
            { "plus",     vt::CompOp::PLUS },
            { "minus",    vt::CompOp::MINUS },
            { "multiply", vt::CompOp::MULTIPLY },
            { "darken",   vt::CompOp::DARKEN },
            { "lighten",  vt::CompOp::LIGHTEN }
        };

        auto it = compOpTable.find(str);
        if (it == compOpTable.end()) {
            throw ParserException("CompOp parsing failed", str);
        }
        return it->second;
    }

    vt::LabelOrientation parseLabelOrientation(const std::string& str) {
        static const std::unordered_map<std::string, vt::LabelOrientation> labelOrientationTable = {
            { "point",         vt::LabelOrientation::BILLBOARD_2D },
            { "nutibillboard", vt::LabelOrientation::BILLBOARD_3D },
            { "nutipoint",     vt::LabelOrientation::POINT },
            { "line",          vt::LabelOrientation::LINE }
        };

        auto it = labelOrientationTable.find(str);
        if (it == labelOrientationTable.end()) {
            throw ParserException("LabelOrientation parsing failed", str);
        }
        return it->second;
    }

    Value parseValue(const std::string& str) {
        std::string::const_iterator it = str.begin();
        std::string::const_iterator end = str.end();
        valparserimpl::encoding::space_type space;
        Value val;
        bool result = boost::spirit::qi::phrase_parse(it, end, ValueParser<std::string::const_iterator>(), space, val);
        if (!result) {
            throw ParserException("Value parsing failed", str);
        }
        if (it != str.end()) {
            throw ParserException("Could not parse to the end of value, error at position " + boost::lexical_cast<std::string>(it - str.begin()), str);
        }
        return val;
    }

    std::shared_ptr<Expression> parseExpression(const std::string& str) {
        static std::mutex exprCacheMutex;
        static std::unordered_map<std::string, std::shared_ptr<Expression>> exprCache;

        std::lock_guard<std::mutex> lock(exprCacheMutex);
        auto exprIt = exprCache.find(str);
        if (exprIt != exprCache.end()) {
            return exprIt->second;
        }

        std::string::const_iterator it = str.begin();
        std::string::const_iterator end = str.end();
        exprparserimpl::encoding::space_type space;
        std::shared_ptr<Expression> expr;
        bool result = boost::spirit::qi::phrase_parse(it, end, ExpressionParser<std::string::const_iterator>(), space, expr);
        if (!result) {
            throw ParserException("Expression parsing failed", str);
        }
        if (it != str.end()) {
            throw ParserException("Could not parse to the end of expression, error at position " + boost::lexical_cast<std::string>(it - str.begin()), str);
        }

        exprCache[str] = expr;
        return expr;
    }

    std::shared_ptr<Expression> parseStringExpression(const std::string& str) {
        static std::mutex exprCacheMutex;
        static std::unordered_map<std::string, std::shared_ptr<Expression>> exprCache;

        std::lock_guard<std::mutex> lock(exprCacheMutex);
        auto exprIt = exprCache.find(str);
        if (exprIt != exprCache.end()) {
            return exprIt->second;
        }

        std::string::const_iterator it = str.begin();
        std::string::const_iterator end = str.end();
        exprparserimpl::encoding::space_type space;
        std::shared_ptr<Expression> expr;
        bool result = boost::spirit::qi::phrase_parse(it, end, StringExpressionParser<std::string::const_iterator>(), space, expr);
        if (!result) {
            throw ParserException("String expression parsing failed", str);
        }
        if (it != str.end()) {
            throw ParserException("Could not parse to the end of string expression, error at position " + boost::lexical_cast<std::string>(it - str.begin()), str);
        }

        exprCache[str] = expr;
        return expr;
    }

    std::vector<std::shared_ptr<Transform> > parseTransformList(const std::string& str) {
        std::string::const_iterator it = str.begin();
        std::string::const_iterator end = str.end();
        transparserimpl::encoding::space_type space;
        std::vector<std::shared_ptr<Transform>> transforms;
        bool result = boost::spirit::qi::phrase_parse(it, end, TransformParser<std::string::const_iterator>() % ',', space, transforms);
        if (!result) {
            throw ParserException("Transform parsing failed", str);
        }
        if (it != str.end()) {
            throw ParserException("Could not parse to the end of transform, error at position " + boost::lexical_cast<std::string>(it - str.begin()), str);
        }
        return transforms;
    }
} }
<|endoftext|>