1 //-*****************************************************************************
2 //
3 // Copyright (c) 2009-2012,
4 //  Sony Pictures Imageworks, Inc. and
5 //  Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd.
6 //
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are
11 // met:
12 // *       Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
14 // *       Redistributions in binary form must reproduce the above
15 // copyright notice, this list of conditions and the following disclaimer
16 // in the documentation and/or other materials provided with the
17 // distribution.
18 // *       Neither the name of Sony Pictures Imageworks, nor
19 // Industrial Light & Magic nor the names of their contributors may be used
20 // to endorse or promote products derived from this software without specific
21 // prior written permission.
22 //
23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 //
35 //-*****************************************************************************
36 
37 #include <Alembic/Abc/IObject.h>
38 #include <Alembic/Abc/IArchive.h>
39 #include <Alembic/Abc/ICompoundProperty.h>
40 #include <Alembic/Abc/ITypedScalarProperty.h>
41 
42 namespace Alembic {
43 namespace Abc {
44 namespace ALEMBIC_VERSION_NS {
45 
46 //-*****************************************************************************
47 // Nothing at the moment, this is just here as a debug entry point for
48 // tracking down problems with reference counting.
~IObject()49 IObject::~IObject()
50 {
51     // Nothing for now.
52     // Mostly here in case we need to add reference-counting debug code.
53     //std::cout << "IObject::~IObject() name: "
54     //          << m_object->getName()
55     //          << std::endl
56     //          << "\tUse count of writer ptr: "
57     //          << m_object.use_count() << std::endl;
58 }
59 
60 namespace {
61 
62 const AbcA::ObjectHeader g_ohd;
63 
64 }
65 
66 //-*****************************************************************************
getHeader() const67 const AbcA::ObjectHeader &IObject::getHeader() const
68 {
69     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IObject::getHeader()" );
70 
71     if ( m_object )
72     {
73         return m_object->getHeader();
74     }
75 
76     ALEMBIC_ABC_SAFE_CALL_END();
77 
78     // Not all error handlers throw, so have a default behavior.
79     return g_ohd;
80 };
81 
82 //-*****************************************************************************
getName() const83 const std::string &IObject::getName() const
84 {
85     // Get the name of the original object
86     if ( m_instanceObject )
87     {
88         return m_instanceObject->getHeader().getName();
89     }
90 
91     return m_object->getHeader().getName();
92 }
93 
94 //-*****************************************************************************
getFullName() const95 const std::string &IObject::getFullName() const
96 {
97     if ( !m_instancedFullName.empty() )
98     {
99         return m_instancedFullName;
100     }
101 
102     return getHeader().getFullName();
103 }
104 
105 //-*****************************************************************************
getArchive() const106 IArchive IObject::getArchive() const
107 {
108 
109     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IObject::getArchive()" );
110 
111     // proxies and targets are currently required to be in the
112     // same archive. Just use the m_object archive.
113     if ( m_object )
114     {
115         return IArchive( m_object->getArchive(),
116                          kWrapExisting,
117                          getErrorHandlerPolicy() );
118     }
119 
120     ALEMBIC_ABC_SAFE_CALL_END();
121 
122     // Not all error handlers throw. Have a default.
123     return IArchive();
124 }
125 
126 namespace { // anonymous
127 
128 static inline
readInstanceSource(AbcA::CompoundPropertyReaderPtr iProp)129 std::string readInstanceSource( AbcA::CompoundPropertyReaderPtr iProp )
130 {
131     if ( !iProp || !iProp->getPropertyHeader(".instanceSource") )
132     {
133         return std::string();
134     }
135 
136     IStringProperty instanceSourceProp( iProp, ".instanceSource" );
137     if ( !instanceSourceProp )
138         return std::string();
139 
140     return instanceSourceProp.getValue();
141 }
142 
143 static inline
144 AbcA::ObjectReaderPtr objectReaderByName( AbcA::ObjectReaderPtr iObj,
145                                           const std::string & iInstanceSource );
146 
147 static inline
recurse(AbcA::ObjectReaderPtr iObj,const std::string & iInstanceSource,std::size_t iCurPos)148 AbcA::ObjectReaderPtr recurse( AbcA::ObjectReaderPtr iObj,
149                                const std::string & iInstanceSource,
150                                std::size_t iCurPos )
151 {
152     std::size_t nextSlash = iInstanceSource.find( '/', iCurPos );
153     std::string childName;
154     if ( nextSlash == std::string::npos )
155     {
156         childName = iInstanceSource.substr( iCurPos );
157     }
158     else
159     {
160         childName = iInstanceSource.substr( iCurPos, nextSlash - iCurPos );
161     }
162 
163     AbcA::ObjectReaderPtr child = iObj->getChild( childName );
164 
165     if ( child && nextSlash != std::string::npos )
166     {
167         // we hit an instance so we have to evaluate down to the correct spot
168         if ( child->getMetaData().get("isInstance") == "1" )
169         {
170             // get and recursively walk down this other path
171             AbcA::CompoundPropertyReaderPtr prop = child->getProperties();
172             std::string instanceSource = readInstanceSource( prop );
173             child = objectReaderByName( child, instanceSource);
174         }
175         return recurse( child, iInstanceSource, nextSlash + 1 );
176     }
177 
178     // child not found, or we are on our last child
179     return child;
180 }
181 
182 //-*****************************************************************************
183 static inline
objectReaderByName(AbcA::ObjectReaderPtr iObj,const std::string & iInstanceSource)184 AbcA::ObjectReaderPtr objectReaderByName( AbcA::ObjectReaderPtr iObj,
185                                           const std::string & iInstanceSource )
186 {
187     if ( iInstanceSource.empty() || ! iObj )
188         return AbcA::ObjectReaderPtr();
189 
190     std::size_t curPos = 0;
191     if ( iInstanceSource[0] == '/' )
192     {
193         curPos = 1;
194     }
195 
196     AbcA::ObjectReaderPtr obj = iObj->getArchive()->getTop();
197     return recurse( obj, iInstanceSource, curPos );
198 }
199 
200 //-*****************************************************************************
201 static inline
getParentFullName(const std::string & iChildFullName)202 std::string getParentFullName( const std::string& iChildFullName )
203 {
204     size_t pos = iChildFullName.rfind('/');
205 
206     if ( pos == std::string::npos || pos == 0 )
207     {
208         return std::string();
209     }
210 
211     return iChildFullName.substr(0, pos);
212 }
213 
214 }  // end anonymous namespace
215 
216 //-*****************************************************************************
getParent() const217 IObject IObject::getParent() const
218 {
219 
220     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IObject::getParent()" );
221 
222     if ( !m_instancedFullName.empty() )
223     {
224         std::string parentFullName = getParentFullName( m_instancedFullName );
225 
226         AbcA::ObjectReaderPtr parentPtr = m_object->getParent();
227         bool setFullName = false;
228 
229         // if the instanced full name doesn't match the parents full name
230         // then we have an instanced situation where we need to carefully
231         // walk the hierarchy to make sure we end up with the correct parent
232 
233         // If the names do match, then the parent isn't a part of the instance
234         // and so we don't need to set that full name
235         if ( parentPtr && !parentFullName.empty() &&
236              parentFullName != parentPtr->getFullName() )
237         {
238             parentPtr = objectReaderByName( parentPtr, parentFullName );
239             setFullName = true;
240         }
241 
242         IObject obj( parentPtr,
243                      kWrapExisting,
244                      getErrorHandlerPolicy() );
245 
246         if ( setFullName )
247         {
248             obj.setInstancedFullName( parentFullName );
249         }
250 
251         return obj;
252     }
253     else if ( m_object )
254     {
255         return IObject( m_object->getParent(),
256                         kWrapExisting,
257                         getErrorHandlerPolicy() );
258     }
259 
260     ALEMBIC_ABC_SAFE_CALL_END();
261 
262     // Not all error handlers throw. Have a default.
263     return IObject();
264 }
265 
266 //-*****************************************************************************
getNumChildren() const267 size_t IObject::getNumChildren() const
268 {
269 
270     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IObject::getNumChildren()" );
271 
272     if ( m_object )
273     {
274         return m_object->getNumChildren();
275     }
276 
277     ALEMBIC_ABC_SAFE_CALL_END();
278 
279     // Not all error handlers throw, have a default.
280     return 0;
281 }
282 
283 //-*****************************************************************************
getChildHeader(size_t iIdx) const284 const AbcA::ObjectHeader &IObject::getChildHeader( size_t iIdx ) const
285 {
286 
287     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IObject::getChildHeader()" );
288 
289     if ( m_object )
290     {
291         return m_object->getChildHeader( iIdx );
292     }
293 
294     ALEMBIC_ABC_SAFE_CALL_END();
295 
296     // Not all error handlers throw, have a default.
297     static const AbcA::ObjectHeader hd;
298     return hd;
299 }
300 
301 //-*****************************************************************************
302 const AbcA::ObjectHeader *
getChildHeader(const std::string & iName) const303 IObject::getChildHeader( const std::string &iName ) const
304 {
305 
306     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IObject::getChildHeader( name )" );
307 
308     if ( m_object )
309     {
310         return m_object->getChildHeader( iName );
311     }
312 
313     ALEMBIC_ABC_SAFE_CALL_END();
314 
315     // Not all error handlers throw, have a default.
316     return NULL;
317 }
318 
319 //-*****************************************************************************
getChild(size_t iChildIndex) const320 IObject IObject::getChild( size_t iChildIndex ) const
321 {
322 
323     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IObject::getChild()" );
324 
325     if ( m_object )
326     {
327         IObject obj( m_object->getChild( iChildIndex ),
328                      kWrapExisting,
329                      getErrorHandlerPolicy() );
330 
331         if ( !m_instancedFullName.empty() )
332         {
333             obj.setInstancedFullName(
334                 m_instancedFullName + std::string("/") + obj.getName() );
335         }
336 
337         return obj;
338     }
339 
340     ALEMBIC_ABC_SAFE_CALL_END();
341 
342     // Not all error handlers throw, return something in case.
343     return IObject();
344 }
345 
346 //-*****************************************************************************
getChild(const std::string & iChildName) const347 IObject IObject::getChild( const std::string &iChildName ) const
348 {
349 
350     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IObject::getChild()" );
351 
352     if ( m_object )
353     {
354         IObject obj( m_object->getChild( iChildName ),
355                      kWrapExisting,
356                      getErrorHandlerPolicy() );
357 
358         if ( !m_instancedFullName.empty() )
359         {
360             obj.setInstancedFullName(
361                 m_instancedFullName + std::string("/") + obj.getName() );
362         }
363 
364         return obj;
365     }
366 
367     ALEMBIC_ABC_SAFE_CALL_END();
368 
369     // Not all error handlers throw, return something in case.
370     return IObject();
371 }
372 
373 //-*****************************************************************************
reset()374 void IObject::reset()
375 {
376     m_instanceObject.reset();
377     m_instancedFullName.clear();
378 
379     m_object.reset();
380     Base::reset();
381 }
382 
383 //-*****************************************************************************
getProperties() const384 ICompoundProperty IObject::getProperties() const
385 {
386 
387     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IObject::getProperties()" );
388 
389     if ( m_object )
390     {
391         return ICompoundProperty( m_object->getProperties(), kWrapExisting );
392     }
393 
394     ALEMBIC_ABC_SAFE_CALL_END();
395 
396     // Not all error handlers throw, have a default.
397     return ICompoundProperty();
398 }
399 
400 //-*****************************************************************************
getPropertiesHash(Util::Digest & oDigest)401 bool IObject::getPropertiesHash( Util::Digest & oDigest )
402 {
403    ALEMBIC_ABC_SAFE_CALL_BEGIN( "IObject::getPropertiesHash()" );
404 
405     if ( m_object )
406     {
407         return m_object->getPropertiesHash( oDigest );
408     }
409 
410     ALEMBIC_ABC_SAFE_CALL_END();
411 
412     // Not all error handlers throw, have a default.
413     return false;
414 }
415 
416 
417 //-*****************************************************************************
getChildrenHash(Util::Digest & oDigest)418 bool IObject::getChildrenHash( Util::Digest & oDigest )
419 {
420    ALEMBIC_ABC_SAFE_CALL_BEGIN( "IObject::getChildrenHash()" );
421 
422     if ( m_object )
423     {
424         return m_object->getChildrenHash( oDigest );
425     }
426 
427     ALEMBIC_ABC_SAFE_CALL_END();
428 
429     // Not all error handlers throw, have a default.
430     return false;
431 }
432 
433 //-*****************************************************************************
isInstanceRoot() const434 bool IObject::isInstanceRoot() const
435 {
436     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IObject::isInstanceRoot()" );
437 
438     if ( m_instanceObject )
439     {
440         return true;
441     }
442 
443     ALEMBIC_ABC_SAFE_CALL_END();
444 
445     return false;
446 }
447 
448 //-*****************************************************************************
isInstanceDescendant() const449 bool IObject::isInstanceDescendant() const
450 {
451     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IObject::isInstanceDescendant()" );
452 
453     if ( !m_instancedFullName.empty() )
454     {
455         return true;
456     }
457 
458     ALEMBIC_ABC_SAFE_CALL_END();
459 
460     return false;
461 }
462 
463 //-*****************************************************************************
instanceSourcePath() const464 std::string IObject::instanceSourcePath() const
465 {
466     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IObject::instanceSourcePath()" );
467 
468     if ( !m_instanceObject )
469     {
470         return std::string();
471     }
472 
473     AbcA::CompoundPropertyReaderPtr props = m_instanceObject->getProperties();
474     return readInstanceSource( props );
475 
476     ALEMBIC_ABC_SAFE_CALL_END();
477 
478     return std::string();
479 }
480 
481 //-*****************************************************************************
setInstancedFullName(const std::string & parentPath) const482 void IObject::setInstancedFullName( const std::string& parentPath ) const
483 {
484     m_instancedFullName = parentPath;
485 }
486 
487 //-*****************************************************************************
isChildInstance(size_t iChildIndex) const488 bool IObject::isChildInstance( size_t iChildIndex ) const
489 {
490     ALEMBIC_ABC_SAFE_CALL_BEGIN(
491         "IObject::isChildInstanced(size_t iChildIndex)" );
492 
493     IObject child = getChild( iChildIndex );
494 
495     if ( child.valid() )
496     {
497         return child.isInstanceRoot();
498     }
499 
500     ALEMBIC_ABC_SAFE_CALL_END();
501 
502     return false;
503 }
504 
505 //-*****************************************************************************
isChildInstance(const std::string & iChildName) const506 bool IObject::isChildInstance( const std::string &iChildName ) const
507 {
508     ALEMBIC_ABC_SAFE_CALL_BEGIN(
509         "IObject::isChildInstance(const std::string &iChildName)" );
510 
511     IObject child = getChild( iChildName );
512 
513     if ( child.valid() )
514     {
515         return child.isInstanceRoot();
516     }
517 
518     ALEMBIC_ABC_SAFE_CALL_END();
519 
520     return false;
521 }
522 
523 //-*****************************************************************************
init(IArchive & iArchive,const Argument & iArg0)524 void IObject::init( IArchive & iArchive, const Argument &iArg0 )
525 {
526     // Set the error handling policy
527     getErrorHandler().setPolicy(
528         GetErrorHandlerPolicy( iArchive, iArg0 ) );
529 
530     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IObject::init( IArchive )" );
531 
532     m_object = iArchive.getTop().getPtr();
533 
534     ALEMBIC_ABC_SAFE_CALL_END_RESET();
535 }
536 
537 //-*****************************************************************************
init(AbcA::ObjectReaderPtr iParent,const std::string & iName,ErrorHandler::Policy iPolicy)538 void IObject::init( AbcA::ObjectReaderPtr iParent,
539                     const std::string &iName,
540                     ErrorHandler::Policy iPolicy )
541 {
542     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IObject::init()" );
543 
544     getErrorHandler().setPolicy( iPolicy );
545 
546     m_object = iParent->getChild( iName );
547 
548     ALEMBIC_ABC_SAFE_CALL_END();
549 }
550 
551 //-*****************************************************************************
initInstance()552 void IObject::initInstance()
553 {
554 
555     // not an instance so m_instanceObject will stay empty
556     if ( !m_object || m_object->getMetaData().get("isInstance") != "1")
557     {
558         return;
559     }
560 
561     AbcA::CompoundPropertyReaderPtr propsPtr = m_object->getProperties();
562     std::string instanceSource = readInstanceSource( propsPtr );
563     AbcA::ObjectReaderPtr targetObject =
564         objectReaderByName( m_object, instanceSource );
565 
566     m_instanceObject = m_object;
567     m_object = targetObject;
568 
569     // initialize the full name to the instance full name
570     if ( m_instanceObject != 0 )
571     {
572         m_instancedFullName = m_instanceObject->getFullName();
573     }
574 }
575 
576 } // End namespace ALEMBIC_VERSION_NS
577 } // End namespace Abc
578 } // End namespace Alembic
579