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)
645 compositionIsExportedAppOrPlugin =
true;
649 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);
659 size_t mallocSize = strlen(cleanedResourcesPath) + strlen(
"/") + strlen(trimmedUrl) + 1;
660 absolutePath = (
char *)malloc(mallocSize);
661 strlcpy(absolutePath, cleanedResourcesPath, mallocSize);
662 strlcat(absolutePath,
"/", mallocSize);
663 strlcat(absolutePath, trimmedUrl, mallocSize);
669 if (!compositionIsExportedAppOrPlugin)
671 size_t mallocSize = strlen(currentWorkingDir) + strlen(
"/") + strlen(trimmedUrl) + 1;
672 absolutePath = (
char *)malloc(mallocSize);
673 strlcpy(absolutePath, currentWorkingDir, mallocSize);
674 strlcat(absolutePath,
"/", mallocSize);
675 strlcat(absolutePath, trimmedUrl, mallocSize);
684 char *homeDir = getenv(
"HOME");
685 const char *applicationsPrefix =
"/Applications/";
686 size_t homeDirLen = strlen(homeDir);
687 size_t applicationsPrefixLen = strlen(applicationsPrefix);
688 size_t trimmedUrlLen = strlen(trimmedUrl);
689 size_t mallocSize = homeDirLen + applicationsPrefixLen + trimmedUrlLen + 1;
690 char *path = (
char *)malloc(mallocSize);
691 strlcpy(path, homeDir, mallocSize);
692 strlcat(path, applicationsPrefix, mallocSize);
693 strlcat(path, trimmedUrl, mallocSize);
694 if (access(path, 0) == 0)
705 const char *applicationsPrefix =
"/Applications/";
706 size_t applicationsPrefixLen = strlen(applicationsPrefix);
707 size_t trimmedUrlLen = strlen(trimmedUrl);
708 size_t mallocSize = applicationsPrefixLen + trimmedUrlLen + 1;
709 char *path = (
char *)malloc(mallocSize);
710 strlcpy(path, applicationsPrefix, mallocSize);
711 strlcat(path, trimmedUrl, mallocSize);
712 if (access(path, 0) == 0)
723 const char *applicationsPrefix =
"/System/Applications/";
724 size_t applicationsPrefixLen = strlen(applicationsPrefix);
725 size_t trimmedUrlLen = strlen(trimmedUrl);
726 size_t mallocSize = applicationsPrefixLen + trimmedUrlLen + 1;
727 char *path = (
char *)malloc(mallocSize);
728 strlcpy(path, applicationsPrefix, mallocSize);
729 strlcat(path, trimmedUrl, mallocSize);
730 if (access(path, 0) == 0)
741 char *realPath = realpath(absolutePath, NULL);
751 resolvedUrl = (
char *)malloc(mallocSize);
753 strlcat(resolvedUrl, escapedPath, mallocSize);
759 size_t lastIndex = strlen(resolvedUrl) - 1;
760 if (resolvedUrl[lastIndex] ==
'/')
761 resolvedUrl[lastIndex] = 0;
779 unsigned long inLength = strlen(url);
780 char *unescapedUrl = (
char *)malloc(inLength + 1);
781 unsigned long outIndex = 0;
782 for (
unsigned long inIndex = 0; inIndex < inLength; ++inIndex, ++outIndex)
784 char c = url[inIndex];
787 if (inIndex + 2 >= inLength)
789 char highNibbleASCII = url[++inIndex];
790 char lowNibbleASCII = url[++inIndex];
794 unescapedUrl[outIndex] = c;
796 unescapedUrl[outIndex] = 0;
800 return unescapedUrlVT;
818 if (strncmp(url + fileSchemeLength,
"//", 2) == 0)
819 fileSchemeLength += 2;
822 unsigned long inLength = strlen(url);
824 char *unescapedUrl = (
char *)malloc(inLength*3 + 1);
825 unsigned long outIndex = 0;
826 for (
unsigned long inIndex = fileSchemeLength; inIndex < inLength; ++inIndex, ++outIndex)
828 char c = url[inIndex];
831 char highNibbleASCII = url[++inIndex];
832 char lowNibbleASCII = url[++inIndex];
836 unescapedUrl[outIndex] = c;
842 if (unescapedUrl[outIndex] ==
':')
844 unescapedUrl[outIndex++] = 0xea;
845 unescapedUrl[outIndex++] = 0x9e;
846 unescapedUrl[outIndex] = 0x89;
849 unescapedUrl[outIndex] = 0;
854 return unescapedUrlVT;
879 CFStringRef urlCFS = CFStringCreateWithCString(NULL, url, kCFStringEncodingUTF8);
880 CFURLRef cfurl = CFURLCreateWithString(NULL, urlCFS, NULL);
884 VUserLog(
"Error: Couldn't check '%s': Invalid URL.", url);
888 CFTypeRef info = NULL;
889 CFErrorRef error = NULL;
890 bool ret = CFURLCopyResourcePropertyForKey(cfurl, kCFURLIsPackageKey, &info, &error);
894 CFStringRef errorCFS = CFErrorCopyDescription(error);
899 VUserLog(
"Error: Couldn't check '%s': %s", url, errorText);
903 return info == kCFBooleanTrue;
911 char* fileSuffix = strrchr(filename,
'.');
912 char* curExtension = fileSuffix != NULL ? strdup(fileSuffix+1) : NULL;
914 if(curExtension != NULL)
915 for(
char *p = &curExtension[0]; *p; p++) *p = tolower(*p);
918 for (
int i = 0; i < json_object_array_length(validExtensions); ++i)
920 if (curExtension != NULL && strcmp(curExtension, json_object_get_string(json_object_array_get_idx(validExtensions, i))) == 0)
929 const char *chosenExtension = json_object_get_string(json_object_array_get_idx(validExtensions, 0));
930 size_t buf_size = strlen(filename) + strlen(chosenExtension) + 2;
931 char* newfilepath = (
char*)malloc(buf_size *
sizeof(
char));
932 snprintf(newfilepath, buf_size,
"%s.%s", filename, chosenExtension);