Example #1
0
        /// <summary>
        /// Gets XHTML content for a file.
        /// </summary>
        /// <param name="ebook"></param>
        /// <param name="navPoint"></param>
        /// <returns></returns>
        public static async Task <string> GetContentsAsync(this EBook ebook, ManifestItem manifestItem, bool embedImages = true)
        {
            var fullContentPath = Path.GetFullPath(ebook._rootFolder.Path.EnsureEnd("\\") + ebook.ContentLocation);
            var tocPath         = Path.GetFullPath(Path.GetDirectoryName(fullContentPath).EnsureEnd("\\") + ebook.Manifest["ncx"].ContentLocation);
            var filePath        = Path.GetFullPath(Path.GetDirectoryName(tocPath).EnsureEnd("\\") + manifestItem.ContentLocation);
            var contentFile     = await ebook._rootFolder.GetFileFromPathAsync(filePath.Substring(ebook._rootFolder.Path.Length));

            var contents = await FileIO.ReadTextAsync(contentFile);

            contents = WebUtility.HtmlDecode(contents);

            if (embedImages)
            {
                var contentPath  = Path.Combine(ebook._rootFolder.Path, manifestItem.ContentLocation);
                var imageMatches = new Regex(@"<img.*/>", RegexOptions.IgnoreCase).Matches(contents).OfType <Match>().ToList();

                foreach (var match in imageMatches)
                {
                    var imageNode   = HtmlNode.CreateNode(match.Value);
                    var imageSource = imageNode.Attributes["src"].Value;

                    var imgPath   = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(contentPath), imageSource));
                    var imageFile = await ebook._rootFolder.GetFileFromPathAsync(imgPath.Substring(ebook._rootFolder.Path.Length));

                    var image = await FileIO.ReadBufferAsync(imageFile);

                    var base64 = Convert.ToBase64String(image.ToArray());
                    imageNode.Attributes["src"].Value = $"data:image/{imageFile.FileType};base64,{base64}";
                    contents = contents.Replace(match.Value, imageNode.OuterHtml);
                }
            }

            return(contents);
        }
Example #2
0
        internal static async Task <Spine> GetSpineAsync(this EBook ebook)
        {
            var spine = new Spine();

            IEnumerable <XElement> GetSpineItemNodes(string xml)
            {
                var doc  = XDocument.Parse(xml);
                var ns   = doc.Root.GetDefaultNamespace();
                var node = doc.Element(ns + "package").Element(ns + "spine");

                spine.Toc = node.Attribute("toc").Value;
                var itemNodes = node.Elements(ns + "itemref");

                return(itemNodes);
            }

            var contentFile = await ebook._rootFolder.GetFileFromPathAsync(ebook.ContentLocation);

            var contentXml = await FileIO.ReadTextAsync(contentFile);

            foreach (var itemNode in GetSpineItemNodes(contentXml).ToList())
            {
                spine.Add(new SpineItem
                {
                    IdRef = itemNode.Attribute("idref").Value
                });
            }

            return(spine);
        }
Example #3
0
        /// <summary>
        /// Verifies that the EBook has a valid mimetype file.
        /// </summary>
        /// <param name="ebook">The EBook to be checked.</param>
        /// <returns>A bool indicating whether or not the miemtype is valid.</returns>
        internal static async Task <bool> VerifyMimetypeAsync(this EBook ebook)
        {
            bool VerifyMimetypeString(string value) =>
            value == "application/epub+zip";

            if (ebook._rootFolder == null)                                      // Make sure a root folder was specified.
            {
                return(false);
            }

            var mimetypeFile = await ebook._rootFolder.GetItemAsync("mimetype");

            if (mimetypeFile == null)                                           // Make sure file exists.
            {
                return(false);
            }

            var fileContents = await FileIO.ReadTextAsync(mimetypeFile as StorageFile);

            if (!VerifyMimetypeString(fileContents))                         // Make sure file contents are correct.
            {
                return(false);
            }

            return(true);
        }
Example #4
0
        public static Metadata GetMetadata(this EBook eBook)
        {
            var contentXml   = File.ReadAllText(eBook.ContentLocation);
            var doc          = XDocument.Parse(contentXml);
            var ns           = doc.Root.GetDefaultNamespace();
            var metadataNode = doc.Element(ns + "package").Element(ns + "metadata");
            var dcNamespace  = metadataNode.GetNamespaceOfPrefix("dc");

            string GetValue(string node)
            {
                return(metadataNode.Element(dcNamespace + node)?.Value);
            }

            var metadata = new Metadata
            {
                AlternativeTitle = GetValue("alternative"),
                Audience         = GetValue("audience"),
                Available        = GetValue("available") == null ? default(DateTime) : DateTime.Parse(GetValue("available")),
                Contributor      = GetValue("contributor"),
                Created          = GetValue("created") == null ? default(DateTime) : DateTime.Parse(GetValue("created")),
                Creator          = GetValue("creator"),
                Description      = GetValue("description"),
                Language         = GetValue("language"),
                Title            = GetValue("title")
            };

            foreach (var node in metadataNode.Elements(dcNamespace + "date").ToList())
            {
                // TODO: Parse dates. May be a parseable date or just a year.
            }

            return(metadata);
        }
Example #5
0
        /// <summary>
        /// Gets a list of ManifestItems for an EBook.
        /// </summary>
        /// <param name="ebook"></param>
        /// <returns></returns>
        internal static async Task <IEnumerable <ManifestItem> > GetManifestAsync(this EBook ebook)
        {
            var items = new List <ManifestItem>();

            IEnumerable <XElement> GetManifestItemNodes(string xml)
            {
                var doc       = XDocument.Parse(xml);
                var ns        = doc.Root.GetDefaultNamespace();
                var node      = doc.Element(ns + "package").Element(ns + "manifest");
                var itemNodes = node.Elements(ns + "item");

                return(itemNodes);
            }

            var contentFile = await ebook._rootFolder.GetFileFromPathAsync(ebook.ContentLocation);

            var contentXml = await FileIO.ReadTextAsync(contentFile);

            foreach (var itemNode in GetManifestItemNodes(contentXml).ToList())
            {
                items.Add(new ManifestItem
                {
                    ContentLocation = itemNode.Attribute("href").Value,
                    Id        = itemNode.Attribute("id").Value,
                    MediaType = itemNode.Attribute("media-type").Value
                });
            }

            return(items);
        }
Example #6
0
        public static string GetCoverLocation(this EBook eBook)
        {
            if (!eBook.Manifest.ContainsKey("cover"))
            {
                return(null);
            }

            var relativeLocation = eBook.Manifest["cover"].ContentLocation;
            var coverLocation    = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(eBook.ContentLocation), relativeLocation));

            return(coverLocation);
        }
Example #7
0
        /// <summary>
        /// Gets the table of contents for an EBook.
        /// </summary>
        /// <param name="ebook"></param>
        /// <returns></returns>
        internal static async Task <TableOfContents> GetTableOfContentsAsync(this EBook ebook)
        {
            var hashRegex        = new Regex(@"(?<=.html)(#.*)");
            var relativeLocation = ebook.Manifest[ebook.Spine.Toc].ContentLocation;
            var tocFile          = await ebook._rootFolder.GetFileFromPathAsync(Path.Combine(Path.GetDirectoryName(ebook.ContentLocation), relativeLocation));

            var xml = await FileIO.ReadTextAsync(tocFile);

            var doc = XDocument.Parse(xml);
            var ns  = doc.Root.GetDefaultNamespace();

            var tableOfContents = new TableOfContents
            {
                Title = doc.Element(ns + "ncx").Element(ns + "docTitle").Element(ns + "text").Value
            };

            var navMapNode = doc.Element(ns + "ncx").Element(ns + "navMap");

            IEnumerable <NavPoint> ParseNavPoints(XElement node, int level)
            {
                var navPoints     = new List <NavPoint>();
                var navPointNodes = node.Elements(ns + "navPoint").ToList();

                foreach (var navPointNode in navPointNodes)
                {
                    var navPoint = new NavPoint
                    {
                        ContentPath = hashRegex.Replace(navPointNode.Element(ns + "content")?.Attribute("src").Value, string.Empty),
                        Id          = navPointNode.Attribute("id")?.Value,
                        Level       = level,
                        PlayOrder   = int.Parse(navPointNode.Attribute("playOrder")?.Value),
                        Text        = navPointNode.Element(ns + "navLabel")?.Element(ns + "text")?.Value
                    };

                    foreach (var subNavPoint in ParseNavPoints(navPointNode, level + 1).ToList())
                    {
                        navPoint.Items.Add(subNavPoint);
                    }

                    navPoints.Add(navPoint);
                }

                return(navPoints);
            }

            foreach (var navPoint in ParseNavPoints(navMapNode, 0).ToList())
            {
                tableOfContents.Items.Add(navPoint);
            }

            return(tableOfContents);
        }
Example #8
0
        public static void Initialize(this EBook eBook)
        {
            eBook.ContentLocation = eBook.GetContentLocation();
            var manifestItems = eBook.GetManifest().ToList();

            foreach (var item in manifestItems)
            {
                eBook.Manifest[item.Id] = item;
            }

            eBook.CoverLocation = eBook.GetCoverLocation();
            eBook.Metadata      = eBook.GetMetadata();
        }
Example #9
0
        public static string GetContentLocation(this EBook eBook)
        {
            var containerPath = Path.Combine(eBook.BaseDirectory, "META-INF", "container.xml");
            var xml           = File.ReadAllText(containerPath);
            var doc           = XDocument.Parse(xml);
            var ns            = doc.Root.GetDefaultNamespace();
            var node          = doc.Element(ns + "container").Element(ns + "rootfiles").Element(ns + "rootfile");

            if (node.Attribute("media-type")?.Value != "application/oebps-package+xml")
            {
                throw new Exception($"Invalid media type on rootfile node. Unexpected value \"{node.Attribute("media-type")?.Value}\"");
            }

            var path = Path.GetFullPath(Path.Combine(eBook.BaseDirectory, node.Attribute("full-path")?.Value));

            return(path);
        }
Example #10
0
        /// <summary>
        /// Gets a bitmap image of the cover.
        /// </summary>
        /// <param name="ebook"></param>
        /// <returns></returns>
        internal static async Task <ImageSource> GetCoverAsync(this EBook ebook)
        {
            if (!ebook.Manifest.ContainsKey("cover"))
            {
                return(null);
            }

            var relativeLocation = ebook.Manifest["cover"].ContentLocation;
            var coverFile        = await ebook._rootFolder.GetFileFromPathAsync(Path.Combine(Path.GetDirectoryName(ebook.ContentLocation), relativeLocation));

            var stream = await coverFile.OpenReadAsync();

            var bitmap = new BitmapImage();

            bitmap.SetSource(stream);
            return(bitmap);
        }
Example #11
0
        public static IEnumerable <ManifestItem> GetManifest(this EBook eBook)
        {
            var contentXml   = File.ReadAllText(eBook.ContentLocation);
            var doc          = XDocument.Parse(contentXml);
            var ns           = doc.Root.GetDefaultNamespace();
            var manifestNode = doc.Element(ns + "package").Element(ns + "manifest");
            var itemNodes    = manifestNode.Elements(ns + "item").ToList();

            foreach (var node in itemNodes)
            {
                yield return(new ManifestItem
                {
                    ContentLocation = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(eBook.ContentLocation), node.Attribute("href").Value)),
                    Id = node.Attribute("id").Value,
                    MediaType = node.Attribute("media-type").Value
                });
            }
        }
Example #12
0
        public static bool IsMimetypeValid(this EBook eBook)
        {
            var expectedMimetype = "application/epub+zip";
            var mimetypeFiles    = Directory.GetFiles(eBook.BaseDirectory, "mimetype");

            if (mimetypeFiles.Length != 1)
            {
                return(false);
            }

            var mimetypeFile = mimetypeFiles[0];
            var mimetype     = File.ReadAllText(mimetypeFile).Trim(' ', '\n', '\r', '\t').ToLower();

            if (mimetype != expectedMimetype)
            {
                return(false);
            }

            return(true);
        }
Example #13
0
        public static Spine GetSpine(this EBook eBook)
        {
            var spine      = new Spine();
            var contentXml = File.ReadAllText(eBook.ContentLocation);
            var doc        = XDocument.Parse(contentXml);
            var ns         = doc.Root.GetDefaultNamespace();
            var spineNode  = doc.Element(ns + "package").Element(ns + "spine");

            spine.Toc = spineNode.Attribute("toc").Value;
            var itemNodes = spineNode.Elements(ns + "itemref").ToList();

            foreach (var node in itemNodes)
            {
                spine.Add(new SpineItem
                {
                    IdRef = node.Attribute("idref").Value
                });
            }

            return(spine);
        }
Example #14
0
        /// <summary>
        /// Gets metadata from an EBook.
        /// </summary>
        /// <param name="ebook">The EBook for which to get metadata.</param>
        /// <returns>The metadata object.</returns>
        internal static async Task <Metadata> GetMetadataAsync(this EBook ebook)
        {
            XElement GetMetadataNode(string xml)
            {
                var doc  = XDocument.Parse(xml);
                var ns   = doc.Root.GetDefaultNamespace();
                var node = doc.Element(ns + "package").Element(ns + "metadata");

                return(node);
            }

            var contentFile = await ebook._rootFolder.GetFileFromPathAsync(ebook.ContentLocation);

            var contentXml = await FileIO.ReadTextAsync(contentFile);

            var metadataNode = GetMetadataNode(contentXml);
            var dcNamespace  = metadataNode.GetNamespaceOfPrefix("dc");

            string GetValue(string node) =>
            metadataNode.Element(dcNamespace + node)?.Value;

            var metadata = new Metadata
            {
                AlternativeTitle = GetValue("alternative"),
                Audience         = GetValue("audience"),
                Available        = GetValue("available") == null ? default(DateTime) : DateTime.Parse(GetValue("available")),
                Contributor      = GetValue("contributor"),
                Created          = GetValue("created") == null ? default(DateTime) : DateTime.Parse(GetValue("created")),
                Creator          = GetValue("creator"),
                Date             = GetValue("date") == null ? default(DateTime) : DateTime.Parse(GetValue("date")),
                Description      = GetValue("description"),
                Language         = GetValue("language"),
                Title            = GetValue("title")
            };

            return(metadata);
        }
Example #15
0
        /// <summary>
        /// Gets the location of the content.opf file.
        /// </summary>
        /// <param name="ebook">The EBook for which to get the content location.</param>
        /// <returns>A string location.</returns>
        internal static async Task <string> GetContentLocationAsync(this EBook ebook)
        {
            async Task <string> GetContentXmlAsync()
            {
                var folder = await ebook._rootFolder.GetFolderAsync("META-INF");

                var file = await folder.GetFileAsync("container.xml");

                var xml = await FileIO.ReadTextAsync(file);

                return(xml);
            }

            XElement GetRootFileNode(string xml)
            {
                var doc  = XDocument.Parse(xml);
                var ns   = doc.Root.GetDefaultNamespace();
                var node = doc.Element(ns + "container").Element(ns + "rootfiles").Element(ns + "rootfile");

                return(node);
            }

            bool VerifyMediaType(XElement node) =>
            node.Attribute("media-type")?.Value == "application/oebps-package+xml";

            var containerXml = await GetContentXmlAsync();

            var rootFileNode = GetRootFileNode(containerXml);

            if (!VerifyMediaType(rootFileNode))
            {
                throw new Exception("Invalid media type on rootfile node.");
            }

            return(rootFileNode.Attribute("full-path")?.Value);
        }
Example #16
0
        public static async Task <string> GetContentsAsync(this EBook ebook, NavPoint navPoint)
        {
            var manifestItem = ebook.Manifest.FirstOrDefault(a => Path.GetFileName(a.Value.ContentLocation) == Path.GetFileName(navPoint.ContentPath)).Value;

            return(await ebook.GetContentsAsync(manifestItem));
        }
Example #17
0
        public static async Task <string> GetContentsAsync(this EBook ebook, SpineItem spineItem)
        {
            var manifestItem = ebook.Manifest[spineItem.IdRef];

            return(await ebook.GetContentsAsync(manifestItem));
        }
Example #18
0
        public static TableOfContents GetTableOfContents(this EBook eBook)
        {
            if (eBook.Spine == null)
            {
                eBook.Spine = eBook.GetSpine();
            }

            var tocXml          = File.ReadAllText(eBook.Manifest[eBook.Spine.Toc].ContentLocation);
            var doc             = XDocument.Parse(tocXml);
            var ns              = doc.Root.GetDefaultNamespace();
            var ncxNode         = doc.Element(ns + "ncx");
            var tableOfContents = new TableOfContents
            {
                Title = ncxNode.Element(ns + "docTitle").Element(ns + "text").Value
            };
            var navMapNode = ncxNode.Element(ns + "navMap");

            IEnumerable <NavPoint> ParseNavPoints(XElement node, int level)
            {
                var navPoints     = new List <NavPoint>();
                var navPointNodes = node.Elements(ns + "navPoint").ToList();

                foreach (var navPointNode in navPointNodes)
                {
                    var filePath    = navPointNode.Element(ns + "content").Attribute("src").Value;
                    var pathBuilder = new StringBuilder();

                    foreach (var c in filePath)
                    {
                        if (c == '#' && pathBuilder.ToString().EndsWith(".html"))
                        {
                            break;
                        }

                        pathBuilder.Append(c);
                    }

                    var navPoint = new NavPoint
                    {
                        ContentPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(eBook.Manifest[eBook.Spine.Toc].ContentLocation), pathBuilder.ToString())),
                        Id          = navPointNode.Attribute("id")?.Value,
                        Level       = level,
                        PlayOrder   = int.Parse(navPointNode.Attribute("playOrder")?.Value),
                        Text        = navPointNode.Element(ns + "navLabel")?.Element(ns + "text")?.Value
                    };

                    foreach (var subNavPoint in ParseNavPoints(navPointNode, level + 1).ToList())
                    {
                        navPoint.Items.Add(subNavPoint);
                    }

                    navPoints.Add(navPoint);
                }

                return(navPoints);
            }

            foreach (var navPoint in ParseNavPoints(navMapNode, 0).ToList())
            {
                tableOfContents.Items.Add(navPoint);
            }

            return(tableOfContents);
        }
Example #19
0
        public static SpineItem GetSpineItem(this EBook ebook, ManifestItem manifestItem)
        {
            var spineItem = ebook.Spine.FirstOrDefault(a => a.IdRef == manifestItem.Id);

            return(spineItem);
        }
Example #20
0
        public static string GetContents(this EBook eBook, NavPoint navPoint, bool embedImages = false, bool embedStyles = false)
        {
            var manifestItem = eBook.Manifest.SingleOrDefault(item => Path.GetFileName(item.Value.ContentLocation) == Path.GetFileName(navPoint.ContentPath));

            return(eBook.GetContents(manifestItem.Value, embedImages, embedStyles));
        }
Example #21
0
        public static string GetContents(this EBook eBook, SpineItem item, bool embedImages = false, bool embedStyles = false)
        {
            var manifestItem = eBook.Manifest[item.IdRef];

            return(GetContents(eBook, manifestItem, embedImages, embedStyles));
        }
Example #22
0
 public static async Task <StorageFile> GetFileAsync(this EBook ebook, string path)
 {
     return(await ebook._rootFolder.GetFileFromPathAsync(path.Substring(ebook._rootFolder.Path.Length)));
 }
Example #23
0
        public static string GetContents(this EBook eBook, ManifestItem manifestItem, bool embedImages = false, bool embedStyles = false)
        {
            var contents = File.ReadAllText(manifestItem.ContentLocation);

            contents = WebUtility.HtmlDecode(contents);

            if (embedImages)
            {
                var imageMatches = new Regex(@"<img.*/>", RegexOptions.IgnoreCase).Matches(contents).OfType <Match>().ToList();

                foreach (var match in imageMatches)
                {
                    var node   = HtmlNode.CreateNode(match.Value);
                    var source = node.Attributes["src"].Value;

                    if (source.StartsWith("data:"))
                    {
                        continue;
                    }

                    var imagePath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(manifestItem.ContentLocation), source));
                    var buffer    = File.ReadAllBytes(imagePath);
                    var base64    = Convert.ToBase64String(buffer);
                    node.Attributes["src"].Value = $"data:image/{new FileInfo(imagePath).Extension};base64,{base64}";
                    contents = contents.Replace(match.Value, node.OuterHtml);
                }
            }

            if (embedStyles)
            {
                var styleRegex   = new Regex(@"<style>(.*?)<\/style>", RegexOptions.IgnoreCase | RegexOptions.Singleline);
                var styleMatch   = styleRegex.Match(contents);
                var styleBuilder = new StringBuilder();

                if (styleMatch.Success)
                {
                    styleBuilder.Append(styleMatch.Groups[styleMatch.Groups.Count - 1]);
                }

                var stylesheetRegex   = new Regex(@"<link.*?rel=""stylesheet"".*?>", RegexOptions.IgnoreCase);
                var stylesheetMatches = stylesheetRegex.Matches(contents).OfType <Match>().ToList();

                foreach (var match in stylesheetMatches)
                {
                    var node     = HtmlNode.CreateNode(match.Value);
                    var location = node.Attributes["href"].Value;
                    var file     = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(manifestItem.ContentLocation), location));

                    if (!File.Exists(file))
                    {
                        continue;
                    }

                    var css = File.ReadAllText(file);
                    styleBuilder.Append(css);
                    contents = contents.Replace(match.Value, string.Empty);
                }

                var styleTag = $"<style>{styleBuilder.ToString()}</style>";

                if (styleMatch.Success)
                {
                    contents = contents.Replace(styleMatch.Value, styleTag);
                }

                else
                {
                    var endOfHead = contents.IndexOf("</head>");
                    contents = contents.Insert(endOfHead, styleTag);
                }
            }

            return(contents);
        }