]> de.git.xonotic.org Git - voretournament/voretournament.git/blobdiff - misc/mediasource/extra/netradiant-src/libs/fs_filesystem.h
Include netRadiant source in this GIT
[voretournament/voretournament.git] / misc / mediasource / extra / netradiant-src / libs / fs_filesystem.h
diff --git a/misc/mediasource/extra/netradiant-src/libs/fs_filesystem.h b/misc/mediasource/extra/netradiant-src/libs/fs_filesystem.h
new file mode 100644 (file)
index 0000000..0c22a4b
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+Copyright (C) 2001-2006, William Joseph.
+All Rights Reserved.
+
+This file is part of GtkRadiant.
+
+GtkRadiant 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.
+
+GtkRadiant 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 GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#if !defined(INCLUDED_FS_FILESYSTEM_H)
+#define INCLUDED_FS_FILESYSTEM_H
+
+#include "string/string.h"
+#include "os/path.h"
+
+#include <map>
+
+inline unsigned int path_get_depth(const char* path)
+{
+  unsigned int depth = 0;
+  while(path != 0 && path[0] != '\0')
+  {
+    path = strchr(path, '/');
+    if(path != 0)
+    {
+      ++path;
+    }
+    ++depth;
+  }
+  return depth;
+}
+
+/// \brief A generic unix-style file-system which maps paths to files and directories.
+/// Provides average O(log n) find and insert methods.
+/// \param file_type The data type which represents a file.
+template<typename file_type>
+class GenericFileSystem
+{
+  class Path
+  {
+    CopiedString m_path;
+    unsigned int m_depth;
+  public:
+    Path(const char* path)
+      : m_path(path), m_depth(path_get_depth(c_str()))
+    {
+    }
+    Path(StringRange range)
+      : m_path(range), m_depth(path_get_depth(c_str()))
+    {
+    }
+    bool operator<(const Path& other) const
+    {
+      return string_less_nocase(c_str(), other.c_str());
+    }
+    unsigned int depth() const
+    {
+      return m_depth;
+    }
+    const char* c_str() const
+    {
+      return m_path.c_str();
+    }
+  };
+
+  class Entry
+  {
+    file_type* m_file;
+  public:
+    Entry() : m_file(0)
+    {
+    }
+    Entry(file_type* file) : m_file(file)
+    {
+    }
+    file_type* file() const
+    {
+      return m_file;
+    }
+    bool is_directory() const
+    {
+      return file() == 0;
+    }
+  };
+
+  typedef std::map<Path, Entry> Entries;
+  Entries m_entries;
+
+public:
+  typedef typename Entries::iterator iterator;
+  typedef typename Entries::value_type value_type;
+  typedef Entry entry_type;
+
+  iterator begin()
+  {
+    return m_entries.begin();
+  }
+  iterator end()
+  {
+    return m_entries.end();
+  }
+
+  /// \brief Returns the file at \p path.
+  /// Creates all directories below \p path if they do not exist.
+  /// O(log n) on average.
+  entry_type& operator[](const Path& path)
+  {
+    {
+      const char* end = path_remove_directory(path.c_str());
+      while(end[0] != '\0')
+      {
+        Path dir(StringRange(path.c_str(), end));
+        m_entries.insert(value_type(dir, Entry(0)));
+        end = path_remove_directory(end);
+      }
+    }
+
+    return m_entries[path];
+  }
+
+  /// \brief Returns the file at \p path or end() if not found.
+  iterator find(const Path& path)
+  {
+    return m_entries.find(path);
+  }
+
+  iterator begin(const char* root)
+  {
+    if(root[0] == '\0')
+    {
+      return m_entries.begin();
+    }
+    iterator i = m_entries.find(root);
+    if(i == m_entries.end())
+    {
+      return i;
+    }
+    return ++i;
+  }
+
+  /// \brief Performs a depth-first traversal of the file-system subtree rooted at \p root.
+  /// Traverses the entire tree if \p root is "".
+  /// Calls \p visitor.file() with the path to each file relative to the filesystem root.
+  /// Calls \p visitor.directory() with the path to each directory relative to the filesystem root.
+  template<typename visitor_type>
+  void traverse(visitor_type visitor, const char* root)
+  {
+    unsigned int start_depth = path_get_depth(root);
+    unsigned int skip_depth = 0;
+    for(iterator i = begin(root); i != end() && i->first.depth() > start_depth; ++i)
+    {
+      if(i->first.depth() == skip_depth)
+      {
+        skip_depth = 0;
+      }
+      if(skip_depth == 0)
+      {
+        if(!i->second.is_directory())
+        {
+          visitor.file(i->first.c_str());
+        }
+        else if(visitor.directory(i->first.c_str(), i->first.depth() - start_depth))
+        {
+          skip_depth = i->first.depth();
+        }
+      }
+    }
+  }
+};
+
+#endif