<commit_before>#include "VerticalImageList.h"
#include "ListItem.h"

#include "dataset/Bitmap.h"
#include "widgets/DragTargetNull.h"

namespace d2d
{

VerticalImageList::VerticalImageList(wxWindow* parent, const wxString& name/* = wxEmptyString*/,
									 bool draggable /*= true*/)
	: wxVListBox(parent)
	, m_name(name)
{
	SetBackgroundColour(wxColour(229, 229, 229));

	Connect(GetId(), wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(VerticalImageList::onListSelected));
	Connect(GetId(), wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, wxCommandEventHandler(VerticalImageList::onListDoubleClicked));

	if (draggable)
	{
		SetDropTarget(new DragTargetNull);
		Connect(GetId(), wxEVT_MOTION, wxMouseEventHandler(VerticalImageList::onDragInit));
	}
}

VerticalImageList::~VerticalImageList()
{
	clear();
}

void VerticalImageList::traverse(IVisitor& visitor) const
{
	std::vector<ListItem*>::const_iterator itr = m_items.begin();
	for ( ; itr != m_items.end(); ++itr)
	{
		bool hasNext;
		visitor.visit(*itr, hasNext);
		if (!hasNext) break;
	}
}

void VerticalImageList::clear()
{
	for (int i = 0, n = m_items.size(); i < n; ++i) {
		m_items[i]->Release();
	}
	m_items.clear();
	SetItemCount(0);
	Refresh();
}

void VerticalImageList::insert(ListItem* item)
{
	item->Retain();
	m_items.push_back(item);
	SetItemCount(m_items.size());
	SetSelection(m_items.size() - 1);
	Refresh();
}

void VerticalImageList::insertFront(ListItem* item)
{
	item->Retain();
	m_items.insert(m_items.begin(), item);
	SetItemCount(m_items.size());
	SetSelection(0);
	Refresh();
}

void VerticalImageList::remove()
{
	remove(GetSelection());
}

void VerticalImageList::remove(int index)
{
	if (index < 0 || index >= m_items.size())
		return;

	m_items[index]->Release();
	m_items.erase(m_items.begin() + index);
 	SetItemCount(m_items.size());
	Refresh();
}

void VerticalImageList::swap(int i0, int i1)
{
	if (i0 < 0 || i0 >= m_items.size() ||
		i1 < 0 || i1 >= m_items.size())
		return;

	ListItem* tmp = m_items[i0];
	m_items[i0] = m_items[i1];
	m_items[i1] = tmp;

	Refresh();
}

void VerticalImageList::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const
{
	int y = rect.y + SPACE_UP;

	const Bitmap* bmp = m_items[n]->getBitmap();
	if (bmp)
	{
		const wxBitmap* wxBmp = bmp->getBitmap();
		if (wxBmp)
		{
			// bmp
			int x = wxBmp->GetWidth() > rect.width ? 0 : (rect.width - wxBmp->GetWidth()) * 0.5f;
			dc.DrawBitmap(*wxBmp, x, y);

			// info
			wxString info = m_items[n]->getInfo();
			dc.SetFont(wxFont(18, wxDEFAULT, wxNORMAL, wxNORMAL));
			//dc.SetTextForeground(wxColour(0xFF, 0x20, 0xFF));
			wxSize size = dc.GetTextExtent(info);
			//dc.DrawText(info, rect.x/* + rect.width * 0.5f - size.GetWidth() * 0.5f*/, y);
			dc.DrawText(info, rect.x + SPACE_UP, y);

			y += wxBmp->GetHeight();
		}
	}

	// name
	wxString name = m_items[n]->getName();
	dc.SetFont(wxFont(10, wxDEFAULT, wxNORMAL, wxNORMAL));
	wxSize size = dc.GetTextExtent(name);
	dc.DrawText(name, rect.x + rect.width * 0.5f - size.GetWidth() * 0.5f, y + SPACE_UP);
}

// void VerticalImageList::OnDrawBackground(wxDC& dc, const wxRect& rect, size_t n) const
// {
//   	dc.SetPen(*wxRED_PEN);
//   	dc.DrawRectangle(rect);
// }

void VerticalImageList::OnDrawSeparator(wxDC& dc, wxRect& rect, size_t n) const
{
	dc.SetPen(wxPen(wxColour(0, 0, 0), 3));
	dc.DrawLine(rect.GetLeftBottom(), rect.GetRightBottom());
}

wxCoord VerticalImageList::OnMeasureItem(size_t n) const
{
	int size = SPACE_UP + SPACE_DOWN;
	const Bitmap* bmp = m_items[n]->getBitmap();
	if (bmp) {
		const wxBitmap* wxBmp = bmp->getBitmap();
		if (wxBmp) {
			size = wxBmp->GetHeight() + SPACE_UP + SPACE_DOWN;
		}
	}
	return size;
}

void VerticalImageList::onDragInit(wxMouseEvent& event)
{
	if (event.Dragging())
	{
		wxTextDataObject tdo(m_name + "," + wxString::FromDouble(GetSelection()));
		wxDropSource ds(tdo);
		ds.DoDragDrop(wxDrag_CopyOnly);
	}
}
} // d2d<commit_msg>[CHANGED] viewlist选中的颜色<commit_after>#include "VerticalImageList.h"
#include "ListItem.h"

#include "dataset/Bitmap.h"
#include "widgets/DragTargetNull.h"

namespace d2d
{

VerticalImageList::VerticalImageList(wxWindow* parent, const wxString& name/* = wxEmptyString*/,
									 bool draggable /*= true*/)
	: wxVListBox(parent)
	, m_name(name)
{
	SetBackgroundColour(wxColour(229, 229, 229));
	SetSelectionBackground(*wxLIGHT_GREY);

	Connect(GetId(), wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(VerticalImageList::onListSelected));
	Connect(GetId(), wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, wxCommandEventHandler(VerticalImageList::onListDoubleClicked));

	if (draggable)
	{
		SetDropTarget(new DragTargetNull);
		Connect(GetId(), wxEVT_MOTION, wxMouseEventHandler(VerticalImageList::onDragInit));
	}
}

VerticalImageList::~VerticalImageList()
{
	clear();
}

void VerticalImageList::traverse(IVisitor& visitor) const
{
	std::vector<ListItem*>::const_iterator itr = m_items.begin();
	for ( ; itr != m_items.end(); ++itr)
	{
		bool hasNext;
		visitor.visit(*itr, hasNext);
		if (!hasNext) break;
	}
}

void VerticalImageList::clear()
{
	for (int i = 0, n = m_items.size(); i < n; ++i) {
		m_items[i]->Release();
	}
	m_items.clear();
	SetItemCount(0);
	Refresh();
}

void VerticalImageList::insert(ListItem* item)
{
	item->Retain();
	m_items.push_back(item);
	SetItemCount(m_items.size());
	SetSelection(m_items.size() - 1);
	Refresh();
}

void VerticalImageList::insertFront(ListItem* item)
{
	item->Retain();
	m_items.insert(m_items.begin(), item);
	SetItemCount(m_items.size());
	SetSelection(0);
	Refresh();
}

void VerticalImageList::remove()
{
	remove(GetSelection());
}

void VerticalImageList::remove(int index)
{
	if (index < 0 || index >= m_items.size())
		return;

	m_items[index]->Release();
	m_items.erase(m_items.begin() + index);
 	SetItemCount(m_items.size());
	Refresh();
}

void VerticalImageList::swap(int i0, int i1)
{
	if (i0 < 0 || i0 >= m_items.size() ||
		i1 < 0 || i1 >= m_items.size())
		return;

	ListItem* tmp = m_items[i0];
	m_items[i0] = m_items[i1];
	m_items[i1] = tmp;

	Refresh();
}

void VerticalImageList::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const
{
	int y = rect.y + SPACE_UP;

	const Bitmap* bmp = m_items[n]->getBitmap();
	if (bmp)
	{
		const wxBitmap* wxBmp = bmp->getBitmap();
		if (wxBmp)
		{
			// bmp
			int x = wxBmp->GetWidth() > rect.width ? 0 : (rect.width - wxBmp->GetWidth()) * 0.5f;
			dc.DrawBitmap(*wxBmp, x, y);

			// info
			wxString info = m_items[n]->getInfo();
			dc.SetFont(wxFont(18, wxDEFAULT, wxNORMAL, wxNORMAL));
			//dc.SetTextForeground(wxColour(0xFF, 0x20, 0xFF));
			wxSize size = dc.GetTextExtent(info);
			//dc.DrawText(info, rect.x/* + rect.width * 0.5f - size.GetWidth() * 0.5f*/, y);
			dc.DrawText(info, rect.x + SPACE_UP, y);

			y += wxBmp->GetHeight();
		}
	}

	// name
	wxString name = m_items[n]->getName();
	dc.SetFont(wxFont(10, wxDEFAULT, wxNORMAL, wxNORMAL));
	wxSize size = dc.GetTextExtent(name);
	dc.DrawText(name, rect.x + rect.width * 0.5f - size.GetWidth() * 0.5f, y + SPACE_UP);
}

// void VerticalImageList::OnDrawBackground(wxDC& dc, const wxRect& rect, size_t n) const
// {
//   	dc.SetPen(*wxRED_PEN);
//   	dc.DrawRectangle(rect);
// }

void VerticalImageList::OnDrawSeparator(wxDC& dc, wxRect& rect, size_t n) const
{
	dc.SetPen(wxPen(wxColour(0, 0, 0), 3));
	dc.DrawLine(rect.GetLeftBottom(), rect.GetRightBottom());
}

wxCoord VerticalImageList::OnMeasureItem(size_t n) const
{
	int size = SPACE_UP + SPACE_DOWN;
	const Bitmap* bmp = m_items[n]->getBitmap();
	if (bmp) {
		const wxBitmap* wxBmp = bmp->getBitmap();
		if (wxBmp) {
			size = wxBmp->GetHeight() + SPACE_UP + SPACE_DOWN;
		}
	}
	return size;
}

void VerticalImageList::onDragInit(wxMouseEvent& event)
{
	if (event.Dragging())
	{
		wxTextDataObject tdo(m_name + "," + wxString::FromDouble(GetSelection()));
		wxDropSource ds(tdo);
		ds.DoDragDrop(wxDrag_CopyOnly);
	}
}
} // d2d<|endoftext|>


<commit_before>//
// Created by everettjf on 2018/3/30.
//

#include "SourceCodeDockWidget.h"

SourceCodeDockWidget::SourceCodeDockWidget(QWidget *parent) : QDockWidget(parent)
{
    setWindowTitle(tr("Source Code"));

    textEdit = new QTextEdit(this);
    textEdit->setAlignment(Qt::AlignLeft | Qt::AlignTop);
    textEdit->setReadOnly(true);

    setWidget(textEdit);

    //default message
    this->setContent(QStringLiteral("print \"hello world\""));
}
void SourceCodeDockWidget::setContent(const QString &line)
{
    textEdit->setText(line);
}
<commit_msg>source code<commit_after>//
// Created by everettjf on 2018/3/30.
//

#include "SourceCodeDockWidget.h"

SourceCodeDockWidget::SourceCodeDockWidget(QWidget *parent) : QDockWidget(parent)
{
    setWindowTitle(tr("Source Code"));

    textEdit = new QTextEdit(this);
    textEdit->setAlignment(Qt::AlignLeft | Qt::AlignTop);
    textEdit->setReadOnly(true);

    setWidget(textEdit);

    //default message
    std::string code = R"(
#define FAT_MAGIC	0xcafebabe
#define FAT_CIGAM	0xbebafeca	/* NXSwapLong(FAT_MAGIC) */

    struct fat_header {
        uint32_t	magic;		/* FAT_MAGIC */
        uint32_t	nfat_arch;	/* number of structs that follow */
    };

    struct fat_arch {
        cpu_type_t	cputype;	/* cpu specifier (int) */
        cpu_subtype_t	cpusubtype;	/* machine specifier (int) */
        uint32_t	offset;		/* file offset to this object file */
        uint32_t	size;		/* size of this object file */
        uint32_t	align;		/* alignment as a power of 2 */
    };

                       )";
    this->setContent(QString::fromStdString(code));
}
void SourceCodeDockWidget::setContent(const QString &line)
{
    textEdit->setText(line);
}
<|endoftext|>


<commit_before>/* Copyright 2007-2015 QReal Research Group
 *
 * 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 "ev3RbfGeneratorPlugin.h"

#include <QtWidgets/QApplication>
#include <QtCore/QDirIterator>
#include <QtCore/QProcess>

#include <qrutils/widgets/qRealMessageBox.h>
#include <qrkernel/logging.h>
#include <ev3Kit/communication/ev3RobotCommunicationThread.h>
#include <ev3GeneratorBase/robotModel/ev3GeneratorRobotModel.h>
#include <qrkernel/settingsManager.h>
#include "ev3RbfMasterGenerator.h"

using namespace ev3::rbf;
using namespace qReal;

Ev3RbfGeneratorPlugin::Ev3RbfGeneratorPlugin()
	: Ev3GeneratorPluginBase("Ev3RbfUsbGeneratorRobotModel", tr("Autonomous mode (USB)"), 9
			, "Ev3RbfBluetoothGeneratorRobotModel", tr("Autonomous mode (Bluetooth)"), 8)
	, mGenerateCodeAction(new QAction(nullptr))
	, mUploadProgramAction(new QAction(nullptr))
	, mRunProgramAction(new QAction(nullptr))
	, mStopRobotAction(new QAction(nullptr))
{
	mGenerateCodeAction->setText(tr("Generate to Ev3 Robot Byte Code File"));
	mGenerateCodeAction->setIcon(QIcon(":/ev3/rbf/images/generateRbfCode.svg"));
	connect(mGenerateCodeAction, &QAction::triggered, this, &Ev3RbfGeneratorPlugin::generateCode);

	mUploadProgramAction->setText(tr("Upload program"));
	mUploadProgramAction->setIcon(QIcon(":/ev3/rbf/images/uploadProgram.svg"));
	connect(mUploadProgramAction, &QAction::triggered, this, &Ev3RbfGeneratorPlugin::uploadAndRunProgram);

	mRunProgramAction->setObjectName("runEv3RbfProgram");
	mRunProgramAction->setText(tr("Run program"));
	mRunProgramAction->setIcon(QIcon(":/ev3/rbf/images/run.png"));
	connect(mRunProgramAction, &QAction::triggered, this, &Ev3RbfGeneratorPlugin::runProgram, Qt::UniqueConnection);

	mStopRobotAction->setObjectName("stopEv3RbfRobot");
	mStopRobotAction->setText(tr("Stop robot"));
	mStopRobotAction->setIcon(QIcon(":/ev3/rbf/images/stop.png"));
	connect(mStopRobotAction, &QAction::triggered, this, &Ev3RbfGeneratorPlugin::stopRobot, Qt::UniqueConnection);

	text::Languages::registerLanguage(text::LanguageInfo{ "lms"
			, tr("EV3 Source Code language")
			, true
			, 4
			, nullptr
			, {}
	});
}

QList<ActionInfo> Ev3RbfGeneratorPlugin::customActions()
{
	const ActionInfo generateCodeActionInfo(mGenerateCodeAction, "generators", "tools");
	const ActionInfo uploadProgramActionInfo(mUploadProgramAction, "generators", "tools");
	const ActionInfo runProgramActionInfo(mRunProgramAction, "interpreters", "tools");
	const ActionInfo stopRobotActionInfo(mStopRobotAction, "interpreters", "tools");
	return {generateCodeActionInfo, uploadProgramActionInfo, runProgramActionInfo, stopRobotActionInfo};
}

QList<HotKeyActionInfo> Ev3RbfGeneratorPlugin::hotKeyActions()
{
	mGenerateCodeAction->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_G));
	mUploadProgramAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_U));
	mRunProgramAction->setShortcut(QKeySequence(Qt::Key_F5));
	mStopRobotAction->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_F5));

	HotKeyActionInfo generateActionInfo("Generator.GenerateEv3Rbf"
			, tr("Generate Ev3 Robot Byte Code File"), mGenerateCodeAction);
	HotKeyActionInfo uploadProgramInfo("Generator.UploadEv3", tr("Upload EV3 Program"), mUploadProgramAction);
	HotKeyActionInfo runProgramInfo("Generator.RunEv3", tr("Run EV3 Program"), mRunProgramAction);
	HotKeyActionInfo stopRobotInfo("Generator.StopEv3", tr("Stop EV3 Program"), mStopRobotAction);

	return { generateActionInfo, uploadProgramInfo, runProgramInfo, stopRobotInfo };
}

QIcon Ev3RbfGeneratorPlugin::iconForFastSelector(const kitBase::robotModel::RobotModelInterface &robotModel) const
{
	Q_UNUSED(robotModel)
	return QIcon(":/ev3/rbf/images/switch-to-ev3-rbf.svg");
}

int Ev3RbfGeneratorPlugin::priority() const
{
	return 9;
}

QString Ev3RbfGeneratorPlugin::defaultFilePath(QString const &projectName) const
{
	return QString("ev3-rbf/%1/%1.lms").arg(projectName);
}

text::LanguageInfo Ev3RbfGeneratorPlugin::language() const
{
	return text::Languages::pickByExtension("lms");
}

QString Ev3RbfGeneratorPlugin::generatorName() const
{
	return "ev3/rbf";
}

QString Ev3RbfGeneratorPlugin::uploadProgram()
{
	if (!javaInstalled()) {
		mMainWindowInterface->errorReporter()->addError(tr("Java is "\
				"not installed. Please download and install it."));
		return QString();
	}

	QFileInfo const fileInfo = generateCodeForProcessing();
	if (!fileInfo.exists()) {
		return QString();
	}

	if (!copySystemFiles(fileInfo.absolutePath())) {
		mMainWindowInterface->errorReporter()->addError(tr("Can't write source code files to disk!"));
		return QString();
	}

	if (!compile(fileInfo)) {
		QLOG_ERROR() << "EV3 bytecode compillation process failed!";
		mMainWindowInterface->errorReporter()->addError(tr("Compilation error occured."));
		return QString();
	}

	const QString fileOnRobot = upload(fileInfo);
	if (fileOnRobot.isEmpty()) {
		const bool isUsb = mRobotModelManager->model().name().contains("usb", Qt::CaseInsensitive);
		mMainWindowInterface->errorReporter()->addError(tr("Could not upload file to robot. "\
				"Connect to a robot via %1.").arg(isUsb ? tr("USB") : tr("Bluetooth")));
		return QString();
	}

	return fileOnRobot;
}

void Ev3RbfGeneratorPlugin::uploadAndRunProgram()
{
	const QString fileOnRobot = uploadProgram();
	communication::Ev3RobotCommunicationThread * const communicator = currentCommunicator();

	if (fileOnRobot.isEmpty() || !communicator) {
		return;
	}

	const RunPolicy runPolicy = static_cast<RunPolicy>(SettingsManager::value("ev3RunPolicy").toInt());
	switch (runPolicy) {
	case RunPolicy::Ask:
		if (utils::QRealMessageBox::question(mMainWindowInterface->windowWidget(), tr("The program has been uploaded")
				, tr("Do you want to run it?")) == QMessageBox::Yes) {
			communicator->runProgram(fileOnRobot);
		}
		break;
	case RunPolicy::AlwaysRun:
		communicator->runProgram(fileOnRobot);
		break;
	case RunPolicy::NeverRun:
		break;
	}
}

void Ev3RbfGeneratorPlugin::runProgram()
{
	const QString fileOnRobot = uploadProgram();
	communication::Ev3RobotCommunicationThread * const communicator = currentCommunicator();
	if (!fileOnRobot.isEmpty() && communicator) {
		communicator->runProgram(fileOnRobot);
	}
}

void Ev3RbfGeneratorPlugin::stopRobot()
{
	if (communication::Ev3RobotCommunicationThread * const communicator = currentCommunicator()) {
		communicator->stopProgram();
	}
}

bool Ev3RbfGeneratorPlugin::javaInstalled()
{
	QProcess java;
	java.setEnvironment(QProcess::systemEnvironment());

	java.start("java");
	java.waitForFinished();
	return !java.readAllStandardError().isEmpty();
}

bool Ev3RbfGeneratorPlugin::copySystemFiles(const QString &destination)
{
	QDirIterator iterator(":/ev3/rbf/thirdparty");
	while (iterator.hasNext()) {
		const QFileInfo fileInfo(iterator.next());
		const QString destFile = destination + "/" + fileInfo.fileName();
		if (!QFile::exists(destFile) && !QFile::copy(fileInfo.absoluteFilePath(), destFile)) {
			return false;
		}
	}

	return true;
}

bool Ev3RbfGeneratorPlugin::compile(const QFileInfo &lmsFile)
{
	QFile rbfFile(lmsFile.absolutePath() + "/" + lmsFile.baseName() + ".rbf");
	if (rbfFile.exists()) {
		rbfFile.remove();
	}

	QProcess java;
	java.setEnvironment(QProcess::systemEnvironment());
	java.setWorkingDirectory(lmsFile.absolutePath());
	java.start("cmd /c java -jar assembler.jar " + lmsFile.absolutePath() + "/" + lmsFile.baseName());
	connect(&java, &QProcess::readyRead, this, [&java]() { QLOG_INFO() << java.readAll(); });
	java.waitForFinished();
	return true;
}

QString Ev3RbfGeneratorPlugin::upload(const QFileInfo &lmsFile)
{
	const QString folderName = SettingsManager::value("Ev3CommonFolderChecboxChecked", false).toBool()
			? SettingsManager::value("Ev3CommonFolderName", "ts").toString() : lmsFile.baseName();
	const QString targetPath = "../prjs/" + folderName;
	const QString rbfPath = lmsFile.absolutePath() + "/" + lmsFile.baseName() + ".rbf";
	bool connected = false;
	communication::Ev3RobotCommunicationThread *communicator = currentCommunicator();
	if (!communicator) {
		return QString();
	}

	const auto connection = connect(communicator, &communication::Ev3RobotCommunicationThread::connected
			, this, [&connected](bool success, const QString &) { connected = success; });
	communicator->connect();
	disconnect(connection);
	if (connected) {
		return communicator->uploadFile(rbfPath, targetPath);
	}

	return QString();
}

generatorBase::MasterGeneratorBase *Ev3RbfGeneratorPlugin::masterGenerator()
{
	return new Ev3RbfMasterGenerator(*mRepo
			, *mMainWindowInterface->errorReporter()
			, *mParserErrorReporter
			, *mRobotModelManager
			, *mTextLanguage
			, mMainWindowInterface->activeDiagram()
			, generatorName());
}
<commit_msg>fix ev3 autonomous mode for linux<commit_after>/* Copyright 2007-2015 QReal Research Group
 *
 * 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 "ev3RbfGeneratorPlugin.h"

#include <QtWidgets/QApplication>
#include <QtCore/QDirIterator>
#include <QtCore/QProcess>

#include <qrutils/widgets/qRealMessageBox.h>
#include <qrkernel/logging.h>
#include <ev3Kit/communication/ev3RobotCommunicationThread.h>
#include <ev3GeneratorBase/robotModel/ev3GeneratorRobotModel.h>
#include <qrkernel/settingsManager.h>
#include "ev3RbfMasterGenerator.h"

using namespace ev3::rbf;
using namespace qReal;

Ev3RbfGeneratorPlugin::Ev3RbfGeneratorPlugin()
	: Ev3GeneratorPluginBase("Ev3RbfUsbGeneratorRobotModel", tr("Autonomous mode (USB)"), 9
			, "Ev3RbfBluetoothGeneratorRobotModel", tr("Autonomous mode (Bluetooth)"), 8)
	, mGenerateCodeAction(new QAction(nullptr))
	, mUploadProgramAction(new QAction(nullptr))
	, mRunProgramAction(new QAction(nullptr))
	, mStopRobotAction(new QAction(nullptr))
{
	mGenerateCodeAction->setText(tr("Generate to Ev3 Robot Byte Code File"));
	mGenerateCodeAction->setIcon(QIcon(":/ev3/rbf/images/generateRbfCode.svg"));
	connect(mGenerateCodeAction, &QAction::triggered, this, &Ev3RbfGeneratorPlugin::generateCode);

	mUploadProgramAction->setText(tr("Upload program"));
	mUploadProgramAction->setIcon(QIcon(":/ev3/rbf/images/uploadProgram.svg"));
	connect(mUploadProgramAction, &QAction::triggered, this, &Ev3RbfGeneratorPlugin::uploadAndRunProgram);

	mRunProgramAction->setObjectName("runEv3RbfProgram");
	mRunProgramAction->setText(tr("Run program"));
	mRunProgramAction->setIcon(QIcon(":/ev3/rbf/images/run.png"));
	connect(mRunProgramAction, &QAction::triggered, this, &Ev3RbfGeneratorPlugin::runProgram, Qt::UniqueConnection);

	mStopRobotAction->setObjectName("stopEv3RbfRobot");
	mStopRobotAction->setText(tr("Stop robot"));
	mStopRobotAction->setIcon(QIcon(":/ev3/rbf/images/stop.png"));
	connect(mStopRobotAction, &QAction::triggered, this, &Ev3RbfGeneratorPlugin::stopRobot, Qt::UniqueConnection);

	text::Languages::registerLanguage(text::LanguageInfo{ "lms"
			, tr("EV3 Source Code language")
			, true
			, 4
			, nullptr
			, {}
	});
}

QList<ActionInfo> Ev3RbfGeneratorPlugin::customActions()
{
	const ActionInfo generateCodeActionInfo(mGenerateCodeAction, "generators", "tools");
	const ActionInfo uploadProgramActionInfo(mUploadProgramAction, "generators", "tools");
	const ActionInfo runProgramActionInfo(mRunProgramAction, "interpreters", "tools");
	const ActionInfo stopRobotActionInfo(mStopRobotAction, "interpreters", "tools");
	return {generateCodeActionInfo, uploadProgramActionInfo, runProgramActionInfo, stopRobotActionInfo};
}

QList<HotKeyActionInfo> Ev3RbfGeneratorPlugin::hotKeyActions()
{
	mGenerateCodeAction->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_G));
	mUploadProgramAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_U));
	mRunProgramAction->setShortcut(QKeySequence(Qt::Key_F5));
	mStopRobotAction->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_F5));

	HotKeyActionInfo generateActionInfo("Generator.GenerateEv3Rbf"
			, tr("Generate Ev3 Robot Byte Code File"), mGenerateCodeAction);
	HotKeyActionInfo uploadProgramInfo("Generator.UploadEv3", tr("Upload EV3 Program"), mUploadProgramAction);
	HotKeyActionInfo runProgramInfo("Generator.RunEv3", tr("Run EV3 Program"), mRunProgramAction);
	HotKeyActionInfo stopRobotInfo("Generator.StopEv3", tr("Stop EV3 Program"), mStopRobotAction);

	return { generateActionInfo, uploadProgramInfo, runProgramInfo, stopRobotInfo };
}

QIcon Ev3RbfGeneratorPlugin::iconForFastSelector(const kitBase::robotModel::RobotModelInterface &robotModel) const
{
	Q_UNUSED(robotModel)
	return QIcon(":/ev3/rbf/images/switch-to-ev3-rbf.svg");
}

int Ev3RbfGeneratorPlugin::priority() const
{
	return 9;
}

QString Ev3RbfGeneratorPlugin::defaultFilePath(QString const &projectName) const
{
	return QString("ev3-rbf/%1/%1.lms").arg(projectName);
}

text::LanguageInfo Ev3RbfGeneratorPlugin::language() const
{
	return text::Languages::pickByExtension("lms");
}

QString Ev3RbfGeneratorPlugin::generatorName() const
{
	return "ev3/rbf";
}

QString Ev3RbfGeneratorPlugin::uploadProgram()
{
	if (!javaInstalled()) {
		mMainWindowInterface->errorReporter()->addError(tr("Java is "\
				"not installed. Please download and install it."));
		return QString();
	}

	QFileInfo const fileInfo = generateCodeForProcessing();
	if (!fileInfo.exists()) {
		return QString();
	}

	if (!copySystemFiles(fileInfo.absolutePath())) {
		mMainWindowInterface->errorReporter()->addError(tr("Can't write source code files to disk!"));
		return QString();
	}

	if (!compile(fileInfo)) {
		QLOG_ERROR() << "EV3 bytecode compillation process failed!";
		mMainWindowInterface->errorReporter()->addError(tr("Compilation error occured."));
		return QString();
	}

	const QString fileOnRobot = upload(fileInfo);
	if (fileOnRobot.isEmpty()) {
		const bool isUsb = mRobotModelManager->model().name().contains("usb", Qt::CaseInsensitive);
		mMainWindowInterface->errorReporter()->addError(tr("Could not upload file to robot. "\
				"Connect to a robot via %1.").arg(isUsb ? tr("USB") : tr("Bluetooth")));
		return QString();
	}

	return fileOnRobot;
}

void Ev3RbfGeneratorPlugin::uploadAndRunProgram()
{
	const QString fileOnRobot = uploadProgram();
	communication::Ev3RobotCommunicationThread * const communicator = currentCommunicator();

	if (fileOnRobot.isEmpty() || !communicator) {
		return;
	}

	const RunPolicy runPolicy = static_cast<RunPolicy>(SettingsManager::value("ev3RunPolicy").toInt());
	switch (runPolicy) {
	case RunPolicy::Ask:
		if (utils::QRealMessageBox::question(mMainWindowInterface->windowWidget(), tr("The program has been uploaded")
				, tr("Do you want to run it?")) == QMessageBox::Yes) {
			communicator->runProgram(fileOnRobot);
		}
		break;
	case RunPolicy::AlwaysRun:
		communicator->runProgram(fileOnRobot);
		break;
	case RunPolicy::NeverRun:
		break;
	}
}

void Ev3RbfGeneratorPlugin::runProgram()
{
	const QString fileOnRobot = uploadProgram();
	communication::Ev3RobotCommunicationThread * const communicator = currentCommunicator();
	if (!fileOnRobot.isEmpty() && communicator) {
		communicator->runProgram(fileOnRobot);
	}
}

void Ev3RbfGeneratorPlugin::stopRobot()
{
	if (communication::Ev3RobotCommunicationThread * const communicator = currentCommunicator()) {
		communicator->stopProgram();
	}
}

bool Ev3RbfGeneratorPlugin::javaInstalled()
{
	QProcess java;
	java.setEnvironment(QProcess::systemEnvironment());

	java.start("java");
	java.waitForFinished();
	return !java.readAllStandardError().isEmpty();
}

bool Ev3RbfGeneratorPlugin::copySystemFiles(const QString &destination)
{
	QDirIterator iterator(":/ev3/rbf/thirdparty");
	while (iterator.hasNext()) {
		const QFileInfo fileInfo(iterator.next());
		const QString destFile = destination + "/" + fileInfo.fileName();
		if (!QFile::exists(destFile) && !QFile::copy(fileInfo.absoluteFilePath(), destFile)) {
			return false;
		}
	}

	return true;
}

bool Ev3RbfGeneratorPlugin::compile(const QFileInfo &lmsFile)
{
	QFile rbfFile(lmsFile.absolutePath() + "/" + lmsFile.baseName() + ".rbf");
	if (rbfFile.exists()) {
		rbfFile.remove();
	}

	QProcess java;
	java.setEnvironment(QProcess::systemEnvironment());
	java.setWorkingDirectory(lmsFile.absolutePath());
#ifdef Q_OS_WIN
	java.start("cmd /c java -jar assembler.jar " + lmsFile.absolutePath() + "/" + lmsFile.baseName());
#else
	java.start("java -jar assembler.jar " + lmsFile.absolutePath() + "/" + lmsFile.baseName());
#endif
	connect(&java, &QProcess::readyRead, this, [&java]() { QLOG_INFO() << java.readAll(); });
	java.waitForFinished();
	return true;
}

QString Ev3RbfGeneratorPlugin::upload(const QFileInfo &lmsFile)
{
	const QString folderName = SettingsManager::value("Ev3CommonFolderChecboxChecked", false).toBool()
			? SettingsManager::value("Ev3CommonFolderName", "ts").toString() : lmsFile.baseName();
	const QString targetPath = "../prjs/" + folderName;
	const QString rbfPath = lmsFile.absolutePath() + "/" + lmsFile.baseName() + ".rbf";
	bool connected = false;
	communication::Ev3RobotCommunicationThread *communicator = currentCommunicator();
	if (!communicator) {
		return QString();
	}

	const auto connection = connect(communicator, &communication::Ev3RobotCommunicationThread::connected
			, this, [&connected](bool success, const QString &) { connected = success; });
	communicator->connect();
	disconnect(connection);
	if (connected) {
		return communicator->uploadFile(rbfPath, targetPath);
	}

	return QString();
}

generatorBase::MasterGeneratorBase *Ev3RbfGeneratorPlugin::masterGenerator()
{
	return new Ev3RbfMasterGenerator(*mRepo
			, *mMainWindowInterface->errorReporter()
			, *mParserErrorReporter
			, *mRobotModelManager
			, *mTextLanguage
			, mMainWindowInterface->activeDiagram()
			, generatorName());
}
<|endoftext|>


<commit_before>#include <curl/curl.h>

#include <yadisk/client.hpp>
#include <url/params.hpp>
#include <boost/algorithm/string/join.hpp>

#include <sstream>
using std::stringstream;

#include "callbacks.hpp"
#include "quote.hpp"

namespace YandexDisk
{
    static const std::string api_url = "https://cloud-api.yandex.net/v1/disk/resources";

    Client::Client(string token_) : token{token_} {}

    auto Client::patch(url::path resource, json meta, std::list<string> fields) -> json {

        CURL * curl = curl_easy_init();
        url::params_t params;
        params["fields"] = boost::algorithm::join(fields, ",");
        params["path"] = quote(resource.string(), curl);
        stringstream body, response;
        std::string url = api_url + "?" + params.string();
        auto content = meta.dump();
        body << content;
        std::string text = "Authorization: OAuth " + token;

        curl_slist * header = nullptr;
        header = curl_slist_append(header, "Content-Type: application/json");
        header = curl_slist_append(header, text.c_str());

        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write<stringstream>);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, content.c_str());
        curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, content.size());
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
#ifdef DEBUG
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
#endif

        auto result = curl_easy_perform(curl);
        curl_slist_free_all(header);

        return result == CURLE_OK ? json::parse(response) : json();
    }
}
<commit_msg>Update client.cpp<commit_after>#include <curl/curl.h>

#include <url/params.hpp>
#include <yadisk/client.hpp>
#include <boost/algorithm/string/join.hpp>

#include <sstream>
using std::stringstream;

#include "callbacks.hpp"
#include "quote.hpp"

namespace yadisk
{
    static const std::string api_url = "https://cloud-api.yandex.net/v1/disk/resources";

    Client::Client(string token_) : token{token_} {}

    auto Client::patch(url::path resource, json meta, std::list<string> fields) -> json {

        // init http request
        CURL * curl = curl_easy_init();

        // fill http url
        url::params_t url_params;
        url_params["fields"] = boost::algorithm::join(fields, ",");
        url_params["path"] = quote(resource.string(), curl);
        std::string url = api_url + "?" + url_params.string();

        // fill http header
        curl_slist * http_header = nullptr;
        std::string authorization_header = "Authorization: OAuth " + token;
        http_header = curl_slist_append(http_header, "Content-Type: application/json");
        http_header = curl_slist_append(http_header, authorization_header.c_str());

        // fill http body
        auto request_body = meta.dump();

        // build http request
        stringstream response_body;
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write<stringstream>);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request_body.c_str());
        curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, request_body.size());
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_header);

        // perform http request
        auto response_code = curl_easy_perform(curl);

        // clean resources
        curl_slist_free_all(http_header);
        curl_easy_cleanup(curl);

        // check response code
        if ( response_code != CURLE_OK ) return json();

        // handle body of http response
        auto info = json::parse(response_body);
        return info;
    }
}
<|endoftext|>


<commit_before>#include "Tiles.h"

namespace sfc {

Tile::Tile(const Image& image, Mode mode, unsigned bpp, bool no_flip)
: _mode(mode), _bpp(bpp),
  _width(image.width()), _height(image.height()),
  _palette(image.palette())
{
  if (image.indexed_data().empty()) throw std::runtime_error("Can't create tile without indexed data");

  index_t mask = bitmask_at_bpp(_bpp);
  for (index_t ip : image.indexed_data()) _data.push_back(ip & mask);

  if (!no_flip) {
    _mirrors.push_back(mirror(_data, _width, true, false));
    _mirrors.push_back(mirror(_data, _width, false, true));
    _mirrors.push_back(mirror(_data, _width, true, true));
  }
}

Tile::Tile(const std::vector<uint8_t>& native_data, Mode mode, unsigned bpp, bool no_flip, unsigned width, unsigned height)
: _mode(mode), _bpp(bpp),
  _width(width), _height(height),
  _data(unpack_native_tile(native_data, mode, bpp, width, height))
{
  _palette.resize(palette_size_at_bpp(bpp));
  channel_t add = 0x100 / _palette.size();
  for (unsigned i = 0; i < _palette.size(); ++i) {
    channel_t value = add * i;
    _palette[i] = (rgba_t)(0xff000000 + value + (value << 8) + (value << 16));
  }

  if (!no_flip) {
    _mirrors.push_back(mirror(_data, _width, true, false));
    _mirrors.push_back(mirror(_data, _width, false, true));
    _mirrors.push_back(mirror(_data, _width, true, true));
  }
}

Tile::Tile(const std::vector<Tile>& metatile, bool no_flip, unsigned width, unsigned height) {
  if (metatile.empty()) return;

  _mode = metatile[0]._mode;
  _bpp = metatile[0]._bpp;
  _palette = metatile[0]._palette;
  _width = width;
  _height = height;
  _data.resize(width * height);

  const unsigned metatile_dim = metatile[0]._width;
  const unsigned metatiles_h = width / metatile_dim;
  const unsigned metatiles_v = height / metatile_dim;

  unsigned metatile_index = 0;
  for (unsigned my = 0; my < metatiles_v; ++my) {
    for (unsigned mx = 0; mx < metatiles_h; ++mx) {
      for (unsigned blit_y = 0; blit_y < metatile_dim; ++blit_y) {
        std::memcpy(&_data[((blit_y + (my * metatile_dim)) * width) + (mx * metatile_dim)],
                    &metatile[metatile_index]._data[blit_y * metatile_dim], metatile_dim);
      }
      ++metatile_index;
    }
  }

  if (!no_flip) {
    _mirrors.push_back(mirror(_data, _width, true, false));
    _mirrors.push_back(mirror(_data, _width, false, true));
    _mirrors.push_back(mirror(_data, _width, true, true));
  }
}

bool Tile::is_h_flipped(const Tile& other) const {
  if (other._data == _data) return false;
  if (_mirrors.empty()) throw std::runtime_error("Programmer error");
  if (other._data == _mirrors[0] || other._data == _mirrors[2]) return true;
  return false;
}

bool Tile::is_v_flipped(const Tile& other) const {
  if (other._data == _data) return false;
  if (_mirrors.empty()) throw std::runtime_error("Programmer error");
  if (other._data == _mirrors[1] || other._data == _mirrors[2]) return true;
  return false;
}

bool Tile::operator==(const Tile& other) const {
  if (other._data == _data) return true;
  if (!_mirrors.empty()) {
    for (auto& m : _mirrors) {
      if (other._data == m) return true;
    }
  }
  return false;
}

Tile Tile::crop(unsigned x, unsigned y, unsigned crop_width, unsigned crop_height) const {
  Tile t;
  t._mode = _mode;
  t._bpp = _bpp;
  t._width = crop_width;
  t._height = crop_height;
  t._palette = _palette;
  t._data.resize(crop_width * crop_height);

  if (x > _width || y > _height) {
    // no blit
  } else {
    unsigned blit_width = (x + crop_width > _width) ? _width - x : crop_width;
    unsigned blit_height = (y + crop_height > _height) ? _height - y : crop_height;
    for (unsigned iy = 0; iy < blit_height; ++iy) {
      std::memcpy(&t._data[iy * t._width], &_data[(x) + ((iy + y) * _width)], blit_width);
    }
  }

  if (_mirrors.size()) {
    t._mirrors.push_back(mirror(t._data, t._width, true, false));
    t._mirrors.push_back(mirror(t._data, t._width, false, true));
    t._mirrors.push_back(mirror(t._data, t._width, true, true));
  }

  return t;
}

std::vector<Tile> Tile::crops(unsigned tile_width, unsigned tile_height) const {
  std::vector<Tile> tv;
  unsigned x = 0;
  unsigned y = 0;
  while (y < _height) {
    while (x < _width) {
      tv.push_back(crop(x, y, tile_width, tile_height));
      x += tile_width;
    }
    x = 0;
    y += tile_height;
  }
  return tv;
}

std::vector<uint8_t> Tile::native_data() const {
  return pack_native_tile(_data, _mode, _bpp, _width, _height);
}

std::vector<rgba_t> Tile::rgba_data() const {
  std::vector<rgba_t> v(_data.size());
  for (unsigned i = 0; i < _data.size(); ++i) {
    v[i] = (_data[i] == 0) ? transparent_color : _palette[_data[i]];
  }
  return v;
}

Tileset::Tileset(const std::vector<uint8_t>& native_data, Mode mode, unsigned bpp,
                 unsigned tile_width, unsigned tile_height, bool no_flip) {
  _mode = mode;
  _bpp = bpp;
  _tile_width = tile_width;
  _tile_height = tile_height;
  _no_flip = no_flip;

  if (_mode == Mode::snes || _mode == Mode::snes_mode7 || _mode == Mode::gbc || _mode == Mode::gb) {
    unsigned bytes_per_tile = bpp << 3;
    if (native_data.size() % bytes_per_tile != 0) {
      throw std::runtime_error("Tile data can't be deserialized (size doesn't match bpp setting)");
    }

    unsigned tiles = (unsigned)native_data.size() / bytes_per_tile;
    for (unsigned i = 0; i < tiles; ++i) {
      _tiles.push_back(
        Tile(std::vector<uint8_t>(&native_data[i * bytes_per_tile], &native_data[(i + 1) * bytes_per_tile]),
             mode, bpp, no_flip, 8, 8));
    }
  }

  if (_tile_width != 8 || _tile_height != 8) _tiles = remap_tiles_for_input(_tiles, _mode);
}

void Tileset::add(const Image& image, const Palette* palette) {
  Tile tile;

  if (_no_remap) {
    tile = Tile(image, _mode, _bpp, _no_flip);
  } else {
    if (palette == nullptr) throw std::runtime_error("Can't remap tile without palette");
    Image remapped_image = Image(image, palette->subpalette_matching(image));
    tile = Tile(remapped_image, _mode, _bpp, _no_flip);
  }

  if (_no_discard) {
    if (is_full()) throw std::runtime_error("Tileset reached maximum size");
    _tiles.push_back(tile);
  } else {
    if (std::find(_tiles.begin(), _tiles.end(), tile) == _tiles.end()) {
      if (is_full()) throw std::runtime_error("Tileset reached maximum size");
      _tiles.push_back(tile);
    } else {
      ++discarded_tiles;
    }
  }
}

int Tileset::index_of(const Tile& tile) const {
  auto index = std::find(_tiles.begin(), _tiles.end(), tile);
  if (index != _tiles.end()) {
    return (int)std::distance(_tiles.begin(), index);
  } else {
    return -1;
  }
}

void Tileset::save(const std::string& path) const {
  write_file(path, native_data());
}

std::vector<uint8_t> Tileset::native_data() const {
  std::vector<Tile> tv;
  if (_tile_width != 8 || _tile_height != 8) {
    tv = remap_tiles_for_output(_tiles, _mode);
  } else {
    tv = _tiles;
  }

  std::vector<uint8_t> data;
  for (const auto& t : tv) {
    auto nt = t.native_data();
    data.insert(data.end(), nt.begin(), nt.end());
  }

  return data;
}

std::vector<Tile> Tileset::remap_tiles_for_output(const std::vector<Tile>& tiles, Mode mode) const {
  std::vector<Tile> tv;

  if (mode == Mode::snes || mode == Mode::gb || mode == Mode::gbc) {
    const unsigned cells_per_tile_h = _tile_width / 8;
    const unsigned cells_per_tile_v = _tile_height / 8;
    const unsigned cells_per_row = 16;
    const unsigned tiles_per_row = cells_per_row / cells_per_tile_h;
    const unsigned cell_rows = div_ceil((int)tiles.size(), tiles_per_row) * cells_per_tile_v;

    tv.resize(cells_per_row * cell_rows);

    for (unsigned i = 0; i < tiles.size(); ++i) {
      unsigned base_pos = (((i / tiles_per_row) * cells_per_tile_v) * cells_per_row) +
                          ((i % tiles_per_row) << (cells_per_tile_h - 1));
      auto ct = tiles[i].crops(8, 8);
      for (unsigned cy = 0; cy < cells_per_tile_v; ++cy) {
        for (unsigned cx = 0; cx < cells_per_tile_h; ++cx) {
          tv[base_pos + (cy * cells_per_row) + cx] = ct[(cy * cells_per_tile_v) + cx];
        }
      }
    }

  } else if (mode == Mode::snes_mode7) {
    throw std::runtime_error("Programmer error: This can't be!");
  }

  return tv;
}

std::vector<Tile> Tileset::remap_tiles_for_input(const std::vector<Tile>& tiles, Mode mode) const {
  std::vector<Tile> tv;

  if (mode == Mode::snes || mode == Mode::gbc || mode == Mode::gb) {
    const unsigned cells_per_tile_h = _tile_width / 8;
    const unsigned cells_per_tile_v = _tile_height / 8;

    for (unsigned i = 0; i < _tiles.size(); ++i) {
      std::vector<Tile> metatile;
      for (unsigned yo = 0; yo < cells_per_tile_v; ++yo) {
        for (unsigned xo = 0; xo < cells_per_tile_h; ++xo) {
          if ((i + (yo * 16) + xo) < tiles.size()) metatile.push_back(tiles[i + (yo * 16) + xo]);
        }
      }
      if (metatile.size() == cells_per_tile_h * cells_per_tile_v)
        tv.push_back(Tile(metatile, _no_flip, _tile_width, _tile_height));
    }

  } else if (mode == Mode::snes_mode7) {
    throw std::runtime_error("Programmer error");
  }

  return tv;
}

} /* namespace sfc */
<commit_msg>Do not render tiles-image with transparent color zero<commit_after>#include "Tiles.h"

namespace sfc {

Tile::Tile(const Image& image, Mode mode, unsigned bpp, bool no_flip)
: _mode(mode), _bpp(bpp),
  _width(image.width()), _height(image.height()),
  _palette(image.palette())
{
  if (image.indexed_data().empty()) throw std::runtime_error("Can't create tile without indexed data");

  index_t mask = bitmask_at_bpp(_bpp);
  for (index_t ip : image.indexed_data()) _data.push_back(ip & mask);

  if (!no_flip) {
    _mirrors.push_back(mirror(_data, _width, true, false));
    _mirrors.push_back(mirror(_data, _width, false, true));
    _mirrors.push_back(mirror(_data, _width, true, true));
  }
}

Tile::Tile(const std::vector<uint8_t>& native_data, Mode mode, unsigned bpp, bool no_flip, unsigned width, unsigned height)
: _mode(mode), _bpp(bpp),
  _width(width), _height(height),
  _data(unpack_native_tile(native_data, mode, bpp, width, height))
{
  _palette.resize(palette_size_at_bpp(bpp));
  channel_t add = 0x100 / _palette.size();
  for (unsigned i = 0; i < _palette.size(); ++i) {
    channel_t value = add * i;
    _palette[i] = (rgba_t)(0xff000000 + value + (value << 8) + (value << 16));
  }

  if (!no_flip) {
    _mirrors.push_back(mirror(_data, _width, true, false));
    _mirrors.push_back(mirror(_data, _width, false, true));
    _mirrors.push_back(mirror(_data, _width, true, true));
  }
}

Tile::Tile(const std::vector<Tile>& metatile, bool no_flip, unsigned width, unsigned height) {
  if (metatile.empty()) return;

  _mode = metatile[0]._mode;
  _bpp = metatile[0]._bpp;
  _palette = metatile[0]._palette;
  _width = width;
  _height = height;
  _data.resize(width * height);

  const unsigned metatile_dim = metatile[0]._width;
  const unsigned metatiles_h = width / metatile_dim;
  const unsigned metatiles_v = height / metatile_dim;

  unsigned metatile_index = 0;
  for (unsigned my = 0; my < metatiles_v; ++my) {
    for (unsigned mx = 0; mx < metatiles_h; ++mx) {
      for (unsigned blit_y = 0; blit_y < metatile_dim; ++blit_y) {
        std::memcpy(&_data[((blit_y + (my * metatile_dim)) * width) + (mx * metatile_dim)],
                    &metatile[metatile_index]._data[blit_y * metatile_dim], metatile_dim);
      }
      ++metatile_index;
    }
  }

  if (!no_flip) {
    _mirrors.push_back(mirror(_data, _width, true, false));
    _mirrors.push_back(mirror(_data, _width, false, true));
    _mirrors.push_back(mirror(_data, _width, true, true));
  }
}

bool Tile::is_h_flipped(const Tile& other) const {
  if (other._data == _data) return false;
  if (_mirrors.empty()) throw std::runtime_error("Programmer error");
  if (other._data == _mirrors[0] || other._data == _mirrors[2]) return true;
  return false;
}

bool Tile::is_v_flipped(const Tile& other) const {
  if (other._data == _data) return false;
  if (_mirrors.empty()) throw std::runtime_error("Programmer error");
  if (other._data == _mirrors[1] || other._data == _mirrors[2]) return true;
  return false;
}

bool Tile::operator==(const Tile& other) const {
  if (other._data == _data) return true;
  if (!_mirrors.empty()) {
    for (auto& m : _mirrors) {
      if (other._data == m) return true;
    }
  }
  return false;
}

Tile Tile::crop(unsigned x, unsigned y, unsigned crop_width, unsigned crop_height) const {
  Tile t;
  t._mode = _mode;
  t._bpp = _bpp;
  t._width = crop_width;
  t._height = crop_height;
  t._palette = _palette;
  t._data.resize(crop_width * crop_height);

  if (x > _width || y > _height) {
    // no blit
  } else {
    unsigned blit_width = (x + crop_width > _width) ? _width - x : crop_width;
    unsigned blit_height = (y + crop_height > _height) ? _height - y : crop_height;
    for (unsigned iy = 0; iy < blit_height; ++iy) {
      std::memcpy(&t._data[iy * t._width], &_data[(x) + ((iy + y) * _width)], blit_width);
    }
  }

  if (_mirrors.size()) {
    t._mirrors.push_back(mirror(t._data, t._width, true, false));
    t._mirrors.push_back(mirror(t._data, t._width, false, true));
    t._mirrors.push_back(mirror(t._data, t._width, true, true));
  }

  return t;
}

std::vector<Tile> Tile::crops(unsigned tile_width, unsigned tile_height) const {
  std::vector<Tile> tv;
  unsigned x = 0;
  unsigned y = 0;
  while (y < _height) {
    while (x < _width) {
      tv.push_back(crop(x, y, tile_width, tile_height));
      x += tile_width;
    }
    x = 0;
    y += tile_height;
  }
  return tv;
}

std::vector<uint8_t> Tile::native_data() const {
  return pack_native_tile(_data, _mode, _bpp, _width, _height);
}

std::vector<rgba_t> Tile::rgba_data() const {
  std::vector<rgba_t> v(_data.size());
  for (unsigned i = 0; i < _data.size(); ++i) {
    //TODO: Render with transparency if "sprite mode" / col0 is set?
    //v[i] = (_data[i] == 0) ? transparent_color : _palette[_data[i]];
    v[i] = _palette[_data[i]];
  }
  return v;
}

Tileset::Tileset(const std::vector<uint8_t>& native_data, Mode mode, unsigned bpp,
                 unsigned tile_width, unsigned tile_height, bool no_flip) {
  _mode = mode;
  _bpp = bpp;
  _tile_width = tile_width;
  _tile_height = tile_height;
  _no_flip = no_flip;

  if (_mode == Mode::snes || _mode == Mode::snes_mode7 || _mode == Mode::gbc || _mode == Mode::gb) {
    unsigned bytes_per_tile = bpp << 3;
    if (native_data.size() % bytes_per_tile != 0) {
      throw std::runtime_error("Tile data can't be deserialized (size doesn't match bpp setting)");
    }

    unsigned tiles = (unsigned)native_data.size() / bytes_per_tile;
    for (unsigned i = 0; i < tiles; ++i) {
      _tiles.push_back(
        Tile(std::vector<uint8_t>(&native_data[i * bytes_per_tile], &native_data[(i + 1) * bytes_per_tile]),
             mode, bpp, no_flip, 8, 8));
    }
  }

  if (_tile_width != 8 || _tile_height != 8) _tiles = remap_tiles_for_input(_tiles, _mode);
}

void Tileset::add(const Image& image, const Palette* palette) {
  Tile tile;

  if (_no_remap) {
    tile = Tile(image, _mode, _bpp, _no_flip);
  } else {
    if (palette == nullptr) throw std::runtime_error("Can't remap tile without palette");
    Image remapped_image = Image(image, palette->subpalette_matching(image));
    tile = Tile(remapped_image, _mode, _bpp, _no_flip);
  }

  if (_no_discard) {
    if (is_full()) throw std::runtime_error("Tileset reached maximum size");
    _tiles.push_back(tile);
  } else {
    if (std::find(_tiles.begin(), _tiles.end(), tile) == _tiles.end()) {
      if (is_full()) throw std::runtime_error("Tileset reached maximum size");
      _tiles.push_back(tile);
    } else {
      ++discarded_tiles;
    }
  }
}

int Tileset::index_of(const Tile& tile) const {
  auto index = std::find(_tiles.begin(), _tiles.end(), tile);
  if (index != _tiles.end()) {
    return (int)std::distance(_tiles.begin(), index);
  } else {
    return -1;
  }
}

void Tileset::save(const std::string& path) const {
  write_file(path, native_data());
}

std::vector<uint8_t> Tileset::native_data() const {
  std::vector<Tile> tv;
  if (_tile_width != 8 || _tile_height != 8) {
    tv = remap_tiles_for_output(_tiles, _mode);
  } else {
    tv = _tiles;
  }

  std::vector<uint8_t> data;
  for (const auto& t : tv) {
    auto nt = t.native_data();
    data.insert(data.end(), nt.begin(), nt.end());
  }

  return data;
}

std::vector<Tile> Tileset::remap_tiles_for_output(const std::vector<Tile>& tiles, Mode mode) const {
  std::vector<Tile> tv;

  if (mode == Mode::snes || mode == Mode::gb || mode == Mode::gbc) {
    const unsigned cells_per_tile_h = _tile_width / 8;
    const unsigned cells_per_tile_v = _tile_height / 8;
    const unsigned cells_per_row = 16;
    const unsigned tiles_per_row = cells_per_row / cells_per_tile_h;
    const unsigned cell_rows = div_ceil((int)tiles.size(), tiles_per_row) * cells_per_tile_v;

    tv.resize(cells_per_row * cell_rows);

    for (unsigned i = 0; i < tiles.size(); ++i) {
      unsigned base_pos = (((i / tiles_per_row) * cells_per_tile_v) * cells_per_row) +
                          ((i % tiles_per_row) << (cells_per_tile_h - 1));
      auto ct = tiles[i].crops(8, 8);
      for (unsigned cy = 0; cy < cells_per_tile_v; ++cy) {
        for (unsigned cx = 0; cx < cells_per_tile_h; ++cx) {
          tv[base_pos + (cy * cells_per_row) + cx] = ct[(cy * cells_per_tile_v) + cx];
        }
      }
    }

  } else if (mode == Mode::snes_mode7) {
    throw std::runtime_error("Programmer error: This can't be!");
  }

  return tv;
}

std::vector<Tile> Tileset::remap_tiles_for_input(const std::vector<Tile>& tiles, Mode mode) const {
  std::vector<Tile> tv;

  if (mode == Mode::snes || mode == Mode::gbc || mode == Mode::gb) {
    const unsigned cells_per_tile_h = _tile_width / 8;
    const unsigned cells_per_tile_v = _tile_height / 8;

    for (unsigned i = 0; i < _tiles.size(); ++i) {
      std::vector<Tile> metatile;
      for (unsigned yo = 0; yo < cells_per_tile_v; ++yo) {
        for (unsigned xo = 0; xo < cells_per_tile_h; ++xo) {
          if ((i + (yo * 16) + xo) < tiles.size()) metatile.push_back(tiles[i + (yo * 16) + xo]);
        }
      }
      if (metatile.size() == cells_per_tile_h * cells_per_tile_v)
        tv.push_back(Tile(metatile, _no_flip, _tile_width, _tile_height));
    }

  } else if (mode == Mode::snes_mode7) {
    throw std::runtime_error("Programmer error");
  }

  return tv;
}

} /* namespace sfc */
<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2017, Balazs Racz
 * 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.
 *
 * 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 COPYRIGHT HOLDER 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.
 *
 * \file TcpDefs.hxx
 *
 * Static declarations, enums and helper functions for the OpenLCB TCP
 * interfaces.
 *
 * @author Balazs Racz
 * @date 12 September 2017
 */

#ifndef _OPENLCB_TCPDEFS_HXX_
#define _OPENLCB_TCPDEFS_HXX_

#include "utils/macros.h"

namespace openlcb {

class TcpDefs {
public:
    // Protocol to be used for mDNS broadcast
    static const char TcpDefs::MDNS_PROTOCOL_TCP[];
    // base name of the mDNS Service Name for mDNS broadcast as a hub
    static const char TcpDefs::MDNS_SERVICE_NAME_HUB[];
    // complete mDNS broadcast name for a TCP hub
    static const char TcpDefs::MDNS_SERVICE_NAME_HUB_TCP[];
    // base name of the mDNS Service Name for mDNS broadcast as a client
    static const char TcpDefs::MDNS_SERVICE_NAME_GRIDCONNECT_CAN[];
    // complete mDNS broadcast name for a TCP GridConnect protocol client
    static const char TcpDefs::MDNS_SERVICE_NAME_GRIDCONNECT_CAN_TCP[];

private:
    /// Nobody can construct this class.
    TcpDefs();
    DISALLOW_COPY_AND_ASSIGN(TcpDefs);
};  // class TcpDefs

}  // namespace openlcb

#endif // _OPENLCB_TCPDEFS_HXX_
<commit_msg>Update TcpDefs.hxx<commit_after>/** \copyright
 * Copyright (c) 2017, Balazs Racz
 * 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.
 *
 * 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 COPYRIGHT HOLDER 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.
 *
 * \file TcpDefs.hxx
 *
 * Static declarations, enums and helper functions for the OpenLCB TCP
 * interfaces.
 *
 * @author Balazs Racz
 * @date 12 September 2017
 */

#ifndef _OPENLCB_TCPDEFS_HXX_
#define _OPENLCB_TCPDEFS_HXX_

#include "utils/macros.h"

namespace openlcb {

class TcpDefs {
public:
    // Protocol to be used for mDNS broadcast
    static const char MDNS_PROTOCOL_TCP[];
    // base name of the mDNS Service Name for mDNS broadcast as a hub
    static const char MDNS_SERVICE_NAME_HUB[];
    // complete mDNS broadcast name for a TCP hub
    static const char MDNS_SERVICE_NAME_HUB_TCP[];
    // base name of the mDNS Service Name for mDNS broadcast as a client
    static const char MDNS_SERVICE_NAME_GRIDCONNECT_CAN[];
    // complete mDNS broadcast name for a TCP GridConnect protocol client
    static const char MDNS_SERVICE_NAME_GRIDCONNECT_CAN_TCP[];

private:
    /// Nobody can construct this class.
    TcpDefs();
    DISALLOW_COPY_AND_ASSIGN(TcpDefs);
};  // class TcpDefs

}  // namespace openlcb

#endif // _OPENLCB_TCPDEFS_HXX_
<|endoftext|>


<commit_before>
#include "connection.h"
#include "oracle_bindings.h"
#include "statement.h"
#include "reader.h"
#include "outParam.h"

Persistent<FunctionTemplate> OracleClient::s_ct;

ConnectBaton::ConnectBaton(OracleClient* client, oracle::occi::Environment* environment, v8::Handle<v8::Function>* callback) {
  this->client = client;
  if(callback != NULL) {
    uni::Reset(this->callback, *callback);
  } else {
    // TODO: fix next line
    //this->callback = Persistent<Function>();
  }
  this->environment = environment;
  this->error = NULL;
  this->connection = NULL;

  this->hostname = "127.0.0.1";
  this->user = "";
  this->password = "";
  this->database = "";
}

ConnectBaton::~ConnectBaton() {
  callback.Dispose();
  if(error) {
    delete error;
  }
}

void OracleClient::Init(Handle<Object> target) {
  UNI_SCOPE(scope);

  Local<FunctionTemplate> t = FunctionTemplate::New(New);
  uni::Reset(s_ct, t);
  uni::Deref(s_ct)->InstanceTemplate()->SetInternalFieldCount(1);
  uni::Deref(s_ct)->SetClassName(String::NewSymbol("OracleClient"));

  NODE_SET_PROTOTYPE_METHOD(uni::Deref(s_ct), "connect", Connect);
  NODE_SET_PROTOTYPE_METHOD(uni::Deref(s_ct), "connectSync", ConnectSync);

  target->Set(String::NewSymbol("OracleClient"), uni::Deref(s_ct)->GetFunction());
}

uni::CallbackType OracleClient::New(const uni::FunctionCallbackInfo& args) {
  UNI_SCOPE(scope);

  /*
  REQ_OBJECT_ARG(0, settings);

  std:string hostname, user, password, database;
  unsigned int port, minConn, maxConn, incrConn;

  OBJ_GET_STRING(settings, "hostname", hostname);
  OBJ_GET_STRING(settings, "user", user);
  OBJ_GET_STRING(settings, "password", password);
  OBJ_GET_STRING(settings, "database", database);
  OBJ_GET_NUMBER(settings, "port", port, 1521);
  OBJ_GET_NUMBER(settings, "minConn", minConn, 0);
  OBJ_GET_NUMBER(settings, "maxConn", maxConn, 1);
  OBJ_GET_NUMBER(settings, "incrConn", incrConn, 1);

  std::ostringstream connectionStr;
      connectionStr << "//" << hostname << ":" << port << "/" << database;
  */

  OracleClient *client = new OracleClient();
  client->Wrap(args.This());
  UNI_RETURN(scope, args, args.This());
}

OracleClient::OracleClient() {
  m_environment = oracle::occi::Environment::createEnvironment(oracle::occi::Environment::THREADED_MUTEXED);
  /*
  m_connectionPool = m_environment->createConnectionPool(user, password, connectString, minConn, maxConn, incrConn);
  */
}

OracleClient::~OracleClient() {
  /*
  m_environment->terminateConnectionPool (connectionPool);
  */
  oracle::occi::Environment::terminateEnvironment(m_environment);
}

uni::CallbackType OracleClient::Connect(const uni::FunctionCallbackInfo& args) {
  UNI_SCOPE(scope);

  REQ_OBJECT_ARG(0, settings);
  REQ_FUN_ARG(1, callback);

  OracleClient* client = ObjectWrap::Unwrap<OracleClient>(args.This());
  ConnectBaton* baton = new ConnectBaton(client, client->m_environment, &callback);

  OBJ_GET_STRING(settings, "hostname", baton->hostname);
  OBJ_GET_STRING(settings, "user", baton->user);
  OBJ_GET_STRING(settings, "password", baton->password);
  OBJ_GET_STRING(settings, "database", baton->database);
  OBJ_GET_NUMBER(settings, "port", baton->port, 1521);
  OBJ_GET_STRING(settings, "tns", baton->tns);

  client->Ref();

  uv_work_t* req = new uv_work_t();
  req->data = baton;
  uv_queue_work(uv_default_loop(), req, EIO_Connect, (uv_after_work_cb)EIO_AfterConnect);

  UNI_RETURN(scope, args, Undefined());
}

void OracleClient::EIO_Connect(uv_work_t* req) {
  ConnectBaton* baton = static_cast<ConnectBaton*>(req->data);

  baton->error = NULL;

  try {
    std::ostringstream connectionStr;
    if (baton->tns != "") {
      connectionStr << baton->tns;
    } else {
      connectionStr << "//" << baton->hostname << ":" << baton->port << "/" << baton->database;
    }
    baton->connection = baton->environment->createConnection(baton->user, baton->password, connectionStr.str());
  } catch(oracle::occi::SQLException &ex) {
    baton->error = new std::string(ex.getMessage());
  }
}

void OracleClient::EIO_AfterConnect(uv_work_t* req, int status) {
  UNI_SCOPE(scope);
  ConnectBaton* baton = static_cast<ConnectBaton*>(req->data);
  baton->client->Unref();

  Handle<Value> argv[2];
  if(baton->error) {
    argv[0] = Exception::Error(String::New(baton->error->c_str()));
    argv[1] = Undefined();
  } else {
    argv[0] = Undefined();
    Handle<Object> connection = uni::Deref(Connection::constructorTemplate)->GetFunction()->NewInstance();
    (node::ObjectWrap::Unwrap<Connection>(connection))->setConnection(baton->client->m_environment, baton->connection);
    argv[1] = connection;
  }

  node::MakeCallback(Context::GetCurrent()->Global(), uni::Deref(baton->callback), 2, argv);

  delete baton;
  delete req;
}

uni::CallbackType OracleClient::ConnectSync(const uni::FunctionCallbackInfo& args) {
  UNI_SCOPE(scope);
  REQ_OBJECT_ARG(0, settings);

  OracleClient* client = ObjectWrap::Unwrap<OracleClient>(args.This());
  ConnectBaton baton(client, client->m_environment, NULL);

  OBJ_GET_STRING(settings, "hostname", baton.hostname);
  OBJ_GET_STRING(settings, "user", baton.user);
  OBJ_GET_STRING(settings, "password", baton.password);
  OBJ_GET_STRING(settings, "database", baton.database);
  OBJ_GET_NUMBER(settings, "port", baton.port, 1521);

  try {
    std::ostringstream connectionStr;
    connectionStr << "//" << baton.hostname << ":" << baton.port << "/" << baton.database;
    baton.connection = baton.environment->createConnection(baton.user, baton.password, connectionStr.str());
  } catch(oracle::occi::SQLException &ex) {
    baton.error = new std::string(ex.getMessage());
    UNI_THROW(Exception::Error(String::New(baton.error->c_str())));
  } catch (const std::exception& ex) {
    UNI_THROW(Exception::Error(String::New(ex.what())));
  }

  Handle<Object> connection = uni::Deref(Connection::constructorTemplate)->GetFunction()->NewInstance();
      (node::ObjectWrap::Unwrap<Connection>(connection))->setConnection(baton.client->m_environment, baton.connection);

  UNI_RETURN(scope, args, connection);

}

extern "C" {
  static void init(Handle<Object> target) {
    OracleClient::Init(target);
    Connection::Init(target);
    Statement::Init(target);
    Reader::Init(target);
    OutParam::Init(target);
  }

  NODE_MODULE(oracle_bindings, init);
}
<commit_msg>Added generic exception catcher to baton->createConnection to handle TNS not found errors<commit_after>
#include "connection.h"
#include "oracle_bindings.h"
#include "statement.h"
#include "reader.h"
#include "outParam.h"

Persistent<FunctionTemplate> OracleClient::s_ct;

ConnectBaton::ConnectBaton(OracleClient* client, oracle::occi::Environment* environment, v8::Handle<v8::Function>* callback) {
  this->client = client;
  if(callback != NULL) {
    uni::Reset(this->callback, *callback);
  } else {
    // TODO: fix next line
    //this->callback = Persistent<Function>();
  }
  this->environment = environment;
  this->error = NULL;
  this->connection = NULL;

  this->hostname = "127.0.0.1";
  this->user = "";
  this->password = "";
  this->database = "";
}

ConnectBaton::~ConnectBaton() {
  callback.Dispose();
  if(error) {
    delete error;
  }
}

void OracleClient::Init(Handle<Object> target) {
  UNI_SCOPE(scope);

  Local<FunctionTemplate> t = FunctionTemplate::New(New);
  uni::Reset(s_ct, t);
  uni::Deref(s_ct)->InstanceTemplate()->SetInternalFieldCount(1);
  uni::Deref(s_ct)->SetClassName(String::NewSymbol("OracleClient"));

  NODE_SET_PROTOTYPE_METHOD(uni::Deref(s_ct), "connect", Connect);
  NODE_SET_PROTOTYPE_METHOD(uni::Deref(s_ct), "connectSync", ConnectSync);

  target->Set(String::NewSymbol("OracleClient"), uni::Deref(s_ct)->GetFunction());
}

uni::CallbackType OracleClient::New(const uni::FunctionCallbackInfo& args) {
  UNI_SCOPE(scope);

  /*
  REQ_OBJECT_ARG(0, settings);

  std:string hostname, user, password, database;
  unsigned int port, minConn, maxConn, incrConn;

  OBJ_GET_STRING(settings, "hostname", hostname);
  OBJ_GET_STRING(settings, "user", user);
  OBJ_GET_STRING(settings, "password", password);
  OBJ_GET_STRING(settings, "database", database);
  OBJ_GET_NUMBER(settings, "port", port, 1521);
  OBJ_GET_NUMBER(settings, "minConn", minConn, 0);
  OBJ_GET_NUMBER(settings, "maxConn", maxConn, 1);
  OBJ_GET_NUMBER(settings, "incrConn", incrConn, 1);

  std::ostringstream connectionStr;
      connectionStr << "//" << hostname << ":" << port << "/" << database;
  */

  OracleClient *client = new OracleClient();
  client->Wrap(args.This());
  UNI_RETURN(scope, args, args.This());
}

OracleClient::OracleClient() {
  m_environment = oracle::occi::Environment::createEnvironment(oracle::occi::Environment::THREADED_MUTEXED);
  /*
  m_connectionPool = m_environment->createConnectionPool(user, password, connectString, minConn, maxConn, incrConn);
  */
}

OracleClient::~OracleClient() {
  /*
  m_environment->terminateConnectionPool (connectionPool);
  */
  oracle::occi::Environment::terminateEnvironment(m_environment);
}

uni::CallbackType OracleClient::Connect(const uni::FunctionCallbackInfo& args) {
  UNI_SCOPE(scope);

  REQ_OBJECT_ARG(0, settings);
  REQ_FUN_ARG(1, callback);

  OracleClient* client = ObjectWrap::Unwrap<OracleClient>(args.This());
  ConnectBaton* baton = new ConnectBaton(client, client->m_environment, &callback);

  OBJ_GET_STRING(settings, "hostname", baton->hostname);
  OBJ_GET_STRING(settings, "user", baton->user);
  OBJ_GET_STRING(settings, "password", baton->password);
  OBJ_GET_STRING(settings, "database", baton->database);
  OBJ_GET_NUMBER(settings, "port", baton->port, 1521);
  OBJ_GET_STRING(settings, "tns", baton->tns);

  client->Ref();

  uv_work_t* req = new uv_work_t();
  req->data = baton;
  uv_queue_work(uv_default_loop(), req, EIO_Connect, (uv_after_work_cb)EIO_AfterConnect);

  UNI_RETURN(scope, args, Undefined());
}

void OracleClient::EIO_Connect(uv_work_t* req) {
  ConnectBaton* baton = static_cast<ConnectBaton*>(req->data);

  baton->error = NULL;

  try {
    std::ostringstream connectionStr;
    if (baton->tns != "") {
      connectionStr << baton->tns;
    } else {
      connectionStr << "//" << baton->hostname << ":" << baton->port << "/" << baton->database;
    }
    baton->connection = baton->environment->createConnection(baton->user, baton->password, connectionStr.str());
  } catch(oracle::occi::SQLException &ex) {
    baton->error = new std::string(ex.getMessage());
  } catch (const std::exception& ex) {
    baton->error = new std::string(ex.what());
  }
}

void OracleClient::EIO_AfterConnect(uv_work_t* req, int status) {
  UNI_SCOPE(scope);
  ConnectBaton* baton = static_cast<ConnectBaton*>(req->data);
  baton->client->Unref();

  Handle<Value> argv[2];
  if(baton->error) {
    argv[0] = Exception::Error(String::New(baton->error->c_str()));
    argv[1] = Undefined();
  } else {
    argv[0] = Undefined();
    Handle<Object> connection = uni::Deref(Connection::constructorTemplate)->GetFunction()->NewInstance();
    (node::ObjectWrap::Unwrap<Connection>(connection))->setConnection(baton->client->m_environment, baton->connection);
    argv[1] = connection;
  }

  node::MakeCallback(Context::GetCurrent()->Global(), uni::Deref(baton->callback), 2, argv);

  delete baton;
  delete req;
}

uni::CallbackType OracleClient::ConnectSync(const uni::FunctionCallbackInfo& args) {
  UNI_SCOPE(scope);
  REQ_OBJECT_ARG(0, settings);

  OracleClient* client = ObjectWrap::Unwrap<OracleClient>(args.This());
  ConnectBaton baton(client, client->m_environment, NULL);

  OBJ_GET_STRING(settings, "hostname", baton.hostname);
  OBJ_GET_STRING(settings, "user", baton.user);
  OBJ_GET_STRING(settings, "password", baton.password);
  OBJ_GET_STRING(settings, "database", baton.database);
  OBJ_GET_NUMBER(settings, "port", baton.port, 1521);

  try {
    std::ostringstream connectionStr;
    connectionStr << "//" << baton.hostname << ":" << baton.port << "/" << baton.database;
    baton.connection = baton.environment->createConnection(baton.user, baton.password, connectionStr.str());
  } catch(oracle::occi::SQLException &ex) {
    baton.error = new std::string(ex.getMessage());
    UNI_THROW(Exception::Error(String::New(baton.error->c_str())));
  } catch (const std::exception& ex) {
    UNI_THROW(Exception::Error(String::New(ex.what())));
  }

  Handle<Object> connection = uni::Deref(Connection::constructorTemplate)->GetFunction()->NewInstance();
      (node::ObjectWrap::Unwrap<Connection>(connection))->setConnection(baton.client->m_environment, baton.connection);

  UNI_RETURN(scope, args, connection);

}

extern "C" {
  static void init(Handle<Object> target) {
    OracleClient::Init(target);
    Connection::Init(target);
    Statement::Init(target);
    Reader::Init(target);
    OutParam::Init(target);
  }

  NODE_MODULE(oracle_bindings, init);
}
<|endoftext|>


<commit_before>
#include "Utils.h"

#include <array>
#include <chrono>
#include <cstring>
#include <sstream>
#include <iomanip>
#include <cstdint>
#include <cctype>

namespace Utils
{
	void toLower(std::string &str, const std::locale &loc)
	{
		for (auto &c : str)
		{
			c = std::tolower(c, loc);
		}
	}

	void trim(std::string &str)
	{
		static const char whitespace[] = {" \t\n\v\f\r"};

		const size_t last = str.find_last_not_of(whitespace);

		if (std::string::npos == last)
		{
			return str.clear();
		}

		str.assign(str.cbegin() + str.find_first_not_of(whitespace), str.cbegin() + last + 1);
	}

	std::vector<std::string> explode(const std::string &str, const char sep)
	{
		std::vector<std::string> values;

		for (size_t pos = 0; std::string::npos != pos;)
		{
			size_t delimiter = str.find(sep, pos);

			std::string value = str.substr(pos, delimiter);
			trim(value);

			values.emplace_back(std::move(value) );

			pos = delimiter;

			if (std::string::npos != pos)
			{
				++pos;
			}
		}

		return values;
	}

	std::string encodeHtmlSymbols(const std::string &str)
	{
		std::string buf;
		buf.reserve(str.length() );

		for (size_t pos = 0; pos < str.length(); ++pos)
		{
			switch (str[pos])
			{
				case '&': buf.append("&"); break;
				case '\"': buf.append("""); break;
				case '\'': buf.append("'"); break;
				case '<': buf.append("<"); break;
				case '>': buf.append(">"); break;
				default: buf.push_back(str[pos]); break;
			}
		}

		return buf;
	}

	std::string binToHexString(const void *binData, const size_t dataSize)
	{
		std::string str(dataSize * 2, 0);

		const uint8_t *bin = reinterpret_cast<const uint8_t *>(binData);

		const char hexDigits[] = { "0123456789abcdef" };

		for (size_t i = dataSize - 1; std::numeric_limits<size_t>::max() != i; --i)
		{
			str[(i << 1) + 0] = hexDigits[bin[i] >> 4];
			str[(i << 1) + 1] = hexDigits[bin[i] & 0x0F];
		}

		return str;
	}

	static unsigned char hexStringToBinEncodeSymbol(const char c)
	{
		if (c >= '0' && c <= '9')
		{
			return c - 0x30;
		}
		else if (c >= 'a' && c <= 'f')
		{
			return c - 0x57;
		}
		else if (c >= 'A' && c <= 'F')
		{
			return c - 0x37;
		}

		return 0;
	}

	std::string hexStringToBin(const std::string &hexStr)
	{
		std::string bin(hexStr.length() / 2, 0);

		for (size_t i = 0; i < bin.length(); ++i)
		{
			const char a = hexStr[(i << 1) + 0];
			const char b = hexStr[(i << 1) + 1];

			bin[i] = (
				(hexStringToBinEncodeSymbol(a) << 4) | hexStringToBinEncodeSymbol(b)
			);
		}

		return bin;
	}

	unsigned long long htonll(const unsigned long long src)
	{
		enum Endianness {
			INIT = 0,
			LITE = 1,
			BIGE = 2
		};

		static int endian = Endianness::INIT;

		union {
			unsigned long long ull;
			unsigned char c[8];
		} x;

		if (endian == Endianness::INIT)
		{
			x.ull = 0x01;
			endian = (x.c[7] == 0x01ULL) ? Endianness::BIGE : Endianness::LITE;
		}

		if (endian == Endianness::BIGE)
		{
			return src;
		}

		x.ull = src;

		unsigned char c;

		c = x.c[0]; x.c[0] = x.c[7]; x.c[7] = c;
		c = x.c[1]; x.c[1] = x.c[6]; x.c[6] = c;
		c = x.c[2]; x.c[2] = x.c[5]; x.c[5] = c;
		c = x.c[3]; x.c[3] = x.c[4]; x.c[4] = c;

		return x.ull;
	}

	std::string getUniqueName()
	{
		size_t time = std::chrono::high_resolution_clock::now().time_since_epoch().count();

		time = htonll(time);

		return binToHexString(&time, sizeof(time) );
	}

	char *stlStringToPChar(const std::string &str)
	{
		const size_t length = str.length();
		char *s = nullptr;

		if (length)
		{
			s = new char[length + 1];
		#ifdef WIN32
			::strcpy_s(s, length + 1, str.c_str() );
		#elif POSIX
			::strcpy(s, str.c_str() );
			s[length] = '\0';
		#else
			#error "Undefine platform"
		#endif
		}

		return s;
	}

	void filesIncomingToRawFilesInfo(Utils::raw_fileinfo *raw[], const std::unordered_multimap<std::string, HttpServer::FileIncoming> &map)
	{
		if (raw && map.size() )
		{
			raw_fileinfo *arr = new raw_fileinfo[map.size()];

			*raw = arr;

			size_t i = 0;

			for (auto it = map.cbegin(); map.cend() != it; ++it, ++i)
			{
				arr[i].key = stlStringToPChar(it->first);

				const HttpServer::FileIncoming &file = it->second;

				arr[i].file_name = stlStringToPChar(file.getName() );
				arr[i].file_type = stlStringToPChar(file.getType() );
				arr[i].file_size = file.getSize();
			}
		}
	}

	void rawFilesInfoToFilesIncoming(std::unordered_multimap<std::string, HttpServer::FileIncoming> &map, const Utils::raw_fileinfo raw[], const size_t count)
	{
		for (size_t i = 0; i < count; ++i)
		{
			map.emplace(raw[i].key ? raw[i].key : "", HttpServer::FileIncoming(raw[i].file_name, raw[i].file_type, raw[i].file_size) );
		}
	}

	void destroyRawPairs(Utils::raw_pair raw[], const size_t count)
	{
		if (raw)
		{
			for (size_t i = 0; i < count; ++i)
			{
				raw_pair &cur = raw[i];

				delete[] cur.key;
				delete[] cur.value;
			}

			delete[] raw;
		}
	}

	void destroyRawFilesInfo(Utils::raw_fileinfo raw[], const size_t count)
	{
		if (raw)
		{
			for (size_t i = 0; i < count; ++i)
			{
				raw_fileinfo &cur = raw[i];

				delete[] cur.key;
				delete[] cur.file_name;
				delete[] cur.file_type;
			}

			delete[] raw;
		}
	}

	time_t stringTimeToTimestamp(const std::string &strTime)
	{
		static const std::unordered_map<std::string, int> map_months {
			{"Jan", 0}, {"Feb", 1}, {"Mar", 2}, {"Apr", 3}, {"May", 4}, {"Jun", 5}, {"Jul", 6}, {"Aug", 7}, {"Sep", 8}, {"Oct", 9}, {"Nov", 10}, {"Dec", 11}
		};

		if (strTime.length() > 64)
		{
			return ~0;
		}

		const size_t str_mon_length = 64;
		std::vector<char> s_mon(str_mon_length);

		struct ::tm tc = {};

		// Parse RFC 822
	#ifdef WIN32
		if (~0 != ::sscanf_s(strTime.c_str(), "%*s %d %3s %d %d:%d:%d", &tc.tm_mday, s_mon.data(), s_mon.size(), &tc.tm_year, &tc.tm_hour, &tc.tm_min, &tc.tm_sec) )
	#else
		if (~0 != ::sscanf(strTime.c_str(), "%*s %d %3s %d %d:%d:%d", &tc.tm_mday, s_mon.data(), &tc.tm_year, &tc.tm_hour, &tc.tm_min, &tc.tm_sec) )
	#endif
		{
			tc.tm_year -= 1900;

			auto it_mon = map_months.find(s_mon.data() );

            if (map_months.cend() != it_mon)
			{
				tc.tm_mon = it_mon->second;
			}
		}

        tc.tm_isdst = -1;

		return ::mktime(&tc);
	}

	std::string getDatetimeAsString(const ::time_t tTime, const bool isGmtTime)
	{
		std::array<char, 64> buf;

		::time_t cur_time = tTime;

		if (tTime == ~0)
		{
			::time(&cur_time);
		}

	#ifdef WIN32
		struct ::tm stm = {};

		isGmtTime ?
			::localtime_s(&stm, &cur_time) :
			::gmtime_s(&stm, &cur_time);

		// RFC 822
		::strftime(buf.data(), buf.size(), "%a, %d %b %Y %H:%M:%S GMT", &stm);
	#else
		struct ::tm *ptm = isGmtTime ?
			::localtime(&cur_time) :
			::gmtime(&cur_time);

		// RFC 822
		::strftime(buf.data(), buf.size(), "%a, %d %b %G %H:%M:%S GMT", ptm);
	#endif

		return std::string(buf.data() );
	}

	size_t getNumberLength(const size_t number)
	{
		size_t length = 0;

		size_t n = number;

		do
		{
			++length;
			n /= 10;
		}
		while (n);

		return length;
	}

	bool parseCookies(const std::string &cookieHeader, std::unordered_multimap<std::string, std::string> &cookies)
	{
		if (cookieHeader.empty() )
		{
			return true;
		}

		for (size_t cur_pos = 0, next_value; std::string::npos != cur_pos; cur_pos = next_value)
		{
			next_value = cookieHeader.find(';', cur_pos);

			size_t delimiter = cookieHeader.find('=', cur_pos);

			if (std::string::npos == delimiter || delimiter > next_value)
			{
				return false;
			}

			std::string key = cookieHeader.substr(cur_pos, delimiter - cur_pos);
			trim(key);
			key = urlDecode(key);

			++delimiter;

			std::string value = cookieHeader.substr(delimiter, std::string::npos != next_value ? next_value - delimiter : next_value);
			trim(value);
			value = urlDecode(value);

			cookies.emplace(std::move(key), std::move(value) );

			if (std::string::npos != next_value)
			{
				++next_value;
			}
		}

		return true;
	}

	inline bool isUrlAllowed(const char c)
	{
		static const std::string special("-_.~");

		return std::string::npos != special.find(c);
	}

	std::string urlEncode(const std::string &str)
	{
		std::ostringstream encoded;
		encoded.fill('0');
		encoded << std::hex;

		for (auto it = str.cbegin(); str.cend() != it; ++it)
		{
			const char &c = *it;

			if (' ' == c)
			{
				encoded << '+';
			}
			else if (std::isalnum(c) || isUrlAllowed(c) )
			{
				encoded << c;
			}
			else
			{
				encoded << '%' << std::setw(2) << (int) ( (unsigned char) c);
			}
		}

		return encoded.str();
	}

	std::string urlDecode(const std::string &str)
	{
		std::string decoded;

		// ch length must be >= 3
		std::array<char, sizeof(size_t)> ch;

		for (auto it = str.cbegin(); str.cend() != it; ++it)
		{
			const char &c = *it;

			if ('%' == c)
			{
				++it;

				if (str.cend() == it)
				{
					break;
				}

				ch[0] = *it;

				++it;

				if (str.cend() == it)
				{
					break;
				}

				ch[1] = *it;

				decoded.push_back(strtoul(ch.data(), nullptr, 16) );
			}
			else if ('+' == c)
			{
				decoded.push_back(' ');
			}
			else
			{
				decoded.push_back(c);
			}
		}

		return decoded;
	}
};<commit_msg>Fixed url encode/decode functions<commit_after>
#include "Utils.h"

#include <array>
#include <chrono>
#include <cstring>
#include <sstream>
#include <iomanip>
#include <cstdint>
#include <cctype>

namespace Utils
{
	void toLower(std::string &str, const std::locale &loc)
	{
		for (auto &c : str)
		{
			c = std::tolower(c, loc);
		}
	}

	void trim(std::string &str)
	{
		static const std::array<char, 7> whitespace { " \t\n\v\f\r" };

		const size_t last = str.find_last_not_of(whitespace.data() );

		if (std::string::npos == last)
		{
			return str.clear();
		}

		str.assign(str.cbegin() + str.find_first_not_of(whitespace.data() ), str.cbegin() + last + 1);
	}

	std::vector<std::string> explode(const std::string &str, const char sep)
	{
		std::vector<std::string> values;

		for (size_t pos = 0; std::string::npos != pos;)
		{
			size_t delimiter = str.find(sep, pos);

			std::string value = str.substr(pos, delimiter);
			trim(value);

			values.emplace_back(std::move(value) );

			pos = delimiter;

			if (std::string::npos != pos)
			{
				++pos;
			}
		}

		return values;
	}

	std::string encodeHtmlSymbols(const std::string &str)
	{
		std::string buf;
		buf.reserve(str.length() );

		for (size_t pos = 0; pos < str.length(); ++pos)
		{
			switch (str[pos])
			{
				case '&': buf.append("&"); break;
				case '\"': buf.append("""); break;
				case '\'': buf.append("'"); break;
				case '<': buf.append("<"); break;
				case '>': buf.append(">"); break;
				default: buf.push_back(str[pos]); break;
			}
		}

		return buf;
	}

	std::string binToHexString(const void *binData, const size_t dataSize)
	{
		std::string str(dataSize * 2, 0);

		const uint8_t *bin = reinterpret_cast<const uint8_t *>(binData);

		static const std::array<char, 17> hexDigits { "0123456789abcdef" };

		for (size_t i = dataSize - 1; std::numeric_limits<size_t>::max() != i; --i)
		{
			str[i * 2 + 0] = hexDigits[bin[i] >> 4];
			str[i * 2 + 1] = hexDigits[bin[i] & 0x0F];
		}

		return str;
	}

	static unsigned char hexStringToBinEncodeSymbol(const char c)
	{
		if (c >= '0' && c <= '9')
		{
			return c - 0x30;
		}
		else if (c >= 'a' && c <= 'f')
		{
			return c - 0x57;
		}
		else if (c >= 'A' && c <= 'F')
		{
			return c - 0x37;
		}

		return 0;
	}

	std::string hexStringToBin(const std::string &hexStr)
	{
		std::string bin(hexStr.length() / 2, 0);

		for (size_t i = 0; i < bin.length(); ++i)
		{
			const char a = hexStr[i * 2 + 0];
			const char b = hexStr[i * 2 + 1];

			bin[i] = (
				(hexStringToBinEncodeSymbol(a) << 4) | hexStringToBinEncodeSymbol(b)
			);
		}

		return bin;
	}

	unsigned long long htonll(const unsigned long long src)
	{
		enum Endianness {
			INIT = 0,
			LITE = 1,
			BIGE = 2
		};

		static int endian = Endianness::INIT;

		union {
			unsigned long long ull;
			unsigned char c[8];
		} x;

		if (endian == Endianness::INIT)
		{
			x.ull = 0x01;
			endian = (x.c[7] == 0x01ULL) ? Endianness::BIGE : Endianness::LITE;
		}

		if (endian == Endianness::BIGE)
		{
			return src;
		}

		x.ull = src;

		unsigned char c;

		c = x.c[0]; x.c[0] = x.c[7]; x.c[7] = c;
		c = x.c[1]; x.c[1] = x.c[6]; x.c[6] = c;
		c = x.c[2]; x.c[2] = x.c[5]; x.c[5] = c;
		c = x.c[3]; x.c[3] = x.c[4]; x.c[4] = c;

		return x.ull;
	}

	std::string getUniqueName()
	{
		size_t time = std::chrono::high_resolution_clock::now().time_since_epoch().count();

		time = htonll(time);

		return binToHexString(&time, sizeof(time) );
	}

	char *stlStringToPChar(const std::string &str)
	{
		const size_t length = str.length();
		char *s = nullptr;

		if (length)
		{
			s = new char[length + 1];
		#ifdef WIN32
			::strcpy_s(s, length + 1, str.c_str() );
		#elif POSIX
			::strcpy(s, str.c_str() );
			s[length] = '\0';
		#else
			#error "Undefine platform"
		#endif
		}

		return s;
	}

	void filesIncomingToRawFilesInfo(Utils::raw_fileinfo *raw[], const std::unordered_multimap<std::string, HttpServer::FileIncoming> &map)
	{
		if (raw && map.size() )
		{
			raw_fileinfo *arr = new raw_fileinfo[map.size()];

			*raw = arr;

			size_t i = 0;

			for (auto it = map.cbegin(); map.cend() != it; ++it, ++i)
			{
				arr[i].key = stlStringToPChar(it->first);

				const HttpServer::FileIncoming &file = it->second;

				arr[i].file_name = stlStringToPChar(file.getName() );
				arr[i].file_type = stlStringToPChar(file.getType() );
				arr[i].file_size = file.getSize();
			}
		}
	}

	void rawFilesInfoToFilesIncoming(std::unordered_multimap<std::string, HttpServer::FileIncoming> &map, const Utils::raw_fileinfo raw[], const size_t count)
	{
		for (size_t i = 0; i < count; ++i)
		{
			map.emplace(raw[i].key ? raw[i].key : "", HttpServer::FileIncoming(raw[i].file_name, raw[i].file_type, raw[i].file_size) );
		}
	}

	void destroyRawPairs(Utils::raw_pair raw[], const size_t count)
	{
		if (raw)
		{
			for (size_t i = 0; i < count; ++i)
			{
				raw_pair &cur = raw[i];

				delete[] cur.key;
				delete[] cur.value;
			}

			delete[] raw;
		}
	}

	void destroyRawFilesInfo(Utils::raw_fileinfo raw[], const size_t count)
	{
		if (raw)
		{
			for (size_t i = 0; i < count; ++i)
			{
				raw_fileinfo &cur = raw[i];

				delete[] cur.key;
				delete[] cur.file_name;
				delete[] cur.file_type;
			}

			delete[] raw;
		}
	}

	time_t stringTimeToTimestamp(const std::string &strTime)
	{
		static const std::unordered_map<std::string, int> map_months {
			{"Jan", 0}, {"Feb", 1}, {"Mar", 2}, {"Apr", 3}, {"May", 4}, {"Jun", 5}, {"Jul", 6}, {"Aug", 7}, {"Sep", 8}, {"Oct", 9}, {"Nov", 10}, {"Dec", 11}
		};

		if (strTime.length() > 64)
		{
			return ~0;
		}

		const size_t str_mon_length = 64;
		std::vector<char> s_mon(str_mon_length);

		struct ::tm tc = {};

		// Parse RFC 822
	#ifdef WIN32
		if (~0 != ::sscanf_s(strTime.c_str(), "%*s %d %3s %d %d:%d:%d", &tc.tm_mday, s_mon.data(), s_mon.size(), &tc.tm_year, &tc.tm_hour, &tc.tm_min, &tc.tm_sec) )
	#else
		if (~0 != ::sscanf(strTime.c_str(), "%*s %d %3s %d %d:%d:%d", &tc.tm_mday, s_mon.data(), &tc.tm_year, &tc.tm_hour, &tc.tm_min, &tc.tm_sec) )
	#endif
		{
			tc.tm_year -= 1900;

			auto it_mon = map_months.find(s_mon.data() );

            if (map_months.cend() != it_mon)
			{
				tc.tm_mon = it_mon->second;
			}
		}

        tc.tm_isdst = -1;

		return ::mktime(&tc);
	}

	std::string getDatetimeAsString(const ::time_t tTime, const bool isGmtTime)
	{
		std::array<char, 64> buf;

		::time_t cur_time = tTime;

		if (tTime == ~0)
		{
			::time(&cur_time);
		}

	#ifdef WIN32
		struct ::tm stm = {};

		isGmtTime ?
			::localtime_s(&stm, &cur_time) :
			::gmtime_s(&stm, &cur_time);

		// RFC 822
		::strftime(buf.data(), buf.size(), "%a, %d %b %Y %H:%M:%S GMT", &stm);
	#else
		struct ::tm *ptm = isGmtTime ?
			::localtime(&cur_time) :
			::gmtime(&cur_time);

		// RFC 822
		::strftime(buf.data(), buf.size(), "%a, %d %b %G %H:%M:%S GMT", ptm);
	#endif

		return std::string(buf.data() );
	}

	size_t getNumberLength(const size_t number)
	{
		size_t length = 0;

		size_t n = number;

		do
		{
			++length;
			n /= 10;
		}
		while (n);

		return length;
	}

	bool parseCookies(const std::string &cookieHeader, std::unordered_multimap<std::string, std::string> &cookies)
	{
		if (cookieHeader.empty() )
		{
			return true;
		}

		for (size_t cur_pos = 0, next_value; std::string::npos != cur_pos; cur_pos = next_value)
		{
			next_value = cookieHeader.find(';', cur_pos);

			size_t delimiter = cookieHeader.find('=', cur_pos);

			if (std::string::npos == delimiter || delimiter > next_value)
			{
				return false;
			}

			std::string key = cookieHeader.substr(cur_pos, delimiter - cur_pos);
			trim(key);
			key = urlDecode(key);

			++delimiter;

			std::string value = cookieHeader.substr(delimiter, std::string::npos != next_value ? next_value - delimiter : next_value);
			trim(value);
			value = urlDecode(value);

			cookies.emplace(std::move(key), std::move(value) );

			if (std::string::npos != next_value)
			{
				++next_value;
			}
		}

		return true;
	}

	static inline bool isCharUrlAllowed(const char c)
	{
		return c == '-' || c == '_' || c == '.' || c == '~';
	}

	std::string urlEncode(const std::string &str)
	{
		std::string encoded;

		static const std::array<char, 17> hexDigits { "0123456789abcdef" };

		for (size_t i = 0; i < str.length(); ++i)
		{
			const unsigned char c = str[i];

			if (std::isalnum(c) || isCharUrlAllowed(c) )
			{
				encoded.push_back(c);
			}
			else if (' ' == c)
			{
				encoded.push_back('+');
			}
			else
			{
				const uint8_t a = c >> 4;
				const uint8_t b = c & 0x0F;

				encoded.push_back('%');
				encoded.push_back(hexDigits[a]);
				encoded.push_back(hexDigits[b]);
			}
		}

		return encoded;
	}

	std::string urlDecode(const std::string &str)
	{
		std::string decoded;

		for (size_t i = 0; i < str.length(); ++i)
		{
			unsigned char c = str[i];

			if ('%' == c)
			{
				if (i + 2 < str.length() )
				{
					const char a = str[i + 1];
					const char b = str[i + 2];

					c = (
						(hexStringToBinEncodeSymbol(a) << 4) | hexStringToBinEncodeSymbol(b)
					);

					i += 2;
				}
			}
			else if ('+' == c)
			{
				c = ' ';
			}

			decoded.push_back(c);
		}

		return decoded;
	}
};<|endoftext|>