diff --git a/Snap2HTML/CommandLine.cs b/Snap2HTML/CommandLine.cs index 8610917..1aacf2b 100644 --- a/Snap2HTML/CommandLine.cs +++ b/Snap2HTML/CommandLine.cs @@ -1,4 +1,5 @@ // Source: http://jake.ginnivan.net/c-sharp-argument-parser/ (which is based on http://www.codeproject.com/Articles/3111/C-NET-Command-Line-Arguments-Parser , MIT License) +// Removed support for array arguments since snap2html does not need it, and it throws if you try adding a path with comma /* Examples: @@ -117,7 +118,9 @@ namespace CommandLine.Utility //Because of the split index 0 will be a empty string string valuesWithoutQuotes = RemoveMatchingQuotes(parts[2]); - AddListValues(parts[1], valuesWithoutQuotes.Split(',')); + // MOD: Don't split on commas + //AddListValues(parts[1], valuesWithoutQuotes.Split(',')); + Add( parts[1], valuesWithoutQuotes ); break; } } diff --git a/Snap2HTML/Properties/AssemblyInfo.cs b/Snap2HTML/Properties/AssemblyInfo.cs index b565d22..c41bdce 100644 --- a/Snap2HTML/Properties/AssemblyInfo.cs +++ b/Snap2HTML/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("RL Vision")] [assembly: AssemblyProduct("Snap2HTML")] -[assembly: AssemblyCopyright( "Copyright © RL Vision 2011-2017" )] +[assembly: AssemblyCopyright( "Copyright © RL Vision 2011-2020" )] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion( "2.00.0.0" )] -[assembly: AssemblyFileVersion( "2.00.0.0" )] +[assembly: AssemblyVersion( "2.1.0.0" )] +[assembly: AssemblyFileVersion( "2.1.0.0" )] diff --git a/Snap2HTML/Properties/Settings.Designer.cs b/Snap2HTML/Properties/Settings.Designer.cs index f512d73..eed84cc 100644 --- a/Snap2HTML/Properties/Settings.Designer.cs +++ b/Snap2HTML/Properties/Settings.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.18444 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -134,6 +134,7 @@ namespace Snap2HTML.Properties { } [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Configuration.SettingsProviderAttribute(typeof(PortableSettingsProvider))] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("")] public string txtTitle { diff --git a/Snap2HTML/Properties/Settings.settings b/Snap2HTML/Properties/Settings.settings index e4e639c..a5e0739 100644 --- a/Snap2HTML/Properties/Settings.settings +++ b/Snap2HTML/Properties/Settings.settings @@ -26,7 +26,7 @@ -1 - + diff --git a/Snap2HTML/ReadMe.txt b/Snap2HTML/ReadMe.txt index 75cb1e1..9718542 100644 --- a/Snap2HTML/ReadMe.txt +++ b/Snap2HTML/ReadMe.txt @@ -1,7 +1,7 @@ --- Snap2HTML ---------------------------------------------------------------- - Freeware by RL Vision (c) 2011-2017 + Freeware by RL Vision (c) 2011-2020 Homepage: http://www.rlvision.com Portable: @@ -22,7 +22,7 @@ ability to export data as plain text, csv or json. Still, everything is contained in a single HTML file that you can easily store or distribute. - Exported file listings can be used in many ways. One is as a complement + Snap2html file listings can be used in many ways. One is as a complement to your backups (note however that this program does not backup your files! It only creates a list of the files and directories). You can also keep a file list of e.g. external HDDs and other computers, in case @@ -119,6 +119,9 @@ -system - Include system items + -silent - Run without showing the window (only + if both -path and -outfile are used) + Notes: Using -path and -outfile will cause the program to automatically start generating the snapshot, and quit when done! @@ -135,7 +138,10 @@ "template.html" in the application folder. This is the base for the output, and you can modify it with your own enhancements and design changes. If you make something nice you are welcome, to send it to me and I might - distribute it with future versions of the program! + distribute it with future versions of the program or add a link below! + + Showcases: + Amstrad CPC Memory Engraved: https://acpc.me (Amazing!) --- Known Problems ---------------------------------------------------------- @@ -149,13 +155,16 @@ on Win7 Basic, otherwise it would hang when clicking on the browse for folders button. - Internet Explorer may fail to load very large files. The problems seems - to be a hard limit in some versions of IE. I have seen this problem in - IE11 myself. Being a hard limit there is no easy solution right now. + Only files you have access to can be read. Try "Run as Admin" if files are + missing. - Large file tables can be slow to render and appear to have hung the - browser, especially in Internet Explorer. The same can happen when - navigating away from such a large folder and freeing the memory. + Internet Explorer may fail to load very large files. The problems seems to + be a hard limit in some versions of IE. I have seen this problem in IE11 + myself. Being a hard limit there is no easy solution right now. + + Large file tables can be slow to render and appear to have hung the browser, + especially in Internet Explorer. The same can happen when navigating away + from such a large folder and freeing the memory. --- Version History --------------------------------------------------------- @@ -209,6 +218,14 @@ Fixed some bugs concerning filenames with odd characters Many other tweaks and fixes to improve the HTML template + v2.1 (2020-03-16) + Export functionality now has a button to save directly to disk + Added -silent option to run completely hidden from command line + Dates now show formatted in user's locale independent of who created + the file listing. Sort by date also works better. + 8 or so other bug fixes and minor enhancements + Internal code refactoring in preparation for future features + --- End User License Agreement ----------------------------------------------- diff --git a/Snap2HTML/frmMain.Designer.cs b/Snap2HTML/frmMain.Designer.cs index 52ddc1f..7218e60 100644 --- a/Snap2HTML/frmMain.Designer.cs +++ b/Snap2HTML/frmMain.Designer.cs @@ -44,7 +44,7 @@ this.chkSystem = new System.Windows.Forms.CheckBox(); this.cmdCreate = new System.Windows.Forms.Button(); this.txtRoot = new System.Windows.Forms.TextBox(); - this.label1 = new System.Windows.Forms.Label(); + this.labelRootFolder = new System.Windows.Forms.Label(); this.cmdBrowse = new System.Windows.Forms.Button(); this.tabPage3 = new System.Windows.Forms.TabPage(); this.linkLabel5 = new System.Windows.Forms.LinkLabel(); @@ -65,9 +65,9 @@ this.pictureBox2 = new System.Windows.Forms.PictureBox(); this.pictureBox1 = new System.Windows.Forms.PictureBox(); this.linkLabel1 = new System.Windows.Forms.LinkLabel(); - this.label5 = new System.Windows.Forms.Label(); - this.labelVersion = new System.Windows.Forms.Label(); - this.label3 = new System.Windows.Forms.Label(); + this.labelAboutSoftware = new System.Windows.Forms.Label(); + this.labelAboutVersion = new System.Windows.Forms.Label(); + this.labelAboutTitle = new System.Windows.Forms.Label(); this.folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog(); this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog(); this.backgroundWorker = new System.ComponentModel.BackgroundWorker(); @@ -124,7 +124,7 @@ this.tabPage1.Controls.Add(this.chkSystem); this.tabPage1.Controls.Add(this.cmdCreate); this.tabPage1.Controls.Add(this.txtRoot); - this.tabPage1.Controls.Add(this.label1); + this.tabPage1.Controls.Add(this.labelRootFolder); this.tabPage1.Controls.Add(this.cmdBrowse); this.tabPage1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.tabPage1.Location = new System.Drawing.Point(4, 22); @@ -251,14 +251,14 @@ this.txtRoot.TabIndex = 0; this.txtRoot.Text = global::Snap2HTML.Properties.Settings.Default.txtRoot; // - // label1 + // labelRootFolder // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(6, 12); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(62, 13); - this.label1.TabIndex = 1; - this.label1.Text = "Root folder:"; + this.labelRootFolder.AutoSize = true; + this.labelRootFolder.Location = new System.Drawing.Point(6, 12); + this.labelRootFolder.Name = "labelRootFolder"; + this.labelRootFolder.Size = new System.Drawing.Size(62, 13); + this.labelRootFolder.TabIndex = 1; + this.labelRootFolder.Text = "Root folder:"; // // cmdBrowse // @@ -357,9 +357,9 @@ this.tabPage2.Controls.Add(this.groupBoxMoreApps); this.tabPage2.Controls.Add(this.pictureBox1); this.tabPage2.Controls.Add(this.linkLabel1); - this.tabPage2.Controls.Add(this.label5); - this.tabPage2.Controls.Add(this.labelVersion); - this.tabPage2.Controls.Add(this.label3); + this.tabPage2.Controls.Add(this.labelAboutSoftware); + this.tabPage2.Controls.Add(this.labelAboutVersion); + this.tabPage2.Controls.Add(this.labelAboutTitle); this.tabPage2.Location = new System.Drawing.Point(4, 22); this.tabPage2.Name = "tabPage2"; this.tabPage2.Padding = new System.Windows.Forms.Padding(3); @@ -383,7 +383,7 @@ this.groupBoxMoreApps.Size = new System.Drawing.Size(318, 130); this.groupBoxMoreApps.TabIndex = 5; this.groupBoxMoreApps.TabStop = false; - this.groupBoxMoreApps.Text = "More utilities from RL Vision"; + this.groupBoxMoreApps.Text = "More utilities by me"; // // label33 // @@ -492,33 +492,33 @@ this.linkLabel1.Text = "http://www.rlvision.com"; this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked); // - // label5 + // labelAboutSoftware // - this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(163, 87); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(113, 13); - this.label5.TabIndex = 2; - this.label5.Text = "Freeware by RL Vision"; + this.labelAboutSoftware.AutoSize = true; + this.labelAboutSoftware.Location = new System.Drawing.Point(163, 87); + this.labelAboutSoftware.Name = "labelAboutSoftware"; + this.labelAboutSoftware.Size = new System.Drawing.Size(135, 13); + this.labelAboutSoftware.TabIndex = 2; + this.labelAboutSoftware.Text = "Free Software by RL Vision"; // - // labelVersion + // labelAboutVersion // - this.labelVersion.AutoSize = true; - this.labelVersion.Location = new System.Drawing.Point(163, 53); - this.labelVersion.Name = "labelVersion"; - this.labelVersion.Size = new System.Drawing.Size(41, 13); - this.labelVersion.TabIndex = 1; - this.labelVersion.Text = "version"; + this.labelAboutVersion.AutoSize = true; + this.labelAboutVersion.Location = new System.Drawing.Point(163, 53); + this.labelAboutVersion.Name = "labelAboutVersion"; + this.labelAboutVersion.Size = new System.Drawing.Size(41, 13); + this.labelAboutVersion.TabIndex = 1; + this.labelAboutVersion.Text = "version"; // - // label3 + // labelAboutTitle // - this.label3.AutoSize = true; - this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label3.Location = new System.Drawing.Point(161, 23); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(148, 29); - this.label3.TabIndex = 0; - this.label3.Text = "Snap2HTML"; + this.labelAboutTitle.AutoSize = true; + this.labelAboutTitle.Font = new System.Drawing.Font("Microsoft Sans Serif", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelAboutTitle.Location = new System.Drawing.Point(161, 23); + this.labelAboutTitle.Name = "labelAboutTitle"; + this.labelAboutTitle.Size = new System.Drawing.Size(148, 29); + this.labelAboutTitle.TabIndex = 0; + this.labelAboutTitle.Text = "Snap2HTML"; // // folderBrowserDialog1 // @@ -549,7 +549,7 @@ this.MinimizeBox = false; this.Name = "frmMain"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; - this.Text = "Snap2HTML (Press F1 for Help)"; + this.Text = "Snap2HTML"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmMain_FormClosing); this.Load += new System.EventHandler(this.frmMain_Load); this.Shown += new System.EventHandler(this.frmMain_Shown); @@ -581,7 +581,7 @@ private System.Windows.Forms.TabControl tabControl1; private System.Windows.Forms.TabPage tabPage1; private System.Windows.Forms.TextBox txtRoot; - private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label labelRootFolder; private System.Windows.Forms.Button cmdBrowse; private System.Windows.Forms.TabPage tabPage2; private System.Windows.Forms.Button cmdCreate; @@ -589,9 +589,9 @@ private System.Windows.Forms.SaveFileDialog saveFileDialog1; private System.Windows.Forms.PictureBox pictureBox1; private System.Windows.Forms.LinkLabel linkLabel1; - private System.Windows.Forms.Label label5; - private System.Windows.Forms.Label labelVersion; - private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label labelAboutSoftware; + private System.Windows.Forms.Label labelAboutVersion; + private System.Windows.Forms.Label labelAboutTitle; private System.ComponentModel.BackgroundWorker backgroundWorker; private System.Windows.Forms.Label label6; private System.Windows.Forms.CheckBox chkOpenOutput; diff --git a/Snap2HTML/frmMain.cs b/Snap2HTML/frmMain.cs index 303f4fd..27aec48 100644 --- a/Snap2HTML/frmMain.cs +++ b/Snap2HTML/frmMain.cs @@ -21,7 +21,8 @@ namespace Snap2HTML private void frmMain_Load( object sender, EventArgs e ) { - labelVersion.Text = "version " + Application.ProductVersion.Split( '.' )[0] + "." + Application.ProductVersion.Split( '.' )[1]; + this.Text = Application.ProductName + " (Press F1 for Help)"; + labelAboutVersion.Text = "version " + Application.ProductVersion.Split( '.' )[0] + "." + Application.ProductVersion.Split( '.' )[1]; // initialize some settings int left = Snap2HTML.Properties.Settings.Default.WindowLeft; @@ -51,6 +52,8 @@ namespace Snap2HTML cnt.AllowDrop = true; } + Opacity = 0; // for silent mode + initDone = true; } @@ -70,6 +73,8 @@ namespace Snap2HTML } } + var autoRun = false; + if (arguments.IsTrue("hidden")) chkHidden.Checked = true; if (arguments.IsTrue("system")) chkSystem.Checked = true; if( arguments.Exists( "path" ) ) @@ -85,12 +90,23 @@ namespace Snap2HTML // if outfile is also given, start generating snapshot if (arguments.Exists("outfile")) { + autoRun = true; outFile = arguments.Single("outfile"); cmdCreate.PerformClick(); } } } + // keep window hidden in silent mode + if( arguments.IsTrue( "silent" ) && autoRun ) + { + Visible = false; + } + else + { + Opacity = 100; + } + // run link/title after path, since path automatically updates title if( arguments.Exists( "link" ) ) { diff --git a/Snap2HTML/frmMain_BackgroundWorker.cs b/Snap2HTML/frmMain_BackgroundWorker.cs index e0a7573..cc108d0 100644 --- a/Snap2HTML/frmMain_BackgroundWorker.cs +++ b/Snap2HTML/frmMain_BackgroundWorker.cs @@ -6,6 +6,8 @@ using System.Drawing; using System.Text; using System.Windows.Forms; using CommandLine.Utility; +using System.IO; +using System.Diagnostics; namespace Snap2HTML { @@ -13,161 +15,45 @@ namespace Snap2HTML { private void backgroundWorker_DoWork( object sender, DoWorkEventArgs e ) { - backgroundWorker.ReportProgress( 0, "Reading folders..." ); - var sbDirArrays = new StringBuilder(); - int prevDepth = -100; - - // Get all folders - var dirs = new List(); - dirs.Insert( 0, txtRoot.Text ); var skipHidden = ( chkHidden.CheckState == CheckState.Unchecked ); var skipSystem = ( chkSystem.CheckState == CheckState.Unchecked ); - DirSearch( txtRoot.Text, dirs, skipHidden, skipSystem ); - dirs = SortDirList( dirs ); + // Get files & folders + var content = GetContent( txtRoot.Text, skipHidden, skipSystem ); + if( content == null ) + { + backgroundWorker.ReportProgress( 0, "Error reading source" ); + return; + } if( backgroundWorker.CancellationPending ) { backgroundWorker.ReportProgress( 0, "User cancelled" ); return; } - int totDirs = 0; - dirs.Add( "*EOF*" ); - long totSize = 0; - int totFiles = 0; - var lineBreakSymbol = ""; // could set to \n to make html more readable at the expense of increased size - - // Get files in folders - for( int d = 0; d < dirs.Count; d++ ) + // Convert to string with JS data object + var jsContent = BuildJavascriptContentArray( content, 0 ); + if( backgroundWorker.CancellationPending ) { - string currentDir = dirs[d]; - - try - { - int newDepth = currentDir.Split( System.IO.Path.DirectorySeparatorChar ).Length; - if( currentDir.Length < 64 && currentDir == System.IO.Path.GetPathRoot( currentDir ) ) newDepth--; // fix reading from rootfolder, <64 to avoid going over MAX_PATH - - prevDepth = newDepth; - - var sbCurrentDirArrays = new StringBuilder(); - - if( currentDir != "*EOF*" ) - { - bool no_problem = true; - - try - { - var files = new List( System.IO.Directory.GetFiles( currentDir, "*.*", System.IO.SearchOption.TopDirectoryOnly ) ); - files.Sort(); - int f = 0; - - string last_write_date = "-"; - last_write_date = System.IO.Directory.GetLastWriteTime( currentDir ).ToLocalTime().ToString(); - long dir_size = 0; - - sbCurrentDirArrays.Append( "D.p([" + lineBreakSymbol ); - var sDirWithForwardSlash = currentDir.Replace( @"\", "/" ); - sbCurrentDirArrays.Append( "\"" ).Append( MakeCleanJsString( sDirWithForwardSlash ) ).Append( "*" ).Append( dir_size ).Append( "*" ).Append( last_write_date ).Append( "\"," + lineBreakSymbol ); - f++; - long dirSize = 0; - foreach( string sFile in files ) - { - bool bInclude = true; - long fi_length = 0; - last_write_date = "-"; - try - { - System.IO.FileInfo fi = new System.IO.FileInfo( sFile ); - if( ( fi.Attributes & System.IO.FileAttributes.Hidden ) == System.IO.FileAttributes.Hidden && chkHidden.CheckState != CheckState.Checked ) bInclude = false; - if( ( fi.Attributes & System.IO.FileAttributes.System ) == System.IO.FileAttributes.System && chkSystem.CheckState != CheckState.Checked ) bInclude = false; - fi_length = fi.Length; - - try - { - last_write_date = fi.LastWriteTime.ToLocalTime().ToString(); - } - catch( Exception ex ) - { - Console.WriteLine( "{0} Exception caught.", ex ); - } - } - catch( Exception ex ) - { - Console.WriteLine( "{0} Exception caught.", ex ); - bInclude = false; - } - - if( bInclude ) - { - sbCurrentDirArrays.Append( "\"" ).Append( MakeCleanJsString( System.IO.Path.GetFileName( sFile ) ) ).Append( "*" ).Append( fi_length ).Append( "*" ).Append( last_write_date ).Append( "\"," + lineBreakSymbol ); - totSize += fi_length; - dirSize += fi_length; - totFiles++; - f++; - - if( totFiles % 9 == 0 ) - { - backgroundWorker.ReportProgress( 0, "Reading files... " + totFiles + " (" + sFile + ")" ); - } - - } - if( backgroundWorker.CancellationPending ) - { - backgroundWorker.ReportProgress( 0, "Operation Cancelled!" ); - return; - } - } - - // Add total dir size - sbCurrentDirArrays.Append( "" ).Append( dirSize ).Append( "," + lineBreakSymbol ); - - // Add subfolders - string subdirs = ""; - List lstSubDirs = new List( System.IO.Directory.GetDirectories( currentDir ) ); - lstSubDirs = SortDirList( lstSubDirs ); - foreach( string sTmp in lstSubDirs ) - { - int i = dirs.IndexOf( sTmp ); - if( i != -1 ) subdirs += i + "*"; - } - if( subdirs.EndsWith( "*" ) ) subdirs = subdirs.Remove( subdirs.Length - 1 ); - sbCurrentDirArrays.Append( "\"" ).Append( subdirs ).Append( "\"" + lineBreakSymbol ); // subdirs - sbCurrentDirArrays.Append( "])" ); - sbCurrentDirArrays.Append( "\n" ); - } - catch( Exception ex ) - { - Console.WriteLine( "{0} Exception caught.", ex ); - no_problem = false; - } - - if( no_problem == false ) // We need to keep folder even if error occurred for integrity - { - var sDirWithForwardSlash = currentDir.Replace( @"\", "/" ); - sbCurrentDirArrays = new StringBuilder(); - sbCurrentDirArrays.Append( "D.p([\"" ).Append( MakeCleanJsString( sDirWithForwardSlash ) ).Append( "*0*-\"," + lineBreakSymbol ); - sbCurrentDirArrays.Append( "0," + lineBreakSymbol ); // total dir size - sbCurrentDirArrays.Append( "\"\"" + lineBreakSymbol ); // subdirs - sbCurrentDirArrays.Append( "])\n" ); - no_problem = true; - } - - if( no_problem ) - { - sbDirArrays.Append( sbCurrentDirArrays.ToString() ); - totDirs++; - } - } - - } - catch( System.Exception ex ) - { - Console.WriteLine( "{0} exception caught: {1}", ex, ex.Message ); - } - + backgroundWorker.ReportProgress( 0, "User cancelled" ); + return; } - // -- Generate Output -- + // Calculate some stats + int totDirs = 0; + int totFiles = 0; + long totSize = 0; + foreach( var folder in content ) + { + totDirs++; + foreach( var file in folder.Files ) + { + totFiles++; + totSize += Int64.Parse( file.GetProp( "Size" ) ); + } + } + + // Let's generate the output backgroundWorker.ReportProgress( 0, "Generating HTML file..." ); @@ -188,7 +74,7 @@ namespace Snap2HTML } // Build HTML - sbContent.Replace( "[DIR DATA]", sbDirArrays.ToString() ); + sbContent.Replace( "[DIR DATA]", jsContent ); sbContent.Replace( "[TITLE]", txtTitle.Text ); sbContent.Replace( "[APP LINK]", "http://www.rlvision.com" ); sbContent.Replace( "[APP NAME]", Application.ProductName ); @@ -264,5 +150,285 @@ namespace Snap2HTML Application.Exit(); } } + + + // -------------------------------------------------------------------- + + public class SnappedFile + { + public SnappedFile( string name ) + { + this.Name = name; + this.Properties = new Dictionary(); + } + + public string Name { get; set; } + public Dictionary Properties { get; set; } + + public string GetProp( string key ) + { + if( this.Properties.ContainsKey( key ) ) + return this.Properties[key]; + else + return ""; + } + + } + + public class SnappedFolder + { + public SnappedFolder( string name, string path ) + { + this.Name = name; + this.Path = path; + this.Properties = new Dictionary(); + this.Files = new List(); + this.FullPath = ( this.Path + "\\" + this.Name ).Replace( "\\\\", "\\" ); + } + + public string Name { get; set; } + public string Path { get; set; } + public string FullPath { get; set; } + public Dictionary Properties { get; set; } + public List Files { get; set; } + + public string GetProp( string key ) + { + if( this.Properties.ContainsKey( key ) ) + return this.Properties[key]; + else + return ""; + } + } + + // -------------------------------------------------------------------- + + private List GetContent( string rootFolder, bool skipHidden, bool skipSystem ) + { + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + var result = new List(); + + // Get all folders + var dirs = new List(); + dirs.Insert( 0, rootFolder ); + DirSearch( rootFolder, dirs, skipHidden, skipSystem, stopwatch ); + dirs = SortDirList( dirs ); + + if( backgroundWorker.CancellationPending ) + { + return null; + } + + var totFiles = 0; + + stopwatch.Restart(); + + try + { + string modified_date; + string created_date; + + // Parse each folder + for( int d = 0; d < dirs.Count; d++ ) + { + // Get folder properties + var dirName = dirs[d]; + var currentDir = new SnappedFolder( Path.GetFileName( dirName ), Path.GetDirectoryName( dirName ) ); + if( dirName == Path.GetPathRoot( dirName ) ) + { + currentDir = new SnappedFolder( "", dirName ); + } + + modified_date = ""; + created_date = ""; + try + { + modified_date = ToUnixTimestamp(System.IO.Directory.GetLastWriteTime( dirName ).ToLocalTime()).ToString(); + created_date = ToUnixTimestamp( System.IO.Directory.GetCreationTime( dirName ).ToLocalTime() ).ToString(); + } + catch( Exception ex ) + { + Console.WriteLine( "{0} Exception caught.", ex ); + } + currentDir.Properties.Add( "Modified", modified_date ); + currentDir.Properties.Add( "Created", created_date ); + + + // Get files in folder + List files; + try + { + files = new List( System.IO.Directory.GetFiles( dirName, "*.*", System.IO.SearchOption.TopDirectoryOnly ) ); + } + catch( Exception ex ) + { + Console.WriteLine( "{0} Exception caught.", ex ); + result.Add( currentDir ); + continue; + } + files.Sort(); + + // Get file properties + foreach( string sFile in files ) + { + totFiles++; + if(stopwatch.ElapsedMilliseconds >= 50) + { + backgroundWorker.ReportProgress( 0, "Reading files... " + totFiles + " (" + sFile + ")" ); + stopwatch.Restart(); + } + + if( backgroundWorker.CancellationPending ) + { + return null; + } + + var currentFile = new SnappedFile( Path.GetFileName( sFile ) ); + try + { + System.IO.FileInfo fi = new System.IO.FileInfo( sFile ); + var isHidden = ( fi.Attributes & System.IO.FileAttributes.Hidden ) == System.IO.FileAttributes.Hidden; + var isSystem = ( fi.Attributes & System.IO.FileAttributes.System ) == System.IO.FileAttributes.System; + + if( ( isHidden && skipHidden ) || ( isSystem && skipSystem ) ) + { + continue; + } + + currentFile.Properties.Add( "Size", fi.Length.ToString() ); + + modified_date = "-"; + created_date = "-"; + try + { + modified_date = ToUnixTimestamp( fi.LastWriteTime.ToLocalTime() ).ToString(); + created_date = ToUnixTimestamp( fi.CreationTime.ToLocalTime() ).ToString(); + } + catch( Exception ex ) + { + Console.WriteLine( "{0} Exception caught.", ex ); + } + + currentFile.Properties.Add( "Modified", modified_date ); + currentFile.Properties.Add( "Created", created_date ); + + } + catch( Exception ex ) + { + Console.WriteLine( "{0} Exception caught.", ex ); + } + + currentDir.Files.Add( currentFile ); + } + + result.Add( currentDir ); + } + } + catch( System.Exception ex ) + { + Console.WriteLine( "{0} exception caught: {1}", ex, ex.Message ); + } + + return result; + } + + private string BuildJavascriptContentArray(List content, int startIndex) + { + // Data format: + // Each index in "dirs" array is an array representing a directory: + // First item in array: "directory path*always 0*directory modified date" + // Note that forward slashes are used instead of (Windows style) backslashes + // Then, for each each file in the directory: "filename*size of file*file modified date" + // Second to last item in array tells the total size of directory content + // Last item in array refrences IDs to all subdirectories of this dir (if any). + // ID is the item index in dirs array. + // Note: Modified date is in UNIX format + + backgroundWorker.ReportProgress( 0, "Processing content..." ); + + var result = new StringBuilder(); + + var lineBreakSymbol = ""; // Could be set to \n to make the html output more readable, at the expense of increased size + + + // Assign an ID to each folder. This is equal to the index in the JS data array + var dirIndexes = new Dictionary(); + for(var i=0; i>(); + foreach( var dir in content ) + { + subdirs.Add( dir.FullPath, new List() ); + } + if( !subdirs.ContainsKey( content[0].Path ) && content[0].Name != "" ) + { + subdirs.Add( content[0].Path, new List() ); + } + foreach( var dir in content ) + { + if( dir.Name != "" ) + { + try + { + subdirs[dir.Path].Add( dirIndexes[dir.FullPath] ); + } + catch( Exception ex ) + { + // orphan file or folder? + } + } + } + + + // Generate the data array + + foreach( var currentDir in content ) + { + var sbCurrentDirArrays = new StringBuilder(); + sbCurrentDirArrays.Append( "D.p([" + lineBreakSymbol ); + + var sDirWithForwardSlash = currentDir.FullPath.Replace( @"\", "/" ); + sbCurrentDirArrays.Append( "\"" ).Append( MakeCleanJsString( sDirWithForwardSlash ) ).Append( "*" ).Append( "0" ).Append( "*" ).Append( currentDir.GetProp("Modified") ).Append( "\"," + lineBreakSymbol ); + + long dirSize = 0; + + foreach( var currentFile in currentDir.Files ) + { + sbCurrentDirArrays.Append( "\"" ).Append( MakeCleanJsString( currentFile.Name ) ).Append( "*" ).Append( currentFile.GetProp( "Size" ) ).Append( "*" ).Append( currentFile.GetProp("Modified") ).Append( "\"," + lineBreakSymbol ); + try + { + dirSize += Int64.Parse( currentFile.GetProp("Size") ); + } + catch( Exception ex) + { + } + } + + // Add total dir size + sbCurrentDirArrays.Append( "" ).Append( dirSize ).Append( "," + lineBreakSymbol ); + + sbCurrentDirArrays.Append( "\"" ).Append( String.Join( "*", subdirs[currentDir.FullPath].ToArray() ) ).Append( "\"" + lineBreakSymbol ); // subdirs + + // Finalize + sbCurrentDirArrays.Append( "])" ); + sbCurrentDirArrays.Append( "\n" ); + result.Append( sbCurrentDirArrays.ToString() ); + + if( backgroundWorker.CancellationPending ) + { + return null; + } + } + + return result.ToString(); + } + } } + diff --git a/Snap2HTML/frmMain_Helpers.cs b/Snap2HTML/frmMain_Helpers.cs index 15e6d09..b99bb77 100644 --- a/Snap2HTML/frmMain_Helpers.cs +++ b/Snap2HTML/frmMain_Helpers.cs @@ -7,6 +7,7 @@ using System.Text; using System.Windows.Forms; using CommandLine.Utility; using System.IO; +using System.Diagnostics; namespace Snap2HTML { @@ -40,7 +41,7 @@ namespace Snap2HTML } // Recursive function to get all folders and subfolders of given path path - private void DirSearch( string sDir, List lstDirs, bool skipHidden, bool skipSystem ) + public void DirSearch( string sDir, List lstDirs, bool skipHidden, bool skipSystem, Stopwatch stopwatch ) { if( backgroundWorker.CancellationPending ) return; @@ -79,12 +80,13 @@ namespace Snap2HTML { lstDirs.Add( d ); - if( lstDirs.Count % 9 == 0 ) // for performance don't update gui for each file + if(stopwatch.ElapsedMilliseconds >= 50) { - backgroundWorker.ReportProgress( 0, "Aquiring folders... " + lstDirs.Count + " (" + d + ")" ); + backgroundWorker.ReportProgress( 0, "Getting folders... " + lstDirs.Count + " (" + d + ")" ); + stopwatch.Restart(); } - DirSearch( d, lstDirs, skipHidden, skipSystem ); + DirSearch( d, lstDirs, skipHidden, skipSystem, stopwatch ); } } } @@ -118,7 +120,8 @@ namespace Snap2HTML return s.Replace( "\\", "\\\\" ) .Replace( "&", "&" ) .Replace( "\u2028", "" ) - .Replace( "\u2029", "" ); + .Replace( "\u2029", "" ) + .Replace( "\u0004", "" ); } // Test string for matches against a wildcard pattern. Use ? and * as wildcards. (Wrapper around RegEx) @@ -151,5 +154,11 @@ namespace Snap2HTML return regex.IsMatch( text ); } + + private int ToUnixTimestamp(DateTime value) + { + return (int)Math.Truncate( ( value.ToUniversalTime().Subtract( new DateTime( 1970, 1, 1 ) ) ).TotalSeconds ); + } + } } diff --git a/Snap2HTML/template.html b/Snap2HTML/template.html index 1e30421..19874db 100644 --- a/Snap2HTML/template.html +++ b/Snap2HTML/template.html @@ -205,6 +205,7 @@ background-repeat: no-repeat; background-position: center right; cursor: pointer; + text-align: center; } #files.tablesorter tbody td { vertical-align: top; @@ -368,7 +369,7 @@ } .export_text { width: 100%; - height: calc(100% - 4em); /* two .export_options => 4em */ + height: calc(100% - 5em); /* two .export_options => 4em + save link*/ } .export_close:link, .export_close:visited { float: right; @@ -383,6 +384,54 @@ margin-right: 1em; } + + .export_save { + text-align: center; + margin-top: 0.25em; + } + .export_save a:link, .export_save a:visited { + color: black; + text-decoration: none; + } + .export_save a:hover { + text-decoration: underline; + } + + .export_chevron { + box-sizing: border-box; + position: relative; + display: inline-block; + width: 18px; + height: 16px + } + .export_chevron::after, + .export_chevron::before { + content: ""; + display: block; + box-sizing: border-box; + position: absolute; + width: 8px; + height: 8px; + border-bottom: 2px solid; + border-right: 2px solid; + transform: rotate(45deg); + left: 7px; + top: 3px + } + .export_chevron::after { + top: 8px + } + + #export_tip { + color: #eee; + position: absolute; + bottom: 13px; + right: 20px; + font-size: 11px; + } + + + /* --- DynaTree --- */ ul.dynatree-container @@ -566,7 +615,7 @@ @@ -1553,8 +1686,10 @@ + +
Tip: Search for * to export all files and folders
- \ No newline at end of file +