15#include <mach-o/dyld.h>
17#include <CoreServices/CoreServices.h>
18#include "VuoUrlParser.h"
25 "description" :
"Uniform Resource Locator.",
26 "keywords" : [
"link" ],
29 "CoreServices.framework",
44 const char *textString =
"";
45 if (json_object_get_type(js) == json_type_string)
46 textString = json_object_get_string(js);
50 url = strdup(textString);
64 return json_object_new_string(
"");
66 return json_object_new_string(value);
76 char *summary = strdup(t);
91 const char *localURL = url;
92 char *urlWithEmptyAuthority = NULL;
93 struct http_parser_url parsedUrl;
94 size_t urlLen = strlen(url);
95 if (http_parser_parse_url(url, urlLen,
false, &parsedUrl))
98 if (strncmp(url,
"data:", 5) == 0)
119 else if (strncmp(url,
"file:/", 6) == 0 && urlLen > 6 && url[6] !=
'/')
121 urlWithEmptyAuthority = malloc(urlLen + 2 + 1);
122 strcpy(urlWithEmptyAuthority,
"file://");
123 strcat(urlWithEmptyAuthority, url + 5);
124 if (http_parser_parse_url(urlWithEmptyAuthority, urlLen + 2,
false, &parsedUrl))
126 free(urlWithEmptyAuthority);
129 localURL = urlWithEmptyAuthority;
138 if (parsedUrl.field_set & (1 << UF_SCHEMA))
139 *scheme =
VuoText_makeWithMaxLength(localURL + parsedUrl.field_data[UF_SCHEMA ].off, parsedUrl.field_data[UF_SCHEMA ].len);
146 if (parsedUrl.field_set & (1 << UF_USERINFO))
147 *user =
VuoText_makeWithMaxLength(localURL + parsedUrl.field_data[UF_USERINFO].off, parsedUrl.field_data[UF_USERINFO].len);
154 if (parsedUrl.field_set & (1 << UF_HOST))
162 if (parsedUrl.field_set & (1 << UF_PORT))
164 *port = parsedUrl.port;
169 if (strcmp(*scheme,
"http") == 0)
171 else if (strcmp(*scheme,
"https") == 0)
178 if (parsedUrl.field_set & (1 << UF_PATH))
186 if (parsedUrl.field_set & (1 << UF_QUERY))
194 if (parsedUrl.field_set & (1 << UF_FRAGMENT))
195 *fragment =
VuoText_makeWithMaxLength(localURL + parsedUrl.field_data[UF_FRAGMENT].off, parsedUrl.field_data[UF_FRAGMENT].len);
200 if (urlWithEmptyAuthority)
201 free(urlWithEmptyAuthority);
228 if (separatorIndex < length)
231 fileAndExtension = NULL;
278 const char *urlWithSchemePattern =
"^[a-zA-Z][a-zA-Z0-9+-\\.]+:";
279 regex_t urlWithSchemeRegExp;
281 regmatch_t pmatch[0];
283 regcomp(&urlWithSchemeRegExp, urlWithSchemePattern, REG_EXTENDED);
284 bool matchFound = !regexec(&urlWithSchemeRegExp, url, nmatch, pmatch, 0);
285 regfree(&urlWithSchemeRegExp);
295 return ((strlen(url) >= 1) && (url[0] ==
'/'));
303 return ((strlen(url) >= 1) && (url[0] ==
'~'));
322 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
323 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
324 '"',
'$',
'&',
'+',
',',
':',
';',
'=',
'?',
'@',
'#',
' ',
335 unsigned long inLength = strlen(path);
336 unsigned long escapedLength = 0;
337 for (
unsigned long i = 0; i < inLength; ++i)
350 char *escapedUrl = (
char *)malloc(escapedLength + 1);
351 unsigned long outIndex = 0;
352 const char *hexCharSet =
"0123456789ABCDEF";
353 for (
unsigned long inIndex = 0; inIndex < inLength; ++inIndex)
355 unsigned char c = path[inIndex];
356 bool foundEscape =
false;
360 escapedUrl[outIndex++] =
'%';
361 escapedUrl[outIndex++] = hexCharSet[c >> 4];
362 escapedUrl[outIndex++] = hexCharSet[c & 0x0f];
370 if (inIndex+2 < inLength)
371 if (c == 0xea && (
unsigned char)path[inIndex+1] == 0x9e && (
unsigned char)path[inIndex+2] == 0x89)
373 escapedUrl[outIndex++] =
'%';
374 escapedUrl[outIndex++] = hexCharSet[
':' >> 4];
375 escapedUrl[outIndex++] = hexCharSet[
':' & 0x0f];
381 escapedUrl[outIndex++] = c;
383 escapedUrl[outIndex] = 0;
397 unsigned long inLength = strlen(url);
398 unsigned long escapedLength = 0;
399 for (
unsigned long i = 0; i < inLength; ++i)
401 if ((
unsigned char)url[i] > 0x7f)
407 char *escapedUrl = (
char *)malloc(escapedLength + 1);
408 unsigned long outIndex = 0;
409 const char *hexCharSet =
"0123456789ABCDEF";
410 for (
unsigned long inIndex = 0; inIndex < inLength; ++inIndex)
412 unsigned char c = url[inIndex];
415 escapedUrl[outIndex++] =
'%';
416 escapedUrl[outIndex++] = hexCharSet[c >> 4];
417 escapedUrl[outIndex++] = hexCharSet[c & 0x0f];
420 escapedUrl[outIndex++] = c;
422 escapedUrl[outIndex] = 0;
462 VuoText u = url + fileSchemeLength;
463 if (strncmp(u,
"//", 2) == 0)
479 size_t urlLen = strlen(trimmedUrl);
480 size_t spaceCount = 0;
481 for (
size_t i = 0; i < urlLen; ++i)
482 if (trimmedUrl[i] ==
' ')
486 resolvedUrl = (
char *)malloc(strlen(trimmedUrl) + spaceCount*2);
488 for (
size_t i = 0; i < urlLen; ++i)
489 if (trimmedUrl[i] ==
' ')
491 resolvedUrl[p++] =
'%';
492 resolvedUrl[p++] =
'2';
493 resolvedUrl[p++] =
'0';
496 resolvedUrl[p++] = trimmedUrl[i];
500 resolvedUrl = strdup(trimmedUrl);
506 char *filePath = (
char *)trimmedUrl;
513 if (access(filePath, 0) != 0)
515 char userTempDir[PATH_MAX];
516 size_t userTempDirLen;
517 if ((userTempDirLen = confstr(_CS_DARWIN_USER_TEMP_DIR, userTempDir, PATH_MAX)) > 0)
519 size_t filePathLen = strlen(filePath);
520 size_t mallocSize = userTempDirLen + filePathLen + 1;
521 char *privateFilePath = (
char *)malloc(mallocSize);
522 strlcpy(privateFilePath, userTempDir, mallocSize);
523 strlcat(privateFilePath, filePath + 4, mallocSize);
524 filePath = privateFilePath;
532 if (access(filePath, 0) != 0)
534 const char *systemPrefix =
"/System";
535 size_t systemPrefixLen = strlen(systemPrefix);
536 size_t filePathLen = strlen(filePath);
537 size_t mallocSize = systemPrefixLen + filePathLen + 1;
538 char *systemPath = (
char *)malloc(mallocSize);
539 strlcpy(systemPath, systemPrefix, mallocSize);
540 strlcat(systemPath, filePath, mallocSize);
541 if (access(systemPath, 0) == 0)
542 filePath = systemPath;
548 char *realPath = realpath(filePath, NULL);
554 if (filePath != trimmedUrl)
558 resolvedUrl = (
char *)malloc(mallocSize);
560 strlcat(resolvedUrl, escapedPath, mallocSize);
571 char *homeDir = getenv(
"HOME");
572 VuoText paths[2] = { homeDir, trimmedUrl+1 };
578 char *realPath = realpath(absolutePath, NULL);
587 resolvedUrl = (
char *)malloc(mallocSize);
589 strlcat(resolvedUrl, escapedPath, mallocSize);
597 resolvedUrl = (
char *)malloc(mallocSize);
599 strlcat(resolvedUrl, trimmedUrl, mallocSize);
610 bool compositionIsExportedAppOrPlugin =
false;
612 if (strcmp(currentWorkingDir,
"/") == 0
613 || strstr(currentWorkingDir,
"/Library/Containers/"))
620 char rawExecutablePath[PATH_MAX+1];
621 uint32_t size =
sizeof(rawExecutablePath);
622 _NSGetExecutablePath(rawExecutablePath, &size);
624 char cleanedExecutablePath[PATH_MAX+1];
625 realpath(rawExecutablePath, cleanedExecutablePath);
628 size_t pathSize = PATH_MAX + 1;
629 char executableDir[pathSize];
630 strlcpy(executableDir, dirname(cleanedExecutablePath), pathSize);
632 const char *resourcesPathFromExecutable =
"/../Resources";
633 pathSize = strlen(executableDir) + strlen(resourcesPathFromExecutable) + 1;
634 char rawResourcesPath[pathSize];
635 strlcpy(rawResourcesPath, executableDir, pathSize);
636 strlcat(rawResourcesPath, resourcesPathFromExecutable, pathSize);
638 char cleanedResourcesPath[PATH_MAX+1];
639 realpath(rawResourcesPath, cleanedResourcesPath);
643 if (access(cleanedResourcesPath, 0) == 0)
647 char *homeDir = getenv(
"HOME");
650 const char *desktop =
"/Desktop/";
651 size_t mallocSize = strlen(homeDir) + strlen(desktop) + strlen(trimmedUrl) + 1;
652 absolutePath = (
char *)malloc(mallocSize);
653 strlcpy(absolutePath, homeDir, mallocSize);
654 strlcat(absolutePath, desktop, mallocSize);
655 strlcat(absolutePath, trimmedUrl, mallocSize);
656 compositionIsExportedAppOrPlugin =
true;
661 size_t mallocSize = strlen(cleanedResourcesPath) + strlen(
"/") + strlen(trimmedUrl) + 1;
662 absolutePath = (
char *)malloc(mallocSize);
663 strlcpy(absolutePath, cleanedResourcesPath, mallocSize);
664 strlcat(absolutePath,
"/", mallocSize);
665 strlcat(absolutePath, trimmedUrl, mallocSize);
666 compositionIsExportedAppOrPlugin =
true;
672 if (!compositionIsExportedAppOrPlugin)
674 size_t mallocSize = strlen(currentWorkingDir) + strlen(
"/") + strlen(trimmedUrl) + 1;
675 absolutePath = (
char *)malloc(mallocSize);
676 strlcpy(absolutePath, currentWorkingDir, mallocSize);
677 strlcat(absolutePath,
"/", mallocSize);
678 strlcat(absolutePath, trimmedUrl, mallocSize);
686 char *homeDir = getenv(
"HOME");
689 const char *applicationsPrefix =
"/Applications/";
690 size_t homeDirLen = strlen(homeDir);
691 size_t applicationsPrefixLen = strlen(applicationsPrefix);
692 size_t trimmedUrlLen = strlen(trimmedUrl);
693 size_t mallocSize = homeDirLen + applicationsPrefixLen + trimmedUrlLen + 1;
694 char *path = (
char *)malloc(mallocSize);
695 strlcpy(path, homeDir, mallocSize);
696 strlcat(path, applicationsPrefix, mallocSize);
697 strlcat(path, trimmedUrl, mallocSize);
698 if (access(path, 0) == 0)
709 const char *applicationsPrefix =
"/Applications/";
710 size_t applicationsPrefixLen = strlen(applicationsPrefix);
711 size_t trimmedUrlLen = strlen(trimmedUrl);
712 size_t mallocSize = applicationsPrefixLen + trimmedUrlLen + 1;
713 char *path = (
char *)malloc(mallocSize);
714 strlcpy(path, applicationsPrefix, mallocSize);
715 strlcat(path, trimmedUrl, mallocSize);
716 if (access(path, 0) == 0)
727 const char *applicationsPrefix =
"/System/Applications/";
728 size_t applicationsPrefixLen = strlen(applicationsPrefix);
729 size_t trimmedUrlLen = strlen(trimmedUrl);
730 size_t mallocSize = applicationsPrefixLen + trimmedUrlLen + 1;
731 char *path = (
char *)malloc(mallocSize);
732 strlcpy(path, applicationsPrefix, mallocSize);
733 strlcat(path, trimmedUrl, mallocSize);
734 if (access(path, 0) == 0)
745 char *realPath = realpath(absolutePath, NULL);
755 resolvedUrl = (
char *)malloc(mallocSize);
757 strlcat(resolvedUrl, escapedPath, mallocSize);
763 size_t lastIndex = strlen(resolvedUrl) - 1;
764 if (resolvedUrl[lastIndex] ==
'/')
765 resolvedUrl[lastIndex] = 0;
783 unsigned long inLength = strlen(url);
784 char *unescapedUrl = (
char *)malloc(inLength + 1);
785 unsigned long outIndex = 0;
786 for (
unsigned long inIndex = 0; inIndex < inLength; ++inIndex, ++outIndex)
788 char c = url[inIndex];
791 if (inIndex + 2 >= inLength)
793 char highNibbleASCII = url[++inIndex];
794 char lowNibbleASCII = url[++inIndex];
798 unescapedUrl[outIndex] = c;
800 unescapedUrl[outIndex] = 0;
804 return unescapedUrlVT;
822 if (strncmp(url + fileSchemeLength,
"//", 2) == 0)
823 fileSchemeLength += 2;
826 unsigned long inLength = strlen(url);
828 char *unescapedUrl = (
char *)malloc(inLength*3 + 1);
829 unsigned long outIndex = 0;
830 for (
unsigned long inIndex = fileSchemeLength; inIndex < inLength; ++inIndex, ++outIndex)
832 char c = url[inIndex];
835 char highNibbleASCII = url[++inIndex];
836 char lowNibbleASCII = url[++inIndex];
840 unescapedUrl[outIndex] = c;
846 if (unescapedUrl[outIndex] ==
':')
848 unescapedUrl[outIndex++] = 0xea;
849 unescapedUrl[outIndex++] = 0x9e;
850 unescapedUrl[outIndex] = 0x89;
853 unescapedUrl[outIndex] = 0;
858 return unescapedUrlVT;
883 CFStringRef urlCFS = CFStringCreateWithCString(NULL, url, kCFStringEncodingUTF8);
884 CFURLRef cfurl = CFURLCreateWithString(NULL, urlCFS, NULL);
888 VUserLog(
"Error: Couldn't check '%s': Invalid URL.", url);
892 CFTypeRef info = NULL;
893 CFErrorRef error = NULL;
894 bool ret = CFURLCopyResourcePropertyForKey(cfurl, kCFURLIsPackageKey, &info, &error);
898 CFStringRef errorCFS = CFErrorCopyDescription(error);
903 VUserLog(
"Error: Couldn't check '%s': %s", url, errorText);
907 return info == kCFBooleanTrue;
915 char* fileSuffix = strrchr(filename,
'.');
916 char* curExtension = fileSuffix != NULL ? strdup(fileSuffix+1) : NULL;
918 if(curExtension != NULL)
919 for(
char *p = &curExtension[0]; *p; p++) *p = tolower(*p);
922 for (
int i = 0; i < json_object_array_length(validExtensions); ++i)
924 if (curExtension != NULL && strcmp(curExtension, json_object_get_string(json_object_array_get_idx(validExtensions, i))) == 0)
933 const char *chosenExtension = json_object_get_string(json_object_array_get_idx(validExtensions, 0));
934 size_t buf_size = strlen(filename) + strlen(chosenExtension) + 2;
935 char* newfilepath = (
char*)malloc(buf_size *
sizeof(
char));
936 snprintf(newfilepath, buf_size,
"%s.%s", filename, chosenExtension);