Skip to content

Commit 8acdc6b

Browse files
committed
Make the getParent(URI) helper more robust
This fixes the behavior on Windows, avoiding InvalidPathExceptions.
1 parent 61911bf commit 8acdc6b

File tree

1 file changed

+40
-2
lines changed

1 file changed

+40
-2
lines changed

src/main/java/mpicbg/spim/data/generic/XmlIoAbstractSpimData.java

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,12 +199,50 @@ protected URI loadBasePathURI( final Element root, final URI xmlURI ) throws Spi
199199
return XmlHelpers.loadPathURI( root, BASEPATH_TAG, ".", parent );
200200
}
201201

202+
/**
203+
* Gets a URI's parent, e.g. the containing directory of a file.
204+
* <p>
205+
* This function behaves differently than the invocation
206+
* {@code uri.resolve("..")} when the URI ends in a trailing slash:
207+
* </p>
208+
* <pre>{@code
209+
* jshell> var u = new URI("file:/foo/bar/")
210+
* u ==> file:/foo/bar/
211+
*
212+
* jshell> u.resolve("..")
213+
* $2 ==> file:/foo/
214+
*
215+
* jshell> u = new URI("file:/foo/bar")
216+
* u ==> file:/foo/bar
217+
*
218+
* jshell> u.resolve("..")
219+
* $4 ==> file:/
220+
* }</pre>
221+
* <p>
222+
* Whereas this function returns "file:/C:/foo/" in both cases.
223+
*/
202224
private static URI getParent( final URI uri ) throws SpimDataIOException
203225
{
204226
try
205227
{
206-
final String parent = Paths.get( uri.getPath() ).getParent().toString() + "/";
207-
return new URI( uri.getScheme(), uri.getAuthority(), parent, uri.getQuery(), uri.getFragment() );
228+
final String uriPath = uri.getPath();
229+
final int parentSlash = uriPath.lastIndexOf( "/", uriPath.length() - 2 );
230+
if ( parentSlash < 0 )
231+
{
232+
throw new SpimDataIOException( "URI is already at the root" );
233+
}
234+
// NB: The "+ 1" below is *very important*, so that the resultant URI
235+
// ends in a trailing slash. The behaviour of URI differs depending on
236+
// whether this trailing slash is present; specifically:
237+
//
238+
// * new URI("file:/foo/bar/").resolve(".") -> "file:/foo/bar/"
239+
// * new URI("file:/foo/bar").resolve(".") -> "file:/foo/"
240+
//
241+
// That is: /foo/bar/ is considered to be in the directory /foo/bar,
242+
// whereas /foo/bar is considered to be in the directory /foo.
243+
final String parentPath = uriPath.substring( 0, parentSlash + 1 );
244+
return new URI( uri.getScheme(), uri.getUserInfo(), uri.getHost(),
245+
uri.getPort(), parentPath, uri.getQuery(), uri.getFragment() );
208246
}
209247
catch ( URISyntaxException e )
210248
{

0 commit comments

Comments
 (0)