Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Encrypting Editor Notepad Replacement

, 28 Jul 2014
A C# .NET 3.5 (Win7) Windows Forms Application with source code
CryptPad-SourceOnly.zip
CryptPad
CryptPad (read-only).lnk
CryptPad.suo
CryptPad
CryptPad.csproj.user
CryptPad.ico
CryptPad.png
Properties
Settings.settings
hack.safe
Script.CryptPad
SendTo.lnk
Settings.lnk
CryptPad.zip
CryptPad (read-only).lnk
CryptPad.suo
CryptPad.csproj.user
CryptPad.ico
CryptPad.png
Settings.settings
hack.safe
Script.CryptPad
SendTo.lnk
Settings.lnk
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;

using AbbreviateApproximate;
using DateTimeISO_Class;
using Messagebox_Class;

namespace CryptPad
{
	/// <summary> NotePad similar but optionally encrypts file contents
	/// </summary>
	public partial class CryptPad:Form
	{
		#region Program data

		public const string CRYPTPAD_URL = "http://www.frank-t-clark.com/Professional/Papers/CryptPad/CryptPad.html";

		/// <summary> items always used together to remember caret location in a window
		/// </summary>
		public struct Remember
		{
			public int startline;
			public int startcol;
			public int startpoint;
		}

		/// <summary> hold the remembered position
		/// </summary>
		Remember remember_start = new Remember ();

		// assume no file saved
		public static int errorlevel = 1;
		public bool automation = false;
		public bool automation_script = false;
		public int automation_script_line = 0;
		string original_CurrentDirectory;

		// default file extension
		const string sSafe = ".safe";
		const string encryption_prefix = "~!@#";
		const string encryption_prefix2 = "~!@#$";

		//Hold the file name while open for the save action
		private string current_file_name;
		// hold the FileStream while open for the save/discard
		private FileStream file_stream;
		// does the file need backup
		private bool backup;

		//Hold the string/regex for the find replace actions
		public Regex find_regex;
		public string find_string;	// Escaped version needed for regex!
		public string replace_string;	// ditto but not actually required
		public bool checkBoxMatchCase;

		// current encryption string
		public string encryption_string;
		public uint encryption_checksum;
		public int random_seed;

		// encodings
		private Encoding[] encodings =
		{
			Encoding.GetEncoding (0, EncoderExceptionFallback.ExceptionFallback,
				DecoderExceptionFallback.ExceptionFallback),
			new	UTF8Encoding (false,true),
			new	UTF8Encoding (true),
			new UnicodeEncoding(false,true),
			new UnicodeEncoding(true,true),
		};
		private Encoding save_encoding;

		// status bar and settings delayed update performance improvement
		public Timer statusupdateTimer = new System.Windows.Forms.Timer ();

		/// <summary> A Settings shortcut
		/// </summary>
		Properties.Settings Settings = Properties.Settings.Default;

		/// <summary> combobox.items initializations used by find and replace
		/// </summary>
		public string[] combo_search = { "Insert a search pattern." };
		public string[] combo_replacement = { "Insert a replacement pattern." };
		public string[] combo_base = {
			"\\r\\n Carriage Return, New Line",
			"\\t Tab",
			"\\\\ Backslash"};
		public string[] combo_regex_find = {
			". Any character" ,
			"* zero or more times",
			"+ one or more times",
			"? zero or one time",
			"^ beginning of line",
			"$ end of line",
			"\\w Any word character",
			"\\W Any non-word character",
			"\\s Any white-space character",
			"\\S Any non-white-space ",
			"\\d any decimal digit",
			"\\D any non-decimal digit",
			"[] Character group",
			"[^] Not Character group",
			"[a-z] Character range",
			"() Captures subexpression",
			};
		public string[] combo_regex_replace = { "$1 Substitutes subexpression 1" };

		#endregion
		#region Program Startup

		/// <summary> The main entry point for the application.
		/// </summary>
		[STAThread]
		static int Main (string[] args)
		{
			Application.SetCompatibleTextRenderingDefault (false);
			Application.Run (new CryptPad ());
			return errorlevel;
		}

		#endregion
		#region Form code

		public CryptPad ()
		{
			// Required for Windows Form Designer support
			InitializeComponent ();
		}

		private void CryptPad_Load (object sender, EventArgs e)
		{
			this.Font = new Font (SystemFonts.MessageBoxFont, SystemFonts.MessageBoxFont.Style);

			// save for Menu, Tools, Command Line
			original_CurrentDirectory = Environment.CurrentDirectory;

			// No settings?
			if (Settings.WindowPosition.IsEmpty)
				Settings.Upgrade ();
			Backup = Settings.Backup;
			CurrentFont = Settings.CurrentFont;
			FontColor = Settings.FontColor;
			BackgroundColor = Settings.BackColor;
			DisplayBefore = Settings.DisplayBefore;
			DisplayEncoding = Settings.DisplayEncoding;
			DisplayLines = Settings.DisplayLines;
			IsStatusBarVisible = Settings.IsStatusBarVisible;
			WordWrap = Settings.WordWrap;

			if (Settings.WindowPosition.IsEmpty)
				Settings.WindowPosition = Bounds;
			else
				Bounds = Settings.WindowPosition;
			StartPosition = FormStartPosition.Manual;
			statusupdateTimer.Tick += new EventHandler (StatusUpdateTimer);
		}

		private void CryptPad_Shown (object sender, EventArgs e)
		{
			// initialize in case there is no open or there is an open error
			NewAll (true);

			String[] arguments = Environment.GetCommandLineArgs ();

			// Command line arguments?
			if (1 == arguments.Length)
				return;
			// Script or file
			if (2 == arguments.Length)
			{
				if (".CRYPTPAD" == Path.GetExtension (arguments[1]).ToUpper ())
				{
					if (!File.Exists (arguments[1]))
					{
						DisplayArguments (arguments, "Missing script file!");
						return;
					}
					Do_Script (arguments[1]);
				}
				else
				{
					FileOpen (arguments[1]);
					// prepare for Open and Save As dialogs
					Environment.CurrentDirectory = Path.GetDirectoryName (Path.GetFullPath (arguments[1]));
				}
				return;
			}
			// Script and file
			if (3 == arguments.Length)
			{
				if (".CRYPTPAD" != Path.GetExtension (arguments[1]).ToUpper ())
				{
					DisplayArguments (arguments, "Not CryptPad script!");
					return;
				}
				if (!File.Exists (arguments[1]))
				{
					DisplayArguments (arguments, "Missing script file!");
					return;
				}
				// all references relative to the script file
				Environment.CurrentDirectory = Path.GetDirectoryName (Path.GetFullPath (arguments[1]));
				if (0 < arguments[2].Length)
					if (AutoOpen (arguments[2]))
					{
						DisplayArguments (arguments, "");
						return;
					}
				Do_Script (arguments[1]);
				return;
			}
			// Other arguments same as a script line
			if (ProcessArguments (arguments))
				DisplayArguments (arguments, "");
		}

		private void CryptPad_LocationChanged (object sender, EventArgs e)
		{
			BoundsChanged ();
		}

		private void CryptPad_SizeChanged (object sender, EventArgs e)
		{
			BoundsChanged ();
			// word wrap changes lines
			UpdateStatusBar ();
		}

		private void BoundsChanged ()
		{
			// not final settings yet
			if (FormStartPosition.Manual != StartPosition)
				return;
			// don't save maximized or minimized
			if (FormWindowState.Normal != WindowState)
				return;
			Settings.WindowPosition = Bounds;
			Settings.Save ();
		}

		private void CryptPad_FormClosing (object sender, FormClosingEventArgs e)
		{
			if (DiscardChanges ())
			{
				e.Cancel = true;
				return;
			}

			// Discard anything open to speed cleanup
			NewAll (true);
		}

		private void txtBody_MouseDown (object sender, MouseEventArgs e)
		{
			UpdateStatusBar ();
		}

		private void txtBody_KeyDown (object sender, KeyEventArgs e)
		{
			// delay status update until key is processed
			statusupdateTimer.Interval = 1;
			statusupdateTimer.Start ();
		}

		private void StatusUpdateTimer (Object myObject, EventArgs myEventArgs)
		{
			statusupdateTimer.Stop ();
			UpdateStatusBar ();
		}

		private void UpdateStatusBar ()
		{
			// is it more efficient to change statusStrip.Visible only once?
			bool visible = false;
			if (DisplayEncoding)
				visible = true;
			int caret = txtBody.SelectionStart;
			if (IsStatusBarVisible)
			{
				visible = true;
				statusStripLabel1.Visible = true;
				int line = txtBody.GetLineFromCharIndex (caret);
				int col = caret - txtBody.GetFirstCharIndexFromLine (line);
				++line;
				++col;
				statusStripLabel1.Text = "Line: " + line.ToString ("N0")
								+ " Char: " + col.ToString ("N0");
			}
			else
				statusStripLabel1.Visible = false;

			if (DisplayBefore)
			{
				visible = true;
				statusStripLabel2.Visible = true;
				statusStripLabel2.Text = "Before: " + caret.ToString ("N0")
								+ " After: " + (txtBody.TextLength - caret).ToString ("N0");
			}
			else
				statusStripLabel2.Visible = false;

			if (DisplayLines)
			{
				visible = true;
				statusStripLabel3.Visible = true;
				statusStripLabel3.Text = "Lines: " + txtBody.Lines.Length.ToString ("N0")
								+ " Chars: " + txtBody.TextLength.ToString ("N0");
			}
			else
				statusStripLabel3.Visible = false;
			statusStrip.Visible = visible;
		}

		// changes rarely and would add to processing
		private void UpdateEncoding ()
		{
			menuFileForce.Enabled = !ReadOnly & 1252 != save_encoding.CodePage;
			menuFileUTF.Enabled = !ReadOnly & 65001 != save_encoding.CodePage;
			if (DisplayEncoding)
			{
				statusStrip.Visible = true;
				statusStripLabel4.Visible = true;
				if (1252 == save_encoding.CodePage)
					statusStripLabel4.Text = save_encoding.HeaderName;
				else
				{
					byte[] t = save_encoding.GetPreamble ();
					if (0 == t.Length && 65001 == save_encoding.CodePage)
						statusStripLabel4.Text = "UTF-8 (ASCII)";
					else
						statusStripLabel4.Text = save_encoding.EncodingName;
				}
			}
			else
				statusStripLabel4.Visible = false;
		}

		#endregion
		#region Command Line Automation

		/// <summary> Command Line Automation processing
		/// </summary>
		/// <param name="arguments">arguments to process from command line or script</param>
		/// <returns>indicates non-handled failure</returns>
		private bool ProcessArguments (String[] arguments)
		{
			if ("DO" != arguments[1].ToUpper ())
			{
				DisplayArguments (arguments, "Argument 1 must be 'DO'!");
				return false;
			}
			// There must be at least three arguments
			if (3 > arguments.Length)
			{
				DisplayArguments (arguments, "Not enough arguments!");
				return false;
			}
			string str = arguments[2].ToUpper ();
			switch (str)
			{
				case "SCRIPT":
					if (automation_script)
					{
						DisplayArguments (arguments, "Nested SCRIPT is not allowed!");
						return false;
					}
					// There must be four arguments
					if (4 != arguments.Length)
					{
						DisplayArguments (arguments, "Four arguments required!");
						return false;
					}
					if (!File.Exists (arguments[3]))
					{
						DisplayArguments (arguments, "Missing script file!");
						return false;
					}
					Do_Script (arguments[3]);
					break;
				case "ANSI":
					automation = true;
					if (3 == arguments.Length)
					{
						if (null == current_file_name)
						{
							DisplayArguments (arguments, "No open file!");
							return false;
						}
						break;
					}
					if (4 < arguments.Length)
					{
						DisplayArguments (arguments, "Too many arguments!");
						return false;
					}
					if (AutoOpen (arguments[3]))
						return true;
					if (1252 != save_encoding.CodePage)
					{
						menuFileForce_Click (null, null);
						menuFileSave_Click (null, null);
					}
					if (!automation_script)
						menuFileExit_Click (null, null);
					break;
				case "UTF-8":
					automation = true;
					if (3 == arguments.Length)
					{
						if (null == current_file_name)
						{
							DisplayArguments (arguments, "No open file!");
							return false;
						}
						break;
					}
					if (4 < arguments.Length)
					{
						DisplayArguments (arguments, "Too many arguments!");
						return false;
					}
					if (AutoOpen (arguments[3]))
						return true;
					if (65001 != save_encoding.CodePage)
					{
						menuFileUTF_Click (null, null);
						menuFileSave_Click (null, null);
					}
					if (!automation_script)
						menuFileExit_Click (null, null);
					break;
				case "REPLACE":
					if (Arg5Test (arguments))
						return false;
					Replace (Unescape (arguments[3]), Unescape (arguments[4]));
					break;
				case "REPLACEMATCH":
					if (Arg5Test (arguments))
						return false;
					ReplaceMatch (Unescape (arguments[3]), Unescape (arguments[4]));
					break;
				case "REGEX":
					if (Arg5Test (arguments))
						return false;
					txtBody.Text = Regex.Replace (txtBody.Text, Unescape (arguments[3]), Unescape (arguments[4]),
						RegexOptions.Multiline | RegexOptions.IgnoreCase);
					break;
				case "REGEXMATCH":
					if (Arg5Test (arguments))
						return false;
					txtBody.Text = Regex.Replace (txtBody.Text, Unescape (arguments[3]), Unescape (arguments[4]),
						RegexOptions.Multiline);
					break;
				case "READONLY":
					if (automation_script)
					{
						DisplayArguments (arguments, "READONLY is only allowed on command line!");
						return false;
					}
					if (4 != arguments.Length)
					{
						DisplayArguments (arguments, "Four arguments required!");
						return false;
					}
					ReadOnly = true;
					if (FileOpen (arguments[3]))
						return true;
					// prepare for Open and Save As dialogs
					Environment.CurrentDirectory = Path.GetDirectoryName (Path.GetFullPath (arguments[3]));
					break;
				case "EDIT":
					if (4 != arguments.Length)
					{
						DisplayArguments (arguments, "Four arguments required!");
						return false;
					}
					if (AutoOpen (arguments[3]))
						return true;
					// prepare for Open and Save As dialogs
					Environment.CurrentDirectory = Path.GetDirectoryName (Path.GetFullPath (arguments[3]));
					break;
				default:
					DisplayArguments (arguments, str + " is an unrecognized command!");
					break;
			}
			return false;
		}

		private bool Arg5Test (String[] arguments)
		{
			if (!automation_script)
			{
				DisplayArguments (arguments, "SCRIPT command!");
				return true;
			}
			if (5 != arguments.Length)
			{
				DisplayArguments (arguments, "Five arguments required!");
				return true;
			}
			if (null == current_file_name)
			{
				DisplayArguments (arguments, "No open file!");
				return true;
			}
			return false;
		}

		private void ReplaceMatch (string f, string r)
		{
			string str = txtBody.Text;
			if (0 <= str.IndexOf (f))
			{
				txtBody.Text = str.Replace (f, r);
				txtBody.Modified = true;
			}
		}

		private void Replace (string f, string r)
		{
			string str = txtBody.Text;
			int i = 0;
			int jf = f.Length;
			int jr = r.Length;
			bool c = false;

			for (; ; )
			{
				i = str.IndexOf (f, i, StringComparison.CurrentCultureIgnoreCase);
				if (0 > i)
					break;
				c = true;
				str = str.Substring (0, i) + r + str.Substring (i + jf);
				i += jr;
			}
			if (c)
			{
				txtBody.Text = str;
				txtBody.Modified = true;
			}
		}

		/// <summary> Automation open never changes Environment.CurrentDirectory
		/// </summary>
		/// <param name="path"></param>
		private bool AutoOpen (string path)
		{
			// this should always save
			DiscardChanges ();
			NewAll (false);
			if (FileOpen (path))
				return true;
			return false;
		}

		/// <summary> Display command line or script arguments
		/// </summary>
		/// <param name="arguments">string array of arguments</param>
		/// <param name="str">optional error string</param>
		private void DisplayArguments (String[] arguments, string str)
		{
			StringBuilder st = new StringBuilder ();
			if (automation_script)
			{
				st.AppendLine ("Automation Script Line: " + automation_script_line);
				st.AppendLine ();
			}
			if (null != str)
			{
				st.AppendLine ("Command Line Automation is exiting immediately!");
				st.AppendLine ();
				if ("" != str)
				{
					st.AppendLine (str);
					st.AppendLine ();
				}
			}
			st.AppendLine ("Environment.CurrentDirectory = " + original_CurrentDirectory);
			st.AppendLine ();
			st.AppendLine ("Environment.GetCommandLineArgs.Length = " + arguments.Length);
			st.AppendLine ();

			int i;
			for (i = 0; i < arguments.Length; ++i)
				st.AppendLine (String.Format ("{0} = {1}", i, arguments[i]));

			Messagebox.Show (st.ToString ());
			if (null != str)
			{
				errorlevel = 2;
				menuFileExit_Click (null, null);
			}
		}

		private void Do_Script (string path)
		{
			automation_script = true;
			automation = true;
			path = Path.GetFullPath (path);
			// all file references in this script are relative to the script
			Environment.CurrentDirectory = Path.GetDirectoryName (Path.GetFullPath (path));
			StreamReader streamreader = new StreamReader (path);
			List<string> arguments = new List<string> ();
			automation_script_line = 0;
			while (!streamreader.EndOfStream)
			{
				arguments.Clear ();
				arguments.Add (path);
				string str = streamreader.ReadLine ();
				++automation_script_line;
				str = str.Replace ('\0', ' ');
				str = str.Replace ("\\\"", "\0");
				int istart = 0;
				int iend = 0;
				string arg;
				for (; ; )
				{
					// skip leading spaces
					while (istart < str.Length)
						if (' ' == str[istart])
							++istart;
						else
							break;
					if (istart == str.Length)
						break;
					if ('"' == str[istart])
					{
						++istart;
						iend = str.IndexOf ('\"', istart);
						if (0 > iend)
						{
							arguments.Add (str);
							DisplayArguments (arguments.ToArray (), "No terminating quote!");
							arguments.Clear ();
							break;
						}
						arg = str.Substring (istart, iend - istart);
						++iend;
						istart = iend;
						if (str.Length > iend && ' ' != str[iend])
						{
							arguments.Add (str);
							DisplayArguments (arguments.ToArray (), "Terminating quote not followed by a space!");
							arguments.Clear ();
							break;
						}
					}
					else
					{
						iend = str.IndexOf (' ', istart);
						if (0 > iend)
							iend = str.Length;
						arg = str.Substring (istart, iend - istart);
						istart = iend;
					}
					arg = arg.Replace ("\0", "\\\"");
					// special case to insert a quote from a command line
					arg = arg.Replace ("\\q", "\"");
					arguments.Add (arg);
				}
				if (0 == arguments.Count)
					break;
				if (1 == arguments.Count)
					continue;
				if (ProcessArguments (arguments.ToArray ()))
					DisplayArguments (arguments.ToArray (), "");
				if (2 == errorlevel)
					break;
			}
			streamreader.Close ();
			menuFileExit_Click (null, null);
		}

		#endregion
		#region Settings code

		private int Backup
		{
			get
			{
				return Settings.Backup;
			}
			set
			{
				Settings.Backup = value;
				menuToolsBackup0.Checked = false;
				menuToolsBackup1.Checked = false;
				menuToolsBackup2.Checked = false;
				menuToolsBackup3.Checked = false;
				switch (value)
				{
					default:
					case 0:
						menuToolsBackup0.Checked = true;
						break;
					case 1:
						menuToolsBackup1.Checked = true;
						break;
					case 2:
						menuToolsBackup2.Checked = true;
						break;
					case 3:
						menuToolsBackup3.Checked = true;
						break;
				}
				Settings.Save ();
			}
		}

		private Font CurrentFont
		{
			get
			{
				return Settings.CurrentFont;
			}
			set
			{
				txtBody.Font = Settings.CurrentFont = value;
				Settings.Save ();
			}
		}

		private Color FontColor
		{
			get
			{
				return Settings.FontColor;
			}
			set
			{
				txtBody.ForeColor = Settings.FontColor = value;
				Settings.Save ();
			}
		}

		private Color BackgroundColor
		{
			get
			{
				return Settings.BackColor;
			}
			set
			{
				txtBody.BackColor = Settings.BackColor = value;
				Settings.Save ();
			}
		}

		public bool DisplayBefore
		{
			get
			{
				return Settings.DisplayBefore;
			}
			set
			{
				menuViewBefore.Checked = Settings.DisplayBefore = value;
				Settings.Save ();
			}
		}

		public bool DisplayEncoding
		{
			get
			{
				return Settings.DisplayEncoding;
			}
			set
			{
				menuViewEncoding.Checked = Settings.DisplayEncoding = value;
				Settings.Save ();
			}
		}

		public bool DisplayLines
		{
			get
			{
				return Settings.DisplayLines;
			}
			set
			{
				menuViewLines.Checked = Settings.DisplayLines = value;
				Settings.Save ();
			}
		}

		/// <summary> Display Line/Char
		/// </summary>
		public bool IsStatusBarVisible
		{
			get
			{
				return Settings.IsStatusBarVisible;
			}
			set
			{
				menuViewStatus.Checked = Settings.IsStatusBarVisible = value;
				Settings.Save ();
			}
		}

		public bool WordWrap
		{
			get
			{
				return Settings.WordWrap;
			}
			set
			{
				menuFormatWordWrap.Checked = txtBody.WordWrap = Settings.WordWrap = value;
				Settings.Save ();
			}
		}

		#endregion
		#region File Menu Items

		private void menuFileNew_Click (object sender, System.EventArgs e)
		{
			if (DiscardChanges ())
				return;
			NewAll (true);
		}

		private void NewAll (bool clear_encrypt)
		{
			if (clear_encrypt)
			{
				encryption_string = null;
				encryption_checksum = 0;
			}
			if (null != file_stream)
			{
				file_stream.Close ();
				file_stream = null;
			}
			save_encoding = encodings[1];
			UpdateEncoding ();
			txtBody.Clear ();
			txtBody.SelectionStart = 0;	// keep text from being selected
			ReadOnly = false;
			Title (null);
		}

		private void menuFileOpen_Click (object sender, System.EventArgs e)
		{
			if (DiscardChanges ())
				return;
			NewAll (false);
			OpenFileDialog openFileDialog = new OpenFileDialog ();
			openFileDialog.InitialDirectory = Environment.CurrentDirectory;

			openFileDialog.Filter =
				"Open read-only Documents (*.safe, *.txt)|*.safe;*.txt|"	// 1
				+ "Open read-only Encrypted (*.safe)|*.safe|"	// 2
				+ "Open read-only Text (*.txt)|*.txt|"	// 3
				+ "Open read-only All (*.*)|*.*|"	// 4
				+ "All documents (*.safe, *.txt)|*.safe;*.txt|"	// 5
				+ "Encrypted documents (*.safe)|*.safe|"	// 6
				+ "Text Documents (*.txt)|*.txt|"	// 7
				+ "All Files (*.*)|*.*";	// 8

			openFileDialog.FilterIndex = 5;

			if (DialogResult.Cancel == openFileDialog.ShowDialog (this))
			{
				NewAll (true);
				return;
			}

			if (5 > openFileDialog.FilterIndex)
				ReadOnly = true;
			else
				ReadOnly = false;
			Environment.CurrentDirectory = Path.GetDirectoryName (openFileDialog.FileName);
			FileOpen (openFileDialog.FileName);
		}

		private bool FileOpen (string original_filename)
		{
			bool error_flag;
			string str;
			string filename = Path.GetFullPath (original_filename);
			if (!File.Exists (filename))
			{
				Messagebox.Show ("File does not exist!\r\n\r\n" + filename);
				return true;
			}
			// refuse to open a file with a backup extension of 1, 2, or 3.
			str = Path.GetExtension (filename);
			if (str == ".1" || str == ".2" || str == ".3")
			{
				Messagebox.Show ("Cannot open a backup file!\r\n\r\n" + filename);
				return true;
			}

			if (!ReadOnly)
			{
				error_flag = false;
				str = null;
				try
				{
					file_stream = new FileStream (filename, FileMode.Open, FileAccess.ReadWrite, FileShare.Read);
					backup = true;
				}
				catch (Exception err)
				{
					str = err.Message;
					error_flag = true;
				}
				if (error_flag)
				{
					// we don't do read-only in automation
					if (automation)
						return true;
					str += " Open read-only?";
					DialogResult code = Warning_Popup (str);
					if (DialogResult.Cancel == code)
						return true;
					ReadOnly = true;
				}
			}

			if (ReadOnly)
			{
				error_flag = false;
				str = null;
				try
				{
					file_stream = new FileStream (filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
				}
				catch (Exception err)
				{
					str = err.Message;
					error_flag = true;
				}
				if (error_flag)
				{
					Messagebox.Show (str);
					return true;
				}
			}

			if (file_stream.Length > Abbr.ApprI32 ("2M"))
			{
				str = "File size is about " + Abbr.Appr (file_stream.Length)
					+ "! While it may possible to edit a file of this size, it will be slow.";
				if (DialogResult.Cancel == Warning_Popup (str))
				{
					NewAll (false);
					return true;
				}
			}

			// attempt UTF-8 encoding with ANSI error detection
			StreamReader sr = new StreamReader (file_stream, encodings[1], true);

			Cursor.Current = Cursors.WaitCursor;

			str = null;
			try
			{
				// fast part
				//	StopW t = StopW.Start ("Read");
				str = sr.ReadToEnd ();
				//	t.Stop ();
				// what was the actual encoding found
				save_encoding = sr.CurrentEncoding;
				UpdateEncoding ();
			}
			catch
			{
				// ANSI error detection
				save_encoding = null;
			}
			if (null == save_encoding)
			{
				// use ANSI
				save_encoding = encodings[0];
				UpdateEncoding ();
				file_stream.Position = 0;
				sr = new StreamReader (file_stream, save_encoding);
				str = sr.ReadToEnd ();
			}
			if (ReadOnly)
				sr.Close ();
			else
				// don't close or dispose because it closes the underlying file_stream
				sr.DiscardBufferedData ();

			str = Decrypt (str);

			int i = CRLF (str);
			if (0 <= i)
			{
				string str2 = "A dangling CR or LF has been found! "
								+ "Select \"OK\" to Force CR/LF or \"Cancel\" to ignore.";
				if (DialogResult.Cancel != Warning_Popup (str2))
				{
					str = str.Replace ("\r", "");
					str = str.Replace ("\n", "\r\n");
				}
			}

			i = Ctrl (str, 0);
			if (0 <= i)
				Messagebox.Show ("ANSI Blank character found!");

			// Replace the forbidden NUL character
			if (0 <= str.IndexOf ("\x0"))
			{
				Messagebox.Show ("NUL (zero value) characters changed to a space");
				str = str.Replace ("\x0", " ");
			}
			//	StopW t2 = StopW.Start ("Text");
			txtBody.Text = str;
			//	t2.Stop ();
			txtBody.SelectionStart = 0;	// keep text from being selected
			Title (filename);
			return false;
		}

		private void Title (string filename)
		{
			current_file_name = filename;
			this.Text = (null == current_file_name ? "Untitled" : Path.GetFileName (filename))
				+ " - " + this.Name
				+ (ReadOnly ? " (read-only)" : "")
				+ (0 < encryption_checksum ? " (Encrypted)" : "");
			UpdateStatusBar ();
		}

		private string Decrypt (string str)
		{
			bool v2;
			if (str.StartsWith (encryption_prefix2))
				v2 = true;
			else if (str.StartsWith (encryption_prefix))
				v2 = false;
			else
			{
				encryption_string = null;
				encryption_checksum = 0;
				return str;
			}

			StringBuilder st;
			int j;

			// distinguish version 1 and version 2
			if (v2)
			{
				uint data_checksum = 0;
				if (Checksum (str.Substring (5, 8), out data_checksum))
				{
					encryption_string = null;
					encryption_checksum = 0;
					return str;
				}

				j = str.Length;
				uint checksum = 0;
				for (int i = 13; i < j; ++i)
				{
					// checksum
					uint t = 0;
					if (0 < (0x80000000 & checksum))
						t = 1;
					checksum <<= 1;
					checksum |= t;
					checksum ^= (uint) str[i];
				}
				if (data_checksum != checksum)
				{
					Messagebox.Show ("Encrypted data corruption found!");
					encryption_string = null;
					encryption_checksum = 0;
					return str;
				}
				st = new StringBuilder (str.Substring (21));
			}
			else
				st = new StringBuilder (str.Substring (12));

			if (Checksum (str.Substring (v2 ? 13 : 4, 8), out encryption_checksum))
			{
				encryption_string = null;
				encryption_checksum = 0;
				return str;
			}
			Encryption ();
			if (null == encryption_string)
				return str;

			j = st.Length;
			for (int i = 0; i < j; ++i)
			{
				int chr = st[i];

				// decrypt
				if (isASCII ((char) chr))
				{
					chr = ' ' + ((chr - ' ') - E (i) + 95) % 95;
					st[i] = (char) chr;
				}
			}
			return st.ToString ();
		}

		private bool Checksum (string str, out uint checksum)
		{
			string str2;

			// not an encryption_checksum
			if (!UInt32.TryParse (str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out checksum))
				return true;

			str2 = checksum.ToString ("X8");

			// strings don't match!
			if (str != str2)
				return true;

			return false;
		}

		private void menuFileSave_Click (object sender, System.EventArgs e)
		{
			FileSave ();
		}

		private void menuFileSaveAs_Click (object sender, System.EventArgs e)
		{
			FileSaveAs ();
		}

		private bool FileSaveAs ()
		{
			bool error_flag = false;
			SaveFileDialog saveFileDialog = new SaveFileDialog ();
			saveFileDialog.FileName = current_file_name;

			saveFileDialog.InitialDirectory = Environment.CurrentDirectory;

			saveFileDialog.Filter =
				"ANSI encoding (*.*)|*.*|"
				+ "UTF-8 (ASCII) encoding (*.*)|*.*|"
				+ "Unicode (UTF-8) encoding (*.*)|*.*|"
				+ "Unicode encoding (*.*)|*.*|"
				+ "Unicode (Big-Endian) encoding (*.*)|*.*|"
				+ "Encrypted documents (*.safe)|*.safe|"
				+ "Text Documents (*.txt)|*.txt|"
				+ "All documents (*.safe, *.txt)|*.safe;*.txt|"
				+ "All Files (*.*)|*.*";

			int i = encodings.Length + 1;
			if (null == encryption_string)
				++i;
			saveFileDialog.FilterIndex = i;

			if (DialogResult.Cancel == saveFileDialog.ShowDialog ())
				return true;

			if (encodings.Length > saveFileDialog.FilterIndex)
			{
				save_encoding = encodings[saveFileDialog.FilterIndex - 1];
				UpdateEncoding ();
			}

			if (null != file_stream)
				file_stream.Close ();

			Environment.CurrentDirectory = Path.GetDirectoryName (saveFileDialog.FileName);

			try
			{
				file_stream = new FileStream (saveFileDialog.FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
			}
			catch (Exception err)
			{
				Messagebox.Show (err.Message);
				error_flag = true;
			}
			if (error_flag)
				return true;
			ReadOnly = false;
			Title (saveFileDialog.FileName);
			backup = true;	// we could be overwriting!
			bool result = FileSave ();
			backup = true;
			return result;
		}

		private bool FileSave ()
		{
			if (null == current_file_name)
				return FileSaveAs ();

			Cursor.Current = Cursors.WaitCursor;

			string str;
			if (null != encryption_string)
				str = Encrypt (txtBody.Text);
			else
				str = txtBody.Text;

			// will unicode save as possible ANSI encoding?
			bool err_flag = false;
			string err_str = null;
			byte[] test = null;
			try
			{
				test = save_encoding.GetBytes (str);
			}
			catch (Exception err)
			{
				err_str = err.Message;
				err_flag = true;
			}
			if (err_flag)
			{
				if (save_encoding != encodings[0])
				{
					Messagebox.Show (err_str + "\nUnexpected Error!");
					return true;
				}
				if (!automation)
				{
					if (DialogResult.Cancel == Warning_Popup (err_str + "\n\nThis file appears to contain characters in Unicode format which may be lost if you save this file as an ANSI encoded text file. To keep the Unicode information, click Cancel below and then select one of the Unicode options from the \"Save as Type\" dropdown list.\n\nContinue anyway?"))
						return true;
				}
				save_encoding = Encoding.Default;
				UpdateEncoding ();
				err_flag = false;

				Cursor.Current = Cursors.WaitCursor;

				try
				{
					test = save_encoding.GetBytes (str);
				}
				catch (Exception err)
				{
					err_str = err.Message;
					err_flag = true;
				}
				if (err_flag)
				{
					Messagebox.Show (err_str + "\nUnexpected Error!");
					return true;
				}

				// change the screen contents also
				str = save_encoding.GetString (test);
				txtBody.Text = str;
				txtBody.SelectionStart = 0;
			}

			// is this the first save after open and backup generation selected
			if (backup && 0 < Backup)
			{
				backup = false;
				string filename = file_stream.Name;
				for (int i = Backup; i > 1; --i)
					Rename (filename + "." + (i - 1), filename + "." + i);
				file_stream.Close ();
				Rename (filename, filename + ".1");
				file_stream = new FileStream (filename, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
			}
			else
				// discard any previous possible contents
				file_stream.SetLength (0);
			// use the StreamWriter to automatically handle the optional BOM
			StreamWriter sw = new StreamWriter (file_stream, save_encoding);
			sw.Write (str);
			sw.Flush ();
			txtBody.Modified = false;
			errorlevel = 0;	// a successful save
			return false;
		}

		/// <summary> Rename backup files with error handling
		/// </summary>
		/// <param name="source">file path</param>
		/// <param name="destination">file path</param>
		private void Rename (string source, string destination)
		{
			if (!File.Exists (source))
				return;
			if (File.Exists (destination))
			{
				try
				{
					File.Delete (destination);
				}
				catch (Exception e)
				{
					Messagebox.Show ("Error replacing " + destination + "\r\n\r\n" + e.Message);
					return;
				}
			}
			try
			{
				File.Move (source, destination);
			}
			catch (Exception e)
			{
				Messagebox.Show ("Error moving " + source + "\r\n\r\n" + e.Message);
				return;
			}
		}

		private string Encrypt (string str)
		{
			if (null == encryption_string)
				if (DialogResult.Cancel == Encryption ())
					return str;

			StringBuilder st = new StringBuilder (str);

			int j = st.Length;
			for (int i = 0; i < j; ++i)
			{
				int chr = st[i];

				// encrypt
				if (isASCII ((char) chr))
				{
					chr = ' ' + (((chr - ' ') + E (i)) % 95);
					st[i] = (char) chr;
				}
			}

			str = encryption_checksum.ToString ("X8") + st;

			j = str.Length;
			uint checksum = 0;
			for (int i = 0; i < j; ++i)
			{
				// checksum
				uint t = 0;
				if (0 < (0x80000000 & checksum))
					t = 1;
				checksum <<= 1;
				checksum |= t;
				checksum ^= (uint) str[i];
			}
			return encryption_prefix2 + checksum.ToString ("X8") + str;
		}

		private int E (int i)
		{
			return (encryption_string[i % encryption_string.Length] + i + i * random_seed) % 95;
		}

		private void menuFileForce_Click (object sender, EventArgs e)
		{
			save_encoding = encodings[0];
			UpdateEncoding ();
			txtBody.Modified = true;
		}

		private void menuFileUTF_Click (object sender, EventArgs e)
		{
			save_encoding = encodings[1];
			UpdateEncoding ();
			txtBody.Modified = true;
		}

		private void menuFileEncryption_Click (object sender, EventArgs e)
		{
			uint save_checksum = encryption_checksum;
			encryption_checksum = 0;
			if (DialogResult.Cancel == Encryption ())
				encryption_checksum = save_checksum;
			else
				txtBody.Modified = true;
		}

		private DialogResult Encryption ()
		{
			Encryption form = new Encryption ();
			form.Font = new Font (SystemFonts.MessageBoxFont, FontStyle.Regular);
			DialogResult t = form.ShowDialog (this);
			return t;
		}

		private void menuFileExit_Click (object sender, EventArgs e)
		{
			if (DiscardChanges ())
				return;
			Application.Exit ();
		}

		private bool DiscardChanges ()
		{
			DialogResult result;
			if (ReadOnly)
			{
				txtBody.Modified = false;
				return false;
			}
			if (txtBody.Modified)
			{
				if (automation)
					result = DialogResult.Yes;
				else
					result = Messagebox.Show (
								  "Save " + current_file_name + "?",
								  null,
								  MessageBoxButtons.YesNoCancel);
				switch (result)
				{
					case DialogResult.Yes:
						if (FileSave ())
							return true;
						break;
					case DialogResult.No:
						break;
					case DialogResult.Cancel:
						return true;
				}
				txtBody.Modified = false;
			}
			return false;
		}

		#endregion
		#region Edit Menu Items

		private void menuEdit_Popup (object sender, EventArgs e)
		{
			menuEditUndo.Enabled = !ReadOnly & txtBody.CanUndo;
			menuEditPaste.Enabled = !ReadOnly & Clipboard.ContainsText ();
			bool f = (0 < txtBody.SelectionLength);
			menuEditCut.Enabled = !ReadOnly & f;
			menuEditCopy.Enabled = f;
			menuEditDelete.Enabled = !ReadOnly & f;
			menuEditCapitalize.Enabled = !ReadOnly & f;
			menuEditLowercase.Enabled = !ReadOnly & f;
			menuEditUppercase.Enabled = !ReadOnly & f;
			menuEditTranspose.Enabled = !ReadOnly & !f;
		}

		private void menuEditUndo_Click (object sender, EventArgs e)
		{
			txtBody.Undo ();
		}

		private void menuEditCut_Click (object sender, System.EventArgs e)
		{
			txtBody.Cut ();
		}

		private void menuEditCopy_Click (object sender, System.EventArgs e)
		{
			txtBody.Copy ();
		}

		private void menuEditPaste_Click (object sender, System.EventArgs e)
		{
			txtBody.Paste ();
		}

		private void menuEditDelete_Click (object sender, EventArgs e)
		{
			txtBody.Paste ("");
		}

		private void menuEditUppercase_Click (object sender, EventArgs e)
		{
			if (0 == txtBody.SelectionLength)
				return;
			int s = txtBody.SelectionStart;
			int l = txtBody.SelectionLength;
			txtBody.Paste (txtBody.SelectedText.ToUpper ());
			txtBody.Select (s, l);
		}

		private void menuEditLowercase_Click (object sender, EventArgs e)
		{
			if (0 == txtBody.SelectionLength)
				return;
			int s = txtBody.SelectionStart;
			int l = txtBody.SelectionLength;
			txtBody.Paste (txtBody.SelectedText.ToLower ());
			txtBody.Select (s, l);
		}

		private void menuEditCapitalize_Click (object sender, EventArgs e)
		{
			int i;

			if (0 == txtBody.SelectionLength)
				return;
			String str = " " + txtBody.SelectedText.ToLower ();
			i = 0;
			for (; ; )
			{
				i = str.IndexOf (' ', i);
				if (0 > i || i == str.Length - 1)
					break;
				++i;
				str = str.Substring (0, i) + str.Substring (i, 1).ToUpper () + str.Substring (i + 1);
			}
			int s = txtBody.SelectionStart;
			int l = txtBody.SelectionLength;
			txtBody.Paste (str.Substring (1));
			txtBody.Select (s, l);
		}

		private void menuEditTranspose_Click (object sender, EventArgs e)
		{
			if (0 < txtBody.SelectionLength)
				return;
			int i = txtBody.SelectionStart;
			if (0 == i || txtBody.Text.Length == i)
				return;
			txtBody.Select (i - 1, 2);
			String str = txtBody.SelectedText;
			if (!isASCII (str[0]) || !isASCII (str[1]))
				return;
			str = str[1].ToString () + str[0].ToString ();
			txtBody.Paste (str);
			txtBody.SelectionStart = i;
		}

		public Form find_Form;	// non-modal return here
		private void menuEditFind_Click (object sender, EventArgs e)
		{
			if (txtBody.Text.Length == 0) return;
			if (null != replace_Form)
				replace_Form.Close ();
			if (null == find_Form)
			{
				find_Form = new Find ();
				find_Form.Font = new Font (SystemFonts.MessageBoxFont, FontStyle.Regular);
				find_Form.Show (this);
			}
			else
				find_Form.Focus ();
		}

		public void Position (Form dialog)
		{
			// Find and Replace non-modal dialogs need positioning
			// particularly to dodge the caret
			// Center horizontally
			dialog.Left = this.Left + (this.Width - dialog.Width) / 2;
			int t = Screen.GetWorkingArea (this).Right;
			if (0 > dialog.Left)
				dialog.Left = 0;
			else if (t < dialog.Right)
				dialog.Left -= dialog.Right - t;

			// Center vertically dodging the caret
			dialog.Top = this.Top + (this.Height - dialog.Height) / 2;
			t = txtBody.PointToScreen (txtBody.GetPositionFromCharIndex (txtBody.SelectionStart)).Y;
			int h = (int) txtBody.Font.Height * 3;

			// is the selection area covered by the dialog
			if (t + h > dialog.Top && t - h < dialog.Bottom)
				// is it closer to move the dialog down
				if (t - h < dialog.Bottom - dialog.Height)
					dialog.Top = t + h;
				else
					dialog.Top = t - h - dialog.Height;
		}

		private void menuEditFindNext_Click (object sender, EventArgs e)
		{
			FindNext (true);
		}

		public void FindNext (bool next)
		{
			if (null == find_string)
			{
				menuEditFind_Click (null, null);
				return;
			}

			Cursor.Current = Cursors.WaitCursor;

			int i = txtBody.SelectionStart;

			if (null != find_regex)
			{
				// previous correct searching right to left?
				if (!next)
				{
					RegexOptions options = RegexOptions.Compiled
						| RegexOptions.Multiline
						| RegexOptions.RightToLeft;
					if (!checkBoxMatchCase)
						options |= RegexOptions.IgnoreCase;
					Regex regex = new Regex (find_string, options);
					Match matchb = regex.Match (txtBody.Text, i);
					if (matchb.Success)
						SelectScroll (matchb.Groups[0].Index, matchb.Groups[0].Value.Length);
					else
						NoFind ();
					return;
				}
				i += txtBody.SelectionLength;
				Match match = find_regex.Match (txtBody.Text, i);
				if (match.Success)
					SelectScroll (match.Groups[0].Index, match.Groups[0].Value.Length);
				else
					NoFind ();
				return;
			}

			string str_find = Unescape (find_string);
			StringComparison t;
			if (checkBoxMatchCase)
				t = StringComparison.CurrentCulture;
			else
				t = StringComparison.CurrentCultureIgnoreCase;

			if (next)
			{
				i += txtBody.SelectionLength;
				i = txtBody.Text.IndexOf (str_find, i, t);
			}
			else
			{
				--i;
				if (0 <= i)
					i = txtBody.Text.LastIndexOf (str_find, i, t);
			}
			if (i < 0)
				NoFind ();
			else
				SelectScroll (i, str_find.Length);
			return;
		}

		private void menuEditFindPrevious_Click (object sender, EventArgs e)
		{
			FindNext (false);
		}

		public Form replace_Form;	// non-modal return here
		private void menuEditReplace_Click (object sender, EventArgs e)
		{
			if (txtBody.Text.Length == 0) return;
			if (null != find_Form)
				find_Form.Close ();
			if (null == replace_Form)
			{
				replace_Form = new Replace ();
				replace_Form.Font = new Font (SystemFonts.MessageBoxFont, FontStyle.Regular);
				replace_Form.Show (this);
			}
			else
				replace_Form.Focus ();
		}

		private void menuEditGoTo_Click (object sender, EventArgs e)
		{
			GoTo form = new GoTo ();
			form.Font = new Font (SystemFonts.MessageBoxFont, FontStyle.Regular);
			form.ShowDialog (this);
			UpdateStatusBar ();
		}

		private void menuEditSelectAll_Click (object sender, System.EventArgs e)
		{
			txtBody.SelectAll ();
		}

		private void menuEditTimeDate_Click (object sender, EventArgs e)
		{
			txtBody.Paste (DateTimeISO.strDateTime ());
		}

		#endregion
		#region Tools Menu Items

		private void menuToolsPassword_Click (object sender, EventArgs e)
		{
			string str = "";
			Random r = new Random ();
			for (int i = 0; i < 16; ++i)
			{
				int j = r.Next (62);
				if (j < 10)
					str += (char) ('0' + j);
				else if (j < 36)
					str += (char) ('A' + j - 10);
				else
					str += (char) ('a' + j - 36);
			}
			txtBody.Paste (str);
		}

		private void menuToolsQuickCrypt_Click (object sender, EventArgs e)
		{
			string str;

			Cursor.Current = Cursors.WaitCursor;

			if (txtBody.Text.StartsWith (encryption_prefix)
				|| txtBody.Text.StartsWith (encryption_prefix2))
				str = Decrypt (txtBody.Text);
			else
				str = Encrypt (txtBody.Text);
			if (null == str)
				return;
			txtBody.SelectAll ();
			txtBody.Paste (str);
			txtBody.SelectionStart = 0;	// keep text from being selected
		}

		private void menuToolsASCII_Click (object sender, EventArgs e)
		{
			int i, j;

			Cursor.Current = Cursors.WaitCursor;

			string str = txtBody.Text;
			j = str.Length;
			for (i = txtBody.SelectionStart + txtBody.SelectionLength; i < j; ++i)
			{
				if (127 < str[i])
					break;
			}
			if (i == j)
			{
				Messagebox.Show ("No non-ASCII characters found!");
				return;
			}
			SelectScroll (i, 1);
		}

		private void menuToolsLong_Click (object sender, EventArgs e)
		{
			int i, j, l;

			Cursor.Current = Cursors.WaitCursor;

			string[] str = txtBody.Lines;
			j = str.Length;
			int length = 0;
			int index = -1;
			int select = 0;
			for (i = 0; i < j; ++i)
			{
				l = str[i].Length;
				select += l + 2;
				if (length < l)
				{
					length = l;
					index = select;
				}
			}
			SelectScroll (index - 2, 0);
		}

		private void menuToolsBlank_Click (object sender, EventArgs e)
		{
			RememberCaretPosition ();
			string str = txtBody.Text;
			int i = Ctrl (str, txtBody.SelectionStart);
			if (0 > i)
			{
				RestoreCaretPosition ();
				Messagebox.Show ("No ANSI Blank found!");
				return;
			}
			txtBody.Select (i, 1);
			int j = str[i];
			str = "\\x" + j.ToString ("X2");
			txtBody.Paste (str);
			SelectScroll (i, 4);
		}

		private void menuToolsCR_Click (object sender, EventArgs e)
		{
			RememberCaretPosition ();
			string str = txtBody.Text;
			str = str.Replace ("\r\n", "\n");
			str = str.Replace ("\r", "\n");
			str = str.Replace ("\n", "\r\n");
			txtBody.SelectAll ();
			txtBody.Paste (str);
			RestoreCaretPosition ();
		}

		private void menuToolsLF_Click (object sender, EventArgs e)
		{
			RememberCaretPosition ();
			string str = txtBody.Text;
			str = str.Replace ("\r\n", "\n");
			str = str.Replace ("\r", "\n");
			txtBody.SelectAll ();
			txtBody.Paste (str);
			RestoreCaretPosition ();
		}

		private void menuToolsDangle_Click (object sender, EventArgs e)
		{
			RememberCaretPosition ();
			string str = txtBody.Text;
			int i = CRLF (str);
			if (0 > i)
			{
				RestoreCaretPosition ();
				Messagebox.Show ("No Dangling CR or LF found!");
				return;
			}
			txtBody.Select (i, 1);
			if ('\r' == str[i])
				str = "\\r";
			else
				str = "\\n";
			txtBody.Paste (str);
			SelectScroll (i, 2);
		}

		private void menuToolsWrap_Click (object sender, EventArgs e)
		{
			RememberCaretPosition ();
			string str = txtBody.Text;
			for (int line = txtBody.GetLineFromCharIndex (txtBody.TextLength); line > 0; --line)
			{
				int i = txtBody.GetFirstCharIndexFromLine (line);
				if (' ' == str[i - 1])
					str = str.Insert (i, "\r\n");
			}
			txtBody.SelectAll ();
			txtBody.Paste (str);
			RestoreCaretPosition ();
		}

		private void menuToolsUnwrap_Click (object sender, EventArgs e)
		{
			RememberCaretPosition ();
			string str = txtBody.Text;

			str = str.Replace (" \r\n", " ");
			txtBody.SelectAll ();
			txtBody.Paste (str);
			RestoreCaretPosition ();
		}

		private void menuToolsTrim_Click (object sender, EventArgs e)
		{
			RememberCaretPosition ();
			string str = txtBody.Text;

			str = str.Replace ("  \r\n", "\r\n");
			str = str.Replace (" \r\n", "\r\n");
			str = str.Replace ("\r\n   ", "\r\n");
			str = str.Replace ("\r\n ", "\r\n");
			txtBody.SelectAll ();
			txtBody.Paste (str);
			RestoreCaretPosition ();
		}

		private void menuToolsCommandLine_Click (object sender, EventArgs e)
		{
			DisplayArguments (Environment.GetCommandLineArgs (), null);
		}

		private void menuToolsBackup0_Click (object sender, EventArgs e)
		{
			Backup = 0;
		}

		private void menuToolsBackup1_Click (object sender, EventArgs e)
		{
			Backup = 1;
		}

		private void menuToolsBackup2_Click (object sender, EventArgs e)
		{
			Backup = 2;
		}

		private void menuToolsBackup3_Click (object sender, EventArgs e)
		{
			Backup = 3;
		}

		#endregion
		#region Format Menu Items

		private void menuFormatWordWrap_Click (object sender, EventArgs e)
		{
			int i = txtBody.SelectionStart;
			WordWrap = !(menuFormatWordWrap.Checked);
			txtBody.DeselectAll ();
			SelectScroll (i, 0);
		}

		private void menuFormatFont_Click (object sender, System.EventArgs e)
		{
			FontDialog dlgFont = new FontDialog ();
			dlgFont.Font = CurrentFont;
			dlgFont.FontMustExist = true;
			dlgFont.ShowEffects = false;
			dlgFont.AllowScriptChange = false;
			dlgFont.AllowSimulations = false;
			dlgFont.AllowVectorFonts = false;
			dlgFont.AllowVerticalFonts = false;
			if (DialogResult.Cancel == dlgFont.ShowDialog (this))
				return;
			CurrentFont = dlgFont.Font;
		}

		private void menuFormatFontColor_Click (object sender, EventArgs e)
		{
			ColorDialog dlgColor = new ColorDialog ();
			dlgColor.Color = FontColor;
			dlgColor.AnyColor = true;
			if (DialogResult.Cancel == dlgColor.ShowDialog (this))
				return;
			FontColor = dlgColor.Color;
		}

		private void menuFormatColor_Click (object sender, EventArgs e)
		{
			ColorDialog dlgColor = new ColorDialog ();
			dlgColor.Color = BackgroundColor;
			dlgColor.AnyColor = true;
			if (DialogResult.Cancel == dlgColor.ShowDialog (this))
				return;
			BackgroundColor = dlgColor.Color;
		}

		#endregion
		#region View Menu Items

		private void menuViewStatus_Click (object sender, EventArgs e)
		{
			IsStatusBarVisible = !menuViewStatus.Checked;
			UpdateStatusBar ();
		}

		private void menuViewBefore_Click (object sender, EventArgs e)
		{
			DisplayBefore = !menuViewBefore.Checked;
			UpdateStatusBar ();
		}

		private void menuViewLines_Click (object sender, EventArgs e)
		{
			DisplayLines = !menuViewLines.Checked;
			UpdateStatusBar ();
		}

		private void menuViewEncoding_Click (object sender, EventArgs e)
		{
			DisplayEncoding = !menuViewEncoding.Checked;
			UpdateEncoding ();
			UpdateStatusBar ();
		}

		#endregion
		#region Help Menu Items

		private void menuHelpOnline_Click (object sender, EventArgs e)
		{
			Process process = new Process ();
			process.StartInfo.FileName = CRYPTPAD_URL;
			bool result = process.Start ();
		}

		private void menuHelpLocal_Click (object sender, EventArgs e)
		{
			string path = AppDomain.CurrentDomain.BaseDirectory + "\\CryptPad.html";
			if (!File.Exists (path))
			{
				string[] lines = { "Open online location", CRYPTPAD_URL, "and save a local copy to", path };
				System.IO.File.WriteAllLines (path, lines);
			}
			Process process = new Process ();
			process.StartInfo.FileName = path;
			bool result = process.Start ();
		}

		private void menuHelpAbout_Click (object sender, EventArgs e)
		{
			About form = new About ();
			form.Font = new Font (SystemFonts.MessageBoxFont, FontStyle.Regular);
			form.ShowDialog (this);
		}

		#endregion
		#region Shared functions

		public DialogResult Warning_Popup (string str)
		{
			return Messagebox.Show (str, null, MessageBoxButtons.OKCancel);
		}

		public void NoFind ()
		{
			Messagebox.Show ("Cannot find \"" + find_string + "\"!");
		}

		public bool isASCII (char chr)
		{
			if (' ' <= chr && '~' >= chr)
				return true;
			return false;
		}

		// do not change this variable directly!
		// use the ReadOnly property
		private bool read_only = false;
		public bool ReadOnly
		{
			get
			{
				return read_only;
			}
			set
			{
				txtBody.ReadOnly = read_only = value;
				this.menuFileForce.Enabled =
				this.menuFileUTF.Enabled =
				this.menuFileSave.Enabled =
				this.menuFileEncryption.Enabled =
				this.menuEditUndo.Enabled =
				this.menuEditCut.Enabled =
				this.menuEditPaste.Enabled =
				this.menuEditDelete.Enabled =
				this.menuEditUppercase.Enabled =
				this.menuEditLowercase.Enabled =
				this.menuEditCapitalize.Enabled =
				this.menuEditTranspose.Enabled =
				this.menuEditReplace.Enabled =
				this.menuEditTimeDate.Enabled =
				this.menuToolsPassword.Enabled =
				this.menuToolsQuickCrypt.Enabled =
				this.menuToolsASCII.Enabled =
				this.menuToolsCR.Enabled =
				this.menuToolsLF.Enabled =
				this.menuToolsDangle.Enabled =
				this.menuToolsCtrl.Enabled =
				this.menuToolsTrim.Enabled =
				this.menuToolsUnwrap.Enabled =
				this.menuToolsWrap.Enabled = !read_only;
			}
		}

		private int CRLF (string str)
		{
			// Find dangerous dangling CR or LF characters
			int i = 0;
			for (; ; )
			{
				int j = str.IndexOf ('\r', i);
				i = str.IndexOf ('\n', i);
				// is i == -1 and j== -1
				if (i == j)
					return i;
				i++;
				// is '\r' followed by '\n'
				if (i == j + 2)
					continue;
				if (0 > j)
					return i - 1;
				if (0 >= i || j < i)
					return j;
				return i - 1;
			}
		}

		private int Ctrl (string str, int i)
		{
			// Find next ANSI Blank characters
			for (; i < str.Length; ++i)
			{
				int j = str[i];
				switch (j)
				{
					default:
						break;
					case '\x1':
						return i;
					case '\x1c':
						return i;
					case '\x1d':
						return i;
					case '\x1e':
						return i;
					case '\x1f':
						return i;
					case '\x81':
						return i;
					case '\x8d':
						return i;
					case '\x8f':
						return i;
					case '\x90':
						return i;
					case '\x9d':
						return i;
					case '\xa0':
						return i;
				}
			}
			return -1;
		}

		/// <summary> Select text and scroll into view plus a couple of lines
		/// </summary>
		/// <param name="index">select start point</param>
		/// <param name="length">select length</param>
		public void SelectScroll (int index, int length)
		{
			// first make sure we are visible, if at top
			txtBody.Select (index, 0);
			txtBody.ScrollToCaret ();

			// then make sure there are at least two lines underneath us
			int i = txtBody.GetLineFromCharIndex (index);
			int lines = txtBody.GetLineFromCharIndex (txtBody.TextLength);
			i += 2;
			if (i > lines)
				i = lines;
			i = txtBody.GetFirstCharIndexFromLine (i);
			txtBody.Select (i, 0);
			txtBody.ScrollToCaret ();
			txtBody.Select (index, length);
			UpdateStatusBar ();
		}

		/// <summary> Remember where we were when we started
		/// </summary>
		public void RememberCaretPosition ()
		{
			int index = txtBody.SelectionStart;
			remember_start.startpoint = txtBody.GetPositionFromCharIndex (index).Y;
			remember_start.startline = txtBody.GetLineFromCharIndex (index);
			remember_start.startcol = index - txtBody.GetFirstCharIndexFromLine (remember_start.startline);
		}

		/// <summary> Restore where we were when we started
		/// as far as practical
		/// </summary>
		public void RestoreCaretPosition ()
		{
			// did the end of the file move up too much?
			int last_char = txtBody.Text.Length;
			int last = txtBody.GetLineFromCharIndex (last_char);
			if (last < remember_start.startline)
				remember_start.startline = last;
			int index = txtBody.GetFirstCharIndexFromLine (remember_start.startline);
			index += remember_start.startcol;
			if (last_char < index)
				index = last_char;

			// test for restoring the y
			for (int line = remember_start.startline; line >= 0; --line)
			{
				txtBody.SelectionStart = txtBody.GetFirstCharIndexFromLine (line);
				txtBody.ScrollToCaret ();
				if (remember_start.startpoint <= txtBody.GetPositionFromCharIndex (index).Y)
					break;
			}
			txtBody.Select (index, 0);
		}

		/// <summary> called by Find or Replace when the find_string is changed
		/// checks regex flag and sets regex
		/// </summary>
		/// <param name="flag">checkBoxRegEx status</param>
		public void checkBoxRegEx (bool flag)
		{
			find_regex = null;
			if (flag)
			{
				RegexOptions options = RegexOptions.Compiled
					| RegexOptions.Multiline;
				if (!checkBoxMatchCase)
					options |= RegexOptions.IgnoreCase;
				try
				{
					find_regex = new Regex (find_string, options);
				}
				catch (Exception ex)
				{
					Messagebox.Show ("Regex Exception: " + ex.Message);
				}
			}
		}

		public void comboBoxPatterns_Click (object sender, EventArgs e)
		{
			ComboBox comboBoxPatterns = (ComboBox) sender;
			comboBoxPatterns.DroppedDown = true;
		}

		/// <summary> called by Find or Replace when the combobox selection changes
		/// </summary>
		public void comboBoxPatterns_SelectedIndexChanged (object sender, EventArgs e)
		{
			ComboBox comboBoxPatterns = (ComboBox) sender;
			TextBox txtbox = (TextBox) comboBoxPatterns.Tag;
			if (0 < comboBoxPatterns.SelectedIndex)
			{
				string str = (string) comboBoxPatterns.SelectedItem;
				txtbox.SelectedText = str.Substring (0, str.IndexOf (' '));
			}
			comboBoxPatterns.Text=(string)comboBoxPatterns.Items[0];
			txtbox.Focus ();
		}
		#endregion
		#region Clipboard escape functions

		// add slash
		public string Escape (string str)
		{
			if (null == str)
				return null;
			str = str.Replace ("\\", "\\\\");
			str = str.Replace ("\n", "\\n");
			str = str.Replace ("\r", "\\r");
			str = str.Replace ("\t", "\\t");
			return str;
		}

		// remove slash
		public string Unescape (string str)
		{
			if (null == str)
				return null;
			str = str.Replace ("\\\\", "\x0");
			str = str.Replace ("\\n", "\n");
			str = str.Replace ("\\r", "\r");
			str = str.Replace ("\\t", "\t");
			str = str.Replace ("\x0", "\\");
			return str;
		}

		#endregion
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Frank T. Clark
Systems Engineer Three Angels Broadcasting Network
United States United States
I am a Software Systems Design Engineer experienced with IEEE standards and the entire IEEE software development life cycle. Concept Exploration, Requirements, Design, Implementation, Test, Installation and Checkout, Operation and Maintenance. I enjoy working with people and solving customer problems.
 
I am currently employed as Information Technology Staff in the religious satellite broadcasting industry.

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 28 Jul 2014
Article Copyright 2013 by Frank T. Clark
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid