<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2010 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#undef OSL_DEBUG_LEVEL

#include <osl/diagnose.h>

#include "internal/global.hxx"
#include "internal/propertyhdl.hxx"
#include "internal/fileextensions.hxx"
#include "internal/metainforeader.hxx"
#include "internal/utilities.hxx"
#include "internal/config.hxx"

#include <propkey.h>
#include <propvarutil.h>
#include <sal/macros.h>

#include <malloc.h>
#include <strsafe.h>

#include "internal/stream_helper.hxx"

//---------------------------
// Module global
//---------------------------
long g_DllRefCnt = 0;
HINSTANCE g_hModule = NULL;

// Map of property keys to the locations of their value(s) in the .??? XML schema
struct PROPERTYMAP
{
    PROPERTYKEY key;
    PCWSTR pszXPathParent;
    PCWSTR pszValueNodeName;
};

PROPERTYMAP g_rgPROPERTYMAP[] =
{
    { PKEY_Title,          L"LibreOffice",          L"Title" },
    { PKEY_Author,         L"LibreOffice",          L"Author" },
    { PKEY_Subject,        L"LibreOffice",          L"Subject" },
    { PKEY_Keywords,       L"LibreOffice",          L"Keyword" },
    { PKEY_Comment,        L"LibreOffice",          L"Comments" },
};

size_t gPropertyMapTableSize = sizeof(g_rgPROPERTYMAP)/sizeof(g_rgPROPERTYMAP[0]);

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

CPropertyHdl::CPropertyHdl( long nRefCnt ) :
    m_RefCnt( nRefCnt ),
    m_pCache( NULL )
{
    OutputDebugStringFormat( "CPropertyHdl: CTOR\n" );
    InterlockedIncrement( &g_DllRefCnt );
}

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

CPropertyHdl::~CPropertyHdl()
{
    if ( m_pCache )
    {
        m_pCache->Release();
        m_pCache = NULL;
    }
    InterlockedDecrement( &g_DllRefCnt );
}

//-----------------------------
// IUnknown methods
//-----------------------------
HRESULT STDMETHODCALLTYPE CPropertyHdl::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject)
{
    *ppvObject = 0;

    if (IID_IUnknown == riid || IID_IPropertyStore == riid)
    {
        OutputDebugStringFormat( "CPropertyHdl: QueryInterface (IID_IPropertyStore)\n" );
        IUnknown* pUnk = static_cast<IPropertyStore*>(this);
        pUnk->AddRef();
        *ppvObject = pUnk;
        return S_OK;
    }
    else if (IID_IPropertyStoreCapabilities == riid)
    {
        OutputDebugStringFormat( "CPropertyHdl: QueryInterface (IID_IPropertyStoreCapabilities)\n" );
        IUnknown* pUnk = static_cast<IPropertyStore*>(this);
        pUnk->AddRef();
        *ppvObject = pUnk;
        return S_OK;
    }
    else if (IID_IInitializeWithStream == riid)
    {
        OutputDebugStringFormat( "CPropertyHdl: QueryInterface (IID_IInitializeWithStream)\n" );
        IUnknown* pUnk = static_cast<IInitializeWithStream*>(this);
        pUnk->AddRef();
        *ppvObject = pUnk;
        return S_OK;
    }
    OutputDebugStringFormat( "CPropertyHdl: QueryInterface (something different)\n" );

    return E_NOINTERFACE;
}

//----------------------------
ULONG STDMETHODCALLTYPE CPropertyHdl::AddRef( void )
{
    return InterlockedIncrement( &m_RefCnt );
}

//----------------------------
ULONG STDMETHODCALLTYPE CPropertyHdl::Release( void )
{
    long refcnt = InterlockedDecrement( &m_RefCnt );

    if ( 0 == m_RefCnt )
        delete this;

    return refcnt;
}

//-----------------------------
// IPropertyStore
//-----------------------------
HRESULT STDMETHODCALLTYPE CPropertyHdl::GetCount( DWORD *pcProps )
{
    HRESULT hr = E_UNEXPECTED;
    if ( m_pCache && pcProps )
    {
        hr = m_pCache->GetCount( pcProps );
    }

    return hr;
}

//-----------------------------
HRESULT STDMETHODCALLTYPE CPropertyHdl::GetAt( DWORD iProp, PROPERTYKEY *pKey )
{
    HRESULT hr = E_UNEXPECTED;
    if ( m_pCache )
    {
        hr = m_pCache->GetAt( iProp, pKey );
    }

    return hr;
}

//-----------------------------
HRESULT STDMETHODCALLTYPE CPropertyHdl::GetValue( REFPROPERTYKEY key, PROPVARIANT *pPropVar )
{
    HRESULT hr = E_UNEXPECTED;
    if ( m_pCache )
    {
        hr = m_pCache->GetValue( key, pPropVar );
    }

    return hr;
}

//-----------------------------
HRESULT STDMETHODCALLTYPE CPropertyHdl::SetValue( REFPROPERTYKEY key, REFPROPVARIANT propVar )
{
    HRESULT hr = E_UNEXPECTED;
    if ( m_pCache )
    {
        hr = STG_E_ACCESSDENIED;
    }
    return hr;
}

//-----------------------------
HRESULT STDMETHODCALLTYPE CPropertyHdl::Commit()
{
    return S_OK;
}

//-----------------------------
// IPropertyStore
//-----------------------------
HRESULT STDMETHODCALLTYPE CPropertyHdl::IsPropertyWritable( REFPROPERTYKEY key )
{
    // We start with read only properties only
    return S_FALSE;
}

//-----------------------------
// IInitializeWithStream
//-----------------------------
HRESULT STDMETHODCALLTYPE CPropertyHdl::Initialize( IStream *pStream, DWORD grfMode )
{
    if ( grfMode & STGM_READWRITE )
        return STG_E_ACCESSDENIED;

    if ( !m_pCache )
    {
#ifdef __MINGW32__
        if ( FAILED( PSCreateMemoryPropertyStore( IID_IPropertyStoreCache, reinterpret_cast<void**>(&m_pCache) ) ) )
#else
        if ( FAILED( PSCreateMemoryPropertyStore( IID_PPV_ARGS( &m_pCache ) ) ) )
#endif
            OutputDebugStringFormat( "CPropertyHdl::Initialize: PSCreateMemoryPropertyStore failed" );

        BufferStream tmpStream(pStream);

        CMetaInfoReader *pMetaInfoReader = NULL;

        try
        {
            pMetaInfoReader = new CMetaInfoReader( &tmpStream );
            LoadProperties( pMetaInfoReader );
            delete pMetaInfoReader;
        }
        catch (const std::exception& e)
        {
            OutputDebugStringFormat( "CPropertyHdl::Initialize: Caught exception [%s]", e.what() );
            return E_FAIL;
        }
    }

    return S_OK;
}

//-----------------------------
void CPropertyHdl::LoadProperties( CMetaInfoReader *pMetaInfoReader )
{
    OutputDebugStringFormat( "CPropertyHdl: LoadProperties\n" );
    PROPVARIANT propvarValues;

    for ( UINT i = 0; i < (UINT)gPropertyMapTableSize; ++i )
    {
        PropVariantClear( &propvarValues );
        HRESULT hr = GetItemData( pMetaInfoReader, i, &propvarValues);
        if (hr == S_OK)
        {
            // coerce the value(s) to the appropriate type for the property key
            hr = PSCoerceToCanonicalValue( g_rgPROPERTYMAP[i].key, &propvarValues );
            if (SUCCEEDED(hr))
            {
                // cache the value(s) loaded
                hr = m_pCache->SetValueAndState( g_rgPROPERTYMAP[i].key, &propvarValues, PSC_NORMAL );
            }
        }
    }
}

//-----------------------------
HRESULT CPropertyHdl::GetItemData( CMetaInfoReader *pMetaInfoReader, UINT nIndex, PROPVARIANT *pVarData )
{
    switch (nIndex) {
    case 0: {
            pVarData->vt = VT_BSTR;
            pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_TITLE ).c_str() );
            OutputDebugStringFormat( "CPropertyHdl::GetItemData: Title=%S.\n", pMetaInfoReader->getTagData( META_INFO_TITLE ).c_str() );
            return S_OK;
    }
    case 1: {
            pVarData->vt = VT_BSTR;
            pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_AUTHOR ).c_str() );
            OutputDebugStringFormat( "CPropertyHdl::GetItemData: Author=%S.\n", pMetaInfoReader->getTagData( META_INFO_AUTHOR ).c_str() );
            return S_OK;
    }
    case 2: {
            pVarData->vt = VT_BSTR;
            pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_SUBJECT ).c_str() );
            OutputDebugStringFormat( "CPropertyHdl::GetItemData: Subject=%S.\n", pMetaInfoReader->getTagData( META_INFO_SUBJECT ).c_str() );
            return S_OK;
    }
    case 3: {
            pVarData->vt = VT_BSTR;
            pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_KEYWORDS ).c_str() );
            OutputDebugStringFormat( "CPropertyHdl::GetItemData: Keywords=%S.\n", pMetaInfoReader->getTagData( META_INFO_KEYWORDS ).c_str() );
            return S_OK;
    }
    case 4: {
            pVarData->vt = VT_BSTR;
            pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_DESCRIPTION ).c_str() );
            OutputDebugStringFormat( "CPropertyHdl::GetItemData: Description=%S.\n", pMetaInfoReader->getTagData( META_INFO_DESCRIPTION ).c_str() );
            return S_OK;
    }
    case 5: {
            pVarData->vt = VT_BSTR;
            pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagAttribute( META_INFO_DOCUMENT_STATISTIC, META_INFO_PAGES ).c_str() );
            OutputDebugStringFormat( "CPropertyHdl::GetItemData: Pages=%S.\n", pMetaInfoReader->getTagAttribute( META_INFO_DOCUMENT_STATISTIC, META_INFO_PAGES ).c_str() );
            return S_OK;
    }
    }

    return S_FALSE;
}

//-----------------------------------------------------------------------------
//                              CClassFactory
//-----------------------------------------------------------------------------

long CClassFactory::s_ServerLocks = 0;

//-----------------------------------------------------------------------------
CClassFactory::CClassFactory( const CLSID& clsid ) :
    m_RefCnt(1),
    m_Clsid(clsid)
{
    InterlockedIncrement( &g_DllRefCnt );
}

//-----------------------------------------------------------------------------
CClassFactory::~CClassFactory()
{
    InterlockedDecrement( &g_DllRefCnt );
}

//-----------------------------------------------------------------------------
//                              IUnknown methods
//-----------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CClassFactory::QueryInterface( REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject )
{
    *ppvObject = 0;

    if ( IID_IUnknown == riid || IID_IClassFactory == riid )
    {
        IUnknown* pUnk = this;
        pUnk->AddRef();
        *ppvObject = pUnk;
        return S_OK;
    }

    return E_NOINTERFACE;
}

//-----------------------------------------------------------------------------
ULONG STDMETHODCALLTYPE CClassFactory::AddRef( void )
{
    return InterlockedIncrement( &m_RefCnt );
}

//-----------------------------------------------------------------------------
ULONG STDMETHODCALLTYPE CClassFactory::Release( void )
{
    long refcnt = InterlockedDecrement( &m_RefCnt );

    if (0 == refcnt)
        delete this;

    return refcnt;
}

//-----------------------------------------------------------------------------
//                          IClassFactory methods
//-----------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CClassFactory::CreateInstance(
            IUnknown __RPC_FAR *pUnkOuter,
            REFIID riid,
            void __RPC_FAR *__RPC_FAR *ppvObject)
{
    if ( pUnkOuter != NULL )
        return CLASS_E_NOAGGREGATION;

    IUnknown* pUnk = 0;

    if ( CLSID_PROPERTY_HANDLER == m_Clsid )
        pUnk = static_cast<IPropertyStore*>( new CPropertyHdl() );

    OSL_POSTCOND(pUnk != 0, "Could not create COM object");

    if (0 == pUnk)
        return E_OUTOFMEMORY;

    HRESULT hr = pUnk->QueryInterface( riid, ppvObject );

    // if QueryInterface failed the component will destroy itself
    pUnk->Release();

    return hr;
}

//-----------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CClassFactory::LockServer( BOOL fLock )
{
    if ( fLock )
        InterlockedIncrement( &s_ServerLocks );
    else
        InterlockedDecrement( &s_ServerLocks );

    return S_OK;
}

//-----------------------------------------------------------------------------
bool CClassFactory::IsLocked()
{
    return ( s_ServerLocks > 0 );
}

//-----------------------------------------------------------------------------
extern "C" STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)
{
    OutputDebugStringFormat( "DllGetClassObject.\n" );
    *ppv = 0;

    if ( rclsid != CLSID_PROPERTY_HANDLER )
        return CLASS_E_CLASSNOTAVAILABLE;

    if ( (riid != IID_IUnknown) && (riid != IID_IClassFactory) )
        return E_NOINTERFACE;

    IUnknown* pUnk = new CClassFactory( rclsid );
    if ( 0 == pUnk )
        return E_OUTOFMEMORY;

    *ppv = pUnk;
    return S_OK;
}

//-----------------------------------------------------------------------------
extern "C" STDAPI DllCanUnloadNow( void )
{
    OutputDebugStringFormat( "DllCanUnloadNow.\n" );
    if (CClassFactory::IsLocked() || g_DllRefCnt > 0)
        return S_FALSE;

    return S_OK;
}

//-----------------------------------------------------------------------------
BOOL WINAPI DllMain( HINSTANCE hInst, ULONG /*ul_reason_for_call*/, LPVOID /*lpReserved*/ )
{
    OutputDebugStringFormat( "DllMain.\n" );
    g_hModule = hInst;
    return TRUE;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>warning C4100: unreferenced formal parameter<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2010 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#undef OSL_DEBUG_LEVEL

#include <osl/diagnose.h>

#include "internal/global.hxx"
#include "internal/propertyhdl.hxx"
#include "internal/fileextensions.hxx"
#include "internal/metainforeader.hxx"
#include "internal/utilities.hxx"
#include "internal/config.hxx"

#include <propkey.h>
#include <propvarutil.h>
#include <sal/macros.h>

#include <malloc.h>
#include <strsafe.h>

#include "internal/stream_helper.hxx"

//---------------------------
// Module global
//---------------------------
long g_DllRefCnt = 0;
HINSTANCE g_hModule = NULL;

// Map of property keys to the locations of their value(s) in the .??? XML schema
struct PROPERTYMAP
{
    PROPERTYKEY key;
    PCWSTR pszXPathParent;
    PCWSTR pszValueNodeName;
};

PROPERTYMAP g_rgPROPERTYMAP[] =
{
    { PKEY_Title,          L"LibreOffice",          L"Title" },
    { PKEY_Author,         L"LibreOffice",          L"Author" },
    { PKEY_Subject,        L"LibreOffice",          L"Subject" },
    { PKEY_Keywords,       L"LibreOffice",          L"Keyword" },
    { PKEY_Comment,        L"LibreOffice",          L"Comments" },
};

size_t gPropertyMapTableSize = sizeof(g_rgPROPERTYMAP)/sizeof(g_rgPROPERTYMAP[0]);

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

CPropertyHdl::CPropertyHdl( long nRefCnt ) :
    m_RefCnt( nRefCnt ),
    m_pCache( NULL )
{
    OutputDebugStringFormat( "CPropertyHdl: CTOR\n" );
    InterlockedIncrement( &g_DllRefCnt );
}

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

CPropertyHdl::~CPropertyHdl()
{
    if ( m_pCache )
    {
        m_pCache->Release();
        m_pCache = NULL;
    }
    InterlockedDecrement( &g_DllRefCnt );
}

//-----------------------------
// IUnknown methods
//-----------------------------
HRESULT STDMETHODCALLTYPE CPropertyHdl::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject)
{
    *ppvObject = 0;

    if (IID_IUnknown == riid || IID_IPropertyStore == riid)
    {
        OutputDebugStringFormat( "CPropertyHdl: QueryInterface (IID_IPropertyStore)\n" );
        IUnknown* pUnk = static_cast<IPropertyStore*>(this);
        pUnk->AddRef();
        *ppvObject = pUnk;
        return S_OK;
    }
    else if (IID_IPropertyStoreCapabilities == riid)
    {
        OutputDebugStringFormat( "CPropertyHdl: QueryInterface (IID_IPropertyStoreCapabilities)\n" );
        IUnknown* pUnk = static_cast<IPropertyStore*>(this);
        pUnk->AddRef();
        *ppvObject = pUnk;
        return S_OK;
    }
    else if (IID_IInitializeWithStream == riid)
    {
        OutputDebugStringFormat( "CPropertyHdl: QueryInterface (IID_IInitializeWithStream)\n" );
        IUnknown* pUnk = static_cast<IInitializeWithStream*>(this);
        pUnk->AddRef();
        *ppvObject = pUnk;
        return S_OK;
    }
    OutputDebugStringFormat( "CPropertyHdl: QueryInterface (something different)\n" );

    return E_NOINTERFACE;
}

//----------------------------
ULONG STDMETHODCALLTYPE CPropertyHdl::AddRef( void )
{
    return InterlockedIncrement( &m_RefCnt );
}

//----------------------------
ULONG STDMETHODCALLTYPE CPropertyHdl::Release( void )
{
    long refcnt = InterlockedDecrement( &m_RefCnt );

    if ( 0 == m_RefCnt )
        delete this;

    return refcnt;
}

//-----------------------------
// IPropertyStore
//-----------------------------
HRESULT STDMETHODCALLTYPE CPropertyHdl::GetCount( DWORD *pcProps )
{
    HRESULT hr = E_UNEXPECTED;
    if ( m_pCache && pcProps )
    {
        hr = m_pCache->GetCount( pcProps );
    }

    return hr;
}

//-----------------------------
HRESULT STDMETHODCALLTYPE CPropertyHdl::GetAt( DWORD iProp, PROPERTYKEY *pKey )
{
    HRESULT hr = E_UNEXPECTED;
    if ( m_pCache )
    {
        hr = m_pCache->GetAt( iProp, pKey );
    }

    return hr;
}

//-----------------------------
HRESULT STDMETHODCALLTYPE CPropertyHdl::GetValue( REFPROPERTYKEY key, PROPVARIANT *pPropVar )
{
    HRESULT hr = E_UNEXPECTED;
    if ( m_pCache )
    {
        hr = m_pCache->GetValue( key, pPropVar );
    }

    return hr;
}

//-----------------------------
HRESULT STDMETHODCALLTYPE
CPropertyHdl::SetValue(REFPROPERTYKEY /*key*/, REFPROPVARIANT /*propVar*/)
{
    HRESULT hr = E_UNEXPECTED;
    if ( m_pCache )
    {
        hr = STG_E_ACCESSDENIED;
    }
    return hr;
}

//-----------------------------
HRESULT STDMETHODCALLTYPE CPropertyHdl::Commit()
{
    return S_OK;
}

//-----------------------------
// IPropertyStore
//-----------------------------
HRESULT STDMETHODCALLTYPE
CPropertyHdl::IsPropertyWritable(REFPROPERTYKEY /*key*/)
{
    // We start with read only properties only
    return S_FALSE;
}

//-----------------------------
// IInitializeWithStream
//-----------------------------
HRESULT STDMETHODCALLTYPE CPropertyHdl::Initialize( IStream *pStream, DWORD grfMode )
{
    if ( grfMode & STGM_READWRITE )
        return STG_E_ACCESSDENIED;

    if ( !m_pCache )
    {
#ifdef __MINGW32__
        if ( FAILED( PSCreateMemoryPropertyStore( IID_IPropertyStoreCache, reinterpret_cast<void**>(&m_pCache) ) ) )
#else
        if ( FAILED( PSCreateMemoryPropertyStore( IID_PPV_ARGS( &m_pCache ) ) ) )
#endif
            OutputDebugStringFormat( "CPropertyHdl::Initialize: PSCreateMemoryPropertyStore failed" );

        BufferStream tmpStream(pStream);

        CMetaInfoReader *pMetaInfoReader = NULL;

        try
        {
            pMetaInfoReader = new CMetaInfoReader( &tmpStream );
            LoadProperties( pMetaInfoReader );
            delete pMetaInfoReader;
        }
        catch (const std::exception& e)
        {
            OutputDebugStringFormat( "CPropertyHdl::Initialize: Caught exception [%s]", e.what() );
            return E_FAIL;
        }
    }

    return S_OK;
}

//-----------------------------
void CPropertyHdl::LoadProperties( CMetaInfoReader *pMetaInfoReader )
{
    OutputDebugStringFormat( "CPropertyHdl: LoadProperties\n" );
    PROPVARIANT propvarValues;

    for ( UINT i = 0; i < (UINT)gPropertyMapTableSize; ++i )
    {
        PropVariantClear( &propvarValues );
        HRESULT hr = GetItemData( pMetaInfoReader, i, &propvarValues);
        if (hr == S_OK)
        {
            // coerce the value(s) to the appropriate type for the property key
            hr = PSCoerceToCanonicalValue( g_rgPROPERTYMAP[i].key, &propvarValues );
            if (SUCCEEDED(hr))
            {
                // cache the value(s) loaded
                hr = m_pCache->SetValueAndState( g_rgPROPERTYMAP[i].key, &propvarValues, PSC_NORMAL );
            }
        }
    }
}

//-----------------------------
HRESULT CPropertyHdl::GetItemData( CMetaInfoReader *pMetaInfoReader, UINT nIndex, PROPVARIANT *pVarData )
{
    switch (nIndex) {
    case 0: {
            pVarData->vt = VT_BSTR;
            pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_TITLE ).c_str() );
            OutputDebugStringFormat( "CPropertyHdl::GetItemData: Title=%S.\n", pMetaInfoReader->getTagData( META_INFO_TITLE ).c_str() );
            return S_OK;
    }
    case 1: {
            pVarData->vt = VT_BSTR;
            pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_AUTHOR ).c_str() );
            OutputDebugStringFormat( "CPropertyHdl::GetItemData: Author=%S.\n", pMetaInfoReader->getTagData( META_INFO_AUTHOR ).c_str() );
            return S_OK;
    }
    case 2: {
            pVarData->vt = VT_BSTR;
            pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_SUBJECT ).c_str() );
            OutputDebugStringFormat( "CPropertyHdl::GetItemData: Subject=%S.\n", pMetaInfoReader->getTagData( META_INFO_SUBJECT ).c_str() );
            return S_OK;
    }
    case 3: {
            pVarData->vt = VT_BSTR;
            pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_KEYWORDS ).c_str() );
            OutputDebugStringFormat( "CPropertyHdl::GetItemData: Keywords=%S.\n", pMetaInfoReader->getTagData( META_INFO_KEYWORDS ).c_str() );
            return S_OK;
    }
    case 4: {
            pVarData->vt = VT_BSTR;
            pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_DESCRIPTION ).c_str() );
            OutputDebugStringFormat( "CPropertyHdl::GetItemData: Description=%S.\n", pMetaInfoReader->getTagData( META_INFO_DESCRIPTION ).c_str() );
            return S_OK;
    }
    case 5: {
            pVarData->vt = VT_BSTR;
            pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagAttribute( META_INFO_DOCUMENT_STATISTIC, META_INFO_PAGES ).c_str() );
            OutputDebugStringFormat( "CPropertyHdl::GetItemData: Pages=%S.\n", pMetaInfoReader->getTagAttribute( META_INFO_DOCUMENT_STATISTIC, META_INFO_PAGES ).c_str() );
            return S_OK;
    }
    }

    return S_FALSE;
}

//-----------------------------------------------------------------------------
//                              CClassFactory
//-----------------------------------------------------------------------------

long CClassFactory::s_ServerLocks = 0;

//-----------------------------------------------------------------------------
CClassFactory::CClassFactory( const CLSID& clsid ) :
    m_RefCnt(1),
    m_Clsid(clsid)
{
    InterlockedIncrement( &g_DllRefCnt );
}

//-----------------------------------------------------------------------------
CClassFactory::~CClassFactory()
{
    InterlockedDecrement( &g_DllRefCnt );
}

//-----------------------------------------------------------------------------
//                              IUnknown methods
//-----------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CClassFactory::QueryInterface( REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject )
{
    *ppvObject = 0;

    if ( IID_IUnknown == riid || IID_IClassFactory == riid )
    {
        IUnknown* pUnk = this;
        pUnk->AddRef();
        *ppvObject = pUnk;
        return S_OK;
    }

    return E_NOINTERFACE;
}

//-----------------------------------------------------------------------------
ULONG STDMETHODCALLTYPE CClassFactory::AddRef( void )
{
    return InterlockedIncrement( &m_RefCnt );
}

//-----------------------------------------------------------------------------
ULONG STDMETHODCALLTYPE CClassFactory::Release( void )
{
    long refcnt = InterlockedDecrement( &m_RefCnt );

    if (0 == refcnt)
        delete this;

    return refcnt;
}

//-----------------------------------------------------------------------------
//                          IClassFactory methods
//-----------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CClassFactory::CreateInstance(
            IUnknown __RPC_FAR *pUnkOuter,
            REFIID riid,
            void __RPC_FAR *__RPC_FAR *ppvObject)
{
    if ( pUnkOuter != NULL )
        return CLASS_E_NOAGGREGATION;

    IUnknown* pUnk = 0;

    if ( CLSID_PROPERTY_HANDLER == m_Clsid )
        pUnk = static_cast<IPropertyStore*>( new CPropertyHdl() );

    OSL_POSTCOND(pUnk != 0, "Could not create COM object");

    if (0 == pUnk)
        return E_OUTOFMEMORY;

    HRESULT hr = pUnk->QueryInterface( riid, ppvObject );

    // if QueryInterface failed the component will destroy itself
    pUnk->Release();

    return hr;
}

//-----------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE CClassFactory::LockServer( BOOL fLock )
{
    if ( fLock )
        InterlockedIncrement( &s_ServerLocks );
    else
        InterlockedDecrement( &s_ServerLocks );

    return S_OK;
}

//-----------------------------------------------------------------------------
bool CClassFactory::IsLocked()
{
    return ( s_ServerLocks > 0 );
}

//-----------------------------------------------------------------------------
extern "C" STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)
{
    OutputDebugStringFormat( "DllGetClassObject.\n" );
    *ppv = 0;

    if ( rclsid != CLSID_PROPERTY_HANDLER )
        return CLASS_E_CLASSNOTAVAILABLE;

    if ( (riid != IID_IUnknown) && (riid != IID_IClassFactory) )
        return E_NOINTERFACE;

    IUnknown* pUnk = new CClassFactory( rclsid );
    if ( 0 == pUnk )
        return E_OUTOFMEMORY;

    *ppv = pUnk;
    return S_OK;
}

//-----------------------------------------------------------------------------
extern "C" STDAPI DllCanUnloadNow( void )
{
    OutputDebugStringFormat( "DllCanUnloadNow.\n" );
    if (CClassFactory::IsLocked() || g_DllRefCnt > 0)
        return S_FALSE;

    return S_OK;
}

//-----------------------------------------------------------------------------
BOOL WINAPI DllMain( HINSTANCE hInst, ULONG /*ul_reason_for_call*/, LPVOID /*lpReserved*/ )
{
    OutputDebugStringFormat( "DllMain.\n" );
    g_hModule = hInst;
    return TRUE;
}

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


<commit_before>//===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements the MemoryBuffer interface.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/MemoryBuffer.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Errno.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/system_error.h"
#include <cassert>
#include <cstdio>
#include <cstring>
#include <cerrno>
#include <new>
#include <sys/types.h>
#include <sys/stat.h>
#if !defined(_MSC_VER) && !defined(__MINGW32__)
#include <unistd.h>
#else
#include <io.h>
#endif
#include <fcntl.h>
using namespace llvm;

//===----------------------------------------------------------------------===//
// MemoryBuffer implementation itself.
//===----------------------------------------------------------------------===//

MemoryBuffer::~MemoryBuffer() { }

/// init - Initialize this MemoryBuffer as a reference to externally allocated
/// memory, memory that we know is already null terminated.
void MemoryBuffer::init(const char *BufStart, const char *BufEnd,
                        bool RequiresNullTerminator) {
  assert((!RequiresNullTerminator || BufEnd[0] == 0) &&
         "Buffer is not null terminated!");
  BufferStart = BufStart;
  BufferEnd = BufEnd;
}

//===----------------------------------------------------------------------===//
// MemoryBufferMem implementation.
//===----------------------------------------------------------------------===//

/// CopyStringRef - Copies contents of a StringRef into a block of memory and
/// null-terminates it.
static void CopyStringRef(char *Memory, StringRef Data) {
  memcpy(Memory, Data.data(), Data.size());
  Memory[Data.size()] = 0; // Null terminate string.
}

/// GetNamedBuffer - Allocates a new MemoryBuffer with Name copied after it.
template <typename T>
static T *GetNamedBuffer(StringRef Buffer, StringRef Name,
                         bool RequiresNullTerminator) {
  char *Mem = static_cast<char*>(operator new(sizeof(T) + Name.size() + 1));
  CopyStringRef(Mem + sizeof(T), Name);
  return new (Mem) T(Buffer, RequiresNullTerminator);
}

namespace {
/// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory.
class MemoryBufferMem : public MemoryBuffer {
public:
  MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) {
    init(InputData.begin(), InputData.end(), RequiresNullTerminator);
  }

  virtual const char *getBufferIdentifier() const {
     // The name is stored after the class itself.
    return reinterpret_cast<const char*>(this + 1);
  }

  virtual BufferKind getBufferKind() const {
    return MemoryBuffer_Malloc;
  }
};
}

/// getMemBuffer - Open the specified memory range as a MemoryBuffer.  Note
/// that InputData must be a null terminated if RequiresNullTerminator is true!
MemoryBuffer *MemoryBuffer::getMemBuffer(StringRef InputData,
                                         StringRef BufferName,
                                         bool RequiresNullTerminator) {
  return GetNamedBuffer<MemoryBufferMem>(InputData, BufferName,
                                         RequiresNullTerminator);
}

/// getMemBufferCopy - Open the specified memory range as a MemoryBuffer,
/// copying the contents and taking ownership of it.  This has no requirements
/// on EndPtr[0].
MemoryBuffer *MemoryBuffer::getMemBufferCopy(StringRef InputData,
                                             StringRef BufferName) {
  MemoryBuffer *Buf = getNewUninitMemBuffer(InputData.size(), BufferName);
  if (!Buf) return 0;
  memcpy(const_cast<char*>(Buf->getBufferStart()), InputData.data(),
         InputData.size());
  return Buf;
}

/// getNewUninitMemBuffer - Allocate a new MemoryBuffer of the specified size
/// that is not initialized.  Note that the caller should initialize the
/// memory allocated by this method.  The memory is owned by the MemoryBuffer
/// object.
MemoryBuffer *MemoryBuffer::getNewUninitMemBuffer(size_t Size,
                                                  StringRef BufferName) {
  // Allocate space for the MemoryBuffer, the data and the name. It is important
  // that MemoryBuffer and data are aligned so PointerIntPair works with them.
  size_t AlignedStringLen =
    RoundUpToAlignment(sizeof(MemoryBufferMem) + BufferName.size() + 1,
                       sizeof(void*)); // TODO: Is sizeof(void*) enough?
  size_t RealLen = AlignedStringLen + Size + 1;
  char *Mem = static_cast<char*>(operator new(RealLen, std::nothrow));
  if (!Mem) return 0;

  // The name is stored after the class itself.
  CopyStringRef(Mem + sizeof(MemoryBufferMem), BufferName);

  // The buffer begins after the name and must be aligned.
  char *Buf = Mem + AlignedStringLen;
  Buf[Size] = 0; // Null terminate buffer.

  return new (Mem) MemoryBufferMem(StringRef(Buf, Size), true);
}

/// getNewMemBuffer - Allocate a new MemoryBuffer of the specified size that
/// is completely initialized to zeros.  Note that the caller should
/// initialize the memory allocated by this method.  The memory is owned by
/// the MemoryBuffer object.
MemoryBuffer *MemoryBuffer::getNewMemBuffer(size_t Size, StringRef BufferName) {
  MemoryBuffer *SB = getNewUninitMemBuffer(Size, BufferName);
  if (!SB) return 0;
  memset(const_cast<char*>(SB->getBufferStart()), 0, Size);
  return SB;
}

/// getFileOrSTDIN - Open the specified file as a MemoryBuffer, or open stdin
/// if the Filename is "-".  If an error occurs, this returns null and fills
/// in *ErrStr with a reason.  If stdin is empty, this API (unlike getSTDIN)
/// returns an empty buffer.
error_code MemoryBuffer::getFileOrSTDIN(StringRef Filename,
                                        OwningPtr<MemoryBuffer> &result,
                                        int64_t FileSize) {
  if (Filename == "-")
    return getSTDIN(result);
  return getFile(Filename, result, FileSize);
}

error_code MemoryBuffer::getFileOrSTDIN(const char *Filename,
                                        OwningPtr<MemoryBuffer> &result,
                                        int64_t FileSize) {
  if (strcmp(Filename, "-") == 0)
    return getSTDIN(result);
  return getFile(Filename, result, FileSize);
}

//===----------------------------------------------------------------------===//
// MemoryBuffer::getFile implementation.
//===----------------------------------------------------------------------===//

namespace {
/// MemoryBufferMMapFile - This represents a file that was mapped in with the
/// sys::Path::MapInFilePages method.  When destroyed, it calls the
/// sys::Path::UnMapFilePages method.
class MemoryBufferMMapFile : public MemoryBufferMem {
public:
  MemoryBufferMMapFile(StringRef Buffer, bool RequiresNullTerminator)
    : MemoryBufferMem(Buffer, RequiresNullTerminator) { }

  ~MemoryBufferMMapFile() {
    static int PageSize = sys::Process::GetPageSize();

    uintptr_t Start = reinterpret_cast<uintptr_t>(getBufferStart());
    size_t Size = getBufferSize();
    uintptr_t RealStart = Start & ~(PageSize - 1);
    size_t RealSize = Size + (Start - RealStart);

    sys::Path::UnMapFilePages(reinterpret_cast<const char*>(RealStart),
                              RealSize);
  }

  virtual BufferKind getBufferKind() const {
    return MemoryBuffer_MMap;
  }
};
}

error_code MemoryBuffer::getFile(StringRef Filename,
                                 OwningPtr<MemoryBuffer> &result,
                                 int64_t FileSize,
                                 bool RequiresNullTerminator) {
  // Ensure the path is null terminated.
  SmallString<256> PathBuf(Filename.begin(), Filename.end());
  return MemoryBuffer::getFile(PathBuf.c_str(), result, FileSize,
                               RequiresNullTerminator);
}

error_code MemoryBuffer::getFile(const char *Filename,
                                 OwningPtr<MemoryBuffer> &result,
                                 int64_t FileSize,
                                 bool RequiresNullTerminator) {
  int OpenFlags = O_RDONLY;
#ifdef O_BINARY
  OpenFlags |= O_BINARY;  // Open input file in binary mode on win32.
#endif
  int FD = ::open(Filename, OpenFlags);
  if (FD == -1)
    return error_code(errno, posix_category());

  error_code ret = getOpenFile(FD, Filename, result, FileSize, FileSize,
                               0, RequiresNullTerminator);
  close(FD);
  return ret;
}

static bool shouldUseMmap(int FD,
                          size_t FileSize,
                          size_t MapSize,
                          off_t Offset,
                          bool RequiresNullTerminator,
                          int PageSize) {
  // We don't use mmap for small files because this can severely fragment our
  // address space.
  if (MapSize < 4096*4)
    return false;

  if (!RequiresNullTerminator)
    return true;

  // If we don't know the file size, use fstat to find out.  fstat on an open
  // file descriptor is cheaper than stat on a random path.
  // FIXME: this chunk of code is duplicated, but it avoids a fstat when
  // RequiresNullTerminator = false and MapSize != -1.
  if (FileSize == size_t(-1)) {
    struct stat FileInfo;
    // TODO: This should use fstat64 when available.
    if (fstat(FD, &FileInfo) == -1) {
      return error_code(errno, posix_category());
    }
    FileSize = FileInfo.st_size;
  }

  // If we need a null terminator and the end of the map is inside the file,
  // we cannot use mmap.
  size_t End = Offset + MapSize;
  assert(End <= FileSize);
  if (End != FileSize)
    return false;

  // Don't try to map files that are exactly a multiple of the system page size
  // if we need a null terminator.
  if ((FileSize & (PageSize -1)) == 0)
    return false;

  return true;
}

error_code MemoryBuffer::getOpenFile(int FD, const char *Filename,
                                     OwningPtr<MemoryBuffer> &result,
                                     uint64_t FileSize, uint64_t MapSize,
                                     int64_t Offset,
                                     bool RequiresNullTerminator) {
  static int PageSize = sys::Process::GetPageSize();

  // Default is to map the full file.
  if (MapSize == uint64_t(-1)) {
    // If we don't know the file size, use fstat to find out.  fstat on an open
    // file descriptor is cheaper than stat on a random path.
    if (FileSize == uint64_t(-1)) {
      struct stat FileInfo;
      // TODO: This should use fstat64 when available.
      if (fstat(FD, &FileInfo) == -1) {
        return error_code(errno, posix_category());
      }
      FileSize = FileInfo.st_size;
    }
    MapSize = FileSize;
  }

  if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator,
                    PageSize)) {
    off_t RealMapOffset = Offset & ~(PageSize - 1);
    off_t Delta = Offset - RealMapOffset;
    size_t RealMapSize = MapSize + Delta;

    if (const char *Pages = sys::Path::MapInFilePages(FD,
                                                      RealMapSize,
                                                      RealMapOffset)) {
      result.reset(GetNamedBuffer<MemoryBufferMMapFile>(
          StringRef(Pages + Delta, MapSize), Filename, RequiresNullTerminator));

      if (RequiresNullTerminator && result->getBufferEnd()[0] != '\0') {
        // There could be a racing issue that resulted in the file being larger
        // than the FileSize passed by the caller. We already have an assertion
        // for this in MemoryBuffer::init() but have a runtime guarantee that
        // the buffer will be null-terminated here, so do a copy that adds a
        // null-terminator.
        result.reset(MemoryBuffer::getMemBufferCopy(result->getBuffer(),
                                                    Filename));
      }
      return error_code::success();
    }
  }

  MemoryBuffer *Buf = MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename);
  if (!Buf) {
    // Failed to create a buffer. The only way it can fail is if
    // new(std::nothrow) returns 0.
    return make_error_code(errc::not_enough_memory);
  }

  OwningPtr<MemoryBuffer> SB(Buf);
  char *BufPtr = const_cast<char*>(SB->getBufferStart());

  size_t BytesLeft = MapSize;
#ifndef HAVE_PREAD
  if (lseek(FD, Offset, SEEK_SET) == -1)
    return error_code(errno, posix_category());
#endif

  while (BytesLeft) {
#ifdef HAVE_PREAD
    ssize_t NumRead = ::pread(FD, BufPtr, BytesLeft, MapSize-BytesLeft+Offset);
#else
    ssize_t NumRead = ::read(FD, BufPtr, BytesLeft);
#endif
    if (NumRead == -1) {
      if (errno == EINTR)
        continue;
      // Error while reading.
      return error_code(errno, posix_category());
    }
    if (NumRead == 0) {
      assert(0 && "We got inaccurate FileSize value or fstat reported an "
                   "invalid file size.");
      *BufPtr = '\0'; // null-terminate at the actual size.
      break;
    }
    BytesLeft -= NumRead;
    BufPtr += NumRead;
  }

  result.swap(SB);
  return error_code::success();
}

//===----------------------------------------------------------------------===//
// MemoryBuffer::getSTDIN implementation.
//===----------------------------------------------------------------------===//

error_code MemoryBuffer::getSTDIN(OwningPtr<MemoryBuffer> &result) {
  // Read in all of the data from stdin, we cannot mmap stdin.
  //
  // FIXME: That isn't necessarily true, we should try to mmap stdin and
  // fallback if it fails.
  sys::Program::ChangeStdinToBinary();

  const ssize_t ChunkSize = 4096*4;
  SmallString<ChunkSize> Buffer;
  ssize_t ReadBytes;
  // Read into Buffer until we hit EOF.
  do {
    Buffer.reserve(Buffer.size() + ChunkSize);
    ReadBytes = read(0, Buffer.end(), ChunkSize);
    if (ReadBytes == -1) {
      if (errno == EINTR) continue;
      return error_code(errno, posix_category());
    }
    Buffer.set_size(Buffer.size() + ReadBytes);
  } while (ReadBytes != 0);

  result.reset(getMemBufferCopy(Buffer, "<stdin>"));
  return error_code::success();
}
<commit_msg>Check that a file is not a directory before reading it into a MemoryBuffer.<commit_after>//===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements the MemoryBuffer interface.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/MemoryBuffer.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Errno.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/system_error.h"
#include <cassert>
#include <cstdio>
#include <cstring>
#include <cerrno>
#include <new>
#include <sys/types.h>
#include <sys/stat.h>
#if !defined(_MSC_VER) && !defined(__MINGW32__)
#include <unistd.h>
#else
#include <io.h>
#endif
#include <fcntl.h>
using namespace llvm;

//===----------------------------------------------------------------------===//
// MemoryBuffer implementation itself.
//===----------------------------------------------------------------------===//

MemoryBuffer::~MemoryBuffer() { }

/// init - Initialize this MemoryBuffer as a reference to externally allocated
/// memory, memory that we know is already null terminated.
void MemoryBuffer::init(const char *BufStart, const char *BufEnd,
                        bool RequiresNullTerminator) {
  assert((!RequiresNullTerminator || BufEnd[0] == 0) &&
         "Buffer is not null terminated!");
  BufferStart = BufStart;
  BufferEnd = BufEnd;
}

//===----------------------------------------------------------------------===//
// MemoryBufferMem implementation.
//===----------------------------------------------------------------------===//

/// CopyStringRef - Copies contents of a StringRef into a block of memory and
/// null-terminates it.
static void CopyStringRef(char *Memory, StringRef Data) {
  memcpy(Memory, Data.data(), Data.size());
  Memory[Data.size()] = 0; // Null terminate string.
}

/// GetNamedBuffer - Allocates a new MemoryBuffer with Name copied after it.
template <typename T>
static T *GetNamedBuffer(StringRef Buffer, StringRef Name,
                         bool RequiresNullTerminator) {
  char *Mem = static_cast<char*>(operator new(sizeof(T) + Name.size() + 1));
  CopyStringRef(Mem + sizeof(T), Name);
  return new (Mem) T(Buffer, RequiresNullTerminator);
}

namespace {
/// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory.
class MemoryBufferMem : public MemoryBuffer {
public:
  MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) {
    init(InputData.begin(), InputData.end(), RequiresNullTerminator);
  }

  virtual const char *getBufferIdentifier() const {
     // The name is stored after the class itself.
    return reinterpret_cast<const char*>(this + 1);
  }

  virtual BufferKind getBufferKind() const {
    return MemoryBuffer_Malloc;
  }
};
}

/// getMemBuffer - Open the specified memory range as a MemoryBuffer.  Note
/// that InputData must be a null terminated if RequiresNullTerminator is true!
MemoryBuffer *MemoryBuffer::getMemBuffer(StringRef InputData,
                                         StringRef BufferName,
                                         bool RequiresNullTerminator) {
  return GetNamedBuffer<MemoryBufferMem>(InputData, BufferName,
                                         RequiresNullTerminator);
}

/// getMemBufferCopy - Open the specified memory range as a MemoryBuffer,
/// copying the contents and taking ownership of it.  This has no requirements
/// on EndPtr[0].
MemoryBuffer *MemoryBuffer::getMemBufferCopy(StringRef InputData,
                                             StringRef BufferName) {
  MemoryBuffer *Buf = getNewUninitMemBuffer(InputData.size(), BufferName);
  if (!Buf) return 0;
  memcpy(const_cast<char*>(Buf->getBufferStart()), InputData.data(),
         InputData.size());
  return Buf;
}

/// getNewUninitMemBuffer - Allocate a new MemoryBuffer of the specified size
/// that is not initialized.  Note that the caller should initialize the
/// memory allocated by this method.  The memory is owned by the MemoryBuffer
/// object.
MemoryBuffer *MemoryBuffer::getNewUninitMemBuffer(size_t Size,
                                                  StringRef BufferName) {
  // Allocate space for the MemoryBuffer, the data and the name. It is important
  // that MemoryBuffer and data are aligned so PointerIntPair works with them.
  size_t AlignedStringLen =
    RoundUpToAlignment(sizeof(MemoryBufferMem) + BufferName.size() + 1,
                       sizeof(void*)); // TODO: Is sizeof(void*) enough?
  size_t RealLen = AlignedStringLen + Size + 1;
  char *Mem = static_cast<char*>(operator new(RealLen, std::nothrow));
  if (!Mem) return 0;

  // The name is stored after the class itself.
  CopyStringRef(Mem + sizeof(MemoryBufferMem), BufferName);

  // The buffer begins after the name and must be aligned.
  char *Buf = Mem + AlignedStringLen;
  Buf[Size] = 0; // Null terminate buffer.

  return new (Mem) MemoryBufferMem(StringRef(Buf, Size), true);
}

/// getNewMemBuffer - Allocate a new MemoryBuffer of the specified size that
/// is completely initialized to zeros.  Note that the caller should
/// initialize the memory allocated by this method.  The memory is owned by
/// the MemoryBuffer object.
MemoryBuffer *MemoryBuffer::getNewMemBuffer(size_t Size, StringRef BufferName) {
  MemoryBuffer *SB = getNewUninitMemBuffer(Size, BufferName);
  if (!SB) return 0;
  memset(const_cast<char*>(SB->getBufferStart()), 0, Size);
  return SB;
}

/// getFileOrSTDIN - Open the specified file as a MemoryBuffer, or open stdin
/// if the Filename is "-".  If an error occurs, this returns null and fills
/// in *ErrStr with a reason.  If stdin is empty, this API (unlike getSTDIN)
/// returns an empty buffer.
error_code MemoryBuffer::getFileOrSTDIN(StringRef Filename,
                                        OwningPtr<MemoryBuffer> &result,
                                        int64_t FileSize) {
  if (Filename == "-")
    return getSTDIN(result);
  return getFile(Filename, result, FileSize);
}

error_code MemoryBuffer::getFileOrSTDIN(const char *Filename,
                                        OwningPtr<MemoryBuffer> &result,
                                        int64_t FileSize) {
  if (strcmp(Filename, "-") == 0)
    return getSTDIN(result);
  return getFile(Filename, result, FileSize);
}

//===----------------------------------------------------------------------===//
// MemoryBuffer::getFile implementation.
//===----------------------------------------------------------------------===//

namespace {
/// MemoryBufferMMapFile - This represents a file that was mapped in with the
/// sys::Path::MapInFilePages method.  When destroyed, it calls the
/// sys::Path::UnMapFilePages method.
class MemoryBufferMMapFile : public MemoryBufferMem {
public:
  MemoryBufferMMapFile(StringRef Buffer, bool RequiresNullTerminator)
    : MemoryBufferMem(Buffer, RequiresNullTerminator) { }

  ~MemoryBufferMMapFile() {
    static int PageSize = sys::Process::GetPageSize();

    uintptr_t Start = reinterpret_cast<uintptr_t>(getBufferStart());
    size_t Size = getBufferSize();
    uintptr_t RealStart = Start & ~(PageSize - 1);
    size_t RealSize = Size + (Start - RealStart);

    sys::Path::UnMapFilePages(reinterpret_cast<const char*>(RealStart),
                              RealSize);
  }

  virtual BufferKind getBufferKind() const {
    return MemoryBuffer_MMap;
  }
};
}

error_code MemoryBuffer::getFile(StringRef Filename,
                                 OwningPtr<MemoryBuffer> &result,
                                 int64_t FileSize,
                                 bool RequiresNullTerminator) {
  // Ensure the path is null terminated.
  SmallString<256> PathBuf(Filename.begin(), Filename.end());
  return MemoryBuffer::getFile(PathBuf.c_str(), result, FileSize,
                               RequiresNullTerminator);
}

error_code MemoryBuffer::getFile(const char *Filename,
                                 OwningPtr<MemoryBuffer> &result,
                                 int64_t FileSize,
                                 bool RequiresNullTerminator) {
  // First check that the "file" is not a directory
  bool is_dir = false;
  error_code err = sys::fs::is_directory(Filename, is_dir);
  if (err)
    return err;
  else if (is_dir)
    return make_error_code(errc::is_a_directory);

  int OpenFlags = O_RDONLY;
#ifdef O_BINARY
  OpenFlags |= O_BINARY;  // Open input file in binary mode on win32.
#endif
  int FD = ::open(Filename, OpenFlags);
  if (FD == -1)
    return error_code(errno, posix_category());

  error_code ret = getOpenFile(FD, Filename, result, FileSize, FileSize,
                               0, RequiresNullTerminator);
  close(FD);
  return ret;
}

static bool shouldUseMmap(int FD,
                          size_t FileSize,
                          size_t MapSize,
                          off_t Offset,
                          bool RequiresNullTerminator,
                          int PageSize) {
  // We don't use mmap for small files because this can severely fragment our
  // address space.
  if (MapSize < 4096*4)
    return false;

  if (!RequiresNullTerminator)
    return true;

  // If we don't know the file size, use fstat to find out.  fstat on an open
  // file descriptor is cheaper than stat on a random path.
  // FIXME: this chunk of code is duplicated, but it avoids a fstat when
  // RequiresNullTerminator = false and MapSize != -1.
  if (FileSize == size_t(-1)) {
    struct stat FileInfo;
    // TODO: This should use fstat64 when available.
    if (fstat(FD, &FileInfo) == -1) {
      return error_code(errno, posix_category());
    }
    FileSize = FileInfo.st_size;
  }

  // If we need a null terminator and the end of the map is inside the file,
  // we cannot use mmap.
  size_t End = Offset + MapSize;
  assert(End <= FileSize);
  if (End != FileSize)
    return false;

  // Don't try to map files that are exactly a multiple of the system page size
  // if we need a null terminator.
  if ((FileSize & (PageSize -1)) == 0)
    return false;

  return true;
}

error_code MemoryBuffer::getOpenFile(int FD, const char *Filename,
                                     OwningPtr<MemoryBuffer> &result,
                                     uint64_t FileSize, uint64_t MapSize,
                                     int64_t Offset,
                                     bool RequiresNullTerminator) {
  static int PageSize = sys::Process::GetPageSize();

  // Default is to map the full file.
  if (MapSize == uint64_t(-1)) {
    // If we don't know the file size, use fstat to find out.  fstat on an open
    // file descriptor is cheaper than stat on a random path.
    if (FileSize == uint64_t(-1)) {
      struct stat FileInfo;
      // TODO: This should use fstat64 when available.
      if (fstat(FD, &FileInfo) == -1) {
        return error_code(errno, posix_category());
      }
      FileSize = FileInfo.st_size;
    }
    MapSize = FileSize;
  }

  if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator,
                    PageSize)) {
    off_t RealMapOffset = Offset & ~(PageSize - 1);
    off_t Delta = Offset - RealMapOffset;
    size_t RealMapSize = MapSize + Delta;

    if (const char *Pages = sys::Path::MapInFilePages(FD,
                                                      RealMapSize,
                                                      RealMapOffset)) {
      result.reset(GetNamedBuffer<MemoryBufferMMapFile>(
          StringRef(Pages + Delta, MapSize), Filename, RequiresNullTerminator));

      if (RequiresNullTerminator && result->getBufferEnd()[0] != '\0') {
        // There could be a racing issue that resulted in the file being larger
        // than the FileSize passed by the caller. We already have an assertion
        // for this in MemoryBuffer::init() but have a runtime guarantee that
        // the buffer will be null-terminated here, so do a copy that adds a
        // null-terminator.
        result.reset(MemoryBuffer::getMemBufferCopy(result->getBuffer(),
                                                    Filename));
      }
      return error_code::success();
    }
  }

  MemoryBuffer *Buf = MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename);
  if (!Buf) {
    // Failed to create a buffer. The only way it can fail is if
    // new(std::nothrow) returns 0.
    return make_error_code(errc::not_enough_memory);
  }

  OwningPtr<MemoryBuffer> SB(Buf);
  char *BufPtr = const_cast<char*>(SB->getBufferStart());

  size_t BytesLeft = MapSize;
#ifndef HAVE_PREAD
  if (lseek(FD, Offset, SEEK_SET) == -1)
    return error_code(errno, posix_category());
#endif

  while (BytesLeft) {
#ifdef HAVE_PREAD
    ssize_t NumRead = ::pread(FD, BufPtr, BytesLeft, MapSize-BytesLeft+Offset);
#else
    ssize_t NumRead = ::read(FD, BufPtr, BytesLeft);
#endif
    if (NumRead == -1) {
      if (errno == EINTR)
        continue;
      // Error while reading.
      return error_code(errno, posix_category());
    }
    if (NumRead == 0) {
      assert(0 && "We got inaccurate FileSize value or fstat reported an "
                   "invalid file size.");
      *BufPtr = '\0'; // null-terminate at the actual size.
      break;
    }
    BytesLeft -= NumRead;
    BufPtr += NumRead;
  }

  result.swap(SB);
  return error_code::success();
}

//===----------------------------------------------------------------------===//
// MemoryBuffer::getSTDIN implementation.
//===----------------------------------------------------------------------===//

error_code MemoryBuffer::getSTDIN(OwningPtr<MemoryBuffer> &result) {
  // Read in all of the data from stdin, we cannot mmap stdin.
  //
  // FIXME: That isn't necessarily true, we should try to mmap stdin and
  // fallback if it fails.
  sys::Program::ChangeStdinToBinary();

  const ssize_t ChunkSize = 4096*4;
  SmallString<ChunkSize> Buffer;
  ssize_t ReadBytes;
  // Read into Buffer until we hit EOF.
  do {
    Buffer.reserve(Buffer.size() + ChunkSize);
    ReadBytes = read(0, Buffer.end(), ChunkSize);
    if (ReadBytes == -1) {
      if (errno == EINTR) continue;
      return error_code(errno, posix_category());
    }
    Buffer.set_size(Buffer.size() + ReadBytes);
  } while (ReadBytes != 0);

  result.reset(getMemBufferCopy(Buffer, "<stdin>"));
  return error_code::success();
}
<|endoftext|>


<commit_before>//===-- TargetMachine.cpp - General Target Information ---------------------==//
//
// This file describes the general parts of a Target machine.
// This file also implements MachineInstrInfo and MachineCacheInfo.
//
//===----------------------------------------------------------------------===//

#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/MachineInstrInfo.h"
#include "llvm/Target/MachineCacheInfo.h"
#include "llvm/CodeGen/PreSelection.h"
#include "llvm/CodeGen/InstrSelection.h"
#include "llvm/CodeGen/InstrScheduling.h"
#include "llvm/CodeGen/RegisterAllocation.h"
#include "llvm/CodeGen/MachineCodeForMethod.h"
#include "llvm/CodeGen/MachineCodeForInstruction.h"
#include "llvm/Reoptimizer/Mapping/MappingInfo.h"
#include "llvm/Reoptimizer/Mapping/FInfo.h"
#include "llvm/Transforms/Scalar.h"
#include "Support/CommandLine.h"
#include "llvm/PassManager.h"
#include "llvm/Function.h"
#include "llvm/DerivedTypes.h"

//---------------------------------------------------------------------------
// Command line options to control choice of code generation passes.
//---------------------------------------------------------------------------

static cl::opt<bool> DisablePreSelect("nopreselect",
                                      cl::desc("Disable preselection pass"));

static cl::opt<bool> DisableSched("nosched",
                                  cl::desc("Disable local scheduling pass"));

//---------------------------------------------------------------------------
// class TargetMachine
//
// Purpose:
//   Machine description.
//
//---------------------------------------------------------------------------

// function TargetMachine::findOptimalStorageSize
//
// Purpose:
//   This default implementation assumes that all sub-word data items use
//   space equal to optSizeForSubWordData, and all other primitive data
//   items use space according to the type.
//
unsigned int
TargetMachine::findOptimalStorageSize(const Type* ty) const
{
  switch(ty->getPrimitiveID())
    {
    case Type::BoolTyID:
    case Type::UByteTyID:
    case Type::SByteTyID:
    case Type::UShortTyID:
    case Type::ShortTyID:
      return optSizeForSubWordData;

    default:
      return DataLayout.getTypeSize(ty);
    }
}

//===---------------------------------------------------------------------===//
// Default code generation passes.
//
// Native code generation for a specified target.
//===---------------------------------------------------------------------===//

class ConstructMachineCodeForFunction : public FunctionPass {
  TargetMachine &Target;
public:
  inline ConstructMachineCodeForFunction(TargetMachine &T) : Target(T) {}

  const char *getPassName() const {
    return "ConstructMachineCodeForFunction";
  }

  bool runOnFunction(Function &F) {
    MachineCodeForMethod::construct(&F, Target);
    return false;
  }
};

struct FreeMachineCodeForFunction : public FunctionPass {
  const char *getPassName() const { return "FreeMachineCodeForFunction"; }

  static void freeMachineCode(Instruction &I) {
    MachineCodeForInstruction::destroy(&I);
  }

  bool runOnFunction(Function &F) {
    for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI)
      for (BasicBlock::iterator I = FI->begin(), E = FI->end(); I != E; ++I)
        MachineCodeForInstruction::get(I).dropAllReferences();

    for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI)
      for_each(FI->begin(), FI->end(), freeMachineCode);

    return false;
  }
};

// addPassesToEmitAssembly - This method controls the entire code generation
// process for the ultra sparc.
//
void
TargetMachine::addPassesToEmitAssembly(PassManager &PM, std::ostream &Out)
{
  // Construct and initialize the MachineCodeForMethod object for this fn.
  PM.add(new ConstructMachineCodeForFunction(*this));

  // Specialize LLVM code for this target machine and then
  // run basic dataflow optimizations on LLVM code.
  if (!DisablePreSelect)
    {
      PM.add(createPreSelectionPass(*this));
      PM.add(createReassociatePass());
      PM.add(createGCSEPass());
      PM.add(createLICMPass());
    }

  PM.add(createInstructionSelectionPass(*this));

  if (!DisableSched)
    PM.add(createInstructionSchedulingWithSSAPass(*this));

  PM.add(getRegisterAllocator(*this));

  //PM.add(new OptimizeLeafProcedures());
  //PM.add(new DeleteFallThroughBranches());
  //PM.add(new RemoveChainedBranches());    // should be folded with previous
  //PM.add(new RemoveRedundantOps());       // operations with %g0, NOP, etc.

  PM.add(getPrologEpilogInsertionPass());

  PM.add(MappingInfoForFunction(Out));

  // Output assembly language to the .s file.  Assembly emission is split into
  // two parts: Function output and Global value output.  This is because
  // function output is pipelined with all of the rest of code generation stuff,
  // allowing machine code representations for functions to be free'd after the
  // function has been emitted.
  //
  PM.add(getFunctionAsmPrinterPass(Out));
  PM.add(new FreeMachineCodeForFunction());  // Free stuff no longer needed

  // Emit Module level assembly after all of the functions have been processed.
  PM.add(getModuleAsmPrinterPass(Out));

  // Emit bytecode to the assembly file into its special section next
  PM.add(getEmitBytecodeToAsmPass(Out));
  PM.add(getFunctionInfo(Out));
}

//---------------------------------------------------------------------------
// class MachineInstructionInfo
//	Interface to description of machine instructions
//---------------------------------------------------------------------------

/*ctor*/
MachineInstrInfo::MachineInstrInfo(const TargetMachine& tgt,
                                   const MachineInstrDescriptor* _desc,
				   unsigned int _descSize,
				   unsigned int _numRealOpCodes)
  : target(tgt),
    desc(_desc), descSize(_descSize), numRealOpCodes(_numRealOpCodes)
{
  // FIXME: TargetInstrDescriptors should not be global
  assert(TargetInstrDescriptors == NULL && desc != NULL);
  TargetInstrDescriptors = desc;	// initialize global variable
}

MachineInstrInfo::~MachineInstrInfo()
{
  TargetInstrDescriptors = NULL;	// reset global variable
}

bool
MachineInstrInfo::constantFitsInImmedField(MachineOpCode opCode,
					   int64_t intValue) const
{
  // First, check if opCode has an immed field.
  bool isSignExtended;
  uint64_t maxImmedValue = maxImmedConstant(opCode, isSignExtended);
  if (maxImmedValue != 0)
    {
      // NEED TO HANDLE UNSIGNED VALUES SINCE THEY MAY BECOME MUCH
      // SMALLER AFTER CASTING TO SIGN-EXTENDED int, short, or char.
      // See CreateUIntSetInstruction in SparcInstrInfo.cpp.

      // Now check if the constant fits
      if (intValue <= (int64_t) maxImmedValue &&
	  intValue >= -((int64_t) maxImmedValue+1))
	return true;
    }

  return false;
}

//---------------------------------------------------------------------------
// class MachineCacheInfo
//
// Purpose:
//   Describes properties of the target cache architecture.
//---------------------------------------------------------------------------

/*ctor*/
MachineCacheInfo::MachineCacheInfo(const TargetMachine& tgt)
  : target(tgt)
{
  Initialize();
}

void
MachineCacheInfo::Initialize()
{
  numLevels = 2;
  cacheLineSizes.push_back(16);  cacheLineSizes.push_back(32);
  cacheSizes.push_back(1 << 15); cacheSizes.push_back(1 << 20);
  cacheAssoc.push_back(1);       cacheAssoc.push_back(4);
}
<commit_msg>Add peephole optimization pass at the end of code generation.<commit_after>//===-- TargetMachine.cpp - General Target Information ---------------------==//
//
// This file describes the general parts of a Target machine.
// This file also implements MachineInstrInfo and MachineCacheInfo.
//
//===----------------------------------------------------------------------===//

#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/MachineInstrInfo.h"
#include "llvm/Target/MachineCacheInfo.h"
#include "llvm/CodeGen/PreSelection.h"
#include "llvm/CodeGen/InstrSelection.h"
#include "llvm/CodeGen/InstrScheduling.h"
#include "llvm/CodeGen/RegisterAllocation.h"
#include "llvm/CodeGen/PeepholeOpts.h"
#include "llvm/CodeGen/MachineCodeForMethod.h"
#include "llvm/CodeGen/MachineCodeForInstruction.h"
#include "llvm/Reoptimizer/Mapping/MappingInfo.h"
#include "llvm/Reoptimizer/Mapping/FInfo.h"
#include "llvm/Transforms/Scalar.h"
#include "Support/CommandLine.h"
#include "llvm/PassManager.h"
#include "llvm/Function.h"
#include "llvm/DerivedTypes.h"

//---------------------------------------------------------------------------
// Command line options to control choice of code generation passes.
//---------------------------------------------------------------------------

static cl::opt<bool> DisablePreSelect("nopreselect",
                                      cl::desc("Disable preselection pass"));

static cl::opt<bool> DisableSched("nosched",
                                  cl::desc("Disable local scheduling pass"));

static cl::opt<bool> DisablePeephole("nopeephole",
                                     cl::desc("Disable peephole optimization pass"));

//---------------------------------------------------------------------------
// class TargetMachine
//
// Purpose:
//   Machine description.
//
//---------------------------------------------------------------------------

// function TargetMachine::findOptimalStorageSize
//
// Purpose:
//   This default implementation assumes that all sub-word data items use
//   space equal to optSizeForSubWordData, and all other primitive data
//   items use space according to the type.
//
unsigned int
TargetMachine::findOptimalStorageSize(const Type* ty) const
{
  switch(ty->getPrimitiveID())
    {
    case Type::BoolTyID:
    case Type::UByteTyID:
    case Type::SByteTyID:
    case Type::UShortTyID:
    case Type::ShortTyID:
      return optSizeForSubWordData;

    default:
      return DataLayout.getTypeSize(ty);
    }
}

//===---------------------------------------------------------------------===//
// Default code generation passes.
//
// Native code generation for a specified target.
//===---------------------------------------------------------------------===//

class ConstructMachineCodeForFunction : public FunctionPass {
  TargetMachine &Target;
public:
  inline ConstructMachineCodeForFunction(TargetMachine &T) : Target(T) {}

  const char *getPassName() const {
    return "ConstructMachineCodeForFunction";
  }

  bool runOnFunction(Function &F) {
    MachineCodeForMethod::construct(&F, Target);
    return false;
  }
};

struct FreeMachineCodeForFunction : public FunctionPass {
  const char *getPassName() const { return "FreeMachineCodeForFunction"; }

  static void freeMachineCode(Instruction &I) {
    MachineCodeForInstruction::destroy(&I);
  }

  bool runOnFunction(Function &F) {
    for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI)
      for (BasicBlock::iterator I = FI->begin(), E = FI->end(); I != E; ++I)
        MachineCodeForInstruction::get(I).dropAllReferences();

    for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI)
      for_each(FI->begin(), FI->end(), freeMachineCode);

    return false;
  }
};

// addPassesToEmitAssembly - This method controls the entire code generation
// process for the ultra sparc.
//
void
TargetMachine::addPassesToEmitAssembly(PassManager &PM, std::ostream &Out)
{
  // Construct and initialize the MachineCodeForMethod object for this fn.
  PM.add(new ConstructMachineCodeForFunction(*this));

  // Specialize LLVM code for this target machine and then
  // run basic dataflow optimizations on LLVM code.
  if (!DisablePreSelect)
    {
      PM.add(createPreSelectionPass(*this));
      PM.add(createReassociatePass());
      PM.add(createGCSEPass());
      PM.add(createLICMPass());
    }

  PM.add(createInstructionSelectionPass(*this));

  if (!DisableSched)
    PM.add(createInstructionSchedulingWithSSAPass(*this));

  PM.add(getRegisterAllocator(*this));

  PM.add(getPrologEpilogInsertionPass());

  if (!DisablePeephole)
    PM.add(createPeepholeOptsPass(*this));

  PM.add(MappingInfoForFunction(Out));

  // Output assembly language to the .s file.  Assembly emission is split into
  // two parts: Function output and Global value output.  This is because
  // function output is pipelined with all of the rest of code generation stuff,
  // allowing machine code representations for functions to be free'd after the
  // function has been emitted.
  //
  PM.add(getFunctionAsmPrinterPass(Out));
  PM.add(new FreeMachineCodeForFunction());  // Free stuff no longer needed

  // Emit Module level assembly after all of the functions have been processed.
  PM.add(getModuleAsmPrinterPass(Out));

  // Emit bytecode to the assembly file into its special section next
  PM.add(getEmitBytecodeToAsmPass(Out));
  PM.add(getFunctionInfo(Out));
}

//---------------------------------------------------------------------------
// class MachineInstructionInfo
//	Interface to description of machine instructions
//---------------------------------------------------------------------------

/*ctor*/
MachineInstrInfo::MachineInstrInfo(const TargetMachine& tgt,
                                   const MachineInstrDescriptor* _desc,
				   unsigned int _descSize,
				   unsigned int _numRealOpCodes)
  : target(tgt),
    desc(_desc), descSize(_descSize), numRealOpCodes(_numRealOpCodes)
{
  // FIXME: TargetInstrDescriptors should not be global
  assert(TargetInstrDescriptors == NULL && desc != NULL);
  TargetInstrDescriptors = desc;	// initialize global variable
}

MachineInstrInfo::~MachineInstrInfo()
{
  TargetInstrDescriptors = NULL;	// reset global variable
}

bool
MachineInstrInfo::constantFitsInImmedField(MachineOpCode opCode,
					   int64_t intValue) const
{
  // First, check if opCode has an immed field.
  bool isSignExtended;
  uint64_t maxImmedValue = maxImmedConstant(opCode, isSignExtended);
  if (maxImmedValue != 0)
    {
      // NEED TO HANDLE UNSIGNED VALUES SINCE THEY MAY BECOME MUCH
      // SMALLER AFTER CASTING TO SIGN-EXTENDED int, short, or char.
      // See CreateUIntSetInstruction in SparcInstrInfo.cpp.

      // Now check if the constant fits
      if (intValue <= (int64_t) maxImmedValue &&
	  intValue >= -((int64_t) maxImmedValue+1))
	return true;
    }

  return false;
}

//---------------------------------------------------------------------------
// class MachineCacheInfo
//
// Purpose:
//   Describes properties of the target cache architecture.
//---------------------------------------------------------------------------

/*ctor*/
MachineCacheInfo::MachineCacheInfo(const TargetMachine& tgt)
  : target(tgt)
{
  Initialize();
}

void
MachineCacheInfo::Initialize()
{
  numLevels = 2;
  cacheLineSizes.push_back(16);  cacheLineSizes.push_back(32);
  cacheSizes.push_back(1 << 15); cacheSizes.push_back(1 << 20);
  cacheAssoc.push_back(1);       cacheAssoc.push_back(4);
}
<|endoftext|>


<commit_before>#ifndef WIN_IMPL_BASE_HPP
#define WIN_IMPL_BASE_HPP

#include "stdafx.h"

#define USE(FEATURE) (defined USE_##FEATURE  && USE_##FEATURE)
#define ENABLE(FEATURE) (defined ENABLE_##FEATURE  && ENABLE_##FEATURE)

#define USE_ZIP_SKIN 0
#define USE_EMBEDED_RESOURCE 0

namespace DuiLib
{

	enum UILIB_RESOURCETYPE
	{
		UILIB_FILE=1,
		UILIB_ZIP,
		UILIB_RESOURCE,
		UILIB_ZIPRESOURCE,
	};

	class WindowImplBase
		: public CWindowWnd
		, public INotifyUI
		, public IMessageFilterUI
		, public IDialogBuilderCallback
	{
	public:
		WindowImplBase(){};
		virtual ~WindowImplBase(){};

		virtual void InitWindow(){};

		virtual void OnFinalMessage()
		{
			m_PaintManager.RemovePreMessageFilter(this);
			m_PaintManager.RemoveNotifier(this);
			m_PaintManager.ReapObjects(m_PaintManager.GetRoot());
		}

	protected:
		virtual CDuiString GetSkinFolder() = 0;
		virtual CDuiString GetSkinFile() = 0;
		virtual LPCTSTR GetWindowClassName(void) const =0 ;
		virtual void Notify(TNotifyUI &msg)=0;

		LRESULT ResponseDefaultKeyEvent(WPARAM wParam)
		{
			if (wParam == VK_RETURN)
			{
				return FALSE;
			}
			else if (wParam == VK_ESCAPE)
			{
				Close();
				return TRUE;
			}

			return FALSE;
		}

		CPaintManagerUI m_PaintManager;
		static LPBYTE m_lpResourceZIPBuffer;

	public:
		virtual UINT GetClassStyle() const
		{
			return CS_DBLCLKS;
		}

		virtual UILIB_RESOURCETYPE GetResourceType() const
		{
			return UILIB_FILE;
		}

		virtual CDuiString GetZIPFileName() const
		{
			return _T("");
		}

		virtual LPCTSTR GetResourceID() const
		{
			return _T("");
		}

		virtual CControlUI* CreateControl(LPCTSTR pstrClass)
		{
			return NULL;
		}

		virtual LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/, bool& /*bHandled*/)
		{
			if (uMsg == WM_KEYDOWN)
			{
				switch (wParam)
				{
				case VK_RETURN:
				case VK_ESCAPE:
					return ResponseDefaultKeyEvent(wParam);
				default:
					break;
				}
			}
			return FALSE;
		}

		virtual LRESULT OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

#if defined(WIN32) && !defined(UNDER_CE)
		virtual LRESULT OnNcActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
		{
			if( ::IsIconic(*this) ) bHandled = FALSE;
			return (wParam == 0) ? TRUE : FALSE;
		}

		virtual LRESULT OnNcCalcSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
		{
			return 0;
		}

		virtual LRESULT OnNcPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
		{
			return 0;
		}

		virtual LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			POINT pt; pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam);
			::ScreenToClient(*this, &pt);

			RECT rcClient;
			::GetClientRect(*this, &rcClient);

			RECT rcCaption = m_PaintManager.GetCaptionRect();
			if( pt.x >= rcClient.left + rcCaption.left && pt.x < rcClient.right - rcCaption.right \
				&& pt.y >= rcCaption.top && pt.y < rcCaption.bottom ) {
					CControlUI* pControl = static_cast<CControlUI*>(m_PaintManager.FindControl(pt));
					if( pControl && _tcsicmp(pControl->GetClass(), _T("ButtonUI")) != 0 &&
						_tcsicmp(pControl->GetClass(), _T("OptionUI")) != 0 &&
						_tcsicmp(pControl->GetClass(), _T("TextUI")) != 0 )
						return HTCAPTION;
			}

			return HTCLIENT;
		}

		virtual LRESULT OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			MONITORINFO oMonitor = {};
			oMonitor.cbSize = sizeof(oMonitor);
			::GetMonitorInfo(::MonitorFromWindow(*this, MONITOR_DEFAULTTOPRIMARY), &oMonitor);
			CDuiRect rcWork = oMonitor.rcWork;
			rcWork.Offset(-rcWork.left, -rcWork.top);

			LPMINMAXINFO lpMMI = (LPMINMAXINFO) lParam;
			lpMMI->ptMaxPosition.x	= rcWork.left;
			lpMMI->ptMaxPosition.y	= rcWork.top;
			lpMMI->ptMaxSize.x		= rcWork.right;
			lpMMI->ptMaxSize.y		= rcWork.bottom;

			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnMouseWheel(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnMouseHover(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}
#endif

		virtual LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			SIZE szRoundCorner = m_PaintManager.GetRoundCorner();
#if defined(WIN32) && !defined(UNDER_CE)
			if( !::IsIconic(*this) && (szRoundCorner.cx != 0 || szRoundCorner.cy != 0) ) {
				CDuiRect rcWnd;
				::GetWindowRect(*this, &rcWnd);
				rcWnd.Offset(-rcWnd.left, -rcWnd.top);
				rcWnd.right++; rcWnd.bottom++;
				HRGN hRgn = ::CreateRoundRectRgn(rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom, szRoundCorner.cx, szRoundCorner.cy);
				::SetWindowRgn(*this, hRgn, TRUE);
				::DeleteObject(hRgn);
			}
#endif
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			if (wParam == SC_CLOSE)
			{
				bHandled = TRUE;
				SendMessage(WM_CLOSE);
				return 0;
			}
#if defined(WIN32) && !defined(UNDER_CE)
			BOOL bZoomed = ::IsZoomed(*this);
			LRESULT lRes = CWindowWnd::HandleMessage(uMsg, wParam, lParam);
			if( ::IsZoomed(*this) != bZoomed )
			{
			}
#else
			LRESULT lRes = CWindowWnd::HandleMessage(uMsg, wParam, lParam);
#endif
			return lRes;
		}

		virtual LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			LONG styleValue = ::GetWindowLong(*this, GWL_STYLE);
			styleValue &= ~WS_CAPTION;
			::SetWindowLong(*this, GWL_STYLE, styleValue | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
			RECT rcClient;
			::GetClientRect(*this, &rcClient);
			::SetWindowPos(*this, NULL, rcClient.left, rcClient.top, rcClient.right - rcClient.left, \
				rcClient.bottom - rcClient.top, SWP_FRAMECHANGED);

			m_PaintManager.Init(m_hWnd);
			m_PaintManager.AddPreMessageFilter(this);

			CDialogBuilder builder;
			CDuiString strResourcePath=m_PaintManager.GetInstancePath();
			strResourcePath+=GetSkinFolder().c_str();
			m_PaintManager.SetResourcePath(strResourcePath.c_str());

			switch(GetResourceType())
			{
			case UILIB_ZIP:
				m_PaintManager.SetResourceZip(GetZIPFileName().c_str(), true);
				break;
			case UILIB_ZIPRESOURCE:
				{
					HRSRC hResource = ::FindResource(m_PaintManager.GetResourceDll(), GetResourceID(), _T("ZIPRES"));
					if( hResource == NULL )
						return 0L;
					DWORD dwSize = 0;
					HGLOBAL hGlobal = ::LoadResource(m_PaintManager.GetResourceDll(), hResource);
					if( hGlobal == NULL )
					{
#if defined(WIN32) && !defined(UNDER_CE)
						::FreeResource(hResource);
#endif
						return 0L;
					}
					dwSize = ::SizeofResource(m_PaintManager.GetResourceDll(), hResource);
					if( dwSize == 0 )
						return 0L;
					m_lpResourceZIPBuffer = new BYTE[ dwSize ];
					if (m_lpResourceZIPBuffer != NULL)
					{
						::CopyMemory(m_lpResourceZIPBuffer, (LPBYTE)::LockResource(hGlobal), dwSize);
					}
#if defined(WIN32) && !defined(UNDER_CE)
					::FreeResource(hResource);
#endif
					m_PaintManager.SetResourceZip(m_lpResourceZIPBuffer, dwSize);
				}
				break;
			}

			CControlUI* pRoot = builder.Create(GetSkinFile().c_str(), (UINT)0, this, &m_PaintManager);
			ASSERT(pRoot);
			if (pRoot==NULL)
			{
				MessageBox(NULL,_T("Դļʧ"),_T("Duilib"),MB_OK|MB_ICONERROR);
				ExitProcess(1);
				return 0;
			}
			m_PaintManager.AttachDialog(pRoot);
			m_PaintManager.AddNotifier(this);
			m_PaintManager.SetBackgroundTransparent(TRUE);

			InitWindow();
			return 0;
		}

		virtual LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnKillFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
		{
			LRESULT lRes = 0;
			BOOL bHandled = TRUE;
			switch (uMsg)
			{
			case WM_CREATE:			lRes = OnCreate(uMsg, wParam, lParam, bHandled); break;
			case WM_CLOSE:			lRes = OnClose(uMsg, wParam, lParam, bHandled); break;
			case WM_DESTROY:		lRes = OnDestroy(uMsg, wParam, lParam, bHandled); break;
#if defined(WIN32) && !defined(UNDER_CE)
			case WM_NCACTIVATE:		lRes = OnNcActivate(uMsg, wParam, lParam, bHandled); break;
			case WM_NCCALCSIZE:		lRes = OnNcCalcSize(uMsg, wParam, lParam, bHandled); break;
			case WM_NCPAINT:		lRes = OnNcPaint(uMsg, wParam, lParam, bHandled); break;
			case WM_NCHITTEST:		lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); break;
			case WM_GETMINMAXINFO:	lRes = OnGetMinMaxInfo(uMsg, wParam, lParam, bHandled); break;
			case WM_MOUSEWHEEL:		lRes = OnMouseWheel(uMsg, wParam, lParam, bHandled); break;
#endif
			case WM_SIZE:			lRes = OnSize(uMsg, wParam, lParam, bHandled); break;
			case WM_CHAR:		lRes = OnChar(uMsg, wParam, lParam, bHandled); break;
			case WM_SYSCOMMAND:		lRes = OnSysCommand(uMsg, wParam, lParam, bHandled); break;
			case WM_KEYDOWN:		lRes = OnKeyDown(uMsg, wParam, lParam, bHandled); break;
			case WM_KILLFOCUS:		lRes = OnKillFocus(uMsg, wParam, lParam, bHandled); break;
			case WM_SETFOCUS:		lRes = OnSetFocus(uMsg, wParam, lParam, bHandled); break;
			case WM_LBUTTONUP:		lRes = OnLButtonUp(uMsg, wParam, lParam, bHandled); break;
			case WM_LBUTTONDOWN:	lRes = OnLButtonDown(uMsg, wParam, lParam, bHandled); break;
			case WM_MOUSEMOVE:		lRes = OnMouseMove(uMsg, wParam, lParam, bHandled); break;
			case WM_MOUSEHOVER:	lRes = OnMouseHover(uMsg, wParam, lParam, bHandled); break;
			default:				bHandled = FALSE; break;
			}
			if (bHandled) return lRes;

			lRes = HandleCustomMessage(uMsg, wParam, lParam, bHandled);
			if (bHandled) return lRes;

			if (m_PaintManager.MessageHandler(uMsg, wParam, lParam, lRes))
				return lRes;
			return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
		}

		virtual LRESULT HandleCustomMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LONG GetStyle()
		{
			LONG styleValue = ::GetWindowLong(*this, GWL_STYLE);
			styleValue &= ~WS_CAPTION;

			return styleValue;
		}
	};

	__declspec(selectany) LPBYTE WindowImplBase::m_lpResourceZIPBuffer=NULL;
}

#endif // WIN_IMPL_BASE_HPP
<commit_msg>同325，修复WM_GETMINMAXINFO 处理问题。<commit_after>#ifndef WIN_IMPL_BASE_HPP
#define WIN_IMPL_BASE_HPP

#include "stdafx.h"

#define USE(FEATURE) (defined USE_##FEATURE  && USE_##FEATURE)
#define ENABLE(FEATURE) (defined ENABLE_##FEATURE  && ENABLE_##FEATURE)

#define USE_ZIP_SKIN 0
#define USE_EMBEDED_RESOURCE 0

namespace DuiLib
{

	enum UILIB_RESOURCETYPE
	{
		UILIB_FILE=1,
		UILIB_ZIP,
		UILIB_RESOURCE,
		UILIB_ZIPRESOURCE,
	};

	class WindowImplBase
		: public CWindowWnd
		, public INotifyUI
		, public IMessageFilterUI
		, public IDialogBuilderCallback
	{
	public:
		WindowImplBase(){};
		virtual ~WindowImplBase(){};

		virtual void InitWindow(){};

		virtual void OnFinalMessage()
		{
			m_PaintManager.RemovePreMessageFilter(this);
			m_PaintManager.RemoveNotifier(this);
			m_PaintManager.ReapObjects(m_PaintManager.GetRoot());
		}

	protected:
		virtual CDuiString GetSkinFolder() = 0;
		virtual CDuiString GetSkinFile() = 0;
		virtual LPCTSTR GetWindowClassName(void) const =0 ;
		virtual void Notify(TNotifyUI &msg)=0;

		LRESULT ResponseDefaultKeyEvent(WPARAM wParam)
		{
			if (wParam == VK_RETURN)
			{
				return FALSE;
			}
			else if (wParam == VK_ESCAPE)
			{
				Close();
				return TRUE;
			}

			return FALSE;
		}

		CPaintManagerUI m_PaintManager;
		static LPBYTE m_lpResourceZIPBuffer;

	public:
		virtual UINT GetClassStyle() const
		{
			return CS_DBLCLKS;
		}

		virtual UILIB_RESOURCETYPE GetResourceType() const
		{
			return UILIB_FILE;
		}

		virtual CDuiString GetZIPFileName() const
		{
			return _T("");
		}

		virtual LPCTSTR GetResourceID() const
		{
			return _T("");
		}

		virtual CControlUI* CreateControl(LPCTSTR pstrClass)
		{
			return NULL;
		}

		virtual LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/, bool& /*bHandled*/)
		{
			if (uMsg == WM_KEYDOWN)
			{
				switch (wParam)
				{
				case VK_RETURN:
				case VK_ESCAPE:
					return ResponseDefaultKeyEvent(wParam);
				default:
					break;
				}
			}
			return FALSE;
		}

		virtual LRESULT OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

#if defined(WIN32) && !defined(UNDER_CE)
		virtual LRESULT OnNcActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
		{
			if( ::IsIconic(*this) ) bHandled = FALSE;
			return (wParam == 0) ? TRUE : FALSE;
		}

		virtual LRESULT OnNcCalcSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
		{
			return 0;
		}

		virtual LRESULT OnNcPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
		{
			return 0;
		}

		virtual LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			POINT pt; pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam);
			::ScreenToClient(*this, &pt);

			RECT rcClient;
			::GetClientRect(*this, &rcClient);

			RECT rcCaption = m_PaintManager.GetCaptionRect();
			if( pt.x >= rcClient.left + rcCaption.left && pt.x < rcClient.right - rcCaption.right \
				&& pt.y >= rcCaption.top && pt.y < rcCaption.bottom ) {
					CControlUI* pControl = static_cast<CControlUI*>(m_PaintManager.FindControl(pt));
					if( pControl && _tcsicmp(pControl->GetClass(), _T("ButtonUI")) != 0 &&
						_tcsicmp(pControl->GetClass(), _T("OptionUI")) != 0 &&
						_tcsicmp(pControl->GetClass(), _T("TextUI")) != 0 )
						return HTCAPTION;
			}

			return HTCLIENT;
		}

		virtual LRESULT OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			MONITORINFO oMonitor = {};
			oMonitor.cbSize = sizeof(oMonitor);
			::GetMonitorInfo(::MonitorFromWindow(*this, MONITOR_DEFAULTTOPRIMARY), &oMonitor);
			CDuiRect rcWork = oMonitor.rcWork;
			rcWork.Offset(-oMonitor.rcMonitor.left, -oMonitor.rcMonitor.top);

			LPMINMAXINFO lpMMI = (LPMINMAXINFO) lParam;
			lpMMI->ptMaxPosition.x	= rcWork.left;
			lpMMI->ptMaxPosition.y	= rcWork.top;
			lpMMI->ptMaxSize.x		= rcWork.right;
			lpMMI->ptMaxSize.y		= rcWork.bottom;

			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnMouseWheel(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnMouseHover(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}
#endif

		virtual LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			SIZE szRoundCorner = m_PaintManager.GetRoundCorner();
#if defined(WIN32) && !defined(UNDER_CE)
			if( !::IsIconic(*this) && (szRoundCorner.cx != 0 || szRoundCorner.cy != 0) ) {
				CDuiRect rcWnd;
				::GetWindowRect(*this, &rcWnd);
				rcWnd.Offset(-rcWnd.left, -rcWnd.top);
				rcWnd.right++; rcWnd.bottom++;
				HRGN hRgn = ::CreateRoundRectRgn(rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom, szRoundCorner.cx, szRoundCorner.cy);
				::SetWindowRgn(*this, hRgn, TRUE);
				::DeleteObject(hRgn);
			}
#endif
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			if (wParam == SC_CLOSE)
			{
				bHandled = TRUE;
				SendMessage(WM_CLOSE);
				return 0;
			}
#if defined(WIN32) && !defined(UNDER_CE)
			BOOL bZoomed = ::IsZoomed(*this);
			LRESULT lRes = CWindowWnd::HandleMessage(uMsg, wParam, lParam);
			if( ::IsZoomed(*this) != bZoomed )
			{
			}
#else
			LRESULT lRes = CWindowWnd::HandleMessage(uMsg, wParam, lParam);
#endif
			return lRes;
		}

		virtual LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			LONG styleValue = ::GetWindowLong(*this, GWL_STYLE);
			styleValue &= ~WS_CAPTION;
			::SetWindowLong(*this, GWL_STYLE, styleValue | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
			RECT rcClient;
			::GetClientRect(*this, &rcClient);
			::SetWindowPos(*this, NULL, rcClient.left, rcClient.top, rcClient.right - rcClient.left, \
				rcClient.bottom - rcClient.top, SWP_FRAMECHANGED);

			m_PaintManager.Init(m_hWnd);
			m_PaintManager.AddPreMessageFilter(this);

			CDialogBuilder builder;
			CDuiString strResourcePath=m_PaintManager.GetInstancePath();
			strResourcePath+=GetSkinFolder().c_str();
			m_PaintManager.SetResourcePath(strResourcePath.c_str());

			switch(GetResourceType())
			{
			case UILIB_ZIP:
				m_PaintManager.SetResourceZip(GetZIPFileName().c_str(), true);
				break;
			case UILIB_ZIPRESOURCE:
				{
					HRSRC hResource = ::FindResource(m_PaintManager.GetResourceDll(), GetResourceID(), _T("ZIPRES"));
					if( hResource == NULL )
						return 0L;
					DWORD dwSize = 0;
					HGLOBAL hGlobal = ::LoadResource(m_PaintManager.GetResourceDll(), hResource);
					if( hGlobal == NULL )
					{
#if defined(WIN32) && !defined(UNDER_CE)
						::FreeResource(hResource);
#endif
						return 0L;
					}
					dwSize = ::SizeofResource(m_PaintManager.GetResourceDll(), hResource);
					if( dwSize == 0 )
						return 0L;
					m_lpResourceZIPBuffer = new BYTE[ dwSize ];
					if (m_lpResourceZIPBuffer != NULL)
					{
						::CopyMemory(m_lpResourceZIPBuffer, (LPBYTE)::LockResource(hGlobal), dwSize);
					}
#if defined(WIN32) && !defined(UNDER_CE)
					::FreeResource(hResource);
#endif
					m_PaintManager.SetResourceZip(m_lpResourceZIPBuffer, dwSize);
				}
				break;
			}

			CControlUI* pRoot = builder.Create(GetSkinFile().c_str(), (UINT)0, this, &m_PaintManager);
			ASSERT(pRoot);
			if (pRoot==NULL)
			{
				MessageBox(NULL,_T("Դļʧ"),_T("Duilib"),MB_OK|MB_ICONERROR);
				ExitProcess(1);
				return 0;
			}
			m_PaintManager.AttachDialog(pRoot);
			m_PaintManager.AddNotifier(this);
			m_PaintManager.SetBackgroundTransparent(TRUE);

			InitWindow();
			return 0;
		}

		virtual LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnKillFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
		{
			LRESULT lRes = 0;
			BOOL bHandled = TRUE;
			switch (uMsg)
			{
			case WM_CREATE:			lRes = OnCreate(uMsg, wParam, lParam, bHandled); break;
			case WM_CLOSE:			lRes = OnClose(uMsg, wParam, lParam, bHandled); break;
			case WM_DESTROY:		lRes = OnDestroy(uMsg, wParam, lParam, bHandled); break;
#if defined(WIN32) && !defined(UNDER_CE)
			case WM_NCACTIVATE:		lRes = OnNcActivate(uMsg, wParam, lParam, bHandled); break;
			case WM_NCCALCSIZE:		lRes = OnNcCalcSize(uMsg, wParam, lParam, bHandled); break;
			case WM_NCPAINT:		lRes = OnNcPaint(uMsg, wParam, lParam, bHandled); break;
			case WM_NCHITTEST:		lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); break;
			case WM_GETMINMAXINFO:	lRes = OnGetMinMaxInfo(uMsg, wParam, lParam, bHandled); break;
			case WM_MOUSEWHEEL:		lRes = OnMouseWheel(uMsg, wParam, lParam, bHandled); break;
#endif
			case WM_SIZE:			lRes = OnSize(uMsg, wParam, lParam, bHandled); break;
			case WM_CHAR:		lRes = OnChar(uMsg, wParam, lParam, bHandled); break;
			case WM_SYSCOMMAND:		lRes = OnSysCommand(uMsg, wParam, lParam, bHandled); break;
			case WM_KEYDOWN:		lRes = OnKeyDown(uMsg, wParam, lParam, bHandled); break;
			case WM_KILLFOCUS:		lRes = OnKillFocus(uMsg, wParam, lParam, bHandled); break;
			case WM_SETFOCUS:		lRes = OnSetFocus(uMsg, wParam, lParam, bHandled); break;
			case WM_LBUTTONUP:		lRes = OnLButtonUp(uMsg, wParam, lParam, bHandled); break;
			case WM_LBUTTONDOWN:	lRes = OnLButtonDown(uMsg, wParam, lParam, bHandled); break;
			case WM_MOUSEMOVE:		lRes = OnMouseMove(uMsg, wParam, lParam, bHandled); break;
			case WM_MOUSEHOVER:	lRes = OnMouseHover(uMsg, wParam, lParam, bHandled); break;
			default:				bHandled = FALSE; break;
			}
			if (bHandled) return lRes;

			lRes = HandleCustomMessage(uMsg, wParam, lParam, bHandled);
			if (bHandled) return lRes;

			if (m_PaintManager.MessageHandler(uMsg, wParam, lParam, lRes))
				return lRes;
			return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
		}

		virtual LRESULT HandleCustomMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			bHandled = FALSE;
			return 0;
		}

		virtual LONG GetStyle()
		{
			LONG styleValue = ::GetWindowLong(*this, GWL_STYLE);
			styleValue &= ~WS_CAPTION;

			return styleValue;
		}
	};

	__declspec(selectany) LPBYTE WindowImplBase::m_lpResourceZIPBuffer=NULL;
}

#endif // WIN_IMPL_BASE_HPP
<|endoftext|>