Check file name is valid windows name - c++

I wanna check if my string is valid windows file path. I was searching around and it seems that there is no reliable method to do that. Also I checked boost filesystem library , and no obvious function exist to do this check , maybe something like is_valid_windows_name

You could use _splitpath() function and parse the output (based on it, you could easily say if your path is valid or not).
See MSDN for additional information.
Note that this function is windows-specific.

I do not believe there is a standard c++ api for that.
Note that the Windows API allows more filenames than the Windows Shell (The filenames the user is allowed to use in windws explorer).
You should have a look at the windows shell api.
Another possibility is to use trial and error, this way you are truly independend of the current filesystem.
The easiest way is to disallow
\ / < > | " : ? *
and you should be fine.

Yes, there is a boost function that does what you want. Take a look at boost::filesystem::windows_name(...). You will need to include boost/filesystem/path.hpp as well as link against the correct (version- and architecture-specific) libboost_system and libboost_filesystem libraries since path is not a header-only lib.

It's a pity even the newest C++17 filesystem library doesn't have a function to verify file names.
You can use the Windows-specific Shell Lightweight Utility function PathFileExists or the Windows API GetFileAttributes and check the last error code specifically for ERROR_INVALID_NAME.
I think it's kind of a misuse (because there really should be a dedicated function for it) but serves the purpose.

Related

Getting specfic files in C++ code from *nix system

I want to get all the files of type A*.txt present in current directory via C++ code. My OS is *Nix system. Also, I want to get the names of such files.
Please suggest how can this be done.
I tried using system command but system doesn't return anything apart a integer which says if command was executed properly or not.
Thanks
There are basically three ways you can go about this.
One is to use basically what you tried before, but using the popen function, which allows you to read the output of the command(s) you run.
The second solution is to use e.g. opendir and readdir or scandir to manually filter and find the files you look for.
The third and easiest way is to use the glob function.
There is actually a fourth way as well, one which is platform independent and more C++-ish than the above methods: Using the Boost filesystem library.

How to check in a portable way that a file path is potentially valid?

I need to determine that a string entered by a user is OK to create a file with that name. My application is built on Qt and runs on Windows and Mac OS.
I've found a check function in boost.filesystem, namely native(). The documentation says, 'Returns true for names considered valid by the operating system's native file systems.' Sounds like what I need, but the function doesn't work properly and returns false always. I've tried both back and forward slashes in the path, and tested the function with both existing and non-existing paths—all these tests failed on Windows. Thanks to chris (see a comment below) who pointed that the function may be intentionally broken (I tend to agree with that).
So the question is: how to achieve what I need?

Finding unique path name for a given input

I'm working on a problem where I need to have a way to convert a user inputted filename to a unique path name. Let's say I let the user specify a path name that points to a file that contains some data. I can then do Data* pData=Open(PathName). Now if the user specifies the same path name again, I'd like to be able to have a table of already opened files and just return a pointer to the same data: Data* pData2=GetOpenedData(PathName). This is easy to accomplish with a simple std::map<std::string,Data*>, the problem is that different values of PathName can point to the same file. The simplest case is on Windows case insensitivity comes into play.
The code is cross platform C++ and I don't have access to .NET stuff (but I'm happy to #ifdef the differences between Windows and UNIX if needed). Does anyone know of either Windows API or POSIX functions that can take a path name and return a unique (to the system) string that I can key off of. The key doesn't have to be the same in both systems (Windows/POSIX), just unique within a running instance of my code.
For now, I'm not worried about links or two ways to get to the same file. Such as in Windows, if I had \myserver\share mapped to S: then \myserver\share\blah and S:\blah are the same file, but I can live with those being thought of as different. But S:\blah and S:\Blah should be the same. If there is a way to make \myserver\share and S:\ also be unique, that's a bonus and I'd be really happy, but I can live without it. (Likewise, if there are multiple links to the same file in UNIX).
Edited to add:
It's not as simple as just doing a case insensitive search in windows. For example: c://data/mydata.dat while that's an "invalid" filename, windows will accept it and it will actualy point to c:\data\mydata.dat
Edited to add another thing:
I'd also like c:\mydirectory\..\blah.dat to be recognized at the same as c:\blah.dat
For Windows, PathCanonicalize() is your friend. The shell path handing package in Windows has a few additional routines that'll help you out.
Unfortunately, I'm not sure what the Unix equivalents to this package is.
For Windows you can store the full path of a resource making all lowercase (or uppercase).
I don't use *nix so can't tell about that. But I believe in *nix systems case does matter (\home\a and \home\A are different). If that is the case then you can omit converting case of user input for *nix.
You can optionally instantiate std::map with a third template argument, which is the comparison function/functor (see e.g. http://www.cplusplus.com/reference/stl/map/). You could provide a case-insensitive string comparison function.
I believe Scott Meyers provides a good example of such a function in Effective STL; I can check this when I get home.

C++, console Application, reading files from directory

I have a directory and I want to read all the text files in it using C++ and having windows OS also using console application
I don't know the files' names or their number
thanks in advance
Take a look at Boost.Filesystem, especially the basic_directory_iterator.
If you want the C++ and portable way, follow the solution by #Space_C0wb0y and use boost.Filesystem, otherwise, if you want to get your hands dirty with the Windows APIs, you can use the FindFirstFile/FindNextFile/FindClose functions.
You can find here an example related to them.

All users path?

In C# I can do the following:
DirectoryInfo di = new DirectoryInfo(System.Environment.GetEnvironmentVariable("ALLUSERSPROFILE"));
Which will get me the path to the all users profile.
In C++ I can use the SHGetFolderPath, but it does not seem to have a CSLID for all users.
Is there an equlivant function that I can blow the %ALLUSERSPROFILE% out to its path value?
Use SHGetFolderPath with CSIDL_COMMON_APPDATA. Or SHGetKnownFolderPath since Vista with FOLDERID_ProgramData.
Alternatively, use the .NET native Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)
Use ExpandEnvironmentStrings to expand the %ALLUSERSPROFILE% string. This method is part of Kernel32.dll.
For most purposes, you should be able to use SHGetFolderPath with one of the CSIDL_COMMON_... values (see here for a complete list) to get the subdirectory of the all users' path that you're interested in. (For Windows Vista and above, you can use SHGetKnownFolderPath with one of the FOLDERID_Public... values; see here.)
Note that in certain security situations that folder might not even be a real folder. There not being a CSIDL_ for it is always a strong hint that you're off the beaten path.
Are you sure you're not better off with _APPDATA?
You could use the getenv CRT function to get the value of the ALLUSERSPROFILE environment variable in much the same way as you are for C#.