/// <summary>
        /// Determine if the projectItem is equal to the file.
        /// </summary>
        /// <param name="projectItem">
        /// The Project Item to compare.
        /// </param>
        /// <param name="fileName">
        /// The file to compare the project item against.
        /// </param>
        /// <param name="tokenReplacement">
        /// Token replacement to user for the file on disk before comparing.
        /// </param>
        /// <returns>
        /// Returns true if the two are equal; false otherwise.
        /// </returns>
        public static bool AreFilesEqual(ProjectItem projectItem, string fileName, TokenReplacementBuilder tokenReplacement)
        {
            bool areEqual = true;

            UsingProjectItemBuffer(
                projectItem,
                buffer =>
            {
                int lineCount;
                buffer.GetLineCount(out lineCount);

                using (var reader = new StreamReader(fileName, detectEncodingFromByteOrderMarks: true))
                {
                    foreach (var item in buffer.GetTextLinesEnumerator(0, lineCount))
                    {
                        // We reached the end of file name before the end of the projectItem.
                        if (reader.EndOfStream)
                        {
                            // Ignore whitespace at the end of the file. VB/C# seem to
                            // return blank lines as part of the text buffer.
                            if (string.IsNullOrWhiteSpace(item.Item2))
                            {
                                continue;
                            }

                            areEqual = false;
                            return;
                        }

                        string lhs = reader.ReadLine();
                        if (tokenReplacement != null)
                        {
                            lhs = tokenReplacement.Build(lhs);
                        }

                        string rhs = item.Item2.TrimEnd(Environment.NewLine.ToCharArray());

                        areEqual &= string.Equals(lhs, rhs, StringComparison.CurrentCulture);

                        if (!areEqual)
                        {
                            return;
                        }
                    }

                    // We didn't reach the end of file name even though we reached the end of the projectItem.
                    if (!reader.EndOfStream)
                    {
                        areEqual = false;
                        return;
                    }
                }
            });

            return(areEqual);
        }
        /// <summary>
        /// Given an input, replace any tokens found in the specified dictionary with the specified values.
        /// </summary>
        /// <param name="input">
        /// The text to update.
        /// </param>
        /// <param name="additionalReplacementValues">
        /// A dictionary of key/value pairs that will be used to replace tokens in the input.
        /// These values are additional to the values in TokenReplacementValues.  In the case of conflicts, the
        /// values specified in additionalReplacementValues will override the TokenReplacementValues.
        /// </param>
        /// <returns>
        /// Returns a new string with the tokens replace with the values from the specified dictionary.
        /// </returns>
        public override string PerformTokenReplacement(string input, IDictionary <string, string> additionalReplacementValues = null)
        {
            TokenReplacementBuilder tokenReplacement = BuildTokenReplacement(additionalReplacementValues);

            return(tokenReplacement.Build(input));
        }