Hi Nikolay,
SplitCFA is now ready for inclusion in the 1.8.0 Ripley release (I'll send you the source code by private email). Thank you for a new nice and useful tool.
This tool brings up an important development topic that I want to comment briefly here: recursive directory search. In SplitCFA, you implement a recursive search to find DSLR raw and OSC FITS frames.
Recursive directory search operations are potentially dangerous. When they are used just to load or analyze files, the potential risks are normally not very high. However, imagine that you are gathering files as part of a file copy, move or delete task. In such cases the risks are extremely high, and if not well designed and implemented, a failing file search routine can lead to an unrecoverable disaster.
Since the topic is of special importance, here is a PCL routine that implements recursive directory search in a secure way. Note that the security checks are not just to protect the search operation (some of the checks look for theoretically impossible conditions under normal operation), but to protect it from mistakes that we developers/programmers can make---and
do make, no matter how experienced we are.
/*
* Secure recursive directory search routine.
*/
static
void SearchDirectory_Recursive( StringList& foundFiles, const String& whereToFind, const String& baseDir )
{
if ( whereToFind.Has( ".." ) )
throw Error( "Attempt to climb up the filesystem in file search operation: " + whereToFind );
if ( !whereToFind.BeginsWith( baseDir ) )
throw Error( "Attempt to walk on a parallel directory tree in file search operation: '" + whereToFind
+ "'; expected to be rooted at '" + baseDir + "'" );
if ( !File::DirectoryExists( whereToFind ) )
throw Error( "Nonexistent directory in file search operation: " + whereToFind );
String currentDir = whereToFind;
if ( !currentDir.EndsWith( '/' ) )
currentDir += '/';
StringList directories;
FindFileInfo info;
for ( File::Find f( currentDir + "*" ); f.NextItem( info ); )
if ( info.IsDirectory() )
{
if ( info.name != "." && info.name != ".." )
directories.Add( info.name );
}
else
{
String ext = File::ExtractExtension( info.name ).LowerCase();
if ( ext == ".cr2" || ext == ".fit" || ext == ".fits" || ext == ".fts" || ext == ".nef" || ext == ".dng" )
foundFiles.Add( currentDir + info.name );
}
for ( StringList::const_iterator i = directories.Begin(); i != directories.End(); ++i )
SearchDirectory_Recursive( foundFiles, currentDir + *i, baseDir );
}
static
StringList SearchDirectory( const String& whereToFind )
{
StringList foundFiles;
try
{
SearchDirectory_Recursive( foundFiles, whereToFind, whereToFind );
}
ERROR_HANDLER
return foundFiles;
}
This routine can easily be modified to make it more flexible (e.g., to search for an arbitrary set of file extensions), or to adapt it to different requirements. The important thing is that a mistake such as:
void DeleteThem( const String& whereToDelete )
{
StringList filesToDelete = SearchDirectory( whereToDelete );
for ( StringList::const_iterator i = filesToDelete.Begin(); i != filesToDelete.End(); ++i )
DestroyItWithoutCompassion( *i );
}
// ...
DeleteThem( ".." );
will not cause what you are thinking on right now. But better don't try it, though, just in case
On a side note, I have included .nef and .dng files besides .cr2, so SplitCFA can also work with Nikon cameras and other brands that use the DNG format. This should probably be extended to cover other camera formats as well.