Castle Game Engine allows you to use filenames everywhere where URLs are
- This is for backward compatibility with engine < 4.1.0.
- This is also for comfort, both for users and for developers.
For developers, e.g. you can use TOpenDialog.FileName value
with Load3D, or TCastleScene.FileName (which is really just an alias
For users, e.g. you can pass both filenames and URLs
as command-line parameters to view3dscene. No need to explicitly
mark what is a filename and what is an URL.
Q: Should I upgrade my code to just use URLs everywhere, that is:
to always pass an absolute URL to the engine routines that take URL parameter?
Even though the above statement says that I don't have to
(since we allow filenames instead of URLs everywhere)?
A: The short answer is "yes".
If you have a filename, you can reliably convert it to an URI
FilenameToURI and URIToFilename are inside URIParser unit, part of FPC,
but better use FilenameToURISafe and URIToFilenameSafe inside CastleURIUtils.
Besides obvious benetifs of using URLs (you will be able
to pull stuff from network using http protocol), there are some smaller
- In case of relative filenames, there are obscure cases
(weird relative filenames with colon inside the name)
that may be mistaken for URIs.
- Because an URL could have some characters encoded.
Inside an URI, "%25" means a "%" and "%4d" means "M".
URIToFilenameSafe and FilenameToURISafe handle
the percent-encoding/decoding consistently.
- For the future: right now, absolute filenames are never mistaken
for an URL (see description below how we do it).
But this depends on special properties of Windows and Unix
filenames, and depends on the fact that no protocol name is a single
letter. What if we are ported some day to a weird OS that has different
filename conventions? What if we use some single-letter protocol
name in the future?
Q: How does it work?
A: URIProtocol is the judge.
- When URIProtocol is not empty, we know that we have an absolute URI.
Absolute URI is just an URI that has a protocol.
This works 100% reliably for absolute filenames.
For Unix, this works since absolute
filename on Unix starts with "/" which cannot be a part of protocol name.
For Windows, it works thanks to the mechanism mentioned above that
ignores single-letter protocols.
So absolute filename will never be mistaken for an URI.
In case you used a relative filename, there is unfortunately
a small possibility of mistakenly treating it as URL with protocol.
That is because some filesystems allow to use colon inside a filename,
so you could make a weird filename that even starts with "http:".
- When URIProtocol is empty, it means that we have an absolute filename
or a relative filename or URI.
Relative filename or relative URI can always be differentiated
(Athough the distinction doesn't really matter, since right now
nothing encodes/decodes any special chars inside URIs.
Except possibly CombineURI (that uses ParseURI that calls EncodeURI
that calls Escape) but CombineURI returns always an absolute URI
- AbsoluteURI function treats them as relative filenames,
relative to the current directory. Almost all URL function parameters
in code are passed to the AbsoluteURI (with the exception of parameters
to special CombineURI).
This means that passing any filenames (absolute or relative) or
absolute URIs to AbsoluteURI is a good way to convert them to URI.
Although when you *know* that you have a filename (not URI),
it's better to use FilenameToURISafe(ExpandFileName(FileName))
(this avoids the ambigous relative filenames with colons problems).
- CombineURI treats the 2nd parameter (Relative) as relative URIs,
relative to the given base URI. All URLs present inside documents
(for example inside VRML/X3D "url" fields) are passed to CombineURI,
as they are always relative to the base document URL.
Passing a filename as the 2nd parameter to CombineURI is *not* allowed.
Although a relative filename using slashes is in practice just like
a relative URI, so not a problem.
But absolute filename (Unix or Windows) or using backslashes
*may* fail. CombineURI depends on ResolveRelativeURI which simply
assumes that we really have an URI, not a filename.