1 /*
2 Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al.
3 All Rights Reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8 * Redistributions of source code must retain the above copyright
9   notice, this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11   notice, this list of conditions and the following disclaimer in the
12   documentation and/or other materials provided with the distribution.
13 * Neither the name of Sony Pictures Imageworks nor the names of its
14   contributors may be used to endorse or promote products derived from
15   this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include <OpenColorIO/OpenColorIO.h>
30 
31 #include <algorithm>
32 
33 #include "LookParse.h"
34 #include "ParseUtils.h"
35 #include "pystring/pystring.h"
36 #include <iostream>
37 
38 OCIO_NAMESPACE_ENTER
39 {
40     void LookParseResult::Token::parse(const std::string & str)
41     {
42         // Assert no commas, colons, or | in str.
43 
44         if(pystring::startswith(str, "+"))
45         {
46             name = pystring::lstrip(str, "+");
47             dir = TRANSFORM_DIR_FORWARD;
48         }
49         // TODO: Handle --
50         else if(pystring::startswith(str, "-"))
51         {
52             name = pystring::lstrip(str, "-");
53             dir = TRANSFORM_DIR_INVERSE;
54         }
55         else
56         {
57             name = str;
58             dir = TRANSFORM_DIR_FORWARD;
59         }
60     }
61 
62     void LookParseResult::Token::serialize(std::ostream & os) const
63     {
64         if(dir==TRANSFORM_DIR_FORWARD)
65         {
66             os << name;
67         }
68         else if(dir==TRANSFORM_DIR_INVERSE)
69         {
70             os << "-" << name;
71         }
72         else
73         {
74             os << "?" << name;
75         }
76     }
77 
78     void LookParseResult::serialize(std::ostream & os, const Tokens & tokens)
79     {
80         for(unsigned int i=0; i<tokens.size(); ++i)
81         {
82             if(i!=0) os << ", ";
83             tokens[i].serialize(os);
84         }
85     }
86 
87     const LookParseResult::Options & LookParseResult::parse(const std::string & looksstr)
88     {
89         m_options.clear();
90 
91         std::string strippedlooks = pystring::strip(looksstr);
92         if(strippedlooks.empty())
93         {
94             return m_options;
95         }
96 
97         std::vector<std::string> options;
98         pystring::split(strippedlooks, options, "|");
99 
100         std::vector<std::string> vec;
101 
102         for(unsigned int optionsindex=0;
103             optionsindex<options.size();
104             ++optionsindex)
105         {
106             LookParseResult::Tokens tokens;
107 
108             vec.clear();
109             SplitStringEnvStyle(vec, options[optionsindex].c_str());
110             for(unsigned int i=0; i<vec.size(); ++i)
111             {
112                 LookParseResult::Token t;
113                 t.parse(vec[i]);
114                 tokens.push_back(t);
115             }
116 
117             m_options.push_back(tokens);
118         }
119 
120         return m_options;
121     }
122 
123     const LookParseResult::Options & LookParseResult::getOptions() const
124     {
125         return m_options;
126     }
127 
128     bool LookParseResult::empty() const
129     {
130         return m_options.empty();
131     }
132 
133     void LookParseResult::reverse()
134     {
135         // m_options itself should NOT be reversed.
136         // The individual looks
137         // need to be applied in the inverse direction. But, the precedence
138         // for which option to apply is to be maintained!
139 
140         for(unsigned int optionindex=0;
141             optionindex<m_options.size();
142             ++optionindex)
143         {
144             std::reverse(m_options[optionindex].begin(), m_options[optionindex].end());
145 
146             for(unsigned int tokenindex=0;
147                 tokenindex<m_options[optionindex].size();
148                 ++tokenindex)
149             {
150                 m_options[optionindex][tokenindex].dir =
151                     GetInverseTransformDirection(
152                         m_options[optionindex][tokenindex].dir);
153             }
154         }
155     }
156 }
157 OCIO_NAMESPACE_EXIT
158 
159 
160 
161 ///////////////////////////////////////////////////////////////////////////////
162 
163 #ifdef OCIO_UNIT_TEST
164 
165 OCIO_NAMESPACE_USING
166 
167 #include "UnitTest.h"
168 
169 OIIO_ADD_TEST(LookParse, Parse)
170 {
171     LookParseResult r;
172 
173     {
174     const LookParseResult::Options & options = r.parse("");
175     OIIO_CHECK_EQUAL(options.size(), 0);
176     OIIO_CHECK_EQUAL(options.empty(), true);
177     }
178 
179     {
180     const LookParseResult::Options & options = r.parse("  ");
181     OIIO_CHECK_EQUAL(options.size(), 0);
182     OIIO_CHECK_EQUAL(options.empty(), true);
183     }
184 
185     {
186     const LookParseResult::Options & options = r.parse("cc");
187     OIIO_CHECK_EQUAL(options.size(), 1);
188     OIIO_CHECK_EQUAL(options[0][0].name, "cc");
189     OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
190     OIIO_CHECK_EQUAL(options.empty(), false);
191     }
192 
193     {
194     const LookParseResult::Options & options = r.parse("+cc");
195     OIIO_CHECK_EQUAL(options.size(), 1);
196     OIIO_CHECK_EQUAL(options[0][0].name, "cc");
197     OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
198     OIIO_CHECK_EQUAL(options.empty(), false);
199     }
200 
201     {
202     const LookParseResult::Options & options = r.parse("  +cc");
203     OIIO_CHECK_EQUAL(options.size(), 1);
204     OIIO_CHECK_EQUAL(options[0][0].name, "cc");
205     OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
206     OIIO_CHECK_EQUAL(options.empty(), false);
207     }
208 
209     {
210     const LookParseResult::Options & options = r.parse("  +cc   ");
211     OIIO_CHECK_EQUAL(options.size(), 1);
212     OIIO_CHECK_EQUAL(options[0][0].name, "cc");
213     OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
214     OIIO_CHECK_EQUAL(options.empty(), false);
215     }
216 
217     {
218     const LookParseResult::Options & options = r.parse("+cc,-di");
219     OIIO_CHECK_EQUAL(options.size(), 1);
220     OIIO_CHECK_EQUAL(options[0].size(), 2);
221     OIIO_CHECK_EQUAL(options[0][0].name, "cc");
222     OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
223     OIIO_CHECK_EQUAL(options[0][1].name, "di");
224     OIIO_CHECK_EQUAL(options[0][1].dir, TRANSFORM_DIR_INVERSE);
225     OIIO_CHECK_EQUAL(options.empty(), false);
226     }
227 
228     {
229     const LookParseResult::Options & options = r.parse("  +cc ,  -di");
230     OIIO_CHECK_EQUAL(options.size(), 1);
231     OIIO_CHECK_EQUAL(options[0].size(), 2);
232     OIIO_CHECK_EQUAL(options[0][0].name, "cc");
233     OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
234     OIIO_CHECK_EQUAL(options[0][1].name, "di");
235     OIIO_CHECK_EQUAL(options[0][1].dir, TRANSFORM_DIR_INVERSE);
236     OIIO_CHECK_EQUAL(options.empty(), false);
237     }
238 
239     {
240     const LookParseResult::Options & options = r.parse("  +cc :  -di");
241     OIIO_CHECK_EQUAL(options.size(), 1);
242     OIIO_CHECK_EQUAL(options[0].size(), 2);
243     OIIO_CHECK_EQUAL(options[0][0].name, "cc");
244     OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
245     OIIO_CHECK_EQUAL(options[0][1].name, "di");
246     OIIO_CHECK_EQUAL(options[0][1].dir, TRANSFORM_DIR_INVERSE);
247     OIIO_CHECK_EQUAL(options.empty(), false);
248     }
249 
250     {
251     const LookParseResult::Options & options = r.parse("+cc, -di |-cc");
252     OIIO_CHECK_EQUAL(options.size(), 2);
253     OIIO_CHECK_EQUAL(options[0].size(), 2);
254     OIIO_CHECK_EQUAL(options[0][0].name, "cc");
255     OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
256     OIIO_CHECK_EQUAL(options[0][1].name, "di");
257     OIIO_CHECK_EQUAL(options[0][1].dir, TRANSFORM_DIR_INVERSE);
258     OIIO_CHECK_EQUAL(options[1].size(), 1);
259     OIIO_CHECK_EQUAL(options.empty(), false);
260     OIIO_CHECK_EQUAL(options[1][0].name, "cc");
261     OIIO_CHECK_EQUAL(options[1][0].dir, TRANSFORM_DIR_INVERSE);
262     }
263 
264     {
265     const LookParseResult::Options & options = r.parse("+cc, -di |-cc|   ");
266     OIIO_CHECK_EQUAL(options.size(), 3);
267     OIIO_CHECK_EQUAL(options[0].size(), 2);
268     OIIO_CHECK_EQUAL(options[0][0].name, "cc");
269     OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
270     OIIO_CHECK_EQUAL(options[0][1].name, "di");
271     OIIO_CHECK_EQUAL(options[0][1].dir, TRANSFORM_DIR_INVERSE);
272     OIIO_CHECK_EQUAL(options[1].size(), 1);
273     OIIO_CHECK_EQUAL(options.empty(), false);
274     OIIO_CHECK_EQUAL(options[1][0].name, "cc");
275     OIIO_CHECK_EQUAL(options[1][0].dir, TRANSFORM_DIR_INVERSE);
276     OIIO_CHECK_EQUAL(options[2].size(), 1);
277     OIIO_CHECK_EQUAL(options[2][0].name, "");
278     OIIO_CHECK_EQUAL(options[2][0].dir, TRANSFORM_DIR_FORWARD);
279     }
280 }
281 
OIIO_ADD_TEST(LookParse,Reverse)282 OIIO_ADD_TEST(LookParse, Reverse)
283 {
284     LookParseResult r;
285 
286     {
287     r.parse("+cc, -di |-cc|   ");
288     r.reverse();
289     const LookParseResult::Options & options = r.getOptions();
290 
291     OIIO_CHECK_EQUAL(options.size(), 3);
292     OIIO_CHECK_EQUAL(options[0].size(), 2);
293     OIIO_CHECK_EQUAL(options[0][1].name, "cc");
294     OIIO_CHECK_EQUAL(options[0][1].dir, TRANSFORM_DIR_INVERSE);
295     OIIO_CHECK_EQUAL(options[0][0].name, "di");
296     OIIO_CHECK_EQUAL(options[0][0].dir, TRANSFORM_DIR_FORWARD);
297     OIIO_CHECK_EQUAL(options[1].size(), 1);
298     OIIO_CHECK_EQUAL(options.empty(), false);
299     OIIO_CHECK_EQUAL(options[1][0].name, "cc");
300     OIIO_CHECK_EQUAL(options[1][0].dir, TRANSFORM_DIR_FORWARD);
301     OIIO_CHECK_EQUAL(options[2].size(), 1);
302     OIIO_CHECK_EQUAL(options[2][0].name, "");
303     OIIO_CHECK_EQUAL(options[2][0].dir, TRANSFORM_DIR_INVERSE);
304     }
305 
306 
307 }
308 
309 #endif // OCIO_UNIT_TEST
310