<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: mailmergewizard.cxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: vg $ $Date: 2006-11-22 10:25:10 $
 *
 *  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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"
#ifdef SW_DLLIMPLEMENTATION
#undef SW_DLLIMPLEMENTATION
#endif

#ifndef _MAILMERGEWIZARD_HXX
#include <mailmergewizard.hxx>
#endif
#ifndef _MAILMERGEDOCSELECTPAGE_HXX
#include <mmdocselectpage.hxx>
#endif
#ifndef _MAILMERGEOUTPUTTYPEPAGE_HXX
#include <mmoutputtypepage.hxx>
#endif
#ifndef _MAILMERGEADDRESSBLOCKPAGE_HXX
#include <mmaddressblockpage.hxx>
#endif
#ifndef _MAILMERGEPREPAREMERGEPAGE_HXX
#include <mmpreparemergepage.hxx>
#endif
#ifndef _MAILMERGEMERGEPAGE_HXX
#include <mmmergepage.hxx>
#endif
#ifndef _MAILMERGEGREETINGSPAGE_HXX
#include <mmgreetingspage.hxx>
#endif
#ifndef _MAILMERGEOUTPUTPAGE_HXX
#include <mmoutputpage.hxx>
#endif
#ifndef _MAILMERGELAYOUTPAGE_HXX
#include <mmlayoutpage.hxx>
#endif
#ifndef _MMCONFIGITEM_HXX
#include <mmconfigitem.hxx>
#endif
#ifndef _SW_ABSTDLG_HXX
#include <swabstdlg.hxx>
#endif
#ifndef _DBUI_HRC
#include <dbui.hrc>
#endif
#ifndef _SWVIEW_HXX
#include <view.hxx>
#endif
#ifndef _DBMGR_HXX
#include <dbmgr.hxx>
#endif
#ifndef _SFXVIEWFRM_HXX
#include <sfx2/viewfrm.hxx>
#endif
#ifndef _WRTSH_HXX
#include <wrtsh.hxx>
#endif
#ifndef _SFXVIEWFRM_HXX
#include <sfx2/viewfrm.hxx>
#endif
#ifndef _SV_MSGBOX_HXX
#include "vcl/msgbox.hxx" // RET_CANCEL
#endif

#include <helpid.h>
#include <dbui.hrc>
#include <mailmergewizard.hrc>

using namespace svt;
using namespace ::com::sun::star;
/*-- 01.04.2004 16:52:49---------------------------------------------------

  -----------------------------------------------------------------------*/
SwMailMergeWizard::SwMailMergeWizard(SwView& rView, SwMailMergeConfigItem& rItem) :
        RoadmapWizard(&rView.GetViewFrame()->GetWindow(),
                        SW_RES(DLG_MAILMERGEWIZARD),
                        WZB_NEXT|WZB_PREVIOUS|WZB_FINISH|WZB_CANCEL|WZB_HELP, ResId( STR_ROADMAP_TITLE )),
        m_pSwView(&rView),
        m_rConfigItem(rItem),
        m_sStarting(        ResId( ST_STARTING      )),
        m_sDocumentType(    ResId( ST_DOCUMETNTYPE   )),
        m_sAddressBlock(    ResId( ST_ADDRESSBLOCK   )),
        m_sAddressList(     ResId( ST_ADDRESSLIST )),
        m_sGreetingsLine(   ResId( ST_GREETINGSLINE   )),
        m_sLayout(          ResId( ST_LAYOUT        )),
        m_sPrepareMerge(    ResId( ST_PREPAREMERGE )),
        m_sMerge(           ResId( ST_MERGE        )),
        m_sOutput(          ResId( ST_OUTPUT       )),
        m_sFinish(          ResId( ST_FINISH       )),
        m_nRestartPage( MM_DOCUMENTSELECTPAGE )
{
    FreeResource();
    ShowButtonFixedLine(sal_True);
    defaultButton(WZB_NEXT);
    enableButtons(WZB_FINISH, sal_False);

    m_pFinish->SetText(m_sFinish);
    m_pNextPage->SetHelpId(HID_MM_NEXT_PAGE);
    m_pPrevPage->SetHelpId(HID_MM_PREV_PAGE);

    //#i51949# no output type page visible if e-Mail is not supported
    if(rItem.IsMailAvailable())
        declarePath(
            0,
            MM_DOCUMENTSELECTPAGE,
            MM_OUTPUTTYPETPAGE,
            MM_ADDRESSBLOCKPAGE,
            MM_GREETINGSPAGE,
            MM_LAYOUTPAGE,
            MM_PREPAREMERGEPAGE,
            MM_MERGEPAGE,
            MM_OUTPUTPAGE,
            WZS_INVALID_STATE
        );
    else
        declarePath(
            0,
            MM_DOCUMENTSELECTPAGE,
            MM_ADDRESSBLOCKPAGE,
            MM_GREETINGSPAGE,
            MM_LAYOUTPAGE,
            MM_PREPAREMERGEPAGE,
            MM_MERGEPAGE,
            MM_OUTPUTPAGE,
            WZS_INVALID_STATE
        );

    ActivatePage();
    UpdateRoadmap();
}
/*-- 01.04.2004 16:52:53---------------------------------------------------

  -----------------------------------------------------------------------*/
SwMailMergeWizard::~SwMailMergeWizard()
{
}
/*-- 01.04.2004 16:52:53---------------------------------------------------

  -----------------------------------------------------------------------*/
OWizardPage*    SwMailMergeWizard::createPage(WizardState _nState)
{
    OWizardPage* pRet = 0;
    switch(_nState)
    {
        case MM_DOCUMENTSELECTPAGE : pRet = new SwMailMergeDocSelectPage(this);     break;
        case MM_OUTPUTTYPETPAGE : pRet = new SwMailMergeOutputTypePage(this);       break;
        case MM_ADDRESSBLOCKPAGE  : pRet = new SwMailMergeAddressBlockPage(this);     break;
        case MM_GREETINGSPAGE     : pRet = new SwMailMergeGreetingsPage(this);      break;
        case MM_LAYOUTPAGE        : pRet = new SwMailMergeLayoutPage(this);     break;
        case MM_PREPAREMERGEPAGE  : pRet = new SwMailMergePrepareMergePage(this);   break;
        case MM_MERGEPAGE         : pRet = new SwMailMergeMergePage(this);          break;
        case MM_OUTPUTPAGE       :  pRet = new SwMailMergeOutputPage(this);         break;
    }
    DBG_ASSERT(pRet, "no page created in ::createPage");
    return pRet;
}
/*-- 04.06.2004 13:18:47---------------------------------------------------

  -----------------------------------------------------------------------*/
void SwMailMergeWizard::enterState( WizardState _nState )
{
    ::svt::RoadmapWizard::enterState( _nState );
/*
    entering a page after the layoutpage requires the insertion
    of greeting and address block - if not yet done
    entering the merge or output page requires to create the output document
*/
    if(_nState > MM_LAYOUTPAGE && m_rConfigItem.GetSourceView() &&
            ((m_rConfigItem.IsAddressBlock() && !m_rConfigItem.IsAddressInserted()) ||
             (m_rConfigItem.IsGreetingLine(sal_False) && !m_rConfigItem.IsGreetingInserted() )))
    {
        SwMailMergeLayoutPage::InsertAddressAndGreeting(m_rConfigItem.GetSourceView(),
                                m_rConfigItem, Point(-1, -1), true);
    }
    if(_nState >= MM_MERGEPAGE && !m_rConfigItem.GetTargetView())
    {
        CreateTargetDocument();
        m_nRestartPage = _nState;
        EndDialog(RET_TARGET_CREATED);
        return;
    }
    else if(_nState < MM_MERGEPAGE && m_rConfigItem.GetTargetView())
    {
        //close the dialog, remove the target view, show the source view
        m_nRestartPage = _nState;
        //set ResultSet back to start
        m_rConfigItem.MoveResultSet(1);
        EndDialog(RET_REMOVE_TARGET);
        return;
    }
    bool bEnablePrev = true;
    bool bEnableNext = true;
    switch(_nState)
    {
        case MM_DOCUMENTSELECTPAGE :
            bEnablePrev = false;
        break;
        case MM_ADDRESSBLOCKPAGE  :
            bEnableNext = m_rConfigItem.GetResultSet().is();
        break;
        case MM_OUTPUTPAGE       :
            bEnableNext = false;
        break;
    }
    enableButtons( WZB_PREVIOUS, bEnablePrev);
    enableButtons( WZB_NEXT, bEnableNext);

    UpdateRoadmap();
}
/*-- 04.06.2004 12:54:13---------------------------------------------------

  -----------------------------------------------------------------------*/
String  SwMailMergeWizard::getStateDisplayName( WizardState _nState )
{
    String sRet;
    switch(_nState)
    {
        case MM_DOCUMENTSELECTPAGE :sRet = m_sStarting;      break;
        case MM_OUTPUTTYPETPAGE :   sRet = m_sDocumentType;  break;
        case MM_ADDRESSBLOCKPAGE  :
            sRet =  m_rConfigItem.IsOutputToLetter() ?
                    m_sAddressBlock : m_sAddressList;

        break;
        case MM_GREETINGSPAGE     : sRet = m_sGreetingsLine; break;
        case MM_LAYOUTPAGE        : sRet = m_sLayout;        break;
        case MM_PREPAREMERGEPAGE  : sRet = m_sPrepareMerge;  break;
        case MM_MERGEPAGE         : sRet = m_sMerge;         break;
        case MM_OUTPUTPAGE       : sRet = m_sOutput;        break;
    }
    return sRet;
}
/*-- 24.06.2004 09:24:45---------------------------------------------------
    enables/disables pages in the roadmap depending on the current
    page and state
  -----------------------------------------------------------------------*/
void SwMailMergeWizard::UpdateRoadmap()
{
/*
    MM_DOCUMENTSELECTPAGE       > inactive after the layoutpage
    MM_OUTPUTTYPETPAGE :        > inactive after the layoutpage
    MM_ADDRESSBLOCKPAGE         > inactive after the layoutpage
    MM_GREETINGSPAGE            > inactive after the layoutpage
    MM_LAYOUTPAGE               >   inactive after the layoutpage
                                    inactive if address block and greeting are switched off
                                    or are already inserted into the source document
    MM_PREPAREMERGEPAGE         > only active if address data has been selected
                                    inactive after preparemerge page
    MM_MERGEPAGE                > only active if address data has been selected

    MM_OUTPUTPAGE               > only active if address data has been selected
*/

    // enableState( <page id>, false );
    const sal_uInt16 nCurPage = GetCurLevel();
    TabPage* pCurPage = GetPage( nCurPage );
    if(!pCurPage)
        return;
    bool bEnable = false;
    bool bAddressFieldsConfigured = !m_rConfigItem.IsOutputToLetter() ||
                !m_rConfigItem.IsAddressBlock() ||
                m_rConfigItem.IsAddressFieldsAssigned();
    bool bGreetingFieldsConfigured = !m_rConfigItem.IsGreetingLine(sal_False) ||
            !m_rConfigItem.IsIndividualGreeting(sal_False)||
                    m_rConfigItem.IsGreetingFieldsAssigned();
    bool bEnableOutputTypePage = (nCurPage != MM_DOCUMENTSELECTPAGE) ||
            static_cast<svt::OWizardPage*>(pCurPage)->commitPage(IWizardPage::CR_VALIDATE);

    for(sal_uInt16 nPage = MM_DOCUMENTSELECTPAGE; nPage <= MM_OUTPUTPAGE; ++nPage)
    {
        switch(nPage)
        {
            case MM_DOCUMENTSELECTPAGE :
                bEnable = sal_True;
            break;
            case MM_OUTPUTTYPETPAGE :
            case MM_ADDRESSBLOCKPAGE  :
                bEnable = bEnableOutputTypePage;
            break;
            case MM_GREETINGSPAGE     :
                bEnable = bEnableOutputTypePage &&
                    m_rConfigItem.GetResultSet().is() &&
                            bAddressFieldsConfigured;
            break;
            case MM_PREPAREMERGEPAGE  :
            case MM_MERGEPAGE         :
            case MM_OUTPUTPAGE       :
            case MM_LAYOUTPAGE        :
                bEnable = bEnableOutputTypePage &&
                            m_rConfigItem.GetResultSet().is() &&
                            bAddressFieldsConfigured &&
                            bGreetingFieldsConfigured;
                if(MM_LAYOUTPAGE == nPage)
                    bEnable &=
                        ((m_rConfigItem.IsAddressBlock() && !m_rConfigItem.IsAddressInserted()) ||
                            (m_rConfigItem.IsGreetingLine(sal_False) && !m_rConfigItem.IsGreetingInserted() ));
            break;
        }
        enableState( nPage, bEnable );
    }
}
/*-- 24.06.2004 09:24:45---------------------------------------------------
    enables/disables pages in the roadmap depending on the current
    page and state
  -----------------------------------------------------------------------*/
void SwMailMergeWizard::CreateTargetDocument()
{
    sal_Int32 nMerged = GetSwView()->GetWrtShell().GetNewDBMgr()->
                MergeDocuments( m_rConfigItem, *GetSwView() );
    m_rConfigItem.SetMergeDone();
    if( m_rConfigItem.GetTargetView() )
        m_rConfigItem.GetTargetView()->GetViewFrame()->GetFrame()->Appear();
}
/*-- 23.08.2004 08:51:36---------------------------------------------------

  -----------------------------------------------------------------------*/
void SwMailMergeWizard::updateRoadmapItemLabel( WizardState _nState )
{
    svt::RoadmapWizard::updateRoadmapItemLabel( _nState );
}

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

short SwMailMergeWizard::Execute()
{
    DBG_ERROR( "SwMailMergeWizard cannot be executed via Dialog::Execute!\n"
               "It creates a thread (MailDispatcher instance) that will call"
               "back to VCL apartment => deadlock!\n"
               "Use Dialog::StartExecuteModal to execute the dialog!" );
    return RET_CANCEL;
}

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

void SwMailMergeWizard::StartExecuteModal( const Link& rEndDialogHdl )
{
    ::svt::RoadmapWizard::StartExecuteModal( rEndDialogHdl );
}
<commit_msg>INTEGRATION: CWS residcleanup (1.12.158); FILE MERGED 2007/03/04 17:02:57 pl 1.12.158.1: #i73635# ResId cleanup<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: mailmergewizard.cxx,v $
 *
 *  $Revision: 1.13 $
 *
 *  last change: $Author: rt $ $Date: 2007-04-26 09:02:53 $
 *
 *  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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"
#ifdef SW_DLLIMPLEMENTATION
#undef SW_DLLIMPLEMENTATION
#endif

#ifndef _MAILMERGEWIZARD_HXX
#include <mailmergewizard.hxx>
#endif
#ifndef _MAILMERGEDOCSELECTPAGE_HXX
#include <mmdocselectpage.hxx>
#endif
#ifndef _MAILMERGEOUTPUTTYPEPAGE_HXX
#include <mmoutputtypepage.hxx>
#endif
#ifndef _MAILMERGEADDRESSBLOCKPAGE_HXX
#include <mmaddressblockpage.hxx>
#endif
#ifndef _MAILMERGEPREPAREMERGEPAGE_HXX
#include <mmpreparemergepage.hxx>
#endif
#ifndef _MAILMERGEMERGEPAGE_HXX
#include <mmmergepage.hxx>
#endif
#ifndef _MAILMERGEGREETINGSPAGE_HXX
#include <mmgreetingspage.hxx>
#endif
#ifndef _MAILMERGEOUTPUTPAGE_HXX
#include <mmoutputpage.hxx>
#endif
#ifndef _MAILMERGELAYOUTPAGE_HXX
#include <mmlayoutpage.hxx>
#endif
#ifndef _MMCONFIGITEM_HXX
#include <mmconfigitem.hxx>
#endif
#ifndef _SW_ABSTDLG_HXX
#include <swabstdlg.hxx>
#endif
#ifndef _DBUI_HRC
#include <dbui.hrc>
#endif
#ifndef _SWVIEW_HXX
#include <view.hxx>
#endif
#ifndef _DBMGR_HXX
#include <dbmgr.hxx>
#endif
#ifndef _SFXVIEWFRM_HXX
#include <sfx2/viewfrm.hxx>
#endif
#ifndef _WRTSH_HXX
#include <wrtsh.hxx>
#endif
#ifndef _SFXVIEWFRM_HXX
#include <sfx2/viewfrm.hxx>
#endif
#ifndef _SV_MSGBOX_HXX
#include "vcl/msgbox.hxx" // RET_CANCEL
#endif

#include <helpid.h>
#include <dbui.hrc>
#include <mailmergewizard.hrc>

using namespace svt;
using namespace ::com::sun::star;
/*-- 01.04.2004 16:52:49---------------------------------------------------

  -----------------------------------------------------------------------*/
SwMailMergeWizard::SwMailMergeWizard(SwView& rView, SwMailMergeConfigItem& rItem) :
        RoadmapWizard(&rView.GetViewFrame()->GetWindow(),
                        SW_RES(DLG_MAILMERGEWIZARD),
                        WZB_NEXT|WZB_PREVIOUS|WZB_FINISH|WZB_CANCEL|WZB_HELP, SW_RES( STR_ROADMAP_TITLE )),
        m_pSwView(&rView),
        m_rConfigItem(rItem),
        m_sStarting(        SW_RES( ST_STARTING      )),
        m_sDocumentType(    SW_RES( ST_DOCUMETNTYPE   )),
        m_sAddressBlock(    SW_RES( ST_ADDRESSBLOCK   )),
        m_sAddressList(     SW_RES( ST_ADDRESSLIST )),
        m_sGreetingsLine(   SW_RES( ST_GREETINGSLINE   )),
        m_sLayout(          SW_RES( ST_LAYOUT        )),
        m_sPrepareMerge(    SW_RES( ST_PREPAREMERGE )),
        m_sMerge(           SW_RES( ST_MERGE        )),
        m_sOutput(          SW_RES( ST_OUTPUT       )),
        m_sFinish(          SW_RES( ST_FINISH       )),
        m_nRestartPage( MM_DOCUMENTSELECTPAGE )
{
    FreeResource();
    ShowButtonFixedLine(sal_True);
    defaultButton(WZB_NEXT);
    enableButtons(WZB_FINISH, sal_False);

    m_pFinish->SetText(m_sFinish);
    m_pNextPage->SetHelpId(HID_MM_NEXT_PAGE);
    m_pPrevPage->SetHelpId(HID_MM_PREV_PAGE);

    //#i51949# no output type page visible if e-Mail is not supported
    if(rItem.IsMailAvailable())
        declarePath(
            0,
            MM_DOCUMENTSELECTPAGE,
            MM_OUTPUTTYPETPAGE,
            MM_ADDRESSBLOCKPAGE,
            MM_GREETINGSPAGE,
            MM_LAYOUTPAGE,
            MM_PREPAREMERGEPAGE,
            MM_MERGEPAGE,
            MM_OUTPUTPAGE,
            WZS_INVALID_STATE
        );
    else
        declarePath(
            0,
            MM_DOCUMENTSELECTPAGE,
            MM_ADDRESSBLOCKPAGE,
            MM_GREETINGSPAGE,
            MM_LAYOUTPAGE,
            MM_PREPAREMERGEPAGE,
            MM_MERGEPAGE,
            MM_OUTPUTPAGE,
            WZS_INVALID_STATE
        );

    ActivatePage();
    UpdateRoadmap();
}
/*-- 01.04.2004 16:52:53---------------------------------------------------

  -----------------------------------------------------------------------*/
SwMailMergeWizard::~SwMailMergeWizard()
{
}
/*-- 01.04.2004 16:52:53---------------------------------------------------

  -----------------------------------------------------------------------*/
OWizardPage*    SwMailMergeWizard::createPage(WizardState _nState)
{
    OWizardPage* pRet = 0;
    switch(_nState)
    {
        case MM_DOCUMENTSELECTPAGE : pRet = new SwMailMergeDocSelectPage(this);     break;
        case MM_OUTPUTTYPETPAGE : pRet = new SwMailMergeOutputTypePage(this);       break;
        case MM_ADDRESSBLOCKPAGE  : pRet = new SwMailMergeAddressBlockPage(this);     break;
        case MM_GREETINGSPAGE     : pRet = new SwMailMergeGreetingsPage(this);      break;
        case MM_LAYOUTPAGE        : pRet = new SwMailMergeLayoutPage(this);     break;
        case MM_PREPAREMERGEPAGE  : pRet = new SwMailMergePrepareMergePage(this);   break;
        case MM_MERGEPAGE         : pRet = new SwMailMergeMergePage(this);          break;
        case MM_OUTPUTPAGE       :  pRet = new SwMailMergeOutputPage(this);         break;
    }
    DBG_ASSERT(pRet, "no page created in ::createPage");
    return pRet;
}
/*-- 04.06.2004 13:18:47---------------------------------------------------

  -----------------------------------------------------------------------*/
void SwMailMergeWizard::enterState( WizardState _nState )
{
    ::svt::RoadmapWizard::enterState( _nState );
/*
    entering a page after the layoutpage requires the insertion
    of greeting and address block - if not yet done
    entering the merge or output page requires to create the output document
*/
    if(_nState > MM_LAYOUTPAGE && m_rConfigItem.GetSourceView() &&
            ((m_rConfigItem.IsAddressBlock() && !m_rConfigItem.IsAddressInserted()) ||
             (m_rConfigItem.IsGreetingLine(sal_False) && !m_rConfigItem.IsGreetingInserted() )))
    {
        SwMailMergeLayoutPage::InsertAddressAndGreeting(m_rConfigItem.GetSourceView(),
                                m_rConfigItem, Point(-1, -1), true);
    }
    if(_nState >= MM_MERGEPAGE && !m_rConfigItem.GetTargetView())
    {
        CreateTargetDocument();
        m_nRestartPage = _nState;
        EndDialog(RET_TARGET_CREATED);
        return;
    }
    else if(_nState < MM_MERGEPAGE && m_rConfigItem.GetTargetView())
    {
        //close the dialog, remove the target view, show the source view
        m_nRestartPage = _nState;
        //set ResultSet back to start
        m_rConfigItem.MoveResultSet(1);
        EndDialog(RET_REMOVE_TARGET);
        return;
    }
    bool bEnablePrev = true;
    bool bEnableNext = true;
    switch(_nState)
    {
        case MM_DOCUMENTSELECTPAGE :
            bEnablePrev = false;
        break;
        case MM_ADDRESSBLOCKPAGE  :
            bEnableNext = m_rConfigItem.GetResultSet().is();
        break;
        case MM_OUTPUTPAGE       :
            bEnableNext = false;
        break;
    }
    enableButtons( WZB_PREVIOUS, bEnablePrev);
    enableButtons( WZB_NEXT, bEnableNext);

    UpdateRoadmap();
}
/*-- 04.06.2004 12:54:13---------------------------------------------------

  -----------------------------------------------------------------------*/
String  SwMailMergeWizard::getStateDisplayName( WizardState _nState )
{
    String sRet;
    switch(_nState)
    {
        case MM_DOCUMENTSELECTPAGE :sRet = m_sStarting;      break;
        case MM_OUTPUTTYPETPAGE :   sRet = m_sDocumentType;  break;
        case MM_ADDRESSBLOCKPAGE  :
            sRet =  m_rConfigItem.IsOutputToLetter() ?
                    m_sAddressBlock : m_sAddressList;

        break;
        case MM_GREETINGSPAGE     : sRet = m_sGreetingsLine; break;
        case MM_LAYOUTPAGE        : sRet = m_sLayout;        break;
        case MM_PREPAREMERGEPAGE  : sRet = m_sPrepareMerge;  break;
        case MM_MERGEPAGE         : sRet = m_sMerge;         break;
        case MM_OUTPUTPAGE       : sRet = m_sOutput;        break;
    }
    return sRet;
}
/*-- 24.06.2004 09:24:45---------------------------------------------------
    enables/disables pages in the roadmap depending on the current
    page and state
  -----------------------------------------------------------------------*/
void SwMailMergeWizard::UpdateRoadmap()
{
/*
    MM_DOCUMENTSELECTPAGE       > inactive after the layoutpage
    MM_OUTPUTTYPETPAGE :        > inactive after the layoutpage
    MM_ADDRESSBLOCKPAGE         > inactive after the layoutpage
    MM_GREETINGSPAGE            > inactive after the layoutpage
    MM_LAYOUTPAGE               >   inactive after the layoutpage
                                    inactive if address block and greeting are switched off
                                    or are already inserted into the source document
    MM_PREPAREMERGEPAGE         > only active if address data has been selected
                                    inactive after preparemerge page
    MM_MERGEPAGE                > only active if address data has been selected

    MM_OUTPUTPAGE               > only active if address data has been selected
*/

    // enableState( <page id>, false );
    const sal_uInt16 nCurPage = GetCurLevel();
    TabPage* pCurPage = GetPage( nCurPage );
    if(!pCurPage)
        return;
    bool bEnable = false;
    bool bAddressFieldsConfigured = !m_rConfigItem.IsOutputToLetter() ||
                !m_rConfigItem.IsAddressBlock() ||
                m_rConfigItem.IsAddressFieldsAssigned();
    bool bGreetingFieldsConfigured = !m_rConfigItem.IsGreetingLine(sal_False) ||
            !m_rConfigItem.IsIndividualGreeting(sal_False)||
                    m_rConfigItem.IsGreetingFieldsAssigned();
    bool bEnableOutputTypePage = (nCurPage != MM_DOCUMENTSELECTPAGE) ||
            static_cast<svt::OWizardPage*>(pCurPage)->commitPage(IWizardPage::CR_VALIDATE);

    for(sal_uInt16 nPage = MM_DOCUMENTSELECTPAGE; nPage <= MM_OUTPUTPAGE; ++nPage)
    {
        switch(nPage)
        {
            case MM_DOCUMENTSELECTPAGE :
                bEnable = sal_True;
            break;
            case MM_OUTPUTTYPETPAGE :
            case MM_ADDRESSBLOCKPAGE  :
                bEnable = bEnableOutputTypePage;
            break;
            case MM_GREETINGSPAGE     :
                bEnable = bEnableOutputTypePage &&
                    m_rConfigItem.GetResultSet().is() &&
                            bAddressFieldsConfigured;
            break;
            case MM_PREPAREMERGEPAGE  :
            case MM_MERGEPAGE         :
            case MM_OUTPUTPAGE       :
            case MM_LAYOUTPAGE        :
                bEnable = bEnableOutputTypePage &&
                            m_rConfigItem.GetResultSet().is() &&
                            bAddressFieldsConfigured &&
                            bGreetingFieldsConfigured;
                if(MM_LAYOUTPAGE == nPage)
                    bEnable &=
                        ((m_rConfigItem.IsAddressBlock() && !m_rConfigItem.IsAddressInserted()) ||
                            (m_rConfigItem.IsGreetingLine(sal_False) && !m_rConfigItem.IsGreetingInserted() ));
            break;
        }
        enableState( nPage, bEnable );
    }
}
/*-- 24.06.2004 09:24:45---------------------------------------------------
    enables/disables pages in the roadmap depending on the current
    page and state
  -----------------------------------------------------------------------*/
void SwMailMergeWizard::CreateTargetDocument()
{
    sal_Int32 nMerged = GetSwView()->GetWrtShell().GetNewDBMgr()->
                MergeDocuments( m_rConfigItem, *GetSwView() );
    m_rConfigItem.SetMergeDone();
    if( m_rConfigItem.GetTargetView() )
        m_rConfigItem.GetTargetView()->GetViewFrame()->GetFrame()->Appear();
}
/*-- 23.08.2004 08:51:36---------------------------------------------------

  -----------------------------------------------------------------------*/
void SwMailMergeWizard::updateRoadmapItemLabel( WizardState _nState )
{
    svt::RoadmapWizard::updateRoadmapItemLabel( _nState );
}

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

short SwMailMergeWizard::Execute()
{
    DBG_ERROR( "SwMailMergeWizard cannot be executed via Dialog::Execute!\n"
               "It creates a thread (MailDispatcher instance) that will call"
               "back to VCL apartment => deadlock!\n"
               "Use Dialog::StartExecuteModal to execute the dialog!" );
    return RET_CANCEL;
}

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

void SwMailMergeWizard::StartExecuteModal( const Link& rEndDialogHdl )
{
    ::svt::RoadmapWizard::StartExecuteModal( rEndDialogHdl );
}
<|endoftext|>


<commit_before>#include "iotsaRequest.h"
#include <base64.h>
#ifdef ESP32
#include <HTTPClient.h>
#else
#include <ESP8266HTTPClient.h>
#endif

#ifdef ESP32
#define SSL_INFO_NAME "rootCA"
#else
#define SSL_INFO_NAME "fingerprint"
#endif

void IotsaRequest::configLoad(IotsaConfigFileLoad& cf, String& name) {
    cf.get(name+"url", url, "");
    cf.get(name + SSL_INFO_NAME, sslInfo, "");
    cf.get(name + "credentials", credentials, "");
    cf.get(name + "token", token, "");
}

void IotsaRequest::configSave(IotsaConfigFileSave& cf, String& name) {
    cf.put(name + "url", url);
    cf.put(name + SSL_INFO_NAME, sslInfo);
    cf.put(name + "credentials", credentials);
    cf.put(name + token, token);
}

void IotsaRequest::formHandler(String& message, String& text, String& name) {
    message += "" + text +  "
\n";
    message += "Activation URL: <input name='" + name +  "url' value='";
    message += url;
    message += "'>
\n";
#ifdef ESP32
    message += "Root CA cert (https only): <input name='" + name + "rootCA' value='";
    message += sslInfo;
#else
    message += "Fingerprint (https only): <input name='" + name +  "fingerprint' value='";
    message += sslInfo;
#endif
    message += "'>
\n";

    message += "Bearer token (optional): <input name='" + name + "token' value='";
    message += token;
    message += "'>
\n";

    message += "Credentials (optional, user:pass): <input name='" + name + "credentials' value='";
    message += credentials;
    message += "'>
\n";
}

#ifdef IOTSA_WITH_WEB
bool IotsaRequest::formArgHandler(IotsaWebServer *server, String name) {
  bool any = false;
  String wtdName = name + "url";
  if (server->hasArg(wtdName)) {
    IotsaMod::percentDecode(server->arg(wtdName), url);
    IFDEBUG IotsaSerial.print(wtdName);
    IFDEBUG IotsaSerial.print("=");
    IFDEBUG IotsaSerial.println(url);
    any = true;
  }
  wtdName = name + "SSL_INFO_NAME";
  if (server->hasArg(wtdName)) {
    IotsaMod::percentDecode(server->arg(wtdName), sslInfo);
    IFDEBUG IotsaSerial.print(wtdName);
    IFDEBUG IotsaSerial.print("=");
    IFDEBUG IotsaSerial.println(sslInfo);
    any = true;
  }
  wtdName = name + "credentials";
  if (server->hasArg(wtdName)) {
    IotsaMod::percentDecode(server->arg(wtdName), credentials);
    IFDEBUG IotsaSerial.print(wtdName);
    IFDEBUG IotsaSerial.print("=");
    IFDEBUG IotsaSerial.println(credentials);
    any = true;
    }
  wtdName = name + "token";
  if (server->hasArg(wtdName)) {
    IotsaMod::percentDecode(server->arg(wtdName), token);
    IFDEBUG IotsaSerial.print(wtdName);
    IFDEBUG IotsaSerial.print("=");
    IFDEBUG IotsaSerial.println(token);
    any = true;
  }
  return any;
}
#endif // IOTSA_WITH_WEB

bool IotsaRequest::send() {
  bool rv = true;
  HTTPClient http;

  if (url.startsWith("https:")) {
#ifdef ESP32
    rv = http.begin(url, sslInfo.c_str());
#else
    rv = http.begin(url, sslInfo);
#endif
  } else {
    rv = http.begin(url);
  }
  if (!rv) return false;
  if (token != "") {
    http.addHeader("Authorization", "Bearer " + token);
  }

  if (credentials != "") {
#if 0
    IotsaSerial.print("Credentials not yet implemented");
#else
  	String cred64 = base64::encode(credentials);
    http.addHeader("Authorization", "Basic " + cred64);
#endif
  }
  int code = http.GET();
  if (code >= 200 && code <= 299) {
    IFDEBUG IotsaSerial.print(code);
    IFDEBUG IotsaSerial.print(" OK GET ");
    IFDEBUG IotsaSerial.println(url);
  } else {
    IFDEBUG IotsaSerial.print(code);
    IFDEBUG IotsaSerial.print(" FAIL GET ");
    IFDEBUG IotsaSerial.print(url);
#ifdef ESP32
    IFDEBUG IotsaSerial.print(", RootCA ");
#else
    IFDEBUG IotsaSerial.print(", fingerprint ");
#endif
    IFDEBUG IotsaSerial.println(sslInfo);
    rv = false;
  }
  http.end();
  return rv;
}

void IotsaRequest::getHandler(JsonObject& reply) {
  reply["url"] = url;
  reply[SSL_INFO_NAME] = sslInfo;
  reply["hasCredentials"] = credentials != "";
  reply["hasToken"] = token != "";
}

bool IotsaRequest::putHandler(const JsonVariant& request) {
  if (!request.is<JsonObject>()) return false;
  bool any = false;
  const JsonObject& reqObj = request.as<JsonObject>();
  if (reqObj.containsKey("url")) {
    any = true;
    url = reqObj.get<String>("url");
  }
  if (reqObj.containsKey(SSL_INFO_NAME)) {
    any = true;
    sslInfo = reqObj.get<String>(SSL_INFO_NAME);
  }
  if (reqObj.containsKey("credentials")) {
    any = true;
    credentials = reqObj.get<String>("credentials");
  }
  if (reqObj.containsKey("token")) {
    any = true;
    token = reqObj.get<String>("token");
  }
  return any;
}
<commit_msg>Define getHandler and putHandler only if building with API.<commit_after>#include "iotsaRequest.h"
#include <base64.h>
#ifdef ESP32
#include <HTTPClient.h>
#else
#include <ESP8266HTTPClient.h>
#endif

#ifdef ESP32
#define SSL_INFO_NAME "rootCA"
#else
#define SSL_INFO_NAME "fingerprint"
#endif

void IotsaRequest::configLoad(IotsaConfigFileLoad& cf, String& name) {
    cf.get(name+"url", url, "");
    cf.get(name + SSL_INFO_NAME, sslInfo, "");
    cf.get(name + "credentials", credentials, "");
    cf.get(name + "token", token, "");
}

void IotsaRequest::configSave(IotsaConfigFileSave& cf, String& name) {
    cf.put(name + "url", url);
    cf.put(name + SSL_INFO_NAME, sslInfo);
    cf.put(name + "credentials", credentials);
    cf.put(name + token, token);
}

void IotsaRequest::formHandler(String& message, String& text, String& name) {
    message += "" + text +  "
\n";
    message += "Activation URL: <input name='" + name +  "url' value='";
    message += url;
    message += "'>
\n";
#ifdef ESP32
    message += "Root CA cert (https only): <input name='" + name + "rootCA' value='";
    message += sslInfo;
#else
    message += "Fingerprint (https only): <input name='" + name +  "fingerprint' value='";
    message += sslInfo;
#endif
    message += "'>
\n";

    message += "Bearer token (optional): <input name='" + name + "token' value='";
    message += token;
    message += "'>
\n";

    message += "Credentials (optional, user:pass): <input name='" + name + "credentials' value='";
    message += credentials;
    message += "'>
\n";
}

#ifdef IOTSA_WITH_WEB
bool IotsaRequest::formArgHandler(IotsaWebServer *server, String name) {
  bool any = false;
  String wtdName = name + "url";
  if (server->hasArg(wtdName)) {
    IotsaMod::percentDecode(server->arg(wtdName), url);
    IFDEBUG IotsaSerial.print(wtdName);
    IFDEBUG IotsaSerial.print("=");
    IFDEBUG IotsaSerial.println(url);
    any = true;
  }
  wtdName = name + "SSL_INFO_NAME";
  if (server->hasArg(wtdName)) {
    IotsaMod::percentDecode(server->arg(wtdName), sslInfo);
    IFDEBUG IotsaSerial.print(wtdName);
    IFDEBUG IotsaSerial.print("=");
    IFDEBUG IotsaSerial.println(sslInfo);
    any = true;
  }
  wtdName = name + "credentials";
  if (server->hasArg(wtdName)) {
    IotsaMod::percentDecode(server->arg(wtdName), credentials);
    IFDEBUG IotsaSerial.print(wtdName);
    IFDEBUG IotsaSerial.print("=");
    IFDEBUG IotsaSerial.println(credentials);
    any = true;
    }
  wtdName = name + "token";
  if (server->hasArg(wtdName)) {
    IotsaMod::percentDecode(server->arg(wtdName), token);
    IFDEBUG IotsaSerial.print(wtdName);
    IFDEBUG IotsaSerial.print("=");
    IFDEBUG IotsaSerial.println(token);
    any = true;
  }
  return any;
}
#endif // IOTSA_WITH_WEB

bool IotsaRequest::send() {
  bool rv = true;
  HTTPClient http;

  if (url.startsWith("https:")) {
#ifdef ESP32
    rv = http.begin(url, sslInfo.c_str());
#else
    rv = http.begin(url, sslInfo);
#endif
  } else {
    rv = http.begin(url);
  }
  if (!rv) return false;
  if (token != "") {
    http.addHeader("Authorization", "Bearer " + token);
  }

  if (credentials != "") {
#if 0
    IotsaSerial.print("Credentials not yet implemented");
#else
  	String cred64 = base64::encode(credentials);
    http.addHeader("Authorization", "Basic " + cred64);
#endif
  }
  int code = http.GET();
  if (code >= 200 && code <= 299) {
    IFDEBUG IotsaSerial.print(code);
    IFDEBUG IotsaSerial.print(" OK GET ");
    IFDEBUG IotsaSerial.println(url);
  } else {
    IFDEBUG IotsaSerial.print(code);
    IFDEBUG IotsaSerial.print(" FAIL GET ");
    IFDEBUG IotsaSerial.print(url);
#ifdef ESP32
    IFDEBUG IotsaSerial.print(", RootCA ");
#else
    IFDEBUG IotsaSerial.print(", fingerprint ");
#endif
    IFDEBUG IotsaSerial.println(sslInfo);
    rv = false;
  }
  http.end();
  return rv;
}

#ifdef IOTSA_WITH_API
void IotsaRequest::getHandler(JsonObject& reply) {
  reply["url"] = url;
  reply[SSL_INFO_NAME] = sslInfo;
  reply["hasCredentials"] = credentials != "";
  reply["hasToken"] = token != "";
}

bool IotsaRequest::putHandler(const JsonVariant& request) {
  if (!request.is<JsonObject>()) return false;
  bool any = false;
  const JsonObject& reqObj = request.as<JsonObject>();
  if (reqObj.containsKey("url")) {
    any = true;
    url = reqObj.get<String>("url");
  }
  if (reqObj.containsKey(SSL_INFO_NAME)) {
    any = true;
    sslInfo = reqObj.get<String>(SSL_INFO_NAME);
  }
  if (reqObj.containsKey("credentials")) {
    any = true;
    credentials = reqObj.get<String>("credentials");
  }
  if (reqObj.containsKey("token")) {
    any = true;
    token = reqObj.get<String>("token");
  }
  return any;
}
#endif // IOTSA_WITH_API<|endoftext|>


<commit_before>#include "jpeg_encoder.h"

JpegEncoder::JpegEncoder(unsigned char *ddata, int wwidth, int hheight,
    int qquality, buffer_type bbuf_type)
    :
      data(ddata), width(wwidth), height(hheight), quality(qquality), smoothing(0),
    buf_type(bbuf_type),
    jpeg(NULL), jpeg_len(0),
    offset(0, 0, 0, 0) {}

JpegEncoder::~JpegEncoder() {
    free(jpeg);
}

#if JPEG_LIB_VERSION < 80
// copied over from latest libjpeg

#define OUTPUT_BUF_SIZE 4096

typedef struct {
  struct jpeg_destination_mgr pub; /* public fields */

  unsigned char ** outbuffer;	/* target buffer */
  unsigned long * outsize;
  unsigned char * newbuffer;	/* newly allocated buffer */
  JOCTET * buffer;		/* start of buffer */
  size_t bufsize;
} my_mem_destination_mgr;

typedef my_mem_destination_mgr * my_mem_dest_ptr;

void
init_mem_destination (j_compress_ptr cinfo)
{
  /* no work necessary here */
}

boolean
empty_mem_output_buffer (j_compress_ptr cinfo)
{
  size_t nextsize;
  JOCTET * nextbuffer;
  my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;

  /* Try to allocate new buffer with double size */
  nextsize = dest->bufsize * 2;
  nextbuffer = (JOCTET *)malloc(nextsize);

  if (nextbuffer == NULL)
    throw "malloc failed in empty_mem_output_buffer";

  memcpy(nextbuffer, dest->buffer, dest->bufsize);

  if (dest->newbuffer != NULL)
    free(dest->newbuffer);

  dest->newbuffer = nextbuffer;

  dest->pub.next_output_byte = nextbuffer + dest->bufsize;
  dest->pub.free_in_buffer = dest->bufsize;

  dest->buffer = nextbuffer;
  dest->bufsize = nextsize;

  return TRUE;
}

void
term_mem_destination (j_compress_ptr cinfo)
{
  my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;

  *dest->outbuffer = dest->buffer;
  *dest->outsize = dest->bufsize - dest->pub.free_in_buffer;
}

void
jpeg_mem_dest (j_compress_ptr cinfo,
	       unsigned char ** outbuffer, unsigned long * outsize)
{
  my_mem_dest_ptr dest;

  /* The destination object is made permanent so that multiple JPEG images
   * can be written to the same buffer without re-executing jpeg_mem_dest.
   */
  if (cinfo->dest == NULL) {	/* first time for this JPEG object? */
    cinfo->dest = (struct jpeg_destination_mgr *)
      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
				  sizeof(my_mem_destination_mgr));
  }

  dest = (my_mem_dest_ptr) cinfo->dest;
  dest->pub.init_destination = init_mem_destination;
  dest->pub.empty_output_buffer = empty_mem_output_buffer;
  dest->pub.term_destination = term_mem_destination;
  dest->outbuffer = outbuffer;
  dest->outsize = outsize;
  dest->newbuffer = NULL;

  if (*outbuffer == NULL || *outsize == 0) {
    /* Allocate initial buffer */
    dest->newbuffer = *outbuffer = (unsigned char *)malloc(OUTPUT_BUF_SIZE);
    if (dest->newbuffer == NULL)
      throw "out of memory in jpeg_mem_dest (copied implementation)";
    *outsize = OUTPUT_BUF_SIZE;
  }

  dest->pub.next_output_byte = dest->buffer = *outbuffer;
  dest->pub.free_in_buffer = dest->bufsize = *outsize;
}
#endif

void
JpegEncoder::encode()
{
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;

    cinfo.err = jpeg_std_error(&jerr);

    jpeg_create_compress(&cinfo);
    jpeg_mem_dest(&cinfo, &jpeg, &jpeg_len);

    if (offset.isNull()) {
        cinfo.image_width = width;
        cinfo.image_height = height;
    }
    else {
        cinfo.image_width = offset.w;
        cinfo.image_height = offset.h;
    }
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;

    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, quality, TRUE);
    cinfo.smoothing_factor = smoothing;
    jpeg_start_compress(&cinfo, TRUE);

    unsigned char *rgb_data;
    switch (buf_type) {
    case BUF_RGBA:
        rgb_data = rgba_to_rgb(data, width*height*4);
        if (!rgb_data) throw "malloc failed in JpegEncoder::encode/rgba_to_rgb.";
        break;

    case BUF_BGRA:
        rgb_data = bgra_to_rgb(data, width*height*4);
        if (!rgb_data) throw "malloc failed in JpegEncoder::encode/bgra_to_rgb.";
        break;

    case BUF_BGR:
        rgb_data = bgr_to_rgb(data, width*height*3);
        if (!rgb_data) throw "malloc failed in JpegEncoder::encode/bgr_to_rgb.";
        break;

    case BUF_RGB:
        rgb_data = data;
        break;

    default:
        throw "Unexpected buf_type in JpegEncoder::encode";
    }

    JSAMPROW row_pointer;
    int start = 0;
    if (!offset.isNull()) {
        start = offset.y*width*3 + offset.x*3;
    }
    while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer = &rgb_data[start + cinfo.next_scanline*3*width];
        jpeg_write_scanlines(&cinfo, &row_pointer, 1);
    }

    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);

    if (buf_type == BUF_BGR || buf_type == BUF_RGBA || buf_type == BUF_BGRA)
        free(rgb_data);
}

void
JpegEncoder::set_quality(int q)
{
    quality = q;
}

void JpegEncoder::set_smoothing(int ssmoothing)
{
    smoothing  = ssmoothing;
}

const unsigned char *
JpegEncoder::get_jpeg() const
{
    return jpeg;
}

unsigned int
JpegEncoder::get_jpeg_len() const
{
    return jpeg_len;
}

void
JpegEncoder::setRect(const Rect &r)
{
    offset = r;
}

<commit_msg>show encode timings<commit_after>#include "jpeg_encoder.h"
#include "time.h"

JpegEncoder::JpegEncoder(unsigned char *ddata, int wwidth, int hheight,
    int qquality, buffer_type bbuf_type)
    :
      data(ddata), width(wwidth), height(hheight), quality(qquality), smoothing(0),
    buf_type(bbuf_type),
    jpeg(NULL), jpeg_len(0),
    offset(0, 0, 0, 0) {}

JpegEncoder::~JpegEncoder() {
    free(jpeg);
}

#if JPEG_LIB_VERSION < 80
// copied over from latest libjpeg

#define OUTPUT_BUF_SIZE 4096

typedef struct {
  struct jpeg_destination_mgr pub; /* public fields */

  unsigned char ** outbuffer;	/* target buffer */
  unsigned long * outsize;
  unsigned char * newbuffer;	/* newly allocated buffer */
  JOCTET * buffer;		/* start of buffer */
  size_t bufsize;
} my_mem_destination_mgr;

typedef my_mem_destination_mgr * my_mem_dest_ptr;

void
init_mem_destination (j_compress_ptr cinfo)
{
  /* no work necessary here */
}

boolean
empty_mem_output_buffer (j_compress_ptr cinfo)
{
  size_t nextsize;
  JOCTET * nextbuffer;
  my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;

  /* Try to allocate new buffer with double size */
  nextsize = dest->bufsize * 2;
  nextbuffer = (JOCTET *)malloc(nextsize);

  if (nextbuffer == NULL)
    throw "malloc failed in empty_mem_output_buffer";

  memcpy(nextbuffer, dest->buffer, dest->bufsize);

  if (dest->newbuffer != NULL)
    free(dest->newbuffer);

  dest->newbuffer = nextbuffer;

  dest->pub.next_output_byte = nextbuffer + dest->bufsize;
  dest->pub.free_in_buffer = dest->bufsize;

  dest->buffer = nextbuffer;
  dest->bufsize = nextsize;

  return TRUE;
}

void
term_mem_destination (j_compress_ptr cinfo)
{
  my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;

  *dest->outbuffer = dest->buffer;
  *dest->outsize = dest->bufsize - dest->pub.free_in_buffer;
}

void
jpeg_mem_dest (j_compress_ptr cinfo,
	       unsigned char ** outbuffer, unsigned long * outsize)
{
  my_mem_dest_ptr dest;

  /* The destination object is made permanent so that multiple JPEG images
   * can be written to the same buffer without re-executing jpeg_mem_dest.
   */
  if (cinfo->dest == NULL) {	/* first time for this JPEG object? */
    cinfo->dest = (struct jpeg_destination_mgr *)
      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
				  sizeof(my_mem_destination_mgr));
  }

  dest = (my_mem_dest_ptr) cinfo->dest;
  dest->pub.init_destination = init_mem_destination;
  dest->pub.empty_output_buffer = empty_mem_output_buffer;
  dest->pub.term_destination = term_mem_destination;
  dest->outbuffer = outbuffer;
  dest->outsize = outsize;
  dest->newbuffer = NULL;

  if (*outbuffer == NULL || *outsize == 0) {
    /* Allocate initial buffer */
    dest->newbuffer = *outbuffer = (unsigned char *)malloc(OUTPUT_BUF_SIZE);
    if (dest->newbuffer == NULL)
      throw "out of memory in jpeg_mem_dest (copied implementation)";
    *outsize = OUTPUT_BUF_SIZE;
  }

  dest->pub.next_output_byte = dest->buffer = *outbuffer;
  dest->pub.free_in_buffer = dest->bufsize = *outsize;
}
#endif

void
JpegEncoder::encode()
{

    clock_t t = clock();

    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;

    cinfo.err = jpeg_std_error(&jerr);

    jpeg_create_compress(&cinfo);
    jpeg_mem_dest(&cinfo, &jpeg, &jpeg_len);

    if (offset.isNull()) {
        cinfo.image_width = width;
        cinfo.image_height = height;
    }
    else {
        cinfo.image_width = offset.w;
        cinfo.image_height = offset.h;
    }
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;

    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, quality, TRUE);
    cinfo.smoothing_factor = smoothing;
    jpeg_start_compress(&cinfo, TRUE);

    unsigned char *rgb_data;
    switch (buf_type) {
    case BUF_RGBA:
        rgb_data = rgba_to_rgb(data, width*height*4);
        if (!rgb_data) throw "malloc failed in JpegEncoder::encode/rgba_to_rgb.";
        break;

    case BUF_BGRA:
        rgb_data = bgra_to_rgb(data, width*height*4);
        if (!rgb_data) throw "malloc failed in JpegEncoder::encode/bgra_to_rgb.";
        break;

    case BUF_BGR:
        rgb_data = bgr_to_rgb(data, width*height*3);
        if (!rgb_data) throw "malloc failed in JpegEncoder::encode/bgr_to_rgb.";
        break;

    case BUF_RGB:
        rgb_data = data;
        break;

    default:
        throw "Unexpected buf_type in JpegEncoder::encode";
    }

    JSAMPROW row_pointer;
    int start = 0;
    if (!offset.isNull()) {
        start = offset.y*width*3 + offset.x*3;
    }
    while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer = &rgb_data[start + cinfo.next_scanline*3*width];
        jpeg_write_scanlines(&cinfo, &row_pointer, 1);
    }

    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);

    if (buf_type == BUF_BGR || buf_type == BUF_RGBA || buf_type == BUF_BGRA)
        free(rgb_data);

    t = clock() - t;
    printf ("encode( took %d clicks (%f ms).\n",(int)t,((float)(t*1000))/CLOCKS_PER_SEC);
}

void
JpegEncoder::set_quality(int q)
{
    quality = q;
}

void JpegEncoder::set_smoothing(int ssmoothing)
{
    smoothing  = ssmoothing;
}

const unsigned char *
JpegEncoder::get_jpeg() const
{
    return jpeg;
}

unsigned int
JpegEncoder::get_jpeg_len() const
{
    return jpeg_len;
}

void
JpegEncoder::setRect(const Rect &r)
{
    offset = r;
}

<|endoftext|>


<commit_before>//===- IndVarSimplify.cpp - Induction Variable Elimination ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Guarantees that all loops with identifiable, linear, induction variables will
// be transformed to have a single, canonical, induction variable.  After this
// pass runs, it guarantees the the first PHI node of the header block in the
// loop is the canonical induction variable if there is one.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/Analysis/InductionVariable.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/iPHINode.h"
#include "llvm/iOther.h"
#include "llvm/Type.h"
#include "llvm/Constants.h"
#include "llvm/Support/CFG.h"
#include "Support/Debug.h"
#include "Support/Statistic.h"
#include "Support/STLExtras.h"

namespace llvm {

namespace {
  Statistic<> NumRemoved ("indvars", "Number of aux indvars removed");
  Statistic<> NumInserted("indvars", "Number of canonical indvars added");
}

// InsertCast - Cast Val to Ty, setting a useful name on the cast if Val has a
// name...
//
static Instruction *InsertCast(Value *Val, const Type *Ty,
                               Instruction *InsertBefore) {
  return new CastInst(Val, Ty, Val->getName()+"-casted", InsertBefore);
}

static bool TransformLoop(LoopInfo *Loops, Loop *Loop) {
  // Transform all subloops before this loop...
  bool Changed = reduce_apply_bool(Loop->getSubLoops().begin(),
                                   Loop->getSubLoops().end(),
                              std::bind1st(std::ptr_fun(TransformLoop), Loops));
  // Get the header node for this loop.  All of the phi nodes that could be
  // induction variables must live in this basic block.
  //
  BasicBlock *Header = Loop->getHeader();

  // Loop over all of the PHI nodes in the basic block, calculating the
  // induction variables that they represent... stuffing the induction variable
  // info into a vector...
  //
  std::vector<InductionVariable> IndVars;    // Induction variables for block
  BasicBlock::iterator AfterPHIIt = Header->begin();
  for (; PHINode *PN = dyn_cast<PHINode>(AfterPHIIt); ++AfterPHIIt)
    IndVars.push_back(InductionVariable(PN, Loops));
  // AfterPHIIt now points to first non-phi instruction...

  // If there are no phi nodes in this basic block, there can't be indvars...
  if (IndVars.empty()) return Changed;

  // Loop over the induction variables, looking for a canonical induction
  // variable, and checking to make sure they are not all unknown induction
  // variables.
  //
  bool FoundIndVars = false;
  InductionVariable *Canonical = 0;
  for (unsigned i = 0; i < IndVars.size(); ++i) {
    if (IndVars[i].InductionType == InductionVariable::Canonical &&
        !isa<PointerType>(IndVars[i].Phi->getType()))
      Canonical = &IndVars[i];
    if (IndVars[i].InductionType != InductionVariable::Unknown)
      FoundIndVars = true;
  }

  // No induction variables, bail early... don't add a canonical indvar
  if (!FoundIndVars) return Changed;

  // Okay, we want to convert other induction variables to use a canonical
  // indvar.  If we don't have one, add one now...
  if (!Canonical) {
    // Create the PHI node for the new induction variable, and insert the phi
    // node at the start of the PHI nodes...
    PHINode *PN = new PHINode(Type::UIntTy, "cann-indvar", Header->begin());

    // Create the increment instruction to add one to the counter...
    Instruction *Add = BinaryOperator::create(Instruction::Add, PN,
                                              ConstantUInt::get(Type::UIntTy,1),
                                              "add1-indvar", AfterPHIIt);

    // Figure out which block is incoming and which is the backedge for the loop
    BasicBlock *Incoming, *BackEdgeBlock;
    pred_iterator PI = pred_begin(Header);
    assert(PI != pred_end(Header) && "Loop headers should have 2 preds!");
    if (Loop->contains(*PI)) {  // First pred is back edge...
      BackEdgeBlock = *PI++;
      Incoming      = *PI++;
    } else {
      Incoming      = *PI++;
      BackEdgeBlock = *PI++;
    }
    assert(PI == pred_end(Header) && "Loop headers should have 2 preds!");

    // Add incoming values for the PHI node...
    PN->addIncoming(Constant::getNullValue(Type::UIntTy), Incoming);
    PN->addIncoming(Add, BackEdgeBlock);

    // Analyze the new induction variable...
    IndVars.push_back(InductionVariable(PN, Loops));
    assert(IndVars.back().InductionType == InductionVariable::Canonical &&
           "Just inserted canonical indvar that is not canonical!");
    Canonical = &IndVars.back();
    ++NumInserted;
    Changed = true;
  } else {
    // If we have a canonical induction variable, make sure that it is the first
    // one in the basic block.
    if (&Header->front() != Canonical->Phi)
      Header->getInstList().splice(Header->begin(), Header->getInstList(),
                                   Canonical->Phi);
  }

  DEBUG(std::cerr << "Induction variables:\n");

  // Get the current loop iteration count, which is always the value of the
  // canonical phi node...
  //
  PHINode *IterCount = Canonical->Phi;

  // Loop through and replace all of the auxiliary induction variables with
  // references to the canonical induction variable...
  //
  for (unsigned i = 0; i < IndVars.size(); ++i) {
    InductionVariable *IV = &IndVars[i];

    DEBUG(IV->print(std::cerr));

    // Don't do math with pointers...
    const Type *IVTy = IV->Phi->getType();
    if (isa<PointerType>(IVTy)) IVTy = Type::ULongTy;

    // Don't modify the canonical indvar or unrecognized indvars...
    if (IV != Canonical && IV->InductionType != InductionVariable::Unknown) {
      Instruction *Val = IterCount;
      if (!isa<ConstantInt>(IV->Step) ||   // If the step != 1
          !cast<ConstantInt>(IV->Step)->equalsInt(1)) {

        // If the types are not compatible, insert a cast now...
        if (Val->getType() != IVTy)
          Val = InsertCast(Val, IVTy, AfterPHIIt);
        if (IV->Step->getType() != IVTy)
          IV->Step = InsertCast(IV->Step, IVTy, AfterPHIIt);

        Val = BinaryOperator::create(Instruction::Mul, Val, IV->Step,
                                     IV->Phi->getName()+"-scale", AfterPHIIt);
      }

      // If the start != 0
      if (IV->Start != Constant::getNullValue(IV->Start->getType())) {
        // If the types are not compatible, insert a cast now...
        if (Val->getType() != IVTy)
          Val = InsertCast(Val, IVTy, AfterPHIIt);
        if (IV->Start->getType() != IVTy)
          IV->Start = InsertCast(IV->Start, IVTy, AfterPHIIt);

        // Insert the instruction after the phi nodes...
        Val = BinaryOperator::create(Instruction::Add, Val, IV->Start,
                                     IV->Phi->getName()+"-offset", AfterPHIIt);
      }

      // If the PHI node has a different type than val is, insert a cast now...
      if (Val->getType() != IV->Phi->getType())
        Val = InsertCast(Val, IV->Phi->getType(), AfterPHIIt);

      // Replace all uses of the old PHI node with the new computed value...
      IV->Phi->replaceAllUsesWith(Val);

      // Move the PHI name to it's new equivalent value...
      std::string OldName = IV->Phi->getName();
      IV->Phi->setName("");
      Val->setName(OldName);

      // Delete the old, now unused, phi node...
      Header->getInstList().erase(IV->Phi);
      Changed = true;
      ++NumRemoved;
    }
  }

  return Changed;
}

namespace {
  struct InductionVariableSimplify : public FunctionPass {
    virtual bool runOnFunction(Function &) {
      LoopInfo &LI = getAnalysis<LoopInfo>();

      // Induction Variables live in the header nodes of loops
      return reduce_apply_bool(LI.getTopLevelLoops().begin(),
                               LI.getTopLevelLoops().end(),
                               std::bind1st(std::ptr_fun(TransformLoop), &LI));
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<LoopInfo>();
      AU.addRequiredID(LoopSimplifyID);
      AU.setPreservesCFG();
    }
  };
  RegisterOpt<InductionVariableSimplify> X("indvars",
                                           "Canonicalize Induction Variables");
}

Pass *createIndVarSimplifyPass() {
  return new InductionVariableSimplify();
}

} // End llvm namespace
<commit_msg>Finegrainify namespacification Reorder #includes Implement: IndVarsSimplify/2003-12-10-IndVarDeadCode.ll<commit_after>//===- IndVarSimplify.cpp - Induction Variable Elimination ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Guarantees that all loops with identifiable, linear, induction variables will
// be transformed to have a single, canonical, induction variable.  After this
// pass runs, it guarantees the the first PHI node of the header block in the
// loop is the canonical induction variable if there is one.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/Constants.h"
#include "llvm/Type.h"
#include "llvm/iPHINode.h"
#include "llvm/iOther.h"
#include "llvm/Analysis/InductionVariable.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Support/CFG.h"
#include "llvm/Transforms/Utils/Local.h"
#include "Support/Debug.h"
#include "Support/Statistic.h"
#include "Support/STLExtras.h"
using namespace llvm;

namespace {
  Statistic<> NumRemoved ("indvars", "Number of aux indvars removed");
  Statistic<> NumInserted("indvars", "Number of canonical indvars added");
}

// InsertCast - Cast Val to Ty, setting a useful name on the cast if Val has a
// name...
//
static Instruction *InsertCast(Value *Val, const Type *Ty,
                               Instruction *InsertBefore) {
  return new CastInst(Val, Ty, Val->getName()+"-casted", InsertBefore);
}

static bool TransformLoop(LoopInfo *Loops, Loop *Loop) {
  // Transform all subloops before this loop...
  bool Changed = reduce_apply_bool(Loop->getSubLoops().begin(),
                                   Loop->getSubLoops().end(),
                              std::bind1st(std::ptr_fun(TransformLoop), Loops));
  // Get the header node for this loop.  All of the phi nodes that could be
  // induction variables must live in this basic block.
  //
  BasicBlock *Header = Loop->getHeader();

  // Loop over all of the PHI nodes in the basic block, calculating the
  // induction variables that they represent... stuffing the induction variable
  // info into a vector...
  //
  std::vector<InductionVariable> IndVars;    // Induction variables for block
  BasicBlock::iterator AfterPHIIt = Header->begin();
  for (; PHINode *PN = dyn_cast<PHINode>(AfterPHIIt); ++AfterPHIIt)
    IndVars.push_back(InductionVariable(PN, Loops));
  // AfterPHIIt now points to first non-phi instruction...

  // If there are no phi nodes in this basic block, there can't be indvars...
  if (IndVars.empty()) return Changed;

  // Loop over the induction variables, looking for a canonical induction
  // variable, and checking to make sure they are not all unknown induction
  // variables.
  //
  bool FoundIndVars = false;
  InductionVariable *Canonical = 0;
  for (unsigned i = 0; i < IndVars.size(); ++i) {
    if (IndVars[i].InductionType == InductionVariable::Canonical &&
        !isa<PointerType>(IndVars[i].Phi->getType()))
      Canonical = &IndVars[i];
    if (IndVars[i].InductionType != InductionVariable::Unknown)
      FoundIndVars = true;
  }

  // No induction variables, bail early... don't add a canonical indvar
  if (!FoundIndVars) return Changed;

  // Okay, we want to convert other induction variables to use a canonical
  // indvar.  If we don't have one, add one now...
  if (!Canonical) {
    // Create the PHI node for the new induction variable, and insert the phi
    // node at the start of the PHI nodes...
    PHINode *PN = new PHINode(Type::UIntTy, "cann-indvar", Header->begin());

    // Create the increment instruction to add one to the counter...
    Instruction *Add = BinaryOperator::create(Instruction::Add, PN,
                                              ConstantUInt::get(Type::UIntTy,1),
                                              "add1-indvar", AfterPHIIt);

    // Figure out which block is incoming and which is the backedge for the loop
    BasicBlock *Incoming, *BackEdgeBlock;
    pred_iterator PI = pred_begin(Header);
    assert(PI != pred_end(Header) && "Loop headers should have 2 preds!");
    if (Loop->contains(*PI)) {  // First pred is back edge...
      BackEdgeBlock = *PI++;
      Incoming      = *PI++;
    } else {
      Incoming      = *PI++;
      BackEdgeBlock = *PI++;
    }
    assert(PI == pred_end(Header) && "Loop headers should have 2 preds!");

    // Add incoming values for the PHI node...
    PN->addIncoming(Constant::getNullValue(Type::UIntTy), Incoming);
    PN->addIncoming(Add, BackEdgeBlock);

    // Analyze the new induction variable...
    IndVars.push_back(InductionVariable(PN, Loops));
    assert(IndVars.back().InductionType == InductionVariable::Canonical &&
           "Just inserted canonical indvar that is not canonical!");
    Canonical = &IndVars.back();
    ++NumInserted;
    Changed = true;
  } else {
    // If we have a canonical induction variable, make sure that it is the first
    // one in the basic block.
    if (&Header->front() != Canonical->Phi)
      Header->getInstList().splice(Header->begin(), Header->getInstList(),
                                   Canonical->Phi);
  }

  DEBUG(std::cerr << "Induction variables:\n");

  // Get the current loop iteration count, which is always the value of the
  // canonical phi node...
  //
  PHINode *IterCount = Canonical->Phi;

  // Loop through and replace all of the auxiliary induction variables with
  // references to the canonical induction variable...
  //
  for (unsigned i = 0; i < IndVars.size(); ++i) {
    InductionVariable *IV = &IndVars[i];

    DEBUG(IV->print(std::cerr));

    // Don't do math with pointers...
    const Type *IVTy = IV->Phi->getType();
    if (isa<PointerType>(IVTy)) IVTy = Type::ULongTy;

    // Don't modify the canonical indvar or unrecognized indvars...
    if (IV != Canonical && IV->InductionType != InductionVariable::Unknown) {
      Instruction *Val = IterCount;
      if (!isa<ConstantInt>(IV->Step) ||   // If the step != 1
          !cast<ConstantInt>(IV->Step)->equalsInt(1)) {

        // If the types are not compatible, insert a cast now...
        if (Val->getType() != IVTy)
          Val = InsertCast(Val, IVTy, AfterPHIIt);
        if (IV->Step->getType() != IVTy)
          IV->Step = InsertCast(IV->Step, IVTy, AfterPHIIt);

        Val = BinaryOperator::create(Instruction::Mul, Val, IV->Step,
                                     IV->Phi->getName()+"-scale", AfterPHIIt);
      }

      // If the start != 0
      if (IV->Start != Constant::getNullValue(IV->Start->getType())) {
        // If the types are not compatible, insert a cast now...
        if (Val->getType() != IVTy)
          Val = InsertCast(Val, IVTy, AfterPHIIt);
        if (IV->Start->getType() != IVTy)
          IV->Start = InsertCast(IV->Start, IVTy, AfterPHIIt);

        // Insert the instruction after the phi nodes...
        Val = BinaryOperator::create(Instruction::Add, Val, IV->Start,
                                     IV->Phi->getName()+"-offset", AfterPHIIt);
      }

      // If the PHI node has a different type than val is, insert a cast now...
      if (Val->getType() != IV->Phi->getType())
        Val = InsertCast(Val, IV->Phi->getType(), AfterPHIIt);

      // Replace all uses of the old PHI node with the new computed value...
      IV->Phi->replaceAllUsesWith(Val);

      // Move the PHI name to it's new equivalent value...
      std::string OldName = IV->Phi->getName();
      IV->Phi->setName("");
      Val->setName(OldName);

      // Get the incoming values used by the PHI node
      std::vector<Value*> PHIOps;
      PHIOps.reserve(IV->Phi->getNumIncomingValues());
      for (unsigned i = 0, e = IV->Phi->getNumIncomingValues(); i != e; ++i)
        PHIOps.push_back(IV->Phi->getIncomingValue(i));

      // Delete the old, now unused, phi node...
      Header->getInstList().erase(IV->Phi);

      // If the PHI is the last user of any instructions for computing PHI nodes
      // that are irrelevant now, delete those instructions.
      while (!PHIOps.empty()) {
        Instruction *MaybeDead = dyn_cast<Instruction>(PHIOps.back());
        PHIOps.pop_back();

        if (MaybeDead && isInstructionTriviallyDead(MaybeDead)) {
          PHIOps.insert(PHIOps.end(), MaybeDead->op_begin(),
                        MaybeDead->op_end());
          MaybeDead->getParent()->getInstList().erase(MaybeDead);
        }
      }

      Changed = true;
      ++NumRemoved;
    }
  }

  return Changed;
}

namespace {
  struct InductionVariableSimplify : public FunctionPass {
    virtual bool runOnFunction(Function &) {
      LoopInfo &LI = getAnalysis<LoopInfo>();

      // Induction Variables live in the header nodes of loops
      return reduce_apply_bool(LI.getTopLevelLoops().begin(),
                               LI.getTopLevelLoops().end(),
                               std::bind1st(std::ptr_fun(TransformLoop), &LI));
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<LoopInfo>();
      AU.addRequiredID(LoopSimplifyID);
      AU.setPreservesCFG();
    }
  };
  RegisterOpt<InductionVariableSimplify> X("indvars",
                                           "Canonicalize Induction Variables");
}

Pass *llvm::createIndVarSimplifyPass() {
  return new InductionVariableSimplify();
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <cctype>
#include <algorithm>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return unsigned(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || (id[2] < '0')
			|| (id[3] < '0') || (id[4] < '0')
			|| (id[5] < '0') || (id[6] < '0')
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.id[0] = id[1];
		ret.id[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+6, "--"))
		{
			if ((id[1] < '0') || (id[2] < '0')
				|| (id[3] < '0'))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.id[0] = id[0];
		ret.id[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		if (!std::isprint(id[0])
			|| !std::isalnum(id[1])
			|| id[2] != '-'
			|| !std::isalnum(id[3])
			|| id[4] != '-'
			|| !std::isalnum(id[5])
			|| !std::equal(id.begin() + 6, id.begin() + 8, "--"))
			return boost::optional<fingerprint>();

		fingerprint ret("..", 0, 0, 0, 0);

		ret.id[0] = id[0];
		ret.id[1] = 0;
		ret.major_version = decode_digit(id[1]);
		ret.minor_version = decode_digit(id[3]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	typedef std::pair<char const*, char const*> map_entry;

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		map_entry("A",  "ABC")
		, map_entry("AR", "Arctic Torrent")
		, map_entry("AZ", "Azureus")
		, map_entry("BB", "BitBuddy")
		, map_entry("BC", "BitComet")
		, map_entry("BS", "BTSlave")
		, map_entry("BX", "BittorrentX")
		, map_entry("CT", "CTorrent")
		, map_entry("LT", "libtorrent")
		, map_entry("M",  "Mainline")
		, map_entry("MP", "MooPolice")
		, map_entry("MT", "Moonlight Torrent")
		, map_entry("O",  "Osprey Permaseed")
		, map_entry("S",  "Shadow")
		, map_entry("SB", "Swiftbit")
		, map_entry("SN", "ShareNet")
		, map_entry("SS", "SwarmScope")
		, map_entry("T",  "BitTornado")
		, map_entry("TN", "Torrent.NET")
		, map_entry("TS", "TorrentStorm")
		, map_entry("U",  "UPnP")
		, map_entry("XT", "XanTorrent")
		, map_entry("ZT", "ZipTorrent")
		, map_entry("lt", "libTorrent (libtorrent.rakshasa.no/)")
		, map_entry("pX", "pHoeniX")
	};

	bool compare_first_string(map_entry const& e, char const* str)
	{
		return e.first[0] < str[0]
			|| ((e.first[0] == str[0]) && (e.first[1] < str[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, f.id, &compare_first_string);

#ifndef NDEBUG
		for (int i = 1; i < size; ++i)
		{
			assert(compare_first_string(name_map[i-1]
				, name_map[i].first));
		}
#endif

		if (i < name_map + size && std::equal(f.id, f.id + 2, i->first))
			identity << i->second;
		else
			identity << std::string(f.id, f.id + 2);

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version
			<< "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		if (find_string(PID, "Deadman Walking-")) return "Deadman";
		if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2";
		if (find_string(PID, "DansClient")) return "XanTorrent";
		if (find_string(PID + 4, "btfans")) return "SimpleBT";
		if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II";
		if (find_string(PID, "P87.P---")) return "Bittorrent Plus!";
		if (find_string(PID, "S587Plus")) return "Bittorrent Plus!";
		if (find_string(PID, "martini")) return "Martini Man";
		if (find_string(PID, "Plus---")) return "Bittorrent Plus";
		if (find_string(PID, "turbobt")) return "TurboBT";
		if (find_string(PID, "a00---0")) return "Swarmy";
		if (find_string(PID, "a02---0")) return "Swarmy";
		if (find_string(PID, "T00---0")) return "Teeweety";
		if (find_string(PID, "BTDWV-")) return "Deadman Walking";
		if (find_string(PID + 2, "BS")) return "BitSpirit";
		if (find_string(PID, "btuga")) return "BTugaXP";
		if (find_string(PID, "oernu")) return "BTugaXP";
		if (find_string(PID, "Mbrst")) return "Burst!";
		if (find_string(PID, "Plus")) return "Plus!";
		if (find_string(PID, "-Qt-")) return "Qt";
		if (find_string(PID, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "OP")) return "Opera";
		if (find_string(PID, "XBT")) return "XBT";

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<commit_msg>updated client identification<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <cctype>
#include <algorithm>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return unsigned(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || (id[2] < '0')
			|| (id[3] < '0') || (id[4] < '0')
			|| (id[5] < '0') || (id[6] < '0')
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.id[0] = id[1];
		ret.id[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+6, "--"))
		{
			if ((id[1] < '0') || (id[2] < '0')
				|| (id[3] < '0'))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.id[0] = id[0];
		ret.id[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		if (!std::isprint(id[0])
			|| !std::isalnum(id[1])
			|| id[2] != '-'
			|| !std::isalnum(id[3])
			|| id[4] != '-'
			|| !std::isalnum(id[5])
			|| !std::equal(id.begin() + 6, id.begin() + 8, "--"))
			return boost::optional<fingerprint>();

		fingerprint ret("..", 0, 0, 0, 0);

		ret.id[0] = id[0];
		ret.id[1] = 0;
		ret.major_version = decode_digit(id[1]);
		ret.minor_version = decode_digit(id[3]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	typedef std::pair<char const*, char const*> map_entry;

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		map_entry("A",  "ABC")
		, map_entry("AR", "Arctic Torrent")
		, map_entry("AZ", "Azureus")
		, map_entry("BB", "BitBuddy")
		, map_entry("BC", "BitComet")
		, map_entry("BS", "BTSlave")
		, map_entry("BX", "BittorrentX")
		, map_entry("CT", "CTorrent")
		, map_entry("KT", "KTorrent")
		, map_entry("LT", "libtorrent")
		, map_entry("M",  "Mainline")
		, map_entry("MP", "MooPolice")
		, map_entry("MT", "Moonlight Torrent")
		, map_entry("O",  "Osprey Permaseed")
		, map_entry("S",  "Shadow")
		, map_entry("SB", "Swiftbit")
		, map_entry("SN", "ShareNet")
		, map_entry("SS", "SwarmScope")
		, map_entry("SZ", "Shareaza")
		, map_entry("T",  "BitTornado")
		, map_entry("TN", "Torrent.NET")
		, map_entry("TS", "TorrentStorm")
		, map_entry("U",  "UPnP")
		, map_entry("UT", "MicroTorrent")
		, map_entry("XT", "XanTorrent")
		, map_entry("ZT", "ZipTorrent")
		, map_entry("lt", "libTorrent (libtorrent.rakshasa.no/)")
		, map_entry("pX", "pHoeniX")
	};

	bool compare_first_string(map_entry const& e, char const* str)
	{
		return e.first[0] < str[0]
			|| ((e.first[0] == str[0]) && (e.first[1] < str[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, f.id, &compare_first_string);

#ifndef NDEBUG
		for (int i = 1; i < size; ++i)
		{
			assert(compare_first_string(name_map[i-1]
				, name_map[i].first));
		}
#endif

		if (i < name_map + size && std::equal(f.id, f.id + 2, i->first))
			identity << i->second;
		else
			identity << std::string(f.id, f.id + 2);

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version
			<< "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		if (find_string(PID, "Deadman Walking-")) return "Deadman";
		if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2";
		if (find_string(PID, "DansClient")) return "XanTorrent";
		if (find_string(PID + 4, "btfans")) return "SimpleBT";
		if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II";
		if (find_string(PID, "P87.P---")) return "Bittorrent Plus!";
		if (find_string(PID, "S587Plus")) return "Bittorrent Plus!";
		if (find_string(PID, "martini")) return "Martini Man";
		if (find_string(PID, "Plus---")) return "Bittorrent Plus";
		if (find_string(PID, "turbobt")) return "TurboBT";
		if (find_string(PID, "a00---0")) return "Swarmy";
		if (find_string(PID, "a02---0")) return "Swarmy";
		if (find_string(PID, "T00---0")) return "Teeweety";
		if (find_string(PID, "BTDWV-")) return "Deadman Walking";
		if (find_string(PID + 2, "BS")) return "BitSpirit";
		if (find_string(PID, "btuga")) return "BTugaXP";
		if (find_string(PID, "oernu")) return "BTugaXP";
		if (find_string(PID, "Mbrst")) return "Burst!";
		if (find_string(PID, "Plus")) return "Plus!";
		if (find_string(PID, "-Qt-")) return "Qt";
		if (find_string(PID, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "XBT")) return "XBT";
		if (find_string(PID, "OP")) return "Opera";

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <cctype>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
	using ::toupper;
	using ::isalnum;
}
#endif

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return std::toupper(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || !std::isprint(id[2])
			|| !std::isalnum(id[3]) || !std::isalnum(id[4])
			|| !std::isalnum(id[5]) || !std::isalnum(id[6])
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.id[0] = id[1];
		ret.id[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+8, "----"))
		{
			if (!std::isalnum(id[1]) || !std::isalnum(id[2])
				|| !std::isalnum(id[3]))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.id[0] = id[0];
		ret.id[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		if (!std::isprint(id[0])
			|| !std::isalnum(id[1])
			|| id[2] != '-'
			|| !std::isalnum(id[3])
			|| id[4] != '-'
			|| !std::isalnum(id[5])
			|| !std::equal(id.begin() + 6, id.begin() + 8, "--"))
			return boost::optional<fingerprint>();

		fingerprint ret("..", 0, 0, 0, 0);

		ret.id[0] = id[0];
		ret.id[1] = 0;
		ret.major_version = decode_digit(id[1]);
		ret.minor_version = decode_digit(id[3]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	typedef std::pair<char const*, char const*> map_entry;

	// must be ordered alphabetically
	map_entry name_map[] =
	{
		map_entry("A",  "ABC")
		, map_entry("AZ", "Azureus")
		, map_entry("BB", "BitBuddy")
		, map_entry("BX", "BittorrentX")
		, map_entry("CT", "CTorrent")
		, map_entry("LT", "libtorrent")
		, map_entry("M",  "Mainline")
		, map_entry("MT", "Moonlight Torrent")
		, map_entry("S",  "Shadow")
		, map_entry("SS", "SwarmScope")
		, map_entry("T",  "BitTornado")
		, map_entry("TN", "TorrentDonNet")
		, map_entry("TS", "TorrentStorm")
		, map_entry("U",  "UPnP")
		, map_entry("XT", "XanTorrent")
	};

	bool compare_first_string(map_entry const& e, char const* str)
	{
		return e.first[0] < str[0]
			|| ((e.first[0] == str[0]) && (e.first[1] < str[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, f.id, &compare_first_string);

		if (i < name_map + size && std::equal(f.id, f.id + 2, i->first))
			identity << i->second;
		else
			identity << std::string(f.id, f.id + 2);

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version
			<< "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		// ----------------------
		// non standard encodings
		// ----------------------

		if (find_string(PID, "Deadman Walking-")) return "Deadman";
		if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2";
		if (find_string(PID, "DansClient")) return "XanTorrent";
		if (find_string(PID + 4, "btfans")) return "SimpleBT";
		if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II";
		if (find_string(PID, "P87.P---")) return "Bittorrent Plus!";
		if (find_string(PID, "S587Plus")) return "Bittorrent Plus!";
		if (find_string(PID, "martini")) return "Martini Man";
		if (find_string(PID, "Plus---")) return "Bittorrent Plus";
		if (find_string(PID, "turbobt")) return "TurboBT";
		if (find_string(PID, "BTDWV-")) return "Deadman Walking";
		if (find_string(PID + 2, "BS")) return "BitSpirit";
		if (find_string(PID, "btuga")) return "BTugaXP";
		if (find_string(PID, "oernu")) return "BTugaXP";
		if (find_string(PID, "Mbrst")) return "Burst!";
		if (find_string(PID, "Plus")) return "Plus!";
		if (find_string(PID, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "XBT")) return "XBT";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<commit_msg>spelling mistake bugfix for TorrentDotNET<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <cctype>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
	using ::toupper;
	using ::isalnum;
}
#endif

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return std::toupper(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || !std::isprint(id[2])
			|| !std::isalnum(id[3]) || !std::isalnum(id[4])
			|| !std::isalnum(id[5]) || !std::isalnum(id[6])
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.id[0] = id[1];
		ret.id[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+8, "----"))
		{
			if (!std::isalnum(id[1]) || !std::isalnum(id[2])
				|| !std::isalnum(id[3]))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.id[0] = id[0];
		ret.id[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		if (!std::isprint(id[0])
			|| !std::isalnum(id[1])
			|| id[2] != '-'
			|| !std::isalnum(id[3])
			|| id[4] != '-'
			|| !std::isalnum(id[5])
			|| !std::equal(id.begin() + 6, id.begin() + 8, "--"))
			return boost::optional<fingerprint>();

		fingerprint ret("..", 0, 0, 0, 0);

		ret.id[0] = id[0];
		ret.id[1] = 0;
		ret.major_version = decode_digit(id[1]);
		ret.minor_version = decode_digit(id[3]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	typedef std::pair<char const*, char const*> map_entry;

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		map_entry("A",  "ABC")
		, map_entry("AZ", "Azureus")
		, map_entry("BB", "BitBuddy")
		, map_entry("BX", "BittorrentX")
		, map_entry("CT", "CTorrent")
		, map_entry("LT", "libtorrent")
		, map_entry("M",  "Mainline")
		, map_entry("MT", "Moonlight Torrent")
		, map_entry("S",  "Shadow")
		, map_entry("SS", "SwarmScope")
		, map_entry("T",  "BitTornado")
		, map_entry("TN", "TorrentDotNET")
		, map_entry("TS", "TorrentStorm")
		, map_entry("U",  "UPnP")
		, map_entry("XT", "XanTorrent")
	};

	bool compare_first_string(map_entry const& e, char const* str)
	{
		return e.first[0] < str[0]
			|| ((e.first[0] == str[0]) && (e.first[1] < str[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, f.id, &compare_first_string);

		if (i < name_map + size && std::equal(f.id, f.id + 2, i->first))
			identity << i->second;
		else
			identity << std::string(f.id, f.id + 2);

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version
			<< "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		// ----------------------
		// non standard encodings
		// ----------------------

		if (find_string(PID, "Deadman Walking-")) return "Deadman";
		if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2";
		if (find_string(PID, "DansClient")) return "XanTorrent";
		if (find_string(PID + 4, "btfans")) return "SimpleBT";
		if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II";
		if (find_string(PID, "P87.P---")) return "Bittorrent Plus!";
		if (find_string(PID, "S587Plus")) return "Bittorrent Plus!";
		if (find_string(PID, "martini")) return "Martini Man";
		if (find_string(PID, "Plus---")) return "Bittorrent Plus";
		if (find_string(PID, "turbobt")) return "TurboBT";
		if (find_string(PID, "BTDWV-")) return "Deadman Walking";
		if (find_string(PID + 2, "BS")) return "BitSpirit";
		if (find_string(PID, "btuga")) return "BTugaXP";
		if (find_string(PID, "oernu")) return "BTugaXP";
		if (find_string(PID, "Mbrst")) return "Burst!";
		if (find_string(PID, "Plus")) return "Plus!";
		if (find_string(PID, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "XBT")) return "XBT";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<|endoftext|>