/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts 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 . */ // WDTView.cpp : implementation file // #include "stdafx.h" #include "wdump.h" #include "WDTView.h" #include "wdumpdoc.h" #include "chunk_d.h" #include "finddialog.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CWDumpTreeView IMPLEMENT_DYNCREATE(CWDumpTreeView, CTreeView) CWDumpTreeView::CWDumpTreeView() { } CWDumpTreeView::~CWDumpTreeView() { } BEGIN_MESSAGE_MAP(CWDumpTreeView, CTreeView) //{{AFX_MSG_MAP(CWDumpTreeView) ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged) ON_COMMAND(IDM_TOOLS_FIND, OnToolsFind) ON_COMMAND(IDM_TOOLS_FIND_NEXT, OnToolsFindNext) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CWDumpTreeView drawing void CWDumpTreeView::OnDraw(CDC* pDC) { CDocument* pDoc = GetDocument(); // TODO: add draw code here } ///////////////////////////////////////////////////////////////////////////// // CWDumpTreeView diagnostics #ifdef _DEBUG void CWDumpTreeView::AssertValid() const { CTreeView::AssertValid(); } void CWDumpTreeView::Dump(CDumpContext& dc) const { CTreeView::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CWDumpTreeView message handlers void CWDumpTreeView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) { // add all the chunk items to the view CTreeCtrl &tree = GetTreeCtrl(); tree.DeleteAllItems(); long flags = tree.GetStyle(); flags |= TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS | TVS_DISABLEDRAGDROP; SetWindowLong(tree.GetSafeHwnd(), GWL_STYLE, flags); CWdumpDoc *doc= (CWdumpDoc *) GetDocument(); ChunkData *data = &doc->m_ChunkData; POSITION p = data->Chunks.GetHeadPosition(); while(p) { ChunkItem *item = data->Chunks.GetNext(p); InsertItem(item); } } void CWDumpTreeView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; CWdumpDoc *doc= (CWdumpDoc *) GetDocument(); doc->m_ChunkItem = (ChunkItem *) pNMTreeView->itemNew.lParam; doc->UpdateAllViews(this); *pResult = 0; } void CWDumpTreeView::InsertItem(ChunkItem * item, HTREEITEM Parent) { const char *name; if(item->Type) name = item->Type->Name; else { static char _buf[256]; sprintf(_buf,"Unknown: id=0x%X",item->ID); name = _buf; } CTreeCtrl &tree = GetTreeCtrl(); HTREEITEM tree_item = tree.InsertItem(name, Parent); tree.SetItem(tree_item, TVIF_PARAM,0,0,0,0,0, (long) item); POSITION p = item->Chunks.GetHeadPosition(); while(p != 0) { ChunkItem *subitem = item->Chunks.GetNext(p); InsertItem(subitem, tree_item); } } void CWDumpTreeView::OnToolsFind() { FindDialog finder; if (finder.DoModal() == IDOK) { // If there is a string go find it. if (strlen (FindDialog::String()) > 0) { OnToolsFindNext(); } } } void CWDumpTreeView::OnToolsFindNext() { ChunkItem *matchedchunkitem; // If no string go request one. if (strlen (FindDialog::String()) == 0) { OnToolsFind(); } else { FindDialog::Found (false); // Iterate over all chunks in the hierarchy. If a match is found select the tree // item that corresponds to the matched chunk item. { CWaitCursor waitcursor; HTREEITEM selectedtreeitem; ChunkItem *selectedchunkitem; SearchStateEnum searchstate; CWdumpDoc *doc = (CWdumpDoc *) GetDocument(); ChunkData *data = &doc->m_ChunkData; POSITION p; // Get the currently selected chunk item. selectedtreeitem = GetTreeCtrl().GetSelectedItem(); if (selectedtreeitem != NULL) { selectedchunkitem = (ChunkItem*) GetTreeCtrl().GetItemData (selectedtreeitem); searchstate = FIND_SELECTED_ITEM; } else { selectedchunkitem = NULL; searchstate = FIND_STRING; } p = 0; matchedchunkitem = NULL; while (true) { ChunkItem *chunkitem; // Get the root chunk item. if (p == 0) { p = data->Chunks.GetHeadPosition(); if (p == 0) break; } chunkitem = data->Chunks.GetNext (p); matchedchunkitem = FindChunkItem (selectedchunkitem, chunkitem, searchstate); if ((matchedchunkitem != NULL) || (searchstate == SEARCH_WRAPPED)) break; } } // Was a match found? if (matchedchunkitem != NULL) { SelectTreeItem (GetTreeCtrl().GetRootItem(), matchedchunkitem); } else { const char *controlstring = "Cannot find \"%s\"."; char *message; message = new char [strlen (controlstring) + strlen (FindDialog::String())]; ASSERT (message != NULL); sprintf (message, controlstring, FindDialog::String()); MessageBox (message, "Find String", MB_OK | MB_ICONEXCLAMATION); delete [] message; } } } ChunkItem *CWDumpTreeView::FindChunkItem (ChunkItem *selectedchunkitem, ChunkItem *chunkitem, SearchStateEnum &searchstate) { // Searching for the currently selected item or looking for a match? switch (searchstate) { case FIND_SELECTED_ITEM: // Searching for the currently selected chunk item. if (chunkitem == selectedchunkitem) { searchstate = FIND_STRING; } break; case FIND_STRING: // Searching for a string associated with the chunk item. if (chunkitem == selectedchunkitem) { searchstate = SEARCH_WRAPPED; return (NULL); } else { if ((chunkitem != 0) && (chunkitem->Type != 0) && (chunkitem->Type->Callback != 0)) { (*chunkitem->Type->Callback)(chunkitem, NULL); } if (FindDialog::Found()) return (chunkitem); } break; case SEARCH_WRAPPED: // This case should never occur at this point. As soon as it has been detected // that the search has wrapped the stack should unwind immediately. ASSERT (FALSE); return (NULL); break; } // Iterate over all chunks in the hierarchy. Return immediately if a match is found or if the search has wrapped. POSITION p = chunkitem->Chunks.GetHeadPosition(); while (p != 0) { ChunkItem *subchunkitem, *matchedchunkitem; subchunkitem = chunkitem->Chunks.GetNext (p); matchedchunkitem = FindChunkItem (selectedchunkitem, subchunkitem, searchstate); if ((matchedchunkitem != NULL) || (searchstate == SEARCH_WRAPPED)) return (matchedchunkitem); } // No match found. return (NULL); } void CWDumpTreeView::SelectTreeItem (HTREEITEM treeitem, ChunkItem *chunkitem) { CTreeCtrl &tree = GetTreeCtrl(); // Select a tree item that matches the given chunk item. Recurse if necessary. while (treeitem != NULL) { HTREEITEM subtreeitem; if (tree.GetItemData (treeitem) == (DWORD) chunkitem) { tree.SelectItem (treeitem); } subtreeitem = tree.GetChildItem (treeitem); if (subtreeitem != NULL) { SelectTreeItem (subtreeitem, chunkitem); } treeitem = tree.GetNextSiblingItem (treeitem); } }