private static void AddLine(Block block, LineInfo lineInfo, string ln, int offset, int length = -1)
        {
            if (!block.IsOpen)
                throw new CommonMarkException(string.Format(CultureInfo.InvariantCulture, "Attempted to add line '{0}' to closed container ({1}).", ln, block.Tag));

            var len = length == -1 ? ln.Length - offset : length;
            if (len <= 0)
                return;

            var curSC = block.StringContent;
            if (curSC == null)
            {
                block.StringContent = curSC = new StringContent();
                if (lineInfo.IsTrackingPositions)
                    curSC.PositionTracker = new PositionTracker(lineInfo.LineOffset);
            }

            if (lineInfo.IsTrackingPositions)
                curSC.PositionTracker.AddOffset(lineInfo, offset, len);

            curSC.Append(ln, offset, len);
        }
        /// <summary>
        /// Encodes the given text with HTML encoding (ampersand-encoding) and writes the result to the target writer.
        /// </summary>
        protected void WriteEncodedHtml(StringContent text)
        {
            if (text == null)
                return;

            HtmlFormatterSlim.EscapeHtml(text, _target);
        }
        /// <summary>
        /// Writes the specified text to the target writer.
        /// </summary>
        protected void Write(StringContent text)
        {
            if (text == null)
                return;

            text.WriteTo(_target);
        }
Exemple #4
0
        /// <summary>
        /// Generates documentation.
        /// </summary>
        /// <returns>The generation errors.</returns>
        public Model.GenerationError[] Generate(Configuration configuration)
        {
            // Initialize the list containing all generation errors
            List<Model.GenerationError> generationError = new List<Model.GenerationError>();

            // Ensure output directory exists
            if (!this.OutputDirectory.Exists)
            {
                this.OutputDirectory.Create();
            }

            // Process all pages
            List<Model.Page> pages = new List<Model.Page>();
            foreach (Page page in configuration.Pages)
            {
                // Compute the page id used as a tab id and page prefix for bookmarking
                string pageId = page.Path.Replace(".", string.Empty).Replace("/", string.Empty).Replace("\\", string.Empty);

                // Load the document
                Block document;

                // Process the page
                string pageFilePath = this.fileSystem.FileInfo.FromFileName(page.FileSystemPath).FullName;
                using (StreamReader reader = new StreamReader(this.fileSystem.File.Open(pageFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)))
                {
                    document = CommonMarkConverter.ProcessStage1(reader);
                }

                // Process snippet
                CommonMarkConverter.ProcessStage2(document);
                Dictionary<Guid, Extension.Model.Snippet> snippetDictionary = new Dictionary<Guid, Extension.Model.Snippet>();
                foreach (var node in document.AsEnumerable())
                {
                    // Filter fenced code
                    if (node.Block != null && node.Block.Tag == BlockTag.FencedCode)
                    {
                        // Build extraction rule
                        string fencedCode = node.Block.FencedCodeData.Info;

                        // Do not trigger extraction if the fenced code is empty
                        if (string.IsNullOrWhiteSpace(fencedCode))
                        {
                            continue;
                        }

                        SnippetExtractionRule snippetExtractionRule = SnippetExtractionRule.Parse(fencedCode);

                        // Extract and inject snippet and the factory were able to create an extractor
                        if (null != snippetExtractionRule)
                        {
                            // Cleanup Projbook specific syntax
                            node.Block.FencedCodeData.Info = snippetExtractionRule.Language;

                            // Inject snippet
                            try
                            {
                                // Retrieve the extractor instance
                                ISnippetExtractor snippetExtractor;
                                if (!this.extractorCache.TryGetValue(snippetExtractionRule.TargetPath, out snippetExtractor))
                                {
                                    snippetExtractor = this.snippetExtractorFactory.CreateExtractor(snippetExtractionRule);
                                    this.extractorCache[snippetExtractionRule.TargetPath] = snippetExtractor;
                                }

                                // Look for the file in available source directories
                                FileSystemInfoBase fileSystemInfo = null;
                                DirectoryInfoBase[] directoryInfos = null;
                                if (TargetType.FreeText != snippetExtractor.TargetType)
                                {
                                    directoryInfos = this.ExtractSourceDirectories(this.CsprojFile);
                                    foreach (DirectoryInfoBase directoryInfo in directoryInfos)
                                    {
                                        // Get directory name
                                        string directoryName = directoryInfo.FullName;
                                        if (1 == directoryName.Length && Path.DirectorySeparatorChar == directoryName[0])
                                            directoryName = string.Empty;

                                        // Compute file full path
                                        string fullFilePath = this.fileSystem.Path.GetFullPath(this.fileSystem.Path.Combine(directoryName, snippetExtractionRule.TargetPath ?? string.Empty));
                                        switch (snippetExtractor.TargetType)
                                        {
                                            case TargetType.File:
                                                if (this.fileSystem.File.Exists(fullFilePath))
                                                {
                                                    fileSystemInfo = this.fileSystem.FileInfo.FromFileName(fullFilePath);
                                                }
                                                break;
                                            case TargetType.Folder:
                                                if (this.fileSystem.Directory.Exists(fullFilePath))
                                                {
                                                    fileSystemInfo = this.fileSystem.DirectoryInfo.FromDirectoryName(fullFilePath);
                                                }
                                                break;
                                        }

                                        // Stop lookup if the file system info is found
                                        if (null != fileSystemInfo)
                                        {
                                            break;
                                        }
                                    }
                                }

                                // Raise an error if cannot find the file
                                if (null == fileSystemInfo && TargetType.FreeText != snippetExtractor.TargetType)
                                {
                                    // Locate block line
                                    int line = this.LocateBlockLine(node.Block, page);

                                    // Compute error column: Index of the path in the fenced code + 3 (for the ``` prefix) + 1 (to be 1 based)
                                    int column = fencedCode.IndexOf(snippetExtractionRule.TargetPath) + 4;

                                    // Report error
                                    generationError.Add(new Model.GenerationError(
                                        sourceFile: page.Path,
                                        message: string.Format("Cannot find target '{0}' in any referenced project ({0})", snippetExtractionRule.TargetPath, string.Join(";", directoryInfos.Select(x => x.FullName))),
                                        line: line,
                                        column: column));
                                    continue;
                                }

                                // Extract the snippet
                                Extension.Model.Snippet snippet =
                                    TargetType.FreeText == snippetExtractor.TargetType
                                    ? snippetExtractor.Extract(null, snippetExtractionRule.TargetPath)
                                    : snippetExtractor.Extract(fileSystemInfo, snippetExtractionRule.Pattern);

                                // Reference snippet
                                Guid guid = Guid.NewGuid();
                                snippetDictionary[guid] = snippet;

                                // Inject reference as content
                                StringContent code = new StringContent();
                                string content = SNIPPET_REFERENCE_PREFIX + guid;
                                code.Append(content, 0, content.Length);
                                node.Block.StringContent = code;

                                // Change tag to html for node snippets
                                NodeSnippet nodeSnippet = snippet as NodeSnippet;
                                if (null != nodeSnippet)
                                {
                                    node.Block.Tag = BlockTag.HtmlBlock;
                                }
                            }
                            catch (SnippetExtractionException snippetExtraction)
                            {
                                // Locate block line
                                int line = this.LocateBlockLine(node.Block, page);

                                // Compute error column: Fenced code length - pattern length + 3 (for the ``` prefix) + 1 (to be 1 based)
                                int column = fencedCode.Length - snippetExtractionRule.Pattern.Length + 4;

                                // Report error
                                generationError.Add(new Model.GenerationError(
                                    sourceFile: page.Path,
                                    message: string.Format("{0}: {1}", snippetExtraction.Message, snippetExtraction.Pattern),
                                    line: line,
                                    column: column));
                            }
                            catch (System.Exception exception)
                            {
                                generationError.Add(new Model.GenerationError(
                                    sourceFile: page.Path,
                                    message: exception.Message,
                                    line: 0,
                                    column: 0));
                            }
                        }
                    }
                }

                // Write to output
                ProjbookHtmlFormatter projbookHtmlFormatter = null;
                MemoryStream documentStream = new MemoryStream();
                using (StreamWriter writer = new StreamWriter(documentStream))
                {
                    // Setup custom formatter
                    CommonMarkSettings.Default.OutputDelegate = (d, o, s) => (projbookHtmlFormatter = new ProjbookHtmlFormatter(pageId, o, s, configuration.SectionTitleBase, snippetDictionary, SNIPPET_REFERENCE_PREFIX)).WriteDocument(d);

                    // Render
                    CommonMarkConverter.ProcessStage3(document, writer);
                }

                // Initialize the pre section content
                string preSectionContent = string.Empty;

                // Retrieve page content
                byte[] pageContent = documentStream.ToArray();

                // Set the whole page content if no page break is detected
                if (projbookHtmlFormatter.PageBreak.Length == 0)
                {
                    preSectionContent = System.Text.Encoding.UTF8.GetString(pageContent);
                }

                // Compute pre section content from the position 0 to the first page break position
                if (projbookHtmlFormatter.PageBreak.Length > 0 && projbookHtmlFormatter.PageBreak.First().Position > 0)
                {
                    preSectionContent = this.StringFromByteArray(pageContent, 0, projbookHtmlFormatter.PageBreak.First().Position);
                }

                // Build section list
                List<Model.Section> sections = new List<Model.Section>();
                for (int i = 0; i < projbookHtmlFormatter.PageBreak.Length; ++i)
                {
                    // Retrieve the current page break
                    PageBreakInfo pageBreak = projbookHtmlFormatter.PageBreak[i];

                    // Extract the content from the current page break to the next one if any
                    string content = null;
                    if (i < projbookHtmlFormatter.PageBreak.Length - 1)
                    {
                        PageBreakInfo nextBreak = projbookHtmlFormatter.PageBreak[1 + i];
                        content = this.StringFromByteArray(pageContent, pageBreak.Position, nextBreak.Position - pageBreak.Position);
                    }

                    // Otherwise extract the content from the current page break to the end of the content
                    else
                    {
                        content = this.StringFromByteArray(pageContent, pageBreak.Position, pageContent.Length - pageBreak.Position);
                    }

                    // Create a new section and add to the known list
                    sections.Add(new Model.Section(
                        id: pageBreak.Id,
                        level: pageBreak.Level,
                        title: pageBreak.Title,
                        content: content));
                }

                // Add new page
                pages.Add(new Model.Page(
                    id: pageId,
                    title: page.Title,
                    preSectionContent: preSectionContent,
                    sections: sections.ToArray()));
            }

            // Html generation
            if (configuration.GenerateHtml)
            {
                try
                {
                    string outputFileHtml = this.fileSystem.Path.Combine(this.OutputDirectory.FullName, configuration.OutputHtml);
                    this.GenerateFile(configuration.TemplateHtml, outputFileHtml, configuration, pages);
                }
                catch (TemplateParsingException templateParsingException)
                {
                    generationError.Add(new Model.GenerationError(configuration.TemplateHtml, string.Format("Error during HTML generation: {0}", templateParsingException.Message), templateParsingException.Line, templateParsingException.Column));
                }
                catch (System.Exception exception)
                {
                    generationError.Add(new Model.GenerationError(configuration.TemplateHtml, string.Format("Error during HTML generation: {0}", exception.Message), 0, 0));
                }
            }

            // Pdf generation
            if (configuration.GeneratePdf && !this.SkipPdf)
            {
                try
                {
                    // Generate the pdf template
                    string outputFileHtml = this.fileSystem.Path.Combine(this.OutputDirectory.FullName, configuration.OutputPdf);
                    this.GenerateFile(configuration.TemplatePdf, outputFileHtml, configuration, pages);

            #if !NOPDF
                    // Compute file names
                    string outputPdf = this.fileSystem.Path.ChangeExtension(configuration.OutputPdf, ".pdf");
                    string outputFilePdf = this.fileSystem.Path.Combine(this.OutputDirectory.FullName, outputPdf);

                    // Prepare the converter
                    MultiplexingConverter pdfConverter = new MultiplexingConverter();
                    pdfConverter.ObjectSettings.Page = outputFileHtml;
                    pdfConverter.Error += (s, e) => {
                        generationError.Add(new Model.GenerationError(configuration.TemplatePdf, string.Format("Error during PDF generation: {0}", e.Value), 0, 0));
                    };

                    // Prepare file system if abstracted
                    bool requireCopyToFileSystem = !File.Exists(outputFileHtml);
                    try
                    {
                        // File system may be abstracted, this requires to copy the pdf generation file to the actual file system
                        // in order to allow wkhtmltopdf to process the generated html as input file
                        if (requireCopyToFileSystem)
                        {
                            File.WriteAllBytes(outputFileHtml, this.fileSystem.File.ReadAllBytes(outputFileHtml));
                        }

                        // Run pdf converter
                        using (pdfConverter)
                        using (Stream outputFileStream = this.fileSystem.File.Open(outputFilePdf, FileMode.Create, FileAccess.Write, FileShare.None))
                        {
                            try
                            {
                                byte[] buffer = pdfConverter.Convert();
                                outputFileStream.Write(buffer, 0, buffer.Length);
                            }
                            catch
                            {
                                // Ignore generation errors at that level
                                // Errors are handled by the error handling having the best description
                            }
                        }
                    }
                    finally
                    {
                        if (requireCopyToFileSystem && File.Exists(outputFileHtml))
                        {
                            File.Delete(outputFileHtml);
                        }
                    }
            #endif
                }
                catch (TemplateParsingException templateParsingException)
                {
                    generationError.Add(new Model.GenerationError(configuration.TemplatePdf, string.Format("Error during PDF generation: {0}", templateParsingException.Message), templateParsingException.Line, templateParsingException.Column));
                }
                catch (System.Exception exception)
                {
                    if (null != exception.InnerException && INCORRECT_FORMAT_HRESULT == exception.InnerException.HResult)
                    {
                        // Report detailed error message for wrong architecture loading
                        string runningArchitectureProccess = IntPtr.Size == 8 ? "x64" : "x86";
                        string otherRunningArchitectureProccess = IntPtr.Size != 8 ? "x64" : "x86";
                        generationError.Add(new Model.GenerationError(configuration.TemplatePdf, string.Format("Error during PDF generation: Could not load wkhtmltopdf for {0}. Try again running as a {1} process.", runningArchitectureProccess, otherRunningArchitectureProccess), 0, 0));
                    }
                    else
                    {
                        // Report unknown error
                        generationError.Add(new Model.GenerationError(configuration.TemplatePdf, string.Format("Error during PDF generation: {0}", exception.Message), 0, 0));
                    }
                }
            }

            // Return the generation errors
            return generationError.ToArray();
        }
 private static bool ContainsSingleLine(StringContent content)
 {
     if (content == null)
         return true;
     var i = content.IndexOf('\n');
     return (i == -1 || i == content.Length - 1);
 }
        /// <summary>
        /// Generates documentation.
        /// </summary>
        public Model.GenerationError[] Generate()
        {
            // Initialize the list containing all generation errors
            List<Model.GenerationError> generationError = new List<Model.GenerationError>();

            // Ensute output directory exists
            if (!this.OutputDirectory.Exists)
            {
                this.OutputDirectory.Create();
            }

            // Read configuration
            ConfigurationLoader configurationLoader = new ConfigurationLoader();
            Configuration configuration;
            try
            {
                configuration = configurationLoader.Load(this.ConfigFile);
            }
            catch (System.Exception exception)
            {
                generationError.Add(new Model.GenerationError(this.ConfigFile.FullName, string.Format("Error during loading configuration: {0}", exception.Message)));
                return generationError.ToArray();
            }

            // Process all pages
            List<Model.Page> pages = new List<Model.Page>();
            bool first = true;
            foreach (Page page in configuration.Pages)
            {
                // Declare formatter
                InjectAnchorHtmlFormatter formatter = null;

                // Load the document
                Block document;
                FileInfo fileInfo = new FileInfo(page.Path);

                // Skip the page if doesn't exist
                if (!fileInfo.Exists)
                {
                    generationError.Add(new Model.GenerationError(this.ConfigFile.FullName, string.Format("Error during loading configuration: Could not find file '{0}'", fileInfo.FullName)));
                    continue;
                }

                // Process the page
                using (StreamReader reader = new StreamReader(new FileStream(new FileInfo(page.Path).FullName, FileMode.Open)))
                {
                    document = CommonMarkConverter.ProcessStage1(reader);
                }

                // Process snippet
                CommonMarkConverter.ProcessStage2(document);
                foreach (var node in document.AsEnumerable())
                {
                    // Filter fenced code
                    if (node.Block != null && node.Block.Tag == BlockTag.FencedCode)
                    {
                        // Extract snippet
                        string fencedCode = node.Block.FencedCodeData.Info;
                        ISnippetExtractor snippetExtractor = this.snippetExtractorFactory.CreateExtractor(fencedCode);

                        // Extract and inject snippet and the factory were able to create an extractor
                        if (null != snippetExtractor)
                        {
                            // Cleanup Projbook specific syntax
                            node.Block.FencedCodeData.Info = snippetExtractor.Language;

                            // Inject snippet
                            try
                            {
                                Model.Snippet snippet = snippetExtractor.Extract();
                                StringContent code = new StringContent();
                                code.Append(snippet.Content, 0, snippet.Content.Length);
                                node.Block.StringContent = code;
                            }
                            catch (SnippetExtractionException snippetExtraction)
                            {
                                generationError.Add(new Model.GenerationError(
                                    sourceFile: page.Path,
                                    message: string.Format("{0}: {1}", snippetExtraction.Message, snippetExtraction.Pattern)));
                            }
                            catch (System.Exception exception)
                            {
                                generationError.Add(new Model.GenerationError(
                                    sourceFile: page.Path,
                                    message: exception.Message));
                            }
                        }
                    }
                }

                // Setup custom formatter
                CommonMarkSettings.Default.OutputDelegate =
                    (d, output, settings) =>
                    {
                        formatter = new InjectAnchorHtmlFormatter(page.Path, output, settings);
                        formatter.WriteDocument(d);
                    };

                // Write to output
                MemoryStream documentStream = new MemoryStream();
                using (StreamWriter writer = new StreamWriter(documentStream))
                {
                    CommonMarkConverter.ProcessStage3(document, writer);
                }

                // Add new page
                pages.Add(new Model.Page(
                    id: page.Path.Replace(".", string.Empty).Replace("/", string.Empty),
                    title: page.Title,
                    isHome: first,
                    anchor: formatter.Anchors,
                    content: System.Text.Encoding.UTF8.GetString(documentStream.ToArray())));
                first = false;
            }

            // Standard generation
            try
            {
                this.GenerateFile(this.TemplateFile.FullName, this.TemplateFile.FullName, configuration, pages);
            }
            catch (System.Exception exception)
            {
                generationError.Add(new Model.GenerationError(this.TemplateFile.FullName, string.Format("Error during HTML generation: {0}", exception.Message)));
            }

            // Pdf specific generation
            string pdfTemplate = this.TemplateFilePdf.Exists ? this.TemplateFilePdf.FullName : this.TemplateFile.FullName;
            try
            {
                this.GenerateFile(pdfTemplate, this.TemplateFilePdf.FullName, configuration, pages);
            }
            catch (System.Exception exception)
            {
                generationError.Add(new Model.GenerationError(pdfTemplate, string.Format("Error during PDF generation: {0}", exception.Message)));
            }

            // Return the generation errors
            return generationError.ToArray();
        }
        /// <summary>
        /// Escapes special HTML characters.
        /// </summary>
        /// <remarks>Orig: escape_html(inp, preserve_entities)</remarks>
        internal static void EscapeHtml(StringContent inp, HtmlTextWriter target)
        {
            int pos;
            int lastPos;
            char[] buffer = target.Buffer;

            var parts = inp.RetrieveParts();
            for (var i = parts.Offset; i < parts.Offset + parts.Count; i++)
            {
                var part = parts.Array[i];

                if (buffer.Length < part.Length)
                    buffer = target.Buffer = new char[part.Length];

                part.Source.CopyTo(part.StartIndex, buffer, 0, part.Length);

                lastPos = part.StartIndex;
                while ((pos = part.Source.IndexOfAny(EscapeHtmlCharacters, lastPos, part.Length - lastPos + part.StartIndex)) != -1)
                {
                    target.Write(buffer, lastPos - part.StartIndex, pos - lastPos);
                    lastPos = pos + 1;

                    switch (part.Source[pos])
                    {
                        case '<':
                            target.WriteConstant(EscapeHtmlLessThan);
                            break;
                        case '>':
                            target.WriteConstant(EscapeHtmlGreaterThan);
                            break;
                        case '&':
                            target.WriteConstant(EscapeHtmlAmpersand);
                            break;
                        case '"':
                            target.WriteConstant(EscapeHtmlQuote);
                            break;
                    }
                }

                target.Write(buffer, lastPos - part.StartIndex, part.Length - lastPos + part.StartIndex);
            }
        }
Exemple #8
0
        /// <summary>
        /// Generates documentation.
        /// </summary>
        public Model.GenerationError[] Generate()
        {
            // Initialize the list containing all generation errors
            List<Model.GenerationError> generationError = new List<Model.GenerationError>();

            // Ensute output directory exists
            if (!this.OutputDirectory.Exists)
            {
                this.OutputDirectory.Create();
            }

            // Read configuration
            ConfigurationLoader configurationLoader = new ConfigurationLoader();
            Configuration configuration;
            try
            {
                configuration = configurationLoader.Load(this.ConfigFile);
            }
            catch (System.Exception exception)
            {
                generationError.Add(new Model.GenerationError(this.ConfigFile.FullName, string.Format("Error during loading configuration: {0}", exception.Message)));
                return generationError.ToArray();
            }

            // Process all pages
            List<Model.Page> pages = new List<Model.Page>();
            foreach (Page page in configuration.Pages)
            {
                // Compute the page id used as a tab id and page prefix for bookmarking
                string pageId = page.Path.Replace(".", string.Empty).Replace("/", string.Empty);

                // Load the document
                Block document;
                FileInfo fileInfo = new FileInfo(page.Path);

                // Skip the page if doesn't exist
                if (!fileInfo.Exists)
                {
                    generationError.Add(new Model.GenerationError(this.ConfigFile.FullName, string.Format("Error during loading configuration: Could not find file '{0}'", fileInfo.FullName)));
                    continue;
                }

                // Process the page
                using (StreamReader reader = new StreamReader(new FileStream(new FileInfo(page.Path).FullName, FileMode.Open)))
                {
                    document = CommonMarkConverter.ProcessStage1(reader);
                }

                // Process snippet
                CommonMarkConverter.ProcessStage2(document);
                foreach (var node in document.AsEnumerable())
                {
                    // Filter fenced code
                    if (node.Block != null && node.Block.Tag == BlockTag.FencedCode)
                    {
                        // Buil extraction rule
                        string fencedCode = node.Block.FencedCodeData.Info;
                        SnippetExtractionRule snippetExtractionRule = SnippetExtractionRule.Parse(fencedCode);

                        // Extract and inject snippet and the factory were able to create an extractor
                        if (null != snippetExtractionRule)
                        {
                            // Cleanup Projbook specific syntax
                            node.Block.FencedCodeData.Info = snippetExtractionRule.Language;

                            // Inject snippet
                            try
                            {
                                // Retrieve the extractor instance
                                ISnippetExtractor snippetExtractor;
                                if (!this.extractorCache.TryGetValue(snippetExtractionRule.FileName, out snippetExtractor))
                                {
                                    snippetExtractor = this.snippetExtractorFactory.CreateExtractor(snippetExtractionRule);
                                    this.extractorCache[snippetExtractionRule.FileName] = snippetExtractor;
                                }

                                // Extract the snippet
                                Model.Snippet snippet = snippetExtractor.Extract(snippetExtractionRule.FileName, snippetExtractionRule.Pattern);
                                StringContent code = new StringContent();
                                code.Append(snippet.Content, 0, snippet.Content.Length);
                                node.Block.StringContent = code;
                            }
                            catch (SnippetExtractionException snippetExtraction)
                            {
                                generationError.Add(new Model.GenerationError(
                                    sourceFile: page.Path,
                                    message: string.Format("{0}: {1}", snippetExtraction.Message, snippetExtraction.Pattern)));
                            }
                            catch (System.Exception exception)
                            {
                                generationError.Add(new Model.GenerationError(
                                    sourceFile: page.Path,
                                    message: exception.Message));
                            }
                        }
                    }
                }

                // Setup custom formatter
                CommonMarkSettings.Default.OutputDelegate = (d, o, s) => new InjectAnchorHtmlFormatter(pageId, this.sectionSplittingIdentifier, o, s).WriteDocument(d);

                // Write to output
                MemoryStream documentStream = new MemoryStream();
                using (StreamWriter writer = new StreamWriter(documentStream))
                {
                    CommonMarkConverter.ProcessStage3(document, writer);
                }

                // Initialize the pre section content
                string preSectionContent = string.Empty;

                // Retrieve page content
                string pageContent = System.Text.Encoding.UTF8.GetString(documentStream.ToArray());

                // Build section list
                List<Model.Section> sections = new List<Model.Section>();
                Match match = regex.Match(pageContent);
                bool matched = false;
                while(match.Success)
                {
                    // Initialize the pre section part from 0 to the first matching index for the first matching
                    if (!matched)
                    {
                        preSectionContent = pageContent.Substring(0, match.Groups[0].Index);
                    }

                    // Create a new section and add to the known list
                    sections.Add(new Model.Section(
                        id: match.Groups[2].Value,
                        title: match.Groups[1].Value,
                        content: match.Groups[3].Value));

                    // Mode to the next match
                    match = match.NextMatch();
                    matched = true;
                }

                // If nothing has been matching simple consider the whole input as pre section content
                if (!matched)
                {
                    preSectionContent = pageContent;
                }

                // Add new page
                pages.Add(new Model.Page(
                    id: pageId,
                    title: page.Title,
                    preSectionContent: preSectionContent,
                    sections: sections.ToArray()));
            }

            // Standard generation
            try
            {
                this.GenerateFile(this.TemplateFile.FullName, this.TemplateFile.FullName, configuration, pages);
            }
            catch (System.Exception exception)
            {
                generationError.Add(new Model.GenerationError(this.TemplateFile.FullName, string.Format("Error during HTML generation: {0}", exception.Message)));
            }

            // Pdf specific generation
            string pdfTemplate = this.TemplateFilePdf.Exists ? this.TemplateFilePdf.FullName : this.TemplateFile.FullName;
            try
            {
                this.GenerateFile(pdfTemplate, this.TemplateFilePdf.FullName, configuration, pages);
            }
            catch (System.Exception exception)
            {
                generationError.Add(new Model.GenerationError(pdfTemplate, string.Format("Error during PDF generation: {0}", exception.Message)));
            }

            // Return the generation errors
            return generationError.ToArray();
        }