#include <string>
#include <stack>
#include <fstream>
#include <sstream>
#include <assert.h>
#include <stdlib.h>
#include <maya/MFnPlugin.h>
#include <maya/MGlobal.h>
#include <maya/MString.h>
#include <maya/MPxCacheFormat.h>
using namespace std;
class XmlCacheFormat : public MPxCacheFormat
{
public:
XmlCacheFormat();
~XmlCacheFormat();
static void* creator();
static void setPluginName(const MString& name);
static MString translatorName();
MStatus isValid();
MStatus open( const MString& fileName, FileAccessMode mode);
void close();
MStatus readHeader();
MStatus writeHeader(const MString& version, MTime& startTime, MTime& endTime);
void beginWriteChunk();
void endWriteChunk();
MStatus beginReadChunk();
void endReadChunk();
MStatus writeTime(MTime& time);
MStatus readTime(MTime& time);
MStatus findTime(MTime& time, MTime& foundTime);
MStatus readNextTime(MTime& foundTime);
unsigned readArraySize();
MStatus writeDoubleArray(const MDoubleArray&);
MStatus readDoubleArray(MDoubleArray&, unsigned size);
MStatus writeFloatArray(const MFloatArray&);
MStatus readFloatArray(MFloatArray&, unsigned size);
MStatus writeDoubleVectorArray(const MVectorArray& array);
MStatus readDoubleVectorArray(MVectorArray&, unsigned arraySize);
MStatus writeFloatVectorArray(const MFloatVectorArray& array);
MStatus readFloatVectorArray(MFloatVectorArray& array, unsigned arraySize);
MStatus writeChannelName(const MString & name);
MStatus findChannelName(const MString & name);
MStatus readChannelName(MString& name);
MStatus writeInt32(int);
int readInt32();
MStatus rewind();
MString extension();
protected:
static MString comment(const MString& text);
static MString quote(const MString& text);
static MString fExtension;
static MString fCacheFormatName;
private:
void startXmlBlock( string& t );
void endXmlBlock();
void writeXmlTagValue( string& tag, string value );
void writeXmlTagValue( string& tag, int value );
bool readXmlTagValue(string tag, MStringArray& value);
bool readXmlTagValueInChunk(string tag, MStringArray& values);
void readXmlTag(string& value);
bool findXmlStartTag(string& tag);
bool findXmlStartTagInChunk(string& tag );
bool findXmlEndTag(string& tag);
void writeXmlValue( string& value );
void writeXmlValue( double value );
void writeXmlValue( float value );
void writeXmlValue( int value );
MString fFileName;
fstream fFile;
stack<string> fXmlStack;
FileAccessMode fMode;
};
MString XmlCacheFormat::fExtension = "mc";
MString XmlCacheFormat::fCacheFormatName = "xml";
inline MString XmlCacheFormat::translatorName()
{ return fCacheFormatName; }
void* XmlCacheFormat::creator()
{
return new XmlCacheFormat();
}
string XMLSTARTTAG( string x)
{
return ( "<" + x + ">" );
}
string XMLENDTAG( string x)
{
return ( "<\\" + x + ">" );
}
string cacheTag("awGeoCache");
string startTimeTag("startTime");
string endTimeTag("endTime");
string versionTag("version");
string timeTag("time");
string sizeTag("size");
string intTag("integer32");
string doubleArrayTag("doubleArray");
string floatArrayTag("floatArray");
string doubleVectorArrayTag("doubleVectorArray");
string floatVectorArrayTag("floatVectorArray");
string channelTag("channel");
string chunkTag("chunk");
XmlCacheFormat::XmlCacheFormat()
{
}
XmlCacheFormat::~XmlCacheFormat()
{
close();
}
MStatus
XmlCacheFormat::open(const MString& fileName, FileAccessMode mode )
{
bool rtn = true;
assert((fileName.length() > 0));
fFileName = fileName;
if( mode == kWrite ) {
fFile.open(fFileName.asChar(), ios::out);
}
else if (mode == kReadWrite) {
fFile.open(fFileName.asChar(), ios::app);
} else {
fFile.open(fFileName.asChar(), ios::in);
}
if (!fFile.is_open()) {
rtn = false;
} else {
if (mode == kRead) {
rtn = readHeader();
}
}
return rtn ? MS::kSuccess : MS::kFailure ;
}
MStatus
XmlCacheFormat::isValid()
{
bool rtn = fFile.is_open();
return rtn ? MS::kSuccess : MS::kFailure ;
}
MStatus
XmlCacheFormat::readHeader()
{
bool rtn = false;
if (kWrite != fMode) {
if( fFile.is_open() ) {
string tag;
readXmlTag( tag );
if( tag == XMLSTARTTAG(cacheTag) )
{
MStringArray value;
readXmlTagValue( versionTag, value );
readXmlTagValue( startTimeTag, value );
readXmlTagValue( endTimeTag, value );
readXmlTag( tag );
if( tag != XMLENDTAG(cacheTag) )
{
}
rtn = true;
}
}
}
return rtn ? MS::kSuccess : MS::kFailure ;
}
MStatus
XmlCacheFormat::rewind()
{
if( fFile.is_open() )
{
close();
if(!open(fFileName, kRead ))
{
return MS::kFailure;
}
return MS::kSuccess;
}
else
{
return MS::kFailure;
}
}
void XmlCacheFormat::close()
{
if( fFile.is_open() ) {
fFile.close();
}
}
MStatus XmlCacheFormat::writeInt32(int i)
{
writeXmlTagValue(intTag, i);
return MS::kSuccess;
}
int
XmlCacheFormat::readInt32()
{
MStringArray value;
readXmlTagValue(intTag, value);
return atoi( value[0].asChar() );
}
MStatus
XmlCacheFormat::writeHeader(const MString& version, MTime& startTime, MTime& endTime)
{
stringstream oss;
startXmlBlock(cacheTag);
string v(version.asChar());
writeXmlTagValue(versionTag, v);
oss << startTime;
writeXmlTagValue(startTimeTag, oss.str() );
oss.str("");
oss.clear();
oss << endTime;
writeXmlTagValue(endTimeTag, oss.str() );
endXmlBlock();
return MS::kSuccess;
}
MStatus
XmlCacheFormat::readTime(MTime& time)
{
MStringArray timeValue;
readXmlTagValue(timeTag, timeValue);
time.setValue( strtod( timeValue[0].asChar(), NULL ) );
return MS::kSuccess;
}
MStatus
XmlCacheFormat::writeTime(MTime& time)
{
stringstream oss;
oss << time;
writeXmlTagValue(timeTag, oss.str() );
return MS::kSuccess;
}
MStatus
XmlCacheFormat::findChannelName(const MString& name)
{
MStringArray value;
while (readXmlTagValueInChunk(channelTag, value))
{
if( value.length() == 1 && value[0] == name )
{
return MS::kSuccess;
}
}
return MS::kFailure;
}
MStatus
XmlCacheFormat::readChannelName(MString& name)
{
MStringArray value;
readXmlTagValueInChunk(channelTag, value);
name = value[0];
return name.length() == 0 ? MS::kFailure : MS::kSuccess;
}
MStatus
XmlCacheFormat::readNextTime(MTime& foundTime)
{
MTime readAwTime(0.0, MTime::k6000FPS);
bool ret = readTime(readAwTime);
foundTime = readAwTime;
return ret ? MS::kSuccess : MS::kFailure ;
}
MStatus
XmlCacheFormat::findTime(MTime& time, MTime& foundTime)
{
MTime timeTolerance(0.0, MTime::k6000FPS);
MTime seekTime(time);
MTime preTime( seekTime - timeTolerance );
MTime postTime( seekTime + timeTolerance );
bool fileRewound = false;
while (1) {
bool timeTagFound = beginReadChunk();
if ( ! timeTagFound && !fileRewound ) {
if(!rewind())
{
return MS::kFailure;
}
fileRewound = true;
timeTagFound = beginReadChunk();
}
if ( timeTagFound )
{
MTime rTime(0.0, MTime::k6000FPS);
readTime(rTime);
if(rTime >= preTime && rTime <= postTime) {
foundTime = rTime;
return MS::kSuccess;
}
if(rTime > postTime )
{
if (!fileRewound)
{
if(!rewind())
{
return MS::kFailure;
}
fileRewound = true;
}
else
{
return MS::kFailure;
}
}
else
{
fileRewound = true;
}
endReadChunk();
}
else
{
break;
}
}
return MS::kFailure;
}
MStatus
XmlCacheFormat::writeChannelName(const MString& name)
{
string chan = name.asChar();
writeXmlTagValue( channelTag, chan );
return MS::kSuccess;
}
void XmlCacheFormat::beginWriteChunk()
{
startXmlBlock(chunkTag);
}
void XmlCacheFormat::endWriteChunk()
{
endXmlBlock();
}
MStatus XmlCacheFormat::beginReadChunk()
{
return findXmlStartTag(chunkTag) ? MS::kSuccess : MS::kFailure;
}
void XmlCacheFormat::endReadChunk()
{
findXmlEndTag(chunkTag);
}
MStatus
XmlCacheFormat::writeDoubleArray(const MDoubleArray& array)
{
int size = array.length();
assert(size != 0);
writeXmlTagValue(sizeTag,size);
startXmlBlock( doubleArrayTag );
for(int i = 0; i < size; i++) {
writeXmlValue(array[i]);
}
endXmlBlock();
return MS::kSuccess;
}
MStatus
XmlCacheFormat::writeFloatArray(const MFloatArray& array)
{
int size = array.length();
assert(size != 0);
writeXmlTagValue(sizeTag,size);
startXmlBlock( floatArrayTag );
for(int i = 0; i < size; i++) {
writeXmlValue(array[i]);
}
endXmlBlock();
return MS::kSuccess;
}
MStatus
XmlCacheFormat::writeDoubleVectorArray(const MVectorArray& array)
{
int size = array.length();
assert(size != 0);
writeXmlTagValue(sizeTag,size);
startXmlBlock( doubleVectorArrayTag );
for(int i = 0; i < size; i++) {
writeXmlValue(array[i][0]);
writeXmlValue(array[i][1]);
writeXmlValue(array[i][2]);
string endl("\n");
writeXmlValue(endl);
}
endXmlBlock();
return MS::kSuccess;
}
MStatus
XmlCacheFormat::writeFloatVectorArray(const MFloatVectorArray& array)
{
int size = array.length();
assert(size != 0);
writeXmlTagValue(sizeTag,size);
startXmlBlock( floatVectorArrayTag );
for(int i = 0; i < size; i++) {
writeXmlValue(array[i][0]);
writeXmlValue(array[i][1]);
writeXmlValue(array[i][2]);
string endl("\n");
writeXmlValue(endl);
}
endXmlBlock();
return MS::kSuccess;
}
unsigned
XmlCacheFormat::readArraySize()
{
MStringArray value;
if (readXmlTagValue(sizeTag, value)) {
unsigned readSize = (unsigned) atoi( value[0].asChar() );
return readSize;
}
return 0;
}
MStatus
XmlCacheFormat::readDoubleArray(MDoubleArray& array, unsigned arraySize)
{
MStringArray value;
readXmlTagValue(doubleArrayTag, value);
assert( value.length() == arraySize );
array.setLength( arraySize );
for ( unsigned int i = 0; i < value.length(); i++ )
{
array[i] = strtod( value[i].asChar(), NULL );
}
return MS::kSuccess;
}
MStatus
XmlCacheFormat::readFloatArray(MFloatArray& array, unsigned arraySize)
{
MStringArray value;
readXmlTagValue(floatArrayTag, value);
assert( value.length() == arraySize );
array.setLength( arraySize );
for ( unsigned int i = 0; i < value.length(); i++ )
{
array[i] = (float)strtod( value[i].asChar(), NULL );
}
return MS::kSuccess;
}
MStatus
XmlCacheFormat::readDoubleVectorArray(MVectorArray& array, unsigned arraySize)
{
MStringArray value;
if( !readXmlTagValue(doubleVectorArrayTag, value) )
{
return MS::kFailure;
}
assert( value.length() == arraySize * 3 );
array.setLength( arraySize );
for (unsigned i = 0; i < arraySize; i++ )
{
double v[3];
v[0] = strtod( value[i*3].asChar(), NULL );
v[1] = strtod( value[i*3+1].asChar(), NULL );
v[2] = strtod( value[i*3+2].asChar(), NULL );
array.set( v, i );
}
return MS::kSuccess;
}
MStatus
XmlCacheFormat::readFloatVectorArray(MFloatVectorArray& array, unsigned arraySize)
{
MStringArray value;
readXmlTagValue(floatVectorArrayTag, value);
assert( value.length() == arraySize * 3 );
array.clear();
array.setLength( arraySize );
for (unsigned i = 0; i < arraySize; i++ )
{
float v[3];
v[0] = (float)strtod( value[i*3].asChar(), NULL );
v[1] = (float)strtod( value[i*3+1].asChar(), NULL );
v[2] = (float)strtod( value[i*3+2].asChar(), NULL );
array.set(v,i);
}
return MS::kSuccess;
}
MString
XmlCacheFormat::extension()
{
return fExtension;
}
void XmlCacheFormat::startXmlBlock( string& t )
{
fXmlStack.push(t);
fFile << "<" << t << ">\n";
}
void XmlCacheFormat::endXmlBlock()
{
string block = fXmlStack.top();
fFile << "<\\" << block << ">\n";
fXmlStack.pop();
}
void XmlCacheFormat::writeXmlTagValue( string& tag, string value )
{
for (unsigned int i = 0; i < fXmlStack.size(); i++ )
fFile << "\t";
fFile << "<" << tag << "> ";
fFile << value;
fFile << " <\\" << tag << ">\n";
}
void XmlCacheFormat::writeXmlTagValue( string& tag, int value )
{
for (unsigned int i = 0; i < fXmlStack.size(); i++ )
fFile << "\t";
fFile << "<" << tag << "> ";
ostringstream oss;
oss << value;
fFile << oss.str();
fFile << " <\\" << tag << ">\n";
}
bool XmlCacheFormat::readXmlTagValue(string tag, MStringArray& values)
{
string endTag = XMLENDTAG(tag);
bool status = true;
values.clear();
if( findXmlStartTag(tag) )
{
string token;
fFile >> token;
while ( !fFile.eof() && token != endTag )
{
values.append( token.data() );
fFile >> token;
}
}
else
{
status = false;
}
return status;
}
bool XmlCacheFormat::readXmlTagValueInChunk(string tag, MStringArray& values)
{
string endTag = XMLENDTAG(tag);
bool status = true;
values.clear();
if( findXmlStartTagInChunk(tag) )
{
string token;
fFile >> token;
while ( !fFile.eof() && token != endTag )
{
values.append( token.data() );
fFile >> token;
}
}
else
{
status = false;
}
return status;
}
void XmlCacheFormat::readXmlTag(string& value)
{
value.clear();
fFile >> value;
}
bool XmlCacheFormat::findXmlStartTag(string& tag )
{
string tagRead;
string tagExpected = XMLSTARTTAG(tag);
fFile >> tagRead;
while(!fFile.eof() && tagRead != tagExpected)
{
fFile >> tagRead;
}
if( tagRead != tagExpected )
{
}
return ( tagRead == tagExpected );
}
bool XmlCacheFormat::findXmlStartTagInChunk(string& tag )
{
string tagRead;
string tagExpected = XMLSTARTTAG(tag);
string tagEndChunk("<\\"+chunkTag+">");
fFile >> tagRead;
while((!fFile.eof()) && (tagRead != tagExpected) && (tagRead != tagEndChunk))
{
fFile >> tagRead;
}
if( (tagRead != tagExpected) && (tagRead != tagEndChunk) )
{
}
return ( tagRead == tagExpected );
}
bool XmlCacheFormat::findXmlEndTag(string& tag)
{
string tagRead;
string tagExpected("<\\"+tag+">");
fFile >> tagRead;
if( tagRead != tagExpected )
{
}
return ( tagRead == tagExpected );
}
void XmlCacheFormat::writeXmlValue( string& value )
{
fFile << value << " ";
}
void XmlCacheFormat::writeXmlValue( double value )
{
fFile << value << " ";
}
void XmlCacheFormat::writeXmlValue( float value )
{
fFile << value << " ";
}
void XmlCacheFormat::writeXmlValue( int value )
{
fFile << value << " ";
}
MStatus initializePlugin(MObject obj)
{
MFnPlugin plugin(obj, PLUGIN_COMPANY, "1.0", "Any");
plugin.registerCacheFormat(
XmlCacheFormat::translatorName(),
XmlCacheFormat::creator
);
return MS::kSuccess;
}
MStatus uninitializePlugin(MObject obj)
{
MFnPlugin plugin( obj );
plugin.deregisterCacheFormat(XmlCacheFormat::translatorName());
return MS::kSuccess;
}