1 ////////////////////////////////////////////////////////////////////////////////
2 // MillScript: an Open Spice interpreter and batch website creation tool
3 // Copyright (C) 2005 Kevin Rogers
4 //
5 // This file is part of MillScript.
6 //
7 // MillScript is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU General Public License as published by the Free
9 // Software Foundation; either version 2 of the License, or (at your option)
10 // any later version.
11 //
12 // MillScript is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License along with
18 // MillScript; if not, write to the Free Software Foundation, Inc., 59 Temple
19 // Place, Suite 330, Boston, MA 02111-1307 USA
20 ////////////////////////////////////////////////////////////////////////////////
21 package org.millscript.commons.vfs.util;
22
23 import org.millscript.commons.vfs.VFile;
24 import org.millscript.commons.vfs.VFolder;
25 import org.millscript.commons.vfs.VVolume;
26 import org.millscript.commons.vfs.mime.MIMETypeHandler;
27
28 /**
29 * A utility class providing URI path resolution methods for the virtual
30 * filesystem.
31 */
32 public final class Resolver {
33
34 /**
35 * Hidden constructor.
36 */
37 private Resolver() {
38 }
39
40 /**
41 * Resolves the specified path to a virtual file against the specified
42 * folder. The new file may have different parent folders.
43 *
44 * @param base the virtual folder to resolve the path against
45 * @param path the path to get a virtual file for
46 * @return a VFile for the specified relative URI
47 */
48 public static VFile resolveAsFile( final VFolder base, final String path ) {
49 // First get the index of the first slash
50 int n1 = path.indexOf( '/', 0 );
51 if ( n1 < 0 ) {
52 // The path doesn't contain a slash, so get it as a file
53 return base.checkVFile( path );
54 } else if ( n1 == 0 ) {
55 // It begins with a slash so it's an absolute path
56 // We need to get to the root and resolve against that
57 if ( base.getParent() == null ) {
58 // We're at the root object, so strip the leading slash and
59 // resolve as a relative path
60 return resolveAsFile( base, path.substring( 1 ) );
61 } else {
62 // Not at the root yet. Jump up to the parent and try again
63 return resolveAsFile( base.getParent(), path );
64 }
65 } else if ( n1 == path.length() - 1 ) {
66 // The slash is at the end of the path so remove it and resolve
67 return resolveAsFile( base, path.substring( 0, n1 ) );
68 } else {
69 // It's a relative path
70 // Get the first segment as a folder. NOTE - the increment on n1 is
71 // there so we include the slash at the end of the segment
72 final VFolder folder = resolveAsFolder( base, path.substring( 0, ++n1 ) );
73 // Resolve the remaining path on the folder
74 return resolveAsFile( folder, path.substring( n1 ) );
75 }
76 }
77
78 /**
79 * Resolves the specified path to a virtual folder against the specified
80 * folder. The new folder may have different parent folders.
81 *
82 * @param base the virtual folder to resolve the path against
83 * @param path the path to get a virtual folder for
84 * @return a VFile for the specified relative URI
85 */
86 public static VFolder resolveAsFolder( final VFolder base, final String path ) {
87 // First get the index of the first slash
88 int n1 = path.indexOf( '/', 0 );
89 if ( n1 < 0 ) {
90 // The path doesn't contain a slash, so get it as a folder
91 // This step requires a MIME type check. If the path is a
92 // recognised VFS MIME type then we have to handle it as
93 // appropriate
94 // First check it's MIME type
95 final String type = base.getMIMEType( path );
96 // Do we have a handler for this type
97 final MIMETypeHandler handler = base.getMIMETypeHandler( type );
98 if ( handler == null ) {
99 // It's nothing special, so make a normal folder for it
100 return base.getVFolder( path );
101 } else {
102 // Oooo. We've got something special
103 // We treat this segment like a file
104 final VFile file = resolveAsFile( base, path );
105 // And now use the handler to turn it into a folder
106 return handler.resolveAsFolder( file );
107 }
108 } else if ( n1 == 0 ) {
109 // It begins with a slash so it's an absolute path
110 // We need to get to the root and resolve against that
111 if ( base.getParent() == null ) {
112 // We're at the root object, so strip the leading slash and
113 // resolve as a relative path
114 return resolveAsFolder( base, path.substring( 1 ) );
115 } else {
116 // Not at the root yet. Jump up to the parent and try again
117 return resolveAsFolder( base.getParent(), path );
118 }
119 } else if ( n1 == path.length() - 1 ) {
120 // The slash is at the end of the path so remove it and resolve
121 return resolveAsFolder( base, path.substring( 0, n1 ) );
122 } else {
123 // It's a relative path
124 // Get the first segment as a folder. NOTE - the increment on n1 is
125 // there so we include the slash at the end of the segment
126 final VFolder folder = resolveAsFolder( base, path.substring( 0, ++n1 ) );
127 // Resolve the remaining path on the folder
128 return resolveAsFolder( folder, path.substring( n1 ) );
129 }
130 }
131
132 /**
133 * Resolves the specified path to a new virtual volume against the
134 * specified folder, with the volumes root at the resolved path. For this
135 * to work it must be possible to resolve the specified path as a folder.
136 *
137 * @param base the virtual folder to resolve the path against
138 * @param path the path to get a virtual volume for
139 * @return a VVolume for the specified relative URI
140 */
141 public static VVolume resolveAsVolume( final VFolder base, final String path ) {
142 // Get the path as a folder and return it as a new volume
143 return resolveAsFolder( base, path ).toVolume();
144 }
145
146 }