532 lines
18 KiB
C++
532 lines
18 KiB
C++
//
|
|
// The developer of the original code and/or files is Tripwire, Inc.
|
|
// Portions created by Tripwire, Inc. are copyright (C) 2000-2018 Tripwire,
|
|
// Inc. Tripwire is a registered trademark of Tripwire, Inc. All rights
|
|
// reserved.
|
|
//
|
|
// This program is free software. The contents of this file are subject
|
|
// to the terms of the GNU General Public License as published by the
|
|
// Free Software Foundation; either version 2 of the License, or (at your
|
|
// option) any later version. You may redistribute it and/or modify it
|
|
// only in compliance with the GNU General Public License.
|
|
//
|
|
// This program is distributed in the hope that it will be useful.
|
|
// However, this program is distributed AS-IS WITHOUT ANY
|
|
// WARRANTY; INCLUDING THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS
|
|
// FOR A PARTICULAR PURPOSE. Please see the GNU General Public License
|
|
// for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
// USA.
|
|
//
|
|
// Nothing in the GNU General Public License or any other license to use
|
|
// the code or files shall permit you to use Tripwire's trademarks,
|
|
// service marks, or other intellectual property without Tripwire's
|
|
// prior written consent.
|
|
//
|
|
// If you have any questions, please contact Tripwire, Inc. at either
|
|
// info@tripwire.org or www.tripwire.org.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// textdbviewer.cpp -- implementation for dbviewer class
|
|
//
|
|
|
|
//=========================================================================
|
|
// DIRECTIVES
|
|
//=========================================================================
|
|
|
|
|
|
//=========================================================================
|
|
// INCLUDES
|
|
//=========================================================================
|
|
#include "stdtw.h"
|
|
|
|
#include <fstream>
|
|
#include <iomanip>
|
|
|
|
#include "core/tchar.h"
|
|
#include "textdbviewer.h"
|
|
#include "core/debug.h"
|
|
#include "fcodatabasefile.h"
|
|
#include "dbdatasource.h"
|
|
#include "fco/fcospec.h"
|
|
#include "fco/iterproxy.h"
|
|
#include "fco/fcopropvector.h"
|
|
#include "fco/fcopropset.h"
|
|
#include "fco/fcoprop.h"
|
|
#include "core/fsservices.h"
|
|
#include "fco/fcospecattr.h"
|
|
#include "core/timeconvert.h"
|
|
#include "fco/fcopropdisplayer.h"
|
|
#include "headerinfo.h"
|
|
#include "fco/genreswitcher.h"
|
|
#include "core/twlocale.h"
|
|
#include "fco/twfactory.h"
|
|
#include "fco/fconametranslator.h"
|
|
#include "fco/fcoundefprop.h"
|
|
#include "tw/twstrings.h"
|
|
#include "core/displayencoder.h"
|
|
|
|
//=========================================================================
|
|
// USING NAMESPACE
|
|
//=========================================================================
|
|
|
|
using namespace std;
|
|
|
|
//=========================================================================
|
|
// GLOBALS
|
|
//=========================================================================
|
|
|
|
static const TCHAR* g_sz79Dashes = _T("-------------------------------------------------------------------------------");
|
|
static const TCHAR* g_sz79Equals = _T("===============================================================================");
|
|
|
|
//=========================================================================
|
|
// UTIL FUNCTION PROTOTYES
|
|
//=========================================================================
|
|
static void InitOStream( TOSTREAM* pOut );
|
|
static void DisplayFCOProps( const iFCO* const pFCO, const iFCOPropDisplayer* pPD, TOSTREAM* pOut );
|
|
|
|
static void OutputDatabaseHeader ( const cFCODbHeader& dbHeader, TOSTREAM* pOut );
|
|
// Currently we don't have a rule summary. See function definition below
|
|
//static void OutputRulesSummary ( const cFCODatabaseFileIter& genreIter, const iFCONameTranslator* pNT, TOSTREAM* pOut );
|
|
|
|
|
|
static void OutputSectionDelimiter( int nString, TOSTREAM* pOut );
|
|
static void OutputGenreDelimiter( cGenre::Genre g, TOSTREAM* pOut );
|
|
|
|
static void OutputObjectSummary( cFCODatabaseFile& rd, TOSTREAM* pOut, int margin );
|
|
static void OutputObjectDetail( cFCODatabaseFile& rd, TOSTREAM* pOut );
|
|
|
|
static void OutputObjectSummary( cFCODatabaseFileIter& genreIter, const iFCONameTranslator* pNT, TOSTREAM* pOut, int margin );
|
|
static void OutputObjectDetail( cFCODatabaseFileIter& genreIter, const iFCONameTranslator* pNT, TOSTREAM* pOut );
|
|
|
|
|
|
static void OutputIterChildren ( cDbDataSourceIter dbIter, const iFCOPropDisplayer* pPD, const iFCONameTranslator* pNT, TOSTREAM* pOut, bool fDetails );
|
|
static void OutputIterPeers ( cDbDataSourceIter dbIter, const iFCOPropDisplayer* pPD, const iFCONameTranslator* pNT, TOSTREAM* pOut, bool fDetails );
|
|
//static void OutputIter ( cDbDataSourceIter& dbIter, const iFCOPropDisplayer* pPD, TOSTREAM* pOut, bool fDetails );
|
|
static void PrintFCOShort ( const iFCO* pFCO, const iFCOPropDisplayer* pPD, const iFCONameTranslator* pNT, TOSTREAM* pOut, int margin );
|
|
//static void OutputSpecHeader( const cFCODbSpecIter& dbi, TOSTREAM* pOut );
|
|
//static void OutputDetailHeader( const cFCODbSpecIter& dbi, int nObjects, TOSTREAM* pOut );
|
|
|
|
static TSTRING util_Encode( const TSTRING& sIn )
|
|
{
|
|
static cDisplayEncoder e;
|
|
TSTRING sOut = sIn;
|
|
e.Encode( sOut );
|
|
return sOut;
|
|
}
|
|
|
|
//=========================================================================
|
|
// METHOD CODE
|
|
//=========================================================================
|
|
|
|
void cTextDBViewer::PrintDB( cFCODatabaseFile& rd, const TSTRING& strFilename )
|
|
{
|
|
TOSTREAM* pOut;
|
|
TOFSTREAM fileOut;
|
|
bool fIsFile = false;
|
|
|
|
if( strFilename == _T("-") )
|
|
{
|
|
pOut = &TCOUT;
|
|
}
|
|
else
|
|
{
|
|
//Gonna have to insert a lame hack here, since ostr.open DEMANDS a const char*!!
|
|
fileOut.open( strFilename.c_str() );
|
|
|
|
if( fileOut.is_open() )
|
|
{
|
|
pOut = &fileOut;
|
|
fIsFile = true;
|
|
}
|
|
else
|
|
{
|
|
ASSERT( false );
|
|
throw eArchiveOpen( strFilename, iFSServices::GetInstance()->GetErrString() );
|
|
}
|
|
}
|
|
|
|
InitOStream( pOut );
|
|
|
|
//
|
|
// output header, just like it sez....
|
|
//
|
|
OutputDatabaseHeader( rd.GetHeader(), pOut );
|
|
|
|
OutputObjectSummary( rd, pOut, DETAILS_MARGIN );
|
|
|
|
OutputObjectDetail( rd, pOut );
|
|
|
|
|
|
// we're done
|
|
(*pOut) << g_sz79Dashes << endl;
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_END_OF_DB ) << endl << endl;
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_COPYRIGHT ) << endl;
|
|
|
|
if( fIsFile )
|
|
static_cast<TOFSTREAM*>(pOut)->close();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// OutputFCO
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cTextDBViewer::OutputFCO( cDbDataSourceIter& dbIter, const iFCOPropDisplayer* pPD, const iFCONameTranslator* pNT, TOSTREAM* pOut, bool fDetails )
|
|
{
|
|
InitOStream( pOut );
|
|
|
|
if( dbIter.HasFCOData() )
|
|
{
|
|
iFCO* pFCO = dbIter.CreateFCO();
|
|
|
|
if( fDetails )
|
|
{
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_OBJECT_NAME ) << _T(" ") << pNT->ToStringDisplay( pFCO->GetName() ).c_str() << endl << endl;
|
|
DisplayFCOProps( pFCO, pPD, pOut );
|
|
(*pOut) << endl << endl;
|
|
}
|
|
else
|
|
PrintFCOShort( pFCO, pPD, pNT, pOut, DETAILS_MARGIN );
|
|
|
|
pFCO->Release();
|
|
}
|
|
}
|
|
|
|
|
|
//=========================================================================
|
|
// UTIL FUNCTION CODE
|
|
//=========================================================================
|
|
|
|
void InitOStream( TOSTREAM* pOut )
|
|
{
|
|
// align left
|
|
(*pOut).flags( ( (*pOut).flags() & ~std::ios::adjustfield ) | std::ios::left );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// PrintFCOShort
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static void PrintFCOShort( const iFCO* pFCO, const iFCOPropDisplayer* pPD, const iFCONameTranslator* pNT, TOSTREAM* pOut, int margin )
|
|
{
|
|
ASSERT( pOut != 0);
|
|
|
|
TSTRING strDetails;
|
|
|
|
//
|
|
// output "<name of FCO>"\n\t<details of FCO>"
|
|
//
|
|
(*pOut) << _T(" ");
|
|
(*pOut) << pNT->ToStringDisplay( pFCO->GetName() ).c_str();
|
|
(*pOut) << endl;
|
|
(*pOut) << setw( margin ) << _T("");
|
|
pPD->GetDetails( pFCO, strDetails );
|
|
(*pOut) << strDetails;
|
|
(*pOut) << _T("\n");
|
|
}
|
|
|
|
|
|
static void OutputIterChildren( cDbDataSourceIter dbIter, const iFCOPropDisplayer* pPD, const iFCONameTranslator* pNT, TOSTREAM* pOut, bool fDetails )
|
|
{
|
|
dbIter.Descend();
|
|
OutputIterPeers( dbIter, pPD, pNT, pOut, fDetails );
|
|
}
|
|
|
|
static void OutputIterPeers( cDbDataSourceIter dbIter, const iFCOPropDisplayer* pPD, const iFCONameTranslator* pNT, TOSTREAM* pOut, bool fDetails )
|
|
{
|
|
for ( dbIter.SeekBegin(); ! dbIter.Done(); dbIter.Next() )
|
|
{
|
|
// TODO: this obviously needs to be expanded upon.
|
|
cTextDBViewer::OutputFCO( dbIter, pPD, pNT, pOut, fDetails );
|
|
|
|
if( dbIter.CanDescend() )
|
|
OutputIterChildren( dbIter, pPD, pNT, pOut, fDetails );
|
|
}
|
|
}
|
|
|
|
|
|
static void OutputDatabaseHeader( const cFCODbHeader& dbHeader, TOSTREAM* pOut )
|
|
{
|
|
const int headerColumnWidth = 30;
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_DBPRINT_TITLE ) << endl << endl;
|
|
|
|
(*pOut).width(headerColumnWidth);
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_DB_GENERATED_BY ) << util_Encode( dbHeader.GetCreator() ) << endl;
|
|
|
|
TSTRING tstrDummy;
|
|
int64 i64CreateTime = dbHeader.GetCreationTime();
|
|
(*pOut).width(headerColumnWidth);
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_DB_CREATED_ON ) << cTWLocale::FormatTime( i64CreateTime, tstrDummy ).c_str() << endl;
|
|
|
|
(*pOut).width(headerColumnWidth);
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_DB_LAST_UPDATE );
|
|
|
|
int64 i64LastDBUTime = dbHeader.GetLastDBUpdateTime();
|
|
if( i64LastDBUTime == 0 )
|
|
{
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_NEVER ) << endl << endl;
|
|
}
|
|
else
|
|
{
|
|
(*pOut) << cTWLocale::FormatTime( i64LastDBUTime, tstrDummy ).c_str() << endl << endl;
|
|
}
|
|
|
|
OutputSectionDelimiter( tw::STR_DB_SUMMARY, pOut );
|
|
|
|
(*pOut).width(headerColumnWidth);
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_HOST_NAME ) << dbHeader.GetSystemName().c_str() << endl;
|
|
(*pOut).width(headerColumnWidth);
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_HOST_IP ) << dbHeader.GetIPAddress() << endl;
|
|
|
|
|
|
(*pOut).width(headerColumnWidth);
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_HOST_ID );
|
|
|
|
if(! dbHeader.GetHostID().empty() )
|
|
(*pOut) << dbHeader.GetHostID() << endl;
|
|
else
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_NONE ) << endl;
|
|
|
|
|
|
(*pOut) << setw(headerColumnWidth)
|
|
<< TSS_GetString( cTW, tw::STR_POLICY_FILE_USED )
|
|
<< util_Encode( dbHeader.GetPolicyFilename() )
|
|
<< endl;
|
|
|
|
(*pOut) << setw(headerColumnWidth)
|
|
<< TSS_GetString( cTW, tw::STR_CONFIG_FILE_USED )
|
|
<< util_Encode( dbHeader.GetConfigFilename() )
|
|
<< endl;
|
|
|
|
(*pOut) << setw(headerColumnWidth)
|
|
<< TSS_GetString( cTW, tw::STR_DB_FILE_USED )
|
|
<< util_Encode( dbHeader.GetDBFilename() )
|
|
<< endl;
|
|
|
|
(*pOut) << setw(headerColumnWidth)
|
|
<< TSS_GetString( cTW, tw::STR_CMD_LINE_USED )
|
|
<< util_Encode( dbHeader.GetCommandLineParams() )
|
|
<< endl
|
|
<< endl;
|
|
}
|
|
|
|
#if 0
|
|
// The rules summary is not working due to changes in the databasse infrastructure. Until
|
|
// we hear different from the product manager, it is out of here.
|
|
static void OutputRulesSummary(const cFCODatabaseFileIter& genreIter, const iFCONameTranslator* pNT, TOSTREAM* pOut )
|
|
{
|
|
const cHierDatabase& db = genreIter.GetDb();
|
|
|
|
// these should add up to 79
|
|
const int nameWidth = 50;
|
|
const int numObjectsWidth = 10;
|
|
|
|
(*pOut) << g_sz79Dashes << endl;
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_RULE_SUMMARY ) << endl;
|
|
(*pOut) << g_sz79Dashes << endl << endl;
|
|
|
|
(*pOut).width(nameWidth);
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_RULE_NAME );
|
|
(*pOut).width(numObjectsWidth);
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_OBJECTS ) << endl;
|
|
|
|
(*pOut) << setw( nameWidth ) << _T("---------");
|
|
(*pOut) << setw( numObjectsWidth ) << _T("-------");
|
|
(*pOut) << endl;
|
|
|
|
// output spec stats
|
|
cFCOSpecListCanonicalIter specIter( genreIter.GetSpecList() );
|
|
|
|
// iterate over all database elements
|
|
int nTotalObjects = 0;
|
|
for( specIter.SeekBegin(); !specIter.Done(); specIter.Next() )
|
|
{
|
|
(*pOut) << setw( nameWidth ) << specIter.Spec()->GetName();
|
|
|
|
// if the name is too long, put it on its own line
|
|
if( specIter.Spec()->GetName().length() >= nameWidth )
|
|
{
|
|
(*pOut) << endl;
|
|
|
|
// output space holder
|
|
(*pOut).width(nameWidth);
|
|
(*pOut) << _T("");
|
|
}
|
|
|
|
(*pOut).width(numObjectsWidth);
|
|
(*pOut) << _T("TODO");
|
|
//(*pOut) << specIter.GetFCOSet()->Size(); TODO: Do this right
|
|
(*pOut) << endl;
|
|
}
|
|
|
|
(*pOut) << endl;
|
|
|
|
// NOTE 4 Jan 99 mdb -- this used to use dbHeader.GetTotalObjectsScanned() but it was not always consistent with the
|
|
// total number of objects in the database. TODO -- if we are really not going to use this number, then we should
|
|
// not store it in the database at all.
|
|
//
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_TOTAL_NUM_FILES );
|
|
//(*pOut) << _T(" ") << nTotalObjects << endl;
|
|
(*pOut) << _T("TODO") << endl;
|
|
(*pOut) << endl;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
void OutputSectionDelimiter( int nString, TOSTREAM* pOut )
|
|
{
|
|
(*pOut) << g_sz79Equals << endl;
|
|
(*pOut) << TSS_GetString( cTW, nString ) << endl;
|
|
(*pOut) << g_sz79Equals << endl << endl;
|
|
}
|
|
|
|
void OutputGenreDelimiter( cGenre::Genre g, TOSTREAM* pOut )
|
|
{
|
|
(*pOut) << g_sz79Dashes << endl;
|
|
(*pOut) << _T("# ") << TSS_GetString( cTW, tw::STR_SECTION );
|
|
(*pOut) << _T(": ") << cGenreSwitcher::GetInstance()->GenreToString( g, true ) << endl;
|
|
(*pOut) << g_sz79Dashes << endl << endl;
|
|
}
|
|
|
|
void OutputObjectSummary( cFCODatabaseFile& rd, TOSTREAM* pOut, int margin )
|
|
{
|
|
OutputSectionDelimiter( tw::STR_OBJECT_SUMMARY, pOut );
|
|
|
|
cFCODatabaseFileIter genreIter(rd);
|
|
for (genreIter.SeekBegin(); !genreIter.Done(); genreIter.Next())
|
|
{
|
|
cGenreSwitcher::GetInstance()->SelectGenre( (cGenre::Genre) genreIter.GetGenre() );
|
|
|
|
iFCONameTranslator* pNT = iTWFactory::GetInstance()->GetNameTranslator();
|
|
|
|
OutputGenreDelimiter( (cGenre::Genre) genreIter.GetGenre(), pOut );
|
|
|
|
// Currently we don't have a rule summary. See function definition below
|
|
//OutputRulesSummary( genreIter, pNT, pOut);
|
|
|
|
OutputObjectSummary( genreIter, pNT, pOut, margin );
|
|
}
|
|
}
|
|
|
|
void OutputObjectSummary( cFCODatabaseFileIter& genreIter, const iFCONameTranslator* pNT, TOSTREAM* pOut, int margin )
|
|
{
|
|
const cDbDataSourceIter dbIter( &genreIter.GetDb() );
|
|
ASSERT(dbIter.AtRoot());
|
|
|
|
(*pOut) << setw( margin ) << _T("");
|
|
TSTRING strBuf;
|
|
(*pOut) << genreIter.GetGenreHeader().GetPropDisplayer()->GetDetailsHeader( strBuf, margin ).c_str() << endl;
|
|
|
|
OutputIterPeers( dbIter, genreIter.GetGenreHeader().GetPropDisplayer(), pNT, pOut, false );
|
|
(*pOut) << endl;
|
|
}
|
|
|
|
|
|
void OutputObjectDetail( cFCODatabaseFile& rd, TOSTREAM* pOut )
|
|
{
|
|
OutputSectionDelimiter( tw::STR_OBJECT_DETAIL, pOut );
|
|
|
|
cFCODatabaseFileIter genreIter(rd);
|
|
for (genreIter.SeekBegin(); !genreIter.Done(); genreIter.Next())
|
|
{
|
|
cGenreSwitcher::GetInstance()->SelectGenre( (cGenre::Genre) genreIter.GetGenre() );
|
|
iFCONameTranslator* pNT = iTWFactory::GetInstance()->GetNameTranslator();
|
|
|
|
OutputGenreDelimiter( (cGenre::Genre) genreIter.GetGenre(), pOut );
|
|
|
|
OutputObjectDetail( genreIter, pNT, pOut );
|
|
}
|
|
}
|
|
|
|
|
|
void OutputObjectDetail( cFCODatabaseFileIter& genreIter, const iFCONameTranslator* pNT, TOSTREAM* pOut )
|
|
{
|
|
const cDbDataSourceIter dbIterDetails(&genreIter.GetDb());
|
|
|
|
OutputIterPeers( dbIterDetails, genreIter.GetGenreHeader().GetPropDisplayer(), pNT, pOut, true);
|
|
(*pOut) << endl;
|
|
}
|
|
|
|
|
|
/*
|
|
static void OutputDetailHeader( const cFCODbSpecIter &dbi, int nObjects, TOSTREAM* pOut )
|
|
{
|
|
(*pOut) << g_sz79Dashes << _T( "\n" );
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_FILE_DETAIL ) << endl;
|
|
|
|
TOSTRINGSTREAM ostr2;
|
|
ostr2 << TSS_GetString( cTW, tw::STR_RULE_NAME ) << _T(": ") << dbi.GetSpec()->GetName().c_str();
|
|
ostr2 << _T( " (" ) << dbi.GetSpec()->GetStartPoint().AsString().c_str() << _T( ")" ) << endl;
|
|
(*pOut) << ostr2.str().c_str();
|
|
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_TOTAL_NUM_FILES ) << _T(" ") << nObjects << endl;
|
|
|
|
(*pOut) << g_sz79Dashes << endl << endl;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static void OutputSpecHeader( const cFCODbSpecIter &dbi, TOSTREAM* pOut )
|
|
{
|
|
(*pOut) << g_sz79Dashes << _T( "\n" );
|
|
|
|
TOSTRINGSTREAM ostr2;
|
|
ostr2 << TSS_GetString( cTW, tw::STR_RULE_NAME ) << _T(": ") << dbi.GetSpec()->GetName().c_str();
|
|
ostr2 << _T( " (" ) << dbi.GetSpec()->GetStartPoint().AsString().c_str() << _T( ")" ) << endl;
|
|
(*pOut) << ostr2.str().c_str();
|
|
|
|
(*pOut) << g_sz79Dashes << _T( "\n" );
|
|
}
|
|
*/
|
|
|
|
|
|
void DisplayFCOProps( const iFCO* const pFCO, const iFCOPropDisplayer* pPD, TOSTREAM* pOut )
|
|
{
|
|
ASSERT( pOut != 0);
|
|
ASSERT( pFCO != 0);
|
|
|
|
const int attrNameWidth = 24;
|
|
const int attrValueWidth = 28;
|
|
|
|
// output header
|
|
// TODO: make these constants into enums
|
|
(*pOut).width( attrNameWidth );
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_ATTRIBUTES );
|
|
(*pOut).width( attrValueWidth );
|
|
(*pOut) << TSS_GetString( cTW, tw::STR_ATTR_VALUE );
|
|
(*pOut) << endl;
|
|
|
|
(*pOut).width( attrNameWidth );
|
|
(*pOut) << _T("-------------");
|
|
(*pOut).width( attrValueWidth );
|
|
(*pOut) << _T("-----------");
|
|
(*pOut) << endl;
|
|
|
|
int iNumProps = pFCO->GetPropSet()->GetNumProps();
|
|
for( int j = 0; j < iNumProps; j++ )
|
|
{
|
|
// output if prop is in FCO, and prop is not cFCOUndefinedProp
|
|
if(
|
|
pFCO->GetPropSet()->GetValidVector().ContainsItem( j )
|
|
&&
|
|
pFCO->GetPropSet()->GetPropAt( j )->GetType() != cFCOUndefinedProp::GetInstance()->GetType()
|
|
)
|
|
{
|
|
TSTRING strProp;
|
|
|
|
// output property name
|
|
(*pOut).width( attrNameWidth );
|
|
(*pOut) << pFCO->GetPropSet()->GetPropName(j);
|
|
(*pOut).width( attrValueWidth );
|
|
(*pOut) << pPD->PropAsString( pFCO, j, attrNameWidth, 0 );
|
|
(*pOut) << _T("\n");
|
|
}
|
|
}
|
|
}
|
|
|