<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: tempfile.cxx,v $
 *
 *  $Revision: 1.24 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 14:09:51 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <unotools/tempfile.hxx>
#include <tools/tempfile.hxx>
#include <unotools/localfilehelper.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <ucbhelper/fileidentifierconverter.hxx>
#include <ucbhelper/contentbroker.hxx>
#include <rtl/ustring.hxx>
#ifndef INCLUDED_RTL_INSTANCE_HXX
#include <rtl/instance.hxx>
#endif
#include <osl/file.hxx>
#include <tools/time.hxx>
#include <tools/debug.hxx>
#include <stdio.h>

#ifdef UNX
#include <sys/stat.h>
#endif

using namespace osl;

namespace
{
    struct TempNameBase_Impl
        : public rtl::Static< ::rtl::OUString, TempNameBase_Impl > {};
}

namespace utl
{

struct TempFile_Impl
{
    String      aName;
    String      aURL;
    SvStream*   pStream;
    sal_Bool    bIsDirectory;

                TempFile_Impl()
                    : pStream(0)
                    {}
};

rtl::OUString getParentName( const rtl::OUString& aFileName )
{
    sal_Int32 lastIndex = aFileName.lastIndexOf( sal_Unicode('/') );
    rtl::OUString aParent = aFileName.copy( 0,lastIndex );

    if( aParent[ aParent.getLength()-1] == sal_Unicode(':') && aParent.getLength() == 6 )
        aParent += rtl::OUString::createFromAscii( "/" );

    if( 0 == aParent.compareToAscii( "file://" ) )
        aParent = rtl::OUString::createFromAscii( "file:///" );

    return aParent;
}

sal_Bool ensuredir( const rtl::OUString& rUnqPath )
{
    rtl::OUString aPath;
    if ( rUnqPath.getLength() < 1 )
        return sal_False;

    // remove trailing slash
    if ( rUnqPath[ rUnqPath.getLength() - 1 ] == sal_Unicode( '/' ) )
        aPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 );
    else
        aPath = rUnqPath;

    // HACK: create directory on a mount point with nobrowse option
    // returns ENOSYS in any case !!
    osl::Directory aDirectory( aPath );
#ifdef UNX
/* RW permission for the user only! */
 mode_t old_mode = umask(077);
#endif
    osl::FileBase::RC nError = aDirectory.open();
#ifdef UNX
umask(old_mode);
#endif
    aDirectory.close();
    if( nError == osl::File::E_None )
        return sal_True;

    // try to create the directory
    nError = osl::Directory::create( aPath );
    sal_Bool  bSuccess = ( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
    if( !bSuccess )
    {
        // perhaps parent(s) don't exist
        rtl::OUString aParentDir = getParentName( aPath );
        if ( aParentDir != aPath )
        {
            bSuccess = ensuredir( getParentName( aPath ) );

            // After parent directory structure exists try it one's more
            if ( bSuccess )
            {
                // Parent directory exists, retry creation of directory
                nError = osl::Directory::create( aPath );
                bSuccess =( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
            }
        }
    }

    return bSuccess;
}

#define TMPNAME_SIZE  ( 1 + 5 + 5 + 4 + 1 )
String ConstructTempDir_Impl( const String* pParent )
{
    String aName;
    if ( pParent && pParent->Len() )
    {
        ::ucb::ContentBroker* pBroker = ::ucb::ContentBroker::get();
        if ( pBroker )
        {
            ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContentProviderManager > xManager =
                    pBroker->getContentProviderManagerInterface();

            // if parent given try to use it
            rtl::OUString aTmp( *pParent );

            // test for valid filename
            rtl::OUString aRet;
            ::osl::FileBase::getFileURLFromSystemPath(
                ::ucb::getSystemPathFromFileURL( xManager, aTmp ),
                aRet );
            if ( aRet.getLength() )
            {
                ::osl::DirectoryItem aItem;
                sal_Int32 i = aRet.getLength();
                if ( aRet[i-1] == '/' )
                    i--;

                if ( DirectoryItem::get( ::rtl::OUString( aRet, i ), aItem ) == FileBase::E_None )
                    aName = aRet;
            }
        }
        else
        {
            DBG_WARNING( "::unotools::TempFile : UCB not present or not initialized!" );
        }
    }

    if ( !aName.Len() )
    {
        ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
        if (rTempNameBase_Impl.getLength() == 0)
        {
            ::rtl::OUString ustrTempDirURL;
            ::osl::FileBase::RC rc = ::osl::File::getTempDirURL(
                ustrTempDirURL );
            if (rc == ::osl::FileBase::E_None)
                rTempNameBase_Impl = ustrTempDirURL;
        }
        // if no parent or invalid parent : use default directory
        DBG_ASSERT( rTempNameBase_Impl.getLength(), "No TempDir!" );
        aName = rTempNameBase_Impl;
        ensuredir( aName );
    }

    // Make sure that directory ends with a separator
    xub_StrLen i = aName.Len();
    if( i>0 && aName.GetChar(i-1) != '/' )
        aName += '/';

    return aName;
}

void CreateTempName_Impl( String& rName, sal_Bool bKeep, sal_Bool bDir = sal_True )
{
    // add a suitable tempname
    // Prefix can have 5 chars, leaving 3 for numbers. 26 ** 3 == 17576
    // ER 13.07.00  why not radix 36 [0-9A-Z] ?!?
    const unsigned nRadix = 26;
    String aName( rName );
    aName += String::CreateFromAscii( "sv" );

    rName.Erase();
    static unsigned long u = Time::GetSystemTicks();
    for ( unsigned long nOld = u; ++u != nOld; )
    {
        u %= (nRadix*nRadix*nRadix);
        String aTmp( aName );
        aTmp += String::CreateFromInt32( (sal_Int32) (unsigned) u, nRadix );
        aTmp += String::CreateFromAscii( ".tmp" );

        if ( bDir )
        {
            FileBase::RC err = Directory::create( aTmp );
            if (  err == FileBase::E_None )
            {
                // !bKeep: only for creating a name, not a file or directory
                if ( bKeep || Directory::remove( aTmp ) == FileBase::E_None )
                    rName = aTmp;
                break;
            }
            else if ( err != FileBase::E_EXIST )
            {
                // if f.e. name contains invalid chars stop trying to create dirs
                break;
            }
        }
        else
        {
            DBG_ASSERT( bKeep, "Too expensive, use directory for creating name!" );
            File aFile( aTmp );
#ifdef UNX
/* RW permission for the user only! */
 mode_t old_mode = umask(077);
#endif
            FileBase::RC err = aFile.open(osl_File_OpenFlag_Create);
#ifdef UNX
umask(old_mode);
#endif
            if (  err == FileBase::E_None )
            {
                rName = aTmp;
                aFile.close();
                break;
            }
            else if ( err != FileBase::E_EXIST )
            {
                 // if f.e. name contains invalid chars stop trying to create files
                 // but if there is a folder with such name proceed further

                 DirectoryItem aTmpItem;
                 FileStatus aTmpStatus( FileStatusMask_Type );
                 if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
                   || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
                   || aTmpStatus.getFileType() != FileStatus::Directory )
                     break;
            }
        }
    }
}

String TempFile::CreateTempName( const String* pParent )
{
    // get correct directory
    String aName = ConstructTempDir_Impl( pParent );

    // get TempFile name with default naming scheme
    CreateTempName_Impl( aName, sal_False );

    // convert to file URL
    rtl::OUString aTmp;
    if ( aName.Len() )
        FileBase::getSystemPathFromFileURL( aName, aTmp );
    return aTmp;
}

TempFile::TempFile( const String* pParent, sal_Bool bDirectory )
    : pImp( new TempFile_Impl )
    , bKillingFileEnabled( sal_False )
{
    pImp->bIsDirectory = bDirectory;

    // get correct directory
    pImp->aName = ConstructTempDir_Impl( pParent );

    // get TempFile with default naming scheme
    CreateTempName_Impl( pImp->aName, sal_True, bDirectory );
}

TempFile::TempFile( const String& rLeadingChars, const String* pExtension, const String* pParent, sal_Bool bDirectory )
    : pImp( new TempFile_Impl )
    , bKillingFileEnabled( sal_False )
{
    pImp->bIsDirectory = bDirectory;

    // get correct directory
    String aName = ConstructTempDir_Impl( pParent );

    // now use special naming scheme ( name takes leading chars and an index counting up from zero
    aName += rLeadingChars;
    for ( sal_Int32 i=0;; i++ )
    {
        String aTmp( aName );
        aTmp += String::CreateFromInt32( i );
        if ( pExtension )
            aTmp += *pExtension;
        else
            aTmp += String::CreateFromAscii( ".tmp" );
        if ( bDirectory )
        {
            FileBase::RC err = Directory::create( aTmp );
            if ( err == FileBase::E_None )
            {
                pImp->aName = aTmp;
                break;
            }
            else if ( err != FileBase::E_EXIST )
                // if f.e. name contains invalid chars stop trying to create dirs
                break;
        }
        else
        {
            File aFile( aTmp );
#ifdef UNX
/* RW permission for the user only! */
 mode_t old_mode = umask(077);
#endif
            FileBase::RC err = aFile.open(osl_File_OpenFlag_Create);
#ifdef UNX
umask(old_mode);
#endif
            if ( err == FileBase::E_None )
            {
                pImp->aName = aTmp;
                aFile.close();
                break;
            }
            else if ( err != FileBase::E_EXIST )
            {
                // if f.e. name contains invalid chars stop trying to create dirs
                // but if there is a folder with such name proceed further

                DirectoryItem aTmpItem;
                FileStatus aTmpStatus( FileStatusMask_Type );
                if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
                  || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
                  || aTmpStatus.getFileType() != FileStatus::Directory )
                    break;
            }
        }
    }
}

TempFile::~TempFile()
{
    delete pImp->pStream;
    if ( bKillingFileEnabled )
    {
        if ( pImp->bIsDirectory )
        {
            // at the moment no recursiv algorithm present
            Directory::remove( pImp->aName );
        }
        else
        {
            File::remove( pImp->aName );
        }
    }

    delete pImp;
}

sal_Bool TempFile::IsValid() const
{
    return pImp->aName.Len() != 0;
}

String TempFile::GetFileName() const
{
    rtl::OUString aTmp;
    FileBase::getSystemPathFromFileURL( pImp->aName, aTmp );
    return aTmp;
}

String TempFile::GetURL() const
{
    if ( !pImp->aURL.Len() )
    {
        String aTmp;
        LocalFileHelper::ConvertPhysicalNameToURL( GetFileName(), aTmp );
        pImp->aURL = aTmp;
    }

    return pImp->aURL;
}

SvStream* TempFile::GetStream( StreamMode eMode )
{
    if ( !pImp->pStream )
    {
        if ( GetURL().Len() )
            pImp->pStream = UcbStreamHelper::CreateStream( pImp->aURL, eMode, sal_True /* bFileExists */ );
        else
            pImp->pStream = new SvMemoryStream( eMode );
    }

    return pImp->pStream;
}

void TempFile::CloseStream()
{
    if ( pImp->pStream )
    {
        delete pImp->pStream;
        pImp->pStream = NULL;
    }
}

String TempFile::SetTempNameBaseDirectory( const String &rBaseName )
{
    if( !rBaseName.Len() )
        return String();

    rtl::OUString aUnqPath( rBaseName );

    // remove trailing slash
    if ( rBaseName.GetChar( rBaseName.Len() - 1 ) == sal_Unicode( '/' ) )
        aUnqPath = rBaseName.Copy( 0, rBaseName.Len() - 1 );

    // try to create the directory
    sal_Bool bRet = sal_False;
    osl::FileBase::RC err = osl::Directory::create( aUnqPath );
    if ( err != FileBase::E_None && err != FileBase::E_EXIST )
        // perhaps parent(s) don't exist
        bRet = ensuredir( aUnqPath );
    else
        bRet = sal_True;

    // failure to create base directory means returning an empty string
    rtl::OUString aTmp;
    if ( bRet )
    {
        // append own internal directory
        bRet = sal_True;
        ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
        rTempNameBase_Impl = rBaseName;
        rTempNameBase_Impl += String( '/' );

        TempFile aBase( NULL, sal_True );
        if ( aBase.IsValid() )
            // use it in case of success
            rTempNameBase_Impl = aBase.pImp->aName;

        // return system path of used directory
        FileBase::getSystemPathFromFileURL( rTempNameBase_Impl, aTmp );
    }

    return aTmp;
}

String TempFile::GetTempNameBaseDirectory()
{
    const ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
    if ( !rTempNameBase_Impl.getLength() )
        return String();

    rtl::OUString aTmp;
    FileBase::getSystemPathFromFileURL( rTempNameBase_Impl, aTmp );
    return aTmp;
}

}
<commit_msg>INTEGRATION: CWS pchfix02 (1.24.16); FILE MERGED 2006/09/01 17:56:26 kaib 1.24.16.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: tempfile.cxx,v $
 *
 *  $Revision: 1.25 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 01:29:54 $
 *
 *  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_unotools.hxx"

#include <unotools/tempfile.hxx>
#include <tools/tempfile.hxx>
#include <unotools/localfilehelper.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <ucbhelper/fileidentifierconverter.hxx>
#include <ucbhelper/contentbroker.hxx>
#include <rtl/ustring.hxx>
#ifndef INCLUDED_RTL_INSTANCE_HXX
#include <rtl/instance.hxx>
#endif
#include <osl/file.hxx>
#include <tools/time.hxx>
#include <tools/debug.hxx>
#include <stdio.h>

#ifdef UNX
#include <sys/stat.h>
#endif

using namespace osl;

namespace
{
    struct TempNameBase_Impl
        : public rtl::Static< ::rtl::OUString, TempNameBase_Impl > {};
}

namespace utl
{

struct TempFile_Impl
{
    String      aName;
    String      aURL;
    SvStream*   pStream;
    sal_Bool    bIsDirectory;

                TempFile_Impl()
                    : pStream(0)
                    {}
};

rtl::OUString getParentName( const rtl::OUString& aFileName )
{
    sal_Int32 lastIndex = aFileName.lastIndexOf( sal_Unicode('/') );
    rtl::OUString aParent = aFileName.copy( 0,lastIndex );

    if( aParent[ aParent.getLength()-1] == sal_Unicode(':') && aParent.getLength() == 6 )
        aParent += rtl::OUString::createFromAscii( "/" );

    if( 0 == aParent.compareToAscii( "file://" ) )
        aParent = rtl::OUString::createFromAscii( "file:///" );

    return aParent;
}

sal_Bool ensuredir( const rtl::OUString& rUnqPath )
{
    rtl::OUString aPath;
    if ( rUnqPath.getLength() < 1 )
        return sal_False;

    // remove trailing slash
    if ( rUnqPath[ rUnqPath.getLength() - 1 ] == sal_Unicode( '/' ) )
        aPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 );
    else
        aPath = rUnqPath;

    // HACK: create directory on a mount point with nobrowse option
    // returns ENOSYS in any case !!
    osl::Directory aDirectory( aPath );
#ifdef UNX
/* RW permission for the user only! */
 mode_t old_mode = umask(077);
#endif
    osl::FileBase::RC nError = aDirectory.open();
#ifdef UNX
umask(old_mode);
#endif
    aDirectory.close();
    if( nError == osl::File::E_None )
        return sal_True;

    // try to create the directory
    nError = osl::Directory::create( aPath );
    sal_Bool  bSuccess = ( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
    if( !bSuccess )
    {
        // perhaps parent(s) don't exist
        rtl::OUString aParentDir = getParentName( aPath );
        if ( aParentDir != aPath )
        {
            bSuccess = ensuredir( getParentName( aPath ) );

            // After parent directory structure exists try it one's more
            if ( bSuccess )
            {
                // Parent directory exists, retry creation of directory
                nError = osl::Directory::create( aPath );
                bSuccess =( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
            }
        }
    }

    return bSuccess;
}

#define TMPNAME_SIZE  ( 1 + 5 + 5 + 4 + 1 )
String ConstructTempDir_Impl( const String* pParent )
{
    String aName;
    if ( pParent && pParent->Len() )
    {
        ::ucb::ContentBroker* pBroker = ::ucb::ContentBroker::get();
        if ( pBroker )
        {
            ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContentProviderManager > xManager =
                    pBroker->getContentProviderManagerInterface();

            // if parent given try to use it
            rtl::OUString aTmp( *pParent );

            // test for valid filename
            rtl::OUString aRet;
            ::osl::FileBase::getFileURLFromSystemPath(
                ::ucb::getSystemPathFromFileURL( xManager, aTmp ),
                aRet );
            if ( aRet.getLength() )
            {
                ::osl::DirectoryItem aItem;
                sal_Int32 i = aRet.getLength();
                if ( aRet[i-1] == '/' )
                    i--;

                if ( DirectoryItem::get( ::rtl::OUString( aRet, i ), aItem ) == FileBase::E_None )
                    aName = aRet;
            }
        }
        else
        {
            DBG_WARNING( "::unotools::TempFile : UCB not present or not initialized!" );
        }
    }

    if ( !aName.Len() )
    {
        ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
        if (rTempNameBase_Impl.getLength() == 0)
        {
            ::rtl::OUString ustrTempDirURL;
            ::osl::FileBase::RC rc = ::osl::File::getTempDirURL(
                ustrTempDirURL );
            if (rc == ::osl::FileBase::E_None)
                rTempNameBase_Impl = ustrTempDirURL;
        }
        // if no parent or invalid parent : use default directory
        DBG_ASSERT( rTempNameBase_Impl.getLength(), "No TempDir!" );
        aName = rTempNameBase_Impl;
        ensuredir( aName );
    }

    // Make sure that directory ends with a separator
    xub_StrLen i = aName.Len();
    if( i>0 && aName.GetChar(i-1) != '/' )
        aName += '/';

    return aName;
}

void CreateTempName_Impl( String& rName, sal_Bool bKeep, sal_Bool bDir = sal_True )
{
    // add a suitable tempname
    // Prefix can have 5 chars, leaving 3 for numbers. 26 ** 3 == 17576
    // ER 13.07.00  why not radix 36 [0-9A-Z] ?!?
    const unsigned nRadix = 26;
    String aName( rName );
    aName += String::CreateFromAscii( "sv" );

    rName.Erase();
    static unsigned long u = Time::GetSystemTicks();
    for ( unsigned long nOld = u; ++u != nOld; )
    {
        u %= (nRadix*nRadix*nRadix);
        String aTmp( aName );
        aTmp += String::CreateFromInt32( (sal_Int32) (unsigned) u, nRadix );
        aTmp += String::CreateFromAscii( ".tmp" );

        if ( bDir )
        {
            FileBase::RC err = Directory::create( aTmp );
            if (  err == FileBase::E_None )
            {
                // !bKeep: only for creating a name, not a file or directory
                if ( bKeep || Directory::remove( aTmp ) == FileBase::E_None )
                    rName = aTmp;
                break;
            }
            else if ( err != FileBase::E_EXIST )
            {
                // if f.e. name contains invalid chars stop trying to create dirs
                break;
            }
        }
        else
        {
            DBG_ASSERT( bKeep, "Too expensive, use directory for creating name!" );
            File aFile( aTmp );
#ifdef UNX
/* RW permission for the user only! */
 mode_t old_mode = umask(077);
#endif
            FileBase::RC err = aFile.open(osl_File_OpenFlag_Create);
#ifdef UNX
umask(old_mode);
#endif
            if (  err == FileBase::E_None )
            {
                rName = aTmp;
                aFile.close();
                break;
            }
            else if ( err != FileBase::E_EXIST )
            {
                 // if f.e. name contains invalid chars stop trying to create files
                 // but if there is a folder with such name proceed further

                 DirectoryItem aTmpItem;
                 FileStatus aTmpStatus( FileStatusMask_Type );
                 if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
                   || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
                   || aTmpStatus.getFileType() != FileStatus::Directory )
                     break;
            }
        }
    }
}

String TempFile::CreateTempName( const String* pParent )
{
    // get correct directory
    String aName = ConstructTempDir_Impl( pParent );

    // get TempFile name with default naming scheme
    CreateTempName_Impl( aName, sal_False );

    // convert to file URL
    rtl::OUString aTmp;
    if ( aName.Len() )
        FileBase::getSystemPathFromFileURL( aName, aTmp );
    return aTmp;
}

TempFile::TempFile( const String* pParent, sal_Bool bDirectory )
    : pImp( new TempFile_Impl )
    , bKillingFileEnabled( sal_False )
{
    pImp->bIsDirectory = bDirectory;

    // get correct directory
    pImp->aName = ConstructTempDir_Impl( pParent );

    // get TempFile with default naming scheme
    CreateTempName_Impl( pImp->aName, sal_True, bDirectory );
}

TempFile::TempFile( const String& rLeadingChars, const String* pExtension, const String* pParent, sal_Bool bDirectory )
    : pImp( new TempFile_Impl )
    , bKillingFileEnabled( sal_False )
{
    pImp->bIsDirectory = bDirectory;

    // get correct directory
    String aName = ConstructTempDir_Impl( pParent );

    // now use special naming scheme ( name takes leading chars and an index counting up from zero
    aName += rLeadingChars;
    for ( sal_Int32 i=0;; i++ )
    {
        String aTmp( aName );
        aTmp += String::CreateFromInt32( i );
        if ( pExtension )
            aTmp += *pExtension;
        else
            aTmp += String::CreateFromAscii( ".tmp" );
        if ( bDirectory )
        {
            FileBase::RC err = Directory::create( aTmp );
            if ( err == FileBase::E_None )
            {
                pImp->aName = aTmp;
                break;
            }
            else if ( err != FileBase::E_EXIST )
                // if f.e. name contains invalid chars stop trying to create dirs
                break;
        }
        else
        {
            File aFile( aTmp );
#ifdef UNX
/* RW permission for the user only! */
 mode_t old_mode = umask(077);
#endif
            FileBase::RC err = aFile.open(osl_File_OpenFlag_Create);
#ifdef UNX
umask(old_mode);
#endif
            if ( err == FileBase::E_None )
            {
                pImp->aName = aTmp;
                aFile.close();
                break;
            }
            else if ( err != FileBase::E_EXIST )
            {
                // if f.e. name contains invalid chars stop trying to create dirs
                // but if there is a folder with such name proceed further

                DirectoryItem aTmpItem;
                FileStatus aTmpStatus( FileStatusMask_Type );
                if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
                  || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
                  || aTmpStatus.getFileType() != FileStatus::Directory )
                    break;
            }
        }
    }
}

TempFile::~TempFile()
{
    delete pImp->pStream;
    if ( bKillingFileEnabled )
    {
        if ( pImp->bIsDirectory )
        {
            // at the moment no recursiv algorithm present
            Directory::remove( pImp->aName );
        }
        else
        {
            File::remove( pImp->aName );
        }
    }

    delete pImp;
}

sal_Bool TempFile::IsValid() const
{
    return pImp->aName.Len() != 0;
}

String TempFile::GetFileName() const
{
    rtl::OUString aTmp;
    FileBase::getSystemPathFromFileURL( pImp->aName, aTmp );
    return aTmp;
}

String TempFile::GetURL() const
{
    if ( !pImp->aURL.Len() )
    {
        String aTmp;
        LocalFileHelper::ConvertPhysicalNameToURL( GetFileName(), aTmp );
        pImp->aURL = aTmp;
    }

    return pImp->aURL;
}

SvStream* TempFile::GetStream( StreamMode eMode )
{
    if ( !pImp->pStream )
    {
        if ( GetURL().Len() )
            pImp->pStream = UcbStreamHelper::CreateStream( pImp->aURL, eMode, sal_True /* bFileExists */ );
        else
            pImp->pStream = new SvMemoryStream( eMode );
    }

    return pImp->pStream;
}

void TempFile::CloseStream()
{
    if ( pImp->pStream )
    {
        delete pImp->pStream;
        pImp->pStream = NULL;
    }
}

String TempFile::SetTempNameBaseDirectory( const String &rBaseName )
{
    if( !rBaseName.Len() )
        return String();

    rtl::OUString aUnqPath( rBaseName );

    // remove trailing slash
    if ( rBaseName.GetChar( rBaseName.Len() - 1 ) == sal_Unicode( '/' ) )
        aUnqPath = rBaseName.Copy( 0, rBaseName.Len() - 1 );

    // try to create the directory
    sal_Bool bRet = sal_False;
    osl::FileBase::RC err = osl::Directory::create( aUnqPath );
    if ( err != FileBase::E_None && err != FileBase::E_EXIST )
        // perhaps parent(s) don't exist
        bRet = ensuredir( aUnqPath );
    else
        bRet = sal_True;

    // failure to create base directory means returning an empty string
    rtl::OUString aTmp;
    if ( bRet )
    {
        // append own internal directory
        bRet = sal_True;
        ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
        rTempNameBase_Impl = rBaseName;
        rTempNameBase_Impl += String( '/' );

        TempFile aBase( NULL, sal_True );
        if ( aBase.IsValid() )
            // use it in case of success
            rTempNameBase_Impl = aBase.pImp->aName;

        // return system path of used directory
        FileBase::getSystemPathFromFileURL( rTempNameBase_Impl, aTmp );
    }

    return aTmp;
}

String TempFile::GetTempNameBaseDirectory()
{
    const ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
    if ( !rTempNameBase_Impl.getLength() )
        return String();

    rtl::OUString aTmp;
    FileBase::getSystemPathFromFileURL( rTempNameBase_Impl, aTmp );
    return aTmp;
}

}
<|endoftext|>


<commit_before>// Copyright 2017-2020 The Verible Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "verilog/formatting/comment_controls.h"

#include <iostream>
#include <vector>

#include "absl/strings/match.h"
#include "absl/strings/str_split.h"
#include "absl/strings/strip.h"
#include "common/strings/comment_utils.h"
#include "common/util/logging.h"
#include "verilog/parser/verilog_parser.h"
#include "verilog/parser/verilog_token_enum.h"

namespace verilog {
namespace formatter {

ByteOffsetSet DisableFormattingRanges(absl::string_view text,
                                      const verible::TokenSequence& tokens) {
  static constexpr absl::string_view kTrigger = "verilog_format:";
  static const auto kDelimiters = absl::ByAnyChar(" \t");
  static constexpr int kNullOffset = -1;
  const verible::TokenInfo::Context context(
      text,
      [](std::ostream& stream, int e) { stream << verilog_symbol_name(e); });

  // By default, no text ranges are formatter-disabled.
  int begin_disable_offset = kNullOffset;
  ByteOffsetSet disable_set;
  for (const auto& token : tokens) {
    VLOG(2) << verible::TokenWithContext{token, context};
    switch (token.token_enum) {
      case TK_EOL_COMMENT:
      case TK_COMMENT_BLOCK: {
        // Focus on the space-delimited tokens in the comment text.
        auto commands = verible::StripCommentAndSpacePadding(token.text);
        if (absl::ConsumePrefix(&commands, kTrigger)) {
          const std::vector<absl::string_view> comment_tokens(
              absl::StrSplit(commands, kDelimiters, absl::SkipEmpty()));
          if (!comment_tokens.empty()) {
            // "off" marks the start of a disabling range, at end of comment.
            // "on" marks the end of disabling range, at start of comment.
            if (comment_tokens.front() == "off") {
              if (begin_disable_offset == kNullOffset) {
                begin_disable_offset = token.right(text);
                if (token.token_enum == TK_EOL_COMMENT) {
                  ++begin_disable_offset;  // to cover the trailing '\n'
                }
              }  // else ignore
            } else if (comment_tokens.front() == "on") {
              if (begin_disable_offset != kNullOffset) {
                const int end_disable_offset = token.left(text);
                if (begin_disable_offset != end_disable_offset) {
                  disable_set.Add({begin_disable_offset, end_disable_offset});
                }
                begin_disable_offset = kNullOffset;
              }  // else ignore
            }
          }
        }
        break;
      }
      default:
        break;
    }
  }
  // If the disabling interval remains open, close it (to end-of-buffer).
  if (begin_disable_offset != kNullOffset) {
    disable_set.Add({begin_disable_offset, text.length()});
  }
  return disable_set;
}

}  // namespace formatter
}  // namespace verilog
<commit_msg>Fix signedness matching on byte offset ranges.<commit_after>// Copyright 2017-2020 The Verible Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "verilog/formatting/comment_controls.h"

#include <iostream>
#include <vector>

#include "absl/strings/match.h"
#include "absl/strings/str_split.h"
#include "absl/strings/strip.h"
#include "common/strings/comment_utils.h"
#include "common/util/logging.h"
#include "verilog/parser/verilog_parser.h"
#include "verilog/parser/verilog_token_enum.h"

namespace verilog {
namespace formatter {

ByteOffsetSet DisableFormattingRanges(absl::string_view text,
                                      const verible::TokenSequence& tokens) {
  static constexpr absl::string_view kTrigger = "verilog_format:";
  static const auto kDelimiters = absl::ByAnyChar(" \t");
  static constexpr size_t kNullOffset = static_cast<size_t>(-1);
  const verible::TokenInfo::Context context(
      text,
      [](std::ostream& stream, int e) { stream << verilog_symbol_name(e); });

  // By default, no text ranges are formatter-disabled.
  size_t begin_disable_offset = kNullOffset;
  ByteOffsetSet disable_set;
  for (const auto& token : tokens) {
    VLOG(2) << verible::TokenWithContext{token, context};
    switch (token.token_enum) {
      case TK_EOL_COMMENT:
      case TK_COMMENT_BLOCK: {
        // Focus on the space-delimited tokens in the comment text.
        auto commands = verible::StripCommentAndSpacePadding(token.text);
        if (absl::ConsumePrefix(&commands, kTrigger)) {
          const std::vector<absl::string_view> comment_tokens(
              absl::StrSplit(commands, kDelimiters, absl::SkipEmpty()));
          if (!comment_tokens.empty()) {
            // "off" marks the start of a disabling range, at end of comment.
            // "on" marks the end of disabling range, at start of comment.
            if (comment_tokens.front() == "off") {
              if (begin_disable_offset == kNullOffset) {
                begin_disable_offset = token.right(text);
                if (token.token_enum == TK_EOL_COMMENT) {
                  ++begin_disable_offset;  // to cover the trailing '\n'
                }
              }  // else ignore
            } else if (comment_tokens.front() == "on") {
              if (begin_disable_offset != kNullOffset) {
                const size_t end_disable_offset = token.left(text);
                if (begin_disable_offset != end_disable_offset) {
                  disable_set.Add({begin_disable_offset, end_disable_offset});
                }
                begin_disable_offset = kNullOffset;
              }  // else ignore
            }
          }
        }
        break;
      }
      default:
        break;
    }
  }
  // If the disabling interval remains open, close it (to end-of-buffer).
  if (begin_disable_offset != kNullOffset) {
    disable_set.Add({begin_disable_offset, text.length()});
  }
  return disable_set;
}

}  // namespace formatter
}  // namespace verilog
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/io/p9_io_erepairConsts.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///
/// @file p9_io_erepairConsts.H
/// @brief eRepair Constants
///
//----------------------------------------------------------------------------
// *HWP HWP Owner       : Chris Steffen <cwsteffen@us.ibm.com>
// *HWP HWP Backup Owner: Gary Peterson <garyp@us.ibm.com>
// *HWP FW Owner        : Sumit Kumar <sumit_kumar@in.ibm.com>
// *HWP Team            : IO
// *HWP Level           : 2
// *HWP Consumed by     : FSP:HB
//----------------------------------------------------------------------------

#ifndef P9_IO_EREPAIRCONSTS_H_
#define P9_IO_EREPAIRCONSTS_H_

/******************************************************************************
 * Erepair constants
 *****************************************************************************/

namespace EREPAIR
{
const uint8_t INVALID_FAIL_LANE_NUMBER = 0;

// X-Bus is 16+1 lanes wide in 2 byte mode
// Data lanes numbering:  0 - 15 in 2 byte mode
// Spare lanes numbering: 16     in 2 byte mode
const uint8_t XBUS_2_ACTIVE_LANE_START   = 0;
const uint8_t XBUS_2_ACTIVE_LANE_END     = 15;

const uint8_t XBUS_SPARE_DEPLOY_LANE_1   = 0;
const uint8_t XBUS_MAXSPARES_IN_HW       = 1;
const uint8_t XBUS_MAX_LANE_WIDTH        = 16;

// O-Bus is 12+2 lanes wide.
// Data lanes numbering: 0 - 11
// Spare lane numbering: 12,13
const uint8_t OBUS_ACTIVE_LANE_START     = 0;
const uint8_t OBUS_ACTIVE_LANE_END       = 11;

const uint8_t OBUS_SPARE_DEPLOY_LANE_1   = 0;
const uint8_t OBUS_SPARE_DEPLOY_LANE_2   = 1;
const uint8_t OBUS_MAXSPARES_IN_HW       = 2;
const uint8_t OBUS_MAX_LANE_WIDTH        = 12;

// UpStream DMI-Bus is 21+2 lanes wide.
// Data lanes numbering:  0 - 20
// Spare lanes numbering: 21, 22
const uint8_t DMIBUS_UPSTREAM_ACTIVE_LANE_START   = 0;
const uint8_t DMIBUS_UPSTREAM_ACTIVE_LANE_END     = 20;

// DownStream DMI-Bus is 14+2 lanes wide.
// Data lanes numbering:  0 - 13
// Spare lanes numbering: 14, 15
const uint8_t DMIBUS_DOWNSTREAM_ACTIVE_LANE_START = 0;
const uint8_t DMIBUS_DOWNSTREAM_ACTIVE_LANE_END   = 13;

const uint8_t DMIBUS_SPARE_DEPLOY_LANE_1          = 0;
const uint8_t DMIBUS_SPARE_DEPLOY_LANE_2          = 1;
const uint8_t DMIBUS_MAXSPARES_IN_HW              = 2;
const uint8_t DMIBUS_UPSTREAM_MAX_LANE_WIDTH      = 21;
const uint8_t DMIBUS_DNSTREAM_MAX_LANE_WIDTH      = 14;

const uint32_t EREPAIR_P9_MODULE_VPD_FIELD_SIZE       = 0x10E; // 270 bytes
const uint32_t EREPAIR_P9_MODULE_VPD_MNFG_SIZE        = 0x10E; // 270 bytes
const uint32_t EREPAIR_MEM_FIELD_VPD_SIZE_PER_CENTAUR = 0x36;  // 54 bytes
const uint32_t EREPAIR_MEM_MNFG_VPD_SIZE_PER_CENTAUR  = 0x36;  // 54 bytes

//TODO:
enum busType
{
    UNKNOWN_BUS_TYPE = 0,
    PROCESSOR_OPT            = 1,
    PROCESSOR_EDIP           = 2,
    MEMORY_EDIP              = 3
};

enum interfaceType
{
    UNKNOWN_INT_TYPE         = 0,
    PBUS_DRIVER              = 1,  // X-Bus, O-Bus transmit
    PBUS_RECEIVER            = 2,  // X-Bus, O-Bus receive
    DMI_MCS_RECEIVE          = 3,  // MCS receive
    DMI_MCS_DRIVE            = 4,  // MCS transmit
    DMI_MEMBUF_RECEIVE       = 5,  // Centaur receive
    DMI_MEMBUF_DRIVE         = 6,  // Centaur transmit
    DRIVE                    = 7,  // Tx
    RECEIVE                  = 8   // Rx
};

// VPD Type to read-write
enum erepairVpdType
{
    EREPAIR_VPD_UNKNOWN = 0,
    EREPAIR_VPD_MNFG    = 1,
    EREPAIR_VPD_FIELD   = 2,
};

}// end of EREPAIR namespace

/******************************************************************************
 * VPD Structures.
 *****************************************************************************/

// eRepair Header
struct eRepairHeader
{
    struct
    {
        uint8_t eye1;
        uint8_t eye2;
    } eyeCatcher;

    uint8_t version;
    uint8_t sizeOfRecord;
    uint8_t maxNumRecord;
    uint8_t availNumRecord;
};

// Device info structure of the P8 Processor
struct eRepairProcDevInfo
{
    uint8_t processor_id;// Range:0x00-0xFF. Value:Processor MRU IDs
    uint8_t fabricBus;   // Range:0x00-0xFF. Value: FabricBus(ATTR_CHIP_UNIT_POS)
};

// eRepair structure for failing lanes on Power Bus
struct eRepairPowerBus
{
    eRepairProcDevInfo device;     // Device info of P9
    uint8_t type      : 4;         // Range:0x0-0xF. Value:PROCESSOR_EDIP
    uint8_t interface : 4;         // Range:0x0-0xF. Value:[PBUS_DRIVER|PBUS_RECEIVER]
    uint32_t failBit : 24;         // Bit stream value: Bit 0:Lane 0; Bit 1:Lane 1 ...
};

// Device info structure of the endpoints of the Memory Channel
struct eRepairMemDevInfo
{
    uint8_t proc_centaur_id;// Range:0x00-0xFF.Value:Processor or Centaur MRU ID
    uint8_t memChannel;   // Range:0x00-0xFF.Value: MemoryBus(ATTR_CHIP_UNIT_POS)
};

// eRepair structure of failing lanes on Memory Channel
struct eRepairMemBus
{
    eRepairMemDevInfo device;          // Device info of P9 and Centaur
    uint8_t             type      : 4; // Range:0x0-0xF. Value:MEMORY_EDIP
    uint8_t             interface : 4; // Range:0x0-0xF. Value:[MCS_Receive|MCS_Drive|memBuf_Receive|memBuf_Drive]
    uint32_t            failBit  : 24; // Bit stream value: Bit 0:Lane 0; Bit 1:Lane 1 ...
};

/**
 * @brief This function combines the eRepair lane numbers read from
 *        Manufacturing VPD and Field VPD
 *
 * @param [in]  i_mnfgFaillanes  The eRepair lane numbers read from the
 *                               Manufacturing VPD
 * @param [in]  i_fieldFaillanes The eRepair lane numbers read from the
 *                               Field VPD
 * @param [out] o_allFaillanes   The eRepair lane numbers which is the union
 *                               of the Field and Manufacturing eRepair lanes
 *                               passed as first iand second params
 *
 * @return void
 */
void combineFieldandMnfgLanes(std::vector<uint8_t>& i_mnfgFaillanes,
                              std::vector<uint8_t>& i_fieldFaillanes,
                              std::vector<uint8_t>& o_allFailLanes);

/**
 * @brief This function checks to see if the passed vectors have matching
 *        fail lane numbers. If no matching lane number is found, such lane
 *        value will be invalidated in the vector
 *
 * @param [in]  io_endp1_txFaillanes        Reference to vector which has fail
 *                                          lane numbers of Tx side
 * @param [in]  io_endp2_rxFaillanes        Reference to vector which has fail
 *                                          lane numbers of Rx side
 * @param [out] o_invalidFails_inTx_Ofendp1 If TRUE, indicates that Tx has fail
 *                                          lane numbers for which there is no
 *                                          matching entry on Rx side
 * @param [out] o_invalidFails_inRx_Ofendp2 If TRUE, indicates that Tx has fail
 *                                          lane numbers for which there is no
 *                                          matching entry on Tx side
 *
 * @return void
 */
void invalidateNonMatchingFailLanes(std::vector<uint8_t>& io_endp1_txFaillanes,
                                    std::vector<uint8_t>& io_endp2_rxFaillanes,
                                    bool& o_invalidFails_inTx_Ofendp1,
                                    bool& o_invalidFails_inRx_Ofendp2);

#endif
<commit_msg>eRepair: Fixed records update for failed lanes in vpd<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/io/p9_io_erepairConsts.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///
/// @file p9_io_erepairConsts.H
/// @brief eRepair Constants
///
//----------------------------------------------------------------------------
// *HWP HWP Owner       : Chris Steffen <cwsteffen@us.ibm.com>
// *HWP HWP Backup Owner: Gary Peterson <garyp@us.ibm.com>
// *HWP FW Owner        : Sumit Kumar <sumit_kumar@in.ibm.com>
// *HWP Team            : IO
// *HWP Level           : 2
// *HWP Consumed by     : FSP:HB
//----------------------------------------------------------------------------

#ifndef P9_IO_EREPAIRCONSTS_H_
#define P9_IO_EREPAIRCONSTS_H_

/******************************************************************************
 * Erepair constants
 *****************************************************************************/

namespace EREPAIR
{
const uint8_t INVALID_FAIL_LANE_NUMBER = 0;

// X-Bus is 16+1 lanes wide in 2 byte mode
// Data lanes numbering:  0 - 15 in 2 byte mode
// Spare lanes numbering: 16     in 2 byte mode
const uint8_t XBUS_2_ACTIVE_LANE_START   = 0;
const uint8_t XBUS_2_ACTIVE_LANE_END     = 15;

const uint8_t XBUS_SPARE_DEPLOY_LANE_1   = 0;
const uint8_t XBUS_MAXSPARES_IN_HW       = 1;
const uint8_t XBUS_MAX_LANE_WIDTH        = 17;

// O-Bus is 12+2 lanes wide.
// Data lanes numbering: 0 - 11
// Spare lane numbering: 12,13
const uint8_t OBUS_ACTIVE_LANE_START     = 0;
const uint8_t OBUS_ACTIVE_LANE_END       = 11;

const uint8_t OBUS_SPARE_DEPLOY_LANE_1   = 0;
const uint8_t OBUS_SPARE_DEPLOY_LANE_2   = 1;
const uint8_t OBUS_MAXSPARES_IN_HW       = 2;
const uint8_t OBUS_MAX_LANE_WIDTH        = 13;

// UpStream DMI-Bus is 21+2+1(calibration) lanes wide.
// Data lanes numbering:  0 - 20
// Spare lanes numbering: 21, 22
const uint8_t DMIBUS_UPSTREAM_ACTIVE_LANE_START   = 0;
const uint8_t DMIBUS_UPSTREAM_ACTIVE_LANE_END     = 20;

// DownStream DMI-Bus is 14+2 lanes wide.
// Data lanes numbering:  0 - 13
// Spare lanes numbering: 14, 15
const uint8_t DMIBUS_DOWNSTREAM_ACTIVE_LANE_START = 0;
const uint8_t DMIBUS_DOWNSTREAM_ACTIVE_LANE_END   = 13;

const uint8_t DMIBUS_SPARE_DEPLOY_LANE_1          = 0;
const uint8_t DMIBUS_SPARE_DEPLOY_LANE_2          = 1;
const uint8_t DMIBUS_MAXSPARES_IN_HW              = 2;
const uint8_t DMIBUS_UPSTREAM_MAX_LANE_WIDTH      = 24;
const uint8_t DMIBUS_DNSTREAM_MAX_LANE_WIDTH      = 17;

const uint32_t EREPAIR_P9_MODULE_VPD_FIELD_SIZE       = 0x10E; // 270 bytes
const uint32_t EREPAIR_P9_MODULE_VPD_MNFG_SIZE        = 0x10E; // 270 bytes
const uint32_t EREPAIR_MEM_FIELD_VPD_SIZE_PER_CENTAUR = 0x36;  // 54 bytes
const uint32_t EREPAIR_MEM_MNFG_VPD_SIZE_PER_CENTAUR  = 0x36;  // 54 bytes

//TODO:
enum busType
{
    UNKNOWN_BUS_TYPE = 0,
    PROCESSOR_OPT            = 1,
    PROCESSOR_EDIP           = 2,
    MEMORY_EDIP              = 3
};

enum interfaceType
{
    UNKNOWN_INT_TYPE         = 0,
    PBUS_DRIVER              = 1,  // X-Bus, O-Bus transmit
    PBUS_RECEIVER            = 2,  // X-Bus, O-Bus receive
    DMI_MCS_RECEIVE          = 3,  // MCS receive
    DMI_MCS_DRIVE            = 4,  // MCS transmit
    DMI_MEMBUF_RECEIVE       = 5,  // Centaur receive
    DMI_MEMBUF_DRIVE         = 6,  // Centaur transmit
    DRIVE                    = 7,  // Tx
    RECEIVE                  = 8   // Rx
};

// VPD Type to read-write
enum erepairVpdType
{
    EREPAIR_VPD_UNKNOWN = 0,
    EREPAIR_VPD_MNFG    = 1,
    EREPAIR_VPD_FIELD   = 2,
};

}// end of EREPAIR namespace

/******************************************************************************
 * VPD Structures.
 *****************************************************************************/

// eRepair Header
struct eRepairHeader
{
    struct
    {
        uint8_t eye1;
        uint8_t eye2;
    } eyeCatcher;

    uint8_t version;
    uint8_t sizeOfRecord;
    uint8_t maxNumRecord;
    uint8_t availNumRecord;
};

// Device info structure of the P8 Processor
struct eRepairProcDevInfo
{
    uint8_t processor_id;// Range:0x00-0xFF. Value:Processor MRU IDs
    uint8_t fabricBus;   // Range:0x00-0xFF. Value: FabricBus(ATTR_CHIP_UNIT_POS)
};

// eRepair structure for failing lanes on Power Bus
struct eRepairPowerBus
{
    eRepairProcDevInfo device;     // Device info of P9
    uint8_t type      : 4;         // Range:0x0-0xF. Value:PROCESSOR_EDIP
    uint8_t interface : 4;         // Range:0x0-0xF. Value:[PBUS_DRIVER|PBUS_RECEIVER]
    uint32_t failBit : 24;         // Bit stream value: Bit 0:Lane 0; Bit 1:Lane 1 ...
};

// Device info structure of the endpoints of the Memory Channel
struct eRepairMemDevInfo
{
    uint8_t proc_centaur_id;// Range:0x00-0xFF.Value:Processor or Centaur MRU ID
    uint8_t memChannel;   // Range:0x00-0xFF.Value: MemoryBus(ATTR_CHIP_UNIT_POS)
};

// eRepair structure of failing lanes on Memory Channel
struct eRepairMemBus
{
    eRepairMemDevInfo device;          // Device info of P9 and Centaur
    uint8_t             type      : 4; // Range:0x0-0xF. Value:MEMORY_EDIP
    uint8_t             interface : 4; // Range:0x0-0xF. Value:[MCS_Receive|MCS_Drive|memBuf_Receive|memBuf_Drive]
    uint32_t            failBit  : 24; // Bit stream value: Bit 0:Lane 0; Bit 1:Lane 1 ...
};

/**
 * @brief This function combines the eRepair lane numbers read from
 *        Manufacturing VPD and Field VPD
 *
 * @param [in]  i_mnfgFaillanes  The eRepair lane numbers read from the
 *                               Manufacturing VPD
 * @param [in]  i_fieldFaillanes The eRepair lane numbers read from the
 *                               Field VPD
 * @param [out] o_allFaillanes   The eRepair lane numbers which is the union
 *                               of the Field and Manufacturing eRepair lanes
 *                               passed as first iand second params
 *
 * @return void
 */
void combineFieldandMnfgLanes(std::vector<uint8_t>& i_mnfgFaillanes,
                              std::vector<uint8_t>& i_fieldFaillanes,
                              std::vector<uint8_t>& o_allFailLanes);

/**
 * @brief This function checks to see if the passed vectors have matching
 *        fail lane numbers. If no matching lane number is found, such lane
 *        value will be invalidated in the vector
 *
 * @param [in]  io_endp1_txFaillanes        Reference to vector which has fail
 *                                          lane numbers of Tx side
 * @param [in]  io_endp2_rxFaillanes        Reference to vector which has fail
 *                                          lane numbers of Rx side
 * @param [out] o_invalidFails_inTx_Ofendp1 If TRUE, indicates that Tx has fail
 *                                          lane numbers for which there is no
 *                                          matching entry on Rx side
 * @param [out] o_invalidFails_inRx_Ofendp2 If TRUE, indicates that Tx has fail
 *                                          lane numbers for which there is no
 *                                          matching entry on Tx side
 *
 * @return void
 */
void invalidateNonMatchingFailLanes(std::vector<uint8_t>& io_endp1_txFaillanes,
                                    std::vector<uint8_t>& io_endp2_rxFaillanes,
                                    bool& o_invalidFails_inTx_Ofendp1,
                                    bool& o_invalidFails_inRx_Ofendp2);

#endif
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_scominit.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file p9_mss_scominit.C
/// @brief SCOM inits for PHY, MC
///
// *HWP HWP Owner: Louis Stermole <stermole@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <p9_mss_scominit.H>
#include <p9n_mca_scom.H>
#include <p9n_mcbist_scom.H>
#include <p9n_ddrphy_scom.H>
#include <lib/utils/count_dimm.H>
#include <generic/memory/lib/utils/find.H>
#include <lib/phy/ddr_phy.H>
#include <lib/mc/mc.H>
#include <lib/fir/unmask.H>

using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_MCBIST;
using fapi2::FAPI2_RC_SUCCESS;

///
/// @brief SCOM inits for PHY, MC
/// @param[in] i_target, the MCBIST
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode p9_mss_scominit( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
{
    FAPI_INF("Start MSS SCOM init");

    // We need to make sure we scominit the magic port.
    const auto l_mca_targets = mss::find_targets_with_magic<TARGET_TYPE_MCA>(i_target);

    fapi2::ReturnCode l_rc;
    fapi2::Target<fapi2::TARGET_TYPE_SYSTEM> FAPI_SYSTEM;

    if (mss::count_dimm(i_target) == 0)
    {
        FAPI_INF("... skipping mss_scominit %s - no DIMM ...", mss::c_str(i_target));
        return fapi2::FAPI2_RC_SUCCESS;
    }

    for (const auto& l_mca_target : l_mca_targets )
    {
        FAPI_INF("scominit for %s", mss::c_str(l_mca_target));

        // Can't MCA init ports with no DIMM, they don't have attributes like timing.
        if (mss::count_dimm(l_mca_target) != 0)
        {
            FAPI_INF("mca scominit for %s", mss::c_str(l_mca_target));
            FAPI_EXEC_HWP(l_rc, p9n_mca_scom, l_mca_target, i_target, l_mca_target.getParent<fapi2::TARGET_TYPE_MCS>(),
                          FAPI_SYSTEM, i_target.getParent<fapi2::TARGET_TYPE_PROC_CHIP>());

            if (l_rc)
            {
                FAPI_ERR("Error from p9.mca.scom.initfile");
                fapi2::current_err = l_rc;
                goto fapi_try_exit;
            }

            FAPI_INF("mca thermal throttle scominit for %s", mss::c_str(l_mca_target));
            FAPI_TRY(mss::mc::thermal_throttle_scominit(l_mca_target));
        }

        // ... but we do scominit PHY's with no DIMM. There are no attributes needed and we need
        // to make sure we init the magic port.
        FAPI_INF("phy scominit for %s", mss::c_str(l_mca_target));
        FAPI_EXEC_HWP(l_rc, p9n_ddrphy_scom, l_mca_target, i_target.getParent<fapi2::TARGET_TYPE_PROC_CHIP>());

        if (l_rc)
        {
            FAPI_ERR("Error from p9.ddrphy.scom.initfile");
            fapi2::current_err = l_rc;
            goto fapi_try_exit;
        }
    }

    FAPI_EXEC_HWP(l_rc, p9n_mcbist_scom, i_target );

    if (l_rc)
    {
        FAPI_ERR("Error from p9.mcbist.scom.initfile");
        fapi2::current_err = l_rc;
        goto fapi_try_exit;
    }

    // Initialize via scoms for non-static PHY items.
    FAPI_TRY( mss::phy_scominit(i_target) );

    // Do FIRry things
    FAPI_TRY( mss::unmask::after_scominit(i_target) );

fapi_try_exit:
    FAPI_INF("End MSS SCOM init");
    return fapi2::current_err;
}
<commit_msg>Moves count_dimm to be in the memory generic folder<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_scominit.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file p9_mss_scominit.C
/// @brief SCOM inits for PHY, MC
///
// *HWP HWP Owner: Louis Stermole <stermole@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <p9_mss_scominit.H>
#include <p9n_mca_scom.H>
#include <p9n_mcbist_scom.H>
#include <p9n_ddrphy_scom.H>
#include <generic/memory/lib/utils/count_dimm.H>
#include <generic/memory/lib/utils/find.H>
#include <lib/phy/ddr_phy.H>
#include <lib/mc/mc.H>
#include <lib/fir/unmask.H>

using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_MCBIST;
using fapi2::FAPI2_RC_SUCCESS;

///
/// @brief SCOM inits for PHY, MC
/// @param[in] i_target, the MCBIST
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode p9_mss_scominit( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
{
    FAPI_INF("Start MSS SCOM init");

    // We need to make sure we scominit the magic port.
    const auto l_mca_targets = mss::find_targets_with_magic<TARGET_TYPE_MCA>(i_target);

    fapi2::ReturnCode l_rc;
    fapi2::Target<fapi2::TARGET_TYPE_SYSTEM> FAPI_SYSTEM;

    if (mss::count_dimm(i_target) == 0)
    {
        FAPI_INF("... skipping mss_scominit %s - no DIMM ...", mss::c_str(i_target));
        return fapi2::FAPI2_RC_SUCCESS;
    }

    for (const auto& l_mca_target : l_mca_targets )
    {
        FAPI_INF("scominit for %s", mss::c_str(l_mca_target));

        // Can't MCA init ports with no DIMM, they don't have attributes like timing.
        if (mss::count_dimm(l_mca_target) != 0)
        {
            FAPI_INF("mca scominit for %s", mss::c_str(l_mca_target));
            FAPI_EXEC_HWP(l_rc, p9n_mca_scom, l_mca_target, i_target, l_mca_target.getParent<fapi2::TARGET_TYPE_MCS>(),
                          FAPI_SYSTEM, i_target.getParent<fapi2::TARGET_TYPE_PROC_CHIP>());

            if (l_rc)
            {
                FAPI_ERR("Error from p9.mca.scom.initfile");
                fapi2::current_err = l_rc;
                goto fapi_try_exit;
            }

            FAPI_INF("mca thermal throttle scominit for %s", mss::c_str(l_mca_target));
            FAPI_TRY(mss::mc::thermal_throttle_scominit(l_mca_target));
        }

        // ... but we do scominit PHY's with no DIMM. There are no attributes needed and we need
        // to make sure we init the magic port.
        FAPI_INF("phy scominit for %s", mss::c_str(l_mca_target));
        FAPI_EXEC_HWP(l_rc, p9n_ddrphy_scom, l_mca_target, i_target.getParent<fapi2::TARGET_TYPE_PROC_CHIP>());

        if (l_rc)
        {
            FAPI_ERR("Error from p9.ddrphy.scom.initfile");
            fapi2::current_err = l_rc;
            goto fapi_try_exit;
        }
    }

    FAPI_EXEC_HWP(l_rc, p9n_mcbist_scom, i_target );

    if (l_rc)
    {
        FAPI_ERR("Error from p9.mcbist.scom.initfile");
        fapi2::current_err = l_rc;
        goto fapi_try_exit;
    }

    // Initialize via scoms for non-static PHY items.
    FAPI_TRY( mss::phy_scominit(i_target) );

    // Do FIRry things
    FAPI_TRY( mss::unmask::after_scominit(i_target) );

fapi_try_exit:
    FAPI_INF("End MSS SCOM init");
    return fapi2::current_err;
}
<|endoftext|>


<commit_before>/*  Pokopom - Input Plugin for PSX/PS2 Emulators
 *  Copyright (C) 2012  KrossX
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "Controller.h"
#include "Codes_IDs.h"
#include "General.h"

void Controller::Reset()
{
	memset(dataBuffer, 0xFF, sizeof(dataBuffer));
	memset(cmdBuffer, 0x00, sizeof(cmdBuffer));

	dataBuffer[2] = 0x5A;
	padID = settings.defaultAnalog ? (unsigned char)ID_ANALOG : (unsigned char)ID_DIGITAL;

	buttons = buttonsStick = 0xFFFF;
	analogL = analogR = 0x7F7F;

	motorMapS = 0xFF;
	motorMapL = 0xFF;

	gamepadPlugged = false;
	bConfig = bModeLock = false;
}

Controller::Controller(_Settings &config, unsigned short bsize):
settings(config), sizeBuffer(bsize)
{
	cmdBuffer = new unsigned char[sizeBuffer];
	dataBuffer = new unsigned char[sizeBuffer];

	Reset();
}

unsigned char Controller::command(const unsigned int counter, const unsigned char data)
{
	if(counter >= sizeBuffer)
	{
		printf("Pokopom: Out of Bound Buffer ERROR! [%02d:%02d]\n", sizeBuffer, counter);
		return 0x00;
	}

	cmdBuffer[counter] = data;

	if(!gamepadPlugged)
	{
		if(counter == 0) Recheck();
		if(!gamepadPlugged) return 0x00;
	}

	switch(counter)
	{
	case 0x00: Cmd0(); break;

	case 0x01:
		dataBuffer[1] = bConfig? ID_CONFIG : padID;
		if(cmdBuffer[0]==0x01) Cmd1(cmdBuffer[1]);
		break;

	case 0x04: if(cmdBuffer[0]==0x01) Cmd4(cmdBuffer[1]); break;
	case 0x08: if(cmdBuffer[0]==0x01) Cmd8(cmdBuffer[1]); break;
	}

	return dataBuffer[counter];
}

void Controller::ReadInput(unsigned char *buffer)
{
	poll();

	if(padID == ID_DIGITAL)
	{
		buffer[3] = buttonsStick & 0xFF;
		buffer[4] = buttonsStick >> 8;
		memset(&buffer[5], 0xFF, 4);
	}
	else
	{
		buffer[3] = buttons & 0xFF;
		buffer[4] = buttons >> 8;

		buffer[5] = analogR & 0xFF;
		buffer[6] = analogR >> 8;
		buffer[7] = analogL & 0xFF;
		buffer[8] = analogL >> 8;
	}
}

void Controller::SetVibration()
{
	motorMapS = motorMapL = 0xFF;

	for(unsigned char i = 3; i<9; i++)
	{
		if(cmdBuffer[i] == 0x00) motorMapS = i - 3;
		if(cmdBuffer[i] == 0x01) motorMapL = i - 3;
	}
}

void Controller::Cmd0()
{
	static bool bPressed = false;

	if(!bModeLock)
	{
		if(!bPressed && !!(GetAsyncKeyState(VK_SCROLL) >> 1))
		{
			if(padID == ID_DIGITAL)
			{
				padID = ID_ANALOG;
				//printf("Pokopom -> [%d] Switched to analog mode.\n", Settings.padPort);
			}
			else if(padID == ID_ANALOG)
			{
				padID = ID_DIGITAL;
				//printf("Pokopom -> [%d] Switched to digital mode.\n", Settings.padPort);
			}

			bPressed = true;
		}
		else if (bPressed && !(GetAsyncKeyState(VK_SCROLL) >> 1))
		{
			bPressed = false;
		}
	}

	if(gamepadPlugged && !bPressed)
	{
		bool ledScrollLock = GetKeyState(VK_SCROLL)&0x1;

		if((padID != ID_DIGITAL && !ledScrollLock) || (padID == ID_DIGITAL && ledScrollLock))
		{
			keybd_event( VK_SCROLL, 0x45, KEYEVENTF_EXTENDEDKEY, 0 );
			keybd_event( VK_SCROLL, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0 );
		}
	}
}

void Controller::Cmd1(const unsigned char data)
{
	switch(data)
	{
	case 0x40: if(bConfig) memcpy(&dataBuffer[3], WTF, 6); // WTF ???!!!

	case 0x41: break;

	case 0x42: // Read_Data
		if(bConfig) memset(&dataBuffer[3], 0xFF, 6);
		else ReadInput(dataBuffer);
		break;

	case 0x43: // Config mode
		if(bConfig) memset(&dataBuffer[3], 0x00, 6);
		else ReadInput(dataBuffer);
		break;

	case 0x44: // Set mode and lock
		memset(&dataBuffer[3], 0x00, 6);
		break;

	case 0x45: if(bConfig) { // Query model, 5th means LED status
		memcpy(&dataBuffer[3], DUALSHOCK2_MODEL, 6); // Using DS2 Model for now
		dataBuffer[5] = padID == ID_DIGITAL? 0x00 : 0x01; }
		break;

	case 0x46:
	case 0x47:
		if(bConfig) dataBuffer[3] =0x00;
		break;

	case 0x48: break;
	case 0x49: break;
	case 0x4A: break;
	case 0x4B: break;

	case 0x4C:
		if(bConfig) dataBuffer[3] = 0x00;
		break;

	case 0x4D: if(bConfig) { // Sets which bytes will be for vibration on cmd42
		dataBuffer[3] = motorMapS;
		dataBuffer[4] = motorMapL;
		memset(&dataBuffer[5], 0xFF, 4);	}
		break;

	case 0x4E: break;
	case 0x4F: break;
	}
}

void Controller::Cmd4(const unsigned char data)
{
	switch(data)
	{
	case 0x40: break;
	case 0x41: break;
	case 0x42: break;

	case 0x43: // Config mode
		bConfig = cmdBuffer[3] == 1;
		break;

	case 0x44: if(bConfig) {// Set mode and lock
		padID = cmdBuffer[3] == 0x01 ? (unsigned char)ID_ANALOG : (unsigned char)ID_DIGITAL;
		bModeLock = cmdBuffer[4] == 0x03; } // Disgaea sends 0x01 here
		break;

	case 0x45: break;

	// Using DS2 ID code
	case 0x46: if(bConfig) {// Unknown constant part 1 and 2
		if(cmdBuffer[3] == 0x00) memcpy(&dataBuffer[4], DUALSHOCK2_ID[0], 5);
		else memcpy(&dataBuffer[4], DUALSHOCK2_ID[1], 5);}
		break;

	case 0x47: if(bConfig) {//Unknown constant part 3
		memcpy(&dataBuffer[4], DUALSHOCK2_ID[2], 5); }
		break;

	case 0x48: break;
	case 0x49: break;
	case 0x4A: break;
	case 0x4B: break;

	case 0x4C: if(bConfig) {// Unknown constant part 4 and 5
		if(cmdBuffer[3] == 0x00) memcpy(&dataBuffer[4], DUALSHOCK2_ID[3], 5);
		else memcpy(&dataBuffer[4], DUALSHOCK2_ID[4], 5);}
		break;

	case 0x4D: break;
	case 0x4E: break;
	case 0x4F: break;
	}
}

void Controller::Cmd8(const unsigned char data)
{
	switch(data)
	{
	case 0x40: break;
	case 0x41: break;

	case 0x42:
		vibration(	motorMapS == 0xFF? 0: cmdBuffer[motorMapS+3],
					motorMapL == 0xFF? 0: cmdBuffer[motorMapL+3]);
		break;

	case 0x43: break;
	case 0x44: break;
	case 0x45: break;
	case 0x46: break;
	case 0x47: break;
	case 0x48: break;
	case 0x49: break;
	case 0x4A: break;
	case 0x4B: break;
	case 0x4C: break;

	case 0x4D:
		SetVibration();
		break;

	case 0x4E: break;
	case 0x4F: break;
	}
}<commit_msg>Only show the Out of Bounds error message for plugged controllers.<commit_after>/*  Pokopom - Input Plugin for PSX/PS2 Emulators
 *  Copyright (C) 2012  KrossX
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "Controller.h"
#include "Codes_IDs.h"
#include "General.h"

void Controller::Reset()
{
	memset(dataBuffer, 0xFF, sizeof(dataBuffer));
	memset(cmdBuffer, 0x00, sizeof(cmdBuffer));

	dataBuffer[2] = 0x5A;
	padID = settings.defaultAnalog ? (unsigned char)ID_ANALOG : (unsigned char)ID_DIGITAL;

	buttons = buttonsStick = 0xFFFF;
	analogL = analogR = 0x7F7F;

	motorMapS = 0xFF;
	motorMapL = 0xFF;

	gamepadPlugged = false;
	bConfig = bModeLock = false;
}

Controller::Controller(_Settings &config, unsigned short bsize):
settings(config), sizeBuffer(bsize)
{
	cmdBuffer = new unsigned char[sizeBuffer];
	dataBuffer = new unsigned char[sizeBuffer];

	Reset();
}

unsigned char Controller::command(const unsigned int counter, const unsigned char data)
{
	if((counter >= sizeBuffer) && gamepadPlugged)
	{
		printf("Pokopom: Out of Bound Buffer ERROR! [%02d:%02d]\n", sizeBuffer, counter);
		return 0x00;
	}

	cmdBuffer[counter] = data;

	if(!gamepadPlugged)
	{
		if(counter == 0) Recheck();
		if(!gamepadPlugged) return 0x00;
	}

	switch(counter)
	{
	case 0x00: Cmd0(); break;

	case 0x01:
		dataBuffer[1] = bConfig? ID_CONFIG : padID;
		if(cmdBuffer[0]==0x01) Cmd1(cmdBuffer[1]);
		break;

	case 0x04: if(cmdBuffer[0]==0x01) Cmd4(cmdBuffer[1]); break;
	case 0x08: if(cmdBuffer[0]==0x01) Cmd8(cmdBuffer[1]); break;
	}

	return dataBuffer[counter];
}

void Controller::ReadInput(unsigned char *buffer)
{
	poll();

	if(padID == ID_DIGITAL)
	{
		buffer[3] = buttonsStick & 0xFF;
		buffer[4] = buttonsStick >> 8;
		memset(&buffer[5], 0xFF, 4);
	}
	else
	{
		buffer[3] = buttons & 0xFF;
		buffer[4] = buttons >> 8;

		buffer[5] = analogR & 0xFF;
		buffer[6] = analogR >> 8;
		buffer[7] = analogL & 0xFF;
		buffer[8] = analogL >> 8;
	}
}

void Controller::SetVibration()
{
	motorMapS = motorMapL = 0xFF;

	for(unsigned char i = 3; i<9; i++)
	{
		if(cmdBuffer[i] == 0x00) motorMapS = i - 3;
		if(cmdBuffer[i] == 0x01) motorMapL = i - 3;
	}
}

void Controller::Cmd0()
{
	static bool bPressed = false;

	if(!bModeLock)
	{
		if(!bPressed && !!(GetAsyncKeyState(VK_SCROLL) >> 1))
		{
			if(padID == ID_DIGITAL)
			{
				padID = ID_ANALOG;
				//printf("Pokopom -> [%d] Switched to analog mode.\n", Settings.padPort);
			}
			else if(padID == ID_ANALOG)
			{
				padID = ID_DIGITAL;
				//printf("Pokopom -> [%d] Switched to digital mode.\n", Settings.padPort);
			}

			bPressed = true;
		}
		else if (bPressed && !(GetAsyncKeyState(VK_SCROLL) >> 1))
		{
			bPressed = false;
		}
	}

	if(gamepadPlugged && !bPressed)
	{
		bool ledScrollLock = GetKeyState(VK_SCROLL)&0x1;

		if((padID != ID_DIGITAL && !ledScrollLock) || (padID == ID_DIGITAL && ledScrollLock))
		{
			keybd_event( VK_SCROLL, 0x45, KEYEVENTF_EXTENDEDKEY, 0 );
			keybd_event( VK_SCROLL, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0 );
		}
	}
}

void Controller::Cmd1(const unsigned char data)
{
	switch(data)
	{
	case 0x40: if(bConfig) memcpy(&dataBuffer[3], WTF, 6); // WTF ???!!!

	case 0x41: break;

	case 0x42: // Read_Data
		if(bConfig) memset(&dataBuffer[3], 0xFF, 6);
		else ReadInput(dataBuffer);
		break;

	case 0x43: // Config mode
		if(bConfig) memset(&dataBuffer[3], 0x00, 6);
		else ReadInput(dataBuffer);
		break;

	case 0x44: // Set mode and lock
		memset(&dataBuffer[3], 0x00, 6);
		break;

	case 0x45: if(bConfig) { // Query model, 5th means LED status
		memcpy(&dataBuffer[3], DUALSHOCK2_MODEL, 6); // Using DS2 Model for now
		dataBuffer[5] = padID == ID_DIGITAL? 0x00 : 0x01; }
		break;

	case 0x46:
	case 0x47:
		if(bConfig) dataBuffer[3] =0x00;
		break;

	case 0x48: break;
	case 0x49: break;
	case 0x4A: break;
	case 0x4B: break;

	case 0x4C:
		if(bConfig) dataBuffer[3] = 0x00;
		break;

	case 0x4D: if(bConfig) { // Sets which bytes will be for vibration on cmd42
		dataBuffer[3] = motorMapS;
		dataBuffer[4] = motorMapL;
		memset(&dataBuffer[5], 0xFF, 4);	}
		break;

	case 0x4E: break;
	case 0x4F: break;
	}
}

void Controller::Cmd4(const unsigned char data)
{
	switch(data)
	{
	case 0x40: break;
	case 0x41: break;
	case 0x42: break;

	case 0x43: // Config mode
		bConfig = cmdBuffer[3] == 1;
		break;

	case 0x44: if(bConfig) {// Set mode and lock
		padID = cmdBuffer[3] == 0x01 ? (unsigned char)ID_ANALOG : (unsigned char)ID_DIGITAL;
		bModeLock = cmdBuffer[4] == 0x03; } // Disgaea sends 0x01 here
		break;

	case 0x45: break;

	// Using DS2 ID code
	case 0x46: if(bConfig) {// Unknown constant part 1 and 2
		if(cmdBuffer[3] == 0x00) memcpy(&dataBuffer[4], DUALSHOCK2_ID[0], 5);
		else memcpy(&dataBuffer[4], DUALSHOCK2_ID[1], 5);}
		break;

	case 0x47: if(bConfig) {//Unknown constant part 3
		memcpy(&dataBuffer[4], DUALSHOCK2_ID[2], 5); }
		break;

	case 0x48: break;
	case 0x49: break;
	case 0x4A: break;
	case 0x4B: break;

	case 0x4C: if(bConfig) {// Unknown constant part 4 and 5
		if(cmdBuffer[3] == 0x00) memcpy(&dataBuffer[4], DUALSHOCK2_ID[3], 5);
		else memcpy(&dataBuffer[4], DUALSHOCK2_ID[4], 5);}
		break;

	case 0x4D: break;
	case 0x4E: break;
	case 0x4F: break;
	}
}

void Controller::Cmd8(const unsigned char data)
{
	switch(data)
	{
	case 0x40: break;
	case 0x41: break;

	case 0x42:
		vibration(	motorMapS == 0xFF? 0: cmdBuffer[motorMapS+3],
					motorMapL == 0xFF? 0: cmdBuffer[motorMapL+3]);
		break;

	case 0x43: break;
	case 0x44: break;
	case 0x45: break;
	case 0x46: break;
	case 0x47: break;
	case 0x48: break;
	case 0x49: break;
	case 0x4A: break;
	case 0x4B: break;
	case 0x4C: break;

	case 0x4D:
		SetVibration();
		break;

	case 0x4E: break;
	case 0x4F: break;
	}
}<|endoftext|>