1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2007, Weta Digital Ltd
4 //
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are
9 // met:
10 // *       Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // *       Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following disclaimer
14 // in the documentation and/or other materials provided with the
15 // distribution.
16 // *       Neither the name of Weta Digital nor the names of
17 // its contributors may be used to endorse or promote products derived
18 // from this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 //
32 ///////////////////////////////////////////////////////////////////////////
33 
34 //-----------------------------------------------------------------------------
35 //
36 //	Functions related to accessing channels
37 //	and views in multi-view OpenEXR files.
38 //
39 //-----------------------------------------------------------------------------
40 
41 #include <ImfMultiView.h>
42 
43 using namespace std;
44 #include "ImfNamespace.h"
45 
46 OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
47 
48 namespace {
49 
50 StringVector
parseString(string name,char c='.')51 parseString (string name, char c = '.')
52 {
53     //
54     // Turn name into a list of strings, separating
55     // on char 'c' with whitespace stripped.
56     //
57 
58     StringVector r;
59 
60     while (name.size() > 0)
61     {
62 	size_t s = name.find (c);
63 	string sec = name.substr (0, s);
64 
65 	//
66 	// Strip spaces from beginning
67 	//
68 
69 	while (sec.size() > 0 && sec[0] == ' ')
70 	    sec.erase (0, 1);
71 
72 	//
73 	// Strip spaces from end
74 	//
75 
76 	while (sec.size() > 0 && sec[sec.size() - 1] == ' ')
77 	    sec.erase (sec.size() - 1);
78 
79 	r.push_back (sec);
80 
81 	//
82 	// Strip off name including ending 'c'
83 	//
84 
85 	if (s == name.npos)
86 	    name = "";
87 	else
88 	    name = name.substr (s + 1);
89     }
90 
91     return r;
92 }
93 
94 
95 int
viewNum(const string & view,const StringVector & multiView)96 viewNum (const string &view, const StringVector &multiView)
97 {
98     //
99     // returns which view number is called 'view'
100     // returns -1 if no member of multiView is 'view'
101     // (i.e. if viewNum() returns -1, 'view' isn't a view name
102     //       if viewNum() returns 0, 'view' is the default view
103     // otherwise, it's some other (valid) view
104     //
105 
106     for (size_t i = 0; i < multiView.size(); ++i)
107     {
108 	if (multiView[i] == view)
109 	    return i;
110     }
111 
112     return -1;
113 }
114 
115 } // namespace
116 
117 
118 string
defaultViewName(const StringVector & multiView)119 defaultViewName (const StringVector &multiView)
120 {
121     if (multiView.size() > 0)
122 	return multiView[0];
123     else
124 	return "";
125 }
126 
127 
128 string
viewFromChannelName(const string & channel,const StringVector & multiView)129 viewFromChannelName (const string &channel,
130 		     const StringVector &multiView)
131 {
132     //
133     // Given the name of a channel, return the name of the view to
134     // which it belongs.
135     //
136 
137     //
138     // View name is penultimate section of name separated by periods ('.'s)
139     //
140 
141     StringVector s = parseString (channel, '.');
142 
143     if (s.size() == 0)
144 	return ""; // nothing in, nothing out
145 
146     if (s.size() == 1)
147     {
148 	//
149 	// Return default view name.
150 	// The rules say ALL channels with no periods
151 	// in the name belong to the default view.
152 	//
153 
154 	return multiView[0];
155     }
156     else
157     {
158 	//
159 	// size >= 2 - the last part is the channel name,
160 	// the next-to-last part is the view name.
161 	// Check if that part of the name really is
162 	// a valid view and, if it is, return it.
163 	//
164 
165 	const string &viewName = s[s.size() - 2];
166 
167 	if (viewNum (viewName, multiView) >= 0)
168 	    return viewName;
169 	else
170 	    return ""; // not associated with any particular view
171     }
172 }
173 
174 
175 ChannelList
channelsInView(const string & viewName,const ChannelList & channelList,const StringVector & multiView)176 channelsInView (const string & viewName,
177 	        const ChannelList & channelList,
178 		const StringVector & multiView)
179 {
180     //
181     // Return a list of all channels belonging to view viewName.
182     //
183 
184     ChannelList q;
185 
186     for (ChannelList::ConstIterator i = channelList.begin();
187 	 i != channelList.end();
188 	 ++i)
189     {
190 	//
191 	// Get view name for this channel
192 	//
193 
194 	string view = viewFromChannelName (i.name(), multiView);
195 
196 
197 	//
198 	// Insert channel into q if it's a member of view viewName
199 	//
200 
201 	if (view == viewName)
202 	   q.insert (i.name(), i.channel());
203     }
204 
205     return q;
206 }
207 
208 
209 ChannelList
channelsInNoView(const ChannelList & channelList,const StringVector & multiView)210 channelsInNoView (const ChannelList &channelList,
211 		  const StringVector &multiView)
212 {
213     //
214     // Return a list of channels not associated with any named view.
215     //
216 
217     return channelsInView ("", channelList, multiView);
218 }
219 
220 
221 
222 bool
areCounterparts(const string & channel1,const string & channel2,const StringVector & multiView)223 areCounterparts (const string &channel1,
224 	         const string &channel2,
225 		 const StringVector &multiView)
226 {
227     //
228     // Given two channels, return true if they are the same
229     // channel in two different views.
230     //
231 
232     StringVector chan1 = parseString (channel1);
233     size_t size1 = chan1.size();	// number of SECTIONS in string
234     					// name (not string length)
235 
236     StringVector chan2 = parseString (channel2);
237     size_t size2 = chan2.size();
238 
239     if (size1 == 0 || size2 == 0)
240 	return false;
241 
242     //
243     // channel1 and channel2 can't be counterparts
244     // if either channel is in no view.
245     //
246 
247     if (size1 > 1 && viewNum (chan1[size1 - 2], multiView) == -1)
248 	return false;
249 
250     if (size2 > 1 && viewNum (chan2[size2 - 2], multiView) == -1)
251 	return false;
252 
253     if (viewFromChannelName (channel1, multiView) ==
254 	viewFromChannelName (channel2, multiView))
255     {
256 	//
257 	// channel1 and channel2 are not counterparts
258 	// if they are in the same view.
259 	//
260 
261 	return false;
262     }
263 
264     if (size1 == 1)
265     {
266 	//
267 	// channel1 is a default channel - the channels will only be
268 	// counterparts if channel2 is of the form <view>.<channel1>
269 	//
270 
271 	return size2 == 2 && chan1[0] == chan2[1];
272     }
273 
274     if (size2 == 1)
275     {
276 	//
277 	// channel2 is a default channel - the channels will only be
278 	// counterparts if channel1 is of the form <view>.<channel2>
279 	//
280 
281 	return size1 == 2 && chan2[0] == chan1[1];
282     }
283 
284     //
285     // Neither channel is a default channel.  To be counterparts both
286     // channel names must have the same number of components, and
287     // all components except the penultimate one must be the same.
288     //
289 
290     if (size1 != size2)
291 	return false;
292 
293     for(size_t i = 0; i < size1; ++i)
294     {
295 	if (i != size1 - 2 && chan1[i] != chan2[i])
296 	    return false;
297     }
298 
299     return true;
300 }
301 
302 
303 ChannelList
channelInAllViews(const string & channelName,const ChannelList & channelList,const StringVector & multiView)304 channelInAllViews (const string &channelName,
305 		   const ChannelList &channelList,
306 		   const StringVector &multiView)
307 {
308     //
309     // Given the name of a channel, return a
310     // list of the same channel in all views.
311     //
312 
313     ChannelList q;
314 
315     for (ChannelList::ConstIterator i=channelList.begin();
316 	 i != channelList.end();
317 	 ++i)
318     {
319 	if (i.name() == channelName ||
320 	    areCounterparts (i.name(), channelName, multiView))
321 	{
322 	    q.insert (i.name(), i.channel());
323 	}
324     }
325 
326     return q;
327 }
328 
329 
330 string
channelInOtherView(const string & channelName,const ChannelList & channelList,const StringVector & multiView,const string & otherViewName)331 channelInOtherView (const string &channelName,
332 		    const ChannelList &channelList,
333 		    const StringVector &multiView,
334 		    const string &otherViewName)
335 {
336     //
337     // Given the name of a channel in one view, return the
338     // corresponding channel name for view otherViewName.
339     //
340 
341     for (ChannelList::ConstIterator i=channelList.begin();
342 	 i != channelList.end();
343 	 ++i)
344     {
345 	if (viewFromChannelName (i.name(), multiView) == otherViewName &&
346 	    areCounterparts (i.name(), channelName, multiView))
347 	{
348 	    return i.name();
349 	}
350     }
351 
352     return "";
353 }
354 
355 
356 string
insertViewName(const string & channel,const StringVector & multiView,int i)357 insertViewName (const string &channel,
358 		const StringVector &multiView,
359 		int i)
360 {
361     //
362     // Insert multiView[i] into the channel name if appropriate.
363     //
364 
365     StringVector s = parseString (channel, '.');
366 
367     if (s.size() == 0)
368 	return ""; // nothing in, nothing out
369 
370     if (s.size() == 1 && i == 0)
371     {
372 	//
373 	// Channel in the default view, with no periods in its name.
374 	// Do not insert view name.
375 	//
376 
377 	return channel;
378     }
379 
380     //
381     // View name becomes penultimate section of new channel name.
382     //
383 
384     string newName;
385 
386     for (size_t j = 0; j < s.size(); ++j)
387     {
388 	if (j < s.size() - 1)
389 	    newName += s[j] + ".";
390 	else
391 	    newName += multiView[i] + "." + s[j];
392     }
393 
394     return newName;
395 }
396 
397 
398 string
removeViewName(const string & channel,const string & view)399 removeViewName(const string & channel,const string & view)
400 {
401     StringVector s = parseString (channel, '.');
402 
403     if (s.size() == 0)
404 	return ""; // nothing in, nothing out
405 
406     if (s.size() == 1)
407     {
408 	//
409 	// Channel in the default view, since no periods in its name.
410 	// No viewname to remove
411 	//
412 
413 	return channel;
414     }
415 
416     string newName;
417     for( size_t j = 0 ; j < s.size() ; ++j)
418     {
419 	    // only add the penultimate string part
420 	    // if it doesn't match the view name
421 	    if(j+2!=s.size() || s[j]!=view)
422 	    {
423                   newName += s[j];
424 	          if(j+1!=s.size())
425 	          {
426                       newName  += ".";
427 	          }
428 	    }
429     }
430 
431     return newName;
432 
433 }
434 
435 OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
436