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