16 #include <mach-o/dyld.h>
39 const char FILE_SEPARATOR =
'/';
41 size_t separatorIndex = path.rfind(FILE_SEPARATOR);
42 string fileAndExtension;
43 if (separatorIndex != string::npos)
45 dir = path.substr(0, separatorIndex + 1);
46 if (separatorIndex < path.length())
47 fileAndExtension = path.substr(separatorIndex + 1, path.length());
51 fileAndExtension = path;
54 size_t dotIndex = fileAndExtension.rfind(
".");
55 if (dotIndex != string::npos)
57 file = fileAndExtension.substr(0, dotIndex);
58 extension = fileAndExtension.substr(dotIndex + 1, fileAndExtension.length());
62 file = fileAndExtension;
73 for (
int i = 0; i < path.length(); ++i)
75 while (i+1 < path.length() && path[i+1] ==
'/')
80 path.erase(path.length()-1);
93 return path1 == path2;
104 char *cwd = getcwd(NULL, 0);
107 VUserLog(
"Couldn't get current working directory: %s", strerror(errno));
111 string absolutePath = string(cwd) +
"/" + path;
125 if (directory.empty())
127 if (directory.at(directory.length()-1) !=
'/')
129 string suffix = (extension.empty() ?
"" : (
"." + extension));
130 string pathTemplate = directory + file +
"-XXXXXX" + suffix;
131 char *path = (
char *)calloc(pathTemplate.length() + 1,
sizeof(char));
132 strncpy(path, pathTemplate.c_str(), pathTemplate.length());
133 int fd = mkstemps(path, suffix.length());
135 string pathStr(path);
151 string pathTemplate =
getTmpDir() +
"/" + prefix +
".XXXXXX";
152 char *path = (
char *)calloc(pathTemplate.length() + 1,
sizeof(char));
153 strncpy(path, pathTemplate.c_str(), pathTemplate.length());
155 string pathStr(path);
186 char *cwd = getcwd(NULL, 0);
188 VUserLog(
"Error in getcwd(): %s", strerror(errno));
190 if (cwd && strstr(cwd,
"/Library/Containers/"))
202 char userTempDir[PATH_MAX];
203 if (confstr(_CS_DARWIN_USER_TEMP_DIR, userTempDir, PATH_MAX) > 0)
205 string userTempDirS(userTempDir);
222 throw VuoException(
"Couldn't create directory with empty path");
227 const char FILE_SEPARATOR =
'/';
228 size_t lastNonSeparator = path.find_last_not_of(FILE_SEPARATOR);
229 if (lastNonSeparator != string::npos)
230 path.resize(lastNonSeparator + 1);
232 string parentDir, file, ext;
238 int ret = mkdir(path.c_str(), 0777);
240 throw VuoException((
string(
"Couldn't create directory \"" + path +
"\": ") + strerror(errno)).c_str());
251 static string frameworkPath;
252 static dispatch_once_t once = 0;
253 dispatch_once(&once, ^{
256 const char *frameworkPathFragment =
"/Vuo.framework/Versions/";
257 uint32_t imageCount = _dyld_image_count();
258 for (uint32_t i = 0; i < imageCount; ++i)
260 const char *dylibPath = _dyld_get_image_name(i);
261 const char *found = strstr(dylibPath, frameworkPathFragment);
264 char *pathC = strndup(dylibPath, found - dylibPath);
265 string path = string(pathC) +
"/Vuo.framework";
269 frameworkPath = path;
276 char executablePath[PATH_MAX + 1];
277 uint32_t size =
sizeof(executablePath);
279 if (! _NSGetExecutablePath(executablePath, &size))
281 char cleanedExecutablePath[PATH_MAX + 1];
283 realpath(executablePath, cleanedExecutablePath);
284 string path = cleanedExecutablePath;
285 string dir, file, ext;
287 path = dir.substr(0, dir.length() - 1);
289 path = dir.substr(0, dir.length() - 1);
290 path +=
"/Frameworks/Vuo.framework";
294 frameworkPath = path;
302 return frameworkPath;
311 static string runnerFrameworkPath;
312 static dispatch_once_t once = 0;
313 dispatch_once(&once, ^{
318 runnerFrameworkPath = possibleFrameworkPath;
323 const char *frameworkPathFragment =
"/VuoRunner.framework/Versions/";
324 uint32_t imageCount = _dyld_image_count();
325 for (uint32_t i = 0; i < imageCount; ++i)
327 const char *dylibPath = _dyld_get_image_name(i);
328 const char *found = strstr(dylibPath, frameworkPathFragment);
331 char *pathC = strndup(dylibPath, found - dylibPath);
332 string path = string(pathC) +
"/VuoRunner.framework";
336 runnerFrameworkPath = path;
343 char executablePath[PATH_MAX + 1];
344 uint32_t size =
sizeof(executablePath);
346 if (! _NSGetExecutablePath(executablePath, &size))
348 char cleanedExecutablePath[PATH_MAX + 1];
350 realpath(executablePath, cleanedExecutablePath);
351 string path = cleanedExecutablePath;
352 string dir, file, ext;
354 path = dir.substr(0, dir.length() - 1);
356 path = dir.substr(0, dir.length() - 1);
357 path +=
"/Frameworks/VuoRunner.framework";
361 runnerFrameworkPath = path;
368 return runnerFrameworkPath;
381 string compositionDir, compositionFile, ext;
385 string parentDir, compositionDirName;
386 splitPath(compositionDir, parentDir, compositionDirName, ext);
389 string compositionBaseDir = (compositionDirName ==
"Modules" ? parentDir : compositionDir);
391 string compositionModulesDir = compositionBaseDir +
"/Modules";
394 return compositionModulesDir;
402 return string(getenv(
"HOME")) +
"/Library/Application Support/Vuo/Modules";
410 return "/Library/Application Support/Vuo/Modules";
418 return string(getenv(
"HOME")) +
"/Library/Caches/org.vuo/" + VUO_VERSION_AND_BUILD_STRING;
431 string dir, file, ext;
456 string bomUtf8 =
"\xEF\xBB\xBF";
457 string bomUtf16Be =
"\xFE\xFF";
458 string bomUtf16Le =
"\xFF\xFE";
459 string boms[] = { bomUtf8, bomUtf16Be, bomUtf16Le };
460 for (
int i = 0; i < 3; ++i)
463 for (
int j = 0; j < boms[i].length(); ++j)
464 if (boms[i][j] != s[j])
468 return boms[i].length();
482 while (getline(cin, line))
497 ifstream in(path.c_str(), ios::in | ios::binary);
499 throw VuoException(
string(
"Couldn't read file: ") + strerror(errno) +
" — " + path);
502 in.seekg(0, ios::end);
503 contents.resize(in.tellg());
504 in.seekg(0, ios::beg);
505 in.read(&contents[0], contents.size());
519 FILE *f = fopen(file.c_str(),
"wb");
521 throw VuoException(
string(
"Couldn't open file for writing: ") + strerror(errno) +
" — " + file);
523 size_t numBytesWritten = fwrite(data,
sizeof(
char), numBytes, f);
524 if (numBytesWritten != numBytes)
527 throw VuoException(
string(
"Couldn't write all data: ") + strerror(errno) +
" — " + file);
555 string dir, file, ext;
557 string tmpPath =
makeTmpFile(
"." + file, ext, dir);
575 return access(path.c_str(), 0) == 0;
590 int status = stat(path.c_str(), &st_buf);
591 return (! status && S_ISDIR(st_buf.st_mode));
600 int status = lstat(path.c_str(), &st_buf);
601 return (! status && S_ISLNK(st_buf.st_mode));
615 return access(path.c_str(), R_OK) == 0;
629 FILE *f = fopen(path.c_str(),
"rb");
633 fseek(f, 0, SEEK_END);
642 fseek(f, 0, SEEK_SET);
644 size_t ret = fread(&z, 1, 1, f);
654 FILE *f = fopen(path.c_str(),
"a");
663 int ret = remove(path.c_str());
665 VUserLog(
"Couldn't delete file: %s — %s", strerror(errno), path.c_str());
676 DIR *d = opendir(path.c_str());
679 VUserLog(
"Couldn't read directory: %s — %s", strerror(errno), path.c_str());
684 while( (de=readdir(d)) )
686 string fileName = de->d_name;
687 string filePath = path +
"/" + fileName;
689 if (fileName ==
"." || fileName ==
"..")
710 int ret = rename(fromPath.c_str(), toPath.c_str());
712 throw VuoException(
string(
"Couldn't move file: ") + strerror(errno) +
" — " + toPath);
738 int i = open(fromPath.c_str(), O_RDONLY);
740 throw VuoException(
string(
"Couldn't open copy source: ") + strerror(errno) +
" — " + fromPath);
744 int o = open(toPath.c_str(), O_WRONLY | O_CREAT, s.st_mode & 0777);
748 throw VuoException(
string(
"Couldn't open copy destination: ") + strerror(errno) +
" — " + toPath);
751 int ret = fcopyfile(i, o, NULL, COPYFILE_DATA | (preserveMetadata ? COPYFILE_STAT : 0));
752 char *e = strerror(errno);
757 throw VuoException(
string(
"Couldn't copy ") + fromPath +
" to " + toPath +
": " + e);
774 char linkDestination[PATH_MAX + 1];
775 ssize_t len = readlink(fromPath.c_str(), linkDestination, PATH_MAX);
776 linkDestination[len] = 0;
777 if (symlink(linkDestination, toPath.c_str()) == -1)
778 throw VuoException(
string(
"Couldn't copy symlink \"") + fromPath +
"\" to \"" + toPath +
"\": " + strerror(errno));
788 for (
auto file : files)
790 string sourceFile = fromPath +
"/" + file->getRelativePath();
791 string targetFile = toPath +
"/" + file->getRelativePath();
804 lstat(path.c_str(), &s);
805 return s.st_mtimespec.tv_sec;
814 lstat(path.c_str(), &s);
817 gettimeofday(&t, NULL);
819 return t.tv_sec - s.st_atimespec.tv_sec;
836 bool shouldSearchRecursively)
844 DIR *d = opendir(dirPath.c_str());
847 if (access(dirPath.c_str(), F_OK) != -1)
848 throw VuoException(
string(
"Couldn't read directory: ") + strerror(errno) +
" — " + dirPath);
853 while( (de=readdir(d)) )
855 string fileName = de->d_name;
856 string relativeFilePath = dirPath +
"/" + fileName;
858 if (fileName ==
"." || fileName ==
"..")
861 bool isArchive =
false;
862 for (set<string>::iterator archiveExtension = archiveExtensions.begin(); archiveExtension != archiveExtensions.end(); ++archiveExtension)
872 files.insert(fs.begin(), fs.end());
877 bool shouldSearchDir = shouldSearchRecursively
883 for (set<File *>::iterator i = filesInDir.begin(); i != filesInDir.end(); ++i)
886 f->dirPath = dirPath;
887 f->filePath = fileName +
"/" + f->filePath;
889 files.insert(filesInDir.begin(), filesInDir.end());
893 File *f =
new File(dirPath, fileName);
916 set<File *> matchingFiles;
918 for (set<File *>::iterator i = allFiles.begin(); i != allFiles.end(); ++i)
920 bool endsWithExtension =
false;
921 for (set<string>::iterator extension = extensions.begin(); extension != extensions.end(); ++extension)
923 endsWithExtension =
true;
926 matchingFiles.insert(*i);
931 return matchingFiles;
951 mz_uint numFiles = mz_zip_reader_get_num_files(archive->
zipArchive);
952 for (mz_uint i = 0; i < numFiles; ++i)
954 mz_zip_archive_file_stat file_stat;
955 bool success = mz_zip_reader_file_stat(archive->
zipArchive, i, &file_stat);
958 VUserLog(
"Error: Couldn't read file '%u' in zip archive '%s'.", i, archive->
path.c_str());
962 File *f =
new File(archive, file_stat.m_filename);
984 set<File *> matchingFiles;
986 for (set<File *>::iterator i = allFiles.begin(); i != allFiles.end(); ++i)
990 string dir, file, ext;
994 bool endsWithExtension =
false;
995 for (set<string>::iterator extension = extensions.begin(); extension != extensions.end(); ++extension)
997 endsWithExtension =
true;
999 if (beginsWithDir && endsWithExtension)
1000 matchingFiles.insert(f);
1005 return matchingFiles;
1021 for (set<File *>::iterator i = archiveFiles.begin(); i != archiveFiles.end(); ++i)
1055 this->
zipArchive = (mz_zip_archive *)calloc(1,
sizeof(mz_zip_archive));
1057 bool success = mz_zip_reader_init_file(
zipArchive,
path.c_str(), 0);
1072 mz_zip_reader_end(zipArchive);
1093 this->fileDescriptor = -1;
1094 this->archive = NULL;
1106 this->fileDescriptor = -1;
1107 this->archive = archive;
1117 string newFilePath = basename() +
"." + extension;
1120 return File(archive, newFilePath);
1122 return File(dirPath, newFilePath);
1131 if (archive && --archive->referenceCount == 0)
1140 return (archive != NULL);
1150 return (archive ? archive->path :
"");
1169 throw VuoException(
"Can't return a simple absolute path for a file in an archive.");
1171 return dirPath +
"/" + filePath;
1182 throw VuoException(
"Can't return a simple absolute path for a file in an archive.");
1192 return filePath.substr(0, filePath.find_last_of(
'.'));
1200 return filePath.substr(filePath.find_last_of(
'.') + 1);
1209 return mz_zip_reader_locate_file(archive->zipArchive, filePath.c_str(),
nullptr, MZ_ZIP_FLAG_CASE_SENSITIVE) != -1;
1231 string fullPath = (dirPath.empty() ?
"" : (dirPath +
"/")) + filePath;
1233 FILE *pFile = fopen ( fullPath.c_str() ,
"rb" );
1235 throw VuoException(
string(
"Couldn't open file: ") + strerror(errno) +
" — " + fullPath);
1238 fseek (pFile , 0 , SEEK_END);
1239 size_t lSize = ftell (pFile);
1243 buffer = (
char*) malloc (
sizeof(
char)*lSize);
1246 numBytes = fread (buffer,1,lSize,pFile);
1248 if (numBytes != lSize)
1251 throw VuoException(
string(
"Couldn't read file: ") + strerror(errno) +
" — " + fullPath);
1256 buffer = (
char *)mz_zip_reader_extract_file_to_heap(archive->zipArchive, filePath.c_str(), &numBytes, 0);
1270 char *buffer = getContentsAsRawData(numBytes);
1271 string s(buffer, numBytes);
1287 if (fileDescriptor < 0)
1288 fileDescriptor = open((dirPath +
"/" + filePath).c_str(), O_RDONLY);
1289 int ret = flock(fileDescriptor, LOCK_SH | (nonBlocking ? LOCK_NB : 0));
1304 if (fileDescriptor < 0)
1305 fileDescriptor = open((dirPath +
"/" + filePath).c_str(), O_RDONLY);
1306 int ret = flock(fileDescriptor, LOCK_EX | (nonBlocking ? LOCK_NB : 0));
1316 flock(fileDescriptor, LOCK_UN);
1317 close(fileDescriptor);
1318 fileDescriptor = -1;
1339 string binaryDir, binaryFile, binaryExt;
1340 splitPath(processAndArgs[0], binaryDir, binaryFile, binaryExt);
1342 string errorPrefix =
"Couldn't execute " + binaryFile +
": ";
1346 int ret = pipe(outputPipe);
1348 throw VuoException(errorPrefix +
"couldn't open pipe: " + strerror(ret));
1349 int pipeRead = outputPipe[0];
1350 int pipeWrite = outputPipe[1];
1352 posix_spawn_file_actions_t fileActions;
1353 posix_spawn_file_actions_init(&fileActions);
1354 posix_spawn_file_actions_adddup2(&fileActions, pipeWrite, STDOUT_FILENO);
1355 posix_spawn_file_actions_adddup2(&fileActions, pipeWrite, STDERR_FILENO);
1356 posix_spawn_file_actions_addclose(&fileActions, pipeRead);
1360 char **processAndArgsZ = (
char **)malloc(
sizeof(
char *) * (processAndArgs.size() + 1));
1362 for (
auto arg : processAndArgs)
1364 processAndArgsZ[argCount++] = strdup(binaryFile.c_str());
1366 processAndArgsZ[argCount++] = strdup(arg.c_str());
1367 processAndArgsZ[argCount] =
nullptr;
1371 ret = posix_spawn(&pid, processAndArgs[0].c_str(), &fileActions, NULL, (
char *
const *)processAndArgsZ, NULL);
1373 posix_spawn_file_actions_destroy(&fileActions);
1374 for (
int i = 0; i < argCount; ++i)
1375 free(processAndArgsZ[i]);
1382 if (waitpid(pid, &status, 0) == -1)
1383 throw VuoException(errorPrefix +
"waitpid failed: " + strerror(errno));
1384 else if (status != 0)
1389 while (read(pipeRead, &buf, 255) > 0)
1405 return extension ==
"vuo";
1431 return extensions.find(extension) != extensions.end();
1442 e.insert(
"vuoshader");
1443 e.insert(
"vuoobjectfilter");
1444 return e.find(extension) != e.end();