|
|
|
/*==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 <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
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 <windows.h>
|
|
|
|
#include <commctrl.h>
|
|
|
|
#include <shlwapi.h>
|
|
|
|
#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 : "<NULL>";
|
|
|
|
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 : "<unknown>", 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 : "<unknown>", 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 <commdlg.h>
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|