From ef93cdf4a8b654342e97e6ab707caaf42cb9c64d Mon Sep 17 00:00:00 2001
From: Denis Krjuchkov <denis@crazydev.net>
Date: Tue, 22 Jan 2013 00:14:37 +0600
Subject: Path: move to fs subdirectory

---
 Makefile.am                     |   4 +-
 src/ConfigFile.cxx              |   2 +-
 src/DatabaseSave.cxx            |   2 +-
 src/DecoderThread.cxx           |   2 +-
 src/ExcludeList.cxx             |   2 +-
 src/InotifyUpdate.cxx           |   2 +-
 src/Main.cxx                    |   2 +-
 src/Mapper.cxx                  |   2 +-
 src/Path.cxx                    | 131 --------------------
 src/Path.hxx                    | 264 ----------------------------------------
 src/PlaylistFile.cxx            |   2 +-
 src/PlaylistMapper.cxx          |   2 +-
 src/PlaylistSave.cxx            |   2 +-
 src/PlaylistSong.cxx            |   2 +-
 src/SongUpdate.cxx              |   2 +-
 src/StateFile.hxx               |   2 +-
 src/TextFile.hxx                |   2 +-
 src/UpdateArchive.cxx           |   2 +-
 src/UpdateContainer.cxx         |   2 +-
 src/UpdateIO.cxx                |   2 +-
 src/UpdateWalk.cxx              |   2 +-
 src/db/SimpleDatabasePlugin.hxx |   2 +-
 src/fs/Path.cxx                 | 131 ++++++++++++++++++++
 src/fs/Path.hxx                 | 264 ++++++++++++++++++++++++++++++++++++++++
 24 files changed, 416 insertions(+), 416 deletions(-)
 delete mode 100644 src/Path.cxx
 delete mode 100644 src/Path.hxx
 create mode 100644 src/fs/Path.cxx
 create mode 100644 src/fs/Path.hxx

diff --git a/Makefile.am b/Makefile.am
index 26b678526..adcc21e15 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -151,6 +151,7 @@ src_mpd_SOURCES = \
 	src/thread/PosixCond.hxx \
 	src/thread/WindowsCond.hxx \
 	src/thread/GLibCond.hxx \
+	src/fs/Path.cxx src/fs/Path.hxx \
 	src/fs/FileSystem.cxx src/fs/FileSystem.hxx \
 	src/fs/DirectoryReader.hxx \
 	src/glib_socket.h \
@@ -239,7 +240,6 @@ src_mpd_SOURCES = \
 	src/MusicBuffer.cxx src/MusicBuffer.hxx \
 	src/MusicPipe.cxx src/MusicPipe.hxx \
 	src/MusicChunk.cxx src/MusicChunk.hxx \
-	src/Path.cxx src/Path.hxx \
 	src/Mapper.cxx src/Mapper.hxx \
 	src/page.c \
 	src/Partition.hxx \
@@ -1060,7 +1060,7 @@ test_DumpDatabase_SOURCES = test/DumpDatabase.cxx \
 	src/DatabaseLock.cxx src/DatabaseSave.cxx \
 	src/Song.cxx src/song_sort.c src/SongSave.cxx \
 	src/Tag.cxx src/TagNames.c src/TagPool.cxx src/TagSave.cxx \
-	src/Path.cxx \
+	src/fs/Path.cxx \
 	src/SongFilter.cxx \
 	src/TextFile.cxx \
 	src/ConfigFile.cxx src/tokenizer.c src/utils.c src/string_util.c
diff --git a/src/ConfigFile.cxx b/src/ConfigFile.cxx
index ce71b21d2..614bb4f91 100644
--- a/src/ConfigFile.cxx
+++ b/src/ConfigFile.cxx
@@ -26,7 +26,7 @@ extern "C" {
 #include "tokenizer.h"
 }
 
-#include "Path.hxx"
+#include "fs/Path.hxx"
 #include "mpd_error.h"
 
 #include <glib.h>
diff --git a/src/DatabaseSave.cxx b/src/DatabaseSave.cxx
index 029189ae5..2c46f4a5b 100644
--- a/src/DatabaseSave.cxx
+++ b/src/DatabaseSave.cxx
@@ -26,7 +26,7 @@
 #include "TextFile.hxx"
 #include "TagInternal.hxx"
 #include "tag.h"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 
 #include <glib.h>
 
diff --git a/src/DecoderThread.cxx b/src/DecoderThread.cxx
index 4c493304b..b821c6d7a 100644
--- a/src/DecoderThread.cxx
+++ b/src/DecoderThread.cxx
@@ -26,7 +26,7 @@
 #include "song.h"
 #include "mpd_error.h"
 #include "Mapper.hxx"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 #include "decoder_api.h"
 #include "tag.h"
 #include "input_stream.h"
diff --git a/src/ExcludeList.cxx b/src/ExcludeList.cxx
index 3f929b93c..69a04d5a8 100644
--- a/src/ExcludeList.cxx
+++ b/src/ExcludeList.cxx
@@ -24,7 +24,7 @@
 
 #include "config.h"
 #include "ExcludeList.hxx"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 
 #include <assert.h>
 #include <string.h>
diff --git a/src/InotifyUpdate.cxx b/src/InotifyUpdate.cxx
index a1c3e0393..bd018f5a3 100644
--- a/src/InotifyUpdate.cxx
+++ b/src/InotifyUpdate.cxx
@@ -23,7 +23,7 @@
 #include "InotifyQueue.hxx"
 #include "Mapper.hxx"
 #include "Main.hxx"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 
 #include <glib.h>
 #include <assert.h>
diff --git a/src/Main.cxx b/src/Main.cxx
index 6d4fc82d2..44adf2e28 100644
--- a/src/Main.cxx
+++ b/src/Main.cxx
@@ -47,7 +47,7 @@
 #include "InputInit.hxx"
 #include "event/Loop.hxx"
 #include "IOThread.hxx"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 
 extern "C" {
 #include "daemon.h"
diff --git a/src/Mapper.cxx b/src/Mapper.cxx
index 09fa190f3..5a28874de 100644
--- a/src/Mapper.cxx
+++ b/src/Mapper.cxx
@@ -25,7 +25,7 @@
 #include "Mapper.hxx"
 #include "Directory.hxx"
 #include "song.h"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 
 #include <glib.h>
 
diff --git a/src/Path.cxx b/src/Path.cxx
deleted file mode 100644
index ab8a4e3cc..000000000
--- a/src/Path.cxx
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-#include "Path.hxx"
-#include "conf.h"
-#include "mpd_error.h"
-#include "gcc.h"
-
-#include <glib.h>
-
-#include <assert.h>
-#include <string.h>
-
-#ifdef G_OS_WIN32
-#include <windows.h> // for GetACP()
-#include <stdio.h> // for sprintf()
-#endif
-
-#undef G_LOG_DOMAIN
-#define G_LOG_DOMAIN "path"
-
-static char *fs_charset;
-
-char *
-fs_charset_to_utf8(const char *path_fs)
-{
-	return g_convert(path_fs, -1,
-			 "utf-8", fs_charset,
-			 NULL, NULL, NULL);
-}
-
-char *
-utf8_to_fs_charset(const char *path_utf8)
-{
-	gchar *p;
-
-	p = g_convert(path_utf8, -1,
-		      fs_charset, "utf-8",
-		      NULL, NULL, NULL);
-	if (p == NULL)
-		/* fall back to UTF-8 */
-		p = g_strdup(path_utf8);
-
-	return p;
-}
-
-gcc_pure
-static bool
-IsSupportedCharset(const char *charset)
-{
-	/* convert a space to check if the charset is valid */
-	char *test = g_convert(" ", 1, charset, "UTF-8", NULL, NULL, NULL);
-	if (test == NULL)
-		return false;
-
-	g_free(test);
-	return true;
-}
-
-static void
-path_set_fs_charset(const char *charset)
-{
-	assert(charset != NULL);
-
-	if (!IsSupportedCharset(charset))
-		MPD_ERROR("invalid filesystem charset: %s", charset);
-
-	g_free(fs_charset);
-	fs_charset = g_strdup(charset);
-
-	g_debug("path_set_fs_charset: fs charset is: %s", fs_charset);
-}
-
-const char *path_get_fs_charset(void)
-{
-	return fs_charset;
-}
-
-void path_global_init(void)
-{
-	const char *charset = NULL;
-
-	charset = config_get_string(CONF_FS_CHARSET, NULL);
-	if (charset == NULL) {
-#ifndef G_OS_WIN32
-		const gchar **encodings;
-		g_get_filename_charsets(&encodings);
-
-		if (encodings[0] != NULL && *encodings[0] != '\0')
-			charset = encodings[0];
-#else /* G_OS_WIN32 */
-		/* Glib claims that file system encoding is always utf-8
-		 * on native Win32 (i.e. not Cygwin).
-		 * However this is true only if <gstdio.h> helpers are used.
-		 * MPD uses regular <stdio.h> functions.
-		 * Those functions use encoding determined by GetACP(). */
-		static char win_charset[13];
-		sprintf(win_charset, "cp%u", GetACP());
-		charset = win_charset;
-#endif
-	}
-
-	if (charset) {
-		path_set_fs_charset(charset);
-	} else {
-		g_message("setting filesystem charset to ISO-8859-1");
-		path_set_fs_charset("ISO-8859-1");
-	}
-}
-
-void path_global_finish(void)
-{
-	g_free(fs_charset);
-}
diff --git a/src/Path.hxx b/src/Path.hxx
deleted file mode 100644
index 5c76e4b87..000000000
--- a/src/Path.hxx
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef MPD_PATH_HXX
-#define MPD_PATH_HXX
-
-#include "check.h"
-#include "gcc.h"
-
-#include <glib.h>
-
-#include <algorithm>
-
-#include <assert.h>
-#include <string.h>
-#include <limits.h>
-
-#if !defined(MPD_PATH_MAX)
-#  if defined(MAXPATHLEN)
-#    define MPD_PATH_MAX MAXPATHLEN
-#  elif defined(PATH_MAX)
-#    define MPD_PATH_MAX PATH_MAX
-#  else
-#    define MPD_PATH_MAX 256
-#  endif
-#endif
-
-void path_global_init();
-
-void path_global_finish();
-
-/**
- * Converts a file name in the filesystem charset to UTF-8.  Returns
- * NULL on failure.
- */
-char *
-fs_charset_to_utf8(const char *path_fs);
-
-/**
- * Converts a file name in UTF-8 to the filesystem charset.  Returns a
- * duplicate of the UTF-8 string on failure.
- */
-char *
-utf8_to_fs_charset(const char *path_utf8);
-
-const char *path_get_fs_charset();
-
-/**
- * A path name in the native file system character set.
- */
-class Path {
-public:
-	typedef char value_type;
-	typedef value_type *pointer;
-	typedef const value_type *const_pointer;
-
-private:
-	pointer value;
-
-	struct Donate {};
-
-	/**
-	 * Donate the allocated pointer to a new #Path object.
-	 */
-	constexpr Path(Donate, pointer _value):value(_value) {}
-
-	/**
-	 * Release memory allocated by the value, but do not clear the
-	 * value pointer.
-	 */
-	void Free() {
-		/* free() can be optimized by gcc, while g_free() can
-		   not: when the compiler knows that the value is
-		   nullptr, it will not emit a free() call in the
-		   inlined destructor; however on Windows, we need to
-		   call g_free(), because the value has been allocated
-		   by GLib, and on Windows, this matters */
-#ifdef WIN32
-		g_free(value);
-#else
-		free(value);
-#endif
-	}
-
-public:
-	/**
-	 * Copy a #Path object.
-	 */
-	Path(const Path &other)
-		:value(g_strdup(other.value)) {}
-
-	/**
-	 * Move a #Path object.
-	 */
-	Path(Path &&other):value(other.value) {
-		other.value = nullptr;
-	}
-
-	~Path() {
-		Free();
-	}
-
-	/**
-	 * Return a "nulled" instance.  Its IsNull() method will
-	 * return true.  Such an object must not be used.
-	 *
-	 * @see IsNull()
-	 */
-	gcc_const
-	static Path Null() {
-		return Path(Donate(), nullptr);
-	}
-
-	/**
-	 * Join two path components with the path separator.
-	 */
-	gcc_pure gcc_nonnull_all
-	static Path Build(const_pointer a, const_pointer b) {
-		return Path(Donate(), g_build_filename(a, b, nullptr));
-	}
-
-	gcc_pure gcc_nonnull_all
-	static Path Build(const_pointer a, const Path &b) {
-		return Build(a, b.c_str());
-	}
-
-	gcc_pure gcc_nonnull_all
-	static Path Build(const Path &a, const_pointer b) {
-		return Build(a.c_str(), b);
-	}
-
-	gcc_pure
-	static Path Build(const Path &a, const Path &b) {
-		return Build(a.c_str(), b.c_str());
-	}
-
-	/**
-	 * Convert a C string that is already in the filesystem
-	 * character set to a #Path instance.
-	 */
-	gcc_pure
-	static Path FromFS(const_pointer fs) {
-		return Path(Donate(), g_strdup(fs));
-	}
-
-	/**
-	 * Convert a UTF-8 C string to a #Path instance.
-	 *
-	 * TODO: return a "nulled" instance on error and add checks to
-	 * all callers
-	 */
-	gcc_pure
-	static Path FromUTF8(const char *utf8) {
-		return Path(Donate(), utf8_to_fs_charset(utf8));
-	}
-
-	/**
-	 * Copy a #Path object.
-	 */
-	Path &operator=(const Path &other) {
-		if (this != &other) {
-			Free();
-			value = g_strdup(other.value);
-		}
-
-		return *this;
-	}
-
-	/**
-	 * Move a #Path object.
-	 */
-	Path &operator=(Path &&other) {
-		std::swap(value, other.value);
-		return *this;
-	}
-
-	/**
-	 * Steal the allocated value.  This object has an undefined
-	 * value, and the caller is response for freeing this method's
-	 * return value.
-	 */
-	pointer Steal() {
-		pointer result = value;
-		value = nullptr;
-		return result;
-	}
-
-	/**
-	 * Check if this is a "nulled" instance.  A "nulled" instance
-	 * must not be used.
-	 */
-	bool IsNull() const {
-		return value == nullptr;
-	}
-
-	/**
-	 * Clear this object's value, make it "nulled".
-	 *
-	 * @see IsNull()
-	 */
-	void SetNull() {
-		Free();
-		value = nullptr;
-	}
-
-	gcc_pure
-	bool empty() const {
-		assert(value != nullptr);
-
-		return *value == 0;
-	}
-
-	/**
-	 * @return the length of this string in number of "value_type"
-	 * elements (which may not be the number of characters).
-	 */
-	gcc_pure
-	size_t length() const {
-		assert(value != nullptr);
-
-		return strlen(value);
-	}
-
-	/**
-	 * Returns the value as a const C string.  The returned
-	 * pointer is invalidated whenever the value of life of this
-	 * instance ends.
-	 */
-	gcc_pure
-	const_pointer c_str() const {
-		assert(value != nullptr);
-
-		return value;
-	}
-
-	/**
-	 * Convert the path to UTF-8.  The caller is responsible for
-	 * freeing the return value with g_free().  Returns nullptr on
-	 * error.
-	 */
-	char *ToUTF8() const {
-		return value != nullptr
-			? fs_charset_to_utf8(value)
-			: nullptr;
-	}
-};
-
-#endif
diff --git a/src/PlaylistFile.cxx b/src/PlaylistFile.cxx
index ea81540cf..34f04df77 100644
--- a/src/PlaylistFile.cxx
+++ b/src/PlaylistFile.cxx
@@ -30,7 +30,7 @@
 #include "TextFile.hxx"
 #include "conf.h"
 #include "Idle.hxx"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 
 extern "C" {
 #include "uri.h"
diff --git a/src/PlaylistMapper.cxx b/src/PlaylistMapper.cxx
index e6b8ee439..96106a4cf 100644
--- a/src/PlaylistMapper.cxx
+++ b/src/PlaylistMapper.cxx
@@ -21,7 +21,7 @@
 #include "PlaylistMapper.hxx"
 #include "PlaylistFile.hxx"
 #include "Mapper.hxx"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 
 extern "C" {
 #include "playlist_list.h"
diff --git a/src/PlaylistSave.cxx b/src/PlaylistSave.cxx
index 89feebbde..e5b2a8f69 100644
--- a/src/PlaylistSave.cxx
+++ b/src/PlaylistSave.cxx
@@ -24,7 +24,7 @@
 #include "song.h"
 #include "Mapper.hxx"
 #include "Idle.hxx"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 
 extern "C" {
 #include "uri.h"
diff --git a/src/PlaylistSong.cxx b/src/PlaylistSong.cxx
index 0d60c1413..6c59600f6 100644
--- a/src/PlaylistSong.cxx
+++ b/src/PlaylistSong.cxx
@@ -24,7 +24,7 @@
 #include "DatabaseGlue.hxx"
 #include "ls.hxx"
 #include "tag.h"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 
 extern "C" {
 #include "song.h"
diff --git a/src/SongUpdate.cxx b/src/SongUpdate.cxx
index ed7293f14..120aaf537 100644
--- a/src/SongUpdate.cxx
+++ b/src/SongUpdate.cxx
@@ -26,7 +26,7 @@ extern "C" {
 
 #include "Directory.hxx"
 #include "Mapper.hxx"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 #include "tag.h"
 #include "input_stream.h"
 
diff --git a/src/StateFile.hxx b/src/StateFile.hxx
index 72d71e105..bb1c382f4 100644
--- a/src/StateFile.hxx
+++ b/src/StateFile.hxx
@@ -21,7 +21,7 @@
 #define MPD_STATE_FILE_HXX
 
 #include "event/TimeoutMonitor.hxx"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 #include "gcc.h"
 
 #include <string>
diff --git a/src/TextFile.hxx b/src/TextFile.hxx
index b24889f61..c4822aaf8 100644
--- a/src/TextFile.hxx
+++ b/src/TextFile.hxx
@@ -21,7 +21,7 @@
 #define MPD_TEXT_FILE_HXX
 
 #include "gcc.h"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 
 #include <glib.h>
 
diff --git a/src/UpdateArchive.cxx b/src/UpdateArchive.cxx
index c45e1b733..0765b1ba7 100644
--- a/src/UpdateArchive.cxx
+++ b/src/UpdateArchive.cxx
@@ -24,7 +24,7 @@
 #include "Directory.hxx"
 #include "song.h"
 #include "Mapper.hxx"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 
 extern "C" {
 #include "archive_list.h"
diff --git a/src/UpdateContainer.cxx b/src/UpdateContainer.cxx
index d59fa96c0..f24a1848a 100644
--- a/src/UpdateContainer.cxx
+++ b/src/UpdateContainer.cxx
@@ -26,7 +26,7 @@
 #include "song.h"
 #include "decoder_plugin.h"
 #include "Mapper.hxx"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 
 extern "C" {
 #include "tag_handler.h"
diff --git a/src/UpdateIO.cxx b/src/UpdateIO.cxx
index cbf05b6fc..eca5688a1 100644
--- a/src/UpdateIO.cxx
+++ b/src/UpdateIO.cxx
@@ -21,7 +21,7 @@
 #include "UpdateIO.hxx"
 #include "Directory.hxx"
 #include "Mapper.hxx"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 #include "glib_compat.h"
 
 #include <glib.h>
diff --git a/src/UpdateWalk.cxx b/src/UpdateWalk.cxx
index d0e9281a7..fb6618111 100644
--- a/src/UpdateWalk.cxx
+++ b/src/UpdateWalk.cxx
@@ -31,7 +31,7 @@
 #include "Mapper.hxx"
 #include "ExcludeList.hxx"
 #include "conf.h"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 
 extern "C" {
 #include "uri.h"
diff --git a/src/db/SimpleDatabasePlugin.hxx b/src/db/SimpleDatabasePlugin.hxx
index 3549aa98c..888f9c33e 100644
--- a/src/db/SimpleDatabasePlugin.hxx
+++ b/src/db/SimpleDatabasePlugin.hxx
@@ -21,7 +21,7 @@
 #define MPD_SIMPLE_DATABASE_PLUGIN_HXX
 
 #include "DatabasePlugin.hxx"
-#include "Path.hxx"
+#include "fs/Path.hxx"
 #include "gcc.h"
 
 #include <cassert>
diff --git a/src/fs/Path.cxx b/src/fs/Path.cxx
new file mode 100644
index 000000000..80b41cbaa
--- /dev/null
+++ b/src/fs/Path.cxx
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "fs/Path.hxx"
+#include "conf.h"
+#include "mpd_error.h"
+#include "gcc.h"
+
+#include <glib.h>
+
+#include <assert.h>
+#include <string.h>
+
+#ifdef G_OS_WIN32
+#include <windows.h> // for GetACP()
+#include <stdio.h> // for sprintf()
+#endif
+
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "path"
+
+static char *fs_charset;
+
+char *
+fs_charset_to_utf8(const char *path_fs)
+{
+	return g_convert(path_fs, -1,
+			 "utf-8", fs_charset,
+			 NULL, NULL, NULL);
+}
+
+char *
+utf8_to_fs_charset(const char *path_utf8)
+{
+	gchar *p;
+
+	p = g_convert(path_utf8, -1,
+		      fs_charset, "utf-8",
+		      NULL, NULL, NULL);
+	if (p == NULL)
+		/* fall back to UTF-8 */
+		p = g_strdup(path_utf8);
+
+	return p;
+}
+
+gcc_pure
+static bool
+IsSupportedCharset(const char *charset)
+{
+	/* convert a space to check if the charset is valid */
+	char *test = g_convert(" ", 1, charset, "UTF-8", NULL, NULL, NULL);
+	if (test == NULL)
+		return false;
+
+	g_free(test);
+	return true;
+}
+
+static void
+path_set_fs_charset(const char *charset)
+{
+	assert(charset != NULL);
+
+	if (!IsSupportedCharset(charset))
+		MPD_ERROR("invalid filesystem charset: %s", charset);
+
+	g_free(fs_charset);
+	fs_charset = g_strdup(charset);
+
+	g_debug("path_set_fs_charset: fs charset is: %s", fs_charset);
+}
+
+const char *path_get_fs_charset(void)
+{
+	return fs_charset;
+}
+
+void path_global_init(void)
+{
+	const char *charset = NULL;
+
+	charset = config_get_string(CONF_FS_CHARSET, NULL);
+	if (charset == NULL) {
+#ifndef G_OS_WIN32
+		const gchar **encodings;
+		g_get_filename_charsets(&encodings);
+
+		if (encodings[0] != NULL && *encodings[0] != '\0')
+			charset = encodings[0];
+#else /* G_OS_WIN32 */
+		/* Glib claims that file system encoding is always utf-8
+		 * on native Win32 (i.e. not Cygwin).
+		 * However this is true only if <gstdio.h> helpers are used.
+		 * MPD uses regular <stdio.h> functions.
+		 * Those functions use encoding determined by GetACP(). */
+		static char win_charset[13];
+		sprintf(win_charset, "cp%u", GetACP());
+		charset = win_charset;
+#endif
+	}
+
+	if (charset) {
+		path_set_fs_charset(charset);
+	} else {
+		g_message("setting filesystem charset to ISO-8859-1");
+		path_set_fs_charset("ISO-8859-1");
+	}
+}
+
+void path_global_finish(void)
+{
+	g_free(fs_charset);
+}
diff --git a/src/fs/Path.hxx b/src/fs/Path.hxx
new file mode 100644
index 000000000..24f1d5e19
--- /dev/null
+++ b/src/fs/Path.hxx
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_FS_PATH_HXX
+#define MPD_FS_PATH_HXX
+
+#include "check.h"
+#include "gcc.h"
+
+#include <glib.h>
+
+#include <algorithm>
+
+#include <assert.h>
+#include <string.h>
+#include <limits.h>
+
+#if !defined(MPD_PATH_MAX)
+#  if defined(MAXPATHLEN)
+#    define MPD_PATH_MAX MAXPATHLEN
+#  elif defined(PATH_MAX)
+#    define MPD_PATH_MAX PATH_MAX
+#  else
+#    define MPD_PATH_MAX 256
+#  endif
+#endif
+
+void path_global_init();
+
+void path_global_finish();
+
+/**
+ * Converts a file name in the filesystem charset to UTF-8.  Returns
+ * NULL on failure.
+ */
+char *
+fs_charset_to_utf8(const char *path_fs);
+
+/**
+ * Converts a file name in UTF-8 to the filesystem charset.  Returns a
+ * duplicate of the UTF-8 string on failure.
+ */
+char *
+utf8_to_fs_charset(const char *path_utf8);
+
+const char *path_get_fs_charset();
+
+/**
+ * A path name in the native file system character set.
+ */
+class Path {
+public:
+	typedef char value_type;
+	typedef value_type *pointer;
+	typedef const value_type *const_pointer;
+
+private:
+	pointer value;
+
+	struct Donate {};
+
+	/**
+	 * Donate the allocated pointer to a new #Path object.
+	 */
+	constexpr Path(Donate, pointer _value):value(_value) {}
+
+	/**
+	 * Release memory allocated by the value, but do not clear the
+	 * value pointer.
+	 */
+	void Free() {
+		/* free() can be optimized by gcc, while g_free() can
+		   not: when the compiler knows that the value is
+		   nullptr, it will not emit a free() call in the
+		   inlined destructor; however on Windows, we need to
+		   call g_free(), because the value has been allocated
+		   by GLib, and on Windows, this matters */
+#ifdef WIN32
+		g_free(value);
+#else
+		free(value);
+#endif
+	}
+
+public:
+	/**
+	 * Copy a #Path object.
+	 */
+	Path(const Path &other)
+		:value(g_strdup(other.value)) {}
+
+	/**
+	 * Move a #Path object.
+	 */
+	Path(Path &&other):value(other.value) {
+		other.value = nullptr;
+	}
+
+	~Path() {
+		Free();
+	}
+
+	/**
+	 * Return a "nulled" instance.  Its IsNull() method will
+	 * return true.  Such an object must not be used.
+	 *
+	 * @see IsNull()
+	 */
+	gcc_const
+	static Path Null() {
+		return Path(Donate(), nullptr);
+	}
+
+	/**
+	 * Join two path components with the path separator.
+	 */
+	gcc_pure gcc_nonnull_all
+	static Path Build(const_pointer a, const_pointer b) {
+		return Path(Donate(), g_build_filename(a, b, nullptr));
+	}
+
+	gcc_pure gcc_nonnull_all
+	static Path Build(const_pointer a, const Path &b) {
+		return Build(a, b.c_str());
+	}
+
+	gcc_pure gcc_nonnull_all
+	static Path Build(const Path &a, const_pointer b) {
+		return Build(a.c_str(), b);
+	}
+
+	gcc_pure
+	static Path Build(const Path &a, const Path &b) {
+		return Build(a.c_str(), b.c_str());
+	}
+
+	/**
+	 * Convert a C string that is already in the filesystem
+	 * character set to a #Path instance.
+	 */
+	gcc_pure
+	static Path FromFS(const_pointer fs) {
+		return Path(Donate(), g_strdup(fs));
+	}
+
+	/**
+	 * Convert a UTF-8 C string to a #Path instance.
+	 *
+	 * TODO: return a "nulled" instance on error and add checks to
+	 * all callers
+	 */
+	gcc_pure
+	static Path FromUTF8(const char *utf8) {
+		return Path(Donate(), utf8_to_fs_charset(utf8));
+	}
+
+	/**
+	 * Copy a #Path object.
+	 */
+	Path &operator=(const Path &other) {
+		if (this != &other) {
+			Free();
+			value = g_strdup(other.value);
+		}
+
+		return *this;
+	}
+
+	/**
+	 * Move a #Path object.
+	 */
+	Path &operator=(Path &&other) {
+		std::swap(value, other.value);
+		return *this;
+	}
+
+	/**
+	 * Steal the allocated value.  This object has an undefined
+	 * value, and the caller is response for freeing this method's
+	 * return value.
+	 */
+	pointer Steal() {
+		pointer result = value;
+		value = nullptr;
+		return result;
+	}
+
+	/**
+	 * Check if this is a "nulled" instance.  A "nulled" instance
+	 * must not be used.
+	 */
+	bool IsNull() const {
+		return value == nullptr;
+	}
+
+	/**
+	 * Clear this object's value, make it "nulled".
+	 *
+	 * @see IsNull()
+	 */
+	void SetNull() {
+		Free();
+		value = nullptr;
+	}
+
+	gcc_pure
+	bool empty() const {
+		assert(value != nullptr);
+
+		return *value == 0;
+	}
+
+	/**
+	 * @return the length of this string in number of "value_type"
+	 * elements (which may not be the number of characters).
+	 */
+	gcc_pure
+	size_t length() const {
+		assert(value != nullptr);
+
+		return strlen(value);
+	}
+
+	/**
+	 * Returns the value as a const C string.  The returned
+	 * pointer is invalidated whenever the value of life of this
+	 * instance ends.
+	 */
+	gcc_pure
+	const_pointer c_str() const {
+		assert(value != nullptr);
+
+		return value;
+	}
+
+	/**
+	 * Convert the path to UTF-8.  The caller is responsible for
+	 * freeing the return value with g_free().  Returns nullptr on
+	 * error.
+	 */
+	char *ToUTF8() const {
+		return value != nullptr
+			? fs_charset_to_utf8(value)
+			: nullptr;
+	}
+};
+
+#endif
-- 
cgit v1.2.3