<commit_before>#include "cfilelistview.h"
#include "../columns.h"
#include "model/cfilelistsortfilterproxymodel.h"
#include "delegate/cfilelistitemdelegate.h"

DISABLE_COMPILER_WARNINGS
#include <QApplication>
#include <QDebug>
#include <QDragMoveEvent>
#include <QHeaderView>
#include <QKeyEvent>
#include <QMouseEvent>
RESTORE_COMPILER_WARNINGS

#include <time.h>
#include <set>

#if defined __linux__ || defined __APPLE__
#include "cfocusframestyle.h"
#endif

CFileListView::CFileListView(QWidget *parent) :
	QTreeView(parent),
	_controller(CController::get())
{
	setMouseTracking(true);
	setItemDelegate(new CFileListItemDelegate);
	connect(this, &QTreeView::doubleClicked, [this](const QModelIndex &idx) {

		_currentItemBeforeMouseClick = QModelIndex();
		_singleMouseClickValid = false;

		for(FileListViewEventObserver* observer: _eventObservers)
		{
			if (observer->fileListReturnPressOrDoubleClickPerformed(idx))
				break;
		}
	});

	QHeaderView * headerView = header();
	assert_r(headerView);

	headerView->installEventFilter(this);

#if defined __linux__ || defined __APPLE__
	setStyle(new CFocusFrameStyle);
#endif
}

void CFileListView::addEventObserver(FileListViewEventObserver* observer)
{
	_eventObservers.push_back(observer);
}

// Sets the position (left or right) of a panel that this model represents
void CFileListView::setPanelPosition(enum Panel p)
{
	assert_r(_panelPosition == UnknownPanel); // Doesn't make sense to call this method more than once
	_panelPosition = p;
}

// Preserves item's selection state
void CFileListView::moveCursorToItem(const QModelIndex& index, bool invertSelection)
{
	if (index.isValid() && selectionModel()->model()->hasIndex(index.row(), index.column()))
	{
		const QModelIndex normalizedTargetIndex = model()->index(index.row(), index.column()); // There was some problem with using the index directly, like it was from the wrong model or something
		const QModelIndex currentIdx = currentIndex();
		if (invertSelection && currentIdx.isValid())
		{
			int startRow = std::min(currentIdx.row(), normalizedTargetIndex.row());
			int endRow = std::max(currentIdx.row(), normalizedTargetIndex.row());
			for (int row = startRow; row <= endRow; ++row)
				selectionModel()->setCurrentIndex(model()->index(row, 0), (!_shiftPressedItemSelected ? QItemSelectionModel::Select : QItemSelectionModel::Deselect) | QItemSelectionModel::Rows);
		}

		selectionModel()->setCurrentIndex(normalizedTargetIndex, QItemSelectionModel::Current | QItemSelectionModel::Rows);
		scrollTo(normalizedTargetIndex);
	}
}

// Header management
void CFileListView::saveHeaderState()
{
	if (header())
	{
		_headerGeometry = header()->saveGeometry();
		_headerState    = header()->saveState();
	}
}

void CFileListView::restoreHeaderState()
{
	QHeaderView * headerView = header();
	assert_and_return_r(headerView, );

	if (!_headerGeometry.isEmpty())
		headerView->restoreGeometry(_headerGeometry);
	if (!_headerState.isEmpty())
		headerView->restoreState(_headerState);
}

void CFileListView::invertSelection()
{
	QItemSelection allItems(model()->index(0, 0), model()->index(model()->rowCount() - 1, 0));
	selectionModel()->select(allItems, QItemSelectionModel::Toggle | QItemSelectionModel::Rows);
}

void CFileListView::modelAboutToBeReset()
{
	_currentItemBeforeMouseClick = QModelIndex();
	_singleMouseClickValid = false;
	if (_bHeaderAdjustmentRequired)
	{
		_bHeaderAdjustmentRequired = false;
		for (int i = 0; i < model()->columnCount(); ++i)
			resizeColumnToContents(i);
		sortByColumn(ExtColumn, Qt::AscendingOrder);
	}
}

// For managing selection and cursor
void CFileListView::mousePressEvent(QMouseEvent *e)
{
	_singleMouseClickValid = !_singleMouseClickValid && e->modifiers() == Qt::NoModifier;
	_currentItemBeforeMouseClick = currentIndex();
	const bool selectionWasEmpty = selectionModel()->selectedRows().empty();

	// Always let Qt process this event
	QTreeView::mousePressEvent(e);

	if (_currentItemShouldBeSelectedOnMouseClick && e->modifiers() == Qt::ControlModifier && selectionWasEmpty && _currentItemBeforeMouseClick.isValid())
	{
		_currentItemShouldBeSelectedOnMouseClick = false;
		selectionModel()->select(_currentItemBeforeMouseClick, QItemSelectionModel::Rows | QItemSelectionModel::Select);
	}
}

void CFileListView::mouseMoveEvent(QMouseEvent * e)
{
	if (_singleMouseClickValid && (e->pos() - _singleMouseClickPos).manhattanLength() > 15)
	{
		_singleMouseClickValid = false;
		_currentItemBeforeMouseClick = QModelIndex();
	}

	QTreeView::mouseMoveEvent(e);
}

// For showing context menu
void CFileListView::mouseReleaseEvent(QMouseEvent *event)
{
	if (event->button() == Qt::RightButton)
	{
		// Selecting an item that was clicked upon
		const auto index = indexAt(event->pos());
		if (!index.isValid())
			clearSelection(); // clearing selection if there wasn't any item under cursor

		// Calling a context menu
		emit contextMenuRequested(QCursor::pos()); // Getting global screen coordinates
	}
	else if (event->button() == Qt::LeftButton)
	{
		const QModelIndex itemClicked = indexAt(event->pos());
		if (_currentItemBeforeMouseClick == itemClicked && _singleMouseClickValid && event->modifiers() == Qt::NoModifier)
		{
			_singleMouseClickPos = event->pos();
			QTimer::singleShot(QApplication::doubleClickInterval()+50, [this]() {
				if (_singleMouseClickValid)
				{
					edit(model()->index(currentIndex().row(), 0), AllEditTriggers, nullptr);
					_currentItemBeforeMouseClick = QModelIndex();
					_singleMouseClickValid = false;
				}
			});
		}

		// Bug fix for #49 - preventing item selection with a single LMB click
		if (event->modifiers() == Qt::NoModifier && itemClicked.isValid())
			selectionModel()->clearSelection();
	}

	// Always let Qt process this event
	QTreeView::mouseReleaseEvent(event);
}

// For managing selection and cursor
void CFileListView::keyPressEvent(QKeyEvent *event)
{
	if (event->key() == Qt::Key_Control)
		_currentItemShouldBeSelectedOnMouseClick = true;

	if (event->key() == Qt::Key_Down || event->key() == Qt::Key_Up ||
		event->key() == Qt::Key_PageDown || event->key() == Qt::Key_PageUp ||
		event->key() == Qt::Key_Home || event->key() == Qt::Key_End)
	{
		if ((event->modifiers() & (~Qt::KeypadModifier) & (~Qt::ShiftModifier)) == Qt::NoModifier)
		{
			const bool shiftPressed = (event->modifiers() & Qt::ShiftModifier) != 0;
			if (shiftPressed)
				_shiftPressedItemSelected = currentIndex().isValid() ? selectionModel()->isSelected(currentIndex()) : false;

			if (event->key() == Qt::Key_Down)
				moveCursorToNextItem(shiftPressed);
			else if (event->key() == Qt::Key_Up)
				moveCursorToPreviousItem(shiftPressed);
			else if (event->key() == Qt::Key_Home)
				moveCursorToItem(model()->index(0, 0), shiftPressed);
			else if (event->key() == Qt::Key_End)
				moveCursorToItem(model()->index(model()->rowCount()-1, 0), shiftPressed);
			else if (event->key() == Qt::Key_PageUp)
				pgUp(shiftPressed);
			else if (event->key() == Qt::Key_PageDown)
				pgDn(shiftPressed);

			event->accept();
			return;
		}
	}
	else if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
	{
		const auto modifiers = event->modifiers() & ~Qt::KeypadModifier;
		if (modifiers == Qt::NoModifier)
		{
			bool returnPressConsumed = false;
			for(FileListViewEventObserver* observer: _eventObservers)
			{
				returnPressConsumed = observer->fileListReturnPressed();
				if (returnPressConsumed)
					break;
			}

			if (!returnPressConsumed)
				for (FileListViewEventObserver* observer: _eventObservers)
				{
					if (currentIndex().isValid())
					{
						returnPressConsumed = observer->fileListReturnPressOrDoubleClickPerformed(currentIndex());
						if (returnPressConsumed)
							break;
					}
				}

		}
		else if (modifiers == Qt::ControlModifier)
			emit ctrlEnterPressed();
		else if (modifiers == (Qt::ControlModifier | Qt::ShiftModifier))
			emit ctrlShiftEnterPressed();

		return;
	}
	else if (event->key() == Qt::Key_Shift)
	{
		_shiftPressedItemSelected = currentIndex().isValid() ? selectionModel()->isSelected(currentIndex()) : false;
	}
	else
		emit keyPressed(event->text(), event->key(), event->modifiers());

	QTreeView::keyPressEvent(event);

#ifdef __linux__
	// FIXME: find out why this hack is necessary
	if (event->key() == Qt::Key_Down || event->key() == Qt::Key_Up ||
		event->key() == Qt::Key_PageDown || event->key() == Qt::Key_PageUp ||
		event->key() == Qt::Key_Home || event->key() == Qt::Key_End)
		if ((event->modifiers() & Qt::ShiftModifier) != 0)
			scrollTo(currentIndex());
#endif
}

void CFileListView::keyReleaseEvent(QKeyEvent * event)
{
	if (event->key() == Qt::Key_Control)
		_currentItemShouldBeSelectedOnMouseClick = true;

	QTreeView::keyReleaseEvent(event);
}

bool CFileListView::edit(const QModelIndex & index, QAbstractItemView::EditTrigger trigger, QEvent * event)
{
	return QTreeView::edit(model()->index(index.row(), 0), trigger, event);
}

// canDropMimeData is not called by QAbstractItemModel as of Qt 5.3 (https://bugreports.qt-project.org/browse/QTBUG-30534), so we're re-defining dragEnterEvent to fix this
void CFileListView::dragMoveEvent(QDragMoveEvent * event)
{
	QModelIndex targetIndex = indexAt(event->pos());
	if (model()->canDropMimeData(event->mimeData(), (Qt::DropAction)((int)event->possibleActions()), targetIndex.row(), targetIndex.column(), QModelIndex()))
	{
		if (state() != DraggingState)
			setState(DraggingState);
		QTreeView::dragMoveEvent(event);
	}
	else
		event->ignore();
}

bool CFileListView::eventFilter(QObject* target, QEvent* event)
{
	QHeaderView * headerView = header();
	if (target == headerView && event && event->type() == QEvent::Resize && headerView->count() == NumberOfColumns)
	{
		auto resizeEvent = dynamic_cast<QResizeEvent*>(event);
		assert_and_return_r(resizeEvent, false);
		float oldHeaderWidth = 0.0f;
		for (int i = 0; i < headerView->count(); ++i)
			oldHeaderWidth += (float)headerView->sectionSize(i);

		const float newHeaderWidth = (float)resizeEvent->size().width();
		if (oldHeaderWidth <= 0.0f || newHeaderWidth <= 0.0f || oldHeaderWidth == newHeaderWidth)
			return false;

		std::vector<float> relativeColumnSizes(NumberOfColumns, 0.0f);
		for (int i = 0; i < headerView->count(); ++i)
			relativeColumnSizes[i] = headerView->sectionSize(i) / oldHeaderWidth;

		for (int i = 0; i < headerView->count(); ++i)
			headerView->resizeSection(i, (int)(newHeaderWidth * relativeColumnSizes[i] + 0.5f));

		return false;
	}

	return QTreeView::eventFilter(target, event);
}

void CFileListView::selectRegion(const QModelIndex &start, const QModelIndex &end)
{
	bool itemBelongsToSelection = false;
	assert_r(selectionModel());
	for (int i = 0; i < model()->rowCount(); ++i)
	{
		// Start item found - beginning selection
		QModelIndex currentItem = model()->index(i, 0);
		if (!itemBelongsToSelection && (currentItem == start || currentItem == end))
		{
			itemBelongsToSelection = true;
			selectionModel()->select(currentItem, QItemSelectionModel::Select | QItemSelectionModel::Rows);
		}
		else if (itemBelongsToSelection && (currentItem == start || currentItem == end))
		{
			// End item found - finishing selection
			selectionModel()->select(currentItem, QItemSelectionModel::Select | QItemSelectionModel::Rows);
			return;
		}

		if (itemBelongsToSelection)
			selectionModel()->select(currentItem, QItemSelectionModel::Select | QItemSelectionModel::Rows);
	}
}

void CFileListView::moveCursorToNextItem(bool invertSelection)
{
	if (model()->rowCount() <= 0)
		return;

	const QModelIndex curIdx(currentIndex());
	if (curIdx.isValid() && curIdx.row()+1 < model()->rowCount())
		moveCursorToItem(model()->index(curIdx.row()+1, 0), invertSelection);
	else if (!curIdx.isValid())
		moveCursorToItem(model()->index(0, 0), invertSelection);
}

void CFileListView::moveCursorToPreviousItem(bool invertSelection)
{
	if (model()->rowCount() <= 0)
		return;

	const QModelIndex curIdx(currentIndex());
	if (curIdx.isValid() && curIdx.row() > 0)
		moveCursorToItem(model()->index(curIdx.row()-1, 0), invertSelection);
	else if (!curIdx.isValid())
		moveCursorToItem(model()->index(0, 0), invertSelection);
}

void CFileListView::pgUp(bool invertSelection)
{
	const QModelIndex curIdx(currentIndex());
	if (!curIdx.isValid())
		return;

	const int numItemsVisible = numRowsVisible();
	if (numItemsVisible <= 0)
		return;

	moveCursorToItem(model()->index(std::max(curIdx.row()-numItemsVisible, 0), 0), invertSelection);
}

void CFileListView::pgDn(bool invertSelection)
{
	const QModelIndex curIdx(currentIndex());
	if (!curIdx.isValid())
		return;

	const int numItemsVisible = numRowsVisible();
	if (numItemsVisible <= 0)
		return;

	moveCursorToItem(model()->index(std::min(curIdx.row()+numItemsVisible, model()->rowCount()-1), 0), invertSelection);
}

int CFileListView::numRowsVisible() const
{
	// FIXME: rewrite it with indexAt to be O(1)
	int numRowsVisible = 0;
	for(int row = 0; row < model()->rowCount(); row++)
	{
		if (visualRect(model()->index(row, 0)).intersects(viewport()->rect()))
			++numRowsVisible;
	}
	return numRowsVisible;
}

void CFileListView::setHeaderAdjustmentRequired(bool required)
{
	_bHeaderAdjustmentRequired = required;
}
<commit_msg>Fixed #126<commit_after>#include "cfilelistview.h"
#include "../columns.h"
#include "model/cfilelistsortfilterproxymodel.h"
#include "delegate/cfilelistitemdelegate.h"

DISABLE_COMPILER_WARNINGS
#include <QApplication>
#include <QDebug>
#include <QDragMoveEvent>
#include <QHeaderView>
#include <QKeyEvent>
#include <QMouseEvent>
RESTORE_COMPILER_WARNINGS

#include <time.h>
#include <set>

#if defined __linux__ || defined __APPLE__
#include "cfocusframestyle.h"
#endif

CFileListView::CFileListView(QWidget *parent) :
	QTreeView(parent),
	_controller(CController::get())
{
	setMouseTracking(true);
	setItemDelegate(new CFileListItemDelegate);
	connect(this, &QTreeView::doubleClicked, [this](const QModelIndex &idx) {

		_currentItemBeforeMouseClick = QModelIndex();
		_singleMouseClickValid = false;

		for(FileListViewEventObserver* observer: _eventObservers)
		{
			if (observer->fileListReturnPressOrDoubleClickPerformed(idx))
				break;
		}
	});

	QHeaderView * headerView = header();
	assert_r(headerView);

	headerView->installEventFilter(this);

#if defined __linux__ || defined __APPLE__
	setStyle(new CFocusFrameStyle);
#endif
}

void CFileListView::addEventObserver(FileListViewEventObserver* observer)
{
	_eventObservers.push_back(observer);
}

// Sets the position (left or right) of a panel that this model represents
void CFileListView::setPanelPosition(enum Panel p)
{
	assert_r(_panelPosition == UnknownPanel); // Doesn't make sense to call this method more than once
	_panelPosition = p;
}

// Preserves item's selection state
void CFileListView::moveCursorToItem(const QModelIndex& index, bool invertSelection)
{
	if (index.isValid() && selectionModel()->model()->hasIndex(index.row(), index.column()))
	{
		const QModelIndex normalizedTargetIndex = model()->index(index.row(), index.column()); // There was some problem with using the index directly, like it was from the wrong model or something
		const QModelIndex currentIdx = currentIndex();
		if (invertSelection && currentIdx.isValid())
		{
			for (int row = std::min(currentIdx.row(), normalizedTargetIndex.row()), endRow = std::max(currentIdx.row(), normalizedTargetIndex.row()); row <= endRow; ++row)
				selectionModel()->setCurrentIndex(model()->index(row, 0), (_shiftPressedItemSelected ? QItemSelectionModel::Deselect : QItemSelectionModel::Select) | QItemSelectionModel::Rows);
		}

		selectionModel()->setCurrentIndex(normalizedTargetIndex, QItemSelectionModel::Current | QItemSelectionModel::Rows);
		scrollTo(normalizedTargetIndex);
	}
}

// Header management
void CFileListView::saveHeaderState()
{
	if (header())
	{
		_headerGeometry = header()->saveGeometry();
		_headerState    = header()->saveState();
	}
}

void CFileListView::restoreHeaderState()
{
	QHeaderView * headerView = header();
	assert_and_return_r(headerView, );

	if (!_headerGeometry.isEmpty())
		headerView->restoreGeometry(_headerGeometry);
	if (!_headerState.isEmpty())
		headerView->restoreState(_headerState);
}

void CFileListView::invertSelection()
{
	QItemSelection allItems(model()->index(0, 0), model()->index(model()->rowCount() - 1, 0));
	selectionModel()->select(allItems, QItemSelectionModel::Toggle | QItemSelectionModel::Rows);
}

void CFileListView::modelAboutToBeReset()
{
	_currentItemBeforeMouseClick = QModelIndex();
	_singleMouseClickValid = false;
	if (_bHeaderAdjustmentRequired)
	{
		_bHeaderAdjustmentRequired = false;
		for (int i = 0; i < model()->columnCount(); ++i)
			resizeColumnToContents(i);
		sortByColumn(ExtColumn, Qt::AscendingOrder);
	}
}

// For managing selection and cursor
void CFileListView::mousePressEvent(QMouseEvent *e)
{
	_singleMouseClickValid = !_singleMouseClickValid && e->modifiers() == Qt::NoModifier;
	_currentItemBeforeMouseClick = currentIndex();
	const bool selectionWasEmpty = selectionModel()->selectedRows().empty();

	// Always let Qt process this event
	QTreeView::mousePressEvent(e);

	if (_currentItemShouldBeSelectedOnMouseClick && e->modifiers() == Qt::ControlModifier && selectionWasEmpty && _currentItemBeforeMouseClick.isValid())
	{
		_currentItemShouldBeSelectedOnMouseClick = false;
		selectionModel()->select(_currentItemBeforeMouseClick, QItemSelectionModel::Rows | QItemSelectionModel::Select);
	}
}

void CFileListView::mouseMoveEvent(QMouseEvent * e)
{
	if (_singleMouseClickValid && (e->pos() - _singleMouseClickPos).manhattanLength() > 15)
	{
		_singleMouseClickValid = false;
		_currentItemBeforeMouseClick = QModelIndex();
	}

	QTreeView::mouseMoveEvent(e);
}

// For showing context menu
void CFileListView::mouseReleaseEvent(QMouseEvent *event)
{
	if (event->button() == Qt::RightButton)
	{
		// Selecting an item that was clicked upon
		const auto index = indexAt(event->pos());
		if (!index.isValid())
			clearSelection(); // clearing selection if there wasn't any item under cursor

		// Calling a context menu
		emit contextMenuRequested(QCursor::pos()); // Getting global screen coordinates
	}
	else if (event->button() == Qt::LeftButton)
	{
		const QModelIndex itemClicked = indexAt(event->pos());
		if (_currentItemBeforeMouseClick == itemClicked && _singleMouseClickValid && event->modifiers() == Qt::NoModifier)
		{
			_singleMouseClickPos = event->pos();
			QTimer::singleShot(QApplication::doubleClickInterval()+50, [this]() {
				if (_singleMouseClickValid)
				{
					edit(model()->index(currentIndex().row(), 0), AllEditTriggers, nullptr);
					_currentItemBeforeMouseClick = QModelIndex();
					_singleMouseClickValid = false;
				}
			});
		}

		// Bug fix for #49 - preventing item selection with a single LMB click
		if (event->modifiers() == Qt::NoModifier && itemClicked.isValid())
			selectionModel()->clearSelection();
	}

	// Always let Qt process this event
	QTreeView::mouseReleaseEvent(event);
}

// For managing selection and cursor
void CFileListView::keyPressEvent(QKeyEvent *event)
{
	if (event->key() == Qt::Key_Control)
		_currentItemShouldBeSelectedOnMouseClick = true;

	if (event->key() == Qt::Key_Down || event->key() == Qt::Key_Up ||
		event->key() == Qt::Key_PageDown || event->key() == Qt::Key_PageUp ||
		event->key() == Qt::Key_Home || event->key() == Qt::Key_End)
	{
		if ((event->modifiers() & ~Qt::KeypadModifier & ~Qt::ShiftModifier) == Qt::NoModifier)
		{
			const bool shiftPressed = (event->modifiers() & Qt::ShiftModifier) != 0;
			if (event->key() == Qt::Key_Down)
				moveCursorToNextItem(shiftPressed);
			else if (event->key() == Qt::Key_Up)
				moveCursorToPreviousItem(shiftPressed);
			else if (event->key() == Qt::Key_Home)
				moveCursorToItem(model()->index(0, 0), shiftPressed);
			else if (event->key() == Qt::Key_End)
				moveCursorToItem(model()->index(model()->rowCount()-1, 0), shiftPressed);
			else if (event->key() == Qt::Key_PageUp)
				pgUp(shiftPressed);
			else if (event->key() == Qt::Key_PageDown)
				pgDn(shiftPressed);

			event->accept();
			return;
		}
	}
	else if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
	{
		const auto modifiers = event->modifiers() & ~Qt::KeypadModifier;
		if (modifiers == Qt::NoModifier)
		{
			bool returnPressConsumed = false;
			for(FileListViewEventObserver* observer: _eventObservers)
			{
				returnPressConsumed = observer->fileListReturnPressed();
				if (returnPressConsumed)
					break;
			}

			if (!returnPressConsumed)
				for (FileListViewEventObserver* observer: _eventObservers)
				{
					if (currentIndex().isValid())
					{
						returnPressConsumed = observer->fileListReturnPressOrDoubleClickPerformed(currentIndex());
						if (returnPressConsumed)
							break;
					}
				}

		}
		else if (modifiers == Qt::ControlModifier)
			emit ctrlEnterPressed();
		else if (modifiers == (Qt::ControlModifier | Qt::ShiftModifier))
			emit ctrlShiftEnterPressed();

		return;
	}
	else if (event->key() == Qt::Key_Shift)
	{
		_shiftPressedItemSelected = currentIndex().isValid() ? selectionModel()->isSelected(currentIndex()) : false;
	}
	else
		emit keyPressed(event->text(), event->key(), event->modifiers());

	QTreeView::keyPressEvent(event);

#ifdef __linux__
	// FIXME: find out why this hack is necessary
	if (event->key() == Qt::Key_Down || event->key() == Qt::Key_Up ||
		event->key() == Qt::Key_PageDown || event->key() == Qt::Key_PageUp ||
		event->key() == Qt::Key_Home || event->key() == Qt::Key_End)
		if ((event->modifiers() & Qt::ShiftModifier) != 0)
			scrollTo(currentIndex());
#endif
}

void CFileListView::keyReleaseEvent(QKeyEvent * event)
{
	if (event->key() == Qt::Key_Control)
		_currentItemShouldBeSelectedOnMouseClick = true;
	else if (event->key() == Qt::Key_Shift)
		_shiftPressedItemSelected = false;

	QTreeView::keyReleaseEvent(event);
}

bool CFileListView::edit(const QModelIndex & index, QAbstractItemView::EditTrigger trigger, QEvent * event)
{
	return QTreeView::edit(model()->index(index.row(), 0), trigger, event);
}

// canDropMimeData is not called by QAbstractItemModel as of Qt 5.3 (https://bugreports.qt-project.org/browse/QTBUG-30534), so we're re-defining dragEnterEvent to fix this
void CFileListView::dragMoveEvent(QDragMoveEvent * event)
{
	QModelIndex targetIndex = indexAt(event->pos());
	if (model()->canDropMimeData(event->mimeData(), (Qt::DropAction)((int)event->possibleActions()), targetIndex.row(), targetIndex.column(), QModelIndex()))
	{
		if (state() != DraggingState)
			setState(DraggingState);
		QTreeView::dragMoveEvent(event);
	}
	else
		event->ignore();
}

bool CFileListView::eventFilter(QObject* target, QEvent* event)
{
	QHeaderView * headerView = header();
	if (target == headerView && event && event->type() == QEvent::Resize && headerView->count() == NumberOfColumns)
	{
		auto resizeEvent = dynamic_cast<QResizeEvent*>(event);
		assert_and_return_r(resizeEvent, false);
		float oldHeaderWidth = 0.0f;
		for (int i = 0; i < headerView->count(); ++i)
			oldHeaderWidth += (float)headerView->sectionSize(i);

		const float newHeaderWidth = (float)resizeEvent->size().width();
		if (oldHeaderWidth <= 0.0f || newHeaderWidth <= 0.0f || oldHeaderWidth == newHeaderWidth)
			return false;

		std::vector<float> relativeColumnSizes(NumberOfColumns, 0.0f);
		for (int i = 0; i < headerView->count(); ++i)
			relativeColumnSizes[i] = headerView->sectionSize(i) / oldHeaderWidth;

		for (int i = 0; i < headerView->count(); ++i)
			headerView->resizeSection(i, (int)(newHeaderWidth * relativeColumnSizes[i] + 0.5f));

		return false;
	}

	return QTreeView::eventFilter(target, event);
}

void CFileListView::selectRegion(const QModelIndex &start, const QModelIndex &end)
{
	bool itemBelongsToSelection = false;
	assert_r(selectionModel());
	for (int i = 0; i < model()->rowCount(); ++i)
	{
		// Start item found - beginning selection
		QModelIndex currentItem = model()->index(i, 0);
		if (!itemBelongsToSelection && (currentItem == start || currentItem == end))
		{
			itemBelongsToSelection = true;
			selectionModel()->select(currentItem, QItemSelectionModel::Select | QItemSelectionModel::Rows);
		}
		else if (itemBelongsToSelection && (currentItem == start || currentItem == end))
		{
			// End item found - finishing selection
			selectionModel()->select(currentItem, QItemSelectionModel::Select | QItemSelectionModel::Rows);
			return;
		}

		if (itemBelongsToSelection)
			selectionModel()->select(currentItem, QItemSelectionModel::Select | QItemSelectionModel::Rows);
	}
}

void CFileListView::moveCursorToNextItem(bool invertSelection)
{
	if (model()->rowCount() <= 0)
		return;

	const QModelIndex curIdx(currentIndex());
	if (curIdx.isValid() && curIdx.row()+1 < model()->rowCount())
		moveCursorToItem(model()->index(curIdx.row()+1, 0), invertSelection);
	else if (!curIdx.isValid())
		moveCursorToItem(model()->index(0, 0), invertSelection);
}

void CFileListView::moveCursorToPreviousItem(bool invertSelection)
{
	if (model()->rowCount() <= 0)
		return;

	const QModelIndex curIdx(currentIndex());
	if (curIdx.isValid() && curIdx.row() > 0)
		moveCursorToItem(model()->index(curIdx.row()-1, 0), invertSelection);
	else if (!curIdx.isValid())
		moveCursorToItem(model()->index(0, 0), invertSelection);
}

void CFileListView::pgUp(bool invertSelection)
{
	const QModelIndex curIdx(currentIndex());
	if (!curIdx.isValid())
		return;

	const int numItemsVisible = numRowsVisible();
	if (numItemsVisible <= 0)
		return;

	moveCursorToItem(model()->index(std::max(curIdx.row()-numItemsVisible, 0), 0), invertSelection);
}

void CFileListView::pgDn(bool invertSelection)
{
	const QModelIndex curIdx(currentIndex());
	if (!curIdx.isValid())
		return;

	const int numItemsVisible = numRowsVisible();
	if (numItemsVisible <= 0)
		return;

	moveCursorToItem(model()->index(std::min(curIdx.row()+numItemsVisible, model()->rowCount()-1), 0), invertSelection);
}

int CFileListView::numRowsVisible() const
{
	// TODO: rewrite it with indexAt to be O(1)
	int numRowsVisible = 0;
	for(int row = 0, numRows = model()->rowCount(); row < numRows; row++)
	{
		if (visualRect(model()->index(row, 0)).intersects(viewport()->rect()))
			++numRowsVisible;
	}

	return numRowsVisible;
}

void CFileListView::setHeaderAdjustmentRequired(bool required)
{
	_bHeaderAdjustmentRequired = required;
}
<|endoftext|>


<commit_before>// Copyright (c) Facebook, Inc. and its affiliates.

// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.

#include "ComponentDescriptorRegistry.h"

#include <react/core/ShadowNodeFragment.h>
#include <react/uimanager/ComponentDescriptorProviderRegistry.h>
#include <react/uimanager/primitives.h>

namespace facebook {
namespace react {

ComponentDescriptorRegistry::ComponentDescriptorRegistry(
    ComponentDescriptorParameters const &parameters,
    ComponentDescriptorProviderRegistry const &providerRegistry)
    : parameters_(parameters), providerRegistry_(&providerRegistry) {}

void ComponentDescriptorRegistry::add(
    ComponentDescriptorProvider componentDescriptorProvider) const {
  std::unique_lock<better::shared_mutex> lock(mutex_);

  auto componentDescriptor = componentDescriptorProvider.constructor(
      {parameters_.eventDispatcher,
       parameters_.contextContainer,
       componentDescriptorProvider.flavor});
  assert(
      componentDescriptor->getComponentHandle() ==
      componentDescriptorProvider.handle);
  assert(
      componentDescriptor->getComponentName() ==
      componentDescriptorProvider.name);

  auto sharedComponentDescriptor = std::shared_ptr<ComponentDescriptor const>(
      std::move(componentDescriptor));
  _registryByHandle[componentDescriptorProvider.handle] =
      sharedComponentDescriptor;
  _registryByName[componentDescriptorProvider.name] = sharedComponentDescriptor;

  if (strcmp(componentDescriptorProvider.name, "UnimplementedNativeView") ==
      0) {
    auto *self = const_cast<ComponentDescriptorRegistry *>(this);
    self->setFallbackComponentDescriptor(sharedComponentDescriptor);
  }
}

void ComponentDescriptorRegistry::remove(
    ComponentDescriptorProvider componentDescriptorProvider) const {
  std::unique_lock<better::shared_mutex> lock(mutex_);

  assert(
      _registryByHandle.find(componentDescriptorProvider.handle) !=
      _registryByHandle.end());
  assert(
      _registryByName.find(componentDescriptorProvider.name) !=
      _registryByName.end());

  _registryByHandle.erase(componentDescriptorProvider.handle);
  _registryByName.erase(componentDescriptorProvider.name);
}

void ComponentDescriptorRegistry::registerComponentDescriptor(
    SharedComponentDescriptor componentDescriptor) const {
  ComponentHandle componentHandle = componentDescriptor->getComponentHandle();
  _registryByHandle[componentHandle] = componentDescriptor;

  ComponentName componentName = componentDescriptor->getComponentName();
  _registryByName[componentName] = componentDescriptor;
}

static std::string componentNameByReactViewName(std::string viewName) {
  // We need this function only for the transition period;
  // eventually, all names will be unified.

  std::string rctPrefix("RCT");
  if (std::mismatch(rctPrefix.begin(), rctPrefix.end(), viewName.begin())
          .first == rctPrefix.end()) {
    // If `viewName` has "RCT" prefix, remove it.
    viewName.erase(0, rctPrefix.length());
  }

  // Fabric uses slightly new names for Text components because of differences
  // in semantic.
  if (viewName == "Text") {
    return "Paragraph";
  }
  if (viewName == "VirtualText") {
    return "Text";
  }

  if (viewName == "ImageView") {
    return "Image";
  }

  if (viewName == "AndroidHorizontalScrollView") {
    return "ScrollView";
  }

  if (viewName == "RKShimmeringView") {
    return "ShimmeringView";
  }

  if (viewName == "AndroidProgressBar") {
    return "ActivityIndicatorView";
  }

  // We need this temporarily for testing purposes until we have proper
  // implementation of core components.
  if (viewName == "SafeAreaView" || viewName == "ScrollContentView" ||
      viewName == "AndroidHorizontalScrollContentView" // Android
  ) {
    return "View";
  }

  return viewName;
}

ComponentDescriptor const &ComponentDescriptorRegistry::at(
    std::string const &componentName) const {
  std::shared_lock<better::shared_mutex> lock(mutex_);

  auto unifiedComponentName = componentNameByReactViewName(componentName);

  auto it = _registryByName.find(unifiedComponentName);
  if (it == _registryByName.end()) {
    assert(providerRegistry_);

    mutex_.unlock_shared();
    providerRegistry_->request(unifiedComponentName.c_str());
    mutex_.lock_shared();

    it = _registryByName.find(unifiedComponentName);
    assert(it != _registryByName.end());
  }

  if (it == _registryByName.end()) {
    if (_fallbackComponentDescriptor == nullptr) {
      throw std::invalid_argument(
          ("Unable to find componentDescriptor for " + unifiedComponentName)
              .c_str());
    }
    return *_fallbackComponentDescriptor.get();
  }

  return *it->second;
}

ComponentDescriptor const &ComponentDescriptorRegistry::at(
    ComponentHandle componentHandle) const {
  std::shared_lock<better::shared_mutex> lock(mutex_);

  return *_registryByHandle.at(componentHandle);
}

SharedShadowNode ComponentDescriptorRegistry::createNode(
    Tag tag,
    std::string const &viewName,
    SurfaceId surfaceId,
    folly::dynamic const &propsDynamic,
    SharedEventTarget const &eventTarget) const {
  auto unifiedComponentName = componentNameByReactViewName(viewName);
  auto const &componentDescriptor = this->at(unifiedComponentName);

  auto const eventEmitter =
      componentDescriptor.createEventEmitter(std::move(eventTarget), tag);
  auto const props =
      componentDescriptor.cloneProps(nullptr, RawProps(propsDynamic));
  auto const state = componentDescriptor.createInitialState(
      ShadowNodeFragment{surfaceId, tag, props, eventEmitter});

  return componentDescriptor.createShadowNode({
      /* .tag = */ tag,
      /* .surfaceId = */ surfaceId,
      /* .props = */ props,
      /* .eventEmitter = */ eventEmitter,
      /* .children = */ ShadowNodeFragment::childrenPlaceholder(),
      /* .localData = */ ShadowNodeFragment::localDataPlaceholder(),
      /* .state = */ state,
  });
}

void ComponentDescriptorRegistry::setFallbackComponentDescriptor(
    SharedComponentDescriptor descriptor) {
  _fallbackComponentDescriptor = descriptor;
  registerComponentDescriptor(descriptor);
}

ComponentDescriptor::Shared
ComponentDescriptorRegistry::getFallbackComponentDescriptor() const {
  return _fallbackComponentDescriptor;
}

} // namespace react
} // namespace facebook
<commit_msg>Fix RCTRefreshControl component name in Fabric<commit_after>// Copyright (c) Facebook, Inc. and its affiliates.

// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.

#include "ComponentDescriptorRegistry.h"

#include <react/core/ShadowNodeFragment.h>
#include <react/uimanager/ComponentDescriptorProviderRegistry.h>
#include <react/uimanager/primitives.h>

namespace facebook {
namespace react {

ComponentDescriptorRegistry::ComponentDescriptorRegistry(
    ComponentDescriptorParameters const &parameters,
    ComponentDescriptorProviderRegistry const &providerRegistry)
    : parameters_(parameters), providerRegistry_(&providerRegistry) {}

void ComponentDescriptorRegistry::add(
    ComponentDescriptorProvider componentDescriptorProvider) const {
  std::unique_lock<better::shared_mutex> lock(mutex_);

  auto componentDescriptor = componentDescriptorProvider.constructor(
      {parameters_.eventDispatcher,
       parameters_.contextContainer,
       componentDescriptorProvider.flavor});
  assert(
      componentDescriptor->getComponentHandle() ==
      componentDescriptorProvider.handle);
  assert(
      componentDescriptor->getComponentName() ==
      componentDescriptorProvider.name);

  auto sharedComponentDescriptor = std::shared_ptr<ComponentDescriptor const>(
      std::move(componentDescriptor));
  _registryByHandle[componentDescriptorProvider.handle] =
      sharedComponentDescriptor;
  _registryByName[componentDescriptorProvider.name] = sharedComponentDescriptor;

  if (strcmp(componentDescriptorProvider.name, "UnimplementedNativeView") ==
      0) {
    auto *self = const_cast<ComponentDescriptorRegistry *>(this);
    self->setFallbackComponentDescriptor(sharedComponentDescriptor);
  }
}

void ComponentDescriptorRegistry::remove(
    ComponentDescriptorProvider componentDescriptorProvider) const {
  std::unique_lock<better::shared_mutex> lock(mutex_);

  assert(
      _registryByHandle.find(componentDescriptorProvider.handle) !=
      _registryByHandle.end());
  assert(
      _registryByName.find(componentDescriptorProvider.name) !=
      _registryByName.end());

  _registryByHandle.erase(componentDescriptorProvider.handle);
  _registryByName.erase(componentDescriptorProvider.name);
}

void ComponentDescriptorRegistry::registerComponentDescriptor(
    SharedComponentDescriptor componentDescriptor) const {
  ComponentHandle componentHandle = componentDescriptor->getComponentHandle();
  _registryByHandle[componentHandle] = componentDescriptor;

  ComponentName componentName = componentDescriptor->getComponentName();
  _registryByName[componentName] = componentDescriptor;
}

static std::string componentNameByReactViewName(std::string viewName) {
  // We need this function only for the transition period;
  // eventually, all names will be unified.

  std::string rctPrefix("RCT");
  if (std::mismatch(rctPrefix.begin(), rctPrefix.end(), viewName.begin())
          .first == rctPrefix.end()) {
    // If `viewName` has "RCT" prefix, remove it.
    viewName.erase(0, rctPrefix.length());
  }

  // Fabric uses slightly new names for Text components because of differences
  // in semantic.
  if (viewName == "Text") {
    return "Paragraph";
  }
  if (viewName == "VirtualText") {
    return "Text";
  }

  if (viewName == "ImageView") {
    return "Image";
  }

  if (viewName == "AndroidHorizontalScrollView") {
    return "ScrollView";
  }

  if (viewName == "RKShimmeringView") {
    return "ShimmeringView";
  }

  if (viewName == "RefreshControl") {
    return "PullToRefreshView";
  }

  if (viewName == "AndroidProgressBar") {
    return "ActivityIndicatorView";
  }

  // We need this temporarily for testing purposes until we have proper
  // implementation of core components.
  if (viewName == "SafeAreaView" || viewName == "ScrollContentView" ||
      viewName == "AndroidHorizontalScrollContentView" // Android
  ) {
    return "View";
  }

  return viewName;
}

ComponentDescriptor const &ComponentDescriptorRegistry::at(
    std::string const &componentName) const {
  std::shared_lock<better::shared_mutex> lock(mutex_);

  auto unifiedComponentName = componentNameByReactViewName(componentName);

  auto it = _registryByName.find(unifiedComponentName);
  if (it == _registryByName.end()) {
    assert(providerRegistry_);

    mutex_.unlock_shared();
    providerRegistry_->request(unifiedComponentName.c_str());
    mutex_.lock_shared();

    it = _registryByName.find(unifiedComponentName);
    assert(it != _registryByName.end());
  }

  if (it == _registryByName.end()) {
    if (_fallbackComponentDescriptor == nullptr) {
      throw std::invalid_argument(
          ("Unable to find componentDescriptor for " + unifiedComponentName)
              .c_str());
    }
    return *_fallbackComponentDescriptor.get();
  }

  return *it->second;
}

ComponentDescriptor const &ComponentDescriptorRegistry::at(
    ComponentHandle componentHandle) const {
  std::shared_lock<better::shared_mutex> lock(mutex_);

  return *_registryByHandle.at(componentHandle);
}

SharedShadowNode ComponentDescriptorRegistry::createNode(
    Tag tag,
    std::string const &viewName,
    SurfaceId surfaceId,
    folly::dynamic const &propsDynamic,
    SharedEventTarget const &eventTarget) const {
  auto unifiedComponentName = componentNameByReactViewName(viewName);
  auto const &componentDescriptor = this->at(unifiedComponentName);

  auto const eventEmitter =
      componentDescriptor.createEventEmitter(std::move(eventTarget), tag);
  auto const props =
      componentDescriptor.cloneProps(nullptr, RawProps(propsDynamic));
  auto const state = componentDescriptor.createInitialState(
      ShadowNodeFragment{surfaceId, tag, props, eventEmitter});

  return componentDescriptor.createShadowNode({
      /* .tag = */ tag,
      /* .surfaceId = */ surfaceId,
      /* .props = */ props,
      /* .eventEmitter = */ eventEmitter,
      /* .children = */ ShadowNodeFragment::childrenPlaceholder(),
      /* .localData = */ ShadowNodeFragment::localDataPlaceholder(),
      /* .state = */ state,
  });
}

void ComponentDescriptorRegistry::setFallbackComponentDescriptor(
    SharedComponentDescriptor descriptor) {
  _fallbackComponentDescriptor = descriptor;
  registerComponentDescriptor(descriptor);
}

ComponentDescriptor::Shared
ComponentDescriptorRegistry::getFallbackComponentDescriptor() const {
  return _fallbackComponentDescriptor;
}

} // namespace react
} // namespace facebook
<|endoftext|>


<commit_before>#include "autoattach.h"
#include <lua.hpp>
#include <mutex>
#include <stack>
#include <set>
#include <vector>
#include <intrin.h>
#include <detours.h>
#include "fp_call.h"
#include "../remotedebug/rdebug_delayload.h"

namespace autoattach {
	std::mutex lockLoadDll;
	std::set<std::wstring> loadedModules;
	std::set<lua_State*> hookLuaStates;
	fn_attach debuggerAttach;
	bool      attachProcess = false;
	HMODULE   hookDll = NULL;

	static bool hook_install(uintptr_t* pointer_ptr, uintptr_t detour) {
		LONG status;
		if ((status = DetourTransactionBegin()) == NO_ERROR) {
			if ((status = DetourUpdateThread(::GetCurrentThread())) == NO_ERROR) {
				if ((status = DetourAttach((PVOID*)pointer_ptr, (PVOID)detour)) == NO_ERROR) {
					if ((status = DetourTransactionCommit()) == NO_ERROR) {
						return true;
					}
				}
			}
			DetourTransactionAbort();
		}
		::SetLastError(status);
		return false;
	}

	static bool hook_uninstall(uintptr_t* pointer_ptr, uintptr_t detour) {
		LONG status;
		if ((status = DetourTransactionBegin()) == NO_ERROR) {
			if ((status = DetourUpdateThread(::GetCurrentThread())) == NO_ERROR) {
				if ((status = DetourDetach((PVOID*)pointer_ptr, (PVOID)detour)) == NO_ERROR) {
					if ((status = DetourTransactionCommit()) == NO_ERROR) {
						return true;
					}
				}
			}
			DetourTransactionAbort();
		}
		::SetLastError(status);
		return false;
	}

	namespace lua {
		namespace real {
			uintptr_t luaL_openlibs = 0;
			uintptr_t lua_close = 0;
			uintptr_t lua_settop = 0;
		}
		namespace fake_launch {
			static void __cdecl luaL_openlibs(lua_State* L) {
				base::c_call<void>(real::luaL_openlibs, L);
				debuggerAttach(L);
			}
		}
		namespace fake_attach {
			static void __cdecl luaL_openlibs(lua_State* L) {
				base::c_call<void>(real::luaL_openlibs, L);
				if (hookLuaStates.insert(L).second) {
					debuggerAttach(L);
				}
			}
			static void __cdecl lua_settop(lua_State *L, int index) {
				if (hookLuaStates.insert(L).second) {
					debuggerAttach(L);
				}
				return base::c_call<void>(real::lua_settop, L, index);
			}
			static void __cdecl lua_close(lua_State* L) {
				hookLuaStates.erase(L);
				return base::c_call<void>(real::lua_close, L);
			}
		}

		bool hook(HMODULE m) {
			struct Hook {
				uintptr_t& real;
				uintptr_t fake;
			};
			std::vector<Hook> tasks;

#define HOOK(type, name) do {\
			if (!real::##name) { \
				real::##name = (uintptr_t)GetProcAddress(m, #name); \
				if (!real::##name) return false; \
				tasks.push_back({real::##name, (uintptr_t)fake_##type##::##name}); \
			} \
		} while (0)

			if (attachProcess) {
				HOOK(attach, luaL_openlibs);
				HOOK(attach, lua_close);
				HOOK(attach, lua_settop);
			}
			else {
				HOOK(launch, luaL_openlibs);
			}

			for (size_t i = 0; i < tasks.size(); ++i) {
				if (!hook_install(&tasks[i].real, tasks[i].fake)) {
					for (ptrdiff_t j = i - 1; j >= 0; ++j) {
						hook_uninstall(&tasks[j].real, tasks[j].fake);
					}
					return false;
				}
			}
			return true;
		}
	}

	static HMODULE enumerateModules(HANDLE hProcess, HMODULE hModuleLast, PIMAGE_NT_HEADERS32 pNtHeader) {
		MEMORY_BASIC_INFORMATION mbi = { 0 };
		for (PBYTE pbLast = (PBYTE)hModuleLast + 0x10000;; pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) {
			if (VirtualQueryEx(hProcess, (PVOID)pbLast, &mbi, sizeof(mbi)) <= 0) {
				break;
			}
			if (((PBYTE)mbi.BaseAddress + mbi.RegionSize) < pbLast) {
				break;
			}
			if ((mbi.State != MEM_COMMIT) ||
				((mbi.Protect & 0xff) == PAGE_NOACCESS) ||
				(mbi.Protect & PAGE_GUARD)) {
				continue;
			}
			__try {
				IMAGE_DOS_HEADER idh;
				if (!ReadProcessMemory(hProcess, pbLast, &idh, sizeof(idh), NULL)) {
					continue;
				}
				if (idh.e_magic != IMAGE_DOS_SIGNATURE || (DWORD)idh.e_lfanew > mbi.RegionSize || (DWORD)idh.e_lfanew < sizeof(idh)) {
					continue;
				}
				if (!ReadProcessMemory(hProcess, pbLast + idh.e_lfanew, pNtHeader, sizeof(*pNtHeader), NULL)) {
					continue;
				}
				if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
					continue;
				}
				return (HMODULE)pbLast;
			}
			__except (EXCEPTION_EXECUTE_HANDLER) {
				continue;
			}
		}
		return NULL;
	}

	static bool tryHookLuaDll(HMODULE hModule) {
		if (hookDll) {
			return true;
		}
		wchar_t moduleName[MAX_PATH];
		GetModuleFileNameW(hModule, moduleName, MAX_PATH);
		if (loadedModules.find(moduleName) != loadedModules.end()) {
			return false;
		}
		loadedModules.insert(moduleName);
		if (!lua::hook(hModule)) {
			return false;
		}
		hookDll = hModule;
		remotedebug::delayload::set_luadll(hModule);
		remotedebug::delayload::set_luaapi(luaapi);
		return true;
	}

	static bool findLuaDll() {
		std::unique_lock<std::mutex> lock(lockLoadDll);
		HANDLE hProcess = GetCurrentProcess();
		HMODULE hModule = NULL;
		for (;;) {
			IMAGE_NT_HEADERS32 inh;
			if ((hModule = enumerateModules(hProcess, hModule, &inh)) == NULL) {
				break;
			}
			if (tryHookLuaDll(hModule)) {
				return true;
			}
		}
		return false;
	}

	uintptr_t realLoadLibraryExW = 0;
	HMODULE __stdcall fakeLoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) {
		HMODULE hModule = base::std_call<HMODULE>(realLoadLibraryExW, lpLibFileName, hFile, dwFlags);
		std::unique_lock<std::mutex> lock(lockLoadDll);
		tryHookLuaDll(hModule);
		return hModule;
	}

	static void waitLuaDll() {
		HMODULE hModuleKernel = GetModuleHandleW(L"kernel32.dll");
		if (hModuleKernel) {
			realLoadLibraryExW = (uintptr_t)GetProcAddress(hModuleKernel, "LoadLibraryExW");
			if (realLoadLibraryExW) {
				hook_install(&realLoadLibraryExW, (uintptr_t)fakeLoadLibraryExW);
			}
		}
	}

	void initialize(fn_attach attach, bool ap) {
		if (debuggerAttach) {
			if (!attachProcess && ap && hookDll) {
				attachProcess = ap;
				lua::hook(hookDll);
			}
			return;
		}
		debuggerAttach = attach;
		attachProcess  = ap;
		if (!findLuaDll()) {
			waitLuaDll();
		}
	}

	FARPROC luaapi(const char* name) {
#define FIND(api) \
		if (lua::real::##api && strcmp(name, #api) == 0) { \
			return (FARPROC)lua::real::##api; \
		}
		FIND(luaL_openlibs)
		FIND(lua_close)
		FIND(lua_settop)
		return 0;
#undef  FIND
	}
}
<commit_msg>修正一个错误<commit_after>#include "autoattach.h"
#include <lua.hpp>
#include <mutex>
#include <stack>
#include <set>
#include <vector>
#include <intrin.h>
#include <detours.h>
#include "fp_call.h"
#include "../remotedebug/rdebug_delayload.h"

namespace autoattach {
	std::mutex lockLoadDll;
	std::set<std::wstring> loadedModules;
	std::set<lua_State*> hookLuaStates;
	fn_attach debuggerAttach;
	bool      attachProcess = false;
	HMODULE   hookDll = NULL;

	static bool hook_install(uintptr_t* pointer_ptr, uintptr_t detour) {
		LONG status;
		if ((status = DetourTransactionBegin()) == NO_ERROR) {
			if ((status = DetourUpdateThread(::GetCurrentThread())) == NO_ERROR) {
				if ((status = DetourAttach((PVOID*)pointer_ptr, (PVOID)detour)) == NO_ERROR) {
					if ((status = DetourTransactionCommit()) == NO_ERROR) {
						return true;
					}
				}
			}
			DetourTransactionAbort();
		}
		::SetLastError(status);
		return false;
	}

	static bool hook_uninstall(uintptr_t* pointer_ptr, uintptr_t detour) {
		LONG status;
		if ((status = DetourTransactionBegin()) == NO_ERROR) {
			if ((status = DetourUpdateThread(::GetCurrentThread())) == NO_ERROR) {
				if ((status = DetourDetach((PVOID*)pointer_ptr, (PVOID)detour)) == NO_ERROR) {
					if ((status = DetourTransactionCommit()) == NO_ERROR) {
						return true;
					}
				}
			}
			DetourTransactionAbort();
		}
		::SetLastError(status);
		return false;
	}

	namespace lua {
		namespace real {
			uintptr_t luaL_openlibs = 0;
			uintptr_t lua_close = 0;
			uintptr_t lua_settop = 0;
		}
		namespace fake_launch {
			static void __cdecl luaL_openlibs(lua_State* L) {
				base::c_call<void>(real::luaL_openlibs, L);
				debuggerAttach(L);
			}
		}
		namespace fake_attach {
			static void __cdecl luaL_openlibs(lua_State* L) {
				base::c_call<void>(real::luaL_openlibs, L);
				if (hookLuaStates.insert(L).second) {
					debuggerAttach(L);
				}
			}
			static void __cdecl lua_settop(lua_State *L, int index) {
				if (hookLuaStates.insert(L).second) {
					debuggerAttach(L);
				}
				return base::c_call<void>(real::lua_settop, L, index);
			}
			static void __cdecl lua_close(lua_State* L) {
				base::c_call<void>(real::lua_close, L);
				hookLuaStates.erase(L);
			}
		}

		bool hook(HMODULE m) {
			struct Hook {
				uintptr_t& real;
				uintptr_t fake;
			};
			std::vector<Hook> tasks;

#define HOOK(type, name) do {\
			if (!real::##name) { \
				real::##name = (uintptr_t)GetProcAddress(m, #name); \
				if (!real::##name) return false; \
				tasks.push_back({real::##name, (uintptr_t)fake_##type##::##name}); \
			} \
		} while (0)

			if (attachProcess) {
				HOOK(attach, luaL_openlibs);
				HOOK(attach, lua_close);
				HOOK(attach, lua_settop);
			}
			else {
				HOOK(launch, luaL_openlibs);
			}

			for (size_t i = 0; i < tasks.size(); ++i) {
				if (!hook_install(&tasks[i].real, tasks[i].fake)) {
					for (ptrdiff_t j = i - 1; j >= 0; ++j) {
						hook_uninstall(&tasks[j].real, tasks[j].fake);
					}
					return false;
				}
			}
			return true;
		}
	}

	static HMODULE enumerateModules(HANDLE hProcess, HMODULE hModuleLast, PIMAGE_NT_HEADERS32 pNtHeader) {
		MEMORY_BASIC_INFORMATION mbi = { 0 };
		for (PBYTE pbLast = (PBYTE)hModuleLast + 0x10000;; pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) {
			if (VirtualQueryEx(hProcess, (PVOID)pbLast, &mbi, sizeof(mbi)) <= 0) {
				break;
			}
			if (((PBYTE)mbi.BaseAddress + mbi.RegionSize) < pbLast) {
				break;
			}
			if ((mbi.State != MEM_COMMIT) ||
				((mbi.Protect & 0xff) == PAGE_NOACCESS) ||
				(mbi.Protect & PAGE_GUARD)) {
				continue;
			}
			__try {
				IMAGE_DOS_HEADER idh;
				if (!ReadProcessMemory(hProcess, pbLast, &idh, sizeof(idh), NULL)) {
					continue;
				}
				if (idh.e_magic != IMAGE_DOS_SIGNATURE || (DWORD)idh.e_lfanew > mbi.RegionSize || (DWORD)idh.e_lfanew < sizeof(idh)) {
					continue;
				}
				if (!ReadProcessMemory(hProcess, pbLast + idh.e_lfanew, pNtHeader, sizeof(*pNtHeader), NULL)) {
					continue;
				}
				if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
					continue;
				}
				return (HMODULE)pbLast;
			}
			__except (EXCEPTION_EXECUTE_HANDLER) {
				continue;
			}
		}
		return NULL;
	}

	static bool tryHookLuaDll(HMODULE hModule) {
		if (hookDll) {
			return true;
		}
		wchar_t moduleName[MAX_PATH];
		GetModuleFileNameW(hModule, moduleName, MAX_PATH);
		if (loadedModules.find(moduleName) != loadedModules.end()) {
			return false;
		}
		loadedModules.insert(moduleName);
		if (!lua::hook(hModule)) {
			return false;
		}
		hookDll = hModule;
		remotedebug::delayload::set_luadll(hModule);
		remotedebug::delayload::set_luaapi(luaapi);
		return true;
	}

	static bool findLuaDll() {
		std::unique_lock<std::mutex> lock(lockLoadDll);
		HANDLE hProcess = GetCurrentProcess();
		HMODULE hModule = NULL;
		for (;;) {
			IMAGE_NT_HEADERS32 inh;
			if ((hModule = enumerateModules(hProcess, hModule, &inh)) == NULL) {
				break;
			}
			if (tryHookLuaDll(hModule)) {
				return true;
			}
		}
		return false;
	}

	uintptr_t realLoadLibraryExW = 0;
	HMODULE __stdcall fakeLoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) {
		HMODULE hModule = base::std_call<HMODULE>(realLoadLibraryExW, lpLibFileName, hFile, dwFlags);
		std::unique_lock<std::mutex> lock(lockLoadDll);
		tryHookLuaDll(hModule);
		return hModule;
	}

	static void waitLuaDll() {
		HMODULE hModuleKernel = GetModuleHandleW(L"kernel32.dll");
		if (hModuleKernel) {
			realLoadLibraryExW = (uintptr_t)GetProcAddress(hModuleKernel, "LoadLibraryExW");
			if (realLoadLibraryExW) {
				hook_install(&realLoadLibraryExW, (uintptr_t)fakeLoadLibraryExW);
			}
		}
	}

	void initialize(fn_attach attach, bool ap) {
		if (debuggerAttach) {
			if (!attachProcess && ap && hookDll) {
				attachProcess = ap;
				lua::hook(hookDll);
			}
			return;
		}
		debuggerAttach = attach;
		attachProcess  = ap;
		if (!findLuaDll()) {
			waitLuaDll();
		}
	}

	FARPROC luaapi(const char* name) {
#define FIND(api) \
		if (lua::real::##api && strcmp(name, #api) == 0) { \
			return (FARPROC)lua::real::##api; \
		}
		FIND(luaL_openlibs)
		FIND(lua_close)
		FIND(lua_settop)
		return 0;
#undef  FIND
	}
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
 * This file is part of the libetonyek project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <algorithm>
#include <cassert>

#include "libetonyek_utils.h"
#include "KEYMemoryStream.h"

namespace libetonyek
{

KEYMemoryStream::KEYMemoryStream(const RVNGInputStreamPtr_t &input)
  : m_data(0)
  , m_length(0)
  , m_pos(0)
{
  const unsigned long begin = input->tell();
  if (input->seek(0, librevenge::RVNG_SEEK_END))
  {
    while (!input->isEnd())
      readU8(input);
  }
  const unsigned long end = input->tell();
  input->seek(begin, librevenge::RVNG_SEEK_SET);

  read(input, static_cast<unsigned>(end - begin));
}

KEYMemoryStream::KEYMemoryStream(const RVNGInputStreamPtr_t &input, const unsigned length)
  : m_data(0)
  , m_length(0)
  , m_pos(0)
{
  read(input, length);
}

KEYMemoryStream::KEYMemoryStream(std::vector<unsigned char> &data)
  : m_data(0)
  , m_length(data.size())
  , m_pos(0)
{
  if (data.empty())
    throw GenericException();

  assign(&data[0], data.size());
}

KEYMemoryStream::KEYMemoryStream(const unsigned char *const data, const unsigned length)
  : m_data(0)
  , m_length(length)
  , m_pos(0)
{
  if (0 == length)
    throw GenericException();

  assign(data, length);
}

KEYMemoryStream::~KEYMemoryStream()
{
  delete[] m_data;
}

bool KEYMemoryStream::isStructured()
{
  return false;
}

unsigned KEYMemoryStream::subStreamCount()
{
  return 0;
}

const char *KEYMemoryStream::subStreamName(unsigned)
{
  return 0;
}

librevenge::RVNGInputStream *KEYMemoryStream::getSubStreamByName(const char *)
{
  return 0;
}

librevenge::RVNGInputStream *KEYMemoryStream::getSubStreamById(unsigned)
{
  return 0;
}

const unsigned char *KEYMemoryStream::read(unsigned long numBytes, unsigned long &numBytesRead) try
{
  numBytesRead = 0;

  if (0 == numBytes)
    return 0;

  if ((m_pos + numBytes) >= static_cast<unsigned long>(m_length))
    numBytes = static_cast<unsigned long>(m_length - m_pos);

  const long oldPos = m_pos;
  m_pos += numBytes;

  numBytesRead = numBytes;
  return m_data + oldPos;
}
catch (...)
{
  return 0;
}

int KEYMemoryStream::seek(const long offset, librevenge::RVNG_SEEK_TYPE seekType) try
{
  long pos = 0;
  switch (seekType)
  {
  case librevenge::RVNG_SEEK_SET :
    pos = offset;
    break;
  case librevenge::RVNG_SEEK_CUR :
    pos = offset + m_pos;
    break;
  case librevenge::RVNG_SEEK_END :
    pos = offset + m_length;
    break;
  default :
    return -1;
  }

  if ((pos < 0) || (pos > m_length))
    return 1;

  m_pos = pos;
  return 0;
}
catch (...)
{
  return -1;
}

long KEYMemoryStream::tell()
{
  return m_pos;
}

bool KEYMemoryStream::isEnd()
{
  return m_length == m_pos;
}

void KEYMemoryStream::assign(const unsigned char *const data, const unsigned length)
{
  assert(0 != length);

  unsigned char *buffer = new unsigned char[length];
  std::copy(data, data + length, buffer);
  m_data = buffer;
}

void KEYMemoryStream::read(const RVNGInputStreamPtr_t &input, const unsigned length)
{
  if (0 == length)
    return;

  unsigned long readBytes = 0;
  const unsigned char *const data = bool(input) ? input->read(length, readBytes) : 0;
  if (length != readBytes)
    throw EndOfStreamException();

  m_length = length;
  assign(data, length);
}

}

/* vim:set shiftwidth=2 softtabstop=2 expandtab: */
<commit_msg>CID#1130378 rearrange a bit<commit_after>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
 * This file is part of the libetonyek project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <algorithm>
#include <cassert>

#include "libetonyek_utils.h"
#include "KEYMemoryStream.h"

namespace libetonyek
{

KEYMemoryStream::KEYMemoryStream(const RVNGInputStreamPtr_t &input)
  : m_data(0)
  , m_length(0)
  , m_pos(0)
{
  const unsigned long begin = input->tell();
  if (input->seek(0, librevenge::RVNG_SEEK_END))
  {
    while (!input->isEnd())
      readU8(input);
  }
  const unsigned long end = input->tell();
  input->seek(begin, librevenge::RVNG_SEEK_SET);

  read(input, static_cast<unsigned>(end - begin));
}

KEYMemoryStream::KEYMemoryStream(const RVNGInputStreamPtr_t &input, const unsigned length)
  : m_data(0)
  , m_length(0)
  , m_pos(0)
{
  read(input, length);
}

KEYMemoryStream::KEYMemoryStream(std::vector<unsigned char> &data)
  : m_data(0)
  , m_length(data.size())
  , m_pos(0)
{
  if (data.empty())
    throw GenericException();

  assign(&data[0], data.size());
}

KEYMemoryStream::KEYMemoryStream(const unsigned char *const data, const unsigned length)
  : m_data(0)
  , m_length(length)
  , m_pos(0)
{
  if (0 == length)
    throw GenericException();

  assign(data, length);
}

KEYMemoryStream::~KEYMemoryStream()
{
  delete[] m_data;
}

bool KEYMemoryStream::isStructured()
{
  return false;
}

unsigned KEYMemoryStream::subStreamCount()
{
  return 0;
}

const char *KEYMemoryStream::subStreamName(unsigned)
{
  return 0;
}

librevenge::RVNGInputStream *KEYMemoryStream::getSubStreamByName(const char *)
{
  return 0;
}

librevenge::RVNGInputStream *KEYMemoryStream::getSubStreamById(unsigned)
{
  return 0;
}

const unsigned char *KEYMemoryStream::read(unsigned long numBytes, unsigned long &numBytesRead) try
{
  numBytesRead = 0;

  if (0 == numBytes)
    return 0;

  if ((m_pos + numBytes) >= static_cast<unsigned long>(m_length))
    numBytes = static_cast<unsigned long>(m_length - m_pos);

  const long oldPos = m_pos;
  m_pos += numBytes;

  numBytesRead = numBytes;
  return m_data + oldPos;
}
catch (...)
{
  return 0;
}

int KEYMemoryStream::seek(const long offset, librevenge::RVNG_SEEK_TYPE seekType) try
{
  long pos = 0;
  switch (seekType)
  {
  case librevenge::RVNG_SEEK_SET :
    pos = offset;
    break;
  case librevenge::RVNG_SEEK_CUR :
    pos = offset + m_pos;
    break;
  case librevenge::RVNG_SEEK_END :
    pos = offset + m_length;
    break;
  default :
    return -1;
  }

  if ((pos < 0) || (pos > m_length))
    return 1;

  m_pos = pos;
  return 0;
}
catch (...)
{
  return -1;
}

long KEYMemoryStream::tell()
{
  return m_pos;
}

bool KEYMemoryStream::isEnd()
{
  return m_length == m_pos;
}

void KEYMemoryStream::assign(const unsigned char *const data, const unsigned length)
{
  assert(0 != length);

  unsigned char *buffer = new unsigned char[length];
  std::copy(data, data + length, buffer);
  m_data = buffer;
}

void KEYMemoryStream::read(const RVNGInputStreamPtr_t &input, const unsigned length)
{
  if (0 == length)
    return;
  if (!bool(input))
    throw EndOfStreamException();

  unsigned long readBytes = 0;
  const unsigned char *const data = input->read(length, readBytes);
  if (length != readBytes)
    throw EndOfStreamException();

  m_length = length;
  assign(data, length);
}

}

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


<commit_before>/* Copyright (C) 2003 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include <ndb_global.h>

#include <NdbTCP.h>
#include <socket_io.h>
#include <NdbOut.hpp>

extern "C"
int
read_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
	    char * buf, int buflen){
  if(buflen < 1)
    return 0;

  fd_set readset;
  FD_ZERO(&readset);
  FD_SET(socket, &readset);

  struct timeval timeout;
  timeout.tv_sec  = (timeout_millis / 1000);
  timeout.tv_usec = (timeout_millis % 1000) * 1000;

  const int selectRes = select(socket + 1, &readset, 0, 0, &timeout);
  if(selectRes == 0)
    return 0;

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

  return recv(socket, &buf[0], buflen, 0);
}

extern "C"
int
readln_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
	      char * buf, int buflen){
  if(buflen <= 1)
    return 0;

  int sock_flags= fcntl(socket, F_GETFL);
  if(fcntl(socket, F_SETFL, sock_flags | O_NONBLOCK) == -1)
    return -1;

  fd_set readset;
  FD_ZERO(&readset);
  FD_SET(socket, &readset);

  struct timeval timeout;
  timeout.tv_sec  = (timeout_millis / 1000);
  timeout.tv_usec = (timeout_millis % 1000) * 1000;

  const int selectRes = select(socket + 1, &readset, 0, 0, &timeout);
  if(selectRes == 0){
    return 0;
  }

  if(selectRes == -1){
    fcntl(socket, F_SETFL, sock_flags);
    return -1;
  }

  buf[0] = 0;
  const int t = recv(socket, buf, buflen, MSG_PEEK);

  if(t < 1)
  {
    fcntl(socket, F_SETFL, sock_flags);
    return -1;
  }

  for(int i=0; i< t;i++)
  {
    if(buf[i] == '\n'){
      recv(socket, buf, i+1, 0);
      buf[i] = 0;

      if(i > 0 && buf[i-1] == '\r'){
        i--;
        buf[i] = 0;
      }

      fcntl(socket, F_SETFL, sock_flags);
      return t;
    }
  }

  if(t == (buflen - 1)){
    recv(socket, buf, t, 0);
    buf[t] = 0;
    fcntl(socket, F_SETFL, sock_flags);
    return buflen;
  }

  return 0;
}

extern "C"
int
write_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
	     const char buf[], int len){
  fd_set writeset;
  FD_ZERO(&writeset);
  FD_SET(socket, &writeset);
  struct timeval timeout;
  timeout.tv_sec  = (timeout_millis / 1000);
  timeout.tv_usec = (timeout_millis % 1000) * 1000;

  const int selectRes = select(socket + 1, 0, &writeset, 0, &timeout);
  if(selectRes != 1){
    return -1;
  }

  const char * tmp = &buf[0];
  while(len > 0){
    const int w = send(socket, tmp, len, 0);
    if(w == -1){
      return -1;
    }
    len -= w;
    tmp += w;

    if(len == 0)
      break;

    FD_ZERO(&writeset);
    FD_SET(socket, &writeset);
    timeout.tv_sec  = 1;
    timeout.tv_usec = 0;
    const int selectRes = select(socket + 1, 0, &writeset, 0, &timeout);
    if(selectRes != 1){
      return -1;
    }
  }

  return 0;
}

extern "C"
int
print_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
	     const char * fmt, ...){
  va_list ap;
  va_start(ap, fmt);
  int ret = vprint_socket(socket, timeout_millis, fmt, ap);
  va_end(ap);

  return ret;
}

extern "C"
int
println_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
	       const char * fmt, ...){
  va_list ap;
  va_start(ap, fmt);
  int ret = vprintln_socket(socket, timeout_millis, fmt, ap);
  va_end(ap);
  return ret;
}

extern "C"
int
vprint_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
	      const char * fmt, va_list ap){
  char buf[1000];
  char *buf2 = buf;
  size_t size;

  if (fmt != 0 && fmt[0] != 0) {
    size = BaseString::vsnprintf(buf, sizeof(buf), fmt, ap);
    /* Check if the output was truncated */
    if(size > sizeof(buf)) {
      buf2 = (char *)malloc(size);
      if(buf2 == NULL)
	return -1;
      BaseString::vsnprintf(buf2, size, fmt, ap);
    }
  } else
    return 0;

  int ret = write_socket(socket, timeout_millis, buf2, size);
  if(buf2 != buf)
    free(buf2);
  return ret;
}

extern "C"
int
vprintln_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
		const char * fmt, va_list ap){
  char buf[1000];
  char *buf2 = buf;
  size_t size;

  if (fmt != 0 && fmt[0] != 0) {
    size = BaseString::vsnprintf(buf, sizeof(buf), fmt, ap)+1;// extra byte for '/n'
    /* Check if the output was truncated */
    if(size > sizeof(buf)) {
      buf2 = (char *)malloc(size);
      if(buf2 == NULL)
	return -1;
      BaseString::vsnprintf(buf2, size, fmt, ap);
    }
  } else {
    size = 1;
  }
  buf2[size-1]='\n';

  int ret = write_socket(socket, timeout_millis, buf2, size);
  if(buf2 != buf)
    free(buf2);
  return ret;
}

#ifdef NDB_WIN32

class INIT_WINSOCK2
{
public:
    INIT_WINSOCK2(void);
    ~INIT_WINSOCK2(void);

private:
    bool m_bAcceptable;
};

INIT_WINSOCK2 g_init_winsock2;

INIT_WINSOCK2::INIT_WINSOCK2(void)
: m_bAcceptable(false)
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD( 2, 2 );

    err = WSAStartup( wVersionRequested, &wsaData );
    if ( err != 0 ) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        m_bAcceptable = false;
    }

    /* Confirm that the WinSock DLL supports 2.2.*/
    /* Note that if the DLL supports versions greater    */
    /* than 2.2 in addition to 2.2, it will still return */
    /* 2.2 in wVersion since that is the version we      */
    /* requested.                                        */

    if ( LOBYTE( wsaData.wVersion ) != 2 ||
        HIBYTE( wsaData.wVersion ) != 2 ) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        WSACleanup( );
        m_bAcceptable = false;
    }

    /* The WinSock DLL is acceptable. Proceed. */
    m_bAcceptable = true;
}

INIT_WINSOCK2::~INIT_WINSOCK2(void)
{
    if(m_bAcceptable)
    {
        m_bAcceptable = false;
        WSACleanup();
    }
}

#endif

<commit_msg>ndb - bug#24011   <commit_after>/* Copyright (C) 2003 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include <ndb_global.h>

#include <NdbTCP.h>
#include <socket_io.h>
#include <NdbOut.hpp>

extern "C"
int
read_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
	    char * buf, int buflen){
  if(buflen < 1)
    return 0;

  fd_set readset;
  FD_ZERO(&readset);
  FD_SET(socket, &readset);

  struct timeval timeout;
  timeout.tv_sec  = (timeout_millis / 1000);
  timeout.tv_usec = (timeout_millis % 1000) * 1000;

  const int selectRes = select(socket + 1, &readset, 0, 0, &timeout);
  if(selectRes == 0)
    return 0;

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

  return recv(socket, &buf[0], buflen, 0);
}

extern "C"
int
readln_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
	      char * buf, int buflen){
  if(buflen <= 1)
    return 0;

  fd_set readset;
  FD_ZERO(&readset);
  FD_SET(socket, &readset);

  struct timeval timeout;
  timeout.tv_sec  = (timeout_millis / 1000);
  timeout.tv_usec = (timeout_millis % 1000) * 1000;

  const int selectRes = select(socket + 1, &readset, 0, 0, &timeout);
  if(selectRes == 0){
    return 0;
  }

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

  char* ptr = buf;
  int len = buflen;
  do
  {
    int t;
    while((t = recv(socket, ptr, len, MSG_PEEK)) == -1 && errno == EINTR);

    if(t < 1)
    {
      return -1;
    }

    for(int i = 0; i<t; i++)
    {
      if(ptr[i] == '\n')
      {
	/**
	 * Now consume
	 */
	for (len = 1 + i; len; )
	{
	  while ((t = recv(socket, ptr, len, 0)) == -1 && errno == EINTR);
	  if (t < 1)
	    return -1;
	  ptr += t;
	  len -= t;
	}
	ptr[0]= 0;
	return ptr - buf;
      }
    }

    for (int tmp = t; tmp; )
    {
      while ((t = recv(socket, ptr, tmp, 0)) == -1 && errno == EINTR);
      if (t < 1)
      {
	return -1;
      }
      ptr += t;
      len -= t;
      tmp -= t;
    }

    FD_ZERO(&readset);
    FD_SET(socket, &readset);
    timeout.tv_sec  = (timeout_millis / 1000);
    timeout.tv_usec = (timeout_millis % 1000) * 1000;
    const int selectRes = select(socket + 1, &readset, 0, 0, &timeout);
    if(selectRes != 1){
      return -1;
    }
  } while (len > 0);

  return -1;
}

extern "C"
int
write_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
	     const char buf[], int len){
  fd_set writeset;
  FD_ZERO(&writeset);
  FD_SET(socket, &writeset);
  struct timeval timeout;
  timeout.tv_sec  = (timeout_millis / 1000);
  timeout.tv_usec = (timeout_millis % 1000) * 1000;

  const int selectRes = select(socket + 1, 0, &writeset, 0, &timeout);
  if(selectRes != 1){
    return -1;
  }

  const char * tmp = &buf[0];
  while(len > 0){
    const int w = send(socket, tmp, len, 0);
    if(w == -1){
      return -1;
    }
    len -= w;
    tmp += w;

    if(len == 0)
      break;

    FD_ZERO(&writeset);
    FD_SET(socket, &writeset);
    timeout.tv_sec  = 1;
    timeout.tv_usec = 0;
    const int selectRes = select(socket + 1, 0, &writeset, 0, &timeout);
    if(selectRes != 1){
      return -1;
    }
  }

  return 0;
}

extern "C"
int
print_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
	     const char * fmt, ...){
  va_list ap;
  va_start(ap, fmt);
  int ret = vprint_socket(socket, timeout_millis, fmt, ap);
  va_end(ap);

  return ret;
}

extern "C"
int
println_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
	       const char * fmt, ...){
  va_list ap;
  va_start(ap, fmt);
  int ret = vprintln_socket(socket, timeout_millis, fmt, ap);
  va_end(ap);
  return ret;
}

extern "C"
int
vprint_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
	      const char * fmt, va_list ap){
  char buf[1000];
  char *buf2 = buf;
  size_t size;

  if (fmt != 0 && fmt[0] != 0) {
    size = BaseString::vsnprintf(buf, sizeof(buf), fmt, ap);
    /* Check if the output was truncated */
    if(size > sizeof(buf)) {
      buf2 = (char *)malloc(size);
      if(buf2 == NULL)
	return -1;
      BaseString::vsnprintf(buf2, size, fmt, ap);
    }
  } else
    return 0;

  int ret = write_socket(socket, timeout_millis, buf2, size);
  if(buf2 != buf)
    free(buf2);
  return ret;
}

extern "C"
int
vprintln_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
		const char * fmt, va_list ap){
  char buf[1000];
  char *buf2 = buf;
  size_t size;

  if (fmt != 0 && fmt[0] != 0) {
    size = BaseString::vsnprintf(buf, sizeof(buf), fmt, ap)+1;// extra byte for '/n'
    /* Check if the output was truncated */
    if(size > sizeof(buf)) {
      buf2 = (char *)malloc(size);
      if(buf2 == NULL)
	return -1;
      BaseString::vsnprintf(buf2, size, fmt, ap);
    }
  } else {
    size = 1;
  }
  buf2[size-1]='\n';

  int ret = write_socket(socket, timeout_millis, buf2, size);
  if(buf2 != buf)
    free(buf2);
  return ret;
}

#ifdef NDB_WIN32

class INIT_WINSOCK2
{
public:
    INIT_WINSOCK2(void);
    ~INIT_WINSOCK2(void);

private:
    bool m_bAcceptable;
};

INIT_WINSOCK2 g_init_winsock2;

INIT_WINSOCK2::INIT_WINSOCK2(void)
: m_bAcceptable(false)
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD( 2, 2 );

    err = WSAStartup( wVersionRequested, &wsaData );
    if ( err != 0 ) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        m_bAcceptable = false;
    }

    /* Confirm that the WinSock DLL supports 2.2.*/
    /* Note that if the DLL supports versions greater    */
    /* than 2.2 in addition to 2.2, it will still return */
    /* 2.2 in wVersion since that is the version we      */
    /* requested.                                        */

    if ( LOBYTE( wsaData.wVersion ) != 2 ||
        HIBYTE( wsaData.wVersion ) != 2 ) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        WSACleanup( );
        m_bAcceptable = false;
    }

    /* The WinSock DLL is acceptable. Proceed. */
    m_bAcceptable = true;
}

INIT_WINSOCK2::~INIT_WINSOCK2(void)
{
    if(m_bAcceptable)
    {
        m_bAcceptable = false;
        WSACleanup();
    }
}

#endif

<|endoftext|>


<commit_before>#include "CharacterSelectState.h"
#include "Game.h"
#include "MenuState.h"
#include "BattleState.h"

CharacterSelectState::CharacterSelectState(){
	background = Sprite("character_select/background.png");
	character_slots = Sprite("character_select/character_slots.png");

	// FIXME 2 enabled characters
	for(int i=0;i<2;i++){
		available_skin[get_char_info(i).first].assign(4, true);

		char_name[get_char_info(i).first] = Sprite("character_select/chars/" + get_char_info(i).first + "/name.png");

		// loop to get skins
		for(int j=0;j<4;j++){
			char_sprite[get_char_info(i).first].push_back(Sprite("character_select/chars/" + get_char_info(i).first + "/" + to_string(j) + ".png",
													get_char_info(i).second,
													13));
			char_sprite[get_char_info(i).first][j].set_scale_x(3);
			char_sprite[get_char_info(i).first][j].set_scale_y(3);
		}
	}

	for(int i=0;i<4;i++){
		name_tag[i] = Sprite("character_select/name_tag_" + to_string(i + 1) + ".png");
		number[i] = Sprite("character_select/number_" + to_string(i + 1) + ".png");
	}

	names = { {"flesh",""}, {"blood",""}, {"",""}, {"",""} };

	memset(cur_selection_col, 0, sizeof cur_selection_col);
	memset(cur_selection_row, 0, sizeof cur_selection_row);
	memset(cur_skin, 0, sizeof cur_skin);
	memset(selected, false, sizeof selected);

	name_tag_positions = { ii(91, 234), ii(92, 583), ii(956, 234), ii(955, 583) };
	number_delta = { ii(12, 9), ii(93, 9), ii(12, 101), ii(93, 101) };
	name_delta = { ii(118, 53), ii(117, 55), ii(47, 54), ii(50, 54) };
	sprite_pos = { ii(155, 32), ii(141, 379), ii(923, 34), ii(946, 381) };

	col_slots = { 510, 645 };
	row_slots = { 55, 197, 395, 536 };
}

void CharacterSelectState::update(float delta){
	InputManager * input_manager = InputManager::get_instance();

	// inputs
	if(input_manager->quit_requested() ||
		input_manager->key_press(SDLK_ESCAPE) ||
		(not selected[0] && input_manager->joystick_button_press(InputManager::B, 0)) ||
		input_manager->joystick_button_press(InputManager::SELECT, 0)){
		m_quit_requested = true;
		Game::get_instance().push(new MenuState(true));
		return;
	}

	// only enable start when all players have selected a character
	if(all_players_selected()){
		if(input_manager->key_press(SDLK_RETURN) || input_manager->joystick_button_press(InputManager::START, 0)){
			m_quit_requested = true;
			Game::get_instance().push(new BattleState("1", "swamp_song.ogg"));
			return;
		}
	}

	for(int i=0;i<4;i++){
		if(not selected[i]){
			if((input_manager->key_press(SDLK_LEFT) || input_manager->joystick_button_press(InputManager::LEFT, i))
			&& cur_selection_col[i] != 0){
				if(character_enabled(cur_selection_row[i], cur_selection_col[i] - 1))
					cur_selection_col[i]--;
			}

			if((input_manager->key_press(SDLK_RIGHT) || input_manager->joystick_button_press(InputManager::RIGHT, i))
			&& cur_selection_col[i] != 1){
				if(character_enabled(cur_selection_row[i], cur_selection_col[i] + 1))
					cur_selection_col[i]++;
			}

			if((input_manager->key_press(SDLK_UP) || input_manager->joystick_button_press(InputManager::UP, i))
			&& cur_selection_row[i] != 0){
				if(character_enabled(cur_selection_row[i] - 1, cur_selection_col[i]))
					cur_selection_row[i]--;
			}

			if((input_manager->key_press(SDLK_DOWN) || input_manager->joystick_button_press(InputManager::DOWN, i))
			&& cur_selection_row[i] != 3){
				if(character_enabled(cur_selection_row[i] + 1, cur_selection_col[i]))
					cur_selection_row[i]++;
			}

			// skins
			if(input_manager->key_press(SDLK_COMMA) || input_manager->joystick_button_press(InputManager::LT, i)){
				cur_skin[i] = (cur_skin[i] - 1 + 4) % 4;
			}

			if(input_manager->key_press(SDLK_PERIOD) || input_manager->joystick_button_press(InputManager::RT, i)){
				cur_skin[i] = (cur_skin[i] + 1) % 4;
			}

			// select character && lock skin
			if(input_manager->key_press(SDLK_x) || input_manager->joystick_button_press(InputManager::A, i)){
				int col_sel = cur_selection_col[i];
				int row_sel = cur_selection_row[i];
				string char_selected = names[col_sel][row_sel];

				if(not available_skin[char_selected][cur_skin[i]]){
					printf("SKIN [%d] of [%s] ALREADY CHOSEN\n", cur_skin[i], char_selected.c_str());
				}
				else{
					printf("PLAYER %d CHOSE SKIN [%d] of [%s]\n", i + 1, cur_skin[i], char_selected.c_str());
					available_skin[char_selected][cur_skin[i]] = false;
					selected[i] = true;
				}
			}
		}
		else{
			// unselect character
			if(input_manager->key_press(SDLK_y) || input_manager->joystick_button_press(InputManager::B, i)){
				int col_sel = cur_selection_col[i];
				int row_sel = cur_selection_row[i];
				string char_selected = names[col_sel][row_sel];

				available_skin[char_selected][cur_skin[i]] = true;
				selected[i] = false;
				printf("PLAYER %d UNSELECTED SKIN [%d] of [%s]\n", i + 1, cur_skin[i], char_selected.c_str());
			}
		}
	}

	for(auto it = char_sprite.begin(); it != char_sprite.end(); it++){
		for(int i=0; i < (*it).second.size(); i++){
			(*it).second[i].update(delta);
		}
	}
}

void CharacterSelectState::render(){
	background.render(0, 0);
	character_slots.render(0, 0);

	for(int i=0;i<4;i++){
		int col_sel = cur_selection_col[i];
		int row_sel = cur_selection_row[i];

		string char_selected = names[col_sel][row_sel];

		char_sprite[char_selected][cur_skin[i]].render(sprite_pos[i].first, sprite_pos[i].second);
		name_tag[i].render(name_tag_positions[i].first, name_tag_positions[i].second);

		char_name[char_selected].render(
			name_tag_positions[i].first + name_delta[i].first,
			name_tag_positions[i].second + name_delta[i].second
		);
		number[i].render(col_slots[col_sel] + number_delta[i].first, row_slots[row_sel] + number_delta[i].second);
	}
}

void CharacterSelectState::pause(){

}

void CharacterSelectState::resume(){

}

bool CharacterSelectState::character_enabled(int row, int){
	// Only characters in first row are available
	return row == 0;
}

// returns name and number of frames in corresponding sprite
pair<string, int> CharacterSelectState::get_char_info(int idx){
	switch(idx){
		case 0: return pair<string, int> ("flesh", 12);
		case 1: return pair<string, int> ("blood", 8);
	}
}

bool CharacterSelectState::all_players_selected(){
	for(auto cur : selected)
		if(not cur) return false;
	return true;
}
<commit_msg>Add constants to character select menu<commit_after>#include "CharacterSelectState.h"
#include "Game.h"
#include "MenuState.h"
#include "BattleState.h"

#define AVAILABLE_CHARS 2
#define NUMBER_OF_PLAYERS 4
#define AVAILABLE_SKINS 4
#define FIRST_PLAYER 0
#define COL_SLOTS 2
#define ROW_SLOTS 4

CharacterSelectState::CharacterSelectState(){
	background = Sprite("character_select/background.png");
	character_slots = Sprite("character_select/character_slots.png");

	for(int i=0;i<AVAILABLE_CHARS;i++){
		available_skin[get_char_info(i).first].assign(AVAILABLE_SKINS, true);

		char_name[get_char_info(i).first] = Sprite("character_select/chars/" + get_char_info(i).first + "/name.png");

		// loop to get skins
		for(int j=0;j<AVAILABLE_SKINS;j++){
			char_sprite[get_char_info(i).first].push_back(Sprite("character_select/chars/" + get_char_info(i).first + "/" + to_string(j) + ".png",
													get_char_info(i).second,
													13));
			char_sprite[get_char_info(i).first][j].set_scale_x(3);
			char_sprite[get_char_info(i).first][j].set_scale_y(3);
		}
	}

	for(int i=0;i<NUMBER_OF_PLAYERS;i++){
		name_tag[i] = Sprite("character_select/name_tag_" + to_string(i + 1) + ".png");
		number[i] = Sprite("character_select/number_" + to_string(i + 1) + ".png");
	}

	names = { {"flesh",""}, {"blood",""}, {"",""}, {"",""} };

	memset(cur_selection_col, 0, sizeof cur_selection_col);
	memset(cur_selection_row, 0, sizeof cur_selection_row);
	memset(cur_skin, 0, sizeof cur_skin);
	memset(selected, false, sizeof selected);

	name_tag_positions = { ii(91, 234), ii(92, 583), ii(956, 234), ii(955, 583) };
	number_delta = { ii(12, 9), ii(93, 9), ii(12, 101), ii(93, 101) };
	name_delta = { ii(118, 53), ii(117, 55), ii(47, 54), ii(50, 54) };
	sprite_pos = { ii(155, 32), ii(141, 379), ii(923, 34), ii(946, 381) };

	col_slots = { 510, 645 };
	row_slots = { 55, 197, 395, 536 };
}

void CharacterSelectState::update(float delta){
	InputManager * input_manager = InputManager::get_instance();

	// inputs
	if(input_manager->quit_requested() ||
		input_manager->key_press(SDLK_ESCAPE) ||
		(not selected[FIRST_PLAYER] && input_manager->joystick_button_press(InputManager::B, FIRST_PLAYER)) ||
		input_manager->joystick_button_press(InputManager::SELECT, FIRST_PLAYER)){
		m_quit_requested = true;
		Game::get_instance().push(new MenuState(true));
		return;
	}

	// only enable start when all players have selected a character
	if(all_players_selected()){
		if(input_manager->key_press(SDLK_RETURN) || input_manager->joystick_button_press(InputManager::START, FIRST_PLAYER)){
			m_quit_requested = true;
			Game::get_instance().push(new BattleState("1", "swamp_song.ogg"));
			return;
		}
	}

	for(int i=0;i<NUMBER_OF_PLAYERS;i++){
		if(not selected[i]){
			if((input_manager->key_press(SDLK_LEFT) || input_manager->joystick_button_press(InputManager::LEFT, i))
			&& cur_selection_col[i] != 0){
				if(character_enabled(cur_selection_row[i], cur_selection_col[i] - 1))
					cur_selection_col[i]--;
			}

			if((input_manager->key_press(SDLK_RIGHT) || input_manager->joystick_button_press(InputManager::RIGHT, i))
			&& cur_selection_col[i] + 1 < COL_SLOTS){
				if(character_enabled(cur_selection_row[i], cur_selection_col[i] + 1))
					cur_selection_col[i]++;
			}

			if((input_manager->key_press(SDLK_UP) || input_manager->joystick_button_press(InputManager::UP, i))
			&& cur_selection_row[i] != 0){
				if(character_enabled(cur_selection_row[i] - 1, cur_selection_col[i]))
					cur_selection_row[i]--;
			}

			if((input_manager->key_press(SDLK_DOWN) || input_manager->joystick_button_press(InputManager::DOWN, i))
			&& cur_selection_row[i] + 1 < ROW_SLOTS){
				if(character_enabled(cur_selection_row[i] + 1, cur_selection_col[i]))
					cur_selection_row[i]++;
			}

			// skins
			if(input_manager->key_press(SDLK_COMMA) || input_manager->joystick_button_press(InputManager::LT, i)){
				cur_skin[i] = (cur_skin[i] - 1 + AVAILABLE_SKINS) % AVAILABLE_SKINS;
			}

			if(input_manager->key_press(SDLK_PERIOD) || input_manager->joystick_button_press(InputManager::RT, i)){
				cur_skin[i] = (cur_skin[i] + 1) % AVAILABLE_SKINS;
			}

			// select character && lock skin
			if(input_manager->key_press(SDLK_x) || input_manager->joystick_button_press(InputManager::A, i)){
				int col_sel = cur_selection_col[i];
				int row_sel = cur_selection_row[i];
				string char_selected = names[col_sel][row_sel];

				if(not available_skin[char_selected][cur_skin[i]]){
					printf("SKIN [%d] of [%s] ALREADY CHOSEN\n", cur_skin[i], char_selected.c_str());
				}
				else{
					printf("PLAYER %d CHOSE SKIN [%d] of [%s]\n", i + 1, cur_skin[i], char_selected.c_str());
					available_skin[char_selected][cur_skin[i]] = false;
					selected[i] = true;
				}
			}
		}
		else{
			// unselect character
			if(input_manager->key_press(SDLK_y) || input_manager->joystick_button_press(InputManager::B, i)){
				int col_sel = cur_selection_col[i];
				int row_sel = cur_selection_row[i];
				string char_selected = names[col_sel][row_sel];

				available_skin[char_selected][cur_skin[i]] = true;
				selected[i] = false;
				printf("PLAYER %d UNSELECTED SKIN [%d] of [%s]\n", i + 1, cur_skin[i], char_selected.c_str());
			}
		}
	}

	for(auto it = char_sprite.begin(); it != char_sprite.end(); it++){
		for(int i=0; i < (*it).second.size(); i++){
			(*it).second[i].update(delta);
		}
	}
}

void CharacterSelectState::render(){
	background.render(0, 0);
	character_slots.render(0, 0);

	for(int i=0;i<NUMBER_OF_PLAYERS;i++){
		int col_sel = cur_selection_col[i];
		int row_sel = cur_selection_row[i];

		string char_selected = names[col_sel][row_sel];

		char_sprite[char_selected][cur_skin[i]].render(sprite_pos[i].first, sprite_pos[i].second);
		name_tag[i].render(name_tag_positions[i].first, name_tag_positions[i].second);

		char_name[char_selected].render(
			name_tag_positions[i].first + name_delta[i].first,
			name_tag_positions[i].second + name_delta[i].second
		);
		number[i].render(col_slots[col_sel] + number_delta[i].first, row_slots[row_sel] + number_delta[i].second);
	}
}

void CharacterSelectState::pause(){

}

void CharacterSelectState::resume(){

}

bool CharacterSelectState::character_enabled(int row, int){
	// Only characters in first row are available
	return row == 0;
}

// returns name and number of frames in corresponding sprite
pair<string, int> CharacterSelectState::get_char_info(int idx){
	switch(idx){
		case 0: return pair<string, int> ("flesh", 12);
		case 1: return pair<string, int> ("blood", 8);
	}
}

bool CharacterSelectState::all_players_selected(){
	for(auto cur : selected)
		if(not cur) return false;
	return true;
}
<|endoftext|>