Project

General

Profile

Feature #1137 ยป 1173.patch

Robin Mills, 24 Nov 2015 18:27

View differences:

src/actions.cpp (working copy)
528 528
        return printMetadata(image.get());
529 529
    } // Print::printList
530 530

  
531
    int Print::printMetadata(const Exiv2::Image* image)
531
    int Print::printMetadata(const Exiv2::Image* image,std::ostream& out /*=std::cout*/)
532 532
    {
533 533
        bool ret = false;
534 534
        bool noExif = false;
......
536 536
            const Exiv2::ExifData& exifData = image->exifData();
537 537
            for (Exiv2::ExifData::const_iterator md = exifData.begin();
538 538
                 md != exifData.end(); ++md) {
539
                ret |= printMetadatum(*md, image);
539
                ret |= printMetadatum(*md, image,out);
540 540
            }
541 541
            if (exifData.empty()) noExif = true;
542 542
        }
......
546 546
            const Exiv2::IptcData& iptcData = image->iptcData();
547 547
            for (Exiv2::IptcData::const_iterator md = iptcData.begin();
548 548
                 md != iptcData.end(); ++md) {
549
                ret |= printMetadatum(*md, image);
549
                ret |= printMetadatum(*md, image,out);
550 550
            }
551 551
            if (iptcData.empty()) noIptc = true;
552 552
        }
......
556 556
            const Exiv2::XmpData& xmpData = image->xmpData();
557 557
            for (Exiv2::XmpData::const_iterator md = xmpData.begin();
558 558
                 md != xmpData.end(); ++md) {
559
                ret |= printMetadatum(*md, image);
559
                ret |= printMetadatum(*md, image,out);
560 560
            }
561 561
            if (xmpData.empty()) noXmp = true;
562 562
        }
......
601 601
        return result ;
602 602
    }
603 603

  
604
    bool Print::printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* pImage)
604
    bool Print::printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* pImage,std::ostream& out /*=std::cout*/)
605 605
    {
606 606
        if (!grepTag(md.key())) return false;
607 607
        if (!keyTag (md.key())) return false;
......
612 612
        }
613 613
        bool const manyFiles = Params::instance().files_.size() > 1;
614 614
        if (manyFiles) {
615
            std::cout << std::setfill(' ') << std::left << std::setw(20)
615
            out << std::setfill(' ') << std::left << std::setw(20)
616 616
                      << path_ << "  ";
617 617
        }
618 618
        bool first = true;
619 619
        if (Params::instance().printItems_ & Params::prTag) {
620
            if (!first) std::cout << " ";
620
            if (!first) out << " ";
621 621
            first = false;
622
            std::cout << "0x" << std::setw(4) << std::setfill('0')
622
            out << "0x" << std::setw(4) << std::setfill('0')
623 623
                      << std::right << std::hex
624 624
                      << md.tag();
625 625
        }
626 626
        if (Params::instance().printItems_ & Params::prSet) {
627
            if (!first) std::cout << " ";
627
            if (!first) out << " ";
628 628
            first = false;
629
            std::cout << "set" ;
629
            out << "set" ;
630 630
        }
631 631
        if (Params::instance().printItems_ & Params::prGroup) {
632
            if (!first) std::cout << " ";
632
            if (!first) out << " ";
633 633
            first = false;
634
            std::cout << std::setw(12) << std::setfill(' ') << std::left
634
            out << std::setw(12) << std::setfill(' ') << std::left
635 635
                      << md.groupName();
636 636
        }
637 637
        if (Params::instance().printItems_ & Params::prKey) {
638
            if (!first) std::cout << " ";
638
            if (!first) out << " ";
639 639
            first = false;
640
            std::cout << std::setfill(' ') << std::left << std::setw(44)
640
            out << std::setfill(' ') << std::left << std::setw(44)
641 641
                      << md.key();
642 642
        }
643 643
        if (Params::instance().printItems_ & Params::prName) {
644
            if (!first) std::cout << " ";
644
            if (!first) out << " ";
645 645
            first = false;
646
            std::cout << std::setw(27) << std::setfill(' ') << std::left
646
            out << std::setw(27) << std::setfill(' ') << std::left
647 647
                      << md.tagName();
648 648
        }
649 649
        if (Params::instance().printItems_ & Params::prLabel) {
650
            if (!first) std::cout << " ";
650
            if (!first) out << " ";
651 651
            first = false;
652
            std::cout << std::setw(30) << std::setfill(' ') << std::left
652
            out << std::setw(30) << std::setfill(' ') << std::left
653 653
                      << md.tagLabel();
654 654
        }
655 655
        if (Params::instance().printItems_ & Params::prType) {
656
            if (!first) std::cout << " ";
656
            if (!first) out << " ";
657 657
            first = false;
658
            std::cout << std::setw(9) << std::setfill(' ') << std::left;
658
            out << std::setw(9) << std::setfill(' ') << std::left;
659 659
            const char* tn = md.typeName();
660 660
            if (tn) {
661
                std::cout << tn;
661
                out << tn;
662 662
            }
663 663
            else {
664 664
                std::ostringstream os;
665 665
                os << "0x" << std::setw(4) << std::setfill('0') << std::hex << md.typeId();
666
                std::cout << os.str();
666
                out << os.str();
667 667
            }
668 668
        }
669 669
        if (Params::instance().printItems_ & Params::prCount) {
670
            if (!first) std::cout << " ";
670
            if (!first) out << " ";
671 671
            first = false;
672
            std::cout << std::dec << std::setw(3)
672
            out << std::dec << std::setw(3)
673 673
                      << std::setfill(' ') << std::right
674 674
                      << md.count();
675 675
        }
676 676
        if (Params::instance().printItems_ & Params::prSize) {
677
            if (!first) std::cout << " ";
677
            if (!first) out << " ";
678 678
            first = false;
679
            std::cout << std::dec << std::setw(3)
679
            out << std::dec << std::setw(3)
680 680
                      << std::setfill(' ') << std::right
681 681
                      << md.size();
682 682
        }
683 683
        if (Params::instance().printItems_ & Params::prValue) {
684
            if (!first) std::cout << "  ";
684
            if (!first) out << "  ";
685 685
            first = false;
686 686
            if (   Params::instance().binary_
687 687
                && (   md.typeId() == Exiv2::undefined
688 688
                    || md.typeId() == Exiv2::unsignedByte
689 689
                    || md.typeId() == Exiv2::signedByte)
690 690
                && md.size() > 128) {
691
                std::cout << _("(Binary value suppressed)") << std::endl;
691
                out << _("(Binary value suppressed)") << std::endl;
692 692
                return true;
693 693
            }
694 694
            bool done = false;
......
697 697
                if (pcv) {
698 698
                    Exiv2::CommentValue::CharsetId csId = pcv->charsetId();
699 699
                    if (csId != Exiv2::CommentValue::undefined) {
700
                        std::cout << "charset=\"" << Exiv2::CommentValue::CharsetInfo::name(csId) << "\" ";
700
                        out << "charset=\"" << Exiv2::CommentValue::CharsetInfo::name(csId) << "\" ";
701 701
                    }
702
                    std::cout << pcv->comment(Params::instance().charset_.c_str());
702
                    out << pcv->comment(Params::instance().charset_.c_str());
703 703
                    done = true;
704 704
                }
705 705
            }
706 706
            if (!done) {
707 707
                // #1114 - show negative values for SByte
708 708
                if (md.typeId() != Exiv2::signedByte){
709
                    std::cout << std::dec << md.value();
709
                    out << std::dec << md.value();
710 710
                } else {
711 711
                    int value = md.value().toLong();
712
                    std::cout << std::dec << (value<128?value:value-256);
712
                    out << std::dec << (value<128?value:value-256);
713 713
                }
714 714
            }
715 715
        }
716 716
        if (Params::instance().printItems_ & Params::prTrans) {
717
            if (!first) std::cout << "  ";
717
            if (!first) out << "  ";
718 718
            first = false;
719 719
            if (   Params::instance().binary_
720 720
                && (   md.typeId() == Exiv2::undefined
721 721
                    || md.typeId() == Exiv2::unsignedByte
722 722
                    || md.typeId() == Exiv2::signedByte)
723 723
                && md.size() > 128) {
724
                std::cout << _("(Binary value suppressed)") << std::endl;
724
                out << _("(Binary value suppressed)") << std::endl;
725 725
                return true;
726 726
            }
727 727
            bool done = false;
728 728
            if (0 == strcmp(md.key().c_str(), "Exif.Photo.UserComment")) {
729 729
                const Exiv2::CommentValue* pcv = dynamic_cast<const Exiv2::CommentValue*>(&md.value());
730 730
                if (pcv) {
731
                    std::cout << pcv->comment(Params::instance().charset_.c_str());
731
                    out << pcv->comment(Params::instance().charset_.c_str());
732 732
                    done = true;
733 733
                }
734 734
            }
735
            if (!done) std::cout << std::dec << md.print(&pImage->exifData());
735
            if (!done) out << std::dec << md.print(&pImage->exifData());
736 736
        }
737 737
        if (Params::instance().printItems_ & Params::prHex) {
738
            if (!first) std::cout << std::endl;
738
            if (!first) out << std::endl;
739 739
            first = false;
740 740
            if (   Params::instance().binary_
741 741
                && (   md.typeId() == Exiv2::undefined
742 742
                    || md.typeId() == Exiv2::unsignedByte
743 743
                    || md.typeId() == Exiv2::signedByte)
744 744
                && md.size() > 128) {
745
                std::cout << _("(Binary value suppressed)") << std::endl;
745
                out << _("(Binary value suppressed)") << std::endl;
746 746
                return true;
747 747
            }
748 748
            Exiv2::DataBuf buf(md.size());
749 749
            md.copy(buf.pData_, pImage->byteOrder());
750
            Exiv2::hexdump(std::cout, buf.pData_, buf.size_);
750
            Exiv2::hexdump(out, buf.pData_, buf.size_);
751 751
        }
752
        std::cout << std::endl;
752
        out << std::endl;
753 753
        return true;
754 754
    } // Print::printMetadatum
755 755

  
src/actions.hpp (working copy)
175 175
        //! Return true if key should be printed, else false
176 176
        bool keyTag(const std::string& key);
177 177
        //! Print all metadata in a user defined format
178
        int printMetadata(const Exiv2::Image* image);
178
        int printMetadata(const Exiv2::Image* images,std::ostream& out=std::cout);
179 179
        //! Print a metadatum in a user defined format, return true if something was printed
180
        bool printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* image);
180
        bool printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* image,std::ostream& out);
181 181
        //! Print the label for a summary line
182 182
        void printLabel(const std::string& label) const;
183 183
        //! Print image Structure information
src/exiv2.cpp (working copy)
94 94
                            int j);
95 95

  
96 96
    /*!
97
      @brief Parse metadata modification commands from a steam
98
      @param modifyCmds Reference to a structure to store the parsed commands
99
      @param is input stream
100
      @param filename path to input stream
101
     */
102
    bool parseCmdStream(ModifyCmds& modifyCmds,
103
                        std::istream& is,
104
                        const std::string& filename);
105

  
106
    /*!
97 107
      @brief Parse metadata modification commands from multiple files
98 108
      @param modifyCmds Reference to a structure to store the parsed commands
99 109
      @param cmdFiles Container with the file names
......
610 620
            case 'v': printItems_ |= prValue; break;
611 621
            case 't': printItems_ |= prTrans; break;
612 622
            case 'h': printItems_ |= prHex;   break;
613
            case 'V': printItems_ |= prSet|prValue;break;
623
            case 'V': printItems_ |= prSet|prValue|prKey;break;
624
            case '1': printItems_ |= prFirst; break;
614 625
            default:
615 626
                std::cerr << progname() << ": " << _("Unrecognized print item") << " `"
616 627
                          << optarg[i] << "'\n";
......
846 857

  
847 858
int Params::getopt(int argc, char* const Argv[])
848 859
{
849
	char** argv = new char* [argc+1];
850
	argv[argc] = NULL;
851
	long_t longs;
860
    char** argv = new char* [argc+1];
861
    argv[argc] = NULL;
862
    long_t longs;
852 863

  
853
	longs["--adjust"   ] = "-a";
854
	longs["--binary"   ] = "-b";
855
	longs["--comment"  ] = "-c";
856
	longs["--delete"   ] = "-d";
857
	longs["--days"     ] = "-D";
858
	longs["--force"    ] = "-f";
859
	longs["--Force"    ] = "-F";
860
	longs["--grep"     ] = "-g";
861
	longs["--help"     ] = "-h";
862
	longs["--insert"   ] = "-i";
863
	longs["--keep"     ] = "-k";
864
	longs["--key"      ] = "-K";
865
	longs["--location" ] = "-l";
866
	longs["--modify"   ] = "-m";
867
	longs["--Modify"   ] = "-M";
868
	longs["--encode"   ] = "-n";
869
	longs["--months"   ] = "-O";
870
	longs["--print"    ] = "-p";
871
	longs["--Print"    ] = "-P";
872
	longs["--quiet"    ] = "-q";
873
	longs["--log"      ] = "-Q";
874
	longs["--rename"   ] = "-r";
875
	longs["--suffix"   ] = "-S";
876
	longs["--timestamp"] = "-t";
877
	longs["--Timestamp"] = "-T";
878
	longs["--unknown"  ] = "-u";
879
	longs["--verbose"  ] = "-v";
880
	longs["--Version"  ] = "-V";
881
	longs["--version"  ] = "-V";
882
	longs["--years"    ] = "-Y";
864
    longs["--adjust"   ] = "-a";
865
    longs["--binary"   ] = "-b";
866
    longs["--comment"  ] = "-c";
867
    longs["--delete"   ] = "-d";
868
    longs["--days"     ] = "-D";
869
    longs["--force"    ] = "-f";
870
    longs["--Force"    ] = "-F";
871
    longs["--grep"     ] = "-g";
872
    longs["--help"     ] = "-h";
873
    longs["--insert"   ] = "-i";
874
    longs["--keep"     ] = "-k";
875
    longs["--key"      ] = "-K";
876
    longs["--location" ] = "-l";
877
    longs["--modify"   ] = "-m";
878
    longs["--Modify"   ] = "-M";
879
    longs["--encode"   ] = "-n";
880
    longs["--months"   ] = "-O";
881
    longs["--print"    ] = "-p";
882
    longs["--Print"    ] = "-P";
883
    longs["--quiet"    ] = "-q";
884
    longs["--log"      ] = "-Q";
885
    longs["--rename"   ] = "-r";
886
    longs["--suffix"   ] = "-S";
887
    longs["--timestamp"] = "-t";
888
    longs["--Timestamp"] = "-T";
889
    longs["--unknown"  ] = "-u";
890
    longs["--verbose"  ] = "-v";
891
    longs["--Version"  ] = "-V";
892
    longs["--version"  ] = "-V";
893
    longs["--years"    ] = "-Y";
883 894

  
884
	for ( int i = 0 ; i < argc ; i++ ) {
885
		std::string* arg = new std::string(Argv[i]);
886
		if (longs.find(*arg) != longs.end() ) {
887
			argv[i] = ::strdup(longs[*arg].c_str());
888
		} else {
889
			argv[i] = ::strdup(Argv[i]);
890
		}
891
		delete arg;
892
	}
895
    for ( int i = 0 ; i < argc ; i++ ) {
896
        std::string* arg = new std::string(Argv[i]);
897
        if (longs.find(*arg) != longs.end() ) {
898
            argv[i] = ::strdup(longs[*arg].c_str());
899
        } else {
900
            argv[i] = ::strdup(Argv[i]);
901
        }
902
        delete arg;
903
    }
893 904

  
894 905
    int rc = Util::Getopt::getopt(argc, argv, optstring_);
895 906
    // Further consistency checks
......
914 925
                  << _("Modify action requires at least one -c, -m or -M option\n");
915 926
        rc = 1;
916 927
    }
928
    // #1137
929
    // when -P1 is set (prFirst), pop the first file, print the metadata to stream and parse
930
    // set the action to modify to read the generated commands
931
    //
932
    // implementing the -P+ (prPair) feature is a simple variation of this code
933
    // to read (and subsequently remove) every other file in params->files_ to stream
934
    if (rc == 0 && Params::instance().printItems_ & Params::prFirst ) {
935
        Params& params = Params::instance();
936
        // Cancel prFirst
937
        params.printItems_ |= !Params::prFirst;
938

  
939
        std::string           file  = params.files_[0];
940
        Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file);
941
        assert(image.get() != 0);
942
        image->readMetadata();
943

  
944
        params.printTags_ |= Exiv2::mdExif | Exiv2::mdIptc | Exiv2::mdXmp;
945
        params.files_.erase (Params::instance().files_.begin());
946

  
947
        Action::Print* printAction = new Action::Print();
948

  
949
        std::ostringstream    os ;
950
        printAction->printMetadata(image.get(),os);
951
        delete printAction;
952

  
953
        std::istringstream is(os.str());
954
        parseCmdStream(modifyCmds_,is,file);
955
        params.action_ = Action::modify;
956
    }
957

  
917 958
    if (0 == files_.size()) {
918 959
        std::cerr << progname() << ": " << _("At least one file is required\n");
919 960
        rc = 1;
......
958 999
        rc = 1;
959 1000
    }
960 1001

  
961
	// cleanup the argument vector
962
	for ( int i = 0 ; i < argc ; i++ ) ::free((void*)argv[i]);
1002
    // cleanup the argument vector
1003
    for ( int i = 0 ; i < argc ; i++ ) ::free((void*)argv[i]);
963 1004
    delete [] argv;
964 1005

  
965 1006
    return rc;
......
1089 1130
        return (int) (k - j);
1090 1131
    } // parsePreviewNumbers
1091 1132

  
1133
    bool parseCmdStream(ModifyCmds& modifyCmds,std::istream& is, const std::string& filename)
1134
    {
1135
        bool result = true;
1136
        try {
1137
            int num = 0;
1138
            std::string line;
1139
            while (std::getline(is, line)) {
1140
                ModifyCmd modifyCmd;
1141
                if (parseLine(modifyCmd, line, ++num)) {
1142
                    modifyCmds.push_back(modifyCmd);
1143
                }
1144
            }
1145
        }
1146
        catch (const Exiv2::AnyError& error) {
1147
            std::cerr << filename << ", " << _("line") << " " << error << "\n";
1148
            result = false;
1149
        }
1150
        return result;
1151
    }
1152

  
1092 1153
    bool parseCmdFiles(ModifyCmds& modifyCmds,
1093 1154
                       const Params::CmdFiles& cmdFiles)
1094 1155
    {
1156
        bool result = true ;
1095 1157
        Params::CmdFiles::const_iterator end = cmdFiles.end();
1096 1158
        Params::CmdFiles::const_iterator filename = cmdFiles.begin();
1097
        for ( ; filename != end; ++filename) {
1098
            try {
1099
                std::ifstream file(filename->c_str());
1100
                bool bStdin = filename->compare("-")== 0;
1101
                if (!file && !bStdin) {
1102
                    std::cerr << *filename << ": "
1103
                              << _("Failed to open command file for reading\n");
1104
                    return false;
1105
                }
1106
                int num = 0;
1107
                std::string line;
1108
                while (std::getline(bStdin? std::cin : file, line)) {
1109
                    ModifyCmd modifyCmd;
1110
                    if (parseLine(modifyCmd, line, ++num)) {
1111
                        modifyCmds.push_back(modifyCmd);
1112
                    }
1113
                }
1114
            }
1115
            catch (const Exiv2::AnyError& error) {
1116
                std::cerr << *filename << ", " << _("line") << " " << error << "\n";
1159
        for ( ; result && filename != end; ++filename) {
1160
            std::ifstream file(filename->c_str());
1161
            bool bStdin = filename->compare("-")== 0;
1162
            if (!file && !bStdin) {
1163
                std::cerr << *filename << ": "
1164
                          << _("Failed to open command file for reading\n");
1117 1165
                return false;
1118 1166
            }
1167
            result = parseCmdStream(modifyCmds,bStdin?std::cin:file, *filename);
1119 1168
        }
1120
        return true;
1169
        return result;
1121 1170
    } // parseCmdFile
1122 1171

  
1123 1172
    bool parseCmdLines(ModifyCmds& modifyCmds,
src/exiv2app.hpp (working copy)
147 147
        pmList,
148 148
        pmComment,
149 149
        pmPreview,
150
		pmStructure,
151
		pmXMP,
152
		pmIccProfile,
153
		pmRecursive
150
        pmStructure,
151
        pmXMP,
152
        pmIccProfile,
153
        pmRecursive
154 154
    };
155 155

  
156 156
    //! Individual items to print, bitmap
157 157
    enum PrintItem {
158
        prTag   =    1,
159
        prGroup =    2,
160
        prKey   =    4,
161
        prName  =    8,
162
        prLabel =   16,
163
        prType  =   32,
164
        prCount =   64,
165
        prSize  =  128,
166
        prValue =  256,
167
        prTrans =  512,
168
        prHex   = 1024,
169
        prSet   = 2048
158
        prTag   =   0x01,
159
        prGroup =   0x02,
160
        prKey   =   0x04,
161
        prName  =   0x08,
162
        prLabel =   0x10,
163
        prType  =   0x20,
164
        prCount =   0x40,
165
        prSize  =   0x80,
166
        prValue =  0x100,
167
        prTrans =  0x200,
168
        prHex   =  0x400,
169
        prSet   =  0x800,
170
        prFirst = 0x1000
170 171
    };
171 172

  
172 173
    //! Enumerates common targets, bitmap
    (1-1/1)