From 076ac2739bdc8e08c0f96cb52d24b6ab46758473 Mon Sep 17 00:00:00 2001 From: SHB743 Date: Mon, 15 Jun 2020 23:49:53 +0530 Subject: [PATCH 01/12] added support for V3 Epubs --- analysis_options.yaml | 2 +- lib/src/readers/navigation_reader.dart | 326 +++++++++++++++------ lib/src/readers/package_reader.dart | 3 + lib/src/schema/opf/epub_manifest_item.dart | 9 +- 4 files changed, 254 insertions(+), 86 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 1728f8db..96a25a49 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,7 +1,7 @@ # Defines a default set of lint rules enforced for # projects at Google. For details and rationale, # see https://github.com/dart-lang/pedantic#enabled-lints. -include: package:pedantic/analysis_options.yaml +#include: package:pedantic/analysis_options.yaml # For lint rules and documentation, see http://dart-lang.github.io/linter/lints. # Uncomment to specify additional rules. diff --git a/lib/src/readers/navigation_reader.dart b/lib/src/readers/navigation_reader.dart index 922fa38f..a534a30a 100644 --- a/lib/src/readers/navigation_reader.dart +++ b/lib/src/readers/navigation_reader.dart @@ -24,105 +24,174 @@ import '../schema/opf/epub_package.dart'; import '../utils/enum_from_string.dart'; import '../utils/zip_path_utils.dart'; +// ignore: omit_local_variable_types class NavigationReader { static Future readNavigation(Archive epubArchive, String contentDirectoryPath, EpubPackage package) async { EpubNavigation result = EpubNavigation(); - String tocId = package.Spine.TableOfContents; - if (tocId == null || tocId.isEmpty) { - if (package.Version == EpubVersion.Epub2) { + if (package.Version == EpubVersion.Epub2) { + String tocId = package.Spine.TableOfContents; + if (tocId == null || tocId.isEmpty) { throw Exception("EPUB parsing error: TOC ID is empty."); } - return null; - } - EpubManifestItem tocManifestItem = package.Manifest.Items.firstWhere( - (EpubManifestItem item) => item.Id.toLowerCase() == tocId.toLowerCase(), - orElse: () => null); - if (tocManifestItem == null) { - throw Exception( - "EPUB parsing error: TOC item ${tocId} not found in EPUB manifest."); - } + EpubManifestItem tocManifestItem = package.Manifest.Items.firstWhere( + (EpubManifestItem item) => + item.Id.toLowerCase() == tocId.toLowerCase(), + orElse: () => null); + if (tocManifestItem == null) { + throw Exception( + "EPUB parsing error: TOC item ${tocId} not found in EPUB manifest."); + } - String tocFileEntryPath = - ZipPathUtils.combine(contentDirectoryPath, tocManifestItem.Href); - ArchiveFile tocFileEntry = epubArchive.files.firstWhere( - (ArchiveFile file) => - file.name.toLowerCase() == tocFileEntryPath.toLowerCase(), - orElse: () => null); - if (tocFileEntry == null) { - throw Exception( - "EPUB parsing error: TOC file ${tocFileEntryPath} not found in archive."); - } + String tocFileEntryPath = + ZipPathUtils.combine(contentDirectoryPath, tocManifestItem.Href); + ArchiveFile tocFileEntry = epubArchive.files.firstWhere( + (ArchiveFile file) => + file.name.toLowerCase() == tocFileEntryPath.toLowerCase(), + orElse: () => null); + if (tocFileEntry == null) { + throw Exception( + "EPUB parsing error: TOC file ${tocFileEntryPath} not found in archive."); + } - xml.XmlDocument containerDocument = - xml.parse(convert.utf8.decode(tocFileEntry.content)); + xml.XmlDocument containerDocument = + xml.parse(convert.utf8.decode(tocFileEntry.content)); + + String ncxNamespace = "http://www.daisy.org/z3986/2005/ncx/"; + xml.XmlElement ncxNode = containerDocument + .findAllElements("ncx", namespace: ncxNamespace) + .firstWhere((xml.XmlElement elem) => elem != null, + orElse: () => null); + if (ncxNode == null) { + throw Exception( + "EPUB parsing error: TOC file does not contain ncx element."); + } - String ncxNamespace = "http://www.daisy.org/z3986/2005/ncx/"; - xml.XmlElement ncxNode = containerDocument - .findAllElements("ncx", namespace: ncxNamespace) - .firstWhere((xml.XmlElement elem) => elem != null, orElse: () => null); - if (ncxNode == null) { - throw Exception( - "EPUB parsing error: TOC file does not contain ncx element."); - } + xml.XmlElement headNode = ncxNode + .findAllElements("head", namespace: ncxNamespace) + .firstWhere((xml.XmlElement elem) => elem != null, + orElse: () => null); + if (headNode == null) { + throw Exception( + "EPUB parsing error: TOC file does not contain head element."); + } - xml.XmlElement headNode = ncxNode - .findAllElements("head", namespace: ncxNamespace) - .firstWhere((xml.XmlElement elem) => elem != null, orElse: () => null); - if (headNode == null) { - throw Exception( - "EPUB parsing error: TOC file does not contain head element."); - } + EpubNavigationHead navigationHead = readNavigationHead(headNode); + result.Head = navigationHead; + xml.XmlElement docTitleNode = ncxNode + .findElements("docTitle", namespace: ncxNamespace) + .firstWhere((xml.XmlElement elem) => elem != null, + orElse: () => null); + if (docTitleNode == null) { + throw Exception( + "EPUB parsing error: TOC file does not contain docTitle element."); + } - EpubNavigationHead navigationHead = readNavigationHead(headNode); - result.Head = navigationHead; - xml.XmlElement docTitleNode = ncxNode - .findElements("docTitle", namespace: ncxNamespace) - .firstWhere((xml.XmlElement elem) => elem != null, orElse: () => null); - if (docTitleNode == null) { - throw Exception( - "EPUB parsing error: TOC file does not contain docTitle element."); - } + EpubNavigationDocTitle navigationDocTitle = + readNavigationDocTitle(docTitleNode); + result.DocTitle = navigationDocTitle; + result.DocAuthors = List(); + ncxNode + .findElements("docAuthor", namespace: ncxNamespace) + .forEach((xml.XmlElement docAuthorNode) { + EpubNavigationDocAuthor navigationDocAuthor = + readNavigationDocAuthor(docAuthorNode); + result.DocAuthors.add(navigationDocAuthor); + }); + + xml.XmlElement navMapNode = ncxNode + .findElements("navMap", namespace: ncxNamespace) + .firstWhere((xml.XmlElement elem) => elem != null, + orElse: () => null); + if (navMapNode == null) { + throw Exception( + "EPUB parsing error: TOC file does not contain navMap element."); + } - EpubNavigationDocTitle navigationDocTitle = - readNavigationDocTitle(docTitleNode); - result.DocTitle = navigationDocTitle; - result.DocAuthors = List(); - ncxNode - .findElements("docAuthor", namespace: ncxNamespace) - .forEach((xml.XmlElement docAuthorNode) { - EpubNavigationDocAuthor navigationDocAuthor = - readNavigationDocAuthor(docAuthorNode); - result.DocAuthors.add(navigationDocAuthor); - }); + EpubNavigationMap navMap = readNavigationMap(navMapNode); + result.NavMap = navMap; + xml.XmlElement pageListNode = ncxNode + .findElements("pageList", namespace: ncxNamespace) + .firstWhere((xml.XmlElement elem) => elem != null, + orElse: () => null); + if (pageListNode != null) { + EpubNavigationPageList pageList = readNavigationPageList(pageListNode); + result.PageList = pageList; + } + + result.NavLists = List(); + ncxNode + .findElements("navList", namespace: ncxNamespace) + .forEach((xml.XmlElement navigationListNode) { + EpubNavigationList navigationList = + readNavigationList(navigationListNode); + result.NavLists.add(navigationList); + }); + }else{ //Version 3 + + EpubManifestItem tocManifestItem = package.Manifest.Items.firstWhere((element) => element.Properties == "nav" ,orElse: null); + if (tocManifestItem == null) { + throw Exception( + "EPUB parsing error: TOC item, not found in EPUB manifest."); + } + + String tocFileEntryPath = + ZipPathUtils.combine(contentDirectoryPath, tocManifestItem.Href); + ArchiveFile tocFileEntry = epubArchive.files.firstWhere( + (ArchiveFile file) => + file.name.toLowerCase() == tocFileEntryPath.toLowerCase(), + orElse: () => null); + if (tocFileEntry == null) { + throw Exception( + "EPUB parsing error: TOC file ${tocFileEntryPath} not found in archive."); + } + xml.XmlDocument containerDocument = xml.parse(convert.utf8.decode(tocFileEntry.content)); + + xml.XmlElement headNode = containerDocument + .findAllElements("head") + .firstWhere((xml.XmlElement elem) => elem != null, + orElse: () => null); + if (headNode == null) { + throw Exception( + "EPUB parsing error: TOC file does not contain head element."); + } + + + result.DocTitle = EpubNavigationDocTitle(); + result.DocTitle.Titles.add(headNode.findAllElements("title").firstWhere((element) => elem != null, orElse: () => null).text); + + result.DocAuthors = List(); + + + xml.XmlElement navNode = containerDocument + .findAllElements("nav") + .firstWhere((xml.XmlElement elem) => elem != null, + orElse: () => null); + if (navNode == null) { + throw Exception( + "EPUB parsing error: TOC file does not contain head element."); + } + xml.XmlElement navMapNode = navNode.findElements("ol").single; + + + EpubNavigationMap navMap = readNavigationMapV3(navMapNode); + result.NavMap = navMap; + + //TODO : Implement pagesLists +// xml.XmlElement pageListNode = ncxNode +// .findElements("pageList", namespace: ncxNamespace) +// .firstWhere((xml.XmlElement elem) => elem != null, +// orElse: () => null); +// if (pageListNode != null) { +// EpubNavigationPageList pageList = readNavigationPageList(pageListNode); +// result.PageList = pageList; +// } - xml.XmlElement navMapNode = ncxNode - .findElements("navMap", namespace: ncxNamespace) - .firstWhere((xml.XmlElement elem) => elem != null, orElse: () => null); - if (navMapNode == null) { - throw Exception( - "EPUB parsing error: TOC file does not contain navMap element."); - } - EpubNavigationMap navMap = readNavigationMap(navMapNode); - result.NavMap = navMap; - xml.XmlElement pageListNode = ncxNode - .findElements("pageList", namespace: ncxNamespace) - .firstWhere((xml.XmlElement elem) => elem != null, orElse: () => null); - if (pageListNode != null) { - EpubNavigationPageList pageList = readNavigationPageList(pageListNode); - result.PageList = pageList; } - result.NavLists = List(); - ncxNode - .findElements("navList", namespace: ncxNamespace) - .forEach((xml.XmlElement navigationListNode) { - EpubNavigationList navigationList = - readNavigationList(navigationListNode); - result.NavLists.add(navigationList); - }); + return result; } @@ -150,6 +219,29 @@ class NavigationReader { return result; } + + static EpubNavigationContent readNavigationContentV3( + xml.XmlElement navigationContentNode) { + EpubNavigationContent result = EpubNavigationContent(); + navigationContentNode.attributes + .forEach((xml.XmlAttribute navigationContentNodeAttribute) { + String attributeValue = navigationContentNodeAttribute.value; + switch (navigationContentNodeAttribute.name.local.toLowerCase()) { + case "id": + result.Id = attributeValue; + break; + case "href": + result.Source = attributeValue; + break; + } + }); + if (result.Source == null || result.Source.isEmpty) { + throw Exception( + "Incorrect EPUB navigation content: content source is missing."); + } + return result; + } + static EpubNavigationDocAuthor readNavigationDocAuthor( xml.XmlElement docAuthorNode) { EpubNavigationDocAuthor result = EpubNavigationDocAuthor(); @@ -234,6 +326,14 @@ class NavigationReader { return result; } + + static EpubNavigationLabel readNavigationLabelV3( + xml.XmlElement navigationLabelNode) { + EpubNavigationLabel result = EpubNavigationLabel(); + result.Text = navigationLabelNode.text; + return result; + } + static EpubNavigationList readNavigationList( xml.XmlElement navigationListNode) { EpubNavigationList result = EpubNavigationList(); @@ -287,6 +387,22 @@ class NavigationReader { return result; } + + static EpubNavigationMap readNavigationMapV3(xml.XmlElement navigationMapNode) { + EpubNavigationMap result = EpubNavigationMap(); + result.Points = List(); + navigationMapNode.children + .whereType() + .forEach((xml.XmlElement navigationPointNode) { + if (navigationPointNode.name.local.toLowerCase() == "li") { + EpubNavigationPoint navigationPoint = + readNavigationPoint(navigationPointNode); + result.Points.add(navigationPoint); + } + }); + return result; + } + static EpubNavigationPageList readNavigationPageList( xml.XmlElement navigationPageListNode) { EpubNavigationPageList result = EpubNavigationPageList(); @@ -419,6 +535,52 @@ class NavigationReader { return result; } + + + + + + static EpubNavigationPoint readNavigationPointV3( + xml.XmlElement navigationPointNode) { + EpubNavigationPoint result = EpubNavigationPoint(); + + result.NavigationLabels = List(); + result.ChildNavigationPoints = List(); + navigationPointNode.children + .whereType() + .forEach((xml.XmlElement navigationPointChildNode) { + switch (navigationPointChildNode.name.local.toLowerCase()) { + case "a": + EpubNavigationLabel navigationLabel = + readNavigationLabelV3(navigationPointChildNode); + result.NavigationLabels.add(navigationLabel); + EpubNavigationContent content = + readNavigationContentV3(navigationPointChildNode); + result.Content = content; + break; + case "ol": + EpubNavigationPoint childNavigationPoint = + readNavigationPointV3(navigationPointChildNode); + result.ChildNavigationPoints.add(childNavigationPoint); + break; + } + }); + + if (result.NavigationLabels.isEmpty) { + throw Exception( + "EPUB parsing error: navigation point ${result.Id} should contain at least one navigation label."); + } + if (result.Content == null) { + throw Exception( + "EPUB parsing error: navigation point ${result.Id} should contain content."); + } + + return result; + } + + + + static EpubNavigationTarget readNavigationTarget( xml.XmlElement navigationTargetNode) { EpubNavigationTarget result = EpubNavigationTarget(); diff --git a/lib/src/readers/package_reader.dart b/lib/src/readers/package_reader.dart index afd7cefb..533c9b6e 100644 --- a/lib/src/readers/package_reader.dart +++ b/lib/src/readers/package_reader.dart @@ -88,6 +88,9 @@ class PackageReader { case "fallback-style": manifestItem.FallbackStyle = attributeValue; break; + case "properties": + manifestItem.Properties = attributeValue; + break; } }); diff --git a/lib/src/schema/opf/epub_manifest_item.dart b/lib/src/schema/opf/epub_manifest_item.dart index d5eaef60..d06619bd 100644 --- a/lib/src/schema/opf/epub_manifest_item.dart +++ b/lib/src/schema/opf/epub_manifest_item.dart @@ -8,6 +8,7 @@ class EpubManifestItem { String RequiredModules; String Fallback; String FallbackStyle; + String Properties; @override int get hashCode => hashObjects([ @@ -17,7 +18,8 @@ class EpubManifestItem { RequiredNamespace.hashCode, RequiredModules.hashCode, Fallback.hashCode, - FallbackStyle.hashCode + FallbackStyle.hashCode, + Properties.hashCode ]); bool operator ==(other) { @@ -32,10 +34,11 @@ class EpubManifestItem { RequiredNamespace == otherAs.RequiredNamespace && RequiredModules == otherAs.RequiredModules && Fallback == otherAs.Fallback && - FallbackStyle == otherAs.FallbackStyle; + FallbackStyle == otherAs.FallbackStyle && + Properties == otherAs.Properties; } String toString() { - return "Id: ${Id}, Href = ${Href}, MediaType = ${MediaType}"; + return "Id: ${Id}, Href = ${Href}, MediaType = ${MediaType}, Properties = ${Properties}"; } } From 0a99ed71c869d9e70d172e2cce1d2bce5e0a34b4 Mon Sep 17 00:00:00 2001 From: shoaibomar Date: Tue, 16 Jun 2020 00:00:32 +0530 Subject: [PATCH 02/12] fix typo --- lib/src/readers/navigation_reader.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/readers/navigation_reader.dart b/lib/src/readers/navigation_reader.dart index a534a30a..1a94f6fc 100644 --- a/lib/src/readers/navigation_reader.dart +++ b/lib/src/readers/navigation_reader.dart @@ -159,7 +159,7 @@ class NavigationReader { result.DocTitle = EpubNavigationDocTitle(); - result.DocTitle.Titles.add(headNode.findAllElements("title").firstWhere((element) => elem != null, orElse: () => null).text); + result.DocTitle.Titles.add(headNode.findAllElements("title").firstWhere((element) => element != null, orElse: () => null).text); result.DocAuthors = List(); From 197364749b4ef6cba4e666910072a8eabde118ec Mon Sep 17 00:00:00 2001 From: shoaibomar Date: Tue, 16 Jun 2020 00:04:18 +0530 Subject: [PATCH 03/12] fix typo --- lib/src/readers/navigation_reader.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/readers/navigation_reader.dart b/lib/src/readers/navigation_reader.dart index 1a94f6fc..fa7f0229 100644 --- a/lib/src/readers/navigation_reader.dart +++ b/lib/src/readers/navigation_reader.dart @@ -396,7 +396,7 @@ class NavigationReader { .forEach((xml.XmlElement navigationPointNode) { if (navigationPointNode.name.local.toLowerCase() == "li") { EpubNavigationPoint navigationPoint = - readNavigationPoint(navigationPointNode); + readNavigationPointV3(navigationPointNode); result.Points.add(navigationPoint); } }); From 1c1c5cfb2d8eaa26e14a94e3f5d10684313c7af3 Mon Sep 17 00:00:00 2001 From: shoaibomar Date: Tue, 16 Jun 2020 00:30:35 +0530 Subject: [PATCH 04/12] fixed recursive search --- lib/src/readers/navigation_reader.dart | 31 +++++++++++++------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/lib/src/readers/navigation_reader.dart b/lib/src/readers/navigation_reader.dart index fa7f0229..b324c1cc 100644 --- a/lib/src/readers/navigation_reader.dart +++ b/lib/src/readers/navigation_reader.dart @@ -159,7 +159,7 @@ class NavigationReader { result.DocTitle = EpubNavigationDocTitle(); - result.DocTitle.Titles.add(headNode.findAllElements("title").firstWhere((element) => element != null, orElse: () => null).text); + result.DocTitle.Titles.add(headNode.findAllElements("title").firstWhere((element) => element != null, orElse: () => null).text.replaceAllMapped(RegExp(r'/^\s+|\s+$/g'), (match) {return '"${match.group(0)}"';})); result.DocAuthors = List(); @@ -174,7 +174,6 @@ class NavigationReader { } xml.XmlElement navMapNode = navNode.findElements("ol").single; - EpubNavigationMap navMap = readNavigationMapV3(navMapNode); result.NavMap = navMap; @@ -355,12 +354,12 @@ class NavigationReader { switch (navigationListChildNode.name.local.toLowerCase()) { case "navlabel": EpubNavigationLabel navigationLabel = - readNavigationLabel(navigationListChildNode); + readNavigationLabel(navigationListChildNode); result.NavigationLabels.add(navigationLabel); break; case "navtarget": EpubNavigationTarget navigationTarget = - readNavigationTarget(navigationListChildNode); + readNavigationTarget(navigationListChildNode); result.NavigationTargets.add(navigationTarget); break; } @@ -380,7 +379,7 @@ class NavigationReader { .forEach((xml.XmlElement navigationPointNode) { if (navigationPointNode.name.local.toLowerCase() == "navpoint") { EpubNavigationPoint navigationPoint = - readNavigationPoint(navigationPointNode); + readNavigationPoint(navigationPointNode); result.Points.add(navigationPoint); } }); @@ -412,7 +411,7 @@ class NavigationReader { .forEach((xml.XmlElement pageTargetNode) { if (pageTargetNode.name.local == "pageTarget") { EpubNavigationPageTarget pageTarget = - readNavigationPageTarget(pageTargetNode); + readNavigationPageTarget(pageTargetNode); result.Targets.add(pageTarget); } }); @@ -459,12 +458,12 @@ class NavigationReader { switch (navigationPageTargetChildNode.name.local.toLowerCase()) { case "navlabel": EpubNavigationLabel navigationLabel = - readNavigationLabel(navigationPageTargetChildNode); + readNavigationLabel(navigationPageTargetChildNode); result.NavigationLabels.add(navigationLabel); break; case "content": EpubNavigationContent content = - readNavigationContent(navigationPageTargetChildNode); + readNavigationContent(navigationPageTargetChildNode); result.Content = content; break; } @@ -507,17 +506,17 @@ class NavigationReader { switch (navigationPointChildNode.name.local.toLowerCase()) { case "navlabel": EpubNavigationLabel navigationLabel = - readNavigationLabel(navigationPointChildNode); + readNavigationLabel(navigationPointChildNode); result.NavigationLabels.add(navigationLabel); break; case "content": EpubNavigationContent content = - readNavigationContent(navigationPointChildNode); + readNavigationContent(navigationPointChildNode); result.Content = content; break; case "navpoint": EpubNavigationPoint childNavigationPoint = - readNavigationPoint(navigationPointChildNode); + readNavigationPoint(navigationPointChildNode); result.ChildNavigationPoints.add(childNavigationPoint); break; } @@ -559,9 +558,9 @@ class NavigationReader { result.Content = content; break; case "ol": - EpubNavigationPoint childNavigationPoint = - readNavigationPointV3(navigationPointChildNode); - result.ChildNavigationPoints.add(childNavigationPoint); + readNavigationMapV3(navigationPointChildNode).Points.forEach((point) { + result.ChildNavigationPoints.add(point); + }); break; } }); @@ -613,12 +612,12 @@ class NavigationReader { switch (navigationTargetChildNode.name.local.toLowerCase()) { case "navlabel": EpubNavigationLabel navigationLabel = - readNavigationLabel(navigationTargetChildNode); + readNavigationLabel(navigationTargetChildNode); result.NavigationLabels.add(navigationLabel); break; case "content": EpubNavigationContent content = - readNavigationContent(navigationTargetChildNode); + readNavigationContent(navigationTargetChildNode); result.Content = content; break; } From 602d46758aa9a6f089d13c10b91cd0367a2b5f3a Mon Sep 17 00:00:00 2001 From: shoaibomar Date: Tue, 16 Jun 2020 17:28:53 +0530 Subject: [PATCH 05/12] switched to dart trim --- lib/src/readers/navigation_reader.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/readers/navigation_reader.dart b/lib/src/readers/navigation_reader.dart index b324c1cc..c267be72 100644 --- a/lib/src/readers/navigation_reader.dart +++ b/lib/src/readers/navigation_reader.dart @@ -159,7 +159,7 @@ class NavigationReader { result.DocTitle = EpubNavigationDocTitle(); - result.DocTitle.Titles.add(headNode.findAllElements("title").firstWhere((element) => element != null, orElse: () => null).text.replaceAllMapped(RegExp(r'/^\s+|\s+$/g'), (match) {return '"${match.group(0)}"';})); + result.DocTitle.Titles.add(headNode.findAllElements("title").firstWhere((element) => element != null, orElse: () => null).text.trim()); result.DocAuthors = List(); @@ -329,7 +329,7 @@ class NavigationReader { static EpubNavigationLabel readNavigationLabelV3( xml.XmlElement navigationLabelNode) { EpubNavigationLabel result = EpubNavigationLabel(); - result.Text = navigationLabelNode.text; + result.Text = navigationLabelNode.text.trim(); return result; } @@ -629,4 +629,4 @@ class NavigationReader { return result; } -} +} \ No newline at end of file From 99a0f65c5000414aab31d84087eb16c84ab05bdc Mon Sep 17 00:00:00 2001 From: shoaibomar Date: Wed, 17 Jun 2020 15:53:31 +0530 Subject: [PATCH 06/12] got page progression direction --- lib/src/readers/package_reader.dart | 2 ++ lib/src/schema/opf/epub_spine.dart | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/src/readers/package_reader.dart b/lib/src/readers/package_reader.dart index 533c9b6e..b60495dd 100644 --- a/lib/src/readers/package_reader.dart +++ b/lib/src/readers/package_reader.dart @@ -372,6 +372,8 @@ class PackageReader { result.Items = List(); String tocAttribute = spineNode.getAttribute("toc"); result.TableOfContents = tocAttribute; + String pageProgression = spineNode.getAttribute("page-progression-direction"); + result.ltr = ((pageProgression == null) || pageProgression.toLowerCase() == "ltr"); spineNode.children .whereType() .forEach((xml.XmlElement spineItemNode) { diff --git a/lib/src/schema/opf/epub_spine.dart b/lib/src/schema/opf/epub_spine.dart index 9b3b2ba8..e64ed6fa 100644 --- a/lib/src/schema/opf/epub_spine.dart +++ b/lib/src/schema/opf/epub_spine.dart @@ -6,11 +6,13 @@ import 'epub_spine_item_ref.dart'; class EpubSpine { String TableOfContents; List Items; + bool ltr; @override int get hashCode { var objs = [] ..add(TableOfContents.hashCode) + ..add(ltr.hashCode) ..addAll(Items.map((item) => item.hashCode)); return hashObjects(objs); } @@ -22,6 +24,6 @@ class EpubSpine { if (!collections.listsEqual(Items, otherAs.Items)) { return false; } - return TableOfContents == otherAs.TableOfContents; + return ((TableOfContents == otherAs.TableOfContents) && (ltr == otherAs.ltr)); } } From 5bc22dd5ce9a95a84f2b40408cf20b5f80524900 Mon Sep 17 00:00:00 2001 From: shoaibomar Date: Wed, 17 Jun 2020 16:35:31 +0530 Subject: [PATCH 07/12] now supports relative file paths for navigation epub v3 --- lib/src/readers/navigation_reader.dart | 29 ++++++++++++++++++-------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/lib/src/readers/navigation_reader.dart b/lib/src/readers/navigation_reader.dart index c267be72..9044a106 100644 --- a/lib/src/readers/navigation_reader.dart +++ b/lib/src/readers/navigation_reader.dart @@ -25,7 +25,10 @@ import '../utils/enum_from_string.dart'; import '../utils/zip_path_utils.dart'; // ignore: omit_local_variable_types + + class NavigationReader { + static String _tocFileEntryPath; static Future readNavigation(Archive epubArchive, String contentDirectoryPath, EpubPackage package) async { EpubNavigation result = EpubNavigation(); @@ -44,15 +47,15 @@ class NavigationReader { "EPUB parsing error: TOC item ${tocId} not found in EPUB manifest."); } - String tocFileEntryPath = - ZipPathUtils.combine(contentDirectoryPath, tocManifestItem.Href); + _tocFileEntryPath = + ZipPathUtils.combine(contentDirectoryPath, tocManifestItem.Href); ArchiveFile tocFileEntry = epubArchive.files.firstWhere( (ArchiveFile file) => - file.name.toLowerCase() == tocFileEntryPath.toLowerCase(), + file.name.toLowerCase() == _tocFileEntryPath.toLowerCase(), orElse: () => null); if (tocFileEntry == null) { throw Exception( - "EPUB parsing error: TOC file ${tocFileEntryPath} not found in archive."); + "EPUB parsing error: TOC file ${_tocFileEntryPath} not found in archive."); } xml.XmlDocument containerDocument = @@ -136,16 +139,19 @@ class NavigationReader { "EPUB parsing error: TOC item, not found in EPUB manifest."); } - String tocFileEntryPath = - ZipPathUtils.combine(contentDirectoryPath, tocManifestItem.Href); + _tocFileEntryPath = + ZipPathUtils.combine(contentDirectoryPath, tocManifestItem.Href); ArchiveFile tocFileEntry = epubArchive.files.firstWhere( (ArchiveFile file) => - file.name.toLowerCase() == tocFileEntryPath.toLowerCase(), + file.name.toLowerCase() == _tocFileEntryPath.toLowerCase(), orElse: () => null); if (tocFileEntry == null) { throw Exception( - "EPUB parsing error: TOC file ${tocFileEntryPath} not found in archive."); + "EPUB parsing error: TOC file ${_tocFileEntryPath} not found in archive."); } + //Get relative toc file path + _tocFileEntryPath = ((_tocFileEntryPath.split("/")..removeLast())..removeAt(0)).join("/")+'/'; + xml.XmlDocument containerDocument = xml.parse(convert.utf8.decode(tocFileEntry.content)); xml.XmlElement headNode = containerDocument @@ -230,7 +236,12 @@ class NavigationReader { result.Id = attributeValue; break; case "href": - result.Source = attributeValue; + if (_tocFileEntryPath.length == 0 || attributeValue.contains(_tocFileEntryPath)){ + result.Source = attributeValue; + }else{ + result.Source = _tocFileEntryPath+attributeValue; + } + break; } }); From ee803494a0def50e4e91aa2300fa90d0f8271b52 Mon Sep 17 00:00:00 2001 From: shoaibomar Date: Wed, 17 Jun 2020 16:38:10 +0530 Subject: [PATCH 08/12] now supports relative file paths for navigation epub v3 --- lib/src/readers/navigation_reader.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/readers/navigation_reader.dart b/lib/src/readers/navigation_reader.dart index 9044a106..a7eca380 100644 --- a/lib/src/readers/navigation_reader.dart +++ b/lib/src/readers/navigation_reader.dart @@ -236,7 +236,7 @@ class NavigationReader { result.Id = attributeValue; break; case "href": - if (_tocFileEntryPath.length == 0 || attributeValue.contains(_tocFileEntryPath)){ + if (_tocFileEntryPath.length < 2 || attributeValue.contains(_tocFileEntryPath)){ result.Source = attributeValue; }else{ result.Source = _tocFileEntryPath+attributeValue; From 0d635840045e27ece3e32fe25a91360217f0a1f2 Mon Sep 17 00:00:00 2001 From: shoaibomar Date: Thu, 18 Jun 2020 13:56:32 +0530 Subject: [PATCH 09/12] now gets media-overlays for manifest items --- lib/src/readers/package_reader.dart | 3 +++ lib/src/schema/opf/epub_manifest_item.dart | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/src/readers/package_reader.dart b/lib/src/readers/package_reader.dart index b60495dd..23e4f35f 100644 --- a/lib/src/readers/package_reader.dart +++ b/lib/src/readers/package_reader.dart @@ -76,6 +76,9 @@ class PackageReader { case "media-type": manifestItem.MediaType = attributeValue; break; + case "media-overlay": + manifestItem.MediaOverlay = attributeValue; + break; case "required-namespace": manifestItem.RequiredNamespace = attributeValue; break; diff --git a/lib/src/schema/opf/epub_manifest_item.dart b/lib/src/schema/opf/epub_manifest_item.dart index d06619bd..b269a170 100644 --- a/lib/src/schema/opf/epub_manifest_item.dart +++ b/lib/src/schema/opf/epub_manifest_item.dart @@ -4,6 +4,7 @@ class EpubManifestItem { String Id; String Href; String MediaType; + String MediaOverlay; String RequiredNamespace; String RequiredModules; String Fallback; @@ -15,6 +16,7 @@ class EpubManifestItem { Id.hashCode, Href.hashCode, MediaType.hashCode, + MediaOverlay.hashCode, RequiredNamespace.hashCode, RequiredModules.hashCode, Fallback.hashCode, @@ -31,6 +33,7 @@ class EpubManifestItem { return Id == otherAs.Id && Href == otherAs.Href && MediaType == otherAs.MediaType && + MediaOverlay == otherAs.MediaOverlay && RequiredNamespace == otherAs.RequiredNamespace && RequiredModules == otherAs.RequiredModules && Fallback == otherAs.Fallback && @@ -39,6 +42,6 @@ class EpubManifestItem { } String toString() { - return "Id: ${Id}, Href = ${Href}, MediaType = ${MediaType}, Properties = ${Properties}"; + return "Id: ${Id}, Href = ${Href}, MediaType = ${MediaType}, Properties = ${Properties}, MediaOverlay = ${MediaOverlay}"; } } From be9dafb5b5ad05f4a96171e92524ca5365595b55 Mon Sep 17 00:00:00 2001 From: Shoaib Omar Date: Sun, 5 Jul 2020 15:57:49 +0530 Subject: [PATCH 10/12] all meta attributes are now accessible --- lib/src/readers/package_reader.dart | 2 ++ lib/src/schema/opf/epub_metadata_meta.dart | 1 + 2 files changed, 3 insertions(+) diff --git a/lib/src/readers/package_reader.dart b/lib/src/readers/package_reader.dart index 23e4f35f..8dee7ee1 100644 --- a/lib/src/readers/package_reader.dart +++ b/lib/src/readers/package_reader.dart @@ -290,9 +290,11 @@ class PackageReader { static EpubMetadataMeta readMetadataMetaVersion3( xml.XmlElement metadataMetaNode) { EpubMetadataMeta result = EpubMetadataMeta(); + result.Attributes = {}; metadataMetaNode.attributes .forEach((xml.XmlAttribute metadataMetaNodeAttribute) { String attributeValue = metadataMetaNodeAttribute.value; + result.Attributes[metadataMetaNodeAttribute.name.local.toLowerCase()] = attributeValue; switch (metadataMetaNodeAttribute.name.local.toLowerCase()) { case "id": result.Id = attributeValue; diff --git a/lib/src/schema/opf/epub_metadata_meta.dart b/lib/src/schema/opf/epub_metadata_meta.dart index b90b1dad..381927bc 100644 --- a/lib/src/schema/opf/epub_metadata_meta.dart +++ b/lib/src/schema/opf/epub_metadata_meta.dart @@ -7,6 +7,7 @@ class EpubMetadataMeta { String Refines; String Property; String Scheme; + Map Attributes; @override int get hashCode => hashObjects([ From 2c0a37be61c0993e16063a39850bbcfbb31dc024 Mon Sep 17 00:00:00 2001 From: shoaibomar Date: Mon, 24 Aug 2020 16:23:02 +0530 Subject: [PATCH 11/12] removed requirenment for title in Nav Doc --- lib/.DS_Store | Bin 0 -> 6148 bytes lib/src/.DS_Store | Bin 0 -> 10244 bytes lib/src/readers/navigation_reader.dart | 3 ++- lib/src/schema/.DS_Store | Bin 0 -> 6148 bytes 4 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 lib/.DS_Store create mode 100644 lib/src/.DS_Store create mode 100644 lib/src/schema/.DS_Store diff --git a/lib/.DS_Store b/lib/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..e8767f9a0350328c1fa40ff53e4c9d2b65b25500 GIT binary patch literal 6148 zcmeHK&2AGh5FRIidV{LwfYcs+LE;cqiCU$H3TYL}AvdH&Z~)Zqb|bpdvW~JFA_zhI z8t?`@3Qxe}z>Gbqh*GX?RLw}^Z#u49XmM;K12lI5j9~&ZNZ_COvzJM36KtiWaf2no!~_Uyky% zsGm1SCG&E^ef>%%c~(}v-fz`twjMm((YmeMyY2VUm7PabT+Pa1Jbg>GmvMEKu>H!~ z{MwF_*V%Y}-g*4o7FC=T#+CjcT{Bb}g47e>l4 zj3Hy~5nE7{Pet^pik}$Dr=#C+T*z2^^y#4Z@uB$3ieD(oeI5HZE*w8l+&|6lz7{lA_hHDN#)xK|9Q)>(8m#3Aw7x-mF9YYplJDhb8a9ID6U48)MJ_J|%7xd=EKq!0#fm4UycuV%mi literal 0 HcmV?d00001 diff --git a/lib/src/.DS_Store b/lib/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..0420a37ad052416ab56fe966dcb2478230dd7270 GIT binary patch literal 10244 zcmeHM%}*0S6o12qYzxTpQ6TDJBQYVNF(o1#jIk7qHXb09AOx`NwoBQ#?9|;Y6%f;l ze}f-aPo9l`fJZN0J$mpTFfpF-&CC|I%f}5vnwezg_jcyJeLKIIzR8;c0LfH};{X}} zC|DV)UD%vb*f^^vN=wkwk4VrSzy}LV@Uk{7oY0mXk^#wpWI!??8ITNI1_toVW<}`~ zC|k*ZWI!@-!~lyA8diqs0BZty=)i`j0Elha%?rwy2XGrLz;u8$f!q||DY6F=n35pH zAi^BSHKvZ34zMOrm;({!KmyMs$WRFPj&>SX2a*;jTgiZA;3NYqcULfHcX;j|%HIu} z8aT#&PWP~m9`b_HDf&j$D+l`DjIwQcek%2Yw6wOhU+GYkxDxMXdMd*{Mie87g2v9$b`lC}QivZA2Z>XBQzMB0r%`n8>hw74Ko z20gOhS>SjV3LFi(%}QLuB(1_u5E;qmdSv{ms`c0yi+6T)U+qzQ`}%tadJ~Dn;80?? z@7nde+HdHE=Ovd#xfyCxH)B`KyxQYo+{_lJGw+%^7$cW`^QE7&_Hd{#Vz6KqpB;BC z?v_z!;JAao^pR_t&T7fEigTNrp6M?$4+WRn_B{10-=fY+Xmn+bd-u)ltg}hcBm086 zGE?)GOxHs^VZXehyRPn(%*^h(tsAC2=VYkw)9qyoXTiRlJIIywg5{J(9{k1~gC#bS z9u<-bBSOGqMB7J!0hcugY z--o6cp{WDHhg zk^#xUrC@-x&E{q^_$l=~DEd|Gu3f{rft3}eR};uhu;JJ7i2OPpAJ}y~PvNjHg)%QF mr element != null, orElse: () => null).text.trim()); + result.DocTitle.Titles = package.Metadata.Titles; +// result.DocTitle.Titles.add(headNode.findAllElements("title").firstWhere((element) => element != null, orElse: () => null).text.trim()); result.DocAuthors = List(); diff --git a/lib/src/schema/.DS_Store b/lib/src/schema/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..317aeece6fe6a5cc055fb1e806ef62191639ab90 GIT binary patch literal 6148 zcmeHK&2AGh5FRH1oS=#vkm%7DBn~+wqDl`4X%*T-Z%A9gfueSor0q(}I!ZQ;APw5r zfH&Y#c!EAo`;F~ZEorZ`LNn6%8+&HF>(7>dh)4})!yZwah%}V3)H5VH3%D~5JHu(M(~b^XNNp>MZdSvG5vmT*)faF&2GnR zyzVcTP5t6!@9oaP*Kgk!r^_Ed-Ec@@0XumX@DhH(xRs!jcv9rHID(&Z>sa(-I{b^a z-|$?g4OJ0gKo}4P?w^6M<>{yQ|10tb!hkUFz!>2D!9W?KfR#tLb)axh03cr@oxtYn zBIlTZQNYS0JP_qmfj(7*Cx-IrXg47)3Rrpc>7>HrLxnG^@Iq1U>*(LOa8i*+DTM)H z;3flgUv2aGzkT=n|7McZgaKjTzhXc&w&JY;h7``$mBH~@YoG^E7LKbtUZucrM=@gg dC|-v;LAzlC7zM06q6H!s0Y`%r!oWXe-~#WMZ94z} literal 0 HcmV?d00001 From 9c67bd25429b6fd91f117a903893847aa31cddbc Mon Sep 17 00:00:00 2001 From: shoaibomar Date: Mon, 24 Aug 2020 16:24:49 +0530 Subject: [PATCH 12/12] removed requirenment for title in Nav Doc --- lib/.DS_Store | Bin 6148 -> 0 bytes lib/src/.DS_Store | Bin 10244 -> 0 bytes lib/src/schema/.DS_Store | Bin 6148 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lib/.DS_Store delete mode 100644 lib/src/.DS_Store delete mode 100644 lib/src/schema/.DS_Store diff --git a/lib/.DS_Store b/lib/.DS_Store deleted file mode 100644 index e8767f9a0350328c1fa40ff53e4c9d2b65b25500..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK&2AGh5FRIidV{LwfYcs+LE;cqiCU$H3TYL}AvdH&Z~)Zqb|bpdvW~JFA_zhI z8t?`@3Qxe}z>Gbqh*GX?RLw}^Z#u49XmM;K12lI5j9~&ZNZ_COvzJM36KtiWaf2no!~_Uyky% zsGm1SCG&E^ef>%%c~(}v-fz`twjMm((YmeMyY2VUm7PabT+Pa1Jbg>GmvMEKu>H!~ z{MwF_*V%Y}-g*4o7FC=T#+CjcT{Bb}g47e>l4 zj3Hy~5nE7{Pet^pik}$Dr=#C+T*z2^^y#4Z@uB$3ieD(oeI5HZE*w8l+&|6lz7{lA_hHDN#)xK|9Q)>(8m#3Aw7x-mF9YYplJDhb8a9ID6U48)MJ_J|%7xd=EKq!0#fm4UycuV%mi diff --git a/lib/src/.DS_Store b/lib/src/.DS_Store deleted file mode 100644 index 0420a37ad052416ab56fe966dcb2478230dd7270..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeHM%}*0S6o12qYzxTpQ6TDJBQYVNF(o1#jIk7qHXb09AOx`NwoBQ#?9|;Y6%f;l ze}f-aPo9l`fJZN0J$mpTFfpF-&CC|I%f}5vnwezg_jcyJeLKIIzR8;c0LfH};{X}} zC|DV)UD%vb*f^^vN=wkwk4VrSzy}LV@Uk{7oY0mXk^#wpWI!??8ITNI1_toVW<}`~ zC|k*ZWI!@-!~lyA8diqs0BZty=)i`j0Elha%?rwy2XGrLz;u8$f!q||DY6F=n35pH zAi^BSHKvZ34zMOrm;({!KmyMs$WRFPj&>SX2a*;jTgiZA;3NYqcULfHcX;j|%HIu} z8aT#&PWP~m9`b_HDf&j$D+l`DjIwQcek%2Yw6wOhU+GYkxDxMXdMd*{Mie87g2v9$b`lC}QivZA2Z>XBQzMB0r%`n8>hw74Ko z20gOhS>SjV3LFi(%}QLuB(1_u5E;qmdSv{ms`c0yi+6T)U+qzQ`}%tadJ~Dn;80?? z@7nde+HdHE=Ovd#xfyCxH)B`KyxQYo+{_lJGw+%^7$cW`^QE7&_Hd{#Vz6KqpB;BC z?v_z!;JAao^pR_t&T7fEigTNrp6M?$4+WRn_B{10-=fY+Xmn+bd-u)ltg}hcBm086 zGE?)GOxHs^VZXehyRPn(%*^h(tsAC2=VYkw)9qyoXTiRlJIIywg5{J(9{k1~gC#bS z9u<-bBSOGqMB7J!0hcugY z--o6cp{WDHhg zk^#xUrC@-x&E{q^_$l=~DEd|Gu3f{rft3}eR};uhu;JJ7i2OPpAJ}y~PvNjHg)%QF mr(7>dh)4})!yZwah%}V3)H5VH3%D~5JHu(M(~b^XNNp>MZdSvG5vmT*)faF&2GnR zyzVcTP5t6!@9oaP*Kgk!r^_Ed-Ec@@0XumX@DhH(xRs!jcv9rHID(&Z>sa(-I{b^a z-|$?g4OJ0gKo}4P?w^6M<>{yQ|10tb!hkUFz!>2D!9W?KfR#tLb)axh03cr@oxtYn zBIlTZQNYS0JP_qmfj(7*Cx-IrXg47)3Rrpc>7>HrLxnG^@Iq1U>*(LOa8i*+DTM)H z;3flgUv2aGzkT=n|7McZgaKjTzhXc&w&JY;h7``$mBH~@YoG^E7LKbtUZucrM=@gg dC|-v;LAzlC7zM06q6H!s0Y`%r!oWXe-~#WMZ94z}