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

com.cedarsoft.io.RelativePathFinder Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) cedarsoft GmbH.
 *
 * Licensed under the GNU General Public License version 3 (the "License")
 * with Classpath Exception; you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *         http://www.cedarsoft.org/gpl3ce
 *         (GPL 3 with Classpath Exception)
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 3 only, as
 * published by the Free Software Foundation. cedarsoft GmbH designates this
 * particular file as subject to the "Classpath" exception as provided
 * by cedarsoft GmbH in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 3 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 3 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact cedarsoft GmbH, 72810 Gomaringen, Germany,
 * or visit www.cedarsoft.com if you need additional information or
 * have any questions.
 */

package com.cedarsoft.io;


import javax.annotation.Nonnull;

import java.io.File;
import java.lang.String;

/**
 * Resolves the relative path
 *
 * @author Johannes Schneider ([email protected])
 */
public class RelativePathFinder {
  private static final char BACKSLASH = '\\';
  private static final char SLASH = '/';

  /**
   * Calculates the relative path
   *
   * @param target    the target path
   * @param base      the base (a directory)
   * @param separator the separator
   * @return the relative path pointing to the target (from the base)
   */
  public static String getRelativePath( @Nonnull final String target, @Nonnull final String base, @Nonnull final String separator ) {
    //
    // remove trailing file separator
    //
    @Nonnull
    String canonicalBase = base;
    if ( base.charAt( base.length() - 1 ) == SLASH || base.charAt( base.length() - 1 ) == BACKSLASH ) {
      canonicalBase = base.substring( 0, base.length() - 1 );
    }

    //
    // get canonical name of target and remove trailing separator
    //
    @Nonnull
    String canonicalTarget = target;

    if ( canonicalTarget.charAt( canonicalTarget.length() - 1 ) == SLASH || canonicalTarget.charAt( canonicalTarget.length() - 1 ) == BACKSLASH ) {
      canonicalTarget = canonicalTarget.substring( 0, canonicalTarget.length() - 1 );
    }

    if ( canonicalTarget.equals( canonicalBase ) ) {
      return ".";
    }

    //
    // see if the prefixes are the same
    //
    if ( canonicalBase.substring( 0, 2 ).equals( "\\\\" ) ) {
      //
      // UNC file name, if target file doesn't also start with same
      // server name, don't go there
      int endPrefix = canonicalBase.indexOf( BACKSLASH, 2 );
      @Nonnull
      String prefix1 = canonicalBase.substring( 0, endPrefix );
      @Nonnull
      String prefix2 = canonicalTarget.substring( 0, endPrefix );
      if ( !prefix1.equals( prefix2 ) ) {
        return canonicalTarget;
      }
    } else {
      if ( canonicalBase.substring( 1, 3 ).equals( ":\\" ) ) {
        int endPrefix = 2;
        @Nonnull
        String prefix1 = canonicalBase.substring( 0, endPrefix );
        @Nonnull
        String prefix2 = canonicalTarget.substring( 0, endPrefix );
        if ( !prefix1.equals( prefix2 ) ) {
          return canonicalTarget;
        }
      } else {
        if ( canonicalBase.charAt( 0 ) == SLASH ) {
          if ( canonicalTarget.charAt( 0 ) != SLASH ) {
            return canonicalTarget;
          }
        }
      }
    }

    // char separator = File.separatorChar;
    int minLength = canonicalBase.length();

    if ( canonicalTarget.length() < minLength ) {
      minLength = canonicalTarget.length();
    }

    int firstDifference = minLength + 1;

    //
    // walk to the shorter of the two paths
    // finding the last separator they have in common
    int lastSeparator = -1;
    for ( int i = 0; i < minLength; i++ ) {
      if ( canonicalTarget.charAt( i ) == canonicalBase.charAt( i ) ) {
        if ( canonicalTarget.charAt( i ) == SLASH
          || canonicalTarget.charAt( i ) == BACKSLASH ) {
          lastSeparator = i;
        }
      } else {
        firstDifference = lastSeparator + 1;
        break;
      }
    }

    StringBuilder relativePath = new StringBuilder( 50 );

    //
    // walk from the first difference to the end of the base
    // adding "../" for each separator encountered
    //
    if ( canonicalBase.length() > firstDifference ) {
      relativePath.append( ".." );
      for ( int i = firstDifference; i < canonicalBase.length(); i++ ) {
        if ( canonicalBase.charAt( i ) == SLASH
          || canonicalBase.charAt( i ) == BACKSLASH ) {
          relativePath.append( separator );
          relativePath.append( ".." );
        }
      }
    }

    if ( canonicalTarget.length() > firstDifference ) {
      //
      // append the rest of the target
      //

      if ( relativePath.length() > 0 ) {
        relativePath.append( separator );
      }
      relativePath.append( canonicalTarget.substring( firstDifference ) );
    }

    return relativePath.toString();
  }

  /**
   * 

getRelativePath

* * @param target a File object. * @param base a File object. * @param pathSeparator a String object. * @return a File object. */ @Nonnull public static File getRelativePath( @Nonnull File target, @Nonnull File base, @Nonnull String pathSeparator ) { return new File( getRelativePath( target.getPath(), base.getPath(), pathSeparator ) ); } /** *

getRelativePath

* * @param target a File object. * @param base a File object. * @return a File object. */ public static File getRelativePath( @Nonnull File target, @Nonnull File base ) { return getRelativePath( target, base, File.separator ); } /** *

getRelativePath

* * @param targetPath a String object. * @param basePath a String object. * @return a String object. */ @Nonnull public static String getRelativePath( @Nonnull String targetPath, @Nonnull String basePath ) { return getRelativePath( targetPath, basePath, File.separator ); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy