void run()
 {
    for( AbstractClassRep* classRep = AbstractClassRep::getClassList();
         classRep != NULL;
         classRep = classRep->getNextClass() )
    {
       // Create object.
       
       ConsoleObject* object = classRep->create();
       test( object, avar( "AbstractClassRep::create failed for class '%s'", classRep->getClassName() ) );
       if( !object )
          continue;
       
       // Make sure it's a SimObject.
       
       SimObject* simObject = dynamic_cast< SimObject* >( object );
       if( !simObject )
       {
          SAFE_DELETE( object );
          continue;
       }
       
       // Register the object.
       
       bool result = simObject->registerObject();
       test( result, avar( "registerObject failed for object of class '%s'", classRep->getClassName() ) );
       
       if( result )
          simObject->deleteObject();
       else
          SAFE_DELETE( simObject );
    }
 }
Пример #2
0
   S32 script_simobject_find(const char* classname, const char* name)
   {
      SimObject *object;
      if( Sim::findObject( name, object ) )
      {
         // if we specified a classname do type checking
         if (classname && dStrlen(classname))
         {
            AbstractClassRep* ocr = object->getClassRep();
            while (ocr)
            {
               if (!dStricmp(ocr->getClassName(), classname))
                  return object->getId();
               ocr = ocr->getParentClass();
            }

         }

         // invalid type
         return 0;
      }

      // didn't find object
      return 0;
   }
Пример #3
0
//--------------------------------------
ConsoleObject* AbstractClassRep::create(const U32 groupId, const U32 typeId, const U32 in_classId)
{
   AbstractClassRep* classRep = findClassRep( groupId, typeId, in_classId );
   if( !classRep )
      return NULL;

   return classRep->create();
}
Пример #4
0
void SimDataBlockEvent::unpack(NetConnection *cptr, BitStream *bstream)
{
   if(bstream->readFlag())
   {
      mProcess = true;
      id = bstream->readInt(DataBlockObjectIdBitSize) + DataBlockObjectIdFirst;
      S32 classId = bstream->readClassId(NetClassTypeDataBlock, cptr->getNetClassGroup());
      mIndex = bstream->readInt(DataBlockObjectIdBitSize);
      mTotal = bstream->readInt(DataBlockObjectIdBitSize + 1);
      
      SimObject* ptr;
      if( Sim::findObject( id, ptr ) )
      {
         // An object with the given ID already exists.  Make sure it has the right class.
         
         AbstractClassRep* classRep = AbstractClassRep::findClassRep( cptr->getNetClassGroup(), NetClassTypeDataBlock, classId );
         if( classRep && dStrcmp( classRep->getClassName(), ptr->getClassName() ) != 0 )
         {
            Con::warnf( "A '%s' datablock with id: %d already existed. "
                        "Clobbering it with new '%s' datablock from server.",
                        ptr->getClassName(), id, classRep->getClassName() );
            ptr->deleteObject();
            ptr = NULL;
         }
      }
      
      if( !ptr )
         ptr = ( SimObject* ) ConsoleObject::create( cptr->getNetClassGroup(), NetClassTypeDataBlock, classId );
         
      mObj = dynamic_cast< SimDataBlock* >( ptr );
      if( mObj != NULL )
      {
         #ifdef DEBUG_SPEW
         Con::printf(" - SimDataBlockEvent: unpacking event of type: %s", mObj->getClassName());
         #endif
         
         mObj->unpackData( bstream );
      }
      else
      {
         #ifdef DEBUG_SPEW
         Con::printf(" - SimDataBlockEvent: INVALID PACKET!  Could not create class with classID: %d", classId);
         #endif
         
         delete ptr;
         cptr->setLastError("Invalid packet in SimDataBlockEvent::unpack()");
      }

#ifdef TORQUE_DEBUG_NET
      U32 checksum = bstream->readInt(32);
      AssertISV( (checksum ^ DebugChecksum) == (U32)classId,
         avar("unpack did not match pack for event of class %s.",
            mObj->getClassName()) );
#endif

   }
}
Пример #5
0
bool EditorIconRegistry::hasIconNoRecurse( const SimObject *object )
{
   AbstractClassRep *classRep = object->getClassRep();
      
   StringNoCase key( classRep->getClassName() );

   IconMap::Iterator icon = mIcons.find( key );

   return icon != mIcons.end();
}
Пример #6
0
AbstractClassRep* AbstractClassRep::findClassRep(const char* in_pClassName)
{
   AssertFatal(initialized,
      "AbstractClassRep::findClassRep() - Tried to find an AbstractClassRep before AbstractClassRep::initialize().");

   for (AbstractClassRep *walk = classLinkList; walk; walk = walk->nextClass)
      if (!dStricmp(walk->getClassName(), in_pClassName))
         return walk;

   return NULL;
}
Пример #7
0
void EditorIconRegistry::loadFromPath( const String &path, bool overwrite )
{
   AbstractClassRep *classRep = AbstractClassRep::getClassList();
   while ( classRep )
   {
      String iconFile = String::ToString( "%s%s", path.c_str(), classRep->getClassName() );
      add( classRep->getClassName(), iconFile.c_str(), overwrite );
      classRep = classRep->getNextClass();
   }

   String defaultIconFile = path + "default";

   mDefaultIcon.set( defaultIconFile,
                     &GFXDefaultPersistentProfile, 
                     avar("%s() - mIcons[] (line %d)", 
                     __FUNCTION__, __LINE__) );
}
Пример #8
0
AbstractClassRep* GuiInspectorGroup::findCommonAncestorClass()
{
   AbstractClassRep* classRep = getInspector()->getInspectObject( 0 )->getClassRep();
   const U32 numInspectObjects = getInspector()->getNumInspectObjects();
   
   for( U32 i = 1; i < numInspectObjects; ++ i )
   {
      SimObject* object = getInspector()->getInspectObject( i );
      while( !object->getClassRep()->isClass( classRep ) )
      {
         classRep = classRep->getParentClass();
         AssertFatal( classRep, "GuiInspectorGroup::findcommonAncestorClass - Walked above ConsoleObject!" );
      }
   }
      
   return classRep;
}
Пример #9
0
void TypeValidator::consoleError(SimObject *object, const char *format, ...)
{
    char buffer[1024];
    va_list argptr;
    va_start(argptr, format);
    dVsprintf(buffer, sizeof(buffer), format, argptr);
    va_end(argptr);

    AbstractClassRep *rep = object->getClassRep();
    AbstractClassRep::Field &fld = rep->mFieldList[fieldIndex];
    const char *objectName = object->getName();
    if(!objectName)
        objectName = "unnamed";


    Con::warnf("%s - %s(%d) - invalid value for %s: %s",
               rep->getClassName(), objectName, object->getId(), fld.pFieldname, buffer);
}
Пример #10
0
void GuiInspectorDatablockField::setClassName( StringTableEntry className )
{
   // Walk the ACR list and find a matching class if any.
   AbstractClassRep *walk = AbstractClassRep::getClassList();
   while(walk)
   {
      if(!dStricmp(walk->getClassName(), className))
      {
         // Match!
         mDesiredClass = walk;
         return;
      }

      walk = walk->getNextClass();
   }

   // No dice.
   Con::warnf("GuiInspectorDatablockField::setClassName - no class '%s' found!", className);
   return;
}
Пример #11
0
GFXTexHandle EditorIconRegistry::findIcon( const char *className )
{   
   // On the chance we have this className already in the map,
   // check there first because its a lot faster...
   
   StringNoCase key( className );
   IconMap::Iterator icon = mIcons.find( key );

   if ( icon != mIcons.end() && icon->value.isValid() )
      return icon->value;

   // Well, we could still have an icon for a parent class,
   // so find the AbstractClassRep for the className.
   //
   // Unfortunately the only way to do this is looping through
   // the AbstractClassRep linked list.

   bool found = false;
   AbstractClassRep* pClassRep = AbstractClassRep::getClassList();
   
   while ( pClassRep )
   {
      if ( key.equal( pClassRep->getClassName(), String::NoCase ) )
      {
         found = true;
         break;
      }
      pClassRep = pClassRep->getNextClass();
   }

   if ( !found )
   {
      Con::errorf( "EditorIconRegistry::findIcon, passed className %s was not an AbstractClassRep!", key.c_str() );
      return mDefaultIcon;
   }
   
   // Now do a find by AbstractClassRep recursively up the class tree...
   return findIcon( pClassRep );
}
Пример #12
0
AbstractClassRep *AbstractClassRep::getCommonParent( const AbstractClassRep *otherClass ) const
{
   // CodeReview: This may be a noob way of doing it. There may be some kind of
   // super-spiffy algorithm to do what the code below does, but this appeared
   // to make sense to me, and it is pretty easy to see what it is doing [6/23/2007 Pat]

   static VectorPtr<AbstractClassRep *> thisClassHeirarchy;
   thisClassHeirarchy.clear();

   AbstractClassRep *walk = const_cast<AbstractClassRep *>( this );

   while( walk != NULL )
   {
      thisClassHeirarchy.push_front( walk );
      walk = walk->getParentClass();
   }

   static VectorPtr<AbstractClassRep *> compClassHeirarchy;
   compClassHeirarchy.clear();
   walk = const_cast<AbstractClassRep *>( otherClass );
   while( walk != NULL )
   {
      compClassHeirarchy.push_front( walk );
      walk = walk->getParentClass();
   }

   // Make sure we only iterate over the list the number of times we can
   S32 maxIterations = getMin( compClassHeirarchy.size(), thisClassHeirarchy.size() );

   U32 i = 0;
   for( ; i < maxIterations; i++ )
   {
      if( compClassHeirarchy[i] != thisClassHeirarchy[i] )
         break;
   }

   return compClassHeirarchy[i];
}
Пример #13
0
   void XMLExport::exportNamespaces()
   {

      // keep track of which enumTables are in use
      Vector < const EnumTable*> enumTables;

      mXML->pushNewElement("Namespaces");

      for (Namespace *walk = Namespace::mNamespaceList; walk; walk = walk->mNext)
      {

         if ( walk->mName && !walk->isClass() )
            continue;

         const char *name = walk->mName ? walk->mName : "";

         mXML->pushNewElement("Namespace");
         mXML->setAttribute("name", name);

         Namespace *p = walk->mParent;

         mXML->pushNewElement("Parents");

         while (p)
         {
            if (p->mName == walk->mName)
            {
               p = p->mParent;
               continue;
            }

            const char* pname = p->mName ? p->mName : "";

            mXML->pushNewElement("Parent");
            mXML->setAttribute("name", pname);
            mXML->popElement(); // Parent

            p = p->mParent;
         }

         mXML->popElement(); // Parents

         // Entries (Engine/Script Methods/Functions)

         mXML->pushNewElement("Entries");

         Namespace::Entry *entry;
         VectorPtr<Namespace::Entry *> vec;

         walk->getEntryList(&vec);

         for( NamespaceEntryListIterator compItr = vec.begin(); compItr != vec.end(); compItr++ )
         {

            entry = *compItr;

            if (entry->mNamespace != walk)
               continue;

            if (entry->mNamespace->mName != walk->mName)
               continue;

            mXML->pushNewElement("Entry");

            //consistently name functions
            char functionName[512];
            dSprintf(functionName, 512, entry->mFunctionName);
            functionName[0] = dTolower(functionName[0]);

            S32 minArgs = entry->mMinArgs;
            S32 maxArgs = entry->mMaxArgs;

            if (maxArgs < minArgs)
               maxArgs = minArgs;

            mXML->setAttribute("name", functionName);
            mXML->setAttribute("minArgs", avar("%i", minArgs));
            mXML->setAttribute("maxArgs", avar("%i", maxArgs));

            const char* usage = "";
            if (entry->mUsage && entry->mUsage[0])
               usage = entry->mUsage;
            mXML->setAttribute("usage", usage);
            mXML->setAttribute("package", entry->mPackage ? entry->mPackage : "");
            mXML->setAttribute("entryType", avar("%i", entry->mType));

            mXML->popElement(); // Entry

         }

         mXML->popElement(); // Entries

         // Fields

         mXML->pushNewElement("Fields");

         AbstractClassRep *rep = walk->mClassRep;
         Vector<U32> classFields;

         if (rep)
         {
            AbstractClassRep *parentRep = rep->getParentClass();

            const AbstractClassRep::FieldList& flist = rep->mFieldList;

            for(U32 i = 0; i < flist.size(); i++)
            {
               if (parentRep)
               {
                  if (parentRep->findField(flist[i].pFieldname))
                     continue;

               }
               classFields.push_back(i);
            }

            for(U32 i = 0; i < classFields.size(); i++)
            {
               U32 index = classFields[i];

               char fieldName[256];

               dSprintf(fieldName, 256, flist[index].pFieldname);

               //consistently name fields
               fieldName[0] = dToupper(fieldName[0]);

               mXML->pushNewElement("Field");

               mXML->setAttribute("name", fieldName);
               mXML->setAttribute("type", avar("%i", flist[index].type));

// RD: temporarily deactivated; TypeEnum is no more; need to sync this up
//               if (flist[index].type == TypeEnum  && flist[index].table && dStrlen(flist[index].table->name))
//               {
//                  if (!enumTables.contains(flist[index].table))
//                     enumTables.push_back(flist[index].table);
//
//                  mXML->setAttribute("enumTable", flist[index].table->name);
//
//               }

               const char* pFieldDocs = "";
               if (flist[index].pFieldDocs && flist[index].pFieldDocs[0])
                  pFieldDocs = flist[index].pFieldDocs;

               mXML->setAttribute("docs", pFieldDocs);
               mXML->setAttribute("elementCount", avar("%i", flist[index].elementCount));

               mXML->popElement(); // Field
            }
         }

         mXML->popElement(); // Fields
         mXML->popElement(); // Namespace
      }

      mXML->popElement(); // Namespaces

      mXML->pushNewElement("EnumTables");

      // write out the used EnumTables
      for (S32 i = 0; i < enumTables.size(); i++)
      {
         mXML->pushNewElement("EnumTable");

         const EnumTable* table = enumTables[i];

         mXML->setAttribute("name", table->name);
         mXML->setAttribute("firstFlag", avar("%i", table->firstFlag));
         mXML->setAttribute("mask", avar("%i", table->mask));

         mXML->pushNewElement("Enums");

         for (S32 j = 0; j < table->size; j++)
         {
            mXML->pushNewElement("Enum");

            mXML->setAttribute("name", table->table[j].label);
            mXML->setAttribute("index", avar("%i", table->table[j].index));

            mXML->popElement(); // Enum

         }

         mXML->popElement(); //Enums

         mXML->popElement(); // EnumTable
      }

      mXML->popElement(); // EnumTables
      
   }
Пример #14
0
void AbstractClassRep::initialize()
{
   AssertFatal(!initialized, "Duplicate call to AbstractClassRep::initialize()!");
   Vector<AbstractClassRep *> dynamicTable(__FILE__, __LINE__);

   AbstractClassRep *walk;

   // Initialize namespace references...
   for (walk = classLinkList; walk; walk = walk->nextClass)
   {
      walk->mNamespace = Con::lookupNamespace(StringTable->insert(walk->getClassName()));
      walk->mNamespace->mUsage = walk->getDocString();
      walk->mNamespace->mClassRep = walk;
   }

   // Initialize field lists... (and perform other console registration).
   for (walk = classLinkList; walk; walk = walk->nextClass)
   {
      // sg_tempFieldList is used as a staging area for field lists
      // (see addField, addGroup, etc.)
      sg_tempFieldList.setSize(0);

      walk->init();

      // So if we have things in it, copy it over...
      if (sg_tempFieldList.size() != 0)
         walk->mFieldList = sg_tempFieldList;

      // And of course delete it every round.
      sg_tempFieldList.clear();
   }

   // Calculate counts and bit sizes for the various NetClasses.
   for (U32 group = 0; group < NetClassGroupsCount; group++)
   {
      U32 groupMask = 1 << group;

      // Specifically, for each NetClass of each NetGroup...
      for(U32 type = 0; type < NetClassTypesCount; type++)
      {
         // Go through all the classes and find matches...
         for (walk = classLinkList; walk; walk = walk->nextClass)
         {
            if(walk->mClassType == type && walk->mClassGroupMask & groupMask)
               dynamicTable.push_back(walk);
         }

         // Set the count for this NetGroup and NetClass
         NetClassCount[group][type] = dynamicTable.size();
         if(!NetClassCount[group][type])
            continue; // If no classes matched, skip to next.

         // Sort by type and then by name.
         dQsort((void *) &dynamicTable[0], dynamicTable.size(), sizeof(AbstractClassRep *), ACRCompare);

         // Allocate storage in the classTable
         classTable[group][type] = new AbstractClassRep*[NetClassCount[group][type]];

         // Fill this in and assign class ids for this group.
         for(U32 i = 0; i < NetClassCount[group][type];i++)
         {
            classTable[group][type][i] = dynamicTable[i];
            dynamicTable[i]->mClassId[group] = i;
         }

         // And calculate the size of bitfields for this group and type.
         NetClassBitSize[group][type] =
               getBinLog2(getNextPow2(NetClassCount[group][type] + 1));
         AssertFatal(NetClassCount[group][type] < (1 << NetClassBitSize[group][type]), "NetClassBitSize too small!");

         dynamicTable.clear();
      }
   }

   // Ok, we're golden!
   initialized = true;
}
Пример #15
0
bool SceneObject::isSelectionEnabled() const
{
   AbstractClassRep *classRep = getClassRep();
   return ( mObjectFlags.test( SelectionEnabledFlag ) && classRep->isSelectionEnabled() );
}
Пример #16
0
void TamlBinaryReader::parseChildren( Stream& stream, TamlCallbacks* pCallbacks, SimObject* pSimObject, const U32 versionId )
{
    // Debug Profiling.
    PROFILE_SCOPE(TamlBinaryReader_ParseChildren);

    // Sanity!
    AssertFatal( pSimObject != NULL, "Taml: Cannot parse children on a NULL object." );

    // Fetch children count.
    U32 childrenCount;
    stream.read( &childrenCount );

    // Finish if no children.
    if ( childrenCount == 0 )
        return;

    // Fetch the Taml children.
    TamlChildren* pChildren = dynamic_cast<TamlChildren*>( pSimObject );

    // Is this a sim set?
    if ( pChildren == NULL )
    {
        // No, so warn.
        Con::warnf("Taml: Child element found under parent but object cannot have children." );
        return;
    }

    // Fetch any container child class specifier.
    AbstractClassRep* pContainerChildClass = pSimObject->getClassRep()->getContainerChildClass( true );

    // Iterate children.
    for ( U32 index = 0; index < childrenCount; ++ index )
    {
        // Parse child element.
        SimObject* pChildSimObject = parseElement( stream, versionId );

        // Finish if child failed.
        if ( pChildSimObject == NULL )
            return;

        // Do we have a container child class?
        if ( pContainerChildClass != NULL )
        {
            // Yes, so is the child object the correctly derived type?
            if ( !pChildSimObject->getClassRep()->isClass( pContainerChildClass ) )
            {
                // No, so warn.
                Con::warnf("Taml: Child element '%s' found under parent '%s' but object is restricted to children of type '%s'.",
                    pChildSimObject->getClassName(),
                    pSimObject->getClassName(),
                    pContainerChildClass->getClassName() );

                // NOTE: We can't delete the object as it may be referenced elsewhere!
                pChildSimObject = NULL;

                // Skip.
                continue;
            }
        }

        // Add child.
        pChildren->addTamlChild( pChildSimObject );

        // Find Taml callbacks for child.
        TamlCallbacks* pChildCallbacks = dynamic_cast<TamlCallbacks*>( pChildSimObject );

        // Do we have callbacks on the child?
        if ( pChildCallbacks != NULL )
        {
            // Yes, so perform callback.
            mpTaml->tamlAddParent( pChildCallbacks, pSimObject );
        }
    }
}
Пример #17
0
GuiInspectorField* GuiInspectorGroup::constructField( S32 fieldType )
{
   // See if we can construct a field of this type
   ConsoleBaseType *cbt = ConsoleBaseType::getType(fieldType);
   if( !cbt )
      return NULL;

   // Alright, is it a datablock?
   if(cbt->isDatablock())
   {
      // Default to GameBaseData
      StringTableEntry typeClassName = cbt->getTypeClassName();

      if( mParent->getNumInspectObjects() == 1 && !dStricmp(typeClassName, "GameBaseData") )
      {
         // Try and setup the classname based on the object type
         char className[256];
         dSprintf(className,256,"%sData", mParent->getInspectObject( 0 )->getClassName());
         // Walk the ACR list and find a matching class if any.
         AbstractClassRep *walk = AbstractClassRep::getClassList();
         while(walk)
         {
            if(!dStricmp(walk->getClassName(), className))
               break;

            walk = walk->getNextClass();
         }

         // We found a valid class
         if (walk)
            typeClassName = walk->getClassName();

      }


      GuiInspectorDatablockField *dbFieldClass = new GuiInspectorDatablockField( typeClassName );
      if( dbFieldClass != NULL )
      {
         // return our new datablock field with correct datablock type enumeration info
         return dbFieldClass;
      }
   }

   // Nope, not a datablock. So maybe it has a valid inspector field override we can use?
   if(!cbt->getInspectorFieldType())
      // Nothing, so bail.
      return NULL;

   // Otherwise try to make it!
   ConsoleObject *co = create(cbt->getInspectorFieldType());
   GuiInspectorField *gif = dynamic_cast<GuiInspectorField*>(co);

   if(!gif)
   {
      // Wasn't appropriate type, bail.
      delete co;
      return NULL;
   }

   return gif;
}
Пример #18
0
static void dumpClasses( Stream &stream )
{
   Namespace::trashCache();

   VectorPtr<Namespace*> vec;
   vec.reserve( 1024 );

   // We use mHashSequence to mark if we have traversed...
   // so mark all as zero to start.
   for ( Namespace *walk = Namespace::mNamespaceList; walk; walk = walk->mNext )
      walk->mHashSequence = 0;

   for(Namespace *walk = Namespace::mNamespaceList; walk; walk = walk->mNext)
   {
      VectorPtr<Namespace*> stack;
      stack.reserve( 1024 );

      // Get all the parents of this namespace... (and mark them as we go)
      Namespace *parentWalk = walk;
      while(parentWalk)
      {
         if(parentWalk->mHashSequence != 0)
            break;
         if(parentWalk->mPackage == 0)
         {
            parentWalk->mHashSequence = 1;   // Mark as traversed.
            stack.push_back(parentWalk);
         }
         parentWalk = parentWalk->mParent;
      }

      // Load stack into our results vector.
      while(stack.size())
      {
         vec.push_back(stack[stack.size() - 1]);
         stack.pop_back();
      }
   }

   // Go through previously discovered classes
   U32 i;
   for(i = 0; i < vec.size(); i++)
   {
      const char *className = vec[i]->mName;
      const char *superClassName = vec[i]->mParent ? vec[i]->mParent->mName : NULL;

      // Skip the global namespace, that gets dealt with in dumpFunctions
      if(!className) 
         continue;

      // We're just dumping engine functions, then we don't want to dump
      // a class that only contains script functions. So, we iterate over 
      // all the functions.
      bool found = false;
      for( Namespace::Entry *ewalk = vec[i]->mEntryList; ewalk; ewalk = ewalk->mNext )
      {
         if( ewalk->mType != Namespace::Entry::ConsoleFunctionType )
         {
            found = true;
            break;
         }
      }

      // If we don't have engine functions and the namespace name
      // doesn't match the class name... then its a script class.
      if ( !found && !vec[i]->isClass() )
         continue;
  
      // If we hit a class with no members and no classRep, do clever filtering.
      if(vec[i]->mEntryList == NULL && vec[i]->mClassRep == NULL)
      {
         // Print out a short stub so we get a proper class hierarchy.
         if ( superClassName )  
         { 
            // Filter hack; we don't want non-inheriting classes...
            dumpClassHeader( stream, NULL, className, superClassName );
            dumpClassFooter( stream );
         }
         continue;
      }

      // Skip over hidden or internal classes.
      if(   vec[i]->mUsage &&
            ( dStrstr( vec[i]->mUsage, "@hide" ) || dStrstr( vec[i]->mUsage, "@internal" ) ) )
         continue;

      // Print the header for the class..
      dumpClassHeader( stream, vec[i]->mUsage, className, superClassName );
      
      // Dump all fragments for this class.
      
      for( ConsoleDocFragment* fragment = ConsoleDocFragment::smFirst; fragment != NULL; fragment = fragment->mNext )
         if( fragment->mClass && dStricmp( fragment->mClass, className ) == 0 )
            dumpFragment( stream, fragment );

      // Dump member functions.
      dumpNamespaceEntries( stream, vec[ i ], false );
      
      // Dump callbacks.
      dumpGroupStart( stream, "Callbacks" );
      dumpNamespaceEntries( stream, vec[ i ], true );
      dumpGroupEnd( stream );
      
      // Dump static member variables.
      dumpVariables( stream, className );

      // Deal with the classRep (to get members)...
      AbstractClassRep *rep = vec[i]->mClassRep;
      AbstractClassRep::FieldList emptyList;
      AbstractClassRep::FieldList *parentList = &emptyList;
      AbstractClassRep::FieldList *fieldList = &emptyList;
      if ( rep )
      {
         // Get information about the parent's fields...
         AbstractClassRep *parentRep = vec[i]->mParent ? vec[i]->mParent->mClassRep : NULL;
         if(parentRep)
            parentList = &(parentRep->mFieldList);

         // Get information about our fields
         fieldList = &(rep->mFieldList);

         // Go through all our fields...
         for(U32 j = 0; j < fieldList->size(); j++)
         {
            const AbstractClassRep::Field &field = (*fieldList)[j];

            switch( field.type )
            {
            case AbstractClassRep::StartArrayFieldType:
            case AbstractClassRep::EndArrayFieldType:
               break;
            case AbstractClassRep::StartGroupFieldType:
               dumpGroupStart( stream, field.pGroupname, field.pFieldDocs );
               break;
            case AbstractClassRep::EndGroupFieldType:
               dumpGroupEnd( stream );
               break;
            default:
            case AbstractClassRep::DeprecatedFieldType:
               // Skip over fields that are already defined in
               // our parent class.
               if ( parentRep && parentRep->findField( field.pFieldname ) )
                  continue;
                     
               dumpClassMember( stream, field );
               break;
            }
         }
      }

      // Close the class/namespace.
      dumpClassFooter( stream );
   }
}