/*==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->%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; } */ }