Ejemplo n.º 1
0
 /// <summary>
 /// Creates a new column definition.
 /// </summary>
 /// <param name="name">Name of column.</param>
 /// <param name="type">Type of column</param>
 /// <param name="length">Length of column.</param>
 /// <param name="primaryKey">If column is primary key.</param>
 /// <param name="nullable">If column is nullable.</param>
 /// <param name="modularizeType">Type of modularization for column</param>
 /// <param name="localizable">If the column is localizable.</param>
 /// <param name="minValueSet">If the minimum of the value was set.</param>
 /// <param name="minValue">Minimum value for the column.</param>
 /// <param name="maxValueSet">If the maximum value was set.</param>
 /// <param name="maxValue">Maximum value for the colum.</param>
 /// <param name="keyTable">Optional name of table for foreign key.</param>
 /// <param name="keyColumnSet">If the key column was set.</param>
 /// <param name="keyColumn">Optional name of column for foreign key.</param>
 /// <param name="category">Validation category for column.</param>
 /// <param name="possibilities">Set of possible values for column.</param>
 /// <param name="description">Description of column in vaidation table.</param>
 /// <param name="escapeIdtCharacters">If characters should be escaped in IDT.</param>
 /// <param name="useCData">If whitespace should be preserved in a CDATA node.</param>
 public ColumnDefinition(string name, ColumnType type, int length, bool primaryKey, bool nullable, ColumnModularizeType modularizeType, bool localizable, bool minValueSet, int minValue, bool maxValueSet, int maxValue, string keyTable, bool keyColumnSet, int keyColumn, ColumnCategory category, string possibilities, string description, bool escapeIdtCharacters, bool useCData)
 {
     this.name                = name;
     this.type                = type;
     this.length              = length;
     this.primaryKey          = primaryKey;
     this.nullable            = nullable;
     this.modularize          = modularizeType;
     this.localizable         = localizable;
     this.minValueSet         = minValueSet;
     this.minValue            = minValue;
     this.maxValueSet         = maxValueSet;
     this.maxValue            = maxValue;
     this.keyTable            = keyTable;
     this.keyColumnSet        = keyColumnSet;
     this.keyColumn           = keyColumn;
     this.category            = category;
     this.possibilities       = possibilities;
     this.description         = description;
     this.escapeIdtCharacters = escapeIdtCharacters;
     this.useCData            = useCData;
 }
Ejemplo n.º 2
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 (CompilerCore.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()) && CompilerCore.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 (!CompilerCore.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 (plus a space).  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\s|EQV\s|XOR\s|OR\s|AND\s|IMP\s|"".*?""|%[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);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Returns the field data in a format usable in IDT files.
        /// </summary>
        /// <param name="field">The field to modularize.</param>
        /// <param name="moduleGuid">String containing the GUID of the Merge Module to append the the field value, if appropriate.</param>
        /// <param name="ignoreModularizations">Optional collection of identifers that should not be modularized.</param>
        /// <remarks>moduleGuid is expected to be null when not being used to compile a Merge Module.</remarks>
        /// <returns>Field data in string IDT format.</returns>
        public string GetIdtValue(Field field, string moduleGuid, IgnoreModularizationCollection ignoreModularizations)
        {
            if (field.Column.IsUnreal)
            {
                return(null);
            }
            if (null == field.Data)
            {
                return(String.Empty);
            }

            string fieldData = Convert.ToString(field.Data);

            // special idt-specific escaping
            if (field.Column.EscapeIdtCharacters)
            {
                fieldData = fieldData.Replace('\t', '\x10');
                fieldData = fieldData.Replace('\r', '\x11');
                fieldData = fieldData.Replace('\n', '\x19');
            }

            string idtValue;

            if (null != moduleGuid && ColumnModularizeType.None != field.Column.ModularizeType && !Common.IsExcludedFromModularization(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.row[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 (CompilerCore.IsIdentifier(fieldData))
                        {
                            modularizeType = ColumnModularizeType.Column;
                        }
                        else
                        {
                            modularizeType = ColumnModularizeType.Property;
                        }
                        break;

                    default:     // formatted
                        modularizeType = ColumnModularizeType.Property;
                        break;
                    }
                }

                switch (modularizeType)
                {
                case ColumnModularizeType.Column:
                    // ensure the value is an identifier (otherwise it shouldn't be modularized this way)
                    if (!CompilerCore.IsIdentifier(fieldData))
                    {
                        throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "The value '{0}' is not a legal identifier and therefore cannot be modularized.", fieldData));
                    }

                    // if we're not supposed to ignore this identifier
                    if (null == ignoreModularizations || !ignoreModularizations.ShouldIgnoreModularization(fieldData))
                    {
                        idtValue = String.Concat(fieldData, ".", moduleGuid);
                    }
                    else
                    {
                        idtValue = fieldData;
                    }
                    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.Compiled | 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.Compiled | 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.Compiled | 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 (!Common.IsStandardProperty(identifier) && (null == ignoreModularizations || !ignoreModularizations.ShouldIgnoreModularization(identifier)))
                            {
                                sb.Insert(group.Index + group.Length, '.');
                                sb.Insert(group.Index + group.Length + 1, moduleGuid);
                            }
                        }
                    }

                    idtValue = 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 == ignoreModularizations || !ignoreModularizations.ShouldIgnoreModularization(fieldData)) &&
                        0 < fieldData.Length && !Char.IsDigit(fieldData, 0))
                    {
                        idtValue = String.Concat(fieldData, ".", moduleGuid);
                    }
                    else
                    {
                        idtValue = fieldData;
                    }
                    break;

                case ColumnModularizeType.Icon:
                    if (null == ignoreModularizations || !ignoreModularizations.ShouldIgnoreModularization(fieldData))
                    {
                        start = fieldData.LastIndexOf(".");
                        if (-1 == start)
                        {
                            idtValue = String.Concat(fieldData, ".", moduleGuid);
                        }
                        else
                        {
                            idtValue = String.Concat(fieldData.Substring(0, start), ".", moduleGuid, fieldData.Substring(start));
                        }
                    }
                    else
                    {
                        idtValue = fieldData;
                    }
                    break;

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

                default:
                    idtValue = fieldData;
                    break;
                }
            }
            else // no modularization necessary, just use the field data
            {
                idtValue = fieldData;
            }

            return(idtValue);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Parses a column definition in a table definition.
        /// </summary>
        /// <param name="reader">Reader to get data from.</param>
        /// <returns>The ColumnDefintion represented by the Xml.</returns>
        internal static ColumnDefinition Parse(XmlReader reader)
        {
            Debug.Assert("columnDefinition" == reader.LocalName);

            bool                 added               = false;
            ColumnCategory       category            = ColumnCategory.Unknown;
            string               description         = null;
            bool                 empty               = reader.IsEmptyElement;
            bool                 escapeIdtCharacters = false;
            int                  keyColumn           = -1;
            bool                 keyColumnSet        = false;
            string               keyTable            = null;
            int                  length              = -1;
            bool                 localizable         = false;
            int                  maxValue            = 0;
            bool                 maxValueSet         = false;
            int                  minValue            = 0;
            bool                 minValueSet         = false;
            ColumnModularizeType modularize          = ColumnModularizeType.None;
            string               name          = null;
            bool                 nullable      = false;
            string               possibilities = null;
            bool                 primaryKey    = false;
            ColumnType           type          = ColumnType.Unknown;
            bool                 useCData      = false;

            // parse the attributes
            while (reader.MoveToNextAttribute())
            {
                switch (reader.LocalName)
                {
                case "added":
                    added = Common.IsYes(SourceLineNumberCollection.FromUri(reader.BaseURI), "columnDefinition", reader.Name, reader.Value);
                    break;

                case "category":
                    switch (reader.Value)
                    {
                    case "anyPath":
                        category = ColumnCategory.AnyPath;
                        break;

                    case "binary":
                        category = ColumnCategory.Binary;
                        break;

                    case "cabinet":
                        category = ColumnCategory.Cabinet;
                        break;

                    case "condition":
                        category = ColumnCategory.Condition;
                        break;

                    case "customSource":
                        category = ColumnCategory.CustomSource;
                        break;

                    case "defaultDir":
                        category = ColumnCategory.DefaultDir;
                        break;

                    case "doubleInteger":
                        category = ColumnCategory.DoubleInteger;
                        break;

                    case "filename":
                        category = ColumnCategory.Filename;
                        break;

                    case "formatted":
                        category = ColumnCategory.Formatted;
                        break;

                    case "formattedSddl":
                        category = ColumnCategory.FormattedSDDLText;
                        break;

                    case "guid":
                        category = ColumnCategory.Guid;
                        break;

                    case "identifier":
                        category = ColumnCategory.Identifier;
                        break;

                    case "integer":
                        category = ColumnCategory.Integer;
                        break;

                    case "language":
                        category = ColumnCategory.Language;
                        break;

                    case "lowerCase":
                        category = ColumnCategory.LowerCase;
                        break;

                    case "path":
                        category = ColumnCategory.Path;
                        break;

                    case "paths":
                        category = ColumnCategory.Paths;
                        break;

                    case "property":
                        category = ColumnCategory.Property;
                        break;

                    case "regPath":
                        category = ColumnCategory.RegPath;
                        break;

                    case "shortcut":
                        category = ColumnCategory.Shortcut;
                        break;

                    case "template":
                        category = ColumnCategory.Template;
                        break;

                    case "text":
                        category = ColumnCategory.Text;
                        break;

                    case "timeDate":
                        category = ColumnCategory.TimeDate;
                        break;

                    case "upperCase":
                        category = ColumnCategory.UpperCase;
                        break;

                    case "version":
                        category = ColumnCategory.Version;
                        break;

                    case "wildCardFilename":
                        category = ColumnCategory.WildCardFilename;
                        break;

                    default:
                        throw new WixException(WixErrors.IllegalAttributeValue(SourceLineNumberCollection.FromUri(reader.BaseURI), "columnDefinition", reader.Name, reader.Value, "anyPath", "binary", "cabinet", "condition", "customSource", "defaultDir", "doubleInteger", "filename", "formatted", "formattedSddl", "guid", "identifier", "integer", "language", "lowerCase", "path", "paths", "property", "regPath", "shortcut", "template", "text", "timeDate", "upperCase", "version", "wildCardFilename"));
                    }
                    break;

                case "description":
                    description = reader.Value;
                    break;

                case "escapeIdtCharacters":
                    escapeIdtCharacters = Common.IsYes(SourceLineNumberCollection.FromUri(reader.BaseURI), "columnDefinition", reader.Name, reader.Value);
                    break;

                case "keyColumn":
                    keyColumnSet = true;
                    keyColumn    = Convert.ToInt32(reader.Value, 10);
                    break;

                case "keyTable":
                    keyTable = reader.Value;
                    break;

                case "length":
                    length = Convert.ToInt32(reader.Value, 10);
                    break;

                case "localizable":
                    localizable = Common.IsYes(SourceLineNumberCollection.FromUri(reader.BaseURI), "columnDefinition", reader.Name, reader.Value);
                    break;

                case "maxValue":
                    maxValueSet = true;
                    maxValue    = Convert.ToInt32(reader.Value, 10);
                    break;

                case "minValue":
                    minValueSet = true;
                    minValue    = Convert.ToInt32(reader.Value, 10);
                    break;

                case "modularize":
                    switch (reader.Value)
                    {
                    case "column":
                        modularize = ColumnModularizeType.Column;
                        break;

                    case "companionFile":
                        modularize = ColumnModularizeType.CompanionFile;
                        break;

                    case "condition":
                        modularize = ColumnModularizeType.Condition;
                        break;

                    case "controlEventArgument":
                        modularize = ColumnModularizeType.ControlEventArgument;
                        break;

                    case "controlText":
                        modularize = ColumnModularizeType.ControlText;
                        break;

                    case "icon":
                        modularize = ColumnModularizeType.Icon;
                        break;

                    case "none":
                        modularize = ColumnModularizeType.None;
                        break;

                    case "property":
                        modularize = ColumnModularizeType.Property;
                        break;

                    case "semicolonDelimited":
                        modularize = ColumnModularizeType.SemicolonDelimited;
                        break;

                    default:
                        throw new WixException(WixErrors.IllegalAttributeValue(SourceLineNumberCollection.FromUri(reader.BaseURI), "columnDefinition", reader.Name, reader.Value, "column", "companionFile", "condition", "controlEventArgument", "controlText", "icon", "property", "semicolonDelimited"));
                    }
                    break;

                case "name":
                    switch (reader.Value)
                    {
                    case "CREATE":
                    case "DELETE":
                    case "DROP":
                    case "INSERT":
                        throw new WixException(WixErrors.IllegalColumnName(SourceLineNumberCollection.FromUri(reader.BaseURI), "columnDefinition", reader.Name, reader.Value));

                    default:
                        name = reader.Value;
                        break;
                    }
                    break;

                case "nullable":
                    nullable = Common.IsYes(SourceLineNumberCollection.FromUri(reader.BaseURI), "columnDefinition", reader.Name, reader.Value);
                    break;

                case "primaryKey":
                    primaryKey = Common.IsYes(SourceLineNumberCollection.FromUri(reader.BaseURI), "columnDefinition", reader.Name, reader.Value);
                    break;

                case "set":
                    possibilities = reader.Value;
                    break;

                case "type":
                    switch (reader.Value)
                    {
                    case "localized":
                        type = ColumnType.Localized;
                        break;

                    case "number":
                        type = ColumnType.Number;
                        break;

                    case "object":
                        type = ColumnType.Object;
                        break;

                    case "string":
                        type = ColumnType.String;
                        break;

                    case "preserved":
                        type = ColumnType.Preserved;
                        break;

                    default:
                        throw new WixException(WixErrors.IllegalAttributeValue(SourceLineNumberCollection.FromUri(reader.BaseURI), "columnDefinition", reader.Name, reader.Value, "localized", "number", "object", "string"));
                    }
                    break;

                case "useCData":
                    useCData = Common.IsYes(SourceLineNumberCollection.FromUri(reader.BaseURI), "columnDefinition", reader.Name, reader.Value);
                    break;

                default:
                    if (!reader.NamespaceURI.StartsWith("http://www.w3.org/", StringComparison.Ordinal))
                    {
                        throw new WixException(WixErrors.UnexpectedAttribute(SourceLineNumberCollection.FromUri(reader.BaseURI), "columnDefinition", reader.Name));
                    }
                    break;
                }
            }

            // parse the child elements (there should be none)
            if (!empty)
            {
                bool done = false;

                while (!done && reader.Read())
                {
                    switch (reader.NodeType)
                    {
                    case XmlNodeType.Element:
                        throw new WixException(WixErrors.UnexpectedElement(SourceLineNumberCollection.FromUri(reader.BaseURI), "columnDefinition", reader.Name));

                    case XmlNodeType.EndElement:
                        done = true;
                        break;
                    }
                }

                if (!done)
                {
                    throw new WixException(WixErrors.ExpectedEndElement(SourceLineNumberCollection.FromUri(reader.BaseURI), "columnDefinition"));
                }
            }

            ColumnDefinition columnDefinition = new ColumnDefinition(name, type, length, primaryKey, nullable, modularize, localizable, minValueSet, minValue, maxValueSet, maxValue, keyTable, keyColumnSet, keyColumn, category, possibilities, description, escapeIdtCharacters, useCData);

            columnDefinition.Added = added;

            return(columnDefinition);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Parses a column definition in a table definition.
        /// </summary>
        /// <param name="reader">Reader to get data from.</param>
        /// <returns>The ColumnDefintion represented by the Xml.</returns>
        internal static ColumnDefinition Parse(XmlReader reader)
        {
            Debug.Assert("columnDefinition" == reader.LocalName);

            string name = null;
            ColumnType type = ColumnType.Unknown;
            int length = -1;
            bool primaryKey = false;
            bool symbol = false;
            bool nullable = false;
            ColumnModularizeType modularize = ColumnModularizeType.None;
            bool unreal = false;
            bool localizable = false;

            bool minValueSet = false;
            int minValue = 0;
            bool maxValueSet = false;
            int maxValue = 0;
            string keyTable = null;
            bool keyColumnSet = false;
            int keyColumn = -1;
            ColumnCategory category = ColumnCategory.Unknown;
            string possibilities = null;
            string description = null;
            bool escapeIdtCharacters = false;
            bool useCData = false;
            bool empty = reader.IsEmptyElement;

            // parse the attributes
            while (reader.MoveToNextAttribute())
            {
                switch (reader.LocalName)
                {
                    case "name":
                        name = reader.Value;
                        break;
                    case "type":
                        switch (reader.Value)
                        {
                            case "string":
                                type = ColumnType.String;
                                break;
                            case "localized":
                                type = ColumnType.Localized;
                                break;
                            case "localizedNumber":
                                type = ColumnType.LocalizedNumber;
                                break;
                            case "number":
                                type = ColumnType.Number;
                                break;
                            case "object":
                                type = ColumnType.Object;
                                break;
                            default:
                                throw new WixParseException(String.Format("The columnDefinition/@type attribute contains an unexpected value '{0}'.", reader.Value));
                        }
                        break;
                    case "length":
                        length = Convert.ToInt32(reader.Value, 10);
                        break;
                    case "primaryKey":
                        primaryKey = Common.IsYes(reader.Value, null, "columnDefinition", "primaryKey", name);
                        break;
                    case "nullable":
                        nullable = Common.IsYes(reader.Value, null, "columnDefinition", "nullable", name);
                        break;
                    case "modularize":
                        switch (reader.Value)
                        {
                            case "none":
                                modularize = ColumnModularizeType.None;
                                break;
                            case "column":
                                modularize = ColumnModularizeType.Column;
                                break;
                            case "companionFile":
                                modularize = ColumnModularizeType.CompanionFile;
                                break;
                            case "condition":
                                modularize = ColumnModularizeType.Condition;
                                break;
                            case "controlEventArgument":
                                modularize = ColumnModularizeType.ControlEventArgument;
                                break;
                            case "icon":
                                modularize = ColumnModularizeType.Icon;
                                break;
                            case "property":
                                modularize = ColumnModularizeType.Property;
                                break;
                            case "semicolonDelimited":
                                modularize = ColumnModularizeType.SemicolonDelimited;
                                break;
                            default:
                                throw new WixParseException(String.Format("The columnDefinition/@modularize attribute contains an unexpected value '{0}'.", reader.Value));
                        }
                        break;
                    case "symbol":
                        symbol = Common.IsYes(reader.Value, null, "columnDefinition", "symbol", name);
                        break;
                    case "unreal":
                        unreal = Common.IsYes(reader.Value, null, "columnDefinition", "unreal", name);
                        break;
                    case "localizable":
                        localizable = Common.IsYes(reader.Value, null, "columnDefinition", "localizable", name);
                        break;
                    case "minValue":
                        minValueSet = true;
                        minValue = Convert.ToInt32(reader.Value, 10);
                        break;
                    case "maxValue":
                        maxValueSet = true;
                        maxValue = Convert.ToInt32(reader.Value, 10);
                        break;
                    case "keyTable":
                        keyTable = reader.Value;
                        break;
                    case "keyColumn":
                        keyColumnSet = true;
                        keyColumn = Convert.ToInt32(reader.Value, 10);
                        break;
                    case "category":
                        switch (reader.Value)
                        {
                            case "text":
                                category = ColumnCategory.Text;
                                break;
                            case "upperCase":
                                category = ColumnCategory.UpperCase;
                                break;
                            case "lowerCase":
                                category = ColumnCategory.LowerCase;
                                break;
                            case "integer":
                                category = ColumnCategory.Integer;
                                break;
                            case "doubleInteger":
                                category = ColumnCategory.DoubleInteger;
                                break;
                            case "timeDate":
                                category = ColumnCategory.TimeDate;
                                break;
                            case "identifier":
                                category = ColumnCategory.Identifier;
                                break;
                            case "property":
                                category = ColumnCategory.Property;
                                break;
                            case "filename":
                                category = ColumnCategory.Filename;
                                break;
                            case "wildCardFilename":
                                category = ColumnCategory.WildCardFilename;
                                break;
                            case "path":
                                category = ColumnCategory.Path;
                                break;
                            case "paths":
                                category = ColumnCategory.Paths;
                                break;
                            case "anyPath":
                                category = ColumnCategory.AnyPath;
                                break;
                            case "defaultDir":
                                category = ColumnCategory.DefaultDir;
                                break;
                            case "regPath":
                                category = ColumnCategory.RegPath;
                                break;
                            case "formatted":
                                category = ColumnCategory.Formatted;
                                break;
                            case "template":
                                category = ColumnCategory.Template;
                                break;
                            case "condition":
                                category = ColumnCategory.Condition;
                                break;
                            case "guid":
                                category = ColumnCategory.Guid;
                                break;
                            case "version":
                                category = ColumnCategory.Version;
                                break;
                            case "language":
                                category = ColumnCategory.Language;
                                break;
                            case "binary":
                                category = ColumnCategory.Binary;
                                break;
                            case "customSource":
                                category = ColumnCategory.CustomSource;
                                break;
                            case "cabinet":
                                category = ColumnCategory.Cabinet;
                                break;
                            case "shortcut":
                                category = ColumnCategory.Shortcut;
                                break;
                            default:
                                throw new WixParseException(String.Format("The columnDefinition/@category attribute contains an unexpected value '{0}'.", reader.Value));
                        }
                        break;
                    case "set":
                        possibilities = reader.Value;
                        break;
                    case "description":
                        description = reader.Value;
                        break;
                    case "escapeIdtCharacters":
                        escapeIdtCharacters = Common.IsYes(reader.Value, null, "columnDefinition", reader.LocalName, name);
                        break;
                    case "useCData":
                        useCData = Common.IsYes(reader.Value, null, "columnDefinition", reader.LocalName, name);
                        break;
                    default:
                        throw new WixParseException(String.Format("The columnDefinition element contains an unexpected attribute '{0}'.", reader.Name));
                }
            }

            // parse the child elements (there should be none)
            if (!empty)
            {
                bool done = false;

                while (!done && reader.Read())
                {
                    switch (reader.NodeType)
                    {
                        case XmlNodeType.Element:
                            throw new WixParseException(String.Format("The columnDefinition element contains an unexpected child element {0}.", reader.Name));
                        case XmlNodeType.EndElement:
                            done = true;
                            break;
                    }
                }

                if (!done)
                {
                    throw new WixParseException("Missing end element while processing the columnDefinition element.");
                }
            }

            return new ColumnDefinition(name, type, length, primaryKey, symbol, nullable, modularize, unreal, localizable, minValueSet, minValue, maxValueSet, maxValue, keyTable, keyColumnSet, keyColumn, category, possibilities, description, escapeIdtCharacters, useCData);
        }
Ejemplo n.º 6
0
 /// <summary>
 /// Creates a new column definition.
 /// </summary>
 /// <param name="name">Name of column.</param>
 /// <param name="type">Type of column</param>
 /// <param name="length">Length of column.</param>
 /// <param name="primaryKey">If column is primary key.</param>
 /// <param name="symbol">If column is part of the symbol.</param>
 /// <param name="nullable">If column is nullable.</param>
 /// <param name="modularizeType">Type of modularization for column</param>
 /// <param name="unreal">If column is unreal/virtual.</param>
 /// <param name="localizable">If the column is localizable.</param>
 /// <param name="minValueSet">If the minimum of the value was set.</param>
 /// <param name="minValue">Minimum value for the column.</param>
 /// <param name="maxValueSet">If the maximum value was set.</param>
 /// <param name="maxValue">Maximum value for the colum.</param>
 /// <param name="keyTable">Optional name of table for foreign key.</param>
 /// <param name="keyColumnSet">If the key column was set.</param>
 /// <param name="keyColumn">Optional name of column for foreign key.</param>
 /// <param name="category">Validation category for column.</param>
 /// <param name="possibilities">Set of possible values for column.</param>
 /// <param name="description">Description of column in vaidation table.</param>
 /// <param name="escapeIdtCharacters">If characters should be escaped in IDT.</param>
 /// <param name="useCData">If whitespace should be preserved in a CDATA node.</param>
 public ColumnDefinition(string name, ColumnType type, int length, bool primaryKey, bool symbol, bool nullable, ColumnModularizeType modularizeType, bool unreal, bool localizable, bool minValueSet, int minValue, bool maxValueSet, int maxValue, string keyTable, bool keyColumnSet, int keyColumn, ColumnCategory category, string possibilities, string description, bool escapeIdtCharacters, bool useCData)
 {
     this.name = name;
     this.type = type;
     this.length = length;
     this.primaryKey = primaryKey;
     this.symbol = symbol;
     this.nullable = nullable;
     this.modularize = modularizeType;
     this.unreal = unreal;
     this.localizable = localizable;
     this.minValueSet = minValueSet;
     this.minValue = minValue;
     this.maxValueSet = maxValueSet;
     this.maxValue = maxValue;
     this.keyTable = keyTable;
     this.keyColumnSet = keyColumnSet;
     this.keyColumn = keyColumn;
     this.category = category;
     this.possibilities = possibilities;
     this.description = description;
     this.escapeIdtCharacters = escapeIdtCharacters;
     this.useCData = useCData;
 }
Ejemplo n.º 7
0
        public Output Execute()
        {
            string modularizationGuid = null;
            Output output             = new Output(new SourceLineNumber(this.DatabasePath));
            View   validationView     = null;

            // set the output type
            output.Type = this.OutputType;

            // get the codepage
            this.Database.Export("_ForceCodepage", this.IntermediateFolder, "_ForceCodepage.idt");
            using (StreamReader sr = File.OpenText(Path.Combine(this.IntermediateFolder, "_ForceCodepage.idt")))
            {
                string line;

                while (null != (line = sr.ReadLine()))
                {
                    string[] data = line.Split('\t');

                    if (2 == data.Length)
                    {
                        output.Codepage = Convert.ToInt32(data[0], CultureInfo.InvariantCulture);
                    }
                }
            }

            // get the summary information table if it exists; it won't if unbinding a transform
            if (!this.SkipSummaryInfo)
            {
                using (SummaryInformation summaryInformation = new SummaryInformation(this.Database))
                {
                    Table table = new Table(this.TableDefinitions["_SummaryInformation"]);

                    for (int i = 1; 19 >= i; i++)
                    {
                        string value = summaryInformation.GetProperty(i);

                        if (0 < value.Length)
                        {
                            Row row = table.CreateRow(output.SourceLineNumbers);
                            row[0] = i;
                            row[1] = value;
                        }
                    }

                    output.Tables.Add(table);
                }
            }

            try
            {
                // open a view on the validation table if it exists
                if (this.Database.TableExists("_Validation"))
                {
                    validationView = this.Database.OpenView("SELECT * FROM `_Validation` WHERE `Table` = ? AND `Column` = ?");
                }

                // get the normal tables
                using (View tablesView = this.Database.OpenExecuteView("SELECT * FROM _Tables"))
                {
                    while (true)
                    {
                        using (Record tableRecord = tablesView.Fetch())
                        {
                            if (null == tableRecord)
                            {
                                break;
                            }

                            string tableName = tableRecord.GetString(1);

                            using (View tableView = this.Database.OpenExecuteView(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM `{0}`", tableName)))
                            {
                                ColumnDefinition[] columns;
                                using (Record columnNameRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFONAMES),
                                       columnTypeRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFOTYPES))
                                {
                                    // index the primary keys
                                    HashSet <string> tablePrimaryKeys = new HashSet <string>();
                                    using (Record primaryKeysRecord = this.Database.PrimaryKeys(tableName))
                                    {
                                        int primaryKeysFieldCount = primaryKeysRecord.GetFieldCount();

                                        for (int i = 1; i <= primaryKeysFieldCount; i++)
                                        {
                                            tablePrimaryKeys.Add(primaryKeysRecord.GetString(i));
                                        }
                                    }

                                    int columnCount = columnNameRecord.GetFieldCount();
                                    columns = new ColumnDefinition[columnCount];
                                    for (int i = 1; i <= columnCount; i++)
                                    {
                                        string columnName = columnNameRecord.GetString(i);
                                        string idtType    = columnTypeRecord.GetString(i);

                                        ColumnType columnType;
                                        int        length;
                                        bool       nullable;

                                        ColumnCategory       columnCategory       = ColumnCategory.Unknown;
                                        ColumnModularizeType columnModularizeType = ColumnModularizeType.None;
                                        bool   primary     = tablePrimaryKeys.Contains(columnName);
                                        int?   minValue    = null;
                                        int?   maxValue    = null;
                                        string keyTable    = null;
                                        int?   keyColumn   = null;
                                        string category    = null;
                                        string set         = null;
                                        string description = null;

                                        // get the column type, length, and whether its nullable
                                        switch (Char.ToLower(idtType[0], CultureInfo.InvariantCulture))
                                        {
                                        case 'i':
                                            columnType = ColumnType.Number;
                                            break;

                                        case 'l':
                                            columnType = ColumnType.Localized;
                                            break;

                                        case 's':
                                            columnType = ColumnType.String;
                                            break;

                                        case 'v':
                                            columnType = ColumnType.Object;
                                            break;

                                        default:
                                            // TODO: error
                                            columnType = ColumnType.Unknown;
                                            break;
                                        }
                                        length   = Convert.ToInt32(idtType.Substring(1), CultureInfo.InvariantCulture);
                                        nullable = Char.IsUpper(idtType[0]);

                                        // try to get validation information
                                        if (null != validationView)
                                        {
                                            using (Record validationRecord = new Record(2))
                                            {
                                                validationRecord.SetString(1, tableName);
                                                validationRecord.SetString(2, columnName);

                                                validationView.Execute(validationRecord);
                                            }

                                            using (Record validationRecord = validationView.Fetch())
                                            {
                                                if (null != validationRecord)
                                                {
                                                    string validationNullable = validationRecord.GetString(3);
                                                    minValue    = validationRecord.IsNull(4) ? null : (int?)validationRecord.GetInteger(4);
                                                    maxValue    = validationRecord.IsNull(5) ? null : (int?)validationRecord.GetInteger(5);
                                                    keyTable    = validationRecord.IsNull(6) ? null : validationRecord.GetString(6);
                                                    keyColumn   = validationRecord.IsNull(7) ? null : (int?)validationRecord.GetInteger(7);
                                                    category    = validationRecord.IsNull(8) ? null : validationRecord.GetString(8);
                                                    set         = validationRecord.IsNull(9) ? null : validationRecord.GetString(9);
                                                    description = validationRecord.IsNull(10) ? null : validationRecord.GetString(10);

                                                    // check the validation nullable value against the column definition
                                                    if (null == validationNullable)
                                                    {
                                                        // TODO: warn for illegal validation nullable column
                                                    }
                                                    else if ((nullable && "Y" != validationNullable) || (!nullable && "N" != validationNullable))
                                                    {
                                                        // TODO: warn for mismatch between column definition and validation nullable
                                                    }

                                                    // convert category to ColumnCategory
                                                    if (null != category)
                                                    {
                                                        try
                                                        {
                                                            columnCategory = (ColumnCategory)Enum.Parse(typeof(ColumnCategory), category, true);
                                                        }
                                                        catch (ArgumentException)
                                                        {
                                                            columnCategory = ColumnCategory.Unknown;
                                                        }
                                                    }
                                                }
                                                else
                                                {
                                                    // TODO: warn about no validation information
                                                }
                                            }
                                        }

                                        // guess the modularization type
                                        if ("Icon" == keyTable && 1 == keyColumn)
                                        {
                                            columnModularizeType = ColumnModularizeType.Icon;
                                        }
                                        else if ("Condition" == columnName)
                                        {
                                            columnModularizeType = ColumnModularizeType.Condition;
                                        }
                                        else if (ColumnCategory.Formatted == columnCategory || ColumnCategory.FormattedSDDLText == columnCategory)
                                        {
                                            columnModularizeType = ColumnModularizeType.Property;
                                        }
                                        else if (ColumnCategory.Identifier == columnCategory)
                                        {
                                            columnModularizeType = ColumnModularizeType.Column;
                                        }

                                        columns[i - 1] = new ColumnDefinition(columnName, columnType, length, primary, nullable, columnCategory, minValue, maxValue, keyTable, keyColumn, set, description, columnModularizeType, (ColumnType.Localized == columnType), true);
                                    }
                                }

                                TableDefinition tableDefinition = new TableDefinition(tableName, columns, false, false);

                                // use our table definitions if core properties are the same; this allows us to take advantage
                                // of wix concepts like localizable columns which current code assumes
                                if (this.TableDefinitions.Contains(tableName) && 0 == tableDefinition.CompareTo(this.TableDefinitions[tableName]))
                                {
                                    tableDefinition = this.TableDefinitions[tableName];
                                }

                                Table table = new Table(tableDefinition);

                                while (true)
                                {
                                    using (Record rowRecord = tableView.Fetch())
                                    {
                                        if (null == rowRecord)
                                        {
                                            break;
                                        }

                                        int recordCount = rowRecord.GetFieldCount();
                                        Row row         = table.CreateRow(output.SourceLineNumbers);

                                        for (int i = 0; recordCount > i && row.Fields.Length > i; i++)
                                        {
                                            if (rowRecord.IsNull(i + 1))
                                            {
                                                if (!row.Fields[i].Column.Nullable)
                                                {
                                                    // TODO: display an error for a null value in a non-nullable field OR
                                                    // display a warning and put an empty string in the value to let the compiler handle it
                                                    // (the second option is risky because the later code may make certain assumptions about
                                                    // the contents of a row value)
                                                }
                                            }
                                            else
                                            {
                                                switch (row.Fields[i].Column.Type)
                                                {
                                                case ColumnType.Number:
                                                    bool success  = false;
                                                    int  intValue = rowRecord.GetInteger(i + 1);
                                                    if (row.Fields[i].Column.IsLocalizable)
                                                    {
                                                        success = row.BestEffortSetField(i, Convert.ToString(intValue, CultureInfo.InvariantCulture));
                                                    }
                                                    else
                                                    {
                                                        success = row.BestEffortSetField(i, intValue);
                                                    }

                                                    if (!success)
                                                    {
                                                        this.Messaging.Write(WarningMessages.BadColumnDataIgnored(row.SourceLineNumbers, Convert.ToString(intValue, CultureInfo.InvariantCulture), tableName, row.Fields[i].Column.Name));
                                                    }
                                                    break;

                                                case ColumnType.Object:
                                                    string sourceFile = "FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES";

                                                    if (null != this.ExportBasePath)
                                                    {
                                                        string relativeSourceFile = Path.Combine(tableName, row.GetPrimaryKey('.'));
                                                        sourceFile = Path.Combine(this.ExportBasePath, relativeSourceFile);

                                                        // ensure the parent directory exists
                                                        System.IO.Directory.CreateDirectory(Path.Combine(this.ExportBasePath, tableName));

                                                        using (FileStream fs = System.IO.File.Create(sourceFile))
                                                        {
                                                            int    bytesRead;
                                                            byte[] buffer = new byte[512];

                                                            while (0 != (bytesRead = rowRecord.GetStream(i + 1, buffer, buffer.Length)))
                                                            {
                                                                fs.Write(buffer, 0, bytesRead);
                                                            }
                                                        }
                                                    }

                                                    row[i] = sourceFile;
                                                    break;

                                                default:
                                                    string value = rowRecord.GetString(i + 1);

                                                    switch (row.Fields[i].Column.Category)
                                                    {
                                                    case ColumnCategory.Guid:
                                                        value = value.ToUpper(CultureInfo.InvariantCulture);
                                                        break;
                                                    }

                                                    // de-modularize
                                                    if (!this.SuppressDemodularization && OutputType.Module == output.Type && ColumnModularizeType.None != row.Fields[i].Column.ModularizeType)
                                                    {
                                                        Regex modularization = new Regex(@"\.[0-9A-Fa-f]{8}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{12}");

                                                        if (null == modularizationGuid)
                                                        {
                                                            Match match = modularization.Match(value);
                                                            if (match.Success)
                                                            {
                                                                modularizationGuid = String.Concat('{', match.Value.Substring(1).Replace('_', '-'), '}');
                                                            }
                                                        }

                                                        value = modularization.Replace(value, String.Empty);
                                                    }

                                                    // escape "$(" for the preprocessor
                                                    value = value.Replace("$(", "$$(");

                                                    // escape things that look like wix variables
                                                    MatchCollection matches = Common.WixVariableRegex.Matches(value);
                                                    for (int j = matches.Count - 1; 0 <= j; j--)
                                                    {
                                                        value = value.Insert(matches[j].Index, "!");
                                                    }

                                                    row[i] = value;
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }

                                output.Tables.Add(table);
                            }
                        }
                    }
                }
            }
            finally
            {
                if (null != validationView)
                {
                    validationView.Close();
                }
            }

            // set the modularization guid as the PackageCode
            if (null != modularizationGuid)
            {
                Table table = output.Tables["_SummaryInformation"];

                foreach (Row row in table.Rows)
                {
                    if (9 == (int)row[0]) // PID_REVNUMBER
                    {
                        row[1] = modularizationGuid;
                    }
                }
            }

            if (this.IsAdminImage)
            {
                GenerateWixFileTable(this.DatabasePath, output);
                GenerateSectionIds(output);
            }

            return(output);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Parses a column definition in a table definition.
        /// </summary>
        /// <param name="reader">Reader to get data from.</param>
        /// <returns>The ColumnDefintion represented by the Xml.</returns>
        internal static ColumnDefinition Parse(XmlReader reader)
        {
            Debug.Assert("columnDefinition" == reader.LocalName);

            string               name        = null;
            ColumnType           type        = ColumnType.Unknown;
            int                  length      = -1;
            bool                 primaryKey  = false;
            bool                 symbol      = false;
            bool                 nullable    = false;
            ColumnModularizeType modularize  = ColumnModularizeType.None;
            bool                 unreal      = false;
            bool                 localizable = false;

            bool           minValueSet         = false;
            int            minValue            = 0;
            bool           maxValueSet         = false;
            int            maxValue            = 0;
            string         keyTable            = null;
            bool           keyColumnSet        = false;
            int            keyColumn           = -1;
            ColumnCategory category            = ColumnCategory.Unknown;
            string         possibilities       = null;
            string         description         = null;
            bool           escapeIdtCharacters = false;
            bool           useCData            = false;
            bool           empty = reader.IsEmptyElement;

            // parse the attributes
            while (reader.MoveToNextAttribute())
            {
                switch (reader.LocalName)
                {
                case "name":
                    name = reader.Value;
                    break;

                case "type":
                    switch (reader.Value)
                    {
                    case "string":
                        type = ColumnType.String;
                        break;

                    case "localized":
                        type = ColumnType.Localized;
                        break;

                    case "localizedNumber":
                        type = ColumnType.LocalizedNumber;
                        break;

                    case "number":
                        type = ColumnType.Number;
                        break;

                    case "object":
                        type = ColumnType.Object;
                        break;

                    default:
                        throw new WixParseException(String.Format("The columnDefinition/@type attribute contains an unexpected value '{0}'.", reader.Value));
                    }
                    break;

                case "length":
                    length = Convert.ToInt32(reader.Value, 10);
                    break;

                case "primaryKey":
                    primaryKey = Common.IsYes(reader.Value, null, "columnDefinition", "primaryKey", name);
                    break;

                case "nullable":
                    nullable = Common.IsYes(reader.Value, null, "columnDefinition", "nullable", name);
                    break;

                case "modularize":
                    switch (reader.Value)
                    {
                    case "none":
                        modularize = ColumnModularizeType.None;
                        break;

                    case "column":
                        modularize = ColumnModularizeType.Column;
                        break;

                    case "companionFile":
                        modularize = ColumnModularizeType.CompanionFile;
                        break;

                    case "condition":
                        modularize = ColumnModularizeType.Condition;
                        break;

                    case "controlEventArgument":
                        modularize = ColumnModularizeType.ControlEventArgument;
                        break;

                    case "icon":
                        modularize = ColumnModularizeType.Icon;
                        break;

                    case "property":
                        modularize = ColumnModularizeType.Property;
                        break;

                    case "semicolonDelimited":
                        modularize = ColumnModularizeType.SemicolonDelimited;
                        break;

                    default:
                        throw new WixParseException(String.Format("The columnDefinition/@modularize attribute contains an unexpected value '{0}'.", reader.Value));
                    }
                    break;

                case "symbol":
                    symbol = Common.IsYes(reader.Value, null, "columnDefinition", "symbol", name);
                    break;

                case "unreal":
                    unreal = Common.IsYes(reader.Value, null, "columnDefinition", "unreal", name);
                    break;

                case "localizable":
                    localizable = Common.IsYes(reader.Value, null, "columnDefinition", "localizable", name);
                    break;

                case "minValue":
                    minValueSet = true;
                    minValue    = Convert.ToInt32(reader.Value, 10);
                    break;

                case "maxValue":
                    maxValueSet = true;
                    maxValue    = Convert.ToInt32(reader.Value, 10);
                    break;

                case "keyTable":
                    keyTable = reader.Value;
                    break;

                case "keyColumn":
                    keyColumnSet = true;
                    keyColumn    = Convert.ToInt32(reader.Value, 10);
                    break;

                case "category":
                    switch (reader.Value)
                    {
                    case "text":
                        category = ColumnCategory.Text;
                        break;

                    case "upperCase":
                        category = ColumnCategory.UpperCase;
                        break;

                    case "lowerCase":
                        category = ColumnCategory.LowerCase;
                        break;

                    case "integer":
                        category = ColumnCategory.Integer;
                        break;

                    case "doubleInteger":
                        category = ColumnCategory.DoubleInteger;
                        break;

                    case "timeDate":
                        category = ColumnCategory.TimeDate;
                        break;

                    case "identifier":
                        category = ColumnCategory.Identifier;
                        break;

                    case "property":
                        category = ColumnCategory.Property;
                        break;

                    case "filename":
                        category = ColumnCategory.Filename;
                        break;

                    case "wildCardFilename":
                        category = ColumnCategory.WildCardFilename;
                        break;

                    case "path":
                        category = ColumnCategory.Path;
                        break;

                    case "paths":
                        category = ColumnCategory.Paths;
                        break;

                    case "anyPath":
                        category = ColumnCategory.AnyPath;
                        break;

                    case "defaultDir":
                        category = ColumnCategory.DefaultDir;
                        break;

                    case "regPath":
                        category = ColumnCategory.RegPath;
                        break;

                    case "formatted":
                        category = ColumnCategory.Formatted;
                        break;

                    case "template":
                        category = ColumnCategory.Template;
                        break;

                    case "condition":
                        category = ColumnCategory.Condition;
                        break;

                    case "guid":
                        category = ColumnCategory.Guid;
                        break;

                    case "version":
                        category = ColumnCategory.Version;
                        break;

                    case "language":
                        category = ColumnCategory.Language;
                        break;

                    case "binary":
                        category = ColumnCategory.Binary;
                        break;

                    case "customSource":
                        category = ColumnCategory.CustomSource;
                        break;

                    case "cabinet":
                        category = ColumnCategory.Cabinet;
                        break;

                    case "shortcut":
                        category = ColumnCategory.Shortcut;
                        break;

                    default:
                        throw new WixParseException(String.Format("The columnDefinition/@category attribute contains an unexpected value '{0}'.", reader.Value));
                    }
                    break;

                case "set":
                    possibilities = reader.Value;
                    break;

                case "description":
                    description = reader.Value;
                    break;

                case "escapeIdtCharacters":
                    escapeIdtCharacters = Common.IsYes(reader.Value, null, "columnDefinition", reader.LocalName, name);
                    break;

                case "useCData":
                    useCData = Common.IsYes(reader.Value, null, "columnDefinition", reader.LocalName, name);
                    break;

                default:
                    throw new WixParseException(String.Format("The columnDefinition element contains an unexpected attribute '{0}'.", reader.Name));
                }
            }

            // parse the child elements (there should be none)
            if (!empty)
            {
                bool done = false;

                while (!done && reader.Read())
                {
                    switch (reader.NodeType)
                    {
                    case XmlNodeType.Element:
                        throw new WixParseException(String.Format("The columnDefinition element contains an unexpected child element {0}.", reader.Name));

                    case XmlNodeType.EndElement:
                        done = true;
                        break;
                    }
                }

                if (!done)
                {
                    throw new WixParseException("Missing end element while processing the columnDefinition element.");
                }
            }

            return(new ColumnDefinition(name, type, length, primaryKey, symbol, nullable, modularize, unreal, localizable, minValueSet, minValue, maxValueSet, maxValue, keyTable, keyColumnSet, keyColumn, category, possibilities, description, escapeIdtCharacters, useCData));
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Unbind an MSI database file.
        /// </summary>
        /// <param name="databaseFile">The database file.</param>
        /// <param name="database">The opened database.</param>
        /// <param name="outputType">The type of output to create.</param>
        /// <param name="exportBasePath">The path where files should be exported.</param>
        /// <returns>The output representing the database.</returns>
        private Output UnbindDatabase(string databaseFile, Database database, OutputType outputType, string exportBasePath)
        {
            string modularizationGuid = null;
            Output output             = new Output(SourceLineNumberCollection.FromFileName(databaseFile));
            View   validationView     = null;

            // set the output type
            output.Type = outputType;

            // get the codepage
            database.Export("_ForceCodepage", this.TempFilesLocation, "_ForceCodepage.idt");
            using (StreamReader sr = File.OpenText(Path.Combine(this.TempFilesLocation, "_ForceCodepage.idt")))
            {
                string line;

                while (null != (line = sr.ReadLine()))
                {
                    string[] data = line.Split('\t');

                    if (2 == data.Length)
                    {
                        output.Codepage = Convert.ToInt32(data[0], CultureInfo.InvariantCulture);
                    }
                }
            }

            // get the summary information table
            using (SummaryInformation summaryInformation = new SummaryInformation(database))
            {
                Table table = new Table(null, this.tableDefinitions["_SummaryInformation"]);

                for (int i = 1; 19 >= i; i++)
                {
                    string value = summaryInformation.GetProperty(i);

                    if (0 < value.Length)
                    {
                        Row row = table.CreateRow(output.SourceLineNumbers);
                        row[0] = i;
                        row[1] = value;
                    }
                }

                output.Tables.Add(table);
            }

            try
            {
                // open a view on the validation table if it exists
                if (database.TableExists("_Validation"))
                {
                    validationView = database.OpenView("SELECT * FROM `_Validation` WHERE `Table` = ? AND `Column` = ?");
                }

                // get the normal tables
                using (View tablesView = database.OpenExecuteView("SELECT * FROM _Tables"))
                {
                    Record tableRecord;

                    while (null != (tableRecord = tablesView.Fetch()))
                    {
                        string tableName = tableRecord.GetString(1);

                        using (View tableView = database.OpenExecuteView(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM `{0}`", tableName)))
                        {
                            Record          rowRecord;
                            Table           table;
                            TableDefinition tableDefinition;

                            if (this.tableDefinitions.Contains(tableName))
                            {
                                tableDefinition = this.tableDefinitions[tableName];

                                // TODO: verify table definitions
                                // - error for different column name or data type
                                // - warn for additional columns
                                // - need extra info for new columns in standard tables (MSI 4.0 changes)
                            }
                            else // custom table
                            {
                                TableDefinition customTableDefinition  = new TableDefinition(tableName, false, false);
                                Hashtable       customTablePrimaryKeys = new Hashtable();

                                Record customColumnNameRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFONAMES);
                                Record customColumnTypeRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFOTYPES);
                                int    customColumnCount      = customColumnNameRecord.GetFieldCount();

                                // index the primary keys
                                using (Record primaryKeysRecord = database.PrimaryKeys(tableName))
                                {
                                    int primaryKeysFieldCount = primaryKeysRecord.GetFieldCount();

                                    for (int i = 1; i <= primaryKeysFieldCount; i++)
                                    {
                                        customTablePrimaryKeys[primaryKeysRecord.GetString(i)] = null;
                                    }
                                }

                                for (int i = 1; i <= customColumnCount; i++)
                                {
                                    string columnName = customColumnNameRecord.GetString(i);
                                    string idtType    = customColumnTypeRecord.GetString(i);

                                    ColumnType columnType;
                                    int        length;
                                    bool       nullable;

                                    ColumnCategory       columnCategory       = ColumnCategory.Unknown;
                                    ColumnModularizeType columnModularizeType = ColumnModularizeType.None;
                                    bool   primary      = customTablePrimaryKeys.Contains(columnName);
                                    bool   minValueSet  = false;
                                    int    minValue     = -1;
                                    bool   maxValueSet  = false;
                                    int    maxValue     = -1;
                                    string keyTable     = null;
                                    bool   keyColumnSet = false;
                                    int    keyColumn    = -1;
                                    string category     = null;
                                    string set          = null;
                                    string description  = null;

                                    // get the column type, length, and whether its nullable
                                    switch (Char.ToLower(idtType[0], CultureInfo.InvariantCulture))
                                    {
                                    case 'i':
                                        columnType = ColumnType.Number;
                                        break;

                                    case 'l':
                                        columnType = ColumnType.Localized;
                                        break;

                                    case 's':
                                        columnType = ColumnType.String;
                                        break;

                                    case 'v':
                                        columnType = ColumnType.Object;
                                        break;

                                    default:
                                        // TODO: error
                                        columnType = ColumnType.Unknown;
                                        break;
                                    }
                                    length   = Convert.ToInt32(idtType.Substring(1), CultureInfo.InvariantCulture);
                                    nullable = Char.IsUpper(idtType[0]);

                                    // try to get validation information
                                    if (null != validationView)
                                    {
                                        Record validationRecord = new Record(2);
                                        validationRecord.SetString(1, tableName);
                                        validationRecord.SetString(2, columnName);

                                        validationView.Execute(validationRecord);
                                        validationRecord.Close();

                                        if (null != (validationRecord = validationView.Fetch()))
                                        {
                                            string validationNullable = validationRecord.GetString(3);
                                            minValueSet  = !validationRecord.IsNull(4);
                                            minValue     = (minValueSet ? validationRecord.GetInteger(4) : -1);
                                            maxValueSet  = !validationRecord.IsNull(5);
                                            maxValue     = (maxValueSet ? validationRecord.GetInteger(5) : -1);
                                            keyTable     = (!validationRecord.IsNull(6) ? validationRecord.GetString(6) : null);
                                            keyColumnSet = !validationRecord.IsNull(7);
                                            keyColumn    = (keyColumnSet ? validationRecord.GetInteger(7) : -1);
                                            category     = (!validationRecord.IsNull(8) ? validationRecord.GetString(8) : null);
                                            set          = (!validationRecord.IsNull(9) ? validationRecord.GetString(9) : null);
                                            description  = (!validationRecord.IsNull(10) ? validationRecord.GetString(10) : null);

                                            // check the validation nullable value against the column definition
                                            if (null == validationNullable)
                                            {
                                                // TODO: warn for illegal validation nullable column
                                            }
                                            else if ((nullable && "Y" != validationNullable) || (!nullable && "N" != validationNullable))
                                            {
                                                // TODO: warn for mismatch between column definition and validation nullable
                                            }

                                            // convert category to ColumnCategory
                                            if (null != category)
                                            {
                                                try
                                                {
                                                    columnCategory = (ColumnCategory)Enum.Parse(typeof(ColumnCategory), category, true);
                                                }
                                                catch (ArgumentException)
                                                {
                                                    columnCategory = ColumnCategory.Unknown;
                                                }
                                            }

                                            validationRecord.Close();
                                        }
                                        else
                                        {
                                            // TODO: warn about no validation information
                                        }
                                    }

                                    // guess the modularization type
                                    if ("Icon" == keyTable && 1 == keyColumn)
                                    {
                                        columnModularizeType = ColumnModularizeType.Icon;
                                    }
                                    else if ("Condition" == columnName)
                                    {
                                        columnModularizeType = ColumnModularizeType.Condition;
                                    }
                                    else if (ColumnCategory.Formatted == columnCategory)
                                    {
                                        columnModularizeType = ColumnModularizeType.Property;
                                    }
                                    else if (ColumnCategory.Identifier == columnCategory)
                                    {
                                        columnModularizeType = ColumnModularizeType.Column;
                                    }

                                    customTableDefinition.Columns.Add(new ColumnDefinition(columnName, columnType, length, primary, nullable, columnModularizeType, (ColumnType.Localized == columnType), minValueSet, minValue, maxValueSet, maxValue, keyTable, keyColumnSet, keyColumn, columnCategory, set, description, true, true));
                                }

                                tableDefinition = customTableDefinition;

                                customColumnNameRecord.Close();
                                customColumnTypeRecord.Close();
                            }

                            table = new Table(null, tableDefinition);

                            while (null != (rowRecord = tableView.Fetch()))
                            {
                                int recordCount = rowRecord.GetFieldCount();
                                Row row         = table.CreateRow(output.SourceLineNumbers);

                                for (int i = 0; recordCount > i && row.Fields.Length > i; i++)
                                {
                                    if (rowRecord.IsNull(i + 1))
                                    {
                                        if (!row.Fields[i].Column.IsNullable)
                                        {
                                            // TODO: display an error for a null value in a non-nullable field OR
                                            // display a warning and put an empty string in the value to let the compiler handle it
                                            // (the second option is risky because the later code may make certain assumptions about
                                            // the contents of a row value)
                                        }
                                    }
                                    else
                                    {
                                        switch (row.Fields[i].Column.Type)
                                        {
                                        case ColumnType.Number:
                                            if (row.Fields[i].Column.IsLocalizable)
                                            {
                                                row[i] = Convert.ToString(rowRecord.GetInteger(i + 1), CultureInfo.InvariantCulture);
                                            }
                                            else
                                            {
                                                row[i] = rowRecord.GetInteger(i + 1);
                                            }
                                            break;

                                        case ColumnType.Object:
                                            string sourceFile = "FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES";

                                            if (null != exportBasePath)
                                            {
                                                string relativeSourceFile = Path.Combine(tableName, row.GetPrimaryKey('.'));
                                                sourceFile = Path.Combine(exportBasePath, relativeSourceFile);

                                                // ensure the parent directory exists
                                                System.IO.Directory.CreateDirectory(Path.Combine(exportBasePath, tableName));

                                                using (FileStream fs = System.IO.File.Create(sourceFile))
                                                {
                                                    int    bytesRead;
                                                    byte[] buffer = new byte[512];

                                                    while (0 != (bytesRead = rowRecord.GetStream(i + 1, buffer, buffer.Length)))
                                                    {
                                                        fs.Write(buffer, 0, bytesRead);
                                                    }
                                                }
                                            }

                                            row[i] = sourceFile;
                                            break;

                                        default:
                                            string value = rowRecord.GetString(i + 1);

                                            switch (row.Fields[i].Column.Category)
                                            {
                                            case ColumnCategory.Guid:
                                                value = value.ToUpper(CultureInfo.InvariantCulture);
                                                break;
                                            }

                                            // de-modularize
                                            if (!this.suppressDemodularization && OutputType.Module == output.Type && ColumnModularizeType.None != row.Fields[i].Column.ModularizeType)
                                            {
                                                Regex modularization = new Regex(@"\.[0-9A-Fa-f]{8}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{12}");

                                                if (null == modularizationGuid)
                                                {
                                                    Match match = modularization.Match(value);
                                                    if (match.Success)
                                                    {
                                                        modularizationGuid = String.Concat('{', match.Value.Substring(1).Replace('_', '-'), '}');
                                                    }
                                                }

                                                value = modularization.Replace(value, String.Empty);
                                            }

                                            // escape "$(" for the preprocessor
                                            value = value.Replace("$(", "$$(");

                                            // escape things that look like wix variables
                                            MatchCollection matches = Common.WixVariableRegex.Matches(value);
                                            for (int j = matches.Count - 1; 0 <= j; j--)
                                            {
                                                value = value.Insert(matches[j].Index, "!");
                                            }

                                            row[i] = value;
                                            break;
                                        }
                                    }
                                }

                                rowRecord.Close();
                            }

                            output.Tables.Add(table);
                        }

                        tableRecord.Close();
                    }
                }
            }
            finally
            {
                if (null != validationView)
                {
                    validationView.Close();
                }
            }

            // set the modularization guid as the PackageCode
            if (null != modularizationGuid)
            {
                Table table = output.Tables["_SummaryInformation"];

                foreach (Row row in table.Rows)
                {
                    if (9 == (int)row[0]) // PID_REVNUMBER
                    {
                        row[1] = modularizationGuid;
                    }
                }
            }

            return(output);
        }