<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Syscoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

// NOTE: This file is intended to be customised by the end user, and includes only local node policy logic

#include "policy/policy.h"

#include "main.h"
#include "tinyformat.h"
#include "util.h"
#include "utilstrencodings.h"

#include <boost/foreach.hpp>
// SYSCOIN need constant SYSCOIN_TX_VERSION
extern int GetSyscoinTxVersion();
    /**
     * Check transaction inputs to mitigate two
     * potential denial-of-service attacks:
     *
     * 1. scriptSigs with extra data stuffed into them,
     *    not consumed by scriptPubKey (or P2SH script)
     * 2. P2SH scripts with a crazy number of expensive
     *    CHECKSIG/CHECKMULTISIG operations
     *
     * Why bother? To avoid denial-of-service attacks; an attacker
     * can submit a standard HASH... OP_EQUAL transaction,
     * which will get accepted into blocks. The redemption
     * script can be anything; an attacker could use a very
     * expensive-to-check-upon-redemption script like:
     *   DUP CHECKSIG DROP ... repeated 100 times... OP_1
     */

bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool witnessEnabled)
{
    std::vector<std::vector<unsigned char> > vSolutions;
    if (!Solver(scriptPubKey, whichType, vSolutions))
        return false;

    if (whichType == TX_MULTISIG)
    {
        unsigned char m = vSolutions.front()[0];
        unsigned char n = vSolutions.back()[0];
		// Support up to x-of-3 multisig txns as standard
        if (n < 1 || n > 3)
            return false;
        if (m < 1 || m > n)
            return false;
	// SYSCOIN check for size of sys tx, normal tx size is checked in isstandardtx now
    } else if (whichType == TX_NULL_DATA &&
               (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes*75))
          return false;

    else if (!witnessEnabled && (whichType == TX_WITNESS_V0_KEYHASH || whichType == TX_WITNESS_V0_SCRIPTHASH))
        return false;

    return whichType != TX_NONSTANDARD;
}

bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnessEnabled)
{
	// SYSCOIN check for syscoin or bitcoin tx
    if ((tx.nVersion > CTransaction::MAX_STANDARD_VERSION || tx.nVersion < 1) && tx.nVersion != GetSyscoinTxVersion()) {
        reason = "version";
        return false;
    }

    // Extremely large transactions with lots of inputs can cost the network
    // almost as much to process as they cost the sender in fees, because
    // computing signature hashes is O(ninputs*txsize). Limiting transactions
    // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks.
    unsigned int sz = GetTransactionWeight(tx);
    if (sz >= MAX_STANDARD_TX_WEIGHT) {
        reason = "tx-size";
        return false;
    }

    BOOST_FOREACH(const CTxIn& txin, tx.vin)
    {
        // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
        // keys (remember the 520 byte limit on redeemScript size). That works
        // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
        // bytes of scriptSig, which we round off to 1650 bytes for some minor
        // future-proofing. That's also enough to spend a 20-of-20
        // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
        // considered standard.
        if (txin.scriptSig.size() > 1650) {
            reason = "scriptsig-size";
            return false;
        }
        if (!txin.scriptSig.IsPushOnly()) {
            reason = "scriptsig-not-pushonly";
            return false;
        }
    }

    unsigned int nDataOut = 0;
    txnouttype whichType;
    BOOST_FOREACH(const CTxOut& txout, tx.vout) {
        if (!::IsStandard(txout.scriptPubKey, whichType, witnessEnabled)) {
            reason = "scriptpubkey";
            return false;
        }

        if (whichType == TX_NULL_DATA)
		{
			// SYSCOIN if not syscoin tx and opreturn size is bigger than maxcarrier bytes, return false
			// we need this because if it is a sys tx then we allow 75x maxcarrier bytes.
			if(tx.nVersion != GetSyscoinTxVersion() && txout.scriptPubKey.size() > nMaxDatacarrierBytes)
			{
				reason = "scriptpubkey";
				return false;
			}

            nDataOut++;
		}
        else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
            reason = "bare-multisig";
            return false;
        } else if (txout.IsDust(::minRelayTxFee)) {
            reason = "dust";
            return false;
        }
    }

    // only one OP_RETURN txout is permitted
    if (nDataOut > 1) {
        reason = "multi-op-return";
        return false;
    }

    return true;
}

bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
    if (tx.IsCoinBase())
        return true; // Coinbases don't use vin normally

    for (unsigned int i = 0; i < tx.vin.size(); i++)
    {
        const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]);

        std::vector<std::vector<unsigned char> > vSolutions;
        txnouttype whichType;
        // get the scriptPubKey corresponding to this input:
        const CScript& prevScript = prev.scriptPubKey;
        if (!Solver(prevScript, whichType, vSolutions))
            return false;

        if (whichType == TX_SCRIPTHASH)
        {
            std::vector<std::vector<unsigned char> > stack;
            // convert the scriptSig into a stack, so we can inspect the redeemScript
            if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SIGVERSION_BASE))
                return false;
            if (stack.empty())
                return false;
            CScript subscript(stack.back().begin(), stack.back().end());
            if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) {
                return false;
            }
        }
    }

    return true;
}
bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
    if (tx.IsCoinBase())
        return true; // Coinbases are skipped

    for (unsigned int i = 0; i < tx.vin.size(); i++)
    {
        // We don't care if witness for this input is empty, since it must not be bloated.
        // If the script is invalid without witness, it would be caught sooner or later during validation.
        if (tx.wit.vtxinwit[i].IsNull())
            continue;

        const CTxOut &prev = mapInputs.GetOutputFor(tx.vin[i]);

        // get the scriptPubKey corresponding to this input:
        CScript prevScript = prev.scriptPubKey;

        if (prevScript.IsPayToScriptHash()) {
            std::vector <std::vector<unsigned char> > stack;
            // If the scriptPubKey is P2SH, we try to extract the redeemScript casually by converting the scriptSig
            // into a stack. We do not check IsPushOnly nor compare the hash as these will be done later anyway.
            // If the check fails at this stage, we know that this txid must be a bad one.
            if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SIGVERSION_BASE))
                return false;
            if (stack.empty())
                return false;
            prevScript = CScript(stack.back().begin(), stack.back().end());
        }

        int witnessversion = 0;
        std::vector<unsigned char> witnessprogram;

        // Non-witness program must not be associated with any witness
        if (!prevScript.IsWitnessProgram(witnessversion, witnessprogram))
            return false;

        // Check P2WSH standard limits
        if (witnessversion == 0 && witnessprogram.size() == 32) {
            if (tx.wit.vtxinwit[i].scriptWitness.stack.back().size() > MAX_STANDARD_P2WSH_SCRIPT_SIZE)
                return false;
            size_t sizeWitnessStack = tx.wit.vtxinwit[i].scriptWitness.stack.size() - 1;
            if (sizeWitnessStack > MAX_STANDARD_P2WSH_STACK_ITEMS)
                return false;
            for (unsigned int j = 0; j < sizeWitnessStack; j++) {
                if (tx.wit.vtxinwit[i].scriptWitness.stack[j].size() > MAX_STANDARD_P2WSH_STACK_ITEM_SIZE)
                    return false;
            }
        }
    }
    return true;
}
unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;

int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost)
{
    return (std::max(nWeight, nSigOpCost * nBytesPerSigOp) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;
}

int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost)
{
    return GetVirtualTransactionSize(GetTransactionWeight(tx), nSigOpCost);
}
<commit_msg>Revert "fix version check"<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Syscoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

// NOTE: This file is intended to be customised by the end user, and includes only local node policy logic

#include "policy/policy.h"

#include "main.h"
#include "tinyformat.h"
#include "util.h"
#include "utilstrencodings.h"

#include <boost/foreach.hpp>
// SYSCOIN need constant SYSCOIN_TX_VERSION
extern int GetSyscoinTxVersion();
    /**
     * Check transaction inputs to mitigate two
     * potential denial-of-service attacks:
     *
     * 1. scriptSigs with extra data stuffed into them,
     *    not consumed by scriptPubKey (or P2SH script)
     * 2. P2SH scripts with a crazy number of expensive
     *    CHECKSIG/CHECKMULTISIG operations
     *
     * Why bother? To avoid denial-of-service attacks; an attacker
     * can submit a standard HASH... OP_EQUAL transaction,
     * which will get accepted into blocks. The redemption
     * script can be anything; an attacker could use a very
     * expensive-to-check-upon-redemption script like:
     *   DUP CHECKSIG DROP ... repeated 100 times... OP_1
     */

bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool witnessEnabled)
{
    std::vector<std::vector<unsigned char> > vSolutions;
    if (!Solver(scriptPubKey, whichType, vSolutions))
        return false;

    if (whichType == TX_MULTISIG)
    {
        unsigned char m = vSolutions.front()[0];
        unsigned char n = vSolutions.back()[0];
		// Support up to x-of-3 multisig txns as standard
        if (n < 1 || n > 3)
            return false;
        if (m < 1 || m > n)
            return false;
	// SYSCOIN check for size of sys tx, normal tx size is checked in isstandardtx now
    } else if (whichType == TX_NULL_DATA &&
               (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes*75))
          return false;

    else if (!witnessEnabled && (whichType == TX_WITNESS_V0_KEYHASH || whichType == TX_WITNESS_V0_SCRIPTHASH))
        return false;

    return whichType != TX_NONSTANDARD;
}

bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnessEnabled)
{
	// SYSCOIN check for syscoin or bitcoin tx
    if ((tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) && tx.nVersion != GetSyscoinTxVersion()) {
        reason = "version";
        return false;
    }

    // Extremely large transactions with lots of inputs can cost the network
    // almost as much to process as they cost the sender in fees, because
    // computing signature hashes is O(ninputs*txsize). Limiting transactions
    // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks.
    unsigned int sz = GetTransactionWeight(tx);
    if (sz >= MAX_STANDARD_TX_WEIGHT) {
        reason = "tx-size";
        return false;
    }

    BOOST_FOREACH(const CTxIn& txin, tx.vin)
    {
        // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
        // keys (remember the 520 byte limit on redeemScript size). That works
        // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
        // bytes of scriptSig, which we round off to 1650 bytes for some minor
        // future-proofing. That's also enough to spend a 20-of-20
        // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
        // considered standard.
        if (txin.scriptSig.size() > 1650) {
            reason = "scriptsig-size";
            return false;
        }
        if (!txin.scriptSig.IsPushOnly()) {
            reason = "scriptsig-not-pushonly";
            return false;
        }
    }

    unsigned int nDataOut = 0;
    txnouttype whichType;
    BOOST_FOREACH(const CTxOut& txout, tx.vout) {
        if (!::IsStandard(txout.scriptPubKey, whichType, witnessEnabled)) {
            reason = "scriptpubkey";
            return false;
        }

        if (whichType == TX_NULL_DATA)
		{
			// SYSCOIN if not syscoin tx and opreturn size is bigger than maxcarrier bytes, return false
			// we need this because if it is a sys tx then we allow 75x maxcarrier bytes.
			if(tx.nVersion != GetSyscoinTxVersion() && txout.scriptPubKey.size() > nMaxDatacarrierBytes)
			{
				reason = "scriptpubkey";
				return false;
			}

            nDataOut++;
		}
        else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
            reason = "bare-multisig";
            return false;
        } else if (txout.IsDust(::minRelayTxFee)) {
            reason = "dust";
            return false;
        }
    }

    // only one OP_RETURN txout is permitted
    if (nDataOut > 1) {
        reason = "multi-op-return";
        return false;
    }

    return true;
}

bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
    if (tx.IsCoinBase())
        return true; // Coinbases don't use vin normally

    for (unsigned int i = 0; i < tx.vin.size(); i++)
    {
        const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]);

        std::vector<std::vector<unsigned char> > vSolutions;
        txnouttype whichType;
        // get the scriptPubKey corresponding to this input:
        const CScript& prevScript = prev.scriptPubKey;
        if (!Solver(prevScript, whichType, vSolutions))
            return false;

        if (whichType == TX_SCRIPTHASH)
        {
            std::vector<std::vector<unsigned char> > stack;
            // convert the scriptSig into a stack, so we can inspect the redeemScript
            if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SIGVERSION_BASE))
                return false;
            if (stack.empty())
                return false;
            CScript subscript(stack.back().begin(), stack.back().end());
            if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) {
                return false;
            }
        }
    }

    return true;
}
bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
    if (tx.IsCoinBase())
        return true; // Coinbases are skipped

    for (unsigned int i = 0; i < tx.vin.size(); i++)
    {
        // We don't care if witness for this input is empty, since it must not be bloated.
        // If the script is invalid without witness, it would be caught sooner or later during validation.
        if (tx.wit.vtxinwit[i].IsNull())
            continue;

        const CTxOut &prev = mapInputs.GetOutputFor(tx.vin[i]);

        // get the scriptPubKey corresponding to this input:
        CScript prevScript = prev.scriptPubKey;

        if (prevScript.IsPayToScriptHash()) {
            std::vector <std::vector<unsigned char> > stack;
            // If the scriptPubKey is P2SH, we try to extract the redeemScript casually by converting the scriptSig
            // into a stack. We do not check IsPushOnly nor compare the hash as these will be done later anyway.
            // If the check fails at this stage, we know that this txid must be a bad one.
            if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SIGVERSION_BASE))
                return false;
            if (stack.empty())
                return false;
            prevScript = CScript(stack.back().begin(), stack.back().end());
        }

        int witnessversion = 0;
        std::vector<unsigned char> witnessprogram;

        // Non-witness program must not be associated with any witness
        if (!prevScript.IsWitnessProgram(witnessversion, witnessprogram))
            return false;

        // Check P2WSH standard limits
        if (witnessversion == 0 && witnessprogram.size() == 32) {
            if (tx.wit.vtxinwit[i].scriptWitness.stack.back().size() > MAX_STANDARD_P2WSH_SCRIPT_SIZE)
                return false;
            size_t sizeWitnessStack = tx.wit.vtxinwit[i].scriptWitness.stack.size() - 1;
            if (sizeWitnessStack > MAX_STANDARD_P2WSH_STACK_ITEMS)
                return false;
            for (unsigned int j = 0; j < sizeWitnessStack; j++) {
                if (tx.wit.vtxinwit[i].scriptWitness.stack[j].size() > MAX_STANDARD_P2WSH_STACK_ITEM_SIZE)
                    return false;
            }
        }
    }
    return true;
}
unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;

int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost)
{
    return (std::max(nWeight, nSigOpCost * nBytesPerSigOp) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;
}

int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost)
{
    return GetVirtualTransactionSize(GetTransactionWeight(tx), nSigOpCost);
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "findinfiles.h"

#include <coreplugin/editormanager/editormanager.h>

#include <QtCore/QtDebug>
#include <QtCore/QSettings>
#include <QtCore/QDir>
#include <QtCore/QDirIterator>
#include <QtGui/QPushButton>
#include <QtGui/QFileDialog>
#include <QtGui/QHBoxLayout>
#include <QtGui/QVBoxLayout>

using namespace Find;
using namespace TextEditor;

FindInFiles::FindInFiles()
  : m_configWidget(0),
    m_directory(0)
{
}

QString FindInFiles::id() const
{
    return "Files on Disk";
}

QString FindInFiles::displayName() const
{
    return tr("Files on File System");
}

void FindInFiles::findAll(const QString &txt, Find::FindFlags findFlags)
{
    updateComboEntries(m_directory, true);
    BaseFileFind::findAll(txt, findFlags);
}

Utils::FileIterator *FindInFiles::files() const
{
    return new Utils::SubDirFileIterator(QStringList() << QDir::fromNativeSeparators(m_directory->currentText()),
                                         fileNameFilters(),
                                         Core::EditorManager::instance()->defaultTextCodec());
}

QString FindInFiles::label() const
{
    const QStringList &nonEmptyComponents = QDir::cleanPath(
                QFileInfo(QDir::fromNativeSeparators(m_directory->currentText())).absoluteFilePath())
            .split(QLatin1Char('/'), QString::SkipEmptyParts);
    return tr("Directory '%1':").arg(nonEmptyComponents.isEmpty() ? "/" : nonEmptyComponents.last());
}

QString FindInFiles::toolTip() const
{
    // %3 is filled by BaseFileFind::runNewSearch
    return tr("Path: %1\nFilter: %2\n%3")
            .arg(QDir::toNativeSeparators(QFileInfo(m_directory->currentText()).absoluteFilePath()))
            .arg(fileNameFilters().join(QLatin1String(",")));
}

QWidget *FindInFiles::createConfigWidget()
{
    if (!m_configWidget) {
        m_configWidget = new QWidget;
        QGridLayout * const gridLayout = new QGridLayout(m_configWidget);
        gridLayout->setMargin(0);
        m_configWidget->setLayout(gridLayout);

        QLabel *dirLabel = new QLabel(tr("Director&y:"));
        gridLayout->addWidget(dirLabel, 0, 0, Qt::AlignRight);
        m_directory = new QComboBox;
        m_directory->setEditable(true);
        m_directory->setMaxCount(30);
        m_directory->setMinimumContentsLength(10);
        m_directory->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
        m_directory->setInsertPolicy(QComboBox::InsertAtTop);
        m_directory->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
        m_directory->setModel(&m_directoryStrings);
        syncComboWithSettings(m_directory, m_directorySetting);
        dirLabel->setBuddy(m_directory);
        gridLayout->addWidget(m_directory, 0, 1);
        QPushButton *browseButton = new QPushButton(tr("&Browse"));
        gridLayout->addWidget(browseButton, 0, 2);
        connect(browseButton, SIGNAL(clicked()), this, SLOT(openFileBrowser()));

        QLabel * const filePatternLabel = new QLabel(tr("Fi&le pattern:"));
        filePatternLabel->setMinimumWidth(80);
        filePatternLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
        filePatternLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
        QWidget *patternWidget = createPatternWidget();
        filePatternLabel->setBuddy(patternWidget);
        gridLayout->addWidget(filePatternLabel, 1, 0);
        gridLayout->addWidget(patternWidget, 1, 1, 1, 2);
        m_configWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
    }
    return m_configWidget;
}

void FindInFiles::openFileBrowser()
{
    if (!m_directory)
        return;
    QString oldDir = m_directory->currentText();
    if (!QDir(oldDir).exists())
        oldDir.clear();
    QString dir = QFileDialog::getExistingDirectory(m_configWidget,
        tr("Directory to search"), oldDir);
    if (!dir.isEmpty())
        m_directory->setEditText(dir);
}

void FindInFiles::writeSettings(QSettings *settings)
{
    settings->beginGroup("FindInFiles");
    writeCommonSettings(settings);
    settings->setValue("directories", m_directoryStrings.stringList());
    if (m_directory)
        settings->setValue("currentDirectory", m_directory->currentText());
    settings->endGroup();
}

void FindInFiles::readSettings(QSettings *settings)
{
    settings->beginGroup("FindInFiles");
    readCommonSettings(settings, "*.cpp,*.h");
    m_directoryStrings.setStringList(settings->value("directories").toStringList());
    m_directorySetting = settings->value("currentDirectory").toString();
    settings->endGroup();
    syncComboWithSettings(m_directory, m_directorySetting);
}

void FindInFiles::setDirectory(const QString &directory)
{
    syncComboWithSettings(m_directory, directory);
}

<commit_msg>Minor string fix<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "findinfiles.h"

#include <coreplugin/editormanager/editormanager.h>

#include <QtCore/QtDebug>
#include <QtCore/QSettings>
#include <QtCore/QDir>
#include <QtCore/QDirIterator>
#include <QtGui/QPushButton>
#include <QtGui/QFileDialog>
#include <QtGui/QHBoxLayout>
#include <QtGui/QVBoxLayout>

using namespace Find;
using namespace TextEditor;

FindInFiles::FindInFiles()
  : m_configWidget(0),
    m_directory(0)
{
}

QString FindInFiles::id() const
{
    return "Files on Disk";
}

QString FindInFiles::displayName() const
{
    return tr("Files on File System");
}

void FindInFiles::findAll(const QString &txt, Find::FindFlags findFlags)
{
    updateComboEntries(m_directory, true);
    BaseFileFind::findAll(txt, findFlags);
}

Utils::FileIterator *FindInFiles::files() const
{
    return new Utils::SubDirFileIterator(QStringList() << QDir::fromNativeSeparators(m_directory->currentText()),
                                         fileNameFilters(),
                                         Core::EditorManager::instance()->defaultTextCodec());
}

QString FindInFiles::label() const
{
    const QStringList &nonEmptyComponents = QDir::cleanPath(
                QFileInfo(QDir::fromNativeSeparators(m_directory->currentText())).absoluteFilePath())
            .split(QLatin1Char('/'), QString::SkipEmptyParts);
    return tr("Directory '%1':").arg(nonEmptyComponents.isEmpty() ? "/" : nonEmptyComponents.last());
}

QString FindInFiles::toolTip() const
{
    // %3 is filled by BaseFileFind::runNewSearch
    return tr("Path: %1\nFilter: %2\n%3")
            .arg(QDir::toNativeSeparators(QFileInfo(m_directory->currentText()).absoluteFilePath()))
            .arg(fileNameFilters().join(QLatin1String(",")));
}

QWidget *FindInFiles::createConfigWidget()
{
    if (!m_configWidget) {
        m_configWidget = new QWidget;
        QGridLayout * const gridLayout = new QGridLayout(m_configWidget);
        gridLayout->setMargin(0);
        m_configWidget->setLayout(gridLayout);

        QLabel *dirLabel = new QLabel(tr("Director&y:"));
        gridLayout->addWidget(dirLabel, 0, 0, Qt::AlignRight);
        m_directory = new QComboBox;
        m_directory->setEditable(true);
        m_directory->setMaxCount(30);
        m_directory->setMinimumContentsLength(10);
        m_directory->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
        m_directory->setInsertPolicy(QComboBox::InsertAtTop);
        m_directory->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
        m_directory->setModel(&m_directoryStrings);
        syncComboWithSettings(m_directory, m_directorySetting);
        dirLabel->setBuddy(m_directory);
        gridLayout->addWidget(m_directory, 0, 1);
        QPushButton *browseButton = new QPushButton(tr("&Browse..."));
        gridLayout->addWidget(browseButton, 0, 2);
        connect(browseButton, SIGNAL(clicked()), this, SLOT(openFileBrowser()));

        QLabel * const filePatternLabel = new QLabel(tr("Fi&le pattern:"));
        filePatternLabel->setMinimumWidth(80);
        filePatternLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
        filePatternLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
        QWidget *patternWidget = createPatternWidget();
        filePatternLabel->setBuddy(patternWidget);
        gridLayout->addWidget(filePatternLabel, 1, 0);
        gridLayout->addWidget(patternWidget, 1, 1, 1, 2);
        m_configWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
    }
    return m_configWidget;
}

void FindInFiles::openFileBrowser()
{
    if (!m_directory)
        return;
    QString oldDir = m_directory->currentText();
    if (!QDir(oldDir).exists())
        oldDir.clear();
    QString dir = QFileDialog::getExistingDirectory(m_configWidget,
        tr("Directory to search"), oldDir);
    if (!dir.isEmpty())
        m_directory->setEditText(dir);
}

void FindInFiles::writeSettings(QSettings *settings)
{
    settings->beginGroup("FindInFiles");
    writeCommonSettings(settings);
    settings->setValue("directories", m_directoryStrings.stringList());
    if (m_directory)
        settings->setValue("currentDirectory", m_directory->currentText());
    settings->endGroup();
}

void FindInFiles::readSettings(QSettings *settings)
{
    settings->beginGroup("FindInFiles");
    readCommonSettings(settings, "*.cpp,*.h");
    m_directoryStrings.setStringList(settings->value("directories").toStringList());
    m_directorySetting = settings->value("currentDirectory").toString();
    settings->endGroup();
    syncComboWithSettings(m_directory, m_directorySetting);
}

void FindInFiles::setDirectory(const QString &directory)
{
    syncComboWithSettings(m_directory, directory);
}

<|endoftext|>


<commit_before>// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2022 projectchrono.org
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Author: Deniz Tanyildiz, Radu Serban
// =============================================================================
//
// Object drop on SPH terrain
//
// =============================================================================

#include <cstdio>
#include <string>
#include <stdexcept>
#include <iomanip>

#include "chrono/physics/ChSystemNSC.h"
#include "chrono/physics/ChBodyEasy.h"
#include "chrono/utils/ChUtilsGeometry.h"
#include "chrono/utils/ChUtilsInputOutput.h"

#include "chrono_fsi/ChSystemFsi.h"
#include "chrono_fsi/ChVisualizationFsi.h"

#include "chrono_vehicle/ChVehicleModelData.h"

#include "chrono_thirdparty/cxxopts/ChCLI.h"
#include "chrono_thirdparty/filesystem/path.h"

using namespace chrono;
using namespace chrono::fsi;
using namespace chrono::vehicle;

using std::cout;
using std::cin;
using std::endl;

// ===================================================================================================================

#ifdef CHRONO_OPENGL

class SimStats : public opengl::ChOpenGLStats {
  public:
    SimStats(const ChSystemFsi& sysFSI) : ChOpenGLStats(), m_sys(sysFSI) {}
    virtual void GenerateStats(ChSystem& sys) override {
        char buffer[150];
        sprintf(buffer, "TIME:     %.4f s", m_sys.GetSimTime());
        text.Render(buffer, screen.LEFT, screen.TOP - 1 * screen.SPACING, screen.SX, screen.SY);
    }

    const ChSystemFsi& m_sys;
};

class ParticleSelector : public opengl::ChOpenGLParticleCB {
  public:
    ParticleSelector() {}
    virtual bool Render(const ChVector<>& pos) const override { return pos.y() > 0; }
};

#endif

// ===================================================================================================================

std::shared_ptr<chrono::ChBody> CreateSolids(chrono::ChSystemNSC& sys,
                                             chrono::fsi::ChSystemFsi& sysFSI,
                                             const ChVector<>& b_size) {
    // Set common material Properties
    auto mat = chrono_types::make_shared<ChMaterialSurfaceNSC>();
    mat->SetFriction(0.2f);
    mat->SetRestitution(0.05f);

    // Get particle spacing in the simulation
    auto init_spacing = sysFSI.GetInitialSpacing();

    // Create bottom plate
    double factor = 3.0;
    double gxDim = factor * b_size.x();
    double gyDim = factor * b_size.y();
    double gzDim = 0.1;
    double top_z = -3 * init_spacing;

    auto ground = chrono_types::make_shared<ChBodyEasyBox>(gxDim, gyDim, gzDim, 1000, true, true, mat);
    ground->SetPos(ChVector<>(0.0, 0.0, top_z - 0.5 * gzDim));
    ground->SetCollide(true);
    ground->SetBodyFixed(true);
    sys.AddBody(ground);

    // Add BCE markers
    sysFSI.AddBoxBCE(ground, ChVector<>(0.0, 0.0, 0), QUNIT, ChVector<>(gxDim, gyDim, gzDim), 12);

    // Create a falling sphere
    double sphere_radius = 0.25;
    double volume = chrono::utils::CalcSphereVolume(sphere_radius);
    double density = 4000;
    double mass = density * volume;
    ChVector<> sphere_pos = ChVector<>(0.0, 0, b_size.z() + sphere_radius);
    ChVector<> sphere_vel = ChVector<>(0.0, 0.0, 0.0);
    ChVector<> gyration = chrono::utils::CalcSphereGyration(sphere_radius).diagonal();

    auto sphere = chrono_types::make_shared<ChBody>();
    sphere->SetPos(sphere_pos);
    sphere->SetPos_dt(sphere_vel);
    sphere->SetMass(mass);
    sphere->SetInertiaXX(mass * gyration);
    sphere->SetCollide(true);
    sphere->SetBodyFixed(false);
    sphere->GetCollisionModel()->ClearModel();
    chrono::utils::AddSphereGeometry(sphere.get(), mat, sphere_radius, VNULL, QUNIT);
    sphere->GetCollisionModel()->BuildModel();
    sys.AddBody(sphere);

    // Add this body to the FSI system and create BCEs
    sysFSI.AddFsiBody(sphere);
    sysFSI.AddSphereBCE(sphere, ChVector<>(0), ChQuaternion<>(1, 0, 0, 0), sphere_radius);

    return sphere;
}

int main(int argc, char* argv[]) {
    double tend = 30;
    double step_size = 5e-4;
    double output_fps = 120;
    double render_fps = 120;

    bool render = true;
    bool output = true;

    // Create the Chrono systems
    ChSystemNSC sys;
    ChSystemFsi sysFSI(sys);

    const ChVector<> gravity(0, 0, -9.81);
    sysFSI.Set_G_acc(gravity);
    sys.Set_G_acc(gravity);

    // Soil material properties
    double rho = 1700.0;
    double friction = 0.7;
    double cohesion = 1.0e3;

    ChSystemFsi::ElasticMaterialProperties mat_props;
    mat_props.Young_modulus = 1e6;
    mat_props.Poisson_ratio = 0.3;
    mat_props.stress = 0;  // default
    mat_props.viscosity_alpha = 0.5;
    mat_props.viscosity_beta = 0.0;
    mat_props.mu_I0 = 0.03;
    mat_props.mu_fric_s = friction;
    mat_props.mu_fric_2 = friction;
    mat_props.average_diam = 0.005;
    mat_props.friction_angle = CH_C_PI / 10;  // default
    mat_props.dilation_angle = CH_C_PI / 10;  // default
    mat_props.cohesion_coeff = 0;             // default
    mat_props.kernel_threshold = 0.8;

    sysFSI.SetElasticSPH(mat_props);
    sysFSI.SetDensity(rho);
    sysFSI.SetCohesionForce(cohesion);

    double init_spacing = 0.02;
    double kernel_length = 0.03;
    sysFSI.SetInitialSpacing(init_spacing);
    sysFSI.SetKernelLength(kernel_length);

    // Dimension of soil block
    ChVector<> b_size(1.0, 1.0, 0.5);
    sysFSI.SetContainerDim(b_size);
    sysFSI.SetDiscreType(false, false);
    sysFSI.SetWallBC(BceVersion::ADAMI);
    sysFSI.SetRigidBodyBC(BceVersion::ADAMI);
    sysFSI.SetSPHMethod(FluidDynamics::WCSPH);
    sysFSI.SetOutputLength(0);
    sysFSI.SetVerbose(false);

    sysFSI.SetStepSize(step_size);
    sysFSI.SetMaxStepSize(step_size);

    // Set up the periodic boundary condition (if not, set relative larger values)
    sysFSI.SetBoundaries(-3.0 * b_size, +3.0 * b_size);

    // Initialize the SPH particles
    sysFSI.AddBoxSPH(init_spacing, kernel_length, ChVector<>(0.0, 0.0, b_size.z() / 2), b_size / 2);

    // Create bottom plate and dropping sphere with BCE markers
    auto sphere = CreateSolids(sys, sysFSI, b_size);

#ifdef CHRONO_OPENGL
    // Create run-time visualization
    opengl::ChVisualSystemOpenGL vis;
    ChVisualizationFsi visFSI(&sysFSI, &vis);
    visFSI.SetTitle("Object drop test");
    visFSI.SetSize(1280, 720);
    visFSI.SetCameraPosition(ChVector<>(0, -2 * b_size.y(), b_size.z()), ChVector<>(0, 0, b_size.z()));
    visFSI.SetCameraMoveScale(0.02f);
    visFSI.EnableFluidMarkers(true);
    visFSI.EnableRigidBodyMarkers(false);
    visFSI.EnableBoundaryMarkers(false);
    visFSI.SetRenderMode(ChVisualizationFsi::RenderMode::SOLID);

    auto stats = chrono_types::make_shared<SimStats>(sysFSI);
    vis.AttachStatsRenderer(stats);
    vis.EnableStats(true);

    auto sel = chrono_types::make_shared<ParticleSelector>();
    vis.AttachParticleSelector(sel);

    vis.AttachSystem(&sys);
    vis.Initialize();
#endif

    // Output directory
    std::string out_dir = GetChronoOutputPath() + "COHESION_SPH/";
    std::string vis_dir = out_dir + "f" + std::to_string(friction) + "_c" + std::to_string(cohesion) + "/";
    if (!filesystem::create_directory(filesystem::path(out_dir))) {
        cout << "Error creating directory " << out_dir << endl;
        return 1;
    }
    if (!filesystem::create_directory(filesystem::path(vis_dir))) {
        cout << "Error creating directory " << vis_dir << endl;
        return 1;
    }

    // Simulation loop
    int output_steps = (int)std::round((1.0 / output_fps) / step_size);
    int render_steps = (int)std::round((1.0 / render_fps) / step_size);
    int vis_output_frame = 0;

    double t = 0;
    int frame = 0;
    sysFSI.Initialize();
#ifdef CHRONO_OPENGL
    visFSI.Initialize();
#endif

    while (t < tend) {
        // Visualization data output
        if (output && frame % output_steps == 0) {
            sysFSI.PrintParticleToFile(vis_dir);
            vis_output_frame++;
        }

#ifdef CHRONO_OPENGL
        // Run-time visualization
        if (render && frame % render_steps == 0) {
            if (!visFSI.Render())
                break;
        }
#endif

        // Advance both FSI and embedded MBD systems
        sysFSI.DoStepDynamics_FSI();
        t += step_size;

        frame++;
    }

    return 0;
}
<commit_msg>Add output to SPH cohesion test<commit_after>// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2022 projectchrono.org
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Author: Deniz Tanyildiz, Radu Serban
// =============================================================================
//
// Object drop on SPH terrain
//
// =============================================================================

#include <cstdio>
#include <string>
#include <stdexcept>
#include <iomanip>
#include <fstream>

#include "chrono/physics/ChSystemNSC.h"
#include "chrono/physics/ChBodyEasy.h"
#include "chrono/utils/ChUtilsGeometry.h"
#include "chrono/utils/ChUtilsInputOutput.h"

#include "chrono_fsi/ChSystemFsi.h"
#include "chrono_fsi/ChVisualizationFsi.h"

#include "chrono_vehicle/ChVehicleModelData.h"

#include "chrono_thirdparty/cxxopts/ChCLI.h"
#include "chrono_thirdparty/filesystem/path.h"

using namespace chrono;
using namespace chrono::fsi;
using namespace chrono::vehicle;

using std::cout;
using std::cin;
using std::endl;

// ===================================================================================================================

#ifdef CHRONO_OPENGL

class SimStats : public opengl::ChOpenGLStats {
  public:
    SimStats(const ChSystemFsi& sysFSI) : ChOpenGLStats(), m_sys(sysFSI) {}
    virtual void GenerateStats(ChSystem& sys) override {
        char buffer[150];
        sprintf(buffer, "TIME:     %.4f s", m_sys.GetSimTime());
        text.Render(buffer, screen.LEFT, screen.TOP - 1 * screen.SPACING, screen.SX, screen.SY);
    }

    const ChSystemFsi& m_sys;
};

class ParticleSelector : public opengl::ChOpenGLParticleCB {
  public:
    ParticleSelector() {}
    virtual bool Render(const ChVector<>& pos) const override { return pos.y() > 0; }
};

#endif

// ===================================================================================================================

std::shared_ptr<chrono::ChBody> CreateSolids(chrono::ChSystemNSC& sys,
                                             chrono::fsi::ChSystemFsi& sysFSI,
                                             const ChVector<>& b_size) {
    // Set common material Properties
    auto mat = chrono_types::make_shared<ChMaterialSurfaceNSC>();
    mat->SetFriction(0.2f);
    mat->SetRestitution(0.05f);

    // Get particle spacing in the simulation
    auto init_spacing = sysFSI.GetInitialSpacing();

    // Create bottom plate
    double factor = 3.0;
    double gxDim = factor * b_size.x();
    double gyDim = factor * b_size.y();
    double gzDim = 0.1;
    double top_z = -3 * init_spacing;

    auto ground = chrono_types::make_shared<ChBodyEasyBox>(gxDim, gyDim, gzDim, 1000, true, true, mat);
    ground->SetPos(ChVector<>(0.0, 0.0, top_z - 0.5 * gzDim));
    ground->SetCollide(true);
    ground->SetBodyFixed(true);
    sys.AddBody(ground);

    // Add BCE markers
    sysFSI.AddBoxBCE(ground, ChVector<>(0.0, 0.0, 0), QUNIT, ChVector<>(gxDim, gyDim, gzDim), 12);

    // Create a falling sphere
    double sphere_radius = 0.25;
    double volume = chrono::utils::CalcSphereVolume(sphere_radius);
    double density = 4000;
    double mass = density * volume;
    ChVector<> sphere_pos = ChVector<>(0.0, 0, b_size.z() + sphere_radius + 2 * init_spacing);
    ChVector<> sphere_vel = ChVector<>(0.0, 0.0, 0.0);
    ChVector<> gyration = chrono::utils::CalcSphereGyration(sphere_radius).diagonal();

    auto sphere = chrono_types::make_shared<ChBody>();
    sphere->SetPos(sphere_pos);
    sphere->SetPos_dt(sphere_vel);
    sphere->SetMass(mass);
    sphere->SetInertiaXX(mass * gyration);
    sphere->SetCollide(true);
    sphere->SetBodyFixed(false);
    sphere->GetCollisionModel()->ClearModel();
    chrono::utils::AddSphereGeometry(sphere.get(), mat, sphere_radius, VNULL, QUNIT);
    sphere->GetCollisionModel()->BuildModel();
    sys.AddBody(sphere);

    // Add this body to the FSI system and create BCEs
    sysFSI.AddFsiBody(sphere);
    sysFSI.AddSphereBCE(sphere, ChVector<>(0), ChQuaternion<>(1, 0, 0, 0), sphere_radius);

    return sphere;
}

int main(int argc, char* argv[]) {
    double tend = 1.0;
    double step_size = 5e-4;
    double output_fps = 100;
    double render_fps = 50;

    bool render = true;
    bool output = true;

    // Create the Chrono systems
    ChSystemNSC sys;
    ChSystemFsi sysFSI(sys);

    const ChVector<> gravity(0, 0, -9.81);
    sysFSI.Set_G_acc(gravity);
    sys.Set_G_acc(gravity);

    // Soil material properties
    double rho = 1700.0;
    double friction = 0.1;
    double cohesion = 1.0e4;

    ChSystemFsi::ElasticMaterialProperties mat_props;
    mat_props.Young_modulus = 1e6;
    mat_props.Poisson_ratio = 0.3;
    mat_props.stress = 0;  // default
    mat_props.viscosity_alpha = 0.5;
    mat_props.viscosity_beta = 0.0;
    mat_props.mu_I0 = 0.03;
    mat_props.mu_fric_s = friction;
    mat_props.mu_fric_2 = friction;
    mat_props.average_diam = 0.005;
    mat_props.friction_angle = CH_C_PI / 10;  // default
    mat_props.dilation_angle = CH_C_PI / 10;  // default
    mat_props.cohesion_coeff = 0;             // default
    mat_props.kernel_threshold = 0.8;

    sysFSI.SetElasticSPH(mat_props);
    sysFSI.SetDensity(rho);
    sysFSI.SetCohesionForce(cohesion);

    double init_spacing = 0.02;
    double kernel_length = 0.03;
    sysFSI.SetInitialSpacing(init_spacing);
    sysFSI.SetKernelLength(kernel_length);

    // Dimension of soil block
    ChVector<> b_size(1.0, 1.0, 0.5);
    sysFSI.SetContainerDim(b_size);
    sysFSI.SetDiscreType(false, false);
    sysFSI.SetWallBC(BceVersion::ADAMI);
    sysFSI.SetRigidBodyBC(BceVersion::ADAMI);
    sysFSI.SetSPHMethod(FluidDynamics::WCSPH);
    sysFSI.SetOutputLength(0);
    sysFSI.SetVerbose(false);

    sysFSI.SetStepSize(step_size);
    sysFSI.SetMaxStepSize(step_size);

    // Set up the periodic boundary condition (if not, set relative larger values)
    sysFSI.SetBoundaries(-5.0 * b_size, +5.0 * b_size);

    // Initialize the SPH particles
    sysFSI.AddBoxSPH(init_spacing, kernel_length, ChVector<>(0.0, 0.0, b_size.z() / 2), b_size / 2);

    // Create bottom plate and dropping sphere with BCE markers
    auto sphere = CreateSolids(sys, sysFSI, b_size);

#ifdef CHRONO_OPENGL
    // Create run-time visualization
    opengl::ChVisualSystemOpenGL vis;
    ChVisualizationFsi visFSI(&sysFSI, &vis);
    visFSI.SetTitle("Object drop test");
    visFSI.SetSize(1280, 720);
    visFSI.SetCameraPosition(ChVector<>(0, -2 * b_size.y(), b_size.z()), ChVector<>(0, 0, b_size.z()));
    visFSI.SetCameraMoveScale(0.02f);
    visFSI.EnableFluidMarkers(true);
    visFSI.EnableRigidBodyMarkers(false);
    visFSI.EnableBoundaryMarkers(false);
    visFSI.SetRenderMode(ChVisualizationFsi::RenderMode::SOLID);

    auto stats = chrono_types::make_shared<SimStats>(sysFSI);
    vis.AttachStatsRenderer(stats);
    vis.EnableStats(true);

    auto sel = chrono_types::make_shared<ParticleSelector>();
    vis.AttachParticleSelector(sel);

    vis.AttachSystem(&sys);
    vis.Initialize();
#endif

    // Output directory
    std::string out_dir = GetChronoOutputPath() + "COHESION_SPH/";
    std::string vis_dir = out_dir + "f" + std::to_string(friction) + "_c" + std::to_string(cohesion) + "/";
    if (!filesystem::create_directory(filesystem::path(out_dir))) {
        cout << "Error creating directory " << out_dir << endl;
        return 1;
    }
    if (!filesystem::create_directory(filesystem::path(vis_dir))) {
        cout << "Error creating directory " << vis_dir << endl;
        return 1;
    }

    // Simulation loop
    int output_steps = (int)std::round((1.0 / output_fps) / step_size);
    int render_steps = (int)std::round((1.0 / render_fps) / step_size);
    int vis_output_frame = 0;

    double t = 0;
    int frame = 0;
    sysFSI.Initialize();
#ifdef CHRONO_OPENGL
    visFSI.Initialize();
#endif

    while (t < tend) {
        // Visualization data output
        if (output && frame % output_steps == 0) {
            sysFSI.PrintParticleToFile(vis_dir);

            auto psph = sphere->GetPos();
            std::ofstream fsph;
            fsph.open(vis_dir + "sphere" + std::to_string(vis_output_frame) + ".csv");
            fsph << "x, y, z, |U|" << std::endl;
            fsph << psph.x() << ", " << psph.y() << ", " << psph.z() << ", " << sphere->GetPos_dt().Length()
                 << std::endl;
            fsph.close();

            vis_output_frame++;
        }

#ifdef CHRONO_OPENGL
        // Run-time visualization
        if (render && frame % render_steps == 0) {
            if (!visFSI.Render())
                break;
        }
#endif

        // Advance both FSI and embedded MBD systems
        sysFSI.DoStepDynamics_FSI();
        t += step_size;

        frame++;
    }

    return 0;
}
<|endoftext|>


<commit_before>//===-- PPCMachOWriter.cpp - Emit a Mach-O file for the PowerPC backend ---===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Nate Begeman and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a Mach-O writer for the PowerPC backend.  The public
// interface to this file is the createPPCMachOObjectWriterPass function.
//
//===----------------------------------------------------------------------===//

#include "PPCRelocations.h"
#include "PPCTargetMachine.h"
#include "llvm/PassManager.h"
#include "llvm/CodeGen/MachOWriter.h"
#include "llvm/Support/Compiler.h"
using namespace llvm;

namespace {
  class VISIBILITY_HIDDEN PPCMachOWriter : public MachOWriter {
  public:
    PPCMachOWriter(std::ostream &O, PPCTargetMachine &TM) : MachOWriter(O, TM) {
      if (TM.getTargetData()->getPointerSizeInBits() == 64) {
        Header.cputype = MachOHeader::CPU_TYPE_POWERPC64;
      } else {
        Header.cputype = MachOHeader::CPU_TYPE_POWERPC;
      }
      Header.cpusubtype = MachOHeader::CPU_SUBTYPE_POWERPC_ALL;
    }

    virtual void GetTargetRelocation(MachineRelocation &MR, MachOSection &MOS,
                                     unsigned ToIndex);
    virtual MachineRelocation GetJTRelocation(unsigned Offset,
                                              MachineBasicBlock *MBB);

    virtual const char *getPassName() const {
      return "PowerPC Mach-O Writer";
    }

    // Constants for the relocation r_type field.
    // see <mach-o/ppc/reloc.h>
    enum { PPC_RELOC_VANILLA, // generic relocation
           PPC_RELOC_PAIR,    // the second relocation entry of a pair
           PPC_RELOC_BR14,    // 14 bit branch displacement to word address
           PPC_RELOC_BR24,    // 24 bit branch displacement to word address
           PPC_RELOC_HI16,    // a PAIR follows with the low 16 bits
           PPC_RELOC_LO16,    // a PAIR follows with the high 16 bits
           PPC_RELOC_HA16,    // a PAIR follows, which is sign extended to 32b
           PPC_RELOC_LO14     // LO16 with low 2 bits implicitly zero
    };
  };
}

/// addPPCMachOObjectWriterPass - Returns a pass that outputs the generated code
/// as a Mach-O object file.
///
void llvm::addPPCMachOObjectWriterPass(FunctionPassManager &FPM,
                                       std::ostream &O, PPCTargetMachine &TM) {
  PPCMachOWriter *MOW = new PPCMachOWriter(O, TM);
  FPM.add(MOW);
  FPM.add(createPPCCodeEmitterPass(TM, MOW->getMachineCodeEmitter()));
}

/// GetTargetRelocation - For the MachineRelocation MR, convert it to one or
/// more PowerPC MachORelocation(s), add the new relocations to the
/// MachOSection, and rewrite the instruction at the section offset if required
/// by that relocation type.
void PPCMachOWriter::GetTargetRelocation(MachineRelocation &MR,
                                         MachOSection &MOS,
                                         unsigned ToIndex) {
  uint64_t Addr = 0;

  // Keep track of whether or not this is an externally defined relocation.
  bool     isExtern = false;

  // Get the address of whatever it is we're relocating, if possible.
  if (!isExtern)
    Addr = (uintptr_t)MR.getResultPointer();

  switch ((PPC::RelocationType)MR.getRelocationType()) {
  default: assert(0 && "Unknown PPC relocation type!");
  case PPC::reloc_absolute_low_ix:
    assert(0 && "Unhandled PPC relocation type!");
    break;
  case PPC::reloc_vanilla:
    {
      // FIXME: need to handle 64 bit vanilla relocs
      MachORelocation VANILLA(MR.getMachineCodeOffset(), ToIndex, false, 2,
                              isExtern, PPC_RELOC_VANILLA);
      outword(MOS.RelocBuffer, VANILLA.r_address);
      outword(MOS.RelocBuffer, VANILLA.getPackedFields());
    }
    MOS.nreloc += 1;
    fixword(MOS.SectionData, Addr, MR.getMachineCodeOffset());
    break;
  case PPC::reloc_pcrel_bx:
    Addr -= MR.getMachineCodeOffset();
    Addr >>= 2;
    // ??? Addr & 0xFFFFFF;  Possibly this was supposed to be Addr &= 0xFFFFFF ?
    Addr <<= 2;
    Addr |= (MOS.SectionData[MR.getMachineCodeOffset()] << 24);
    fixword(MOS.SectionData, Addr, MR.getMachineCodeOffset());
    break;
  case PPC::reloc_pcrel_bcx:
    Addr -= MR.getMachineCodeOffset();
    Addr &= 0xFFFC;
    fixhalf(MOS.SectionData, Addr, MR.getMachineCodeOffset() + 2);
    break;
  case PPC::reloc_absolute_high:
    {
      MachORelocation HA16(MR.getMachineCodeOffset(), ToIndex, false, 2,
                           isExtern, PPC_RELOC_HA16);
      MachORelocation PAIR(Addr & 0xFFFF, 0xFFFFFF, false, 2, isExtern,
                           PPC_RELOC_PAIR);
      outword(MOS.RelocBuffer, HA16.r_address);
      outword(MOS.RelocBuffer, HA16.getPackedFields());
      outword(MOS.RelocBuffer, PAIR.r_address);
      outword(MOS.RelocBuffer, PAIR.getPackedFields());
    }
    printf("ha16: %x\n", (unsigned)Addr);
    MOS.nreloc += 2;
    Addr += 0x8000;
    fixhalf(MOS.SectionData, Addr >> 16, MR.getMachineCodeOffset() + 2);
    break;
  case PPC::reloc_absolute_low:
    {
      MachORelocation LO16(MR.getMachineCodeOffset(), ToIndex, false, 2,
                           isExtern, PPC_RELOC_LO16);
      MachORelocation PAIR(Addr >> 16, 0xFFFFFF, false, 2, isExtern,
                           PPC_RELOC_PAIR);
      outword(MOS.RelocBuffer, LO16.r_address);
      outword(MOS.RelocBuffer, LO16.getPackedFields());
      outword(MOS.RelocBuffer, PAIR.r_address);
      outword(MOS.RelocBuffer, PAIR.getPackedFields());
    }
    printf("lo16: %x\n", (unsigned)Addr);
    MOS.nreloc += 2;
    fixhalf(MOS.SectionData, Addr, MR.getMachineCodeOffset() + 2);
    break;
  }
}

MachineRelocation PPCMachOWriter::GetJTRelocation(unsigned Offset,
                                                  MachineBasicBlock *MBB) {
  // FIXME: do something about PIC
  return MachineRelocation::getBB(Offset, PPC::reloc_vanilla, MBB);
}

<commit_msg>fix a bug reid noticed<commit_after>//===-- PPCMachOWriter.cpp - Emit a Mach-O file for the PowerPC backend ---===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Nate Begeman and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a Mach-O writer for the PowerPC backend.  The public
// interface to this file is the createPPCMachOObjectWriterPass function.
//
//===----------------------------------------------------------------------===//

#include "PPCRelocations.h"
#include "PPCTargetMachine.h"
#include "llvm/PassManager.h"
#include "llvm/CodeGen/MachOWriter.h"
#include "llvm/Support/Compiler.h"
using namespace llvm;

namespace {
  class VISIBILITY_HIDDEN PPCMachOWriter : public MachOWriter {
  public:
    PPCMachOWriter(std::ostream &O, PPCTargetMachine &TM) : MachOWriter(O, TM) {
      if (TM.getTargetData()->getPointerSizeInBits() == 64) {
        Header.cputype = MachOHeader::CPU_TYPE_POWERPC64;
      } else {
        Header.cputype = MachOHeader::CPU_TYPE_POWERPC;
      }
      Header.cpusubtype = MachOHeader::CPU_SUBTYPE_POWERPC_ALL;
    }

    virtual void GetTargetRelocation(MachineRelocation &MR, MachOSection &MOS,
                                     unsigned ToIndex);
    virtual MachineRelocation GetJTRelocation(unsigned Offset,
                                              MachineBasicBlock *MBB);

    virtual const char *getPassName() const {
      return "PowerPC Mach-O Writer";
    }

    // Constants for the relocation r_type field.
    // see <mach-o/ppc/reloc.h>
    enum { PPC_RELOC_VANILLA, // generic relocation
           PPC_RELOC_PAIR,    // the second relocation entry of a pair
           PPC_RELOC_BR14,    // 14 bit branch displacement to word address
           PPC_RELOC_BR24,    // 24 bit branch displacement to word address
           PPC_RELOC_HI16,    // a PAIR follows with the low 16 bits
           PPC_RELOC_LO16,    // a PAIR follows with the high 16 bits
           PPC_RELOC_HA16,    // a PAIR follows, which is sign extended to 32b
           PPC_RELOC_LO14     // LO16 with low 2 bits implicitly zero
    };
  };
}

/// addPPCMachOObjectWriterPass - Returns a pass that outputs the generated code
/// as a Mach-O object file.
///
void llvm::addPPCMachOObjectWriterPass(FunctionPassManager &FPM,
                                       std::ostream &O, PPCTargetMachine &TM) {
  PPCMachOWriter *MOW = new PPCMachOWriter(O, TM);
  FPM.add(MOW);
  FPM.add(createPPCCodeEmitterPass(TM, MOW->getMachineCodeEmitter()));
}

/// GetTargetRelocation - For the MachineRelocation MR, convert it to one or
/// more PowerPC MachORelocation(s), add the new relocations to the
/// MachOSection, and rewrite the instruction at the section offset if required
/// by that relocation type.
void PPCMachOWriter::GetTargetRelocation(MachineRelocation &MR,
                                         MachOSection &MOS,
                                         unsigned ToIndex) {
  uint64_t Addr = 0;

  // Keep track of whether or not this is an externally defined relocation.
  bool     isExtern = false;

  // Get the address of whatever it is we're relocating, if possible.
  if (!isExtern)
    Addr = (uintptr_t)MR.getResultPointer();

  switch ((PPC::RelocationType)MR.getRelocationType()) {
  default: assert(0 && "Unknown PPC relocation type!");
  case PPC::reloc_absolute_low_ix:
    assert(0 && "Unhandled PPC relocation type!");
    break;
  case PPC::reloc_vanilla:
    {
      // FIXME: need to handle 64 bit vanilla relocs
      MachORelocation VANILLA(MR.getMachineCodeOffset(), ToIndex, false, 2,
                              isExtern, PPC_RELOC_VANILLA);
      outword(MOS.RelocBuffer, VANILLA.r_address);
      outword(MOS.RelocBuffer, VANILLA.getPackedFields());
    }
    MOS.nreloc += 1;
    fixword(MOS.SectionData, Addr, MR.getMachineCodeOffset());
    break;
  case PPC::reloc_pcrel_bx:
    Addr -= MR.getMachineCodeOffset();
    Addr >>= 2;
    Addr &= 0xFFFFFF;
    Addr <<= 2;
    Addr |= (MOS.SectionData[MR.getMachineCodeOffset()] << 24);
    fixword(MOS.SectionData, Addr, MR.getMachineCodeOffset());
    break;
  case PPC::reloc_pcrel_bcx:
    Addr -= MR.getMachineCodeOffset();
    Addr &= 0xFFFC;
    fixhalf(MOS.SectionData, Addr, MR.getMachineCodeOffset() + 2);
    break;
  case PPC::reloc_absolute_high:
    {
      MachORelocation HA16(MR.getMachineCodeOffset(), ToIndex, false, 2,
                           isExtern, PPC_RELOC_HA16);
      MachORelocation PAIR(Addr & 0xFFFF, 0xFFFFFF, false, 2, isExtern,
                           PPC_RELOC_PAIR);
      outword(MOS.RelocBuffer, HA16.r_address);
      outword(MOS.RelocBuffer, HA16.getPackedFields());
      outword(MOS.RelocBuffer, PAIR.r_address);
      outword(MOS.RelocBuffer, PAIR.getPackedFields());
    }
    printf("ha16: %x\n", (unsigned)Addr);
    MOS.nreloc += 2;
    Addr += 0x8000;
    fixhalf(MOS.SectionData, Addr >> 16, MR.getMachineCodeOffset() + 2);
    break;
  case PPC::reloc_absolute_low:
    {
      MachORelocation LO16(MR.getMachineCodeOffset(), ToIndex, false, 2,
                           isExtern, PPC_RELOC_LO16);
      MachORelocation PAIR(Addr >> 16, 0xFFFFFF, false, 2, isExtern,
                           PPC_RELOC_PAIR);
      outword(MOS.RelocBuffer, LO16.r_address);
      outword(MOS.RelocBuffer, LO16.getPackedFields());
      outword(MOS.RelocBuffer, PAIR.r_address);
      outword(MOS.RelocBuffer, PAIR.getPackedFields());
    }
    printf("lo16: %x\n", (unsigned)Addr);
    MOS.nreloc += 2;
    fixhalf(MOS.SectionData, Addr, MR.getMachineCodeOffset() + 2);
    break;
  }
}

MachineRelocation PPCMachOWriter::GetJTRelocation(unsigned Offset,
                                                  MachineBasicBlock *MBB) {
  // FIXME: do something about PIC
  return MachineRelocation::getBB(Offset, PPC::reloc_vanilla, MBB);
}

<|endoftext|>


<commit_before>#include <sys/types.h>
#include <string>

class MultipartParser {
public:
	typedef void (*Callback)(const char *buffer, size_t start, size_t end, void *userData);

private:
	static const char CR     = 13;
	static const char LF     = 10;
	static const char SPACE  = 32;
	static const char HYPHEN = 45;
	static const char COLON  = 58;
	static const char A      = 97;
	static const char Z      = 122;
	static const size_t UNMARKED = (size_t) -1;

	enum State {
		ERROR,
		START,
		START_BOUNDARY,
		HEADER_FIELD_START,
		HEADER_FIELD,
		HEADER_VALUE_START,
		HEADER_VALUE,
		HEADER_VALUE_ALMOST_DONE,
		HEADERS_ALMOST_DONE,
		PART_DATA_START,
		PART_DATA,
		PART_END,
		END
	};

	enum Flags {
		PART_BOUNDARY = 1,
		LAST_BOUNDARY = 2
	};

	std::string boundary;
	char *lookbehind;
	State state;
	int flags;
	size_t index;
	size_t headerFieldMark;
	size_t headerValueMark;
	size_t partDataMark;

	void callback(Callback cb, const char *buffer = NULL, size_t start = UNMARKED, size_t end = UNMARKED) {
		if (start != UNMARKED && start == end) {
			return;
		}
		if (cb != NULL) {
			cb(buffer, start, end, userData);
		}
	}

	void dataCallback(Callback cb, size_t &mark, const char *buffer, size_t i, size_t bufferLen, bool clear) {
		if (mark == UNMARKED) {
			return;
		}

		if (!clear) {
			callback(cb, buffer, mark, bufferLen);
		} else {
			callback(cb, buffer, mark, i);
			mark = UNMARKED;
		}
	}

	char lower(char c) const {
		return c | 0x20;
	}

	bool isBoundaryChar(char c) const {
		const char *current = boundary.c_str();
		const char *end = current + boundary.size();

		while (current < end) {
			if (*current == c) {
				return true;
			}
			current++;
		}
		return false;
	}

	void setError(const char *message) {
		state = ERROR;
	}

public:
	Callback onPartBegin;
	Callback onHeaderField;
	Callback onHeaderValue;
	Callback onPartData;
	Callback onPartEnd;
	Callback onEnd;
	void *userData;

	MultipartParser() {
		lookbehind = NULL;
		reset();
	}

	MultipartParser(const std::string &boundary) {
		lookbehind = NULL;
		setBoundary(boundary);
	}

	~MultipartParser() {
		delete[] lookbehind;
	}

	void reset() {
		delete[] lookbehind;
		state = ERROR;
		lookbehind = NULL;
		flags = 0;
		index = 0;
		headerFieldMark = UNMARKED;
		headerValueMark = UNMARKED;
		partDataMark    = UNMARKED;

		onPartBegin   = NULL;
		onHeaderField = NULL;
		onHeaderValue = NULL;
		onPartData    = NULL;
		onPartEnd     = NULL;
		onEnd         = NULL;
		userData      = NULL;
	}

	void setBoundary(const std::string &boundary) {
		reset();
		this->boundary = "\r\n--" + boundary;
		lookbehind = new char[this->boundary.size() + 8];
		state = START;
	}

	size_t feed(const char *buffer, size_t len) {
		State state         = this->state;
		int flags           = this->flags;
		size_t prevIndex    = this->index;
		size_t index        = this->index;
		size_t boundarySize = boundary.size();
		size_t boundaryEnd  = boundarySize - 1;
		size_t i;
		char c, cl;

		for (i = 0; i < len; i++) {
			c = buffer[i];

			switch (state) {
			case ERROR:
				return i;
			case START:
				index = 0;
				state = START_BOUNDARY;
			case START_BOUNDARY:
				if (index == boundarySize - 2) {
					if (c != CR) {
						return i;
					}
					index++;
					break;
				} else if (index - 1 == boundarySize - 2) {
					if (c != LF) {
						return i;
					}
					index = 0;
					callback(onPartBegin);
					state = HEADER_FIELD_START;
					break;
				}
				if (c != boundary[index + 2]) {
					return i;
				}
				index++;
				break;
			case HEADER_FIELD_START:
				state = HEADER_FIELD;
				headerFieldMark = i;
			case HEADER_FIELD:
				if (c == CR) {
					headerFieldMark = UNMARKED;
					state = HEADERS_ALMOST_DONE;
					break;
				}

				if (c == HYPHEN) {
					break;
				}

				if (c == COLON) {
					dataCallback(onHeaderField, headerFieldMark, buffer, i, len, true);
					state = HEADER_VALUE_START;
					break;
				}

				cl = lower(c);
				if (cl < A || cl > Z) {
					setError("Malformed header name.");
					return i;
				}
				break;
			case HEADER_VALUE_START:
				if (c == SPACE) {
					break;
				}

				headerValueMark = i;
				state = HEADER_VALUE;
			case HEADER_VALUE:
				if (c == CR) {
					dataCallback(onHeaderValue, headerValueMark, buffer, i, len, true);
					state = HEADER_VALUE_ALMOST_DONE;
				}
				break;
			case HEADER_VALUE_ALMOST_DONE:
				if (c != LF) {
					setError("Malformed header value: LF expected after CR");
					return i;
				}

				state = PART_DATA_START;
				break;
			case PART_DATA_START:
				state = PART_DATA;
				partDataMark = i;
			case PART_DATA:
				prevIndex = index;

				if (index == 0) {
					// boyer-moore derrived algorithm to safely skip non-boundary data
					while (i + boundary.size() <= len) {
						if (isBoundaryChar(buffer[i + boundaryEnd])) {
							break;
						}

						i += boundary.size();
					}
					c = buffer[i];
				}

				if (index < boundary.size()) {
					if (boundary[index] == c) {
						if (index == 0) {
							dataCallback(onPartData, partDataMark, buffer, i, len, true);
						}
						index++;
					} else {
						index = 0;
					}
				} else if (index == boundary.size()) {
					index++;
					if (c == CR) {
						// CR = part boundary
						flags |= PART_BOUNDARY;
					} else if (c == HYPHEN) {
						// HYPHEN = end boundary
						flags |= LAST_BOUNDARY;
					} else {
						index = 0;
					}
				} else if (index - 1 == boundary.size()) {
					if (flags & PART_BOUNDARY) {
						index = 0;
						if (c == LF) {
							// unset the PART_BOUNDARY flag
							flags &= ~PART_BOUNDARY;
							callback(onPartEnd);
							callback(onPartBegin);
							state = HEADER_FIELD_START;
							break;
						}
					} else if (flags & LAST_BOUNDARY) {
						if (c == HYPHEN) {
							index++;
						} else {
							index = 0;
						}
					} else {
						index = 0;
					}
				} else if (index - 2 == boundary.size()) {
					if (c == CR) {
						index++;
					} else {
						index = 0;
					}
				} else if (index - boundary.size() == 3) {
					index = 0;
					if (c == LF) {
						callback(onPartEnd);
						callback(onEnd);
						state = END;
						break;
					}
				}

				if (index > 0) {
					// when matching a possible boundary, keep a lookbehind reference
					// in case it turns out to be a false lead
					lookbehind[index - 1] = c;
				} else if (prevIndex > 0) {
					// if our boundary turned out to be rubbish, the captured lookbehind
					// belongs to partData
					callback(onPartData, lookbehind, 0, prevIndex);
					prevIndex = 0;
					partDataMark = i;
				}

				break;
			default:
				return i;
			}
		}

		dataCallback(onHeaderField, headerFieldMark, buffer, i, len, false);
		dataCallback(onHeaderValue, headerValueMark, buffer, i, len, false);
		dataCallback(onPartData, partDataMark, buffer, i, len, false);

		this->index = index;
		this->state = state;
		this->flags = flags;

		return len;
	}

	bool succeeded() const {
		return state == END;
	}

	bool hasError() const {
		return state == ERROR;
	}

	bool stopped() const {
		return state == ERROR || state == END;
	}
};

#include <stdio.h>
using namespace std;

static void
onPartBegin(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onPartBegin\n");
}

static void
onHeaderField(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onHeaderField: (%s)\n", string(buffer + start, end - start).c_str());
}

static void
onHeaderValue(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onHeaderValue: (%s)\n", string(buffer + start, end - start).c_str());
}

static void
onPartData(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onPartData: (%s)\n", string(buffer + start, end - start).c_str());
}

static void
onPartEnd(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onPartEnd\n");
}

static void
onEnd(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onEnd\n");
}

int
main() {
	MultipartParser parser("abcd");
	parser.onPartBegin = onPartBegin;
	parser.onHeaderField = onHeaderField;
	parser.onHeaderValue = onHeaderValue;
	parser.onPartData = onPartData;
	parser.onPartEnd = onPartEnd;
	parser.onEnd = onEnd;

	while (!feof(stdin)) {
		char buf[1024 * 16];
		size_t len = fread(buf, 1, sizeof(buf), stdin);
		size_t fed = 0;
		do {
			size_t ret = parser.feed(buf + fed, len - fed);
			fed += ret;
			printf("accepted %d bytes\n", (int) ret);
		} while (fed < len && !parser.stopped());
	}
	return 0;
}
<commit_msg>Fix a bug and add more error checking.<commit_after>#include <sys/types.h>
#include <string>
#include <stdexcept>

class MultipartParser {
public:
	typedef void (*Callback)(const char *buffer, size_t start, size_t end, void *userData);

private:
	static const char CR     = 13;
	static const char LF     = 10;
	static const char SPACE  = 32;
	static const char HYPHEN = 45;
	static const char COLON  = 58;
	static const char A      = 97;
	static const char Z      = 122;
	static const size_t UNMARKED = (size_t) -1;

	enum State {
		ERROR,
		START,
		START_BOUNDARY,
		HEADER_FIELD_START,
		HEADER_FIELD,
		HEADER_VALUE_START,
		HEADER_VALUE,
		HEADER_VALUE_ALMOST_DONE,
		HEADERS_ALMOST_DONE,
		PART_DATA_START,
		PART_DATA,
		PART_END,
		END
	};

	enum Flags {
		PART_BOUNDARY = 1,
		LAST_BOUNDARY = 2
	};

	std::string boundary;
	char *lookbehind;
	size_t lookbehindSize;
	State state;
	int flags;
	size_t index;
	size_t headerFieldMark;
	size_t headerValueMark;
	size_t partDataMark;

	void callback(Callback cb, const char *buffer = NULL, size_t start = UNMARKED, size_t end = UNMARKED) {
		if (start != UNMARKED && start == end) {
			return;
		}
		if (cb != NULL) {
			cb(buffer, start, end, userData);
		}
	}

	void dataCallback(Callback cb, size_t &mark, const char *buffer, size_t i, size_t bufferLen, bool clear) {
		if (mark == UNMARKED) {
			return;
		}

		if (!clear) {
			callback(cb, buffer, mark, bufferLen);
		} else {
			callback(cb, buffer, mark, i);
			mark = UNMARKED;
		}
	}

	char lower(char c) const {
		return c | 0x20;
	}

	bool isBoundaryChar(char c) const {
		const char *current = boundary.c_str();
		const char *end = current + boundary.size();

		while (current < end) {
			if (*current == c) {
				return true;
			}
			current++;
		}
		return false;
	}

	void setError(const char *message) {
		state = ERROR;
	}

public:
	Callback onPartBegin;
	Callback onHeaderField;
	Callback onHeaderValue;
	Callback onPartData;
	Callback onPartEnd;
	Callback onEnd;
	void *userData;

	MultipartParser() {
		lookbehind = NULL;
		reset();
	}

	MultipartParser(const std::string &boundary) {
		lookbehind = NULL;
		setBoundary(boundary);
	}

	~MultipartParser() {
		delete[] lookbehind;
	}

	void reset() {
		delete[] lookbehind;
		state = ERROR;
		lookbehind = NULL;
		lookbehindSize = 0;
		flags = 0;
		index = 0;
		headerFieldMark = UNMARKED;
		headerValueMark = UNMARKED;
		partDataMark    = UNMARKED;

		onPartBegin   = NULL;
		onHeaderField = NULL;
		onHeaderValue = NULL;
		onPartData    = NULL;
		onPartEnd     = NULL;
		onEnd         = NULL;
		userData      = NULL;
	}

	void setBoundary(const std::string &boundary) {
		reset();
		this->boundary = "\r\n--" + boundary;
		lookbehind = new char[this->boundary.size() + 8];
		lookbehindSize = this->boundary.size() + 8;
		state = START;
	}

	size_t feed(const char *buffer, size_t len) {
		State state         = this->state;
		int flags           = this->flags;
		size_t prevIndex    = this->index;
		size_t index        = this->index;
		size_t boundarySize = boundary.size();
		size_t boundaryEnd  = boundarySize - 1;
		size_t i;
		char c, cl;

		for (i = 0; i < len; i++) {
			c = buffer[i];

			switch (state) {
			case ERROR:
				return i;
			case START:
				index = 0;
				state = START_BOUNDARY;
			case START_BOUNDARY:
				if (index == boundarySize - 2) {
					if (c != CR) {
						return i;
					}
					index++;
					break;
				} else if (index - 1 == boundarySize - 2) {
					if (c != LF) {
						return i;
					}
					index = 0;
					callback(onPartBegin);
					state = HEADER_FIELD_START;
					break;
				}
				if (c != boundary[index + 2]) {
					return i;
				}
				index++;
				break;
			case HEADER_FIELD_START:
				state = HEADER_FIELD;
				headerFieldMark = i;
			case HEADER_FIELD:
				if (c == CR) {
					headerFieldMark = UNMARKED;
					state = HEADERS_ALMOST_DONE;
					break;
				}

				if (c == HYPHEN) {
					break;
				}

				if (c == COLON) {
					dataCallback(onHeaderField, headerFieldMark, buffer, i, len, true);
					state = HEADER_VALUE_START;
					break;
				}

				cl = lower(c);
				if (cl < A || cl > Z) {
					setError("Malformed header name.");
					return i;
				}
				break;
			case HEADER_VALUE_START:
				if (c == SPACE) {
					break;
				}

				headerValueMark = i;
				state = HEADER_VALUE;
			case HEADER_VALUE:
				if (c == CR) {
					dataCallback(onHeaderValue, headerValueMark, buffer, i, len, true);
					state = HEADER_VALUE_ALMOST_DONE;
				}
				break;
			case HEADER_VALUE_ALMOST_DONE:
				if (c != LF) {
					setError("Malformed header value: LF expected after CR");
					return i;
				}

				state = HEADER_FIELD_START;
				break;
			case HEADERS_ALMOST_DONE:
				if (c != LF) {
					setError("Malformed header ending: LF expected after CR");
					return i;
				}

				state = PART_DATA_START;
				break;
			case PART_DATA_START:
				state = PART_DATA;
				partDataMark = i;
			case PART_DATA:
				prevIndex = index;

				if (index == 0) {
					// boyer-moore derrived algorithm to safely skip non-boundary data
					while (i + boundary.size() <= len) {
						if (isBoundaryChar(buffer[i + boundaryEnd])) {
							break;
						}

						i += boundary.size();
					}
					c = buffer[i];
				}

				if (index < boundary.size()) {
					if (boundary[index] == c) {
						if (index == 0) {
							dataCallback(onPartData, partDataMark, buffer, i, len, true);
						}
						index++;
					} else {
						index = 0;
					}
				} else if (index == boundary.size()) {
					index++;
					if (c == CR) {
						// CR = part boundary
						flags |= PART_BOUNDARY;
					} else if (c == HYPHEN) {
						// HYPHEN = end boundary
						flags |= LAST_BOUNDARY;
					} else {
						index = 0;
					}
				} else if (index - 1 == boundary.size()) {
					if (flags & PART_BOUNDARY) {
						index = 0;
						if (c == LF) {
							// unset the PART_BOUNDARY flag
							flags &= ~PART_BOUNDARY;
							callback(onPartEnd);
							callback(onPartBegin);
							state = HEADER_FIELD_START;
							break;
						}
					} else if (flags & LAST_BOUNDARY) {
						if (c == HYPHEN) {
							index++;
						} else {
							index = 0;
						}
					} else {
						index = 0;
					}
				} else if (index - 2 == boundary.size()) {
					if (c == CR) {
						index++;
					} else {
						index = 0;
					}
				} else if (index - boundary.size() == 3) {
					index = 0;
					if (c == LF) {
						callback(onPartEnd);
						callback(onEnd);
						state = END;
						break;
					}
				}

				if (index > 0) {
					// when matching a possible boundary, keep a lookbehind reference
					// in case it turns out to be a false lead
					if (index - 1 >= lookbehindSize) {
						throw std::out_of_range("index overflows lookbehind buffer");
					}
					lookbehind[index - 1] = c;
				} else if (prevIndex > 0) {
					// if our boundary turned out to be rubbish, the captured lookbehind
					// belongs to partData
					callback(onPartData, lookbehind, 0, prevIndex);
					prevIndex = 0;
					partDataMark = i;
				}

				break;
			default:
				return i;
			}
		}

		dataCallback(onHeaderField, headerFieldMark, buffer, i, len, false);
		dataCallback(onHeaderValue, headerValueMark, buffer, i, len, false);
		dataCallback(onPartData, partDataMark, buffer, i, len, false);

		this->index = index;
		this->state = state;
		this->flags = flags;

		return len;
	}

	bool succeeded() const {
		return state == END;
	}

	bool hasError() const {
		return state == ERROR;
	}

	bool stopped() const {
		return state == ERROR || state == END;
	}
};

#include <stdio.h>
using namespace std;

static void
onPartBegin(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onPartBegin\n");
}

static void
onHeaderField(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onHeaderField: (%s)\n", string(buffer + start, end - start).c_str());
}

static void
onHeaderValue(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onHeaderValue: (%s)\n", string(buffer + start, end - start).c_str());
}

static void
onPartData(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onPartData: (%s)\n", string(buffer + start, end - start).c_str());
}

static void
onPartEnd(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onPartEnd\n");
}

static void
onEnd(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onEnd\n");
}

int
main() {
	MultipartParser parser("abcd");
	parser.onPartBegin = onPartBegin;
	parser.onHeaderField = onHeaderField;
	parser.onHeaderValue = onHeaderValue;
	parser.onPartData = onPartData;
	parser.onPartEnd = onPartEnd;
	parser.onEnd = onEnd;

	while (!feof(stdin)) {
		char buf[1024 * 16];
		size_t len = fread(buf, 1, sizeof(buf), stdin);
		size_t fed = 0;
		do {
			size_t ret = parser.feed(buf + fed, len - fed);
			fed += ret;
			printf("accepted %d bytes\n", (int) ret);
		} while (fed < len && !parser.stopped());
	}
	return 0;
}
<|endoftext|>


<commit_before>#include <sys/types.h>
#include <string>
#include <stdexcept>

class MultipartParser {
public:
	typedef void (*Callback)(const char *buffer, size_t start, size_t end, void *userData);

private:
	static const char CR     = 13;
	static const char LF     = 10;
	static const char SPACE  = 32;
	static const char HYPHEN = 45;
	static const char COLON  = 58;
	static const char A      = 97;
	static const char Z      = 122;
	static const size_t UNMARKED = (size_t) -1;

	enum State {
		ERROR,
		START,
		START_BOUNDARY,
		HEADER_FIELD_START,
		HEADER_FIELD,
		HEADER_VALUE_START,
		HEADER_VALUE,
		HEADER_VALUE_ALMOST_DONE,
		HEADERS_ALMOST_DONE,
		PART_DATA_START,
		PART_DATA,
		PART_END,
		END
	};

	enum Flags {
		PART_BOUNDARY = 1,
		LAST_BOUNDARY = 2
	};

	std::string boundary;
	char *lookbehind;
	size_t lookbehindSize;
	State state;
	int flags;
	size_t index;
	size_t headerFieldMark;
	size_t headerValueMark;
	size_t partDataMark;

	void callback(Callback cb, const char *buffer = NULL, size_t start = UNMARKED, size_t end = UNMARKED) {
		if (start != UNMARKED && start == end) {
			return;
		}
		if (cb != NULL) {
			cb(buffer, start, end, userData);
		}
	}

	void dataCallback(Callback cb, size_t &mark, const char *buffer, size_t i, size_t bufferLen, bool clear) {
		if (mark == UNMARKED) {
			return;
		}

		if (!clear) {
			callback(cb, buffer, mark, bufferLen);
		} else {
			callback(cb, buffer, mark, i);
			mark = UNMARKED;
		}
	}

	char lower(char c) const {
		return c | 0x20;
	}

	bool isBoundaryChar(char c) const {
		const char *current = boundary.c_str();
		const char *end = current + boundary.size();

		while (current < end) {
			if (*current == c) {
				return true;
			}
			current++;
		}
		return false;
	}

	void setError(const char *message) {
		state = ERROR;
	}

public:
	Callback onPartBegin;
	Callback onHeaderField;
	Callback onHeaderValue;
	Callback onPartData;
	Callback onPartEnd;
	Callback onEnd;
	void *userData;

	MultipartParser() {
		lookbehind = NULL;
		reset();
	}

	MultipartParser(const std::string &boundary) {
		lookbehind = NULL;
		setBoundary(boundary);
	}

	~MultipartParser() {
		delete[] lookbehind;
	}

	void reset() {
		delete[] lookbehind;
		state = ERROR;
		lookbehind = NULL;
		lookbehindSize = 0;
		flags = 0;
		index = 0;
		headerFieldMark = UNMARKED;
		headerValueMark = UNMARKED;
		partDataMark    = UNMARKED;

		onPartBegin   = NULL;
		onHeaderField = NULL;
		onHeaderValue = NULL;
		onPartData    = NULL;
		onPartEnd     = NULL;
		onEnd         = NULL;
		userData      = NULL;
	}

	void setBoundary(const std::string &boundary) {
		reset();
		this->boundary = "\r\n--" + boundary;
		lookbehind = new char[this->boundary.size() + 8];
		lookbehindSize = this->boundary.size() + 8;
		state = START;
	}

	size_t feed(const char *buffer, size_t len) {
		State state         = this->state;
		int flags           = this->flags;
		size_t prevIndex    = this->index;
		size_t index        = this->index;
		size_t boundarySize = boundary.size();
		size_t boundaryEnd  = boundarySize - 1;
		size_t i;
		char c, cl;

		for (i = 0; i < len; i++) {
			c = buffer[i];

			switch (state) {
			case ERROR:
				return i;
			case START:
				index = 0;
				state = START_BOUNDARY;
			case START_BOUNDARY:
				if (index == boundarySize - 2) {
					if (c != CR) {
						return i;
					}
					index++;
					break;
				} else if (index - 1 == boundarySize - 2) {
					if (c != LF) {
						return i;
					}
					index = 0;
					callback(onPartBegin);
					state = HEADER_FIELD_START;
					break;
				}
				if (c != boundary[index + 2]) {
					return i;
				}
				index++;
				break;
			case HEADER_FIELD_START:
				state = HEADER_FIELD;
				headerFieldMark = i;
			case HEADER_FIELD:
				if (c == CR) {
					headerFieldMark = UNMARKED;
					state = HEADERS_ALMOST_DONE;
					break;
				}

				if (c == HYPHEN) {
					break;
				}

				if (c == COLON) {
					dataCallback(onHeaderField, headerFieldMark, buffer, i, len, true);
					state = HEADER_VALUE_START;
					break;
				}

				cl = lower(c);
				if (cl < A || cl > Z) {
					setError("Malformed header name.");
					return i;
				}
				break;
			case HEADER_VALUE_START:
				if (c == SPACE) {
					break;
				}

				headerValueMark = i;
				state = HEADER_VALUE;
			case HEADER_VALUE:
				if (c == CR) {
					dataCallback(onHeaderValue, headerValueMark, buffer, i, len, true);
					state = HEADER_VALUE_ALMOST_DONE;
				}
				break;
			case HEADER_VALUE_ALMOST_DONE:
				if (c != LF) {
					setError("Malformed header value: LF expected after CR");
					return i;
				}

				state = HEADER_FIELD_START;
				break;
			case HEADERS_ALMOST_DONE:
				if (c != LF) {
					setError("Malformed header ending: LF expected after CR");
					return i;
				}

				state = PART_DATA_START;
				break;
			case PART_DATA_START:
				state = PART_DATA;
				partDataMark = i;
			case PART_DATA:
				prevIndex = index;

				if (index == 0) {
					// boyer-moore derrived algorithm to safely skip non-boundary data
					while (i + boundary.size() <= len) {
						if (isBoundaryChar(buffer[i + boundaryEnd])) {
							break;
						}

						i += boundary.size();
					}
					c = buffer[i];
				}

				if (index < boundary.size()) {
					if (boundary[index] == c) {
						if (index == 0) {
							dataCallback(onPartData, partDataMark, buffer, i, len, true);
						}
						index++;
					} else {
						index = 0;
					}
				} else if (index == boundary.size()) {
					index++;
					if (c == CR) {
						// CR = part boundary
						flags |= PART_BOUNDARY;
					} else if (c == HYPHEN) {
						// HYPHEN = end boundary
						flags |= LAST_BOUNDARY;
					} else {
						index = 0;
					}
				} else if (index - 1 == boundary.size()) {
					if (flags & PART_BOUNDARY) {
						index = 0;
						if (c == LF) {
							// unset the PART_BOUNDARY flag
							flags &= ~PART_BOUNDARY;
							callback(onPartEnd);
							callback(onPartBegin);
							state = HEADER_FIELD_START;
							break;
						}
					} else if (flags & LAST_BOUNDARY) {
						if (c == HYPHEN) {
							index++;
						} else {
							index = 0;
						}
					} else {
						index = 0;
					}
				} else if (index - 2 == boundary.size()) {
					if (c == CR) {
						index++;
					} else {
						index = 0;
					}
				} else if (index - boundary.size() == 3) {
					index = 0;
					if (c == LF) {
						callback(onPartEnd);
						callback(onEnd);
						state = END;
						break;
					}
				}

				if (index > 0) {
					// when matching a possible boundary, keep a lookbehind reference
					// in case it turns out to be a false lead
					if (index - 1 >= lookbehindSize) {
						throw std::out_of_range("index overflows lookbehind buffer");
					}
					lookbehind[index - 1] = c;
				} else if (prevIndex > 0) {
					// if our boundary turned out to be rubbish, the captured lookbehind
					// belongs to partData
					callback(onPartData, lookbehind, 0, prevIndex);
					prevIndex = 0;
					partDataMark = i;
				}

				break;
			default:
				return i;
			}
		}

		dataCallback(onHeaderField, headerFieldMark, buffer, i, len, false);
		dataCallback(onHeaderValue, headerValueMark, buffer, i, len, false);
		dataCallback(onPartData, partDataMark, buffer, i, len, false);

		this->index = index;
		this->state = state;
		this->flags = flags;

		return len;
	}

	bool succeeded() const {
		return state == END;
	}

	bool hasError() const {
		return state == ERROR;
	}

	bool stopped() const {
		return state == ERROR || state == END;
	}
};

#include <stdio.h>
using namespace std;

static void
onPartBegin(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onPartBegin\n");
}

static void
onHeaderField(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onHeaderField: (%s)\n", string(buffer + start, end - start).c_str());
}

static void
onHeaderValue(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onHeaderValue: (%s)\n", string(buffer + start, end - start).c_str());
}

static void
onPartData(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onPartData: (%s)\n", string(buffer + start, end - start).c_str());
}

static void
onPartEnd(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onPartEnd\n");
}

static void
onEnd(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onEnd\n");
}

int
main() {
	MultipartParser parser("abcd");
	parser.onPartBegin = onPartBegin;
	parser.onHeaderField = onHeaderField;
	parser.onHeaderValue = onHeaderValue;
	parser.onPartData = onPartData;
	parser.onPartEnd = onPartEnd;
	parser.onEnd = onEnd;

	while (!feof(stdin)) {
		char buf[1024 * 16];
		size_t len = fread(buf, 1, sizeof(buf), stdin);
		size_t fed = 0;
		do {
			size_t ret = parser.feed(buf + fed, len - fed);
			fed += ret;
			printf("accepted %d bytes\n", (int) ret);
		} while (fed < len && !parser.stopped());
	}
	return 0;
}
<commit_msg>Fix another bug.<commit_after>#include <sys/types.h>
#include <string>
#include <stdexcept>

class MultipartParser {
public:
	typedef void (*Callback)(const char *buffer, size_t start, size_t end, void *userData);

private:
	static const char CR     = 13;
	static const char LF     = 10;
	static const char SPACE  = 32;
	static const char HYPHEN = 45;
	static const char COLON  = 58;
	static const char A      = 97;
	static const char Z      = 122;
	static const size_t UNMARKED = (size_t) -1;

	enum State {
		ERROR,
		START,
		START_BOUNDARY,
		HEADER_FIELD_START,
		HEADER_FIELD,
		HEADER_VALUE_START,
		HEADER_VALUE,
		HEADER_VALUE_ALMOST_DONE,
		HEADERS_ALMOST_DONE,
		PART_DATA_START,
		PART_DATA,
		PART_END,
		END
	};

	enum Flags {
		PART_BOUNDARY = 1,
		LAST_BOUNDARY = 2
	};

	std::string boundary;
	char *lookbehind;
	size_t lookbehindSize;
	State state;
	int flags;
	size_t index;
	size_t headerFieldMark;
	size_t headerValueMark;
	size_t partDataMark;

	void callback(Callback cb, const char *buffer = NULL, size_t start = UNMARKED, size_t end = UNMARKED) {
		if (start != UNMARKED && start == end) {
			return;
		}
		if (cb != NULL) {
			cb(buffer, start, end, userData);
		}
	}

	void dataCallback(Callback cb, size_t &mark, const char *buffer, size_t i, size_t bufferLen, bool clear) {
		if (mark == UNMARKED) {
			return;
		}

		if (!clear) {
			callback(cb, buffer, mark, bufferLen);
			mark = 0;
		} else {
			callback(cb, buffer, mark, i);
			mark = UNMARKED;
		}
	}

	char lower(char c) const {
		return c | 0x20;
	}

	bool isBoundaryChar(char c) const {
		const char *current = boundary.c_str();
		const char *end = current + boundary.size();

		while (current < end) {
			if (*current == c) {
				return true;
			}
			current++;
		}
		return false;
	}

	void setError(const char *message) {
		state = ERROR;
	}

public:
	Callback onPartBegin;
	Callback onHeaderField;
	Callback onHeaderValue;
	Callback onPartData;
	Callback onPartEnd;
	Callback onEnd;
	void *userData;

	MultipartParser() {
		lookbehind = NULL;
		reset();
	}

	MultipartParser(const std::string &boundary) {
		lookbehind = NULL;
		setBoundary(boundary);
	}

	~MultipartParser() {
		delete[] lookbehind;
	}

	void reset() {
		delete[] lookbehind;
		state = ERROR;
		lookbehind = NULL;
		lookbehindSize = 0;
		flags = 0;
		index = 0;
		headerFieldMark = UNMARKED;
		headerValueMark = UNMARKED;
		partDataMark    = UNMARKED;

		onPartBegin   = NULL;
		onHeaderField = NULL;
		onHeaderValue = NULL;
		onPartData    = NULL;
		onPartEnd     = NULL;
		onEnd         = NULL;
		userData      = NULL;
	}

	void setBoundary(const std::string &boundary) {
		reset();
		this->boundary = "\r\n--" + boundary;
		lookbehind = new char[this->boundary.size() + 8];
		lookbehindSize = this->boundary.size() + 8;
		state = START;
	}

	size_t feed(const char *buffer, size_t len) {
		State state         = this->state;
		int flags           = this->flags;
		size_t prevIndex    = this->index;
		size_t index        = this->index;
		size_t boundarySize = boundary.size();
		size_t boundaryEnd  = boundarySize - 1;
		size_t i;
		char c, cl;

		for (i = 0; i < len; i++) {
			c = buffer[i];

			switch (state) {
			case ERROR:
				return i;
			case START:
				index = 0;
				state = START_BOUNDARY;
			case START_BOUNDARY:
				if (index == boundarySize - 2) {
					if (c != CR) {
						return i;
					}
					index++;
					break;
				} else if (index - 1 == boundarySize - 2) {
					if (c != LF) {
						return i;
					}
					index = 0;
					callback(onPartBegin);
					state = HEADER_FIELD_START;
					break;
				}
				if (c != boundary[index + 2]) {
					return i;
				}
				index++;
				break;
			case HEADER_FIELD_START:
				state = HEADER_FIELD;
				headerFieldMark = i;
			case HEADER_FIELD:
				if (c == CR) {
					headerFieldMark = UNMARKED;
					state = HEADERS_ALMOST_DONE;
					break;
				}

				if (c == HYPHEN) {
					break;
				}

				if (c == COLON) {
					dataCallback(onHeaderField, headerFieldMark, buffer, i, len, true);
					state = HEADER_VALUE_START;
					break;
				}

				cl = lower(c);
				if (cl < A || cl > Z) {
					setError("Malformed header name.");
					return i;
				}
				break;
			case HEADER_VALUE_START:
				if (c == SPACE) {
					break;
				}

				headerValueMark = i;
				state = HEADER_VALUE;
			case HEADER_VALUE:
				if (c == CR) {
					dataCallback(onHeaderValue, headerValueMark, buffer, i, len, true);
					state = HEADER_VALUE_ALMOST_DONE;
				}
				break;
			case HEADER_VALUE_ALMOST_DONE:
				if (c != LF) {
					setError("Malformed header value: LF expected after CR");
					return i;
				}

				state = HEADER_FIELD_START;
				break;
			case HEADERS_ALMOST_DONE:
				if (c != LF) {
					setError("Malformed header ending: LF expected after CR");
					return i;
				}

				state = PART_DATA_START;
				break;
			case PART_DATA_START:
				state = PART_DATA;
				partDataMark = i;
			case PART_DATA:
				prevIndex = index;

				if (index == 0) {
					// boyer-moore derrived algorithm to safely skip non-boundary data
					while (i + boundary.size() <= len) {
						if (isBoundaryChar(buffer[i + boundaryEnd])) {
							break;
						}

						i += boundary.size();
					}
					c = buffer[i];
				}

				if (index < boundary.size()) {
					if (boundary[index] == c) {
						if (index == 0) {
							dataCallback(onPartData, partDataMark, buffer, i, len, true);
						}
						index++;
					} else {
						index = 0;
					}
				} else if (index == boundary.size()) {
					index++;
					if (c == CR) {
						// CR = part boundary
						flags |= PART_BOUNDARY;
					} else if (c == HYPHEN) {
						// HYPHEN = end boundary
						flags |= LAST_BOUNDARY;
					} else {
						index = 0;
					}
				} else if (index - 1 == boundary.size()) {
					if (flags & PART_BOUNDARY) {
						index = 0;
						if (c == LF) {
							// unset the PART_BOUNDARY flag
							flags &= ~PART_BOUNDARY;
							callback(onPartEnd);
							callback(onPartBegin);
							state = HEADER_FIELD_START;
							break;
						}
					} else if (flags & LAST_BOUNDARY) {
						if (c == HYPHEN) {
							index++;
						} else {
							index = 0;
						}
					} else {
						index = 0;
					}
				} else if (index - 2 == boundary.size()) {
					if (c == CR) {
						index++;
					} else {
						index = 0;
					}
				} else if (index - boundary.size() == 3) {
					index = 0;
					if (c == LF) {
						callback(onPartEnd);
						callback(onEnd);
						state = END;
						break;
					}
				}

				if (index > 0) {
					// when matching a possible boundary, keep a lookbehind reference
					// in case it turns out to be a false lead
					if (index - 1 >= lookbehindSize) {
						throw std::out_of_range("index overflows lookbehind buffer");
					}
					lookbehind[index - 1] = c;
				} else if (prevIndex > 0) {
					// if our boundary turned out to be rubbish, the captured lookbehind
					// belongs to partData
					callback(onPartData, lookbehind, 0, prevIndex);
					prevIndex = 0;
					partDataMark = i;
				}

				break;
			default:
				return i;
			}
		}

		dataCallback(onHeaderField, headerFieldMark, buffer, i, len, false);
		dataCallback(onHeaderValue, headerValueMark, buffer, i, len, false);
		dataCallback(onPartData, partDataMark, buffer, i, len, false);

		this->index = index;
		this->state = state;
		this->flags = flags;

		return len;
	}

	bool succeeded() const {
		return state == END;
	}

	bool hasError() const {
		return state == ERROR;
	}

	bool stopped() const {
		return state == ERROR || state == END;
	}
};

#include <stdio.h>
using namespace std;

static void
onPartBegin(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onPartBegin\n");
}

static void
onHeaderField(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onHeaderField: (%s)\n", string(buffer + start, end - start).c_str());
}

static void
onHeaderValue(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onHeaderValue: (%s)\n", string(buffer + start, end - start).c_str());
}

static void
onPartData(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onPartData: (%s)\n", string(buffer + start, end - start).c_str());
}

static void
onPartEnd(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onPartEnd\n");
}

static void
onEnd(const char *buffer, size_t start, size_t end, void *userData) {
	printf("onEnd\n");
}

int
main() {
	MultipartParser parser("abcd");
	parser.onPartBegin = onPartBegin;
	parser.onHeaderField = onHeaderField;
	parser.onHeaderValue = onHeaderValue;
	parser.onPartData = onPartData;
	parser.onPartEnd = onPartEnd;
	parser.onEnd = onEnd;

	while (!feof(stdin)) {
		char buf[1024 * 16];
		size_t len = fread(buf, 1, sizeof(buf), stdin);
		size_t fed = 0;
		do {
			size_t ret = parser.feed(buf + fed, len - fed);
			fed += ret;
			printf("accepted %d bytes\n", (int) ret);
		} while (fed < len && !parser.stopped());
	}
	return 0;
}
<|endoftext|>