<commit_before>#include "updatename.h"
#include <QJsonDocument>
#include <QJsonValue>
#include <QJsonObject>

UpdateName::UpdateName(QObject *parent) :
    Twitter(parent)
{
    try {
        myScreenName = twitter.getScreenName();
    } catch(std::runtime_error &e) {
        qCritical() << "screen_nameの取得に失敗しました。: " << e.what();
    }

    try {
        twitter.statusUpdate("update_nameが起動されました。");
    } catch(std::runtime_error &e) {
        qCritical() << "スタートアップメッセージのツイートに失敗しました。: " << e.what();
    }
}

QString UpdateName::lastErrorMessage()
{
    return errorMessage;
}

void UpdateName::exec(const QByteArray twitterStatusObjectJsonData)
{
    QJsonObject statusObject        = QJsonDocument::fromJson(twitterStatusObjectJsonData).object();
    QJsonObject userObject          = statusObject.value("user").toObject();
    QString text                    = statusObject.value("text").toString();
    const QString status_id         = statusObject.value("id_str").toString();
    const QString user_screen_name  = userObject.value("screen_name").toString();
    const QRegExp updateNameRegExp1 = QRegExp(QString("^.*@").append(myScreenName).append("\\s+update_name\\s+.*"));
    const QRegExp updateNameRegExp2 = QRegExp(QString("^\\s*.+\\s*\\(@").append(myScreenName).append("\\).*$"));
    QString newName;

    if(text.isEmpty() || text.startsWith("RT")) {
        return;
    }

    //qDebug() << text;
    //qDebug() << status_id;

    if(updateNameRegExp1.exactMatch(text)) {
        newName = text.remove(QRegExp(QString("^.*@").append(myScreenName).append("\\s+update_name\\s+")));
    } else if(updateNameRegExp2.exactMatch(text)) {
        newName = text.remove(QRegExp(QString("\\s*\\(@").append(myScreenName).append("\\).*$")));
    } else {
        return;
    }

    //qDebug() << newName;

    if(newName.isEmpty()) {
        return;
    } else if(newName.length() > 20) {
        emit stateChanged(Aborted);
        try {
            twitter.statusUpdate(QString(".@").append(user_screen_name).append(" 名前は20文字までですよ。"), status_id);
        } catch(std::runtime_error &e) {
            errorMessage = QString::fromStdString(e.what());
            emit stateChanged(RecieveResultFailed);
            return;
        }
        emit stateChanged(ResultRecieved);
        return;
    }

    try {
        twitter.updateName(newName);
    } catch(std::runtime_error &e) {
        errorMessage = QString::fromStdString(e.what());
        emit stateChanged(NameUpdateFailed);
        try {
            twitter.statusUpdate(QString(".@").append(user_screen_name).append(" update_nameに失敗しました。\n").append(QString::fromStdString(e.what())), status_id);
        } catch(std::runtime_error &e) {
            errorMessage = QString::fromStdString(e.what());
            emit stateChanged(RecieveResultFailed);
            return;
        }
        emit stateChanged(ResultRecieved);
        return;
    }

    emit stateChanged(NameUpdated);

    try {
        twitter.statusUpdate(QString(".@").append(user_screen_name).append(" nameを\"").append(newName).append("\"に変更しました。"), status_id);
    } catch(std::runtime_error &e) {
        emit stateChanged(RecieveResultFailed);
        errorMessage = QString::fromStdString(e.what());
        return;
    }
    emit stateChanged(ResultRecieved);
}
<commit_msg>結果のツイートのバグの修正<commit_after>#include "updatename.h"
#include <QJsonDocument>
#include <QJsonValue>
#include <QJsonObject>

UpdateName::UpdateName(QObject *parent) :
    Twitter(parent)
{
    try {
        myScreenName = twitter.getScreenName();
    } catch(std::runtime_error &e) {
        qCritical() << "screen_nameの取得に失敗しました。: " << e.what();
    }

    try {
        twitter.statusUpdate("update_nameが起動されました。");
    } catch(std::runtime_error &e) {
        qCritical() << "スタートアップメッセージのツイートに失敗しました。: " << e.what();
    }
}

QString UpdateName::lastErrorMessage()
{
    return errorMessage;
}

void UpdateName::exec(const QByteArray twitterStatusObjectJsonData)
{
    QJsonObject statusObject        = QJsonDocument::fromJson(twitterStatusObjectJsonData).object();
    QJsonObject userObject          = statusObject.value("user").toObject();
    QString text                    = statusObject.value("text").toString();
    const QString status_id         = statusObject.value("id_str").toString();
    const QString user_screen_name  = userObject.value("screen_name").toString();
    const QRegExp updateNameRegExp1 = QRegExp(QString("^.*@").append(myScreenName).append("\\s+update_name\\s+.*"));
    const QRegExp updateNameRegExp2 = QRegExp(QString("^\\s*.+\\s*\\(@").append(myScreenName).append("\\).*$"));
    QString newName;
    QString updatedName;

    if(text.isEmpty() || text.startsWith("RT")) {
        return;
    }

    //qDebug() << text;
    //qDebug() << status_id;

    if(updateNameRegExp1.exactMatch(text)) {
        newName = text.remove(QRegExp(QString("^.*@").append(myScreenName).append("\\s+update_name\\s+")));
    } else if(updateNameRegExp2.exactMatch(text)) {
        newName = text.remove(QRegExp(QString("\\s*\\(@").append(myScreenName).append("\\).*$")));
    } else {
        return;
    }

    //qDebug() << newName;

    if(newName.isEmpty()) {
        return;
    } else if(newName.length() > 20) {
        emit stateChanged(Aborted);
        try {
            twitter.statusUpdate(QString(".@").append(user_screen_name).append(" 名前は20文字までですよ。"), status_id);
        } catch(std::runtime_error &e) {
            errorMessage = QString::fromStdString(e.what());
            emit stateChanged(RecieveResultFailed);
            return;
        }
        emit stateChanged(ResultRecieved);
        return;
    }

    try {
        twitter.updateName(newName);
    } catch(std::runtime_error &e) {
        errorMessage = QString::fromStdString(e.what());
        emit stateChanged(NameUpdateFailed);
        try {
            twitter.statusUpdate(QString(".@").append(user_screen_name).append(" update_nameに失敗しました。\n").append(QString::fromStdString(e.what())), status_id);
        } catch(std::runtime_error &e) {
            errorMessage = QString::fromStdString(e.what());
            emit stateChanged(RecieveResultFailed);
            return;
        }
        emit stateChanged(ResultRecieved);
        return;
    }

    emit stateChanged(NameUpdated);

    try {
        updatedName = twitter.getName();
    } catch(...) {
        updatedName = newName;
    }

    try {
        twitter.statusUpdate(QString(".@").append(user_screen_name).append(" nameを\"").append(updatedName).append("\"に変更しました。"), status_id);
    } catch(std::runtime_error &e) {
        emit stateChanged(RecieveResultFailed);
        errorMessage = QString::fromStdString(e.what());
        return;
    }
    emit stateChanged(ResultRecieved);
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <iomanip>
#include <iostream>
#include <ostream>
#include <sstream>
#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkSubtractImageFilter.h"
#include "itkBinaryDilateImageFilter.h"
#include "itkBinaryBallStructuringElement.h"
#include "antsUtilities.h"
#include "itkMaskImageFilter.h"
#include "itkConnectedComponentImageFilter.h"

namespace ants
{
template <unsigned int ImageDimension>
int LesionFilling( int argc, char * argv[] )
{
  typedef int                                   LesionType;
  typedef itk::Image<LesionType, ImageDimension> LesionImageType;
  typedef itk::ImageFileReader<LesionImageType>  LesionReaderType;

  typedef int                                   T1Type;
  typedef itk::Image<LesionType, ImageDimension> T1ImageType;
  typedef itk::ImageFileReader<LesionImageType>  T1ReaderType;

  typedef double           RealPixelType;  //  Operations

  const int * ImageDimension = argv[1];
  const char * method = argv[2];
  const char * LesionMapFileName = argv[3];
  if (method == "-neighbourVoxels")
  {
         const char * T1FileName = argv[4]
  }
  else
  {
         const char * WMFileName = argv[4]
         const char * T1FileName = argv[5]
  }

  typename LesionReaderType::Pointer LesionReader = LesionReaderType::New();
  LesionReader->SetFileName( LesionMapFileName );
  LesionReader->Update();

  if (method == "-neighbourVoxels")
  {
         typedef itk::BinaryBallStructuringElement<
                             InputPixelType,
                             Dimension  >             StructuringElementType;
         //Neighbouring voxel
         //filling lesions with the voxels surrounding them
         //first finding the edges of lesions
         //by subtracting dilated lesion map from lesion map itself
         typedef itk::BinaryDilateImageFilter<
                                   InputImageType,
                                   OutputImageType,
                                   StructuringElementType >  DilateFilterType;
         DilateFilterType::Pointer binaryDilate = DilateFilterType::New();
         structuringElement.SetRadius( 1 );  // 3x3 structuring element
         structuringElement.CreateStructuringElement();
         binaryDilate->SetKernel( structuringElement );
         typedef itk::CastImageFilter< LesionImageType, RealImageType>
                                                                CastToRealFilterType;
         CastToRealFilterType::Pointer toReal = CastToRealFilterType::New();
         toReal->SetInput( LesionReader->GetOutput() );
         binaryDilate->SetInput( toReal->GetOutput() );
         binaryDilate->SetDilateValue( 1 );
         // subtract dilated image form non-dilated one
         typedef itk::SubtractImageFilter <ImageType, ImageType >
                     SubtractImageFilterType;
         SubtractImageFilterType::Pointer subtractFilter
                       = SubtractImageFilterType::New ();
         //output = image1 - image2
         subtractFilter->SetInput1(toReal->GetOutput() );
         subtractFilter->SetInput2(binaryDilate->GetOutput());
         subtractFilter->Update();
         //multiply the outer lesion mask with T1 to get only the neighbouring voxels
         typedef itk::MaskImageFilter< ImageType, ImageType > MaskFilterType;
         MaskFilterType::Pointer maskFilter = MaskFilterType::New();
         maskFilter->SetInput( toReal->GetOutput() );
         maskFilter->SetMaskImage( subtractFilter->GetOutput() );
         //replacing lesions with extracted

  }

  /* LesionFilling d -neighbourVoxels binaryLeisonMap T1
   * LesionFilling d -mean binaryLesionMap AtroposWM T1
   * LesionFilling d -median binaryLesionmap AtroposWM T1
   * LesionFilling d -randomSample binaryLesionMap AtroposWM T1
   */
<commit_msg>connected components, each lesion a component<commit_after>#include <algorithm>
#include <iomanip>
#include <iostream>
#include <ostream>
#include <sstream>
#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkSubtractImageFilter.h"
#include "itkBinaryDilateImageFilter.h"
#include "itkBinaryBallStructuringElement.h"
#include "antsUtilities.h"
#include "itkMaskImageFilter.h"
#include "itkConnectedComponentImageFilter.h"

namespace ants
{
template <unsigned int ImageDimension>
int LesionFilling( int argc, char * argv[] )
{
  typedef int                                   LesionType;
  typedef itk::Image<LesionType, ImageDimension> LesionImageType;
  typedef itk::ImageFileReader<LesionImageType>  LesionReaderType;

  typedef int                                   T1Type;
  typedef itk::Image<LesionType, ImageDimension> T1ImageType;
  typedef itk::ImageFileReader<LesionImageType>  T1ReaderType;

  typedef double           RealPixelType;  //  Operations

  const int * ImageDimension = argv[1];
  const char * method = argv[2];
  const char * LesionMapFileName = argv[3];
  if (method == "-neighbourVoxels")
  {
         const char * T1FileName = argv[4]
  }
  else
  {
         const char * WMFileName = argv[4]
         const char * T1FileName = argv[5]
  }

  typename LesionReaderType::Pointer LesionReader = LesionReaderType::New();
  LesionReader->SetFileName( LesionMapFileName );
  LesionReader->Update();

  if (method == "-neighbourVoxels")
  {

         //finding connected components, we assume each component is one lesion
         typedef itk::ConnectedComponentImageFilter <LesionImageType, LesionImageType>
                     ConnectedComponentImageFilterType;
         ConnectedComponentImageFilterType::Pointer connected =
                     ConnectedComponentImageFilterType::New ();

         typedef itk::BinaryBallStructuringElement<
                             InputPixelType,
                             Dimension  >             StructuringElementType;
         //Neighbouring voxel
         //filling lesions with the voxels surrounding them
         //first finding the edges of lesions
         //by subtracting dilated lesion map from lesion map itself
         typedef itk::BinaryDilateImageFilter<
                                   LesionImageType,
                                   LesionImageType,
                                   StructuringElementType >  DilateFilterType;
         DilateFilterType::Pointer binaryDilate = DilateFilterType::New();
         structuringElement.SetRadius( 1 );  // 3x3 structuring element
         structuringElement.CreateStructuringElement();
         binaryDilate->SetKernel( structuringElement );
         typedef itk::CastImageFilter< LesionImageType, RealImageType>
                                                                CastToRealFilterType;
         CastToRealFilterType::Pointer toReal = CastToRealFilterType::New();
         toReal->SetInput( LesionReader->GetOutput() );
         binaryDilate->SetInput( toReal->GetOutput() );
         binaryDilate->SetDilateValue( 1 );
         // subtract dilated image form non-dilated one
         typedef itk::SubtractImageFilter <ImageType, ImageType >
                     SubtractImageFilterType;
         SubtractImageFilterType::Pointer subtractFilter
                       = SubtractImageFilterType::New ();
         //output = image1 - image2
         subtractFilter->SetInput1(toReal->GetOutput() );
         subtractFilter->SetInput2(binaryDilate->GetOutput());
         subtractFilter->Update();
         //multiply the outer lesion mask with T1 to get only the neighbouring voxels
         typedef itk::MaskImageFilter< ImageType, ImageType > MaskFilterType;
         MaskFilterType::Pointer maskFilter = MaskFilterType::New();
         maskFilter->SetInput( toReal->GetOutput() );
         maskFilter->SetMaskImage( subtractFilter->GetOutput() );
         //replacing lesions with extracted

  }

  /* LesionFilling d -neighbourVoxels binaryLeisonMap T1
   * LesionFilling d -mean binaryLesionMap AtroposWM T1
   * LesionFilling d -median binaryLesionmap AtroposWM T1
   * LesionFilling d -randomSample binaryLesionMap AtroposWM T1
   */
<|endoftext|>


<commit_before>#include "stdafx.h"

#include "BST.h"

using namespace BST;

template <class K, class T>
void Tree<K,T>::insert(K id, T data)
{
	Node<K, T>* tmp = new Node<K, T>;
	tmp->key = data;
	tmp->id = id;
	tmp->left = nullptr;
	tmp->right = nullptr;

	if (this->empty())
	{
		tmp->parent = nullptr;
		this->_root = tmp;
	}
	else {
		Node<K, T>* cElem = this->_root;
		Node<K, T>* parent = nullptr;

		while (cElem != nullptr)
		{
			parent = cElem;
			cElem = (tmp->id < cElem->id) ? cElem->left : cElem->right;
		}

		tmp->parent = parent;

		if (tmp->id < parent->id)
			parent->left = tmp;
		else
			parent->right = tmp;
	}
	_size++;
}
template<class K, class T>
size_t BST::Tree<K, T>::size() const
{
	return _size;
}
;

template <class K, class T>
void Tree<K, T>::deleteNode(K id)
{
	if (!this->empty())
		this->deleteNode(this->findElem(id));
	else
		std::cout << "Tree is empty!" << std::endl;
};

template<class K, class T>
std::vector<T> BST::Tree<K, T>::prepare()
{
	std::vector<T> temp;
	//   ,
	if (_root != nullptr)
	{
		prepare(_root, temp);
		return temp;
	}
	return std::vector<T>();
};

template<class K, class T>
Tree<K, T> BST::Tree<K, T>::operator=(const Tree<K, T>& root)
{
	if (this != &root)
	{
		this->_root = root._root;
		if (root._root->left != nullptr)
			this->copy(root._root->left);
		if (root._root->right != nullptr)
			this->copy(root._root->right);
	}
	return *this;
};

template <class K, class T>
void Tree<K, T>::cleanup()
{
	if (!this->empty())
	{
		cleanup(this->_root);
		this->_root = nullptr;
	}
};

template <class K, class T>
Node<K, T> * Tree<K, T>::findElem(K id)
{
	if (!this->empty())
		return this->findElem(id, this->_root);
	else
	{
		std::cout << "Tree is empty!" << std::endl;
		return nullptr;
	}
}

template<class K, class T>
bool BST::Tree<K, T>::empty()
{
	return this->_root == nullptr;
}

template <class K, class T>
void Tree<K, T>::deleteNode(Node<K, T>* p)
{
	Node<K, T> *q = nullptr;
	Node<K, T> *r = nullptr;

	if (p->left == nullptr || p->right == nullptr)
		q = p;
	else
		q = this->findSuccessor(p->id);

	if (q->left != nullptr)
		r = q->left;
	else
		r = q->right;

	if (r != nullptr)
		r->parent = q->parent;

	if (q->parent == nullptr)
		this->_root = r;
	else if (q == q->parent->left)
		q->parent->left = r;
	else
		q->parent->right = r;

	if (q != p)
	{
		p->key = q->key;
		p->id = q->id;
	}
};

template <class K, class T>
void Tree<K, T>::show(Node<K, T> * node)
{
	if (node != nullptr)
	{
		if (node->right)
			show(node->right);

		std::cout << node->key << std::endl;

		if (node->left)
			show(node->left);
	}
}
template<class K, class T>
void BST::Tree<K, T>::fshow(Node<K, T>* node, std::fstream& stream)
{
	if (node != nullptr)
	{
		if (node->right)
			fshow(node->right, stream);

		stream << node->id << node->key;

		if (node->left)
			fshow(node->left, stream);
	}
}
;

template <class K, class T>
Node<K, T> * Tree<K, T>::findSuccessor(K id)
{
	Node<K, T>* startNode = this->findElem(id);
	Node<K, T>* parent = startNode;

	startNode = startNode->right;
	while (startNode != nullptr && startNode->left != nullptr)
	{
		parent = startNode;
		startNode = startNode->left;
	}

	return startNode;
};

template <class K, class T>
Node<K, T> * Tree<K, T>::findElem(K id, Node<K, T> * node)
{
	if (node != nullptr)
	{
		if (id == node->id)
			return node;

		if (id < node->id)
			return findElem(id, node->left);
		else
			return findElem(id, node->right);
	}
	else
		return nullptr;
};

template<class K, class T>
void BST::Tree<K, T>::copy(Node<K, T> * node)
{
	if (node != nullptr)
	{
		if (node->left)
			this->copy(node->left);

		this->insert(node->id, node->key);

		if (node->right)
			this->copy(node->right);
	}
};

template<class K, class T>
void BST::Tree<K, T>::prepare(Node<K, T>* node, std::vector<T>& temp) const
{
	if (node != nullptr)
	{
		if (node->left)
			prepare(node->left, temp);

		temp.push_back(std::move(node->key));

		if (node->right != nullptr)
			prepare(node->right, temp);
	}
};

template <class K, class T>
void Tree<K, T>::cleanup(Node<K, T> * node)
{
	if (node != nullptr)
	{
		cleanup(node->left);
		cleanup(node->right);
		delete node;
	}
};

template<class K, class T>
Node<K, T> * BST::Tree<K, T>::min(Node<K, T> * rootNode) const
{
	Node<K, T> * node = rootNode;
	while (node->left != nullptr)
		node = node->left;

	return node;
};

template<class K, class T>
Node<K, T>* BST::Tree<K, T>::max(Node<K, T> *rootNode) const
{
	Node<K, T> *node = rootNode;
	while (node->right != nullptr)
		node = node->right;

	return node;
};

template<class K, class T>
TreeIterator<K, T> BST::Tree<K, T>::begin() const
{
	return TreeIterator<K, T>(*this);
}
template<class K, class T>
TreeIterator<K, T> BST::Tree<K, T>::end() const
{
	return TreeIterator<K, T>(*this, END_ITER);
}
;
template<class K, class T>
bool BST::TreeIterator<K, T>::operator==(TreeIterator & another)
{
	if (cursor != nullptr && another.cursor != nullptr)
		return this->cursor->key == another.cursor->key;
	return this->cursor == another.cursor;
}

template<class K, class T>
bool BST::TreeIterator<K, T>::operator!=(TreeIterator & another)
{
	return !(this->operator==(another));
}

template<class K, class T>
BST::TreeIterator<K, T> BST::TreeIterator<K, T>::operator++()
{
	if (cursor == nullptr)
		;
	else if (cursor->right != nullptr)
		cursor = collection->min(cursor->right);
	else
	{
		Node<K, T> * tempNode = cursor->parent;
		while (tempNode != nullptr &&
			   cursor == tempNode->right)
		{
			cursor = tempNode;
			tempNode = tempNode->parent;
		}
		if (cursor->right != tempNode)
			cursor = tempNode;
	}
	return *this;
}

template<class K, class T>
BST::TreeIterator<K, T> BST::TreeIterator<K, T>::operator++(int)
{
	TreeIterator<K, T> old = *this;
	++(*this);
	return old;
}

template<class K, class T>
BST::TreeIterator<K, T> BST::TreeIterator<K, T>::operator--()
{
	if (cursor == nullptr)
		cursor = collection->max(collection->_root);
	else if (cursor->left != nullptr)
		cursor = collection->max(cursor->left);
	else
	{
		Node<K, T> * tempNode;
		while ((tempNode = cursor->parent) != nullptr
			&& cursor == tempNode->left)
			cursor = tempNode;
		if (cursor == nullptr)
			;
		else
			cursor = tempNode;
	}

	return *this;
}

template<class K, class T>
BST::TreeIterator<K, T> BST::TreeIterator<K, T>::operator--(int)
{
	TreeIterator<K, T> old = *this;
	--(*this);
	return old;
}

template<class K, class T>
std::pair<K, T> BST::TreeIterator<K, T>::operator*()
{
	if (cursor != nullptr)
		return std::pair<K, T>(cursor->id, cursor->key);
	return std::pair<K, T>();
}<commit_msg>Missing size reduction added<commit_after>#include "stdafx.h"

#include "BST.h"

using namespace BST;

template <class K, class T>
void Tree<K,T>::insert(K id, T data)
{
	Node<K, T>* tmp = new Node<K, T>;
	tmp->key = data;
	tmp->id = id;
	tmp->left = nullptr;
	tmp->right = nullptr;

	if (this->empty())
	{
		tmp->parent = nullptr;
		this->_root = tmp;
	}
	else {
		Node<K, T>* cElem = this->_root;
		Node<K, T>* parent = nullptr;

		while (cElem != nullptr)
		{
			parent = cElem;
			cElem = (tmp->id < cElem->id) ? cElem->left : cElem->right;
		}

		tmp->parent = parent;

		if (tmp->id < parent->id)
			parent->left = tmp;
		else
			parent->right = tmp;
	}
	_size++;
}
template<class K, class T>
size_t BST::Tree<K, T>::size() const
{
	return _size;
}
;

template <class K, class T>
void Tree<K, T>::deleteNode(K id)
{
	if (!this->empty())
		this->deleteNode(this->findElem(id));
	else
		std::cout << "Tree is empty!" << std::endl;
};

template<class K, class T>
std::vector<T> BST::Tree<K, T>::prepare()
{
	std::vector<T> temp;
	//   ,
	if (_root != nullptr)
	{
		prepare(_root, temp);
		return temp;
	}
	return std::vector<T>();
};

template<class K, class T>
Tree<K, T> BST::Tree<K, T>::operator=(const Tree<K, T>& root)
{
	if (this != &root)
	{
		this->_root = root._root;
		if (root._root->left != nullptr)
			this->copy(root._root->left);
		if (root._root->right != nullptr)
			this->copy(root._root->right);
	}
	return *this;
};

template <class K, class T>
void Tree<K, T>::cleanup()
{
	if (!this->empty())
	{
		cleanup(this->_root);
		this->_root = nullptr;
	}
};

template <class K, class T>
Node<K, T> * Tree<K, T>::findElem(K id)
{
	if (!this->empty())
		return this->findElem(id, this->_root);
	else
	{
		std::cout << "Tree is empty!" << std::endl;
		return nullptr;
	}
}

template<class K, class T>
bool BST::Tree<K, T>::empty()
{
	return this->_root == nullptr;
}

template <class K, class T>
void Tree<K, T>::deleteNode(Node<K, T>* p)
{
	Node<K, T> *q = nullptr;
	Node<K, T> *r = nullptr;

	if (p->left == nullptr || p->right == nullptr)
		q = p;
	else
		q = this->findSuccessor(p->id);

	if (q->left != nullptr)
		r = q->left;
	else
		r = q->right;

	if (r != nullptr)
		r->parent = q->parent;

	if (q->parent == nullptr)
		this->_root = r;
	else if (q == q->parent->left)
		q->parent->left = r;
	else
		q->parent->right = r;

	if (q != p)
	{
		p->key = q->key;
		p->id = q->id;
	}

	_size--;
};

template <class K, class T>
void Tree<K, T>::show(Node<K, T> * node)
{
	if (node != nullptr)
	{
		if (node->right)
			show(node->right);

		std::cout << node->key << std::endl;

		if (node->left)
			show(node->left);
	}
}
template<class K, class T>
void BST::Tree<K, T>::fshow(Node<K, T>* node, std::fstream& stream)
{
	if (node != nullptr)
	{
		if (node->right)
			fshow(node->right, stream);

		stream << node->id << node->key;

		if (node->left)
			fshow(node->left, stream);
	}
}
;

template <class K, class T>
Node<K, T> * Tree<K, T>::findSuccessor(K id)
{
	Node<K, T>* startNode = this->findElem(id);
	Node<K, T>* parent = startNode;

	startNode = startNode->right;
	while (startNode != nullptr && startNode->left != nullptr)
	{
		parent = startNode;
		startNode = startNode->left;
	}

	return startNode;
};

template <class K, class T>
Node<K, T> * Tree<K, T>::findElem(K id, Node<K, T> * node)
{
	if (node != nullptr)
	{
		if (id == node->id)
			return node;

		if (id < node->id)
			return findElem(id, node->left);
		else
			return findElem(id, node->right);
	}
	else
		return nullptr;
};

template<class K, class T>
void BST::Tree<K, T>::copy(Node<K, T> * node)
{
	if (node != nullptr)
	{
		if (node->left)
			this->copy(node->left);

		this->insert(node->id, node->key);

		if (node->right)
			this->copy(node->right);
	}
};

template<class K, class T>
void BST::Tree<K, T>::prepare(Node<K, T>* node, std::vector<T>& temp) const
{
	if (node != nullptr)
	{
		if (node->left)
			prepare(node->left, temp);

		temp.push_back(std::move(node->key));

		if (node->right != nullptr)
			prepare(node->right, temp);
	}
};

template <class K, class T>
void Tree<K, T>::cleanup(Node<K, T> * node)
{
	if (node != nullptr)
	{
		cleanup(node->left);
		cleanup(node->right);
		delete node;
	}
};

template<class K, class T>
Node<K, T> * BST::Tree<K, T>::min(Node<K, T> * rootNode) const
{
	Node<K, T> * node = rootNode;
	while (node->left != nullptr)
		node = node->left;

	return node;
};

template<class K, class T>
Node<K, T>* BST::Tree<K, T>::max(Node<K, T> *rootNode) const
{
	Node<K, T> *node = rootNode;
	while (node->right != nullptr)
		node = node->right;

	return node;
};

template<class K, class T>
TreeIterator<K, T> BST::Tree<K, T>::begin() const
{
	return TreeIterator<K, T>(*this);
}
template<class K, class T>
TreeIterator<K, T> BST::Tree<K, T>::end() const
{
	return TreeIterator<K, T>(*this, END_ITER);
}
;
template<class K, class T>
bool BST::TreeIterator<K, T>::operator==(TreeIterator & another)
{
	if (cursor != nullptr && another.cursor != nullptr)
		return this->cursor->key == another.cursor->key;
	return this->cursor == another.cursor;
}

template<class K, class T>
bool BST::TreeIterator<K, T>::operator!=(TreeIterator & another)
{
	return !(this->operator==(another));
}

template<class K, class T>
BST::TreeIterator<K, T> BST::TreeIterator<K, T>::operator++()
{
	if (cursor == nullptr)
		;
	else if (cursor->right != nullptr)
		cursor = collection->min(cursor->right);
	else
	{
		Node<K, T> * tempNode = cursor->parent;
		while (tempNode != nullptr &&
			   cursor == tempNode->right)
		{
			cursor = tempNode;
			tempNode = tempNode->parent;
		}
		if (cursor->right != tempNode)
			cursor = tempNode;
	}
	return *this;
}

template<class K, class T>
BST::TreeIterator<K, T> BST::TreeIterator<K, T>::operator++(int)
{
	TreeIterator<K, T> old = *this;
	++(*this);
	return old;
}

template<class K, class T>
BST::TreeIterator<K, T> BST::TreeIterator<K, T>::operator--()
{
	if (cursor == nullptr)
		cursor = collection->max(collection->_root);
	else if (cursor->left != nullptr)
		cursor = collection->max(cursor->left);
	else
	{
		Node<K, T> * tempNode;
		while ((tempNode = cursor->parent) != nullptr
			&& cursor == tempNode->left)
			cursor = tempNode;
		if (cursor == nullptr)
			;
		else
			cursor = tempNode;
	}

	return *this;
}

template<class K, class T>
BST::TreeIterator<K, T> BST::TreeIterator<K, T>::operator--(int)
{
	TreeIterator<K, T> old = *this;
	--(*this);
	return old;
}

template<class K, class T>
std::pair<K, T> BST::TreeIterator<K, T>::operator*()
{
	if (cursor != nullptr)
		return std::pair<K, T>(cursor->id, cursor->key);
	return std::pair<K, T>();
}<|endoftext|>


<commit_before>/* Copyright (C) 2005, Thorvald Natvig <thorvald@natvig.com>

   All rights reserved.

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

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

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

#include "DXAudioOutput.h"
#include "MainWindow.h"

#define NBLOCKS 8
#define MAX(a,b)        ( (a) > (b) ? (a) : (b) )
#define MIN(a,b)        ( (a) < (b) ? (a) : (b) )

DXAudioOutput::DXAudioOutput() {
	HRESULT hr;
    DSBUFFERDESC        dsbdesc;
    WAVEFORMATEX wfx;
    WAVEFORMATEX wfxSet;

	    // Create IDirectSound using the preferred sound device
	if( FAILED( hr = DirectSoundCreate8( NULL, &pDS, NULL ) ) )
		qFatal("DXAudioOutput: DirectSoundCreate");

	    // Set coop level to DSSCL_PRIORITY
	if( FAILED( hr = pDS->SetCooperativeLevel( g_mwMainWindow->winId(), DSSCL_PRIORITY ) ) )
		qFatal("DXAudioOutput: SetCooperativeLevel");

    // Obtain primary buffer
    ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
    dsbdesc.dwSize  = sizeof(DSBUFFERDESC);
    dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;

    if( FAILED( hr = pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) )
    	qFatal("DXAudioOutput: CreateSoundBuffer (Primary) : 0x%08lx", hr);

   	ZeroMemory( &wfxSet, sizeof(wfxSet) );
    wfxSet.wFormatTag = WAVE_FORMAT_PCM;

   	ZeroMemory( &wfx, sizeof(wfx) );
    wfx.wFormatTag = WAVE_FORMAT_PCM;

    wfx.nChannels = 2;
    wfx.nSamplesPerSec = 48000;
    wfx.nBlockAlign = 4;
    wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
    wfx.wBitsPerSample = 16;

	if( FAILED( hr = pDSBPrimary->SetFormat( &wfx ) ) )
    	qFatal("DXAudioOutput: SetFormat");

    if( FAILED( hr = pDSBPrimary->GetFormat( &wfxSet, sizeof(wfxSet), NULL ) ) )
       	qFatal("DXAudioOutput: GetFormat");

	qWarning("DXAudioOutput: Primary buffer of %ld Hz, %d channels, %d bits",wfxSet.nSamplesPerSec,wfxSet.nChannels,wfxSet.wBitsPerSample);

	m_bRunning = true;
}

DXAudioOutput::~DXAudioOutput() {
	if (pDSBPrimary)
		pDSBPrimary->Release();
	if (pDS)
		pDS->Release();
}

AudioOutputPlayer *DXAudioOutput::getPlayer(short sId) {
	DXAudioOutputPlayer *daopPlayer = new DXAudioOutputPlayer(this, sId);
	daopPlayer->start();
	return daopPlayer;
}

DXAudioOutputPlayer::DXAudioOutputPlayer(AudioOutput *aoOutput, short sId) : AudioOutputPlayer(aoOutput, sId) {
	dxAudio = static_cast<DXAudioOutput *>(aoOutput);

    DSBUFFERDESC dsbd;
    WAVEFORMATEX wfx;
    HRESULT hr;

    ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );

   	ZeroMemory( &wfx, sizeof(wfx) );
    wfx.wFormatTag = WAVE_FORMAT_PCM;
    wfx.nChannels = 1;
    wfx.nBlockAlign = 2;
    wfx.nSamplesPerSec = SAMPLE_RATE;
    wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
    wfx.wBitsPerSample = 16;

    dsbd.dwSize          = sizeof(DSBUFFERDESC);
    dsbd.dwFlags         = DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2;
	dsbd.dwFlags	 |= DSBCAPS_CTRLPOSITIONNOTIFY;
   	dsbd.dwBufferBytes = m_iFrameSize * 2 * NBLOCKS;
    dsbd.lpwfxFormat     = &wfx;

    // Create the DirectSound buffer
    if( FAILED( hr = dxAudio->pDS->CreateSoundBuffer( &dsbd, &pDSBOutput, NULL ) ) )
    	qFatal("DXAudioOutputPlayer: CreateSoundBuffer (Secondary): 0x%08lx", hr);

	DSBPOSITIONNOTIFY    aPosNotify[NBLOCKS];

	hNotificationEvent = CreateEvent( NULL, FALSE, FALSE, NULL );

	for(int i=0;i<NBLOCKS;i++) {
		aPosNotify[i].dwOffset = m_iFrameSize * 2 * i;
		aPosNotify[i].hEventNotify = hNotificationEvent;
	}

	if( FAILED( hr = pDSBOutput->QueryInterface( IID_IDirectSoundNotify, (VOID**)&pDSNotify ) ) )
		qFatal("DXAudioOutputPlayer: QueryInterface (Notify)");

    if( FAILED( hr = pDSNotify->SetNotificationPositions( NBLOCKS, aPosNotify ) ) )
    	qFatal("DXAudioOutputPlayer: SetNotificationPositions");

    LPVOID aptr1, aptr2;
    DWORD nbytes1, nbytes2;

    if (FAILED( hr = pDSBOutput->Lock(0, 0, &aptr1, &nbytes1, &aptr2, &nbytes2, DSBLOCK_ENTIREBUFFER)))
    	qFatal("DXAudioOutputPlayer: Initial Lock");

    dwBufferSize = nbytes1 + nbytes2;
    if (aptr1)
   		ZeroMemory(aptr1, nbytes1);
   	if (aptr2)
   		ZeroMemory(aptr2, nbytes2);

    if (FAILED( hr = pDSBOutput->Unlock(aptr1, nbytes1, aptr2, nbytes2)))
    	qFatal("DXAudioOutputPlayer: Initial Unlock");

	dwLastWritePos = 0;
	dwLastPlayPos = 0;
	dwTotalPlayPos = 0;

	qWarning("DXAudioOutputPlayer: New %dHz output buffer of %ld bytes", SAMPLE_RATE, dwBufferSize);
}

DXAudioOutputPlayer::~DXAudioOutputPlayer() {
	bRunning = false;
	wait();
	if (pDSNotify)
		pDSNotify->Release();
	if (pDSBOutput)
		pDSBOutput->Release();
}

void DXAudioOutputPlayer::run() {
	int playblock;
	int nowriteblock;
	int lastwriteblock = NBLOCKS-1;
	int iAudioDecodeLag = 4;
	DWORD dwPlayPosition, dwWritePosition;
    HRESULT             hr;

    if (FAILED( hr = pDSBOutput->Play(0, 0, DSBPLAY_LOOPING)))
    	qFatal("DXAUdioOutputPlayer: Play");

	bRunning = true;

	while (bRunning && dxAudio->m_bRunning) {
		if( FAILED( hr = pDSBOutput->GetCurrentPosition(&dwPlayPosition, &dwWritePosition ) ) )
				qFatal("DXAudioOutputPlayer: GetCurrentPosition");

		playblock = dwWritePosition / m_iByteSize;
		nowriteblock = (playblock + iAudioDecodeLag) % NBLOCKS;

		for(int block=(lastwriteblock + 1) % NBLOCKS;block!=nowriteblock;block=(block + 1) % NBLOCKS) {
			lastwriteblock = block;

			decodeNextFrame();

		    LPVOID aptr1, aptr2;
		    DWORD nbytes1, nbytes2;

		    if (FAILED( hr = pDSBOutput->Lock(block * m_iByteSize, m_iByteSize, &aptr1, &nbytes1, &aptr2, &nbytes2, 0)))
		    	qFatal("DXAudioOutput: Lock block %d (%d bytes)",block, m_iByteSize);
			if (aptr1 && nbytes1)
				CopyMemory(aptr1, m_psBuffer, MIN(m_iByteSize, (int) nbytes1));
			if (aptr2 && nbytes2)
				CopyMemory(aptr2, m_psBuffer+(nbytes1/2), MIN(m_iByteSize-nbytes1, nbytes2));
		    if (FAILED( hr = pDSBOutput->Unlock(aptr1, nbytes1, aptr2, nbytes2)))
		    	qFatal("DXAudioOutput: Unlock");

			if( FAILED( hr = pDSBOutput->GetCurrentPosition(&dwPlayPosition, &dwWritePosition ) ) )
				qFatal("DXAudioOutputPlayer: GetCurrentPosition");

			playblock = dwWritePosition / m_iByteSize;
			nowriteblock = (playblock + iAudioDecodeLag) % NBLOCKS;
		}
		WaitForSingleObject(hNotificationEvent, INFINITE);
	}
}
<commit_msg>Make the buffer what we need<commit_after>/* Copyright (C) 2005, Thorvald Natvig <thorvald@natvig.com>

   All rights reserved.

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

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

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

#include "DXAudioOutput.h"
#include "MainWindow.h"

#define NBLOCKS 8
#define MAX(a,b)        ( (a) > (b) ? (a) : (b) )
#define MIN(a,b)        ( (a) < (b) ? (a) : (b) )

DXAudioOutput::DXAudioOutput() {
	HRESULT hr;
    DSBUFFERDESC        dsbdesc;
    WAVEFORMATEX wfx;
    WAVEFORMATEX wfxSet;

	    // Create IDirectSound using the preferred sound device
	if( FAILED( hr = DirectSoundCreate8( NULL, &pDS, NULL ) ) )
		qFatal("DXAudioOutput: DirectSoundCreate");

	    // Set coop level to DSSCL_PRIORITY
	if( FAILED( hr = pDS->SetCooperativeLevel( g_mwMainWindow->winId(), DSSCL_PRIORITY ) ) )
		qFatal("DXAudioOutput: SetCooperativeLevel");

    // Obtain primary buffer
    ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
    dsbdesc.dwSize  = sizeof(DSBUFFERDESC);
    dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;

    if( FAILED( hr = pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) )
    	qFatal("DXAudioOutput: CreateSoundBuffer (Primary) : 0x%08lx", hr);

   	ZeroMemory( &wfxSet, sizeof(wfxSet) );
    wfxSet.wFormatTag = WAVE_FORMAT_PCM;

   	ZeroMemory( &wfx, sizeof(wfx) );
    wfx.wFormatTag = WAVE_FORMAT_PCM;

    wfx.nChannels = 1;
    wfx.nSamplesPerSec = SAMPLE_RATE;
    wfx.nBlockAlign = 2;
    wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
    wfx.wBitsPerSample = 16;

	if( FAILED( hr = pDSBPrimary->SetFormat( &wfx ) ) )
    	qFatal("DXAudioOutput: SetFormat");

    if( FAILED( hr = pDSBPrimary->GetFormat( &wfxSet, sizeof(wfxSet), NULL ) ) )
       	qFatal("DXAudioOutput: GetFormat");

	qWarning("DXAudioOutput: Primary buffer of %ld Hz, %d channels, %d bits",wfxSet.nSamplesPerSec,wfxSet.nChannels,wfxSet.wBitsPerSample);

	m_bRunning = true;
}

DXAudioOutput::~DXAudioOutput() {
	if (pDSBPrimary)
		pDSBPrimary->Release();
	if (pDS)
		pDS->Release();
}

AudioOutputPlayer *DXAudioOutput::getPlayer(short sId) {
	DXAudioOutputPlayer *daopPlayer = new DXAudioOutputPlayer(this, sId);
	daopPlayer->start();
	return daopPlayer;
}

DXAudioOutputPlayer::DXAudioOutputPlayer(AudioOutput *aoOutput, short sId) : AudioOutputPlayer(aoOutput, sId) {
	dxAudio = static_cast<DXAudioOutput *>(aoOutput);

    DSBUFFERDESC dsbd;
    WAVEFORMATEX wfx;
    HRESULT hr;

    ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );

   	ZeroMemory( &wfx, sizeof(wfx) );
    wfx.wFormatTag = WAVE_FORMAT_PCM;
    wfx.nChannels = 1;
    wfx.nBlockAlign = 2;
    wfx.nSamplesPerSec = SAMPLE_RATE;
    wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
    wfx.wBitsPerSample = 16;

    dsbd.dwSize          = sizeof(DSBUFFERDESC);
    dsbd.dwFlags         = DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2;
	dsbd.dwFlags	 |= DSBCAPS_CTRLPOSITIONNOTIFY;
   	dsbd.dwBufferBytes = m_iFrameSize * 2 * NBLOCKS;
    dsbd.lpwfxFormat     = &wfx;

    // Create the DirectSound buffer
    if( FAILED( hr = dxAudio->pDS->CreateSoundBuffer( &dsbd, &pDSBOutput, NULL ) ) )
    	qFatal("DXAudioOutputPlayer: CreateSoundBuffer (Secondary): 0x%08lx", hr);

	DSBPOSITIONNOTIFY    aPosNotify[NBLOCKS];

	hNotificationEvent = CreateEvent( NULL, FALSE, FALSE, NULL );

	for(int i=0;i<NBLOCKS;i++) {
		aPosNotify[i].dwOffset = m_iFrameSize * 2 * i;
		aPosNotify[i].hEventNotify = hNotificationEvent;
	}

	if( FAILED( hr = pDSBOutput->QueryInterface( IID_IDirectSoundNotify, (VOID**)&pDSNotify ) ) )
		qFatal("DXAudioOutputPlayer: QueryInterface (Notify)");

    if( FAILED( hr = pDSNotify->SetNotificationPositions( NBLOCKS, aPosNotify ) ) )
    	qFatal("DXAudioOutputPlayer: SetNotificationPositions");

    LPVOID aptr1, aptr2;
    DWORD nbytes1, nbytes2;

    if (FAILED( hr = pDSBOutput->Lock(0, 0, &aptr1, &nbytes1, &aptr2, &nbytes2, DSBLOCK_ENTIREBUFFER)))
    	qFatal("DXAudioOutputPlayer: Initial Lock");

    dwBufferSize = nbytes1 + nbytes2;
    if (aptr1)
   		ZeroMemory(aptr1, nbytes1);
   	if (aptr2)
   		ZeroMemory(aptr2, nbytes2);

    if (FAILED( hr = pDSBOutput->Unlock(aptr1, nbytes1, aptr2, nbytes2)))
    	qFatal("DXAudioOutputPlayer: Initial Unlock");

	dwLastWritePos = 0;
	dwLastPlayPos = 0;
	dwTotalPlayPos = 0;

	qWarning("DXAudioOutputPlayer: New %dHz output buffer of %ld bytes", SAMPLE_RATE, dwBufferSize);
}

DXAudioOutputPlayer::~DXAudioOutputPlayer() {
	bRunning = false;
	wait();
	if (pDSNotify)
		pDSNotify->Release();
	if (pDSBOutput)
		pDSBOutput->Release();
}

void DXAudioOutputPlayer::run() {
	int playblock;
	int nowriteblock;
	int lastwriteblock = NBLOCKS-1;
	int iAudioDecodeLag = 4;
	DWORD dwPlayPosition, dwWritePosition;
    HRESULT             hr;

    if (FAILED( hr = pDSBOutput->Play(0, 0, DSBPLAY_LOOPING)))
    	qFatal("DXAUdioOutputPlayer: Play");

	bRunning = true;

	while (bRunning && dxAudio->m_bRunning) {
		if( FAILED( hr = pDSBOutput->GetCurrentPosition(&dwPlayPosition, &dwWritePosition ) ) )
				qFatal("DXAudioOutputPlayer: GetCurrentPosition");

		playblock = dwWritePosition / m_iByteSize;
		nowriteblock = (playblock + iAudioDecodeLag) % NBLOCKS;

		for(int block=(lastwriteblock + 1) % NBLOCKS;block!=nowriteblock;block=(block + 1) % NBLOCKS) {
			lastwriteblock = block;

			decodeNextFrame();

		    LPVOID aptr1, aptr2;
		    DWORD nbytes1, nbytes2;

		    if (FAILED( hr = pDSBOutput->Lock(block * m_iByteSize, m_iByteSize, &aptr1, &nbytes1, &aptr2, &nbytes2, 0)))
		    	qFatal("DXAudioOutput: Lock block %d (%d bytes)",block, m_iByteSize);
			if (aptr1 && nbytes1)
				CopyMemory(aptr1, m_psBuffer, MIN(m_iByteSize, (int) nbytes1));
			if (aptr2 && nbytes2)
				CopyMemory(aptr2, m_psBuffer+(nbytes1/2), MIN(m_iByteSize-nbytes1, nbytes2));
		    if (FAILED( hr = pDSBOutput->Unlock(aptr1, nbytes1, aptr2, nbytes2)))
		    	qFatal("DXAudioOutput: Unlock");

			if( FAILED( hr = pDSBOutput->GetCurrentPosition(&dwPlayPosition, &dwWritePosition ) ) )
				qFatal("DXAudioOutputPlayer: GetCurrentPosition");

			playblock = dwWritePosition / m_iByteSize;
			nowriteblock = (playblock + iAudioDecodeLag) % NBLOCKS;
		}
		WaitForSingleObject(hNotificationEvent, INFINITE);
	}
}
<|endoftext|>


<commit_before>// cr: a c++ template parser
//
// Copyright (c) 2012-2016 Timothe Feuillet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#ifndef __CR_STRING_HPP__
#define __CR_STRING_HPP__

#include <initializer_list>
#include <type_traits>
#include <utility>
#include <memory>
#include <vector>
#include <stdexcept>

#define _SL_STRINGIZE(x) #x
#define STRINGIZE(x) _SL_STRINGIZE(x)

namespace neam
{
  // use this as 'constexpr string_t myvar = "blablabla";'
  using string_t = char [];

  namespace ct
  {
    /// \brief Allows string litterals in templates
    template<size_t Count>
    struct string_holder
    {
      consteval string_holder(const char (&_string)[Count])
      {
        std::copy_n(_string, Count, string);
      }
      consteval string_holder(const string_holder&) = default;

      char string[Count];
    };

    /// \brief C-String + Size from array
    struct string
    {
      string() = delete;
      ~string() noexcept = default;

      template<size_t N>
      constexpr string(const char (&_str)[N]) noexcept : str(_str), size(N - 1) {}
      constexpr string(const string& o) noexcept : str(o.str), size(o.size) {}
      constexpr string(const char* _str, size_t _size) noexcept : str(_str), size(_size) {}
      template<size_t N>
      constexpr string &operator = (const char (&_str)[N]) noexcept
      {
        str = _str;
        size = N - 1;
        return *this;
      }
      constexpr string &operator = (const string &o) noexcept
      {
        str = (o.str);
        size = (o.size);
        return *this;
      }

      constexpr const char* begin() const noexcept { return str; }
      constexpr const char* end() const noexcept { return str + size; }

      constexpr size_t find(const string& substr) const noexcept
      {
        if (substr.size > size)
          return ~0ul;
        else if (substr.size == size)
          return (substr == *this ? 0 : ~0ul);
        else if (!substr.size)
          return 0;

        for (size_t i = 0; i < size - substr.size; ++i)
        {
          if (str[i] == substr.str[0])
          {
            size_t j = 1;
            for (; j < substr.size && str[i + j] == substr.str[j]; ++j) {}
            if (j == substr.size)
              return i;
          }
        }
        return ~0ul;
      }

      constexpr string pad(size_t begin_offset, size_t end_offset) const noexcept
      {
        return { str + begin_offset, size - end_offset - begin_offset };
      }

      constexpr bool operator == (const string& o) const noexcept
      {
        if (o.size != size)
          return false;
        for (size_t i = 0; i < size; ++i)
        {
          if (o.str[i] != str[i])
            return false;
        }
        return true;
      }

      constexpr bool operator != (const string& o) const noexcept
      {
        return !(*this == o);
      }

      const char* str;
      size_t size;
    };

    namespace internal
    {
      // strlen function
      inline static constexpr size_t strlen(const char *const str)
      {
        return str[0] ? internal::strlen(str + 1) + 1 : 0;
      }
    } // namespace internal

    static constexpr size_t npos = static_cast<size_t>(-1);

    // strlen function
    template<size_t N>
    inline static constexpr size_t strlen(const char (&)[N])
    {
      return N - 1;
    }
    inline static constexpr size_t strlen(const char *const str)
    {
      return internal::strlen(str);
    }

    inline static constexpr size_t strlen(std::nullptr_t)
    {
      return 0;
    }

    // a safe strlen function
    inline static constexpr size_t safe_strlen(const char *const str)
    {
      return str ? internal::strlen(str) : 0; // GCC 5.2.1 HATE this on constexpr string_t...
    }
  } // namespace ct
} // namespace neam

#endif /*__CR_STRING_HPP__*/
<commit_msg>Fix compilation issue with newer gcc<commit_after>// cr: a c++ template parser
//
// Copyright (c) 2012-2016 Timothe Feuillet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#ifndef __CR_STRING_HPP__
#define __CR_STRING_HPP__

#include <initializer_list>
#include <type_traits>
#include <utility>
#include <algorithm>
#include <memory>
#include <vector>
#include <stdexcept>

#define _SL_STRINGIZE(x) #x
#define STRINGIZE(x) _SL_STRINGIZE(x)

namespace neam
{
  // use this as 'constexpr string_t myvar = "blablabla";'
  using string_t = char [];

  namespace ct
  {
    /// \brief Allows string litterals in templates
    template<size_t Count>
    struct string_holder
    {
      consteval string_holder(const char (&_string)[Count])
      {
        std::copy_n(_string, Count, string);
      }
      consteval string_holder(const string_holder&) = default;

      char string[Count];
    };

    /// \brief C-String + Size from array
    struct string
    {
      string() = delete;
      ~string() noexcept = default;

      template<size_t N>
      constexpr string(const char (&_str)[N]) noexcept : str(_str), size(N - 1) {}
      constexpr string(const string& o) noexcept : str(o.str), size(o.size) {}
      constexpr string(const char* _str, size_t _size) noexcept : str(_str), size(_size) {}
      template<size_t N>
      constexpr string &operator = (const char (&_str)[N]) noexcept
      {
        str = _str;
        size = N - 1;
        return *this;
      }
      constexpr string &operator = (const string &o) noexcept
      {
        str = (o.str);
        size = (o.size);
        return *this;
      }

      constexpr const char* begin() const noexcept { return str; }
      constexpr const char* end() const noexcept { return str + size; }

      constexpr size_t find(const string& substr) const noexcept
      {
        if (substr.size > size)
          return ~0ul;
        else if (substr.size == size)
          return (substr == *this ? 0 : ~0ul);
        else if (!substr.size)
          return 0;

        for (size_t i = 0; i < size - substr.size; ++i)
        {
          if (str[i] == substr.str[0])
          {
            size_t j = 1;
            for (; j < substr.size && str[i + j] == substr.str[j]; ++j) {}
            if (j == substr.size)
              return i;
          }
        }
        return ~0ul;
      }

      constexpr string pad(size_t begin_offset, size_t end_offset) const noexcept
      {
        return { str + begin_offset, size - end_offset - begin_offset };
      }

      constexpr bool operator == (const string& o) const noexcept
      {
        if (o.size != size)
          return false;
        for (size_t i = 0; i < size; ++i)
        {
          if (o.str[i] != str[i])
            return false;
        }
        return true;
      }

      constexpr bool operator != (const string& o) const noexcept
      {
        return !(*this == o);
      }

      const char* str;
      size_t size;
    };

    namespace internal
    {
      // strlen function
      inline static constexpr size_t strlen(const char *const str)
      {
        return str[0] ? internal::strlen(str + 1) + 1 : 0;
      }
    } // namespace internal

    static constexpr size_t npos = static_cast<size_t>(-1);

    // strlen function
    template<size_t N>
    inline static constexpr size_t strlen(const char (&)[N])
    {
      return N - 1;
    }
    inline static constexpr size_t strlen(const char *const str)
    {
      return internal::strlen(str);
    }

    inline static constexpr size_t strlen(std::nullptr_t)
    {
      return 0;
    }

    // a safe strlen function
    inline static constexpr size_t safe_strlen(const char *const str)
    {
      return str ? internal::strlen(str) : 0; // GCC 5.2.1 HATE this on constexpr string_t...
    }
  } // namespace ct
} // namespace neam

#endif /*__CR_STRING_HPP__*/
<|endoftext|>


<commit_before>#pragma once

#include <supermarx/id_t.hpp>

namespace supermarx
{

template<typename T>
class reference
{
private:
	id_t id;

public:
	reference(id_t _id)
	: id(_id)
	{}

	id_t unseal() const // No implicit conversion
	{
		return id;
	}
};

template<typename T>
static inline std::ostream& operator<<(std::ostream& os, reference<T> const& rhs)
{
	os << rhs.unseal();
	return os;
}

}
<commit_msg>Added comparisons for references (for maps and such)<commit_after>#pragma once

#include <supermarx/id_t.hpp>

namespace supermarx
{

template<typename T>
class reference
{
private:
	id_t id;

public:
	reference(id_t _id)
	: id(_id)
	{}

	id_t unseal() const // No implicit conversion
	{
		return id;
	}

	bool operator==(reference<T> const& rhs) const
	{
		return id == rhs.id;
	}

	bool operator<(reference<T> const& rhs) const
	{
		return id < rhs.id;
	}
};

template<typename T>
static inline std::ostream& operator<<(std::ostream& os, reference<T> const& rhs)
{
	os << rhs.unseal();
	return os;
}

}
<|endoftext|>


<commit_before>// Copyright 2015 Las Venturas Playground. All rights reserved.
// Use of this source code is governed by the MIT license, a copy of which can
// be found in the LICENSE file.

#include "bindings/pawn_invoke.h"

#include <string.h>

#include "base/logging.h"
#include "bindings/provided_natives.h"
#include "bindings/runtime.h"
#include "bindings/utilities.h"
#include "performance/scoped_trace.h"
#include "plugin/plugin_controller.h"

namespace bindings {

namespace {

// Types of arguments that can be parsed from the signature passed to the pawnInvoke() function,
// see the class-level comment above the PawnInvoke class for more information.
enum SignatureType {
  SIGNATURE_TYPE_ARRAY,
  SIGNATURE_TYPE_FLOAT,
  SIGNATURE_TYPE_FLOAT_REFERENCE,
  SIGNATURE_TYPE_INT,
  SIGNATURE_TYPE_INT_REFERENCE,
  SIGNATURE_TYPE_STRING,
  SIGNATURE_TYPE_STRING_REFERENCE
};

}  // namespace

// Buffer in which we store the data associated with each invocation. This significantly reduces
// the need to do many allocations for each function invocation, at the expense of a little bit
// of memory usage.
struct PawnInvoke::StaticBuffer {
  SignatureType signature[PawnInvoke::kMaxArgumentCount];

  char arguments_format[PawnInvoke::kMaxArgumentCount];
  void* arguments[PawnInvoke::kMaxArgumentCount];

  // Integer and floating point values will both be stored in the same buffer, but we must be
  // sure that the compiler gives them the same size.
  static_assert(sizeof(float) == sizeof(int), "Expected sizeof(float) == sizeof(int).");
  int number_values[PawnInvoke::kMaxArgumentCount];

  // Maximum length of a string stored in the static buffer. Total memory required for this is
  // kMaxArgumentCount (24) * kMaxStringLength (2048) = 48 KiB.
  static const size_t kMaxStringLength = 2048;

  char string_values[PawnInvoke::kMaxArgumentCount][kMaxStringLength];

  // Maximum number of entries in an array. The total memory required for this buffer is
  // kMaxArgumentCount (24) * kMaxArrayLength (144) * sizeof(int) = 13.5 KiB.
  static const size_t kMaxArrayLength = 144;

  int array_values[PawnInvoke::kMaxArgumentCount][kMaxArrayLength];
};

PawnInvoke::PawnInvoke(plugin::PluginController* plugin_controller)
    : static_buffer_(static_cast<StaticBuffer*>(calloc(1, sizeof(StaticBuffer)))),
      plugin_controller_(plugin_controller) {}

PawnInvoke::~PawnInvoke() {}

v8::Local<v8::Value> PawnInvoke::Call(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  DCHECK(arguments.Length() >= 1);
  DCHECK(arguments[0]->IsString());

  v8::Isolate* isolate = arguments.GetIsolate();

  // The first argument contains the name of the function that should be invoked.
  const std::string function = toString(arguments[0]);

  if (!function.length()) {
    ThrowException("unable to execute pawnInvoke(): the function name must not be empty.");
    return v8::Local<v8::Value>();
  }

  // Issue a warning when pawnInvoke() is used for a native that is not provided by JavaScript
  // before the tests have finished running, because tests should not rely on the Pawn code.
  if (!Runtime::FromIsolate(isolate)->IsReady() && !ProvidedNatives::GetInstance()->IsProvided(function))
    LOG(WARNING) << "Called Pawn function " << function << " whilst running the JavaScript tests.";

  // Fast-path for functions that don't take any arguments at all. Immediately invoke the native on
  // the SA-MP server and return whatever it returned to us.
  if (arguments.Length() == 1)
    return v8::Number::New(isolate, plugin_controller_->CallFunction(function));

  if (!arguments[1]->IsString()) {
    ThrowException("unable to execute pawnInvoke(): expected a string for argument 2.");
    return v8::Local<v8::Value>();
  }

  size_t argument_count = 0;
  size_t return_count = 0;

  // Parse the method's signature. The parsed information will be available in |static_buffer_|,
  // whereas argument and return counters will be written to local variables.
  if (!ParseSignature(arguments[1], &argument_count, &return_count)) {
    ThrowException("unable to execute pawnInvoke(): cannot parse the method's signature.");
    return v8::Local<v8::Value>();
  }

  size_t signature_length = argument_count + return_count;

  // Make sure that enough arguments have been passed to satisfy the signature.
  if (arguments.Length() != argument_count + 2) {
    ThrowException("unable to execute pawnInvoke(): " +
                   std::to_string(argument_count + 2) + " arguments required, but only " +
                   std::to_string(arguments.Length()) + " provided.");

    return v8::Local<v8::Value>();
  }

  size_t argument_offset = 0;

  v8::Local<v8::Context> context = isolate->GetCurrentContext();

  // Iterate over each of the arguments to verify their types and to set pointers accordingly.
  for (size_t signature_index = 0; signature_index < signature_length; ++signature_index) {
    size_t argument = signature_index + argument_offset;
    size_t index = argument + 2;

    bool type_mismatch = false;
    switch (static_buffer_->signature[argument]) {
    case SIGNATURE_TYPE_ARRAY:
      if (type_mismatch = !arguments[index]->IsArray())
        break;

      {
        int* array_data = static_buffer_->array_values[argument];
        size_t array_length = 0;

        v8::Local<v8::Array> js_array = v8::Local<v8::Array>::Cast(arguments[index]);
        uint32_t js_length = js_array->Length();

        for (uint32_t index = 0; index < js_length; ++index) {
          v8::MaybeLocal<v8::Value> maybe_entry = js_array->Get(context, index);
          if (maybe_entry.IsEmpty())
            continue;

          v8::Local<v8::Value> entry = maybe_entry.ToLocalChecked();
          if (type_mismatch = !entry->IsNumber())
            break;

          if (array_length >= PawnInvoke::StaticBuffer::kMaxArrayLength) {
            ThrowException("unable to execute pawnInvoke(): too many array values for argument " +
                           std::to_string(index));
          }

          array_data[array_length++] = entry->Int32Value(context).ToChecked();
        }

        static_buffer_->arguments[argument] = array_data;
        static_buffer_->arguments_format[argument] = 'a';
      }

      break;

    case SIGNATURE_TYPE_FLOAT:
      if (type_mismatch = !arguments[index]->IsNumber())
        break;

      {
        float float_value = static_cast<float>(arguments[index]->NumberValue(context).ToChecked());
        static_buffer_->number_values[argument] = *reinterpret_cast<int*>(&float_value);
      }

      static_buffer_->arguments[argument] = &static_buffer_->number_values[argument];
      static_buffer_->arguments_format[argument] = 'f';
      break;

    case SIGNATURE_TYPE_FLOAT_REFERENCE:
      static_buffer_->arguments[argument] = &static_buffer_->number_values[argument];
      static_buffer_->arguments_format[argument] = 'r';
      break;

    case SIGNATURE_TYPE_INT:
      if (type_mismatch = !arguments[index]->IsNumber())
        break;

      static_buffer_->number_values[argument] = arguments[index]->Int32Value(context).ToChecked();
      static_buffer_->arguments[argument] = &static_buffer_->number_values[argument];
      static_buffer_->arguments_format[argument] = 'i';
      break;

    case SIGNATURE_TYPE_INT_REFERENCE:
      static_buffer_->arguments[argument] = &static_buffer_->number_values[argument];
      static_buffer_->arguments_format[argument] = 'r';
      break;

    case SIGNATURE_TYPE_STRING:
      {
        v8::MaybeLocal<v8::String> maybe = arguments[index]->ToString(context);
        if (maybe.IsEmpty()) {
          ThrowException("unable to execute pawnInvoke(): unable to convert argument " +
                           std::to_string(index) + " to a string.");

          return v8::Local<v8::Value>();
        }

        v8::Local<v8::String> string = maybe.ToLocalChecked();
        if (string->Length() >= StaticBuffer::kMaxStringLength) {
          ThrowException("unable to execute pawnInvoke(): string overflow for argument " +
                           std::to_string(index));

          return v8::Local<v8::Value>();
        }

        string->WriteOneByte(
            isolate, (uint8_t*)&static_buffer_->string_values[argument], 0, string->Length());

        static_buffer_->string_values[argument][string->Length()] = 0;
      }

      static_buffer_->arguments[argument] = &static_buffer_->string_values[argument];
      static_buffer_->arguments_format[argument] = 's';
      break;

    case SIGNATURE_TYPE_STRING_REFERENCE:
      static_buffer_->arguments[argument] = &static_buffer_->string_values[argument];
      static_buffer_->arguments_format[argument] = 'a';

      ++argument_offset;
      ++argument;

      static_buffer_->number_values[argument] = StaticBuffer::kMaxStringLength;
      static_buffer_->arguments[argument] = &static_buffer_->number_values[argument];
      static_buffer_->arguments_format[argument] = 'i';
      break;
    }

    // If a type mismatch occurred, an exception will be thrown to JavaScript. At some point we may
    // want to relax the requirements here by using the ES ToType() conversions.
    if (type_mismatch) {
      ThrowException("unable to execute pawnInvoke(): type mismatch for argument " +
                     std::to_string(index) + ".");

      return v8::Local<v8::Value>();
    }
  }

  // The Pawn argument count may not match the JavaScript one, since we substitute the allowed
  // length for string reference arguments automatically.
  const size_t pawn_argument_count = signature_length + argument_offset;

  // Make sure that the argument format string is zero-terminated.
  static_buffer_->arguments_format[pawn_argument_count] = 0;
  DCHECK(strlen(static_buffer_->arguments_format) == pawn_argument_count);

  // Invoke the native SA-MP function. We simply pass the assembled argument format and the
  // array of void* pointers to the intended arguments to the function itself.
  int result = plugin_controller_->CallFunction(function,
                                                static_buffer_->arguments_format,
                                                static_buffer_->arguments);

  // If there are no explicit return values, simply return the |result|.
  if (!return_count || result == -1 /** internal error code **/)
    return v8::Number::New(isolate, static_cast<double>(result));

  // We want to eagerly return a value immediately if there is only one return value. In all other
  // cases, the return values will be stored in an array, and the array will be returned.
  const bool eager_return = (return_count == 1);

  v8::Local<v8::Array> return_array;
  if (!eager_return)
    return_array = v8::Array::New(isolate, return_count);

  size_t stored_return_values = 0;

  // Iterate over the arguments again to find those which were passed as a reference. Those will
  // be considered return values of the JavaScript function.
  for (size_t argument = 0; argument < pawn_argument_count; ++argument) {
    v8::Local<v8::Value> value;

    switch (static_buffer_->signature[argument]) {
    case SIGNATURE_TYPE_FLOAT:
    case SIGNATURE_TYPE_INT:
    case SIGNATURE_TYPE_STRING:
      break;

    case SIGNATURE_TYPE_FLOAT_REFERENCE:
      value = v8::Number::New(isolate,
                              *reinterpret_cast<float*>(&static_buffer_->number_values[argument]));

      if (eager_return)
        return value;

      return_array->Set(context, stored_return_values++, value);
      break;
    case SIGNATURE_TYPE_INT_REFERENCE:
      value = v8::Number::New(isolate, static_buffer_->number_values[argument]);
      if (eager_return)
        return value;

      return_array->Set(context, stored_return_values++, value);
      break;
    case SIGNATURE_TYPE_STRING_REFERENCE:
      {
        v8::MaybeLocal<v8::String> maybe =
            v8::String::NewFromUtf8(isolate,
                                    static_buffer_->string_values[argument], v8::NewStringType::kNormal);

        if (maybe.IsEmpty())
          value = v8::Null(isolate);
        else
          value = maybe.ToLocalChecked();
      }

      if (eager_return)
        return value;

      return_array->Set(context, stored_return_values++, value);
      break;
    }
  }

  return return_array;
}

bool PawnInvoke::ParseSignature(v8::Local<v8::Value> signature,
                                size_t* argument_count, size_t* return_count) {
  v8::String::Utf8Value string(GetIsolate(), signature);
  DCHECK(*string);

  bool found_reference = false;
  for (int index = 0; index < string.length(); ++index) {
    const char type = (*string)[index];
    const bool is_reference = type == 'F' || type == 'I' || type == 'S';

    // Non-reference arguments may not follow reference arguments.
    if (found_reference && !is_reference)
      return false;

    found_reference |= is_reference;

    switch (type) {
    case 'a':
      static_buffer_->signature[index] = SignatureType::SIGNATURE_TYPE_ARRAY;
      *argument_count += 1;
      break;
    case 'f':
      static_buffer_->signature[index] = SignatureType::SIGNATURE_TYPE_FLOAT;
      *argument_count += 1;
      break;
    case 'F':
      static_buffer_->signature[index] = SignatureType::SIGNATURE_TYPE_FLOAT_REFERENCE;
      *return_count += 1;
      break;
    case 'i':
      static_buffer_->signature[index] = SignatureType::SIGNATURE_TYPE_INT;
      *argument_count += 1;
      break;
    case 'I':
      static_buffer_->signature[index] = SignatureType::SIGNATURE_TYPE_INT_REFERENCE;
      *return_count += 1;
      break;
    case 's':
      static_buffer_->signature[index] = SignatureType::SIGNATURE_TYPE_STRING;
      *argument_count += 1;
      break;
    case 'S':
      static_buffer_->signature[index] = SignatureType::SIGNATURE_TYPE_STRING_REFERENCE;
      *return_count += 1;
      break;
    default:
      // The argument type passed in the signature is unknown.
      return false;
    }
  }

  return true;
}

}  // namespace bindings
<commit_msg>Increase the string limit to 3KiB<commit_after>// Copyright 2015 Las Venturas Playground. All rights reserved.
// Use of this source code is governed by the MIT license, a copy of which can
// be found in the LICENSE file.

#include "bindings/pawn_invoke.h"

#include <string.h>

#include "base/logging.h"
#include "bindings/provided_natives.h"
#include "bindings/runtime.h"
#include "bindings/utilities.h"
#include "performance/scoped_trace.h"
#include "plugin/plugin_controller.h"

namespace bindings {

namespace {

// Types of arguments that can be parsed from the signature passed to the pawnInvoke() function,
// see the class-level comment above the PawnInvoke class for more information.
enum SignatureType {
  SIGNATURE_TYPE_ARRAY,
  SIGNATURE_TYPE_FLOAT,
  SIGNATURE_TYPE_FLOAT_REFERENCE,
  SIGNATURE_TYPE_INT,
  SIGNATURE_TYPE_INT_REFERENCE,
  SIGNATURE_TYPE_STRING,
  SIGNATURE_TYPE_STRING_REFERENCE
};

}  // namespace

// Buffer in which we store the data associated with each invocation. This significantly reduces
// the need to do many allocations for each function invocation, at the expense of a little bit
// of memory usage.
struct PawnInvoke::StaticBuffer {
  SignatureType signature[PawnInvoke::kMaxArgumentCount];

  char arguments_format[PawnInvoke::kMaxArgumentCount];
  void* arguments[PawnInvoke::kMaxArgumentCount];

  // Integer and floating point values will both be stored in the same buffer, but we must be
  // sure that the compiler gives them the same size.
  static_assert(sizeof(float) == sizeof(int), "Expected sizeof(float) == sizeof(int).");
  int number_values[PawnInvoke::kMaxArgumentCount];

  // Maximum length of a string stored in the static buffer. Total memory required for this is
  // kMaxArgumentCount (24) * kMaxStringLength (3072) = 72 KiB.
  static const size_t kMaxStringLength = 3072;

  char string_values[PawnInvoke::kMaxArgumentCount][kMaxStringLength];

  // Maximum number of entries in an array. The total memory required for this buffer is
  // kMaxArgumentCount (24) * kMaxArrayLength (144) * sizeof(int) = 13.5 KiB.
  static const size_t kMaxArrayLength = 144;

  int array_values[PawnInvoke::kMaxArgumentCount][kMaxArrayLength];
};

PawnInvoke::PawnInvoke(plugin::PluginController* plugin_controller)
    : static_buffer_(static_cast<StaticBuffer*>(calloc(1, sizeof(StaticBuffer)))),
      plugin_controller_(plugin_controller) {}

PawnInvoke::~PawnInvoke() {}

v8::Local<v8::Value> PawnInvoke::Call(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  DCHECK(arguments.Length() >= 1);
  DCHECK(arguments[0]->IsString());

  v8::Isolate* isolate = arguments.GetIsolate();

  // The first argument contains the name of the function that should be invoked.
  const std::string function = toString(arguments[0]);

  if (!function.length()) {
    ThrowException("unable to execute pawnInvoke(): the function name must not be empty.");
    return v8::Local<v8::Value>();
  }

  // Issue a warning when pawnInvoke() is used for a native that is not provided by JavaScript
  // before the tests have finished running, because tests should not rely on the Pawn code.
  if (!Runtime::FromIsolate(isolate)->IsReady() && !ProvidedNatives::GetInstance()->IsProvided(function))
    LOG(WARNING) << "Called Pawn function " << function << " whilst running the JavaScript tests.";

  // Fast-path for functions that don't take any arguments at all. Immediately invoke the native on
  // the SA-MP server and return whatever it returned to us.
  if (arguments.Length() == 1)
    return v8::Number::New(isolate, plugin_controller_->CallFunction(function));

  if (!arguments[1]->IsString()) {
    ThrowException("unable to execute pawnInvoke(): expected a string for argument 2.");
    return v8::Local<v8::Value>();
  }

  size_t argument_count = 0;
  size_t return_count = 0;

  // Parse the method's signature. The parsed information will be available in |static_buffer_|,
  // whereas argument and return counters will be written to local variables.
  if (!ParseSignature(arguments[1], &argument_count, &return_count)) {
    ThrowException("unable to execute pawnInvoke(): cannot parse the method's signature.");
    return v8::Local<v8::Value>();
  }

  size_t signature_length = argument_count + return_count;

  // Make sure that enough arguments have been passed to satisfy the signature.
  if (arguments.Length() != argument_count + 2) {
    ThrowException("unable to execute pawnInvoke(): " +
                   std::to_string(argument_count + 2) + " arguments required, but only " +
                   std::to_string(arguments.Length()) + " provided.");

    return v8::Local<v8::Value>();
  }

  size_t argument_offset = 0;

  v8::Local<v8::Context> context = isolate->GetCurrentContext();

  // Iterate over each of the arguments to verify their types and to set pointers accordingly.
  for (size_t signature_index = 0; signature_index < signature_length; ++signature_index) {
    size_t argument = signature_index + argument_offset;
    size_t index = argument + 2;

    bool type_mismatch = false;
    switch (static_buffer_->signature[argument]) {
    case SIGNATURE_TYPE_ARRAY:
      if (type_mismatch = !arguments[index]->IsArray())
        break;

      {
        int* array_data = static_buffer_->array_values[argument];
        size_t array_length = 0;

        v8::Local<v8::Array> js_array = v8::Local<v8::Array>::Cast(arguments[index]);
        uint32_t js_length = js_array->Length();

        for (uint32_t index = 0; index < js_length; ++index) {
          v8::MaybeLocal<v8::Value> maybe_entry = js_array->Get(context, index);
          if (maybe_entry.IsEmpty())
            continue;

          v8::Local<v8::Value> entry = maybe_entry.ToLocalChecked();
          if (type_mismatch = !entry->IsNumber())
            break;

          if (array_length >= PawnInvoke::StaticBuffer::kMaxArrayLength) {
            ThrowException("unable to execute pawnInvoke(): too many array values for argument " +
                           std::to_string(index));
          }

          array_data[array_length++] = entry->Int32Value(context).ToChecked();
        }

        static_buffer_->arguments[argument] = array_data;
        static_buffer_->arguments_format[argument] = 'a';
      }

      break;

    case SIGNATURE_TYPE_FLOAT:
      if (type_mismatch = !arguments[index]->IsNumber())
        break;

      {
        float float_value = static_cast<float>(arguments[index]->NumberValue(context).ToChecked());
        static_buffer_->number_values[argument] = *reinterpret_cast<int*>(&float_value);
      }

      static_buffer_->arguments[argument] = &static_buffer_->number_values[argument];
      static_buffer_->arguments_format[argument] = 'f';
      break;

    case SIGNATURE_TYPE_FLOAT_REFERENCE:
      static_buffer_->arguments[argument] = &static_buffer_->number_values[argument];
      static_buffer_->arguments_format[argument] = 'r';
      break;

    case SIGNATURE_TYPE_INT:
      if (type_mismatch = !arguments[index]->IsNumber())
        break;

      static_buffer_->number_values[argument] = arguments[index]->Int32Value(context).ToChecked();
      static_buffer_->arguments[argument] = &static_buffer_->number_values[argument];
      static_buffer_->arguments_format[argument] = 'i';
      break;

    case SIGNATURE_TYPE_INT_REFERENCE:
      static_buffer_->arguments[argument] = &static_buffer_->number_values[argument];
      static_buffer_->arguments_format[argument] = 'r';
      break;

    case SIGNATURE_TYPE_STRING:
      {
        v8::MaybeLocal<v8::String> maybe = arguments[index]->ToString(context);
        if (maybe.IsEmpty()) {
          ThrowException("unable to execute pawnInvoke(): unable to convert argument " +
                           std::to_string(index) + " to a string.");

          return v8::Local<v8::Value>();
        }

        v8::Local<v8::String> string = maybe.ToLocalChecked();
        if (string->Length() >= StaticBuffer::kMaxStringLength) {
          ThrowException("unable to execute pawnInvoke(): string overflow for argument " +
                           std::to_string(index));

          return v8::Local<v8::Value>();
        }

        string->WriteOneByte(
            isolate, (uint8_t*)&static_buffer_->string_values[argument], 0, string->Length());

        static_buffer_->string_values[argument][string->Length()] = 0;
      }

      static_buffer_->arguments[argument] = &static_buffer_->string_values[argument];
      static_buffer_->arguments_format[argument] = 's';
      break;

    case SIGNATURE_TYPE_STRING_REFERENCE:
      static_buffer_->arguments[argument] = &static_buffer_->string_values[argument];
      static_buffer_->arguments_format[argument] = 'a';

      ++argument_offset;
      ++argument;

      static_buffer_->number_values[argument] = StaticBuffer::kMaxStringLength;
      static_buffer_->arguments[argument] = &static_buffer_->number_values[argument];
      static_buffer_->arguments_format[argument] = 'i';
      break;
    }

    // If a type mismatch occurred, an exception will be thrown to JavaScript. At some point we may
    // want to relax the requirements here by using the ES ToType() conversions.
    if (type_mismatch) {
      ThrowException("unable to execute pawnInvoke(): type mismatch for argument " +
                     std::to_string(index) + ".");

      return v8::Local<v8::Value>();
    }
  }

  // The Pawn argument count may not match the JavaScript one, since we substitute the allowed
  // length for string reference arguments automatically.
  const size_t pawn_argument_count = signature_length + argument_offset;

  // Make sure that the argument format string is zero-terminated.
  static_buffer_->arguments_format[pawn_argument_count] = 0;
  DCHECK(strlen(static_buffer_->arguments_format) == pawn_argument_count);

  // Invoke the native SA-MP function. We simply pass the assembled argument format and the
  // array of void* pointers to the intended arguments to the function itself.
  int result = plugin_controller_->CallFunction(function,
                                                static_buffer_->arguments_format,
                                                static_buffer_->arguments);

  // If there are no explicit return values, simply return the |result|.
  if (!return_count || result == -1 /** internal error code **/)
    return v8::Number::New(isolate, static_cast<double>(result));

  // We want to eagerly return a value immediately if there is only one return value. In all other
  // cases, the return values will be stored in an array, and the array will be returned.
  const bool eager_return = (return_count == 1);

  v8::Local<v8::Array> return_array;
  if (!eager_return)
    return_array = v8::Array::New(isolate, return_count);

  size_t stored_return_values = 0;

  // Iterate over the arguments again to find those which were passed as a reference. Those will
  // be considered return values of the JavaScript function.
  for (size_t argument = 0; argument < pawn_argument_count; ++argument) {
    v8::Local<v8::Value> value;

    switch (static_buffer_->signature[argument]) {
    case SIGNATURE_TYPE_FLOAT:
    case SIGNATURE_TYPE_INT:
    case SIGNATURE_TYPE_STRING:
      break;

    case SIGNATURE_TYPE_FLOAT_REFERENCE:
      value = v8::Number::New(isolate,
                              *reinterpret_cast<float*>(&static_buffer_->number_values[argument]));

      if (eager_return)
        return value;

      return_array->Set(context, stored_return_values++, value);
      break;
    case SIGNATURE_TYPE_INT_REFERENCE:
      value = v8::Number::New(isolate, static_buffer_->number_values[argument]);
      if (eager_return)
        return value;

      return_array->Set(context, stored_return_values++, value);
      break;
    case SIGNATURE_TYPE_STRING_REFERENCE:
      {
        v8::MaybeLocal<v8::String> maybe =
            v8::String::NewFromUtf8(isolate,
                                    static_buffer_->string_values[argument], v8::NewStringType::kNormal);

        if (maybe.IsEmpty())
          value = v8::Null(isolate);
        else
          value = maybe.ToLocalChecked();
      }

      if (eager_return)
        return value;

      return_array->Set(context, stored_return_values++, value);
      break;
    }
  }

  return return_array;
}

bool PawnInvoke::ParseSignature(v8::Local<v8::Value> signature,
                                size_t* argument_count, size_t* return_count) {
  v8::String::Utf8Value string(GetIsolate(), signature);
  DCHECK(*string);

  bool found_reference = false;
  for (int index = 0; index < string.length(); ++index) {
    const char type = (*string)[index];
    const bool is_reference = type == 'F' || type == 'I' || type == 'S';

    // Non-reference arguments may not follow reference arguments.
    if (found_reference && !is_reference)
      return false;

    found_reference |= is_reference;

    switch (type) {
    case 'a':
      static_buffer_->signature[index] = SignatureType::SIGNATURE_TYPE_ARRAY;
      *argument_count += 1;
      break;
    case 'f':
      static_buffer_->signature[index] = SignatureType::SIGNATURE_TYPE_FLOAT;
      *argument_count += 1;
      break;
    case 'F':
      static_buffer_->signature[index] = SignatureType::SIGNATURE_TYPE_FLOAT_REFERENCE;
      *return_count += 1;
      break;
    case 'i':
      static_buffer_->signature[index] = SignatureType::SIGNATURE_TYPE_INT;
      *argument_count += 1;
      break;
    case 'I':
      static_buffer_->signature[index] = SignatureType::SIGNATURE_TYPE_INT_REFERENCE;
      *return_count += 1;
      break;
    case 's':
      static_buffer_->signature[index] = SignatureType::SIGNATURE_TYPE_STRING;
      *argument_count += 1;
      break;
    case 'S':
      static_buffer_->signature[index] = SignatureType::SIGNATURE_TYPE_STRING_REFERENCE;
      *return_count += 1;
      break;
    default:
      // The argument type passed in the signature is unknown.
      return false;
    }
  }

  return true;
}

}  // namespace bindings
<|endoftext|>


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

#include "TemplateSQL.h"
#include <iostream>
#include <sstream>

/* ************************************************************************ */
/* SQL Template                                                             */
/* ************************************************************************ */

const char * TemplateSQL::db_names = "(id,name,type,value)";

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int TemplateSQL::insert_cb(void *nil, int num, char **values, char **names)
{
    if ( num<=0 )
    {
        return -1;
    }

    if ( values[0] == 0 )
    {
        id = 0;
    }
    else
    {
        id = atoi(values[0]) + 1;
    }

    return 0;
}

/* ------------------------------------------------------------------------ */

int TemplateSQL::insert(SqlDB * db)
{
    ostringstream   oss;
    int             rc;

    // Get next id from the DB table
    set_callback(
           static_cast<Callbackable::Callback>(&TemplateSQL::insert_cb));

    oss << "SELECT MAX(id) FROM " << table;

    rc = db->exec(oss,this);

    unset_callback();

    if ( rc != 0 )
    {
        return -1;
    }

    rc = insert_replace(db, false);

    return rc;
}

/* ------------------------------------------------------------------------ */

int TemplateSQL::update(SqlDB * db)
{
    int             rc;

    rc = insert_replace(db, true);

    return rc;
}

/* ------------------------------------------------------------------------ */

int TemplateSQL::insert_replace(SqlDB *db, bool replace)
{
    multimap<string,Attribute *>::iterator  it;
    ostringstream                           oss;
    int                                     rc;
    string *                                attr;
    char *                                  sql_attr;
    Attribute::AttributeType                atype;

    for(it=attributes.begin(),oss.str("");
        it!=attributes.end();
        it++,oss.str(""))
    {
        if ( it->second == 0 )
        {
            continue;
        }

        attr  = it->second->marshall();
        atype = it->second->type();

        if ( attr == 0 )
        {
            continue;
        }

        sql_attr = db->escape_str((*attr).c_str());

        delete attr;

        if ( sql_attr == 0 )
        {
            continue;
        }

        if(replace)
        {
            oss << "REPLACE";
        }
        else
        {
            oss << "INSERT";
        }

        oss << " INTO " << table << " " << db_names
            << " VALUES (" << id << ",'" << it->first << "',"<< atype <<",'"
            << sql_attr << "')";

        rc = db->exec(oss);

        db->free_str(sql_attr);

        if ( rc != 0 )
        {
            goto error_sql;
        }
    }

    return 0;

error_sql:
    drop(db);

    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int TemplateSQL::select_cb(void *nil, int num, char **values, char **names)
{
    Attribute *         attr;

    string              name;
    string              value;
    int                 atype;

    if (num != 4)
    {
        return -1;
    }

    if ( values[1] != 0 )
    {
        name  = values[1];
    }
    else
    {
        return -1;
    }

    if ( values[3] != 0 )
    {
        value = values[3];
    }
    else
    {
        return -1;
    }

    if ( values[2] != 0 )
    {
        atype = atoi(values[2]);

        switch (atype)
        {
        case Attribute::SIMPLE:
            attr = new SingleAttribute(name);
            break;

        case Attribute::VECTOR:
            attr = new VectorAttribute(name);
            break;

        default:
            return -1;
            break;
        };
    }

    attr->unmarshall(value);

    set(attr);

    return 0;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int TemplateSQL::select(SqlDB * db)
{
    ostringstream   oss;
    int             rc;

    if ( id == -1 )
    {
        return -1;
    }

    set_callback(static_cast<Callbackable::Callback>(&TemplateSQL::select_cb));

    oss << "SELECT * FROM " << table << " WHERE id=" << id;

    rc = db->exec(oss,this);

    unset_callback();

    return rc;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int TemplateSQL::drop(SqlDB * db)
{
    ostringstream   oss;

    if ( id == -1 )
    {
        return -1;
    }

    oss << "DELETE FROM " << table << " WHERE id=" << id;

    return db->exec(oss);
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int TemplateSQL::replace_attribute(SqlDB * db, Attribute * attribute)
{
    ostringstream   oss;
    int             rc;

    multimap<string, Attribute *>::iterator i;

    if ( id == -1 || attribute == 0)
    {
        return -1;
    }

    rc  = remove_attribute(db, attribute->name());

    if (rc == 0)
    {
        rc = insert_attribute(db,attribute);
    }

    return rc;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int TemplateSQL::insert_attribute(SqlDB * db, Attribute * attribute)
{
    ostringstream   oss;
    int             rc;
    string *        astr;
    int             atype;

    char *          sql_attr;

    if ( id == -1 || attribute == 0)
    {
        return -1;
    }

    astr  = attribute->marshall();
    atype = attribute->type();

    if ( astr == 0 )
    {
        return -1;
    }

    sql_attr = db->escape_str((*astr).c_str());

    delete astr;

    if ( sql_attr == 0 )
    {
        return -1;
    }

    oss << "INSERT INTO " << table << " " << db_names
        << " VALUES (" << id << ",'" << attribute->name() << "'," << atype
        << ",'" << sql_attr << "')";

    rc = db->exec(oss);

    db->free_str(sql_attr);

    if (rc == 0)
    {
        attributes.insert(make_pair(attribute->name(),attribute));
    }

    return rc;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int TemplateSQL::remove_attribute(SqlDB * db, const string& name)
{
    ostringstream   oss;
    int             rc;
    string *        astr;
    char *          sql_attr;

    multimap<string, Attribute *>::iterator i;

    if ( id == -1 )
    {
        return -1;
    }

    i = attributes.find(name);

    if ( i != attributes.end() )
    {
        astr = i->second->marshall();

        if ( astr == 0 )
        {
            return -1;
        }

        sql_attr = db->escape_str((*astr).c_str());

        delete astr;

        if ( sql_attr == 0 )
        {
            return -1;
        }

        oss << "DELETE FROM " << table << " WHERE id=" << id
            << " AND name='" << name << "' AND value='"
            << sql_attr << "'";

        rc = db->exec(oss);

        db->free_str(sql_attr);

        if (rc != 0 )
        {
            return rc;
        }

        delete i->second;

        attributes.erase(i);
    }

    return 0;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

<commit_msg>feature #200: Remove selecting max oid from template SQL<commit_after>/* ------------------------------------------------------------------------ */
/* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.org)           */
/*                                                                          */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may  */
/* not use this file except in compliance with the License. You may obtain  */
/* a copy of the License at                                                 */
/*                                                                          */
/* http://www.apache.org/licenses/LICENSE-2.0                               */
/*                                                                          */
/* Unless required by applicable law or agreed to in writing, software      */
/* distributed under the License is distributed on an "AS IS" BASIS,        */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and      */
/* limitations under the License.                                           */
/* -------------------------------------------------------------------------*/

#include "TemplateSQL.h"
#include <iostream>
#include <sstream>

/* ************************************************************************ */
/* SQL Template                                                             */
/* ************************************************************************ */

const char * TemplateSQL::db_names = "(id,name,type,value)";

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int TemplateSQL::insert_cb(void *nil, int num, char **values, char **names)
{
    if ( num<=0 )
    {
        return -1;
    }

    if ( values[0] == 0 )
    {
        id = 0;
    }
    else
    {
        id = atoi(values[0]) + 1;
    }

    return 0;
}

/* ------------------------------------------------------------------------ */

int TemplateSQL::insert(SqlDB * db)
{
    int             rc;

    if ( rc != 0 )
    {
        return -1;
    }

    rc = insert_replace(db, false);

    return rc;
}

/* ------------------------------------------------------------------------ */

int TemplateSQL::update(SqlDB * db)
{
    int             rc;

    rc = insert_replace(db, true);

    return rc;
}

/* ------------------------------------------------------------------------ */

int TemplateSQL::insert_replace(SqlDB *db, bool replace)
{
    multimap<string,Attribute *>::iterator  it;
    ostringstream                           oss;
    int                                     rc;
    string *                                attr;
    char *                                  sql_attr;
    Attribute::AttributeType                atype;

    for(it=attributes.begin(),oss.str("");
        it!=attributes.end();
        it++,oss.str(""))
    {
        if ( it->second == 0 )
        {
            continue;
        }

        attr  = it->second->marshall();
        atype = it->second->type();

        if ( attr == 0 )
        {
            continue;
        }

        sql_attr = db->escape_str((*attr).c_str());

        delete attr;

        if ( sql_attr == 0 )
        {
            continue;
        }

        if(replace)
        {
            oss << "REPLACE";
        }
        else
        {
            oss << "INSERT";
        }

        oss << " INTO " << table << " " << db_names
            << " VALUES (" << id << ",'" << it->first << "',"<< atype <<",'"
            << sql_attr << "')";

        rc = db->exec(oss);

        db->free_str(sql_attr);

        if ( rc != 0 )
        {
            goto error_sql;
        }
    }

    return 0;

error_sql:
    drop(db);

    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int TemplateSQL::select_cb(void *nil, int num, char **values, char **names)
{
    Attribute *         attr;

    string              name;
    string              value;
    int                 atype;

    if (num != 4)
    {
        return -1;
    }

    if ( values[1] != 0 )
    {
        name  = values[1];
    }
    else
    {
        return -1;
    }

    if ( values[3] != 0 )
    {
        value = values[3];
    }
    else
    {
        return -1;
    }

    if ( values[2] != 0 )
    {
        atype = atoi(values[2]);

        switch (atype)
        {
        case Attribute::SIMPLE:
            attr = new SingleAttribute(name);
            break;

        case Attribute::VECTOR:
            attr = new VectorAttribute(name);
            break;

        default:
            return -1;
            break;
        };
    }

    attr->unmarshall(value);

    set(attr);

    return 0;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int TemplateSQL::select(SqlDB * db)
{
    ostringstream   oss;
    int             rc;

    if ( id == -1 )
    {
        return -1;
    }

    set_callback(static_cast<Callbackable::Callback>(&TemplateSQL::select_cb));

    oss << "SELECT * FROM " << table << " WHERE id=" << id;

    rc = db->exec(oss,this);

    unset_callback();

    return rc;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int TemplateSQL::drop(SqlDB * db)
{
    ostringstream   oss;

    if ( id == -1 )
    {
        return -1;
    }

    oss << "DELETE FROM " << table << " WHERE id=" << id;

    return db->exec(oss);
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int TemplateSQL::replace_attribute(SqlDB * db, Attribute * attribute)
{
    ostringstream   oss;
    int             rc;

    multimap<string, Attribute *>::iterator i;

    if ( id == -1 || attribute == 0)
    {
        return -1;
    }

    rc  = remove_attribute(db, attribute->name());

    if (rc == 0)
    {
        rc = insert_attribute(db,attribute);
    }

    return rc;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int TemplateSQL::insert_attribute(SqlDB * db, Attribute * attribute)
{
    ostringstream   oss;
    int             rc;
    string *        astr;
    int             atype;

    char *          sql_attr;

    if ( id == -1 || attribute == 0)
    {
        return -1;
    }

    astr  = attribute->marshall();
    atype = attribute->type();

    if ( astr == 0 )
    {
        return -1;
    }

    sql_attr = db->escape_str((*astr).c_str());

    delete astr;

    if ( sql_attr == 0 )
    {
        return -1;
    }

    oss << "INSERT INTO " << table << " " << db_names
        << " VALUES (" << id << ",'" << attribute->name() << "'," << atype
        << ",'" << sql_attr << "')";

    rc = db->exec(oss);

    db->free_str(sql_attr);

    if (rc == 0)
    {
        attributes.insert(make_pair(attribute->name(),attribute));
    }

    return rc;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int TemplateSQL::remove_attribute(SqlDB * db, const string& name)
{
    ostringstream   oss;
    int             rc;
    string *        astr;
    char *          sql_attr;

    multimap<string, Attribute *>::iterator i;

    if ( id == -1 )
    {
        return -1;
    }

    i = attributes.find(name);

    if ( i != attributes.end() )
    {
        astr = i->second->marshall();

        if ( astr == 0 )
        {
            return -1;
        }

        sql_attr = db->escape_str((*astr).c_str());

        delete astr;

        if ( sql_attr == 0 )
        {
            return -1;
        }

        oss << "DELETE FROM " << table << " WHERE id=" << id
            << " AND name='" << name << "' AND value='"
            << sql_attr << "'";

        rc = db->exec(oss);

        db->free_str(sql_attr);

        if (rc != 0 )
        {
            return rc;
        }

        delete i->second;

        attributes.erase(i);
    }

    return 0;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

<|endoftext|>