Opened 10 years ago
Last modified 10 years ago
#12551 confirmed defect
wxMemoryFS bug with Windows filenames
Reported by: | helser | Owned by: | |
---|---|---|---|
Priority: | low | Milestone: | |
Component: | documentation | Version: | 2.8.8 |
Keywords: | Cc: | ||
Blocked By: | Blocking: | ||
Patch: | no |
Description
I added a file to a MemoryFS
wxString name = "C:\data\my_file.txt"; wxMemoryFSHandler::AddFile(name, "some content");
but then I couldn't retrieve it:
wxFileSystem fs; wxFSFile *fs_file = fs.OpenFile("memory:"+name); if (!fs_file) return; // fs_file always NULL.....
Turns out, when trying to look up the file, filesys.cpp:: MakeCorrectPath is called on the string that's passed in, so it converted back-slashes to forward-slashes, and the names weren't equivalent. I did this:
wxString name = "C:\data\my_file.txt"; name.Replace("\\", "/"); wxMemoryFSHandler::AddFile(name, "some content");
and now I'm able to retrieve it, using either / or \ in the path.
I believe this should be fixed internal to wxWidgets. What I suggest is making MakeCorrectPath() a static member of wxFileSystem, and then having wxMemoryFSHandler::AddFile() call it on the path that is passed in for the file. Reasonable?
Change History (9)
comment:1 in reply to: ↑ description Changed 10 years ago by vadz
- Status changed from new to infoneeded_new
comment:2 Changed 10 years ago by helser
- Status changed from infoneeded_new to new
Sorry, I was simplifying. I really do this:
bool MyClass::convertToFoo(const wxString& file_name) { wxFileName fn(file_name); wxStringOutputStream out_s; //.... fill in out_s wxString name = fn.GetFullPath(); name.Replace("\\", "/"); wxMemoryFSHandler::AddFile(name, out_s.GetString()); }
so I'm sure this is a well-formed Windows filename with sensible contents.
comment:3 follow-up: ↓ 4 Changed 10 years ago by vaclavslavik
wxFileSystem works with URLs, where '/' is used as path deliminer, not '\', so this isn't entirely unreasonable behavior. MakeCurrectPath is just a compatibility hack to allow using filenames with wxFileSystem (this was a mistake, but it's too late to fix it). So I'd very much prefer to clarify wxMemoryFSHandler documentation instead.
comment:4 in reply to: ↑ 3 Changed 10 years ago by vadz
- Component changed from base to documentation
- Priority changed from normal to low
I agree, wxMemoryFSHandler::AddFile() clearly should take a file name but the rest of the wxFS functions work with URIs. OTOH I don't really know what should be added to wxMemoryFSHandler documentation -- it already works just fine unless I'm missing something. Or do you mean to write something like
Notice that while a file name is used here, meaning that either slash or backslash can be used as the path separator, you need to use the slashes which are the only valid separators in an URI when accessing this file later using "memory:" URI schema.
?
comment:5 Changed 10 years ago by vaclavslavik
Actually, no. The filename argument to AddFile* functions is badly named, it dates back to when wxFileSystem tried to handle filenames too. It's value is actually the part of URI after "memory:" (as it says) that the data will be available under, i.e. it should follow URI conventions. In particular, it is not a file name.
comment:6 follow-up: ↓ 7 Changed 10 years ago by helser
- Component changed from documentation to base
I documented the result of my problem, but not one of the underlying causes. In my original example,
I added a file to a MemoryFS
wxString filename = "C:\\data\\my_file.txt"; wxMemoryFSHandler::AddFile(filename, "some content");
At this point, the wxMemoryFSHandler stores the file using 'filename' as the key,
calling
m_Hash->Put(filename, ....)
It is not transformed in any way, meaning it still contains back-slash as the path delimiter.
Then I when I try to retrieve it:
wxFileSystem fs; filename.Replace("\\", "/"); // Doesn't matter! wxFSFile *fs_file = fs.OpenFile("memory:"+filename); if (!fs_file) return; // fs_file always NULL.....
it is inaccessible - 'MakeCorrectPath' is called on 'filename', and so the back-slashes are converted to forward-slashes before using it as a key for the hash-table.
That means there is no way to retrieve my file from the memoryFS.
I would advocate one of two possible fixes:
1:
Call MakeCorrectPath on the filename argument of every 'AddFile' method of wxMemoryFSHandler
2: Change the 'filename' argument to a 'location' argument, and make some forms illegal
- an assert in the 'AddFile' to check for illegal characters, like '\'
- documentation changes
- MakeCorrectPath or something similar is a documented, public, static method that takes a filename as an argument and returns a legal 'location' that can be passed to wxMemoryFSHandler::AddFile
I'm not saying 'uri' or 'url' because I'm not sure how to use the terms correctly in this context.
Which is preferred?
Thanks!
comment:7 in reply to: ↑ 6 ; follow-up: ↓ 8 Changed 10 years ago by vaclavslavik
- Component changed from base to documentation
Replying to helser:
wxString filename = "C:\\data\\my_file.txt"; wxMemoryFSHandler::AddFile(filename, "some content");
As I said, this is wrong, the filename argument should be URI part, e.g. "/data/my_file.txt" here.
2: Change the 'filename' argument to a 'location' argument, and make some forms illegal
- an assert in the 'AddFile' to check for illegal characters, like '\'
- documentation changes
Yes, that's what I wrote above. The asserts may be useful, but also relatively expensive, and if they're added there, they should be in other places where wxFileSystem URIs are used.
- MakeCorrectPath or something similar is a documented, public, static method
No, it's an internal helper. Its slashes translation is a side effect that you shouldn't expect or rely on.
Which is preferred?
I'm not sure, see the rest of wxFileSystem (and related classes) docs.
comment:8 in reply to: ↑ 7 Changed 10 years ago by helser
Replying to vaclavslavik:
Replying to helser:
wxString filename = "C:\\data\\my_file.txt"; wxMemoryFSHandler::AddFile(filename, "some content");As I said, this is wrong, the filename argument should be URI part, e.g. "/data/my_file.txt" here.
I agree, currently this doesn't work. I expected it to work based on the documentation, and I would like it to work for my current application. I'm caching a set of files in memory, that are quick enough to generate for some sources that they don't need to be stored on disk, but for larger sources they might need to be saved on disk.
I would guess this is a typical use-case for wxMemoryFS - sometimes the files are on disk, sometimes they are in memory. I would like to my app to use it by adding 'memory:' to the filename I retrieve, but I am willing to add a few more steps if needed.
2: Change the 'filename' argument to a 'location' argument, and make some forms illegal
- an assert in the 'AddFile' to check for illegal characters, like '\'
- documentation changes
Yes, that's what I wrote above. The asserts may be useful, but also relatively expensive, and if they're added there, they should be in other places where wxFileSystem URIs are used.
I was proposing asserts only in the debug build, which would have caught my problem, and wouldn't affect performance in release.
- MakeCorrectPath or something similar is a documented, public, static method
No, it's an internal helper. Its slashes translation is a side effect that you shouldn't expect or rely on.
Can we make available a method that I can expect and rely on? The alternative that I see right now is calling wxFileSystem::FileNameToURL(), and then replacing the leading 'file:' with 'memory:'. (Does anyone do it that way?)
Which is preferred?
I'm not sure, see the rest of wxFileSystem (and related classes) docs.
What are the other common uses for wxMemoryFS? I was kind of expecting it to be similar to wxArchiveFS, which I have not used, but is documented as dealing with filenames that are stored in a Zip file, for example. It seems that platform-legal filenames would be allowed as input. Is this not the case?
I'm pushing towards allowing filenames as input to wxMemoryFS because that's the way I want to use it and expected it to function. I see Vaclav's point coming from http: and wxInternetFSHandler too.
comment:9 Changed 10 years ago by vadz
- Status changed from new to confirmed
I see Vaclav's point too but it's tempting to just add a MakeCorrectPath() call here too because we already do it in other places and it's not clear why shouldn't we do it here as well if we do it inside OpenFile(). I.e. IMO we should either never call MakeCorrectPath() or call it everywhere. And the latter is more backwards compatible, of course.
I don't think MakeCorrectPath() should be made public however. Whatever the wxFS methods should just be documented.
Replying to helser:
Is the above really accurate? I.e. did you really use non-escaped backslashes in a C string like this?