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
+