| /* |
| * Copyright 2000-2014 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.util; |
| |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.util.SystemInfoRt; |
| import com.intellij.openapi.util.io.FileUtil; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.openapi.vfs.StandardFileSystems; |
| import com.intellij.openapi.vfs.VfsUtilCore; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.util.io.URLUtil; |
| import gnu.trove.TObjectHashingStrategy; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.util.Collection; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| public final class Urls { |
| private static final Logger LOG = Logger.getInstance(Urls.class); |
| |
| // about ";" see WEB-100359 |
| private static final Pattern URI_PATTERN = Pattern.compile("^([^:/?#]+):(//)?([^/?#]*)([^?#;]*)(.*)"); |
| |
| @NotNull |
| public static Url newUri(@NotNull String scheme, @NotNull String path) { |
| return new UrlImpl(scheme, null, path); |
| } |
| |
| @NotNull |
| public static Url newLocalFileUrl(@NotNull String path) { |
| return new LocalFileUrl(path); |
| } |
| |
| @NotNull |
| public static Url newLocalFileUrl(@NotNull VirtualFile file) { |
| return newLocalFileUrl(file.getPath()); |
| } |
| |
| @NotNull |
| public static Url newFromEncoded(@NotNull String url) { |
| Url result = parseEncoded(url); |
| LOG.assertTrue(result != null, url); |
| return result; |
| } |
| |
| @Nullable |
| public static Url parseEncoded(@NotNull String url) { |
| return parse(url, false); |
| } |
| |
| @NotNull |
| public static Url newHttpUrl(@NotNull String authority, @Nullable String path) { |
| return newUrl("http", authority, path); |
| } |
| |
| @NotNull |
| public static Url newUrl(@NotNull String scheme, @NotNull String authority, @Nullable String path) { |
| return new UrlImpl(scheme, authority, path); |
| } |
| |
| @NotNull |
| /** |
| * Url will not be normalized (see {@link VfsUtilCore#toIdeaUrl(String)}), parsed as is |
| */ |
| public static Url newFromIdea(@NotNull String url) { |
| Url result = parseFromIdea(url); |
| LOG.assertTrue(result != null, url); |
| return result; |
| } |
| |
| // java.net.URI.create cannot parse "file:///Test Stuff" - but you don't need to worry about it - this method is aware |
| @Nullable |
| public static Url parseFromIdea(@NotNull String url) { |
| return URLUtil.containsScheme(url) ? parseUrl(url) : newLocalFileUrl(url); |
| } |
| |
| @Nullable |
| public static Url parse(@NotNull String url, boolean asLocalIfNoScheme) { |
| if (url.isEmpty()) { |
| return null; |
| } |
| |
| if (asLocalIfNoScheme && !URLUtil.containsScheme(url)) { |
| // nodejs debug — files only in local filesystem |
| return newLocalFileUrl(url); |
| } |
| return parseUrl(VfsUtilCore.toIdeaUrl(url)); |
| } |
| |
| @Nullable |
| public static URI parseAsJavaUriWithoutParameters(@NotNull String url) { |
| Url asUrl = parseUrl(url); |
| if (asUrl == null) { |
| return null; |
| } |
| |
| try { |
| return toUriWithoutParameters(asUrl); |
| } |
| catch (Exception e) { |
| LOG.info("Cannot parse url " + url, e); |
| return null; |
| } |
| } |
| |
| @Nullable |
| private static Url parseUrl(@NotNull String url) { |
| String urlToParse; |
| if (url.startsWith("jar:file://")) { |
| urlToParse = url.substring("jar:".length()); |
| } |
| else { |
| urlToParse = url; |
| } |
| |
| Matcher matcher = URI_PATTERN.matcher(urlToParse); |
| if (!matcher.matches()) { |
| return null; |
| } |
| String scheme = matcher.group(1); |
| if (urlToParse != url) { |
| scheme = "jar:" + scheme; |
| } |
| |
| String authority = StringUtil.nullize(matcher.group(3)); |
| |
| String path = StringUtil.nullize(matcher.group(4)); |
| if (path != null) { |
| path = FileUtil.toCanonicalUriPath(path); |
| } |
| |
| if (authority != null && (StandardFileSystems.FILE_PROTOCOL.equals(scheme) || StringUtil.isEmpty(matcher.group(2)))) { |
| path = path == null ? authority : (authority + path); |
| authority = null; |
| } |
| return new UrlImpl(scheme, authority, path, matcher.group(5)); |
| } |
| |
| @NotNull |
| public static Url newFromVirtualFile(@NotNull VirtualFile file) { |
| if (file.isInLocalFileSystem()) { |
| return newUri(file.getFileSystem().getProtocol(), file.getPath()); |
| } |
| else { |
| Url url = parseUrl(file.getUrl()); |
| return url == null ? new UrlImpl(file.getPath()) : url; |
| } |
| } |
| |
| public static boolean equalsIgnoreParameters(@NotNull Url url, @NotNull Collection<Url> urls) { |
| return equalsIgnoreParameters(url, urls, true); |
| } |
| |
| public static boolean equalsIgnoreParameters(@NotNull Url url, @NotNull Collection<Url> urls, boolean caseSensitive) { |
| for (Url otherUrl : urls) { |
| if (equals(url, otherUrl, caseSensitive, true)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public static boolean equalsIgnoreParameters(@NotNull Url url, @NotNull VirtualFile file) { |
| if (file.isInLocalFileSystem()) { |
| return url.isInLocalFileSystem() && (SystemInfoRt.isFileSystemCaseSensitive |
| ? url.getPath().equals(file.getPath()) : |
| url.getPath().equalsIgnoreCase(file.getPath())); |
| } |
| else if (url.isInLocalFileSystem()) { |
| return false; |
| } |
| |
| Url fileUrl = parseUrl(file.getUrl()); |
| return fileUrl != null && fileUrl.equalsIgnoreParameters(url); |
| } |
| |
| public static boolean equals(@Nullable Url url1, @Nullable Url url2, boolean caseSensitive, boolean ignoreParameters) { |
| if (url1 == null || url2 == null){ |
| return url1 == url2; |
| } |
| |
| Url o1 = ignoreParameters ? url1.trimParameters() : url1; |
| Url o2 = ignoreParameters ? url2.trimParameters() : url2; |
| return caseSensitive ? o1.equals(o2) : o1.equalsIgnoreCase(o2); |
| } |
| |
| @NotNull |
| public static URI toUriWithoutParameters(@NotNull Url url) { |
| try { |
| String externalPath = url.getPath(); |
| boolean inLocalFileSystem = url.isInLocalFileSystem(); |
| if (inLocalFileSystem && SystemInfoRt.isWindows && externalPath.charAt(0) != '/') { |
| externalPath = '/' + externalPath; |
| } |
| return new URI(inLocalFileSystem ? "file" : url.getScheme(), inLocalFileSystem ? "" : url.getAuthority(), externalPath, null, null); |
| } |
| catch (URISyntaxException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static TObjectHashingStrategy<Url> getCaseInsensitiveUrlHashingStrategy() { |
| return CaseInsensitiveUrlHashingStrategy.INSTANCE; |
| } |
| |
| private static final class CaseInsensitiveUrlHashingStrategy implements TObjectHashingStrategy<Url> { |
| private static final TObjectHashingStrategy<Url> INSTANCE = new CaseInsensitiveUrlHashingStrategy(); |
| |
| @Override |
| public int computeHashCode(Url url) { |
| return url == null ? 0 : url.hashCodeCaseInsensitive(); |
| } |
| |
| @Override |
| public boolean equals(Url url1, Url url2) { |
| return Urls.equals(url1, url2, false, false); |
| } |
| } |
| } |