View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2026 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.qulice.spi;
6   
7   import java.io.File;
8   import java.nio.file.Path;
9   
10  /**
11   * Path of a file relative to a base directory.
12   *
13   * <p>Given a base directory and a target file, computes the file path
14   * relative to the base, prefixed with a forward slash and using forward
15   * slashes as separators. Uses {@link Path#relativize(Path)} after
16   * normalising both paths to absolute form, which correctly handles cases
17   * where the file and base dir share a canonical location but differ in
18   * string form (for example, on macOS the {@code /var} symlink to
19   * {@code /private/var}). When the file lies outside the base directory,
20   * returns the file's absolute path unchanged.</p>
21   *
22   * @since 0.24
23   */
24  public final class Relative {
25  
26      /**
27       * Base directory.
28       */
29      private final File base;
30  
31      /**
32       * Target file.
33       */
34      private final File target;
35  
36      /**
37       * Ctor.
38       * @param base Base directory
39       * @param target Target file
40       */
41      public Relative(final File base, final File target) {
42          this.base = base;
43          this.target = target;
44      }
45  
46      /**
47       * Path of the target file relative to the base directory.
48       * @return Relative path starting with a forward slash, or the
49       *  absolute path of the file if it is not under the base directory
50       */
51      public String path() {
52          final Path root = this.base.toPath().toAbsolutePath().normalize();
53          final Path file = this.target.toPath().toAbsolutePath().normalize();
54          final String name;
55          if (file.startsWith(root)) {
56              name = "/".concat(
57                  root.relativize(file).toString().replace(File.separatorChar, '/')
58              );
59          } else {
60              name = file.toString().replace(File.separatorChar, '/');
61          }
62          return name;
63      }
64  }