예제 #1
0
        public void FormatTestListNested()
        {
            TestOutputter    output = new TestOutputter();
            TextileFormatter target = new TextileFormatter(output);

            string input = "# Fuel could be:\n" +
                           "## Coal\n" +
                           "## Gasoline\n" +
                           "## Electricity\n" +
                           "# Humans need only:\n" +
                           "## Water\n" +
                           "## Protein";

            target.Format(input);
            string expected = "<ol>\n" +
                              "<li>Fuel could be:" +
                              "<ol>\n" +
                              "<li>Coal</li>\n" +
                              "<li>Gasoline</li>\n" +
                              "<li>Electricity</li>\n" +
                              "</ol>\n" +
                              "</li>\n" +
                              "<li>Humans need only:" +
                              "<ol>\n" +
                              "<li>Water</li>\n" +
                              "<li>Protein</li>\n" +
                              "</ol>\n" +
                              "</li>\n" +
                              "</ol>\n";
            string actual = output.GetOutput();

            Assert.AreEqual(expected, actual);
        }
예제 #2
0
        public void TestStuff(string input, string expected)
        {
            var outputter = new StringBuilderOutputter();
            var formatter = new TextileFormatter(outputter);

            formatter.Format(input);
            var actual = outputter.GetFormattedText();

            Bitmap diff;

            if (!actual.RendersEqual(expected, out diff))
            {
                var path = Path.Combine(Path.GetTempPath(), "Textile.Test");

                if (Directory.Exists(path))
                {
                }

                Directory.CreateDirectory(path);
                var filename = Path.Combine(path, $"{TestContext.CurrentContext.Test.Name}.png");

                diff.Save(filename);

                Assert.Fail($"HTML does not match.\r\nExpected:\r\n{expected}\r\n\r\nActual:\r\n{actual}\r\n\r\nDiff image: {filename}");
            }
        }
예제 #3
0
        public string Render(string text)
        {
            formatter.Format(text);
            var result = output.GetFormattedText();

            return(result);
        }
        public override string RenderHtml(string innerRepresentation)
        {
            var outputter = new StringBuilderTextileFormatter();
            var renderer  = new TextileFormatter(outputter);

            renderer.Format(innerRepresentation);
            return(outputter.GetFormattedText());
        }
예제 #5
0
        public void ApplyFormating(NoticeMessage message)
        {
            var output    = new StringBuilderTextileFormatter();
            var formatter = new TextileFormatter(output);

            message.Subject = VelocityArguments.Replace(message.Subject, argMatchReplace);
            formatter.Format(message.Body);
            message.Body = Master.Replace("%CONTENT%", output.GetFormattedText());
        }
예제 #6
0
        public void ApplyFormating(NoticeMessage message)
        {
            var output    = new StringBuilderTextileFormatter();
            var formatter = new TextileFormatter(output);

            if (!string.IsNullOrEmpty(message.Subject))
            {
                message.Subject = VelocityArguments.Replace(message.Subject, m => m.Result("${arg}"));
            }

            if (!string.IsNullOrEmpty(message.Body))
            {
                formatter.Format(message.Body);

                var logoMail = ConfigurationManager.AppSettings["web.logo.mail"];
                var logo     = string.IsNullOrEmpty(logoMail) ? "http://cdn.teamlab.com/media/newsletters/images/header_04.jpg" : logoMail;
                message.Body = Resources.TemplateResource.HtmlMaster.Replace("%CONTENT%", output.GetFormattedText()).Replace("%LOGO%", logo);

                var footer  = message.GetArgument("WithPhoto");
                var partner = message.GetArgument("Partner");
                var res     = String.Empty;

                if (partner != null)
                {
                    res = partner.Value.ToString();
                }
                if (String.IsNullOrEmpty(res) && footer != null)
                {
                    switch ((string)footer.Value)
                    {
                    case "photo":
                        res = Resources.TemplateResource.FooterWithPhoto;
                        break;

                    case "links":
                        res = Resources.TemplateResource.FooterWithLinks;
                        break;

                    default:
                        res = String.Empty;
                        break;
                    }
                }
                message.Body = message.Body.Replace("%FOOTER%", res);

                var mail   = message.Recipient.Addresses.FirstOrDefault(r => r.Contains("@"));
                var domain = ConfigurationManager.AppSettings["web.teamlab-site"];
                var site   = string.IsNullOrEmpty(domain) ? "http://www.teamlab.com" : domain;
                var link   = site + string.Format("/Unsubscribe.aspx?id={0}", HttpServerUtility.UrlTokenEncode(Security.Cryptography.InstanceCrypto.Encrypt(Encoding.UTF8.GetBytes(mail.ToLowerInvariant()))));
                var text   = string.Format(Resources.TemplateResource.TextForFooter, link, DateTime.UtcNow.Year);

                message.Body = message.Body.Replace("%TEXTFOOTER%", text);
            }
        }
예제 #7
0
        public void FormatTestParagraphWithClassAndID()
        {
            TestOutputter    output = new TestOutputter();
            TextileFormatter target = new TextileFormatter(output);

            string input = "p(example1#big-red2). Red here.";

            target.Format(input);
            string expected = "<p class=\"example1\" id=\"big-red2\">Red here.</p>\n";
            string actual   = output.GetOutput();

            Assert.AreEqual(expected, actual);
        }
예제 #8
0
        public void FormatTestFootNote()
        {
            TestOutputter    output = new TestOutputter();
            TextileFormatter target = new TextileFormatter(output);

            string input = "fn1. Down here, in fact.";

            target.Format(input);
            string expected = "<p id=\"fn1\"><sup>1</sup> Down here, in fact.</p>\n";
            string actual   = output.GetOutput();

            Assert.AreEqual(expected, actual);
        }
예제 #9
0
        public void FormatTestRandomSentences()
        {
            TestOutputter    output = new TestOutputter();
            TextileFormatter target = new TextileFormatter(output);

            string input = "\"Textile\":http://textism.com/tools/textile/ is a \"Humane Web Text Generator\", as they say.";

            target.Format(input);
            string expected = "<p><a href=\"http://textism.com/tools/textile/\">Textile</a> is a &#8220;Humane Web Text Generator&#8221;, as they say.</p>\n";
            string actual   = output.GetOutput();

            Assert.AreEqual(expected, actual);
        }
예제 #10
0
        public void FormatTestSytledParagraph()
        {
            TestOutputter    output = new TestOutputter();
            TextileFormatter target = new TextileFormatter(output);

            string input = "p{color:blue;margin:30px}. Spacey blue.";

            target.Format(input);
            string expected = "<p style=\"color:blue;margin:30px;\">Spacey blue.</p>\n";
            string actual   = output.GetOutput();

            Assert.AreEqual(expected, actual);
        }
예제 #11
0
        public void FormatTestParagraphWithID()
        {
            TestOutputter    output = new TestOutputter();
            TextileFormatter target = new TextileFormatter(output);

            string input = "p(#big-red). Red here!";

            target.Format(input);
            string expected = "<p id=\"big-red\">Red here!</p>\n";
            string actual   = output.GetOutput();

            Assert.AreEqual(expected, actual);
        }
예제 #12
0
        public void FormatTestParagraphWithClass()
        {
            TestOutputter    output = new TestOutputter();
            TextileFormatter target = new TextileFormatter(output);

            string input = "p(example1). An example.";

            target.Format(input);
            string expected = "<p class=\"example1\">An example.</p>\n";
            string actual   = output.GetOutput();

            Assert.AreEqual(expected, actual);
        }
예제 #13
0
        public void FormatTestOneParagraph()
        {
            TestOutputter    output = new TestOutputter();
            TextileFormatter target = new TextileFormatter(output);

            string input = "A single paragraph.";

            target.Format(input);

            string expected = "<p>A single paragraph.</p>\n";
            string actual   = output.GetOutput();

            Assert.AreEqual(expected, actual);
        }
예제 #14
0
        public void FormatTestHeaders()
        {
            TestOutputter    output = new TestOutputter();
            TextileFormatter target = new TextileFormatter(output);

            string input = "h1. A simple header";

            target.Format(input);
            string expected = "<h1>A simple header</h1>\n";
            string actual   = output.GetOutput();

            Assert.AreEqual(expected, actual);

            input = "h1. A simple header\n" +
                    "h2. A sub header\n" +
                    "h3. A sub sub header";
            target.Format(input);
            expected = "<h1>A simple header</h1>\n" +
                       "<h2>A sub header</h2>\n" +
                       "<h3>A sub sub header</h3>\n";
            actual = output.GetOutput();
            Assert.AreEqual(expected, actual);
        }
예제 #15
0
        public void FormatTestOneParagraphWithLineBreak()
        {
            TestOutputter    output = new TestOutputter();
            TextileFormatter target = new TextileFormatter(output);

            string input = "A single paragraph.\n" +
                           "Followed by the rest.";

            target.Format(input);

            string expected = "<p>A single paragraph.<br />\n" +
                              "Followed by the rest.</p>\n";
            string actual = output.GetOutput();

            Assert.AreEqual(expected, actual);
        }
예제 #16
0
        public void FormatTestBlockQuote()
        {
            TestOutputter    output = new TestOutputter();
            TextileFormatter target = new TextileFormatter(output);

            string input = "An old text\n\n" +
                           "bq. A block quotation.\n\n" +
                           "Any old text";

            target.Format(input);
            string expected = "<p>An old text</p>\n" +
                              "<blockquote><p>A block quotation.</p></blockquote>\n" +
                              "<p>Any old text</p>\n";
            string actual = output.GetOutput();

            Assert.AreEqual(expected, actual);
        }
예제 #17
0
        public void FormatTestTwoParagraphs()
        {
            TestOutputter    output = new TestOutputter();
            TextileFormatter target = new TextileFormatter(output);

            string input = "A single paragraph.\n" +
                           "\n" +
                           "Followed by another.";

            target.Format(input);

            string expected = "<p>A single paragraph.</p>\n" +
                              "<p>Followed by another.</p>\n";
            string actual = output.GetOutput();

            Assert.AreEqual(expected, actual);
        }
예제 #18
0
        public void FormatTestListSimple()
        {
            TestOutputter    output = new TestOutputter();
            TextileFormatter target = new TextileFormatter(output);

            string input = "# A first item\n" +
                           "# A second item\n" +
                           "# A third";

            target.Format(input);
            string expected = "<ol>\n" +
                              "<li>A first item</li>\n" +
                              "<li>A second item</li>\n" +
                              "<li>A third</li>\n" +
                              "</ol>\n";
            string actual = output.GetOutput();

            Assert.AreEqual(expected, actual);
        }
예제 #19
0
        public void FormatTestTableWithCellAttributes()
        {
            TestOutputter    output = new TestOutputter();
            TextileFormatter target = new TextileFormatter(output);

            string input = "|_. attribute list |\n" +
                           "|<. align left |\n" +
                           "|>. align right|\n" +
                           "|=. center |\n" +
                           "|<>. justify |\n" +
                           "|^. valign top |\n" +
                           "|~. bottom |\n";

            target.Format(input);
            string expected = "<table>\n" +
                              "<tr>\n" +
                              "<th>attribute list </th>\n" +
                              "</tr>\n" +
                              "<tr>\n" +
                              "<td style=\"text-align:left;\">align left </td>\n" +
                              "</tr>\n" +
                              "<tr>\n" +
                              "<td style=\"text-align:right;\">align right</td>\n" +
                              "</tr>\n" +
                              "<tr>\n" +
                              "<td style=\"text-align:center;\">center </td>\n" +
                              "</tr>\n" +
                              "<tr>\n" +
                              "<td style=\"text-align:justify;\">justify </td>\n" +
                              "</tr>\n" +
                              "<tr>\n" +
                              "<td style=\"vertical-align:top;\">valign top </td>\n" +
                              "</tr>\n" +
                              "<tr>\n" +
                              "<td style=\"vertical-align:bottom;\">bottom </td>\n" +
                              "</tr>\n" +
                              "</table>\n";
            string actual = output.GetOutput();

            Assert.AreEqual(expected, actual);
        }
예제 #20
0
        public void FormatTestTableWithHeaders()
        {
            TestOutputter    output = new TestOutputter();
            TextileFormatter target = new TextileFormatter(output);

            string input = "|_. name |_.age |_. sex|\n" +
                           "| joan | 24 | f |\n";

            target.Format(input);
            string expected = "<table>\n" +
                              "<tr>\n" +
                              "<th>name </th><th>age </th><th>sex</th>\n" +
                              "</tr>\n" +
                              "<tr>\n" +
                              "<td> joan </td><td> 24 </td><td> f </td>\n" +
                              "</tr>\n" +
                              "</table>\n";
            string actual = output.GetOutput();

            Assert.AreEqual(expected, actual);
        }
예제 #21
0
        public void FormatTestTableSimple()
        {
            TestOutputter    output = new TestOutputter();
            TextileFormatter target = new TextileFormatter(output);

            string input = "|name|age|sex|\n" +
                           "| joan arc| 24 | f |";

            target.Format(input);
            string expected = "<table>\n" +
                              "<tr>\n" +
                              "<td>name</td><td>age</td><td>sex</td>\n" +
                              "</tr>\n" +
                              "<tr>\n" +
                              "<td> joan arc</td><td> 24 </td><td> f </td>\n" +
                              "</tr>\n" +
                              "</table>\n";
            string actual = output.GetOutput();

            Assert.AreEqual(expected, actual);
        }
예제 #22
0
        public void ApplyFormating(NoticeMessage message)
        {
            var output    = new StringBuilderTextileFormatter();
            var formatter = new TextileFormatter(output);

            if (!string.IsNullOrEmpty(message.Subject))
            {
                message.Subject = VelocityArguments.Replace(message.Subject, m => m.Result("${arg}"));
            }

            if (string.IsNullOrEmpty(message.Body))
            {
                return;
            }

            formatter.Format(message.Body);

            var template        = GetTemplate(message);
            var analytics       = GetAnalytics(message);
            var imagePath       = GetImagePath(message);
            var logoImg         = GetLogoImg(message, imagePath);
            var logoText        = GetLogoText(message);
            var mailSettings    = GetMailSettings(message);
            var unsubscribeText = GetUnsubscribeText(message, mailSettings);

            string footerContent;
            string footerSocialContent;

            InitFooter(message, mailSettings, out footerContent, out footerSocialContent);

            message.Body = template.Replace("%ANALYTICS%", analytics)
                           .Replace("%CONTENT%", output.GetFormattedText())
                           .Replace("%LOGO%", logoImg)
                           .Replace("%LOGOTEXT%", logoText)
                           .Replace("%SITEURL%", mailSettings == null ? MailWhiteLabelSettings.DefaultMailSiteUrl : mailSettings.SiteUrl)
                           .Replace("%FOOTER%", footerContent)
                           .Replace("%FOOTERSOCIAL%", footerSocialContent)
                           .Replace("%TEXTFOOTER%", unsubscribeText)
                           .Replace("%IMAGEPATH%", imagePath);
        }
예제 #23
0
        public void ApplyFormating(NoticeMessage message)
        {
            var template       = NotifyTemplateResource.HtmlMaster;
            var isPersonalTmpl = false;

            var output    = new StringBuilderTextileFormatter();
            var formatter = new TextileFormatter(output);

            if (!string.IsNullOrEmpty(message.Subject))
            {
                message.Subject = VelocityArguments.Replace(message.Subject, m => m.Result("${arg}"));
            }

            if (string.IsNullOrEmpty(message.Body))
            {
                return;
            }

            formatter.Format(message.Body);

            var isPersonal = message.GetArgument("IsPersonal");

            if (isPersonal != null && (string)isPersonal.Value == "true")
            {
                isPersonalTmpl = true;
            }

            var templateTag = message.GetArgument("MasterTemplate");

            if (templateTag != null)
            {
                var templateTagValue = templateTag.Value as string;
                if (!string.IsNullOrEmpty(templateTagValue))
                {
                    var templateValue = NotifyTemplateResource.ResourceManager.GetString(templateTagValue);
                    if (!string.IsNullOrEmpty(templateValue))
                    {
                        template = templateValue;
                    }
                }
            }

            string logoImg;

            if (isPersonalTmpl)
            {
                logoImg = "http://cdn.teamlab.com/media/newsletters/images/mail_logo.png";
            }
            else
            {
                logoImg = ConfigurationManager.AppSettings["web.logo.mail"];
                if (String.IsNullOrEmpty(logoImg))
                {
                    var logo = message.GetArgument("LetterLogo");
                    if (logo != null && (string)logo.Value != "")
                    {
                        logoImg = (string)logo.Value;
                    }
                    else
                    {
                        logoImg = "http://cdn.teamlab.com/media/newsletters/images/mail_logo.png";
                    }
                }
            }

            var logoText = ConfigurationManager.AppSettings["web.logotext.mail"];

            if (String.IsNullOrEmpty(logoText))
            {
                var llt = message.GetArgument("LetterLogoText");
                if (llt != null && (string)llt.Value != "")
                {
                    logoText = (string)llt.Value;
                }
                else
                {
                    logoText = TenantWhiteLabelSettings.DefaultLogoText;
                }
            }

            var mailWhiteLabelTag      = message.GetArgument("MailWhiteLabelSettings");
            var mailWhiteLabelSettings = mailWhiteLabelTag == null ? null : mailWhiteLabelTag.Value as MailWhiteLabelSettings;

            message.Body = template.Replace("%CONTENT%", output.GetFormattedText())
                           .Replace("%LOGO%", logoImg)
                           .Replace("%LOGOTEXT%", logoText)
                           .Replace("%SITEURL%", mailWhiteLabelSettings == null ? MailWhiteLabelSettings.DefaultMailSiteUrl : mailWhiteLabelSettings.SiteUrl);

            var footer  = message.GetArgument("Footer");
            var partner = message.GetArgument("Partner");

            var footerContent       = string.Empty;
            var footerSocialContent = string.Empty;

            if (partner != null)
            {
                footerContent = partner.Value.ToString();
            }

            if (String.IsNullOrEmpty(footerContent) && footer != null)
            {
                switch ((string)footer.Value)
                {
                case "common":
                    InitCommonFooter(mailWhiteLabelSettings, out footerContent, out footerSocialContent);
                    break;

                case "personal":
                    footerSocialContent = NotifyTemplateResource.FooterSocial;
                    break;

                case "freecloud":
                    footerContent       = NotifyTemplateResource.FooterFreeCloud;
                    footerSocialContent = NotifyTemplateResource.FooterSocial;
                    break;

                case "opensource":
                    footerContent       = NotifyTemplateResource.FooterOpensource;
                    footerSocialContent = NotifyTemplateResource.FooterSocial;
                    break;
                }
            }

            message.Body = message.Body
                           .Replace("%FOOTER%", footerContent)
                           .Replace("%FOOTERSOCIAL%", footerSocialContent);

            var text = "";

            if (ConfigurationManager.AppSettings["core.base-domain"] != "localhost")
            {
                var noUnsubscribeLink = message.GetArgument("noUnsubscribeLink");
                if (noUnsubscribeLink == null || (string)noUnsubscribeLink.Value == "false")
                {
                    var isHosted = ConfigurationManager.AppSettings["core.payment-partners-hosted"];
                    if (String.IsNullOrEmpty(isHosted) || isHosted == "false")
                    {
                        var mail   = message.Recipient.Addresses.FirstOrDefault(r => r.Contains("@"));
                        var domain = ConfigurationManager.AppSettings["web.teamlab-site"];
                        var site   = string.IsNullOrEmpty(domain) ? "http://www.onlyoffice.com" : domain;
                        var link   = site +
                                     string.Format("/Unsubscribe.aspx?id={0}",
                                                   HttpServerUtility.UrlTokenEncode(
                                                       Security.Cryptography.InstanceCrypto.Encrypt(
                                                           Encoding.UTF8.GetBytes(mail.ToLowerInvariant()))));

                        text = string.Format(NotifyTemplateResource.TextForFooterWithUnsubscribe, link);
                    }
                }

                text += string.Format(NotifyTemplateResource.TextForFooter, DateTime.UtcNow.Year, string.Empty);
            }

            message.Body = message.Body.Replace("%TEXTFOOTER%", text);
        }
예제 #24
0
        public void ApplyFormating(NoticeMessage message)
        {
            bool isPromoTmpl = false;
            var  output      = new StringBuilderTextileFormatter();
            var  formatter   = new TextileFormatter(output);

            if (!string.IsNullOrEmpty(message.Subject))
            {
                message.Subject = VelocityArguments.Replace(message.Subject, m => m.Result("${arg}"));
            }

            if (!string.IsNullOrEmpty(message.Body))
            {
                formatter.Format(message.Body);

                var isPromo = message.GetArgument("isPromoLetter");
                if (isPromo != null && (string)isPromo.Value == "true")
                {
                    isPromoTmpl = true;
                }

                var logoImg = "";
                if (isPromoTmpl)
                {
                    logoImg = "http://cdn.teamlab.com/media/newsletters/images/logo.png";
                }
                else
                {
                    logoImg = ConfigurationManager.AppSettings["web.logo.mail"];
                    if (String.IsNullOrEmpty(logoImg))
                    {
                        var logo = message.GetArgument("LetterLogo");
                        if (logo != null && (string)logo.Value != "")
                        {
                            logoImg = (string)logo.Value;
                        }
                        else
                        {
                            logoImg = "http://cdn.teamlab.com/media/newsletters/images/header_08.png";
                        }
                    }
                }


                var template = isPromoTmpl ? Resources.TemplateResource.HtmlMasterPromo : Resources.TemplateResource.HtmlMaster;
                message.Body = template.Replace("%CONTENT%", output.GetFormattedText()).Replace("%LOGO%", logoImg);

                var footer  = message.GetArgument("WithPhoto");
                var partner = message.GetArgument("Partner");
                var res     = String.Empty;

                if (partner != null)
                {
                    res = partner.Value.ToString();
                }


                if (String.IsNullOrEmpty(res) && footer != null)
                {
                    switch ((string)footer.Value)
                    {
                    case "photo":
                        res = Resources.TemplateResource.FooterWithPhoto;
                        break;

                    case "links":
                        res = Resources.TemplateResource.FooterWithLinks;
                        break;

                    case "personal":
                        res = Resources.TemplateResource.FooterPersonal;
                        break;

                    case "freecloud":
                        res = Resources.TemplateResource.FooterFreeCloud;
                        break;

                    default:
                        res = String.Empty;
                        break;
                    }
                }
                message.Body = message.Body.Replace("%FOOTER%", res);


                var text = "";

                var noUnsubscribeLink = message.GetArgument("noUnsubscribeLink");
                if (noUnsubscribeLink == null || (string)noUnsubscribeLink.Value == "false")
                {
                    var isHosted = ConfigurationManager.AppSettings["core.payment-partners-hosted"];
                    if (String.IsNullOrEmpty(isHosted) || isHosted == "false")
                    {
                        var mail   = message.Recipient.Addresses.FirstOrDefault(r => r.Contains("@"));
                        var domain = ConfigurationManager.AppSettings["web.teamlab-site"];
                        var site   = string.IsNullOrEmpty(domain) ? "http://www.onlyoffice.com" : domain;
                        var link   = site + string.Format("/Unsubscribe.aspx?id={0}", HttpServerUtility.UrlTokenEncode(Security.Cryptography.InstanceCrypto.Encrypt(Encoding.UTF8.GetBytes(mail.ToLowerInvariant()))));

                        text = string.Format(Resources.TemplateResource.TextForFooterWithUnsubscribe, link);
                    }
                }

                text        += string.Format(Resources.TemplateResource.TextForFooter, DateTime.UtcNow.Year, string.Empty);
                message.Body = message.Body.Replace("%TEXTFOOTER%", text);
            }
        }
예제 #25
0
        protected override void ExecuteTask()
        {
            // ensure base directory is set, even if fileset was not initialized from XML
            if (Inputs.BaseDirectory == null)
            {
                Inputs.BaseDirectory = new DirectoryInfo(Project.BaseDirectory);
            }
            // get the complete path of the base directory of the fileset, ie, c:\work\nant\src
            DirectoryInfo srcBaseInfo = Inputs.BaseDirectory;

            #region Configure TextileFormatter
            StringBuilderOutputter outputter = new StringBuilderOutputter();
            TextileFormatter       tf        = new TextileFormatter(outputter);
            tf.FormatFootNotes = this.FormatFootNotes;
            tf.FormatImages    = this.FormatImages;
            tf.FormatLinks     = this.FormatLinks;
            tf.FormatLists     = this.FormatLists;
            tf.FormatTables    = this.FormatTables;
            tf.HeaderOffset    = this.HeaderOffset;
            tf.Rel             = this.LinkRel;
            #endregion

            int numConvertedFiles = 0;
            foreach (string pathname in Inputs.FileNames)
            {
                FileInfo srcInfo = new FileInfo(pathname);
                if (srcInfo.Exists)
                {
                    #region Compute destination path
                    // Gets the relative path and file info from the full source filepath
                    // pathname = C:\f2\f3\file1, srcBaseInfo=C:\f2, then
                    // dstRelFilePath=f3\file1
                    string dstRelFilePath = "";
                    if (srcInfo.FullName.IndexOf(srcBaseInfo.FullName, 0) != -1)
                    {
                        dstRelFilePath = srcInfo.FullName.Substring(srcBaseInfo.FullName.Length);
                    }
                    else
                    {
                        dstRelFilePath = srcInfo.Name;
                    }

                    if (dstRelFilePath[0] == Path.DirectorySeparatorChar)
                    {
                        dstRelFilePath = dstRelFilePath.Substring(1);
                    }
                    #endregion

                    // The full filepath of the destination
                    string dstFilePath = Path.Combine(ToDirectory.FullName, dstRelFilePath);

                    string parentFolder = Path.GetDirectoryName(dstFilePath);
                    if (!Directory.Exists(parentFolder))
                    {
                        Directory.CreateDirectory(parentFolder);
                    }

                    #region Read, format and write
                    string inputTextile;

                    Log(Level.Debug, "Reading input file '{0}'", srcInfo.FullName);
                    using (StreamReader sr = new StreamReader(srcInfo.FullName))
                    {
                        inputTextile = sr.ReadToEnd();
                    }

                    Log(Level.Verbose, "Converting textile from file '{0}' to an HTML string...", srcInfo.FullName);
                    tf.Format(inputTextile);
                    string outputHtml = outputter.GetFormattedText();

                    // TODO: make output extension configurable
                    string outputPath = Path.ChangeExtension(dstFilePath, ".html");
                    // TODO: Add a switch to optionally hide (or at least make it verbose) the following log statement
                    Log(Level.Info, "Generating {0}...", outputPath);
                    using (StreamWriter sw = new StreamWriter(outputPath))
                    {
                        sw.Write(outputHtml);
                    }
                    Log(Level.Verbose, "Generated {0}.", outputPath);
                    #endregion
                    numConvertedFiles++;
                }
                else
                {
                    throw new BuildException(string.Format(CultureInfo.InvariantCulture,
                                                           "Could not find file '{0}' to convert with Textile.", srcInfo.FullName),
                                             Location);
                }
            }
            Log(Level.Verbose, "Converted {0} files.", numConvertedFiles);
        }