📄 path.java
字号:
/******************************************************************************* * Copyright (c) 2000, 2003 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/// Modified by Sasa Bojanicpackage org.enhydra.shark.xpdl;import java.io.File;/** * Paths are always maintained in canonicalized form. That is, parent * references (i.e., <code>../../</code>) and duplicate separators are * resolved. For example, * <pre> new Path("/a/b").append("../foo/bar")</pre> * will yield the path * <pre> /a/foo/bar</pre> * <p> * This class is not intended to be subclassed by clients but * may be instantiated. * </p> */public class Path { /** * Path separator character constant "/" used in paths. */ public static final char SEPARATOR = '/'; /** * Device separator character constant ":" used in paths. */ public static final char DEVICE_SEPARATOR = ':'; /** The path segments */ private String[] segments; /** The device id string. May be null if there is no device. */ private String device = null; /** flags indicating separators (has leading, is UNC, has trailing) */ private int separators; /** masks for separator values */ private static final int HAS_LEADING = 1; private static final int IS_UNC = 2; private static final int HAS_TRAILING = 4; private static final int ALL_SEPARATORS = HAS_LEADING | IS_UNC | HAS_TRAILING;// /** Mask for all bits that are involved in the hashcode */// private static final int HASH_MASK = ~HAS_TRAILING; /** Constant value indicating no segments */ private static final String[] NO_SEGMENTS = new String[0]; /** Constant root path string (<code>"/"</code>). */ private static final String ROOT_STRING = "/"; //$NON-NLS-1$ /** Constant value containing the root path with no device. */ public static final Path ROOT = new Path(ROOT_STRING); /** Constant empty string value. */ private static final String EMPTY_STRING = ""; //$NON-NLS-1$ /** Constant value containing the empty path with no device. */ public static final Path EMPTY = new Path(EMPTY_STRING); //Private implementation note: the segments and separators //arrays are never modified, so that they can be shared between //path instances private Path(String device, String[] segments, int _separators) { // no segment validations are done for performance reasons this.segments = segments; this.device = device; //hashcode is cached in all but the bottom three bits of the separators field this.separators = (computeHashCode() << 3) | (_separators & ALL_SEPARATORS); } /** * Constructs a new path from the given string path. * The given string path must be valid. * The path is canonicalized and double slashes are removed * except at the beginning. (to handle UNC paths) All backslashes ('\') * are replaced with forward slashes. ('/') * * @param fullPath the string path */ public Path(String fullPath) { // no segment validations are done for performance reasons initialize(null, fullPath); } /** * Constructs a new path from the given device id and string path. * The given string path must be valid. * The path is canonicalized and double slashes are removed except * at the beginning (to handle UNC paths). All backslashes ('\') * are replaced with forward slashes. ('/') * * @param device the device id * @param path the string path * @see #setDevice */ public Path(String device, String path) { // no segment validations are done for performance reasons initialize(device, path); } /** * Destructively converts this path to its canonical form. * <p> * In its canonical form, a path does not have any * "." segments, and parent references ("..") are collapsed * where possible. * </p> * @return true if the path was modified, and false otherwise. */ private boolean canonicalize() { //look for segments that need canonicalizing for (int i = 0, max = segments.length; i < max; i++) { String segment = segments[i]; if (segment.charAt(0) == '.' && (segment.equals("..") || segment.equals("."))) { //$NON-NLS-1$ //$NON-NLS-2$ //path needs to be canonicalized collapseParentReferences(); //paths of length 0 have no trailing separator if (segments.length == 0) separators &= (HAS_LEADING | IS_UNC); //recompute hash because canonicalize affects hash separators = (separators & ALL_SEPARATORS) | (computeHashCode() << 3); return true; } } return false; } /** * Destructively removes all occurrences of ".." segments from this path. */ private void collapseParentReferences() { int segmentCount = segments.length; String[] stack = new String[segmentCount]; int stackPointer = 0; for (int i = 0; i < segmentCount; i++) { String segment = segments[i]; if (segment.equals("..")) { //$NON-NLS-1$ if (stackPointer==0) { // if the stack is empty we are going out of our scope // so we need to accumulate segments. But only if the original // path is relative. If it is absolute then we can't go any higher than // root so simply toss the .. references. if (!isAbsolute()) stack[stackPointer++] = segment;//stack push } else { // if the top is '..' then we are accumulating segments so don't pop if ("..".equals(stack[stackPointer-1])) //$NON-NLS-1$ stack[stackPointer++] = ".."; //$NON-NLS-1$ else stackPointer--;//stack pop } //collapse current references } else if (!segment.equals(".") || (i == 0 && !isAbsolute())) //$NON-NLS-1$ stack[stackPointer++] = segment;//stack push } //if the number of segments hasn't changed, then no modification needed if (stackPointer== segmentCount) return; //build the new segment array backwards by popping the stack String[] newSegments = new String[stackPointer]; System.arraycopy(stack, 0, newSegments, 0, stackPointer); this.segments = newSegments; } /** * Removes duplicate slashes from the given path, with the exception * of leading double slash which represents a UNC path. */ private String collapseSlashes(String path) { int length = path.length(); // if the path is only 0, 1 or 2 chars long then it could not possibly have illegal // duplicate slashes. if (length < 3) return path; // check for an occurence of // in the path. Start at index 1 to ensure we skip leading UNC // // If there are no // then there is nothing to collapse so just return. if (path.indexOf("//", 1) == -1) //$NON-NLS-1$ return path; // We found an occurence of // in the path so do the slow collapse. char[] result = new char[path.length()]; int count = 0; boolean hasPrevious = false; char[] characters = path.toCharArray(); for (int index = 0; index < characters.length; index++) { char c = characters[index]; if (c == SEPARATOR) { if (hasPrevious) { // skip double slashes, except for beginning of UNC. // note that a UNC path can't have a device. if (device == null && index == 1) { result[count] = c; count++; } } else { hasPrevious = true; result[count] = c; count++; } } else { hasPrevious = false; result[count] = c; count++; } } return new String(result, 0, count); } /* * Computes the hash code for this object. */ private int computeHashCode() { int hash = device == null ? 17 : device.hashCode(); int segmentCount = segments.length; for (int i = 0; i < segmentCount; i++) { //this function tends to given a fairly even distribution hash = hash * 37 + segments[i].hashCode(); } return hash; } /* * Returns the size of the string that will be created by toString or toOSString. */ private int computeLength() { int length = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -