1
2
3
4
5
6 #include <cmajor/rt/Directory.hpp>
7 #include <soulng/util/Path.hpp>
8 #include <memory>
9 #include <mutex>
10 #include <unordered_map>
11 #include <boost/filesystem.hpp>
12
13 namespace cmajor { namespace rt {
14
15 using namespace soulng::util;
16
17 struct Iteration
18 {
19 boost::filesystem::directory_iterator directoryIterator;
20 std::string directoryName;
21 std::string path;
22 };
23
24 class DirectoryIterationTable
25 {
26 public:
27 static void Init();
28 static void Done();
29 static DirectoryIterationTable& Instance() { return *instance; }
30 int32_t BeginIterate(const char* directoryPath);
31 const char* IterateFiles(int32_t handle);
32 const char* IterateDirectories(int32_t handle);
33 void EndIterate(int32_t handle);
34 private:
35 static std::unique_ptr<DirectoryIterationTable> instance;
36 DirectoryIterationTable();
37 int32_t nextIterationHandle;
38 std::unordered_map<int32_t, Iteration> iterationMap;
39 std::mutex mtx;
40 };
41
42 std::unique_ptr<DirectoryIterationTable> DirectoryIterationTable::instance;
43
44 void DirectoryIterationTable::Init()
45 {
46 instance.reset(new DirectoryIterationTable());
47 }
48
49 void DirectoryIterationTable::Done()
50 {
51 instance.reset();
52 }
53
54 DirectoryIterationTable::DirectoryIterationTable() : nextIterationHandle(0)
55 {
56 }
57
58 int32_t DirectoryIterationTable::BeginIterate(const char* directoryPath)
59 {
60 std::lock_guard<std::mutex> lock(mtx);
61 int32_t handle = nextIterationHandle++;
62 Iteration iteration;
63 iteration.directoryName = GetFullPath(Path::MakeCanonical(directoryPath));
64 iteration.directoryIterator = boost::filesystem::directory_iterator(iteration.directoryName);
65 iterationMap[handle] = iteration;
66 return handle;
67 }
68
69 void DirectoryIterationTable::EndIterate(int32_t handle)
70 {
71 std::lock_guard<std::mutex> lock(mtx);
72 iterationMap.erase(handle);
73 }
74
75 const char* DirectoryIterationTable::IterateFiles(int32_t handle)
76 {
77 std::lock_guard<std::mutex> lock(mtx);
78 auto it = iterationMap.find(handle);
79 if (it != iterationMap.cend())
80 {
81 Iteration& iteration = it->second;
82 while (iteration.directoryIterator != boost::filesystem::directory_iterator() && !boost::filesystem::is_regular_file(*iteration.directoryIterator))
83 {
84 ++iteration.directoryIterator;
85 }
86 if (iteration.directoryIterator != boost::filesystem::directory_iterator())
87 {
88 iteration.path = GetFullPath(Path::Combine(iteration.directoryName, boost::filesystem::path(*iteration.directoryIterator).generic_string()));
89 ++iteration.directoryIterator;
90 return iteration.path.c_str();
91 }
92 return nullptr;
93 }
94 else
95 {
96 return nullptr;
97 }
98 }
99
100 const char* DirectoryIterationTable::IterateDirectories(int32_t handle)
101 {
102 std::lock_guard<std::mutex> lock(mtx);
103 auto it = iterationMap.find(handle);
104 if (it != iterationMap.cend())
105 {
106 Iteration& iteration = it->second;
107 while (iteration.directoryIterator != boost::filesystem::directory_iterator() &&
108 (!boost::filesystem::is_directory(*iteration.directoryIterator) || iteration.directoryIterator->path() == "." || iteration.directoryIterator->path() == ".."))
109 {
110 ++iteration.directoryIterator;
111 }
112 if (iteration.directoryIterator != boost::filesystem::directory_iterator())
113 {
114 iteration.path = GetFullPath(Path::Combine(iteration.directoryName, boost::filesystem::path(*iteration.directoryIterator).generic_string()));
115 ++iteration.directoryIterator;
116 return iteration.path.c_str();
117 }
118 return nullptr;
119 }
120 else
121 {
122 return nullptr;
123 }
124 }
125
126 void InitDirectory()
127 {
128 DirectoryIterationTable::Init();
129 }
130
131 void DoneDirectory()
132 {
133 DirectoryIterationTable::Done();
134 }
135
136 } }
137
138 extern "C" bool RtDirectoryExists(const char* directoryPath)
139 {
140 return boost::filesystem::exists(directoryPath);
141 }
142
143 extern "C" void RtCreateDirectories(const char* directoryPath)
144 {
145 boost::filesystem::create_directories(directoryPath);
146 }
147
148 extern "C" int32_t RtBeginIterateDirectory(const char* directoryPath)
149 {
150 return cmajor::rt::DirectoryIterationTable::Instance().BeginIterate(directoryPath);
151 }
152
153 extern "C" const char* RtGetNextFilePath(int32_t directoryIterationHandle)
154 {
155 return cmajor::rt::DirectoryIterationTable::Instance().IterateFiles(directoryIterationHandle);
156 }
157
158 extern "C" const char* RtGetNextDirectoryPath(int32_t directoryIterationHandle)
159 {
160 return cmajor::rt::DirectoryIterationTable::Instance().IterateDirectories(directoryIterationHandle);
161 }
162
163 extern "C" void RtEndIterateDirectory(int32_t directoryIterationHandle)
164 {
165 cmajor::rt::DirectoryIterationTable::Instance().EndIterate(directoryIterationHandle);
166 }