// ***************************************************************** -*- C++ -*- /* * Copyright (C) 2004-2015 Andreas Huggel * * This program is part of the Exiv2 distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. */ /*! @file exiv2app.hpp @brief Defines class Params, used for the command line handling of exiv2 @version $Rev: 3091 $ @author Andreas Huggel (ahu) ahuggel@gmx.net @date 08-Dec-03, ahu: created */ #ifndef EXIV2APP_HPP_ #define EXIV2APP_HPP_ // ***************************************************************************** // included header files #include "utils.hpp" #include "types.hpp" // + standard includes #include #include #include #include #if EXV_HAVE_REGEX #include #endif #if EXV_HAVE_STDINT_H #include #endif #ifndef _MSC_VER #include #include #include #include #endif // ***************************************************************************** // class definitions //! Command identifiers enum CmdId { invalidCmdId, add, set, del, reg }; //! Metadata identifiers // enum MetadataId { invalidMetadataId, iptc, exif, xmp }; //! Metadata identifiers // mdNone=0, mdExif=1, mdIptc=2, mdComment=4, mdXmp=8 enum MetadataId { invalidMetadataId = Exiv2::mdNone , iptc = Exiv2::mdIptc , exif = Exiv2::mdExif , xmp = Exiv2::mdXmp } ; //! Structure for one parsed modification command struct ModifyCmd { //! C'tor ModifyCmd() : cmdId_(invalidCmdId), metadataId_(invalidMetadataId), typeId_(Exiv2::invalidTypeId), explicitType_(false) {} CmdId cmdId_; //!< Command identifier std::string key_; //!< Exiv2 key string MetadataId metadataId_; //!< Metadata identifier Exiv2::TypeId typeId_; //!< Exiv2 type identifier //! Flag to indicate if the type was explicitly specified (true) bool explicitType_; std::string value_; //!< Data }; //! Container for modification commands typedef std::vector ModifyCmds; //! Structure to link command identifiers to strings struct CmdIdAndString { CmdId cmdId_; //!< Commands identifier std::string cmdString_; //!< Command string }; /*! @brief Implements the command line handling for the program. Derives from Util::Getopt to use the command line argument parsing functionality provided there. This class is implemented as a singleton, i.e., there is only one global instance of it, which can be accessed from everywhere. Usage example:
@code #include "params.h" int main(int argc, char* const argv[]) { Params& params = Params::instance(); if (params.getopt(argc, argv)) { params.usage(); return 1; } if (params.help_) { params.help(); return 0; } if (params.version_) { params.version(); return 0; } // do something useful here... return 0; } @endcode */ // zlib-1.2.8/contrib/iostream2/zstream.h: #if defined(_WIN32) # include # include # define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) #else # define SET_BINARY_MODE(file) #endif // zlib-1.2.8/test/minigzip.c: SET_BINARY_MODE(stdin); class Params : public Util::Getopt { private: std::string optstring_; public: //! Container for command files typedef std::vector CmdFiles; //! Container for commands from the command line typedef std::vector CmdLines; //! Container to store filenames. typedef std::vector Files; //! Container for preview image numbers typedef std::set PreviewNumbers; //! Container for greps typedef exv_grep_keys_t Greps; //! Container for keys typedef std::vector Keys; /*! @brief Controls all access to the global Params instance. @return Reference to the global Params instance. */ static Params& instance(); //! Destructor void cleanup(); //! Enumerates print modes enum PrintMode { pmSummary, pmList, pmComment, pmPreview, pmStructure, pmXMP, pmIccProfile, pmRecursive }; //! Individual items to print, bitmap enum PrintItem { prTag = 1, prGroup = 2, prKey = 4, prName = 8, prLabel = 16, prType = 32, prCount = 64, prSize = 128, prValue = 256, prTrans = 512, prHex = 1024, prSet = 2048 }; //! Enumerates common targets, bitmap enum CommonTarget { ctExif = 1, ctIptc = 2, ctComment = 4, ctThumb = 8, ctXmp = 16, ctXmpSidecar = 32, ctPreview = 64, ctIccProfile = 128, ctXmpRaw = 256, ctStdInOut = 512, ctIptcRaw =1024 }; //! Enumerates the policies to handle existing files in rename action enum FileExistsPolicy { overwritePolicy, renamePolicy, askPolicy }; //! Enumerates year, month and day adjustments. enum Yod { yodYear, yodMonth, yodDay }; //! Structure for year, month and day adjustment command line arguments. struct YodAdjust { bool flag_; //!< Adjustment flag. const char* option_; //!< Adjustment option string. long adjustment_; //!< Adjustment value. }; bool help_; //!< Help option flag. bool version_; //!< Version option flag. bool verbose_; //!< Verbose (talkative) option flag. bool force_; //!< Force overwrites flag. bool binary_; //!< Suppress long binary values. bool unknown_; //!< Suppress unknown tags. bool preserve_; //!< Preserve timestamps flag. bool timestamp_; //!< Rename also sets the file timestamp. bool timestampOnly_; //!< Rename only sets the file timestamp. FileExistsPolicy fileExistsPolicy_; //!< What to do if file to rename exists. bool adjust_; //!< Adjustment flag. PrintMode printMode_; //!< Print mode. unsigned long printItems_; //!< Print items. unsigned long printTags_; //!< Print tags (bitmap of MetadataId flags). //! %Action (integer rather than TaskType to avoid dependency). int action_; int target_; //!< What common target to process. long adjustment_; //!< Adjustment in seconds. YodAdjust yodAdjust_[3]; //!< Year, month and day adjustment info. std::string format_; //!< Filename format (-r option arg). bool formatSet_; //!< Whether the format is set with -r CmdFiles cmdFiles_; //!< Names of the modification command files CmdLines cmdLines_; //!< Commands from the command line ModifyCmds modifyCmds_; //!< Parsed modification commands std::string jpegComment_; //!< Jpeg comment to set in the image std::string directory_; //!< Location for files to extract/insert std::string suffix_; //!< File extension of the file to insert Files files_; //!< List of non-option arguments. PreviewNumbers previewNumbers_; //!< List of preview numbers Greps greps_; //!< List of keys to 'grep' from the metadata Keys keys_; //!< List of keys to match from the metadata std::string charset_; //!< Charset to use for UNICODE Exif user comment Exiv2::DataBuf stdinBuf; //! < DataBuf with the binary bytes from stdin private: //! Pointer to the global Params object. static Params* instance_; //! Initializer for year, month and day adjustment info. static const YodAdjust emptyYodAdjust_[]; bool first_; private: /*! @brief Default constructor. Note that optstring_ is initialized here. The c'tor is private to force instantiation through instance(). */ Params() : optstring_(":hVvqfbuktTFa:Y:O:D:r:p:P:d:e:i:c:m:M:l:S:g:K:n:Q:"), help_(false), version_(false), verbose_(false), force_(false), binary_(true), unknown_(true), preserve_(false), timestamp_(false), timestampOnly_(false), fileExistsPolicy_(askPolicy), adjust_(false), printMode_(pmSummary), printItems_(0), printTags_(Exiv2::mdNone), action_(0), target_(ctExif|ctIptc|ctComment|ctXmp), adjustment_(0), format_("%Y%m%d_%H%M%S"), formatSet_(false), first_(true) { yodAdjust_[yodYear] = emptyYodAdjust_[yodYear]; yodAdjust_[yodMonth] = emptyYodAdjust_[yodMonth]; yodAdjust_[yodDay] = emptyYodAdjust_[yodDay]; } //! Prevent copy-construction: not implemented. Params(const Params& rhs); //! @name Helpers //@{ int setLogLevel(const std::string& optarg); int evalGrep( const std::string& optarg); int evalKey( const std::string& optarg); int evalRename(int opt, const std::string& optarg); int evalAdjust(const std::string& optarg); int evalYodAdjust(const Yod& yod, const std::string& optarg); int evalPrint(const std::string& optarg); int evalPrintFlags(const std::string& optarg); int evalDelete(const std::string& optarg); int evalExtract(const std::string& optarg); int evalInsert(const std::string& optarg); int evalModify(int opt, const std::string& optarg); //@} public: /*! @brief Call Getopt::getopt() with optstring, to inititate command line argument parsing, perform consistency checks after all command line arguments are parsed. @param argc Argument count as passed to main() on program invocation. @param argv Argument array as passed to main() on program invocation. @return 0 if successful, >0 in case of errors. */ int getopt(int argc, char* const argv[]); //! Handle options and their arguments. virtual int option(int opt, const std::string& optarg, int optopt); //! Handle non-option parameters. virtual int nonoption(const std::string& argv); //! Print a minimal usage note to an output stream. void usage(std::ostream& os =std::cout) const; //! Print further usage explanations to an output stream. void help(std::ostream& os =std::cout) const; //! Print version information to an output stream. void version(bool verbose =false, std::ostream& os =std::cout) const; //! Print target_ static std::string printTarget(std::string before,int target,bool bPrint=false,std::ostream& os=std::cout); //! getStdin copy binary data read from stdin by constructor to a DataBuf /* There is a quite deliberate strategy to read stdin by the constructor and this is not deferred until it is known if stdin data is required. stdin can be used by multiple images in the exiv2 command line: For example: $ cat foo.icc | exiv2 -iC- a.jpg b.jpg c.jpg will modify the ICC profile in several images. */ void getStdin(Exiv2::DataBuf& buf) { if ( stdinBuf.size_ == 0 ) { // copy stdin to stdinBuf SET_BINARY_MODE(stdin); #if defined(_MSC_VER) // http://stackoverflow.com/questions/19955617/win32-read-from-stdin-with-timeout INPUT_RECORD record; DWORD numRead; if ( PeekConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &record, 1, &numRead)) { #elif defined(__APPLE__) || defined(__LINUX__) // || defined(__CYGWIN__) // http://stackoverflow.com/questions/34479795/make-c-not-wait-for-user-input/34479916#34479916 fd_set readfds; FD_ZERO (&readfds); FD_SET(STDIN_FILENO, &readfds); struct timeval timeout = { 0,0 }; // if we have something in the pipe, read it if (select(1, &readfds, NULL, NULL, &timeout)) { #endif #if defined(__APPLE__) || defined(__LINUX__) || defined(_MSC_VER) //|| defined(__CYGWIN__) const int buff_size = 4*1028; Exiv2::byte* bytes = (Exiv2::byte*)::malloc(buff_size); int nBytes = 0 ; bool more = bytes != NULL; while ( more ) { char buff[buff_size]; int n = (int) fread(buff,1,buff_size,stdin); more = n > 0 ; if ( more ) { bytes = (Exiv2::byte*) realloc(bytes,nBytes+n); memcpy(bytes+nBytes,buff,n); nBytes += n ; } } if ( nBytes ) { stdinBuf.alloc(nBytes); memcpy(stdinBuf.pData_,(const void*)bytes,nBytes); } if ( bytes != NULL ) ::free(bytes) ; } #endif } if ( stdinBuf.size_ ) { buf.alloc(stdinBuf.size_); memcpy(buf.pData_,stdinBuf.pData_,buf.size_); } }; }; // class Params #endif // #ifndef EXIV2APP_HPP_