/* * [MiniTools.java] * * Summary: Stripped down version of com.mindprod.Tools that does not need a full Configuration. * * Copyright: (c) 2016-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.0 2016-06-12 initial version */ package com.mindprod.jprep; import com.mindprod.common18.EIO; import com.mindprod.fastcat.FastCat; import java.io.File; import java.util.regex.Pattern; /** * Stripped down version of com.mindprod.Tools that does not need a full Configuration. * * @author Roedy Green, Canadian Mind Products * @version 1.0 2016-06-12 initial version * @see com.mindprod.htmlmacros.support.Tools * @since 2016-06-12 */ public class MiniTools { /** * Pattern to split path into directory segments separated by / */ private static final Pattern SPLIT_ON_SLASH = Pattern.compile( "/" ); /** * webroot name with lead E:/ as file */ private static File rootDir; /** * webroot name with lead E:\ */ private static String rootDirNameWithBackslashes; /** * Get name.ext without path. Not Canonical. Will not contain any / or \. * e.g. regex.html * * @param fileBeingDistributed the file having its macros expanded * * @return unqualified filename e.g. bushisms.html. */ private static String basicNameWithExtension( File fileBeingDistributed ) { return fileBeingDistributed.getName(); } // /methods /** * Get the pieces of the directory name, webroot relative. * * @param dir directory name, not fileBeingDistributed Get array of directory segments that make up the directory, * possibly empty. livinglove/methods gives { "livinglove" "methods" } * * @return just segments of directory name. */ private static String[] dirSegments( String dir ) { if ( dir == null || dir.length() == 0 ) { // split would return one empty element // in this case instead of empty array return new String[ 0 ]; } else { if ( dir.indexOf( '/' ) < 0 ) { // faster than splitter, the normal case return new String[] { dir }; } else { // two or more directory segments return SPLIT_ON_SLASH.split( dir ); } } } // /methods /** * Get just the / dir name, relative to webroot. * * @param fileBeingDistributed the file having its macros expanded * * @return just directory part of the name without trailing /, with embedded /. e.g. politics, or politics/laser */ private static String dirWithSlashes( File fileBeingDistributed ) { assert fileBeingDistributed != null : "null fileBeingDistributed"; String path = uPathName( fileBeingDistributed ); int place = path.lastIndexOf( '/' ); if ( place < 0 ) { return ""; } else { return path.substring( 0, place ); } } // /methods /** * Get string representing how deeply nested we are from the root. * * @param level depth we are from webRoot. * * @return empty for root, ../ for one deep, ../../ for two deep * @see #relativeURL */ private static String getLevelString( int level ) { if ( level < 0 ) { throw new IllegalArgumentException( "Tools.getLevelString: invalid directory nesting level " + level ); } switch ( level ) { case 0: return ""; case 1: return "../"; case 2: return "../../"; default: final FastCat sb = new FastCat( level ); for ( int i = 0; i < level; i++ ) { sb.append( "../" ); } return sb.toString(); } // end switch } // /methods /** * Get fully qualified name locally, path, name and ext., not canonical * E:\mindprod\politics\bushisms.html * * @param fileBeingDistributed the file having its macros expanded * * @return fully qualified filename with \ in names e.g. E:\mindprod\politics\bushisms.html with caps in filename * exact. */ private static String qualifiedNameWithBackslashes( File fileBeingDistributed ) { assert fileBeingDistributed != null : "null fileBeingDistributed"; return EIO.getCanOrAbsPath( fileBeingDistributed ) .replace( '/', File.separatorChar ); } // /methods /** * See the webroot * * @param webroot webroot with slashes e.g. E:/mindprod */ static void setWebroot( String webroot ) { rootDir = new File( webroot.toLowerCase() ); rootDirNameWithBackslashes = webroot.replace( '/', '\\' ).toLowerCase(); } /** * Get webroot relative name, with slashes. * * @param fileBeingDistributed the file having its macros expanded * * @return name relative to LOCAL_WEBROOT_WITH_SLASHES with / in names e.g.politics/bushisms.html */ private static String uPathName( File fileBeingDistributed ) { assert fileBeingDistributed != null : "null fileBeingDistributed"; String fullName = qualifiedNameWithBackslashes( fileBeingDistributed ); assert fullName.toLowerCase() .startsWith( rootDirNameWithBackslashes ) : "not uPath filename [" + fullName + "]"; // chop off webRoot and lead \ return fullName.substring( rootDirNameWithBackslashes.length() + 1 ).replace( File.separatorChar, '/' ); } // /methods /** * Generate a relative url from the current file, no <a href= xxx>/a<etc. * * @param uPathFilename file where link jumps to, webRoot relative * @param fileBeingDistributed where the link will be embedded * * @return relative url, with slashes. */ public static String relativeURL( String uPathFilename, File fileBeingDistributed ) { assert fileBeingDistributed != null : "null fileBeingDistributed"; String[] sourceSegs = dirSegments( dirWithSlashes( fileBeingDistributed ) ); final File targetFile = new File( rootDir, uPathFilename ); String[] targetSegs = dirSegments( dirWithSlashes( targetFile ) ); // get base filename.ext#xxxxx String targetName = basicNameWithExtension( targetFile ); // eliminate high order commonality int last = Math.min( sourceSegs.length, targetSegs.length ); for ( int c = 0; c < last; c++ ) { if ( !sourceSegs[ c ].equals( targetSegs[ c ] ) ) { // we found a difference, note where last = c; break; } } // end for c // fell out the bottom. That means source and target directories are // identical. // up to but not including last. // generate URL to work up the tree to common place final FastCat sb = new FastCat( ( targetSegs.length - last ) * 2 + 2 ); sb.append( getLevelString( sourceSegs.length - last ) ); // work back down toward target for ( int d = last; d < targetSegs.length; d++ ) { sb.append( targetSegs[ d ], "/" ); } // end for d sb.append( targetName ); return sb.toString(); // we do not translate ../index.html to ./ because it screws up if files are loaded from local hard disk. } // /methods }