예제 #1
0
        /// <summary>
        /// Processes an xml reader into an xml writer.
        /// </summary>
        /// <param name="include">Specifies if reader is from an included file.</param>
        /// <param name="reader">Reader for the source document.</param>
        /// <param name="writer">Writer where postprocessed data is written.</param>
        /// <param name="offset">Original offset for the line numbers being processed.</param>
        private void PreprocessReader(bool include, XmlReader reader, XmlWriter writer, int offset)
        {
            Stack stack = new Stack(5);
            IfContext context = new IfContext(true, true, IfState.Unknown); // start by assuming we want to keep the nodes in the source code

            // process the reader into the writer
            while (reader.Read())
            {
                // update information here in case an error occurs before the next read
                this.UpdateInformation(reader, offset);

                SourceLineNumberCollection sourceLineNumbers = this.GetCurrentSourceLineNumbers();

                // check for changes in conditional processing
                if (XmlNodeType.ProcessingInstruction == reader.NodeType)
                {
                    bool ignore = false;
                    string name = null;

                    switch (reader.LocalName)
                    {
                        case "if":
                            stack.Push(context);
                            if (context.IsTrue)
                            {
                                context = new IfContext(context.IsTrue & context.Active, this.EvaluateExpression(reader.Value), IfState.If);
                            }
                            else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true
                            {
                                context = new IfContext();
                            }
                            ignore = true;
                            break;
                        case "ifdef":
                            stack.Push(context);
                            name = reader.Value.Trim();
                            if (context.IsTrue)
                            {
                                context = new IfContext(context.IsTrue & context.Active, (null != this.core.GetVariableValue(sourceLineNumbers, name, true)), IfState.If);
                            }
                            else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true
                            {
                                context = new IfContext();
                            }
                            ignore = true;
                            OnIfDef(new IfDefEventArgs(sourceLineNumbers, true, context.IsTrue, name));
                            break;
                        case "ifndef":
                            stack.Push(context);
                            name = reader.Value.Trim();
                            if (context.IsTrue)
                            {
                                context = new IfContext(context.IsTrue & context.Active, (null == this.core.GetVariableValue(sourceLineNumbers, name, true)), IfState.If);
                            }
                            else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true
                            {
                                context = new IfContext();
                            }
                            ignore = true;
                            OnIfDef(new IfDefEventArgs(sourceLineNumbers, false, !context.IsTrue, name));
                            break;
                        case "elseif":
                            if (0 == stack.Count)
                            {
                                throw new WixException(WixErrors.UnmatchedPreprocessorInstruction(this.GetCurrentSourceLineNumbers(), "if", "elseif"));
                            }

                            if (IfState.If != context.IfState && IfState.ElseIf != context.IfState)
                            {
                                throw new WixException(WixErrors.UnmatchedPreprocessorInstruction(this.GetCurrentSourceLineNumbers(), "if", "elseif"));
                            }

                            context.IfState = IfState.ElseIf;   // we're now in an elseif
                            if (!context.WasEverTrue)   // if we've never evaluated the if context to true, then we can try this test
                            {
                                context.IsTrue = this.EvaluateExpression(reader.Value);
                            }
                            else if (context.IsTrue)
                            {
                                context.IsTrue = false;
                            }
                            ignore = true;
                            break;
                        case "else":
                            if (0 == stack.Count)
                            {
                                throw new WixException(WixErrors.UnmatchedPreprocessorInstruction(this.GetCurrentSourceLineNumbers(), "if", "else"));
                            }

                            if (IfState.If != context.IfState && IfState.ElseIf != context.IfState)
                            {
                                throw new WixException(WixErrors.UnmatchedPreprocessorInstruction(this.GetCurrentSourceLineNumbers(), "if", "else"));
                            }

                            context.IfState = IfState.Else;   // we're now in an else
                            context.IsTrue = !context.WasEverTrue;   // if we were never true, we can be true now
                            ignore = true;
                            break;
                        case "endif":
                            if (0 == stack.Count)
                            {
                                throw new WixException(WixErrors.UnmatchedPreprocessorInstruction(this.GetCurrentSourceLineNumbers(), "if", "endif"));
                            }

                            context = (IfContext)stack.Pop();
                            ignore = true;
                            break;
                    }

                    if (ignore)   // ignore this node since we just handled it above
                    {
                        continue;
                    }
                }

                if (!context.Active || !context.IsTrue)   // if our context is not true then skip the rest of the processing and just read the next thing
                {
                    continue;
                }

                switch (reader.NodeType)
                {
                    case XmlNodeType.ProcessingInstruction:
                        switch (reader.LocalName)
                        {
                            case "define":
                                this.PreprocessDefine(reader.Value);
                                break;
                            case "error":
                                this.PreprocessError(reader.Value);
                                break;
                            case "warning":
                                this.PreprocessWarning(reader.Value);
                                break;
                            case "undef":
                                this.PreprocessUndef(reader.Value);
                                break;
                            case "include":
                                this.UpdateInformation(reader, offset);
                                this.PreprocessInclude(reader.Value, writer);
                                break;
                            case "foreach":
                                this.PreprocessForeach(reader, writer, offset);
                                break;
                            case "endforeach": // endforeach is handled in PreprocessForeach, so seeing it here is an error
                                throw new WixException(WixErrors.UnmatchedPreprocessorInstruction(this.GetCurrentSourceLineNumbers(), "foreach", "endforeach"));
                            case "pragma":
                                this.PreprocessPragma(reader.Value, writer);
                                break;
                            default:
                                // unknown processing instructions are currently ignored
                                break;
                        }
                        break;
                    case XmlNodeType.Element:
                        bool empty = reader.IsEmptyElement;

                        if (0 < this.includeNextStack.Count && (bool)this.includeNextStack.Peek())
                        {
                            if ("Include" != reader.LocalName)
                            {
                                this.core.OnMessage(WixErrors.InvalidDocumentElement(this.GetCurrentSourceLineNumbers(), reader.Name, "include", "Include"));
                            }

                            this.includeNextStack.Pop();
                            this.includeNextStack.Push(false);
                            break;
                        }

                        // output any necessary preprocessor processing instructions then write the start of the element
                        this.WriteProcessingInstruction(reader, writer, offset);
                        writer.WriteStartElement(reader.Name);

                        while (reader.MoveToNextAttribute())
                        {
                            string value = this.core.PreprocessString(this.GetCurrentSourceLineNumbers(), reader.Value);
                            writer.WriteAttributeString(reader.Name, value);
                        }

                        if (empty)
                        {
                            writer.WriteEndElement();
                        }
                        break;
                    case XmlNodeType.EndElement:
                        if (0 < reader.Depth || !include)
                        {
                            writer.WriteEndElement();
                        }
                        break;
                    case XmlNodeType.Text:
                        string postprocessedText = this.core.PreprocessString(this.GetCurrentSourceLineNumbers(), reader.Value);
                        writer.WriteString(postprocessedText);
                        break;
                    case XmlNodeType.CDATA:
                        string postprocessedValue = this.core.PreprocessString(this.GetCurrentSourceLineNumbers(), reader.Value);
                        writer.WriteCData(postprocessedValue);
                        break;
                    default:
                        break;
                }
            }

            if (0 != stack.Count)
            {
                throw new WixException(WixErrors.NonterminatedPreprocessorInstruction(this.GetCurrentSourceLineNumbers(), "if", "endif"));
            }
        }
예제 #2
0
        /// <summary>
        /// Processes an xml reader into an xml writer.
        /// </summary>
        /// <param name="include">Specifies if reader is from an included file.</param>
        /// <param name="reader">Reader for the source document.</param>
        /// <param name="writer">Writer where postprocessed data is written.</param>
        /// <param name="offset">Original offset for the line numbers being processed.</param>
        private void PreprocessReader(bool include, XmlReader reader, XmlWriter writer, int offset)
        {
            Stack stack = new Stack(5);
            IfContext context = new IfContext(true, true, IfState.Unknown); // start by assuming we want to keep the nodes in the source code

            // process the reader into the writer
            while (reader.Read())
            {
                // update information here in case an error occurs before the next read
                this.UpdateInformation(reader, offset);

                // check for changes in conditional processing
                if (XmlNodeType.ProcessingInstruction == reader.NodeType)
                {
                    bool ignore = false;
                    string name = null;
                    int index = 0;

                    switch (reader.LocalName)
                    {
                        case "if":
                            stack.Push(context);
                            context = new IfContext(context.IsTrue & context.Active, this.EvaluateExpression(reader.Value), IfState.If);
                            ignore = true;
                            break;
                        case "ifdef":
                            stack.Push(context);
                            name = reader.Value.Trim();
                            index = name.IndexOf('.');
                            if (0 > index || (!Preprocessor.HasStandardPrefix(name) && null == this.FindExtension(name.Substring(0, index))))
                            {
                                name = String.Concat("var.", name);
                            }
                            context = new IfContext(context.IsTrue & context.Active, this.IsVariableDefined(name), IfState.If);
                            ignore = true;
                            break;
                        case "ifndef":
                            stack.Push(context);
                            name = reader.Value.Trim();
                            index = name.IndexOf('.');
                            if (0 > index || (!Preprocessor.HasStandardPrefix(name) && null == this.FindExtension(name.Substring(0, index))))
                            {
                                name = String.Concat("var.", name);
                            }
                            context = new IfContext(context.IsTrue & context.Active, !this.IsVariableDefined(name), IfState.If);
                            ignore = true;
                            break;
                        case "elseif":
                            if (0 == stack.Count)
                            {
                                throw new WixPreprocessorException(this.GetCurrentSourceLineNumbers(), "Missing <?if?> for <?elseif?>");
                            }

                            if (IfState.If != context.IfState && IfState.ElseIf != context.IfState)
                            {
                                throw new WixPreprocessorException(this.GetCurrentSourceLineNumbers(), "Specified <?elseif?> without matching <?if?>");
                            }

                            context.IfState = IfState.ElseIf;   // we're now in an elseif
                            if (!context.WasEverTrue)   // if we've never evaluated the if context to true, then we can try this test
                            {
                                context.IsTrue = this.EvaluateExpression(reader.Value);
                            }
                            else if (context.IsTrue)
                            {
                                context.IsTrue = false;
                            }
                            ignore = true;
                            break;
                        case "else":
                            if (0 == stack.Count)
                            {
                                throw new WixPreprocessorException(this.GetCurrentSourceLineNumbers(), "Missing <?if?> for <?else?>");
                            }

                            if (IfState.If != context.IfState && IfState.ElseIf != context.IfState)
                            {
                                throw new WixPreprocessorException(this.GetCurrentSourceLineNumbers(), "Specified <?else?> without matching <?if?>");
                            }

                            context.IfState = IfState.Else;   // we're now in an else
                            context.IsTrue = !context.WasEverTrue;   // if we were never true, we can be true now
                            ignore = true;
                            break;
                        case "endif":
                            if (0 == stack.Count)
                            {
                                throw new WixPreprocessorException(this.GetCurrentSourceLineNumbers(), "Missing <?if?> for <?endif?>");
                            }

                            context = (IfContext)stack.Pop();
                            ignore = true;
                            break;
                    }

                    if (ignore)   // ignore this node since we just handled it above
                    {
                        continue;
                    }
                }

                if (!context.Active || !context.IsTrue)   // if our context is not true then skip the rest of the processing and just read the next thing
                {
                    continue;
                }

                switch (reader.NodeType)
                {
                    case XmlNodeType.ProcessingInstruction:
                        switch (reader.LocalName)
                        {
                            case "define":
                                this.PreprocessDefine(reader.Value);
                                break;
                            case "undef":
                                this.PreprocessUndef(reader.Value);
                                break;
                            case "include":
                                this.UpdateInformation(reader, offset);
                                this.PreprocessInclude(reader.Value, writer);
                                break;
                            case "foreach":
                                this.PreprocessForeach(reader, writer, offset);
                                break;
                            case "endforeach": // endforeach is handled in PreprocessForeach, so seeing it here is an error
                                throw new WixPreprocessorException(this.GetCurrentSourceLineNumbers(), "Cannot have a <?endforeach?> processing instruction without a matching <?foreach?>.");
                            default:
                                // Console.WriteLine("processing instruction: {0}, {1}", reader.Name, reader.Value);
                                break;
                        }
                        break;
                    case XmlNodeType.Element:
                        bool empty = reader.IsEmptyElement;

                        if (0 < this.includeNextStack.Count && (bool)this.includeNextStack.Peek())
                        {
                            if (reader.Name != "Include")
                            {
                                throw new WixPreprocessorException(this.GetCurrentSourceLineNumbers(), "Included files must have <Include /> document element.");
                            }

                            this.includeNextStack.Pop();
                            this.includeNextStack.Push(false);
                            break;
                        }

                        // output any necessary preprocessor processing instructions then write the start of the element
                        this.WriteProcessingInstruction(reader, writer, offset);
                        writer.WriteStartElement(reader.Name);

                        while (reader.MoveToNextAttribute())
                        {
                            string value = this.PreprocessVariables(reader.Value);
                            writer.WriteAttributeString(reader.Name, value);
                        }

                        if (empty)
                        {
                            writer.WriteEndElement();
                        }
                        break;
                    case XmlNodeType.EndElement:
                        if (0 < reader.Depth || !include)
                        {
                            writer.WriteEndElement();
                        }
                        break;
                    case XmlNodeType.Text:
                    case XmlNodeType.CDATA:
                        string postprocessedValue = this.PreprocessVariables(reader.Value);
                        writer.WriteCData(postprocessedValue);
                        break;
                    default:
                        //Console.WriteLine("processing instruction: {0}, {1}", reader.Name, reader.Value);
                        break;
                }
            }

            if (0 != stack.Count)
            {
                throw new WixPreprocessorException(this.GetCurrentSourceLineNumbers(), "Missing <?endif?> for <?if?>");
            }
        }