430 lines
14 KiB
C++
430 lines
14 KiB
C++
//-*****************************************************************************
|
|
//
|
|
// Copyright (c) 2013,
|
|
// Sony Pictures Imageworks, Inc. and
|
|
// Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd.
|
|
//
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following disclaimer
|
|
// in the documentation and/or other materials provided with the
|
|
// distribution.
|
|
// * Neither the name of Sony Pictures Imageworks, nor
|
|
// Industrial Light & Magic nor the names of their contributors may be used
|
|
// to endorse or promote products derived from this software without specific
|
|
// prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
//-*****************************************************************************
|
|
|
|
#include <Alembic/Abc/All.h>
|
|
#include <Alembic/AbcCoreAbstract/All.h>
|
|
#ifdef ALEMBIC_WITH_HDF5
|
|
#include <Alembic/AbcCoreHDF5/All.h>
|
|
#endif
|
|
#include <Alembic/AbcCoreOgawa/All.h>
|
|
#include <Alembic/AbcCoreFactory/All.h>
|
|
#include <Alembic/AbcCollection/All.h>
|
|
#include <Alembic/AbcGeom/All.h>
|
|
#include <Alembic/AbcMaterial/All.h>
|
|
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <sys/stat.h>
|
|
|
|
#ifdef _MSC_VER
|
|
// set up _S_ISDIR()
|
|
#if !defined(S_ISDIR)
|
|
# if defined( _S_IFDIR) && !defined( __S_IFDIR)
|
|
# define __S_IFDIR _S_IFDIR
|
|
# endif
|
|
# define S_ISDIR(mode) (mode&__S_IFDIR)
|
|
#endif
|
|
#endif // _MSC_VER
|
|
|
|
namespace Abc = ::Alembic::Abc;;
|
|
namespace AbcA = ::Alembic::AbcCoreAbstract;
|
|
namespace AbcF = ::Alembic::AbcCoreFactory;
|
|
namespace AbcG = ::Alembic::AbcGeom;
|
|
|
|
#define RESETCOLOR "\033[0m"
|
|
#define GREENCOLOR "\033[1;32m"
|
|
#define BLUECOLOR "\033[1;34m"
|
|
#define BOLD "\033[1m"
|
|
|
|
//-*****************************************************************************
|
|
bool is_leaf( AbcG::IObject iObj )
|
|
{
|
|
if ( !iObj.getParent().valid() ) {
|
|
return true;
|
|
}
|
|
|
|
Abc::IObject parent = iObj.getParent();
|
|
int numChildren = parent.getNumChildren();
|
|
|
|
Abc::IObject test = parent.getChild(numChildren - 1);
|
|
if ( test.valid() && test.getName() != iObj.getName() ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//-*****************************************************************************
|
|
bool is_leaf( Abc::ICompoundProperty iProp, Abc::PropertyHeader iHeader ) {
|
|
|
|
if ( !iProp.valid() ) {
|
|
return true;
|
|
}
|
|
|
|
int last = iProp.getNumProperties() - 1;
|
|
Abc::PropertyHeader header = iProp.getPropertyHeader( last );
|
|
if ( header.getName() == iHeader.getName() )
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
//-*****************************************************************************
|
|
int index( Abc::ICompoundProperty iProp, Abc::PropertyHeader iHeader ) {
|
|
|
|
for ( size_t i = 0 ; i < iProp.getNumProperties() ; i++ ) {
|
|
Abc::PropertyHeader header = iProp.getPropertyHeader( i );
|
|
if ( header.getName() == iHeader.getName() ) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//-*****************************************************************************
|
|
void tree( Abc::IScalarProperty iProp, std::string prefix = "" )
|
|
{
|
|
if ( iProp.getObject().getFullName() != "/" ) {
|
|
prefix = prefix + " ";
|
|
}
|
|
if ( is_leaf( iProp.getParent(), iProp.getHeader() ) &&
|
|
( iProp.getObject().getNumChildren() == 0 ||
|
|
iProp.getParent().getName() != "" )
|
|
) {
|
|
std::cout << prefix << " `--";
|
|
} else {
|
|
std::cout << prefix << " :--";
|
|
prefix = prefix + " :";
|
|
}
|
|
|
|
std::cout << iProp.getName() << "\r" << std::endl;
|
|
}
|
|
|
|
//-*****************************************************************************
|
|
void tree( Abc::IArrayProperty iProp, std::string prefix = "" )
|
|
{
|
|
if ( iProp.getObject().getFullName() != "/" ) {
|
|
prefix = prefix + " ";
|
|
}
|
|
if ( is_leaf( iProp.getParent(), iProp.getHeader() ) &&
|
|
( iProp.getObject().getNumChildren() == 0 ||
|
|
iProp.getParent().getName() != "" )
|
|
) {
|
|
std::cout << prefix << " `--";
|
|
} else {
|
|
std::cout << prefix << " :--";
|
|
prefix = prefix + " :";
|
|
}
|
|
|
|
std::cout << iProp.getName() << "\r" << std::endl;
|
|
}
|
|
|
|
//-*****************************************************************************
|
|
void tree( Abc::ICompoundProperty iProp, std::string prefix = "" )
|
|
{
|
|
if ( iProp.getObject().getFullName() != "/" ) {
|
|
prefix = prefix + " ";
|
|
}
|
|
if ( is_leaf( iProp.getParent(), iProp.getHeader() ) &&
|
|
iProp.getObject().getNumChildren() == 0
|
|
) {
|
|
std::cout << prefix << " `--";
|
|
prefix = prefix + " ";
|
|
} else {
|
|
if ( is_leaf( iProp.getParent(), iProp.getHeader() ) ) {
|
|
std::cout << prefix << " | `--";
|
|
prefix = prefix + " |";
|
|
} else if ( iProp.getObject().getNumChildren() == 0 ) {
|
|
std::cout << prefix << " :--";
|
|
prefix = prefix + " :";
|
|
} else if ( is_leaf( iProp, iProp.getHeader() ) ) {
|
|
std::cout << prefix << " | `--";
|
|
prefix = prefix + " |";
|
|
} else {
|
|
std::cout << prefix << " | :--";
|
|
prefix = prefix + " | :";
|
|
}
|
|
}
|
|
|
|
std::cout << iProp.getName() << "\r" << std::endl;
|
|
|
|
for ( size_t i = 0 ; i < iProp.getNumProperties() ; i++ ) {
|
|
Abc::PropertyHeader header = iProp.getPropertyHeader( i );
|
|
if ( header.isScalar() ) {
|
|
tree( Abc::IScalarProperty( iProp, header.getName() ), prefix );
|
|
} else if ( header.isArray() ) {
|
|
tree( Abc::IArrayProperty( iProp, header.getName() ), prefix );
|
|
} else {
|
|
tree( Abc::ICompoundProperty( iProp, header.getName() ), prefix );
|
|
}
|
|
}
|
|
}
|
|
|
|
//-*****************************************************************************
|
|
void tree( AbcG::IObject iObj, bool showProps = false, std::string prefix = "" )
|
|
{
|
|
std::string path = iObj.getFullName();
|
|
|
|
if ( path == "/" ) {
|
|
prefix = "";
|
|
}
|
|
else {
|
|
if ( iObj.getParent().getFullName() != "/" ) {
|
|
prefix = prefix + " ";
|
|
}
|
|
if ( is_leaf( iObj ) ) {
|
|
std::cout << prefix << " `--";
|
|
prefix = prefix + " ";
|
|
} else {
|
|
std::cout << prefix << " |--";
|
|
prefix = prefix + " |";
|
|
}
|
|
};
|
|
|
|
if ( showProps )
|
|
std::cout << GREENCOLOR;
|
|
std::cout << iObj.getName();
|
|
if ( showProps )
|
|
std::cout << RESETCOLOR;
|
|
std::cout << "\r" << std::endl;
|
|
|
|
// property tree
|
|
if ( showProps ) {
|
|
Abc::ICompoundProperty props = iObj.getProperties();
|
|
for ( size_t i = 0 ; i < props.getNumProperties() ; i++ ) {
|
|
Abc::PropertyHeader header = props.getPropertyHeader( i );
|
|
if ( header.isScalar() ) {
|
|
tree( Abc::IScalarProperty( props, header.getName() ), prefix );
|
|
} else if ( header.isArray() ) {
|
|
tree( Abc::IArrayProperty( props, header.getName() ), prefix );
|
|
} else {
|
|
tree( Abc::ICompoundProperty( props, header.getName() ), prefix );
|
|
}
|
|
}
|
|
}
|
|
|
|
// object tree
|
|
for ( size_t i = 0 ; i < iObj.getNumChildren() ; i++ ) {
|
|
tree( AbcG::IObject( iObj, iObj.getChildHeader(i).getName() ),
|
|
showProps, prefix );
|
|
};
|
|
}
|
|
|
|
//-*****************************************************************************
|
|
bool isFile( const std::string& filename )
|
|
{
|
|
struct stat buf;
|
|
if ( stat(filename.c_str(), &buf) == 0 && !S_ISDIR( buf.st_mode ) ) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-*****************************************************************************
|
|
bool optionExists(std::vector<std::string> options, std::string option)
|
|
{
|
|
for ( std::size_t i = 0; i < options.size(); i++ )
|
|
if ( options[i].find(option) != std::string::npos )
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
//-*****************************************************************************
|
|
int main( int argc, char *argv[] )
|
|
{
|
|
bool opt_all = false;
|
|
bool opt_meta = false;
|
|
std::string desc( "abctree [OPTION] FILE[/NAME]\n"
|
|
" -a include properties listings\n"
|
|
" -h, --help prints this help message\n"
|
|
" -m print metadata\n"
|
|
);
|
|
|
|
// check for min args
|
|
if ( argc < 2 ) {
|
|
std::cout << desc << std::endl;
|
|
return 0;
|
|
};
|
|
|
|
// parse args
|
|
std::vector<std::string> arguments(argv, argv + argc);
|
|
std::vector<std::string> options;
|
|
std::vector<std::string> files;
|
|
|
|
// separate file args from option args
|
|
for ( std::size_t i = 1; i < arguments.size(); i++ ) {
|
|
if ( arguments[ i ].substr( 0, 1 ) == "-" )
|
|
options.push_back( arguments[ i ] );
|
|
else
|
|
files.push_back( arguments[ i ] );
|
|
}
|
|
|
|
// help
|
|
if ( argc < 2 ||
|
|
optionExists( options, "h" ) ||
|
|
optionExists( options, "help" )
|
|
) {
|
|
std::cout << desc << std::endl;
|
|
return 0;
|
|
};
|
|
|
|
// set some flags
|
|
opt_all = optionExists( options, "a");
|
|
opt_meta = optionExists( options, "m");
|
|
|
|
// open each file
|
|
for ( std::size_t i = 0; i < files.size(); i++ ) {
|
|
if ( files.size() > 1 )
|
|
std::cout << BOLD << files[i] << ':' << RESETCOLOR << std::endl;
|
|
|
|
std::stringstream ss( files[i] );
|
|
std::stringstream fp;
|
|
std::string segment;
|
|
std::vector<std::string> seglist;
|
|
|
|
/*
|
|
* separate file and object paths, e.g.
|
|
*
|
|
* ../dir1/foo.abc/bar/baz
|
|
* \_____________/\______/
|
|
* file obj
|
|
*/
|
|
int j = 0;
|
|
while ( std::getline( ss, segment, '/' ) ) {
|
|
if ( !isFile ( fp.str() ) ) {
|
|
if ( j != 0 )
|
|
fp << "/";
|
|
fp << segment;
|
|
} else {
|
|
seglist.push_back( segment );
|
|
}
|
|
++j;
|
|
}
|
|
|
|
// open the iarchive
|
|
Abc::IArchive archive;
|
|
AbcF::IFactory factory;
|
|
factory.setPolicy(Abc::ErrorHandler::kQuietNoopPolicy);
|
|
AbcF::IFactory::CoreType coreType;
|
|
archive = factory.getArchive(std::string( fp.str() ), coreType);
|
|
|
|
// display file metadata
|
|
if ( opt_meta ) {
|
|
std::cout << "Using "
|
|
<< Alembic::AbcCoreAbstract::GetLibraryVersion ()
|
|
<< std::endl;;
|
|
|
|
std::string appName;
|
|
std::string libraryVersionString;
|
|
Alembic::Util::uint32_t libraryVersion;
|
|
std::string whenWritten;
|
|
std::string userDescription;
|
|
std::string coreName;
|
|
GetArchiveInfo (archive,
|
|
appName,
|
|
libraryVersionString,
|
|
libraryVersion,
|
|
whenWritten,
|
|
userDescription);
|
|
|
|
if ( coreType == AbcF::IFactory::kOgawa ) {
|
|
coreName = "Ogawa";
|
|
} else if ( coreType == AbcF::IFactory::kHDF5 ) {
|
|
coreName = "HDF5";
|
|
} else {
|
|
coreName = "Unknown";
|
|
};
|
|
|
|
if ( appName != "" ) {
|
|
std::cout << " file written by: " << appName << std::endl;
|
|
std::cout << " using Alembic : " << libraryVersionString << std::endl;
|
|
std::cout << " written on : " << whenWritten << std::endl;
|
|
std::cout << " user description : " << userDescription << std::endl;
|
|
} else {
|
|
std::cout << " (file doesn't have any ArchiveInfo)"
|
|
<< std::endl;
|
|
}
|
|
std::cout << " core type : " << coreName << std::endl;
|
|
};
|
|
|
|
// walk object hierarchy and find valid objects
|
|
AbcG::IObject test = archive.getTop();
|
|
AbcG::IObject iObj = test;
|
|
while ( test.valid() && seglist.size() > 0 ) {
|
|
test = test.getChild( seglist.front() );
|
|
if ( test.valid() ) {
|
|
iObj = test;
|
|
seglist.erase( seglist.begin() );
|
|
}
|
|
}
|
|
|
|
// walk property hierarchy for most recent valid object
|
|
Abc::ICompoundProperty props = iObj.getProperties();
|
|
const Abc::PropertyHeader* header;
|
|
bool found = false;
|
|
for ( std::size_t i = 0; i < seglist.size(); ++i ) {
|
|
header = props.getPropertyHeader( seglist[i] );
|
|
if ( header && header->isCompound() ) {
|
|
Abc::ICompoundProperty ptest( props, header->getName() );
|
|
if ( ptest.valid() ) {
|
|
props = ptest;
|
|
found = true;
|
|
}
|
|
} else if ( header && header->isSimple() ) {
|
|
found = true;
|
|
} else {
|
|
std::cout << seglist[i]
|
|
<< ": Invalid object or property"
|
|
<< std::endl;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// walk the archive tree
|
|
if ( found )
|
|
if ( header->isCompound() )
|
|
tree( props );
|
|
else
|
|
tree( Abc::IScalarProperty( props, header->getName() ) );
|
|
else
|
|
tree( iObj, opt_all );
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|