/// <summary> /// Loads the profile with items from the given XML string. See the /// <see cref="sXmlXpath"/>, <see cref="sXmlKeyKey"/> and /// <see cref="sXmlValueKey"/> properties to learn what XML tags are /// expected. /// </summary> /// <param name="asXml"> /// An XML document as a string. /// </param> /// <param name="aeLoadAction"> /// The action to take while loading profile items. /// See <see cref="tvProfileLoadActions"/> /// </param> public void LoadFromXml( String asXml , tvProfileLoadActions aeLoadAction ) { if ( tvProfileLoadActions.Overwrite == aeLoadAction ) { this.Clear(); } XmlDocument loXmlDoc = new XmlDocument(); loXmlDoc.LoadXml(asXml); foreach ( XmlNode loNode in loXmlDoc.SelectNodes(this.sXmlXpath) ) { String lsKey = loNode.Attributes[this.sXmlKeyKey].Value; String lsValue = loNode.Attributes[this.sXmlValueKey].Value.StartsWith(Environment.NewLine) ? loNode.Attributes[this.sXmlValueKey].Value.Substring(Environment.NewLine.Length , loNode.Attributes[this.sXmlValueKey].Value.Length - 2 * Environment.NewLine.Length) : loNode.Attributes[this.sXmlValueKey].Value; switch ( aeLoadAction ) { case tvProfileLoadActions.Append: case tvProfileLoadActions.Overwrite: this.Add(lsKey, lsValue); break; case tvProfileLoadActions.Merge: this.bSaveEnabled = false; int liIndex = this.IndexOfKey(lsKey); if ( -1 != liIndex ) { // Set each entry with a matching key to the given value. foreach ( DictionaryEntry loEntry in this.oOneKeyProfile(lsKey, false) ) { this.SetByIndex(this.IndexOfKey(loEntry.Key.ToString()), lsValue); } } else { // Don't add keys that contain '*'. if ( -1 == lsKey.IndexOf('*') ) this.Add(lsKey, lsValue); } break; } } }
/// <summary> /// Loads the profile with items from the given "command line" string. /// </summary> /// <param name="asCommandLine"> /// A string (not a string array) of the form: /// <see langword='-Key1=one -Key2=2 -Key3 -Key4="we have four"'/>. /// </param> /// <param name="aeLoadAction"> /// The action to take while loading profile items. /// See <see cref="tvProfileLoadActions"/> /// </param> public void LoadFromCommandLine( String asCommandLine , tvProfileLoadActions aeLoadAction ) { if ( null == asCommandLine ) return; // Remove any leading spaces or tabs so that mccSplitMark becomes the first char. asCommandLine = asCommandLine.TrimStart(' '); asCommandLine = asCommandLine.TrimStart('\t'); if ( -1 != asCommandLine.IndexOf('\n') ) { // If the command line is actually already line delimited, then we're practically done. // The use of all known line delimiters allows for passing profiles between environments. this.LoadFromCommandLineArray(asCommandLine.Replace("\r\n", mccSplitMark.ToString()) .Replace("\n", mccSplitMark.ToString()).Split(mccSplitMark), aeLoadAction); } else { StringBuilder lsbNewCommandLine = new StringBuilder(); char lcCurrent = '\u0000'; bool lbQuoteOn = false; for ( int i = 0; i <= asCommandLine.Length - 1; i++ ) { char lcPrevious; lcPrevious = lcCurrent; lcCurrent = asCommandLine[i]; if ( '\"' == lcCurrent ) { lbQuoteOn = ! lbQuoteOn; } if ( lbQuoteOn || '-' != lcCurrent || '=' == lcPrevious ) { // The "|| '=' == lcPrevious" allows for negative numbers. lsbNewCommandLine.Append(lcCurrent); } else if ( '\\' == lcPrevious ) { lsbNewCommandLine.Remove(lsbNewCommandLine.Length - 1, 1); lsbNewCommandLine.Append(lcCurrent); } else { lsbNewCommandLine = new StringBuilder(lsbNewCommandLine.ToString().Trim() + mccSplitMark + "-"); } } //Cleanup any remaining tabs. lsbNewCommandLine.Replace('\t', ' '); //The first occurrence of the separator must be removed. this.LoadFromCommandLineArray(lsbNewCommandLine.ToString() .TrimStart(mccSplitMark).Split(mccSplitMark), aeLoadAction); } }
/// <summary> /// Loads the profile with items from the given "command line" /// string array. /// </summary> /// <param name="asCommandLineArray"> /// A string array of the form: <see langword='-Key1=one'/>, <see langword='-Key2=2'/>, /// <see langword='-Key3'/>, <see langword='-Key4="we have four"'/>. /// </param> /// <param name="aeLoadAction"> /// The action to take while loading profile items. /// See <see cref="tvProfileLoadActions"/> /// </param> public void LoadFromCommandLineArray( String[] asCommandLineArray , tvProfileLoadActions aeLoadAction ) { if ( tvProfileLoadActions.Overwrite == aeLoadAction ) { this.Clear(); } if ( null != asCommandLineArray ) { String lsBlockKey = null; String lsBlockValue = null; Hashtable loMergeKeysMap = new Hashtable(); foreach ( String lsItem in asCommandLineArray ) { if ( !lsItem.TrimStart().StartsWith("-") ) { if ( null != lsBlockKey ) { lsBlockValue += lsItem + Environment.NewLine; } // If an item does not start with a "-" // and is not within a block, ignore it. } else { String lsKey; String lsValue; Object loValue; int liPos = lsItem.IndexOf("="); if ( -1 == liPos ) { lsKey = lsItem.Trim(); loValue = true; } else { lsKey = lsItem.Substring(0, liPos).Trim(); lsValue = lsItem.Substring(liPos + 1).Trim(); if ( lsValue.StartsWith("\"") && lsValue.EndsWith("\"") ) { if ( lsValue.Length < 2 ) loValue = ""; else loValue = lsValue.Substring(1, lsValue.Length - 2); } else { // This is intentionally not trimmed. loValue = lsItem.Substring(liPos + 1); } } lsValue = loValue.ToString(); if ( null != lsBlockKey ) { if ( mcsEndBlockMark == lsValue && lsBlockKey == lsKey ) { lsBlockKey = null; loValue = lsBlockValue; } else { lsBlockValue += lsItem + Environment.NewLine; } } else if ( mcsBeginBlockMark == lsValue ) { lsBlockKey = lsKey; lsBlockValue = null; } if ( null == lsBlockKey ) { switch ( aeLoadAction ) { case tvProfileLoadActions.Append: case tvProfileLoadActions.Overwrite: this.Add(lsKey, loValue); break; case tvProfileLoadActions.Merge: // Only disable saving after merges if the "bSaveSansCmdLine" switch is turned off. // Likewise, only after merges do we bother to check for command line keys to remove. if ( !this.bSaveSansCmdLine ) this.bSaveEnabled = false; int liIndex = this.IndexOfKey(lsKey); // Replace wildcard keys with the first key match, if any. lsKey = ( -1 == liIndex ? lsKey : this.sKey(liIndex) ); if ( loMergeKeysMap.ContainsKey(lsKey) ) { // Set the search index to force adding this key. liIndex = -1; } else { if ( -1 != liIndex ) { // Remove all previous entries with this key (presumably from a file). this.Remove(lsKey); // Set the search index to force adding this key with its overriding value. liIndex = -1; } // Add to the merge key map to prevent any further removals of this key. loMergeKeysMap.Add(lsKey, null); } if ( -1 == liIndex ) { // Don't add keys that contain '*'. if ( -1 == lsKey.IndexOf('*') ) this.Add(lsKey, loValue); } break; } } } } } }
/// <summary> /// Loads the profile with items from the given text file. /// <p> /// If <see cref="bUseXmlFiles"/> is true, text files will be read assuming /// standard XML "configuration file" format rather than line delimited /// "command line" format. /// </p> /// </summary> /// <param name="asPathFile"> /// The path/file location of the text file to load. This value will /// be used to set <see cref="sLoadedPathFile"/> after a successful load. /// </param> /// <param name="aeLoadAction"> /// The action to take while loading profile items. /// See <see cref="tvProfileLoadActions"/> /// </param> public void Load( String asPathFile , tvProfileLoadActions aeLoadAction ) { // If asPathFile is not null, check existence. Otherwise check for the existence // of one of several default filenames. Returned null means none exist. String lsPathFile = this.sFileExistsFromList(this.sRelativeToProfilePathFile(asPathFile)); String lsFilnameOnly = Path.GetFileNameWithoutExtension(this.sExePathFile); String lcsLoadingMsg = lsFilnameOnly + " loading, please wait ..."; if ( null == lsPathFile ) { if ( null == asPathFile ) { lsPathFile = this.sDefaultPathFile; } else { lsPathFile = asPathFile; } if ( tvProfileFileCreateActions.PromptToCreateFile == this.eFileCreateAction ) { // If the EXE is not already in a folder with a matching name and if the // EXE is not already installed in a typical installation folder, proceed. if ( !this.bInOwnFolder && !this.bInstalledAlready ) { String lsNewPath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), lsFilnameOnly); String lsMessage = String.Format(( Directory.Exists(lsNewPath) ? "an existing folder ({0}) on your desktop" : "a new folder ({0}) on your desktop" ), lsFilnameOnly); if ( DialogResult.OK == MessageBox.Show(String.Format(@" For your convenience, this program will be copied to {0}. Depending on your system, this may take several seconds. Copy and proceed from there? " , lsMessage), "Copy EXE to Desktop?", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) ) { if ( null != mttvMessageBox ) { moAppLoadingWaitMsg = Activator.CreateInstance(mttvMessageBox); mttvMessageBox.InvokeMember("ShowWait", BindingFlags.InvokeMethod, null, moAppLoadingWaitMsg , new object[]{null, lcsLoadingMsg, 250}); } String lsNewExePathFile = Path.Combine(lsNewPath, Path.GetFileName(this.sExePathFile)); if ( !Directory.Exists(lsNewPath) ) Directory.CreateDirectory(lsNewPath); File.Copy(this.sExePathFile, lsNewExePathFile, true); ProcessStartInfo loStartInfo = new ProcessStartInfo(lsNewExePathFile); loStartInfo.WorkingDirectory = Path.GetDirectoryName(lsNewExePathFile); Process loProcess = Process.Start(loStartInfo); //this.bExit = true; // This was moved outside the block after disabling the other show below. } this.bExit = true; } //if ( !this.bExit ) //{ // if ( !this.bInOwnFolder && DialogResult.Cancel == MessageBox.Show(String.Format( // "The profile file for this program can't be found ({0}).\n\n" // + "Create it and proceed anyway?", lsPathFile) // , "Create Profile File?" // , MessageBoxButtons.OKCancel, MessageBoxIcon.Question) ) // { // this.bExit = true; // } //} } // Although technically the file was not loaded (since it doesn't exist yet), // we consider it empty and we set the property to allow for subsequent saves. if ( !this.bExit ) this.sLoadedPathFile = lsPathFile; } else { if ( null != mttvMessageBox ) { moAppLoadingWaitMsg = Activator.CreateInstance(mttvMessageBox); mttvMessageBox.InvokeMember("ShowWait", BindingFlags.InvokeMethod, null, moAppLoadingWaitMsg , new object[]{null, lcsLoadingMsg, 250}); } String lsFileAsStream = null; this.UnlockProfileFile(); StreamReader loStreamReader = null; try { loStreamReader = new StreamReader(lsPathFile); lsFileAsStream = loStreamReader.ReadToEnd(); } catch (IOException ex) { if ( !ex.Message.Contains("being used by another process") ) { // Wait a moment ... System.Threading.Thread.Sleep(200); // Then try again. if ( null != loStreamReader ) loStreamReader.Close(); loStreamReader = new StreamReader(lsPathFile); lsFileAsStream = loStreamReader.ReadToEnd(); } } finally { if ( null != loStreamReader ) loStreamReader.Close(); } if ( !this.bLockProfileFile(lsPathFile) ) { this.bExit = true; return; } int liDoOver = 1; do { // mbUseXmlFiles is intentionally used here (instead of "this.bUseXmlFiles") to avoid side effects. if ( mbUseXmlFiles ) { try { this.LoadFromXml(lsFileAsStream, aeLoadAction); // The profile file format is as expected. No do-over is needed. liDoOver = 0; if ( !this.bUseXmlFiles ) { lsPathFile = this.sReformatProfileFile(lsPathFile); } } catch { // mbUseXmlFiles is intentionally used here (instead of "this.bUseXmlFiles") to avoid side effects. mbUseXmlFiles = false; } } // mbUseXmlFiles is intentionally used here (instead of "this.bUseXmlFiles") to avoid side effects. if ( !mbUseXmlFiles ) { if ( lsFileAsStream.Length > 11 ) { // Look for the XML tag only near the top (an XML document could be embedded way below). if ( -1 == lsFileAsStream.IndexOf("<?xml versi", 0, 11) ) { // The profile file format is as expected. No do-over is needed. liDoOver = 0; // The default file format is line delimited "command line" format. // The use of all known line delimiters allows for passing profiles between environments. this.LoadFromCommandLineArray(lsFileAsStream.Replace("\r\n", mccSplitMark.ToString()) .Replace("\n", mccSplitMark.ToString()).Split(mccSplitMark), aeLoadAction); if ( this.bUseXmlFiles ) { lsPathFile = this.sReformatProfileFile(lsPathFile); } } else { // mbUseXmlFiles is intentionally used here (instead of "this.bUseXmlFiles") to avoid side effects. mbUseXmlFiles = true; } } } } while ( liDoOver-- > 0 ); this.sLoadedPathFile = lsPathFile; } // If it doesn't already exist, create the file. if ( !this.bExit && !File.Exists(lsPathFile) && tvProfileFileCreateActions.NoFileCreate != this.eFileCreateAction ) { this.Save(lsPathFile); // In this case, consider the file loaded also. this.sLoadedPathFile = lsPathFile; } }