Esempio n. 1
0
        /// <summary>
        /// Gets the modularized version of the field data.
        /// </summary>
        /// <param name="field">The field to modularize.</param>
        /// <param name="modularizationGuid">String containing the GUID of the Merge Module to append the the field value, if appropriate.</param>
        /// <param name="suppressModularizationIdentifiers">Optional collection of identifiers that should not be modularized.</param>
        /// <remarks>moduleGuid is expected to be null when not being used to compile a Merge Module.</remarks>
        /// <returns>The modularized version of the field data.</returns>
        internal string GetModularizedValue(Field field, string modularizationGuid, Hashtable suppressModularizationIdentifiers)
        {
            Debug.Assert(null != field.Data && 0 < ((string)field.Data).Length);
            string fieldData = Convert.ToString(field.Data, CultureInfo.InvariantCulture);

            if (null != modularizationGuid && ColumnModularizeType.None != field.Column.ModularizeType && !(Util.IsStandardAction(fieldData) || Util.IsStandardProperty(fieldData)))
            {
                StringBuilder        sb;
                int                  start;
                ColumnModularizeType modularizeType = field.Column.ModularizeType;

                // special logic for the ControlEvent table's Argument column
                // this column requires different modularization methods depending upon the value of the Event column
                if (ColumnModularizeType.ControlEventArgument == field.Column.ModularizeType)
                {
                    switch (this[2].ToString())
                    {
                    case "CheckExistingTargetPath": // redirectable property name
                    case "CheckTargetPath":
                    case "DoAction":                // custom action name
                    case "NewDialog":               // dialog name
                    case "SelectionBrowse":
                    case "SetTargetPath":
                    case "SpawnDialog":
                    case "SpawnWaitDialog":
                        if (Common.IsIdentifier(fieldData))
                        {
                            modularizeType = ColumnModularizeType.Column;
                        }
                        else
                        {
                            modularizeType = ColumnModularizeType.Property;
                        }
                        break;

                    default:     // formatted
                        modularizeType = ColumnModularizeType.Property;
                        break;
                    }
                }
                else if (ColumnModularizeType.ControlText == field.Column.ModularizeType)
                {
                    // icons are stored in the Binary table, so they get column-type modularization
                    if (("Bitmap" == this[2].ToString() || "Icon" == this[2].ToString()) && Common.IsIdentifier(fieldData))
                    {
                        modularizeType = ColumnModularizeType.Column;
                    }
                    else
                    {
                        modularizeType = ColumnModularizeType.Property;
                    }
                }

                switch (modularizeType)
                {
                case ColumnModularizeType.Column:
                    // ensure the value is an identifier (otherwise it shouldn't be modularized this way)
                    if (!Common.IsIdentifier(fieldData))
                    {
                        throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_CannotModularizeIllegalID, fieldData));
                    }

                    // if we're not supposed to suppress modularization of this identifier
                    if (null == suppressModularizationIdentifiers || !suppressModularizationIdentifiers.Contains(fieldData))
                    {
                        fieldData = String.Concat(fieldData, ".", modularizationGuid);
                    }
                    break;

                case ColumnModularizeType.Property:
                case ColumnModularizeType.Condition:
                    Regex regex;
                    if (ColumnModularizeType.Property == modularizeType)
                    {
                        regex = new Regex(@"\[(?<identifier>[#$!]?[a-zA-Z_][a-zA-Z0-9_\.]*)]", RegexOptions.Singleline | RegexOptions.ExplicitCapture);
                    }
                    else
                    {
                        Debug.Assert(ColumnModularizeType.Condition == modularizeType);

                        // This heinous looking regular expression is actually quite an elegant way
                        // to shred the entire condition into the identifiers that need to be
                        // modularized.  Let's break it down piece by piece:
                        //
                        // 1. Look for the operators: NOT, EQV, XOR, OR, AND, IMP.  Note that the
                        //    regular expression is case insensitive so we don't have to worry about
                        //    all the permutations of these strings.
                        // 2. Look for quoted strings.  Quoted strings are just text and are ignored
                        //    outright.
                        // 3. Look for environment variables.  These look like identifiers we might
                        //    otherwise be interested in but start with a percent sign.  Like quoted
                        //    strings these enviroment variable references are ignored outright.
                        // 4. Match all identifiers that are things that need to be modularized.  Note
                        //    the special characters (!, $, ?, &) that denote Component and Feature states.
                        regex = new Regex(@"NOT|EQV|XOR|OR|AND|IMP|"".*?""|%[a-zA-Z_][a-zA-Z0-9_\.]*|(?<identifier>[!$\?&]?[a-zA-Z_][a-zA-Z0-9_\.]*)", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);

                        // less performant version of the above with captures showing where everything lives
                        // regex = new Regex(@"(?<operator>NOT|EQV|XOR|OR|AND|IMP)|(?<string>"".*?"")|(?<environment>%[a-zA-Z_][a-zA-Z0-9_\.]*)|(?<identifier>[!$\?&]?[a-zA-Z_][a-zA-Z0-9_\.]*)",RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
                    }

                    MatchCollection matches = regex.Matches(fieldData);

                    sb = new StringBuilder(fieldData);

                    // notice how this code walks backward through the list
                    // because it modifies the string as we through it
                    for (int i = matches.Count - 1; 0 <= i; i--)
                    {
                        Group group = matches[i].Groups["identifier"];
                        if (group.Success)
                        {
                            string identifier = group.Value;
                            if (!Util.IsStandardProperty(identifier) && (null == suppressModularizationIdentifiers || !suppressModularizationIdentifiers.Contains(identifier)))
                            {
                                sb.Insert(group.Index + group.Length, '.');
                                sb.Insert(group.Index + group.Length + 1, modularizationGuid);
                            }
                        }
                    }

                    fieldData = sb.ToString();
                    break;

                case ColumnModularizeType.CompanionFile:
                    // if we're not supposed to ignore this identifier and the value does not start with
                    // a digit, we must have a companion file so modularize it
                    if ((null == suppressModularizationIdentifiers || !suppressModularizationIdentifiers.Contains(fieldData)) &&
                        0 < fieldData.Length && !Char.IsDigit(fieldData, 0))
                    {
                        fieldData = String.Concat(fieldData, ".", modularizationGuid);
                    }
                    break;

                case ColumnModularizeType.Icon:
                    if (null == suppressModularizationIdentifiers || !suppressModularizationIdentifiers.Contains(fieldData))
                    {
                        start = fieldData.LastIndexOf(".", StringComparison.Ordinal);
                        if (-1 == start)
                        {
                            fieldData = String.Concat(fieldData, ".", modularizationGuid);
                        }
                        else
                        {
                            fieldData = String.Concat(fieldData.Substring(0, start), ".", modularizationGuid, fieldData.Substring(start));
                        }
                    }
                    break;

                case ColumnModularizeType.SemicolonDelimited:
                    string[] keys = fieldData.Split(';');
                    for (int i = 0; i < keys.Length; ++i)
                    {
                        keys[i] = String.Concat(keys[i], ".", modularizationGuid);
                    }
                    fieldData = String.Join(";", keys);
                    break;
                }
            }

            return(fieldData);
        }