From 1c3ffc79cc0dd017d53b5b5091f2599c9fe0564f Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Fri, 22 Mar 2024 18:16:56 +1300 Subject: [PATCH 1/2] add -erase option to exrstdattr Signed-off-by: Peter Hillman --- src/bin/exrstdattr/main.cpp | 58 +++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/bin/exrstdattr/main.cpp b/src/bin/exrstdattr/main.cpp index 23e4cabeb4..bff125c2a2 100644 --- a/src/bin/exrstdattr/main.cpp +++ b/src/bin/exrstdattr/main.cpp @@ -206,6 +206,7 @@ usageMessage (ostream& stream, const char* program_name, bool verbose = false) "\n" "Other options:\n" "\n" + " -erase s remove attribute with given name\n" " -h, --help print this message\n" " --version print version information\n" "\n" @@ -224,7 +225,17 @@ struct SetAttr {} }; +struct EraseAttr +{ + string name; + int part; + EraseAttr (const string& name, int part) + : name (name), part (part) + {} +}; + typedef vector SetAttrVector; +typedef vector EraseAttrVector; void isNonNegative (const char attrName[], float f) @@ -445,6 +456,8 @@ getNameAndString (int argc, char** argv, int& i, int part, SetAttrVector& attrs) i += 3; } + + void getNameAndFloat (int argc, char** argv, int& i, int part, SetAttrVector& attrs) { @@ -467,6 +480,17 @@ getNameAndInt (int argc, char** argv, int& i, int part, SetAttrVector& attrs) i += 3; } +void +getName (int argc, char** argv, int& i, int part, EraseAttrVector& attrs) +{ + if (i > argc - 2) throw invalid_argument ("Expected a name and an integer"); + + const char* attrName = argv[i + 1]; + attrs.push_back (EraseAttr(attrName, part)); + i += 2; +} + + void getChromaticities ( const char attrName[], @@ -603,6 +627,7 @@ main (int argc, char** argv) const char* outFileName = 0; SetAttrVector attrs; + EraseAttrVector eraseattrs; int part = -1; int i = 1; @@ -726,6 +751,10 @@ main (int argc, char** argv) { getNameAndInt (argc, argv, i, part, attrs); } + else if (!strcmp (argv[i], "-erase")) + { + getName ( argc,argv,i,part,eraseattrs); + } else if (!strcmp (argv[i], "-h") || !strcmp (argv[i], "--help")) { usageMessage (cout, "exrstdattr", true); @@ -797,6 +826,35 @@ main (int argc, char** argv) } } + Header stdHdr; + for (size_t i = 0 ; i < eraseattrs.size() ; ++i) + { + const EraseAttr& attr = eraseattrs[i]; + if (attr.part == -1 || attr.part == part) + { + if( stdHdr.find(attr.name)!=stdHdr.end() ) + { + cerr << "Cannot erase attribute " << attr.name + << ". " + << "It is an essential attribute" << endl; + return 1; + } + h.erase( attr.name ); + } + else if (attr.part < 0 || attr.part >= numParts) + { + cerr << "Invalid part number " << attr.part + << ". " + "Part numbers in file " + << inFileName + << " " + "go from 0 to " + << numParts - 1 << "." << endl; + + return 1; + } + } + headers.push_back (h); } From 40e3c044fe0b9eac2907db1401295ab844cee643 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Sat, 23 Mar 2024 10:33:33 +1300 Subject: [PATCH 2/2] reorder operations and add test for erase in exrstdattr Signed-off-by: Peter Hillman --- src/bin/exrstdattr/main.cpp | 45 +++++++++++++++++++++------------ src/test/bin/test_exrstdattr.py | 27 ++++++++++++++++++++ 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/src/bin/exrstdattr/main.cpp b/src/bin/exrstdattr/main.cpp index bff125c2a2..a8c54a79d6 100644 --- a/src/bin/exrstdattr/main.cpp +++ b/src/bin/exrstdattr/main.cpp @@ -800,17 +800,36 @@ main (int argc, char** argv) int numParts = in.parts (); vector
headers; + // + // Treat attributes added to a header in its constructor + // as critical and don't allow them to be deleted. + // 'name' and 'type' are only required in multipart + // file and errors will be reported if they + // are erased + // + Header stdHdr; + for (int part = 0; part < numParts; ++part) { Header h = in.header (part); - for (size_t i = 0; i < attrs.size (); ++i) + // + // process attributes to erase first, so they can be reinserted + // with a different type + // + for (size_t i = 0 ; i < eraseattrs.size() ; ++i) { - const SetAttr& attr = attrs[i]; - + const EraseAttr& attr = eraseattrs[i]; if (attr.part == -1 || attr.part == part) { - h.insert (attr.name, *attr.attr); + if( stdHdr.find(attr.name)!=stdHdr.end() ) + { + cerr << "Cannot erase attribute " << attr.name + << ". " + << "It is an essential attribute" << endl; + return 1; + } + h.erase( attr.name ); } else if (attr.part < 0 || attr.part >= numParts) { @@ -826,20 +845,14 @@ main (int argc, char** argv) } } - Header stdHdr; - for (size_t i = 0 ; i < eraseattrs.size() ; ++i) + + for (size_t i = 0; i < attrs.size (); ++i) { - const EraseAttr& attr = eraseattrs[i]; + const SetAttr& attr = attrs[i]; + if (attr.part == -1 || attr.part == part) { - if( stdHdr.find(attr.name)!=stdHdr.end() ) - { - cerr << "Cannot erase attribute " << attr.name - << ". " - << "It is an essential attribute" << endl; - return 1; - } - h.erase( attr.name ); + h.insert (attr.name, *attr.attr); } else if (attr.part < 0 || attr.part >= numParts) { @@ -859,7 +872,7 @@ main (int argc, char** argv) } // - // Crete an output file with the modified headers, + // Create an output file with the modified headers, // and copy the pixels from the input file to the // output file. // diff --git a/src/test/bin/test_exrstdattr.py b/src/test/bin/test_exrstdattr.py index 94c45f6e16..97e23bf860 100644 --- a/src/test/bin/test_exrstdattr.py +++ b/src/test/bin/test_exrstdattr.py @@ -20,6 +20,10 @@ fd, outimage = tempfile.mkstemp(".exr") os.close(fd) +fd, outimage2 = tempfile.mkstemp(".exr") +os.close(fd) + + def cleanup(): print(f"deleting {outimage}") atexit.register(cleanup) @@ -138,4 +142,27 @@ def cleanup(): print(result.stdout) raise +# test for bad erase argument +result = run ([exrstdattr, "-erase"], stdout=PIPE, stderr=PIPE, universal_newlines=True) +print(" ".join(result.args)) +print(result.stderr) +assert(result.returncode != 0), "\n"+result.stderr + +# test for errors trying to delete a critical attribute +result = run ([exrstdattr, "-erase","dataWindow",outimage,outimage2], stdout=PIPE, stderr=PIPE, universal_newlines=True) +print(" ".join(result.args)) +print(result.stderr) +assert(result.returncode != 0), "\n"+result.stderr + +# test deleting 'comments' +result = run ([exrstdattr, "-erase","comments",outimage,outimage2], stdout=PIPE, stderr=PIPE, universal_newlines=True) +print(" ".join(result.args)) +assert(result.returncode == 0), "\n"+result.stderr +assert(os.path.isfile(outimage2)), "\nMissing " + outimage2 + +result = run ([exrinfo, "-v", outimage2], stdout=PIPE, stderr=PIPE, universal_newlines=True) +print(" ".join(result.args)) +assert("comments" not in result.stdout) + + print("success")