Inconsistent handling of UnsupportedFormatException

On macOS, 2019r1.

Suppose I have a file on my desktop with the name: 2018/19 mypic.jpg

If I construct its path, that would be: /Users/tim/Desktop

Then there is an inconsistency between two ways to initialise a folderitem for this file, as follows:

[code]Dim fname, fpath, str as string, fh as folderitem

fname = “2018/19 mypic.jpg”
fpath = “/Users/tim/Desktop”
str = fpath + “/” + fname

fh = GetFolderItem (str, FolderItem.PathTypeNative) // Returns Nil due to the / in 2018/19

fh = new FolderItem (str, FolderItem.PathTypeNative) // Gives me an UnsupportedFormatException
[/code]

Is there a reason for this? I may say that as far as I’m concerned, the behaviour of GetFolderItem is correct in this situation.

I would suggest you build folderItems using CHILD function

f=SpecialFolder.desktop.child("2018").child("19 mypic.jpg")

as to your original question… .it MAY have to do with the space in the name, and a need for quotes (which CHILD won’t care about)

[quote=434463:@Tim Streater]
Is there a reason for this? I may say that as far as I’m concerned, the behaviour of GetFolderItem is correct in this situation.[/quote]

Yes - and its not a bug
Constructors dont “return” anything
A constructor is just a “special” initializer - but its still just a method (you could in fact call it manually if you wanted)
Basically when you use “NEW X” the construction the sequence is

  1. set aside memory for the object with all values initialize to defaults for the type
    this means the object exists and CANNOT be nil

  2. run the constructor method to initialize the values

and now the setting of those initial values fails - but the object still exists so its not nil

Constructors don’t return a value, so raising an exception is the only way they can indicate an error to the calling code.

The file in question may actually be anywhere in the file system, I just chose Desktop as an example.

In essence the problem surfaced because the particular filename happened to contain (perfectly legally under macOS) the directory separator of the underlying OS. If this is viewed as an error, I don’t see why the Constructor can’t (in this instance) free the memory and initialise fh to Nil.

Hmm. The file(s) get selected in the first instance by the user by drag/dropping them, and ISTM I shall have to forbid such files at that stage, since obviously I can’t actually open them (can’t do much if GetFolderItem returns Nil or new Folderitem gives an exception). The DragItem gives me a FolderItem which contains the filename and path, thus:

fnam = f.Name path = f.Parent.NativePath

Shame I can’t actually use them.

see my steps above esp step 1

Constructors are not “allocators” - they dont allocate memory like they do in something like C++
When you use “NEW whatever” the memory is ALWAYS set aside - period
So the object ALWAYS exists when you use “NEW X” and there is no way for the constructor to nil that if something goes wrong

Doing so would be a fundamental change to the entire runtime and VERY unlikey to every happen

FWIW this is not unique to Xojo.
Java constructors behave nearly identically - except that Java prevents you from calling the constructor any other time

[quote=434468:@Tim Streater]The DragItem gives me a FolderItem which contains the filename and path, thus:

fnam = f.Name path = f.Parent.NativePath

Shame I can’t actually use them.[/quote]

If you already have a FolderItem pointing to the file, why are you calling GetFolderItem/New FolderItem in the first place?

Ha ha. I wondered when someone would ask that. It’s a good question.

  1. The user chooses the files, and I make a note of their names and paths in an SQLite database.

  2. At some later point, which could range from minutes to years (but is typically a few minutes), the user wants the files processed. In between times, they could have shut down the app, re-booted, deleted half the files they selected, renamed the other half, changed their mind about actually which files they want processed, any number of things. The best I can do is keep track of their whims and then, when they later press to Go button, manfully knuckle forehead and do it.

In theory get folder item could be implemented as

Function GetFolderItem(path as string, pathType as integer = Folderitem.PathTypeAbsolute) as Folderitem
  try
       dim f as new Folderitem(path, pathType)
       return f
  catch usfx  as UnsupportedFormatException
       return nil
  end try
end Function

but there’s no way to rewrite “new folderitem” such that it could return nil - since it doesnt “return” anything :slight_smile:

It’s not quite a good idea to combine f.Name and f.Parent.NativePath :slight_smile:

See what @Thomas Tempelmann has written in this post:

[quote]in Xojo’s FolderItem and in the Finder you can name a file “a/a” but not “a:a”. The “:” then gets swapped with “/” if you’re using POSIX or Shell paths.
Meaning, if the Finder shows “a/a”, the file’s name in Terminal will be “a:a”.[/quote]

Or in an example:

  • f. Name, f.DisplayName: 2018/19 mypic.png it’s what the user sees, and may contain a /
  • f.NativePath: /Users/username/Desktop/2018:19 mypic.png a user-entered / will be a :
  • f.ShellPath: /Users/username/Desktop/2018\\:19\\ mypic.png a user-entered / will be an escaped :

Store the “Name” for Display purpose, but store the full “NativePath” or “ShellPath” of the file (and not just of it’s .Parent folder) to access it later.
That works just as expected:

[code]Dim f1 As FolderItem = GetFolderItem("/Users/username/Desktop/2018:19 mypic.png", FolderItem.PathTypeNative)
Dim f2 As FolderItem = GetFolderItem("/Users/username/Desktop/2018\:19\ mypic.png", FolderItem.PathTypeShell)

Dim f3 As New FolderItem("/Users/username/Desktop/2018:19 mypic.png", FolderItem.PathTypeNative)
Dim f4 As New FolderItem("/Users/username/Desktop/2018\:19\ mypic.png", FolderItem.PathTypeShell)[/code]

[quote=434468:@Tim Streater]

fnam = f.Name path = f.Parent.NativePath
Shame I can’t actually use them.[/quote]
Sure you can…

You’re storing the NativePath of the Directory. So get that first using PathTypeNative.
Then get the .Child with the Name you’re storing:

[code]Dim fname, fpath as string
Dim fDirectory, fItem as folderitem

fname = “2018/19 mypic.png”
fpath = “/Users/juerg/Desktop”

fDirectory = GetFolderItem (fpath, FolderItem.PathTypeNative)
if fDirectory <> nil and fDirectory.Exists and fDirectory.Directory then
fItem = fDirectory.Child(fname)
end if

fDirectory = new FolderItem (fpath, FolderItem.PathTypeNative)
if fDirectory <> nil and fDirectory.Exists and fDirectory.Directory then
fItem = fDirectory.Child(fname)
end if
[/code]
Again: Just don’t mix/combine “NativePath” and “Name”.

… and stop using illegal characters in your file names for your own sanity. Remember, just because you can, doesn’t mean that you should. Stay away from:

[ ] { } \\ | / ? < > : ; ! @ # $ % ^ & * ( and )

All of those have special meaning on Unix/Linux/Mac systems (and some on Windows). You’ll thank yourself later.

[quote=434500:@Tim Jones]… and stop using illegal characters in your file names for your own sanity. Remember, just because you can, doesn’t mean that you should. Stay away from:

[ ] { } \\ | / ? < > : ; ! @ # $ % ^ & * ( and )

All of those have special meaning on Unix/Linux/Mac systems (and some on Windows). You’ll thank yourself later.[/quote]

I agree. But they’re not my files; they are other peoples’ files. I have no control over how they choose to name their files. :frowning:

[quote=434499:@Jürg Otter]Sure you can…

You’re storing the NativePath of the Directory. So get that first using PathTypeNative.
Then get the .Child with the Name you’re storing:

[code]Dim fname, fpath as string
Dim fDirectory, fItem as folderitem

fname = “2018/19 mypic.png”
fpath = “/Users/juerg/Desktop”

fDirectory = GetFolderItem (fpath, FolderItem.PathTypeNative)
if fDirectory <> nil and fDirectory.Exists and fDirectory.Directory then
fItem = fDirectory.Child(fname)
end if
[/code]
Again: Just don’t mix/combine “NativePath” and “Name”.[/quote]

Thanks - this does the trick nicely. I noticed that this doesn’t work if one is using xojo.io.FolderItem. What happens then is that the portion of the name that looks like path info is appended to the folderitems’s path info, and the filename is reduced to the residue (which in the above case would be “19 mypic.jpg”. I’ll ask separately about that and open a case if it’s a bug.

You can at least lessen your responsibility by documenting these characters. There is no limit to the “creative” manner in which a user will abuse their power on a system. The fact that Apple “allows” those characters is the big dumb-ass move in the environment.

I’ll hold to my BOFH statement from 1990 - Computer use should require a license - like driving. :stuck_out_tongue:

How d’ye know I haven’t? :stuck_out_tongue:

Actually there is another set of files the user can name and there I essentially do prevent the / char. But perhaps I should put something about it in the User Guide - not that people ever read those.