1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2004-2021 musikcube team
4 //
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 // * Redistributions of source code must retain the above copyright notice,
11 // this list of conditions and the following disclaimer.
12 //
13 // * Redistributions in binary form must reproduce the above copyright
14 // notice, this list of conditions and the following disclaimer in the
15 // documentation and/or other materials provided with the distribution.
16 //
17 // * Neither the name of the author nor the names of other contributors may
18 // be used to endorse or promote products derived from this software
19 // without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
32 //
33 //////////////////////////////////////////////////////////////////////////////
34
35 #include "pch.hpp"
36 #include <musikcore/support/Common.h>
37 #include <musikcore/config.h>
38
39 #include <cstdlib>
40 #include <iostream>
41 #include <fstream>
42 #include <functional>
43 #include <vector>
44 #include <string>
45 #include <cctype>
46 #include <algorithm>
47
48 #pragma warning(push, 0)
49 #include <utf8/utf8.h>
50 #pragma warning(pop)
51
52 #ifdef WIN32
53 #include <shellapi.h>
54 #elif __APPLE__
55 #include <mach-o/dyld.h>
56 #else
57 #include <sys/types.h>
58 #include <unistd.h>
59 #include <sys/stat.h>
60 #include <limits.h>
61 #endif
62
63 // given the #ifdef/#else above, the following is not required.
64 // Nor it is the #if FreeBSD below.
65 #ifdef __OpenBSD__
66 #include <sys/types.h>
67 #include <sys/sysctl.h>
68 #include <unistd.h>
69 #include <limits.h>
70 #endif
71
72 #ifdef __FreeBSD__
73 #include <sys/types.h>
74 #include <sys/sysctl.h>
75 #endif
76
silentDelete(const std::string fn)77 static inline void silentDelete(const std::string fn) {
78 boost::system::error_code ec;
79 boost::filesystem::remove(boost::filesystem::path(fn), ec);
80 }
81
82 namespace musik { namespace core {
83
getDataDirectoryRoot()84 static std::string getDataDirectoryRoot() {
85 #ifdef WIN32
86 return GetHomeDirectory();
87 #else
88 return GetHomeDirectory() + "/.config";
89 #endif
90 }
91
GetPluginDirectory()92 std::string GetPluginDirectory() {
93 std::string path(GetApplicationDirectory());
94 path.append("/plugins/");
95 return path;
96 }
97
GetApplicationDirectory()98 std::string GetApplicationDirectory() {
99 std::string result;
100
101 #ifdef WIN32
102 wchar_t widePath[2048];
103 int length = GetModuleFileName(NULL, widePath, 2048);
104 if (length != 0 && length < 2048) {
105 result.assign(GetPath(u16to8(widePath).c_str()));
106 }
107 #elif __APPLE__
108 char pathbuf[PATH_MAX + 1];
109 uint32_t bufsize = sizeof(pathbuf);
110 _NSGetExecutablePath(pathbuf, &bufsize);
111 result.assign(pathbuf);
112 size_t last = result.find_last_of("/");
113 result = result.substr(0, last); /* remove filename component */
114 #else
115 char pathbuf[PATH_MAX + 1] = { 0 };
116
117 #ifdef __FreeBSD__
118 int mib[4];
119 mib[0] = CTL_KERN;
120 mib[1] = KERN_PROC;
121 mib[2] = KERN_PROC_PATHNAME;
122 mib[3] = -1;
123 size_t bufsize = sizeof(pathbuf);
124 sysctl(mib, 4, pathbuf, &bufsize, nullptr, 0);
125 #elif defined __OpenBSD__
126 int mib[4];
127 char **argv;
128 size_t len = ARG_MAX;
129
130 mib[0] = CTL_KERN;
131 mib[1] = KERN_PROC_ARGS;
132 mib[2] = getpid();
133 mib[3] = KERN_PROC_ARGV;
134
135 argv = new char*[len];
136 if (sysctl(mib, 4, argv, &len, nullptr, 0) < 0) abort();
137
138 boost::filesystem::path command = boost::filesystem::system_complete(argv[0]);
139 realpath(command.c_str(), pathbuf);
140 delete[] argv;
141 #else
142 std::string pathToProc = u8fmt("/proc/%d/exe", (int) getpid());
143 readlink(pathToProc.c_str(), pathbuf, PATH_MAX);
144 #endif
145
146 result.assign(pathbuf);
147 size_t last = result.find_last_of("/");
148 result = result.substr(0, last); /* remove filename component */
149 #endif
150
151 return result;
152 }
153
GetHomeDirectory()154 std::string GetHomeDirectory() {
155 std::string directory;
156
157 #ifdef WIN32
158 DWORD bufferSize = GetEnvironmentVariable(L"APPDATA", 0, 0);
159 wchar_t* buffer = new wchar_t[bufferSize + 2];
160 GetEnvironmentVariable(L"APPDATA", buffer, bufferSize);
161 directory.assign(u16to8(buffer));
162 delete[] buffer;
163 #else
164 const char* result = std::getenv("XDG_CONFIG_HOME");
165 if (result && strlen(result)) {
166 directory = std::string(result);
167 }
168 else {
169 directory = std::string(std::getenv("HOME"));
170 }
171 #endif
172
173 return directory;
174 }
175
GetDataDirectory(bool create)176 std::string GetDataDirectory(bool create) {
177 std::string directory = getDataDirectoryRoot() + std::string("/musikcube/");
178
179 if (create) {
180 try {
181 boost::filesystem::path path(directory);
182 if (!boost::filesystem::exists(path)) {
183 boost::filesystem::create_directories(path);
184 }
185 }
186 catch (...) {
187 /* ugh, fixme */
188 }
189 }
190
191 return directory;
192 }
193
GetPath(const std::string & sFile)194 std::string GetPath(const std::string &sFile) {
195 std::string sPath;
196 int length;
197
198 #ifdef WIN32
199 wchar_t widePath[2048];
200 wchar_t *szFile = NULL;
201
202 length = GetFullPathName(u8to16(sFile).c_str(), 2048, widePath, &szFile);
203 if(length != 0 && length < 2048) {
204 sPath.assign(u16to8(widePath).c_str());
205 if(szFile!=0) {
206 std::string sTheFile = u16to8(szFile);
207 sPath.assign(sPath.substr(0,length-sTheFile.length()));
208 }
209 }
210 else {
211 sPath.assign(sFile);
212 }
213 #else
214 char* szDir;
215 sPath.assign(getcwd((char*)szDir, (size_t) length));
216 #endif
217
218 return sPath;
219 }
220
Checksum(char * data,unsigned int bytes)221 int64_t Checksum(char *data,unsigned int bytes) {
222 int64_t sum = 0;
223 for(unsigned int i = 0; i < bytes; ++i) {
224 char ch = *(data + i);
225 sum += (int64_t) ch;
226 }
227 return sum;
228 }
229
CopyString(const std::string & src,char * dst,size_t size)230 size_t CopyString(const std::string& src, char* dst, size_t size) {
231 size_t len = src.size() + 1; /* space for the null terminator */
232 if (dst) {
233 size_t copied = src.copy(dst, size - 1);
234 dst[copied] = '\0';
235 return copied + 1;
236 }
237 return len;
238 }
239
FileToByteArray(const std::string & path,char ** target,int & size,bool nullTerminate)240 bool FileToByteArray(const std::string& path, char** target, int& size, bool nullTerminate) {
241 #ifdef WIN32
242 std::wstring u16fn = u8to16(path);
243 FILE* file = _wfopen(u16fn.c_str(), L"rb");
244 #else
245 FILE* file = fopen(path.c_str(), "rb");
246 #endif
247
248 *target = nullptr;
249 size = 0;
250
251 if (!file) {
252 return false;
253 }
254
255 bool success = false;
256
257 if (fseek(file, 0L, SEEK_END) == 0) {
258 long fileSize = ftell(file);
259 if (fileSize == -1) {
260 goto close_and_return;
261 }
262
263 if (fseek(file, 0L, SEEK_SET) != 0) {
264 goto close_and_return;
265 }
266
267 *target = (char*)malloc(sizeof(char) * (fileSize + (nullTerminate ? 1 : 0)));
268 size = narrow_cast<int>(fread(*target, sizeof(char), fileSize, file));
269
270 if (size == fileSize) {
271 if (nullTerminate) {
272 (*target)[size] = 0;
273 }
274
275 success = true;
276 }
277 }
278
279 close_and_return:
280 fclose(file);
281
282 if (!success) {
283 free(*target);
284 }
285
286 return success;
287 }
288
NormalizeDir(std::string path)289 std::string NormalizeDir(std::string path) {
290 path = boost::filesystem::path(path).make_preferred().string();
291
292 std::string sep(1, boost::filesystem::path::preferred_separator);
293 if (path.size() && path.substr(path.size() - 1, 1) != sep) {
294 path += sep;
295 }
296
297 return path;
298 }
299
ReplaceAll(std::string & input,const std::string & find,const std::string & replace)300 void ReplaceAll(std::string& input, const std::string& find, const std::string& replace) {
301 size_t pos = input.find(find);
302 while (pos != std::string::npos) {
303 input.replace(pos, find.size(), replace);
304 pos = input.find(find, pos + replace.size());
305 }
306 }
307
IsSpace(const char c)308 static inline bool IsSpace(const char c) {
309 return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '\f';
310 }
311
Trim(const std::string & str)312 std::string Trim(const std::string& str) {
313 if (str.size()) {
314 int start = 0;
315 for (size_t i = 0; i < str.length(); i++) {
316 if (!IsSpace(str[i])) {
317 break;
318 }
319 ++start;
320 }
321 int end = (int)str.length();
322 for (size_t i = str.length() - 1; i >= 0; i--) {
323 if (!IsSpace(str[i])) {
324 break;
325 }
326 --end;
327 }
328 if (end > start) {
329 std::string result = str.substr((size_t)start, (size_t)end - start);
330 return result;
331 }
332 }
333 return str;
334 }
335
Split(const std::string & in,const std::string & delim)336 std::vector<std::string> Split(
337 const std::string& in, const std::string& delim)
338 {
339 std::vector<std::string> result;
340 size_t last = 0, next = 0;
341 while ((next = in.find(delim, last)) != std::string::npos) {
342 result.push_back(std::move(Trim(in.substr(last, next - last))));
343 last = next + 1;
344 }
345 result.push_back(std::move(Trim(in.substr(last))));
346 return result;
347 }
348
OpenFile(const std::string & path)349 void OpenFile(const std::string& path) {
350 #ifdef WIN32
351 ShellExecuteA(nullptr, nullptr, path.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
352 #elif __APPLE__
353 std::string command = "open '" + path + "' > /dev/null 2> /dev/null";
354 system(command.c_str());
355 #else
356 std::string command = "xdg-open '" + path + "' > /dev/null 2> /dev/null";
357 system(command.c_str());
358 #endif
359 }
360
CopyFile(const std::string & from,const std::string & to)361 bool CopyFile(const std::string& from, const std::string& to) {
362 if (from.size() && to.size() && from != to) {
363 std::ifstream in(from);
364 if (in.is_open()) {
365 std::ofstream out(to);
366 if (out.is_open()) {
367 out << in.rdbuf();
368 return true;
369 }
370 }
371 }
372 return false;
373 }
374
375 } }
376