
#include "Core.h"
#include <QByteArray>
#include <QFileInfo>
#include <QFile>
#include <QAction>
#include "MD5.h"

//------------------------------------------------------------------------------
// Name: getFileMD5(const QString &s)
// Desc: returns a byte array representing the MD5 of a file
//------------------------------------------------------------------------------
QByteArray edb::core::getFileMD5(const QString &s) {

	QFile libFile(s);
	libFile.open(QIODevice::ReadOnly);
	if(libFile.isOpen()) {
		const QByteArray libBytes = libFile.readAll();

		MD5 md5;
		md5.update(libBytes.data(), libBytes.size());
		md5.finalize();

		// make a deep copy because MD5 is about to go out of scope
		return QByteArray(reinterpret_cast<const char *>(md5.digest()), 16);
	}

	return QByteArray();
}


//------------------------------------------------------------------------------
// Name: basename(const QString &s)
// Desc: 
//------------------------------------------------------------------------------
QString edb::core::basename(const QString &s) {
	
	const QFileInfo fileInfo(s);
	QString ret = fileInfo.baseName();

	if(!fileInfo.completeSuffix().isEmpty()) {
		ret += '.';
		ret += fileInfo.completeSuffix();
	}
	
	return ret;
}

//------------------------------------------------------------------------------
// Name: symlinkTarget(const QString &s)
// Desc: 
//------------------------------------------------------------------------------
QString edb::core::symlinkTarget(const QString &s) {
	return QFileInfo(s).symLinkTarget();
}

//------------------------------------------------------------------------------
// Name: intVersion()
// Desc: returns an integer comparable version of a version string in x.y.z 
//       format, or 0 if error
//------------------------------------------------------------------------------
ulong edb::core::intVersion(const QString &s) {

	ulong ret = 0;
	const QStringList list = s.split(".");
	if(list.size() == 3) {
		bool ok[3];
		const unsigned int maj = list[0].toUInt(&ok[0]);
		const unsigned int min = list[1].toUInt(&ok[1]);
		const unsigned int rev = list[2].toUInt(&ok[2]);
		if(ok[0] && ok[1] && ok[2]) {
			ret = (maj << 12) | (min << 8) | (rev);
		}
	}
	return ret;
}

//------------------------------------------------------------------------------
// Name: parseCommandLine(const QString &cmdline)
// Desc: 
//------------------------------------------------------------------------------
QStringList edb::core::parseCommandLine(const QString &cmdline) {
	
	QStringList args;
	QString arg;

	int bcount = 0;
	bool in_quotes = false;

	QString::const_iterator s = cmdline.begin();

	while(s != cmdline.end()) {
		if(!in_quotes && s->isSpace()) {

			// Close the argument and copy it
			args << arg;
			arg.clear();

			// skip the remaining spaces
			do {
				++s;
			} while(s->isSpace());

			// Start with a new argument
			bcount = 0;
		} else if(*s == '\\') {

			// '\\'
			arg += *s++;
			++bcount;

		} else if (*s == '"') {

			// '"'
			if ((bcount & 1) == 0) {
				/* Preceded by an even number of '\', this is half that
				 * number of '\', plus a quote which we erase.
				 */

				arg.chop(bcount / 2);
				in_quotes = !in_quotes;
			} else {
				/* Preceded by an odd number of '\', this is half that
				 * number of '\' followed by a '"'
				 */

				arg.chop(bcount / 2 + 1);
				arg += '"';
			}
			
			++s;
			bcount = 0;
		} else {
			arg += *s++;
			bcount = 0;
		}
	}

	if(!arg.isEmpty()) {
		args << arg;
	}

	return args;
}

//------------------------------------------------------------------------------
// Name: stringToAddress(const QString &s, bool &ok)
// Desc: 
//------------------------------------------------------------------------------
edb::address_t edb::core::stringToAddress(const QString &s, bool &ok) {
#if defined(EDB_X86)
	return s.left(8).toULongLong(&ok, 16);
#elif defined(EDB_X86_64)
	return s.left(16).toULongLong(&ok, 16);
#endif
}
