From 85ce939590e9f60d51952b4cc1e6af6f9820ca28 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Nusser?= <andre.nusser@googlemail.com>
Date: Sat, 26 Oct 2019 19:11:03 +0200
Subject: Add default midimap functionality.

Move directory.{h,cc} to src/ for this.
---
 src/DGDOM.h          |   1 +
 src/Makefile.am      |   2 +
 src/dgxmlparser.cc   |   5 +
 src/directory.cc     | 567 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/directory.h      |  88 ++++++++
 src/drumkitloader.cc |   7 +
 6 files changed, 670 insertions(+)
 create mode 100644 src/directory.cc
 create mode 100644 src/directory.h

(limited to 'src')

diff --git a/src/DGDOM.h b/src/DGDOM.h
index b6c52ac..474b29c 100644
--- a/src/DGDOM.h
+++ b/src/DGDOM.h
@@ -131,6 +131,7 @@ struct MetadataDOM
 	std::string image;
 	std::string image_map;
 	std::vector<ClickMapDOM> clickmaps;
+	std::string default_midimap_file;
 };
 
 struct DrumkitDOM
diff --git a/src/Makefile.am b/src/Makefile.am
index 56d44ef..93ef5ed 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -22,6 +22,7 @@ nodist_libdg_la_SOURCES = \
 	channelmixer.cc \
 	configfile.cc \
 	configparser.cc \
+	directory.cc \
 	domloader.cc \
 	dgxmlparser.cc \
 	drumgizmo.cc \
@@ -63,6 +64,7 @@ EXTRA_DIST = \
 	channelmixer.h \
 	configfile.h \
 	configparser.h \
+	directory.h \
 	cpp11fix.h \
 	dgxmlparser.h \
 	domloader.h \
diff --git a/src/dgxmlparser.cc b/src/dgxmlparser.cc
index b924cc8..0d3cdcd 100644
--- a/src/dgxmlparser.cc
+++ b/src/dgxmlparser.cc
@@ -245,6 +245,11 @@ bool parseDrumkitFile(const std::string& filename, DrumkitDOM& dom, LogFunction
 				               clickmap, "colour", logger, filename, true);
 			}
 		}
+		pugi::xml_node default_midimap = metadata.child("defaultmidimap");
+		if(default_midimap != pugi::xml_node())
+		{
+			res &= attrcpy(meta.default_midimap_file, default_midimap, "src", logger, filename, true);
+		}
 	}
 
 	pugi::xml_node channels = doc.child("drumkit").child("channels");
diff --git a/src/directory.cc b/src/directory.cc
new file mode 100644
index 0000000..596b045
--- /dev/null
+++ b/src/directory.cc
@@ -0,0 +1,567 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ *            directory.cc
+ *
+ *  Tue Apr 23 22:01:07 CEST 2013
+ *  Copyright 2013 Jonas Suhr Christensen
+ *  jsc@umbraculum.org
+ ****************************************************************************/
+
+/*
+ *  This file is part of DrumGizmo.
+ *
+ *  DrumGizmo is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  DrumGizmo 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with DrumGizmo; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+ */
+#include "directory.h"
+
+#include <dirent.h>
+#include <stdio.h>
+#include <string>
+#include <algorithm>
+#include <vector>
+#include <string.h>
+#include <unistd.h>
+
+#include <platform.h>
+
+#if DG_PLATFORM == DG_PLATFORM_WINDOWS
+#include <direct.h>
+#include <windows.h>
+#endif
+
+#include <hugin.hpp>
+
+#define DRUMKIT_SUFFIX ".xml"
+
+// http://en.wikipedia.org/wiki/Path_(computing)
+#if DG_PLATFORM == DG_PLATFORM_WINDOWS
+#define SEP "\\"
+#else
+#define SEP "/"
+#endif
+
+Directory::Directory(std::string path)
+{
+	setPath(path);
+}
+
+Directory::~Directory()
+{
+}
+
+std::string Directory::seperator()
+{
+	return SEP;
+}
+
+void Directory::setPath(std::string path)
+{
+	//DEBUG(directory, "Setting path to '%s'\n", path.c_str());
+	this->_path = cleanPath(path);
+	refresh();
+}
+
+size_t Directory::count()
+{
+	return _files.size();
+}
+
+void Directory::refresh()
+{
+	_files = listFiles(_path, DIRECTORY_HIDDEN);
+	//_files = listFiles(_path);
+}
+
+bool Directory::cd(std::string dir)
+{
+	//TODO: Should this return true or false?
+	if(dir.empty() || dir == ".")
+	{
+		return true;
+	}
+
+	//DEBUG(directory, "Changing to '%s'\n", dir.c_str());
+	if(exists(_path + SEP + dir))
+	{
+		std::string path = _path + SEP + dir;
+		setPath(path);
+		refresh();
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+bool Directory::cdUp()
+{
+	return this->cd("..");
+}
+
+std::string Directory::path()
+{
+	return cleanPath(_path);
+}
+
+Directory::EntryList Directory::entryList()
+{
+	return _files;
+}
+
+#define MAX_FILE_LENGTH 1024
+std::string Directory::cwd()
+{
+	char path[MAX_FILE_LENGTH];
+	char* c = getcwd(path, MAX_FILE_LENGTH);
+
+	if(c)
+	{
+		return c;
+	}
+	else
+	{
+		return "";
+	}
+}
+
+std::string Directory::cleanPath(std::string path)
+{
+	//DEBUG(directory, "Cleaning path '%s'\n", path.c_str());
+	Directory::Path pathlst = parsePath(path);
+	return Directory::pathToStr(pathlst);
+}
+
+Directory::EntryList Directory::listFiles(std::string path, unsigned char filter)
+{
+	DEBUG(directory, "Listing files in '%s'\n", path.c_str());
+
+	Directory::EntryList entries;
+	DIR *dir = opendir(path.c_str());
+	if(!dir)
+	{
+		//DEBUG(directory, "Couldn't open directory '%s\n", path.c_str());
+		return entries;
+	}
+
+	std::vector<std::string> directories;
+	std::vector<std::string> files;
+
+	struct dirent *entry;
+	while((entry = readdir(dir)) != nullptr)
+	{
+		std::string name = entry->d_name;
+		if(name == ".")
+		{
+			continue;
+		}
+
+		if(Directory::isRoot(path) && name == "..")
+		{
+			continue;
+		}
+
+		unsigned char entryinfo = 0;
+		if(isHidden(path + SEP + name))
+		{
+			entryinfo |= DIRECTORY_HIDDEN;
+		}
+
+		std::string entrypath = path;
+		entrypath += SEP;
+		entrypath += entry->d_name;
+		if(Directory::isDir(entrypath))
+		{
+			if(!(entryinfo && filter))
+			{
+				if(name == "..")
+				{
+					directories.push_back(entry->d_name);
+				}
+				else
+				{
+					directories.push_back(std::string(SEP) + entry->d_name);
+				}
+			}
+		}
+		else
+		{
+			int drumkit_suffix_length = strlen(DRUMKIT_SUFFIX);
+			if((int)name.size() < drumkit_suffix_length)
+			{
+				continue;
+			}
+
+			if(name.substr(name.length() - drumkit_suffix_length,
+			               drumkit_suffix_length) != DRUMKIT_SUFFIX)
+			{
+				continue;
+			}
+
+
+			//if(!(entryinfo && filter)) {
+			files.push_back(entry->d_name);
+			//}
+		}
+	}
+
+#if DG_PLATFORM == DG_PLATFORM_WINDOWS
+	//DEBUG(directory, "Root is %s\n", Directory::root(path).c_str());
+	//DEBUG(directory, "Current path %s is root? %d", path.c_str(),
+	//      Directory::isRoot(path));
+	if(Directory::isRoot(path))
+	{
+		entries.push_back("..");
+	}
+#endif
+
+	// sort
+	for(int x = 0; x < (int)directories.size(); x++)
+	{
+		for(int y = 0; y < (int)directories.size(); y++)
+		{
+			if(directories[x] < directories[y])
+			{
+				std::string tmp = directories[x];
+				directories[x] = directories[y];
+				directories[y] = tmp;
+			}
+		}
+	}
+
+	for(int x = 0; x < (int)files.size(); x++)
+	{
+		for(int y = 0; y < (int)files.size(); y++)
+		{
+			if(files[x] < files[y])
+			{
+				std::string tmp = files[x];
+				files[x] = files[y];
+				files[y] = tmp;
+			}
+		}
+	}
+
+
+	for(auto directory : directories)
+	{
+		entries.push_back(directory);
+	}
+
+	for(auto file : files)
+	{
+		entries.push_back(file);
+	}
+
+	closedir(dir);
+	return entries;
+}
+
+bool Directory::isRoot(std::string path)
+{
+#if DG_PLATFORM == DG_PLATFORM_WINDOWS
+	std::transform(path.begin(), path.end(), path.begin(), ::tolower);
+	std::string root_str = Directory::root(path);
+	std::transform(root_str.begin(), root_str.end(), root_str.begin(), ::tolower);
+
+	// TODO: This is not a correct root calculation, but works with partitions
+	if(path.size() == 2)
+	{
+		if(path == root_str)
+		{
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+	else
+	{
+		if (path.size() == 3)
+		{
+			if(path == root_str + SEP)
+			{
+				return true;
+			}
+			return false;
+		}
+		else
+		{
+			return false;
+		}
+	}
+#else
+	if(path == SEP)
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+#endif
+}
+
+std::string Directory::root()
+{
+	return root(cwd());
+}
+
+std::string Directory::root(std::string path)
+{
+#if DG_PLATFORM == DG_PLATFORM_WINDOWS
+	if(path.size() < 2)
+	{
+		return "c:"; // just something default when input is bad
+	}
+	else
+	{
+		return path.substr(0, 2);
+	}
+#else
+	return SEP;
+#endif
+}
+
+Directory::DriveList Directory::drives()
+{
+	Directory::DriveList drives;
+#if DG_PLATFORM == DG_PLATFORM_WINDOWS
+	unsigned int d = GetLogicalDrives();
+	for(int i = 0; i < 32; ++i)
+	{
+		if(d & (1 << i))
+		{
+			drive_t drive;
+			char name[] = "x:";
+			name[0] = i + 'a';
+
+			drive.name = name;
+			drive.number = i;
+			drives.push_back(drive);
+		}
+	}
+#endif
+	return drives;
+}
+
+bool Directory::isDir()
+{
+	return isDir(_path);
+}
+
+bool Directory::isDir(std::string path)
+{
+	//DEBUG(directory, "Is '%s' a directory?\n", path.c_str());
+	struct stat st;
+	if(stat(path.c_str(), &st) == 0)
+	{
+		if((st.st_mode & S_IFDIR) != 0)
+		{
+			//DEBUG(directory, "\t...yes!\n");
+			return true;
+		}
+	}
+	//DEBUG(directory, "\t...no!\n");
+	return false;
+}
+
+bool Directory::fileExists(std::string filename)
+{
+	return !isDir(_path + SEP + filename);
+}
+
+bool Directory::exists(std::string path)
+{
+	struct stat st;
+	if(stat(path.c_str(), &st) == 0)
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+bool Directory::isHidden(std::string path)
+{
+	//DEBUG(directory, "Is '%s' hidden?\n", path.c_str());
+#if DG_PLATFORM == DG_PLATFORM_WINDOWS
+	// We dont want to filter out '..' pointing to root of a partition
+	unsigned pos = path.find_last_of("/\\");
+	std::string entry = path.substr(pos+1);
+	if(entry == "..")
+	{
+		return false;
+	}
+
+	DWORD fattribs = GetFileAttributes(path.c_str());
+	if(fattribs & FILE_ATTRIBUTE_HIDDEN)
+	{
+		//DEBUG(directory, "\t...yes!\n");
+		return true;
+	}
+	else
+	{
+		if(fattribs & FILE_ATTRIBUTE_SYSTEM)
+		{
+			//DEBUG(directory, "\t...yes!\n");
+			return true;
+		}
+		else
+		{
+			//DEBUG(directory, "\t...no!\n");
+			return false;
+		}
+	}
+#else
+	unsigned pos = path.find_last_of("/\\");
+	std::string entry = path.substr(pos+1);
+	if(entry.size() > 1 &&
+	   entry.at(0) == '.' &&
+	   entry.at(1) != '.')
+	{
+		//DEBUG(directory, "\t...yes!\n");
+		return true;
+	}
+	else
+	{
+		//DEBUG(directory, "\t...no!\n");
+		return false;
+	}
+#endif
+}
+
+Directory::Path Directory::parsePath(std::string path_str)
+{
+	//TODO: Handle "." input and propably other special cases
+
+	//DEBUG(directory, "Parsing path '%s'", path_str.c_str());
+	Directory::Path path;
+
+	std::string current_char;
+	std::string prev_char;
+	std::string dir;
+	for(size_t c = 0; c < path_str.size(); ++c)
+	{
+		current_char = path_str.at(c);
+
+		if(current_char == SEP)
+		{
+			if(prev_char == SEP)
+			{
+				dir.clear();
+				prev_char = current_char;
+				continue;
+			}
+			else
+			{
+				if(prev_char == ".")
+				{
+					prev_char = current_char;
+					continue;
+				}
+			}
+			if(!dir.empty())
+			{
+				path.push_back(dir);
+			}
+			dir.clear();
+			continue;
+		}
+		else
+		{
+			if(current_char == ".")
+			{
+				if(prev_char == ".")
+				{
+					dir.clear();
+					if(!path.empty())
+					{
+						path.pop_back();
+					}
+					continue;
+				}
+			}
+		}
+		dir += current_char;
+		prev_char = current_char;
+	}
+
+	if(!dir.empty())
+	{
+		path.push_back(dir);
+	}
+
+	return path;
+}
+
+std::string Directory::pathToStr(Directory::Path& path)
+{
+	std::string cleaned_path;
+	//DEBUG(directory, "Number of directories in path is %d\n", (int)path.size());
+
+	for(auto it = path.begin(); it != path.end(); ++it)
+	{
+		std::string dir = *it;
+		//DEBUG(directory, "\tDir '%s'\n", dir.c_str());
+#if DG_PLATFORM == DG_PLATFORM_WINDOWS
+		if(it != path.begin())
+		{
+			cleaned_path += SEP;
+		}
+		cleaned_path += dir;
+#else
+		cleaned_path += SEP + dir;
+#endif
+	}
+
+	//DEBUG(directory, "Cleaned path '%s'\n", cleaned_path.c_str());
+
+	if(cleaned_path.empty())
+	{
+		cleaned_path = Directory::root();
+#if DG_PLATFORM == DG_PLATFORM_WINDOWS
+		cleaned_path += SEP;
+#endif
+	}
+
+#if DG_PLATFORM == DG_PLATFORM_WINDOWS
+	if(cleaned_path.size() == 2)
+	{
+		cleaned_path += SEP;
+	}
+#endif
+
+	return cleaned_path;
+}
+
+std::string Directory::pathDirectory(std::string filepath)
+{
+	if(Directory::isDir(filepath))
+	{
+		return filepath;
+	}
+
+	Directory::Path path = parsePath(filepath);
+	if(path.size() > 0)
+	{
+		path.pop_back();
+	}
+
+	return Directory::pathToStr(path);
+}
diff --git a/src/directory.h b/src/directory.h
new file mode 100644
index 0000000..e46c5b9
--- /dev/null
+++ b/src/directory.h
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/***************************************************************************
+ *            directory.h
+ *
+ *  Tue Apr 23 22:01:07 CEST 2013
+ *  Copyright 2013 Jonas Suhr Christensen
+ *  jsc@umbraculum.org
+ ****************************************************************************/
+
+/*
+ *  This file is part of DrumGizmo.
+ *
+ *  DrumGizmo is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  DrumGizmo 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with DrumGizmo; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+ */
+#pragma once
+
+#include <string>
+#include <list>
+
+#include <libgen.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define DIRECTORY_HIDDEN 1
+
+class Directory {
+public:
+	typedef struct drive {
+		int number;
+		std::string name;
+	} drive_t;
+
+	typedef std::list<std::string> EntryList;
+	typedef std::list<drive> DriveList;
+
+	Directory(std::string path);
+	~Directory();
+
+	std::string seperator();
+
+	size_t count();
+	void refresh();
+	std::string path();
+	bool cdUp();
+	bool cd(std::string dir);
+	bool isDir();
+	void setPath(std::string path);
+	bool fileExists(std::string file);
+
+	// Add filter, ie. directories or files only
+	EntryList entryList();
+
+	//void setSorting();
+
+	static std::string cwd();
+	static std::string root();
+	static std::string root(std::string path);
+	static std::string cleanPath(std::string path);
+	static Directory::EntryList listFiles(std::string path, unsigned char filter = 0);
+	static bool isRoot(std::string path);
+	static Directory::DriveList drives();
+	static bool isDir(std::string path);
+	static bool isHidden(std::string entry);
+	static bool exists(std::string path);
+	static std::string pathDirectory(std::string filepath);
+
+private:
+	std::string _path;
+	EntryList _files;
+	DriveList _drives;
+
+	typedef std::list<std::string> Path;
+	static Path parsePath(std::string path);
+	static std::string pathToStr(Path &path);
+};
diff --git a/src/drumkitloader.cc b/src/drumkitloader.cc
index 91e3dd8..6a4c9f4 100644
--- a/src/drumkitloader.cc
+++ b/src/drumkitloader.cc
@@ -36,6 +36,7 @@
 #include "dgxmlparser.h"
 #include "path.h"
 #include "domloader.h"
+#include "directory.h"
 
 #define REFSFILE "refs.conf"
 
@@ -218,6 +219,12 @@ bool DrumKitLoader::loadkit(const std::string& file)
 	settings.drumkit_description = kit.getDescription();
 	settings.drumkit_version = kit.getVersion();
 	settings.drumkit_samplerate = kit.getSamplerate();
+	// only load the default midi map if there is one and no midimap is selected yet
+	if (drumkitdom.metadata.default_midimap_file != "" && settings.midimap_file == "")
+	{
+		const std::string drumkit_path = Directory::pathDirectory(settings.drumkit_file);
+		settings.midimap_file = drumkit_path + "/" + drumkitdom.metadata.default_midimap_file;
+	}
 
 	loadKitAudio(kit);
 
-- 
cgit v1.2.3