pto_move.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00012 /*  This program is free software; you can redistribute it and/or
00013  *  modify it under the terms of the GNU General Public
00014  *  License as published by the Free Software Foundation; either
00015  *  version 2 of the License, or (at your option) any later version.
00016  *
00017  *  This software is distributed in the hope that it will be useful,
00018  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020  *  General Public License for more details.
00021  *
00022  *  You should have received a copy of the GNU General Public
00023  *  License along with this software. If not, see
00024  *  <http://www.gnu.org/licenses/>.
00025  *
00026  */
00027 
00028 #include "hugin_config.h"
00029 #include <iostream>
00030 #include <string>
00031 #include <fstream>
00032 #ifdef HAVE_STD_FILESYSTEM
00033 #include <filesystem>
00034 namespace fs = std::tr2::sys;
00035 #define OVERWRITE_EXISTING std::tr2::sys::copy_options::overwrite_existing
00036 #else
00037 #define BOOST_FILESYSTEM_VERSION 3
00038 #ifdef __GNUC__
00039   #include "hugin_config.h"
00040   #include <boost/version.hpp>
00041   #if BOOST_VERSION<105700
00042     #if BOOST_VERSION>=105100
00043       // workaround a bug in boost filesystem
00044       // boost filesystem is probably compiled with C++03
00045       // but Hugin is compiled with C++11, this results in
00046       // conflicts in boost::filesystems at a enum
00047       // see https://svn.boost.org/trac/boost/ticket/6779
00048       #define BOOST_NO_CXX11_SCOPED_ENUMS
00049     #else
00050       #define BOOST_NO_SCOPED_ENUMS
00051     #endif
00052   #endif
00053 #endif
00054 #include <boost/filesystem.hpp>
00055 namespace fs = boost::filesystem;
00056 #define OVERWRITE_EXISTING boost::filesystem::copy_option::overwrite_if_exists
00057 #endif
00058 #include <getopt.h>
00059 #include <panodata/Panorama.h>
00060 #include <hugin_utils/stl_utils.h>
00061 
00062 std::string IncludeTrailingDelimiter(std::string path)
00063 {
00064     std::string s=path;
00065 #ifdef _WIN32
00066     if(s.compare(s.length()-1,1,"\\")!=0 && s.compare(s.length()-1,1,"/")!=0)
00067     {
00068         s.append("\\");
00069     };
00070 #else
00071     if(s.compare(s.length()-1,1,"/")!=0)
00072     {
00073         s.append("/");
00074     };
00075 #endif
00076     return s;
00077 };
00078 
00079 // rebase a filename from relative to srcPath to relative to destPath and return absolute new dest path
00080 bool RebaseFilename(fs::path srcFile, fs::path& destFile, std::string srcPath, std::string destPath)
00081 {
00082     fs::path input=fs::absolute(srcFile);
00083     std::string fullInputPath=input.string();
00084     std::string srcPathWithTrailingDelimiter=IncludeTrailingDelimiter(srcPath);
00085     if(fullInputPath.compare(0, srcPathWithTrailingDelimiter.length(), srcPathWithTrailingDelimiter)!=0)
00086     {
00087         return false;
00088     };
00089     fullInputPath.replace(0, srcPathWithTrailingDelimiter.length(), IncludeTrailingDelimiter(destPath));
00090     destFile=fs::path(fullInputPath);
00091     return true;
00092 };
00093 
00094 bool checkDestinationDirectory(std::string dir, fs::path& pathTo)
00095 {
00096     pathTo=fs::path(dir);
00097     try
00098     {
00099         // check if a destination directory is given
00100         if(pathTo.extension().string().length()>0)
00101         {
00102             std::cerr << "ERROR: Your destination is a file. Copy/Move several files to " << std::endl
00103                       << "a single file is not allowed." << std::endl
00104                       << "Canceled operation." << std::endl;
00105             return false;
00106         };
00107         // create destination directory if not exists
00108         if(!fs::exists(pathTo))
00109         {
00110             if(!fs::create_directories(pathTo))
00111             {
00112                 std::cerr << "ERROR: Could not create destination directory: " << pathTo.string() << std::endl
00113                           << "Maybe you have not sufficient rights to create this directory." << std::endl;
00114                 return false;
00115             };
00116         };
00117     }
00118     catch (const fs::filesystem_error& ex)
00119     {
00120         std::cout << ex.what() << std::endl;
00121         return false;
00122     }
00123     pathTo=fs::absolute(pathTo);
00124     return true;
00125 };
00126 
00127 typedef std::vector<fs::path> pathVec;
00128 
00129 bool PTOCopyMove(bool movingFile, fs::path src, fs::path dest, bool overwriteAllFiles)
00130 {
00131     fs::path destFile(hugin_utils::GetAbsoluteFilename(dest.string()));
00132     std::cout << (movingFile ? "Moving project file  " : "Copying project file ") << src.filename() << std::endl
00133               << "  from " << src.parent_path() << std::endl
00134               << "  to " << destFile.parent_path() << std::endl;
00135     // open project file
00136     HuginBase::Panorama pano;
00137     std::string input=src.string();
00138     std::ifstream prjfile(input.c_str());
00139     if (!prjfile.good())
00140     {
00141         std::cerr << "ERROR: Could not open script: " << src.string() << std::endl;
00142         return false;
00143     }
00144     std::string inputPathPrefix=hugin_utils::getPathPrefix(input);
00145     std::string outputPathPrefix=hugin_utils::getPathPrefix(destFile.string());
00146     pano.setFilePrefix(inputPathPrefix);
00147     AppBase::DocumentData::ReadWriteError err = pano.readData(prjfile);
00148     if (err != AppBase::DocumentData::SUCCESSFUL)
00149     {
00150         std::cerr << "ERROR: error while parsing panos tool script: " << input << std::endl
00151                   << "AppBase::DocumentData::ReadWriteError code: " << err << std::endl;
00152         return false;
00153     };
00154     prjfile.close();
00155     if(pano.getNrOfImages()==0)
00156     {
00157         std::cerr << "ERROR: project " << input << " does not contain any images." << std::endl;
00158         return false;
00159     };
00160     pathVec imagesFrom, imagesTo;
00161     // check if all images exists
00162     for(size_t i=0; i<pano.getNrOfImages(); i++)
00163     {
00164         fs::path p(pano.getImage(i).getFilename());
00165         imagesFrom.push_back(p);
00166         if(!fs::exists(p) || !fs::is_regular_file(p))
00167         {
00168             std::cerr << "ERROR: image " << p.string() << " not found on disc." << std::endl
00169                       << "Skipping project " << input << std::endl;
00170             return false;
00171         };
00172         p=fs::absolute(p);
00173         // now build now image filename
00174         fs::path newFilename;
00175         if(RebaseFilename(p, newFilename, inputPathPrefix, outputPathPrefix))
00176         {
00177             pano.setImageFilename(i, newFilename.string());
00178             imagesTo.push_back(newFilename);
00179         };
00180     };
00181     if(imagesFrom.size()>0)
00182     {
00183         if(imagesFrom.size()==imagesTo.size())
00184         {
00185             fs::path targetDir(destFile);
00186             targetDir.remove_filename();
00187             if(!checkDestinationDirectory(targetDir.string(), targetDir))
00188             {
00189                 return false;
00190             };
00191             if(fs::exists(destFile) && !overwriteAllFiles)
00192             {
00193                 std::cout << "Project file " << destFile << " does already exists." << std::endl
00194                           << "  Overwrite this file? [Y|N] ";
00195                 std::string userAnswer;
00196                 while(userAnswer.length()==0)
00197                 {
00198                     std::cin >> userAnswer;
00199                 };
00200                 userAnswer=hugin_utils::toupper(userAnswer);
00201                 if(userAnswer!="YES" && userAnswer!="Y")
00202                 {
00203                     std::cout << std::endl << "Moving/Copying of project file " << input << " canceled." << std::endl << std::endl;
00204                     return false;
00205                 }
00206             };
00207             //copy/moving images
00208             for(size_t i=0; i<imagesFrom.size(); i++)
00209             {
00210                 // check if target directory already exists
00211                 targetDir=fs::path(imagesTo[i]);
00212                 targetDir.remove_filename();
00213                 if(!checkDestinationDirectory(targetDir.string(), targetDir))
00214                 {
00215                     return false;
00216                 };
00217                 //check if target image file already exists
00218                 if(fs::exists(imagesTo[i]) && !overwriteAllFiles)
00219                 {
00220                     std::cout << "Images file " << imagesTo[i] << " does already exists." << std::endl
00221                               << "  Overwrite this file? [Y|N] ";
00222                     std::string userAnswer;
00223                     while(userAnswer.length()==0)
00224                     {
00225                         std::cin >> userAnswer;
00226                     };
00227                     userAnswer=hugin_utils::toupper(userAnswer);
00228                     if(userAnswer!="YES" && userAnswer!="Y")
00229                     {
00230                         std::cout << std::endl << "Moving/Copying of project file " << input << " canceled." << std::endl << std::endl;
00231                         return false;
00232                     }
00233                 };
00234                 if(movingFile)
00235                 {
00236                     try
00237                     {
00238                         fs::rename(imagesFrom[i], imagesTo[i]);
00239                     }
00240                     catch (const fs::filesystem_error& ex)
00241                     {
00242                         std::cout << ex.what() << std::endl;
00243                         return false;
00244                     }
00245                 }
00246                 else
00247                 {
00248                     try
00249                     {
00250                         fs::copy_file(imagesFrom[i], imagesTo[i], OVERWRITE_EXISTING);
00251                     }
00252                     catch (const fs::filesystem_error& ex)
00253                     {
00254                         std::cout << ex.what() << std::endl;
00255                         return false;
00256                     }
00257                 };
00258             }; // for loop for all images
00259             // now create pano file in new destination
00260             // write output
00261             HuginBase::UIntSet imgs;
00262             fill_set(imgs, 0, pano.getNrOfImages()-1);
00263             std::ofstream of(destFile.string().c_str());
00264             pano.printPanoramaScript(of, pano.getOptimizeVector(), pano.getOptions(), imgs, false, outputPathPrefix);
00265             of.close();
00266             if(movingFile)
00267             {
00268                 try
00269                 {
00270                     fs::remove(src);
00271                 }
00272                 catch (const fs::filesystem_error& ex)
00273                 {
00274                     std::cout << "Could not remove original file: " << input << std::endl;
00275                     std::cout << ex.what() << std::endl;
00276                     return false;
00277                 }
00278             };
00279         }
00280         else
00281         {
00282             // the images in the project file are not all relative to the same base path
00283             std::cout << "WARNING: Images location in project file are not consistent. " << std::endl
00284                       << "So don't move/copy project file " << src.string() << std::endl;
00285             return false;
00286         };
00287     }
00288     else
00289     {
00290         // now create pano file in new destination, project contains images in paths
00291         // not relative to base directory
00292         // so create only the new project file without copying/moving image files
00293         HuginBase::UIntSet imgs;
00294         fill_set(imgs, 0, pano.getNrOfImages()-1);
00295         std::ofstream of(destFile.string().c_str());
00296         pano.printPanoramaScript(of, pano.getOptimizeVector(), pano.getOptions(), imgs, false, outputPathPrefix);
00297         of.close();
00298         if(movingFile)
00299         {
00300             try
00301             {
00302                 fs::remove(src);
00303             }
00304             catch (const fs::filesystem_error& ex)
00305             {
00306                 std::cout << "Could not remove original file: " << input << std::endl;
00307                 std::cout << ex.what() << std::endl;
00308                 return false;
00309             }
00310         };
00311     };
00312     return true;
00313 };
00314 
00315 template <class iteratorType>
00316 bool iterateFileSystem(std::string src, pathVec& projectFiles)
00317 {
00318     try
00319     {
00320         for(iteratorType it(src); it != iteratorType(); it++)
00321         {
00322             std::string ext=hugin_utils::toupper(it->path().extension().string());
00323             if(ext==".PTO")
00324             {
00325                 projectFiles.push_back(*it);
00326             };
00327         }
00328     }
00329     catch(fs::filesystem_error& e)
00330     {
00331         std::cout << e.what() << std::endl;
00332         return false;
00333     }
00334     return true;
00335 };
00336 
00337 void SearchPTOFilesInDirectory(pathVec& projectFiles, std::string src, bool recursive)
00338 {
00339     if(recursive)
00340     {
00341         iterateFileSystem<fs::recursive_directory_iterator>(src, projectFiles);
00342     }
00343     else
00344     {
00345         iterateFileSystem<fs::directory_iterator>(src, projectFiles);
00346     };
00347 };
00348 
00349 static void usage(const char* name)
00350 {
00351     std::cout << name << ": move a project file with all images in it" << std::endl
00352               << name << " version " << hugin_utils::GetHuginVersion() << std::endl
00353               << std::endl
00354               << "Usage:  pto_move [options] path1/source.pto path2/dest.pto" << std::endl
00355               << "             Rename project file path1/source.pto to " << std::endl
00356               << "             path2/dest.pto. All images contained in the project will" << std::endl
00357               << "             be moved accordingly." << std::endl << std::endl
00358               << "        pto_move [options] sourceFolder destFolder" << std::endl
00359               << "             Moves all project files in the source folder to " << std::endl
00360               << "             the destination folder including all images." << std::endl
00361               << std::endl
00362               << "Options: " << std::endl
00363               << "  --copy       Copy project files and images instead of moving" << std::endl
00364               << "  --recursive  Only effective in use case 2. Go recursive in the" << std::endl
00365               << "               the source folder and move all project files with images" << std::endl
00366               << "               to destination folder by maintaining the folder structure" << std::endl
00367               << "               relative to source folder." << std::endl
00368               << "  --overwrite  Overwrite all existing files. Otherwise you will be asked" << std::endl
00369               << "               for each existing file." << std::endl
00370               << std::endl
00371               << std::endl;
00372 };
00373 
00374 int main(int argc, char* argv[])
00375 {
00376     // parse arguments
00377     const char* optstring = "croh";
00378 
00379     static struct option longOptions[] =
00380     {
00381         {"copy", no_argument, NULL, 'c' },
00382         {"recursive", no_argument, NULL, 'r' },
00383         {"overwrite", no_argument, NULL, 'o' },
00384         {"help", no_argument, NULL, 'h' },
00385         0
00386     };
00387 
00388     bool movingFiles=true; //movingFiles: false->copy, true->move
00389     bool recursive=false;
00390     bool forceOverwrite=false;
00391     int c;
00392     while ((c = getopt_long (argc, argv, optstring, longOptions,nullptr)) != -1)
00393     {
00394         switch (c)
00395         {
00396             case 'h':
00397                 usage(hugin_utils::stripPath(argv[0]).c_str());
00398                 return 0;
00399             case 'c':
00400                 movingFiles=false;
00401                 break;
00402             case 'r':
00403                 recursive=true;
00404                 break;
00405             case 'o':
00406                 forceOverwrite=true;
00407                 break;
00408             case ':':
00409             case '?':
00410                 // missing argument or invalid switch
00411                 return 1;
00412                 break;
00413             default:
00414                 // this should not happen
00415                 abort();
00416         }
00417     }
00418 
00419     if(argc-optind<2)
00420     {
00421         std::cerr << hugin_utils::stripPath(argv[0]) << ": You need to give at least a source and a destination project file or directory." << std::endl;
00422         return 1;
00423     };
00424 
00425     try
00426     {
00427         fs::path p(argv[optind]);
00428         if(fs::exists(p))
00429         {
00430             p=fs::absolute(p);
00431             if(fs::is_directory(p))
00432             {
00433                 // first parameter is a directory
00434                 fs::path pathTo;
00435                 if(!checkDestinationDirectory(std::string(argv[argc-1]), pathTo))
00436                 {
00437                     return 1;
00438                 };
00439                 // search all pto files in directory
00440                 pathVec projectFiles;
00441                 std::cout << "Searching project files in " << p << std::endl;
00442                 SearchPTOFilesInDirectory(projectFiles, p.string(), recursive);
00443                 if(projectFiles.size()==0)
00444                 {
00445                     std::cout << "No project files found in given directory " << p.string() << std::endl;
00446                     return 0;
00447                 };
00448                 std::cout << "Found " << projectFiles.size() << " project files." << std::endl << std::endl;
00449                 for(pathVec::const_iterator it=projectFiles.begin(); it!=projectFiles.end(); ++it)
00450                 {
00451                     fs::path newPath;
00452                     if(RebaseFilename(*it, newPath, p.string(), pathTo.string()))
00453                     {
00454                         PTOCopyMove(movingFiles, *it, newPath, forceOverwrite);
00455                     };
00456                 };
00457             }
00458             else
00459             {
00460                 if(argc-optind>2)
00461                 {
00462                     // several files given
00463                     // check if destination is a directory and create it if necessary
00464                     fs::path pathTo;
00465                     if(!checkDestinationDirectory(std::string(argv[argc-1]), pathTo))
00466                     {
00467                         return 1;
00468                     };
00469                     while(optind<argc-1)
00470                     {
00471                         p=fs::path(argv[optind]);
00472                         std::string ext=hugin_utils::toupper(p.extension().string());
00473                         // work only on pto files
00474                         if(ext==".PTO")
00475                         {
00476                             if(fs::exists(p) && fs::is_regular_file(p))
00477                             {
00478                                 p=fs::absolute(p);
00479                                 fs::path newPath = pathTo / p.filename();
00480                                 PTOCopyMove(movingFiles, p, newPath, forceOverwrite);
00481                             }
00482                             else
00483                             {
00484                                 std::cout << "WARNING: File " << p << " does not exists" << std::endl
00485                                           << "Skipping this file." << std::endl;
00486                             };
00487                         };
00488                         optind++;
00489                     };
00490                 }
00491                 else
00492                 {
00493                     // exactly 2 files given
00494                     fs::path pathTo(argv[argc-1]);
00495                     if(pathTo.extension().string().length()>0)
00496                     {
00497                         // user has given filename with extension
00498                         // so simply copy/move file
00499                         pathTo=fs::absolute(pathTo);
00500                         PTOCopyMove(movingFiles, p, pathTo, forceOverwrite);
00501                     }
00502                     else
00503                     {
00504                         // target is a directory
00505                         if(!checkDestinationDirectory(std::string(argv[argc-1]), pathTo))
00506                         {
00507                             return 1;
00508                         };
00509                         pathTo=pathTo / p.filename();
00510                         if(p==pathTo)
00511                         {
00512                             std::cerr << "ERROR: Target and destination file are the same." << std::endl
00513                                       << "Skipping file processing." << std::endl;
00514                             return 1;
00515                         };
00516                         PTOCopyMove(movingFiles, p, pathTo, forceOverwrite);
00517                     };
00518                 };
00519             };
00520         };
00521     }
00522     catch (const fs::filesystem_error& ex)
00523     {
00524         std::cout << ex.what() << std::endl;
00525     }
00526     return 0;
00527 }

Generated on 22 Jan 2018 for Hugintrunk by  doxygen 1.4.7