diff --git a/Ficdown.Console/Program.cs b/Ficdown.Console/Program.cs index 37158c5..c8c035b 100644 --- a/Ficdown.Console/Program.cs +++ b/Ficdown.Console/Program.cs @@ -8,7 +8,7 @@ internal class Program { - private static void Main(string[] args) + private static int Main(string[] args) { string infile = null; string output = null; @@ -23,6 +23,7 @@ if (args[0] == "/?" || args[0] == "/help" || args[0] == "-help" || args[0] == "--help") { ShowHelp(); + return 0; } } else if (args.Length > 1) @@ -55,23 +56,24 @@ break; default: Console.WriteLine(@"Unknown option: {0}", args[i]); - return; + return 1; } } } else { ShowHelp(); + return 0; } - if (string.IsNullOrWhiteSpace(format)) + if (string.IsNullOrWhiteSpace(format) || string.IsNullOrWhiteSpace(infile)) { ShowHelp(); - return; + return 1; } - if (string.IsNullOrWhiteSpace(infile) || !File.Exists(infile)) + if (!File.Exists(infile)) { Console.WriteLine(@"Source file {0} not found.", infile); - return; + return 2; } if (string.IsNullOrWhiteSpace(output)) if (format == "html") @@ -82,14 +84,14 @@ if (!string.IsNullOrWhiteSpace(output) && (Directory.Exists(output) || File.Exists(output))) { Console.WriteLine(@"Specified output {0} already exists.", output); - return; + return 2; } if (!string.IsNullOrWhiteSpace(tempdir)) { if (!Directory.Exists(tempdir)) { Console.WriteLine(@"Template directory {0} does not exist.", tempdir); - return; + return 2; } if (!File.Exists(Path.Combine(tempdir, "index.html")) || !File.Exists(Path.Combine(tempdir, "scene.html")) || @@ -103,7 +105,7 @@ if (!string.IsNullOrWhiteSpace(images) && !Directory.Exists(images)) { Console.WriteLine(@"Images directory {0} does not exist.", images); - return; + return 2; } var parser = new FicdownParser(); @@ -124,13 +126,13 @@ if (string.IsNullOrWhiteSpace(author)) { Console.WriteLine(@"Epub format requires the --author argument."); - return; + return 1; } rend = new EpubRenderer(author); break; default: ShowHelp(); - return; + return 1; } if (!string.IsNullOrWhiteSpace(tempdir)) @@ -147,6 +149,7 @@ rend.Render(story, output, debug); Console.WriteLine(@"Done."); + return 0; } diff --git a/Ficdown.Parser.Tests/UtilityTests.cs b/Ficdown.Parser.Tests/UtilityTests.cs index 32a8076..51d3b81 100644 --- a/Ficdown.Parser.Tests/UtilityTests.cs +++ b/Ficdown.Parser.Tests/UtilityTests.cs @@ -6,6 +6,11 @@ public class UtilityTests { + private Utilities Utilities + { + get { return Utilities.GetInstance("none", 0); } + } + [Fact] public void FullAnchorMatches() { diff --git a/Ficdown.Parser/Ficdown.Parser.csproj b/Ficdown.Parser/Ficdown.Parser.csproj index 3290170..7a7a1ca 100644 --- a/Ficdown.Parser/Ficdown.Parser.csproj +++ b/Ficdown.Parser/Ficdown.Parser.csproj @@ -1,110 +1,112 @@ - - - - - Debug - AnyCPU - {780F652D-7541-4171-BB89-2D263D3961DC} - Library - Properties - Ficdown.Parser - Ficdown.Parser - v4.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\Epub4Net.1.2.0\lib\net40\Epub4Net.dll - - - ..\packages\DotNetZip.1.9.1.8\lib\net20\Ionic.Zip.dll - - - ..\packages\MarkdownSharp.1.13.0.0\lib\35\MarkdownSharp.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - Template.resx - - - - - - - - - - - - - - - ResXFileCodeGenerator - Template.Designer.cs - - - + + + + Debug + AnyCPU + {780F652D-7541-4171-BB89-2D263D3961DC} + Library + Properties + Ficdown.Parser + Ficdown.Parser + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Epub4Net.1.2.0\lib\net40\Epub4Net.dll + + + ..\packages\DotNetZip.1.9.1.8\lib\net20\Ionic.Zip.dll + + + ..\packages\MarkdownSharp.1.13.0.0\lib\35\MarkdownSharp.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Template.resx + + + + + + + + + + + + + + + + + + ResXFileCodeGenerator + Template.Designer.cs + + + - \ No newline at end of file + --> + diff --git a/Ficdown.Parser/Model/Parser/Block.cs b/Ficdown.Parser/Model/Parser/Block.cs index 36e4c63..2cd1f03 100644 --- a/Ficdown.Parser/Model/Parser/Block.cs +++ b/Ficdown.Parser/Model/Parser/Block.cs @@ -6,6 +6,7 @@ { public BlockType Type { get; set; } public string Name { get; set; } - public IList Lines { get; set; } + public IList Lines { get; set; } + public int LineNumber { get; set; } } } diff --git a/Ficdown.Parser/Model/Parser/FicdownException.cs b/Ficdown.Parser/Model/Parser/FicdownException.cs new file mode 100644 index 0000000..8e20729 --- /dev/null +++ b/Ficdown.Parser/Model/Parser/FicdownException.cs @@ -0,0 +1,34 @@ +namespace Ficdown.Parser.Model.Parser +{ + using System; + + public class FicdownException : Exception + { + private string _blockName; + private int? _lineNumber; + private string _message; + + public FicdownException(string blockName, int? lineNumber, string message) : base(message) + { + _blockName = blockName; + _lineNumber = lineNumber; + _message = message; + } + + public FicdownException(string message) : base(message) + { + _message = message; + } + + public override string ToString() + { + return !string.IsNullOrEmpty(_blockName) + ? string.Format("Error in block \"{0}\" (Line {1}): {2}", + _blockName, + _lineNumber.HasValue + ? _lineNumber.ToString() + : "unknown", _message) + : string.Format("Error: {0}", _message); + } + } +} diff --git a/Ficdown.Parser/Model/Parser/Line.cs b/Ficdown.Parser/Model/Parser/Line.cs new file mode 100644 index 0000000..8970b69 --- /dev/null +++ b/Ficdown.Parser/Model/Parser/Line.cs @@ -0,0 +1,8 @@ +namespace Ficdown.Parser.Model.Parser +{ + public class Line + { + public int Number { get; set; } + public string Text { get; set; } + } +} diff --git a/Ficdown.Parser/Model/Story/Action.cs b/Ficdown.Parser/Model/Story/Action.cs index 6bbd788..04a8136 100644 --- a/Ficdown.Parser/Model/Story/Action.cs +++ b/Ficdown.Parser/Model/Story/Action.cs @@ -5,5 +5,6 @@ public int Id { get; set; } public string Toggle { get; set; } public string Description { get; set; } + public int LineNumber { get; set; } } } diff --git a/Ficdown.Parser/Model/Story/Scene.cs b/Ficdown.Parser/Model/Story/Scene.cs index dd5f8b1..14f02b7 100644 --- a/Ficdown.Parser/Model/Story/Scene.cs +++ b/Ficdown.Parser/Model/Story/Scene.cs @@ -9,5 +9,6 @@ public string Key { get; set; } public string Description { get; set; } public IDictionary Conditions { get; set; } + public int LineNumber { get; set; } } -} \ No newline at end of file +} diff --git a/Ficdown.Parser/Parser/BlockHandler.cs b/Ficdown.Parser/Parser/BlockHandler.cs index 693dec0..9c14dee 100644 --- a/Ficdown.Parser/Parser/BlockHandler.cs +++ b/Ficdown.Parser/Parser/BlockHandler.cs @@ -14,6 +14,7 @@ { var blocks = new List(); Block currentBlock = null; + var lineNum = 1; foreach (var line in lines) { var match = Regex.Match(line, @"^(?#{1,3})\s+(?[^#].*)$"); @@ -24,12 +25,17 @@ { Type = (BlockType) match.Groups["level"].Length, Name = match.Groups["name"].Value, - Lines = new List() + Lines = new List(), + LineNumber = lineNum++ }; } else { - if (currentBlock != null) currentBlock.Lines.Add(line); + if (currentBlock != null) currentBlock.Lines.Add(new Line + { + Number = lineNum++, + Text = line + }); } } if (currentBlock != null) blocks.Add(currentBlock); @@ -40,14 +46,13 @@ { // get the story var storyBlock = blocks.SingleOrDefault(b => b.Type == BlockType.Story); - if(storyBlock == null) throw new FormatException("No story block found"); + if(storyBlock == null) throw new FicdownException("No story block found"); - var storyAnchor = Utilities.ParseAnchor(storyBlock.Name); + var storyAnchor = Utilities.GetInstance(storyBlock.Name, storyBlock.LineNumber).ParseAnchor(storyBlock.Name); if (storyAnchor.Href.Target == null || storyAnchor.Href.Conditions != null || storyAnchor.Href.Toggles != null) - throw new FormatException(string.Format("Story href should only have target: {0}", - storyAnchor.Original)); + throw new FicdownException(storyBlock.Name, storyBlock.LineNumber, "Story href should only have target"); var story = new Story { @@ -69,7 +74,7 @@ blocks.Where(b => b.Type == BlockType.Action).Select(b => BlockToAction(b, aid++)).ToDictionary(a => a.Toggle, a => a); if (!story.Scenes.ContainsKey(storyAnchor.Href.Target)) - throw new FormatException(string.Format("Story targets non-existent scene: {0}", storyAnchor.Href.Target)); + throw new FicdownException(storyBlock.Name, storyBlock.LineNumber, string.Format("Story targets non-existent scene: {0}", storyAnchor.Href.Target)); story.FirstScene = storyAnchor.Href.Target; return story; @@ -81,22 +86,23 @@ var scene = new Scene { Id = id, - Description = string.Join("\n", block.Lines).Trim() + LineNumber = block.LineNumber, + Description = string.Join("\n", block.Lines.Select(l => l.Text)).Trim() }; try { - var sceneName = Utilities.ParseAnchor(block.Name); + var sceneName = Utilities.GetInstance(block.Name, block.LineNumber).ParseAnchor(block.Name); scene.Name = sceneName.Title != null ? sceneName.Title.Trim() : sceneName.Text.Trim(); - scene.Key = Utilities.NormalizeString(sceneName.Text); + scene.Key = Utilities.GetInstance(block.Name, block.LineNumber).NormalizeString(sceneName.Text); if(sceneName.Href.Target != null || sceneName.Href.Toggles != null) - throw new FormatException(string.Format("Scene href should only have conditions: {0}", block.Name)); + throw new FicdownException(block.Name, block.LineNumber, string.Format("Scene href should only have conditions: {0}", block.Name)); scene.Conditions = sceneName.Href.Conditions; } - catch(FormatException) + catch(FicdownException) { scene.Name = block.Name.Trim(); - scene.Key = Utilities.NormalizeString(block.Name); + scene.Key = Utilities.GetInstance(block.Name, block.LineNumber).NormalizeString(block.Name); } return scene; @@ -107,9 +113,10 @@ return new Action { Id = id, - Toggle = Utilities.NormalizeString(block.Name), - Description = string.Join("\n", block.Lines).Trim() + Toggle = Utilities.GetInstance(block.Name, block.LineNumber).NormalizeString(block.Name), + Description = string.Join("\n", block.Lines.Select(l => l.Text)).Trim(), + LineNumber = block.LineNumber }; } } -} \ No newline at end of file +} diff --git a/Ficdown.Parser/Parser/ParserExtensions.cs b/Ficdown.Parser/Parser/ParserExtensions.cs new file mode 100644 index 0000000..7957dbc --- /dev/null +++ b/Ficdown.Parser/Parser/ParserExtensions.cs @@ -0,0 +1,24 @@ +namespace Ficdown.Parser.Parser +{ + using System; + using System.Linq; + using System.Collections.Generic; + + public static class ParserExtensions + { + public static string ToHrefString(this IDictionary values, string separator) + { + return values != null + ? string.Join(separator, + values.Where(v => !v.Key.StartsWith(">")) + .Select(v => string.Format("{0}{1}", v.Value ? null : "!", v.Key)) + .ToArray()) + : null; + } + + public static string ToHrefString(this IEnumerable values, string separator) + { + return values != null ? string.Join(separator, values.ToArray()) : null; + } + } +} diff --git a/Ficdown.Parser/Parser/StateResolver.cs b/Ficdown.Parser/Parser/StateResolver.cs index a270f55..6aeee92 100644 --- a/Ficdown.Parser/Parser/StateResolver.cs +++ b/Ficdown.Parser/Parser/StateResolver.cs @@ -40,13 +40,13 @@ }; } - private string ResolveAnchor(Anchor anchor, IDictionary playerState, string targetHash) + private string ResolveAnchor(string blockName, int lineNumber, Anchor anchor, IDictionary playerState, string targetHash) { var text = anchor.Text; if (anchor.Href.Conditions != null) { - var satisfied = Utilities.ConditionsMet(playerState, anchor.Href.Conditions); - var alts = Utilities.ParseConditionalText(text); + var satisfied = Utilities.GetInstance(blockName, lineNumber).ConditionsMet(playerState, anchor.Href.Conditions); + var alts = Utilities.GetInstance(blockName, lineNumber).ParseConditionalText(text); var replace = alts[satisfied]; text = RegexLib.EscapeChar.Replace(replace, string.Empty); } @@ -66,7 +66,7 @@ if (page.State.ActionsToShow[i]) { var actionTuple = _story.Actions.Single(a => a.Value.Id == i + 1); - var actionAnchors = Utilities.ParseAnchors(actionTuple.Value.Description); + var actionAnchors = Utilities.GetInstance(page.Scene.Name, page.Scene.LineNumber).ParseAnchors(actionTuple.Value.Description); var anchorDict = GetStateDictionary(page); if ( actionAnchors.Any( @@ -80,19 +80,19 @@ resolved.AppendFormat("{0}\n\n", actionAnchors.Aggregate(actionTuple.Value.Description, (current, anchor) => current.Replace(anchor.Original, - ResolveAnchor(anchor, anchorDict, + ResolveAnchor(page.Scene.Name, page.Scene.LineNumber, anchor, anchorDict, page.Links.ContainsKey(anchor.Original) ? page.Links[anchor.Original] : null)))); } } - var anchors = Utilities.ParseAnchors(page.Scene.Description); + var anchors = Utilities.GetInstance(page.Scene.Name, page.Scene.LineNumber).ParseAnchors(page.Scene.Description); var stateDict = GetStateDictionary(page); var text = RegexLib.EmptyListItem.Replace( anchors.Aggregate(page.Scene.Description, (current, anchor) => current.Replace(anchor.Original, - ResolveAnchor(anchor, stateDict, + ResolveAnchor(page.Scene.Name, page.Scene.LineNumber, anchor, stateDict, page.Links.ContainsKey(anchor.Original) ? page.Links[anchor.Original] : null))), string.Empty); var seen = page.State.ScenesSeen[page.Scene.Id - 1]; @@ -135,4 +135,4 @@ return builder.ToString(); } } -} \ No newline at end of file +} diff --git a/Ficdown.Parser/Parser/Utilities.cs b/Ficdown.Parser/Parser/Utilities.cs index ed83b6c..8362bfd 100644 --- a/Ficdown.Parser/Parser/Utilities.cs +++ b/Ficdown.Parser/Parser/Utilities.cs @@ -7,14 +7,34 @@ namespace Ficdown.Parser.Parser using System.Text.RegularExpressions; using Model.Parser; - internal static class Utilities + internal class Utilities { - public static string NormalizeString(string raw) + public static Utilities GetInstance(string blockName, int lineNumber) + { + return new Utilities + { + _blockName = blockName, + _lineNumber = lineNumber + }; + } + + public static Utilities GetInstance(string blockName) + { + return new Utilities + { + _blockName = blockName + }; + } + + protected string _blockName; + protected int? _lineNumber; + + public string NormalizeString(string raw) { return Regex.Replace(Regex.Replace(raw.ToLower(), @"^\W+|\W+$", string.Empty), @"\W+", "-"); } - private static Href ParseHref(string href) + private Href ParseHref(string href) { var match = RegexLib.Href.Match(href); if (match.Success) @@ -37,23 +57,23 @@ namespace Ficdown.Parser.Parser : null }; } - throw new FormatException(string.Format("Invalid href: {0}", href)); + throw new FicdownException(_blockName, _lineNumber, string.Format("Invalid href: {0}", href)); } - public static Anchor ParseAnchor(string anchorText) + public Anchor ParseAnchor(string anchorText) { var match = RegexLib.Anchors.Match(anchorText); - if (!match.Success) throw new FormatException(string.Format("Invalid anchor: {0}", anchorText)); + if (!match.Success) throw new FicdownException(_blockName, _lineNumber, string.Format("Invalid anchor: {0}", anchorText)); return MatchToAnchor(match); } - public static IList ParseAnchors(string text) + public IList ParseAnchors(string text) { var matches = RegexLib.Anchors.Matches(text); return matches.Cast().Select(MatchToAnchor).ToList(); } - private static Anchor MatchToAnchor(Match match) + private Anchor MatchToAnchor(Match match) { var astr = match.Groups["anchor"].Value; var txstr = match.Groups["text"].Value; @@ -73,10 +93,10 @@ namespace Ficdown.Parser.Parser }; } - public static IDictionary ParseConditionalText(string text) + public IDictionary ParseConditionalText(string text) { var match = RegexLib.ConditionalText.Match(text); - if (!match.Success) throw new FormatException(string.Format(@"Invalid conditional text: {0}", text)); + if (!match.Success) throw new FicdownException(_blockName, _lineNumber, string.Format(@"Invalid conditional text: {0}", text)); return new Dictionary { {true, match.Groups["true"].Value}, @@ -84,22 +104,7 @@ namespace Ficdown.Parser.Parser }; } - public static string ToHrefString(this IDictionary values, string separator) - { - return values != null - ? string.Join(separator, - values.Where(v => !v.Key.StartsWith(">")) - .Select(v => string.Format("{0}{1}", v.Value ? null : "!", v.Key)) - .ToArray()) - : null; - } - - public static string ToHrefString(this IEnumerable values, string separator) - { - return values != null ? string.Join(separator, values.ToArray()) : null; - } - - public static bool ConditionsMet(IDictionary playerState, IDictionary conditions) + public bool ConditionsMet(IDictionary playerState, IDictionary conditions) { return conditions.All( diff --git a/Ficdown.Parser/Player/GameTraverser.cs b/Ficdown.Parser/Player/GameTraverser.cs index f13d84d..cdd23ac 100644 --- a/Ficdown.Parser/Player/GameTraverser.cs +++ b/Ficdown.Parser/Player/GameTraverser.cs @@ -99,9 +99,9 @@ { var states = new HashSet(); - var anchors = Utilities.ParseAnchors(currentState.Page.Scene.Description).ToList(); + var anchors = Utilities.GetInstance(currentState.Page.Scene.Name, currentState.Page.Scene.LineNumber).ParseAnchors(currentState.Page.Scene.Description).ToList(); foreach (var action in GetActionsForPage(currentState.Page)) - anchors.AddRange(Utilities.ParseAnchors(action.Description)); + anchors.AddRange(Utilities.GetInstance(action.Toggle, action.LineNumber).ParseAnchors(action.Description)); var conditionals = anchors.SelectMany( a => a.Href.Conditions != null ? a.Href.Conditions.Select(c => c.Key) : new string[] {}) @@ -126,8 +126,8 @@ // don't follow links that would be hidden if (anchor.Href.Conditions != null && string.IsNullOrEmpty( - Utilities.ParseConditionalText(anchor.Text)[ - Utilities.ConditionsMet(StateResolver.GetStateDictionary(currentState.Page), + Utilities.GetInstance(currentState.Page.Scene.Name, currentState.Page.Scene.LineNumber).ParseConditionalText(anchor.Text)[ + Utilities.GetInstance(currentState.Page.Scene.Name, currentState.Page.Scene.LineNumber).ConditionsMet(StateResolver.GetStateDictionary(currentState.Page), anchor.Href.Conditions)])) continue; var newState = _manager.ResolveNewState(anchor, currentState.Page); @@ -144,4 +144,4 @@ } } } -} \ No newline at end of file +} diff --git a/Ficdown.Parser/Player/StateManager.cs b/Ficdown.Parser/Player/StateManager.cs index ef60404..6a7fcf5 100644 --- a/Ficdown.Parser/Player/StateManager.cs +++ b/Ficdown.Parser/Player/StateManager.cs @@ -21,14 +21,14 @@ _story = story; var allScenes = _story.Scenes.SelectMany(s => s.Value); _sceneCount = allScenes.Max(s => s.Id); - _actionCount = _story.Actions.Max(a => a.Value.Id); + _actionCount = _story.Actions.Count > 0 ? _story.Actions.Max(a => a.Value.Id) : 0; _stateMatrix = new Dictionary(); var state = 0; foreach ( var toggle in allScenes.SelectMany( sc => - Utilities.ParseAnchors(sc.Description) + Utilities.GetInstance(sc.Name, sc.LineNumber).ParseAnchors(sc.Description) .SelectMany( a => a.Href.Toggles != null @@ -83,7 +83,7 @@ if(actionFirstToggles == null) actionFirstToggles = new List(); newState.State.ActionsToShow[_story.Actions[toggle].Id - 1] = true; if ( - Utilities.ParseAnchors(_story.Actions[toggle].Description) + Utilities.GetInstance(_story.Actions[toggle].Toggle, _story.Actions[toggle].LineNumber).ParseAnchors(_story.Actions[toggle].Description) .Any(a => a.Href.Conditions != null && a.Href.Conditions.ContainsKey(toggle))) actionFirstToggles.Add(!current.State.PlayerState[_stateMatrix[toggle]]); } @@ -93,7 +93,7 @@ newState.State.ActionFirstToggles = actionFirstToggles != null ? new BitArray(actionFirstToggles.ToArray()) : null; - newState.Scene = GetScene(target, newState.State.PlayerState); + newState.Scene = GetScene(current.Scene.Name, current.Scene.LineNumber, target, newState.State.PlayerState); return newState; } @@ -138,10 +138,10 @@ return GetUniqueHash(compressed, page.Scene.Key); } - private Scene GetScene(string target, BitArray playerState) + private Scene GetScene(string blockName, int lineNumber, string target, BitArray playerState) { if (!_story.Scenes.ContainsKey(target)) - throw new FormatException(string.Format("Encountered link to non-existant scene: {0}", target)); + throw new FicdownException(blockName, lineNumber, string.Format("Encountered link to non-existent scene: {0}", target)); Scene newScene = null; foreach (var scene in _story.Scenes[target]) @@ -154,13 +154,17 @@ } } if (newScene == null) - throw new FormatException(string.Format("Scene {0} reached with unmatched player state", target)); + throw new FicdownException(blockName, lineNumber, string.Format("Scene {0} reached with unmatched player state", target)); return newScene; } private bool ConditionsMatch(Scene scene, BitArray playerState) { if (scene.Conditions == null) return true; + scene.Conditions.ToList().ForEach(c => + { + if(!_stateMatrix.ContainsKey(c.Key)) throw new FicdownException(scene.Name, scene.LineNumber, string.Format("Reference to non-existent state: {0}", c.Key)); + }); return scene.Conditions.All(c => playerState[_stateMatrix[c.Key]] == c.Value); } diff --git a/Ficdown.Parser/Render/EpubRenderer.cs b/Ficdown.Parser/Render/EpubRenderer.cs index 458061a..a7eae5d 100644 --- a/Ficdown.Parser/Render/EpubRenderer.cs +++ b/Ficdown.Parser/Render/EpubRenderer.cs @@ -1,10 +1,91 @@ namespace Ficdown.Parser.Render { using System; + using System.Text; using System.Collections.Generic; using System.IO; using System.Linq; using Epub4Net; + using Ionic.Zip; + using Ionic.Zlib; + + #region fix for bug in epub4net + // https://bitbucket.org/dalager/epub4net/issues/2/windows-path-separator-hard-coded-in + + public class FixedFileSystemManager : IFileSystemManager + { + private FileSystemManager _fsm; + + public FixedFileSystemManager() + { + _fsm = new FileSystemManager(Guid.NewGuid().ToString()); + } + + public void SetupOutputDir() + { + _fsm.SetupOutputDir(); + } + + public string ContentDir + { + get { return _fsm.ContentDir; } + set { _fsm.ContentDir = value; } + } + + public string BuildDirectory + { + get { return _fsm.BuildDirectory; } + set { _fsm.BuildDirectory = value; } + } + + public void CreateTocFile(Epub epub) + { + _fsm.CreateTocFile(epub); + } + + public void CreateContentOpfFile(Epub epub) + { + _fsm.CreateContentOpfFile(epub); + } + + public void CopyChapterFilesToContentFolder(Epub epub) + { + _fsm.CopyChapterFilesToContentFolder(epub); + } + + public string ZipEpub(Epub epub) + { + var epubFilename = epub.Title + ".epub"; + if(File.Exists(epubFilename)) File.Delete(epubFilename); + using(var zip = new ZipFile(epubFilename, Encoding.UTF8)) + { + zip.EmitTimesInWindowsFormatWhenSaving = false; + zip.CompressionLevel = CompressionLevel.None; + zip.AddFile(Path.Combine(_fsm.BuildDirectory, "mimetype"), "\\"); + zip.Save(); + File.Delete(Path.Combine(_fsm.BuildDirectory, "mimetype")); + zip.AddDirectory(_fsm.BuildDirectory); + zip.Save(); + } + return epubFilename; + } + + public void CopyResourceFilesToContentFolder(Epub epub) + { + _fsm.CopyResourceFilesToContentFolder(epub); + } + + public void ValidatePathsExists(IEnumerable fileList) + { + _fsm.ValidatePathsExists(fileList); + } + + public void DeleteBuildDir() + { + _fsm.DeleteBuildDir(); + } + } + #endregion public class EpubRenderer : HtmlRenderer { @@ -46,7 +127,7 @@ } } - var builder = new EPubBuilder(); + var builder = new EPubBuilder(new FixedFileSystemManager(), Guid.NewGuid().ToString()); var built = builder.Build(epub); File.Move(built, outPath); diff --git a/Ficdown.Parser/Render/HtmlRenderer.cs b/Ficdown.Parser/Render/HtmlRenderer.cs index 9fdd67d..9ad6160 100644 --- a/Ficdown.Parser/Render/HtmlRenderer.cs +++ b/Ficdown.Parser/Render/HtmlRenderer.cs @@ -51,7 +51,7 @@ File.WriteAllText(Path.Combine(outPath, "styles.css"), StylesTemplate ?? Template.Styles); var content = page.Content; - foreach (var anchor in Utilities.ParseAnchors(page.Content)) + foreach (var anchor in Utilities.GetInstance(page.Name).ParseAnchors(page.Content)) { var newAnchor = string.Format("[{0}]({1}.html)", anchor.Text, anchor.Href.Target); content = content.Replace(anchor.Original, newAnchor); diff --git a/Ficdown.Parser/packages.config b/Ficdown.Parser/packages.config index 764fdfe..63e5c17 100644 --- a/Ficdown.Parser/packages.config +++ b/Ficdown.Parser/packages.config @@ -3,4 +3,4 @@ - \ No newline at end of file +