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 struct http_parser_url parsedUrl;
92 size_t urlLen = strlen(url);
93 if (http_parser_parse_url(url, urlLen,
false, &parsedUrl))
96 if (strncmp(url,
"data:", 5) == 0)
117 else if (strncmp(url,
"file:/", 6) == 0 && urlLen > 6 && url[6] !=
'/')
119 char *urlWithEmptyAuthority = malloc(urlLen + 2 + 1);
120 strcpy(urlWithEmptyAuthority,
"file://");
121 strcat(urlWithEmptyAuthority, url + 5);
122 if (http_parser_parse_url(urlWithEmptyAuthority, urlLen + 2,
false, &parsedUrl))
124 free(urlWithEmptyAuthority);
127 free(urlWithEmptyAuthority);
136 if (parsedUrl.field_set & (1 << UF_SCHEMA))
144 if (parsedUrl.field_set & (1 << UF_USERINFO))
152 if (parsedUrl.field_set & (1 << UF_HOST))
160 if (parsedUrl.field_set & (1 << UF_PORT))
162 *port = parsedUrl.port;
167 if (strcmp(*scheme,
"http") == 0)
169 else if (strcmp(*scheme,
"https") == 0)
176 if (parsedUrl.field_set & (1 << UF_PATH))
184 if (parsedUrl.field_set & (1 << UF_QUERY))
192 if (parsedUrl.field_set & (1 << UF_FRAGMENT))
193 *fragment =
VuoText_makeWithMaxLength(url + parsedUrl.field_data[UF_FRAGMENT].off, parsedUrl.field_data[UF_FRAGMENT].len);
223 if (separatorIndex < length)
226 fileAndExtension = NULL;
273 const char *urlWithSchemePattern =
"^[a-zA-Z][a-zA-Z0-9+-\\.]+:";
274 regex_t urlWithSchemeRegExp;
276 regmatch_t pmatch[0];
278 regcomp(&urlWithSchemeRegExp, urlWithSchemePattern, REG_EXTENDED);
279 bool matchFound = !regexec(&urlWithSchemeRegExp, url, nmatch, pmatch, 0);
280 regfree(&urlWithSchemeRegExp);
290 return ((strlen(url) >= 1) && (url[0] ==
'/'));
298 return ((strlen(url) >= 1) && (url[0] ==
'~'));
317 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
318 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
319 '"',
'$',
'&',
'+',
',',
':',
';',
'=',
'?',
'@',
'#',
' ',
330 unsigned long inLength = strlen(path);
331 unsigned long escapedLength = 0;
332 for (
unsigned long i = 0; i < inLength; ++i)
345 char *escapedUrl = (
char *)malloc(escapedLength + 1);
346 unsigned long outIndex = 0;
347 const char *hexCharSet =
"0123456789ABCDEF";
348 for (
unsigned long inIndex = 0; inIndex < inLength; ++inIndex)
350 unsigned char c = path[inIndex];
351 bool foundEscape =
false;
355 escapedUrl[outIndex++] =
'%';
356 escapedUrl[outIndex++] = hexCharSet[c >> 4];
357 escapedUrl[outIndex++] = hexCharSet[c & 0x0f];
365 if (inIndex+2 < inLength)
366 if (c == 0xea && (
unsigned char)path[inIndex+1] == 0x9e && (
unsigned char)path[inIndex+2] == 0x89)
368 escapedUrl[outIndex++] =
'%';
369 escapedUrl[outIndex++] = hexCharSet[
':' >> 4];
370 escapedUrl[outIndex++] = hexCharSet[
':' & 0x0f];
376 escapedUrl[outIndex++] = c;
378 escapedUrl[outIndex] = 0;
392 unsigned long inLength = strlen(url);
393 unsigned long escapedLength = 0;
394 for (
unsigned long i = 0; i < inLength; ++i)
396 if ((
unsigned char)url[i] > 0x7f)
402 char *escapedUrl = (
char *)malloc(escapedLength + 1);
403 unsigned long outIndex = 0;
404 const char *hexCharSet =
"0123456789ABCDEF";
405 for (
unsigned long inIndex = 0; inIndex < inLength; ++inIndex)
407 unsigned char c = url[inIndex];
410 escapedUrl[outIndex++] =
'%';
411 escapedUrl[outIndex++] = hexCharSet[c >> 4];
412 escapedUrl[outIndex++] = hexCharSet[c & 0x0f];
415 escapedUrl[outIndex++] = c;
417 escapedUrl[outIndex] = 0;
457 VuoText u = url + fileSchemeLength;
458 if (strncmp(u,
"//", 2) == 0)
474 size_t urlLen = strlen(trimmedUrl);
475 size_t spaceCount = 0;
476 for (
size_t i = 0; i < urlLen; ++i)
477 if (trimmedUrl[i] ==
' ')
481 resolvedUrl = (
char *)malloc(strlen(trimmedUrl) + spaceCount*2);
483 for (
size_t i = 0; i < urlLen; ++i)
484 if (trimmedUrl[i] ==
' ')
486 resolvedUrl[p++] =
'%';
487 resolvedUrl[p++] =
'2';
488 resolvedUrl[p++] =
'0';
491 resolvedUrl[p++] = trimmedUrl[i];
495 resolvedUrl = strdup(trimmedUrl);
501 char *filePath = (
char *)trimmedUrl;
508 if (access(filePath, 0) != 0)
510 char userTempDir[PATH_MAX];
511 size_t userTempDirLen;
512 if ((userTempDirLen = confstr(_CS_DARWIN_USER_TEMP_DIR, userTempDir, PATH_MAX)) > 0)
514 size_t filePathLen = strlen(filePath);
515 size_t mallocSize = userTempDirLen + filePathLen + 1;
516 char *privateFilePath = (
char *)malloc(mallocSize);
517 strlcpy(privateFilePath, userTempDir, mallocSize);
518 strlcat(privateFilePath, filePath + 4, mallocSize);
519 filePath = privateFilePath;
527 if (access(filePath, 0) != 0)
529 const char *systemPrefix =
"/System";
530 size_t systemPrefixLen = strlen(systemPrefix);
531 size_t filePathLen = strlen(filePath);
532 size_t mallocSize = systemPrefixLen + filePathLen + 1;
533 char *systemPath = (
char *)malloc(mallocSize);
534 strlcpy(systemPath, systemPrefix, mallocSize);
535 strlcat(systemPath, filePath, mallocSize);
536 if (access(systemPath, 0) == 0)
537 filePath = systemPath;
543 char *realPath = realpath(filePath, NULL);
549 if (filePath != trimmedUrl)
553 resolvedUrl = (
char *)malloc(mallocSize);
555 strlcat(resolvedUrl, escapedPath, mallocSize);
566 char *homeDir = getenv(
"HOME");
567 VuoText paths[2] = { homeDir, trimmedUrl+1 };
573 char *realPath = realpath(absolutePath, NULL);
582 resolvedUrl = (
char *)malloc(mallocSize);
584 strlcat(resolvedUrl, escapedPath, mallocSize);
592 resolvedUrl = (
char *)malloc(mallocSize);
594 strlcat(resolvedUrl, trimmedUrl, mallocSize);
605 bool compositionIsExportedAppOrPlugin =
false;
607 if (strcmp(currentWorkingDir,
"/") == 0
608 || strstr(currentWorkingDir,
"/Library/Containers/"))
615 char rawExecutablePath[PATH_MAX+1];
616 uint32_t size =
sizeof(rawExecutablePath);
617 _NSGetExecutablePath(rawExecutablePath, &size);
619 char cleanedExecutablePath[PATH_MAX+1];
620 realpath(rawExecutablePath, cleanedExecutablePath);
623 size_t pathSize = PATH_MAX + 1;
624 char executableDir[pathSize];
625 strlcpy(executableDir, dirname(cleanedExecutablePath), pathSize);
627 const char *resourcesPathFromExecutable =
"/../Resources";
628 pathSize = strlen(executableDir) + strlen(resourcesPathFromExecutable) + 1;
629 char rawResourcesPath[pathSize];
630 strlcpy(rawResourcesPath, executableDir, pathSize);
631 strlcat(rawResourcesPath, resourcesPathFromExecutable, pathSize);
633 char cleanedResourcesPath[PATH_MAX+1];
634 realpath(rawResourcesPath, cleanedResourcesPath);
638 if (access(cleanedResourcesPath, 0) == 0)
640 compositionIsExportedAppOrPlugin =
true;
644 char *homeDir = getenv(
"HOME");
645 const char *desktop =
"/Desktop/";
646 size_t mallocSize = strlen(homeDir) + strlen(desktop) + strlen(trimmedUrl) + 1;
647 absolutePath = (
char *)malloc(mallocSize);
648 strlcpy(absolutePath, homeDir, mallocSize);
649 strlcat(absolutePath, desktop, mallocSize);
650 strlcat(absolutePath, trimmedUrl, mallocSize);
654 size_t mallocSize = strlen(cleanedResourcesPath) + strlen(
"/") + strlen(trimmedUrl) + 1;
655 absolutePath = (
char *)malloc(mallocSize);
656 strlcpy(absolutePath, cleanedResourcesPath, mallocSize);
657 strlcat(absolutePath,
"/", mallocSize);
658 strlcat(absolutePath, trimmedUrl, mallocSize);
664 if (!compositionIsExportedAppOrPlugin)
666 size_t mallocSize = strlen(currentWorkingDir) + strlen(
"/") + strlen(trimmedUrl) + 1;
667 absolutePath = (
char *)malloc(mallocSize);
668 strlcpy(absolutePath, currentWorkingDir, mallocSize);
669 strlcat(absolutePath,
"/", mallocSize);
670 strlcat(absolutePath, trimmedUrl, mallocSize);
679 char *homeDir = getenv(
"HOME");
680 const char *applicationsPrefix =
"/Applications/";
681 size_t homeDirLen = strlen(homeDir);
682 size_t applicationsPrefixLen = strlen(applicationsPrefix);
683 size_t trimmedUrlLen = strlen(trimmedUrl);
684 size_t mallocSize = homeDirLen + applicationsPrefixLen + trimmedUrlLen + 1;
685 char *path = (
char *)malloc(mallocSize);
686 strlcpy(path, homeDir, mallocSize);
687 strlcat(path, applicationsPrefix, mallocSize);
688 strlcat(path, trimmedUrl, mallocSize);
689 if (access(path, 0) == 0)
700 const char *applicationsPrefix =
"/Applications/";
701 size_t applicationsPrefixLen = strlen(applicationsPrefix);
702 size_t trimmedUrlLen = strlen(trimmedUrl);
703 size_t mallocSize = applicationsPrefixLen + trimmedUrlLen + 1;
704 char *path = (
char *)malloc(mallocSize);
705 strlcpy(path, applicationsPrefix, mallocSize);
706 strlcat(path, trimmedUrl, mallocSize);
707 if (access(path, 0) == 0)
718 const char *applicationsPrefix =
"/System/Applications/";
719 size_t applicationsPrefixLen = strlen(applicationsPrefix);
720 size_t trimmedUrlLen = strlen(trimmedUrl);
721 size_t mallocSize = applicationsPrefixLen + trimmedUrlLen + 1;
722 char *path = (
char *)malloc(mallocSize);
723 strlcpy(path, applicationsPrefix, mallocSize);
724 strlcat(path, trimmedUrl, mallocSize);
725 if (access(path, 0) == 0)
736 char *realPath = realpath(absolutePath, NULL);
746 resolvedUrl = (
char *)malloc(mallocSize);
748 strlcat(resolvedUrl, escapedPath, mallocSize);
754 size_t lastIndex = strlen(resolvedUrl) - 1;
755 if (resolvedUrl[lastIndex] ==
'/')
756 resolvedUrl[lastIndex] = 0;
774 unsigned long inLength = strlen(url);
775 char *unescapedUrl = (
char *)malloc(inLength + 1);
776 unsigned long outIndex = 0;
777 for (
unsigned long inIndex = 0; inIndex < inLength; ++inIndex, ++outIndex)
779 char c = url[inIndex];
782 if (inIndex + 2 >= inLength)
784 char highNibbleASCII = url[++inIndex];
785 char lowNibbleASCII = url[++inIndex];
789 unescapedUrl[outIndex] = c;
791 unescapedUrl[outIndex] = 0;
795 return unescapedUrlVT;
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;
849 return unescapedUrlVT;
874 CFStringRef urlCFS = CFStringCreateWithCString(NULL, url, kCFStringEncodingUTF8);
875 CFURLRef cfurl = CFURLCreateWithString(NULL, urlCFS, NULL);
879 VUserLog(
"Error: Couldn't check '%s': Invalid URL.", url);
883 LSItemInfoRecord outItemInfo;
884 OSStatus ret = LSCopyItemInfoForURL(cfurl, kLSRequestAllFlags, &outItemInfo);
889 VUserLog(
"Error: Couldn't check '%s': %s", url, errorString);
893 return outItemInfo.flags & kLSItemInfoIsPackage;
901 char* fileSuffix = strrchr(filename,
'.');
902 char* curExtension = fileSuffix != NULL ? strdup(fileSuffix+1) : NULL;
904 if(curExtension != NULL)
905 for(
char *p = &curExtension[0]; *p; p++) *p = tolower(*p);
908 for (
int i = 0; i < json_object_array_length(validExtensions); ++i)
910 if (curExtension != NULL && strcmp(curExtension, json_object_get_string(json_object_array_get_idx(validExtensions, i))) == 0)
919 const char *chosenExtension = json_object_get_string(json_object_array_get_idx(validExtensions, 0));
920 size_t buf_size = strlen(filename) + strlen(chosenExtension) + 2;
921 char* newfilepath = (
char*)malloc(buf_size *
sizeof(
char));
922 snprintf(newfilepath, buf_size,
"%s.%s", filename, chosenExtension);