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;
394 unsigned long inLength = strlen(url);
395 unsigned long escapedLength = 0;
396 for (
unsigned long i = 0; i < inLength; ++i)
398 if ((
unsigned char)url[i] > 0x7f)
404 char *escapedUrl = (
char *)malloc(escapedLength + 1);
405 unsigned long outIndex = 0;
406 const char *hexCharSet =
"0123456789ABCDEF";
407 for (
unsigned long inIndex = 0; inIndex < inLength; ++inIndex)
409 unsigned char c = url[inIndex];
412 escapedUrl[outIndex++] =
'%';
413 escapedUrl[outIndex++] = hexCharSet[c >> 4];
414 escapedUrl[outIndex++] = hexCharSet[c & 0x0f];
417 escapedUrl[outIndex++] = c;
419 escapedUrl[outIndex] = 0;
456 VuoText u = url + fileSchemeLength;
457 if (strncmp(u,
"//", 2) == 0)
473 size_t urlLen = strlen(trimmedUrl);
474 size_t spaceCount = 0;
475 for (
size_t i = 0; i < urlLen; ++i)
476 if (trimmedUrl[i] ==
' ')
480 resolvedUrl = (
char *)malloc(strlen(trimmedUrl) + spaceCount*2);
482 for (
size_t i = 0; i < urlLen; ++i)
483 if (trimmedUrl[i] ==
' ')
485 resolvedUrl[p++] =
'%';
486 resolvedUrl[p++] =
'2';
487 resolvedUrl[p++] =
'0';
490 resolvedUrl[p++] = trimmedUrl[i];
494 resolvedUrl = strdup(trimmedUrl);
500 char *filePath = (
char *)trimmedUrl;
507 if (access(filePath, 0) != 0)
509 char userTempDir[PATH_MAX];
510 size_t userTempDirLen;
511 if ((userTempDirLen = confstr(_CS_DARWIN_USER_TEMP_DIR, userTempDir, PATH_MAX)) > 0)
513 size_t filePathLen = strlen(filePath);
514 size_t mallocSize = userTempDirLen + filePathLen + 1;
515 char *privateFilePath = (
char *)malloc(mallocSize);
516 strlcpy(privateFilePath, userTempDir, mallocSize);
517 strlcat(privateFilePath, filePath + 4, mallocSize);
518 filePath = privateFilePath;
526 if (access(filePath, 0) != 0)
528 const char *systemPrefix =
"/System";
529 size_t systemPrefixLen = strlen(systemPrefix);
530 size_t filePathLen = strlen(filePath);
531 size_t mallocSize = systemPrefixLen + filePathLen + 1;
532 char *systemPath = (
char *)malloc(mallocSize);
533 strlcpy(systemPath, systemPrefix, mallocSize);
534 strlcat(systemPath, filePath, mallocSize);
535 if (access(systemPath, 0) == 0)
536 filePath = systemPath;
542 char *realPath = realpath(filePath, NULL);
548 if (filePath != trimmedUrl)
552 resolvedUrl = (
char *)malloc(mallocSize);
554 strlcat(resolvedUrl, escapedPath, mallocSize);
565 char *homeDir = getenv(
"HOME");
566 VuoText paths[2] = { homeDir, trimmedUrl+1 };
572 char *realPath = realpath(absolutePath, NULL);
581 resolvedUrl = (
char *)malloc(mallocSize);
583 strlcat(resolvedUrl, escapedPath, mallocSize);
591 resolvedUrl = (
char *)malloc(mallocSize);
593 strlcat(resolvedUrl, trimmedUrl, mallocSize);
604 bool compositionIsExportedAppOrPlugin =
false;
606 if (strcmp(currentWorkingDir,
"/") == 0
607 || strstr(currentWorkingDir,
"/Library/Containers/"))
614 char rawExecutablePath[PATH_MAX+1];
615 uint32_t size =
sizeof(rawExecutablePath);
616 _NSGetExecutablePath(rawExecutablePath, &size);
618 char cleanedExecutablePath[PATH_MAX+1];
619 realpath(rawExecutablePath, cleanedExecutablePath);
622 size_t pathSize = PATH_MAX + 1;
623 char executableDir[pathSize];
624 strlcpy(executableDir, dirname(cleanedExecutablePath), pathSize);
626 const char *resourcesPathFromExecutable =
"/../Resources";
627 pathSize = strlen(executableDir) + strlen(resourcesPathFromExecutable) + 1;
628 char rawResourcesPath[pathSize];
629 strlcpy(rawResourcesPath, executableDir, pathSize);
630 strlcat(rawResourcesPath, resourcesPathFromExecutable, pathSize);
632 char cleanedResourcesPath[PATH_MAX+1];
633 realpath(rawResourcesPath, cleanedResourcesPath);
637 if (access(cleanedResourcesPath, 0) == 0)
641 char *homeDir = getenv(
"HOME");
644 const char *desktop =
"/Desktop/";
645 size_t mallocSize = strlen(homeDir) + strlen(desktop) + strlen(trimmedUrl) + 1;
646 absolutePath = (
char *)malloc(mallocSize);
647 strlcpy(absolutePath, homeDir, mallocSize);
648 strlcat(absolutePath, desktop, mallocSize);
649 strlcat(absolutePath, trimmedUrl, mallocSize);
650 compositionIsExportedAppOrPlugin =
true;
655 size_t mallocSize = strlen(cleanedResourcesPath) + strlen(
"/") + strlen(trimmedUrl) + 1;
656 absolutePath = (
char *)malloc(mallocSize);
657 strlcpy(absolutePath, cleanedResourcesPath, mallocSize);
658 strlcat(absolutePath,
"/", mallocSize);
659 strlcat(absolutePath, trimmedUrl, mallocSize);
660 compositionIsExportedAppOrPlugin =
true;
666 if (!compositionIsExportedAppOrPlugin)
668 size_t mallocSize = strlen(currentWorkingDir) + strlen(
"/") + strlen(trimmedUrl) + 1;
669 absolutePath = (
char *)malloc(mallocSize);
670 strlcpy(absolutePath, currentWorkingDir, mallocSize);
671 strlcat(absolutePath,
"/", mallocSize);
672 strlcat(absolutePath, trimmedUrl, mallocSize);
680 char *homeDir = getenv(
"HOME");
683 const char *applicationsPrefix =
"/Applications/";
684 size_t homeDirLen = strlen(homeDir);
685 size_t applicationsPrefixLen = strlen(applicationsPrefix);
686 size_t trimmedUrlLen = strlen(trimmedUrl);
687 size_t mallocSize = homeDirLen + applicationsPrefixLen + trimmedUrlLen + 1;
688 char *path = (
char *)malloc(mallocSize);
689 strlcpy(path, homeDir, mallocSize);
690 strlcat(path, applicationsPrefix, mallocSize);
691 strlcat(path, trimmedUrl, mallocSize);
692 if (access(path, 0) == 0)
703 const char *applicationsPrefix =
"/Applications/";
704 size_t applicationsPrefixLen = strlen(applicationsPrefix);
705 size_t trimmedUrlLen = strlen(trimmedUrl);
706 size_t mallocSize = applicationsPrefixLen + trimmedUrlLen + 1;
707 char *path = (
char *)malloc(mallocSize);
708 strlcpy(path, applicationsPrefix, mallocSize);
709 strlcat(path, trimmedUrl, mallocSize);
710 if (access(path, 0) == 0)
721 const char *applicationsPrefix =
"/System/Applications/";
722 size_t applicationsPrefixLen = strlen(applicationsPrefix);
723 size_t trimmedUrlLen = strlen(trimmedUrl);
724 size_t mallocSize = applicationsPrefixLen + trimmedUrlLen + 1;
725 char *path = (
char *)malloc(mallocSize);
726 strlcpy(path, applicationsPrefix, mallocSize);
727 strlcat(path, trimmedUrl, mallocSize);
728 if (access(path, 0) == 0)
739 char *realPath = realpath(absolutePath, NULL);
749 resolvedUrl = (
char *)malloc(mallocSize);
751 strlcat(resolvedUrl, escapedPath, mallocSize);
757 size_t lastIndex = strlen(resolvedUrl) - 1;
758 if (resolvedUrl[lastIndex] ==
'/')
759 resolvedUrl[lastIndex] = 0;
776 unsigned long inLength = strlen(url);
777 char *unescapedUrl = (
char *)malloc(inLength + 1);
778 unsigned long outIndex = 0;
779 for (
unsigned long inIndex = 0; inIndex < inLength; ++inIndex, ++outIndex)
781 char c = url[inIndex];
784 if (inIndex + 2 >= inLength)
786 char highNibbleASCII = url[++inIndex];
787 char lowNibbleASCII = url[++inIndex];
791 unescapedUrl[outIndex] = c;
793 unescapedUrl[outIndex] = 0;
813 if (strncmp(url + fileSchemeLength,
"//", 2) == 0)
814 fileSchemeLength += 2;
817 unsigned long inLength = strlen(url);
819 char *unescapedUrl = (
char *)malloc(inLength*3 + 1);
820 unsigned long outIndex = 0;
821 for (
unsigned long inIndex = fileSchemeLength; inIndex < inLength; ++inIndex, ++outIndex)
823 char c = url[inIndex];
826 char highNibbleASCII = url[++inIndex];
827 char lowNibbleASCII = url[++inIndex];
831 unescapedUrl[outIndex] = c;
837 if (unescapedUrl[outIndex] ==
':')
839 unescapedUrl[outIndex++] = 0xea;
840 unescapedUrl[outIndex++] = 0x9e;
841 unescapedUrl[outIndex] = 0x89;
844 unescapedUrl[outIndex] = 0;
871 CFStringRef urlCFS = CFStringCreateWithCString(NULL, url, kCFStringEncodingUTF8);
872 CFURLRef cfurl = CFURLCreateWithString(NULL, urlCFS, NULL);
876 VUserLog(
"Error: Couldn't check '%s': Invalid URL.", url);
880 CFTypeRef info = NULL;
881 CFErrorRef error = NULL;
882 bool ret = CFURLCopyResourcePropertyForKey(cfurl, kCFURLIsPackageKey, &info, &error);
886 CFStringRef errorCFS = CFErrorCopyDescription(error);
891 VUserLog(
"Error: Couldn't check '%s': %s", url, errorText);
895 return info == kCFBooleanTrue;
903 char* fileSuffix = strrchr(filename,
'.');
904 char* curExtension = fileSuffix != NULL ? strdup(fileSuffix+1) : NULL;
906 if(curExtension != NULL)
907 for(
char *p = &curExtension[0]; *p; p++) *p = tolower(*p);
910 for (
int i = 0; i < json_object_array_length(validExtensions); ++i)
912 if (curExtension != NULL && strcmp(curExtension, json_object_get_string(json_object_array_get_idx(validExtensions, i))) == 0)
921 const char *chosenExtension = json_object_get_string(json_object_array_get_idx(validExtensions, 0));
922 size_t buf_size = strlen(filename) + strlen(chosenExtension) + 2;
923 char* newfilepath = (
char*)malloc(buf_size *
sizeof(
char));
924 snprintf(newfilepath, buf_size,
"%s.%s", filename, chosenExtension);