diff --git a/include/osgDB/FileUtils b/include/osgDB/FileUtils index 8103cd750..3eb1b7c74 100644 --- a/include/osgDB/FileUtils +++ b/include/osgDB/FileUtils @@ -23,6 +23,26 @@ namespace osgDB { +/** Overload of the standard fopen function. If OSG_USE_UTF8_FILENAME is defined, + * filename will be expanded from UTF8 to UTF16 and _wfopen will be called. */ +extern OSGDB_EXPORT FILE* fopen(const char* filename, const char* mode); + +/** Make a new directory. Returns true if directory exists or was created. */ +extern OSGDB_EXPORT bool makeDirectory( const std::string &directoryPath ); + +/** Make a new directory for a given file. */ +extern OSGDB_EXPORT bool makeDirectoryForFile( const std::string &filePath ); + +/** Get current working directory. */ +extern OSGDB_EXPORT std::string getCurrentWorkingDirectory( void ); + +/** Set current working directory. */ +extern OSGDB_EXPORT bool setCurrentWorkingDirectory( const std::string &newCurrentWorkingDirectory ); + + +/** return true if a file exists. */ +extern OSGDB_EXPORT bool fileExists(const std::string& filename); + enum FileType { FILE_NOT_FOUND, @@ -30,26 +50,6 @@ enum FileType DIRECTORY }; -// Overload of the standard fopen function. If OSG_USE_UTF8_FILENAME is defined, -// filename will be expanded from UTF8 to UTF16 and _wfopen will be called. -extern OSGDB_EXPORT FILE* fopen(const char* filename, const char* mode); - -// Make a new directory. Returns true if directory exists or was created. -extern OSGDB_EXPORT bool makeDirectory( const std::string &directoryPath ); - -// Make a new directory for a given file. -extern OSGDB_EXPORT bool makeDirectoryForFile( const std::string &filePath ); - -// Get current working directory. -extern OSGDB_EXPORT std::string getCurrentWorkingDirectory( void ); - -// Set current working directory. -extern OSGDB_EXPORT bool setCurrentWorkingDirectory( const std::string &newCurrentWorkingDirectory ); - - -/** return true if a file exists. */ -extern OSGDB_EXPORT bool fileExists(const std::string& filename); - /** return type of file. */ extern OSGDB_EXPORT FileType fileType(const std::string& filename); @@ -72,6 +72,29 @@ extern OSGDB_EXPORT DirectoryContents getDirectoryContents(const std::string& di +namespace FileOpResult { + enum Value + { + OK, /**< Operation done. */ + SOURCE_EQUALS_DESTINATION, /**< Operation is useless (source == destination). */ + BAD_ARGUMENT, + SOURCE_MISSING, /**< Source file doesn't exist. */ + SOURCE_NOT_OPENED, /**< Error opening source file. */ + DESTINATION_NOT_OPENED, /**< Error opening destination file. */ + READ_ERROR, + WRITE_ERROR + }; +} + +/** Copy a file to another location, overwriting if necessary. + * You must provide full path for both source and destination. + * \return true on success, or if source and destination are the same. + * \todo Replace the implementation with filesystem functions from TR2 when available. +*/ +extern OSGDB_EXPORT FileOpResult::Value copyFile(const std::string & source, const std::string & destination); + + + inline void setDataFilePathList(const FilePathList& filepath) { osgDB::Registry::instance()->setDataFilePathList(filepath); } inline void setDataFilePathList(const std::string& paths) { osgDB::Registry::instance()->setDataFilePathList(paths); } @@ -102,6 +125,6 @@ extern OSGDB_EXPORT void convertStringPathIntoFilePathList(const std::string& pa extern OSGDB_EXPORT void appendPlatformSpecificLibraryFilePaths(FilePathList& filepath); extern OSGDB_EXPORT void appendPlatformSpecificResourceFilePaths(FilePathList& filepath); -} +} // namespace osgDB #endif diff --git a/src/osgDB/FileUtils.cpp b/src/osgDB/FileUtils.cpp index 4999fcf87..b799f34f2 100644 --- a/src/osgDB/FileUtils.cpp +++ b/src/osgDB/FileUtils.cpp @@ -530,6 +530,75 @@ static void appendInstallationLibraryFilePaths(osgDB::FilePathList& filepath) #endif // unix getDirectoryContexts +osgDB::FileOpResult::Value osgDB::copyFile(const std::string & source, const std::string & destination) +{ + if (source.empty() || destination.empty()) + { + osg::notify(osg::INFO) << "copyFile(): Empty file name." << std::endl; + return FileOpResult::BAD_ARGUMENT; + } + + // Check if source and destination are the same + if (source == destination || osgDB::getRealPath(source) == osgDB::getRealPath(destination)) + { + osg::notify(osg::INFO) << "copyFile(): Source and destination point to the same file: source=" << source << ", destination=" << destination << std::endl; + return FileOpResult::SOURCE_EQUALS_DESTINATION; + } + + // Check if source file exists + if (!osgDB::fileExists(source)) + { + osg::notify(osg::INFO) << "copyFile(): Source file does not exist: " << source << std::endl; + return FileOpResult::SOURCE_MISSING; + } + + // Open source file + osgDB::ifstream fin(source.c_str(), std::ios::in | std::ios::binary); + if (!fin) + { + osg::notify(osg::NOTICE) << "copyFile(): Can't read source file: " << source << std::endl; + return FileOpResult::SOURCE_NOT_OPENED; // Return success since it's not an output error. + } + + // Ensure the directory exists or else the FBX SDK will fail + if (!osgDB::makeDirectoryForFile(destination)) + { + osg::notify(osg::INFO) << "Can't create directory for file '" << destination << "'. Copy may fail creating the file." << std::endl; + } + + // Open destination file + osgDB::ofstream fout(destination.c_str(), std::ios::out | std::ios::binary | std::ios::trunc); + if (!fout) + { + osg::notify(osg::NOTICE) << "copyFile(): Can't write destination file: " << destination << std::endl; + return FileOpResult::DESTINATION_NOT_OPENED; + } + + // Copy file + const unsigned int BUFFER_SIZE = 10240; + osgDB::ifstream::char_type buffer[BUFFER_SIZE]; + for(; fin.good() && fout.good() && !fin.eof(); ) + { + fin.read(buffer, BUFFER_SIZE); + fout.write(buffer, fin.gcount()); + } + + if (!fout.good()) + { + osg::notify(osg::NOTICE) << "copyFile(): Error writing destination file: " << destination << std::endl; + return FileOpResult::WRITE_ERROR; + } + + if (!fin.eof()) + { + osg::notify(osg::NOTICE) << "copyFile(): Error reading source file: " << source << std::endl; + return FileOpResult::READ_ERROR; + } + + return FileOpResult::OK; +} + + ///////////////////////////////////////////////////////////////////////////////////////////////// // // Implementation of appendPlatformSpecificLibraryFilePaths(..)