/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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, see .
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "hsWindows.h"
#include "plResTreeView.h"
#include "../plResMgr/plResManager.h"
#include "../plResMgr/plRegistryHelpers.h"
#include "../plResMgr/plRegistryNode.h"
#include "../plResMgr/plPageInfo.h"
#include "../pnKeyedObject/plUoid.h"
#include "../pnKeyedObject/plKey.h"
#include "../pnKeyedObject/plKeyImp.h"
#include "../pnFactory/plFactory.h"
#include
#include
#include
#include "res\resource.h"
extern HINSTANCE gInstance;
HWND plResTreeView::fInfoDlg = nil;
bool plResTreeView::fFilter = false;
static char gSearchString[ 512 ];
static HTREEITEM fFoundItem = nil;
extern void ViewPatchDetails( plKey &patchKey );
BOOL CALLBACK FindDialogProc( HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_INITDIALOG:
return true;
case WM_COMMAND:
if( LOWORD( wParam ) == IDOK )
{
GetDlgItemText( dlg, IDC_SEARCHSTRING, gSearchString, sizeof( gSearchString ) );
fFoundItem = nil;
EndDialog( dlg, IDOK );
}
else if( LOWORD( wParam ) == IDCANCEL )
EndDialog( dlg, IDCANCEL );
return -1;
}
return 0;
}
struct plKeyInfo
{
plKey fKey;
plRegistryPageNode *fPage;
plKeyInfo( plKey k, plRegistryPageNode *p ) : fKey( k ), fPage( p ) {}
};
// How's this for functionality?
class plResDlgLoader : public plRegistryPageIterator, public plRegistryKeyIterator
{
protected:
HWND fTree;
HTREEITEM fCurrItem, fCurrTypeItem;
UInt16 fCurrType;
bool fFilter;
plRegistryPageNode *fCurrPage;
HTREEITEM AddLeaf(HWND hTree, HTREEITEM hParent, const char *text, plKeyInfo *info )
{
TVITEM tvi = {0};
tvi.mask = TVIF_TEXT | TVIF_PARAM;
tvi.pszText = text ? (char*)text : "";
tvi.cchTextMax = text ? strlen(text) : 7;
tvi.lParam = (LPARAM)info;
TVINSERTSTRUCT tvins = {0};
tvins.item = tvi;
tvins.hParent = hParent;
tvins.hInsertAfter = TVI_SORT;
return TreeView_InsertItem(hTree, &tvins);
}
public:
plResDlgLoader( HWND hTree, bool filter )
{
fFilter = filter;
fTree = hTree;
((plResManager *)hsgResMgr::ResMgr())->IterateAllPages( this );
}
virtual hsBool EatPage( plRegistryPageNode *page )
{
char str[ 512 ];
fCurrPage = page;
const plPageInfo &info = page->GetPageInfo();
sprintf( str, "%s->%s", info.GetAge(), info.GetPage() );
fCurrItem = AddLeaf( fTree, NULL, str, new plKeyInfo( nil, fCurrPage ) );
fCurrType = (UInt16)-1;
page->LoadKeys();
page->IterateKeys( this );
return true;
}
virtual hsBool EatKey( const plKey& key )
{
if( fCurrType != key->GetUoid().GetClassType() )
{
fCurrType = key->GetUoid().GetClassType();
const char *className = plFactory::GetNameOfClass( fCurrType );
fCurrTypeItem = AddLeaf( fTree, fCurrItem, className != nil ? className : "", nil );
}
if( !fFilter )
AddLeaf( fTree, fCurrTypeItem, key->GetUoid().GetObjectName(), new plKeyInfo( key, fCurrPage ) );
return true;
}
};
void plResTreeView::FillTreeViewFromRegistry( HWND hWnd )
{
plResDlgLoader loader( hWnd, fFilter );
}
HTREEITEM IGetNextTreeItem( HWND tree, HTREEITEM item )
{
// First try child items of this one
HTREEITEM next = TreeView_GetChild( tree, item );
if( next == nil )
// If no child items, try next sibling
next = TreeView_GetNextSibling( tree, item );
if( next == nil )
{
// If no siblings, go up to the parent and keep searching until we find a parent with a sibling
next = item;
while( true )
{
next = TreeView_GetParent( tree, next );
if( next == nil )
{
// No parent; not found, so stop
break;
}
else if( TreeView_GetNextSibling( tree, next ) != nil )
{
next = TreeView_GetNextSibling( tree, next );
break;
}
}
}
return next;
}
void plResTreeView::FindNextObject( HWND tree )
{
if( fFoundItem == nil )
FindObject( tree );
else
{
fFoundItem = IGetNextTreeItem( tree, fFoundItem );
IFindNextObject( tree );
}
}
void plResTreeView::FindObject( HWND tree )
{
if( DialogBox( gInstance, MAKEINTRESOURCE( IDD_FINDOBJ ), tree, FindDialogProc ) == IDOK )
{
fFoundItem = TreeView_GetRoot( tree );
IFindNextObject( tree );
}
}
void plResTreeView::IFindNextObject( HWND tree )
{
while( fFoundItem != nil )
{
// Get the item
TVITEM itemInfo;
itemInfo.mask = TVIF_PARAM | TVIF_HANDLE;
itemInfo.hItem = fFoundItem;
TreeView_GetItem( tree, &itemInfo );
plKeyInfo *keyInfo = (plKeyInfo *)itemInfo.lParam;
if( keyInfo != nil && keyInfo->fKey != nil )
{
if( StrStrI( keyInfo->fKey->GetUoid().GetObjectName(), gSearchString ) != nil )
{
/// FOUND
TreeView_SelectItem( tree, fFoundItem );
return;
}
}
// Keep searching. First try child items of this one
fFoundItem = IGetNextTreeItem( tree, fFoundItem );
}
MessageBox( tree, "No objects found", "Find Object", MB_OK );
}
void IDeleteRecurse( HWND tree, HTREEITEM item )
{
while( item != nil )
{
HTREEITEM child = TreeView_GetChild( tree, item );
if( child != nil )
IDeleteRecurse( tree, child );
TVITEM itemInfo;
itemInfo.mask = TVIF_PARAM | TVIF_HANDLE;
itemInfo.hItem = item;
TreeView_GetItem( tree, &itemInfo );
plKeyInfo *keyInfo = (plKeyInfo *)itemInfo.lParam;
if( keyInfo != nil )
{
delete keyInfo;
itemInfo.lParam = 0;
TreeView_SetItem( tree, &itemInfo );
}
item = TreeView_GetNextSibling( tree, item );
}
}
void plResTreeView::ClearTreeView( HWND hWnd )
{
HTREEITEM root = TreeView_GetRoot( hWnd );
if( root != nil )
IDeleteRecurse( hWnd, root );
TreeView_DeleteAllItems( hWnd );
}
void plResTreeView::SelectionDblClicked( HWND treeCtrl )
{
HTREEITEM sel = TreeView_GetSelection( treeCtrl );
if( sel != nil )
{
TVITEM item;
item.mask = TVIF_PARAM | TVIF_HANDLE;
item.hItem = sel;
if( !TreeView_GetItem( treeCtrl, &item ) )
return;
}
}
void plResTreeView::FilterLoadables( bool filter, HWND treeCtrl )
{
fFilter = filter;
ClearTreeView( treeCtrl );
FillTreeViewFromRegistry( treeCtrl );
}
BOOL CALLBACK plResTreeView::InfoDlgProc( HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_INITDIALOG:
fInfoDlg = dlg;
break;
case WM_COMMAND:
return SendMessage( GetParent( dlg ), msg, wParam, lParam );
}
return 0;
}
void plResTreeView::VerifyCurrentPage( HWND treeCtrl )
{
HTREEITEM sel = TreeView_GetSelection( treeCtrl );
if( sel != nil )
{
TVITEM item;
item.mask = TVIF_PARAM | TVIF_HANDLE;
item.hItem = sel;
if( !TreeView_GetItem( treeCtrl, &item ) )
return;
plKeyInfo *info = (plKeyInfo *)item.lParam;
if( info != nil )
{
if( info->fPage != nil )
{
// TODO: FIXME
/*
/// HACK. Live with it
class plHackResManager : public plResManager
{
public:
plRegistry *GetRegistry( void ) { return IGetRegistry(); }
};
plRegistry *registry = ((plHackResManager *)hsgResMgr::ResMgr())->GetRegistry();
plRegistry::plPageCond result = registry->VerifyOnePage( info->fPage );
char msg[ 512 ];
if( result == plRegistry::kOK || result == plRegistry::kTooNew )
strcpy( msg, "Page verifies OK" );
else if( result == plRegistry::kChecksumInvalid )
strcpy( msg, "Checksums for page are invalid" );
else if( result == plRegistry::kOutOfDate )
strcpy( msg, "Page is older than the current data version" );
hsMessageBox( msg, "Verification Results", hsMessageBoxNormal );
*/
}
}
}
}
void plResTreeView::UpdateInfoDlg( HWND treeCtrl )
{
hsBool showAsHex = (hsBool)IsDlgButtonChecked( fInfoDlg, IDC_SHOWASHEX );
SetDlgItemText( fInfoDlg, IDC_NAME, "" );
SetDlgItemText( fInfoDlg, IDC_CLASS, "" );
SetDlgItemText( fInfoDlg, IDC_LENGTH, "" );
SetDlgItemText( fInfoDlg, IDC_STARTPOS, "" );
EnableWindow( GetDlgItem( fInfoDlg, ID_FILE_VERIFYPAGE ), FALSE );
HTREEITEM sel = TreeView_GetSelection( treeCtrl );
if( sel != nil )
{
TVITEM item;
item.mask = TVIF_PARAM | TVIF_HANDLE;
item.hItem = sel;
if( !TreeView_GetItem( treeCtrl, &item ) )
return;
plKeyInfo *info = (plKeyInfo *)item.lParam;
if( info != nil )
{
if( info->fPage != nil )
{
const plPageInfo &pageInfo = info->fPage->GetPageInfo();
char tempStr[ 32 ];
SetDlgItemText( fInfoDlg, IDC_AGE, pageInfo.GetAge() );
SetDlgItemText( fInfoDlg, IDC_PAGE, pageInfo.GetPage() );
SetDlgItemText( fInfoDlg, IDC_LOCATION, pageInfo.GetLocation().StringIze( tempStr ) );
CheckDlgButton(fInfoDlg, IDC_RESERVED, (pageInfo.GetLocation().GetFlags() & plLocation::kReserved) ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(fInfoDlg, IDC_BUILTIN, (pageInfo.GetLocation().GetFlags() & plLocation::kBuiltIn) ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(fInfoDlg, IDC_VOLATILE, (pageInfo.GetLocation().GetFlags() & plLocation::kVolatile) ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(fInfoDlg, IDC_LOCAL_ONLY, (pageInfo.GetLocation().GetFlags() & plLocation::kLocalOnly) ? BST_CHECKED : BST_UNCHECKED);
sprintf( tempStr, "%d", pageInfo.GetMajorVersion());
SetDlgItemText( fInfoDlg, IDC_DATAVERSION, tempStr );
SetDlgItemText( fInfoDlg, IDC_CHECKSUMTYPE, "Basic (file size)" );
EnableWindow( GetDlgItem( fInfoDlg, ID_FILE_VERIFYPAGE ), TRUE );
}
if( info->fKey != nil )
{
char str[ 128 ];
SetDlgItemText( fInfoDlg, IDC_NAME, info->fKey->GetUoid().GetObjectName() );
const char *name = plFactory::GetNameOfClass( info->fKey->GetUoid().GetClassType() );
sprintf( str, "%s (%d)", name != nil ? name : "", info->fKey->GetUoid().GetClassType() );
SetDlgItemText( fInfoDlg, IDC_CLASS, str );
plKeyImp *imp = (plKeyImp *)info->fKey;
EnableWindow( GetDlgItem( fInfoDlg, IDC_STARTPOS_LABEL ), true );
EnableWindow( GetDlgItem( fInfoDlg, IDC_SIZE_LABEL ), true );
if( showAsHex )
sprintf( str, "0x%X", imp->GetStartPos() );
else
sprintf( str, "%d", imp->GetStartPos() );
SetDlgItemText( fInfoDlg, IDC_STARTPOS, str );
if( imp->GetDataLen() < 1024 )
sprintf( str, "%d bytes", imp->GetDataLen() );
else if( imp->GetDataLen() < 1024 * 1024 )
sprintf( str, "%4.2f kB", imp->GetDataLen() / 1024.f );
else
sprintf( str, "%4.2f MB", imp->GetDataLen() / 1024.f / 1024.f );
SetDlgItemText( fInfoDlg, IDC_LENGTH, str );
}
}
}
}
#include "hsStream.h"
#include
void plResTreeView::SaveSelectedObject(HWND treeCtrl)
{
// TODO: FIXME
/*
plKey itemKey = nil;
HTREEITEM sel = TreeView_GetSelection(treeCtrl);
if (sel != nil)
{
TVITEM item;
item.mask = TVIF_PARAM | TVIF_HANDLE;
item.hItem = sel;
if (TreeView_GetItem(treeCtrl, &item))
{
plKeyInfo *info = (plKeyInfo*)item.lParam;
if (info != nil)
itemKey = info->fKey;
}
}
if (!itemKey)
return;
char fileName[MAX_PATH];
sprintf(fileName, "%s.bin", itemKey->GetName());
OPENFILENAME openInfo;
memset( &openInfo, 0, sizeof( OPENFILENAME ) );
// openInfo.hInstance = gInstance;
// openInfo.hwndOwner = hWnd;
openInfo.lStructSize = sizeof( OPENFILENAME );
openInfo.lpstrFile = fileName;
openInfo.nMaxFile = sizeof( fileName );
openInfo.lpstrFilter = "Binary Files\0*.bin\0All Files\0*.*\0";
// openInfo.lpstrTitle = "Choose a pack index file to browse:";
// openInfo.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
if (GetSaveFileName(&openInfo))
{
plKeyImp* keyImp = (plKeyImp*)itemKey;
if (keyImp->GetDataLen() <= 0)
return;
plResManager* resMgr = (plResManager*)hsgResMgr::ResMgr();
const plPageInfo& pageInfo = resMgr->FindPage(keyImp->GetUoid().GetLocation())->GetPageInfo();
plRegistryDataStream *stream = registry->OpenPageDataStream( keyImp->GetUoid().GetLocation(), false );
if( stream == nil )
return;
hsStream *dataStream = stream->GetStream();
UInt8 *buffer = TRACKED_NEW UInt8[ keyImp->GetDataLen() ];
if( buffer != nil )
{
dataStream->SetPosition( keyImp->GetStartPos() );
dataStream->Read( keyImp->GetDataLen(), buffer );
}
delete stream;
if( buffer == nil )
return;
hsUNIXStream outStream;
outStream.Open(fileName, "wb");
outStream.Write(keyImp->GetDataLen(), buffer);
outStream.Close();
delete [] buffer;
}
*/
}