<commit_before>/*************************************************************************
 *
 *  $RCSfile: ChartController_TextEdit.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: bm $ $Date: 2004-02-10 10:21:12 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2003 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#include "ChartController.hxx"

#include "DrawViewWrapper.hxx"
#include "ChartWindow.hxx"
#include "TitleHelper.hxx"
#include "chartview/ObjectIdentifier.hxx"
#include "macros.hxx"

#include <svx/svdotext.hxx>

// header for class SvxCharacterMap
#ifndef _SVX_CHARMAP_HXX
#include <svx/charmap.hxx>
#endif
// header for define RET_OK
#ifndef _SV_MSGBOX_HXX
#include <vcl/msgbox.hxx>
#endif
// header for class SdrOutliner
#ifndef _SVDOUTL_HXX
#include <svx/svdoutl.hxx>
#endif

#ifndef _SVX_DIALOG_HXX
#include <svx/svxdlg.hxx>
#endif
#ifndef _SVX_DIALOGS_HRC
#include <svx/dialogs.hrc>
#endif

#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif

//.............................................................................
namespace chart
{
//.............................................................................
using namespace ::com::sun::star;
//using namespace ::com::sun::star::chart2;

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

void SAL_CALL ChartController::executeDispatch_EditText()
{
    this->StartTextEdit();
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

void ChartController::StartTextEdit()
{
    //the first marked object will be edited

    SdrObject* pTextObj = m_pDrawViewWrapper->getTextEditObject();
    if(!pTextObj)
        return;

    SdrOutliner* pOutliner = m_pDrawViewWrapper->getOutliner();
    //pOutliner->SetRefDevice(m_pChartWindow);
    //pOutliner->SetStyleSheetPool((SfxStyleSheetPool*)pStyleSheetPool);
    //pOutliner->SetDefaultLanguage( eLang );
    //pOutliner->SetHyphenator( xHyphenator );
    BOOL bEdit = m_pDrawViewWrapper->BegTextEdit( pTextObj
                    , m_pDrawViewWrapper->GetPageView()
                    , m_pChartWindow
                    , FALSE //bIsNewObj
                    , pOutliner
                    , NULL //pOutlinerView
                    , TRUE //bDontDeleteOutliner
                    , TRUE //bOnlyOneView
                    );
    if(bEdit)
    {
        // set undo manager at topmost shell ( SdDrawTextObjectBar )
        /*
        if( pViewSh )
            pViewSh->GetViewFrame()->GetDispatcher()->GetShell( 0 )->
                SetUndoManager(&pOutliner->GetUndoManager());
        */
        m_pDrawViewWrapper->SetEditMode();

        //we invalidate the outliner region because the outliner has some
        //paint problems (some characters are painted twice a little bit shifted)
        m_pChartWindow->Invalidate( m_pDrawViewWrapper->GetMarkedObjBoundRect() );
    }
}

bool ChartController::EndTextEdit()
{
    m_pDrawViewWrapper->EndTextEdit();
    SdrObject* pTextObject = m_pDrawViewWrapper->getTextEditObject();
    if(!pTextObject)
        return false;

    SdrOutliner* pOutliner = m_pDrawViewWrapper->getOutliner();
    OutlinerParaObject* pParaObj = pTextObject->GetOutlinerParaObject();
    if( pParaObj && pOutliner )
    {
        pOutliner->SetText( *pParaObj );

        String aString = pOutliner->GetText(
                            pOutliner->GetParagraph( 0 ),
                            pOutliner->GetParagraphCount() );
        uno::Reference< beans::XPropertySet > xPropSet =
            ObjectIdentifier::getObjectPropertySet( m_aSelectedObjectCID, getModel() );

        //Paragraph* pPara =
        TitleHelper::setCompleteString( aString, uno::Reference<
            ::com::sun::star::chart2::XTitle >::query( xPropSet ), m_xCC );
        try
        {
            //need to rebuild to react on changed size of title
            impl_rebuildView();
        }
        catch( uno::RuntimeException& e)
        {
            ASSERT_EXCEPTION( e );
        }
    }
    return true;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

void SAL_CALL ChartController::executeDispatch_InsertSpecialCharacter()
{
    SvxAbstractDialogFactory * pFact = SvxAbstractDialogFactory::Create();
    DBG_ASSERT( pFact, "No dialog factory" );
    AbstractSvxCharacterMap * pDlg = pFact->CreateSvxCharacterMap( NULL,  ResId( RID_SVXDLG_CHARMAP ), FALSE );
    DBG_ASSERT( pDlg, "Couldn't create SvxCharacterMap dialog" );

    //set fixed current font
    pDlg->SetFont( m_pDrawViewWrapper->getOutliner()->GetRefDevice()->GetFont() );
    pDlg->DisableFontSelection(); //maybe not necessary in future

    if( pDlg->Execute() == RET_OK )
    {
        String aString( pDlg->GetCharacters() );

        OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView();
        SdrOutliner*  pOutliner = m_pDrawViewWrapper->getOutliner();

        if(!pOutliner || !pOutlinerView)
            return;

        // insert string to outliner

        // prevent flicker
        pOutlinerView->HideCursor();
        pOutliner->SetUpdateMode(FALSE);

        // delete current selection by inserting empty String, so current
        // attributes become unique (sel. has to be erased anyway)
        pOutlinerView->InsertText(String());

        //SfxUndoManager& rUndoMgr =  pOutliner->GetUndoManager();
        //rUndoMgr.EnterListAction( String( SchResId( STR_UNDO_INSERT_SPECCHAR )), String( SchResId( STR_UNDO_INSERT_SPECCHAR )));
        pOutlinerView->InsertText(aString, TRUE);

        ESelection aSel = pOutlinerView->GetSelection();
        aSel.nStartPara = aSel.nEndPara;
        aSel.nStartPos = aSel.nEndPos;
        pOutlinerView->SetSelection(aSel);

        //rUndoMgr.LeaveListAction();

        // show changes
        pOutliner->SetUpdateMode(TRUE);
        pOutlinerView->ShowCursor();
    }

    delete pDlg;
}

//.............................................................................
} //namespace chart
//.............................................................................
<commit_msg>INTEGRATION: CWS ooo19126 (1.6.108); FILE MERGED 2005/09/05 18:42:43 rt 1.6.108.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ChartController_TextEdit.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 00:32:57 $
 *
 *  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
 *
 ************************************************************************/
#include "ChartController.hxx"

#include "DrawViewWrapper.hxx"
#include "ChartWindow.hxx"
#include "TitleHelper.hxx"
#include "chartview/ObjectIdentifier.hxx"
#include "macros.hxx"

#include <svx/svdotext.hxx>

// header for class SvxCharacterMap
#ifndef _SVX_CHARMAP_HXX
#include <svx/charmap.hxx>
#endif
// header for define RET_OK
#ifndef _SV_MSGBOX_HXX
#include <vcl/msgbox.hxx>
#endif
// header for class SdrOutliner
#ifndef _SVDOUTL_HXX
#include <svx/svdoutl.hxx>
#endif

#ifndef _SVX_DIALOG_HXX
#include <svx/svxdlg.hxx>
#endif
#ifndef _SVX_DIALOGS_HRC
#include <svx/dialogs.hrc>
#endif

#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif

//.............................................................................
namespace chart
{
//.............................................................................
using namespace ::com::sun::star;
//using namespace ::com::sun::star::chart2;

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

void SAL_CALL ChartController::executeDispatch_EditText()
{
    this->StartTextEdit();
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

void ChartController::StartTextEdit()
{
    //the first marked object will be edited

    SdrObject* pTextObj = m_pDrawViewWrapper->getTextEditObject();
    if(!pTextObj)
        return;

    SdrOutliner* pOutliner = m_pDrawViewWrapper->getOutliner();
    //pOutliner->SetRefDevice(m_pChartWindow);
    //pOutliner->SetStyleSheetPool((SfxStyleSheetPool*)pStyleSheetPool);
    //pOutliner->SetDefaultLanguage( eLang );
    //pOutliner->SetHyphenator( xHyphenator );
    BOOL bEdit = m_pDrawViewWrapper->BegTextEdit( pTextObj
                    , m_pDrawViewWrapper->GetPageView()
                    , m_pChartWindow
                    , FALSE //bIsNewObj
                    , pOutliner
                    , NULL //pOutlinerView
                    , TRUE //bDontDeleteOutliner
                    , TRUE //bOnlyOneView
                    );
    if(bEdit)
    {
        // set undo manager at topmost shell ( SdDrawTextObjectBar )
        /*
        if( pViewSh )
            pViewSh->GetViewFrame()->GetDispatcher()->GetShell( 0 )->
                SetUndoManager(&pOutliner->GetUndoManager());
        */
        m_pDrawViewWrapper->SetEditMode();

        //we invalidate the outliner region because the outliner has some
        //paint problems (some characters are painted twice a little bit shifted)
        m_pChartWindow->Invalidate( m_pDrawViewWrapper->GetMarkedObjBoundRect() );
    }
}

bool ChartController::EndTextEdit()
{
    m_pDrawViewWrapper->EndTextEdit();
    SdrObject* pTextObject = m_pDrawViewWrapper->getTextEditObject();
    if(!pTextObject)
        return false;

    SdrOutliner* pOutliner = m_pDrawViewWrapper->getOutliner();
    OutlinerParaObject* pParaObj = pTextObject->GetOutlinerParaObject();
    if( pParaObj && pOutliner )
    {
        pOutliner->SetText( *pParaObj );

        String aString = pOutliner->GetText(
                            pOutliner->GetParagraph( 0 ),
                            pOutliner->GetParagraphCount() );
        uno::Reference< beans::XPropertySet > xPropSet =
            ObjectIdentifier::getObjectPropertySet( m_aSelectedObjectCID, getModel() );

        //Paragraph* pPara =
        TitleHelper::setCompleteString( aString, uno::Reference<
            ::com::sun::star::chart2::XTitle >::query( xPropSet ), m_xCC );
        try
        {
            //need to rebuild to react on changed size of title
            impl_rebuildView();
        }
        catch( uno::RuntimeException& e)
        {
            ASSERT_EXCEPTION( e );
        }
    }
    return true;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

void SAL_CALL ChartController::executeDispatch_InsertSpecialCharacter()
{
    SvxAbstractDialogFactory * pFact = SvxAbstractDialogFactory::Create();
    DBG_ASSERT( pFact, "No dialog factory" );
    AbstractSvxCharacterMap * pDlg = pFact->CreateSvxCharacterMap( NULL,  ResId( RID_SVXDLG_CHARMAP ), FALSE );
    DBG_ASSERT( pDlg, "Couldn't create SvxCharacterMap dialog" );

    //set fixed current font
    pDlg->SetFont( m_pDrawViewWrapper->getOutliner()->GetRefDevice()->GetFont() );
    pDlg->DisableFontSelection(); //maybe not necessary in future

    if( pDlg->Execute() == RET_OK )
    {
        String aString( pDlg->GetCharacters() );

        OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView();
        SdrOutliner*  pOutliner = m_pDrawViewWrapper->getOutliner();

        if(!pOutliner || !pOutlinerView)
            return;

        // insert string to outliner

        // prevent flicker
        pOutlinerView->HideCursor();
        pOutliner->SetUpdateMode(FALSE);

        // delete current selection by inserting empty String, so current
        // attributes become unique (sel. has to be erased anyway)
        pOutlinerView->InsertText(String());

        //SfxUndoManager& rUndoMgr =  pOutliner->GetUndoManager();
        //rUndoMgr.EnterListAction( String( SchResId( STR_UNDO_INSERT_SPECCHAR )), String( SchResId( STR_UNDO_INSERT_SPECCHAR )));
        pOutlinerView->InsertText(aString, TRUE);

        ESelection aSel = pOutlinerView->GetSelection();
        aSel.nStartPara = aSel.nEndPara;
        aSel.nStartPos = aSel.nEndPos;
        pOutlinerView->SetSelection(aSel);

        //rUndoMgr.LeaveListAction();

        // show changes
        pOutliner->SetUpdateMode(TRUE);
        pOutlinerView->ShowCursor();
    }

    delete pDlg;
}

//.............................................................................
} //namespace chart
//.............................................................................
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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.
 */

#include "HttpConnection.hxx"
#include "ClusterConfig.hxx"
#include "ListenerConfig.hxx"
#include "Goto.txx"
#include "ForwardHttpRequest.hxx"
#include "TranslationHandler.hxx"
#include "Instance.hxx"
#include "Cookie.hxx"
#include "http_server/http_server.hxx"
#include "http_server/Request.hxx"
#include "http_server/Handler.hxx"
#include "http_server/Error.hxx"
#include "SocketProtocolError.hxx"
#include "access_log/Glue.hxx"
#include "pool.hxx"
#include "address_string.hxx"
#include "thread_socket_filter.hxx"
#include "thread_pool.hxx"
#include "uri/uri_verify.hxx"
#include "ssl/ssl_filter.hxx"
#include "net/StaticSocketAddress.hxx"
#include "net/UniqueSocketDescriptor.hxx"
#include "system/Error.hxx"
#include "util/Exception.hxx"

#include <assert.h>

LbHttpConnection::LbHttpConnection(struct pool &_pool, LbInstance &_instance,
                                   const LbListenerConfig &_listener,
                                   const LbGoto &_destination,
                                   SocketAddress _client_address)
    :pool(_pool), instance(_instance), listener(_listener),
     initial_destination(_destination),
     client_address(address_to_string(pool, _client_address)),
     logger(*this)
{
    if (client_address == nullptr)
        client_address = "unknown";
}

gcc_pure
static int
HttpServerLogLevel(std::exception_ptr e)
{
    try {
        FindRetrowNested<HttpServerSocketError>(e);
    } catch (const HttpServerSocketError &) {
        e = std::current_exception();

        /* some socket errors caused by our client are less
           important */

        try {
            FindRetrowNested<std::system_error>(e);
        } catch (const std::system_error &se) {
            if (se.code().category() == ErrnoCategory() &&
                se.code().value() == ECONNRESET)
                return 4;
            return 4;
        }

        try {
            FindRetrowNested<SocketProtocolError>(e);
        } catch (...) {
            return 4;
        }
    }

    return 2;
}

/*
 * public
 *
 */

LbHttpConnection *
NewLbHttpConnection(LbInstance &instance,
                    const LbListenerConfig &listener,
                    const LbGoto &destination,
                    SslFactory *ssl_factory,
                    UniqueSocketDescriptor &&fd, SocketAddress address)
{
    assert(listener.destination.GetProtocol() == LbProtocol::HTTP);

    /* determine the local socket address */
    StaticSocketAddress local_address = fd.GetLocalAddress();

    auto fd_type = FdType::FD_TCP;

    SslFilter *ssl_filter = nullptr;
    const SocketFilter *filter = nullptr;
    void *filter_ctx = nullptr;

    if (ssl_factory != nullptr) {
        ssl_filter = ssl_filter_new(*ssl_factory);
        filter = &thread_socket_filter;
        filter_ctx =
            new ThreadSocketFilter(instance.event_loop,
                                   thread_pool_get_queue(instance.event_loop),
                                   &ssl_filter_get_handler(*ssl_filter));
    }

    struct pool *pool = pool_new_linear(instance.root_pool,
                                        "http_connection",
                                        2048);
    pool_set_major(pool);

    auto *connection = NewFromPool<LbHttpConnection>(*pool, *pool, instance,
                                                     listener, destination,
                                                     address);
    connection->ssl_filter = ssl_filter;

    instance.http_connections.push_back(*connection);

    connection->http = http_server_connection_new(pool, instance.event_loop,
                                                  fd.Release(), fd_type,
                                                  filter, filter_ctx,
                                                  local_address.IsDefined()
                                                  ? (SocketAddress)local_address
                                                  : nullptr,
                                                  address,
                                                  false,
                                                  *connection);
    return connection;
}

void
LbHttpConnection::Destroy()
{
    assert(!instance.http_connections.empty());

    auto &connections = instance.http_connections;
    connections.erase(connections.iterator_to(*this));

    DeleteUnrefTrashPool(pool, this);
}

void
LbHttpConnection::CloseAndDestroy()
{
    assert(listener.destination.GetProtocol() == LbProtocol::HTTP);
    assert(http != nullptr);

    http_server_connection_close(http);

    Destroy();
}

void
LbHttpConnection::SendError(HttpServerRequest &request, std::exception_ptr ep)
{
    const char *msg = listener.verbose_response
        ? p_strdup(request.pool, GetFullMessage(ep).c_str())
        : "Bad gateway";

    http_server_send_message(&request, HTTP_STATUS_BAD_GATEWAY, msg);
}

void
LbHttpConnection::LogSendError(HttpServerRequest &request,
                               std::exception_ptr ep)
{
    logger(2, ep);
    SendError(request, ep);
}

static void
SendResponse(HttpServerRequest &request,
             const LbSimpleHttpResponse &response)
{
    assert(response.IsDefined());

    http_server_simple_response(request, response.status,
                                response.location.empty() ? nullptr : response.location.c_str(),
                                response.message.empty() ? nullptr : response.message.c_str());
}

/*
 * http connection handler
 *
 */

void
LbHttpConnection::HandleHttpRequest(HttpServerRequest &request,
                                    CancellablePointer &cancel_ptr)
{
    ++instance.http_request_counter;

    request_start_time = std::chrono::steady_clock::now();
    canonical_host = nullptr;

    if (!uri_path_verify_quick(request.uri)) {
        request.CheckCloseUnusedBody();
        http_server_send_message(&request, HTTP_STATUS_BAD_REQUEST,
                                 "Malformed request URI");
        return;
    }

    HandleHttpRequest(initial_destination, request, cancel_ptr);
}

void
LbHttpConnection::HandleHttpRequest(const LbGoto &destination,
                                    HttpServerRequest &request,
                                    CancellablePointer &cancel_ptr)
{
    const auto &goto_ = destination.FindRequestLeaf(request);
    if (goto_.response != nullptr) {
        request.CheckCloseUnusedBody();
        SendResponse(request, *goto_.response);
        return;
    }

    if (goto_.lua != nullptr) {
        InvokeLua(*goto_.lua, request, cancel_ptr);
        return;
    }

    if (goto_.translation != nullptr) {
        AskTranslationServer(*goto_.translation, request, cancel_ptr);
        return;
    }

    assert(goto_.cluster != nullptr);
    ForwardHttpRequest(*goto_.cluster, request, cancel_ptr);
}

void
LbHttpConnection::ForwardHttpRequest(LbCluster &cluster,
                                     HttpServerRequest &request,
                                     CancellablePointer &cancel_ptr)
{
    ::ForwardHttpRequest(*this, request, cluster, cancel_ptr);
}

void
LbHttpConnection::LogHttpRequest(HttpServerRequest &request,
                                 http_status_t status, int64_t length,
                                 uint64_t bytes_received, uint64_t bytes_sent)
{
    if (instance.access_log != nullptr)
        instance.access_log->Log(request, nullptr,
                                 request.headers.Get("referer"),
                                 request.headers.Get("user-agent"),
                                 status, length,
                                 bytes_received, bytes_sent,
                                 std::chrono::steady_clock::now() - request_start_time);
}

void
LbHttpConnection::HttpConnectionError(std::exception_ptr e)
{
    logger(HttpServerLogLevel(e), e);

    assert(http != nullptr);
    http = nullptr;

    Destroy();
}

void
LbHttpConnection::HttpConnectionClosed()
{
    assert(http != nullptr);
    http = nullptr;

    Destroy();
}

std::string
LbHttpConnection::MakeLoggerDomain() const noexcept
{
    return "listener='" + listener.name
        + "' cluster='" + listener.destination.GetName()
        + "' client='" + client_address
        + "'";
}
<commit_msg>lb/HttpConnection: remove redundant "return"<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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.
 */

#include "HttpConnection.hxx"
#include "ClusterConfig.hxx"
#include "ListenerConfig.hxx"
#include "Goto.txx"
#include "ForwardHttpRequest.hxx"
#include "TranslationHandler.hxx"
#include "Instance.hxx"
#include "Cookie.hxx"
#include "http_server/http_server.hxx"
#include "http_server/Request.hxx"
#include "http_server/Handler.hxx"
#include "http_server/Error.hxx"
#include "SocketProtocolError.hxx"
#include "access_log/Glue.hxx"
#include "pool.hxx"
#include "address_string.hxx"
#include "thread_socket_filter.hxx"
#include "thread_pool.hxx"
#include "uri/uri_verify.hxx"
#include "ssl/ssl_filter.hxx"
#include "net/StaticSocketAddress.hxx"
#include "net/UniqueSocketDescriptor.hxx"
#include "system/Error.hxx"
#include "util/Exception.hxx"

#include <assert.h>

LbHttpConnection::LbHttpConnection(struct pool &_pool, LbInstance &_instance,
                                   const LbListenerConfig &_listener,
                                   const LbGoto &_destination,
                                   SocketAddress _client_address)
    :pool(_pool), instance(_instance), listener(_listener),
     initial_destination(_destination),
     client_address(address_to_string(pool, _client_address)),
     logger(*this)
{
    if (client_address == nullptr)
        client_address = "unknown";
}

gcc_pure
static int
HttpServerLogLevel(std::exception_ptr e)
{
    try {
        FindRetrowNested<HttpServerSocketError>(e);
    } catch (const HttpServerSocketError &) {
        e = std::current_exception();

        /* some socket errors caused by our client are less
           important */

        try {
            FindRetrowNested<std::system_error>(e);
        } catch (const std::system_error &se) {
            if (se.code().category() == ErrnoCategory() &&
                se.code().value() == ECONNRESET)
                return 4;
        }

        try {
            FindRetrowNested<SocketProtocolError>(e);
        } catch (...) {
            return 4;
        }
    }

    return 2;
}

/*
 * public
 *
 */

LbHttpConnection *
NewLbHttpConnection(LbInstance &instance,
                    const LbListenerConfig &listener,
                    const LbGoto &destination,
                    SslFactory *ssl_factory,
                    UniqueSocketDescriptor &&fd, SocketAddress address)
{
    assert(listener.destination.GetProtocol() == LbProtocol::HTTP);

    /* determine the local socket address */
    StaticSocketAddress local_address = fd.GetLocalAddress();

    auto fd_type = FdType::FD_TCP;

    SslFilter *ssl_filter = nullptr;
    const SocketFilter *filter = nullptr;
    void *filter_ctx = nullptr;

    if (ssl_factory != nullptr) {
        ssl_filter = ssl_filter_new(*ssl_factory);
        filter = &thread_socket_filter;
        filter_ctx =
            new ThreadSocketFilter(instance.event_loop,
                                   thread_pool_get_queue(instance.event_loop),
                                   &ssl_filter_get_handler(*ssl_filter));
    }

    struct pool *pool = pool_new_linear(instance.root_pool,
                                        "http_connection",
                                        2048);
    pool_set_major(pool);

    auto *connection = NewFromPool<LbHttpConnection>(*pool, *pool, instance,
                                                     listener, destination,
                                                     address);
    connection->ssl_filter = ssl_filter;

    instance.http_connections.push_back(*connection);

    connection->http = http_server_connection_new(pool, instance.event_loop,
                                                  fd.Release(), fd_type,
                                                  filter, filter_ctx,
                                                  local_address.IsDefined()
                                                  ? (SocketAddress)local_address
                                                  : nullptr,
                                                  address,
                                                  false,
                                                  *connection);
    return connection;
}

void
LbHttpConnection::Destroy()
{
    assert(!instance.http_connections.empty());

    auto &connections = instance.http_connections;
    connections.erase(connections.iterator_to(*this));

    DeleteUnrefTrashPool(pool, this);
}

void
LbHttpConnection::CloseAndDestroy()
{
    assert(listener.destination.GetProtocol() == LbProtocol::HTTP);
    assert(http != nullptr);

    http_server_connection_close(http);

    Destroy();
}

void
LbHttpConnection::SendError(HttpServerRequest &request, std::exception_ptr ep)
{
    const char *msg = listener.verbose_response
        ? p_strdup(request.pool, GetFullMessage(ep).c_str())
        : "Bad gateway";

    http_server_send_message(&request, HTTP_STATUS_BAD_GATEWAY, msg);
}

void
LbHttpConnection::LogSendError(HttpServerRequest &request,
                               std::exception_ptr ep)
{
    logger(2, ep);
    SendError(request, ep);
}

static void
SendResponse(HttpServerRequest &request,
             const LbSimpleHttpResponse &response)
{
    assert(response.IsDefined());

    http_server_simple_response(request, response.status,
                                response.location.empty() ? nullptr : response.location.c_str(),
                                response.message.empty() ? nullptr : response.message.c_str());
}

/*
 * http connection handler
 *
 */

void
LbHttpConnection::HandleHttpRequest(HttpServerRequest &request,
                                    CancellablePointer &cancel_ptr)
{
    ++instance.http_request_counter;

    request_start_time = std::chrono::steady_clock::now();
    canonical_host = nullptr;

    if (!uri_path_verify_quick(request.uri)) {
        request.CheckCloseUnusedBody();
        http_server_send_message(&request, HTTP_STATUS_BAD_REQUEST,
                                 "Malformed request URI");
        return;
    }

    HandleHttpRequest(initial_destination, request, cancel_ptr);
}

void
LbHttpConnection::HandleHttpRequest(const LbGoto &destination,
                                    HttpServerRequest &request,
                                    CancellablePointer &cancel_ptr)
{
    const auto &goto_ = destination.FindRequestLeaf(request);
    if (goto_.response != nullptr) {
        request.CheckCloseUnusedBody();
        SendResponse(request, *goto_.response);
        return;
    }

    if (goto_.lua != nullptr) {
        InvokeLua(*goto_.lua, request, cancel_ptr);
        return;
    }

    if (goto_.translation != nullptr) {
        AskTranslationServer(*goto_.translation, request, cancel_ptr);
        return;
    }

    assert(goto_.cluster != nullptr);
    ForwardHttpRequest(*goto_.cluster, request, cancel_ptr);
}

void
LbHttpConnection::ForwardHttpRequest(LbCluster &cluster,
                                     HttpServerRequest &request,
                                     CancellablePointer &cancel_ptr)
{
    ::ForwardHttpRequest(*this, request, cluster, cancel_ptr);
}

void
LbHttpConnection::LogHttpRequest(HttpServerRequest &request,
                                 http_status_t status, int64_t length,
                                 uint64_t bytes_received, uint64_t bytes_sent)
{
    if (instance.access_log != nullptr)
        instance.access_log->Log(request, nullptr,
                                 request.headers.Get("referer"),
                                 request.headers.Get("user-agent"),
                                 status, length,
                                 bytes_received, bytes_sent,
                                 std::chrono::steady_clock::now() - request_start_time);
}

void
LbHttpConnection::HttpConnectionError(std::exception_ptr e)
{
    logger(HttpServerLogLevel(e), e);

    assert(http != nullptr);
    http = nullptr;

    Destroy();
}

void
LbHttpConnection::HttpConnectionClosed()
{
    assert(http != nullptr);
    http = nullptr;

    Destroy();
}

std::string
LbHttpConnection::MakeLoggerDomain() const noexcept
{
    return "listener='" + listener.name
        + "' cluster='" + listener.destination.GetName()
        + "' client='" + client_address
        + "'";
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) MZ3 Project Team All rights reserved.
 * Code licensed under the BSD License:
 * http://www.mz3.jp/license.txt
 */
#include "stdafx.h"
#include "MZ3.h"
#include "Mz3GroupData.h"
#include "util_base.h"
#include "util_mz3.h"
#include "inifile.h"

/**
 * gbvy[Wp̏
 *
 * O[vXgƂ̔z̃Xg̐B
 */
bool Mz3GroupData::initForTopPage(AccessTypeInfo& accessTypeInfo, const InitializeType initType)
{
	this->groups.clear();
	this->services = initType.strSelectedServices;

	// T[rX̏ꍇ͑SIƂ݂ȂST[rXǉ
	if (this->services.empty()) {
		for (size_t idx=0; idx<theApp.m_luaServices.size(); idx++) {
			this->services += " ";
			this->services += theApp.m_luaServices[idx].name;
		}
	}

	// CxgnȟĂяo
	util::CallMZ3ScriptHookFunctions("", "creating_default_group", this);

	return true;
}

/**
 * JeSURL̈ڍs
 *
 * JeSύX\(:"݂Ȃecho"  "݂Ȃ̃{CX")
 */
inline CString getNormalizedCategoryUrl(LPCTSTR default_category_url,
										CStringA category_url,
										ACCESS_TYPE category_type,
										std::string& category_name)
{

#ifdef BT_MZ3
	// `init@C̈ڍs
	if (category_type == ACCESS_LIST_FOOTSTEP && category_url == "show_log.pl") {
		// URLAPIpURLɒu(ftHgURL̗p)
		return default_category_url;
	}

	/* Ĺu}C~Nꗗv "list_friend.pl"  API ɈڍsƂ̏
	if (category_type == ACCESS_LIST_FRIEND && category_url == "list_friend.pl") {
		// }C~NꗗURLAPIpURLɒu(ftHgURL̗p)
		return default_category_url;
	}
	*/

	if (category_type == ACCESS_LIST_FRIEND) {
		// }C~NꗗURL̓ftHgURL("list_friend.pl"  API  URL ͔p~Ƃ)
		return default_category_url;
	}

	if (category_type == ACCESS_MIXI_RECENT_VOICE &&
		category_url.Find("recent_echo.pl")>=0)
	{
		// ڍsFrecent_echo.pl  recent_voice.pl ɏ
		CString strCategoryUrl(category_url);
		strCategoryUrl.Replace(L"recent_echo.pl",
							   L"recent_voice.pl");
		category_name = "݂Ȃ̃{CX";
		return strCategoryUrl;
	}

	if (category_type == ACCESS_MIXI_RECENT_VOICE &&
		category_url.Find("res_echo.pl")>=0 &&
		strstr(category_name.c_str(), "ԐM")!=NULL)
	{
		// ڍsFres_voice.pl  2010/04/14 mixidlύXŏ̂ōڂƂĂ폜
		return L"";
	}
#endif

	if (category_type == ACCESS_TWITTER_FRIENDS_TIMELINE &&
		category_url.Find("http://twitter.com/statuses/friends_timeline.xml")>=0)
	{
		// ڍsFfriends_timeline.xml  home_timeline.xml ɏ
		CString strCategoryUrl(category_url);
		strCategoryUrl.Replace(L"http://twitter.com/statuses/friends_timeline.xml",
							   L"http://twitter.com/statuses/home_timeline.xml");
		return strCategoryUrl;
	}

	return CString(category_url);
}

/**
 * group ɃJeSǉB
 *
 * category_url  NULL ܂͋̏ꍇ́AJeSʂɉftHgURLw肷B
 * JeSʂɉJ^Cvw肷B
 */
bool Mz3GroupData::appendCategoryByIniData(
	AccessTypeInfo& accessTypeInfo,
	CGroupItem& group, std::string category_name, ACCESS_TYPE category_type, const char* category_url, bool bCruise )
{
	// ftHgURLicategory_url w̏ꍇɗpURLj
	LPCTSTR default_category_url = accessTypeInfo.getDefaultCategoryURL(category_type);

	AccessTypeInfo::BODY_INDICATE_TYPE colType1 = accessTypeInfo.getBodyHeaderCol1Type(category_type);
	AccessTypeInfo::BODY_INDICATE_TYPE colType2 = accessTypeInfo.getBodyHeaderCol2Type(category_type);
	AccessTypeInfo::BODY_INDICATE_TYPE colType3 = accessTypeInfo.getBodyHeaderCol3Type(category_type);

	if (colType1==AccessTypeInfo::BODY_INDICATE_TYPE_NONE ||
		colType2==AccessTypeInfo::BODY_INDICATE_TYPE_NONE)
	{
		// T|[gÔߒǉI
//		MZ3LOGGER_ERROR(L"T|[gÔߒǉ܂B");
		return false;
	}

	// ANZXʕɔڍs
#ifdef BT_MZ3
	switch( category_type ) {
	case ACCESS_LIST_FAVORITE_USER:
		// Cɓ胆[U
		if (category_url != NULL && strstr(category_url, "kind=community")!=NULL) {
			// uCɓR~vƂď
			category_type = ACCESS_LIST_FAVORITE_COMMUNITY;
		}
		break;
	}
#endif

	// URL w肳Ă΂ URL pB
	// AǍÂURLɂĂ͈ڍssB
	CString url = default_category_url;
	if (category_url!=NULL && strlen(category_url) > 0) {

		// JeSURL̈ڍs
		url = getNormalizedCategoryUrl(default_category_url, category_url, category_type, category_name);
		if (url.IsEmpty()) {
			return true;
		}
	}

	static CCategoryItem item;
	item.init(
		util::my_mbstowcs(category_name).c_str(),
		url,
		category_type,
		group.categories.size(),
		colType1, colType2, colType3 );
	item.m_bCruise = bCruise;
	group.categories.push_back( item );

	return true;
}

/**
 * L̃}bv𐶐B
 *
 * JeSʕ  JeS
 */
void Mz3GroupDataInifileHelper::InitMap(AccessTypeInfo& accessTypeInfo) {
	category_string2type.RemoveAll();
	category_string2type.InitHashTable( 20 );

	// AccessTypeInfo ̃VACYL[enbVe[u\z
	AccessTypeInfo::ACCESS_TYPE_TO_DATA_MAP::iterator it;
	for (it=accessTypeInfo.m_map.begin(); it!=accessTypeInfo.m_map.end(); it++) {
		ACCESS_TYPE accessType = it->first;
		AccessTypeInfo::Data& data = it->second;

		switch (data.infoType) {
		case AccessTypeInfo::INFO_TYPE_CATEGORY:
			// category_string2type ̍\z
			if (!data.serializeKey.empty()) {
				category_string2type[ util::my_mbstowcs(data.serializeKey.c_str()).c_str() ] = accessType;
			}
			break;

		default:
			// nothing to do.
			break;
		}
	}
}

/**
 * ini t@CiO[v`t@Cj Mz3GroupData 𐶐B
 */
bool Mz3GroupDataReader::load( AccessTypeInfo& accessTypeInfo, Mz3GroupData& target, const CString& inifilename )
{
	target.groups.clear();

	inifile::IniFile inifile;
	Mz3GroupDataInifileHelper helper(accessTypeInfo);

	// O[v`t@C̃[h
	if(! inifile.Load( inifilename ) ) {
		return false;
	}

	// \[gς݃ZNVXg擾
	std::vector<std::string> group_section_names;
	{
		// ZNVꗗ擾B
		group_section_names = inifile.GetSectionNames();

		// ZNVꗗ̂uGroupvŎn܂̂𒊏oB
		for( size_t i=0; i<group_section_names.size(); ) {
			if( strncmp( group_section_names[i].c_str(), "Group", 5 ) != 0 ) {
				// uGroupvŎn܂Ȃ̂ŏB
				group_section_names.erase( group_section_names.begin()+i );
			}else{
				i++;
			}
		}

		// \[g
		sort( group_section_names.begin(), group_section_names.end() );
	}

	// eZNVɑ΂Ēǉs
	for( size_t i=0; i<group_section_names.size(); i++ ) {
		const char* section_name = group_section_names[i].c_str();

		// "Name" ̒l擾AO[vƂB
		std::string group_name = inifile.GetValue( "Name", section_name );
		if( group_name.empty() ) {
			continue;
		}

		// "Type" ̒l擾AO[vʂƂB
		// O[v̎ʂ͔p~BS GROUP_GENERAL ƂB
		ACCESS_TYPE group_type = ACCESS_GROUP_GENERAL;

		// "Url" ̒l擾AURLƂB
		std::string url = inifile.GetValue( "Url", section_name );

		// O[v쐬
		CGroupItem group;
		group.init( util::my_mbstowcs(group_name).c_str(), util::my_mbstowcs(url).c_str(), group_type );

		// "CategoryXX" ̒l擾ABXX  [01,30] ƂB
		for( int j=0; j<30; j++ ) {
			CStringA key;
			key.Format( "Category%02d", j+1 );

			// "CategoryXX" ̒l݂ȂΏIB
			if(! inifile.RecordExists( (const char*)key, section_name ) ) {
				break;
			}

			// "CategoryXX" ̒l擾B
			std::string value = inifile.GetValue( (const char*)key, section_name );

			// J}؂ŕ񃊃XgB
			std::vector<std::string> values;
			util::split_by_comma( values, value );
			if( values.size() < 2 ) {
				continue;
			}

			// 񃊃Xg̑1vfJeSƂB
			std::string& category_name = values[0];

			// 񃊃Xg̑2vfJeSʂƂB
			// JeSʖJeSʕϊsB
			ACCESS_TYPE category_type = helper.CategoryString2Type( util::my_mbstowcs(values[1]).c_str() );
			if( category_type == ACCESS_INVALID ) {
				continue;
			}

			// 񃊃Xg̑3vfURLƂB
			// ݂Ȃꍇ̓JeSʂ̃ftHglpB
			const char* category_url = NULL;
			if( values.size() >= 3 ) {
				category_url = values[2].c_str();
			}

			// 񃊃Xg̑4vftOƂB
			// ݂ȂꍇȂƂB
			bool bCruise = false;
			if( values.size() >= 4 ) {
				bCruise = atoi(values[3].c_str()) != 0 ? true : false;
			}

			// JeSǉB
			target.appendCategoryByIniData( accessTypeInfo, group, category_name, category_type, category_url, bCruise );
		}

		// JeSPȏȂAgroups ɒǉB
		if( group.categories.size() >= 1 ) {
			target.groups.push_back( group );
		}
	}

	// O[vvf[ȂIB
	if( target.groups.empty() ) {
		return false;
	}

	return true;
}

/**
 * Mz3GroupData IuWFNg ini t@CiO[v`t@CjB
 */
bool Mz3GroupDataWriter::save( AccessTypeInfo& accessTypeInfo, const Mz3GroupData& target, const CString& inifilename )
{
	inifile::IniFile inifile;

	const int n = target.groups.size();
	for( int i=0; i<n; i++ ) {
		const CGroupItem& group = target.groups[i];

		if (!group.bSaveToGroupFile) {
			continue;
		}

		// ZNV
		CStringA strSectionName;
		strSectionName.Format( "Group%02d", i+1 );

		// Name o
		inifile.SetValue( L"Name", group.name, strSectionName );

		// Type o( GROUP_GENERAL Ƃ)
		inifile.SetValue( "Type", accessTypeInfo.getSerializeKey(ACCESS_GROUP_GENERAL), (LPCSTR)strSectionName );

		// Url o
		inifile.SetValue( L"Url", group.mixi.GetURL(), strSectionName );

		// CategoryXX o
		int nc = group.categories.size();
		int categoryNumber = 1;
		for( int j=0; j<nc; j++ ) {
			// L[
			CString key;
			key.Format( L"Category%02d", categoryNumber );

			// EӒl
			// EӒlɁAuJeŚvAuJeSʕvAuURLv
			const CCategoryItem& item = group.categories[j];
			CString categoryString = util::my_mbstowcs(accessTypeInfo.getSerializeKey(item.m_mixi.GetAccessType())).c_str();
			if (categoryString.IsEmpty() || item.bSaveToGroupFile==false)
				continue;

			CString value;
			value.Format( L"%s,%s,%s,%d",
				item.m_name,
				categoryString,
				item.m_mixi.GetURL(),
				item.m_bCruise ? 1 : 0
				);

			// o
			inifile.SetValue( key, value, strSectionName );
			categoryNumber ++;
		}
	}

	// ۑ
	return inifile.Save( inifilename, false );
}
<commit_msg>-- http://twitter.com/statuses/home_timeline.xml を http://api.twitter.com/1/statuses/home_timeline.xml に変更<commit_after>/*
 * Copyright (c) MZ3 Project Team All rights reserved.
 * Code licensed under the BSD License:
 * http://www.mz3.jp/license.txt
 */
#include "stdafx.h"
#include "MZ3.h"
#include "Mz3GroupData.h"
#include "util_base.h"
#include "util_mz3.h"
#include "inifile.h"

/**
 * gbvy[Wp̏
 *
 * O[vXgƂ̔z̃Xg̐B
 */
bool Mz3GroupData::initForTopPage(AccessTypeInfo& accessTypeInfo, const InitializeType initType)
{
	this->groups.clear();
	this->services = initType.strSelectedServices;

	// T[rX̏ꍇ͑SIƂ݂ȂST[rXǉ
	if (this->services.empty()) {
		for (size_t idx=0; idx<theApp.m_luaServices.size(); idx++) {
			this->services += " ";
			this->services += theApp.m_luaServices[idx].name;
		}
	}

	// CxgnȟĂяo
	util::CallMZ3ScriptHookFunctions("", "creating_default_group", this);

	return true;
}

/**
 * JeSURL̈ڍs
 *
 * JeSύX\(:"݂Ȃecho"  "݂Ȃ̃{CX")
 */
inline CString getNormalizedCategoryUrl(LPCTSTR default_category_url,
										CStringA category_url,
										ACCESS_TYPE category_type,
										std::string& category_name)
{

#ifdef BT_MZ3
	// `init@C̈ڍs
	if (category_type == ACCESS_LIST_FOOTSTEP && category_url == "show_log.pl") {
		// URLAPIpURLɒu(ftHgURL̗p)
		return default_category_url;
	}

	/* Ĺu}C~Nꗗv "list_friend.pl"  API ɈڍsƂ̏
	if (category_type == ACCESS_LIST_FRIEND && category_url == "list_friend.pl") {
		// }C~NꗗURLAPIpURLɒu(ftHgURL̗p)
		return default_category_url;
	}
	*/

	if (category_type == ACCESS_LIST_FRIEND) {
		// }C~NꗗURL̓ftHgURL("list_friend.pl"  API  URL ͔p~Ƃ)
		return default_category_url;
	}

	if (category_type == ACCESS_MIXI_RECENT_VOICE &&
		category_url.Find("recent_echo.pl")>=0)
	{
		// ڍsFrecent_echo.pl  recent_voice.pl ɏ
		CString strCategoryUrl(category_url);
		strCategoryUrl.Replace(L"recent_echo.pl",
							   L"recent_voice.pl");
		category_name = "݂Ȃ̃{CX";
		return strCategoryUrl;
	}

	if (category_type == ACCESS_MIXI_RECENT_VOICE &&
		category_url.Find("res_echo.pl")>=0 &&
		strstr(category_name.c_str(), "ԐM")!=NULL)
	{
		// ڍsFres_voice.pl  2010/04/14 mixidlύXŏ̂ōڂƂĂ폜
		return L"";
	}
#endif

	if (category_type == ACCESS_TWITTER_FRIENDS_TIMELINE) {
		// ڍsFfriends_timeline.xml => home_timeline.xml
		if (category_url.Find("http://twitter.com/statuses/friends_timeline.xml")>=0) {
			category_url.Replace("http://twitter.com/statuses/friends_timeline.xml",
								 "http://api.twitter.com/1/statuses/home_timeline.xml");
			return CString(category_url);
		}

		// ڍsFhome_timeline.xml (BASICFؗp) => api p URL
		if (category_url.Find("http://twitter.com/statuses/home_timeline.xml")>=0) {
			category_url.Replace("http://twitter.com/statuses/home_timeline.xml",
								 "http://api.twitter.com/1/statuses/home_timeline.xml");
			return CString(category_url);
		}
	}

	return CString(category_url);
}

/**
 * group ɃJeSǉB
 *
 * category_url  NULL ܂͋̏ꍇ́AJeSʂɉftHgURLw肷B
 * JeSʂɉJ^Cvw肷B
 */
bool Mz3GroupData::appendCategoryByIniData(
	AccessTypeInfo& accessTypeInfo,
	CGroupItem& group, std::string category_name, ACCESS_TYPE category_type, const char* category_url, bool bCruise )
{
	// ftHgURLicategory_url w̏ꍇɗpURLj
	LPCTSTR default_category_url = accessTypeInfo.getDefaultCategoryURL(category_type);

	AccessTypeInfo::BODY_INDICATE_TYPE colType1 = accessTypeInfo.getBodyHeaderCol1Type(category_type);
	AccessTypeInfo::BODY_INDICATE_TYPE colType2 = accessTypeInfo.getBodyHeaderCol2Type(category_type);
	AccessTypeInfo::BODY_INDICATE_TYPE colType3 = accessTypeInfo.getBodyHeaderCol3Type(category_type);

	if (colType1==AccessTypeInfo::BODY_INDICATE_TYPE_NONE ||
		colType2==AccessTypeInfo::BODY_INDICATE_TYPE_NONE)
	{
		// T|[gÔߒǉI
//		MZ3LOGGER_ERROR(L"T|[gÔߒǉ܂B");
		return false;
	}

	// ANZXʕɔڍs
#ifdef BT_MZ3
	switch( category_type ) {
	case ACCESS_LIST_FAVORITE_USER:
		// Cɓ胆[U
		if (category_url != NULL && strstr(category_url, "kind=community")!=NULL) {
			// uCɓR~vƂď
			category_type = ACCESS_LIST_FAVORITE_COMMUNITY;
		}
		break;
	}
#endif

	// URL w肳Ă΂ URL pB
	// AǍÂURLɂĂ͈ڍssB
	CString url = default_category_url;
	if (category_url!=NULL && strlen(category_url) > 0) {

		// JeSURL̈ڍs
		url = getNormalizedCategoryUrl(default_category_url, category_url, category_type, category_name);
		if (url.IsEmpty()) {
			return true;
		}
	}

	static CCategoryItem item;
	item.init(
		util::my_mbstowcs(category_name).c_str(),
		url,
		category_type,
		group.categories.size(),
		colType1, colType2, colType3 );
	item.m_bCruise = bCruise;
	group.categories.push_back( item );

	return true;
}

/**
 * L̃}bv𐶐B
 *
 * JeSʕ  JeS
 */
void Mz3GroupDataInifileHelper::InitMap(AccessTypeInfo& accessTypeInfo) {
	category_string2type.RemoveAll();
	category_string2type.InitHashTable( 20 );

	// AccessTypeInfo ̃VACYL[enbVe[u\z
	AccessTypeInfo::ACCESS_TYPE_TO_DATA_MAP::iterator it;
	for (it=accessTypeInfo.m_map.begin(); it!=accessTypeInfo.m_map.end(); it++) {
		ACCESS_TYPE accessType = it->first;
		AccessTypeInfo::Data& data = it->second;

		switch (data.infoType) {
		case AccessTypeInfo::INFO_TYPE_CATEGORY:
			// category_string2type ̍\z
			if (!data.serializeKey.empty()) {
				category_string2type[ util::my_mbstowcs(data.serializeKey.c_str()).c_str() ] = accessType;
			}
			break;

		default:
			// nothing to do.
			break;
		}
	}
}

/**
 * ini t@CiO[v`t@Cj Mz3GroupData 𐶐B
 */
bool Mz3GroupDataReader::load( AccessTypeInfo& accessTypeInfo, Mz3GroupData& target, const CString& inifilename )
{
	target.groups.clear();

	inifile::IniFile inifile;
	Mz3GroupDataInifileHelper helper(accessTypeInfo);

	// O[v`t@C̃[h
	if(! inifile.Load( inifilename ) ) {
		return false;
	}

	// \[gς݃ZNVXg擾
	std::vector<std::string> group_section_names;
	{
		// ZNVꗗ擾B
		group_section_names = inifile.GetSectionNames();

		// ZNVꗗ̂uGroupvŎn܂̂𒊏oB
		for( size_t i=0; i<group_section_names.size(); ) {
			if( strncmp( group_section_names[i].c_str(), "Group", 5 ) != 0 ) {
				// uGroupvŎn܂Ȃ̂ŏB
				group_section_names.erase( group_section_names.begin()+i );
			}else{
				i++;
			}
		}

		// \[g
		sort( group_section_names.begin(), group_section_names.end() );
	}

	// eZNVɑ΂Ēǉs
	for( size_t i=0; i<group_section_names.size(); i++ ) {
		const char* section_name = group_section_names[i].c_str();

		// "Name" ̒l擾AO[vƂB
		std::string group_name = inifile.GetValue( "Name", section_name );
		if( group_name.empty() ) {
			continue;
		}

		// "Type" ̒l擾AO[vʂƂB
		// O[v̎ʂ͔p~BS GROUP_GENERAL ƂB
		ACCESS_TYPE group_type = ACCESS_GROUP_GENERAL;

		// "Url" ̒l擾AURLƂB
		std::string url = inifile.GetValue( "Url", section_name );

		// O[v쐬
		CGroupItem group;
		group.init( util::my_mbstowcs(group_name).c_str(), util::my_mbstowcs(url).c_str(), group_type );

		// "CategoryXX" ̒l擾ABXX  [01,30] ƂB
		for( int j=0; j<30; j++ ) {
			CStringA key;
			key.Format( "Category%02d", j+1 );

			// "CategoryXX" ̒l݂ȂΏIB
			if(! inifile.RecordExists( (const char*)key, section_name ) ) {
				break;
			}

			// "CategoryXX" ̒l擾B
			std::string value = inifile.GetValue( (const char*)key, section_name );

			// J}؂ŕ񃊃XgB
			std::vector<std::string> values;
			util::split_by_comma( values, value );
			if( values.size() < 2 ) {
				continue;
			}

			// 񃊃Xg̑1vfJeSƂB
			std::string& category_name = values[0];

			// 񃊃Xg̑2vfJeSʂƂB
			// JeSʖJeSʕϊsB
			ACCESS_TYPE category_type = helper.CategoryString2Type( util::my_mbstowcs(values[1]).c_str() );
			if( category_type == ACCESS_INVALID ) {
				continue;
			}

			// 񃊃Xg̑3vfURLƂB
			// ݂Ȃꍇ̓JeSʂ̃ftHglpB
			const char* category_url = NULL;
			if( values.size() >= 3 ) {
				category_url = values[2].c_str();
			}

			// 񃊃Xg̑4vftOƂB
			// ݂ȂꍇȂƂB
			bool bCruise = false;
			if( values.size() >= 4 ) {
				bCruise = atoi(values[3].c_str()) != 0 ? true : false;
			}

			// JeSǉB
			target.appendCategoryByIniData( accessTypeInfo, group, category_name, category_type, category_url, bCruise );
		}

		// JeSPȏȂAgroups ɒǉB
		if( group.categories.size() >= 1 ) {
			target.groups.push_back( group );
		}
	}

	// O[vvf[ȂIB
	if( target.groups.empty() ) {
		return false;
	}

	return true;
}

/**
 * Mz3GroupData IuWFNg ini t@CiO[v`t@CjB
 */
bool Mz3GroupDataWriter::save( AccessTypeInfo& accessTypeInfo, const Mz3GroupData& target, const CString& inifilename )
{
	inifile::IniFile inifile;

	const int n = target.groups.size();
	for( int i=0; i<n; i++ ) {
		const CGroupItem& group = target.groups[i];

		if (!group.bSaveToGroupFile) {
			continue;
		}

		// ZNV
		CStringA strSectionName;
		strSectionName.Format( "Group%02d", i+1 );

		// Name o
		inifile.SetValue( L"Name", group.name, strSectionName );

		// Type o( GROUP_GENERAL Ƃ)
		inifile.SetValue( "Type", accessTypeInfo.getSerializeKey(ACCESS_GROUP_GENERAL), (LPCSTR)strSectionName );

		// Url o
		inifile.SetValue( L"Url", group.mixi.GetURL(), strSectionName );

		// CategoryXX o
		int nc = group.categories.size();
		int categoryNumber = 1;
		for( int j=0; j<nc; j++ ) {
			// L[
			CString key;
			key.Format( L"Category%02d", categoryNumber );

			// EӒl
			// EӒlɁAuJeŚvAuJeSʕvAuURLv
			const CCategoryItem& item = group.categories[j];
			CString categoryString = util::my_mbstowcs(accessTypeInfo.getSerializeKey(item.m_mixi.GetAccessType())).c_str();
			if (categoryString.IsEmpty() || item.bSaveToGroupFile==false)
				continue;

			CString value;
			value.Format( L"%s,%s,%s,%d",
				item.m_name,
				categoryString,
				item.m_mixi.GetURL(),
				item.m_bCruise ? 1 : 0
				);

			// o
			inifile.SetValue( key, value, strSectionName );
			categoryNumber ++;
		}
	}

	// ۑ
	return inifile.Save( inifilename, false );
}
<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file LexLua.cxx
 ** Lexer for Lua language.
 **
 ** Written by Paul Winwood.
 ** Folder by Alexey Yutkin.
 ** Modified by Marcos E. Wurzius & Philippe Lhoste
 **/

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <fcntl.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static inline bool IsAWordChar(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '.');
}

static inline bool IsAWordStart(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

static inline bool IsANumberChar(const int ch) {
	// Not exactly following number definition (several dots are seen as OK, etc.)
	// but probably enough in most cases.
	return (ch < 0x80) &&
	        (isdigit(ch) || toupper(ch) == 'E' ||
             ch == '.' || ch == '-' || ch == '+');
}

static inline bool IsLuaOperator(int ch) {
	if (ch >= 0x80 || isalnum(ch)) {
		return false;
	}
	// '.' left out as it is used to make up numbers
	if (ch == '*' || ch == '/' || ch == '-' || ch == '+' ||
		ch == '(' || ch == ')' || ch == '=' ||
		ch == '{' || ch == '}' || ch == '~' ||
		ch == '[' || ch == ']' || ch == ';' ||
		ch == '<' || ch == '>' || ch == ',' ||
		ch == '.' || ch == '^' || ch == '%' || ch == ':') {
		return true;
	}
	return false;
}

static void ColouriseLuaDoc(
	unsigned int startPos,
	int length,
	int initStyle,
	WordList *keywordlists[],
	Accessor &styler) {

	WordList &keywords = *keywordlists[0];
	WordList &keywords2 = *keywordlists[1];
	WordList &keywords3 = *keywordlists[2];
	WordList &keywords4 = *keywordlists[3];
	WordList &keywords5 = *keywordlists[4];
	WordList &keywords6 = *keywordlists[5];
	WordList &keywords7 = *keywordlists[6];
	WordList &keywords8 = *keywordlists[7];

	int currentLine = styler.GetLine(startPos);
	// Initialize the literal string [[ ... ]] nesting level, if we are inside such a string.
	int literalStringLevel = 0;
	if (initStyle == SCE_LUA_LITERALSTRING) {
		literalStringLevel = styler.GetLineState(currentLine - 1);
	}
	// Initialize the block comment --[[ ... ]] nesting level, if we are inside such a comment
	int blockCommentLevel = 0;
	if (initStyle == SCE_LUA_COMMENT) {
		blockCommentLevel = styler.GetLineState(currentLine - 1);
	}

	// Do not leak onto next line
	if (initStyle == SCE_LUA_STRINGEOL) {
		initStyle = SCE_LUA_DEFAULT;
	}

	StyleContext sc(startPos, length, initStyle, styler);
	if (startPos == 0 && sc.ch == '#') {
		// shbang line: # is a comment only if first char of the script
		sc.SetState(SCE_LUA_COMMENTLINE);
	}
	for (; sc.More(); sc.Forward()) {
		if (sc.atLineEnd) {
			// Update the line state, so it can be seen by next line
			currentLine = styler.GetLine(sc.currentPos);
			switch (sc.state) {
			case SCE_LUA_LITERALSTRING:
				// Inside a literal string, we set the line state
				styler.SetLineState(currentLine, literalStringLevel);
				break;
			case SCE_LUA_COMMENT: 	// Block comment
				// Inside a block comment, we set the line state
				styler.SetLineState(currentLine, blockCommentLevel);
				break;
			default:
				// Reset the line state
				styler.SetLineState(currentLine, 0);
				break;
			}
		}
		if (sc.atLineStart && (sc.state == SCE_LUA_STRING)) {
			// Prevent SCE_LUA_STRINGEOL from leaking back to previous line
			sc.SetState(SCE_LUA_STRING);
		}

		// Handle string line continuation
		if ((sc.state == SCE_LUA_STRING || sc.state == SCE_LUA_CHARACTER) &&
		        sc.ch == '\\') {
			if (sc.chNext == '\n' || sc.chNext == '\r') {
				sc.Forward();
				if (sc.ch == '\r' && sc.chNext == '\n') {
					sc.Forward();
				}
				continue;
			}
		}

		// Determine if the current state should terminate.
		if (sc.state == SCE_LUA_OPERATOR) {
			sc.SetState(SCE_LUA_DEFAULT);
		} else if (sc.state == SCE_LUA_NUMBER) {
			// We stop the number definition on non-numerical non-dot non-eE non-sign char
			if (!IsANumberChar(sc.ch)) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_IDENTIFIER) {
			if (!IsAWordChar(sc.ch)) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (keywords.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD);
				} else if (keywords2.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD2);
				} else if (keywords3.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD3);
				} else if (keywords4.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD4);
				} else if (keywords5.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD5);
				} else if (keywords6.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD6);
				} else if (keywords6.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD6);
				} else if (keywords7.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD7);
				} else if (keywords8.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD8);
				}
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_COMMENTLINE ) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_PREPROCESSOR ) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_STRING) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\"') {
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_LUA_STRINGEOL);
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_CHARACTER) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\'') {
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_LUA_STRINGEOL);
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_LITERALSTRING) {
			if (sc.Match('[', '[')) {
				literalStringLevel++;
				sc.Forward();
				sc.SetState(SCE_LUA_LITERALSTRING);
			} else if (sc.Match(']', ']') && literalStringLevel > 0) {
				literalStringLevel--;
				sc.Forward();
				if (literalStringLevel == 0) {
					sc.ForwardSetState(SCE_LUA_DEFAULT);
				}
			}
		} else if (sc.state == SCE_LUA_COMMENT) {	// Lua 5.0's block comment
			if (sc.Match('[', '[')) {
				blockCommentLevel++;
				sc.Forward();
			} else if (sc.Match(']', ']') && blockCommentLevel > 0) {
				blockCommentLevel--;
				sc.Forward();
				if (blockCommentLevel == 0) {
					sc.ForwardSetState(SCE_LUA_DEFAULT);
				}
			}
		}

		// Determine if a new state should be entered.
		if (sc.state == SCE_LUA_DEFAULT) {
			if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
				sc.SetState(SCE_LUA_NUMBER);
			} else if (IsAWordStart(sc.ch)) {
				sc.SetState(SCE_LUA_IDENTIFIER);
			} else if (sc.Match('\"')) {
				sc.SetState(SCE_LUA_STRING);
			} else if (sc.Match('\'')) {
				sc.SetState(SCE_LUA_CHARACTER);
			} else if (sc.Match('[', '[')) {
				literalStringLevel = 1;
				sc.SetState(SCE_LUA_LITERALSTRING);
				sc.Forward();
			} else if (sc.Match("--[[")) {	// Lua 5.0's block comment
				blockCommentLevel = 1;
				sc.SetState(SCE_LUA_COMMENT);
				sc.Forward(3);
			} else if (sc.Match('-', '-')) {
				sc.SetState(SCE_LUA_COMMENTLINE);
				sc.Forward();
			} else if (sc.atLineStart && sc.Match('$')) {
				sc.SetState(SCE_LUA_PREPROCESSOR);	// Obsolete since Lua 4.0, but still in old code
			} else if (IsLuaOperator(static_cast<char>(sc.ch))) {
				sc.SetState(SCE_LUA_OPERATOR);
			}
		}
	}
	sc.Complete();
}

static void FoldLuaDoc(unsigned int startPos, int length, int /* initStyle */, WordList *[],
                       Accessor &styler) {
	unsigned int lengthDoc = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	int styleNext = styler.StyleAt(startPos);
	char s[10];

	for (unsigned int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (style == SCE_LUA_WORD) {
			if (ch == 'i' || ch == 'd' || ch == 'f' || ch == 'e') {
				for (unsigned int j = 0; j < 8; j++) {
					if (!iswordchar(styler[i + j])) {
						break;
					}
					s[j] = styler[i + j];
					s[j + 1] = '\0';
				}

				if ((strcmp(s, "if") == 0) || (strcmp(s, "do") == 0) || (strcmp(s, "function") == 0)) {
					levelCurrent++;
				}
				if ((strcmp(s, "end") == 0) || (strcmp(s, "elseif") == 0)) {
					levelCurrent--;
				}
			}
		} else if (style == SCE_LUA_OPERATOR) {
			if (ch == '{' || ch == '(') {
				levelCurrent++;
			} else if (ch == '}' || ch == ')') {
				levelCurrent--;
			}
		}

		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0 && foldCompact) {
				lev |= SC_FOLDLEVELWHITEFLAG;
			}
			if ((levelCurrent > levelPrev) && (visibleChars > 0)) {
				lev |= SC_FOLDLEVELHEADERFLAG;
			}
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch)) {
			visibleChars++;
		}
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later

	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

static const char * const luaWordListDesc[] = {
	"Keywords",
	"Basic functions",
	"String, (table) & math functions",
	"(coroutines), I/O & system facilities",
	"XXX",
	"XXX",
	0
};

LexerModule lmLua(SCLEX_LUA, ColouriseLuaDoc, "lua", FoldLuaDoc, luaWordListDesc);
<commit_msg>Fix from Kein-Hong Man to treat .. as an operator rather than part of an identifier.<commit_after>// Scintilla source code edit control
/** @file LexLua.cxx
 ** Lexer for Lua language.
 **
 ** Written by Paul Winwood.
 ** Folder by Alexey Yutkin.
 ** Modified by Marcos E. Wurzius & Philippe Lhoste
 **/

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <fcntl.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static inline bool IsAWordChar(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '.');
}

static inline bool IsAWordStart(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

static inline bool IsANumberChar(const int ch) {
	// Not exactly following number definition (several dots are seen as OK, etc.)
	// but probably enough in most cases.
	return (ch < 0x80) &&
	        (isdigit(ch) || toupper(ch) == 'E' ||
             ch == '.' || ch == '-' || ch == '+');
}

static inline bool IsLuaOperator(int ch) {
	if (ch >= 0x80 || isalnum(ch)) {
		return false;
	}
	// '.' left out as it is used to make up numbers
	if (ch == '*' || ch == '/' || ch == '-' || ch == '+' ||
		ch == '(' || ch == ')' || ch == '=' ||
		ch == '{' || ch == '}' || ch == '~' ||
		ch == '[' || ch == ']' || ch == ';' ||
		ch == '<' || ch == '>' || ch == ',' ||
		ch == '.' || ch == '^' || ch == '%' || ch == ':') {
		return true;
	}
	return false;
}

static void ColouriseLuaDoc(
	unsigned int startPos,
	int length,
	int initStyle,
	WordList *keywordlists[],
	Accessor &styler) {

	WordList &keywords = *keywordlists[0];
	WordList &keywords2 = *keywordlists[1];
	WordList &keywords3 = *keywordlists[2];
	WordList &keywords4 = *keywordlists[3];
	WordList &keywords5 = *keywordlists[4];
	WordList &keywords6 = *keywordlists[5];
	WordList &keywords7 = *keywordlists[6];
	WordList &keywords8 = *keywordlists[7];

	int currentLine = styler.GetLine(startPos);
	// Initialize the literal string [[ ... ]] nesting level, if we are inside such a string.
	int literalStringLevel = 0;
	if (initStyle == SCE_LUA_LITERALSTRING) {
		literalStringLevel = styler.GetLineState(currentLine - 1);
	}
	// Initialize the block comment --[[ ... ]] nesting level, if we are inside such a comment
	int blockCommentLevel = 0;
	if (initStyle == SCE_LUA_COMMENT) {
		blockCommentLevel = styler.GetLineState(currentLine - 1);
	}

	// Do not leak onto next line
	if (initStyle == SCE_LUA_STRINGEOL) {
		initStyle = SCE_LUA_DEFAULT;
	}

	StyleContext sc(startPos, length, initStyle, styler);
	if (startPos == 0 && sc.ch == '#') {
		// shbang line: # is a comment only if first char of the script
		sc.SetState(SCE_LUA_COMMENTLINE);
	}
	for (; sc.More(); sc.Forward()) {
		if (sc.atLineEnd) {
			// Update the line state, so it can be seen by next line
			currentLine = styler.GetLine(sc.currentPos);
			switch (sc.state) {
			case SCE_LUA_LITERALSTRING:
				// Inside a literal string, we set the line state
				styler.SetLineState(currentLine, literalStringLevel);
				break;
			case SCE_LUA_COMMENT: 	// Block comment
				// Inside a block comment, we set the line state
				styler.SetLineState(currentLine, blockCommentLevel);
				break;
			default:
				// Reset the line state
				styler.SetLineState(currentLine, 0);
				break;
			}
		}
		if (sc.atLineStart && (sc.state == SCE_LUA_STRING)) {
			// Prevent SCE_LUA_STRINGEOL from leaking back to previous line
			sc.SetState(SCE_LUA_STRING);
		}

		// Handle string line continuation
		if ((sc.state == SCE_LUA_STRING || sc.state == SCE_LUA_CHARACTER) &&
		        sc.ch == '\\') {
			if (sc.chNext == '\n' || sc.chNext == '\r') {
				sc.Forward();
				if (sc.ch == '\r' && sc.chNext == '\n') {
					sc.Forward();
				}
				continue;
			}
		}

		// Determine if the current state should terminate.
		if (sc.state == SCE_LUA_OPERATOR) {
			sc.SetState(SCE_LUA_DEFAULT);
		} else if (sc.state == SCE_LUA_NUMBER) {
			// We stop the number definition on non-numerical non-dot non-eE non-sign char
			if (!IsANumberChar(sc.ch)) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_IDENTIFIER) {
			if (!IsAWordChar(sc.ch) || sc.Match('.', '.')) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (keywords.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD);
				} else if (keywords2.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD2);
				} else if (keywords3.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD3);
				} else if (keywords4.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD4);
				} else if (keywords5.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD5);
				} else if (keywords6.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD6);
				} else if (keywords6.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD6);
				} else if (keywords7.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD7);
				} else if (keywords8.InList(s)) {
					sc.ChangeState(SCE_LUA_WORD8);
				}
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_COMMENTLINE ) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_PREPROCESSOR ) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_STRING) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\"') {
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_LUA_STRINGEOL);
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_CHARACTER) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\'') {
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_LUA_STRINGEOL);
				sc.ForwardSetState(SCE_LUA_DEFAULT);
			}
		} else if (sc.state == SCE_LUA_LITERALSTRING) {
			if (sc.Match('[', '[')) {
				literalStringLevel++;
				sc.Forward();
				sc.SetState(SCE_LUA_LITERALSTRING);
			} else if (sc.Match(']', ']') && literalStringLevel > 0) {
				literalStringLevel--;
				sc.Forward();
				if (literalStringLevel == 0) {
					sc.ForwardSetState(SCE_LUA_DEFAULT);
				}
			}
		} else if (sc.state == SCE_LUA_COMMENT) {	// Lua 5.0's block comment
			if (sc.Match('[', '[')) {
				blockCommentLevel++;
				sc.Forward();
			} else if (sc.Match(']', ']') && blockCommentLevel > 0) {
				blockCommentLevel--;
				sc.Forward();
				if (blockCommentLevel == 0) {
					sc.ForwardSetState(SCE_LUA_DEFAULT);
				}
			}
		}

		// Determine if a new state should be entered.
		if (sc.state == SCE_LUA_DEFAULT) {
			if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
				sc.SetState(SCE_LUA_NUMBER);
			} else if (IsAWordStart(sc.ch)) {
				sc.SetState(SCE_LUA_IDENTIFIER);
			} else if (sc.Match('\"')) {
				sc.SetState(SCE_LUA_STRING);
			} else if (sc.Match('\'')) {
				sc.SetState(SCE_LUA_CHARACTER);
			} else if (sc.Match('[', '[')) {
				literalStringLevel = 1;
				sc.SetState(SCE_LUA_LITERALSTRING);
				sc.Forward();
			} else if (sc.Match("--[[")) {	// Lua 5.0's block comment
				blockCommentLevel = 1;
				sc.SetState(SCE_LUA_COMMENT);
				sc.Forward(3);
			} else if (sc.Match('-', '-')) {
				sc.SetState(SCE_LUA_COMMENTLINE);
				sc.Forward();
			} else if (sc.atLineStart && sc.Match('$')) {
				sc.SetState(SCE_LUA_PREPROCESSOR);	// Obsolete since Lua 4.0, but still in old code
			} else if (IsLuaOperator(static_cast<char>(sc.ch))) {
				sc.SetState(SCE_LUA_OPERATOR);
			}
		}
	}
	sc.Complete();
}

static void FoldLuaDoc(unsigned int startPos, int length, int /* initStyle */, WordList *[],
                       Accessor &styler) {
	unsigned int lengthDoc = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	int styleNext = styler.StyleAt(startPos);
	char s[10];

	for (unsigned int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (style == SCE_LUA_WORD) {
			if (ch == 'i' || ch == 'd' || ch == 'f' || ch == 'e') {
				for (unsigned int j = 0; j < 8; j++) {
					if (!iswordchar(styler[i + j])) {
						break;
					}
					s[j] = styler[i + j];
					s[j + 1] = '\0';
				}

				if ((strcmp(s, "if") == 0) || (strcmp(s, "do") == 0) || (strcmp(s, "function") == 0)) {
					levelCurrent++;
				}
				if ((strcmp(s, "end") == 0) || (strcmp(s, "elseif") == 0)) {
					levelCurrent--;
				}
			}
		} else if (style == SCE_LUA_OPERATOR) {
			if (ch == '{' || ch == '(') {
				levelCurrent++;
			} else if (ch == '}' || ch == ')') {
				levelCurrent--;
			}
		}

		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0 && foldCompact) {
				lev |= SC_FOLDLEVELWHITEFLAG;
			}
			if ((levelCurrent > levelPrev) && (visibleChars > 0)) {
				lev |= SC_FOLDLEVELHEADERFLAG;
			}
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch)) {
			visibleChars++;
		}
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later

	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

static const char * const luaWordListDesc[] = {
	"Keywords",
	"Basic functions",
	"String, (table) & math functions",
	"(coroutines), I/O & system facilities",
	"XXX",
	"XXX",
	0
};

LexerModule lmLua(SCLEX_LUA, ColouriseLuaDoc, "lua", FoldLuaDoc, luaWordListDesc);
<|endoftext|>


<commit_before>//Copyright (c) 2018 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "MergeInfillLines.h"

namespace cura
{

MergeInfillLines::MergeInfillLines(ExtruderPlan& plan) : extruder_plan(plan)
{
    //Just copy the parameters to their fields.
}

bool MergeInfillLines::mergeInfillLines(std::vector<GCodePath>& paths) const
{
    /* Algorithm overview:
        1. Loop over all lines to see if they can be merged.
        1a. Check if two adjacent lines can be merged.
        1b. If they can, merge both lines into the first line.
        1c. If they are merged, check next that the first line can be merged with
            the line after the second line.
        2. Do a second iteration over all paths to remove the tombstones. */

    std::vector<size_t> remove_path_indices;

    //For each two adjacent lines, see if they can be merged.
    size_t first_path_index = 0;
    size_t second_path_index = 1;
    for (; second_path_index < paths.size(); second_path_index++)
    {
        GCodePath& first_path = paths[first_path_index];
        GCodePath& second_path = paths[second_path_index];

        if (isConvertible(first_path, second_path))
        {
            /* If we combine two lines, the second path is inside the first
            line, so the iteration after that we need to merge the first line
            with the line after the second line, so we do NOT update
            first_path_index. */
            mergeLines(first_path, second_path);
            remove_path_indices.push_back(second_path_index);
        }
        else
        {
            /* If we do not combine, the next iteration we must simply merge the
            second path with the line after it. */
            first_path_index = second_path_index;
        }
    }

    //Delete all removed lines in one pass so that we need to move lines less often.
    if (!remove_path_indices.empty())
    {
        size_t path_index = remove_path_indices[0];
        for (size_t removed_position = 1; removed_position < remove_path_indices.size(); removed_position++)
        {
            for (; path_index < remove_path_indices[removed_position] - removed_position; path_index++)
            {
                paths[path_index] = paths[path_index + removed_position]; //Shift all paths.
            }
        }
        for (; path_index < paths.size() - remove_path_indices.size(); path_index++) //Remaining shifts at the end.
        {
            paths[path_index] = paths[path_index + remove_path_indices.size()];
        }
        paths.resize(path_index);
        return true;
    }
    else
    {
        return false;
    }
}

bool MergeInfillLines::isConvertible(GCodePath& first_path, GCodePath& second_path) const
{
    return false; //TODO.
}

void MergeInfillLines::mergeLines(GCodePath& first_path, const GCodePath& second_path) const
{
    //TODO.
}

}//namespace cura
<commit_msg>Skip travel paths in deciding which two paths to merge<commit_after>//Copyright (c) 2018 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "MergeInfillLines.h"

namespace cura
{

MergeInfillLines::MergeInfillLines(ExtruderPlan& plan) : extruder_plan(plan)
{
    //Just copy the parameters to their fields.
}

bool MergeInfillLines::mergeInfillLines(std::vector<GCodePath>& paths) const
{
    /* Algorithm overview:
        1. Loop over all lines to see if they can be merged.
        1a. Check if two adjacent lines can be merged (skipping travel moves in
            between).
        1b. If they can, merge both lines into the first line.
        1c. If they are merged, check next that the first line can be merged
            with the line after the second line.
        2. Do a second iteration over all paths to remove the tombstones. */

    std::vector<size_t> remove_path_indices;

    //For each two adjacent lines, see if they can be merged.
    size_t first_path_index = 0;
    size_t second_path_index = 1;
    for (; second_path_index < paths.size(); second_path_index++)
    {
        GCodePath& first_path = paths[first_path_index];
        GCodePath& second_path = paths[second_path_index];
        if (second_path.config->isTravelPath())
        {
            continue; //Skip travel paths.
        }

        if (isConvertible(first_path, second_path))
        {
            /* If we combine two lines, the second path is inside the first
            line, so the iteration after that we need to merge the first line
            with the line after the second line, so we do NOT update
            first_path_index. */
            mergeLines(first_path, second_path);
            for (size_t to_delete_index = first_path_index + 1; to_delete_index <= second_path_index; to_delete_index++)
            {
                remove_path_indices.push_back(to_delete_index);
            }
        }
        else
        {
            /* If we do not combine, the next iteration we must simply merge the
            second path with the line after it. */
            first_path_index = second_path_index;
        }
    }

    //Delete all removed lines in one pass so that we need to move lines less often.
    if (!remove_path_indices.empty())
    {
        size_t path_index = remove_path_indices[0];
        for (size_t removed_position = 1; removed_position < remove_path_indices.size(); removed_position++)
        {
            for (; path_index < remove_path_indices[removed_position] - removed_position; path_index++)
            {
                paths[path_index] = paths[path_index + removed_position]; //Shift all paths.
            }
        }
        for (; path_index < paths.size() - remove_path_indices.size(); path_index++) //Remaining shifts at the end.
        {
            paths[path_index] = paths[path_index + remove_path_indices.size()];
        }
        paths.resize(path_index);
        return true;
    }
    else
    {
        return false;
    }
}

bool MergeInfillLines::isConvertible(GCodePath& first_path, GCodePath& second_path) const
{
    return false; //TODO.
}

void MergeInfillLines::mergeLines(GCodePath& first_path, const GCodePath& second_path) const
{
    //TODO.
}

}//namespace cura
<|endoftext|>


<commit_before>#include "checkerboardrender.h"
#include <QTime>

QImage drawCheckerboard(const QImage &imgL, const QImage &imgR, int panX, int panY, int finalwidth, int finalheight, float zoom, QWidget *parent){
    // Default Stereo Draw is Anglaph
    QTime starttime = QTime::currentTime();

    bool first = 1;
    if(parent){
        first = parent->pos().x()%2 == parent->pos().y()%2;
    }
    if(finalwidth <= 0 || finalheight <= 0){
        finalwidth = imgL.width();
        finalheight = imgL.height();
    }

    if(zoom <= 0.0f){
        zoom = qMin((float)finalwidth / (float)imgL.width(), (float)finalheight / (float)imgL.height());
    }

    panX += (finalwidth*0.5f  - imgL.width()  * zoom * 0.5f);
    panY += (finalheight*0.5f - imgL.height() * zoom * 0.5f);

    QImage final(finalwidth,finalheight,QImage::Format_RGB32);

    QRgb *line;
    QRgb *lineL;
    QRgb *lineR;
    for(int y=0;y<final.height();y++){
        line = (QRgb *)final.scanLine(y);
        int cy = (y-panY)/zoom;
        if(cy >= 0 && cy < imgL.height()){
            lineL = (QRgb *)imgL.constScanLine(cy);
            lineR = (QRgb *)imgR.constScanLine(cy);
            for(int x=0;x<final.width();x++){
                int cx = (x-panX)/zoom;
                if(imgL.valid(cx,cy) && imgR.valid(cx,cy)){
                    if(x%2 == y%2){
                        line[x]=lineR[cx];
                    }else{
                        line[x]=lineL[cx];
                    }
                }
                else{
                    line[x] = qRgb(0,0,0);
                }
            }
        }
        else{
            for(int x=0;x<final.width();x++)
                line[x] = qRgb(0,0,0);
        }
    }

    qDebug() << "Draw time: " << starttime.msecsTo(QTime::currentTime()) << "ms";

    return final;
}

<commit_msg>theoretically fixed checkerboard render. (at least I fixed the compiler warning about unused variable and put in a way of making it checkerboard in screen space... I really need someone to test this...)<commit_after>#include "checkerboardrender.h"
#include <QTime>

QImage drawCheckerboard(const QImage &imgL, const QImage &imgR, int panX, int panY, int finalwidth, int finalheight, float zoom, QWidget *parent){
    QTime starttime = QTime::currentTime();

    if(zoom <= 0.0f){
        zoom = qMin((float)finalwidth / (float)imgL.width(), (float)finalheight / (float)imgL.height());
    }
    QPoint pos = parent->mapToGlobal(QPoint(0,0));

    panX += (finalwidth  * 0.5f - imgL.width()  * zoom * 0.5f);
    panY += (finalheight * 0.5f - imgL.height() * zoom * 0.5f);

    QImage final(finalwidth, finalheight, QImage::Format_RGB32);

    QRgb *line;
    QRgb *lineL;
    QRgb *lineR;

    for(int y = 0; y < final.height(); y++){
        line = (QRgb *)final.scanLine(y);
        int cy = (y - panY) / zoom;
        if(cy >= 0 && cy < imgL.height()){
            lineL = (QRgb *)imgL.constScanLine(cy);
            lineR = (QRgb *)imgR.constScanLine(cy);
            for(int x = 0; x < final.width(); x++){
                int cx = ( x - panX) / zoom;
                if(imgL.valid(cx,cy) && imgR.valid(cx,cy)){
                    if((pos.x() + x) % 2 == (pos.y() + y) % 2){
                        line[x] = lineR[cx];
                    }else{
                        line[x] = lineL[cx];
                    }
                }
                else{
                    line[x] = qRgb(0,0,0);
                }
            }
        }
        else{
            for(int x = 0; x < final.width(); x++)
                line[x] = qRgb(0,0,0);
        }
    }

    qDebug() << "Draw time: " << starttime.msecsTo(QTime::currentTime()) << "ms";

    return final;
}

<|endoftext|>


<commit_before>
#include <nstd/Memory.h>
#include <nstd/Debug.h>

#include <Windows.h>

class _Memory
{
public:
    struct PageHeader
    {
      uint64_t checkValue;
      size_t size;
    };

    struct PageFooter
    {
      uint64_t checkValue;
    };

    struct FreePage : public PageHeader
    {
      FreePage* next;
    };

    static size_t pageSize;
    static FreePage* firstFreePage;
    static FreePage** lastNextFreePage;
    static size_t freePageCount;
    static CRITICAL_SECTION criticalSection;

    static const uint64_t headerCheckValue = 0x1235543212355432LL;
    static const uint64_t headerCheckValueUsed = 0x1235543212355433LL;
    static const uint64_t footerCheckValue = 0x1235543212355432LL;

    static const size_t maxFreePageCount = 64;

private:
    static _Memory memory;

    _Memory()
    {
      InitializeCriticalSection(&criticalSection);
      SYSTEM_INFO si;
      GetSystemInfo(&si);
      pageSize = si.dwPageSize;
    }
    ~_Memory()
    {
      DeleteCriticalSection(&criticalSection);
    }
};

_Memory _Memory::memory;
size_t _Memory::pageSize;
_Memory::FreePage* _Memory::firstFreePage = 0;
_Memory::FreePage** _Memory::lastNextFreePage = &_Memory::firstFreePage;
size_t _Memory::freePageCount = 0;
CRITICAL_SECTION _Memory::criticalSection;

void_t* Memory::alloc(size_t size)
{
  size_t allocatedSize;
  return alloc(size, allocatedSize);
}

void_t* Memory::alloc(size_t size, size_t& rsize)
{
  ASSERT(_Memory::pageSize > 0);
  size_t minAllocSize = size + (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
  if(minAllocSize <= _Memory::pageSize)
  {
    EnterCriticalSection(&_Memory::criticalSection);
    if(_Memory::firstFreePage)
    {
      _Memory::PageHeader* header = _Memory::firstFreePage;
      _Memory::firstFreePage = _Memory::firstFreePage->next;
      --_Memory::freePageCount;
      LeaveCriticalSection(&_Memory::criticalSection);
      rsize = _Memory::pageSize - (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
      header->checkValue = _Memory::headerCheckValue;
      return (uint8_t*)header + sizeof(_Memory::PageHeader);
    }
    else
      LeaveCriticalSection(&_Memory::criticalSection);
  }
  size_t pageCount = (minAllocSize + _Memory::pageSize - 1) / _Memory::pageSize;
  size_t allocSize = pageCount * _Memory::pageSize;

  _Memory::PageHeader* header = (_Memory::PageHeader*)VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  if(!header) // out of memory?
  {
    Debug::printf("Memory::alloc: error: Could not allocate %llu pages.\n", (uint64_t)pageCount); HALT();
    do // wait and try again...
    {
      Sleep(1000);
      header = (_Memory::PageHeader*)VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    } while(!header);
  }
  _Memory::PageFooter* footer = (_Memory::PageFooter*)((uint8_t*)header + allocSize - sizeof(_Memory::PageFooter));
  header->size = allocSize;
  header->checkValue = _Memory::headerCheckValue;
  footer->checkValue = _Memory::footerCheckValue;
  rsize = allocSize - (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
  return (void_t*)((uint8_t*)header + sizeof(_Memory::PageHeader));
}

size_t Memory::size(void_t* buffer)
{
  if(!buffer) return 0;
  _Memory::PageHeader* header = (_Memory::PageHeader*)((uint8_t*)buffer - sizeof(_Memory::PageHeader));
  if(header->checkValue != _Memory::headerCheckValue)
  {
    if(header->checkValue == _Memory::headerCheckValueUsed)
    {
      Debug::print("Memory::free: error: The passed buffer was freed.\n"); HALT();
      return 0;
    }
    Debug::print("Memory::free: error: The passed buffer is invalid or corrupted.\n"); HALT();
    return 0;
  }
  return header->size - (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
}
/*
size_t Memory::pageSize()
{
  return _Memory::pageSize;
}
*/
void_t Memory::free(void_t* buffer)
{
  if(!buffer) return;
  _Memory::PageHeader* header = (_Memory::PageHeader*)((uint8_t*)buffer - sizeof(_Memory::PageHeader));
  if(header->checkValue != _Memory::headerCheckValue)
  {
    if(header->checkValue == _Memory::headerCheckValueUsed)
    {
      Debug::print("Memory::free: error: The passed buffer was already freed.\n"); HALT();
      return;
    }
    Debug::print("Memory::free: error: The passed buffer is invalid or corrupted.\n"); HALT();
    return;
  }
  _Memory::PageFooter* footer = (_Memory::PageFooter*)((uint8_t*)header + header->size - sizeof(_Memory::PageFooter));
  if(footer->checkValue != _Memory::footerCheckValue)
  {
    Debug::print("Memory::free: error: The passed buffer is corrupted.\n"); HALT(); // buffer overrun?
    footer->checkValue = _Memory::footerCheckValue;
  }

  if(header->size > _Memory::pageSize || _Memory::freePageCount >= _Memory::maxFreePageCount)
  {
    VirtualFree(header, header->size, MEM_RELEASE);
    return;
  }

  header->checkValue = _Memory::headerCheckValueUsed;
  ((_Memory::FreePage*)header)->next = 0;

  EnterCriticalSection(&_Memory::criticalSection);
  *_Memory::lastNextFreePage = (_Memory::FreePage*)header;
  _Memory::lastNextFreePage = &((_Memory::FreePage*)header)->next;
  ++_Memory::freePageCount;
  LeaveCriticalSection(&_Memory::criticalSection);
}

void_t Memory::copy(void_t* dest, const void_t* src, size_t length)
{
  CopyMemory(dest, src, length);
}

void_t Memory::move(void_t* dest, const void_t* src, size_t length)
{
  MoveMemory(dest, src, length);
}

void_t Memory::fill(void_t* buffer, byte_t value, size_t size)
{
  FillMemory(buffer, size, value);
}

void_t Memory::zero(void_t* buffer, size_t size)
{
  ZeroMemory(buffer, size);
}

int_t Memory::compare(const void_t* ptr1, const void_t* ptr2, size_t count)
{
  return memcmp(ptr1, ptr2, count);
}

void_t* operator new(size_t size)
{
  return Memory::alloc(size);
}

void_t* operator new [](size_t size)
{
  return Memory::alloc(size);
}

void_t operator delete(void_t* buffer)
{
  Memory::free(buffer);
}

void_t operator delete[](void_t* buffer)
{
  Memory::free(buffer);
}
<commit_msg>Memory: Fix not working page deallocation<commit_after>
#include <nstd/Memory.h>
#include <nstd/Debug.h>

#include <Windows.h>

class _Memory
{
public:
    struct PageHeader
    {
      uint64_t checkValue;
      size_t size;
    };

    struct PageFooter
    {
      uint64_t checkValue;
    };

    struct FreePage : public PageHeader
    {
      FreePage* next;
    };

    static size_t pageSize;
    static FreePage* firstFreePage;
    static FreePage** lastNextFreePage;
    static size_t freePageCount;
    static CRITICAL_SECTION criticalSection; // TODO: is it possible to use atomic operations instead?

    static const uint64_t headerCheckValue = 0x1235543212355432LL;
    static const uint64_t headerCheckValueUsed = 0x1235543212355433LL;
    static const uint64_t footerCheckValue = 0x1235543212355432LL;

    static const size_t maxFreePageCount = 64;

private:
    static _Memory memory;

    _Memory()
    {
      InitializeCriticalSection(&criticalSection);
      SYSTEM_INFO si;
      GetSystemInfo(&si);
      pageSize = si.dwPageSize;
    }
    ~_Memory()
    {
      DeleteCriticalSection(&criticalSection);
    }
};

_Memory _Memory::memory;
size_t _Memory::pageSize;
_Memory::FreePage* _Memory::firstFreePage = 0;
_Memory::FreePage** _Memory::lastNextFreePage = &_Memory::firstFreePage;
size_t _Memory::freePageCount = 0;
CRITICAL_SECTION _Memory::criticalSection;

void_t* Memory::alloc(size_t size)
{
  size_t allocatedSize;
  return alloc(size, allocatedSize);
}

void_t* Memory::alloc(size_t size, size_t& rsize)
{
  ASSERT(_Memory::pageSize > 0);
  size_t minAllocSize = size + (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
  if(minAllocSize <= _Memory::pageSize)
  {
    EnterCriticalSection(&_Memory::criticalSection);
    if(_Memory::firstFreePage)
    {
      _Memory::PageHeader* header = _Memory::firstFreePage;
      _Memory::firstFreePage = _Memory::firstFreePage->next;
      --_Memory::freePageCount;
      LeaveCriticalSection(&_Memory::criticalSection);
      rsize = _Memory::pageSize - (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
      header->checkValue = _Memory::headerCheckValue;
      return (uint8_t*)header + sizeof(_Memory::PageHeader);
    }
    else
      LeaveCriticalSection(&_Memory::criticalSection);
  }
  size_t pageCount = (minAllocSize + _Memory::pageSize - 1) / _Memory::pageSize;
  size_t allocSize = pageCount * _Memory::pageSize;

  _Memory::PageHeader* header = (_Memory::PageHeader*)VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  if(!header) // out of memory?
  {
    Debug::printf("Memory::alloc: error: Could not allocate %llu pages.\n", (uint64_t)pageCount); HALT();
    do // wait and try again...
    {
      Sleep(1000);
      header = (_Memory::PageHeader*)VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    } while(!header);
  }
  _Memory::PageFooter* footer = (_Memory::PageFooter*)((uint8_t*)header + allocSize - sizeof(_Memory::PageFooter));
  header->size = allocSize;
  header->checkValue = _Memory::headerCheckValue;
  footer->checkValue = _Memory::footerCheckValue;
  rsize = allocSize - (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
  return (void_t*)((uint8_t*)header + sizeof(_Memory::PageHeader));
}

size_t Memory::size(void_t* buffer)
{
  if(!buffer) return 0;
  _Memory::PageHeader* header = (_Memory::PageHeader*)((uint8_t*)buffer - sizeof(_Memory::PageHeader));
  if(header->checkValue != _Memory::headerCheckValue)
  {
    if(header->checkValue == _Memory::headerCheckValueUsed)
    {
      Debug::print("Memory::free: error: The passed buffer was freed.\n"); HALT();
      return 0;
    }
    Debug::print("Memory::free: error: The passed buffer is invalid or corrupted.\n"); HALT();
    return 0;
  }
  return header->size - (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
}
/*
size_t Memory::pageSize()
{
  return _Memory::pageSize;
}
*/
void_t Memory::free(void_t* buffer)
{
  if(!buffer) return;
  _Memory::PageHeader* header = (_Memory::PageHeader*)((uint8_t*)buffer - sizeof(_Memory::PageHeader));
  if(header->checkValue != _Memory::headerCheckValue)
  {
    if(header->checkValue == _Memory::headerCheckValueUsed)
    {
      Debug::print("Memory::free: error: The passed buffer was already freed.\n"); HALT();
      return;
    }
    Debug::print("Memory::free: error: The passed buffer is invalid or corrupted.\n"); HALT();
    return;
  }
  _Memory::PageFooter* footer = (_Memory::PageFooter*)((uint8_t*)header + header->size - sizeof(_Memory::PageFooter));
  if(footer->checkValue != _Memory::footerCheckValue)
  {
    Debug::print("Memory::free: error: The passed buffer is corrupted.\n"); HALT(); // buffer overrun?
    footer->checkValue = _Memory::footerCheckValue;
  }

  if(header->size > _Memory::pageSize || _Memory::freePageCount >= _Memory::maxFreePageCount)
  {
    VERIFY(VirtualFree(header, 0, MEM_RELEASE));
    return;
  }

  header->checkValue = _Memory::headerCheckValueUsed;
  ((_Memory::FreePage*)header)->next = 0;

  EnterCriticalSection(&_Memory::criticalSection);
  *_Memory::lastNextFreePage = (_Memory::FreePage*)header;
  _Memory::lastNextFreePage = &((_Memory::FreePage*)header)->next;
  ++_Memory::freePageCount;
  LeaveCriticalSection(&_Memory::criticalSection);
}

void_t Memory::copy(void_t* dest, const void_t* src, size_t length)
{
  CopyMemory(dest, src, length);
}

void_t Memory::move(void_t* dest, const void_t* src, size_t length)
{
  MoveMemory(dest, src, length);
}

void_t Memory::fill(void_t* buffer, byte_t value, size_t size)
{
  FillMemory(buffer, size, value);
}

void_t Memory::zero(void_t* buffer, size_t size)
{
  ZeroMemory(buffer, size);
}

int_t Memory::compare(const void_t* ptr1, const void_t* ptr2, size_t count)
{
  return memcmp(ptr1, ptr2, count);
}

void_t* operator new(size_t size)
{
  return Memory::alloc(size);
}

void_t* operator new [](size_t size)
{
  return Memory::alloc(size);
}

void_t operator delete(void_t* buffer)
{
  Memory::free(buffer);
}

void_t operator delete[](void_t* buffer)
{
  Memory::free(buffer);
}
<|endoftext|>