2017-09-21 18:33:05 +08:00
using CodeWalker.Forms ;
using CodeWalker.GameFiles ;
using CodeWalker.Properties ;
using CodeWalker.World ;
using System ;
using System.Collections.Generic ;
using System.ComponentModel ;
using System.Data ;
using System.Diagnostics ;
using System.Drawing ;
using System.IO ;
using System.Linq ;
using System.Text ;
using System.Threading ;
using System.Threading.Tasks ;
using System.Windows.Forms ;
2018-01-10 12:55:19 +08:00
using System.Xml ;
2018-03-04 00:09:39 +08:00
using WeifenLuo.WinFormsUI.Docking ;
2017-09-21 18:33:05 +08:00
namespace CodeWalker
{
public partial class ExploreForm : Form
{
private volatile bool Ready = false ;
private Dictionary < string , FileTypeInfo > FileTypes ;
private MainTreeFolder RootFolder ;
private MainTreeFolder CurrentFolder ;
private List < MainListItem > CurrentFiles ;
private Stack < MainTreeFolder > BackSteps = new Stack < MainTreeFolder > ( ) ;
private Stack < MainTreeFolder > ForwardSteps = new Stack < MainTreeFolder > ( ) ;
private bool HistoryNavigating = false ;
private int SortColumnIndex = 0 ;
private SortOrder SortDirection = SortOrder . Ascending ;
private int PreviousPathColumnWidth = 0 ;
public volatile bool Searching = false ;
private MainTreeFolder SearchResults ;
private List < RpfFile > AllRpfs { get ; set ; }
2018-02-24 21:59:00 +08:00
private GameFileCache FileCache { get ; set ; } = GameFileCacheFactory . Create ( ) ;
2017-09-21 18:33:05 +08:00
private object FileCacheSyncRoot = new object ( ) ;
2018-12-14 18:23:05 +08:00
public bool EditMode { get ; private set ; } = false ;
2017-09-21 18:33:05 +08:00
2018-03-04 00:09:39 +08:00
public ThemeBase Theme { get ; private set ; }
2017-09-21 18:33:05 +08:00
public ExploreForm ( )
{
InitializeComponent ( ) ;
2018-03-04 00:09:39 +08:00
SetTheme ( Settings . Default . ExplorerWindowTheme , false ) ;
2017-09-21 18:33:05 +08:00
ShowMainListViewPathColumn ( false ) ;
}
2018-03-04 00:09:39 +08:00
private void SetTheme ( string themestr , bool changing = true )
{
//string configFile = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "DockPanel.temp.config");
//MainDockPanel.SaveAsXml(configFile);
//CloseAllContents();
foreach ( ToolStripMenuItem menu in ViewThemeMenu . DropDownItems )
{
menu . Checked = false ;
}
Theme = null ;
var version = VisualStudioToolStripExtender . VsVersion . Vs2015 ;
switch ( themestr )
{
default :
case "Windows" :
//Theme = new VS2005Theme();
ViewThemeWindowsMenu . Checked = true ;
version = VisualStudioToolStripExtender . VsVersion . Unknown ;
if ( changing )
{
MessageBox . Show ( "Please reopen RPF Explorer to change back to Windows theme." ) ;
}
break ;
case "Blue" :
Theme = new VS2015BlueTheme ( ) ;
ViewThemeBlueMenu . Checked = true ;
break ;
case "Light" :
Theme = new VS2015LightTheme ( ) ;
ViewThemeLightMenu . Checked = true ;
break ;
case "Dark" :
Theme = new VS2015DarkTheme ( ) ;
ViewThemeDarkMenu . Checked = true ;
break ;
}
if ( changing )
{
Settings . Default . ExplorerWindowTheme = themestr ;
Settings . Default . Save ( ) ;
}
//Theme.Extender.FloatWindowFactory = new ExplorerFloatWindowFactory();
//MainDockPanel.Theme = Theme;
if ( Theme ! = null )
{
VSExtender . SetStyle ( MainMenu , version , Theme ) ;
VSExtender . SetStyle ( MainToolbar , version , Theme ) ;
VSExtender . SetStyle ( MainStatusBar , version , Theme ) ;
FormTheme . SetTheme ( this , Theme ) ;
MainSplitContainer . BackColor = Theme . ColorPalette . MainWindowActive . Background ;
}
//if (File.Exists(configFile)) MainDockPanel.LoadFromXml(configFile, m_deserializeDockContent);
}
2017-09-21 18:33:05 +08:00
private void Init ( )
{
//called from ExploreForm_Load
InitFileTypes ( ) ;
2018-02-21 16:27:01 +08:00
// This is probably not necessary now that the GTA folder is checked
// in the Program.cs when the game is initiated, but we will leave it
// here for now to make sure
2018-02-18 09:26:35 +08:00
if ( ! GTAFolder . UpdateGTAFolder ( true ) )
2017-09-21 18:33:05 +08:00
{
Close ( ) ;
return ;
}
Task . Run ( ( ) = >
{
try
{
2018-02-24 21:59:00 +08:00
GTA5Keys . LoadFromPath ( GTAFolder . CurrentGTAFolder , Settings . Default . Key ) ;
2017-09-21 18:33:05 +08:00
}
catch
{
UpdateStatus ( "Unable to load gta5.exe!" ) ;
return ;
}
UpdateStatus ( "Scanning..." ) ;
RefreshMainTreeView ( ) ;
UpdateStatus ( "Scan complete." ) ;
InitFileCache ( ) ;
while ( ! IsDisposed ) //run the file cache content thread until the form exits.
{
if ( FileCache . IsInited )
{
2018-01-02 04:52:54 +08:00
bool fcItemsPending = FileCache . ContentThreadProc ( ) ;
2017-09-21 18:33:05 +08:00
2018-01-02 04:52:54 +08:00
if ( ! fcItemsPending )
2017-09-21 18:33:05 +08:00
{
Thread . Sleep ( 10 ) ;
}
}
else
{
Thread . Sleep ( 20 ) ;
}
}
} ) ;
}
private void InitFileCache ( )
{
Task . Run ( ( ) = >
{
lock ( FileCacheSyncRoot )
{
if ( ! FileCache . IsInited )
{
UpdateStatus ( "Loading file cache..." ) ;
var allRpfs = AllRpfs ;
FileCache . Init ( UpdateStatus , UpdateErrorLog , allRpfs ) ; //inits main dicts and archetypes only...
UpdateStatus ( "Loading materials..." ) ;
BoundsMaterialTypes . Init ( FileCache ) ;
UpdateStatus ( "Loading scenario types..." ) ;
Scenarios . EnsureScenarioTypes ( FileCache ) ;
UpdateStatus ( "File cache loaded." ) ;
}
}
} ) ;
}
public GameFileCache GetFileCache ( )
{
lock ( FileCacheSyncRoot )
{
if ( FileCache . IsInited ) return FileCache ;
}
InitFileCache ( ) ; //if we got here, it's not inited yet - init it!
return FileCache ; //return it even though it's probably not inited yet..
}
private void InitFileTypes ( )
{
FileTypes = new Dictionary < string , FileTypeInfo > ( ) ;
InitFileType ( ".rpf" , "Rage Package File" , 3 ) ;
InitFileType ( "" , "File" , 4 ) ;
InitFileType ( ".dat" , "Data File" , 4 ) ;
InitFileType ( ".cab" , "CAB File" , 4 ) ;
InitFileType ( ".txt" , "Text File" , 5 , FileTypeAction . ViewText ) ;
InitFileType ( ".gxt2" , "Global Text Table" , 5 , FileTypeAction . ViewGxt ) ;
InitFileType ( ".log" , "LOG File" , 5 , FileTypeAction . ViewText ) ;
InitFileType ( ".ini" , "Config Text" , 5 , FileTypeAction . ViewText ) ;
InitFileType ( ".vdf" , "Steam Script File" , 5 , FileTypeAction . ViewText ) ;
InitFileType ( ".sps" , "Shader Preset" , 5 , FileTypeAction . ViewText ) ;
InitFileType ( ".xml" , "XML File" , 6 , FileTypeAction . ViewXml ) ;
InitFileType ( ".meta" , "Metadata (XML)" , 6 , FileTypeAction . ViewXml ) ;
InitFileType ( ".ymt" , "Metadata (Binary)" , 6 , FileTypeAction . ViewYmt ) ;
InitFileType ( ".pso" , "Metadata (PSO)" , 6 , FileTypeAction . ViewJPso ) ;
InitFileType ( ".gfx" , "Scaleform Flash" , 7 ) ;
2019-11-01 17:30:29 +08:00
InitFileType ( ".ynd" , "Path Nodes" , 8 , FileTypeAction . ViewYnd ) ;
2017-09-21 18:33:05 +08:00
InitFileType ( ".ynv" , "Nav Mesh" , 9 , FileTypeAction . ViewModel ) ;
InitFileType ( ".yvr" , "Vehicle Record" , 9 , FileTypeAction . ViewYvr ) ;
InitFileType ( ".ywr" , "Waypoint Record" , 9 , FileTypeAction . ViewYwr ) ;
InitFileType ( ".fxc" , "Compiled Shaders" , 9 , FileTypeAction . ViewFxc ) ;
2019-11-21 21:34:27 +08:00
InitFileType ( ".yed" , "Expression Dictionary" , 9 , FileTypeAction . ViewYed ) ;
InitFileType ( ".yld" , "Cloth Dictionary" , 9 , FileTypeAction . ViewYld ) ;
InitFileType ( ".yfd" , "Frame Filter Dictionary" , 9 , FileTypeAction . ViewYfd ) ;
2017-09-21 18:33:05 +08:00
InitFileType ( ".asi" , "ASI Plugin" , 9 ) ;
InitFileType ( ".dll" , "Dynamic Link Library" , 9 ) ;
InitFileType ( ".exe" , "Executable" , 10 ) ;
InitFileType ( ".yft" , "Fragment" , 11 , FileTypeAction . ViewModel ) ;
InitFileType ( ".ydr" , "Drawable" , 11 , FileTypeAction . ViewModel ) ;
InitFileType ( ".ydd" , "Drawable Dictionary" , 12 , FileTypeAction . ViewModel ) ;
InitFileType ( ".cut" , "Cutscene" , 12 , FileTypeAction . ViewCut ) ;
InitFileType ( ".ysc" , "Script" , 13 ) ;
InitFileType ( ".ymf" , "Manifest" , 14 , FileTypeAction . ViewYmf ) ;
InitFileType ( ".bik" , "Bink Video" , 15 ) ;
InitFileType ( ".jpg" , "JPEG Image" , 16 ) ;
InitFileType ( ".jpeg" , "JPEG Image" , 16 ) ;
InitFileType ( ".gif" , "GIF Image" , 16 ) ;
InitFileType ( ".png" , "Portable Network Graphics" , 16 ) ;
InitFileType ( ".dds" , "DirectDraw Surface" , 16 ) ;
InitFileType ( ".ytd" , "Texture Dictionary" , 16 , FileTypeAction . ViewYtd ) ;
InitFileType ( ".mrf" , "MRF File" , 18 ) ;
2017-09-29 20:23:37 +08:00
InitFileType ( ".ycd" , "Clip Dictionary" , 18 , FileTypeAction . ViewYcd ) ;
2017-09-21 18:33:05 +08:00
InitFileType ( ".ypt" , "Particle Effect" , 18 , FileTypeAction . ViewModel ) ;
InitFileType ( ".ybn" , "Static Collisions" , 19 , FileTypeAction . ViewModel ) ;
InitFileType ( ".ide" , "Item Definitions" , 20 , FileTypeAction . ViewText ) ;
InitFileType ( ".ytyp" , "Archetype Definitions" , 20 , FileTypeAction . ViewYtyp ) ;
InitFileType ( ".ymap" , "Map Data" , 21 , FileTypeAction . ViewYmap ) ;
InitFileType ( ".ipl" , "Item Placements" , 21 , FileTypeAction . ViewText ) ;
InitFileType ( ".awc" , "Audio Wave Container" , 22 , FileTypeAction . ViewAwc ) ;
InitFileType ( ".rel" , "Audio Data (REL)" , 23 , FileTypeAction . ViewRel ) ;
2017-12-14 18:49:41 +08:00
InitSubFileType ( ".dat" , "cache_y.dat" , "Cache File" , 6 , FileTypeAction . ViewCacheDat ) ;
2017-09-21 18:33:05 +08:00
}
private void InitFileType ( string ext , string name , int imgidx , FileTypeAction defaultAction = FileTypeAction . ViewHex )
{
var ft = new FileTypeInfo ( ext , name , imgidx , defaultAction ) ;
FileTypes [ ext ] = ft ;
}
2017-12-14 18:49:41 +08:00
private void InitSubFileType ( string ext , string subext , string name , int imgidx , FileTypeAction defaultAction = FileTypeAction . ViewHex )
{
FileTypeInfo pti = null ;
if ( FileTypes . TryGetValue ( ext , out pti ) )
{
var ft = new FileTypeInfo ( subext , name , imgidx , defaultAction ) ;
pti . AddSubType ( ft ) ;
}
}
2017-09-21 18:33:05 +08:00
public FileTypeInfo GetFileType ( string fn )
{
var fi = new FileInfo ( fn ) ;
2017-12-14 18:49:41 +08:00
var ext = fi . Extension . ToLowerInvariant ( ) ;
2017-09-21 18:33:05 +08:00
if ( ! string . IsNullOrEmpty ( ext ) )
{
FileTypeInfo ft ;
if ( FileTypes . TryGetValue ( ext , out ft ) )
{
2017-12-14 18:49:41 +08:00
if ( ft . SubTypes ! = null )
{
var fnl = fn . ToLowerInvariant ( ) ;
foreach ( var sft in ft . SubTypes )
{
if ( fnl . EndsWith ( sft . Extension ) )
{
return sft ;
}
}
}
2017-09-21 18:33:05 +08:00
return ft ;
}
else
{
ft = new FileTypeInfo ( ext , ext . Substring ( 1 ) . ToUpperInvariant ( ) + " File" , 4 , FileTypeAction . ViewHex ) ;
FileTypes [ ft . Extension ] = ft ; //save it for later!
return ft ;
}
}
else
{
return FileTypes [ "" ] ;
}
}
2018-02-18 17:20:39 +08:00
2017-09-21 18:33:05 +08:00
public void UpdateStatus ( string text )
{
try
{
if ( InvokeRequired )
{
BeginInvoke ( new Action ( ( ) = > { UpdateStatus ( text ) ; } ) ) ;
}
else
{
StatusLabel . Text = text ;
}
}
catch { }
}
public void UpdateErrorLog ( string text )
{
try
{
if ( InvokeRequired )
{
BeginInvoke ( new Action ( ( ) = > { UpdateErrorLog ( text ) ; } ) ) ;
}
else
{
//StatusLabel.Text = text;
}
}
catch { }
}
public void Navigate ( MainTreeFolder f )
{
if ( ! Ready ) return ;
if ( f = = CurrentFolder ) return ; //already there!
if ( f . IsSearchResults )
{
2018-02-27 16:25:39 +08:00
AddMainTreeViewRoot ( f ) ; //add the current search result node
TreeNode sr = FindTreeNode ( f , null ) ;
if ( sr ! = null )
{
MainTreeView . SelectedNode = sr ; //navigate to the new search results node
}
2017-09-21 18:33:05 +08:00
foreach ( TreeNode tn in MainTreeView . Nodes )
{
var tnf = tn . Tag as MainTreeFolder ;
2018-02-27 16:25:39 +08:00
if ( ( tn ! = sr ) & & ( tnf ! = null ) & & ( tnf . IsSearchResults ) )
2017-09-21 18:33:05 +08:00
{
MainTreeView . Nodes . Remove ( tn ) ; //remove existing search result node
break ;
}
}
return ;
}
List < MainTreeFolder > hierarchy = new List < MainTreeFolder > ( ) ;
var pf = f ;
while ( pf ! = null )
{
hierarchy . Add ( pf ) ;
pf = pf . Parent ;
}
TreeNode n = null ;
for ( int i = hierarchy . Count - 1 ; i > = 0 ; i - - )
{
n = FindTreeNode ( hierarchy [ i ] , n ) ;
}
if ( n ! = null )
{
if ( MainTreeView . SelectedNode ! = n )
{
MainTreeView . SelectedNode = n ; //this will trigger everything else
}
}
else
{
Navigate ( f . Path ) ; //try again using the path string...
//NavigateFailed(f.Path); //unable to navigate...
}
}
public void Navigate ( string path )
{
if ( ! Ready ) return ;
var pathl = path . ToLowerInvariant ( ) . Replace ( '/' , '\\' ) ;
if ( ( CurrentFolder ! = null ) & & ( CurrentFolder . Path . ToLowerInvariant ( ) = = pathl ) ) return ; //already there
var hierarchy = pathl . Split ( new [ ] { '\\' } , StringSplitOptions . RemoveEmptyEntries ) ;
TreeNode n = MainTreeView . Nodes [ 0 ] ; // FindTreeNode("gta v", null);
if ( ! string . IsNullOrEmpty ( path ) )
{
for ( int i = 0 ; i < hierarchy . Length ; i + + )
{
n = FindTreeNode ( hierarchy [ i ] , n ) ;
}
}
if ( n ! = null )
{
if ( MainTreeView . SelectedNode ! = n )
{
MainTreeView . SelectedNode = n ; //this will trigger everything else
}
}
else
{
NavigateFailed ( path ) ; //unable to navigate...
}
}
private void NavigateFailed ( string path )
{
MessageBox . Show ( "Unable to navigate to \"" + path + "\"." ) ;
}
private void NavigateComplete ( MainTreeFolder prevFolder )
{
//called after the CurrentFolder and CurrentFiles have changed.
UpdateNavigateUI ( ) ;
2018-01-11 12:03:58 +08:00
EnsureEditModeWarning ( ) ;
2017-09-21 18:33:05 +08:00
if ( ! HistoryNavigating ) //only do this if not currently navigating forward or back
{
if ( prevFolder ! = null )
{
ForwardSteps . Clear ( ) ;
BackSteps . Push ( prevFolder ) ;
}
UpdateHistoryUI ( ) ;
}
GoButton . Enabled = true ;
RefreshButton . Enabled = true ;
SearchButton . Enabled = true ;
2018-01-10 11:17:30 +08:00
EditModeButton . Enabled = true ;
2017-09-21 18:33:05 +08:00
}
public void GoUp ( MainTreeFolder toFolder = null )
{
var fld = ( toFolder = = null ) ? CurrentFolder ? . Parent : toFolder ;
if ( fld = = null ) return ;
Navigate ( fld ) ;
}
public void GoBack ( MainTreeFolder toFolder = null )
{
if ( BackSteps . Count = = 0 ) return ;
var s = BackSteps . Pop ( ) ;
ForwardSteps . Push ( CurrentFolder ) ;
while ( ( toFolder ! = null ) & & ( s ! = toFolder ) & & ( BackSteps . Count > 0 ) )
{
ForwardSteps . Push ( s ) ;
s = BackSteps . Pop ( ) ;
}
HistoryNavigating = true ;
Navigate ( s ) ;
HistoryNavigating = false ;
UpdateHistoryUI ( ) ;
}
public void GoForward ( MainTreeFolder toFolder = null )
{
if ( ForwardSteps . Count = = 0 ) return ;
var s = ForwardSteps . Pop ( ) ;
BackSteps . Push ( CurrentFolder ) ;
while ( ( toFolder ! = null ) & & ( s ! = toFolder ) & & ( ForwardSteps . Count > 0 ) )
{
BackSteps . Push ( s ) ;
s = ForwardSteps . Pop ( ) ;
}
HistoryNavigating = true ;
Navigate ( s ) ;
HistoryNavigating = false ;
UpdateHistoryUI ( ) ;
}
private void UpdateNavigateUI ( )
{
UpButton . DropDownItems . Clear ( ) ;
var pf = CurrentFolder ? . Parent ;
int i = 0 ;
while ( pf ! = null )
{
var button = UpButton . DropDownItems . Add ( pf . GetToolText ( ) ) ;
button . Tag = pf ;
button . Click + = UpListButton_Click ;
pf = pf . Parent ;
if ( i > = 10 ) break ;
}
UpButton . Enabled = ( UpButton . DropDownItems . Count > 0 ) ;
}
private void UpdateHistoryUI ( )
{
BackButton . DropDownItems . Clear ( ) ;
ForwardButton . DropDownItems . Clear ( ) ;
int i = 0 ;
foreach ( var step in BackSteps )
{
var button = BackButton . DropDownItems . Add ( step . GetToolText ( ) ) ;
button . Tag = step ;
button . Click + = BackListButton_Click ;
i + + ;
if ( i > = 10 ) break ;
}
i = 0 ;
foreach ( var step in ForwardSteps )
{
var button = ForwardButton . DropDownItems . Add ( step . GetToolText ( ) ) ;
button . Tag = step ;
button . Click + = ForwardListButton_Click ;
i + + ;
if ( i > = 10 ) break ;
}
BackButton . Enabled = ( BackSteps . Count > 0 ) ;
ForwardButton . Enabled = ( ForwardSteps . Count > 0 ) ;
}
private void UpdateSelectionUI ( )
{
var ic = MainListView . VirtualListSize ;
var sc = MainListView . SelectedIndices . Count ;
var str = ic . ToString ( ) + " item" + ( ( ic ! = 1 ) ? "s" : "" ) + " shown" ;
bool isitem = false ;
bool isfile = false ;
2019-03-20 18:21:47 +08:00
bool issearch = CurrentFolder ? . IsSearchResults ? ? false ;
2017-09-21 18:33:05 +08:00
bool canview = false ;
bool canedit = false ;
bool canexportxml = false ;
2019-03-20 18:21:47 +08:00
bool canimport = EditMode & & ( CurrentFolder ? . RpfFolder ! = null ) & & ! issearch ;
2017-09-21 18:33:05 +08:00
if ( sc ! = 0 )
{
long bc = 0 ;
if ( CurrentFiles ! = null )
{
foreach ( int idx in MainListView . SelectedIndices )
{
if ( ( idx < 0 ) | | ( idx > = CurrentFiles . Count ) ) continue ;
var file = CurrentFiles [ idx ] ;
if ( ( file . Folder = = null ) | | ( file . Folder . RpfFile ! = null ) )
{
bc + = file . FileSize ;
}
isitem = true ;
isfile = isfile | | ( file . Folder = = null ) ;
canview = canview | | CanViewFile ( file ) ;
2017-11-25 13:01:56 +08:00
canexportxml = canexportxml | | CanExportXml ( file ) ;
2017-09-21 18:33:05 +08:00
}
}
str + = ", " + sc . ToString ( ) + " selected" ;
if ( bc > 0 )
{
str + = ", " + TextUtil . GetBytesReadable ( bc ) ;
}
}
UpdateStatus ( str ) ;
EditViewMenu . Enabled = canview ;
EditViewHexMenu . Enabled = isfile ;
EditExportXmlMenu . Enabled = canexportxml ;
EditExtractRawMenu . Enabled = isfile ;
EditImportRawMenu . Visible = canimport ;
2019-03-20 18:21:47 +08:00
EditImportFbxMenu . Visible = canimport ;
2017-09-21 18:33:05 +08:00
EditImportXmlMenu . Visible = canimport ;
EditImportMenuSeparator . Visible = canimport ;
EditCopyMenu . Enabled = isfile ;
EditCopyPathMenu . Enabled = isitem ;
EditRenameMenu . Visible = canedit ;
EditReplaceMenu . Visible = canedit ;
EditDeleteMenu . Visible = canedit ;
EditEditModeMenuSeparator . Visible = canedit ;
}
private TreeNode FindTreeNode ( MainTreeFolder f , TreeNode parent )
{
var tnc = ( parent ! = null ) ? parent . Nodes : MainTreeView . Nodes ;
foreach ( TreeNode node in tnc )
{
if ( node . Tag = = f )
{
return node ;
}
}
return null ;
}
private TreeNode FindTreeNode ( string text , TreeNode parent )
{
var tnc = ( parent ! = null ) ? parent . Nodes : MainTreeView . Nodes ;
foreach ( TreeNode node in tnc )
{
if ( node . Text . ToLowerInvariant ( ) = = text )
{
return node ;
}
}
return null ;
}
private void RefreshMainTreeView ( )
{
Ready = false ;
var allRpfs = new List < RpfFile > ( ) ;
ClearMainTreeView ( ) ;
2018-02-18 17:20:39 +08:00
string fullPath = GTAFolder . GetCurrentGTAFolderWithTrailingSlash ( ) ;
2017-09-21 18:33:05 +08:00
2018-02-27 16:59:14 +08:00
string [ ] allpaths = Directory . GetFileSystemEntries ( GTAFolder . CurrentGTAFolder , "*" , SearchOption . AllDirectories ) ;
2017-09-21 18:33:05 +08:00
Dictionary < string , MainTreeFolder > nodes = new Dictionary < string , MainTreeFolder > ( ) ;
MainTreeFolder root = new MainTreeFolder ( ) ;
2018-02-18 17:20:39 +08:00
root . FullPath = GTAFolder . GetCurrentGTAFolderWithTrailingSlash ( ) ;
2017-09-21 18:33:05 +08:00
root . Path = "" ;
root . Name = "GTA V" ;
RootFolder = root ;
UpdateStatus ( "Scanning..." ) ;
2018-02-27 16:59:14 +08:00
foreach ( var path in allpaths )
2017-09-21 18:33:05 +08:00
{
2018-02-27 16:59:14 +08:00
var relpath = path . Replace ( fullPath , "" ) ;
var filepathl = path . ToLowerInvariant ( ) ;
var isFile = File . Exists ( path ) ; //could be a folder
2017-09-21 18:33:05 +08:00
UpdateStatus ( "Scanning " + relpath + "..." ) ;
MainTreeFolder parentnode = null , prevnode = null , node = null ;
var prevnodepath = "" ;
2018-02-27 16:59:14 +08:00
var idx = isFile ? relpath . LastIndexOf ( '\\' ) : relpath . Length ;
2017-09-21 18:33:05 +08:00
while ( idx > 0 ) //create the folder tree nodes and build up the hierarchy
{
var parentpath = relpath . Substring ( 0 , idx ) ;
var parentidx = parentpath . LastIndexOf ( '\\' ) ;
var parentname = parentpath . Substring ( parentidx + 1 ) ;
var exists = nodes . TryGetValue ( parentpath , out node ) ;
if ( ! exists )
{
2018-02-18 17:20:39 +08:00
node = CreateRootDirTreeFolder ( parentname , parentpath , fullPath + parentpath ) ;
2017-09-21 18:33:05 +08:00
nodes [ parentpath ] = node ;
}
if ( parentnode = = null )
{
parentnode = node ;
}
if ( prevnode ! = null )
{
node . AddChild ( prevnode ) ;
}
prevnode = node ;
prevnodepath = parentpath ;
idx = relpath . LastIndexOf ( '\\' , idx - 1 ) ;
if ( exists ) break ;
if ( idx < 0 )
{
root . AddChild ( node ) ;
}
}
2018-02-27 16:59:14 +08:00
if ( isFile )
2017-09-21 18:33:05 +08:00
{
2018-02-27 16:59:14 +08:00
if ( filepathl . EndsWith ( ".rpf" ) ) //add RPF nodes
{
RpfFile rpf = new RpfFile ( path , relpath ) ;
2017-09-21 18:33:05 +08:00
2018-02-27 16:59:14 +08:00
rpf . ScanStructure ( UpdateStatus , UpdateErrorLog ) ;
2017-09-21 18:33:05 +08:00
2019-03-20 18:21:47 +08:00
if ( rpf . LastException ! = null ) //incase of corrupted rpf (or renamed NG encrypted RPF)
{
continue ;
}
2018-02-27 16:59:14 +08:00
node = CreateRpfTreeFolder ( rpf , relpath , path ) ;
2017-09-21 18:33:05 +08:00
2018-02-27 16:59:14 +08:00
RecurseMainTreeViewRPF ( node , allRpfs ) ;
2017-09-21 18:33:05 +08:00
2018-02-27 16:59:14 +08:00
if ( parentnode ! = null )
{
parentnode . AddChild ( node ) ;
}
else
{
root . AddChild ( node ) ;
}
2017-09-21 18:33:05 +08:00
}
else
{
2018-02-27 16:59:14 +08:00
if ( parentnode ! = null )
{
parentnode . AddFile ( path ) ;
}
else
{
root . AddFile ( path ) ;
}
2017-09-21 18:33:05 +08:00
}
}
}
AddMainTreeViewRoot ( root ) ;
if ( root . Children ! = null )
{
root . Children . Sort ( ( n1 , n2 ) = > n1 . Name . CompareTo ( n2 . Name ) ) ;
foreach ( var node in root . Children )
{
AddMainTreeViewNode ( node ) ;
}
}
AllRpfs = allRpfs ;
Ready = true ;
MainTreeViewRefreshComplete ( ) ;
}
private void RecurseMainTreeViewRPF ( MainTreeFolder f , List < RpfFile > allRpfs )
{
2018-02-18 17:20:39 +08:00
var rootpath = GTAFolder . GetCurrentGTAFolderWithTrailingSlash ( ) ;
2017-09-21 18:33:05 +08:00
var fld = f . RpfFolder ;
if ( fld ! = null )
{
if ( fld . Directories ! = null )
{
foreach ( var dir in fld . Directories )
{
2018-01-10 11:17:30 +08:00
var dtnf = CreateRpfDirTreeFolder ( dir , dir . Path , rootpath + dir . Path ) ;
2017-09-21 18:33:05 +08:00
f . AddChild ( dtnf ) ;
RecurseMainTreeViewRPF ( dtnf , allRpfs ) ;
}
}
}
var rpf = f . RpfFile ;
if ( rpf ! = null )
{
allRpfs . Add ( rpf ) ;
if ( rpf . Children ! = null )
{
foreach ( var child in rpf . Children )
{
2018-01-10 11:17:30 +08:00
var ctnf = CreateRpfTreeFolder ( child , child . Path , rootpath + child . Path ) ;
2017-09-21 18:33:05 +08:00
f . AddChildToHierarchy ( ctnf ) ;
RecurseMainTreeViewRPF ( ctnf , allRpfs ) ;
}
}
2018-01-10 11:17:30 +08:00
//JenkIndex.Ensure(rpf.Name);
2017-09-21 18:33:05 +08:00
if ( rpf . AllEntries ! = null )
{
foreach ( RpfEntry entry in rpf . AllEntries )
{
if ( string . IsNullOrEmpty ( entry . NameLower ) ) continue ;
2018-01-10 11:17:30 +08:00
var shortnamel = entry . GetShortNameLower ( ) ;
JenkIndex . Ensure ( shortnamel ) ;
entry . ShortNameHash = JenkHash . GenHash ( shortnamel ) ;
2017-09-21 18:33:05 +08:00
entry . NameHash = JenkHash . GenHash ( entry . NameLower ) ;
}
}
}
}
private void ClearMainTreeView ( )
{
try
{
if ( InvokeRequired )
{
Invoke ( new Action ( ( ) = > { ClearMainTreeView ( ) ; } ) ) ;
}
else
{
GoButton . Enabled = false ;
UpButton . Enabled = false ;
BackButton . Enabled = false ;
ForwardButton . Enabled = false ;
RefreshButton . Enabled = false ;
SearchButton . Enabled = false ;
2018-01-10 11:17:30 +08:00
EditModeButton . Enabled = false ;
2017-09-21 18:33:05 +08:00
MainTreeView . Nodes . Clear ( ) ;
MainListView . VirtualListSize = 0 ; //also clear the list view...
}
}
catch { }
}
private void AddMainTreeViewRoot ( MainTreeFolder f )
{
try
{
if ( InvokeRequired )
{
Invoke ( new Action ( ( ) = > { AddMainTreeViewRoot ( f ) ; } ) ) ;
}
else
{
var rn = MainTreeView . Nodes . Add ( f . Path , f . Name , 0 , 0 ) ; //ROOT imageIndex
rn . ToolTipText = f . FullPath ;
rn . Tag = f ;
2018-02-27 15:58:35 +08:00
f . TreeNode = rn ;
2017-09-21 18:33:05 +08:00
}
}
catch { }
}
private void AddMainTreeViewNode ( MainTreeFolder f )
{
try
{
if ( InvokeRequired )
{
Invoke ( new Action ( ( ) = > { AddMainTreeViewNode ( f ) ; } ) ) ;
}
else
{
string n = f . Name ;
var root = ( MainTreeView . Nodes . Count > 0 ) ? MainTreeView . Nodes [ 0 ] : null ;
RecurseAddMainTreeViewNodes ( f , root ) ;
root . Expand ( ) ;
}
}
catch { }
}
private void RecurseAddMainTreeViewNodes ( MainTreeFolder f , TreeNode parent )
{
int imgIndex = 1 ; //FOLDER imageIndex
if ( f . RpfFile ! = null ) imgIndex = 3 ; //RPF FILE imageIndex
var nc = ( parent ! = null ) ? parent . Nodes : MainTreeView . Nodes ;
var tn = nc . Add ( f . Path , f . Name , imgIndex , imgIndex ) ;
tn . ToolTipText = f . Path ;
tn . Tag = f ;
2018-01-10 11:17:30 +08:00
f . TreeNode = tn ;
2017-09-21 18:33:05 +08:00
if ( f . Children ! = null )
{
f . Children . Sort ( ( n1 , n2 ) = > n1 . Name . CompareTo ( n2 . Name ) ) ;
foreach ( var child in f . Children )
{
RecurseAddMainTreeViewNodes ( child , tn ) ;
}
}
}
private void MainTreeViewRefreshComplete ( )
{
try
{
if ( InvokeRequired )
{
Invoke ( new Action ( ( ) = > { MainTreeViewRefreshComplete ( ) ; } ) ) ;
}
else
{
if ( CurrentFolder ! = null )
{
if ( CurrentFolder . IsSearchResults )
{
Search ( CurrentFolder . SearchTerm ) ;
}
else
{
var path = CurrentFolder . Path ;
CurrentFolder = null ;
Navigate ( path ) ;
}
}
else
{
Navigate ( RootFolder ) ;
}
}
}
catch { }
}
2018-01-10 11:17:30 +08:00
private void AddNewFolderTreeNode ( MainTreeFolder f )
{
if ( CurrentFolder = = null ) return ;
RecurseAddMainTreeViewNodes ( f , CurrentFolder . TreeNode ) ;
CurrentFolder . AddChild ( f ) ;
RefreshMainListView ( ) ;
}
private MainTreeFolder CreateRpfTreeFolder ( RpfFile rpf , string relpath , string fullpath )
{
var node = new MainTreeFolder ( ) ;
node . RpfFile = rpf ;
node . RpfFolder = rpf . Root ;
node . Name = rpf . Name ;
node . Path = relpath ;
node . FullPath = fullpath ;
return node ;
}
private MainTreeFolder CreateRpfDirTreeFolder ( RpfDirectoryEntry dir , string relpath , string fullpath )
{
var node = new MainTreeFolder ( ) ;
node . RpfFolder = dir ;
node . Name = dir . Name ;
node . Path = relpath ;
node . FullPath = fullpath ;
return node ;
}
private MainTreeFolder CreateRootDirTreeFolder ( string name , string path , string fullpath )
{
var node = new MainTreeFolder ( ) ;
node . Name = name ;
node . Path = path ;
node . FullPath = fullpath ;
return node ;
}
private void RenameTreeFolder ( MainTreeFolder f , string newname )
{
if ( f . Parent = = null ) return ;
f . Name = newname ;
f . Path = f . Parent . Path + "\\" + newname . ToLowerInvariant ( ) ;
f . FullPath = f . Parent . FullPath + "\\" + newname ;
if ( f . TreeNode ! = null )
{
f . TreeNode . Text = newname ;
}
if ( f . Children ! = null )
{
foreach ( var item in f . Children )
{
RenameTreeFolder ( item , item . Name ) ; //just to make sure the all the paths are correct...
}
}
if ( f . ListItems ! = null )
{
foreach ( var item in f . ListItems )
{
RenameListItem ( item , item . Name ) ;
}
}
}
private void RenameListItem ( MainListItem i , string newname )
{
if ( i . Parent = = null ) return ;
i . Name = newname ;
i . Path = i . Parent . Path + "\\" + newname . ToLowerInvariant ( ) ;
i . FullPath = i . Parent . FullPath + "\\" + newname ;
if ( i . Parent = = CurrentFolder )
{
int idx = CurrentFiles . IndexOf ( i ) ;
if ( idx > = 0 )
{
MainListView . RedrawItems ( idx , idx , false ) ;
}
}
}
private void RemoveTreeFolder ( MainTreeFolder f )
{
if ( f . Parent = = null ) return ;
f . Parent . Children ? . Remove ( f ) ;
if ( f . TreeNode ! = null )
{
f . TreeNode . Remove ( ) ;
}
}
private void RemoveListItem ( MainListItem i )
{
if ( i . Parent = = null ) return ;
MainListView . VirtualListSize = 0 ;
i . Parent . ListItems ? . Remove ( i ) ;
if ( i . Parent = = CurrentFolder )
{
CurrentFiles . Remove ( i ) ; //should really be the same list as above, but just in case...
}
MainListView . VirtualListSize = CurrentFiles . Count ;
}
2018-02-26 20:49:06 +08:00
private void EnsureImportedRpf ( RpfFileEntry entry , RpfDirectoryEntry parentrpffldr )
{
if ( ( entry = = null ) | | ( parentrpffldr = = null ) ) return ;
var newrpf = parentrpffldr . File ? . FindChildArchive ( entry ) ;
if ( newrpf = = null ) return ;
2018-01-10 11:17:30 +08:00
2018-02-26 20:49:06 +08:00
//an RPF file was imported. add its structure to the UI!
var rootpath = GTAFolder . GetCurrentGTAFolderWithTrailingSlash ( ) ;
var tnf = CreateRpfTreeFolder ( newrpf , newrpf . Path , rootpath + newrpf . Path ) ;
2018-02-28 00:46:06 +08:00
CurrentFolder . AddChildToHierarchy ( tnf ) ;
var pfolder = tnf . Parent ;
if ( pfolder . Children ! = null )
2018-02-26 20:49:06 +08:00
{
//make sure any existing (replaced!) one is removed first!
2018-02-28 00:46:06 +08:00
foreach ( var child in pfolder . Children )
2018-02-26 20:49:06 +08:00
{
2018-02-28 00:46:06 +08:00
if ( ( child ! = tnf ) & & ( child . Path = = tnf . Path ) )
2018-02-26 20:49:06 +08:00
{
2018-02-28 00:46:06 +08:00
pfolder . Children . Remove ( child ) ;
2018-02-26 20:49:06 +08:00
child . TreeNode . Remove ( ) ;
break ;
}
}
}
RecurseMainTreeViewRPF ( tnf , AllRpfs ) ;
2018-02-28 00:46:06 +08:00
RecurseAddMainTreeViewNodes ( tnf , pfolder . TreeNode ) ;
}
private void EnsureImportedFolder ( RpfDirectoryEntry entry , RpfDirectoryEntry parentrpffldr )
{
if ( ( entry = = null ) | | ( parentrpffldr = = null ) ) return ;
var rootpath = GTAFolder . GetCurrentGTAFolderWithTrailingSlash ( ) ;
var tnf = CreateRpfDirTreeFolder ( entry , entry . Path , rootpath + entry . Path ) ;
CurrentFolder . AddChildToHierarchy ( tnf ) ;
if ( tnf . Parent . TreeNode ! = null )
{
RecurseAddMainTreeViewNodes ( tnf , tnf . Parent . TreeNode ) ;
}
foreach ( var subdir in entry . Directories )
{
EnsureImportedFolder ( subdir , entry ) ;
}
foreach ( var subfile in entry . Files )
{
EnsureImportedRpf ( subfile , entry ) ;
}
2018-02-26 20:49:06 +08:00
}
2017-09-21 18:33:05 +08:00
2018-12-14 18:23:05 +08:00
public void RefreshMainListViewInvoke ( )
{
if ( InvokeRequired )
{
BeginInvoke ( new Action ( ( ) = > { RefreshMainListView ( ) ; } ) ) ;
}
else
{
RefreshMainListView ( ) ;
}
}
2017-09-21 18:33:05 +08:00
private void RefreshMainListView ( )
{
MainListView . VirtualListSize = 0 ;
if ( CurrentFolder ! = null )
{
2018-12-14 19:17:13 +08:00
if ( ! CurrentFolder . IsSearchResults )
{
CurrentFolder . ListItems = null ; //makes sure to rebuild the current files list
}
2017-09-21 18:33:05 +08:00
CurrentFiles = CurrentFolder . GetListItems ( ) ;
foreach ( var file in CurrentFiles ) //cache all the data for use by the list view.
{
file . CacheDetails ( this ) ;
}
SortMainListView ( SortColumnIndex , SortDirection ) ; //sorts CurrentItems and sets VirtualListSize
ShowMainListViewPathColumn ( CurrentFolder . IsSearchResults ) ;
}
else
{
UpdateSelectionUI ( ) ;
ShowMainListViewPathColumn ( false ) ;
}
}
private void SortMainListView ( int col , SortOrder dir )
{
if ( dir = = SortOrder . None ) dir = SortOrder . Ascending ; //none not supported for actual sorting!
SortColumnIndex = col ;
SortDirection = dir ;
MainListView . SetSortIcon ( col , dir ) ;
MainListView . VirtualListSize = 0 ;
if ( CurrentFiles = = null ) return ;
CurrentFiles . Sort ( ( i1 , i2 ) = > i1 . SortCompare ( i2 , col , dir ) ) ;
MainListView . VirtualListSize = CurrentFiles . Count ;
UpdateSelectionUI ( ) ;
}
private void ShowMainListViewPathColumn ( bool show )
{
bool visible = ( MainPathColumnHeader . Width > 0 ) ;
if ( show & & ! visible )
{
MainPathColumnHeader . Width = PreviousPathColumnWidth ;
}
else if ( ! show & & visible )
{
PreviousPathColumnWidth = MainPathColumnHeader . Width ;
MainPathColumnHeader . Width = 0 ;
if ( SortColumnIndex = = 4 ) //path col
{
SortMainListView ( 0 , SortDirection ) ; //switch sort to name col
}
}
}
public void Search ( string text )
{
if ( ! Ready ) return ;
if ( Searching ) return ;
if ( string . IsNullOrEmpty ( text ) ) return ;
SearchTextBox . Text = text ;
SearchButton . Image = SearchGlobalButton . Image ;
SearchButton . Text = SearchGlobalButton . Text ;
SearchGlobalButton . Checked = true ;
SearchFilterButton . Checked = false ;
SearchResults = new MainTreeFolder ( ) ;
SearchResults . Name = "Search Results: " + text ;
SearchResults . Path = SearchResults . Name ;
SearchResults . IsSearchResults = true ;
SearchResults . SearchTerm = text ;
Navigate ( SearchResults ) ;
SortDirection = SortOrder . None ;
MainListView . SetSortIcon ( SortColumnIndex , SortDirection ) ;
MainListView . VirtualListSize = 0 ;
CurrentFiles . Clear ( ) ;
UpdateStatus ( "Searching..." ) ;
var term = text . ToLowerInvariant ( ) ;
//Task.Run(() =>
//{
Searching = true ;
Cursor = Cursors . WaitCursor ;
var resultcount = RootFolder . Search ( term , this ) ;
if ( Searching )
{
Searching = false ;
UpdateStatus ( "Search complete. " + resultcount . ToString ( ) + " items found." ) ;
}
else
{
UpdateStatus ( "Search aborted. " + resultcount . ToString ( ) + " items found." ) ;
}
Cursor = Cursors . Default ;
//});
}
public void Filter ( string text )
{
SearchTextBox . Text = text ;
SearchButton . Image = SearchFilterButton . Image ;
SearchButton . Text = SearchFilterButton . Text ;
SearchGlobalButton . Checked = false ;
SearchFilterButton . Checked = true ;
//TODO!
MessageBox . Show ( "Filter TODO!" ) ;
}
public void AddSearchResult ( MainListItem item )
{
if ( SearchResults = = null ) return ;
if ( SearchResults . ListItems ! = CurrentFiles ) return ;
if ( item ! = null )
{
item . CacheDetails ( this ) ;
CurrentFiles . Add ( item ) ;
}
else
{
MainListView . VirtualListSize = CurrentFiles . Count ;
}
//try
//{
// if (InvokeRequired)
// {
// BeginInvoke(new Action(() => { AddSearchResultInner(item); }));
// }
// else
// {
// AddSearchResultInner(item);
// }
//}
//catch { }
}
private byte [ ] GetFileData ( MainListItem file )
{
byte [ ] data = null ;
2018-01-11 09:10:03 +08:00
if ( file . Folder ! = null )
{
var entry = file . Folder . RpfFile ? . ParentFileEntry ;
if ( entry ! = null )
{
data = entry . File . ExtractFile ( entry ) ; //extract an RPF from another.
}
2018-02-26 20:49:06 +08:00
else if ( ! string . IsNullOrEmpty ( file . FullPath ) & & ( file . Folder . RpfFile ! = null ) )
{
data = File . ReadAllBytes ( file . FullPath ) ; //load RPF file from filesystem
}
2018-01-11 09:10:03 +08:00
}
2018-02-26 20:49:06 +08:00
else if ( file . File ! = null ) //load file from RPF
2017-09-21 18:33:05 +08:00
{
2018-01-11 09:10:03 +08:00
if ( file . File . File ! = null ) //need the reference to the RPF archive
{
data = file . File . File . ExtractFile ( file . File ) ;
}
2018-02-26 20:49:06 +08:00
else
{ }
2017-09-21 18:33:05 +08:00
}
else if ( ! string . IsNullOrEmpty ( file . FullPath ) )
{
2018-02-26 20:49:06 +08:00
data = File . ReadAllBytes ( file . FullPath ) ; //load file from filesystem
}
else
{ }
return data ;
}
private byte [ ] GetFileDataCompressResources ( MainListItem file )
{
byte [ ] data = GetFileData ( file ) ;
RpfResourceFileEntry rrfe = file . File as RpfResourceFileEntry ;
if ( rrfe ! = null ) //add resource header if this is a resource file.
{
data = ResourceBuilder . Compress ( data ) ; //not completely ideal to recompress it...
data = ResourceBuilder . AddResourceHeader ( rrfe , data ) ;
2017-09-21 18:33:05 +08:00
}
return data ;
}
2018-02-26 20:49:06 +08:00
2017-09-21 18:33:05 +08:00
private bool CanViewFile ( MainListItem item )
{
if ( item = = null ) return false ;
if ( item . FileType = = null ) return false ;
switch ( item . FileType . DefaultAction )
{
case FileTypeAction . ViewText :
case FileTypeAction . ViewXml :
case FileTypeAction . ViewYtd :
case FileTypeAction . ViewYmt :
case FileTypeAction . ViewYmf :
case FileTypeAction . ViewYmap :
case FileTypeAction . ViewYtyp :
case FileTypeAction . ViewJPso :
case FileTypeAction . ViewModel :
case FileTypeAction . ViewCut :
case FileTypeAction . ViewAwc :
case FileTypeAction . ViewGxt :
case FileTypeAction . ViewRel :
case FileTypeAction . ViewFxc :
case FileTypeAction . ViewYwr :
case FileTypeAction . ViewYvr :
2017-09-29 20:23:37 +08:00
case FileTypeAction . ViewYcd :
2019-11-01 17:30:29 +08:00
case FileTypeAction . ViewYnd :
2017-12-14 18:49:41 +08:00
case FileTypeAction . ViewCacheDat :
2019-11-21 21:34:27 +08:00
case FileTypeAction . ViewYed :
case FileTypeAction . ViewYld :
case FileTypeAction . ViewYfd :
2017-09-21 18:33:05 +08:00
return true ;
case FileTypeAction . ViewHex :
default :
break ;
}
return false ;
}
2017-10-04 15:44:29 +08:00
private bool CanExportXml ( MainListItem item )
{
if ( item = = null ) return false ;
if ( item . FileType = = null ) return false ;
switch ( item . FileType . DefaultAction )
{
case FileTypeAction . ViewYmt :
case FileTypeAction . ViewYmf :
case FileTypeAction . ViewYmap :
case FileTypeAction . ViewYtyp :
case FileTypeAction . ViewJPso :
2018-01-11 11:06:48 +08:00
case FileTypeAction . ViewCut :
2019-01-20 06:34:44 +08:00
case FileTypeAction . ViewRel :
2019-11-01 17:30:29 +08:00
case FileTypeAction . ViewYnd :
2019-11-16 00:18:23 +08:00
case FileTypeAction . ViewYcd :
2017-10-04 15:44:29 +08:00
return true ;
}
return false ;
}
2017-09-21 18:33:05 +08:00
private void View ( MainListItem item )
{
#if ! DEBUG
try
#endif
{
2018-12-14 18:23:05 +08:00
var exform = FindExistingForm ( item ? . File ) ;
if ( exform ! = null )
{
exform . Focus ( ) ;
return ;
}
2017-09-21 18:33:05 +08:00
byte [ ] data = null ;
string name = "" ;
string path = "" ;
if ( item . File ! = null )
{
//load file from RPF
if ( item . File . File = = null ) return ; //no RPF file? go no further
data = item . File . File . ExtractFile ( item . File ) ;
name = item . Name ;
path = item . FullPath ;
}
else if ( ! string . IsNullOrEmpty ( item . FullPath ) )
{
//load file from filesystem
data = File . ReadAllBytes ( item . FullPath ) ;
name = new FileInfo ( item . FullPath ) . Name ;
path = item . FullPath ;
}
if ( data = = null ) return ;
var ft = item . FileType ;
2019-03-22 19:18:28 +08:00
var fe = item . File ;
if ( fe = = null )
{
//this should only happen when opening a file from filesystem...
fe = CreateFileEntry ( name , path , ref data ) ;
}
2017-09-21 18:33:05 +08:00
switch ( ft . DefaultAction )
{
case FileTypeAction . ViewText :
2019-03-22 19:18:28 +08:00
ViewText ( name , path , data , fe ) ;
2017-09-21 18:33:05 +08:00
break ;
case FileTypeAction . ViewXml :
2019-03-22 19:18:28 +08:00
ViewXml ( name , path , data , fe ) ;
2017-09-21 18:33:05 +08:00
break ;
case FileTypeAction . ViewYtd :
2019-03-22 19:18:28 +08:00
ViewYtd ( name , path , data , fe ) ;
2017-09-21 18:33:05 +08:00
break ;
case FileTypeAction . ViewYmt :
2019-03-22 19:18:28 +08:00
ViewYmt ( name , path , data , fe ) ;
2017-09-21 18:33:05 +08:00
break ;
case FileTypeAction . ViewYmf :
2019-03-22 19:18:28 +08:00
ViewYmf ( name , path , data , fe ) ;
2017-09-21 18:33:05 +08:00
break ;
case FileTypeAction . ViewYmap :
2019-03-22 19:18:28 +08:00
ViewYmap ( name , path , data , fe ) ;
2017-09-21 18:33:05 +08:00
break ;
case FileTypeAction . ViewYtyp :
2019-03-22 19:18:28 +08:00
ViewYtyp ( name , path , data , fe ) ;
2017-09-21 18:33:05 +08:00
break ;
case FileTypeAction . ViewJPso :
2019-03-22 19:18:28 +08:00
ViewJPso ( name , path , data , fe ) ;
2017-09-21 18:33:05 +08:00
break ;
case FileTypeAction . ViewCut :
2019-03-22 19:18:28 +08:00
ViewCut ( name , path , data , fe ) ;
2017-09-21 18:33:05 +08:00
break ;
case FileTypeAction . ViewModel :
2019-03-22 19:18:28 +08:00
ViewModel ( name , path , data , fe ) ;
2017-09-21 18:33:05 +08:00
break ;
case FileTypeAction . ViewAwc :
2019-03-22 19:18:28 +08:00
ViewAwc ( name , path , data , fe ) ;
2017-09-21 18:33:05 +08:00
break ;
case FileTypeAction . ViewGxt :
2019-03-22 19:18:28 +08:00
ViewGxt ( name , path , data , fe ) ;
2017-09-21 18:33:05 +08:00
break ;
case FileTypeAction . ViewRel :
2019-03-22 19:18:28 +08:00
ViewRel ( name , path , data , fe ) ;
2017-09-21 18:33:05 +08:00
break ;
case FileTypeAction . ViewFxc :
2019-03-22 19:18:28 +08:00
ViewFxc ( name , path , data , fe ) ;
2017-09-21 18:33:05 +08:00
break ;
case FileTypeAction . ViewYwr :
2019-03-22 19:18:28 +08:00
ViewYwr ( name , path , data , fe ) ;
2017-09-21 18:33:05 +08:00
break ;
case FileTypeAction . ViewYvr :
2019-03-22 19:18:28 +08:00
ViewYvr ( name , path , data , fe ) ;
2017-09-21 18:33:05 +08:00
break ;
2017-09-29 20:23:37 +08:00
case FileTypeAction . ViewYcd :
2019-03-22 19:18:28 +08:00
ViewYcd ( name , path , data , fe ) ;
2017-09-29 20:23:37 +08:00
break ;
2019-11-01 17:30:29 +08:00
case FileTypeAction . ViewYnd :
ViewYnd ( name , path , data , fe ) ;
break ;
2017-12-14 18:49:41 +08:00
case FileTypeAction . ViewCacheDat :
2019-03-22 19:18:28 +08:00
ViewCacheDat ( name , path , data , fe ) ;
2017-12-14 18:49:41 +08:00
break ;
2019-11-21 21:34:27 +08:00
case FileTypeAction . ViewYed :
ViewYed ( name , path , data , fe ) ;
break ;
case FileTypeAction . ViewYld :
ViewYld ( name , path , data , fe ) ;
break ;
case FileTypeAction . ViewYfd :
ViewYfd ( name , path , data , fe ) ;
break ;
2017-09-21 18:33:05 +08:00
case FileTypeAction . ViewHex :
default :
ViewHex ( name , path , data ) ;
break ;
}
}
#if ! DEBUG
catch ( Exception ex )
{
UpdateErrorLog ( ex . ToString ( ) ) ;
return ;
}
#endif
}
private void ViewHex ( MainListItem item )
{
try
{
byte [ ] data = null ;
string name = "" ;
string path = "" ;
if ( item . File ! = null )
{
//load file from RPF
if ( item . File . File = = null ) return ; //no RPF file? go no further
data = item . File . File . ExtractFile ( item . File ) ;
name = item . Name ;
path = item . FullPath ;
}
else if ( ! string . IsNullOrEmpty ( item . FullPath ) )
{
//load file from filesystem
data = File . ReadAllBytes ( item . FullPath ) ;
name = new FileInfo ( item . FullPath ) . Name ;
path = item . FullPath ;
}
if ( data = = null ) return ;
ViewHex ( name , path , data ) ;
}
catch ( Exception ex )
{
UpdateErrorLog ( ex . ToString ( ) ) ;
return ;
}
}
private void ViewHex ( string name , string path , byte [ ] data )
{
HexForm f = new HexForm ( ) ;
f . Show ( ) ;
f . LoadData ( name , path , data ) ;
}
2019-01-20 07:27:46 +08:00
private void ViewXml ( string name , string path , byte [ ] data , RpfFileEntry e )
2017-09-21 18:33:05 +08:00
{
string xml = Encoding . UTF8 . GetString ( data ) ;
2019-01-20 07:27:46 +08:00
XmlForm f = new XmlForm ( this ) ;
2017-09-21 18:33:05 +08:00
f . Show ( ) ;
2019-01-20 07:27:46 +08:00
f . LoadXml ( name , path , xml , e ) ;
2017-09-21 18:33:05 +08:00
}
2019-01-20 07:27:46 +08:00
private void ViewText ( string name , string path , byte [ ] data , RpfFileEntry e )
2017-09-21 18:33:05 +08:00
{
string txt = Encoding . UTF8 . GetString ( data ) ;
2019-01-20 07:27:46 +08:00
TextForm f = new TextForm ( this ) ;
2017-09-21 18:33:05 +08:00
f . Show ( ) ;
2019-01-20 07:27:46 +08:00
f . LoadText ( name , path , txt , e ) ;
2017-09-21 18:33:05 +08:00
}
private void ViewYtd ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var ytd = RpfFile . GetFile < YtdFile > ( e , data ) ;
YtdForm f = new YtdForm ( ) ;
f . Show ( ) ;
f . LoadYtd ( ytd ) ;
}
private void ViewYmt ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var ymt = RpfFile . GetFile < YmtFile > ( e , data ) ;
2018-12-14 18:23:05 +08:00
MetaForm f = new MetaForm ( this ) ;
2017-09-21 18:33:05 +08:00
f . Show ( ) ;
f . LoadMeta ( ymt ) ;
}
private void ViewYmf ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var ymf = RpfFile . GetFile < YmfFile > ( e , data ) ;
2018-12-14 18:23:05 +08:00
MetaForm f = new MetaForm ( this ) ;
2017-09-21 18:33:05 +08:00
f . Show ( ) ;
f . LoadMeta ( ymf ) ;
}
private void ViewYmap ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var ymap = RpfFile . GetFile < YmapFile > ( e , data ) ;
2018-12-14 18:23:05 +08:00
MetaForm f = new MetaForm ( this ) ;
2017-09-21 18:33:05 +08:00
f . Show ( ) ;
f . LoadMeta ( ymap ) ;
}
private void ViewYtyp ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var ytyp = RpfFile . GetFile < YtypFile > ( e , data ) ;
2018-12-14 18:23:05 +08:00
MetaForm f = new MetaForm ( this ) ;
2017-09-21 18:33:05 +08:00
f . Show ( ) ;
f . LoadMeta ( ytyp ) ;
}
private void ViewJPso ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var pso = RpfFile . GetFile < JPsoFile > ( e , data ) ;
2018-12-14 18:23:05 +08:00
MetaForm f = new MetaForm ( this ) ;
2017-09-21 18:33:05 +08:00
f . Show ( ) ;
f . LoadMeta ( pso ) ;
}
private void ViewModel ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var nl = e ? . NameLower ? ? "" ;
2018-03-03 21:03:08 +08:00
var fe = Path . GetExtension ( nl ) ;
2017-09-21 18:33:05 +08:00
ModelForm f = new ModelForm ( this ) ;
f . Show ( ) ;
switch ( fe )
{
case ".ydr" :
var ydr = RpfFile . GetFile < YdrFile > ( e , data ) ;
f . LoadModel ( ydr ) ;
break ;
case ".ydd" :
var ydd = RpfFile . GetFile < YddFile > ( e , data ) ;
f . LoadModels ( ydd ) ;
break ;
case ".yft" :
var yft = RpfFile . GetFile < YftFile > ( e , data ) ;
f . LoadModel ( yft ) ;
break ;
case ".ybn" :
var ybn = RpfFile . GetFile < YbnFile > ( e , data ) ;
f . LoadModel ( ybn ) ;
break ;
case ".ypt" :
var ypt = RpfFile . GetFile < YptFile > ( e , data ) ;
f . LoadParticles ( ypt ) ;
break ;
case ".ynv" :
var ynv = RpfFile . GetFile < YnvFile > ( e , data ) ;
f . LoadNavmesh ( ynv ) ;
break ;
}
}
private void ViewCut ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var cut = RpfFile . GetFile < CutFile > ( e , data ) ;
2018-12-14 18:23:05 +08:00
MetaForm f = new MetaForm ( this ) ;
2017-09-21 18:33:05 +08:00
f . Show ( ) ;
f . LoadMeta ( cut ) ;
}
private void ViewAwc ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var awc = RpfFile . GetFile < AwcFile > ( e , data ) ;
AwcForm f = new AwcForm ( ) ;
f . Show ( ) ;
f . LoadAwc ( awc ) ;
}
private void ViewGxt ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var gxt = RpfFile . GetFile < Gxt2File > ( e , data ) ;
GxtForm f = new GxtForm ( ) ;
f . Show ( ) ;
f . LoadGxt2 ( gxt ) ;
}
private void ViewRel ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var rel = RpfFile . GetFile < RelFile > ( e , data ) ;
2019-01-19 19:39:47 +08:00
RelForm f = new RelForm ( this ) ;
2017-09-21 18:33:05 +08:00
f . Show ( ) ;
f . LoadRel ( rel ) ;
}
private void ViewFxc ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var fxc = RpfFile . GetFile < FxcFile > ( e , data ) ;
FxcForm f = new FxcForm ( ) ;
f . Show ( ) ;
f . LoadFxc ( fxc ) ;
}
private void ViewYwr ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var ywr = RpfFile . GetFile < YwrFile > ( e , data ) ;
YwrForm f = new YwrForm ( ) ;
f . Show ( ) ;
f . LoadYwr ( ywr ) ;
}
private void ViewYvr ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var yvr = RpfFile . GetFile < YvrFile > ( e , data ) ;
YvrForm f = new YvrForm ( ) ;
f . Show ( ) ;
f . LoadYvr ( yvr ) ;
}
2017-09-29 20:23:37 +08:00
private void ViewYcd ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var ycd = RpfFile . GetFile < YcdFile > ( e , data ) ;
YcdForm f = new YcdForm ( ) ;
f . Show ( ) ;
f . LoadYcd ( ycd ) ;
}
2019-11-01 17:30:29 +08:00
private void ViewYnd ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var ynd = RpfFile . GetFile < YndFile > ( e , data ) ;
MetaForm f = new MetaForm ( this ) ;
f . Show ( ) ;
f . LoadMeta ( ynd ) ;
}
2019-11-21 21:34:27 +08:00
private void ViewYed ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var yed = RpfFile . GetFile < YedFile > ( e , data ) ;
GenericForm f = new GenericForm ( this ) ;
f . Show ( ) ;
f . LoadFile ( yed , yed . RpfFileEntry ) ;
}
private void ViewYld ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var yld = RpfFile . GetFile < YldFile > ( e , data ) ;
GenericForm f = new GenericForm ( this ) ;
f . Show ( ) ;
f . LoadFile ( yld , yld . RpfFileEntry ) ;
}
private void ViewYfd ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var yfd = RpfFile . GetFile < YfdFile > ( e , data ) ;
GenericForm f = new GenericForm ( this ) ;
f . Show ( ) ;
f . LoadFile ( yfd , yfd . RpfFileEntry ) ;
}
2017-12-14 18:49:41 +08:00
private void ViewCacheDat ( string name , string path , byte [ ] data , RpfFileEntry e )
{
var cachedat = RpfFile . GetFile < CacheDatFile > ( e , data ) ;
2018-12-14 18:23:05 +08:00
MetaForm f = new MetaForm ( this ) ;
2017-12-14 18:49:41 +08:00
f . Show ( ) ;
f . LoadMeta ( cachedat ) ;
}
2017-09-21 18:33:05 +08:00
2019-03-22 19:18:28 +08:00
private RpfFileEntry CreateFileEntry ( string name , string path , ref byte [ ] data )
{
//this should only really be used when loading a file from the filesystem.
RpfFileEntry e = null ;
uint rsc7 = ( data ? . Length > 4 ) ? BitConverter . ToUInt32 ( data , 0 ) : 0 ;
if ( rsc7 = = 0x37435352 ) //RSC7 header present! create RpfResourceFileEntry and decompress data...
{
e = RpfFile . CreateResourceFileEntry ( ref data , 0 ) ; //"version" should be loadable from the header in the data..
data = ResourceBuilder . Decompress ( data ) ;
}
else
{
var be = new RpfBinaryFileEntry ( ) ;
be . FileSize = ( uint ) data ? . Length ;
be . FileUncompressedSize = be . FileSize ;
e = be ;
}
e . Name = name ;
e . NameLower = name ? . ToLowerInvariant ( ) ;
e . NameHash = JenkHash . GenHash ( e . NameLower ) ;
e . ShortNameHash = JenkHash . GenHash ( Path . GetFileNameWithoutExtension ( e . NameLower ) ) ;
e . Path = path ;
return e ;
}
2017-09-21 18:33:05 +08:00
2018-12-14 18:23:05 +08:00
private Form FindExistingForm ( RpfFileEntry e )
{
if ( e = = null ) return null ;
var allforms = Application . OpenForms ;
var path = e . Path . ToLowerInvariant ( ) ;
foreach ( var form in allforms )
{
var metaform = form as MetaForm ;
if ( metaform ? . rpfFileEntry = = e ) return metaform ;
if ( metaform ? . rpfFileEntry ? . Path ? . ToLowerInvariant ( ) = = path )
return metaform ; //need to test the path as well since the file entry may have been replaced by a new version..!
}
return null ;
}
2017-09-21 18:33:05 +08:00
private void ShowTreeContextMenu ( TreeNode n , Point p )
{
var f = n ? . Tag as MainTreeFolder ;
bool filesys = ( ( f . RpfFolder = = null ) & & ( f . RpfFile = = null ) ) ;
bool expanded = ( ( n ! = null ) & & ( n . IsExpanded ) ) ;
bool collapsed = ( ( n ! = null ) & & ( ! n . IsExpanded ) ) ;
if ( ( f . RpfFile ! = null ) & & ( f . RpfFile . Parent = = null ) )
{
filesys = true ; //allow viewing root RPF's in explorer
}
TreeContextWinExplorerMenu . Enabled = filesys ;
TreeContextExpandMenu . Enabled = collapsed ;
TreeContextCollapseMenu . Enabled = expanded ;
TreeContextMenu . Show ( MainTreeView , p ) ;
}
private void ShowListContextMenu ( MainListItem item )
{
bool isitem = false ;
bool isfile = false ;
bool isfolder = false ;
2018-01-11 09:10:03 +08:00
bool isarchive = false ;
2017-09-21 18:33:05 +08:00
bool isfilesys = false ;
2018-01-10 11:17:30 +08:00
bool issearch = CurrentFolder ? . IsSearchResults ? ? false ;
2017-09-21 18:33:05 +08:00
bool canview = false ;
bool canexportxml = false ;
2018-01-11 09:10:03 +08:00
bool canextract = false ;
2018-01-10 11:17:30 +08:00
bool canimport = EditMode & & ( CurrentFolder ? . RpfFolder ! = null ) & & ! issearch ;
2018-01-11 11:06:48 +08:00
bool cancreate = EditMode & & ! issearch ;
2017-09-21 18:33:05 +08:00
bool canedit = false ;
2018-01-12 12:19:32 +08:00
bool candefrag = false ;
2017-09-21 18:33:05 +08:00
if ( item ! = null )
{
2018-01-11 09:10:03 +08:00
var entry = item . GetRpfEntry ( ) ;
isitem = true ;
isfilesys = ( entry = = null ) ;
isarchive = ( item . Folder ? . RpfFile ! = null ) ;
2017-09-21 18:33:05 +08:00
isfolder = ( item . Folder ! = null ) ;
2018-01-11 09:10:03 +08:00
isfile = ! isfolder ;
2017-09-21 18:33:05 +08:00
canview = CanViewFile ( item ) ;
2017-10-04 15:44:29 +08:00
canexportxml = CanExportXml ( item ) ;
2018-01-10 11:17:30 +08:00
canedit = EditMode & & ! issearch ;
2018-01-11 09:10:03 +08:00
canextract = isfile | | ( isarchive & & ! isfilesys ) ;
2018-01-12 12:19:32 +08:00
candefrag = isarchive & & canedit ;
2017-09-21 18:33:05 +08:00
}
ListContextViewMenu . Enabled = canview ;
ListContextViewHexMenu . Enabled = isfile ;
ListContextExportXmlMenu . Enabled = canexportxml ;
2018-01-11 09:10:03 +08:00
ListContextExtractRawMenu . Enabled = canextract ;
2017-09-27 00:59:39 +08:00
ListContextExtractUncompressedMenu . Enabled = isfile ;
2017-09-21 18:33:05 +08:00
2018-01-11 11:06:48 +08:00
ListContextNewMenu . Visible = cancreate ;
2017-09-21 18:33:05 +08:00
ListContextImportRawMenu . Visible = canimport ;
2019-03-20 18:21:47 +08:00
ListContextImportFbxMenu . Visible = canimport ;
2017-09-21 18:33:05 +08:00
ListContextImportXmlMenu . Visible = canimport ;
2018-01-11 11:06:48 +08:00
ListContextImportSeparator . Visible = cancreate ;
2017-09-21 18:33:05 +08:00
ListContextCopyMenu . Enabled = isfile ;
ListContextCopyPathMenu . Enabled = isitem ;
ListContextOpenFileLocationMenu . Visible = issearch ;
ListContextOpenFileLocationSeparator . Visible = issearch ;
ListContextRenameMenu . Visible = canedit ;
ListContextReplaceMenu . Visible = canedit ;
ListContextDeleteMenu . Visible = canedit ;
ListContextEditSeparator . Visible = canedit ;
2018-01-12 12:19:32 +08:00
ListContextDefragmentMenu . Visible = candefrag ;
ListContextDefragmentSeparator . Visible = candefrag ;
2017-09-21 18:33:05 +08:00
ListContextMenu . Show ( Cursor . Position ) ;
}
2018-01-10 11:17:30 +08:00
private void EnableEditMode ( bool enable )
{
if ( EditMode = = enable )
{
return ;
}
if ( enable )
{
if ( MessageBox . Show ( this , "While in edit mode, all changes are automatically saved.\nDo you want to continue?" , "Warning - Entering edit mode" , MessageBoxButtons . YesNo , MessageBoxIcon . Warning ) ! = DialogResult . Yes )
{
return ;
}
}
EditMode = enable ;
EditModeButton . Checked = enable ;
MainListView . LabelEdit = enable ;
2018-01-11 12:03:58 +08:00
EnsureEditModeWarning ( ) ;
2019-03-20 18:21:47 +08:00
UpdateSelectionUI ( ) ;
2018-01-10 11:17:30 +08:00
}
2018-01-11 12:03:58 +08:00
private void EnsureEditModeWarning ( )
{
2018-01-12 12:19:32 +08:00
bool mods = CurrentFolder . Path . ToLowerInvariant ( ) . StartsWith ( "mods" ) ;
bool srch = CurrentFolder ? . IsSearchResults ? ? false ;
bool show = EditMode & & ! mods & & ! srch ;
2018-01-11 12:03:58 +08:00
int gap = 3 ;
int bot = MainListView . Bottom ;
EditModeBaseWarningPanel . Top = gap ;
EditModeModsWarningPanel . Top = gap ;
EditModeModsWarningPanel . Visible = false ;
2018-01-10 11:17:30 +08:00
2018-01-11 12:03:58 +08:00
MainListView . Top = show ? EditModeBaseWarningPanel . Bottom + gap : gap ;
MainListView . Height = bot - MainListView . Top ;
}
2018-01-10 11:17:30 +08:00
private bool IsFilenameOk ( string name )
{
foreach ( var ic in Path . GetInvalidFileNameChars ( ) )
{
if ( name . Contains ( ic ) )
{
return false ;
}
}
return true ;
}
2018-01-11 09:10:03 +08:00
2018-12-21 16:06:39 +08:00
public bool EnsureRpfValidEncryption ( RpfFile file = null )
2018-01-11 09:10:03 +08:00
{
2018-02-26 20:49:06 +08:00
if ( ( file = = null ) & & ( CurrentFolder . RpfFolder = = null ) ) return false ;
2018-01-11 09:10:03 +08:00
2018-02-26 20:49:06 +08:00
var rpf = file ? ? CurrentFolder . RpfFolder . File ;
2018-01-11 09:10:03 +08:00
if ( rpf = = null ) return false ;
2018-02-26 20:49:06 +08:00
var confirm = new Func < RpfFile , bool > ( ( f ) = >
2018-01-11 09:10:03 +08:00
{
2018-02-26 20:49:06 +08:00
var msg = "Archive " + f . Name + " is currently set to " + f . Encryption . ToString ( ) + " encryption.\nAre you sure you want to change this archive to OPEN encryption?\nLoading by the game will require OpenIV.asi." ;
return ( MessageBox . Show ( msg , "Change RPF encryption type" , MessageBoxButtons . YesNo ) = = DialogResult . Yes ) ;
} ) ;
2018-01-11 09:10:03 +08:00
2018-02-26 20:49:06 +08:00
return RpfFile . EnsureValidEncryption ( rpf , confirm ) ;
2018-01-11 09:10:03 +08:00
}
2017-09-21 18:33:05 +08:00
private void ViewSelected ( )
{
for ( int i = 0 ; i < MainListView . SelectedIndices . Count ; i + + )
{
var idx = MainListView . SelectedIndices [ i ] ;
if ( ( idx < 0 ) | | ( idx > = CurrentFiles . Count ) ) continue ;
var file = CurrentFiles [ idx ] ;
if ( file . Folder = = null )
{
View ( file ) ;
}
}
}
private void ViewSelectedHex ( )
{
for ( int i = 0 ; i < MainListView . SelectedIndices . Count ; i + + )
{
var idx = MainListView . SelectedIndices [ i ] ;
if ( ( idx < 0 ) | | ( idx > = CurrentFiles . Count ) ) continue ;
var file = CurrentFiles [ idx ] ;
if ( file . Folder = = null )
{
ViewHex ( file ) ;
}
}
}
private void ExportXml ( )
{
2017-10-04 15:44:29 +08:00
if ( MainListView . SelectedIndices . Count = = 1 )
2017-09-21 18:33:05 +08:00
{
2017-10-04 15:44:29 +08:00
var idx = MainListView . SelectedIndices [ 0 ] ;
if ( ( idx < 0 ) | | ( idx > = CurrentFiles . Count ) ) return ;
2017-09-21 18:33:05 +08:00
var file = CurrentFiles [ idx ] ;
if ( file . Folder = = null )
{
2017-10-04 15:44:29 +08:00
if ( CanExportXml ( file ) )
{
byte [ ] data = GetFileData ( file ) ;
if ( data = = null )
{
MessageBox . Show ( "Unable to extract file: " + file . Path ) ;
return ;
}
string newfn ;
string xml = MetaXml . GetXml ( file . File , data , out newfn ) ;
if ( string . IsNullOrEmpty ( xml ) )
{
MessageBox . Show ( "Unable to convert file to XML: " + file . Path ) ;
return ;
}
SaveFileDialog . FileName = newfn ;
if ( SaveFileDialog . ShowDialog ( ) = = DialogResult . OK )
{
string path = SaveFileDialog . FileName ;
try
{
File . WriteAllText ( path , xml ) ;
}
catch ( Exception ex )
{
MessageBox . Show ( "Error saving file " + path + ":\n" + ex . ToString ( ) ) ;
}
}
}
}
}
else
{
if ( FolderBrowserDialog . ShowDialog ( ) ! = DialogResult . OK ) return ;
string folderpath = FolderBrowserDialog . SelectedPath ;
if ( ! folderpath . EndsWith ( "\\" ) ) folderpath + = "\\" ;
StringBuilder errors = new StringBuilder ( ) ;
for ( int i = 0 ; i < MainListView . SelectedIndices . Count ; i + + )
{
var idx = MainListView . SelectedIndices [ i ] ;
if ( ( idx < 0 ) | | ( idx > = CurrentFiles . Count ) ) continue ;
var file = CurrentFiles [ idx ] ;
if ( file . Folder = = null )
{
if ( ! CanExportXml ( file ) ) continue ;
var data = GetFileData ( file ) ;
if ( data = = null )
{
errors . AppendLine ( "Unable to extract file: " + file . Path ) ;
continue ;
}
string newfn ;
string xml = MetaXml . GetXml ( file . File , data , out newfn ) ;
if ( string . IsNullOrEmpty ( xml ) )
{
errors . AppendLine ( "Unable to convert file to XML: " + file . Path ) ;
continue ;
}
var path = folderpath + newfn ;
try
{
File . WriteAllText ( path , xml ) ;
}
catch ( Exception ex )
{
errors . AppendLine ( "Error saving file " + path + ":\n" + ex . ToString ( ) ) ;
}
}
}
string errstr = errors . ToString ( ) ;
if ( ! string . IsNullOrEmpty ( errstr ) )
{
MessageBox . Show ( "Errors were encountered:\n" + errstr ) ;
2017-09-21 18:33:05 +08:00
}
}
}
private void ExtractRaw ( )
{
if ( MainListView . SelectedIndices . Count = = 1 )
{
var idx = MainListView . SelectedIndices [ 0 ] ;
if ( ( idx < 0 ) | | ( idx > = CurrentFiles . Count ) ) return ;
var file = CurrentFiles [ idx ] ;
2018-01-11 09:10:03 +08:00
if ( ( file . Folder = = null ) | | ( file . Folder . RpfFile ! = null ) )
2017-09-21 18:33:05 +08:00
{
2018-02-26 20:49:06 +08:00
byte [ ] data = GetFileDataCompressResources ( file ) ;
2017-09-21 18:33:05 +08:00
if ( data = = null )
{
MessageBox . Show ( "Unable to extract file: " + file . Path ) ;
return ;
}
2017-09-27 00:59:39 +08:00
SaveFileDialog . FileName = file . Name ;
if ( SaveFileDialog . ShowDialog ( ) = = DialogResult . OK )
{
string path = SaveFileDialog . FileName ;
try
{
File . WriteAllBytes ( path , data ) ;
}
catch ( Exception ex )
{
MessageBox . Show ( "Error saving file " + path + ":\n" + ex . ToString ( ) ) ;
}
}
}
}
else
{
if ( FolderBrowserDialog . ShowDialog ( ) ! = DialogResult . OK ) return ;
string folderpath = FolderBrowserDialog . SelectedPath ;
if ( ! folderpath . EndsWith ( "\\" ) ) folderpath + = "\\" ;
StringBuilder errors = new StringBuilder ( ) ;
for ( int i = 0 ; i < MainListView . SelectedIndices . Count ; i + + )
{
var idx = MainListView . SelectedIndices [ i ] ;
if ( ( idx < 0 ) | | ( idx > = CurrentFiles . Count ) ) continue ;
var file = CurrentFiles [ idx ] ;
2018-01-11 09:10:03 +08:00
if ( ( file . Folder = = null ) | | ( file . Folder . RpfFile ! = null ) )
2017-09-27 00:59:39 +08:00
{
var path = folderpath + file . Name ;
try
{
2018-02-26 20:49:06 +08:00
var data = GetFileDataCompressResources ( file ) ;
if ( data = = null )
2017-09-27 00:59:39 +08:00
{
2018-02-26 20:49:06 +08:00
errors . AppendLine ( "Unable to extract file: " + file . Path ) ;
continue ;
2017-09-27 00:59:39 +08:00
}
File . WriteAllBytes ( path , data ) ;
}
catch ( Exception ex )
{
errors . AppendLine ( "Error saving file " + path + ":\n" + ex . ToString ( ) ) ;
}
}
}
string errstr = errors . ToString ( ) ;
if ( ! string . IsNullOrEmpty ( errstr ) )
{
MessageBox . Show ( "Errors were encountered:\n" + errstr ) ;
}
}
}
private void ExtractUncompressed ( )
{
if ( MainListView . SelectedIndices . Count = = 1 )
{
var idx = MainListView . SelectedIndices [ 0 ] ;
if ( ( idx < 0 ) | | ( idx > = CurrentFiles . Count ) ) return ;
var file = CurrentFiles [ idx ] ;
if ( file . Folder = = null )
{
byte [ ] data = GetFileData ( file ) ;
if ( data = = null )
{
MessageBox . Show ( "Unable to extract file: " + file . Path ) ;
return ;
}
2017-09-21 18:33:05 +08:00
SaveFileDialog . FileName = file . Name ;
if ( SaveFileDialog . ShowDialog ( ) = = DialogResult . OK )
{
string path = SaveFileDialog . FileName ;
try
{
File . WriteAllBytes ( path , data ) ;
}
catch ( Exception ex )
{
MessageBox . Show ( "Error saving file " + path + ":\n" + ex . ToString ( ) ) ;
}
}
}
}
else
{
if ( FolderBrowserDialog . ShowDialog ( ) ! = DialogResult . OK ) return ;
string folderpath = FolderBrowserDialog . SelectedPath ;
if ( ! folderpath . EndsWith ( "\\" ) ) folderpath + = "\\" ;
StringBuilder errors = new StringBuilder ( ) ;
for ( int i = 0 ; i < MainListView . SelectedIndices . Count ; i + + )
{
var idx = MainListView . SelectedIndices [ i ] ;
if ( ( idx < 0 ) | | ( idx > = CurrentFiles . Count ) ) continue ;
var file = CurrentFiles [ idx ] ;
if ( file . Folder = = null )
{
var path = folderpath + file . Name ;
var data = GetFileData ( file ) ;
if ( data = = null )
{
errors . AppendLine ( "Unable to extract file: " + file . Path ) ;
continue ;
}
try
{
File . WriteAllBytes ( path , data ) ;
}
catch ( Exception ex )
{
errors . AppendLine ( "Error saving file " + path + ":\n" + ex . ToString ( ) ) ;
}
}
}
string errstr = errors . ToString ( ) ;
if ( ! string . IsNullOrEmpty ( errstr ) )
{
MessageBox . Show ( "Errors were encountered:\n" + errstr ) ;
}
}
}
private void ExtractAll ( )
{
if ( CurrentFiles = = null ) return ;
if ( FolderBrowserDialog . ShowDialog ( ) ! = DialogResult . OK ) return ;
string folderpath = FolderBrowserDialog . SelectedPath ;
if ( ! folderpath . EndsWith ( "\\" ) ) folderpath + = "\\" ;
StringBuilder errors = new StringBuilder ( ) ;
foreach ( var file in CurrentFiles )
{
2018-01-11 09:10:03 +08:00
if ( ( file . Folder = = null ) | | ( file . Folder . RpfFile ! = null ) )
2017-09-21 18:33:05 +08:00
{
var path = folderpath + file . Name ;
try
{
2018-02-26 20:49:06 +08:00
var data = GetFileDataCompressResources ( file ) ;
if ( data = = null )
2017-09-27 00:59:39 +08:00
{
2018-02-26 20:49:06 +08:00
errors . AppendLine ( "Unable to extract file: " + file . Path ) ;
continue ;
2017-09-27 00:59:39 +08:00
}
2017-09-21 18:33:05 +08:00
File . WriteAllBytes ( path , data ) ;
}
catch ( Exception ex )
{
errors . AppendLine ( "Error saving file " + path + ":\n" + ex . ToString ( ) ) ;
}
}
}
string errstr = errors . ToString ( ) ;
if ( ! string . IsNullOrEmpty ( errstr ) )
{
MessageBox . Show ( "Errors were encountered:\n" + errstr ) ;
}
}
2018-01-10 11:17:30 +08:00
private void NewFolder ( )
{
if ( CurrentFolder = = null ) return ; //shouldn't happen
if ( CurrentFolder ? . IsSearchResults ? ? false ) return ;
string fname = Prompt . ShowDialog ( this , "Enter a name for the new folder:" , "Create folder" , "folder" ) ;
if ( string . IsNullOrEmpty ( fname ) )
{
return ; //no name was provided.
}
if ( ! IsFilenameOk ( fname ) ) return ; //new name contains invalid char(s). don't do anything
2018-02-27 15:58:35 +08:00
string cpath = ( string . IsNullOrEmpty ( CurrentFolder . Path ) ? "" : CurrentFolder . Path + "\\" ) ;
string relpath = cpath + fname . ToLowerInvariant ( ) ;
2018-02-18 17:20:39 +08:00
var rootpath = GTAFolder . GetCurrentGTAFolderWithTrailingSlash ( ) ;
2018-01-10 11:17:30 +08:00
string fullpath = rootpath + relpath ;
RpfDirectoryEntry newdir = null ;
MainTreeFolder node = null ;
try
{
if ( CurrentFolder . RpfFolder ! = null )
{
2018-01-11 09:10:03 +08:00
if ( ! EnsureRpfValidEncryption ( ) ) return ;
2018-01-10 11:17:30 +08:00
//create new directory entry in the RPF.
newdir = RpfFile . CreateDirectory ( CurrentFolder . RpfFolder , fname ) ;
node = CreateRpfDirTreeFolder ( newdir , relpath , fullpath ) ;
}
else
{
//create a folder in the filesystem.
if ( Directory . Exists ( fullpath ) )
{
throw new Exception ( "Folder " + fullpath + " already exists!" ) ;
}
Directory . CreateDirectory ( fullpath ) ;
node = CreateRootDirTreeFolder ( fname , relpath , fullpath ) ;
}
}
catch ( Exception ex )
{
MessageBox . Show ( "Error creating new folder: " + ex . Message , "Unable to create new folder" ) ;
return ;
}
if ( node ! = null )
{
AddNewFolderTreeNode ( node ) ;
}
}
private void NewRpfArchive ( )
{
if ( CurrentFolder = = null ) return ; //shouldn't happen
if ( CurrentFolder ? . IsSearchResults ? ? false ) return ;
string fname = Prompt . ShowDialog ( this , "Enter a name for the new archive:" , "Create RPF7 archive" , "new" ) ;
if ( string . IsNullOrEmpty ( fname ) )
{
return ; //no name was provided.
}
if ( ! IsFilenameOk ( fname ) ) return ; //new name contains invalid char(s). don't do anything
if ( ! fname . ToLowerInvariant ( ) . EndsWith ( ".rpf" ) )
{
fname = fname + ".rpf" ; //make sure it ends with .rpf
}
2018-02-27 15:58:35 +08:00
string cpath = ( string . IsNullOrEmpty ( CurrentFolder . Path ) ? "" : CurrentFolder . Path + "\\" ) ;
string relpath = cpath + fname . ToLowerInvariant ( ) ;
2018-01-10 11:17:30 +08:00
RpfEncryption encryption = RpfEncryption . OPEN ; //TODO: select encryption mode
RpfFile newrpf = null ;
try
{
if ( CurrentFolder . RpfFolder ! = null )
{
2018-01-11 09:10:03 +08:00
if ( ! EnsureRpfValidEncryption ( ) ) return ;
2018-01-10 11:17:30 +08:00
//adding a new RPF as a child of another
newrpf = RpfFile . CreateNew ( CurrentFolder . RpfFolder , fname , encryption ) ;
}
else
{
//adding a new RPF in the filesystem
2018-02-18 17:20:39 +08:00
newrpf = RpfFile . CreateNew ( GTAFolder . CurrentGTAFolder , relpath , encryption ) ;
2018-01-10 11:17:30 +08:00
}
}
catch ( Exception ex )
{
MessageBox . Show ( "Error creating archive: " + ex . Message , "Unable to create new archive" ) ;
return ;
}
if ( newrpf ! = null )
{
2018-02-18 17:20:39 +08:00
var node = CreateRpfTreeFolder ( newrpf , newrpf . Path , GTAFolder . GetCurrentGTAFolderWithTrailingSlash ( ) + newrpf . Path ) ;
2018-01-10 11:17:30 +08:00
RecurseMainTreeViewRPF ( node , AllRpfs ) ;
AddNewFolderTreeNode ( node ) ;
}
2019-03-20 18:21:47 +08:00
}
private void ImportFbx ( )
{
if ( ! EditMode ) return ;
if ( CurrentFolder ? . IsSearchResults ? ? false ) return ;
RpfDirectoryEntry parentrpffldr = CurrentFolder . RpfFolder ;
if ( parentrpffldr = = null )
{
MessageBox . Show ( "No parent RPF folder selected! This shouldn't happen. Refresh the view and try again." ) ;
return ;
}
if ( ! EnsureRpfValidEncryption ( ) ) return ;
OpenFileDialog . Filter = "FBX Files|*.fbx" ;
if ( OpenFileDialog . ShowDialog ( this ) ! = DialogResult . OK )
{
return ; //canceled
}
var fpaths = OpenFileDialog . FileNames ;
var fdict = new Dictionary < string , byte [ ] > ( ) ;
foreach ( var fpath in fpaths )
{
#if ! DEBUG
try
#endif
{
if ( ! File . Exists ( fpath ) )
{
continue ; //this shouldn't happen...
}
var fi = new FileInfo ( fpath ) ;
var fname = fi . Name ;
var fnamel = fname . ToLowerInvariant ( ) ;
var trimlength = 4 ;
if ( ! fnamel . EndsWith ( ".fbx" ) )
{
MessageBox . Show ( fname + ": Not an FBX file!" , "Cannot import FBX" ) ;
continue ;
}
fname = fname . Substring ( 0 , fname . Length - trimlength ) ;
var data = File . ReadAllBytes ( fpath ) ;
fdict [ fname ] = data ;
}
#if ! DEBUG
catch ( Exception ex )
{
MessageBox . Show ( ex . Message , "Unable to read file " + fpath ) ;
}
#endif
}
var fbxForm = new ImportFbxForm ( ) ;
fbxForm . SetInputFiles ( fdict ) ;
fbxForm . ShowDialog ( ) ;
if ( fbxForm . DialogResult ! = DialogResult . OK )
{
return ; //fbx import canceled
}
var converted = fbxForm . GetOutputFiles ( ) ;
if ( converted = = null )
{
return ;
}
foreach ( var kvp in converted )
{
var fname = kvp . Key ;
var data = kvp . Value ;
if ( data ! = null )
{
RpfFile . CreateFile ( parentrpffldr , fname , data ) ;
}
}
RefreshMainListView ( ) ;
2018-01-10 11:17:30 +08:00
}
2017-09-21 18:33:05 +08:00
private void ImportXml ( )
{
if ( ! EditMode ) return ;
2018-01-10 11:17:30 +08:00
if ( CurrentFolder ? . IsSearchResults ? ? false ) return ;
2018-01-10 12:55:19 +08:00
RpfDirectoryEntry parentrpffldr = CurrentFolder . RpfFolder ;
if ( parentrpffldr = = null )
{
MessageBox . Show ( "No parent RPF folder selected! This shouldn't happen. Refresh the view and try again." ) ;
return ;
}
2018-01-11 09:10:03 +08:00
if ( ! EnsureRpfValidEncryption ( ) ) return ;
2018-01-10 12:55:19 +08:00
OpenFileDialog . Filter = "XML Files|*.xml" ;
if ( OpenFileDialog . ShowDialog ( this ) ! = DialogResult . OK )
{
return ; //canceled
}
2018-02-26 20:49:06 +08:00
var fpaths = OpenFileDialog . FileNames ;
foreach ( var fpath in fpaths )
2018-01-10 12:55:19 +08:00
{
2018-05-01 11:20:39 +08:00
#if ! DEBUG
2018-02-26 20:49:06 +08:00
try
2018-05-01 11:20:39 +08:00
#endif
2018-01-10 12:55:19 +08:00
{
if ( ! File . Exists ( fpath ) )
{
continue ; //this shouldn't happen...
}
var fi = new FileInfo ( fpath ) ;
var fname = fi . Name ;
var fnamel = fname . ToLowerInvariant ( ) ;
2018-12-20 01:28:43 +08:00
var mformat = MetaFormat . RSC ;
var trimlength = 4 ;
2018-01-10 12:55:19 +08:00
if ( ! fnamel . EndsWith ( ".xml" ) )
{
MessageBox . Show ( fname + ": Not an XML file!" , "Cannot import XML" ) ;
continue ;
}
if ( fnamel . EndsWith ( ".pso.xml" ) )
{
2018-12-20 01:28:43 +08:00
mformat = MetaFormat . PSO ;
trimlength = 8 ;
2018-01-10 12:55:19 +08:00
}
if ( fnamel . EndsWith ( ".rbf.xml" ) )
{
MessageBox . Show ( fname + ": RBF XML import not yet supported." , "Cannot import XML" ) ;
continue ;
}
2019-01-20 06:34:44 +08:00
if ( fnamel . EndsWith ( ".rel.xml" ) )
{
mformat = MetaFormat . AudioRel ;
}
2019-11-01 17:30:29 +08:00
if ( fnamel . EndsWith ( ".ynd.xml" ) )
{
mformat = MetaFormat . Ynd ;
}
2019-11-16 00:18:23 +08:00
if ( fnamel . EndsWith ( ".ycd.xml" ) )
{
mformat = MetaFormat . Ycd ;
}
2018-01-10 12:55:19 +08:00
2018-12-20 01:28:43 +08:00
fname = fname . Substring ( 0 , fname . Length - trimlength ) ;
fnamel = fnamel . Substring ( 0 , fnamel . Length - trimlength ) ;
2018-01-10 12:55:19 +08:00
var doc = new XmlDocument ( ) ;
string text = File . ReadAllText ( fpath ) ;
if ( ! string . IsNullOrEmpty ( text ) )
{
doc . LoadXml ( text ) ;
}
2018-12-20 01:28:43 +08:00
byte [ ] data = null ;
2018-01-10 12:55:19 +08:00
2018-12-20 01:28:43 +08:00
switch ( mformat )
2018-01-10 12:55:19 +08:00
{
2018-12-20 01:28:43 +08:00
case MetaFormat . RSC :
{
var meta = XmlMeta . GetMeta ( doc ) ;
if ( ( meta . DataBlocks ? . Data = = null ) | | ( meta . DataBlocks . Count = = 0 ) )
{
MessageBox . Show ( fname + ": Schema not supported." , "Cannot import Meta XML" ) ;
continue ;
}
data = ResourceBuilder . Build ( meta , 2 ) ; //meta is RSC V:2
break ;
}
case MetaFormat . PSO :
{
var pso = XmlPso . GetPso ( doc ) ;
if ( ( pso . DataSection = = null ) | | ( pso . DataMapSection = = null ) | | ( pso . SchemaSection = = null ) )
{
MessageBox . Show ( fname + ": Schema not supported." , "Cannot import PSO XML" ) ;
continue ;
}
data = pso . Save ( ) ;
break ;
}
case MetaFormat . RBF :
{
//todo!
break ;
}
2019-01-20 06:34:44 +08:00
case MetaFormat . AudioRel :
{
var rel = XmlRel . GetRel ( doc ) ;
if ( ( rel . RelDatasSorted = = null ) | | ( rel . RelDatas = = null ) )
{
MessageBox . Show ( fname + ": Schema not supported." , "Cannot import REL XML" ) ;
continue ;
}
data = rel . Save ( ) ;
break ;
}
2019-11-01 17:30:29 +08:00
case MetaFormat . Ynd :
{
var ynd = XmlYnd . GetYnd ( doc ) ;
if ( ynd . NodeDictionary = = null )
{
MessageBox . Show ( fname + ": Schema not supported." , "Cannot import YND XML" ) ;
continue ;
}
data = ynd . Save ( ) ;
break ;
}
2019-11-16 00:18:23 +08:00
case MetaFormat . Ycd :
{
var ycd = XmlYcd . GetYcd ( doc ) ;
if ( ycd . ClipDictionary = = null )
{
MessageBox . Show ( fname + ": Schema not supported." , "Cannot import YCD XML" ) ;
continue ;
}
data = ycd . Save ( ) ;
break ;
}
2018-01-10 12:55:19 +08:00
}
2018-12-20 01:28:43 +08:00
if ( data ! = null )
{
RpfFile . CreateFile ( parentrpffldr , fname , data ) ;
}
2018-01-10 12:55:19 +08:00
}
2018-05-01 11:20:39 +08:00
#if ! DEBUG
2018-02-26 20:49:06 +08:00
catch ( Exception ex )
{
MessageBox . Show ( ex . Message , "Unable to import file" ) ;
}
2018-05-01 11:20:39 +08:00
#endif
2018-01-10 12:55:19 +08:00
}
RefreshMainListView ( ) ;
2017-09-21 18:33:05 +08:00
}
private void ImportRaw ( )
{
if ( ! EditMode ) return ;
2018-01-10 11:17:30 +08:00
if ( CurrentFolder ? . IsSearchResults ? ? false ) return ;
2018-02-26 20:49:06 +08:00
if ( ! EnsureRpfValidEncryption ( ) ) return ;
OpenFileDialog . Filter = string . Empty ;
if ( OpenFileDialog . ShowDialog ( this ) ! = DialogResult . OK )
{
return ; //canceled
}
var fpaths = OpenFileDialog . FileNames ;
ImportRaw ( fpaths , false ) ; //already checked encryption before the file dialog...
}
private void ImportRaw ( string [ ] fpaths , bool checkEncryption = true )
{
if ( ! EditMode ) return ;
if ( CurrentFolder ? . IsSearchResults ? ? false ) return ;
2018-01-10 11:17:30 +08:00
RpfDirectoryEntry parentrpffldr = CurrentFolder . RpfFolder ;
if ( parentrpffldr = = null )
{
MessageBox . Show ( "No parent RPF folder selected! This shouldn't happen. Refresh the view and try again." ) ;
return ;
}
2018-02-26 20:49:06 +08:00
if ( checkEncryption )
2018-01-10 11:17:30 +08:00
{
2018-02-26 20:49:06 +08:00
if ( ! EnsureRpfValidEncryption ( ) ) return ;
2018-01-10 11:17:30 +08:00
}
2018-02-28 00:46:06 +08:00
var filelist = new List < string > ( ) ;
var dirdict = new Dictionary < string , RpfDirectoryEntry > ( ) ;
2018-02-26 20:49:06 +08:00
foreach ( var fpath in fpaths )
2018-02-28 00:46:06 +08:00
{
try
{
if ( File . Exists ( fpath ) )
{
filelist . Add ( fpath ) ;
}
else if ( Directory . Exists ( fpath ) ) //create imported directory structure in the RPF.
{
//create the first directory entry.
var fdi = new DirectoryInfo ( fpath ) ;
var direntry = RpfFile . CreateDirectory ( parentrpffldr , fdi . Name ) ;
dirdict [ fpath ] = direntry ;
var dirpaths = Directory . GetFileSystemEntries ( fpath , "*" , SearchOption . AllDirectories ) ;
var newfiles = new List < string > ( ) ;
foreach ( var dirpath in dirpaths )
{
if ( File . Exists ( dirpath ) )
{
newfiles . Add ( dirpath ) ;
}
else if ( Directory . Exists ( dirpath ) )
{
var cdi = new DirectoryInfo ( dirpath ) ;
RpfDirectoryEntry pdirentry ;
if ( ! dirdict . TryGetValue ( cdi . Parent . FullName , out pdirentry ) )
{
pdirentry = direntry ; //fallback, shouldn't get here
}
if ( pdirentry ! = null )
{
var cdirentry = RpfFile . CreateDirectory ( pdirentry , cdi . Name ) ;
dirdict [ dirpath ] = cdirentry ;
}
}
}
foreach ( var newfile in newfiles )
{
var nfi = new FileInfo ( newfile ) ;
RpfDirectoryEntry ndirentry ;
if ( ! dirdict . TryGetValue ( nfi . DirectoryName , out ndirentry ) )
{
ndirentry = direntry ; //fallback, shouldn't get here
}
filelist . Add ( newfile ) ;
dirdict [ newfile ] = ndirentry ;
}
EnsureImportedFolder ( direntry , parentrpffldr ) ;
}
else
{ } //nothing to see here!
}
catch ( Exception ex )
{
MessageBox . Show ( ex . Message , "Unable to import folder" ) ;
}
}
foreach ( var fpath in filelist )
2018-01-10 11:17:30 +08:00
{
2018-02-26 20:49:06 +08:00
try
2018-01-10 11:17:30 +08:00
{
if ( ! File . Exists ( fpath ) )
{
continue ; //this shouldn't happen...
}
var fi = new FileInfo ( fpath ) ;
var fname = fi . Name ;
if ( fi . Length > 0x3FFFFFFF )
{
MessageBox . Show ( "File " + fname + " is too big! Max 1GB supported." , "Unable to import file" ) ;
continue ;
}
2018-02-26 20:49:06 +08:00
Cursor = Cursors . WaitCursor ;
2018-01-10 12:55:19 +08:00
2018-02-26 20:49:06 +08:00
byte [ ] data = File . ReadAllBytes ( fpath ) ;
2018-01-10 11:17:30 +08:00
2018-01-11 09:10:03 +08:00
2018-02-28 00:46:06 +08:00
var rpffldr = parentrpffldr ;
if ( dirdict . ContainsKey ( fpath ) )
{
rpffldr = dirdict [ fpath ] ;
}
var entry = RpfFile . CreateFile ( rpffldr , fname , data ) ;
EnsureImportedRpf ( entry , rpffldr ) ; //make sure structure is created if an RPF was imported
2018-01-11 09:10:03 +08:00
2018-02-26 20:49:06 +08:00
Cursor = Cursors . Default ;
}
catch ( Exception ex )
{
MessageBox . Show ( ex . Message , "Unable to import file" ) ;
2018-01-10 11:17:30 +08:00
}
}
RefreshMainListView ( ) ;
2017-09-21 18:33:05 +08:00
}
private void CopySelected ( )
{
//only really for edit mode...
MessageBox . Show ( "CopySelected TODO!" ) ;
}
private void CopyPath ( )
{
if ( MainListView . SelectedIndices . Count = = 0 )
{
2018-02-18 17:20:39 +08:00
Clipboard . SetText ( CurrentFolder ? . FullPath ? ? GTAFolder . GetCurrentGTAFolderWithTrailingSlash ( ) ) ;
2017-09-21 18:33:05 +08:00
}
else if ( MainListView . SelectedIndices . Count = = 1 )
{
var idx = MainListView . SelectedIndices [ 0 ] ;
if ( ( idx < 0 ) | | ( idx > = CurrentFiles . Count ) ) return ;
var f = CurrentFiles [ idx ] ;
if ( f . FullPath ! = null )
{
Clipboard . SetText ( f . FullPath ) ;
}
}
else
{
StringBuilder sb = new StringBuilder ( ) ;
foreach ( int idx in MainListView . SelectedIndices )
{
if ( ( idx < 0 ) | | ( idx > = CurrentFiles . Count ) ) return ;
var f = CurrentFiles [ idx ] ;
if ( f . FullPath ! = null )
{
sb . AppendLine ( f . FullPath ) ;
}
}
Clipboard . SetText ( sb . ToString ( ) ) ;
}
}
private void CopyPath ( string path )
{
Clipboard . SetText ( path ) ;
}
private void CopyFileList ( )
{
StringBuilder sb = new StringBuilder ( ) ;
if ( CurrentFiles ! = null )
{
foreach ( var file in CurrentFiles )
{
sb . AppendLine ( file . Name ) ;
}
}
Clipboard . SetText ( sb . ToString ( ) ) ;
}
private void RenameSelected ( )
{
if ( ! EditMode ) return ;
2018-01-12 12:19:32 +08:00
if ( CurrentFolder ? . IsSearchResults ? ? false ) return ;
2018-01-10 11:17:30 +08:00
if ( MainListView . SelectedIndices . Count ! = 1 ) return ;
var idx = MainListView . SelectedIndices [ 0 ] ;
if ( ( CurrentFiles ! = null ) & & ( CurrentFiles . Count > idx ) )
{
var item = CurrentFiles [ idx ] ;
string newname = Prompt . ShowDialog ( this , "Enter the new name for this item:" , "Rename item" , item . Name ) ;
if ( ! string . IsNullOrEmpty ( newname ) )
{
RenameItem ( item , newname ) ;
}
}
}
private void RenameItem ( MainListItem item , string newname )
{
if ( ! EditMode ) return ;
if ( item . Name = = newname ) return ;
if ( CurrentFolder ? . IsSearchResults ? ? false ) return ;
if ( ! IsFilenameOk ( newname ) ) return ; //new name contains invalid char(s). don't do anything
RpfFile file = item . Folder ? . RpfFile ;
RpfEntry entry = item . GetRpfEntry ( ) ;
try
{
if ( file ! = null )
{
//updates all items in the RPF with the new path - no actual file changes made here
RpfFile . RenameArchive ( file , newname ) ;
}
if ( entry ! = null )
{
2018-01-11 09:10:03 +08:00
if ( ! EnsureRpfValidEncryption ( ) ) return ;
2018-01-10 11:17:30 +08:00
//renaming an entry in an RPF
RpfFile . RenameEntry ( entry , newname ) ;
}
else
{
//renaming a filesystem item...
var dirinfo = new DirectoryInfo ( item . FullPath ) ;
var newpath = Path . Combine ( dirinfo . Parent . FullName , newname ) ;
if ( item . FullPath . ToLowerInvariant ( ) = = newpath . ToLowerInvariant ( ) )
{
return ; //filesystem tends to be case-insensitive... paths are the same
}
if ( ( item . Folder ! = null ) & & ( item . Folder . RpfFile = = null ) )
{
//renaming a filesystem folder...
Directory . Move ( item . FullPath , newpath ) ;
}
else
{
//renaming a filesystem file...
File . Move ( item . FullPath , newpath ) ;
}
}
if ( item . Folder ! = null )
{
RenameTreeFolder ( item . Folder , newname ) ;
}
RenameListItem ( item , newname ) ;
}
catch ( Exception ex )
{
MessageBox . Show ( "Error renaming " + item . Path + ": " + ex . Message , "Unable to rename item" ) ;
return ;
}
2017-09-21 18:33:05 +08:00
}
private void ReplaceSelected ( )
{
if ( ! EditMode ) return ;
2018-01-10 11:17:30 +08:00
if ( CurrentFolder ? . IsSearchResults ? ? false ) return ;
if ( MainListView . SelectedIndices . Count ! = 1 ) return ;
MessageBox . Show ( "ReplaceSelected TODO..." ) ;
//delete the selected items, and replace with... choose
2018-01-11 09:10:03 +08:00
//if (!EnsureRpfEncryptionType()) return;
2017-09-21 18:33:05 +08:00
}
private void DeleteSelected ( )
{
if ( ! EditMode ) return ;
2018-01-10 11:17:30 +08:00
if ( CurrentFolder ? . IsSearchResults ? ? false ) return ;
if ( MainListView . SelectedIndices . Count < = 0 ) return ;
//if (MainListView.SelectedIndices.Count == 1) //is confirmation always really necessary?
//{
// var item = CurrentFiles[MainListView.SelectedIndices[0]];
// if (MessageBox.Show("Are you sure you want to permantly delete " + item.Name + "?\nThis cannot be undone.", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes)
// {
// return;
// }
//}
//else
//{
// if (MessageBox.Show("Are you sure you want to permantly delete " + MainListView.SelectedIndices.Count.ToString() + " items?\nThis cannot be undone.", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes)
// {
// return;
// }
//}
var delitems = new List < MainListItem > ( ) ;
foreach ( int idx in MainListView . SelectedIndices )
{
if ( ( idx < 0 ) | | ( idx > = CurrentFiles . Count ) ) return ;
var f = CurrentFiles [ idx ] ; //this could change when deleting.. so need to use the temp list
delitems . Add ( f ) ;
}
foreach ( var f in delitems )
{
DeleteItem ( f ) ;
}
}
private void DeleteItem ( MainListItem item )
{
try
{
2018-01-12 12:19:32 +08:00
if ( item . Folder ? . RpfFile ! = null )
{
//confirm deletion of RPF archives, just to be friendly.
if ( MessageBox . Show ( "Are you sure you want to delete this archive?\n" + item . Path , "Confirm delete archive" , MessageBoxButtons . YesNo ) ! = DialogResult . Yes )
{
return ;
}
}
2018-02-28 00:46:06 +08:00
else if ( ( item . Folder ? . GetItemCount ( ) ? ? 0 ) > 0 )
{
//confirm deletion of non-empty folders, just to be friendly.
if ( MessageBox . Show ( "Are you sure you want to delete this folder and all its contents?\n" + item . Path , "Confirm delete folder" , MessageBoxButtons . YesNo ) ! = DialogResult . Yes )
{
return ;
}
}
2018-01-12 12:19:32 +08:00
2018-01-10 11:17:30 +08:00
var parent = item . Parent ;
if ( parent . RpfFolder ! = null )
{
//delete an item in an RPF.
2018-01-11 09:10:03 +08:00
if ( ! EnsureRpfValidEncryption ( ) ) return ;
2018-01-10 11:17:30 +08:00
RpfEntry entry = item . GetRpfEntry ( ) ;
RpfFile . DeleteEntry ( entry ) ;
}
else
{
//delete an item in the filesystem.
if ( ( item . Folder ! = null ) & & ( item . Folder . RpfFile = = null ) )
{
Directory . Delete ( item . FullPath ) ;
}
else
{
File . Delete ( item . FullPath ) ;
}
}
if ( item . Folder ! = null )
{
RemoveTreeFolder ( item . Folder ) ;
}
RemoveListItem ( item ) ;
}
catch ( Exception ex )
{
MessageBox . Show ( "Error deleting " + item . Path + ": " + ex . Message , "Unable to delete " + item . Name ) ;
return ;
}
2017-09-21 18:33:05 +08:00
}
2018-01-12 12:19:32 +08:00
private void DefragmentSelected ( )
{
if ( ! EditMode ) return ;
if ( CurrentFolder ? . IsSearchResults ? ? false ) return ;
if ( MainListView . SelectedIndices . Count ! = 1 )
{
MessageBox . Show ( "Can only defragment one item at a time. Please have only one item selected." ) ;
return ;
}
var idx = MainListView . SelectedIndices [ 0 ] ;
if ( ( CurrentFiles = = null ) | | ( CurrentFiles . Count < = idx ) )
{
return ;
}
var item = CurrentFiles [ idx ] ;
var rpf = item . Folder ? . RpfFile ;
if ( rpf = = null )
{
MessageBox . Show ( "Can only defragment RPF archives!" ) ;
return ;
}
Form form = new Form ( ) {
Width = 450 ,
Height = 250 ,
FormBorderStyle = FormBorderStyle . FixedDialog ,
Text = "Defragment RPF Archive - CodeWalker by dexyfex" ,
StartPosition = FormStartPosition . CenterParent ,
MaximizeBox = false ,
MinimizeBox = false
} ;
var addCtrl = new Func < Control , Control > ( c = > { form . Controls . Add ( c ) ; return c ; } ) ;
var addLabel = new Func < int , string , Control > ( ( y , t ) = > {
return addCtrl ( new Label ( ) { Left = 30 , Top = y , Width = 370 , Height = 20 , Text = t } ) ;
} ) ;
var rpfNameLabel = addLabel ( 20 , "Archive: " + rpf . Path ) ;
var curSizeLabel = addLabel ( 40 , string . Empty ) ;
var newSizeLabel = addLabel ( 60 , string . Empty ) ;
var redSizeLabel = addLabel ( 80 , string . Empty ) ;
var statusLabel = addLabel ( 110 , string . Empty ) ;
var progressBar = addCtrl ( new ProgressBar ( ) { Left = 30 , Top = 130 , Width = 370 , Height = 20 , Minimum = 0 , Maximum = 1000 , MarqueeAnimationSpeed = 50 } ) as ProgressBar ;
var beginButton = addCtrl ( new Button ( ) { Text = "Begin Defragment" , Left = 30 , Top = 170 , Width = 120 } ) as Button ;
var closeButton = addCtrl ( new Button ( ) { Text = "Close" , Left = 320 , Top = 170 , Width = 80 } ) as Button ;
var inProgress = false ;
var updateProgress = new Action < string , float > ( ( s , p ) = > { form . Invoke ( new Action ( ( ) = > {
statusLabel . Text = s ;
progressBar . Value = Math . Max ( 0 , Math . Min ( ( int ) ( p * 1000 ) , 1000 ) ) ; //p in range 0..1
} ) ) ; } ) ;
var updateSizeLabels = new Action < bool > ( ( init ) = > {
var curSize = rpf . FileSize ;
var newSize = rpf . GetDefragmentedFileSize ( ) ;
var redSize = curSize - newSize ;
curSizeLabel . Text = "Archive current size: " + TextUtil . GetBytesReadable ( curSize ) ;
newSizeLabel . Text = "Defragmented size: " + TextUtil . GetBytesReadable ( newSize ) ;
redSizeLabel . Text = "Size reduction: " + TextUtil . GetBytesReadable ( redSize ) ;
if ( init ) statusLabel . Text = ( redSize < = 0 ) ? "Defragmentation not required." : "Ready to defragment." ;
} ) ;
var enableUi = new Action < bool > ( enable = > { form . Invoke ( new Action ( ( ) = > {
beginButton . Enabled = enable ;
closeButton . Enabled = enable ;
} ) ) ; } ) ;
var defragment = new Action ( ( ) = > { Task . Run ( ( ) = > {
if ( inProgress ) return ;
if ( ! EnsureRpfValidEncryption ( rpf ) ) return ;
inProgress = true ;
enableUi ( false ) ;
RpfFile . Defragment ( rpf , updateProgress ) ;
updateProgress ( "Defragment complete." , 1.0f ) ;
enableUi ( true ) ;
form . Invoke ( new Action ( ( ) = > { updateSizeLabels ( false ) ; } ) ) ;
inProgress = false ;
} ) ; } ) ;
updateSizeLabels ( true ) ;
beginButton . Click + = ( sender , e ) = > { defragment ( ) ; } ;
closeButton . Click + = ( sender , e ) = > { form . Close ( ) ; } ;
form . FormClosing + = ( s , e ) = > { e . Cancel = inProgress ; } ;
form . ShowDialog ( this ) ;
RefreshMainListView ( ) ;
}
2017-09-21 18:33:05 +08:00
private void SelectAll ( )
{
MainListView . SelectAllItems ( ) ;
UpdateSelectionUI ( ) ;
}
private void ShowInExplorer ( string path )
{
try
{
Process . Start ( "explorer" , "/select, \"" + path + "\"" ) ;
}
catch ( Exception ex )
{
UpdateErrorLog ( ex . ToString ( ) ) ;
}
}
private void OpenFileLocation ( )
{
var ind = - 1 ;
if ( MainListView . SelectedIndices . Count = = 1 )
{
ind = MainListView . SelectedIndices [ 0 ] ;
}
if ( ( CurrentFiles ! = null ) & & ( CurrentFiles . Count > ind ) )
{
var file = CurrentFiles [ ind ] ;
var path = file . Path . Replace ( '/' , '\\' ) ;
var bsind = path . LastIndexOf ( '\\' ) ;
if ( bsind > 0 )
{
path = path . Substring ( 0 , bsind ) ;
}
Navigate ( path ) ;
}
}
private void SetView ( View v )
{
MainListView . View = v ;
2018-03-04 00:17:12 +08:00
foreach ( var item in ViewMenu . DropDownItems )
2017-09-21 18:33:05 +08:00
{
2018-03-04 00:17:12 +08:00
var menu = item as ToolStripMenuItem ;
if ( menu ! = null )
{
menu . Checked = false ;
}
2017-09-21 18:33:05 +08:00
}
switch ( v )
{
case System . Windows . Forms . View . LargeIcon :
ViewLargeIconsMenu . Checked = true ;
break ;
case System . Windows . Forms . View . SmallIcon :
ViewSmallIconsMenu . Checked = true ;
break ;
case System . Windows . Forms . View . List :
ViewListMenu . Checked = true ;
break ;
case System . Windows . Forms . View . Details :
ViewDetailsMenu . Checked = true ;
break ;
}
}
2018-02-26 20:49:06 +08:00
private string GetDropFolder ( )
{
return Path . Combine ( Path . GetTempPath ( ) , "CodeWalkerDrop" ) ;
}
private string CreateDropFolder ( )
{
string drop = GetDropFolder ( ) ;
if ( ! Directory . Exists ( drop ) )
{
Directory . CreateDirectory ( drop ) ;
}
string dir = Path . Combine ( drop , Guid . NewGuid ( ) . ToString ( ) ) ;
if ( ! Directory . Exists ( dir ) )
{
Directory . CreateDirectory ( dir ) ;
}
return dir ;
}
private void CleanupDropFolder ( )
{
string drop = GetDropFolder ( ) ;
if ( Directory . Exists ( drop ) )
{
try
{
Directory . Delete ( drop , true ) ; //so broken :[
}
catch { } //not much we can do here...
}
}
2019-03-30 00:30:45 +08:00
protected override void WndProc ( ref Message m )
{
//handle back/forward buttons globally for all the form
if ( m . Msg = = 0x319 ) //WM_APPCOMMAND
{
var cmd = ( m . LParam . ToInt64 ( ) > > 16 ) & 0xFFF ;
if ( cmd = = 1 ) GoBack ( ) ; //APPCOMMAND_BROWSER_BACKWARD
if ( cmd = = 2 ) GoForward ( ) ; //APPCOMMAND_BROWSER_FORWARD
}
base . WndProc ( ref m ) ;
}
2018-02-26 20:49:06 +08:00
2017-09-21 18:33:05 +08:00
private void ExploreForm_Load ( object sender , EventArgs e )
{
Init ( ) ;
}
2018-02-26 20:49:06 +08:00
private void ExploreForm_FormClosed ( object sender , FormClosedEventArgs e )
{
CleanupDropFolder ( ) ;
}
2017-09-21 18:33:05 +08:00
private void MainTreeView_AfterSelect ( object sender , TreeViewEventArgs e )
{
var prev = CurrentFolder ;
CurrentFolder = e . Node ? . Tag as MainTreeFolder ;
LocationTextBox . Text = CurrentFolder ? . Path ? ? "" ;
if ( ! string . IsNullOrEmpty ( CurrentFolder ? . SearchTerm ) )
{
SearchTextBox . Text = CurrentFolder . SearchTerm ;
}
RefreshMainListView ( ) ;
NavigateComplete ( prev ) ;
}
private void MainTreeView_MouseUp ( object sender , MouseEventArgs e )
{
if ( e . Button = = MouseButtons . Right )
{
// Point where the mouse is clicked.
Point p = new Point ( e . X , e . Y ) ;
// Get the node that the user has clicked.
TreeNode node = MainTreeView . GetNodeAt ( p ) ;
if ( node ! = null )
{
// Select the node the user has clicked.
// The node appears selected until the menu is displayed on the screen.
//var oldNode = MainTreeView.SelectedNode;
MainTreeView . SelectedNode = node ;
ShowTreeContextMenu ( node , p ) ;
// Highlight the selected node.
//MainTreeView.SelectedNode = oldNode;
}
}
}
private void MainListView_RetrieveVirtualItem ( object sender , RetrieveVirtualItemEventArgs e )
{
var lvi = new ListViewItem ( ) ;
if ( ( CurrentFiles ! = null ) & & ( e . ItemIndex < CurrentFiles . Count ) )
{
var file = CurrentFiles [ e . ItemIndex ] ;
var fld = file . Folder ;
lvi . Tag = file ;
lvi . Text = file . Name ;
lvi . ToolTipText = file . Path ;
lvi . ImageIndex = file . ImageIndex ;
lvi . SubItems . Add ( file . FileTypeText ) ; //type column
lvi . SubItems . Add ( file . FileSizeText ) ; //size column
lvi . SubItems . Add ( file . Attributes ) ; //attributes column
lvi . SubItems . Add ( file . Path ) ; //path column
}
e . Item = lvi ;
}
private void MainListView_ColumnClick ( object sender , ColumnClickEventArgs e )
{
var newdir = SortDirection ;
var idx = e . Column ;
if ( idx = = SortColumnIndex )
{
switch ( SortDirection )
{
case SortOrder . None : newdir = SortOrder . Ascending ; break ;
case SortOrder . Ascending : newdir = SortOrder . Descending ; break ;
case SortOrder . Descending : newdir = SortOrder . Ascending ; break ;
}
}
SortMainListView ( idx , newdir ) ;
}
private void MainListView_MouseUp ( object sender , MouseEventArgs e )
{
if ( e . Button = = MouseButtons . Right )
{
MainListItem item = null ;
if ( ( MainListView . FocusedItem ! = null ) & & ( MainListView . FocusedItem . Bounds . Contains ( e . Location ) ) )
{
item = MainListView . FocusedItem . Tag as MainListItem ;
}
ShowListContextMenu ( item ) ;
}
UpdateSelectionUI ( ) ; //need to use this instead of SelectedIndexChanged because of shift-click bug :/
}
private void MainListView_KeyDown ( object sender , KeyEventArgs e )
{
var ctrl = ( e . Control & & ! e . Shift ) ;
var ctrlshft = ( e . Control & & e . Shift ) ;
var shft = ( e . Shift & & ! e . Control ) ;
switch ( e . KeyCode )
{
case Keys . P :
if ( ctrl ) ViewSelected ( ) ;
break ;
case Keys . H :
if ( ctrl ) ViewSelectedHex ( ) ;
break ;
case Keys . S :
if ( ctrl ) ExportXml ( ) ;
break ;
case Keys . E :
if ( ctrlshft ) ExtractAll ( ) ;
else if ( ctrl ) ExtractRaw ( ) ;
break ;
case Keys . Insert :
if ( MainListView . SelectedIndices . Count = = 1 )
{
if ( shft ) ReplaceSelected ( ) ;
}
else
{
if ( shft ) ImportXml ( ) ;
else if ( ! ctrl ) ImportRaw ( ) ;
}
break ;
case Keys . C :
if ( ctrlshft ) CopyPath ( ) ;
else if ( ctrl ) CopySelected ( ) ;
break ;
case Keys . F2 :
RenameSelected ( ) ;
break ;
case Keys . Delete :
if ( shft ) DeleteSelected ( ) ;
break ;
case Keys . A :
if ( ctrl ) SelectAll ( ) ;
break ;
}
}
private void MainListView_KeyUp ( object sender , KeyEventArgs e )
{
UpdateSelectionUI ( ) ; //need to use this instead of SelectedIndexChanged because of shift-click bug :/
}
private void MainListView_ItemActivate ( object sender , EventArgs e )
{
if ( MainListView . SelectedIndices . Count = = 1 )
{
var idx = MainListView . SelectedIndices [ 0 ] ;
if ( ( idx > = 0 ) & & ( idx < CurrentFiles . Count ) )
{
var file = CurrentFiles [ idx ] ;
if ( file . Folder ! = null )
{
Navigate ( file . Folder ) ;
}
else
{
//a file was activated. open it... (or, perform "default action"?)
View ( file ) ;
}
}
}
else
{
//how to activate multiple items? open files?
}
}
2018-01-10 11:17:30 +08:00
private void MainListView_AfterLabelEdit ( object sender , LabelEditEventArgs e )
{
if ( ( CurrentFiles ! = null ) & & ( CurrentFiles . Count > e . Item ) & & ( ! string . IsNullOrEmpty ( e . Label ) ) )
{
RenameItem ( CurrentFiles [ e . Item ] , e . Label ) ;
}
}
2018-02-26 20:49:06 +08:00
private void MainListView_ItemDrag ( object sender , ItemDragEventArgs e )
{
if ( MainListView . SelectedIndices . Count < = 0 ) return ;
var dir = CreateDropFolder ( ) ;
var filenames = new List < string > ( ) ;
var errors = new List < string > ( ) ;
Cursor = Cursors . WaitCursor ;
2018-02-28 00:46:06 +08:00
var writeFile = new Action < MainListItem , string , bool > ( ( file , outdir , addfilename ) = >
{
if ( file . FileSize > 0x6400000 ) //100MB
{
errors . Add ( file . Name + " is greater than 100MB, drag-drop for large files is disabled." ) ;
return ;
}
try
{
var data = GetFileDataCompressResources ( file ) ;
var filename = Path . Combine ( outdir , file . Name ) ;
File . WriteAllBytes ( filename , data ) ;
if ( addfilename )
{
filenames . Add ( filename ) ;
}
}
catch ( Exception ex )
{
errors . Add ( ex . ToString ( ) ) ;
}
} ) ;
2018-02-26 20:49:06 +08:00
for ( int i = 0 ; i < MainListView . SelectedIndices . Count ; i + + )
{
var idx = MainListView . SelectedIndices [ i ] ;
if ( ( idx < 0 ) | | ( idx > = CurrentFiles . Count ) ) continue ;
var file = CurrentFiles [ idx ] ;
if ( ( file . Folder = = null ) | | ( file . Folder . RpfFile ! = null ) )
{
2018-02-28 00:46:06 +08:00
//item is a file (or RPF archive).
writeFile ( file , dir , true ) ;
}
else
{
//item is a folder.
var parentpath = file . Parent . Path ;
var folderstack = new Stack < MainTreeFolder > ( ) ;
folderstack . Push ( file . Folder ) ;
while ( folderstack . Count > 0 )
2018-02-26 20:49:06 +08:00
{
2018-02-28 00:46:06 +08:00
var folder = folderstack . Pop ( ) ;
var folderitems = folder . GetListItems ( ) ;
var relpath = folder . Path . Replace ( parentpath , "" ) ;
var abspath = dir + relpath ;
if ( ! Directory . Exists ( abspath ) )
{
Directory . CreateDirectory ( abspath ) ; //create the temp directory...
}
foreach ( var item in folderitems )
{
if ( ( item . Folder = = null ) | | ( item . Folder . RpfFile ! = null ) )
{
writeFile ( item , abspath , false ) ;
}
else
{
folderstack . Push ( item . Folder ) ;
}
}
2018-02-26 20:49:06 +08:00
}
2018-02-28 00:46:06 +08:00
filenames . Add ( dir + "\\" + file . Name ) ;
2018-02-26 20:49:06 +08:00
}
}
Cursor = Cursors . Default ;
if ( filenames . Count > 0 )
{
DataObject dataobj = new DataObject ( DataFormats . FileDrop , filenames . ToArray ( ) ) ;
DoDragDrop ( dataobj , DragDropEffects . Copy ) ;
}
else
{
if ( errors . Count > 0 )
{
MessageBox . Show ( "Errors encountered while dragging:\n" + string . Join ( "\n" , errors . ToArray ( ) ) ) ;
}
}
}
private void MainListView_DragEnter ( object sender , DragEventArgs e )
{
if ( ! EditMode ) return ;
if ( CurrentFolder ? . IsSearchResults ? ? false ) return ;
if ( e . Data . GetDataPresent ( DataFormats . FileDrop ) )
{
var files = e . Data . GetData ( DataFormats . FileDrop ) as string [ ] ;
if ( ( files ! = null ) & & ( files . Length > 0 ) )
{
if ( ! files [ 0 ] . StartsWith ( GetDropFolder ( ) , StringComparison . InvariantCultureIgnoreCase ) ) //don't dry to drop on ourselves...
{
e . Effect = DragDropEffects . Copy ;
}
}
}
}
private void MainListView_DragDrop ( object sender , DragEventArgs e )
{
if ( ! EditMode ) return ;
if ( CurrentFolder ? . IsSearchResults ? ? false ) return ;
if ( e . Data . GetDataPresent ( DataFormats . FileDrop ) )
{
var files = e . Data . GetData ( DataFormats . FileDrop ) as string [ ] ;
if ( ( files = = null ) | | ( files . Length < = 0 ) ) return ;
if ( files [ 0 ] . StartsWith ( GetDropFolder ( ) , StringComparison . InvariantCultureIgnoreCase ) ) return ; //don't dry to drop on ourselves...
ImportRaw ( files ) ;
}
}
2017-09-21 18:33:05 +08:00
private void BackButton_ButtonClick ( object sender , EventArgs e )
{
GoBack ( ) ;
}
private void BackListButton_Click ( object sender , EventArgs e )
{
var step = ( sender as ToolStripItem ) ? . Tag as MainTreeFolder ;
if ( step = = null ) return ;
GoBack ( step ) ;
}
private void ForwardButton_ButtonClick ( object sender , EventArgs e )
{
GoForward ( ) ;
}
private void ForwardListButton_Click ( object sender , EventArgs e )
{
var step = ( sender as ToolStripItem ) ? . Tag as MainTreeFolder ;
if ( step = = null ) return ;
GoForward ( step ) ;
}
private void UpButton_ButtonClick ( object sender , EventArgs e )
{
GoUp ( ) ;
}
private void UpListButton_Click ( object sender , EventArgs e )
{
var step = ( sender as ToolStripItem ) ? . Tag as MainTreeFolder ;
if ( step = = null ) return ;
GoUp ( step ) ;
}
private void LocationTextBox_KeyPress ( object sender , KeyPressEventArgs e )
{
if ( e . KeyChar = = 13 )
{
Navigate ( LocationTextBox . Text ) ;
e . Handled = true ;
}
}
private void LocationTextBox_Enter ( object sender , EventArgs e )
{
BeginInvoke ( new Action ( ( ) = > LocationTextBox . SelectAll ( ) ) ) ;
}
private void GoButton_Click ( object sender , EventArgs e )
{
Navigate ( LocationTextBox . Text ) ;
}
private void RefreshButton_Click ( object sender , EventArgs e )
{
Task . Run ( ( ) = >
{
UpdateStatus ( "Scanning..." ) ;
RefreshMainTreeView ( ) ;
UpdateStatus ( "Scan complete." ) ;
} ) ;
}
2018-01-10 11:17:30 +08:00
private void EditModeButton_Click ( object sender , EventArgs e )
{
EnableEditMode ( ! EditMode ) ;
}
2017-09-21 18:33:05 +08:00
private void SearchTextBox_KeyPress ( object sender , KeyPressEventArgs e )
{
if ( e . KeyChar = = 13 )
{
SearchButton_ButtonClick ( sender , e ) ;
e . Handled = true ;
}
}
private void SearchTextBox_Enter ( object sender , EventArgs e )
{
BeginInvoke ( new Action ( ( ) = > SearchTextBox . SelectAll ( ) ) ) ;
}
private void SearchButton_ButtonClick ( object sender , EventArgs e )
{
if ( SearchGlobalButton . Checked )
{
Search ( SearchTextBox . Text ) ;
}
else
{
Filter ( SearchTextBox . Text ) ;
}
}
private void SearchGlobalButton_Click ( object sender , EventArgs e )
{
Search ( SearchTextBox . Text ) ;
}
private void SearchFilterButton_Click ( object sender , EventArgs e )
{
Filter ( SearchTextBox . Text ) ;
}
private void TreeContextCopyPathMenu_Click ( object sender , EventArgs e )
{
var f = MainTreeView . SelectedNode ? . Tag as MainTreeFolder ;
if ( f ! = null )
{
CopyPath ( f . FullPath ) ;
}
}
private void TreeContextWinExplorerMenu_Click ( object sender , EventArgs e )
{
var folder = MainTreeView . SelectedNode ? . Tag as MainTreeFolder ;
2018-02-18 17:20:39 +08:00
var path = folder ? . FullPath ? ? GTAFolder . GetCurrentGTAFolderWithTrailingSlash ( ) ;
2017-09-21 18:33:05 +08:00
ShowInExplorer ( path ) ;
}
private void TreeContextExpandMenu_Click ( object sender , EventArgs e )
{
if ( MainTreeView . SelectedNode ! = null )
{
MainTreeView . SelectedNode . Expand ( ) ;
}
}
private void TreeContextCollapseMenu_Click ( object sender , EventArgs e )
{
if ( MainTreeView . SelectedNode ! = null )
{
MainTreeView . SelectedNode . Collapse ( ) ;
}
}
private void TreeContextCollapseAllMenu_Click ( object sender , EventArgs e )
{
var seln = MainTreeView . SelectedNode ;
foreach ( TreeNode root in MainTreeView . Nodes )
{
foreach ( TreeNode n in root . Nodes )
{
n . Collapse ( false ) ; //collapse the first level nodes (not the roots)
}
}
if ( MainTreeView . SelectedNode ! = seln )
{
TreeViewEventArgs tve = new TreeViewEventArgs ( MainTreeView . SelectedNode ) ;
MainTreeView_AfterSelect ( MainTreeView , tve ) ; //for some reason, this event doesn't get raised when the selected node changes here
}
}
private void ListContextViewMenu_Click ( object sender , EventArgs e )
{
ViewSelected ( ) ;
}
private void ListContextViewHexMenu_Click ( object sender , EventArgs e )
{
ViewSelectedHex ( ) ;
}
private void ListContextExportXmlMenu_Click ( object sender , EventArgs e )
{
ExportXml ( ) ;
}
private void ListContextExtractRawMenu_Click ( object sender , EventArgs e )
{
ExtractRaw ( ) ;
}
2017-09-27 00:59:39 +08:00
private void ListContextExtractUncompressedMenu_Click ( object sender , EventArgs e )
{
ExtractUncompressed ( ) ;
}
2017-09-21 18:33:05 +08:00
private void ListContextExtractAllMenu_Click ( object sender , EventArgs e )
{
ExtractAll ( ) ;
}
2018-01-10 11:17:30 +08:00
private void ListContextNewFolderMenu_Click ( object sender , EventArgs e )
{
NewFolder ( ) ;
}
private void ListContextNewRpfArchiveMenu_Click ( object sender , EventArgs e )
{
NewRpfArchive ( ) ;
}
2019-03-20 18:21:47 +08:00
private void ListContextImportFbxMenu_Click ( object sender , EventArgs e )
{
ImportFbx ( ) ;
}
2017-09-21 18:33:05 +08:00
private void ListContextImportXmlMenu_Click ( object sender , EventArgs e )
{
ImportXml ( ) ;
}
private void ListContextImportRawMenu_Click ( object sender , EventArgs e )
{
ImportRaw ( ) ;
}
private void ListContextCopyMenu_Click ( object sender , EventArgs e )
{
CopySelected ( ) ;
}
private void ListContextCopyPathMenu_Click ( object sender , EventArgs e )
{
CopyPath ( ) ;
}
private void ListContextCopyFileListMenu_Click ( object sender , EventArgs e )
{
CopyFileList ( ) ;
}
private void ListContextOpenFileLocationMenu_Click ( object sender , EventArgs e )
{
OpenFileLocation ( ) ;
}
private void ListContextRenameMenu_Click ( object sender , EventArgs e )
{
RenameSelected ( ) ;
}
private void ListContextReplaceMenu_Click ( object sender , EventArgs e )
{
ReplaceSelected ( ) ;
}
private void ListContextDeleteMenu_Click ( object sender , EventArgs e )
{
DeleteSelected ( ) ;
}
2018-01-12 12:19:32 +08:00
private void ListContextDefragmentMenu_Click ( object sender , EventArgs e )
{
DefragmentSelected ( ) ;
}
2017-09-21 18:33:05 +08:00
private void ListContextSelectAllMenu_Click ( object sender , EventArgs e )
{
SelectAll ( ) ;
}
private void FileExitMenu_Click ( object sender , EventArgs e )
{
Close ( ) ;
}
private void EditViewMenu_Click ( object sender , EventArgs e )
{
ViewSelected ( ) ;
}
private void EditViewHexMenu_Click ( object sender , EventArgs e )
{
ViewSelectedHex ( ) ;
}
private void EditExportXmlMenu_Click ( object sender , EventArgs e )
{
ExportXml ( ) ;
}
private void EditExtractRawMenu_Click ( object sender , EventArgs e )
{
ExtractRaw ( ) ;
}
private void EditExtractAllMenu_Click ( object sender , EventArgs e )
{
ExtractAll ( ) ;
}
2019-03-20 18:21:47 +08:00
private void EditImportFbxMenu_Click ( object sender , EventArgs e )
{
ImportFbx ( ) ;
}
2017-09-21 18:33:05 +08:00
private void EditImportXmlMenu_Click ( object sender , EventArgs e )
{
ImportXml ( ) ;
}
private void EditImportRawMenu_Click ( object sender , EventArgs e )
{
ImportRaw ( ) ;
}
private void EditCopyMenu_Click ( object sender , EventArgs e )
{
CopySelected ( ) ;
}
private void EditCopyPathMenu_Click ( object sender , EventArgs e )
{
CopyPath ( ) ;
}
private void EditCopyFileListMenu_Click ( object sender , EventArgs e )
{
CopyFileList ( ) ;
}
private void EditRenameMenu_Click ( object sender , EventArgs e )
{
RenameSelected ( ) ;
}
private void EditReplaceMenu_Click ( object sender , EventArgs e )
{
ReplaceSelected ( ) ;
}
private void EditDeleteMenu_Click ( object sender , EventArgs e )
{
DeleteSelected ( ) ;
}
private void EditSelectAllMenu_Click ( object sender , EventArgs e )
{
SelectAll ( ) ;
}
private void ViewLargeIconsMenu_Click ( object sender , EventArgs e )
{
SetView ( System . Windows . Forms . View . LargeIcon ) ;
}
private void ViewSmallIconsMenu_Click ( object sender , EventArgs e )
{
SetView ( System . Windows . Forms . View . SmallIcon ) ;
}
private void ViewListMenu_Click ( object sender , EventArgs e )
{
SetView ( System . Windows . Forms . View . List ) ;
}
private void ViewDetailsMenu_Click ( object sender , EventArgs e )
{
SetView ( System . Windows . Forms . View . Details ) ;
}
2018-03-04 00:09:39 +08:00
private void ViewThemeWindowsMenu_Click ( object sender , EventArgs e )
{
SetTheme ( "Windows" ) ;
}
private void ViewThemeBlueMenu_Click ( object sender , EventArgs e )
{
SetTheme ( "Blue" ) ;
}
private void ViewThemeLightMenu_Click ( object sender , EventArgs e )
{
SetTheme ( "Light" ) ;
}
private void ViewThemeDarkMenu_Click ( object sender , EventArgs e )
{
SetTheme ( "Dark" ) ;
}
2017-09-21 18:33:05 +08:00
private void ToolsOptionsMenu_Click ( object sender , EventArgs e )
{
MessageBox . Show ( "Options TODO!" ) ;
}
private void ToolsRpfBrowserMenu_Click ( object sender , EventArgs e )
{
BrowseForm f = new BrowseForm ( ) ;
f . Show ( this ) ;
}
2017-12-24 20:36:18 +08:00
private void ToolsBinSearchMenu_Click ( object sender , EventArgs e )
{
BinarySearchForm f = new BinarySearchForm ( FileCache ) ;
f . Show ( this ) ;
}
2017-09-21 18:33:05 +08:00
}
public class MainTreeFolder
{
public string Name { get ; set ; }
public string Path { get ; set ; }
public string FullPath { get ; set ; }
public RpfFile RpfFile { get ; set ; }
public RpfDirectoryEntry RpfFolder { get ; set ; }
public List < string > Files { get ; set ; }
public MainTreeFolder Parent { get ; set ; }
public List < MainTreeFolder > Children { get ; set ; }
public List < MainListItem > ListItems { get ; set ; }
2018-01-10 11:17:30 +08:00
public TreeNode TreeNode { get ; set ; }
2017-09-21 18:33:05 +08:00
public bool IsSearchResults { get ; set ; }
public string SearchTerm { get ; set ; }
public void AddFile ( string file )
{
if ( Files = = null ) Files = new List < string > ( ) ;
Files . Add ( file ) ;
}
public void AddChild ( MainTreeFolder child )
{
if ( Children = = null ) Children = new List < MainTreeFolder > ( ) ;
Children . Add ( child ) ;
child . Parent = this ;
}
public void AddChildToHierarchy ( MainTreeFolder child )
{
var relpath = child . Path . Replace ( Path + "\\" , "" ) ;
var idx = relpath . IndexOf ( '\\' ) ;
var lidx = 0 ;
var parent = this ;
while ( idx > 0 )
{
var pname = relpath . Substring ( lidx , idx - lidx ) ;
if ( parent . Children = = null ) break ;
foreach ( var tc in parent . Children )
{
2018-02-28 00:46:06 +08:00
if ( tc . Name . Equals ( pname , StringComparison . InvariantCultureIgnoreCase ) )
2017-09-21 18:33:05 +08:00
{
parent = tc ;
break ;
}
}
lidx = idx + 1 ;
if ( lidx > = relpath . Length ) break ;
idx = relpath . IndexOf ( '\\' , lidx ) ;
}
parent . AddChild ( child ) ;
}
public List < MainListItem > GetListItems ( )
{
if ( ListItems = = null )
{
ListItems = new List < MainListItem > ( ) ;
2018-02-18 17:20:39 +08:00
var rootpath = GTAFolder . GetCurrentGTAFolderWithTrailingSlash ( ) ;
2017-09-21 18:33:05 +08:00
if ( Children ! = null )
{
foreach ( var child in Children )
{
ListItems . Add ( new MainListItem ( child ) ) ;
}
}
if ( Files ! = null )
{
foreach ( var file in Files )
{
ListItems . Add ( new MainListItem ( file , rootpath , this ) ) ;
}
}
if ( ( RpfFolder ! = null ) & & ( RpfFolder . Files ! = null ) )
{
foreach ( var file in RpfFolder . Files )
{
if ( file . NameLower . EndsWith ( ".rpf" ) ) continue ; //RPF files are already added..
ListItems . Add ( new MainListItem ( file , rootpath , this ) ) ;
}
}
}
return ListItems ;
}
public int GetItemCount ( )
{
int ic = 0 ;
if ( Children ! = null ) ic + = Children . Count ;
if ( Files ! = null ) ic + = Files . Count ;
if ( ( RpfFolder ! = null ) & & ( RpfFolder . Files ! = null ) )
{
foreach ( var file in RpfFolder . Files )
{
if ( file . NameLower . EndsWith ( ".rpf" ) ) continue ; //RPF files are already added..
ic + + ;
}
}
return ic ;
}
public string GetToolText ( )
{
if ( string . IsNullOrEmpty ( Path ) ) return Name ;
return Path ;
}
public int Search ( string term , ExploreForm form )
{
int resultcount = 0 ;
//if (!form.Searching) return resultcount;
form . UpdateStatus ( "Searching " + Path + "..." ) ;
if ( Name . ToLowerInvariant ( ) . Contains ( term ) )
{
form . AddSearchResult ( new MainListItem ( this ) ) ;
resultcount + + ;
}
2018-02-18 17:20:39 +08:00
var rootpath = GTAFolder . GetCurrentGTAFolderWithTrailingSlash ( ) ;
2017-09-21 18:33:05 +08:00
if ( Files ! = null )
{
foreach ( var file in Files )
{
//if (!form.Searching) return resultcount;
var fi = new FileInfo ( file ) ;
if ( fi . Name . ToLowerInvariant ( ) . Contains ( term ) )
{
form . AddSearchResult ( new MainListItem ( file , rootpath , this ) ) ;
resultcount + + ;
}
}
}
if ( ( RpfFolder ! = null ) & & ( RpfFolder . Files ! = null ) )
{
foreach ( var file in RpfFolder . Files )
{
//if (!form.Searching) return resultcount;
if ( file . NameLower . EndsWith ( ".rpf" ) ) continue ; //don't search rpf files..
if ( file . NameLower . Contains ( term ) )
{
form . AddSearchResult ( new MainListItem ( file , rootpath , this ) ) ;
resultcount + + ;
}
}
}
if ( Children ! = null )
{
foreach ( var child in Children )
{
//if (!form.Searching) return resultcount;
resultcount + = child . Search ( term , form ) ;
}
}
form . AddSearchResult ( null ) ;
return resultcount ;
}
public override string ToString ( )
{
return Name ;
}
}
public class MainListItem
{
public string Name { get ; set ; }
public MainTreeFolder Parent { get ; set ; }
public MainTreeFolder Folder { get ; set ; }
public RpfFileEntry File { get ; set ; }
public string Path { get ; set ; }
public string FullPath { get ; set ; }
public FileTypeInfo FileType { get ; set ; }
public string FileTypeText { get ; set ; }
public long FileSize { get ; set ; }
public string FileSizeText { get ; set ; }
public string Attributes { get ; set ; }
public int ImageIndex { get ; set ; }
public MainListItem ( MainTreeFolder f )
{
Parent = f ? . Parent ;
Folder = f ;
Name = f . Name ;
Path = f . Path ;
FullPath = f . FullPath ;
}
public MainListItem ( string file , string rootpath , MainTreeFolder parent )
{
Parent = parent ;
Name = new FileInfo ( file ) . Name ;
Path = file . Replace ( rootpath , "" ) ;
FullPath = file ;
}
public MainListItem ( RpfFileEntry file , string rootpath , MainTreeFolder parent )
{
Parent = parent ;
File = file ;
Name = file . Name ;
Path = file . Path ;
FullPath = rootpath + file . Path ;
}
public override string ToString ( )
{
return Name ;
}
public void CacheDetails ( ExploreForm form )
{
var fld = Folder ;
FileType = form . GetFileType ( Name ) ;
FileTypeText = FileType . Name ;
FileSizeText = "" ;
Attributes = "" ;
ImageIndex = FileType . ImageIndex ;
if ( File ! = null )
{
FileSize = File . GetFileSize ( ) ;
FileSizeText = TextUtil . GetBytesReadable ( FileSize ) ;
if ( File is RpfResourceFileEntry )
{
var resf = File as RpfResourceFileEntry ;
Attributes + = "Resource [V." + resf . Version . ToString ( ) + "]" ;
}
if ( File . IsEncrypted )
{
if ( Attributes . Length > 0 ) Attributes + = ", " ;
Attributes + = "Encrypted" ;
}
}
else if ( fld ! = null )
{
if ( fld . RpfFile ! = null )
{
FileSize = fld . RpfFile . FileSize ;
FileSizeText = TextUtil . GetBytesReadable ( FileSize ) ;
2018-01-11 09:10:03 +08:00
Attributes + = fld . RpfFile . Encryption . ToString ( ) + " encryption" ;
2017-09-21 18:33:05 +08:00
}
else
{
FileTypeText = "Folder" ;
ImageIndex = 1 ; //FOLDER imageIndex
var ic = fld . GetItemCount ( ) ;
FileSize = ic ;
FileSizeText = ic . ToString ( ) + " item" + ( ( ic ! = 1 ) ? "s" : "" ) ;
}
}
else
{
var fi = new FileInfo ( FullPath ) ;
if ( fi . Exists )
{
FileSize = fi . Length ;
FileSizeText = TextUtil . GetBytesReadable ( fi . Length ) ;
}
}
}
public int SortCompare ( MainListItem i , int col , SortOrder dir )
{
var desc = ( dir = = SortOrder . Descending ) ;
if ( Folder ! = null )
{
if ( i . Folder = = null ) return desc ? 1 : - 1 ;
}
else if ( i . Folder ! = null )
{
return desc ? - 1 : 1 ;
}
var i1 = this ;
var i2 = i ;
if ( desc )
{
i1 = i ;
i2 = this ;
}
switch ( col )
{
default :
case 0 : //Name column
return i1 . Name . CompareTo ( i2 . Name ) ;
case 1 : //Type column
var ftc = i1 . FileTypeText . CompareTo ( i2 . FileTypeText ) ;
if ( ftc = = 0 ) return i1 . Name . CompareTo ( i2 . Name ) ; //same type, sort by name...
return ftc ;
case 2 : //Size column
return i1 . FileSize . CompareTo ( i2 . FileSize ) ;
case 3 : //Attributes column
var ac = i1 . Attributes . CompareTo ( i2 . Attributes ) ;
if ( ac = = 0 ) return i1 . Name . CompareTo ( i2 . Name ) ; //same attributes, sort by name...
return ac ;
case 4 : //path column
return i1 . Path . CompareTo ( i2 . Path ) ;
}
//return i1.Name.CompareTo(i2.Name);
}
2018-01-10 11:17:30 +08:00
public RpfEntry GetRpfEntry ( )
{
RpfFile file = Folder ? . RpfFile ;
RpfDirectoryEntry fldr = Folder ? . RpfFolder ;
RpfEntry entry = File ;
if ( entry = = null )
{
if ( file ! = null )
{
//for an RPF file, get its entry in the parent (if any).
entry = file . ParentFileEntry ;
}
else if ( fldr ! = null )
{
//RPF folders are referenced in the item.Folder
entry = fldr ;
}
}
return entry ;
}
2017-09-21 18:33:05 +08:00
}
public class FileTypeInfo
{
public string Name { get ; set ; }
public string Extension { get ; set ; }
public int ImageIndex { get ; set ; }
public FileTypeAction DefaultAction { get ; set ; }
2017-12-14 18:49:41 +08:00
public List < FileTypeInfo > SubTypes { get ; set ; }
2017-09-21 18:33:05 +08:00
public FileTypeInfo ( string extension , string name , int imageindex , FileTypeAction defaultAction )
{
Name = name ;
Extension = extension ;
ImageIndex = imageindex ;
DefaultAction = defaultAction ;
}
2017-12-14 18:49:41 +08:00
public void AddSubType ( FileTypeInfo t )
{
if ( SubTypes = = null ) SubTypes = new List < FileTypeInfo > ( ) ;
SubTypes . Add ( t ) ;
}
2017-09-21 18:33:05 +08:00
}
public enum FileTypeAction
{
ViewHex = 0 ,
ViewText = 1 ,
ViewXml = 2 ,
ViewYtd = 3 ,
ViewYmt = 4 ,
ViewYmf = 5 ,
ViewYmap = 6 ,
ViewYtyp = 7 ,
ViewJPso = 8 ,
ViewModel = 9 ,
ViewCut = 10 ,
ViewAwc = 11 ,
ViewGxt = 12 ,
ViewRel = 13 ,
ViewFxc = 14 ,
ViewYwr = 15 ,
ViewYvr = 16 ,
2017-09-29 20:23:37 +08:00
ViewYcd = 17 ,
2019-11-01 17:30:29 +08:00
ViewYnd = 18 ,
ViewCacheDat = 19 ,
2019-11-21 21:34:27 +08:00
ViewYed = 20 ,
ViewYld = 21 ,
ViewYfd = 22 ,
2017-09-21 18:33:05 +08:00
}
2018-01-10 11:17:30 +08:00
2017-09-21 18:33:05 +08:00
}