// Shave and a Haircut // (c) 2019 Epic Games // US Patent 6720962 #include #include #include "shaveSDK.h" #include "shaveBlindData.h" #include "shaveDebug.h" #include "shaveUtil.h" MTypeId blindShaveData::dataTypeId(0x83001); const MString blindShaveData::dataTypeName("blindShaveData"); /* * Proxy data class implementation */ void* blindShaveData::creator() { return new blindShaveData; } blindShaveData::blindShaveData() { init_MEMFILE(&m, 0); } blindShaveData::~blindShaveData() { free_MEMFILE(&m); } void blindShaveData::clear() { free_MEMFILE(&m); } void blindShaveData::copy(const MPxData& other) // // Deescription: // Perform a copy. // { if (other.typeId() == blindShaveData::dataTypeId) { const blindShaveData& otherData = (const blindShaveData&)other; copy_MEMFILE(&m, (MEMFILE*)&otherData.m); } return; } void blindShaveData::resize(int newSize) { if (newSize < 0) newSize = 0; if (m.size != newSize) { clear(); if (newSize > 0) { m.data = (char*)malloc(newSize); m.size = newSize; } } } void blindShaveData::setValue(const void* newData, int newDataLen) { resize(newDataLen); memcpy(m.data, newData, m.size); } MTypeId blindShaveData::typeId() const { return blindShaveData::dataTypeId; } MString blindShaveData::name() const { return blindShaveData::dataTypeName; } MStatus blindShaveData::readASCII( const MArgList& args, unsigned& lastParsedElement ) { MStatus status; MString s; int datasize; int argLength = args.length(); if (argLength > 0) { datasize = args.asInt(lastParsedElement++, &status); resize(datasize); // // Prior to shaveNode version 11, we stored each byte as a separate // value. From version 11 onward we stored the data as 4-byte // words, with any leftover bytes stored individually at the end. // // So we need to compare the number of remaining arguments against // the overall datasize to see which format this is. // int i; if (argLength - (int)lastParsedElement >= datasize) { for(i = 0; i < datasize; i++) m.data[i] = (char)args.asInt(lastParsedElement++, &status); } else { int intval; #if defined(IRIX) || defined(__ppc__) char* p = (char*)&intval; #endif int stop = datasize - 3; for (i = 0; i < stop; i += 4) { intval = args.asInt(lastParsedElement++, &status); #if defined(IRIX) || defined(__ppc__) // // We save values to file in LSB-first order. IRIX and // PowerPC use MSB_first ordering, so we need to swap the // byte order. // m.data[i+3] = p[0]; m.data[i+2] = p[1]; m.data[i+1] = p[2]; m.data[i] = p[3]; #else *(int *)&m.data[i] = intval; #endif } // // Grab any leftover bytes one at a time. // for (; i < datasize; i++) m.data[i] = (char)args.asInt(lastParsedElement++, &status); } return MS::kSuccess; } return MS::kFailure; } MStatus blindShaveData::writeASCII(ostream& out) { int i; int intval; #if defined(IRIX) || defined(__ppc__) char* p = (char*)&intval; #endif int stop = 0; out << m.size; if (m.size > 3) stop = m.size - 3; // // We write the data out as 4-byte ints because that's a bit faster and // makes the file a bit smaller. // for (i = 0; i < stop; i += 4) { #if defined(IRIX) || defined(__ppc__) // // We save values to file in LSB-first order. IRIX and PowerPC use // MSB-first ordering, so we need to swap the byte order. // p[0] = m.data[i+3]; p[1] = m.data[i+2]; p[2] = m.data[i+1]; p[3] = m.data[i]; #else intval = *(int*)&m.data[i]; #endif out << ' ' << intval; // // Start a new line after every 10 longwords, just to make viewing // and editing the .ma files a bit easier. // if (i % 40 == 36) out << endl; } // // If the number of bytes was not divisible by 4, we'll have a few left // over, so just write them out one byte at a time. // for (; i < m.size; i++) out << ' ' << (int)m.data[i]; return out.fail() ? MS::kFailure : MS::kSuccess; } #ifdef JOETEST MStatus blindShaveData::writeASCII(ostream& out) { char intdata[10000]; int position=0; int start,stop; out << m.size; out << " "; // for(int i = 0; i < m.size; i++) while (positionm.size) stop=m.size; for(int i = start; i < stop; i++) { sprintf(intdata, "%d ",m.data[i]); ii++; } out << intdata; position+=ii; intdata[0]=0; } return out.fail() ? MS::kFailure : MS::kSuccess; } #endif // // NOTE: You might have noticed that we read and write the MEMFILE's // 'pos' member when doing binary I/O but not when doing ASCII // I/O. Clearly Shave manages to get along fine without it, but // this was how I inherited the code, and to change it now would // break a lot of existing scene files, so we let the dichotomy // stand. // MStatus blindShaveData::readBinary(istream& in, unsigned length) { ENTER(); int expectedSize = length - 2 * sizeof(int); int storedSize; bool LSBfirst = false; in.read ((char*) &storedSize, sizeof(int)); #if defined(IRIX) || defined(__ppc__) storedSize = shaveUtil::reorderInt(storedSize); #endif if (storedSize != expectedSize) { // // Prior to version 8 of the shaveNode, little-endian systems such // as IRIX and OSX incorrectly wrote their sizes to the scene file // in little-endian form, which made the files unreadable on other // platforms. // // From version 8 onward that was corrected so that little-endian // systems reorder the bytes before writing them to the file. // // However, it is possible that the current scene file is an old // one from a little-endian system, in which case the sizes will // still be in little-endian format. // // So let's flip the ordering and see if we get a match. // storedSize = shaveUtil::reorderInt(storedSize); if (storedSize != expectedSize) { // // We must have a corrupt file. Just return without an error // code because the license check later on will fail on the // empty blind data and display an appropriate message. // RETURN(MS::kSuccess); } LSBfirst = true; } resize(storedSize); in.read((char*) &(m.pos), sizeof(int)); #if defined(IRIX) || defined(__ppc__) m.pos = shaveUtil::reorderInt(m.pos); #endif if (LSBfirst) m.pos = shaveUtil::reorderInt(m.pos); #ifdef DEBUG char msg[200]; sprintf(msg, "reading %d bytes of blind data", storedSize); MGlobal::displayInfo(msg); #endif in.read((char*) m.data, storedSize); RETURN(in.fail() ? MS::kFailure : MS::kSuccess); } MStatus blindShaveData::writeBinary(ostream& out) { ENTER(); #if defined(IRIX) || defined(__ppc__) int pos = shaveUtil::reorderInt(m.pos); int size = shaveUtil::reorderInt(m.size); #else int pos = m.pos; int size = m.size; #endif out.write ((char*) &(size), sizeof(int)); out.write ((char*) &(pos), sizeof(int)); out.write ((char*) m.data, m.size); #ifdef DEBUG char msg[200]; sprintf(msg, "wrote %d bytes of blind data", m.size); MGlobal::displayInfo(msg); #endif RETURN(out.fail() ? MS::kFailure : MS::kSuccess); }