1 //-*****************************************************************************
2 //
3 // Copyright (c) 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 <algorithm>
38 #include <Alembic/AbcCoreHDF5/HDF5Hierarchy.h>
39 #include <Alembic/AbcCoreHDF5/HDF5Util.h>
40 #include <Alembic/AbcCoreHDF5/ReadUtil.h>
41 
42 namespace Alembic {
43 namespace AbcCoreHDF5 {
44 namespace ALEMBIC_VERSION_NS {
45 
46 //-*****************************************************************************
47 class ObjectVisitor
48 {
49 public:
ObjectVisitor(HDF5Hierarchy & iParent)50     ObjectVisitor( HDF5Hierarchy &iParent )
51       : m_parent( iParent ) {}
52 
53 public:
addObject(hid_t iGroup,const char * iName)54     void addObject( hid_t iGroup, const char *iName )
55     {
56         m_parent.addObject( iGroup, iName );
57     }
58 
addAttr(hid_t iGroup,const char * iName)59     void addAttr( hid_t iGroup, const char *iName )
60     {
61         m_parent.addAttr( iGroup, iName );
62     }
63 
64 private:
65     HDF5Hierarchy &m_parent;
66 };
67 
68 //-*****************************************************************************
VisitAllAttrsCB(hid_t iGroup,const char * iAttrName,const H5A_info_t * iAinfo,void * iOpData)69 static herr_t VisitAllAttrsCB( hid_t iGroup,
70                                const char *iAttrName,
71                                const H5A_info_t *iAinfo,
72                                void *iOpData )
73 {
74     ObjectVisitor *visitor = ( ObjectVisitor * )iOpData;
75     visitor->addAttr( iGroup, iAttrName );
76 
77     return 0;
78 }
79 
80 //-*****************************************************************************
VisitAllGroupsCB(hid_t iGroup,const char * iName,const H5L_info_t * iOinfo,void * iOpData)81 static herr_t VisitAllGroupsCB( hid_t iGroup,
82                                 const char *iName,
83                                 const H5L_info_t *iOinfo,
84                                 void *iOpData )
85 {
86     ObjectVisitor *visitor = ( ObjectVisitor * )iOpData;
87 
88     H5O_info_t Oinfo;
89     H5Oget_info_by_name( iGroup, iName, &Oinfo, H5P_DEFAULT );
90 
91     if ( Oinfo.type == H5O_TYPE_GROUP )
92     {
93         H5Literate_by_name( iGroup, iName,
94                             H5_INDEX_NAME,
95                             H5_ITER_INC,
96                             NULL,
97                             VisitAllGroupsCB,
98                             iOpData,
99                             H5P_DEFAULT );
100 
101         visitor->addObject( iGroup, iName );
102 
103         H5Aiterate_by_name( iGroup, iName,
104                             H5_INDEX_NAME,
105                             H5_ITER_INC,
106                             NULL,
107                             VisitAllAttrsCB,
108                             iOpData,
109                             H5P_DEFAULT );
110 
111     }
112     else if (Oinfo.type == H5O_TYPE_DATASET )
113     {
114         visitor->addObject( iGroup, iName );
115 
116         H5Aiterate_by_name( iGroup, iName,
117                             H5_INDEX_NAME,
118                             H5_ITER_INC,
119                             NULL,
120                             VisitAllAttrsCB,
121                             iOpData,
122                             H5P_DEFAULT );
123     }
124 
125     // Keep iterating!
126     return 0;
127 }
128 
129 //-*****************************************************************************
createNode(hid_t iObject)130 H5Node HDF5Hierarchy::createNode( hid_t iObject )
131 {
132     hobj_ref_t ref;
133     H5Rcreate( &ref, iObject, ".", H5R_OBJECT, -1 );
134 
135     return H5Node( iObject, ref, isEnabled() ? this : NULL );
136 }
137 
138 //-*****************************************************************************
build(hid_t iFile)139 void HDF5Hierarchy::build( hid_t iFile )
140 {
141     clear();
142 
143     ObjectVisitor visitor( *this );
144     H5Literate( iFile,
145                 H5_INDEX_NAME,
146                 H5_ITER_INC,
147                 NULL,
148                 VisitAllGroupsCB,
149                 ( void * )&visitor);
150 }
151 
152 //-*****************************************************************************
clear()153 void HDF5Hierarchy::clear()
154 {
155     for( ObjectMap::iterator it = m_objectMap.begin();
156          it != m_objectMap.end(); ++it )
157     {
158         it->second.m_attrs.clear();
159     }
160 
161     m_objectMap.clear();
162 }
163 
164 //-*****************************************************************************
addObject(hid_t iParent,const char * iName)165 void HDF5Hierarchy::addObject( hid_t iParent, const char *iName )
166 {
167     hobj_ref_t parentRef, childRef;
168     H5Rcreate( &parentRef, iParent, ".", H5R_OBJECT, -1 );
169     H5Rcreate( &childRef, iParent, iName, H5R_OBJECT, -1 );
170 
171     m_objectMap[parentRef].m_children.push_back(
172                                             ChildInfo( iName, childRef ) );
173 }
174 
175 namespace {
176     const std::string g_strInfo( ".info" );
177     const std::string g_strMeta( ".meta" );
178 }
179 
180 //-*****************************************************************************
addAttr(hid_t iParent,const char * iName)181 void HDF5Hierarchy::addAttr( hid_t iParent, const char *iName )
182 {
183     hobj_ref_t parentRef;
184     H5Rcreate( &parentRef, iParent, ".", H5R_OBJECT, -1 );
185 
186     // attribute
187     AttrInfoArray& attrs = m_objectMap[parentRef].m_attrs;
188     attrs.push_back( AttrInfo( iName ) );
189     AttrInfo& info = attrs[attrs.size()-1];
190 
191     std::string strName( iName );
192     const size_t len = strName.size();
193     if ( len < 6 ) return;
194 
195     // property header mask
196     if ( strName.compare( len-5, 5, g_strInfo ) == 0 )
197     {
198         ABCA_ASSERT( !info.m_mask,
199                      "A property header mask alreasy exists." );
200 
201         info.m_mask = new MaskInfo;
202         info.m_mask->m_numFields = 0;
203 
204         ReadSmallArray( iParent, iName, H5T_STD_U32LE,
205                         H5T_NATIVE_UINT32, 5,
206                         info.m_mask->m_numFields,
207                         ( void * ) info.m_mask->m_data );
208     }
209 
210     // meta data string
211     if ( strName.compare( len-5, 5, g_strMeta ) == 0 )
212     {
213         ReadString( iParent, strName, info.m_meta );
214     }
215 
216 }
217 
218 //-*****************************************************************************
getChildRef(hobj_ref_t iParentRef,const std::string & iName)219 hobj_ref_t HDF5Hierarchy::getChildRef( hobj_ref_t iParentRef,
220                                        const std::string& iName )
221 {
222     ChildInfo info( iName );
223     ChildInfoArray& children = m_objectMap[iParentRef].m_children;
224     ChildInfoArray::iterator it = std::lower_bound( children.begin(),
225                                                     children.end(),
226                                                     info );
227 
228     ABCA_ASSERT ( ( it != children.end() && !( info < *it ) ),
229                   "A child object does not exist with name: " << iName );
230 
231     return it->m_ref;
232 }
233 
234 //-*****************************************************************************
childExists(hobj_ref_t iParentRef,const std::string & iName)235 bool HDF5Hierarchy::childExists( hobj_ref_t iParentRef,
236                                  const std::string& iName )
237 {
238     ChildInfo info( iName );
239     ChildInfoArray& children = m_objectMap[iParentRef].m_children;
240     ChildInfoArray::iterator it = std::lower_bound( children.begin(),
241                                                     children.end(),
242                                                     info );
243 
244     return ( it != children.end() && !( info < *it ) );
245 }
246 
247 //-*****************************************************************************
attrExists(hobj_ref_t iParentRef,const std::string & iName)248 bool HDF5Hierarchy::attrExists( hobj_ref_t iParentRef,
249                                 const std::string& iName )
250 {
251     AttrInfo info( iName );
252     AttrInfoArray& attrs = m_objectMap[iParentRef].m_attrs;
253     AttrInfoArray::iterator it = std::lower_bound( attrs.begin(),
254                                                    attrs.end(),
255                                                    info );
256 
257     return ( it != attrs.end() && !( info < *it ) );
258 }
259 
260 //-*****************************************************************************
readMetaDataString(hobj_ref_t iParentRef,const std::string & iMetaDataName,std::string & oMetaDataString)261 void HDF5Hierarchy::readMetaDataString( hobj_ref_t iParentRef,
262                                         const std::string &iMetaDataName,
263                                         std::string &oMetaDataString )
264 {
265     AttrInfo info( iMetaDataName );
266     AttrInfoArray& attrs = m_objectMap[iParentRef].m_attrs;
267     AttrInfoArray::iterator it = std::lower_bound( attrs.begin(),
268                                                    attrs.end(),
269                                                    info );
270     if (it == attrs.end() || info < *it )
271         return;
272 
273     oMetaDataString = it->m_meta;
274 }
275 
276 //-*****************************************************************************
readMaskInfo(hobj_ref_t iParentRef,const std::string & iPropName,size_t & oNumFields,void * oData)277 void HDF5Hierarchy::readMaskInfo( hobj_ref_t iParentRef,
278                                   const std::string &iPropName,
279                                   size_t& oNumFields,
280                                   void* oData )
281 {
282     AttrInfo info( iPropName );
283     AttrInfoArray& attrs = m_objectMap[iParentRef].m_attrs;
284     AttrInfoArray::iterator it = std::lower_bound( attrs.begin(),
285                                                    attrs.end(),
286                                                    info );
287 
288     ABCA_ASSERT ( it != attrs.end() && !( info < *it),
289                   "Can't find a property header info attribute." );
290 
291     if ( !it->m_mask )
292     {
293         return;
294     }
295 
296     MaskInfo& p = *it->m_mask;
297     oNumFields = p.m_numFields;
298     memcpy( oData, p.m_data, sizeof( uint32_t ) * oNumFields );
299 }
300 
301 //-*****************************************************************************
makeCompactObjectHierarchy(std::vector<hobj_ref_t> & oObjectRefs,std::vector<uint32_t> & oChildrenSizes,std::vector<std::string> & oChildrenNames,std::vector<hobj_ref_t> & oChildrenRefs,std::vector<uint32_t> & oAttrSizes,std::vector<std::string> & oAttrNames,std::vector<char> & oHasMask,std::vector<uint32_t> & oMaskBits,std::vector<char> & oHasMeta,std::vector<std::string> & oMetaStrs)302 void HDF5Hierarchy::makeCompactObjectHierarchy(
303     std::vector<hobj_ref_t>     &oObjectRefs,
304 
305     std::vector<uint32_t>       &oChildrenSizes,
306     std::vector<std::string>    &oChildrenNames,
307     std::vector<hobj_ref_t>     &oChildrenRefs,
308 
309     std::vector<uint32_t>       &oAttrSizes,
310     std::vector<std::string>    &oAttrNames,
311     std::vector<char>           &oHasMask,
312     std::vector<uint32_t>       &oMaskBits,
313     std::vector<char>           &oHasMeta,
314     std::vector<std::string>    &oMetaStrs
315     )
316 {
317     oObjectRefs.clear();
318 
319     oChildrenSizes.clear();
320     oChildrenNames.clear();
321     oChildrenRefs.clear();
322 
323     oAttrSizes.clear();
324     oAttrNames.clear();
325     oHasMask.clear();
326     oMaskBits.clear();
327     oHasMeta.clear();
328     oMetaStrs.clear();
329 
330     for( ObjectMap::iterator itp = m_objectMap.begin();
331          itp != m_objectMap.end(); ++itp )
332     {
333         ObjectInfo& info = itp->second;
334 
335         {
336             oObjectRefs.push_back( itp->first );
337         }
338 
339         // children
340         {
341             ChildInfoArray& array = info.m_children;
342 
343             oChildrenSizes.push_back( array.size() );
344 
345             for( ChildInfoArray::iterator itc = array.begin();
346                  itc != array.end(); ++itc )
347             {
348                 oChildrenNames.push_back( itc->m_name );
349                 oChildrenRefs.push_back( itc->m_ref );
350             }
351         }
352 
353         // attributes, property header masks and meta data string
354         {
355             AttrInfoArray& array = info.m_attrs;
356 
357             oAttrSizes.push_back( array.size() );
358 
359             for( AttrInfoArray::iterator itc = array.begin();
360                  itc != array.end(); ++itc )
361             {
362                 // attribute
363                 oAttrNames.push_back( itc->m_name );
364 
365                 // mask
366                 if ( itc->m_mask && itc->m_mask->m_numFields > 0 )
367                 {
368                     MaskInfo& p = *itc->m_mask;
369                     oHasMask.push_back( 1 );
370 
371                     oMaskBits.push_back( p.m_numFields );
372                     oMaskBits.push_back( p.m_data[0] );
373                     oMaskBits.push_back( p.m_data[1] );
374                     oMaskBits.push_back( p.m_data[2] );
375                     oMaskBits.push_back( p.m_data[3] );
376                     oMaskBits.push_back( p.m_data[4] );
377                 }
378                 else
379                 {
380                     oHasMask.push_back( 0 );
381                 }
382 
383                 // meta data
384                 if ( itc->m_meta.size() > 0 )
385                 {
386                     oMetaStrs.push_back( itc->m_meta );
387                     oHasMeta.push_back( 1 );
388                 }
389                 else
390                 {
391                     oHasMeta.push_back( 0 );
392                 }
393             }
394         }
395     }
396 }
397 
398 //-*****************************************************************************
extractFromCompactObjectHierarchy(hid_t iFile,std::vector<hobj_ref_t> & iObjectRefs,std::vector<uint32_t> & iChildrenSizes,std::vector<std::string> & iChildrenNames,std::vector<hobj_ref_t> & iChildrenRefs,std::vector<uint32_t> & iAttrSizes,std::vector<std::string> & iAttrNames,std::vector<char> & iHasMask,std::vector<uint32_t> & iMaskBits,std::vector<char> & iHasMeta,std::vector<std::string> & iMetaStrs)399 void HDF5Hierarchy::extractFromCompactObjectHierarchy(
400     hid_t                       iFile,
401 
402     std::vector<hobj_ref_t>     &iObjectRefs,
403 
404     std::vector<uint32_t>       &iChildrenSizes,
405     std::vector<std::string>    &iChildrenNames,
406     std::vector<hobj_ref_t>     &iChildrenRefs,
407 
408     std::vector<uint32_t>       &iAttrSizes,
409     std::vector<std::string>    &iAttrNames,
410     std::vector<char>           &iHasMask,
411     std::vector<uint32_t>       &iMaskBits,
412     std::vector<char>           &iHasMeta,
413     std::vector<std::string>    &iMetaStrs )
414 {
415     clear();
416 
417     size_t idxCBegin(0), idxCEnd(0);
418     size_t idxABegin(0), idxAEnd(0);
419     size_t idxMask(0), idxMeta(0);
420 
421     for( size_t ip = 0; ip < iObjectRefs.size(); ++ip )
422     {
423         const hobj_ref_t parentRef = iObjectRefs[ip];
424 
425         ObjectInfo& object = m_objectMap[parentRef];
426 
427         // children
428         idxCEnd = idxCBegin + iChildrenSizes[ip];
429         for( size_t ic = idxCBegin; ic < idxCEnd; ++ic )
430         {
431             const hobj_ref_t ref    = iChildrenRefs[ic];
432             const std::string &name = iChildrenNames[ic];
433 
434             object.m_children.push_back( ChildInfo( name, ref) );
435         }
436         idxCBegin = idxCEnd;
437 
438         // attributes, masks and metadata
439         idxAEnd = idxABegin + iAttrSizes[ip];
440         for( size_t ic = idxABegin; ic < idxAEnd; ++ic )
441         {
442             AttrInfoArray& attrs = object.m_attrs;
443 
444             // attribute
445             const std::string &name = iAttrNames[ic];
446             attrs.push_back( AttrInfo( name ) );
447             AttrInfo& info = attrs[attrs.size()- 1];
448 
449             // masks
450             if ( iHasMask[ic] )
451             {
452                 const size_t length  =  iMaskBits[idxMask*6];
453                 const uint32_t* data = &iMaskBits[idxMask*6+1];
454 
455                 info.m_mask = new MaskInfo;
456                 info.m_mask->m_numFields = length;
457                 memcpy( info.m_mask->m_data,
458                         data, sizeof(uint32_t) * length );
459 
460                 idxMask++;
461             }
462 
463             // metadata
464             if (iHasMeta[ic] )
465             {
466                 info.m_meta = iMetaStrs[idxMeta++];
467             }
468         }
469         idxABegin = idxAEnd;
470     }
471 }
472 
473 } // End namespace ALEMBIC_VERSION_NS
474 
475 using namespace ALEMBIC_VERSION_NS;
476 
477 } // End namespace AbcCoreHDF5
478 } // End namespace Alembic
479 
480