////////////////////////////////////////////////////////////////////
//
// Boyer-Moore implementation
// version: 1.12
// (c)2006 Jeremy Collake / Bitsum Technologies
// jeremy@bitsum.com
// Use PECompact today!
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "bmbinbin.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        DisableThreadLibraryCalls(hModule);
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

CBoyerMooreHandle::CBoyerMooreHandle()
{
    m_pTable=new unsigned long[256];
    m_pPhrase=NULL;
}

CBoyerMooreHandle::~CBoyerMooreHandle()
{
    delete m_pTable;
    if(m_pPhrase)
    {
        delete m_pPhrase;
    }
}

bool CBoyerMooreHandle::Init(unsigned char *pPhrase, unsigned long nPhraseLen)
{
    if(!nPhraseLen || !pPhrase)
    {
        return false;
    }
    m_pPhrase=new unsigned char[nPhraseLen];
    memcpy_s(m_pPhrase,nPhraseLen,pPhrase,nPhraseLen);

    for(int nI=0;nI<256;nI++)
    {
        m_pTable[nI]=nPhraseLen;
    }
    // duplicates over-written with smaller value using forward str direction
    for(unsigned int nI=0;nI<nPhraseLen;nI++)
    {
        m_pTable[pPhrase[nI]]=(nPhraseLen-nI)-1;
    }
    m_nPhraseLen=nPhraseLen;
    return true;
}

//
// allocate and initialize table
//
COMMON_API CBoyerMooreHandle * __stdcall BoyerMooreBinBin_Init(unsigned char *pPhrase, unsigned long nPhraseLen)
{
    CBoyerMooreHandle *pBMInfo=new CBoyerMooreHandle;
    if(!pBMInfo->Init(pPhrase,nPhraseLen))
    {
        _ASSERT(0);
        delete pBMInfo;
        return NULL;
    }
    return pBMInfo;
}

COMMON_API int __stdcall BoyerMooreBinBin(CBoyerMooreHandle *pHandle,
                                          unsigned char *pBuffer,
                                          unsigned long nBufferSize,
                                          unsigned long nStart)
{
    bool bMatch;
    nStart+=(pHandle->m_nPhraseLen-1);  // advance up to phrase length
    if(nStart>=nBufferSize)
    {
        return -1;
    }
    for(unsigned long nPos=nStart;nPos<nBufferSize;)
    {
        int nDiff=pHandle->m_pTable[pBuffer[nPos]];     // get character shift value
        switch(nDiff)
        {
        case 0:
            // if shift of 0, then is last character so need to do a reverse comparison
            // .. starting at nPos-1 since we know last character is a match
                bMatch=true;
                for(int nI=pHandle->m_nPhraseLen-1;nI>0;nI--)
                {
                    int nBufferIndex=nPos-(pHandle->m_nPhraseLen-nI);
                    if(pHandle->m_pPhrase[nI-1]!=pBuffer[nBufferIndex])
                    {
                        // reverse comparison failed..
                        // back up to last compared character and apply normal shift
                        nBufferIndex+=pHandle->m_pTable[pBuffer[nBufferIndex]];
                        if(nBufferIndex>++nPos)
                        {
                            nPos=nBufferIndex;
                        }
                        bMatch=false;
                        break;
                    }
                }
                if(bMatch)
                {
                    return nPos-(pHandle->m_nPhraseLen-1);
                }
            break;
        default:
            nPos+=nDiff;            // shift
            break;
        }
    }
    return -1;
}

COMMON_API void __stdcall BoyerMooreBinBin_Deinit(CBoyerMooreHandle *pHandle)
{
    delete pHandle;
}