⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qvnode.cpp

📁 Windows上的MUD客户端程序
💻 CPP
字号:
#include <ctype.h>
#include <QvDB.h>
#include <QvInput.h>
#include <QvDebugError.h>
#include <QvReadError.h>
#include <QvField.h>
#include <QvFieldData.h>
#include <QvNodes.h>
#include <QvUnknownNode.h>

// The global name dictionary
QvDict		*QvNode::nameDict = NULL;

// Syntax for writing instances to files
#define OPEN_BRACE		'{'
#define CLOSE_BRACE		'}'
#define DEFINITION_KEYWORD	"DEF"
#define REFERENCE_KEYWORD	"USE"
#define NULL_KEYWORD		"NULL"
#define ROUTE_NAME			"ROUTE"

void
QvNode::init()
{
    if (nameDict == NULL)
	nameDict = new QvDict;
}

// Added by jwd chaco in quest of plugging leaks
void
QvNode::term()
{
	delete nameDict;
	nameDict = NULL;
}

QvNode::QvNode() : m_iUsage(1), m_pRenderData(0) 
{
    objName = new QvName("");
}

QvNode::~QvNode()
{
    if (! !(*objName))
	removeName(this, objName->getString());
    delete objName;
	delete m_pRenderData;
	m_pRenderData = 0;
}

const QvName &
QvNode::getName() const
{
    return *objName;
}

void
QvNode::setName(const QvName &newName)
{
    if (! !(*objName)) {
	removeName(this, objName->getString());
    }
    delete objName;

    const char *str = newName.getString();
    QvBool isBad = 0;

    if (newName.getLength() > 0 &&
	!QvName::isNodeNameStartChar(str[0])) isBad = TRUE;

    int i;
    for (i = 1; i < newName.getLength() && !isBad; i++) {
	isBad = !QvName::isNodeNameChar(str[i]);
    }

    if (isBad) {
	QvString goodString;

	if (!QvName::isNodeNameStartChar(str[0])) {
	    goodString += "_";
	}
	for (i = 0; i < newName.getLength(); i++) {
	    char temp[2];
	    temp[0] = str[i]; temp[1] = '\0';
	    if (!QvName::isNodeNameChar(str[i]))
		goodString += "_";
	    else
		goodString += temp;
	}
#ifdef DEBUG
	QvDebugError::post("QvNode::setName", "Bad characters in"
			   " name '%s'.  Replacing with name '%s'",
			   str, goodString.getString());
#endif       
	objName = new QvName(goodString);
    }
    else {
	objName = new QvName(newName);
    }
    if (! !(*objName)) {
	addName(this, objName->getString());
    }
}

void
QvNode::addName(QvNode *b, const char *name)
{
    QvPList *list;
    void *t;
    if (!nameDict->find((u_long)name, t)) {
	list = new QvPList;
	nameDict->enter((u_long)name, list, TRUE);
    }
    else {
	list = (QvPList *)t;
    }

    list->append(b);
}

void
QvNode::removeName(QvNode *b, const char *name)
{
    QvPList	*list;
    QvBool	found;
    void	*t;
    int		i;

    found = nameDict->find((u_long) name, t);

    if (found) {
	list = (QvPList *) t;
	i    = list->find(b);

	if (i < 0)
	    found = FALSE;

	else
	    list->remove(i);
    }

    if (! found)
	QvDebugError::post("QvNode::removeName",
			   "Name \"%s\" (node %x) is not in dictionary",
			   name, b);
}

QvBool
QvNode::read(QvInput *in, QvNode *&node)
{
    QvBool	ret;
    QvName	name;

    if (! in->read(name, TRUE)) {
	node = NULL;
	ret = in->headerOk;
    }

    else if (! name || name == NULL_KEYWORD) {
	node = NULL;
	ret = TRUE;
    }

    else if (name == REFERENCE_KEYWORD) {
	node = readReference(in);
	ret = (node != NULL);
    }

    else
	ret = readNode(in, name, node);

    return ret;
}

QvBool
QvNode::readInstance(QvInput *in)
{
    QvName	typeString;
    QvFieldData	*fieldData = getFieldData();

    if (in->read(typeString, TRUE)) {
	if (typeString == "fields") {
	    if (! fieldData->readFieldTypes(in, this)) {
		QvReadError::post(in, "Bad field specifications for node");
		return FALSE;
	    }
	}
	else
	    in->putBack(typeString.getString());
    }

    if (! fieldData->read(in, this))
        return FALSE;

    return TRUE;
}

QvNode *
QvNode::readReference(QvInput *in)
{
    QvName	refName;
    QvNode	*node;

    if (! in->read(refName, FALSE)) {
	QvReadError::post(in, "Premature end of file after "
			  REFERENCE_KEYWORD);
	node = NULL;
    }

    else if ((node = in->findReference(refName)) == NULL)
	QvReadError::post(in, "Unknown reference \"%s\"",
			  refName.getString());
	if (node) node->Use();	// jwd to add usage count
    return node;
}

QvBool
QvNode::readNode(QvInput *in, QvName &className, QvNode *&node)
{
    QvBool	gotChar;
    QvName	refName;
    char	c;
    QvBool	ret = TRUE, flush = FALSE;

    node = NULL;

    if (className == DEFINITION_KEYWORD) {
		if (! in->read(refName, FALSE) || ! in->read(className, TRUE)) {
		    QvReadError::post(in, "Premature end of file after "
				      DEFINITION_KEYWORD);
		    ret = FALSE;
		}

		if (! refName) {
		    QvReadError::post(in, "No name given after ", DEFINITION_KEYWORD);
		    ret = FALSE;
		}

		if (! className) {
		    QvReadError::post(in, "Invalid definition of %s",
				      refName.getString());
		    ret = FALSE;
		}
    }

    if (ret) {
		if(className == ROUTE_NAME)
		{
			ret = QvRoute::readRoute(in, node);
		}
		else
		{

			if (! (gotChar = in->read(c)) || c != OPEN_BRACE) {
			    if (gotChar)
				QvReadError::post(in, "Expected '%c'; got '%c'",
						  OPEN_BRACE, c);
			    else
				QvReadError::post(in, "Expected '%c'; got EOF", OPEN_BRACE);
			    ret = FALSE;
			}

			else {
			    ret = readNodeInstance(in, className, refName, node);

			    if (! ret)
				flush = TRUE;

			    else if (! (gotChar = in->read(c)) || c != CLOSE_BRACE) {
				if (gotChar)
				    QvReadError::post(in, "Expected '%c'; got '%c'",
						      CLOSE_BRACE, c);
				else
				    QvReadError::post(in, "Expected '%c'; got EOF",
						      CLOSE_BRACE);
				ret = FALSE;
			    }
			}
		}
    }

    if (! ret && flush)
	flushInput(in);

    return ret;
}

QvBool
QvNode::readNodeInstance(QvInput *in, const QvName &className,
			 const QvName &refName, QvNode *&node)
{
    node = createInstance(in, className);
    if (node == NULL)
	return FALSE;

    if (! (! refName))
	in->addReference(refName, node);

    return node->readInstance(in);
}

QvNode *
QvNode::createInstance(QvInput *in, const QvName &className)
{
    QvNode		*instance;
    QvString            unknownString;

    instance = createInstanceFromName(className);

    if (instance == NULL) {

		// Changed to allow empty unknown nodes - jwd for Chaco
		if (! in->read(unknownString) )
		{  
		    QvReadError::post(in, "Unknown class \"%s\". Parsing failed.",
				      className.getString());
	    	return NULL;
		}
		else if (unknownString != "fields" && unknownString != "}") 
		{
									// Try to recover, skip to matching brace

			if(skipToBrace(in))
			{
				#if 0
		    	QvReadError::postWarning(in, "Unknown class \"%s\". Node ignored.",
				      className.getString());
				#endif
				// Recovered!
			    QvUnknownNode *tmpNode = new QvUnknownNode;
			    tmpNode->setClassName(className.getString());
			    instance = tmpNode;
			}
			else
			{
		    	QvReadError::post(in, "Unknown class \"%s\". Parsing failed.",
				      className.getString());
		    	return NULL;
			}
		}

		else if (unknownString == "fields")
		{
			// Rather than trying to read it, just skip it and be done
			// with it - this prevents leaks of fieldNames - jwd 5/13/96
			if(skipToBrace(in))
			{
			    QvUnknownNode *tmpNode = new QvUnknownNode;
			    tmpNode->setClassName(className.getString());
			    instance = tmpNode;
			}
			else
			{
		    	QvReadError::post(in, "Unknown class \"%s\". Parsing failed.",
				      className.getString());
		    	return NULL;
			}
		}
		else if ( unknownString == "}")
		{
		    QvUnknownNode *tmpNode = new QvUnknownNode;
		    tmpNode->setClassName(className.getString());
		    instance = tmpNode;
		    in->putBack(unknownString.getString());
		}
    }

    return instance;
}

QvNode *
QvNode::createInstanceFromName(const QvName &className)
{
#define TRY_CLASS(name, class)						      \
    else if (className == name)						      \
	inst = new class

    QvNode *inst = NULL;

    if (0) ;			// So "else" works in first TRY_CLASS
    TRY_CLASS("AsciiText",			QvAsciiText);
    TRY_CLASS("Background",			QvBackground);
    TRY_CLASS("BaseColor",			QvBaseColor);
    TRY_CLASS("Cone",			QvCone);
    TRY_CLASS("Coordinate3",		QvCoordinate3);
    TRY_CLASS("Cube",			QvCube);
    TRY_CLASS("Cylinder",		QvCylinder);
    TRY_CLASS("DirectionalLight",	QvDirectionalLight);
    TRY_CLASS("FontStyle",	QvFontStyle);
    TRY_CLASS("Group",			QvGroup);
    TRY_CLASS("IndexedFaceSet",		QvIndexedFaceSet);
    TRY_CLASS("IndexedLineSet",		QvIndexedLineSet);
    TRY_CLASS("Info",			QvInfo);
    TRY_CLASS("LOD",		QvLOD);
    TRY_CLASS("Material",		QvMaterial);
    TRY_CLASS("MaterialBinding",	QvMaterialBinding);
    TRY_CLASS("MatrixTransform",	QvMatrixTransform);
    TRY_CLASS("Normal",			QvNormal);
    TRY_CLASS("NormalBinding",		QvNormalBinding);
    TRY_CLASS("OrthographicCamera",	QvOrthographicCamera);
    TRY_CLASS("PerspectiveCamera",	QvPerspectiveCamera);
    TRY_CLASS("PointLight",		QvPointLight);
    TRY_CLASS("PointSet",		QvPointSet);
    TRY_CLASS("Rotation",		QvRotation);
    TRY_CLASS("Scale",			QvScale);
    TRY_CLASS("Separator",		QvSeparator);
    TRY_CLASS("ShapeHints",		QvShapeHints);
    TRY_CLASS("Sphere",			QvSphere);
    TRY_CLASS("Spin",			QvSpin);
    TRY_CLASS("SpinGroup",			QvSpinGroup);
    TRY_CLASS("SpotLight",		QvSpotLight);
    TRY_CLASS("Switch",			QvSwitch);
    TRY_CLASS("Texture2",		QvTexture2);
    TRY_CLASS("Texture2Transform",	QvTexture2Transform);
    TRY_CLASS("TextureCoordinate2",	QvTextureCoordinate2);
    TRY_CLASS("Transform",		QvTransform);
    TRY_CLASS("TransformSeparator",	QvTransformSeparator);
    TRY_CLASS("Translation",		QvTranslation);
    TRY_CLASS("WWWAnchor",		QvWWWAnchor);
    TRY_CLASS("WWWInline",		QvWWWInline);
    
    TRY_CLASS("TimeSensor",		QvTimeSensor);
    TRY_CLASS("OrientationInterpolator",		QvOrientationInterpolator);
    TRY_CLASS("PositionInterpolator",		QvPositionInterpolator);
    TRY_CLASS("NavigationInfo",			QvNavigationInfo);
    
    return inst;

#undef TRY_CLASS
}

void
QvNode::flushInput(QvInput *in)
{
    int		nestLevel = 1;
    char	c;

    while (nestLevel > 0 && in->get(c)) {

	if (c == CLOSE_BRACE)
	    nestLevel--;

	else if (c == OPEN_BRACE)
	    nestLevel++;
    }
}

// Added by jwd to skip bad node defns
QvBool
QvNode::skipToBrace(QvInput *in)
{
    QvString            unknownString;
	int count = 1;


	while (count > 0 && in->read(unknownString) )
	{
		if (unknownString == "}")  count --;
		if (unknownString == "{")  count ++;
	}
	if(count > 0) return FALSE;

    in->putBack(unknownString.getString());
    return TRUE;
}


#undef OPEN_BRACE
#undef CLOSE_BRACE
#undef DEFINITION_KEYWORD
#undef REFERENCE_KEYWORD
#undef NULL_KEYWORD
#undef ROUTE_NAME

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -