-
Notifications
You must be signed in to change notification settings - Fork 632
feat: global attribute to enable/disable formats at runtime #4792
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: global attribute to enable/disable formats at runtime #4792
Conversation
0f8b534
to
98b6472
Compare
/easycla |
Definitely needs a test, which I think can be straightforward: maybe in testsuite/oiiotool, one test that does something like
and it should output the correct error message about not reading that format that it would ordinarily be able to read. |
Signed-off-by: Rahul Baradol <[email protected]>
98b6472
to
fd31293
Compare
As I read it, I'm not sure this works. How did you test it? So what I think this is doing is: when it goes to open a file, it checks the attribute that holds the set of allowed formats, and if the format you're looking for is not in the list, it issues an error and refuses to create the ImageInput or ImageOutput. But... if the user doesn't set the attribute in the first place, NOTHING is on the list, right? So all requests will be rejected? Also, I think that as implemented, you're essentially looking up based on the name of the file extension, but that's not the name of the format. (You can pass create() either the name of a format, OR the name of a file, from which it guesses the format based on the file's extension.) Honestly, I think that what you need to do here, before you work on any more code, is come up for a design for how this feature is supposed to work. Let's iterate on the design first, and then when we all agree that it's the right behavior, it should be straightforward to finish the code implementation. When I speak of the design, I mean write down, really step by step, what you think the behavior should be. It doesn't need to be long, but it does need to be complete, or else you won't know what you're really trying to implement or how to judge if it's correct. It should be clear from reading this design how one should reason about the feature. Like, it should be easy to answer these questions:
|
Alright! Design 1 (Current implementation's design)Has two attributes We call
And in And yes, the user has to pass file extension and format name, which I realized would be not convenient After the And we do this check in both Design 2I observed there is a
And We can have two attributes
This would be convenient, as the user would have to pass the We make sure that certain plugins' code is not touched, making it seem OpenImageIO is unaware of the format. What do you say?
What are your thoughts? |
I see. Was it like that originally and I misunderstood all along, or did you fix that section? Yes, now if the string is empty, it returns 0. Here's what the docs say that getattribute does:
I think that this is an interesting question and would like others' opinions. I admit that in this case, the wording is ambiguous about exactly what "if found" means. I usually would consider "failed" here to mean either that the attribute does not exist (like, maybe they misspelled it and asked for an unknown name), or that they asked for a particular type and it's not the right kind of type to ask for this attribute. I never really considered that it should "fail" and return false for an attribute that the system knows about, but that the user did not previously proactively set. I don't think there is any other string attribute that works in this manner. To help us reason about this situation, let's consider what happen if the user code does this:
what does that do? I think most people will believe it means "do not accept any formats". But either way, we agree that the user HAS set the attribute and that it exists, right? So then, subsequently, you see:
Should success be true or false at this point? |
Yeah, I modified the section to handle the attribute that way. Looking at how Now to answer your question using the following snippet,
Even if the user doesn't pass/set the attribute, Now we can either,
We can go for option (2) to avoid confusion in the community, regarding how Regardless of where we handle empty strings, we need to decide to either
|
…ling_formats_at_runtime
How can we proceed here? |
Sorry, got caught up in other things. Will try to look this over today. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is basically sound, but having getattribute fail just because the (existing, valid!) attribute is the empty string doesn't match how it behaves for everything else. Let's succeed (return true), but then just interpret the empty string as "allow anything". I also gave a suggestion for how to change the retrieval and loop to avoid all the extra string allocation and copying by using a version of split that return string_view's.
if (allowed_output_format_list.empty()) { | ||
return false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still believe that we should not return false (which usually indicates that it's an invalid query -- like an attribute name that doesn't exist) for an attribute that exists but happens to be the empty string.
ustring comma_sep_allowed_output_formats; | ||
if (OIIO::getattribute("allowed_output_formats", TypeString, | ||
&comma_sep_allowed_output_formats)) { | ||
std::vector<std::string> allowed_output_formats; | ||
Strutil::split(comma_sep_allowed_output_formats, allowed_output_formats, | ||
",", -1); | ||
|
||
bool isValidFormat = 0; | ||
for (std::string allowed_format : allowed_output_formats) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To solve the "empty list" problem and also eliminate all these string allocations and copies, I would suggest this change here:
ustring comma_sep_allowed_output_formats; | |
if (OIIO::getattribute("allowed_output_formats", TypeString, | |
&comma_sep_allowed_output_formats)) { | |
std::vector<std::string> allowed_output_formats; | |
Strutil::split(comma_sep_allowed_output_formats, allowed_output_formats, | |
",", -1); | |
bool isValidFormat = 0; | |
for (std::string allowed_format : allowed_output_formats) { | |
auto allowed_output_formats = Strutil::splitsv(OIIO::get_string_attribute("allowed_output_formats"), ",", -1); | |
if (allowed_output_formats.size()) { | |
bool isValidFormat = 0; | |
for (auto allowed_format : allowed_output_formats) { |
Wait, I think there is still another problem here: If I'm not mistaken, it's really comparing the file extension to the list of formats, which are not always the same. I think we definitely want the attribute to be the name of formats. So we'll need a step where you use extension_to_format_map to convert the extension to the canonical format name. |
I think, also, that when this attribute is used, we may need to alter the behavior where if the format suggested by the filename extension fails, it tries all the other formats. To see what I mean, let's use an example. Since this is sort of a security feature, consider the case where an application has disabled TIFF files but allows OpenEXR files. Somebody could maliciously name a TIFF file "bad.exr", and then this code as it currently is will think "sure, exr is fine" and proceed, but after failing to open it as an exr file, it will try all formats and happily open it as tiff even though that's supposed to be prohibited. So I think we'll need to add a check there in that "try all formats" logic as well. |
Description
A solve for the issue #4759
Added OIIO attributes to enable/disable formats at runtime
Tests
Checklist:
need to update the documentation, for example if this is a bug fix that
doesn't change the API.)
(adding new test cases if necessary).
corresponding Python bindings (and if altering ImageBufAlgo functions, also
exposed the new functionality as oiiotool options).
already run clang-format before submitting, I definitely will look at the CI
test that runs clang-format and fix anything that it highlights as being
nonconforming.