/// <summary>
        /// Get the source line information for the current element.  The precompiler will insert
        /// special source line number processing instructions before each element that it
        /// encounters.  This is where those line numbers are read and processed.  This function
        /// may return an array of source line numbers because the element may have come from
        /// an included file, in which case the chain of imports is expressed in the array.
        /// </summary>
        /// <param name="node">Element to get source line information for.</param>
        /// <returns>Returns the stack of imports used to author the element being processed.</returns>
        public SourceLineNumberCollection GetSourceLineNumbers(XmlNode node)
        {
            if (XmlNodeType.Element != node.NodeType)               // only elements can have line numbers, sorry
            {
                return(null);
            }

            SourceLineNumberCollection sourceLineNumbers = null;
            XmlNode prev = node.PreviousSibling;

            while (null != prev)
            {
                if (XmlNodeType.ProcessingInstruction == prev.NodeType)
                {
                    if (Preprocessor.LineNumberElementName == prev.LocalName)                       // if we have a line number
                    {
                        sourceLineNumbers = new SourceLineNumberCollection(prev.Value);
                        break;
                    }
                    // otherwise keep walking up processing instructions
                }

                prev = prev.PreviousSibling;
            }

            if (null == sourceLineNumbers && null != this.intermediate.SourcePath)
            {
                sourceLineNumbers = SourceLineNumberCollection.FromFileName(this.intermediate.SourcePath);
            }

            return(sourceLineNumbers);
        }
        /// <summary>
        /// Parse ignore modularization data from the xml.
        /// </summary>
        /// <param name="intermediate">Intermediate to populate with persisted data.</param>
        /// <param name="reader">XmlReader where the intermediate is persisted.</param>
        /// <param name="section">Section to populate with persisted data.</param>
        private static void ParseIgnoreModularization(Intermediate intermediate, XmlReader reader, Section section)
        {
            bool   empty = reader.IsEmptyElement;
            string name  = null;
            string type  = null;

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

                case "type":
                    type = reader.Value;
                    break;
                }
            }
            if (null == name)
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "Reference missing required attribute: 'name'");
            }
            if (null == type)
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "Reference missing required attribute: 'type'");
            }

            if (!empty && reader.Read() && XmlNodeType.EndElement != reader.MoveToContent())
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), String.Format("Unexpected content while processing 'ignoreModularization': {0}", reader.NodeType.ToString()));
            }

            section.IgnoreModularizations.Add(new IgnoreModularization(name, type));
        }
        /// <summary>
        /// Parse a reference from the xml.
        /// </summary>
        /// <param name="intermediate">Intermediate to populate with persisted data.</param>
        /// <param name="reader">XmlReader where the intermediate is persisted.</param>
        /// <param name="section">Section to populate with persisted data.</param>
        private static void ParseReference(Intermediate intermediate, XmlReader reader, Section section)
        {
            bool   empty = reader.IsEmptyElement;
            string id    = null;
            string table = null;

            while (reader.MoveToNextAttribute())
            {
                switch (reader.LocalName)
                {
                case "symbol":
                    id = reader.Value;
                    break;

                case "table":
                    table = reader.Value;
                    break;
                }
            }
            if (null == table)
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "Reference missing required attribute: 'table'");
            }
            if (null == id)
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "Reference missing required attribute: 'id'");
            }

            if (!empty && reader.Read() && XmlNodeType.EndElement != reader.MoveToContent())
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), String.Format("Unexpected content while processing 'reference': {0}", reader.NodeType.ToString()));
            }

            section.References.Add(new Reference(table, id));
        }
Beispiel #4
0
 /// <summary>
 /// Called at the beginning of the validation of a database file.
 /// </summary>
 /// <remarks>
 /// <para>The <see cref="Validator"/> will set
 /// <see cref="DatabaseFile"/> before calling InitializeValidator.</para>
 /// <para><b>Notes to Inheritors:</b> When overriding
 /// <b>InitializeValidator</b> in a derived class, be sure to call
 /// the base class's <b>InitializeValidator</b> to thoroughly
 /// initialize the extension.</para>
 /// </remarks>
 public virtual void InitializeValidator()
 {
     if (this.databaseFile != null)
     {
         this.sourceLineNumbers = SourceLineNumberCollection.FromFileName(databaseFile);
     }
 }
        /// <summary>
        /// Parse a table from the xml.
        /// </summary>
        /// <param name="intermediate">Intermediate to populate with persisted data.</param>
        /// <param name="reader">XmlReader where the intermediate is persisted.</param>
        /// <param name="section">Section to populate with persisted data.</param>
        /// <param name="tableDefinitions">TableDefinitions to use in the intermediate.</param>
        private static void ParseTable(Intermediate intermediate, XmlReader reader, Section section, TableDefinitionCollection tableDefinitions)
        {
            bool   empty = reader.IsEmptyElement;
            string name  = null;

            while (reader.MoveToNextAttribute())
            {
                switch (reader.LocalName)
                {
                case "name":
                    name = reader.Value;
                    break;
                }
            }
            if (null == name)
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "Table missing required attribute: 'name'");
            }

            if (!empty)
            {
                bool done = false;

                // loop through all the rows (tuples) in a table
                while (!done && reader.Read())
                {
                    switch (reader.NodeType)
                    {
                    case XmlNodeType.Element:
                        switch (reader.LocalName)
                        {
                        case "tuple":
                            ParseTuple(intermediate, reader, section, tableDefinitions[name]);
                            break;

                        default:
                            throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), String.Format("Unexpected element while processing 'table': '{0}'", reader.LocalName));
                        }
                        break;

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

                if (!done)
                {
                    throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), String.Format("Missing end element while processing 'table'."));
                }
            }
        }
        /// <summary>
        /// Parse a tuple from the xml.
        /// </summary>
        /// <param name="intermediate">Intermediate to populate with persisted data.</param>
        /// <param name="reader">XmlReader where the intermediate is persisted.</param>
        /// <param name="section">Section to populate with persisted data.</param>
        /// <param name="tableDef">Table definition of the tuple to parse.</param>
        private static void ParseTuple(Intermediate intermediate, XmlReader reader, Section section, TableDefinition tableDef)
        {
            bool empty = reader.IsEmptyElement;
            SourceLineNumberCollection sourceLineNumbers = null;
            int field = 0;

            while (reader.MoveToNextAttribute())
            {
                switch (reader.LocalName)
                {
                case "sourceLineNumber":
                    sourceLineNumbers = new SourceLineNumberCollection(reader.Value);
                    break;
                }
            }

            Row row = Common.CreateRowInSection(sourceLineNumbers, section, tableDef);

            if (!empty)
            {
                bool done = false;

                // loop through all the fields in a row
                while (!done && reader.Read())
                {
                    switch (reader.NodeType)
                    {
                    case XmlNodeType.Element:
                        switch (reader.LocalName)
                        {
                        case "field":
                            row[field] = Field.Parse(reader);
                            ++field;
                            break;

                        default:
                            throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), String.Format("Unexpected element while processing 'tuple': '{0}'", reader.LocalName));
                        }
                        break;

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

                if (!done)
                {
                    throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), String.Format("Missing end element while processing 'tuple'."));
                }
            }
        }
Beispiel #7
0
        /// <summary>
        /// Parse the root library element.
        /// </summary>
        /// <param name="library">Library to read from disk.</param>
        /// <param name="reader">XmlReader with library persisted as Xml.</param>
        /// <param name="tableDefinitions">Collection containing TableDefinitions to use when reconstituting the intermediates.</param>
        /// <param name="suppressVersionCheck">Suppresses check for wix.dll version mismatch.</param>
        private static void ParseLibrary(Library library, XmlReader reader, TableDefinitionCollection tableDefinitions, bool suppressVersionCheck)
        {
            // read the document root
            reader.MoveToContent();
            if ("wixLibrary" != reader.LocalName)
            {
                throw new WixNotLibraryException(SourceLineNumberCollection.FromFileName(library.Path), String.Format("Invalid root element: '{0}', expected 'wixLibrary'", reader.LocalName));
            }

            Version objVersion = null;

            while (reader.MoveToNextAttribute())
            {
                switch (reader.LocalName)
                {
                case "version":
                    objVersion = new Version(reader.Value);
                    break;
                }
            }

            if (null != objVersion && !suppressVersionCheck)
            {
                Version currentVersion = Common.LibraryFormatVersion;
                if (0 != currentVersion.CompareTo(objVersion))
                {
                    throw new WixVersionMismatchException(currentVersion, objVersion, "Library", library.Path);
                }
            }

            // loop through the rest of the xml building up the SectionCollection
            while (reader.Read())
            {
                if (0 == reader.Depth)
                {
                    break;
                }
                else if (1 != reader.Depth)
                {
                    // throw exception since we should only be processing tables
                    throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(library.Path), "Unexpected depth while processing element: 'wixLibrary'");
                }

                if (XmlNodeType.Element == reader.NodeType && "wixObject" == reader.LocalName)
                {
                    Intermediate intermediate = Intermediate.Load(reader, library.Path, tableDefinitions, suppressVersionCheck);

                    library.intermediates.Add(intermediate);
                }
            }
        }
Beispiel #8
0
        /// <summary>
        /// Loads an output from a path on disk.
        /// </summary>
        /// <param name="path">Path to output file saved on disk.</param>
        /// <param name="suppressVersionCheck">Suppresses wix.dll version mismatch check.</param>
        /// <remarks>This method will set the Path property to the appropriate values on successful load.</remarks>
        /// <returns>Output object.</returns>
        public static Output Load(string path, bool suppressVersionCheck)
        {
            XmlTextReader reader = null;

            try
            {
                reader = new XmlTextReader(path);

                reader.MoveToContent();

                if ("wixOutput" != reader.LocalName)
                {
                    throw new WixParseException(String.Format("The xml document element was expected to be tableDefinitions, but was actually {0}.", reader.Name));
                }

                Output output = Parse(reader, suppressVersionCheck, path);

                return(output);
            }
            catch (XmlException xe)
            {
                throw new WixInvalidOutputException(SourceLineNumberCollection.FromFileName(path), xe.Message);
            }
            catch (WixException we)
            {
                throw new WixInvalidOutputException(SourceLineNumberCollection.FromFileName(path), we.Message);
            }
            catch (FormatException fe)
            {
                throw new WixInvalidOutputException(SourceLineNumberCollection.FromFileName(path), fe.Message);
            }
            catch (OverflowException oe)
            {
                throw new WixInvalidOutputException(SourceLineNumberCollection.FromFileName(path), oe.Message);
            }
            finally
            {
                if (null != reader)
                {
                    reader.Close();
                }
            }
        }
        /// <summary>
        /// Parse a complex reference from the xml.
        /// </summary>
        /// <param name="intermediate">Intermediate to populate with persisted data.</param>
        /// <param name="reader">XmlReader where the intermediate is persisted.</param>
        /// <param name="section">Section to populate with persisted data.</param>
        private static void ParseComplexReference(Intermediate intermediate, XmlReader reader, Section section)
        {
            bool empty = reader.IsEmptyElement;
            ComplexReferenceParentType parentType = ComplexReferenceParentType.Unknown;
            string parentId       = null;
            string parentLanguage = null;
            ComplexReferenceChildType childType = ComplexReferenceChildType.Unknown;
            string childId = null;
            bool   primary = false;

            while (reader.MoveToNextAttribute())
            {
                switch (reader.LocalName)
                {
                case "parent":
                    parentId = reader.Value;
                    break;

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

                case "parentType":
                    switch (reader.Value)
                    {
                    case "componentGroup":
                        parentType = ComplexReferenceParentType.ComponentGroup;
                        break;

                    case "feature":
                        parentType = ComplexReferenceParentType.Feature;
                        break;

                    case "module":
                        parentType = ComplexReferenceParentType.Module;
                        break;
                    }
                    break;

                case "child":
                    childId = reader.Value;
                    break;

                case "childType":
                    switch (reader.Value)
                    {
                    case "component":
                        childType = ComplexReferenceChildType.Component;
                        break;

                    case "componentGroup":
                        childType = ComplexReferenceChildType.ComponentGroup;
                        break;

                    case "feature":
                        childType = ComplexReferenceChildType.Feature;
                        break;

                    case "fragment":
                        childType = ComplexReferenceChildType.Fragment;
                        break;

                    case "module":
                        childType = ComplexReferenceChildType.Module;
                        break;
                    }
                    break;

                case "primary":
                    primary = Common.IsYes(reader.Value, SourceLineNumberCollection.FromFileName(intermediate.Path), "complexReference", "primary", parentId);
                    break;
                }
            }
            if (ComplexReferenceParentType.Unknown == parentType)
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "Unknown ComplexReferenceParentType type");
            }
            if (null == parentId)
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "ComplexReference missing required attribute: 'parentId'");
            }
            if (ComplexReferenceChildType.Unknown == childType)
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "Unknown ComplexReferenceChildType type");
            }
            if (null == childId)
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "ComplexReference missing required attribute: 'childId'");
            }

            if (!empty && reader.Read() && XmlNodeType.EndElement != reader.MoveToContent())
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), String.Format("Unexpected content while processing 'complexReference': {0}", reader.NodeType.ToString()));
            }

            section.ComplexReferences.Add(new ComplexReference(parentType, parentId, parentLanguage, childType, childId, primary));
        }
Beispiel #10
0
        /// <summary>
        /// Parse a feature backlink from the xml.
        /// </summary>
        /// <param name="intermediate">Intermediate to populate with persisted data.</param>
        /// <param name="reader">XmlReader where the intermediate is persisted.</param>
        /// <param name="section">Section to populate with persisted data.</param>
        private static void ParseFeatureBacklink(Intermediate intermediate, XmlReader reader, Section section)
        {
            bool   empty             = reader.IsEmptyElement;
            string targetSymbol      = null;
            string component         = null;
            FeatureBacklinkType type = FeatureBacklinkType.Unknown;

            while (reader.MoveToNextAttribute())
            {
                switch (reader.LocalName)
                {
                case "targetSymbol":
                    targetSymbol = reader.Value;
                    break;

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

                case "type":
                    switch (reader.Value)
                    {
                    case "Class":
                        type = FeatureBacklinkType.Class;
                        break;

                    case "Extension":
                        type = FeatureBacklinkType.Extension;
                        break;

                    case "Shortcut":
                        type = FeatureBacklinkType.Shortcut;
                        break;

                    case "PublishComponent":
                        type = FeatureBacklinkType.PublishComponent;
                        break;

                    case "TypeLib":
                        type = FeatureBacklinkType.TypeLib;
                        break;

                    default:
                        throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "Invalid FeatureBacklinkType");
                    }
                    break;
                }
            }
            if (FeatureBacklinkType.Unknown == type)
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "Unknown FeatureBackLink type");
            }
            if (null == component)
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "FeatureBackLink missing required attribute: 'component'");
            }
            if (null == targetSymbol)
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "FeatureBackLink missing required attribute: 'targetSymbol'");
            }

            if (!empty && reader.Read() && XmlNodeType.EndElement != reader.MoveToContent())
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), String.Format("Unexpected content while processing 'featureBacklink': {0}", reader.NodeType.ToString()));
            }

            section.FeatureBacklinks.Add(new FeatureBacklink(component, type, targetSymbol));
        }
Beispiel #11
0
        /// <summary>
        /// Parse a section from the xml.
        /// </summary>
        /// <param name="intermediate">Intermediate to populate with persisted data.</param>
        /// <param name="reader">XmlReader where the intermediate is persisted.</param>
        /// <param name="tableDefinitions">TableDefinitions to use in the intermediate.</param>
        private static void ParseSection(Intermediate intermediate, XmlReader reader, TableDefinitionCollection tableDefinitions)
        {
            Section     section  = null;
            string      id       = null;
            SectionType type     = SectionType.Unknown;
            int         codepage = 0;
            bool        empty    = reader.IsEmptyElement;

            while (reader.MoveToNextAttribute())
            {
                switch (reader.Name)
                {
                case "id":
                    id = reader.Value;
                    break;

                case "type":
                    switch (reader.Value)
                    {
                    case "fragment":
                        type = SectionType.Fragment;
                        break;

                    case "module":
                        type = SectionType.Module;
                        break;

                    case "product":
                        type = SectionType.Product;
                        break;

                    case "patchCreation":
                        type = SectionType.PatchCreation;
                        break;
                    }
                    break;

                case "codepage":
                    codepage = Convert.ToInt32(reader.Value);
                    break;
                }
            }
            if (SectionType.Unknown == type)
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "Unknown section type");
            }
            if (null == id && SectionType.Fragment != type)
            {
                throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "Section missing required attribute: 'id'");
            }

            section = new Section(intermediate, id, type, codepage);

            if (!empty)
            {
                bool done = false;

                while (!done && reader.Read())
                {
                    switch (reader.NodeType)
                    {
                    case XmlNodeType.Element:
                        switch (reader.LocalName)
                        {
                        case "reference":
                            ParseReference(intermediate, reader, section);
                            break;

                        case "complexReference":
                            ParseComplexReference(intermediate, reader, section);
                            break;

                        case "featureBacklink":
                            ParseFeatureBacklink(intermediate, reader, section);
                            break;

                        case "table":
                            ParseTable(intermediate, reader, section, tableDefinitions);
                            break;

                        case "ignoreModularization":
                            ParseIgnoreModularization(intermediate, reader, section);
                            break;

                        default:
                            throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), String.Format("Unexpected element while processing 'section': '{0}'", reader.LocalName));
                        }
                        break;

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

                if (!done)
                {
                    throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), String.Format("Missing end element while processing 'section'."));
                }
            }

            intermediate.Sections.Add(section);
        }
Beispiel #12
0
        /// <summary>
        /// Unbind an MSI transform file.
        /// </summary>
        /// <param name="transformFile">The transform file.</param>
        /// <param name="exportBasePath">The path where files should be exported.</param>
        /// <returns>The unbound transform.</returns>
        private Output UnbindTransform(string transformFile, string exportBasePath)
        {
            Output transform = new Output(SourceLineNumberCollection.FromFileName(transformFile));

            transform.Type = OutputType.Transform;

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

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

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

            // create a schema msi which hopefully matches the table schemas in the transform
            Output schemaOutput    = new Output(null);
            string msiDatabaseFile = Path.Combine(this.tempFiles.BasePath, "schema.msi");

            foreach (TableDefinition tableDefinition in this.tableDefinitions)
            {
                // skip unreal tables and the Patch table
                if (!tableDefinition.IsUnreal && "Patch" != tableDefinition.Name)
                {
                    schemaOutput.EnsureTable(tableDefinition);
                }
            }

            // bind the schema msi
            Binder binder = new Binder();

            binder.SuppressAddingValidationRows = true;
            binder.WixVariableResolver          = new WixVariableResolver();
            binder.GenerateDatabase(schemaOutput, msiDatabaseFile);

            // apply the transform to the database and retrieve the modifications
            Hashtable addedRows = new Hashtable();
            Table     transformViewTable;

            using (Database msiDatabase = new Database(msiDatabaseFile, OpenDatabase.Transact))
            {
                // apply the transform with the ViewTransform option to collect all the modifications
                msiDatabase.ApplyTransform(transformFile, TransformErrorConditions.All | TransformErrorConditions.ViewTransform);

                // unbind the database
                Output transformViewOutput = this.UnbindDatabase(msiDatabaseFile, msiDatabase, OutputType.Product, exportBasePath);

                // index the added and possibly modified rows (added rows may also appears as modified rows)
                transformViewTable = transformViewOutput.Tables["_TransformView"];
                Hashtable modifiedRows = new Hashtable();
                foreach (Row row in transformViewTable.Rows)
                {
                    string tableName   = (string)row[0];
                    string columnName  = (string)row[1];
                    string primaryKeys = (string)row[2];

                    if ("INSERT" == columnName)
                    {
                        string index = String.Concat(tableName, ':', primaryKeys);

                        addedRows.Add(index, null);
                    }
                    else if ("CREATE" != columnName && "DELETE" != columnName && "DROP" != columnName && null != primaryKeys) // modified row
                    {
                        string index = String.Concat(tableName, ':', primaryKeys);

                        modifiedRows[index] = row;
                    }
                }

                // create placeholder rows for modified rows to make the transform insert the updated values when its applied
                foreach (Row row in modifiedRows.Values)
                {
                    string tableName   = (string)row[0];
                    string columnName  = (string)row[1];
                    string primaryKeys = (string)row[2];

                    string index = String.Concat(tableName, ':', primaryKeys);

                    // ignore information for added rows
                    if (!addedRows.Contains(index))
                    {
                        Table table = schemaOutput.Tables[tableName];
                        this.CreateRow(table, primaryKeys, true);
                    }
                }
            }

            // re-bind the schema output with the placeholder rows
            binder.GenerateDatabase(schemaOutput, msiDatabaseFile);

            // apply the transform to the database and retrieve the modifications
            using (Database msiDatabase = new Database(msiDatabaseFile, OpenDatabase.Transact))
            {
                // apply the transform
                msiDatabase.ApplyTransform(transformFile, TransformErrorConditions.All);

                // commit the database to guard against weird errors with streams
                msiDatabase.Commit();

                // unbind the database
                Output output = this.UnbindDatabase(msiDatabaseFile, msiDatabase, OutputType.Product, exportBasePath);

                // index all the rows to easily find modified rows
                Hashtable rows = new Hashtable();
                foreach (Table table in output.Tables)
                {
                    foreach (Row row in table.Rows)
                    {
                        rows.Add(String.Concat(table.Name, ':', row.GetPrimaryKey('\t')), row);
                    }
                }

                // process the _TransformView rows into transform rows
                foreach (Row row in transformViewTable.Rows)
                {
                    string tableName   = (string)row[0];
                    string columnName  = (string)row[1];
                    string primaryKeys = (string)row[2];

                    Table table = transform.Tables.EnsureTable(null, this.tableDefinitions[tableName]);

                    if ("CREATE" == columnName) // added table
                    {
                        table.Operation = TableOperation.Add;
                    }
                    else if ("DELETE" == columnName) // deleted row
                    {
                        Row deletedRow = this.CreateRow(table, primaryKeys, false);
                        deletedRow.Operation = RowOperation.Delete;
                    }
                    else if ("DROP" == columnName) // dropped table
                    {
                        table.Operation = TableOperation.Drop;
                    }
                    else if ("INSERT" == columnName) // added row
                    {
                        string index    = String.Concat(tableName, ':', primaryKeys);
                        Row    addedRow = (Row)rows[index];
                        addedRow.Operation = RowOperation.Add;
                        table.Rows.Add(addedRow);
                    }
                    else if (null != primaryKeys) // modified row
                    {
                        string index = String.Concat(tableName, ':', primaryKeys);

                        // the _TransformView table includes information for added rows
                        // that looks like modified rows so it sometimes needs to be ignored
                        if (!addedRows.Contains(index))
                        {
                            Row modifiedRow = (Row)rows[index];

                            // mark the field as modified
                            int indexOfModifiedValue = modifiedRow.TableDefinition.Columns.IndexOf(columnName);
                            modifiedRow.Fields[indexOfModifiedValue].Modified = true;

                            // move the modified row into the transform the first time its encountered
                            if (RowOperation.None == modifiedRow.Operation)
                            {
                                modifiedRow.Operation = RowOperation.Modify;
                                table.Rows.Add(modifiedRow);
                            }
                        }
                    }
                    else // added column
                    {
                        table.Definition.Columns[columnName].Added = true;
                    }
                }
            }

            return(transform);
        }
Beispiel #13
0
 /// <summary>
 /// Instantiate a new WixInvalidIdtException.
 /// </summary>
 /// <param name="idtFile">The invalid idt file.</param>
 /// <param name="tableName">The table name of the invalid idt file.</param>
 public WixInvalidIdtException(string idtFile, string tableName) :
     base(WixErrors.InvalidIdt(SourceLineNumberCollection.FromFileName(idtFile), idtFile, tableName))
 {
 }
Beispiel #14
0
        /// <summary>
        /// Load localized strings from a wixloc file.
        /// </summary>
        /// <param name="path">Path to the wixloc file.</param>
        public void LoadFromFile(string path)
        {
            SourceLineNumberCollection sourceLineNumbers = SourceLineNumberCollection.FromFileName(path);

            try
            {
                XPathDocument  doc = new XPathDocument(path);
                XPathNavigator nav = doc.CreateNavigator();

                nav.MoveToRoot();
                if (nav.MoveToFirstChild())
                {
                    // move to the first element (skipping comments and stuff)
                    while (XPathNodeType.Element != nav.NodeType)
                    {
                        nav.MoveToNext();
                    }

                    if ("WixLocalization" != nav.LocalName)
                    {
                        this.OnMessage(WixErrors.InvalidDocumentElement(sourceLineNumbers, nav.Name, "localization", "WixLocalization"));
                    }

                    if (nav.MoveToAttribute("Codepage", String.Empty))
                    {
                        try
                        {
                            int newCodepage = Convert.ToInt32(nav.Value, CultureInfo.InvariantCulture.NumberFormat);

                            // if the codepage has not been set
                            if (-1 == this.codepage)
                            {
                                this.codepage = newCodepage;
                            }
                            else if (newCodepage != this.codepage)                             // fail if codepage has already been specified but is different
                            {
                                this.OnMessage(WixErrors.DuplicateLocalizedCodepage(sourceLineNumbers, nav.Value));
                            }
                        }
                        catch (FormatException)
                        {
                            this.OnMessage(WixErrors.IllegalIntegerValue(null, "WixLocalization", nav.Name, nav.Value));
                        }
                        catch (OverflowException)
                        {
                            this.OnMessage(WixErrors.IllegalIntegerValue(null, "WixLocalization", nav.Name, nav.Value));
                        }

                        nav.MoveToParent();
                    }

                    if (nav.MoveToFirstChild())
                    {
                        do
                        {
                            if (XPathNodeType.Element == nav.NodeType)
                            {
                                string localizationId    = null;
                                string localizationValue = String.Empty;

                                if ("String" != nav.LocalName)
                                {
                                    continue;
                                }

                                if (nav.MoveToAttribute("Id", String.Empty))
                                {
                                    localizationId = nav.Value;
                                    nav.MoveToParent();
                                }

                                if (null == localizationId)
                                {
                                    this.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, "String", "Id"));
                                }

                                if (nav.MoveToFirstChild())
                                {
                                    // find the text() of the element
                                    do
                                    {
                                        if (XPathNodeType.Text == nav.NodeType)
                                        {
                                            localizationValue = nav.Value;
                                            break;                                             // found the text() of the element and bail
                                        }
                                    }while (nav.MoveToNext());

                                    nav.MoveToParent();                                     // back up
                                }

                                if (!this.stringDictionary.ContainsKey(localizationId))
                                {
                                    this.stringDictionary.Add(localizationId, localizationValue);
                                }
                                else                                 // duplicate localization identifier
                                {
                                    this.OnMessage(WixErrors.DuplicateLocalizationIdentifier(sourceLineNumbers, localizationId));
                                }
                            }
                        }while (nav.MoveToNext());
                    }
                }
            }
            catch (DirectoryNotFoundException)
            {
                this.OnMessage(WixErrors.FileNotFound(path));
            }
            catch (FileNotFoundException)
            {
                this.OnMessage(WixErrors.FileNotFound(path));
            }
            catch (XmlException e)
            {
                this.OnMessage(WixErrors.InvalidXml(sourceLineNumbers, "localization", e.Message));
            }
        }
Beispiel #15
0
        /// <summary>
        /// Extract the cabinets from a database.
        /// </summary>
        /// <param name="output">The output to use when finding cabinets.</param>
        /// <param name="database">The database containing the cabinets.</param>
        /// <param name="databaseFile">The location of the database file.</param>
        /// <param name="exportBasePath">The path where the files should be exported.</param>
        private void ExtractCabinets(Output output, Database database, string databaseFile, string exportBasePath)
        {
            string           databaseBasePath = Path.GetDirectoryName(databaseFile);
            StringCollection cabinetFiles     = new StringCollection();
            Hashtable        embeddedCabinets = new Hashtable();

            // index all of the cabinet files
            if (OutputType.Module == output.Type)
            {
                embeddedCabinets.Add(0, "MergeModule.CABinet");
            }
            else if (null != output.Tables["Media"])
            {
                foreach (MediaRow mediaRow in output.Tables["Media"].Rows)
                {
                    if (null != mediaRow.Cabinet)
                    {
                        if (OutputType.Product == output.Type ||
                            (OutputType.Transform == output.Type && RowOperation.Add == mediaRow.Operation))
                        {
                            if (mediaRow.Cabinet.StartsWith("#"))
                            {
                                embeddedCabinets.Add(mediaRow.DiskId, mediaRow.Cabinet.Substring(1));
                            }
                            else
                            {
                                cabinetFiles.Add(Path.Combine(databaseBasePath, mediaRow.Cabinet));
                            }
                        }
                    }
                }
            }

            // extract the embedded cabinet files from the database
            if (0 < embeddedCabinets.Count)
            {
                using (View streamsView = database.OpenView("SELECT `Data` FROM `_Streams` WHERE `Name` = ?"))
                {
                    foreach (int diskId in embeddedCabinets.Keys)
                    {
                        Record record = new Record(1);

                        record.SetString(1, (string)embeddedCabinets[diskId]);
                        streamsView.Execute(record);
                        record.Close();

                        if (null != (record = streamsView.Fetch()))
                        {
                            // since the cabinets are stored in case-sensitive streams inside the msi, but the file system is not case-sensitive,
                            // embedded cabinets must be extracted to a canonical file name (like their diskid) to ensure extraction will always work
                            string cabinetFile = Path.Combine(this.TempFilesLocation, String.Concat("Media", Path.DirectorySeparatorChar, diskId.ToString(CultureInfo.InvariantCulture), ".cab"));

                            // ensure the parent directory exists
                            System.IO.Directory.CreateDirectory(Path.GetDirectoryName(cabinetFile));

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

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

                            record.Close();

                            cabinetFiles.Add(cabinetFile);
                        }
                        else
                        {
                            // TODO: warning about missing embedded cabinet
                        }
                    }
                }
            }

            // extract the cabinet files
            if (0 < cabinetFiles.Count)
            {
                string fileDirectory = Path.Combine(exportBasePath, "File");

                // delete the directory and its files to prevent cab extraction due to an existing file
                if (Directory.Exists(fileDirectory))
                {
                    Directory.Delete(fileDirectory, true);
                }

                // ensure the directory exists of extraction will fail
                Directory.CreateDirectory(fileDirectory);

                foreach (string cabinetFile in cabinetFiles)
                {
                    using (WixExtractCab extractCab = new WixExtractCab())
                    {
                        try
                        {
                            extractCab.Extract(cabinetFile, fileDirectory);
                        }
                        catch (FileNotFoundException)
                        {
                            throw new WixException(WixErrors.FileNotFound(SourceLineNumberCollection.FromFileName(databaseFile), cabinetFile));
                        }
                    }
                }
            }
        }
Beispiel #16
0
        /// <summary>
        /// Parse an intermediate from an XML format.
        /// </summary>
        /// <param name="intermediate">Intermediate to populate with persisted data.</param>
        /// <param name="reader">XmlReader where the intermediate is persisted.</param>
        /// <param name="tableDefinitions">TableDefinitions to use in the intermediate.</param>
        /// <param name="suppressVersionCheck">Suppress checking for wix.dll version mismatch.</param>
        private static void ParseIntermediate(Intermediate intermediate, XmlReader reader, TableDefinitionCollection tableDefinitions, bool suppressVersionCheck)
        {
            // read the document root
            reader.MoveToContent();
            if ("wixObject" != reader.LocalName)
            {
                throw new WixNotIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), String.Format("Invalid root element: '{0}', expected 'wixObject'", reader.LocalName));
            }

            bool empty = reader.IsEmptyElement;

            Version objVersion = null;

            while (reader.MoveToNextAttribute())
            {
                switch (reader.LocalName)
                {
                case "src":
                    intermediate.SourcePath = reader.Value;
                    break;

                case "version":
                    objVersion = new Version(reader.Value);
                    break;
                }
            }

            if (null != objVersion && !suppressVersionCheck)
            {
                Version currentVersion = Common.IntermediateFormatVersion;
                if (0 != currentVersion.CompareTo(objVersion))
                {
                    throw new WixVersionMismatchException(currentVersion, objVersion, "Intermediate", intermediate.Path);
                }
            }

            // loop through the rest of the xml building up the SectionCollection
            if (!empty)
            {
                bool done = false;

                while (!done && reader.Read())
                {
                    switch (reader.NodeType)
                    {
                    case XmlNodeType.Element:
                        switch (reader.LocalName)
                        {
                        case "section":
                            ParseSection(intermediate, reader, tableDefinitions);
                            break;

                        default:
                            throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), String.Format("Unexpected element while processing 'wixObject': '{0}'", reader.LocalName));
                        }
                        break;

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

                if (!done)
                {
                    throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), String.Format("Missing end element while processing 'wixObject'."));
                }
            }
        }
Beispiel #17
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);
        }