View | Details | Raw Unified | Return to bug 221556
Collapse All | Expand All

(-)src/org/eclipse/rse/internal/services/HostPath.java (+366 lines)
Added Link Here
1
/********************************************************************************
2
 * Copyright (c) 2008 IBM Corporation. All rights reserved.
3
 * This program and the accompanying materials are made available under the terms
4
 * of the Eclipse Public License v1.0 which accompanies this distribution, and is 
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * <p>
8
 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
9
 * part of a work in progress. There is no guarantee that this API will
10
 * work or that it will remain the same. Please do not use this API without
11
 * consulting with the <Your Team Name> team.
12
 * </p>
13
 *  
14
 * 
15
 * Contributors:
16
 * Rupen Mardirossian (IBM)	[221556] - Create HostPath.java based on org.eclipse.core.runtime.Path (code taken from Path class and modified).
17
 ********************************************************************************/
18
19
package org.eclipse.rse.internal.services;
20
21
import org.eclipse.core.runtime.Assert;
22
23
import org.eclipse.rse.services.clientserver.PathUtility;
24
25
public class HostPath implements IHostPath, Cloneable {
26
	
27
	protected char separator;
28
	
29
	/** The path segments */
30
	private String[] segments;
31
32
	/** Constant value indicating if the current platform is Windows */
33
	private static final boolean WINDOWS = java.io.File.separatorChar == '\\';
34
35
	/** Constant value indicating no segments */
36
	private static final String[] NO_SEGMENTS = new String[0];
37
	
38
	/** The device id string. May be null if there is no device. */
39
	private String device = null;
40
	
41
	/** Constant empty string value. */
42
	private static final String EMPTY_STRING = ""; //$NON-NLS-1$
43
	
44
	/** 
45
	 * Constructs a new path from the given string path.
46
	 * The string path must represent a valid file system path
47
	 * on the local/remote file system. 
48
	 * segment delimiters (separators) are determined, and any
49
	 * segment and device delimiters for the local file system are
50
	 * also respected (such as colon (':') and backslash ('\') on some file systems).
51
	 *
52
	 * @param fullPath the string path
53
	 */
54
	public HostPath(String fullPath) {
55
		Assert.isNotNull(fullPath);
56
		String devicePart = null;
57
		String stringSep = PathUtility.getSeparator(fullPath);
58
		if (stringSep.equals("/"))  //$NON-NLS-1$
59
		{
60
			this.separator = '/';
61
		} 
62
		else if (stringSep.equals("\\")) //$NON-NLS-1$
63
		{
64
			this.separator = '\\';
65
		}
66
		if (WINDOWS) {
67
			//extract device
68
			int i = fullPath.indexOf(DEVICE_SEPARATOR);
69
			if (i != -1) {
70
				//remove leading slash from device part to handle output of URL.getFile()
71
				int start = fullPath.charAt(0) == this.separator ? 1 : 0;
72
				devicePart = fullPath.substring(start, i + 1);
73
				fullPath = fullPath.substring(i + 1, fullPath.length());
74
			}
75
		}
76
		initialize(devicePart, fullPath);
77
	}
78
	
79
	/* 
80
	 * Private constructor.
81
	 */
82
	private HostPath(String device, String[] segments, char separator) {
83
		// no segment validations are done for performance reasons	
84
		this.segments = segments;
85
		this.device = device;
86
		this.separator = separator;
87
	}
88
	
89
	//----------------------------------------------------------------------
90
	// <taken from org.eclipse.core.runtime.Path and modified (Copyright IBM)>
91
	//----------------------------------------------------------------------
92
	/* 
93
	 * Clones this object.
94
	 */
95
	public Object clone() {
96
		try {
97
			return super.clone();
98
		} catch (CloneNotSupportedException e) {
99
			return null;
100
		}
101
	}
102
	
103
	//----------------------------------------------------------------------
104
	// <taken from org.eclipse.core.runtime.Path and modified (Copyright IBM)>
105
	//----------------------------------------------------------------------
106
	/* 
107
	 * Compares objects for equality.
108
	 */
109
	public boolean equals(Object obj) {
110
		if (this == obj)
111
			return true;
112
		if (!(obj instanceof HostPath))
113
			return false;
114
		HostPath target = (HostPath) obj;
115
		String[] targetSegments = target.segments;
116
		int i = segments.length;
117
		//check segment count
118
		if (i != targetSegments.length)
119
			return false;
120
		//check segments in reverse order - later segments more likely to differ
121
		while (--i >= 0)
122
			if (!segments[i].equals(targetSegments[i]))
123
				return false;
124
		//check device last (least likely to differ)
125
		return device == target.device || (device != null && device.equals(target.device));
126
	}
127
128
	
129
	//----------------------------------------------------------------------
130
	// <taken from org.eclipse.core.runtime.Path and modified (Copyright IBM)>
131
	//----------------------------------------------------------------------
132
	/**
133
	 * Computes the segment array for the given canonicalized path.
134
	 */
135
	private String[] computeSegments(String path) {
136
		// performance sensitive --- avoid creating garbage
137
		int segmentCount = computeSegmentCount(path);
138
		if (segmentCount == 0)
139
			return NO_SEGMENTS;
140
		String[] newSegments = new String[segmentCount];
141
		int len = path.length();
142
		// check for initial slash
143
		int firstPosition = (path.charAt(0) == separator) ? 1 : 0;
144
		// check for UNC
145
		if (firstPosition == 1 && len > 1 && (path.charAt(1) == separator))
146
			firstPosition = 2;
147
		int lastPosition = (path.charAt(len - 1) != separator) ? len - 1 : len - 2;
148
		// for non-empty paths, the number of segments is 
149
		// the number of slashes plus 1, ignoring any leading
150
		// and trailing slashes
151
		int next = firstPosition;
152
		for (int i = 0; i < segmentCount; i++) {
153
			int start = next;
154
			int end = path.indexOf(separator, next);
155
			if (end == -1) {
156
				newSegments[i] = path.substring(start, lastPosition + 1);
157
			} else {
158
				newSegments[i] = path.substring(start, end);
159
			}
160
			next = end + 1;
161
		}
162
		return newSegments;
163
	}
164
	
165
	//----------------------------------------------------------------------
166
	// <taken from org.eclipse.core.runtime.Path and modified (Copyright IBM)>
167
	//----------------------------------------------------------------------
168
	/* 
169
	 * Returns the size of the string that will be created by toString or toOSString.
170
	 */
171
	private int computeLength() {
172
		int length = 0;
173
		if (device != null)
174
			length += device.length();
175
		//add the segment lengths
176
		int max = segments.length;
177
		if (max > 0) {
178
			for (int i = 0; i < max; i++) {
179
				length += segments[i].length();
180
			}
181
			//add the separator lengths
182
			length += max;
183
		}
184
		return length;
185
	}
186
	
187
	//----------------------------------------------------------------------
188
	// <taken from org.eclipse.core.runtime.Path and modified (Copyright IBM)>
189
	//----------------------------------------------------------------------
190
	/* 
191
	 * Returns the number of segments in the given path
192
	 */
193
	private int computeSegmentCount(String path) {
194
		int len = path.length();
195
		if (len == 0 || (len == 1 && path.charAt(0) == separator)) {
196
			return 0;
197
		}
198
		int count = 1;
199
		int prev = -1;
200
		int i;
201
		while ((i = path.indexOf(separator, prev + 1)) != -1) {
202
			if (i != prev + 1 && i != len) {
203
				++count;
204
			}
205
			prev = i;
206
		}
207
		if (path.charAt(len - 1) == separator) {
208
			--count;
209
		}
210
		return count;
211
	}
212
	
213
	/*
214
	 * @see IHostPath#getDevice
215
	 */
216
	public String getDevice() {
217
		return device;
218
	}
219
	
220
	/*
221
	 * Initialize the current path with the given string.
222
	 */
223
	private void initialize(String device, String path) 
224
	{	
225
		this.device = device;
226
		this.segments = computeSegments(path);
227
	}
228
	
229
	/*
230
	 * return the number of segments in the path
231
	 */
232
	public int segmentCount() {
233
		return segments.length;
234
	}
235
	
236
	//----------------------------------------------------------------------
237
	// <taken from org.eclipse.core.runtime.Path and modified (Copyright IBM)>
238
	//----------------------------------------------------------------------
239
	/* 
240
	 * @see IHostPath#removeFirstSegments(int)
241
	 */
242
	public IHostPath removeFirstSegments(int count) {
243
		if (count == 0)
244
			return this;
245
		if (count >= segments.length) {
246
			return new HostPath(device, NO_SEGMENTS, separator);
247
		}
248
		Assert.isLegal(count > 0);
249
		int newSize = segments.length - count;
250
		String[] newSegments = new String[newSize];
251
		System.arraycopy(this.segments, count, newSegments, 0, newSize);
252
253
		//result is always a relative path
254
		return new HostPath(device, newSegments, separator);
255
	}
256
	
257
	//----------------------------------------------------------------------
258
	// <taken from org.eclipse.core.runtime.Path and modified (Copyright IBM)>
259
	//----------------------------------------------------------------------
260
	/* 
261
	 * @see IHostPath#removeLastSegments(int)
262
	 */
263
	public IHostPath removeLastSegments(int count) {
264
		if (count == 0)
265
			return this;
266
		if (count >= segments.length) {
267
			//result will have no trailing separator
268
			return new HostPath(device, NO_SEGMENTS, separator);
269
		}
270
		Assert.isLegal(count > 0);
271
		int newSize = segments.length - count;
272
		String[] newSegments = new String[newSize];
273
		System.arraycopy(this.segments, 0, newSegments, 0, newSize);
274
		return new HostPath(device, newSegments, separator);
275
	}
276
	
277
	
278
	/* 
279
	 * return the segment at specified location in array
280
	 */
281
	public String segment(int index) {
282
		if (index >= segments.length)
283
			return null;
284
		return segments[index];
285
	}
286
	
287
	//----------------------------------------------------------------------
288
	// <taken from org.eclipse.core.runtime.Path and modified (Copyright IBM)>
289
	//----------------------------------------------------------------------
290
	/* 
291
	 * return segments of the path in an array 
292
	 */
293
	public String[] segments() {
294
		String[] segmentCopy = new String[segments.length];
295
		System.arraycopy(segments, 0, segmentCopy, 0, segments.length);
296
		return segmentCopy;
297
	}
298
	
299
	//----------------------------------------------------------------------
300
	// <taken from org.eclipse.core.runtime.Path and modified (Copyright IBM)>
301
	//----------------------------------------------------------------------
302
	/*
303
	 * @see IHostPath#setDevice(String)
304
	 */
305
	public IHostPath setDevice(String value) {
306
		if (value != null) {
307
			Assert.isTrue(value.indexOf(IHostPath.DEVICE_SEPARATOR) == (value.length() - 1), "Last character should be the device separator"); //$NON-NLS-1$
308
		}
309
		//return the receiver if the device is the same
310
		if (value == device || (value != null && value.equals(device)))
311
			return this;
312
313
		return new HostPath(value, this.segments, this.separator);
314
	}
315
	
316
	//----------------------------------------------------------------------
317
	// <taken from org.eclipse.core.runtime.Path and modified (Copyright IBM)>
318
	//----------------------------------------------------------------------
319
	/* 
320
	 * @see IHostPath#toString()
321
	 */
322
	public String toString() {
323
		int resultSize = computeLength();
324
		if (resultSize <= 0)
325
			return EMPTY_STRING;
326
		char[] result = new char[resultSize];
327
		int offset = 0;
328
		if (device != null) {
329
			int size = device.length();
330
			device.getChars(0, size, result, offset);
331
			offset += size;
332
			result[offset++] = separator;
333
		}
334
		int len = segments.length - 1;
335
		if (len >= 0) {
336
			//append all but the last segment, with separators
337
			for (int i = 0; i < len; i++) {
338
				int size = segments[i].length();
339
				segments[i].getChars(0, size, result, offset);
340
				offset += size;
341
				result[offset++] = separator;
342
			}
343
			//append the last segment
344
			int size = segments[len].length();
345
			segments[len].getChars(0, size, result, offset);
346
			offset += size;
347
		}
348
		return new String(result);
349
	}
350
	//----------------------------------------------------------------------
351
	// <taken from org.eclipse.core.runtime.Path and modified (Copyright IBM)>
352
	//----------------------------------------------------------------------
353
	/* 
354
	 * @see IHostPath#uptoSegment(int)
355
	 */
356
	public IHostPath uptoSegment(int count) {
357
		if (count == 0)
358
			return new HostPath(device, NO_SEGMENTS, separator);
359
		if (count >= segments.length)
360
			return this;
361
		Assert.isTrue(count > 0, "Invalid parameter to Path.uptoSegment"); //$NON-NLS-1$
362
		String[] newSegments = new String[count];
363
		System.arraycopy(segments, 0, newSegments, 0, count);
364
		return new HostPath(device, newSegments, separator);
365
	}
366
}
(-)src/org/eclipse/rse/internal/services/IHostPath.java (+169 lines)
Added Link Here
1
/********************************************************************************
2
 * Copyright (c) 2008 IBM Corporation. All rights reserved.
3
 * This program and the accompanying materials are made available under the terms
4
 * of the Eclipse Public License v1.0 which accompanies this distribution, and is 
5
 * available at http://www.eclipse.org/legal/epl-v10.html
6
 * 
7
 * <p>
8
 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
9
 * part of a work in progress. There is no guarantee that this API will
10
 * work or that it will remain the same. Please do not use this API without
11
 * consulting with the <Your Team Name> team.
12
 * </p>
13
 *  
14
 * 
15
 * Contributors:
16
 * Rupen Mardirossian (IBM)	[221556] - Create IHostPath.java based on org.eclipse.core.runtime.IPath (code taken from IPath interface and modified).
17
 ********************************************************************************/
18
19
package org.eclipse.rse.internal.services;
20
21
/**
22
 * This interface represents a host path.
23
 */
24
public interface IHostPath extends Cloneable {
25
26
	/** 
27
	 * Device separator character constant ":" used in paths.
28
	 */
29
	public static final char DEVICE_SEPARATOR = ':';
30
	
31
	/**
32
	 * Returns a copy of this path.
33
	 *
34
	 * @return the cloned path
35
	 */
36
	public Object clone();
37
	
38
	/**
39
	 * Returns whether this path equals the given object.
40
	 * <p>
41
	 * Equality for paths is defined to be: same sequence of segments and same device.
42
	 * Paths are not generally considered equal to objects other than paths.
43
	 * </p>
44
	 *
45
	 * @param obj the other object
46
	 * @return <code>true</code> if the paths are equivalent,
47
	 *    and <code>false</code> if they are not
48
	 */
49
	public boolean equals(Object obj);
50
	
51
	/**
52
	 * Returns the device id for this path, or <code>null</code> if this
53
	 * path has no device id. Note that the result will end in ':'.
54
	 *
55
	 * @return the device id, or <code>null</code>
56
	 * @see #setDevice(String)
57
	 */
58
	public String getDevice();
59
	
60
	/**
61
	 * Returns a copy of this path with the given number of segments
62
	 * removed from the beginning. The device id is preserved. 
63
	 * The number must be greater or equal zero.
64
	 * If the count is zero, this path is returned.
65
	 * The resulting path will always be a relative path with respect
66
	 * to this path.  If the number equals or exceeds the number
67
	 * of segments in this path, an empty relative path is returned.
68
	 *
69
	 * @param count the number of segments to remove
70
	 * @return the new path
71
	 */
72
	public IHostPath removeFirstSegments(int count);
73
	
74
	/**
75
	 * Returns a copy of this path with the given number of segments
76
	 * removed from the end. The device id is preserved.
77
	 * The number must be greater or equal zero.
78
	 * If the count is zero, this path is returned.
79
	 * If the number equals or exceeds the number
80
	 * of segments in this path, a path with no segments is returned.
81
	 * </p>
82
	 *
83
	 * @param count the number of segments to remove
84
	 * @return the new path
85
	 */
86
	public IHostPath removeLastSegments(int count);
87
88
	
89
	/**
90
	 * Returns the specified segment of this path, or
91
	 * <code>null</code> if the path does not have such a segment.
92
	 *
93
	 * @param index the 0-based segment index
94
	 * @return the specified segment, or <code>null</code> 
95
	 */
96
	public String segment(int index);
97
98
	/**
99
	 * Returns the number of segments in this path.
100
	 * <p> 
101
	 * Note that both root and empty paths have 0 segments.
102
	 * </p>
103
	 *
104
	 * @return the number of segments
105
	 */
106
	public int segmentCount();
107
	
108
	/**
109
	 * Returns the segments in this path in order.
110
	 *
111
	 * @return an array of string segments
112
	 */
113
	public String[] segments();
114
	
115
	/**
116
	 * Returns a new path which is the same as this path but with 
117
	 * the given device id.  The device id must end with a ":".
118
	 * A device independent path is obtained by passing <code>null</code>.
119
	 * <p>
120
	 * For example, "C:" and "Server/Volume:" are typical device ids.
121
	 * </p>
122
	 *
123
	 * @param device the device id or <code>null</code>
124
	 * @return a new path
125
	 * @see #getDevice()
126
	 */
127
	public IHostPath setDevice(String device);
128
	
129
	/**
130
	 * Returns a string representation of this path, including its
131
	 * device id.  
132
	 * <p>
133
	 * Example result strings (without and with device id):
134
	 * <pre>
135
	 * "/foo/bar.txt"
136
	 * "bar.txt"
137
	 * "/foo/"
138
	 * "foo/"
139
	 * ""
140
	 * "/"
141
	 * "C:/foo/bar.txt"
142
	 * "C:bar.txt"
143
	 * "C:/foo/"
144
	 * "C:foo/"
145
	 * "C:"
146
	 * "C:/"
147
	 * </pre>
148
	 * This string is suitable for passing to <code>Path(String)</code>.
149
	 * </p>
150
	 *
151
	 * @return a string representation of this path
152
	 * @see HostPath
153
	 */
154
	public String toString();
155
	
156
	/**
157
	 * Returns a copy of this path truncated after the
158
	 * given number of segments. The number must not be negative.
159
	 * The device id is preserved.
160
	 * <p>
161
	 * Copying up to segment zero simply means making an copy with
162
	 * no path segments.
163
	 * </p>
164
	 *
165
	 * @param count the segment number at which to truncate the path
166
	 * @return the new path
167
	 */
168
	public IHostPath uptoSegment(int count);
169
}

Return to bug 221556