All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.intellij.openapi.util.URLUtil Maven / Gradle / Ivy

// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.util;

import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public final class URLUtil {
  public static final String SCHEME_SEPARATOR = "://";
  public static final String FILE_PROTOCOL = "file";
  public static final String JAR_PROTOCOL = "jar";
  public static final String JAR_SEPARATOR = "!/";

  private URLUtil() {
  }

  /**
   * Opens a url stream. The semantics is the sames as {@link URL#openStream()}. The
   * separate method is needed, since jar URLs open jars via JarFactory and thus keep them
   * mapped into memory.
   */
  public static @NotNull InputStream openStream(@NotNull URL url) throws IOException {
    String protocol = url.getProtocol();
    return protocol.equals(JAR_PROTOCOL) ? openJarStream(url) : url.openStream();
  }

  private static @NotNull InputStream openJarStream(@NotNull URL url) throws IOException {
    Pair paths = splitJarUrl(url.getFile());
    if (paths == null) {
      throw new MalformedURLException(url.getFile());
    }

    final ZipFile zipFile = new ZipFile(paths.first);
    ZipEntry zipEntry = zipFile.getEntry(paths.second);
    if (zipEntry == null) {
      zipFile.close();
      throw new FileNotFoundException("Entry " + paths.second + " not found in " + paths.first);
    }

    return new FilterInputStream(zipFile.getInputStream(zipEntry)) {
      @Override
      public void close() throws IOException {
        super.close();
        zipFile.close();
      }
    };
  }

  /**
   * Splits .jar URL along a separator and strips "jar" and "file" prefixes if any.
   * Returns a pair of path to a .jar file and entry name inside a .jar, or null if the URL does not contain a separator.
   * 

* E.g. "jar:file:///path/to/jar.jar!/resource.xml" is converted into ["/path/to/jar.jar", "resource.xml"]. *

* Please note that the first part is platform-dependent - see UrlUtilTest.testJarUrlSplitter() for examples. */ public static @Nullable Pair splitJarUrl(@NotNull String url) { int pivot = url.indexOf(JAR_SEPARATOR); if (pivot < 0) return null; String resourcePath = url.substring(pivot + 2); String jarPath = url.substring(0, pivot); if (StringUtil.startsWithConcatenation(jarPath, JAR_PROTOCOL, ":")) { jarPath = jarPath.substring(JAR_PROTOCOL.length() + 1); } if (jarPath.startsWith(FILE_PROTOCOL)) { try { jarPath = urlToFile(new URL(jarPath)).getPath().replace('\\', '/'); } catch (Exception e) { jarPath = jarPath.substring(FILE_PROTOCOL.length()); if (jarPath.startsWith(SCHEME_SEPARATOR)) { jarPath = jarPath.substring(SCHEME_SEPARATOR.length()); } else if (StringUtil.startsWithChar(jarPath, ':')) { jarPath = jarPath.substring(1); } } } return new Pair<>(jarPath, resourcePath); } public static @NotNull File urlToFile(@NotNull URL url) { try { return new File(url.toURI().getSchemeSpecificPart()); } catch (URISyntaxException e) { throw new IllegalArgumentException("URL='" + url + "'", e); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy