<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * 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.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_chart2.hxx"
#include "VLegendSymbolFactory.hxx"
#include "macros.hxx"
#include "PropertyMapper.hxx"
#include "ShapeFactory.hxx"
#include "ObjectIdentifier.hxx"
#include <com/sun/star/drawing/LineStyle.hpp>
#include <com/sun/star/chart2/Symbol.hpp>

// header for define DBG_ASSERT
#include <tools/debug.hxx>

using namespace ::com::sun::star;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Sequence;
using ::rtl::OUString;

namespace
{
void lcl_setPropetiesToShape(
    const Reference< beans::XPropertySet > & xProp,
    const Reference< drawing::XShape > & xShape,
    ::chart::VLegendSymbolFactory::tPropertyType ePropertyType )
{
    const ::chart::tPropertyNameMap & aFilledSeriesNameMap( ::chart::PropertyMapper::getPropertyNameMapForFilledSeriesProperties());
    const ::chart::tPropertyNameMap & aLineSeriesNameMap( ::chart::PropertyMapper::getPropertyNameMapForLineSeriesProperties());
    const ::chart::tPropertyNameMap & aLineNameMap( ::chart::PropertyMapper::getPropertyNameMapForLineProperties());
    const ::chart::tPropertyNameMap & aFillNameMap( ::chart::PropertyMapper::getPropertyNameMapForFillProperties());
    const ::chart::tPropertyNameMap & aFillLineNameMap( ::chart::PropertyMapper::getPropertyNameMapForFillAndLineProperties());

    Reference< beans::XPropertySet > xShapeProp( xShape, uno::UNO_QUERY );
    if( xProp.is() && xShapeProp.is() )
    {
        ::chart::tPropertyNameValueMap aValueMap;
        switch( ePropertyType )
        {
            case ::chart::VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES:
                ::chart::PropertyMapper::getValueMap( aValueMap, aFilledSeriesNameMap, xProp );
                break;
            case ::chart::VLegendSymbolFactory::PROP_TYPE_LINE_SERIES:
                ::chart::PropertyMapper::getValueMap( aValueMap, aLineSeriesNameMap, xProp );
                break;
            case ::chart::VLegendSymbolFactory::PROP_TYPE_LINE:
                ::chart::PropertyMapper::getValueMap( aValueMap, aLineNameMap, xProp );
                break;
            case ::chart::VLegendSymbolFactory::PROP_TYPE_FILL:
                ::chart::PropertyMapper::getValueMap( aValueMap, aFillNameMap, xProp );
                break;
            case ::chart::VLegendSymbolFactory::PROP_TYPE_FILL_AND_LINE:
                ::chart::PropertyMapper::getValueMap( aValueMap, aFillLineNameMap, xProp );
                break;
        }

        ::chart::tNameSequence aPropNames;
        ::chart::tAnySequence aPropValues;
        ::chart::PropertyMapper::getMultiPropertyListsFromValueMap( aPropNames, aPropValues, aValueMap );

        uno::Any* pLineWidthAny = ::chart::PropertyMapper::getValuePointer(aPropValues,aPropNames,C2U("LineWidth"));
        sal_Int32 nLineWidth = 0;
        if( pLineWidthAny && (*pLineWidthAny>>=nLineWidth) )
        {
            const sal_Int32 nMaxLineWidthForLegend = 50;/*1/100 mm*///todo: make this dependent from legend entry height
            if( nLineWidth>nMaxLineWidthForLegend )
                *pLineWidthAny = uno::makeAny( nMaxLineWidthForLegend );
        }

        ::chart::PropertyMapper::setMultiProperties( aPropNames, aPropValues, xShapeProp );
    }
}

} // anonymous namespace

namespace chart
{

Reference< drawing::XShape > VLegendSymbolFactory::createSymbol(
    const awt::Size& rEntryKeyAspectRatio,
    const Reference< drawing::XShapes > xSymbolContainer,
    LegendSymbolStyle eStyle,
    const Reference< lang::XMultiServiceFactory > & xShapeFactory,
    const Reference< beans::XPropertySet > & xLegendEntryProperties,
    tPropertyType ePropertyType, const uno::Any& rExplicitSymbol )
{
    Reference< drawing::XShape > xResult;

    if( ! (xSymbolContainer.is() && xShapeFactory.is()))
        return xResult;

    xResult.set( xShapeFactory->createInstance(
                     C2U( "com.sun.star.drawing.GroupShape" )), uno::UNO_QUERY );
    xSymbolContainer->add( xResult );
    Reference< drawing::XShapes > xResultGroup( xResult, uno::UNO_QUERY );
    if( ! xResultGroup.is())
        return xResult;

    bool bUseBox = false;

    // add an invisible square box to maintain aspect ratio
    Reference< drawing::XShape > xBound( ShapeFactory(xShapeFactory).createInvisibleRectangle(
                xResultGroup, rEntryKeyAspectRatio  ));

    // create symbol
    try
    {
        if( eStyle == LegendSymbolStyle_LINE )
        {
            Reference< drawing::XShape > xLine( xShapeFactory->createInstance(
                    C2U( "com.sun.star.drawing.LineShape" )), uno::UNO_QUERY );
            if( xLine.is())
            {
                xResultGroup->add( xLine );
                xLine->setSize(  awt::Size( rEntryKeyAspectRatio.Width, 0 ));
                xLine->setPosition( awt::Point( 0, rEntryKeyAspectRatio.Height/2 ));

                lcl_setPropetiesToShape( xLegendEntryProperties, xLine, ePropertyType );
            }

            Reference< drawing::XShape > xSymbol;
            const sal_Int32 nSize = std::min(rEntryKeyAspectRatio.Width,rEntryKeyAspectRatio.Height);
            chart2::Symbol aSymbol;
            if( rExplicitSymbol >>= aSymbol )
            {
                drawing::Direction3D aSymbolSize( nSize, nSize, 0 );
                drawing::Position3D aPos( rEntryKeyAspectRatio.Width/2, rEntryKeyAspectRatio.Height/2, 0 );
                ShapeFactory aFactory( xShapeFactory );
                if( aSymbol.Style == chart2::SymbolStyle_STANDARD )
                {
                    // take series color as fill color
                    xLegendEntryProperties->getPropertyValue( C2U("Color")) >>= aSymbol.FillColor;
                    // border of symbols always same as fill color
                    aSymbol.BorderColor = aSymbol.FillColor;

                    xSymbol.set( aFactory.createSymbol2D(
                                     xResultGroup,
                                     aPos,
                                     aSymbolSize,
                                     aSymbol.StandardSymbol,
                                     aSymbol.BorderColor,
                                     aSymbol.FillColor ));
                }
                else if( aSymbol.Style == chart2::SymbolStyle_GRAPHIC )
                {
                    xSymbol.set( aFactory.createGraphic2D(
                                     xResultGroup,
                                     aPos,
                                     aSymbolSize,
                                     aSymbol.Graphic ));
                }
                else if( aSymbol.Style == chart2::SymbolStyle_AUTO )
                {
                    DBG_ERROR("the given parameter is not allowed to contain an automatic symbol style");
                }
            }
        }
        else if( eStyle == LegendSymbolStyle_CIRCLE )
        {
            Reference< drawing::XShape > xShape( xShapeFactory->createInstance(
                C2U( "com.sun.star.drawing.EllipseShape" )), uno::UNO_QUERY );
            if( xShape.is() )
            {
                xResultGroup->add( xShape );
                sal_Int32 nSize = std::min( rEntryKeyAspectRatio.Width, rEntryKeyAspectRatio.Height );
                xShape->setSize( awt::Size( nSize, nSize ) );
                xShape->setPosition( awt::Point( rEntryKeyAspectRatio.Width/2-nSize/2, rEntryKeyAspectRatio.Height/2-nSize/2 ) );
                lcl_setPropetiesToShape( xLegendEntryProperties, xShape, ePropertyType ); // PROP_TYPE_FILLED_SERIES );
            }
        }
        else // eStyle == LegendSymbolStyle_BOX
        {
            Reference< drawing::XShape > xShape( xShapeFactory->createInstance(
                C2U( "com.sun.star.drawing.RectangleShape" )), uno::UNO_QUERY );
            if( xShape.is() )
            {
                xResultGroup->add( xShape );
                xShape->setSize( rEntryKeyAspectRatio );
                xShape->setPosition( awt::Point( 0, 0 ) );
                lcl_setPropetiesToShape( xLegendEntryProperties, xShape, ePropertyType ); // PROP_TYPE_FILLED_SERIES );
            }
        }
    }
    catch( uno::Exception & ex )
    {
        ASSERT_EXCEPTION( ex );
    }

    return xResult;
}

} //  namespace chart
<commit_msg>chart52: compiler warning<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * 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.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_chart2.hxx"
#include "VLegendSymbolFactory.hxx"
#include "macros.hxx"
#include "PropertyMapper.hxx"
#include "ShapeFactory.hxx"
#include "ObjectIdentifier.hxx"
#include <com/sun/star/drawing/LineStyle.hpp>
#include <com/sun/star/chart2/Symbol.hpp>

// header for define DBG_ASSERT
#include <tools/debug.hxx>

using namespace ::com::sun::star;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Sequence;
using ::rtl::OUString;

namespace
{
void lcl_setPropetiesToShape(
    const Reference< beans::XPropertySet > & xProp,
    const Reference< drawing::XShape > & xShape,
    ::chart::VLegendSymbolFactory::tPropertyType ePropertyType )
{
    const ::chart::tPropertyNameMap & aFilledSeriesNameMap( ::chart::PropertyMapper::getPropertyNameMapForFilledSeriesProperties());
    const ::chart::tPropertyNameMap & aLineSeriesNameMap( ::chart::PropertyMapper::getPropertyNameMapForLineSeriesProperties());
    const ::chart::tPropertyNameMap & aLineNameMap( ::chart::PropertyMapper::getPropertyNameMapForLineProperties());
    const ::chart::tPropertyNameMap & aFillNameMap( ::chart::PropertyMapper::getPropertyNameMapForFillProperties());
    const ::chart::tPropertyNameMap & aFillLineNameMap( ::chart::PropertyMapper::getPropertyNameMapForFillAndLineProperties());

    Reference< beans::XPropertySet > xShapeProp( xShape, uno::UNO_QUERY );
    if( xProp.is() && xShapeProp.is() )
    {
        ::chart::tPropertyNameValueMap aValueMap;
        switch( ePropertyType )
        {
            case ::chart::VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES:
                ::chart::PropertyMapper::getValueMap( aValueMap, aFilledSeriesNameMap, xProp );
                break;
            case ::chart::VLegendSymbolFactory::PROP_TYPE_LINE_SERIES:
                ::chart::PropertyMapper::getValueMap( aValueMap, aLineSeriesNameMap, xProp );
                break;
            case ::chart::VLegendSymbolFactory::PROP_TYPE_LINE:
                ::chart::PropertyMapper::getValueMap( aValueMap, aLineNameMap, xProp );
                break;
            case ::chart::VLegendSymbolFactory::PROP_TYPE_FILL:
                ::chart::PropertyMapper::getValueMap( aValueMap, aFillNameMap, xProp );
                break;
            case ::chart::VLegendSymbolFactory::PROP_TYPE_FILL_AND_LINE:
                ::chart::PropertyMapper::getValueMap( aValueMap, aFillLineNameMap, xProp );
                break;
        }

        ::chart::tNameSequence aPropNames;
        ::chart::tAnySequence aPropValues;
        ::chart::PropertyMapper::getMultiPropertyListsFromValueMap( aPropNames, aPropValues, aValueMap );

        uno::Any* pLineWidthAny = ::chart::PropertyMapper::getValuePointer(aPropValues,aPropNames,C2U("LineWidth"));
        sal_Int32 nLineWidth = 0;
        if( pLineWidthAny && (*pLineWidthAny>>=nLineWidth) )
        {
            const sal_Int32 nMaxLineWidthForLegend = 50;/*1/100 mm*///todo: make this dependent from legend entry height
            if( nLineWidth>nMaxLineWidthForLegend )
                *pLineWidthAny = uno::makeAny( nMaxLineWidthForLegend );
        }

        ::chart::PropertyMapper::setMultiProperties( aPropNames, aPropValues, xShapeProp );
    }
}

} // anonymous namespace

namespace chart
{

Reference< drawing::XShape > VLegendSymbolFactory::createSymbol(
    const awt::Size& rEntryKeyAspectRatio,
    const Reference< drawing::XShapes > xSymbolContainer,
    LegendSymbolStyle eStyle,
    const Reference< lang::XMultiServiceFactory > & xShapeFactory,
    const Reference< beans::XPropertySet > & xLegendEntryProperties,
    tPropertyType ePropertyType, const uno::Any& rExplicitSymbol )
{
    Reference< drawing::XShape > xResult;

    if( ! (xSymbolContainer.is() && xShapeFactory.is()))
        return xResult;

    xResult.set( xShapeFactory->createInstance(
                     C2U( "com.sun.star.drawing.GroupShape" )), uno::UNO_QUERY );
    xSymbolContainer->add( xResult );
    Reference< drawing::XShapes > xResultGroup( xResult, uno::UNO_QUERY );
    if( ! xResultGroup.is())
        return xResult;

    // add an invisible square box to maintain aspect ratio
    Reference< drawing::XShape > xBound( ShapeFactory(xShapeFactory).createInvisibleRectangle(
                xResultGroup, rEntryKeyAspectRatio  ));

    // create symbol
    try
    {
        if( eStyle == LegendSymbolStyle_LINE )
        {
            Reference< drawing::XShape > xLine( xShapeFactory->createInstance(
                    C2U( "com.sun.star.drawing.LineShape" )), uno::UNO_QUERY );
            if( xLine.is())
            {
                xResultGroup->add( xLine );
                xLine->setSize(  awt::Size( rEntryKeyAspectRatio.Width, 0 ));
                xLine->setPosition( awt::Point( 0, rEntryKeyAspectRatio.Height/2 ));

                lcl_setPropetiesToShape( xLegendEntryProperties, xLine, ePropertyType );
            }

            Reference< drawing::XShape > xSymbol;
            const sal_Int32 nSize = std::min(rEntryKeyAspectRatio.Width,rEntryKeyAspectRatio.Height);
            chart2::Symbol aSymbol;
            if( rExplicitSymbol >>= aSymbol )
            {
                drawing::Direction3D aSymbolSize( nSize, nSize, 0 );
                drawing::Position3D aPos( rEntryKeyAspectRatio.Width/2, rEntryKeyAspectRatio.Height/2, 0 );
                ShapeFactory aFactory( xShapeFactory );
                if( aSymbol.Style == chart2::SymbolStyle_STANDARD )
                {
                    // take series color as fill color
                    xLegendEntryProperties->getPropertyValue( C2U("Color")) >>= aSymbol.FillColor;
                    // border of symbols always same as fill color
                    aSymbol.BorderColor = aSymbol.FillColor;

                    xSymbol.set( aFactory.createSymbol2D(
                                     xResultGroup,
                                     aPos,
                                     aSymbolSize,
                                     aSymbol.StandardSymbol,
                                     aSymbol.BorderColor,
                                     aSymbol.FillColor ));
                }
                else if( aSymbol.Style == chart2::SymbolStyle_GRAPHIC )
                {
                    xSymbol.set( aFactory.createGraphic2D(
                                     xResultGroup,
                                     aPos,
                                     aSymbolSize,
                                     aSymbol.Graphic ));
                }
                else if( aSymbol.Style == chart2::SymbolStyle_AUTO )
                {
                    DBG_ERROR("the given parameter is not allowed to contain an automatic symbol style");
                }
            }
        }
        else if( eStyle == LegendSymbolStyle_CIRCLE )
        {
            Reference< drawing::XShape > xShape( xShapeFactory->createInstance(
                C2U( "com.sun.star.drawing.EllipseShape" )), uno::UNO_QUERY );
            if( xShape.is() )
            {
                xResultGroup->add( xShape );
                sal_Int32 nSize = std::min( rEntryKeyAspectRatio.Width, rEntryKeyAspectRatio.Height );
                xShape->setSize( awt::Size( nSize, nSize ) );
                xShape->setPosition( awt::Point( rEntryKeyAspectRatio.Width/2-nSize/2, rEntryKeyAspectRatio.Height/2-nSize/2 ) );
                lcl_setPropetiesToShape( xLegendEntryProperties, xShape, ePropertyType ); // PROP_TYPE_FILLED_SERIES );
            }
        }
        else // eStyle == LegendSymbolStyle_BOX
        {
            Reference< drawing::XShape > xShape( xShapeFactory->createInstance(
                C2U( "com.sun.star.drawing.RectangleShape" )), uno::UNO_QUERY );
            if( xShape.is() )
            {
                xResultGroup->add( xShape );
                xShape->setSize( rEntryKeyAspectRatio );
                xShape->setPosition( awt::Point( 0, 0 ) );
                lcl_setPropetiesToShape( xLegendEntryProperties, xShape, ePropertyType ); // PROP_TYPE_FILLED_SERIES );
            }
        }
    }
    catch( uno::Exception & ex )
    {
        ASSERT_EXCEPTION( ex );
    }

    return xResult;
}

} //  namespace chart
<|endoftext|>


<commit_before>#include "server.h"
static messageQueue<msg>m_queue;
static std::map<SOCKET, user>socket_user;
static std::vector<user>users;
static std::atomic<uint32_t>clientNums;
bool server::init() {
    m_hostname = "127.0.0.1";
    m_port = 20000;
    WSADATA wsData;
    WORD sockVersion = MAKEWORD(2, 2);
    if (WSAStartup(sockVersion, &wsData) != 0) {
        std::cout << "start up error\n";
        return false;
    }
    m_listen = socket(PF_INET, SOCK_STREAM, 0);
    if (m_listen == INVALID_SOCKET) {
        std::cout << "can't init listen\n";
        return false;
    }
    m_hent = gethostbyname(m_hostname);
    if (!m_hent) {
        std::cout << "can't get host name\n";
        return false;
    }
    m_serverAddr.sin_family = PF_INET;
    m_serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    m_serverAddr.sin_port = htons(m_port);
    if (bind(m_listen, (const sockaddr *)&m_serverAddr,
             sizeof(m_serverAddr)) == INVALID_SOCKET) {
        std::cout << ("can't bind listen port\n");
        return false;
    }
    if (listen(m_listen, SOMAXCONN) == INVALID_SOCKET) {
        printf("can't listen\n");
        return false;
    }
    return true;
}

void server::send_data() {
    while (true) {
        while (!m_queue.empty()) {
            auto message = m_queue.front();
            m_queue.pop();
            auto data = message.data;
            int len = std::strlen(data);
            for (auto &&i : users) {
                if (i.socket != message.origin)
                    send(i.socket, data, len + 1, 0);
            }
            delete[] message.data;
        }
        std::this_thread::sleep_for(std::chrono::microseconds(1));
    }
}

void server::revc_data(SOCKET socket) {
    while (true) {
        char buffer[ 4096 ] = { 0 };
        int recvinfo = recv(socket, buffer, sizeof(buffer), 0);
        if (recvinfo < 1) {
            clientNums--;
            std::cout << socket_user[ socket ].ip << " disconnect\n";
            show_client();
            return;
        }
        //std::cout <<recvinfo<< '\n';
        auto len = std::strlen(buffer);
        if (len == 0)continue;
        msg m;
        m.origin = socket;
        m.data = new char[ len + 1 ];
        std::strcpy(m.data, buffer);
        m_queue.push(m);
        std::cout << socket_user[ socket ].ip << " : " << buffer << '\n';
    }

}

void server::alive() { }

void server::show_client() {
    std::cout << "client : " << clientNums << '\n';
}

server::server() noexcept {
    if (!init())
        std::cout << "\nsome error\n";
    else
        std::cout << "\nstart server\n";
}

server::~server() {
    WSACleanup();
    std::cout << "server close";
}

void server::loop(bool multithread) {
    SOCKET acceptfd;
    sockaddr_in clientAddr;
    int nSize;
    clientNums = 0;
    std::thread t_send(send_data);
    t_send.detach();
    std::thread t[ m_clients + 1 ];
    std::cout << "server listen :" << m_hostname << " port :" << m_port << '\n';
    while (clientNums < m_clients) {
        show_client();
        nSize = sizeof(clientAddr);
        acceptfd = accept(m_listen, (sockaddr *)&clientAddr, &nSize);
        if (acceptfd == INVALID_SOCKET) {
            std::cout << "error :" << WSAGetLastError() << '\n';
            return;
        }
        std::cout << "Accepted from client:" << inet_ntoa(clientAddr.sin_addr) << '\n';
        user client("unnamed", inet_ntoa(clientAddr.sin_addr));
        client.socket = acceptfd;
        socket_user[ acceptfd ] = client;
        users.emplace_back(client);
        if (multithread) {
            t[ clientNums ] = std::thread(revc_data, acceptfd);
        } else {
            revc_data(acceptfd);
        }
        clientNums++;
    }
}

<commit_msg>fixed con&discon bug<commit_after>#include "server.h"
static messageQueue<msg>m_queue;
static std::map<SOCKET, user>socket_user;
static std::atomic<uint32_t>clientNums;
bool server::init() {
    m_hostname = "127.0.0.1";
    m_port = 20000;
    WSADATA wsData;
    WORD sockVersion = MAKEWORD(2, 2);
    if (WSAStartup(sockVersion, &wsData) != 0) {
        std::cout << "start up error\n";
        return false;
    }
    m_listen = socket(PF_INET, SOCK_STREAM, 0);
    if (m_listen == INVALID_SOCKET) {
        std::cout << "can't init listen\n";
        return false;
    }
    m_hent = gethostbyname(m_hostname);
    if (!m_hent) {
        std::cout << "can't get host name\n";
        return false;
    }
    m_serverAddr.sin_family = PF_INET;
    m_serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    m_serverAddr.sin_port = htons(m_port);
    if (bind(m_listen, (const sockaddr *)&m_serverAddr,
             sizeof(m_serverAddr)) == INVALID_SOCKET) {
        std::cout << ("can't bind listen port\n");
        return false;
    }
    if (listen(m_listen, SOMAXCONN) == INVALID_SOCKET) {
        printf("can't listen\n");
        return false;
    }
    return true;
}

void server::send_data() {
    while (true) {
        while (!m_queue.empty()) {
            auto message = m_queue.front();
            m_queue.pop();
            auto data = message.data;
            int len = std::strlen(data);
            for (auto &&i : socket_user) {
                if (i.first!= message.origin)
                    send(i.first, data, len + 1, 0);
            }
            delete[] message.data;
        }
        std::this_thread::sleep_for(std::chrono::microseconds(1));
    }
}

void server::revc_data(SOCKET socket) {
    while (true) {
        char buffer[ 4096 ] = { 0 };
        int recvinfo = recv(socket, buffer, sizeof(buffer), 0);
        if (recvinfo < 1) {
            clientNums--;
            std::cout << socket_user[ socket ].ip << " disconnect\n";
            socket_user.erase(socket);
            show_client();
            return;
        }
        //std::cout <<recvinfo<< '\n';
        auto len = std::strlen(buffer);
        if (len == 0)continue;
        msg m;
        m.origin = socket;
        m.data = new char[ len + 1 ];
        std::strcpy(m.data, buffer);
        m_queue.push(m);
        std::cout << socket_user[ socket ].ip << " : " << buffer << '\n';
    }

}

void server::alive() { }

void server::show_client() {
    std::cout << "client : " << clientNums << '\n';
}

server::server() noexcept {
    if (!init())
        std::cout << "\nsome error\n";
    else
        std::cout << "\nstart server\n";
}

server::~server() {
    WSACleanup();
    std::cout << "server close";
}

void server::loop(bool multithread) {
    SOCKET acceptfd;
    sockaddr_in clientAddr;
    int nSize;
    clientNums = 0;
    std::thread t_send(send_data);
    t_send.detach();
    std::thread t[ m_clients + 1 ];
    std::cout << "server listen :" << m_hostname << " port :" << m_port << '\n';
    while (clientNums < m_clients) {
        show_client();
        nSize = sizeof(clientAddr);
        acceptfd = accept(m_listen, (sockaddr *)&clientAddr, &nSize);
        if (acceptfd == INVALID_SOCKET) {
            std::cout << "error :" << WSAGetLastError() << '\n';
            return;
        }
        std::cout << "Accepted from client:" << inet_ntoa(clientAddr.sin_addr) << '\n';
        user client("unnamed", inet_ntoa(clientAddr.sin_addr));
        client.socket = acceptfd;
        socket_user[ acceptfd ] = client;
        if (multithread) {
            t[ clientNums ] = std::thread(revc_data, acceptfd);
        } else {
            revc_data(acceptfd);
        }
        clientNums++;
    }
}

<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/url_request/url_request_new_ftp_job.h"

#include "base/compiler_specific.h"
#include "base/file_version_info.h"
#include "base/message_loop.h"
#include "base/sys_string_conversions.h"
#include "net/base/escape.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/ftp/ftp_directory_parser.h"
#include "net/ftp/ftp_response_info.h"
#include "net/ftp/ftp_transaction_factory.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_error_job.h"
#include "unicode/ucsdet.h"

namespace {

// A very simple-minded character encoding detection.
// TODO(jungshik): We can apply more heuristics here (e.g. using various hints
// like TLD, the UI language/default encoding of a client, etc). In that case,
// this should be pulled out of here and moved somewhere in base because there
// can be other use cases.
std::string DetectEncoding(const char*input, size_t len) {
  if (IsStringASCII(std::string(input, len)))
    return std::string();
  UErrorCode status = U_ZERO_ERROR;
  UCharsetDetector* detector = ucsdet_open(&status);
  ucsdet_setText(detector, input, static_cast<int32_t>(len), &status);
  const UCharsetMatch* match = ucsdet_detect(detector, &status);
  const char* encoding = ucsdet_getName(match, &status);
  // Should we check the quality of the match? A rather arbitrary number is
  // assigned by ICU and it's hard to come up with a lower limit.
  if (U_FAILURE(status))
    return std::string();
  return encoding;
}

string16 RawByteSequenceToFilename(const char* raw_filename,
                                   const std::string& encoding) {
  if (encoding.empty())
    return ASCIIToUTF16(raw_filename);

  // Try the detected encoding before falling back to the native codepage.
  // Using the native codepage does not make much sense, but we don't have
  // much else to resort to.
  string16 filename;
  if (!CodepageToUTF16(raw_filename, encoding.c_str(),
                       OnStringUtilConversionError::SUBSTITUTE, &filename))
    filename = WideToUTF16Hack(base::SysNativeMBToWide(raw_filename));
  return filename;
}

}  // namespace

URLRequestNewFtpJob::URLRequestNewFtpJob(URLRequest* request)
    : URLRequestJob(request),
      server_auth_state_(net::AUTH_STATE_DONT_NEED_AUTH),
      response_info_(NULL),
      dir_listing_buf_size_(0),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          start_callback_(this, &URLRequestNewFtpJob::OnStartCompleted)),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          read_callback_(this, &URLRequestNewFtpJob::OnReadCompleted)),
      read_in_progress_(false),
      context_(request->context()) {
}

URLRequestNewFtpJob::~URLRequestNewFtpJob() {
}

// static
URLRequestJob* URLRequestNewFtpJob::Factory(URLRequest* request,
                                            const std::string& scheme) {
  DCHECK(scheme == "ftp");

  if (request->url().has_port() &&
      !net::IsPortAllowedByFtp(request->url().IntPort()))
    return new URLRequestErrorJob(request, net::ERR_UNSAFE_PORT);

  DCHECK(request->context());
  DCHECK(request->context()->ftp_transaction_factory());
  return new URLRequestNewFtpJob(request);
}

void URLRequestNewFtpJob::Start() {
  DCHECK(!transaction_.get());
  request_info_.url = request_->url();
  StartTransaction();
}

void URLRequestNewFtpJob::Kill() {
  if (!transaction_.get())
    return;
  DestroyTransaction();
  URLRequestJob::Kill();
}

bool URLRequestNewFtpJob::ReadRawData(net::IOBuffer* buf,
                                      int buf_size,
                                      int *bytes_read) {
  DCHECK_NE(buf_size, 0);
  DCHECK(bytes_read);
  DCHECK(!read_in_progress_);
  if (response_info_ == NULL) {
     response_info_ = transaction_->GetResponseInfo();
    if (response_info_->is_directory_listing) {
      std::string escaped_path =
          UnescapeURLComponent(request_->url().path(),
          UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS);
      string16 path_utf16;
      // Per RFC 2640, FTP servers should use UTF-8 or its proper subset ASCII,
      // but many old FTP servers use legacy encodings. Try UTF-8 first and
      // detect the encoding.
      if (IsStringUTF8(escaped_path)) {
        path_utf16 = UTF8ToUTF16(escaped_path);
      } else {
        std::string encoding = DetectEncoding(escaped_path.c_str(),
                                              escaped_path.size());
        // Try the detected encoding. If it fails, resort to the
        // OS native encoding.
        if (encoding.empty() ||
            !CodepageToUTF16(escaped_path, encoding.c_str(),
                             OnStringUtilConversionError::SUBSTITUTE,
                             &path_utf16))
          path_utf16 = WideToUTF16Hack(base::SysNativeMBToWide(escaped_path));
      }

      directory_html_ = net::GetDirectoryListingHeader(path_utf16);
      // If this isn't top level directory (i.e. the path isn't "/",)
      // add a link to the parent directory.
      if (request_->url().path().length() > 1)
        directory_html_.append(
            net::GetDirectoryListingEntry(ASCIIToUTF16(".."),
                                          std::string(),
                                          false, 0,
                                          base::Time()));
    }
  }
  if (!directory_html_.empty()) {
    size_t bytes_to_copy = std::min(static_cast<size_t>(buf_size),
                                    directory_html_.size());
    memcpy(buf->data(), directory_html_.c_str(), bytes_to_copy);
    *bytes_read = bytes_to_copy;
    directory_html_.erase(0, bytes_to_copy);
    return true;
  }

  int rv = transaction_->Read(buf, buf_size, &read_callback_);
  if (rv >= 0) {
    if (response_info_->is_directory_listing) {
      *bytes_read = ProcessFtpDir(buf, buf_size, rv);
    } else {
      *bytes_read = rv;
    }
    return true;
  }

  if (response_info_->is_directory_listing) {
    dir_listing_buf_ = buf;
    dir_listing_buf_size_ = buf_size;
  }

  if (rv == net::ERR_IO_PENDING) {
    read_in_progress_ = true;
    SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
  } else {
    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
  }
  return false;
}

int URLRequestNewFtpJob::ProcessFtpDir(net::IOBuffer *buf,
                                       int buf_size,
                                       int bytes_read) {
  std::string file_entry;
  std::string line;
  buf->data()[bytes_read] = 0;

  // If all we've seen so far is ASCII, encoding_ is empty. Try to detect the
  // encoding. We don't do the separate UTF-8 check here because the encoding
  // detection with a longer chunk (as opposed to the relatively short path
  // component of the url) is unlikely to mistake UTF-8 for a legacy encoding.
  // If it turns out to be wrong, a separate UTF-8 check has to be added.
  //
  // TODO(jungshik): UTF-8 has to be 'enforced' without any heuristics when
  // we're talking to an FTP server compliant to RFC 2640 (that is, its response
  // to FEAT command includes 'UTF8').
  // See http://wiki.filezilla-project.org/Character_Set
  if (encoding_.empty())
    encoding_ = DetectEncoding(buf->data(), bytes_read);

  int64 file_size;
  std::istringstream iss(buf->data());
  while (getline(iss, line)) {
    struct net::ListState state;
    struct net::ListResult result;
    base::Time::Exploded et;
    std::replace(line.begin(), line.end(), '\r', '\0');
    net::LineType line_type = ParseFTPLine(line.c_str(), &state, &result);
    switch (line_type) {
      case net::FTP_TYPE_DIRECTORY:
        // TODO(ibrar): There is some problem in ParseFTPLine function or
        // in conversion between tm and base::Time::Exploded.
        // It returns wrong date/time (Differnce is 1 day and 17 Hours).
        memset(&et, 0, sizeof(base::Time::Exploded));
        et.second = result.fe_time.tm_sec;
        et.minute = result.fe_time.tm_min;
        et.hour = result.fe_time.tm_hour;
        et.day_of_month = result.fe_time.tm_mday;
        et.month = result.fe_time.tm_mon + 1;
        et.year = result.fe_time.tm_year + 1900;
        et.day_of_week = result.fe_time.tm_wday;

        file_entry.append(net::GetDirectoryListingEntry(
            RawByteSequenceToFilename(result.fe_fname, encoding_),
            result.fe_fname, true, 0, base::Time::FromLocalExploded(et)));
        break;
      case net::FTP_TYPE_FILE:
        // TODO(ibrar): There should be a way to create a Time object based
        // on "tm" structure. This will remove bunch of line of code to convert
        // tm to Time object.
        memset(&et, 0, sizeof(base::Time::Exploded));
        et.second = result.fe_time.tm_sec;
        et.minute = result.fe_time.tm_min;
        et.hour = result.fe_time.tm_hour;
        et.day_of_month = result.fe_time.tm_mday;
        et.month = result.fe_time.tm_mon + 1;
        et.year = result.fe_time.tm_year + 1900;
        et.day_of_week = result.fe_time.tm_wday;
        // TODO(ibrar): There is some problem in ParseFTPLine function or
        // in conversion between tm and base::Time::Exploded.
        // It returns wrong date/time (Differnce is 1 day and 17 Hours).
        if (StringToInt64(result.fe_size, &file_size))
          file_entry.append(net::GetDirectoryListingEntry(
              RawByteSequenceToFilename(result.fe_fname, encoding_),
              result.fe_fname, false, file_size,
              base::Time::FromLocalExploded(et)));
        break;
      case net::FTP_TYPE_SYMLINK:
      case net::FTP_TYPE_JUNK:
      case net::FTP_TYPE_COMMENT:
        break;
      default:
        break;
    }
  }
  directory_html_.append(file_entry);
  size_t bytes_to_copy = std::min(static_cast<size_t>(buf_size),
                                  directory_html_.length());
  if (bytes_to_copy) {
    memcpy(buf->data(), directory_html_.c_str(), bytes_to_copy);
    directory_html_.erase(0, bytes_to_copy);
  }
  return bytes_to_copy;
}

void URLRequestNewFtpJob::OnStartCompleted(int result) {
  // If the request was destroyed, then there is no more work to do.
  if (!request_ || !request_->delegate())
    return;
  // If the transaction was destroyed, then the job was cancelled, and
  // we can just ignore this notification.
  if (!transaction_.get())
    return;
  // Clear the IO_PENDING status
  SetStatus(URLRequestStatus());
  if (result == net::OK) {
    URLRequestJob::NotifyHeadersComplete();
  } else {
    NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
  }
}

void URLRequestNewFtpJob::OnReadCompleted(int result) {
  read_in_progress_ = false;
  if (result == 0) {
    NotifyDone(URLRequestStatus());
  } else if (result < 0) {
    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result));
  } else {
    // TODO(ibrar): find the best place to delete dir_listing_buf_
    // Filter for Directory listing.
    if (response_info_->is_directory_listing)
      result = ProcessFtpDir(dir_listing_buf_, dir_listing_buf_size_, result);

    // Clear the IO_PENDING status
    SetStatus(URLRequestStatus());
  }
  NotifyReadComplete(result);
}

void URLRequestNewFtpJob::StartTransaction() {
  // Create a transaction.
  DCHECK(!transaction_.get());
  DCHECK(request_->context());
  DCHECK(request_->context()->ftp_transaction_factory());

  transaction_.reset(
  request_->context()->ftp_transaction_factory()->CreateTransaction());

  // No matter what, we want to report our status as IO pending since we will
  // be notifying our consumer asynchronously via OnStartCompleted.
  SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
  int rv;
  if (transaction_.get()) {
    rv = transaction_->Start(&request_info_, &start_callback_);
    if (rv == net::ERR_IO_PENDING)
      return;
  } else {
    rv = net::ERR_FAILED;
  }
  // The transaction started synchronously, but we need to notify the
  // URLRequest delegate via the message loop.
  MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
      this, &URLRequestNewFtpJob::OnStartCompleted, rv));
}

void URLRequestNewFtpJob::DestroyTransaction() {
  DCHECK(transaction_.get());

  transaction_.reset();
  response_info_ = NULL;
}
<commit_msg>Fix a typo pointed out by wtc after I checked in.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/url_request/url_request_new_ftp_job.h"

#include "base/compiler_specific.h"
#include "base/file_version_info.h"
#include "base/message_loop.h"
#include "base/sys_string_conversions.h"
#include "net/base/escape.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/ftp/ftp_directory_parser.h"
#include "net/ftp/ftp_response_info.h"
#include "net/ftp/ftp_transaction_factory.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_error_job.h"
#include "unicode/ucsdet.h"

namespace {

// A very simple-minded character encoding detection.
// TODO(jungshik): We can apply more heuristics here (e.g. using various hints
// like TLD, the UI language/default encoding of a client, etc). In that case,
// this should be pulled out of here and moved somewhere in base because there
// can be other use cases.
std::string DetectEncoding(const char* input, size_t len) {
  if (IsStringASCII(std::string(input, len)))
    return std::string();
  UErrorCode status = U_ZERO_ERROR;
  UCharsetDetector* detector = ucsdet_open(&status);
  ucsdet_setText(detector, input, static_cast<int32_t>(len), &status);
  const UCharsetMatch* match = ucsdet_detect(detector, &status);
  const char* encoding = ucsdet_getName(match, &status);
  // Should we check the quality of the match? A rather arbitrary number is
  // assigned by ICU and it's hard to come up with a lower limit.
  if (U_FAILURE(status))
    return std::string();
  return encoding;
}

string16 RawByteSequenceToFilename(const char* raw_filename,
                                   const std::string& encoding) {
  if (encoding.empty())
    return ASCIIToUTF16(raw_filename);

  // Try the detected encoding before falling back to the native codepage.
  // Using the native codepage does not make much sense, but we don't have
  // much else to resort to.
  string16 filename;
  if (!CodepageToUTF16(raw_filename, encoding.c_str(),
                       OnStringUtilConversionError::SUBSTITUTE, &filename))
    filename = WideToUTF16Hack(base::SysNativeMBToWide(raw_filename));
  return filename;
}

}  // namespace

URLRequestNewFtpJob::URLRequestNewFtpJob(URLRequest* request)
    : URLRequestJob(request),
      server_auth_state_(net::AUTH_STATE_DONT_NEED_AUTH),
      response_info_(NULL),
      dir_listing_buf_size_(0),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          start_callback_(this, &URLRequestNewFtpJob::OnStartCompleted)),
      ALLOW_THIS_IN_INITIALIZER_LIST(
          read_callback_(this, &URLRequestNewFtpJob::OnReadCompleted)),
      read_in_progress_(false),
      context_(request->context()) {
}

URLRequestNewFtpJob::~URLRequestNewFtpJob() {
}

// static
URLRequestJob* URLRequestNewFtpJob::Factory(URLRequest* request,
                                            const std::string& scheme) {
  DCHECK(scheme == "ftp");

  if (request->url().has_port() &&
      !net::IsPortAllowedByFtp(request->url().IntPort()))
    return new URLRequestErrorJob(request, net::ERR_UNSAFE_PORT);

  DCHECK(request->context());
  DCHECK(request->context()->ftp_transaction_factory());
  return new URLRequestNewFtpJob(request);
}

void URLRequestNewFtpJob::Start() {
  DCHECK(!transaction_.get());
  request_info_.url = request_->url();
  StartTransaction();
}

void URLRequestNewFtpJob::Kill() {
  if (!transaction_.get())
    return;
  DestroyTransaction();
  URLRequestJob::Kill();
}

bool URLRequestNewFtpJob::ReadRawData(net::IOBuffer* buf,
                                      int buf_size,
                                      int *bytes_read) {
  DCHECK_NE(buf_size, 0);
  DCHECK(bytes_read);
  DCHECK(!read_in_progress_);
  if (response_info_ == NULL) {
     response_info_ = transaction_->GetResponseInfo();
    if (response_info_->is_directory_listing) {
      std::string escaped_path =
          UnescapeURLComponent(request_->url().path(),
          UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS);
      string16 path_utf16;
      // Per RFC 2640, FTP servers should use UTF-8 or its proper subset ASCII,
      // but many old FTP servers use legacy encodings. Try UTF-8 first and
      // detect the encoding.
      if (IsStringUTF8(escaped_path)) {
        path_utf16 = UTF8ToUTF16(escaped_path);
      } else {
        std::string encoding = DetectEncoding(escaped_path.c_str(),
                                              escaped_path.size());
        // Try the detected encoding. If it fails, resort to the
        // OS native encoding.
        if (encoding.empty() ||
            !CodepageToUTF16(escaped_path, encoding.c_str(),
                             OnStringUtilConversionError::SUBSTITUTE,
                             &path_utf16))
          path_utf16 = WideToUTF16Hack(base::SysNativeMBToWide(escaped_path));
      }

      directory_html_ = net::GetDirectoryListingHeader(path_utf16);
      // If this isn't top level directory (i.e. the path isn't "/",)
      // add a link to the parent directory.
      if (request_->url().path().length() > 1)
        directory_html_.append(
            net::GetDirectoryListingEntry(ASCIIToUTF16(".."),
                                          std::string(),
                                          false, 0,
                                          base::Time()));
    }
  }
  if (!directory_html_.empty()) {
    size_t bytes_to_copy = std::min(static_cast<size_t>(buf_size),
                                    directory_html_.size());
    memcpy(buf->data(), directory_html_.c_str(), bytes_to_copy);
    *bytes_read = bytes_to_copy;
    directory_html_.erase(0, bytes_to_copy);
    return true;
  }

  int rv = transaction_->Read(buf, buf_size, &read_callback_);
  if (rv >= 0) {
    if (response_info_->is_directory_listing) {
      *bytes_read = ProcessFtpDir(buf, buf_size, rv);
    } else {
      *bytes_read = rv;
    }
    return true;
  }

  if (response_info_->is_directory_listing) {
    dir_listing_buf_ = buf;
    dir_listing_buf_size_ = buf_size;
  }

  if (rv == net::ERR_IO_PENDING) {
    read_in_progress_ = true;
    SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
  } else {
    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
  }
  return false;
}

int URLRequestNewFtpJob::ProcessFtpDir(net::IOBuffer *buf,
                                       int buf_size,
                                       int bytes_read) {
  std::string file_entry;
  std::string line;
  buf->data()[bytes_read] = 0;

  // If all we've seen so far is ASCII, encoding_ is empty. Try to detect the
  // encoding. We don't do the separate UTF-8 check here because the encoding
  // detection with a longer chunk (as opposed to the relatively short path
  // component of the url) is unlikely to mistake UTF-8 for a legacy encoding.
  // If it turns out to be wrong, a separate UTF-8 check has to be added.
  //
  // TODO(jungshik): UTF-8 has to be 'enforced' without any heuristics when
  // we're talking to an FTP server compliant to RFC 2640 (that is, its response
  // to FEAT command includes 'UTF8').
  // See http://wiki.filezilla-project.org/Character_Set
  if (encoding_.empty())
    encoding_ = DetectEncoding(buf->data(), bytes_read);

  int64 file_size;
  std::istringstream iss(buf->data());
  while (getline(iss, line)) {
    struct net::ListState state;
    struct net::ListResult result;
    base::Time::Exploded et;
    std::replace(line.begin(), line.end(), '\r', '\0');
    net::LineType line_type = ParseFTPLine(line.c_str(), &state, &result);
    switch (line_type) {
      case net::FTP_TYPE_DIRECTORY:
        // TODO(ibrar): There is some problem in ParseFTPLine function or
        // in conversion between tm and base::Time::Exploded.
        // It returns wrong date/time (Differnce is 1 day and 17 Hours).
        memset(&et, 0, sizeof(base::Time::Exploded));
        et.second = result.fe_time.tm_sec;
        et.minute = result.fe_time.tm_min;
        et.hour = result.fe_time.tm_hour;
        et.day_of_month = result.fe_time.tm_mday;
        et.month = result.fe_time.tm_mon + 1;
        et.year = result.fe_time.tm_year + 1900;
        et.day_of_week = result.fe_time.tm_wday;

        file_entry.append(net::GetDirectoryListingEntry(
            RawByteSequenceToFilename(result.fe_fname, encoding_),
            result.fe_fname, true, 0, base::Time::FromLocalExploded(et)));
        break;
      case net::FTP_TYPE_FILE:
        // TODO(ibrar): There should be a way to create a Time object based
        // on "tm" structure. This will remove bunch of line of code to convert
        // tm to Time object.
        memset(&et, 0, sizeof(base::Time::Exploded));
        et.second = result.fe_time.tm_sec;
        et.minute = result.fe_time.tm_min;
        et.hour = result.fe_time.tm_hour;
        et.day_of_month = result.fe_time.tm_mday;
        et.month = result.fe_time.tm_mon + 1;
        et.year = result.fe_time.tm_year + 1900;
        et.day_of_week = result.fe_time.tm_wday;
        // TODO(ibrar): There is some problem in ParseFTPLine function or
        // in conversion between tm and base::Time::Exploded.
        // It returns wrong date/time (Differnce is 1 day and 17 Hours).
        if (StringToInt64(result.fe_size, &file_size))
          file_entry.append(net::GetDirectoryListingEntry(
              RawByteSequenceToFilename(result.fe_fname, encoding_),
              result.fe_fname, false, file_size,
              base::Time::FromLocalExploded(et)));
        break;
      case net::FTP_TYPE_SYMLINK:
      case net::FTP_TYPE_JUNK:
      case net::FTP_TYPE_COMMENT:
        break;
      default:
        break;
    }
  }
  directory_html_.append(file_entry);
  size_t bytes_to_copy = std::min(static_cast<size_t>(buf_size),
                                  directory_html_.length());
  if (bytes_to_copy) {
    memcpy(buf->data(), directory_html_.c_str(), bytes_to_copy);
    directory_html_.erase(0, bytes_to_copy);
  }
  return bytes_to_copy;
}

void URLRequestNewFtpJob::OnStartCompleted(int result) {
  // If the request was destroyed, then there is no more work to do.
  if (!request_ || !request_->delegate())
    return;
  // If the transaction was destroyed, then the job was cancelled, and
  // we can just ignore this notification.
  if (!transaction_.get())
    return;
  // Clear the IO_PENDING status
  SetStatus(URLRequestStatus());
  if (result == net::OK) {
    URLRequestJob::NotifyHeadersComplete();
  } else {
    NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
  }
}

void URLRequestNewFtpJob::OnReadCompleted(int result) {
  read_in_progress_ = false;
  if (result == 0) {
    NotifyDone(URLRequestStatus());
  } else if (result < 0) {
    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result));
  } else {
    // TODO(ibrar): find the best place to delete dir_listing_buf_
    // Filter for Directory listing.
    if (response_info_->is_directory_listing)
      result = ProcessFtpDir(dir_listing_buf_, dir_listing_buf_size_, result);

    // Clear the IO_PENDING status
    SetStatus(URLRequestStatus());
  }
  NotifyReadComplete(result);
}

void URLRequestNewFtpJob::StartTransaction() {
  // Create a transaction.
  DCHECK(!transaction_.get());
  DCHECK(request_->context());
  DCHECK(request_->context()->ftp_transaction_factory());

  transaction_.reset(
  request_->context()->ftp_transaction_factory()->CreateTransaction());

  // No matter what, we want to report our status as IO pending since we will
  // be notifying our consumer asynchronously via OnStartCompleted.
  SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
  int rv;
  if (transaction_.get()) {
    rv = transaction_->Start(&request_info_, &start_callback_);
    if (rv == net::ERR_IO_PENDING)
      return;
  } else {
    rv = net::ERR_FAILED;
  }
  // The transaction started synchronously, but we need to notify the
  // URLRequest delegate via the message loop.
  MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
      this, &URLRequestNewFtpJob::OnStartCompleted, rv));
}

void URLRequestNewFtpJob::DestroyTransaction() {
  DCHECK(transaction_.get());

  transaction_.reset();
  response_info_ = NULL;
}
<|endoftext|>


<commit_before>#pragma once

#include "../traits.hpp"
#include "fft2d.pb.h"
#include <thrust/device_vector.h>

namespace cujak {
namespace fft2d {

inline int calc_stride(int Ny) { return (Ny % 2 ? Ny / 2 + 1 : Ny / 2); }

template <typename Container> class wrapper_base {
protected:
  const int Nx, Ny, stride, N;
  Container &u;
  wrapper_base(int Nx_, int Ny_, int stride_, int N_, Container &u_)
      : Nx(Nx_), Ny(Ny_), stride(stride_), N(N_), u(u_) {}

public:
  typedef typename Container::value_type value_type;

  pb::Property property;

  value_type *get() { return u.data().get(); }
  Container &data() const { return u; }

  value_type operator()(int i, int j) const { return u[stride * i + j]; }
  value_type &operator()(int i, int j) { return u[stride * i + j]; }

  int size_x() const { return Nx; }
  int size_y() const { return Ny; }
  int size() const { return Nx * Ny; }
};

template <typename Float>
class Field_wrapper : public wrapper_base<typename traits<Float>::rVector> {
public:
  typedef typename traits<Float>::rVector Container;
  Field_wrapper(int Nx, int Ny, Container &u)
      : wrapper_base<Container>(Nx, Ny, Ny, Nx * Ny, u) {}
};

template <typename Float>
class Coefficient_wrapper
    : public wrapper_base<typename traits<Float>::cVector> {

public:
  typedef typename traits<Float>::cVector Container;
  Coefficient_wrapper(int Nx, int Ny, Container &u)
      : wrapper_base<Container>(Nx, Ny, calc_stride(Ny), Nx * calc_stride(Ny),
                                u) {}
};

template <typename Float> class Field : public Field_wrapper<Float> {
  typename Field_wrapper<Float>::Container data;

public:
  Field(int Nx, int Ny) : data(Nx * Ny), Field_wrapper<Float>(Nx, Ny, data) {}
};

template <typename Float>
class Coefficient : public Coefficient_wrapper<Float> {
  typename Coefficient_wrapper<Float>::Container data;

public:
  Coefficient(int Nx, int Ny)
      : data(Nx * calc_stride(Ny)), Coefficient_wrapper<Float>(Nx, Ny, data) {}
};

} // namespace fft2d
} // namespace Kolmogorov2D
<commit_msg>Restore set function and bug fix<commit_after>#pragma once

#include "../traits.hpp"
#include "fft2d.pb.h"
#include <thrust/device_vector.h>

namespace cujak {
namespace fft2d {

inline int calc_stride(int Ny) { return (Ny % 2 ? Ny / 2 + 1 : Ny / 2); }

template <typename Container> class wrapper_base {
protected:
  const int Nx, Ny, stride, N;
  Container &u;
  wrapper_base(int Nx_, int Ny_, int stride_, int N_, Container &u_)
      : Nx(Nx_), Ny(Ny_), stride(stride_), N(N_), u(u_) {}

public:
  typedef typename Container::value_type value_type;

  pb::Property property;

  value_type *get() const { return u.data().get(); }
  Container &data() const { return u; }

  value_type operator()(int i, int j) const { return u[stride * i + j]; }
  void set(int i, int j, value_type v) { u[stride * i + j] = v; }

  int size_x() const { return Nx; }
  int size_y() const { return Ny; }
  int size() const { return Nx * Ny; }
};

template <typename Float>
class Field_wrapper : public wrapper_base<typename traits<Float>::rVector> {
public:
  typedef typename traits<Float>::rVector Container;
  Field_wrapper(int Nx, int Ny, Container &u)
      : wrapper_base<Container>(Nx, Ny, Ny, Nx * Ny, u) {}
};

template <typename Float>
class Coefficient_wrapper
    : public wrapper_base<typename traits<Float>::cVector> {

public:
  typedef typename traits<Float>::cVector Container;
  Coefficient_wrapper(int Nx, int Ny, Container &u)
      : wrapper_base<Container>(Nx, Ny, calc_stride(Ny), Nx * calc_stride(Ny),
                                u) {}
};

template <typename Float> class Field : public Field_wrapper<Float> {
  typename Field_wrapper<Float>::Container data;

public:
  Field(int Nx, int Ny) : data(Nx * Ny), Field_wrapper<Float>(Nx, Ny, data) {}
};

template <typename Float>
class Coefficient : public Coefficient_wrapper<Float> {
  typename Coefficient_wrapper<Float>::Container data;

public:
  Coefficient(int Nx, int Ny)
      : data(Nx * calc_stride(Ny)), Coefficient_wrapper<Float>(Nx, Ny, data) {}
};

} // namespace fft2d
} // namespace Kolmogorov2D
<|endoftext|>


<commit_before>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2017 Baldur Karlsson
 *
 * 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 "PerformanceCounterSelection.h"
#include <QMenu>
#include <QSet>
#include "Code/CaptureContext.h"
#include "Code/Interface/QRDInterface.h"
#include "Code/Resources.h"
#include "ui_PerformanceCounterSelection.h"

#include <unordered_map>

#define JSON_ID "rdocPerformanceCounterSettings"
#define JSON_VER 1

// we can't specialise the template, but creating an overload works. This lets us use
// QSet<GPUCounter>
inline uint qHash(const GPUCounter &t)
{
  return qHash(uint32_t(t));
}

namespace
{
enum class CounterFamily
{
  Unknown,
  Generic,
  AMD,
  Intel,
  NVIDIA,
};

CounterFamily GetCounterFamily(GPUCounter counter)
{
  if(IsAMDCounter(counter))
  {
    return CounterFamily::AMD;
  }
  else if(IsIntelCounter(counter))
  {
    return CounterFamily::Intel;
  }
  else if(IsNvidiaCounter(counter))
  {
    return CounterFamily::NVIDIA;
  }

  return CounterFamily::Generic;
}

QString ToString(CounterFamily family)
{
  switch(family)
  {
    case CounterFamily::AMD: return lit("AMD");
    case CounterFamily::Generic: return lit("Generic");
    case CounterFamily::Intel: return lit("Intel");
    case CounterFamily::NVIDIA: return lit("NVIDIA");
    case CounterFamily::Unknown: return lit("Unknown");
  }

  return QString();
}
}

const int PerformanceCounterSelection::CounterDescriptionRole = Qt::UserRole + 1;
const int PerformanceCounterSelection::CounterIdRole = Qt::UserRole + 2;
const int PerformanceCounterSelection::PreviousCheckStateRole = Qt::UserRole + 3;

void PerformanceCounterSelection::uncheckAllChildren(RDTreeWidgetItem *item)
{
  for(int i = 0; i < item->childCount(); i++)
  {
    uncheckAllChildren(item->child(i));

    item->child(i)->setCheckState(0, Qt::Unchecked);
    item->child(i)->setData(0, PreviousCheckStateRole, Qt::Unchecked);
  }
}

void PerformanceCounterSelection::checkAllChildren(RDTreeWidgetItem *item)
{
  for(int i = 0; i < item->childCount(); i++)
  {
    checkAllChildren(item->child(i));

    item->child(i)->setCheckState(0, Qt::Checked);
    item->child(i)->setData(0, PreviousCheckStateRole, Qt::Checked);
  }
}

void PerformanceCounterSelection::updateParentCheckState(RDTreeWidgetItem *item)
{
  if(!item)
    return;

  int numChecked = 0;
  int numPartial = 0;

  for(int i = 0; i < item->childCount(); i++)
  {
    Qt::CheckState state = item->child(i)->checkState(0);
    if(state == Qt::PartiallyChecked)
      numPartial++;
    else if(state == Qt::Checked)
      numChecked++;
  }

  if(numChecked == item->childCount())
    item->setCheckState(0, Qt::Checked);
  else if(numChecked > 0 || numPartial > 0)
    item->setCheckState(0, Qt::PartiallyChecked);
  else
    item->setCheckState(0, Qt::Unchecked);

  item->setData(0, PreviousCheckStateRole, item->checkState(0));

  updateParentCheckState(item->parent());
}

void PerformanceCounterSelection::expandToNode(RDTreeWidgetItem *node)
{
  RDTreeWidgetItem *n = node;
  while(node != NULL)
  {
    ui->counterTree->expandItem(node);
    node = node->parent();
  }

  if(n)
    ui->counterTree->scrollToItem(n);
}

PerformanceCounterSelection::PerformanceCounterSelection(ICaptureContext &ctx,
                                                         const QList<GPUCounter> &selectedCounters,
                                                         QWidget *parent)
    : QDialog(parent), ui(new Ui::PerformanceCounterSelection), m_Ctx(ctx)
{
  ui->setupUi(this);

  setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);

  ui->counterTree->setColumns({QString()});
  ui->counterTree->setHeaderHidden(true);

  connect(ui->counterTree, &RDTreeWidget::currentItemChanged,
          [this](RDTreeWidgetItem *item, RDTreeWidgetItem *) -> void {
            const QVariant d = item->data(0, CounterDescriptionRole);

            if(d.isValid())
            {
              ui->counterDescription->setText(
                  QString(lit("%1
%2")).arg(item->text(0)).arg(d.toString()));
            }
          });

  connect(ui->save, &QPushButton::pressed, this, &PerformanceCounterSelection::Save);
  connect(ui->load, &QPushButton::pressed, this, &PerformanceCounterSelection::Load);
  connect(ui->sampleCounters, &QPushButton::pressed, this, &PerformanceCounterSelection::accept);
  connect(ui->cancel, &QPushButton::pressed, this, &PerformanceCounterSelection::reject);

  connect(ui->counterTree, &RDTreeWidget::itemChanged, [this](RDTreeWidgetItem *item, int) -> void {
    const QVariant d = item->data(0, CounterIdRole);

    static bool recurse = false;

    if(d.isValid())
    {
      if(item->checkState(0) == Qt::Checked)
      {
        // Add
        QListWidgetItem *listItem = new QListWidgetItem(ui->enabledCounters);
        listItem->setText(item->text(0));
        listItem->setData(CounterIdRole, d);
        m_SelectedCounters.insert((GPUCounter)d.toUInt(), listItem);
      }
      else
      {
        // Remove
        QListWidgetItem *listItem = m_SelectedCounters.take((GPUCounter)d.toUInt());
        delete listItem;
      }

      if(!recurse)
      {
        recurse = true;
        updateParentCheckState(item->parent());
        recurse = false;
      }
    }
    else if(!recurse)
    {
      Qt::CheckState prev = item->data(0, PreviousCheckStateRole).value<Qt::CheckState>();

      if(item->checkState(0) != prev)
      {
        recurse = true;

        if(item->checkState(0) == Qt::Checked)
        {
          checkAllChildren(item);
        }
        else
        {
          uncheckAllChildren(item);
        }

        item->setData(0, PreviousCheckStateRole, item->checkState(0));

        updateParentCheckState(item);

        recurse = false;
      }
    }
  });

  ui->counterTree->setMouseTracking(true);

  ctx.Replay().AsyncInvoke([this, selectedCounters](IReplayController *controller) -> void {
    QVector<CounterDescription> counterDescriptions;
    for(const GPUCounter counter : controller->EnumerateCounters())
    {
      counterDescriptions.append(controller->DescribeCounter(counter));
    }

    GUIInvoke::call([counterDescriptions, selectedCounters, this]() -> void {
      SetCounters(counterDescriptions);
      SetSelectedCounters(selectedCounters);
    });
  });

  ui->counterTree->setContextMenuPolicy(Qt::CustomContextMenu);
  QObject::connect(ui->counterTree, &RDTreeWidget::customContextMenuRequested, this,
                   &PerformanceCounterSelection::counterTree_contextMenu);
}

PerformanceCounterSelection::~PerformanceCounterSelection()
{
  delete ui;
}

void PerformanceCounterSelection::SetCounters(const QVector<CounterDescription> &descriptions)
{
  ui->counterTree->clear();
  ui->enabledCounters->clear();

  RDTreeWidgetItem *currentRoot = NULL;
  CounterFamily currentFamily = CounterFamily::Unknown;

  std::unordered_map<std::string, RDTreeWidgetItem *> categories;

  for(const CounterDescription &desc : descriptions)
  {
    m_CounterToUuid[desc.counterID] = desc.uuid;
    m_UuidToCounter[desc.uuid] = desc.counterID;

    const CounterFamily family = GetCounterFamily(desc.counterID);
    if(family != currentFamily)
    {
      currentRoot = new RDTreeWidgetItem();
      ui->counterTree->addTopLevelItem(currentRoot);
      currentRoot->setText(0, ToString(family));
      currentRoot->setCheckState(0, Qt::Unchecked);
      currentRoot->setData(0, PreviousCheckStateRole, Qt::Unchecked);

      categories.clear();

      currentFamily = family;
    }

    RDTreeWidgetItem *categoryItem = NULL;

    const std::string category = desc.category;
    auto categoryIterator = categories.find(category);

    if(categoryIterator == categories.end())
    {
      RDTreeWidgetItem *item = new RDTreeWidgetItem();
      currentRoot->addChild(item);
      item->setText(0, desc.category);
      item->setCheckState(0, Qt::Unchecked);
      item->setData(0, PreviousCheckStateRole, Qt::Unchecked);

      categories[category] = item;
      categoryItem = item;
    }
    else
    {
      categoryItem = categoryIterator->second;
    }

    RDTreeWidgetItem *counterItem = new RDTreeWidgetItem();
    categoryItem->addChild(counterItem);
    counterItem->setText(0, desc.name);
    counterItem->setData(0, CounterDescriptionRole, desc.description);
    counterItem->setData(0, CounterIdRole, (uint32_t)desc.counterID);
    counterItem->setCheckState(0, Qt::Unchecked);
    counterItem->setData(0, PreviousCheckStateRole, Qt::Unchecked);

    m_CounterToTreeItem[desc.counterID] = counterItem;
  }
}

QList<GPUCounter> PerformanceCounterSelection::GetSelectedCounters() const
{
  return m_SelectedCounters.keys();
}

void PerformanceCounterSelection::SetSelectedCounters(const QList<GPUCounter> &counters)
{
  // We we walk over the complete tree, and toggle everything so it
  // matches the settings
  RDTreeWidgetItemIterator it(ui->counterTree);
  while(*it)
  {
    const QVariant id = (*it)->data(0, Qt::UserRole + 2);
    if(id.isValid())
    {
      const GPUCounter counter = (GPUCounter)id.toUInt();

      (*it)->setCheckState(0, counters.contains(counter) ? Qt::Checked : Qt::Unchecked);
    }

    // The loop above will uncheck all unknown counters, and not crash if some counter is no
    // longer present, or unknown

    ++it;
  }
}

void PerformanceCounterSelection::Save()
{
  QString filename = RDDialog::getSaveFileName(this, tr("Save File"), QDir::homePath(),
                                               tr("Performance Counter Settings (*.json)"));

  if(filename.isEmpty())
    return;

  QVariantList counterIds;
  for(const GPUCounter v : m_SelectedCounters.keys())
  {
    const Uuid uuid = m_CounterToUuid[v];
    QVariantList e;

    for(const byte b : uuid.bytes)
    {
      e.append(b);
    }

    counterIds.append(QVariant(e));
  }

  QVariantMap doc;
  doc[lit("counters")] = counterIds;

  QFile f(filename);
  if(f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
  {
    SaveToJSON(doc, f, JSON_ID, JSON_VER);
  }
  else
  {
    RDDialog::critical(this, tr("Error saving config"),
                       tr("Couldn't open path %1 for write.").arg(filename));
  }
}

void PerformanceCounterSelection::Load()
{
  QString filename = RDDialog::getOpenFileName(this, tr("Load file"), QDir::homePath(),
                                               tr("Performance Counter Settings (*.json)"));

  if(filename.isEmpty())
    return;

  QVariantMap doc;
  QFile f(filename);
  if(f.open(QIODevice::ReadOnly | QIODevice::Text))
  {
    LoadFromJSON(doc, f, JSON_ID, JSON_VER);

    QSet<GPUCounter> selectedCounters;

    QVariantList counters = doc[lit("counters")].toList();

    for(const QVariant &counter : counters)
    {
      QVariantList bytes = counter.toList();
      Uuid uuid;

      /// TODO assert counter.size () == 4

      for(int i = 0; i < 4; ++i)
      {
        uuid.bytes[i] = bytes[i].toUInt();
      }

      if(!m_UuidToCounter.contains(uuid))
        continue;

      selectedCounters.insert(m_UuidToCounter[uuid]);
    }

    SetSelectedCounters(selectedCounters.toList());
  }
  else
  {
    RDDialog::critical(this, tr("Error loading config"),
                       tr("Couldn't open path %1 for reading.").arg(filename));
  }
}
void PerformanceCounterSelection::counterTree_contextMenu(const QPoint &pos)
{
  RDTreeWidgetItem *item = ui->counterTree->itemAt(pos);

  QMenu contextMenu(this);

  QAction expandAll(tr("&Expand All"), this);
  QAction collapseAll(tr("&Collapse All"), this);

  contextMenu.addAction(&expandAll);
  contextMenu.addAction(&collapseAll);

  expandAll.setIcon(Icons::arrow_out());
  collapseAll.setIcon(Icons::arrow_in());

  expandAll.setEnabled(item && item->childCount() > 0);
  collapseAll.setEnabled(item && item->childCount() > 0);

  QObject::connect(&expandAll, &QAction::triggered,
                   [this, item]() { ui->counterTree->expandAllItems(item); });

  QObject::connect(&collapseAll, &QAction::triggered,
                   [this, item]() { ui->counterTree->collapseAllItems(item); });

  RDDialog::show(&contextMenu, ui->counterTree->viewport()->mapToGlobal(pos));
}

void PerformanceCounterSelection::on_enabledCounters_activated(const QModelIndex &index)
{
  QListWidgetItem *item = ui->enabledCounters->item(index.row());

  if(!item)
    return;

  QVariant counterID = item->data(CounterIdRole);

  // locate the item in the description tree
  auto it = m_CounterToTreeItem.find((GPUCounter)counterID.toUInt());

  if(it != m_CounterToTreeItem.end())
  {
    ui->counterTree->setCurrentItem(it.value());
    ui->counterTree->setSelectedItem(it.value());

    expandToNode(it.value());
  }
}
<commit_msg>Use the correct role instead of a magic number.<commit_after>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2017 Baldur Karlsson
 *
 * 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 "PerformanceCounterSelection.h"
#include <QMenu>
#include <QSet>
#include "Code/CaptureContext.h"
#include "Code/Interface/QRDInterface.h"
#include "Code/Resources.h"
#include "ui_PerformanceCounterSelection.h"

#include <unordered_map>

#define JSON_ID "rdocPerformanceCounterSettings"
#define JSON_VER 1

// we can't specialise the template, but creating an overload works. This lets us use
// QSet<GPUCounter>
inline uint qHash(const GPUCounter &t)
{
  return qHash(uint32_t(t));
}

namespace
{
enum class CounterFamily
{
  Unknown,
  Generic,
  AMD,
  Intel,
  NVIDIA,
};

CounterFamily GetCounterFamily(GPUCounter counter)
{
  if(IsAMDCounter(counter))
  {
    return CounterFamily::AMD;
  }
  else if(IsIntelCounter(counter))
  {
    return CounterFamily::Intel;
  }
  else if(IsNvidiaCounter(counter))
  {
    return CounterFamily::NVIDIA;
  }

  return CounterFamily::Generic;
}

QString ToString(CounterFamily family)
{
  switch(family)
  {
    case CounterFamily::AMD: return lit("AMD");
    case CounterFamily::Generic: return lit("Generic");
    case CounterFamily::Intel: return lit("Intel");
    case CounterFamily::NVIDIA: return lit("NVIDIA");
    case CounterFamily::Unknown: return lit("Unknown");
  }

  return QString();
}
}

const int PerformanceCounterSelection::CounterDescriptionRole = Qt::UserRole + 1;
const int PerformanceCounterSelection::CounterIdRole = Qt::UserRole + 2;
const int PerformanceCounterSelection::PreviousCheckStateRole = Qt::UserRole + 3;

void PerformanceCounterSelection::uncheckAllChildren(RDTreeWidgetItem *item)
{
  for(int i = 0; i < item->childCount(); i++)
  {
    uncheckAllChildren(item->child(i));

    item->child(i)->setCheckState(0, Qt::Unchecked);
    item->child(i)->setData(0, PreviousCheckStateRole, Qt::Unchecked);
  }
}

void PerformanceCounterSelection::checkAllChildren(RDTreeWidgetItem *item)
{
  for(int i = 0; i < item->childCount(); i++)
  {
    checkAllChildren(item->child(i));

    item->child(i)->setCheckState(0, Qt::Checked);
    item->child(i)->setData(0, PreviousCheckStateRole, Qt::Checked);
  }
}

void PerformanceCounterSelection::updateParentCheckState(RDTreeWidgetItem *item)
{
  if(!item)
    return;

  int numChecked = 0;
  int numPartial = 0;

  for(int i = 0; i < item->childCount(); i++)
  {
    Qt::CheckState state = item->child(i)->checkState(0);
    if(state == Qt::PartiallyChecked)
      numPartial++;
    else if(state == Qt::Checked)
      numChecked++;
  }

  if(numChecked == item->childCount())
    item->setCheckState(0, Qt::Checked);
  else if(numChecked > 0 || numPartial > 0)
    item->setCheckState(0, Qt::PartiallyChecked);
  else
    item->setCheckState(0, Qt::Unchecked);

  item->setData(0, PreviousCheckStateRole, item->checkState(0));

  updateParentCheckState(item->parent());
}

void PerformanceCounterSelection::expandToNode(RDTreeWidgetItem *node)
{
  RDTreeWidgetItem *n = node;
  while(node != NULL)
  {
    ui->counterTree->expandItem(node);
    node = node->parent();
  }

  if(n)
    ui->counterTree->scrollToItem(n);
}

PerformanceCounterSelection::PerformanceCounterSelection(ICaptureContext &ctx,
                                                         const QList<GPUCounter> &selectedCounters,
                                                         QWidget *parent)
    : QDialog(parent), ui(new Ui::PerformanceCounterSelection), m_Ctx(ctx)
{
  ui->setupUi(this);

  setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);

  ui->counterTree->setColumns({QString()});
  ui->counterTree->setHeaderHidden(true);

  connect(ui->counterTree, &RDTreeWidget::currentItemChanged,
          [this](RDTreeWidgetItem *item, RDTreeWidgetItem *) -> void {
            const QVariant d = item->data(0, CounterDescriptionRole);

            if(d.isValid())
            {
              ui->counterDescription->setText(
                  QString(lit("%1
%2")).arg(item->text(0)).arg(d.toString()));
            }
          });

  connect(ui->save, &QPushButton::pressed, this, &PerformanceCounterSelection::Save);
  connect(ui->load, &QPushButton::pressed, this, &PerformanceCounterSelection::Load);
  connect(ui->sampleCounters, &QPushButton::pressed, this, &PerformanceCounterSelection::accept);
  connect(ui->cancel, &QPushButton::pressed, this, &PerformanceCounterSelection::reject);

  connect(ui->counterTree, &RDTreeWidget::itemChanged, [this](RDTreeWidgetItem *item, int) -> void {
    const QVariant d = item->data(0, CounterIdRole);

    static bool recurse = false;

    if(d.isValid())
    {
      if(item->checkState(0) == Qt::Checked)
      {
        // Add
        QListWidgetItem *listItem = new QListWidgetItem(ui->enabledCounters);
        listItem->setText(item->text(0));
        listItem->setData(CounterIdRole, d);
        m_SelectedCounters.insert((GPUCounter)d.toUInt(), listItem);
      }
      else
      {
        // Remove
        QListWidgetItem *listItem = m_SelectedCounters.take((GPUCounter)d.toUInt());
        delete listItem;
      }

      if(!recurse)
      {
        recurse = true;
        updateParentCheckState(item->parent());
        recurse = false;
      }
    }
    else if(!recurse)
    {
      Qt::CheckState prev = item->data(0, PreviousCheckStateRole).value<Qt::CheckState>();

      if(item->checkState(0) != prev)
      {
        recurse = true;

        if(item->checkState(0) == Qt::Checked)
        {
          checkAllChildren(item);
        }
        else
        {
          uncheckAllChildren(item);
        }

        item->setData(0, PreviousCheckStateRole, item->checkState(0));

        updateParentCheckState(item);

        recurse = false;
      }
    }
  });

  ui->counterTree->setMouseTracking(true);

  ctx.Replay().AsyncInvoke([this, selectedCounters](IReplayController *controller) -> void {
    QVector<CounterDescription> counterDescriptions;
    for(const GPUCounter counter : controller->EnumerateCounters())
    {
      counterDescriptions.append(controller->DescribeCounter(counter));
    }

    GUIInvoke::call([counterDescriptions, selectedCounters, this]() -> void {
      SetCounters(counterDescriptions);
      SetSelectedCounters(selectedCounters);
    });
  });

  ui->counterTree->setContextMenuPolicy(Qt::CustomContextMenu);
  QObject::connect(ui->counterTree, &RDTreeWidget::customContextMenuRequested, this,
                   &PerformanceCounterSelection::counterTree_contextMenu);
}

PerformanceCounterSelection::~PerformanceCounterSelection()
{
  delete ui;
}

void PerformanceCounterSelection::SetCounters(const QVector<CounterDescription> &descriptions)
{
  ui->counterTree->clear();
  ui->enabledCounters->clear();

  RDTreeWidgetItem *currentRoot = NULL;
  CounterFamily currentFamily = CounterFamily::Unknown;

  std::unordered_map<std::string, RDTreeWidgetItem *> categories;

  for(const CounterDescription &desc : descriptions)
  {
    m_CounterToUuid[desc.counterID] = desc.uuid;
    m_UuidToCounter[desc.uuid] = desc.counterID;

    const CounterFamily family = GetCounterFamily(desc.counterID);
    if(family != currentFamily)
    {
      currentRoot = new RDTreeWidgetItem();
      ui->counterTree->addTopLevelItem(currentRoot);
      currentRoot->setText(0, ToString(family));
      currentRoot->setCheckState(0, Qt::Unchecked);
      currentRoot->setData(0, PreviousCheckStateRole, Qt::Unchecked);

      categories.clear();

      currentFamily = family;
    }

    RDTreeWidgetItem *categoryItem = NULL;

    const std::string category = desc.category;
    auto categoryIterator = categories.find(category);

    if(categoryIterator == categories.end())
    {
      RDTreeWidgetItem *item = new RDTreeWidgetItem();
      currentRoot->addChild(item);
      item->setText(0, desc.category);
      item->setCheckState(0, Qt::Unchecked);
      item->setData(0, PreviousCheckStateRole, Qt::Unchecked);

      categories[category] = item;
      categoryItem = item;
    }
    else
    {
      categoryItem = categoryIterator->second;
    }

    RDTreeWidgetItem *counterItem = new RDTreeWidgetItem();
    categoryItem->addChild(counterItem);
    counterItem->setText(0, desc.name);
    counterItem->setData(0, CounterDescriptionRole, desc.description);
    counterItem->setData(0, CounterIdRole, (uint32_t)desc.counterID);
    counterItem->setCheckState(0, Qt::Unchecked);
    counterItem->setData(0, PreviousCheckStateRole, Qt::Unchecked);

    m_CounterToTreeItem[desc.counterID] = counterItem;
  }
}

QList<GPUCounter> PerformanceCounterSelection::GetSelectedCounters() const
{
  return m_SelectedCounters.keys();
}

void PerformanceCounterSelection::SetSelectedCounters(const QList<GPUCounter> &counters)
{
  // We we walk over the complete tree, and toggle everything so it
  // matches the settings
  RDTreeWidgetItemIterator it(ui->counterTree);
  while(*it)
  {
    const QVariant id = (*it)->data(0, CounterIdRole);
    if(id.isValid())
    {
      const GPUCounter counter = (GPUCounter)id.toUInt();

      (*it)->setCheckState(0, counters.contains(counter) ? Qt::Checked : Qt::Unchecked);
    }

    // The loop above will uncheck all unknown counters, and not crash if some counter is no
    // longer present, or unknown

    ++it;
  }
}

void PerformanceCounterSelection::Save()
{
  QString filename = RDDialog::getSaveFileName(this, tr("Save File"), QDir::homePath(),
                                               tr("Performance Counter Settings (*.json)"));

  if(filename.isEmpty())
    return;

  QVariantList counterIds;
  for(const GPUCounter v : m_SelectedCounters.keys())
  {
    const Uuid uuid = m_CounterToUuid[v];
    QVariantList e;

    for(const byte b : uuid.bytes)
    {
      e.append(b);
    }

    counterIds.append(QVariant(e));
  }

  QVariantMap doc;
  doc[lit("counters")] = counterIds;

  QFile f(filename);
  if(f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
  {
    SaveToJSON(doc, f, JSON_ID, JSON_VER);
  }
  else
  {
    RDDialog::critical(this, tr("Error saving config"),
                       tr("Couldn't open path %1 for write.").arg(filename));
  }
}

void PerformanceCounterSelection::Load()
{
  QString filename = RDDialog::getOpenFileName(this, tr("Load file"), QDir::homePath(),
                                               tr("Performance Counter Settings (*.json)"));

  if(filename.isEmpty())
    return;

  QVariantMap doc;
  QFile f(filename);
  if(f.open(QIODevice::ReadOnly | QIODevice::Text))
  {
    LoadFromJSON(doc, f, JSON_ID, JSON_VER);

    QSet<GPUCounter> selectedCounters;

    QVariantList counters = doc[lit("counters")].toList();

    for(const QVariant &counter : counters)
    {
      QVariantList bytes = counter.toList();
      Uuid uuid;

      /// TODO assert counter.size () == 4

      for(int i = 0; i < 4; ++i)
      {
        uuid.bytes[i] = bytes[i].toUInt();
      }

      if(!m_UuidToCounter.contains(uuid))
        continue;

      selectedCounters.insert(m_UuidToCounter[uuid]);
    }

    SetSelectedCounters(selectedCounters.toList());
  }
  else
  {
    RDDialog::critical(this, tr("Error loading config"),
                       tr("Couldn't open path %1 for reading.").arg(filename));
  }
}
void PerformanceCounterSelection::counterTree_contextMenu(const QPoint &pos)
{
  RDTreeWidgetItem *item = ui->counterTree->itemAt(pos);

  QMenu contextMenu(this);

  QAction expandAll(tr("&Expand All"), this);
  QAction collapseAll(tr("&Collapse All"), this);

  contextMenu.addAction(&expandAll);
  contextMenu.addAction(&collapseAll);

  expandAll.setIcon(Icons::arrow_out());
  collapseAll.setIcon(Icons::arrow_in());

  expandAll.setEnabled(item && item->childCount() > 0);
  collapseAll.setEnabled(item && item->childCount() > 0);

  QObject::connect(&expandAll, &QAction::triggered,
                   [this, item]() { ui->counterTree->expandAllItems(item); });

  QObject::connect(&collapseAll, &QAction::triggered,
                   [this, item]() { ui->counterTree->collapseAllItems(item); });

  RDDialog::show(&contextMenu, ui->counterTree->viewport()->mapToGlobal(pos));
}

void PerformanceCounterSelection::on_enabledCounters_activated(const QModelIndex &index)
{
  QListWidgetItem *item = ui->enabledCounters->item(index.row());

  if(!item)
    return;

  QVariant counterID = item->data(CounterIdRole);

  // locate the item in the description tree
  auto it = m_CounterToTreeItem.find((GPUCounter)counterID.toUInt());

  if(it != m_CounterToTreeItem.end())
  {
    ui->counterTree->setCurrentItem(it.value());
    ui->counterTree->setSelectedItem(it.value());

    expandToNode(it.value());
  }
}
<|endoftext|>