geometryCacheConverter/geometryCacheFile.cpp

geometryCacheConverter/geometryCacheFile.cpp
//-
// ==========================================================================
// Copyright 2015 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk
// license agreement provided at the time of installation or download,
// or which otherwise accompanies this software in either electronic
// or hard copy form.
// ==========================================================================
//+
//
// File Name: geometryCacheFile.cpp
//
// Description : An interface used for reading cache file data, storing it
// and converting it to ASCII. See geometryCacheFile.h for file format info.
//
// Project includes
//
#include "geometryCacheFile.h"
#include "geometryCacheBlockBase.h"
#include "geometryCacheBlockStringData.h"
#include "geometryCacheBlockIntData.h"
#include "geometryCacheBlockDVAData.h"
#include "geometryCacheBlockFVAData.h"
// Maya includes
//
#include <maya/flib.h>
#include <maya/MString.h>
#include <maya/MGlobal.h>
// Other includes
//
#include <fstream>
#if defined (OSMac_)
#include <stdlib.h>
#else
#include <malloc.h>
#endif
//
// Methods
//
geometryCacheFile::geometryCacheFile( const MString& fileName, MIffFile* iffFile )
:cacheFileName( fileName )
//
// Description : ( public method )
// Constructor
//
{
readStatus = false;
iffFilePtr = iffFile;
}
geometryCacheFile::~geometryCacheFile()
//
// Description : ( public method )
// Destructor
//
{
// Free all the pointers in the blockList.
// Start from the back of the list, delete the pointer returned then
// pop it off the stack.
//
while( blockList.size() )
{
// Get current pointer
//
geometryCacheBlockBase * block = blockList.back();
delete block;
// Pop the back item of the stack
//
blockList.pop_back();
}
// Close the cache file
//
iffFilePtr->close();
}
const MString& geometryCacheFile::fileName()
//
// Description : ( public method )
// Returns the file name
//
{
return cacheFileName;
}
const bool& geometryCacheFile::isRead()
//
// Description : ( public method )
// Indicates if the file has been read
//
{
return readStatus;
}
bool geometryCacheFile::readCacheFiles()
//
// Description : ( public method )
// Read the cache file
//
{
MStatus status = MS::kSuccess;
// Attempt to open the file
//
status = iffFilePtr->open( cacheFileName );
if( !status ) return false;
// Proceed if the file is open
//
if( iffFilePtr->isActive() ) {
// Read the Header
//
readStatus = readHeaderGroup( status );
if( !readStatus ) return false;
// Read all the channel groups
//
do {
// Read the next channel group
//
readStatus = readChannelGroup( status );
if( !readStatus ) return false;
} while ( status == MS::kSuccess );
} else
// If file failed to open
//
return false;
return true;
}
bool geometryCacheFile::convertToAscii()
//
// Description : ( public method )
// Convert the file to Ascii
//
{
// Generate an output file name by changing the file name extention to txt
//
int loc = cacheFileName.rindex('.');
MString outputFileName = cacheFileName.substring(0, loc-1);
outputFileName += ".txt";
// Create an output file steam to flush our data to ascii
//
std::ofstream oFile( outputFileName.asChar() );
if( !oFile.bad() )
{
// Create an iterator to iterate through the blockList
//
cacheBlockIterator blockIt;
// Write out all the blocks in the blockList
//
for( blockIt = blockList.begin();
blockIt != blockList.end();
blockIt++ )
{
// Get the current block
//
geometryCacheBlockBase* block = *blockIt;
// OutputToAscii
//
block->outputToAscii( oFile );
}
} else
// If output file stream could not open the file
//
return false;
// Output a message to indicate that the file has been converted
//
MGlobal::displayInfo( "Converted file \"" +
cacheFileName +
"\" to file \"" +
outputFileName +
"\"" );
return true;
}
bool geometryCacheFile::readHeaderGroup( MStatus& status )
//
// Description : ( private method )
// Read the Header group CACH.
// The header of every disk cache file consists of these tags
//
// CACH ( header group )
// VRSN ( version )
// STIM ( startTime in ticks )
// ETIM ( endTime in ticks )
//
{
MIffTag tmpTag;
MIffTag cachTag;
status = iffFilePtr->beginReadGroup( tmpTag, cachTag );
if( status ) {
if( cachTag == MIffTag('C', 'A', 'C', 'H') ) {
// Store a "CACH" tag into the blockList
//
storeCacheBlock( "CACH" );
// Read the header version
//
readStatus = readHeaderVersion();
if( !readStatus ) return false;
// Read the Time Range
//
readStatus = readHeaderTimeRange();
if( !readStatus ) return false;
// Store an ending "/CACH" tag into the blockList
//
storeCacheBlock( "/CACH" );
}
}
iffFilePtr->endReadGroup();
return true;
}
bool geometryCacheFile::readHeaderVersion()
//
// Description : ( private method )
// Read and store the cache file version from the VRSN block.
//
{
MStatus status = MS::kSuccess;
MIffTag tmpTag;
unsigned int byteCount;
status = iffFilePtr->beginGet( tmpTag, (unsigned *)&byteCount );
if( !status ) return false;
char *tmpName = (char*)alloca(sizeof(char)* (byteCount+1));
//pointers allocated by alloca are from the stack and automatically freed when
//the function exits. Do not free explicitly.
if( tmpName && tmpTag == MIffTag('V', 'R', 'S', 'N') ) {
// read the data from the block
//
iffFilePtr->get( tmpName, byteCount, &status);
if( !status ) return false;
// Store the cache file version in the blockList
//
storeCacheBlock( "VRSN", tmpName );
status = iffFilePtr->endGet();
if( !status ) return false;
}
return true;
}
bool geometryCacheFile::readHeaderTimeRange()
//
// Description : ( private method )
// Read and store the start and end time from the STIM and ETIM blocks.
// The data from these blocks are only used for multiple cache files.
// If the cache file is a single cache file, then the values will only be
// from 0 to 1.
//
{
MIffTag tmpTag;
unsigned int byteCount;
#if (!defined BYTE_ORDER) || (BYTE_ORDER == BIG_ENDIAN)
const int *startTime = (int *)iffFilePtr->getChunk(
tmpTag,
(unsigned int *)&byteCount );
if( startTime == NULL ||
!(tmpTag == MIffTag ('S', 'T', 'I', 'M')) ||
byteCount != sizeof(int) )
return false;
// Store the start time in the blockList
//
storeCacheBlock( "STIM", *startTime );
const int *endTime = (int *)iffFilePtr->getChunk(
tmpTag,
(unsigned int *)&byteCount );
if( endTime == NULL ||
!(tmpTag == MIffTag('E', 'T', 'I', 'M')) ||
byteCount != sizeof(int) )
return false;
// Store the end time in the blockList
//
storeCacheBlock( "ETIM", *endTime );
#else
const int *startTime = (int *)iffFilePtr->getChunk( tmpTag, (unsigned int *)&byteCount );
if( startTime == NULL ||
// There is no != operator for MIffTag
!(tmpTag == MIffTag ('S', 'T', 'I', 'M')) ||
byteCount != sizeof(int) )
return false;
// Store the start time in the blockList
//
storeCacheBlock( "STIM", FLswapword(*startTime) );
const int *endTime = (int *)iffFilePtr->getChunk( tmpTag, (unsigned int *)&byteCount );
if( endTime == NULL ||
!(tmpTag == MIffTag('E', 'T', 'I', 'M')) ||
byteCount != sizeof(int) )
return false;
// Store the end time in the blockList
//
storeCacheBlock( "ETIM", FLswapword(*endTime) );
#endif
return true;
}
bool geometryCacheFile::readChannelGroup( MStatus& groupStatus )
//
// Description : ( private method )
// Read the channel group MYCH.
// The channel group can consist of these following tags
//
// MYCH ( time group )
// TIME ( time in ticks )
// CHNM ( channel name )
// SIZE ( size )
// DVCA ( geometry point data )
//
{
MIffTag mychTag;
MIffTag tmpTag;
unsigned int byteCount;
groupStatus = iffFilePtr->beginReadGroup(tmpTag, mychTag);
if( groupStatus == MS::kSuccess ) {
if( mychTag == MIffTag('M', 'Y', 'C', 'H')) {
// Store the "MYCH" group in the blockList
//
storeCacheBlock( "MYCH" );
// Get the next tag
//
MStatus stat = iffFilePtr->beginGet(tmpTag, (unsigned *)&byteCount);
if (!stat) return false;
// If the tag is TIME, then this is a single file cache file
// Read the time chunk before the channel name chunk
//
if( tmpTag == MIffTag('T', 'I', 'M', 'E') )
{
// Read channel time
//
readStatus = readChannelTime();
if ( !readStatus ) return false;
// End Get
//
stat = iffFilePtr->endGet();
if (!stat) return false;
}
// Read Channel
//
MStatus channelStatus = MS::kSuccess;
do {
// Read channel name, size and data
//
readStatus = readChannel( channelStatus );
if( !readStatus ) return false;
} while ( channelStatus == MS::kSuccess );
// Store the ending "/MYCH" in the blockList
//
storeCacheBlock( "/MYCH" );
}
}
iffFilePtr->endReadGroup();
return readStatus;
}
bool geometryCacheFile::readChannelTime()
//
// Description : ( private method )
// Read and store the channel time from the TIME block.
//
{
MIffTag tmpTag;
unsigned int byteCount;
const int *tmpNum = (int*) iffFilePtr->getChunk( tmpTag, (unsigned *)&byteCount );
if( tmpNum &&
tmpTag == MIffTag('T', 'I', 'M', 'E') &&
byteCount == sizeof(int)) {
#if (!defined BYTE_ORDER) || (BYTE_ORDER == BIG_ENDIAN)
// Store the channel time in the blockList
//
storeCacheBlock( "TIME", *tmpNum );
#else
// Store the channel time in the blockList
//
storeCacheBlock( "TIME", FLswapword(*tmpNum) );
#endif
}
return true;
}
bool geometryCacheFile::readChannel( MStatus& channelStatus )
//
// Description : ( private method )
// Read and store the channel data.
//
{
readStatus = readChannelName( channelStatus );
if( !readStatus ) return false;
// If channelStatus is not MS::Success then this means that there is no
// more channel data to read. Return from function.
//
if( !channelStatus ) return true;
readStatus = readChannelData();
if( !readStatus ) return false;
return true;
}
bool geometryCacheFile::readChannelName( MStatus& channelStatus )
//
// Description : ( private method )
// Read and store the channel name from the CHNM block.
//
{
MStatus lStatus;
unsigned int byteCount;
MIffTag chnmTag;
channelStatus = iffFilePtr->beginGet( chnmTag, (unsigned *)&byteCount );
if( channelStatus == MS::kSuccess ) {
char *tmpName = (char*)alloca(sizeof(char)* (byteCount+1));
//pointers allocated by alloca are from the stack and automatically freed when
//the function exits. Do not free explicitly.
if( tmpName && chnmTag == MIffTag('C', 'H', 'N', 'M') ) {
iffFilePtr->get( tmpName, byteCount, &lStatus);
if( !lStatus ) return false;
MString channelName = tmpName;
// Store the channel name in the blockList
//
storeCacheBlock( "CHNM", channelName );
} else return false;
}
iffFilePtr->endGet();
return true;
}
bool geometryCacheFile::readChannelData()
//
// Description : ( private method )
// Read and store the channel size and geometry point data from the SIZE
// and DVCA or FVCA blocks.
//
{
MIffTag tmpTag;
unsigned int byteCount;
uint size;
// Read the channel size
//
const int *tmpNum = (int*) iffFilePtr->getChunk(tmpTag, (unsigned *)&byteCount);
if( tmpNum &&
tmpTag == MIffTag('S', 'I', 'Z', 'E') &&
byteCount == sizeof(int))
{
#if (!defined BYTE_ORDER) || (BYTE_ORDER == BIG_ENDIAN)
size = *tmpNum;
#else
size = FLswapword(*tmpNum);
#endif
// Store the channel size in the blockList
//
storeCacheBlock( "SIZE", size );
} else return false;
// Read the channel data
//
if( size ) {
const void *tmpVec = (double*) iffFilePtr->getChunk(tmpTag, (unsigned *)&byteCount);
if( tmpVec &&
tmpTag == MIffTag('D', 'V', 'C', 'A') &&
size * sizeof(double)*3 == byteCount )
{
double *tmpVecDbl = (double*) tmpVec;
double *dataArray = new double[size*3];
#if (!defined BYTE_ORDER) || (BYTE_ORDER == BIG_ENDIAN)
memcpy(dataArray, tmpVec, byteCount);
#else
for(unsigned int i = 0; i < size*3; i++) {
FLswapdouble(tmpVecDbl[i], &(dataArray[i]));
}
#endif
// Store the channel geometry points in the blockList
//
storeCacheBlock( "DVCA", dataArray, size );
delete [] dataArray;
} else if( tmpVec &&
tmpTag == MIffTag('F', 'V', 'C', 'A') &&
size * sizeof(float)*3 == byteCount ) {
float *tmpVecFlt = (float*) tmpVec;
float *dataArray = new float[size*3];
#if (!defined BYTE_ORDER) || (BYTE_ORDER == BIG_ENDIAN)
memcpy(dataArray, tmpVec, byteCount);
#else
for(unsigned int i = 0; i < size*3; i++) {
FLswapfloat(tmpVecFlt[i], &(dataArray[i]));
}
#endif
// Store the channel geometry points in the blockList
//
storeCacheBlock( "FVCA", dataArray, size );
delete [] dataArray;
} else {
return false;
}
}
return true;
}
void geometryCacheFile::storeCacheBlock( const MString& tag )
//
// Description : ( private method )
// Stores the specified data into the blockList.
//
{
blockList.push_back( new geometryCacheBlockBase( tag ) );
}
void geometryCacheFile::storeCacheBlock( const MString& tag, const int& value )
//
// Description : ( private method )
// Stores the specified data into the blockList.
//
{
blockList.push_back( new geometryCacheBlockIntData( tag, value ) );
}
void geometryCacheFile::storeCacheBlock( const MString& tag, const MString& value )
//
// Description : ( private method )
// Stores the specified data into the blockList.
//
{
blockList.push_back( new geometryCacheBlockStringData( tag, value ) );
}
void geometryCacheFile::storeCacheBlock( const MString& tag, const double* value, const uint& size )
//
// Description : ( private method )
// Stores the specified data into the blockList.
//
{
blockList.push_back( new geometryCacheBlockDVAData( tag, value, size ) );
}
void geometryCacheFile::storeCacheBlock( const MString& tag, const float* value, const uint& size )
//
// Description : ( private method )
// Stores the specified data into the blockList.
//
{
blockList.push_back( new geometryCacheBlockFVAData( tag, value, size ) );
}