From dc24ae7244e150be5473dfdee41fc31b53e53139 Mon Sep 17 00:00:00 2001 From: ag2s20150909 Date: Sat, 27 Mar 2021 20:13:47 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E4=BC=98=E5=8C=96epublib,=E6=B8=85?= =?UTF-8?q?=E9=99=A4=E8=AD=A6=E5=91=8A=EF=BC=8C=E5=B0=9D=E8=AF=95=E5=85=BC?= =?UTF-8?q?=E5=AE=B9epub=20v3=E6=A0=BC=E5=BC=8F=E7=9A=84=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epublib/src/main/AndroidManifest.xml | 5 +- .../main/java/me/ag2s/epublib/Constants.java | 2 +- .../browsersupport/NavigationEvent.java | 12 +- .../NavigationEventListener.java | 2 +- .../browsersupport/NavigationHistory.java | 22 +- .../epublib/browsersupport/Navigator.java | 21 +- .../java/me/ag2s/epublib/domain/Author.java | 112 +-- .../java/me/ag2s/epublib/domain/Book.java | 323 ++++++++ .../java/me/ag2s/epublib/domain/Date.java | 134 ++-- .../java/me/ag2s/epublib/domain/EpubBook.java | 314 +------- .../java/me/ag2s/epublib/domain/Guide.java | 10 +- .../ag2s/epublib/domain/GuideReference.java | 2 +- .../me/ag2s/epublib/domain/Identifier.java | 7 +- .../me/ag2s/epublib/domain/LazyResource.java | 7 +- .../domain/ManifestItemProperties.java | 4 +- .../domain/ManifestItemRefProperties.java | 4 +- .../me/ag2s/epublib/domain/MediaType.java | 12 +- .../me/ag2s/epublib/domain/MediaTypes.java | 11 +- .../java/me/ag2s/epublib/domain/Metadata.java | 429 +++++------ .../java/me/ag2s/epublib/domain/Resource.java | 18 +- .../epublib/domain/ResourceReference.java | 2 +- .../me/ag2s/epublib/domain/Resources.java | 689 +++++++++--------- .../java/me/ag2s/epublib/domain/Spine.java | 21 +- .../ag2s/epublib/domain/SpineReference.java | 74 +- .../me/ag2s/epublib/domain/TOCReference.java | 9 +- .../ag2s/epublib/domain/TableOfContents.java | 25 +- .../domain/TitledResourceReference.java | 148 ++-- .../me/ag2s/epublib/epub/BookProcessor.java | 4 +- .../epublib/epub/BookProcessorPipeline.java | 18 +- .../java/me/ag2s/epublib/epub/DOMUtil.java | 49 +- .../epublib/epub/EpubProcessorSupport.java | 215 +++--- .../java/me/ag2s/epublib/epub/EpubReader.java | 268 +++---- .../java/me/ag2s/epublib/epub/EpubWriter.java | 60 +- .../me/ag2s/epublib/epub/HtmlProcessor.java | 2 +- .../main/java/me/ag2s/epublib/epub/Main.java | 5 - .../me/ag2s/epublib/epub/NCXDocument.java | 296 -------- .../me/ag2s/epublib/epub/NCXDocumentV2.java | 574 ++++++++------- .../me/ag2s/epublib/epub/NCXDocumentV3.java | 376 ++++++++-- .../epublib/epub/PackageDocumentBase.java | 9 +- .../epub/PackageDocumentMetadataReader.java | 49 +- .../epub/PackageDocumentMetadataWriter.java | 44 +- .../epublib/epub/PackageDocumentReader.java | 94 ++- .../epublib/epub/PackageDocumentWriter.java | 407 +++++------ .../me/ag2s/epublib/epub/ResourcesLoader.java | 276 +++---- .../me/ag2s/epublib/util/CollectionUtil.java | 15 +- .../java/me/ag2s/epublib/util/IOUtil.java | 34 +- .../epublib/util/NoCloseOutputStream.java | 3 +- .../me/ag2s/epublib/util/NoCloseWriter.java | 5 +- .../me/ag2s/epublib/util/ResourceUtil.java | 293 ++++---- .../epublib/util/StreamWriterDelegate.txt | 202 ----- .../java/me/ag2s/epublib/util/StringUtil.java | 465 ++++++------ .../util/commons/io/BOMInputStream.java | 6 + .../util/commons/io/ByteOrderMark.java | 1 + .../util/commons/io/ProxyInputStream.java | 8 +- .../util/commons/io/XmlStreamReader.java | 21 +- .../commons/io/XmlStreamReaderException.java | 1 + 56 files changed, 3030 insertions(+), 3189 deletions(-) create mode 100644 epublib/src/main/java/me/ag2s/epublib/domain/Book.java delete mode 100644 epublib/src/main/java/me/ag2s/epublib/epub/Main.java delete mode 100644 epublib/src/main/java/me/ag2s/epublib/epub/NCXDocument.java delete mode 100644 epublib/src/main/java/me/ag2s/epublib/util/StreamWriterDelegate.txt diff --git a/epublib/src/main/AndroidManifest.xml b/epublib/src/main/AndroidManifest.xml index 827b5c1cd..f8f3d7bea 100644 --- a/epublib/src/main/AndroidManifest.xml +++ b/epublib/src/main/AndroidManifest.xml @@ -1,7 +1,4 @@ - - - + \ No newline at end of file diff --git a/epublib/src/main/java/me/ag2s/epublib/Constants.java b/epublib/src/main/java/me/ag2s/epublib/Constants.java index 37da37912..e26c56815 100644 --- a/epublib/src/main/java/me/ag2s/epublib/Constants.java +++ b/epublib/src/main/java/me/ag2s/epublib/Constants.java @@ -6,7 +6,7 @@ public interface Constants { String CHARACTER_ENCODING = "UTF-8"; String DOCTYPE_XHTML = ""; String NAMESPACE_XHTML = "http://www.w3.org/1999/xhtml"; - String EPUB4J_GENERATOR_NAME = "EpubLib"; + String EPUB_GENERATOR_NAME = "Ag2S EpubLib"; char FRAGMENT_SEPARATOR_CHAR = '#'; String DEFAULT_TOC_ID = "toc"; } diff --git a/epublib/src/main/java/me/ag2s/epublib/browsersupport/NavigationEvent.java b/epublib/src/main/java/me/ag2s/epublib/browsersupport/NavigationEvent.java index 54807e7c8..25d5fd46d 100644 --- a/epublib/src/main/java/me/ag2s/epublib/browsersupport/NavigationEvent.java +++ b/epublib/src/main/java/me/ag2s/epublib/browsersupport/NavigationEvent.java @@ -2,7 +2,7 @@ package me.ag2s.epublib.browsersupport; import java.util.EventObject; -import me.ag2s.epublib.domain.EpubBook; +import me.ag2s.epublib.domain.Book; import me.ag2s.epublib.domain.Resource; import me.ag2s.epublib.util.StringUtil; @@ -13,6 +13,7 @@ import me.ag2s.epublib.util.StringUtil; * @author paul * */ +@SuppressWarnings("unused") public class NavigationEvent extends EventObject { private static final long serialVersionUID = -6346750144308952762L; @@ -20,7 +21,7 @@ public class NavigationEvent extends EventObject { private Resource oldResource; private int oldSpinePos; private Navigator navigator; - private EpubBook oldBook; + private Book oldBook; private int oldSectionPos; private String oldFragmentId; @@ -60,7 +61,7 @@ public class NavigationEvent extends EventObject { this.oldFragmentId = oldFragmentId; } - public EpubBook getOldBook() { + public Book getOldBook() { return oldBook; } @@ -123,11 +124,11 @@ public class NavigationEvent extends EventObject { } - public void setOldBook(EpubBook oldBook) { + public void setOldBook(Book oldBook) { this.oldBook = oldBook; } - public EpubBook getCurrentBook() { + public Book getCurrentBook() { return getNavigator().getBook(); } @@ -135,6 +136,7 @@ public class NavigationEvent extends EventObject { return oldResource != getCurrentResource(); } + @SuppressWarnings("NullableProblems") public String toString() { return StringUtil.toString( "oldSectionPos", oldSectionPos, diff --git a/epublib/src/main/java/me/ag2s/epublib/browsersupport/NavigationEventListener.java b/epublib/src/main/java/me/ag2s/epublib/browsersupport/NavigationEventListener.java index 747d1999d..a856347ce 100644 --- a/epublib/src/main/java/me/ag2s/epublib/browsersupport/NavigationEventListener.java +++ b/epublib/src/main/java/me/ag2s/epublib/browsersupport/NavigationEventListener.java @@ -12,7 +12,7 @@ public interface NavigationEventListener { /** * Called whenever the user navigates to another position in the book. * - * @param navigationEvent + * @param navigationEvent f */ void navigationPerformed(NavigationEvent navigationEvent); } \ No newline at end of file diff --git a/epublib/src/main/java/me/ag2s/epublib/browsersupport/NavigationHistory.java b/epublib/src/main/java/me/ag2s/epublib/browsersupport/NavigationHistory.java index e362624a0..eec56dd6f 100644 --- a/epublib/src/main/java/me/ag2s/epublib/browsersupport/NavigationHistory.java +++ b/epublib/src/main/java/me/ag2s/epublib/browsersupport/NavigationHistory.java @@ -1,15 +1,15 @@ package me.ag2s.epublib.browsersupport; +import me.ag2s.epublib.domain.Book; +import me.ag2s.epublib.domain.Resource; import java.util.ArrayList; import java.util.List; -import me.ag2s.epublib.domain.EpubBook; -import me.ag2s.epublib.domain.Resource; - /** * A history of the user's locations with the epub. * * @author paul.siegmann + * */ public class NavigationHistory implements NavigationEventListener { @@ -36,8 +36,8 @@ public class NavigationHistory implements NavigationEventListener { } private long lastUpdateTime = 0; - private List locations = new ArrayList(); - private Navigator navigator; + private List locations = new ArrayList<>(); + private final Navigator navigator; private int currentPos = -1; private int currentSize = 0; private int maxHistorySize = DEFAULT_MAX_HISTORY_SIZE; @@ -58,11 +58,11 @@ public class NavigationHistory implements NavigationEventListener { return currentSize; } - public void initBook(EpubBook book) { + public void initBook(Book book) { if (book == null) { return; } - locations = new ArrayList(); + locations = new ArrayList<>(); currentPos = -1; currentSize = 0; if (navigator.getCurrentResource() != null) { @@ -103,8 +103,8 @@ public class NavigationHistory implements NavigationEventListener { *
* If this nr of locations becomes larger then the historySize then the * first item(s) will be removed. - * - * @param location + *v + * @param location d */ public void addLocation(Location location) { // do nothing if the new location matches the current location @@ -149,9 +149,9 @@ public class NavigationHistory implements NavigationEventListener { * Moves the current positions delta positions. * * move(-1) to go one position back in history.
- * move(1) to go one position forward.
+ * move(1) to go one position forward.
发 * - * @param delta + * @param delta f * * @return Whether we actually moved. If the requested value is illegal * it will return false, true otherwise. diff --git a/epublib/src/main/java/me/ag2s/epublib/browsersupport/Navigator.java b/epublib/src/main/java/me/ag2s/epublib/browsersupport/Navigator.java index 744588d0c..e73fbe166 100644 --- a/epublib/src/main/java/me/ag2s/epublib/browsersupport/Navigator.java +++ b/epublib/src/main/java/me/ag2s/epublib/browsersupport/Navigator.java @@ -1,12 +1,11 @@ package me.ag2s.epublib.browsersupport; +import me.ag2s.epublib.domain.Book; +import me.ag2s.epublib.domain.Resource; import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import me.ag2s.epublib.domain.EpubBook; -import me.ag2s.epublib.domain.Resource; - /** * A helper class for epub browser applications. * @@ -19,19 +18,19 @@ import me.ag2s.epublib.domain.Resource; public class Navigator implements Serializable { private static final long serialVersionUID = 1076126986424925474L; - private EpubBook book; + private Book book; private int currentSpinePos; private Resource currentResource; private int currentPagePos; private String currentFragmentId; - private List eventListeners = new ArrayList<>(); + private final List eventListeners = new ArrayList<>(); public Navigator() { this(null); } - public Navigator(EpubBook book) { + public Navigator(Book book) { this.book = book; this.currentSpinePos = 0; if (book != null) { @@ -136,8 +135,8 @@ public class Navigator implements Serializable { * Go to a specific section. * Illegal spine positions are silently ignored. * - * @param newSpinePos - * @param source + * @param newSpinePos f + * @param source f * @return The current position within the spine */ public int gotoSpineSection(int newSpinePos, int newPagePos, Object source) { @@ -159,7 +158,7 @@ public class Navigator implements Serializable { return gotoSpineSection(book.getSpine().size() - 1, source); } - public void gotoBook(EpubBook book, Object source) { + public void gotoBook(Book book, Object source) { NavigationEvent navigationEvent = new NavigationEvent(source, this); this.book = book; this.currentFragmentId = null; @@ -187,14 +186,14 @@ public class Navigator implements Serializable { * * If you want the eventListeners called use gotoSection(index); * - * @param currentIndex + * @param currentIndex f */ public void setCurrentSpinePos(int currentIndex) { this.currentSpinePos = currentIndex; this.currentResource = book.getSpine().getResource(currentIndex); } - public EpubBook getBook() { + public Book getBook() { return book; } diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/Author.java b/epublib/src/main/java/me/ag2s/epublib/domain/Author.java index dff314135..a604a5d08 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/Author.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/Author.java @@ -1,79 +1,89 @@ package me.ag2s.epublib.domain; + + import me.ag2s.epublib.util.StringUtil; + import java.io.Serializable; /** * Represents one of the authors of the book * * @author paul - * */ public class Author implements Serializable { - private static final long serialVersionUID = 6663408501416574200L; + private static final long serialVersionUID = 6663408501416574200L; - private String firstname; - private String lastname; - private Relator relator = Relator.AUTHOR; + private String firstname; + private String lastname; + private Relator relator = Relator.AUTHOR; - public Author(String singleName) { - this("", singleName); - } + public Author(String singleName) { + this("", singleName); + } + + public Author(String firstname, String lastname) { + this.firstname = firstname; + this.lastname = lastname; + } - public Author(String firstname, String lastname) { - this.firstname = firstname; - this.lastname = lastname; - } + public String getFirstname() { + return firstname; + } - public String getFirstname() { - return firstname; - } + public void setFirstname(String firstname) { + this.firstname = firstname; + } - public void setFirstname(String firstname) { - this.firstname = firstname; - } + public String getLastname() { + return lastname; + } - public String getLastname() { - return lastname; - } + public void setLastname(String lastname) { + this.lastname = lastname; + } - public void setLastname(String lastname) { - this.lastname = lastname; - } - public String toString() { - return lastname + ", " + firstname; - } + @Override + @SuppressWarnings("NullableProblems") + public String toString() { + return this.lastname + ", " + this.firstname; + } - public int hashCode() { - return StringUtil.hashCode(firstname, lastname); - } + public int hashCode() { + return StringUtil.hashCode(firstname, lastname); + } - public boolean equals(Object authorObject) { - if (!(authorObject instanceof Author)) { - return false; + public boolean equals(Object authorObject) { + if (!(authorObject instanceof Author)) { + return false; + } + Author other = (Author) authorObject; + return StringUtil.equals(firstname, other.firstname) + && StringUtil.equals(lastname, other.lastname); } - Author other = (Author) authorObject; - return StringUtil.equals(firstname, other.firstname) - && StringUtil.equals(lastname, other.lastname); - } - - public Relator setRole(String code) { - Relator result = Relator.byCode(code); - if (result == null) { - result = Relator.AUTHOR; + + /** + * 设置贡献者的角色 + * + * @param code 角色编号 + */ + + public void setRole(String code) { + Relator result = Relator.byCode(code); + if (result == null) { + result = Relator.AUTHOR; + } + this.relator = result; } - this.relator = result; - return result; - } - public Relator getRelator() { - return relator; - } + public Relator getRelator() { + return relator; + } - public void setRelator(Relator relator) { - this.relator = relator; - } + public void setRelator(Relator relator) { + this.relator = relator; + } } diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/Book.java b/epublib/src/main/java/me/ag2s/epublib/domain/Book.java new file mode 100644 index 000000000..24e79be79 --- /dev/null +++ b/epublib/src/main/java/me/ag2s/epublib/domain/Book.java @@ -0,0 +1,323 @@ +package me.ag2s.epublib.domain; + + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Representation of a Book. + *

+ * All resources of a Book (html, css, xml, fonts, images) are represented + * as Resources. See getResources() for access to these.
+ * A Book as 3 indexes into these Resources, as per the epub specification.
+ *

+ *
Spine
+ *
these are the Resources to be shown when a user reads the book from + * start to finish.
+ *
Table of Contents
+ *
The table of contents. Table of Contents references may be in a + * different order and contain different Resources than the spine, and often do. + *
Guide
+ *
The Guide has references to a set of special Resources like the + * cover page, the Glossary, the copyright page, etc. + *
+ *

+ * The complication is that these 3 indexes may and usually do point to + * different pages. + * A chapter may be split up in 2 pieces to fit it in to memory. Then the + * spine will contain both pieces, but the Table of Contents only the first. + *

+ * The Content page may be in the Table of Contents, the Guide, but not + * in the Spine. + * Etc. + *

+ *

+ * Please see the illustration at: doc/schema.svg + * + * @author paul + * @author jake + */ +public class Book implements Serializable { + + private static final long serialVersionUID = 2068355170895770100L; + + private Resources resources = new Resources(); + private Metadata metadata = new Metadata(); + private Spine spine = new Spine(); + private TableOfContents tableOfContents = new TableOfContents(); + private final Guide guide = new Guide(); + private Resource opfResource; + private Resource ncxResource; + private Resource coverImage; + + + private String version="2.0"; + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public boolean isEpub3() { + return this.version.startsWith("3."); + } + + @SuppressWarnings("UnusedReturnValue") + public TOCReference addSection( + TOCReference parentSection, String sectionTitle, Resource resource) { + return addSection(parentSection, sectionTitle, resource, null); + } + + /** + * Adds the resource to the table of contents of the book as a child + * section of the given parentSection + * + * @param parentSection parentSection + * @param sectionTitle sectionTitle + * @param resource resource + * @param fragmentId fragmentId + * @return The table of contents + */ + public TOCReference addSection( + TOCReference parentSection, String sectionTitle, Resource resource, + String fragmentId) { + getResources().add(resource); + if (spine.findFirstResourceById(resource.getId()) < 0) { + spine.addSpineReference(new SpineReference(resource)); + } + return parentSection.addChildSection( + new TOCReference(sectionTitle, resource, fragmentId)); + } + + public TOCReference addSection(String title, Resource resource) { + return addSection(title, resource, null); + } + + /** + * Adds a resource to the book's set of resources, table of contents and + * if there is no resource with the id in the spine also adds it to the spine. + * + * @param title title + * @param resource resource + * @param fragmentId fragmentId + * @return The table of contents + */ + public TOCReference addSection( + String title, Resource resource, String fragmentId) { + getResources().add(resource); + TOCReference tocReference = tableOfContents + .addTOCReference(new TOCReference(title, resource, fragmentId)); + if (spine.findFirstResourceById(resource.getId()) < 0) { + spine.addSpineReference(new SpineReference(resource)); + } + return tocReference; + } + + @SuppressWarnings("unused") + public void generateSpineFromTableOfContents() { + Spine spine = new Spine(tableOfContents); + + // in case the tocResource was already found and assigned + spine.setTocResource(this.spine.getTocResource()); + + this.spine = spine; + } + + /** + * The Book's metadata (titles, authors, etc) + * + * @return The Book's metadata (titles, authors, etc) + */ + public Metadata getMetadata() { + return metadata; + } + + public void setMetadata(Metadata metadata) { + this.metadata = metadata; + } + + + public void setResources(Resources resources) { + this.resources = resources; + } + + @SuppressWarnings("unused") + public Resource addResource(Resource resource) { + return resources.add(resource); + } + + /** + * The collection of all images, chapters, sections, xhtml files, + * stylesheets, etc that make up the book. + * + * @return The collection of all images, chapters, sections, xhtml files, + * stylesheets, etc that make up the book. + */ + public Resources getResources() { + return resources; + } + + + /** + * The sections of the book that should be shown if a user reads the book + * from start to finish. + * + * @return The Spine + */ + public Spine getSpine() { + return spine; + } + + + public void setSpine(Spine spine) { + this.spine = spine; + } + + + /** + * The Table of Contents of the book. + * + * @return The Table of Contents of the book. + */ + public TableOfContents getTableOfContents() { + return tableOfContents; + } + + + public void setTableOfContents(TableOfContents tableOfContents) { + this.tableOfContents = tableOfContents; + } + + /** + * The book's cover page as a Resource. + * An XHTML document containing a link to the cover image. + * + * @return The book's cover page as a Resource + */ + public Resource getCoverPage() { + Resource coverPage = guide.getCoverPage(); + if (coverPage == null) { + coverPage = spine.getResource(0); + } + return coverPage; + } + + + public void setCoverPage(Resource coverPage) { + if (coverPage == null) { + return; + } + if (resources.notContainsByHref(coverPage.getHref())) { + resources.add(coverPage); + } + guide.setCoverPage(coverPage); + } + + /** + * Gets the first non-blank title from the book's metadata. + * + * @return the first non-blank title from the book's metadata. + */ + public String getTitle() { + return getMetadata().getFirstTitle(); + } + + + /** + * The book's cover image. + * + * @return The book's cover image. + */ + public Resource getCoverImage() { + return coverImage; + } + + public void setCoverImage(Resource coverImage) { + if (coverImage == null) { + return; + } + if (resources.notContainsByHref(coverImage.getHref())) { + resources.add(coverImage); + } + this.coverImage = coverImage; + } + + /** + * The guide; contains references to special sections of the book like + * colophon, glossary, etc. + * + * @return The guide; contains references to special sections of the book + * like colophon, glossary, etc. + */ + public Guide getGuide() { + return guide; + } + + /** + * All Resources of the Book that can be reached via the Spine, the + * TableOfContents or the Guide. + *

+ * Consists of a list of "reachable" resources: + *

    + *
  • The coverpage
  • + *
  • The resources of the Spine that are not already in the result
  • + *
  • The resources of the Table of Contents that are not already in the + * result
  • + *
  • The resources of the Guide that are not already in the result
  • + *
+ * To get all html files that make up the epub file use + * {@link #getResources()} + * + * @return All Resources of the Book that can be reached via the Spine, + * the TableOfContents or the Guide. + */ + public List getContents() { + Map result = new LinkedHashMap<>(); + addToContentsResult(getCoverPage(), result); + + for (SpineReference spineReference : getSpine().getSpineReferences()) { + addToContentsResult(spineReference.getResource(), result); + } + + for (Resource resource : getTableOfContents().getAllUniqueResources()) { + addToContentsResult(resource, result); + } + + for (GuideReference guideReference : getGuide().getReferences()) { + addToContentsResult(guideReference.getResource(), result); + } + + return new ArrayList<>(result.values()); + } + + private static void addToContentsResult(Resource resource, + Map allReachableResources) { + if (resource != null && (!allReachableResources + .containsKey(resource.getHref()))) { + allReachableResources.put(resource.getHref(), resource); + } + } + + public Resource getOpfResource() { + return opfResource; + } + + public void setOpfResource(Resource opfResource) { + this.opfResource = opfResource; + } + + public void setNcxResource(Resource ncxResource) { + this.ncxResource = ncxResource; + } + + public Resource getNcxResource() { + return ncxResource; + } +} + diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/Date.java b/epublib/src/main/java/me/ag2s/epublib/domain/Date.java index 419dc4701..b72990bca 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/Date.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/Date.java @@ -1,104 +1,108 @@ package me.ag2s.epublib.domain; import me.ag2s.epublib.epub.PackageDocumentBase; + import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.Locale; /** * A Date used by the book's metadata. - * + *

* Examples: creation-date, modification-date, etc * * @author paul - * */ public class Date implements Serializable { - private static final long serialVersionUID = 7533866830395120136L; + private static final long serialVersionUID = 7533866830395120136L; - public enum Event { - PUBLICATION("publication"), - MODIFICATION("modification"), - CREATION("creation"); + public enum Event { + PUBLICATION("publication"), + MODIFICATION("modification"), + CREATION("creation"); - private final String value; + private final String value; - Event(String v) { - value = v; - } + Event(String v) { + value = v; + } - public static Event fromValue(String v) { - for (Event c : Event.values()) { - if (c.value.equals(v)) { - return c; + public static Event fromValue(String v) { + for (Event c : Event.values()) { + if (c.value.equals(v)) { + return c; + } + } + return null; } - } - return null; - } - public String toString() { - return value; + @Override + @SuppressWarnings("NullableProblems") + public String toString() { + return value; + } } - } - private Event event; - private String dateString; + private Event event; + private String dateString; - public Date(java.util.Date date) { - this(date, (Event) null); - } + public Date(java.util.Date date) { + this(date, (Event) null); + } - public Date(String dateString) { - this(dateString, (Event) null); - } + public Date(String dateString) { + this(dateString, (Event) null); + } - public Date(java.util.Date date, Event event) { - this((new SimpleDateFormat(PackageDocumentBase.dateFormat, Locale.US)).format(date), - event); - } + public Date(java.util.Date date, Event event) { + this((new SimpleDateFormat(PackageDocumentBase.dateFormat, Locale.US)).format(date), + event); + } - public Date(String dateString, Event event) { - this.dateString = dateString; - this.event = event; - } + public Date(String dateString, Event event) { + this.dateString = dateString; + this.event = event; + } - public Date(java.util.Date date, String event) { - this((new SimpleDateFormat(PackageDocumentBase.dateFormat,Locale.US)).format(date), - event); - } + public Date(java.util.Date date, String event) { + this((new SimpleDateFormat(PackageDocumentBase.dateFormat, Locale.US)).format(date), + event); + } - public Date(String dateString, String event) { - this(checkDate(dateString), Event.fromValue(event)); - this.dateString = dateString; - } + public Date(String dateString, String event) { + this(checkDate(dateString), Event.fromValue(event)); + this.dateString = dateString; + } - private static String checkDate(String dateString) { - if (dateString == null) { - throw new IllegalArgumentException( - "Cannot create a date from a blank string"); + private static String checkDate(String dateString) { + if (dateString == null) { + throw new IllegalArgumentException( + "Cannot create a date from a blank string"); + } + return dateString; } - return dateString; - } - public String getValue() { - return dateString; - } + public String getValue() { + return dateString; + } - public Event getEvent() { - return event; - } + public Event getEvent() { + return event; + } - public void setEvent(Event event) { - this.event = event; - } + public void setEvent(Event event) { + this.event = event; + } - public String toString() { - if (event == null) { - return dateString; + @Override + @SuppressWarnings("NullableProblems") + public String toString() { + if (event == null) { + return dateString; + } + return "" + event + ":" + dateString; } - return "" + event + ":" + dateString; - } } diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/EpubBook.java b/epublib/src/main/java/me/ag2s/epublib/domain/EpubBook.java index 271cc7b6f..e21cb0fa5 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/EpubBook.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/EpubBook.java @@ -1,316 +1,8 @@ package me.ag2s.epublib.domain; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - /** - * Representation of a Book. - * - * All resources of a Book (html, css, xml, fonts, images) are represented - * as Resources. See getResources() for access to these.
- * A Book as 3 indexes into these Resources, as per the epub specification.
- *

- *
Spine
- *
these are the Resources to be shown when a user reads the book from - * start to finish.
- *
Table of Contents
- *
The table of contents. Table of Contents references may be in a - * different order and contain different Resources than the spine, and often do. - *
Guide
- *
The Guide has references to a set of special Resources like the - * cover page, the Glossary, the copyright page, etc. - *
- *

- * The complication is that these 3 indexes may and usually do point to - * different pages. - * A chapter may be split up in 2 pieces to fit it in to memory. Then the - * spine will contain both pieces, but the Table of Contents only the first. - * - * The Content page may be in the Table of Contents, the Guide, but not - * in the Spine. - * Etc. - *

- * - * Please see the illustration at: doc/schema.svg - * - * @author paul - * @author jake + * 这个是用于其它与Book类同名时替换的 */ -public class EpubBook implements Serializable { - - private static final long serialVersionUID = 2068355170895770100L; - - private Resources resources = new Resources(); - private Metadata metadata = new Metadata(); - private Spine spine = new Spine(); - private TableOfContents tableOfContents = new TableOfContents(); - private Guide guide = new Guide(); - private Resource opfResource; - private Resource ncxResource; - private Resource coverImage; - - - - private String version; - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public TOCReference addSection( - TOCReference parentSection, String sectionTitle, Resource resource) { - return addSection(parentSection, sectionTitle, resource, null); - } - - /** - * Adds the resource to the table of contents of the book as a child - * section of the given parentSection - * - * @param parentSection - * @param sectionTitle - * @param resource - * @param fragmentId - * @return The table of contents - */ - public TOCReference addSection( - TOCReference parentSection, String sectionTitle, Resource resource, - String fragmentId) { - getResources().add(resource); - if (spine.findFirstResourceById(resource.getId()) < 0) { - spine.addSpineReference(new SpineReference(resource)); - } - return parentSection.addChildSection( - new TOCReference(sectionTitle, resource, fragmentId)); - } - - public TOCReference addSection(String title, Resource resource) { - return addSection(title, resource, null); - } - - /** - * Adds a resource to the book's set of resources, table of contents and - * if there is no resource with the id in the spine also adds it to the spine. - * - * @param title - * @param resource - * @param fragmentId - * @return The table of contents - */ - public TOCReference addSection( - String title, Resource resource, String fragmentId) { - getResources().add(resource); - TOCReference tocReference = tableOfContents - .addTOCReference(new TOCReference(title, resource, fragmentId)); - if (spine.findFirstResourceById(resource.getId()) < 0) { - spine.addSpineReference(new SpineReference(resource)); - } - return tocReference; - } - - public void generateSpineFromTableOfContents() { - Spine spine = new Spine(tableOfContents); - - // in case the tocResource was already found and assigned - spine.setTocResource(this.spine.getTocResource()); - - this.spine = spine; - } - - /** - * The Book's metadata (titles, authors, etc) - * - * @return The Book's metadata (titles, authors, etc) - */ - public Metadata getMetadata() { - return metadata; - } - - public void setMetadata(Metadata metadata) { - this.metadata = metadata; - } - - - public void setResources(Resources resources) { - this.resources = resources; - } - - - public Resource addResource(Resource resource) { - return resources.add(resource); - } - - /** - * The collection of all images, chapters, sections, xhtml files, - * stylesheets, etc that make up the book. - * - * @return The collection of all images, chapters, sections, xhtml files, - * stylesheets, etc that make up the book. - */ - public Resources getResources() { - return resources; - } - - - /** - * The sections of the book that should be shown if a user reads the book - * from start to finish. - * - * @return The Spine - */ - public Spine getSpine() { - return spine; - } - - - public void setSpine(Spine spine) { - this.spine = spine; - } - - - /** - * The Table of Contents of the book. - * - * @return The Table of Contents of the book. - */ - public TableOfContents getTableOfContents() { - return tableOfContents; - } - - - public void setTableOfContents(TableOfContents tableOfContents) { - this.tableOfContents = tableOfContents; - } - - /** - * The book's cover page as a Resource. - * An XHTML document containing a link to the cover image. - * - * @return The book's cover page as a Resource - */ - public Resource getCoverPage() { - Resource coverPage = guide.getCoverPage(); - if (coverPage == null) { - coverPage = spine.getResource(0); - } - return coverPage; - } - - - public void setCoverPage(Resource coverPage) { - if (coverPage == null) { - return; - } - if (!resources.containsByHref(coverPage.getHref())) { - resources.add(coverPage); - } - guide.setCoverPage(coverPage); - } - - /** - * Gets the first non-blank title from the book's metadata. - * - * @return the first non-blank title from the book's metadata. - */ - public String getTitle() { - return getMetadata().getFirstTitle(); - } - - - /** - * The book's cover image. - * - * @return The book's cover image. - */ - public Resource getCoverImage() { - return coverImage; - } - - public void setCoverImage(Resource coverImage) { - if (coverImage == null) { - return; - } - if (!resources.containsByHref(coverImage.getHref())) { - resources.add(coverImage); - } - this.coverImage = coverImage; - } - - /** - * The guide; contains references to special sections of the book like - * colophon, glossary, etc. - * - * @return The guide; contains references to special sections of the book - * like colophon, glossary, etc. - */ - public Guide getGuide() { - return guide; - } - - /** - * All Resources of the Book that can be reached via the Spine, the - * TableOfContents or the Guide. - *

- * Consists of a list of "reachable" resources: - *

    - *
  • The coverpage
  • - *
  • The resources of the Spine that are not already in the result
  • - *
  • The resources of the Table of Contents that are not already in the - * result
  • - *
  • The resources of the Guide that are not already in the result
  • - *
- * To get all html files that make up the epub file use - * {@link #getResources()} - * @return All Resources of the Book that can be reached via the Spine, - * the TableOfContents or the Guide. - */ - public List getContents() { - Map result = new LinkedHashMap(); - addToContentsResult(getCoverPage(), result); - - for (SpineReference spineReference : getSpine().getSpineReferences()) { - addToContentsResult(spineReference.getResource(), result); - } - - for (Resource resource : getTableOfContents().getAllUniqueResources()) { - addToContentsResult(resource, result); - } - - for (GuideReference guideReference : getGuide().getReferences()) { - addToContentsResult(guideReference.getResource(), result); - } - - return new ArrayList(result.values()); - } - - private static void addToContentsResult(Resource resource, - Map allReachableResources) { - if (resource != null && (!allReachableResources - .containsKey(resource.getHref()))) { - allReachableResources.put(resource.getHref(), resource); - } - } - - public Resource getOpfResource() { - return opfResource; - } - - public void setOpfResource(Resource opfResource) { - this.opfResource = opfResource; - } - - public void setNcxResource(Resource ncxResource) { - this.ncxResource = ncxResource; - } - - public Resource getNcxResource() { - return ncxResource; - } +@SuppressWarnings("unused declaration") +public class EpubBook extends Book { } - diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/Guide.java b/epublib/src/main/java/me/ag2s/epublib/domain/Guide.java index a6fab3879..57c0467a9 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/Guide.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/Guide.java @@ -25,7 +25,7 @@ public class Guide implements Serializable { public static final String DEFAULT_COVER_TITLE = GuideReference.COVER; - private List references = new ArrayList(); + private List references = new ArrayList<>(); private static final int COVERPAGE_NOT_FOUND = -1; private static final int COVERPAGE_UNITIALIZED = -2; @@ -51,7 +51,7 @@ public class Guide implements Serializable { } return null; } - + @SuppressWarnings("UnusedReturnValue") public int setCoverReference(GuideReference guideReference) { if (coverPageIndex >= 0) { references.set(coverPageIndex, guideReference); @@ -100,7 +100,7 @@ public class Guide implements Serializable { setCoverReference(coverpageGuideReference); } - + @SuppressWarnings("UnusedReturnValue") public ResourceReference addReference(GuideReference reference) { this.references.add(reference); uncheckCoverPage(); @@ -111,13 +111,13 @@ public class Guide implements Serializable { * A list of all GuideReferences that have the given * referenceTypeName (ignoring case). * - * @param referenceTypeName + * @param referenceTypeName referenceTypeName * @return A list of all GuideReferences that have the given * referenceTypeName (ignoring case). */ public List getGuideReferencesByType( String referenceTypeName) { - List result = new ArrayList(); + List result = new ArrayList<>(); for (GuideReference guideReference : references) { if (referenceTypeName.equalsIgnoreCase(guideReference.getType())) { result.add(guideReference); diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/GuideReference.java b/epublib/src/main/java/me/ag2s/epublib/domain/GuideReference.java index 2f009825d..89bd3ff12 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/GuideReference.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/GuideReference.java @@ -20,7 +20,7 @@ public class GuideReference extends TitledResourceReference /** * the book cover(s), jacket information, etc. */ - public static String COVER = "cover"; + public static final String COVER = "cover"; /** * human-readable page with title, author, publisher, and other metadata diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/Identifier.java b/epublib/src/main/java/me/ag2s/epublib/domain/Identifier.java index 626425655..ccb46186f 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/Identifier.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/Identifier.java @@ -15,7 +15,7 @@ import java.util.UUID; public class Identifier implements Serializable { private static final long serialVersionUID = 955949951416391810L; - + @SuppressWarnings("unused") public interface Scheme { String UUID = "UUID"; @@ -48,7 +48,7 @@ public class Identifier implements Serializable { * If no identifier has bookId == true then the first bookId identifier * is written as the primary. * - * @param identifiers + * @param identifiers i * @return The first identifier for which the bookId is true is made * the bookId identifier. */ @@ -119,7 +119,8 @@ public class Identifier implements Serializable { return StringUtil.equals(scheme, ((Identifier) otherIdentifier).scheme) && StringUtil.equals(value, ((Identifier) otherIdentifier).value); } - + @SuppressWarnings("NullableProblems") + @Override public String toString() { if (StringUtil.isBlank(scheme)) { return "" + value; diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/LazyResource.java b/epublib/src/main/java/me/ag2s/epublib/domain/LazyResource.java index d7629ee04..1c833401c 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/LazyResource.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/LazyResource.java @@ -3,7 +3,6 @@ package me.ag2s.epublib.domain; import android.util.Log; import me.ag2s.epublib.util.IOUtil; -//import io.documentnode.minilog.Logger; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -15,7 +14,7 @@ import java.io.InputStream; public class LazyResource extends Resource { private static final long serialVersionUID = 5089400472352002866L; - private static String TAG= LazyResource.class.getName(); + private final String TAG= getClass().getName(); private final LazyResourceProvider resourceProvider; private final long cachedSize; @@ -51,7 +50,7 @@ public class LazyResource extends Resource { * * @return The contents of the Resource. * - * @throws IOException + * @throws IOException IOException */ public InputStream getInputStream() throws IOException { if (isInitialized()) { @@ -64,7 +63,7 @@ public class LazyResource extends Resource { /** * Initializes the resource by loading its data into memory. * - * @throws IOException + * @throws IOException IOException */ public void initialize() throws IOException { getData(); diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/ManifestItemProperties.java b/epublib/src/main/java/me/ag2s/epublib/domain/ManifestItemProperties.java index 4d5e6151a..dd21eead5 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/ManifestItemProperties.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/ManifestItemProperties.java @@ -1,5 +1,5 @@ package me.ag2s.epublib.domain; - +@SuppressWarnings("unused") public enum ManifestItemProperties implements ManifestProperties { COVER_IMAGE("cover-image"), MATHML("mathml"), @@ -9,7 +9,7 @@ public enum ManifestItemProperties implements ManifestProperties { SVG("svg"), SWITCH("switch"); - private String name; + private final String name; ManifestItemProperties(String name) { this.name = name; diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/ManifestItemRefProperties.java b/epublib/src/main/java/me/ag2s/epublib/domain/ManifestItemRefProperties.java index 228cd71fd..b67d63f91 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/ManifestItemRefProperties.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/ManifestItemRefProperties.java @@ -1,10 +1,10 @@ package me.ag2s.epublib.domain; - +@SuppressWarnings("unused") public enum ManifestItemRefProperties implements ManifestProperties { PAGE_SPREAD_LEFT("page-spread-left"), PAGE_SPREAD_RIGHT("page-spread-right"); - private String name; + private final String name; ManifestItemRefProperties(String name) { this.name = name; diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/MediaType.java b/epublib/src/main/java/me/ag2s/epublib/domain/MediaType.java index 1e6163d6d..9a6817996 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/MediaType.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/MediaType.java @@ -18,9 +18,9 @@ import java.util.Collection; public class MediaType implements Serializable { private static final long serialVersionUID = -7256091153727506788L; - private String name; - private String defaultExtension; - private Collection extensions; + private final String name; + private final String defaultExtension; + private final Collection extensions; public MediaType(String name, String defaultExtension) { this(name, defaultExtension, new String[]{defaultExtension}); @@ -39,11 +39,11 @@ public class MediaType implements Serializable { } public MediaType(String name, String defaultExtension, - Collection extensions) { + Collection mextensions) { super(); this.name = name; this.defaultExtension = defaultExtension; - this.extensions = extensions; + this.extensions = mextensions; } public String getName() { @@ -66,7 +66,7 @@ public class MediaType implements Serializable { } return name.equals(((MediaType) otherMediaType).getName()); } - + @SuppressWarnings("NullableProblems") public String toString() { return name; } diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/MediaTypes.java b/epublib/src/main/java/me/ag2s/epublib/domain/MediaTypes.java index d221d5315..61d51ad64 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/MediaTypes.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/MediaTypes.java @@ -1,6 +1,5 @@ package me.ag2s.epublib.domain; -import me.ag2s.epublib.domain.MediaType; import me.ag2s.epublib.util.StringUtil; import java.util.HashMap; import java.util.Map; @@ -54,16 +53,16 @@ public class MediaTypes { public static final MediaType PLS = new MediaType("application/pls+xml", ".pls"); - public static MediaType[] mediaTypes = new MediaType[]{ + public static final MediaType[] mediaTypes = new MediaType[]{ XHTML, EPUB, JPG, PNG, GIF, CSS, SVG, TTF, NCX, XPGT, OPENTYPE, WOFF, SMIL, PLS, JAVASCRIPT, MP3, MP4, OGG }; - public static Map mediaTypesByName = new HashMap(); + public static final Map mediaTypesByName = new HashMap<>(); static { - for (int i = 0; i < mediaTypes.length; i++) { - mediaTypesByName.put(mediaTypes[i].getName(), mediaTypes[i]); + for (MediaType mediaType : mediaTypes) { + mediaTypesByName.put(mediaType.getName(), mediaType); } } @@ -75,7 +74,7 @@ public class MediaTypes { * Gets the MediaType based on the file extension. * Null of no matching extension found. * - * @param filename + * @param filename filename * @return the MediaType based on the file extension. */ public static MediaType determineMediaType(String filename) { diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/Metadata.java b/epublib/src/main/java/me/ag2s/epublib/domain/Metadata.java index e2d1168ec..71c995dbe 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/Metadata.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/Metadata.java @@ -1,11 +1,13 @@ package me.ag2s.epublib.domain; import me.ag2s.epublib.util.StringUtil; + import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; + import javax.xml.namespace.QName; /** @@ -17,214 +19,223 @@ import javax.xml.namespace.QName; */ public class Metadata implements Serializable { - private static final long serialVersionUID = -2437262888962149444L; - - public static final String DEFAULT_LANGUAGE = "en"; - - private boolean autoGeneratedId = true; - private List authors = new ArrayList(); - private List contributors = new ArrayList(); - private List dates = new ArrayList(); - private String language = DEFAULT_LANGUAGE; - private Map otherProperties = new HashMap(); - private List rights = new ArrayList(); - private List titles = new ArrayList(); - private List identifiers = new ArrayList(); - private List subjects = new ArrayList(); - private String format = MediaTypes.EPUB.getName(); - private List types = new ArrayList(); - private List descriptions = new ArrayList(); - private List publishers = new ArrayList(); - private Map metaAttributes = new HashMap(); - - public Metadata() { - identifiers.add(new Identifier()); - autoGeneratedId = true; - } - - public boolean isAutoGeneratedId() { - return autoGeneratedId; - } - - /** - * Metadata properties not hard-coded like the author, title, etc. - * - * @return Metadata properties not hard-coded like the author, title, etc. - */ - public Map getOtherProperties() { - return otherProperties; - } - - public void setOtherProperties(Map otherProperties) { - this.otherProperties = otherProperties; - } - - public Date addDate(Date date) { - this.dates.add(date); - return date; - } - - public List getDates() { - return dates; - } - - public void setDates(List dates) { - this.dates = dates; - } - - public Author addAuthor(Author author) { - authors.add(author); - return author; - } - - public List getAuthors() { - return authors; - } - - public void setAuthors(List authors) { - this.authors = authors; - } - - public Author addContributor(Author contributor) { - contributors.add(contributor); - return contributor; - } - - public List getContributors() { - return contributors; - } - - public void setContributors(List contributors) { - this.contributors = contributors; - } - - public String getLanguage() { - return language; - } - - public void setLanguage(String language) { - this.language = language; - } - - public List getSubjects() { - return subjects; - } - - public void setSubjects(List subjects) { - this.subjects = subjects; - } - - public void setRights(List rights) { - this.rights = rights; - } - - public List getRights() { - return rights; - } - - - /** - * Gets the first non-blank title of the book. - * Will return "" if no title found. - * - * @return the first non-blank title of the book. - */ - public String getFirstTitle() { - if (titles == null || titles.isEmpty()) { - return ""; - } - for (String title : titles) { - if (StringUtil.isNotBlank(title)) { + private static final long serialVersionUID = -2437262888962149444L; + + public static final String DEFAULT_LANGUAGE = "en"; + + private boolean autoGeneratedId;//true; + private List authors = new ArrayList<>(); + private List contributors = new ArrayList<>(); + private List dates = new ArrayList<>(); + private String language = DEFAULT_LANGUAGE; + private Map otherProperties = new HashMap<>(); + private List rights = new ArrayList<>(); + private List titles = new ArrayList<>(); + private List identifiers = new ArrayList<>(); + private List subjects = new ArrayList<>(); + private String format = MediaTypes.EPUB.getName(); + private List types = new ArrayList<>(); + private List descriptions = new ArrayList<>(); + private List publishers = new ArrayList<>(); + private Map metaAttributes = new HashMap<>(); + + public Metadata() { + identifiers.add(new Identifier()); + autoGeneratedId = true; + } + + @SuppressWarnings("unused") + public boolean isAutoGeneratedId() { + return autoGeneratedId; + } + + /** + * Metadata properties not hard-coded like the author, title, etc. + * + * @return Metadata properties not hard-coded like the author, title, etc. + */ + public Map getOtherProperties() { + return otherProperties; + } + + public void setOtherProperties(Map otherProperties) { + this.otherProperties = otherProperties; + } + + @SuppressWarnings("unused") + public Date addDate(Date date) { + this.dates.add(date); + return date; + } + + public List getDates() { + return dates; + } + + public void setDates(List dates) { + this.dates = dates; + } + + @SuppressWarnings("UnusedReturnValue") + public Author addAuthor(Author author) { + authors.add(author); + return author; + } + + public List getAuthors() { + return authors; + } + + public void setAuthors(List authors) { + this.authors = authors; + } + + @SuppressWarnings("UnusedReturnValue") + public Author addContributor(Author contributor) { + contributors.add(contributor); + return contributor; + } + + public List getContributors() { + return contributors; + } + + public void setContributors(List contributors) { + this.contributors = contributors; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public List getSubjects() { + return subjects; + } + + public void setSubjects(List subjects) { + this.subjects = subjects; + } + + public void setRights(List rights) { + this.rights = rights; + } + + public List getRights() { + return rights; + } + + + /** + * Gets the first non-blank title of the book. + * Will return "" if no title found. + * + * @return the first non-blank title of the book. + */ + public String getFirstTitle() { + if (titles == null || titles.isEmpty()) { + return ""; + } + for (String title : titles) { + if (StringUtil.isNotBlank(title)) { + return title; + } + } + return ""; + } + + public String addTitle(String title) { + this.titles.add(title); return title; - } - } - return ""; - } - - public String addTitle(String title) { - this.titles.add(title); - return title; - } - - public void setTitles(List titles) { - this.titles = titles; - } - - public List getTitles() { - return titles; - } - - public String addPublisher(String publisher) { - this.publishers.add(publisher); - return publisher; - } - - public void setPublishers(List publishers) { - this.publishers = publishers; - } - - public List getPublishers() { - return publishers; - } - - public String addDescription(String description) { - this.descriptions.add(description); - return description; - } - - public void setDescriptions(List descriptions) { - this.descriptions = descriptions; - } - - public List getDescriptions() { - return descriptions; - } - - public Identifier addIdentifier(Identifier identifier) { - if (autoGeneratedId && (!(identifiers.isEmpty()))) { - identifiers.set(0, identifier); - } else { - identifiers.add(identifier); - } - autoGeneratedId = false; - return identifier; - } - - public void setIdentifiers(List identifiers) { - this.identifiers = identifiers; - autoGeneratedId = false; - } - - public List getIdentifiers() { - return identifiers; - } - - public void setFormat(String format) { - this.format = format; - } - - public String getFormat() { - return format; - } - - public String addType(String type) { - this.types.add(type); - return type; - } - - public List getTypes() { - return types; - } - - public void setTypes(List types) { - this.types = types; - } - - public String getMetaAttribute(String name) { - return metaAttributes.get(name); - } - - public void setMetaAttributes(Map metaAttributes) { - this.metaAttributes = metaAttributes; - } + } + + public void setTitles(List titles) { + this.titles = titles; + } + + public List getTitles() { + return titles; + } + + @SuppressWarnings("UnusedReturnValue") + public String addPublisher(String publisher) { + this.publishers.add(publisher); + return publisher; + } + + public void setPublishers(List publishers) { + this.publishers = publishers; + } + + public List getPublishers() { + return publishers; + } + + @SuppressWarnings("UnusedReturnValue") + public String addDescription(String description) { + this.descriptions.add(description); + return description; + } + + public void setDescriptions(List descriptions) { + this.descriptions = descriptions; + } + + public List getDescriptions() { + return descriptions; + } + + @SuppressWarnings("unused") + public Identifier addIdentifier(Identifier identifier) { + if (autoGeneratedId && (!(identifiers.isEmpty()))) { + identifiers.set(0, identifier); + } else { + identifiers.add(identifier); + } + autoGeneratedId = false; + return identifier; + } + + public void setIdentifiers(List identifiers) { + this.identifiers = identifiers; + autoGeneratedId = false; + } + + public List getIdentifiers() { + return identifiers; + } + + public void setFormat(String format) { + this.format = format; + } + + public String getFormat() { + return format; + } + + @SuppressWarnings("UnusedReturnValue") + public String addType(String type) { + this.types.add(type); + return type; + } + + public List getTypes() { + return types; + } + + public void setTypes(List types) { + this.types = types; + } + + @SuppressWarnings("unused") + public String getMetaAttribute(String name) { + return metaAttributes.get(name); + } + + public void setMetaAttributes(Map metaAttributes) { + this.metaAttributes = metaAttributes; + } } diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/Resource.java b/epublib/src/main/java/me/ag2s/epublib/domain/Resource.java index 648bfd8e5..4820a7aff 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/Resource.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/Resource.java @@ -27,9 +27,9 @@ public class Resource implements Serializable { private String properties; - protected String originalHref; + protected final String originalHref; private MediaType mediaType; - private String inputEncoding = Constants.CHARACTER_ENCODING; + private String inputEncoding; protected byte[] data; /** @@ -147,7 +147,7 @@ public class Resource implements Serializable { * * @return The contents of the Resource. * - * @throws IOException + * @throws IOException IOException */ public InputStream getInputStream() throws IOException { return new ByteArrayInputStream(getData()); @@ -174,7 +174,7 @@ public class Resource implements Serializable { * Sets the data of the Resource. * If the data is a of a different type then the original data then make sure to change the MediaType. * - * @param data + * @param data the data of the Resource */ public void setData(byte[] data) { this.data = data; @@ -201,7 +201,7 @@ public class Resource implements Serializable { /** * Sets the Resource's id: Make sure it is unique and a valid identifier. * - * @param id + * @param id Resource's id */ public void setId(String id) { this.id = id; @@ -233,7 +233,7 @@ public class Resource implements Serializable { /** * Sets the Resource's href. * - * @param href + * @param href Resource's href. */ public void setHref(String href) { this.href = href; @@ -252,7 +252,7 @@ public class Resource implements Serializable { /** * Sets the Resource's input character encoding. * - * @param encoding + * @param encoding Resource's input character encoding. */ public void setInputEncoding(String encoding) { this.inputEncoding = encoding; @@ -264,7 +264,7 @@ public class Resource implements Serializable { * Does all sorts of smart things (courtesy of apache commons io XMLStreamREader) to handle encodings, byte order markers, etc. * * @return the contents of the Resource as Reader. - * @throws IOException + * @throws IOException IOException */ public Reader getReader() throws IOException { return new XmlStreamReader(new ByteArrayInputStream(getData()), @@ -315,7 +315,7 @@ public class Resource implements Serializable { public void setProperties(String properties) { this.properties = properties; } - + @SuppressWarnings("NullableProblems") public String toString() { return StringUtil.toString("id", id, "title", title, diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/ResourceReference.java b/epublib/src/main/java/me/ag2s/epublib/domain/ResourceReference.java index ea54d9749..f09c97643 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/ResourceReference.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/ResourceReference.java @@ -20,7 +20,7 @@ public class ResourceReference implements Serializable { /** * Besides setting the resource it also sets the fragmentId to null. * - * @param resource + * @param resource resource */ public void setResource(Resource resource) { this.resource = resource; diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/Resources.java b/epublib/src/main/java/me/ag2s/epublib/domain/Resources.java index f4125b4d9..7566f4f3a 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/Resources.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/Resources.java @@ -2,6 +2,7 @@ package me.ag2s.epublib.domain; import me.ag2s.epublib.Constants; import me.ag2s.epublib.util.StringUtil; + import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; @@ -15,373 +16,387 @@ import java.util.Map; * XHTML files, images and epub xml documents must be here. * * @author paul - * */ public class Resources implements Serializable { - private static final long serialVersionUID = 2450876953383871451L; - private static final String IMAGE_PREFIX = "image_"; - private static final String ITEM_PREFIX = "item_"; - private int lastId = 1; - - private Map resources = new HashMap<>(); - - /** - * Adds a resource to the resources. - * - * Fixes the resources id and href if necessary. - * - * @param resource - * @return the newly added resource - */ - public Resource add(Resource resource) { - fixResourceHref(resource); - fixResourceId(resource); - this.resources.put(resource.getHref(), resource); - return resource; - } - - /** - * Checks the id of the given resource and changes to a unique identifier if it isn't one already. - * - * @param resource - */ - public void fixResourceId(Resource resource) { - String resourceId = resource.getId(); - - // first try and create a unique id based on the resource's href - if (StringUtil.isBlank(resource.getId())) { - resourceId = StringUtil.substringBeforeLast(resource.getHref(), '.'); - resourceId = StringUtil.substringAfterLast(resourceId, '/'); + private static final long serialVersionUID = 2450876953383871451L; + private static final String IMAGE_PREFIX = "image_"; + private static final String ITEM_PREFIX = "item_"; + private int lastId = 1; + + private Map resources = new HashMap<>(); + + /** + * Adds a resource to the resources. + *

+ * Fixes the resources id and href if necessary. + * + * @param resource resource + * @return the newly added resource + */ + public Resource add(Resource resource) { + fixResourceHref(resource); + fixResourceId(resource); + this.resources.put(resource.getHref(), resource); + return resource; } - resourceId = makeValidId(resourceId, resource); + /** + * Checks the id of the given resource and changes to a unique identifier if it isn't one already. + * + * @param resource resource + */ + public void fixResourceId(Resource resource) { + String resourceId = resource.getId(); + + // first try and create a unique id based on the resource's href + if (StringUtil.isBlank(resource.getId())) { + resourceId = StringUtil.substringBeforeLast(resource.getHref(), '.'); + resourceId = StringUtil.substringAfterLast(resourceId, '/'); + } + + resourceId = makeValidId(resourceId, resource); + + // check if the id is unique. if not: create one from scratch + if (StringUtil.isBlank(resourceId) || containsId(resourceId)) { + resourceId = createUniqueResourceId(resource); + } + resource.setId(resourceId); + } - // check if the id is unique. if not: create one from scratch - if (StringUtil.isBlank(resourceId) || containsId(resourceId)) { - resourceId = createUniqueResourceId(resource); + /** + * Check if the id is a valid identifier. if not: prepend with valid identifier + * + * @param resource resource + * @return a valid id + */ + private String makeValidId(String resourceId, Resource resource) { + if (StringUtil.isNotBlank(resourceId) && !Character + .isJavaIdentifierStart(resourceId.charAt(0))) { + resourceId = getResourceItemPrefix(resource) + resourceId; + } + return resourceId; } - resource.setId(resourceId); - } - - /** - * Check if the id is a valid identifier. if not: prepend with valid identifier - * - * @param resource - * @return a valid id - */ - private String makeValidId(String resourceId, Resource resource) { - if (StringUtil.isNotBlank(resourceId) && !Character - .isJavaIdentifierStart(resourceId.charAt(0))) { - resourceId = getResourceItemPrefix(resource) + resourceId; + + private String getResourceItemPrefix(Resource resource) { + String result; + if (MediaTypes.isBitmapImage(resource.getMediaType())) { + result = IMAGE_PREFIX; + } else { + result = ITEM_PREFIX; + } + return result; } - return resourceId; - } - - private String getResourceItemPrefix(Resource resource) { - String result; - if (MediaTypes.isBitmapImage(resource.getMediaType())) { - result = IMAGE_PREFIX; - } else { - result = ITEM_PREFIX; + + /** + * Creates a new resource id that is guaranteed to be unique for this set of Resources + * + * @param resource resource + * @return a new resource id that is guaranteed to be unique for this set of Resources + */ + private String createUniqueResourceId(Resource resource) { + int counter = lastId; + if (counter == Integer.MAX_VALUE) { + if (resources.size() == Integer.MAX_VALUE) { + throw new IllegalArgumentException( + "Resources contains " + Integer.MAX_VALUE + + " elements: no new elements can be added"); + } else { + counter = 1; + } + } + String prefix = getResourceItemPrefix(resource); + String result = prefix + counter; + while (containsId(result)) { + result = prefix + (++counter); + } + lastId = counter; + return result; } - return result; - } - - /** - * Creates a new resource id that is guaranteed to be unique for this set of Resources - * - * @param resource - * @return a new resource id that is guaranteed to be unique for this set of Resources - */ - private String createUniqueResourceId(Resource resource) { - int counter = lastId; - if (counter == Integer.MAX_VALUE) { - if (resources.size() == Integer.MAX_VALUE) { - throw new IllegalArgumentException( - "Resources contains " + Integer.MAX_VALUE - + " elements: no new elements can be added"); - } else { - counter = 1; - } + + /** + * Whether the map of resources already contains a resource with the given id. + * + * @param id id + * @return Whether the map of resources already contains a resource with the given id. + */ + public boolean containsId(String id) { + if (StringUtil.isBlank(id)) { + return false; + } + for (Resource resource : resources.values()) { + if (id.equals(resource.getId())) { + return true; + } + } + return false; } - String prefix = getResourceItemPrefix(resource); - String result = prefix + counter; - while (containsId(result)) { - result = prefix + (++counter); + + /** + * Gets the resource with the given id. + * + * @param id id + * @return null if not found + */ + public Resource getById(String id) { + if (StringUtil.isBlank(id)) { + return null; + } + for (Resource resource : resources.values()) { + if (id.equals(resource.getId())) { + return resource; + } + } + return null; } - lastId = counter; - return result; - } - - /** - * Whether the map of resources already contains a resource with the given id. - * - * @param id - * @return Whether the map of resources already contains a resource with the given id. - */ - public boolean containsId(String id) { - if (StringUtil.isBlank(id)) { - return false; + + public Resource getByProperties(String properties) { + if (StringUtil.isBlank(properties)) { + return null; + } + for (Resource resource : resources.values()) { + if (properties.equals(resource.getProperties())) { + return resource; + } + } + return null; } - for (Resource resource : resources.values()) { - if (id.equals(resource.getId())) { - return true; - } + + /** + * Remove the resource with the given href. + * + * @param href href + * @return the removed resource, null if not found + */ + public Resource remove(String href) { + return resources.remove(href); } - return false; - } - - /** - * Gets the resource with the given id. - * - * @param id - * @return null if not found - */ - public Resource getById(String id) { - if (StringUtil.isBlank(id)) { - return null; + + private void fixResourceHref(Resource resource) { + if (StringUtil.isNotBlank(resource.getHref()) + && !resources.containsKey(resource.getHref())) { + return; + } + if (StringUtil.isBlank(resource.getHref())) { + if (resource.getMediaType() == null) { + throw new IllegalArgumentException( + "Resource must have either a MediaType or a href"); + } + int i = 1; + String href = createHref(resource.getMediaType(), i); + while (resources.containsKey(href)) { + href = createHref(resource.getMediaType(), (++i)); + } + resource.setHref(href); + } } - for (Resource resource : resources.values()) { - if (id.equals(resource.getId())) { - return resource; - } + + private String createHref(MediaType mediaType, int counter) { + if (MediaTypes.isBitmapImage(mediaType)) { + return "image_" + counter + mediaType.getDefaultExtension(); + } else { + return "item_" + counter + mediaType.getDefaultExtension(); + } } - return null; - } - public Resource getByProperties(String properties) { - if (StringUtil.isBlank(properties)) { - return null; + + + public boolean isEmpty() { + return resources.isEmpty(); } - for (Resource resource : resources.values()) { - if (properties.equals(resource.getProperties())) { - return resource; - } + + /** + * The number of resources + * + * @return The number of resources + */ + public int size() { + return resources.size(); } - return null; - } - - /** - * Remove the resource with the given href. - * - * @param href - * @return the removed resource, null if not found - */ - public Resource remove(String href) { - return resources.remove(href); - } - - private void fixResourceHref(Resource resource) { - if (StringUtil.isNotBlank(resource.getHref()) - && !resources.containsKey(resource.getHref())) { - return; + + /** + * The resources that make up this book. + * Resources can be xhtml pages, images, xml documents, etc. + * + * @return The resources that make up this book. + */ + @SuppressWarnings("unused") + public Map getResourceMap() { + return resources; } - if (StringUtil.isBlank(resource.getHref())) { - if (resource.getMediaType() == null) { - throw new IllegalArgumentException( - "Resource must have either a MediaType or a href"); - } - int i = 1; - String href = createHref(resource.getMediaType(), i); - while (resources.containsKey(href)) { - href = createHref(resource.getMediaType(), (++i)); - } - resource.setHref(href); + + public Collection getAll() { + return resources.values(); } - } - private String createHref(MediaType mediaType, int counter) { - if (MediaTypes.isBitmapImage(mediaType)) { - return "image_" + counter + mediaType.getDefaultExtension(); - } else { - return "item_" + counter + mediaType.getDefaultExtension(); + + /** + * Whether there exists a resource with the given href + * + * @param href href + * @return Whether there exists a resource with the given href + */ + public boolean notContainsByHref(String href) { + if (StringUtil.isBlank(href)) { + return true; + } else { + return !resources.containsKey( + StringUtil.substringBefore(href, Constants.FRAGMENT_SEPARATOR_CHAR)); + } } - } - - - public boolean isEmpty() { - return resources.isEmpty(); - } - - /** - * The number of resources - * @return The number of resources - */ - public int size() { - return resources.size(); - } - - /** - * The resources that make up this book. - * Resources can be xhtml pages, images, xml documents, etc. - * - * @return The resources that make up this book. - */ - public Map getResourceMap() { - return resources; - } - - public Collection getAll() { - return resources.values(); - } - - - /** - * Whether there exists a resource with the given href - * @param href - * @return Whether there exists a resource with the given href - */ - public boolean containsByHref(String href) { - if (StringUtil.isBlank(href)) { - return false; + /** + * Whether there exists a resource with the given href + * + * @param href href + * @return Whether there exists a resource with the given href + */ + @SuppressWarnings("unused") + public boolean containsByHref(String href) { + return !notContainsByHref(href); } - return resources.containsKey( - StringUtil.substringBefore(href, Constants.FRAGMENT_SEPARATOR_CHAR)); - } - - /** - * Sets the collection of Resources to the given collection of resources - * - * @param resources - */ - public void set(Collection resources) { - this.resources.clear(); - addAll(resources); - } - - /** - * Adds all resources from the given Collection of resources to the existing collection. - * - * @param resources - */ - public void addAll(Collection resources) { - for (Resource resource : resources) { - fixResourceHref(resource); - this.resources.put(resource.getHref(), resource); + + /** + * Sets the collection of Resources to the given collection of resources + * + * @param resources resources + */ + public void set(Collection resources) { + this.resources.clear(); + addAll(resources); } - } - - /** - * Sets the collection of Resources to the given collection of resources - * - * @param resources A map with as keys the resources href and as values the Resources - */ - public void set(Map resources) { - this.resources = new HashMap(resources); - } - - - /** - * First tries to find a resource with as id the given idOrHref, if that - * fails it tries to find one with the idOrHref as href. - * - * @param idOrHref - * @return the found Resource - */ - public Resource getByIdOrHref(String idOrHref) { - Resource resource = getById(idOrHref); - if (resource == null) { - resource = getByHref(idOrHref); + + /** + * Adds all resources from the given Collection of resources to the existing collection. + * + * @param resources resources + */ + public void addAll(Collection resources) { + for (Resource resource : resources) { + fixResourceHref(resource); + this.resources.put(resource.getHref(), resource); + } } - return resource; - } - - - /** - * Gets the resource with the given href. - * If the given href contains a fragmentId then that fragment id will be ignored. - * - * @param href - * @return null if not found. - */ - public Resource getByHref(String href) { - if (StringUtil.isBlank(href)) { - return null; + + /** + * Sets the collection of Resources to the given collection of resources + * + * @param resources A map with as keys the resources href and as values the Resources + */ + public void set(Map resources) { + this.resources = new HashMap<>(resources); } - href = StringUtil.substringBefore(href, Constants.FRAGMENT_SEPARATOR_CHAR); - Resource result = resources.get(href); - return result; - } - - /** - * Gets the first resource (random order) with the give mediatype. - * - * Useful for looking up the table of contents as it's supposed to be the only resource with NCX mediatype. - * - * @param mediaType - * @return the first resource (random order) with the give mediatype. - */ - public Resource findFirstResourceByMediaType(MediaType mediaType) { - return findFirstResourceByMediaType(resources.values(), mediaType); - } - - /** - * Gets the first resource (random order) with the give mediatype. - * - * Useful for looking up the table of contents as it's supposed to be the only resource with NCX mediatype. - * - * @param mediaType - * @return the first resource (random order) with the give mediatype. - */ - public static Resource findFirstResourceByMediaType( - Collection resources, MediaType mediaType) { - for (Resource resource : resources) { - if (resource.getMediaType() == mediaType) { + + + /** + * First tries to find a resource with as id the given idOrHref, if that + * fails it tries to find one with the idOrHref as href. + * + * @param idOrHref idOrHref + * @return the found Resource + */ + public Resource getByIdOrHref(String idOrHref) { + Resource resource = getById(idOrHref); + if (resource == null) { + resource = getByHref(idOrHref); + } return resource; - } } - return null; - } - - /** - * All resources that have the given MediaType. - * - * @param mediaType - * @return All resources that have the given MediaType. - */ - public List getResourcesByMediaType(MediaType mediaType) { - List result = new ArrayList(); - if (mediaType == null) { - return result; + + + /** + * Gets the resource with the given href. + * If the given href contains a fragmentId then that fragment id will be ignored. + * + * @param href href + * @return null if not found. + */ + public Resource getByHref(String href) { + if (StringUtil.isBlank(href)) { + return null; + } + href = StringUtil.substringBefore(href, Constants.FRAGMENT_SEPARATOR_CHAR); + return resources.get(href); + } + + /** + * Gets the first resource (random order) with the give mediatype. + *

+ * Useful for looking up the table of contents as it's supposed to be the only resource with NCX mediatype. + * + * @param mediaType mediaType + * @return the first resource (random order) with the give mediatype. + */ + public Resource findFirstResourceByMediaType(MediaType mediaType) { + return findFirstResourceByMediaType(resources.values(), mediaType); + } + + /** + * Gets the first resource (random order) with the give mediatype. + *

+ * Useful for looking up the table of contents as it's supposed to be the only resource with NCX mediatype. + * + * @param mediaType mediaType + * @return the first resource (random order) with the give mediatype. + */ + public static Resource findFirstResourceByMediaType( + Collection resources, MediaType mediaType) { + for (Resource resource : resources) { + if (resource.getMediaType() == mediaType) { + return resource; + } + } + return null; } - for (Resource resource : getAll()) { - if (resource.getMediaType() == mediaType) { - result.add(resource); - } + + /** + * All resources that have the given MediaType. + * + * @param mediaType mediaType + * @return All resources that have the given MediaType. + */ + public List getResourcesByMediaType(MediaType mediaType) { + List result = new ArrayList<>(); + if (mediaType == null) { + return result; + } + for (Resource resource : getAll()) { + if (resource.getMediaType() == mediaType) { + result.add(resource); + } + } + return result; } - return result; - } - - /** - * All Resources that match any of the given list of MediaTypes - * - * @param mediaTypes - * @return All Resources that match any of the given list of MediaTypes - */ - public List getResourcesByMediaTypes(MediaType[] mediaTypes) { - List result = new ArrayList(); - if (mediaTypes == null) { - return result; + + /** + * All Resources that match any of the given list of MediaTypes + * + * @param mediaTypes mediaType + * @return All Resources that match any of the given list of MediaTypes + */ + @SuppressWarnings("unused") + public List getResourcesByMediaTypes(MediaType[] mediaTypes) { + List result = new ArrayList<>(); + if (mediaTypes == null) { + return result; + } + + // this is the fastest way of doing this according to + // http://stackoverflow.com/questions/1128723/in-java-how-can-i-test-if-an-array-contains-a-certain-value + List mediaTypesList = Arrays.asList(mediaTypes); + for (Resource resource : getAll()) { + if (mediaTypesList.contains(resource.getMediaType())) { + result.add(resource); + } + } + return result; } - // this is the fastest way of doing this according to - // http://stackoverflow.com/questions/1128723/in-java-how-can-i-test-if-an-array-contains-a-certain-value - List mediaTypesList = Arrays.asList(mediaTypes); - for (Resource resource : getAll()) { - if (mediaTypesList.contains(resource.getMediaType())) { - result.add(resource); - } + + /** + * All resource hrefs + * + * @return all resource hrefs + */ + public Collection getAllHrefs() { + return resources.keySet(); } - return result; - } - - - /** - * All resource hrefs - * - * @return all resource hrefs - */ - public Collection getAllHrefs() { - return resources.keySet(); - } } diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/Spine.java b/epublib/src/main/java/me/ag2s/epublib/domain/Spine.java index 7f25a986c..293837086 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/Spine.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/Spine.java @@ -22,13 +22,13 @@ public class Spine implements Serializable { private List spineReferences; public Spine() { - this(new ArrayList()); + this(new ArrayList<>()); } /** * Creates a spine out of all the resources in the table of contents. * - * @param tableOfContents + * @param tableOfContents tableOfContents */ public Spine(TableOfContents tableOfContents) { this.spineReferences = createSpineReferences( @@ -41,8 +41,8 @@ public class Spine implements Serializable { public static List createSpineReferences( Collection resources) { - List result = new ArrayList( - resources.size()); + List result = new ArrayList<>( + resources.size()); for (Resource resource : resources) { result.add(new SpineReference(resource)); } @@ -61,7 +61,7 @@ public class Spine implements Serializable { * Gets the resource at the given index. * Null if not found. * - * @param index + * @param index index * @return the resource at the given index. */ public Resource getResource(int index) { @@ -76,7 +76,7 @@ public class Spine implements Serializable { * * Null if not found. * - * @param resourceId + * @param resourceId resourceId * @return the first resource that has the given resourceId. */ public int findFirstResourceById(String resourceId) { @@ -96,12 +96,12 @@ public class Spine implements Serializable { /** * Adds the given spineReference to the spine references and returns it. * - * @param spineReference + * @param spineReference spineReference * @return the given spineReference */ public SpineReference addSpineReference(SpineReference spineReference) { if (spineReferences == null) { - this.spineReferences = new ArrayList(); + this.spineReferences = new ArrayList<>(); } spineReferences.add(spineReference); return spineReference; @@ -112,6 +112,7 @@ public class Spine implements Serializable { * * @return the given spineReference */ + @SuppressWarnings("unused") public SpineReference addResource(Resource resource) { return addSpineReference(new SpineReference(resource)); } @@ -130,7 +131,7 @@ public class Spine implements Serializable { * The epubwriter will look for it here first, followed by some clever tricks to find it elsewhere if not found. * Put it here to be sure of the expected behaviours. * - * @param tocResource + * @param tocResource tocResource */ public void setTocResource(Resource tocResource) { this.tocResource = tocResource; @@ -149,7 +150,7 @@ public class Spine implements Serializable { /** * The position within the spine of the given resource. * - * @param currentResource + * @param currentResource currentResource * @return something < 0 if not found. * */ diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/SpineReference.java b/epublib/src/main/java/me/ag2s/epublib/domain/SpineReference.java index 9c9c9d00f..135e4e6bf 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/SpineReference.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/SpineReference.java @@ -11,42 +11,42 @@ import java.io.Serializable; */ public class SpineReference extends ResourceReference implements Serializable { - private static final long serialVersionUID = -7921609197351510248L; - private boolean linear = true; - - public SpineReference(Resource resource) { - this(resource, true); - } - - - public SpineReference(Resource resource, boolean linear) { - super(resource); - this.linear = linear; - } - - /** - * Linear denotes whether the section is Primary or Auxiliary. - * Usually the cover page has linear set to false and all the other sections - * have it set to true. - * - * It's an optional property that readers may also ignore. - * - *

primary or auxiliary is useful for Reading Systems which - * opt to present auxiliary content differently than primary content. - * For example, a Reading System might opt to render auxiliary content in - * a popup window apart from the main window which presents the primary - * content. (For an example of the types of content that may be considered - * auxiliary, refer to the example below and the subsequent discussion.)
- * @see OPF Spine specification - * - * @return whether the section is Primary or Auxiliary. - */ - public boolean isLinear() { - return linear; - } - - public void setLinear(boolean linear) { - this.linear = linear; - } + private static final long serialVersionUID = -7921609197351510248L; + private boolean linear;//default = true; + + public SpineReference(Resource resource) { + this(resource, true); + } + + + public SpineReference(Resource resource, boolean linear) { + super(resource); + this.linear = linear; + } + + /** + * Linear denotes whether the section is Primary or Auxiliary. + * Usually the cover page has linear set to false and all the other sections + * have it set to true. + *

+ * It's an optional property that readers may also ignore. + * + *

primary or auxiliary is useful for Reading Systems which + * opt to present auxiliary content differently than primary content. + * For example, a Reading System might opt to render auxiliary content in + * a popup window apart from the main window which presents the primary + * content. (For an example of the types of content that may be considered + * auxiliary, refer to the example below and the subsequent discussion.)
+ * + * @return whether the section is Primary or Auxiliary. + * @see OPF Spine specification + */ + public boolean isLinear() { + return linear; + } + + public void setLinear(boolean linear) { + this.linear = linear; + } } diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/TOCReference.java b/epublib/src/main/java/me/ag2s/epublib/domain/TOCReference.java index b55ef8122..5fe9c71bb 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/TOCReference.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/TOCReference.java @@ -17,11 +17,8 @@ public class TOCReference extends TitledResourceReference private static final long serialVersionUID = 5787958246077042456L; private List children; - private static final Comparator COMPARATOR_BY_TITLE_IGNORE_CASE = - (tocReference1, tocReference2) -> - String.CASE_INSENSITIVE_ORDER - .compare(tocReference1.getTitle(), tocReference2.getTitle()); - + private static final Comparator COMPARATOR_BY_TITLE_IGNORE_CASE = (tocReference1, tocReference2) -> String.CASE_INSENSITIVE_ORDER.compare(tocReference1.getTitle(), tocReference2.getTitle()); + @Deprecated public TOCReference() { this(null, null, null); } @@ -39,7 +36,7 @@ public class TOCReference extends TitledResourceReference super(resource, title, fragmentId); this.children = children; } - + @SuppressWarnings("unused") public static Comparator getComparatorByTitleIgnoreCase() { return COMPARATOR_BY_TITLE_IGNORE_CASE; } diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/TableOfContents.java b/epublib/src/main/java/me/ag2s/epublib/domain/TableOfContents.java index 0be7c123e..6c268358d 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/TableOfContents.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/TableOfContents.java @@ -29,7 +29,7 @@ public class TableOfContents implements Serializable { private List tocReferences; public TableOfContents() { - this(new ArrayList()); + this(new ArrayList<>()); } public TableOfContents(List tocReferences) { @@ -48,6 +48,7 @@ public class TableOfContents implements Serializable { * Calls addTOCReferenceAtLocation after splitting the path using the DEFAULT_PATH_SEPARATOR. * @return the new TOCReference */ + @SuppressWarnings("unused") public TOCReference addSection(Resource resource, String path) { return addSection(resource, path, DEFAULT_PATH_SEPARATOR); } @@ -55,9 +56,9 @@ public class TableOfContents implements Serializable { /** * Calls addTOCReferenceAtLocation after splitting the path using the given pathSeparator. * - * @param resource - * @param path - * @param pathSeparator + * @param resource resource + * @param path path + * @param pathSeparator pathSeparator * @return the new TOCReference */ public TOCReference addSection(Resource resource, String path, @@ -69,8 +70,8 @@ public class TableOfContents implements Serializable { /** * Finds the first TOCReference in the given list that has the same title as the given Title. * - * @param title - * @param tocReferences + * @param title title + * @param tocReferences tocReferences * @return null if not found. */ private static TOCReference findTocReferenceByTitle(String title, @@ -95,8 +96,8 @@ public class TableOfContents implements Serializable { * will point to the given Resource * * - * @param resource - * @param pathElements + * @param resource resource + * @param pathElements pathElements * @return the new TOCReference */ public TOCReference addSection(Resource resource, String[] pathElements) { @@ -105,8 +106,7 @@ public class TableOfContents implements Serializable { } TOCReference result = null; List currentTocReferences = this.tocReferences; - for (int i = 0; i < pathElements.length; i++) { - String currentTitle = pathElements[i]; + for (String currentTitle : pathElements) { result = findTocReferenceByTitle(currentTitle, currentTocReferences); if (result == null) { result = new TOCReference(currentTitle, null); @@ -130,10 +130,11 @@ public class TableOfContents implements Serializable { * If this TOCReference didn't exist yet it will be created and have a title of "" * * - * @param resource - * @param pathElements + * @param resource resource + * @param pathElements pathElements * @return the new TOCReference */ + @SuppressWarnings("unused") public TOCReference addSection(Resource resource, int[] pathElements, String sectionTitlePrefix, String sectionNumberSeparator) { if (pathElements == null || pathElements.length == 0) { diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/TitledResourceReference.java b/epublib/src/main/java/me/ag2s/epublib/domain/TitledResourceReference.java index 4496fa73e..cba1ed83f 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/TitledResourceReference.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/TitledResourceReference.java @@ -2,77 +2,87 @@ package me.ag2s.epublib.domain; import me.ag2s.epublib.Constants; import me.ag2s.epublib.util.StringUtil; + import java.io.Serializable; public class TitledResourceReference extends ResourceReference - implements Serializable { - - private static final long serialVersionUID = 3918155020095190080L; - private String fragmentId; - private String title; - - public TitledResourceReference(Resource resource) { - this(resource, null); - } - - public TitledResourceReference(Resource resource, String title) { - this(resource, title, null); - } - - public TitledResourceReference(Resource resource, String title, - String fragmentId) { - super(resource); - this.title = title; - this.fragmentId = fragmentId; - } - - public String getFragmentId() { - return fragmentId; - } - - public void setFragmentId(String fragmentId) { - this.fragmentId = fragmentId; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - - /** - * If the fragmentId is blank it returns the resource href, otherwise - * it returns the resource href + '#' + the fragmentId. - * - * @return If the fragmentId is blank it returns the resource href, - * otherwise it returns the resource href + '#' + the fragmentId. - */ - public String getCompleteHref() { - if (StringUtil.isBlank(fragmentId)) { - return resource.getHref(); - } else { - return resource.getHref() + Constants.FRAGMENT_SEPARATOR_CHAR - + fragmentId; + implements Serializable { + + private static final long serialVersionUID = 3918155020095190080L; + private String fragmentId; + private String title; + + /** + * 这会使title为null + * + * @param resource resource + */ + @Deprecated + @SuppressWarnings("unused") + public TitledResourceReference(Resource resource) { + this(resource, null); + } + + public TitledResourceReference(Resource resource, String title) { + this(resource, title, null); + } + + public TitledResourceReference(Resource resource, String title, + String fragmentId) { + super(resource); + this.title = title; + this.fragmentId = fragmentId; + } + + public String getFragmentId() { + return fragmentId; + } + + public void setFragmentId(String fragmentId) { + this.fragmentId = fragmentId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + + /** + * If the fragmentId is blank it returns the resource href, otherwise + * it returns the resource href + '#' + the fragmentId. + * + * @return If the fragmentId is blank it returns the resource href, + * otherwise it returns the resource href + '#' + the fragmentId. + */ + public String getCompleteHref() { + if (StringUtil.isBlank(fragmentId)) { + return resource.getHref(); + } else { + return resource.getHref() + Constants.FRAGMENT_SEPARATOR_CHAR + + fragmentId; + } + } + + @Override + public Resource getResource() { + //修复getTitle为null的bug + resource.setTitle(title); + return resource; + } + + public void setResource(Resource resource, String fragmentId) { + super.setResource(resource); + this.fragmentId = fragmentId; + } + + /** + * Sets the resource to the given resource and sets the fragmentId to null. + */ + public void setResource(Resource resource) { + setResource(resource, null); } - } - @Override - public Resource getResource() { - resource.setTitle(title); - return resource; - } - - public void setResource(Resource resource, String fragmentId) { - super.setResource(resource); - this.fragmentId = fragmentId; - } - - /** - * Sets the resource to the given resource and sets the fragmentId to null. - */ - public void setResource(Resource resource) { - setResource(resource, null); - } } diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/BookProcessor.java b/epublib/src/main/java/me/ag2s/epublib/epub/BookProcessor.java index 219c566c9..5a44dfdcf 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/BookProcessor.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/BookProcessor.java @@ -1,6 +1,6 @@ package me.ag2s.epublib.epub; -import me.ag2s.epublib.domain.EpubBook; +import me.ag2s.epublib.domain.Book; /** * Post-processes a book. @@ -16,5 +16,5 @@ public interface BookProcessor { */ BookProcessor IDENTITY_BOOKPROCESSOR = book -> book; - EpubBook processBook(EpubBook book); + Book processBook(Book book); } diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/BookProcessorPipeline.java b/epublib/src/main/java/me/ag2s/epublib/epub/BookProcessorPipeline.java index 44dfdf092..ee9ff3ba5 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/BookProcessorPipeline.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/BookProcessorPipeline.java @@ -2,25 +2,23 @@ package me.ag2s.epublib.epub; import android.util.Log; +import me.ag2s.epublib.domain.Book; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import me.ag2s.epublib.domain.EpubBook; - -//import io.documentnode.minilog.Logger; - /** * A book processor that combines several other bookprocessors - *

+ * * Fixes coverpage/coverimage. * Cleans up the XHTML. * * @author paul.siegmann */ +@SuppressWarnings("unused declaration") public class BookProcessorPipeline implements BookProcessor { - private static String TAG= BookProcessorPipeline.class.getName(); + private static final String TAG= BookProcessorPipeline.class.getName(); private List bookProcessors; public BookProcessorPipeline() { @@ -32,7 +30,7 @@ public class BookProcessorPipeline implements BookProcessor { } @Override - public EpubBook processBook(EpubBook book) { + public Book processBook(Book book) { if (bookProcessors == null) { return book; } @@ -40,7 +38,7 @@ public class BookProcessorPipeline implements BookProcessor { try { book = bookProcessor.processBook(book); } catch (Exception e) { - Log.e(TAG, e.getMessage(), e); + Log.e(TAG,e.getMessage(), e); } } return book; @@ -48,14 +46,14 @@ public class BookProcessorPipeline implements BookProcessor { public void addBookProcessor(BookProcessor bookProcessor) { if (this.bookProcessors == null) { - bookProcessors = new ArrayList(); + bookProcessors = new ArrayList<>(); } this.bookProcessors.add(bookProcessor); } public void addBookProcessors(Collection bookProcessors) { if (this.bookProcessors == null) { - this.bookProcessors = new ArrayList(); + this.bookProcessors = new ArrayList<>(); } this.bookProcessors.addAll(bookProcessors); } diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/DOMUtil.java b/epublib/src/main/java/me/ag2s/epublib/epub/DOMUtil.java index 37702c1ae..34e826abc 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/DOMUtil.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/DOMUtil.java @@ -21,10 +21,10 @@ class DOMUtil { /** * First tries to get the attribute value by doing an getAttributeNS on the element, if that gets an empty element it does a getAttribute without namespace. * - * @param element - * @param namespace - * @param attribute - * @return + * @param element element + * @param namespace namespace + * @param attribute attribute + * @return String Attribute */ public static String getAttribute(Element element, String namespace, String attribute) { @@ -38,16 +38,17 @@ class DOMUtil { /** * Gets all descendant elements of the given parentElement with the given namespace and tagname and returns their text child as a list of String. * - * @param parentElement - * @param namespace - * @param tagname - * @return + * @param parentElement parentElement + * @param namespace namespace + * @param tagName tagName + * @return List */ public static List getElementsTextChild(Element parentElement, - String namespace, String tagname) { + String namespace, String tagName) { NodeList elements = parentElement - .getElementsByTagNameNS(namespace, tagname); - List result = new ArrayList(elements.getLength()); + .getElementsByTagNameNS(namespace, tagName); + //ArrayList 初始化时指定长度提高性能 + List result = new ArrayList<>(elements.getLength()); for (int i = 0; i < elements.getLength(); i++) { result.add(getTextChildrenContent((Element) elements.item(i))); } @@ -58,13 +59,13 @@ class DOMUtil { * Finds in the current document the first element with the given namespace and elementName and with the given findAttributeName and findAttributeValue. * It then returns the value of the given resultAttributeName. * - * @param document - * @param namespace - * @param elementName - * @param findAttributeName - * @param findAttributeValue - * @param resultAttributeName - * @return + * @param document document + * @param namespace namespace + * @param elementName elementName + * @param findAttributeName findAttributeName + * @param findAttributeValue findAttributeValue + * @param resultAttributeName resultAttributeName + * @return String value */ public static String getFindAttributeValue(Document document, String namespace, String elementName, String findAttributeName, @@ -85,10 +86,10 @@ class DOMUtil { /** * Gets the first element that is a child of the parentElement and has the given namespace and tagName * - * @param parentElement - * @param namespace - * @param tagName - * @return + * @param parentElement parentElement + * @param namespace namespace + * @param tagName tagName + * @return Element */ public static Element getFirstElementByTagNameNS(Element parentElement, String namespace, String tagName) { @@ -111,8 +112,8 @@ class DOMUtil { * when the text is Chinese characters then on Android each Characater is represented in the DOM as * an individual Text node. * - * @param parentElement - * @return + * @param parentElement parentElement + * @return String value */ public static String getTextChildrenContent(Element parentElement) { if (parentElement == null) { diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/EpubProcessorSupport.java b/epublib/src/main/java/me/ag2s/epublib/epub/EpubProcessorSupport.java index e0fc6e983..dd741cc4c 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/EpubProcessorSupport.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/EpubProcessorSupport.java @@ -3,7 +3,7 @@ package me.ag2s.epublib.epub; import android.util.Log; import me.ag2s.epublib.Constants; -//import io.documentnode.minilog.Logger; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -11,13 +11,14 @@ import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.URL; +import java.util.Objects; + import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -//import org.kxml2.io.KXmlSerializer; + import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; -import org.xml.sax.SAXException; import org.xmlpull.v1.XmlPullParserFactory; import org.xmlpull.v1.XmlSerializer; @@ -25,114 +26,114 @@ import org.xmlpull.v1.XmlSerializer; * Various low-level support methods for reading/writing epubs. * * @author paul.siegmann - * */ public class EpubProcessorSupport { - private static String TAG= EpubProcessorSupport.class.getName(); - - protected static DocumentBuilderFactory documentBuilderFactory; - - static { - init(); - } - - static class EntityResolverImpl implements EntityResolver { - - private String previousLocation; - - @Override - public InputSource resolveEntity(String publicId, String systemId) - throws SAXException, IOException { - String resourcePath; - if (systemId.startsWith("http:")) { - URL url = new URL(systemId); - resourcePath = "dtd/" + url.getHost() + url.getPath(); - previousLocation = resourcePath - .substring(0, resourcePath.lastIndexOf('/')); - } else { - resourcePath = - previousLocation + systemId.substring(systemId.lastIndexOf('/')); - } - - if (this.getClass().getClassLoader().getResource(resourcePath) == null) { - throw new RuntimeException( - "remote resource is not cached : [" + systemId - + "] cannot continue"); - } - - InputStream in = EpubProcessorSupport.class.getClassLoader() - .getResourceAsStream(resourcePath); - return new InputSource(in); + private static final String TAG = EpubProcessorSupport.class.getName(); + + protected static DocumentBuilderFactory documentBuilderFactory; + + static { + init(); + } + + static class EntityResolverImpl implements EntityResolver { + + private String previousLocation; + + @Override + public InputSource resolveEntity(String publicId, String systemId) + throws IOException { + String resourcePath; + if (systemId.startsWith("http:")) { + URL url = new URL(systemId); + resourcePath = "dtd/" + url.getHost() + url.getPath(); + previousLocation = resourcePath + .substring(0, resourcePath.lastIndexOf('/')); + } else { + resourcePath = + previousLocation + systemId.substring(systemId.lastIndexOf('/')); + } + + if (Objects.requireNonNull(this.getClass().getClassLoader()).getResource(resourcePath) == null) { + throw new RuntimeException( + "remote resource is not cached : [" + systemId + + "] cannot continue"); + } + + InputStream in = Objects.requireNonNull(EpubProcessorSupport.class.getClassLoader()) + .getResourceAsStream(resourcePath); + return new InputSource(in); + } } - } - - - private static void init() { - EpubProcessorSupport.documentBuilderFactory = DocumentBuilderFactory - .newInstance(); - documentBuilderFactory.setNamespaceAware(true); - documentBuilderFactory.setValidating(false); - } - - public static XmlSerializer createXmlSerializer(OutputStream out) - throws UnsupportedEncodingException { - return createXmlSerializer( - new OutputStreamWriter(out, Constants.CHARACTER_ENCODING)); - } - - public static XmlSerializer createXmlSerializer(Writer out) { - XmlSerializer result = null; - try { - /* - * Disable XmlPullParserFactory here before it doesn't work when - * building native image using GraalVM - */ - XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); - factory.setValidating(true); - result = factory.newSerializer(); - - //result = new KXmlSerializer(); - result.setFeature( - "http://xmlpull.org/v1/doc/features.html#indent-output", true); - result.setOutput(out); - } catch (Exception e) { - Log.e(TAG, - "When creating XmlSerializer: " + e.getClass().getName() + ": " + e - .getMessage()); + + + private static void init() { + EpubProcessorSupport.documentBuilderFactory = DocumentBuilderFactory + .newInstance(); + documentBuilderFactory.setNamespaceAware(true); + documentBuilderFactory.setValidating(false); } - return result; - } - - /** - * Gets an EntityResolver that loads dtd's and such from the epub4j classpath. - * In order to enable the loading of relative urls the given EntityResolver contains the previousLocation. - * Because of a new EntityResolver is created every time this method is called. - * Fortunately the EntityResolver created uses up very little memory per instance. - * - * @return an EntityResolver that loads dtd's and such from the epub4j classpath. - */ - public static EntityResolver getEntityResolver() { - return new EntityResolverImpl(); - } - - public DocumentBuilderFactory getDocumentBuilderFactory() { - return documentBuilderFactory; - } - - /** - * Creates a DocumentBuilder that looks up dtd's and schema's from epub4j's classpath. - * - * @return a DocumentBuilder that looks up dtd's and schema's from epub4j's classpath. - */ - public static DocumentBuilder createDocumentBuilder() { - DocumentBuilder result = null; - try { - result = documentBuilderFactory.newDocumentBuilder(); - result.setEntityResolver(getEntityResolver()); - } catch (ParserConfigurationException e) { - Log.e(TAG,e.getMessage()); + + public static XmlSerializer createXmlSerializer(OutputStream out) + throws UnsupportedEncodingException { + return createXmlSerializer( + new OutputStreamWriter(out, Constants.CHARACTER_ENCODING)); + } + + public static XmlSerializer createXmlSerializer(Writer out) { + XmlSerializer result = null; + try { + /* + * Disable XmlPullParserFactory here before it doesn't work when + * building native image using GraalVM + */ + XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); + factory.setValidating(true); + result = factory.newSerializer(); + + //result = new KXmlSerializer(); + result.setFeature( + "http://xmlpull.org/v1/doc/features.html#indent-output", true); + result.setOutput(out); + } catch (Exception e) { + Log.e(TAG, + "When creating XmlSerializer: " + e.getClass().getName() + ": " + e + .getMessage()); + } + return result; + } + + /** + * Gets an EntityResolver that loads dtd's and such from the epub4j classpath. + * In order to enable the loading of relative urls the given EntityResolver contains the previousLocation. + * Because of a new EntityResolver is created every time this method is called. + * Fortunately the EntityResolver created uses up very little memory per instance. + * + * @return an EntityResolver that loads dtd's and such from the epub4j classpath. + */ + public static EntityResolver getEntityResolver() { + return new EntityResolverImpl(); + } + + @SuppressWarnings("unused") + public DocumentBuilderFactory getDocumentBuilderFactory() { + return documentBuilderFactory; + } + + /** + * Creates a DocumentBuilder that looks up dtd's and schema's from epub4j's classpath. + * + * @return a DocumentBuilder that looks up dtd's and schema's from epub4j's classpath. + */ + public static DocumentBuilder createDocumentBuilder() { + DocumentBuilder result = null; + try { + result = documentBuilderFactory.newDocumentBuilder(); + result.setEntityResolver(getEntityResolver()); + } catch (ParserConfigurationException e) { + Log.e(TAG, e.getMessage()); + } + return result; } - return result; - } } diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/EpubReader.java b/epublib/src/main/java/me/ag2s/epublib/epub/EpubReader.java index 2e96ceecb..fe9411d09 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/EpubReader.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/EpubReader.java @@ -13,7 +13,7 @@ import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; import me.ag2s.epublib.Constants; -import me.ag2s.epublib.domain.EpubBook; +import me.ag2s.epublib.domain.Book; import me.ag2s.epublib.domain.MediaType; import me.ag2s.epublib.domain.MediaTypes; import me.ag2s.epublib.domain.Resource; @@ -21,150 +21,156 @@ import me.ag2s.epublib.domain.Resources; import me.ag2s.epublib.util.ResourceUtil; import me.ag2s.epublib.util.StringUtil; -//import io.documentnode.minilog.Logger; - /** * Reads an epub file. * * @author paul - * */ public class EpubReader { - private static String TAG= EpubReader.class.getName(); - private BookProcessor bookProcessor = BookProcessor.IDENTITY_BOOKPROCESSOR; - - public EpubBook readEpub(InputStream in) throws IOException { - return readEpub(in, Constants.CHARACTER_ENCODING); - } - - public EpubBook readEpub(ZipInputStream in) throws IOException { - return readEpub(in, Constants.CHARACTER_ENCODING); - } - - public EpubBook readEpub(ZipFile zipfile) throws IOException { - return readEpub(zipfile, Constants.CHARACTER_ENCODING); - } - - /** - * Read epub from inputstream - * - * @param in the inputstream from which to read the epub - * @param encoding the encoding to use for the html files within the epub - * @return the Book as read from the inputstream - * @throws IOException - */ - public EpubBook readEpub(InputStream in, String encoding) throws IOException { - return readEpub(new ZipInputStream(in), encoding); - } - - - /** - * Reads this EPUB without loading any resources into memory. - * - * @param zipFile the file to load - * @param encoding the encoding for XHTML files - * @return this Book without loading all resources into memory. - * @throws IOException - */ - public EpubBook readEpubLazy(ZipFile zipFile, String encoding) - throws IOException { - return readEpubLazy(zipFile, encoding, - Arrays.asList(MediaTypes.mediaTypes)); - } - - public EpubBook readEpub(ZipInputStream in, String encoding) throws IOException { - return readEpub(ResourcesLoader.loadResources(in, encoding)); - } - - public EpubBook readEpub(ZipFile in, String encoding) throws IOException { - return readEpub(ResourcesLoader.loadResources(in, encoding)); - } - - /** - * Reads this EPUB without loading all resources into memory. - * - * @param zipFile the file to load - * @param encoding the encoding for XHTML files - * @param lazyLoadedTypes a list of the MediaType to load lazily - * @return this Book without loading all resources into memory. - * @throws IOException - */ - public EpubBook readEpubLazy(ZipFile zipFile, String encoding, - List lazyLoadedTypes) throws IOException { - Resources resources = ResourcesLoader - .loadResources(zipFile, encoding, lazyLoadedTypes); - return readEpub(resources); - } - - public EpubBook readEpub(Resources resources) throws IOException { - return readEpub(resources, new EpubBook()); - } - - public EpubBook readEpub(Resources resources, EpubBook result) throws IOException { - if (result == null) { - result = new EpubBook(); + private static final String TAG = EpubReader.class.getName(); + private final BookProcessor bookProcessor = BookProcessor.IDENTITY_BOOKPROCESSOR; + + public Book readEpub(InputStream in) throws IOException { + return readEpub(in, Constants.CHARACTER_ENCODING); + } + + @SuppressWarnings("unused") + public Book readEpub(ZipInputStream in) throws IOException { + return readEpub(in, Constants.CHARACTER_ENCODING); + } + + @SuppressWarnings("unused") + public Book readEpub(ZipFile zipfile) throws IOException { + return readEpub(zipfile, Constants.CHARACTER_ENCODING); + } + + /** + * Read epub from inputstream + * + * @param in the inputstream from which to read the epub + * @param encoding the encoding to use for the html files within the epub + * @return the Book as read from the inputstream + * @throws IOException IOException + */ + public Book readEpub(InputStream in, String encoding) throws IOException { + return readEpub(new ZipInputStream(in), encoding); + } + + + /** + * Reads this EPUB without loading any resources into memory. + * + * @param zipFile the file to load + * @param encoding the encoding for XHTML files + * @return this Book without loading all resources into memory. + * @throws IOException IOException + */ + @SuppressWarnings("unused") + public Book readEpubLazy(ZipFile zipFile, String encoding) + throws IOException { + return readEpubLazy(zipFile, encoding, + Arrays.asList(MediaTypes.mediaTypes)); + } + + public Book readEpub(ZipInputStream in, String encoding) throws IOException { + return readEpub(ResourcesLoader.loadResources(in, encoding)); } - handleMimeType(result, resources); - String packageResourceHref = getPackageResourceHref(resources); - Resource packageResource = processPackageResource(packageResourceHref, - result, resources); - result.setOpfResource(packageResource); - Resource ncxResource = processNcxResource(packageResource, result); - result.setNcxResource(ncxResource); - result = postProcessBook(result); - return result; - } - - - private EpubBook postProcessBook(EpubBook book) { - if (bookProcessor != null) { - book = bookProcessor.processBook(book); + + public Book readEpub(ZipFile in, String encoding) throws IOException { + return readEpub(ResourcesLoader.loadResources(in, encoding)); } - return book; - } - - private Resource processNcxResource(Resource packageResource, EpubBook book) { - Log.d(TAG, "OPF:getHref()" + packageResource.getHref()); - - return NCXDocument.read(book, this); - } - - private Resource processPackageResource(String packageResourceHref, EpubBook book, - Resources resources) { - Resource packageResource = resources.remove(packageResourceHref); - try { - PackageDocumentReader.read(packageResource, this, book, resources); - } catch (Exception e) { - Log.e(TAG,e.getMessage(), e); + + /** + * Reads this EPUB without loading all resources into memory. + * + * @param zipFile the file to load + * @param encoding the encoding for XHTML files + * @param lazyLoadedTypes a list of the MediaType to load lazily + * @return this Book without loading all resources into memory. + * @throws IOException IOException + */ + public Book readEpubLazy(ZipFile zipFile, String encoding, + List lazyLoadedTypes) throws IOException { + Resources resources = ResourcesLoader + .loadResources(zipFile, encoding, lazyLoadedTypes); + return readEpub(resources); } - return packageResource; - } - private String getPackageResourceHref(Resources resources) { - String defaultResult = "OEBPS/content.opf"; - String result = defaultResult; + public Book readEpub(Resources resources) { + return readEpub(resources, new Book()); + } - Resource containerResource = resources.remove("META-INF/container.xml"); - if (containerResource == null) { - return result; + public Book readEpub(Resources resources, Book result) { + if (result == null) { + result = new Book(); + } + handleMimeType(result, resources); + String packageResourceHref = getPackageResourceHref(resources); + Resource packageResource = processPackageResource(packageResourceHref, + result, resources); + result.setOpfResource(packageResource); + Resource ncxResource = processNcxResource(packageResource, result); + result.setNcxResource(ncxResource); + result = postProcessBook(result); + return result; } - try { - Document document = ResourceUtil.getAsDocument(containerResource); - Element rootFileElement = (Element) ((Element) document - .getDocumentElement().getElementsByTagName("rootfiles").item(0)) - .getElementsByTagName("rootfile").item(0); - result = rootFileElement.getAttribute("full-path"); - } catch (Exception e) { - Log.e(TAG,e.getMessage(), e); + + + private Book postProcessBook(Book book) { + if (bookProcessor != null) { + book = bookProcessor.processBook(book); + } + return book; } - if (StringUtil.isBlank(result)) { - result = defaultResult; + + private Resource processNcxResource(Resource packageResource, Book book) { + Log.d(TAG, "OPF:getHref()" + packageResource.getHref()); + if (book.isEpub3()) { + return NCXDocumentV3.read(book, this); + } else { + return NCXDocumentV2.read(book, this); + } + + } + + private Resource processPackageResource(String packageResourceHref, Book book, + Resources resources) { + Resource packageResource = resources.remove(packageResourceHref); + try { + PackageDocumentReader.read(packageResource, this, book, resources); + } catch (Exception e) { + Log.e(TAG, e.getMessage(), e); + } + return packageResource; } - return result; - } - private void handleMimeType(EpubBook result, Resources resources) { - resources.remove("mimetype"); - } + private String getPackageResourceHref(Resources resources) { + String defaultResult = "OEBPS/content.opf"; + String result = defaultResult; + + Resource containerResource = resources.remove("META-INF/container.xml"); + if (containerResource == null) { + return result; + } + try { + Document document = ResourceUtil.getAsDocument(containerResource); + Element rootFileElement = (Element) ((Element) document + .getDocumentElement().getElementsByTagName("rootfiles").item(0)) + .getElementsByTagName("rootfile").item(0); + result = rootFileElement.getAttribute("full-path"); + } catch (Exception e) { + Log.e(TAG, e.getMessage(), e); + } + if (StringUtil.isBlank(result)) { + result = defaultResult; + } + return result; + } + + @SuppressWarnings("unused") + private void handleMimeType(Book result, Resources resources) { + resources.remove("mimetype"); + //result.setResources(resources); + } } diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/EpubWriter.java b/epublib/src/main/java/me/ag2s/epublib/epub/EpubWriter.java index 19238c001..76c84c94c 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/EpubWriter.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/EpubWriter.java @@ -2,8 +2,10 @@ package me.ag2s.epublib.epub; import android.util.Log; -import org.xmlpull.v1.XmlSerializer; - +import me.ag2s.epublib.domain.Book; +import me.ag2s.epublib.domain.MediaTypes; +import me.ag2s.epublib.domain.Resource; +import me.ag2s.epublib.util.IOUtil; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -12,13 +14,7 @@ import java.io.Writer; import java.util.zip.CRC32; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; - -import me.ag2s.epublib.domain.EpubBook; -import me.ag2s.epublib.domain.MediaTypes; -import me.ag2s.epublib.domain.Resource; -import me.ag2s.epublib.util.IOUtil; - -//import io.documentnode.minilog.Logger; +import org.xmlpull.v1.XmlSerializer; /** * Generates an epub file. Not thread-safe, single use object. @@ -27,12 +23,12 @@ import me.ag2s.epublib.util.IOUtil; */ public class EpubWriter { - private static String TAG= EpubWriter.class.getName(); + private static final String TAG= EpubWriter.class.getName(); // package static final String EMPTY_NAMESPACE_PREFIX = ""; - private BookProcessor bookProcessor = BookProcessor.IDENTITY_BOOKPROCESSOR; + private BookProcessor bookProcessor; public EpubWriter() { this(BookProcessor.IDENTITY_BOOKPROCESSOR); @@ -44,7 +40,7 @@ public class EpubWriter { } - public void write(EpubBook book, OutputStream out) throws IOException { + public void write(Book book, OutputStream out) throws IOException { book = processBook(book); ZipOutputStream resultStream = new ZipOutputStream(out); writeMimeType(resultStream); @@ -55,17 +51,22 @@ public class EpubWriter { resultStream.close(); } - private EpubBook processBook(EpubBook book) { + private Book processBook(Book book) { if (bookProcessor != null) { book = bookProcessor.processBook(book); } return book; } - private void initTOCResource(EpubBook book) { + private void initTOCResource(Book book) { Resource tocResource; try { - tocResource = NCXDocument.createNCXResource(book); + if(book.isEpub3()){ + tocResource = NCXDocumentV3.createNCXResource(book); + }else { + tocResource = NCXDocumentV2.createNCXResource(book); + } + Resource currentTocResource = book.getSpine().getTocResource(); if (currentTocResource != null) { book.getResources().remove(currentTocResource.getHref()); @@ -80,8 +81,7 @@ public class EpubWriter { } - private void writeResources(EpubBook book, ZipOutputStream resultStream) - throws IOException { + private void writeResources(Book book, ZipOutputStream resultStream) { for (Resource resource : book.getResources().getAll()) { writeResource(resource, resultStream); } @@ -90,12 +90,10 @@ public class EpubWriter { /** * Writes the resource to the resultStream. * - * @param resource - * @param resultStream - * @throws IOException + * @param resource resource + * @param resultStream resultStream */ - private void writeResource(Resource resource, ZipOutputStream resultStream) - throws IOException { + private void writeResource(Resource resource, ZipOutputStream resultStream) { if (resource == null) { return; } @@ -110,11 +108,11 @@ public class EpubWriter { } - private void writePackageDocument(EpubBook book, ZipOutputStream resultStream) - throws IOException { + private void writePackageDocument(Book book, ZipOutputStream resultStream) + throws IOException { resultStream.putNextEntry(new ZipEntry("OEBPS/content.opf")); XmlSerializer xmlSerializer = EpubProcessorSupport - .createXmlSerializer(resultStream); + .createXmlSerializer(resultStream); PackageDocumentWriter.write(this, xmlSerializer, book); xmlSerializer.flush(); // String resultAsString = result.toString(); @@ -124,8 +122,8 @@ public class EpubWriter { /** * Writes the META-INF/container.xml file. * - * @param resultStream - * @throws IOException + * @param resultStream resultStream + * @throws IOException IOException */ private void writeContainer(ZipOutputStream resultStream) throws IOException { resultStream.putNextEntry(new ZipEntry("META-INF/container.xml")); @@ -144,8 +142,8 @@ public class EpubWriter { /** * Stores the mimetype as an uncompressed file in the ZipOutputStream. * - * @param resultStream - * @throws IOException + * @param resultStream resultStream + * @throws IOException IOException */ private void writeMimeType(ZipOutputStream resultStream) throws IOException { ZipEntry mimetypeZipEntry = new ZipEntry("mimetype"); @@ -175,11 +173,13 @@ public class EpubWriter { return MediaTypes.NCX.getName(); } + + @SuppressWarnings("unused") public BookProcessor getBookProcessor() { return bookProcessor; } - + @SuppressWarnings("unused") public void setBookProcessor(BookProcessor bookProcessor) { this.bookProcessor = bookProcessor; } diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/HtmlProcessor.java b/epublib/src/main/java/me/ag2s/epublib/epub/HtmlProcessor.java index d895d8b9e..7780f6b47 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/HtmlProcessor.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/HtmlProcessor.java @@ -2,7 +2,7 @@ package me.ag2s.epublib.epub; import me.ag2s.epublib.domain.Resource; import java.io.OutputStream; - +@SuppressWarnings("unused") public interface HtmlProcessor { void processHtmlResource(Resource resource, OutputStream out); diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/Main.java b/epublib/src/main/java/me/ag2s/epublib/epub/Main.java deleted file mode 100644 index 86ca14994..000000000 --- a/epublib/src/main/java/me/ag2s/epublib/epub/Main.java +++ /dev/null @@ -1,5 +0,0 @@ -package me.ag2s.epublib.epub; - -public class Main { - -} diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/NCXDocument.java b/epublib/src/main/java/me/ag2s/epublib/epub/NCXDocument.java deleted file mode 100644 index ec603088c..000000000 --- a/epublib/src/main/java/me/ag2s/epublib/epub/NCXDocument.java +++ /dev/null @@ -1,296 +0,0 @@ -package me.ag2s.epublib.epub; - -import android.util.Log; - -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xmlpull.v1.XmlSerializer; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -import me.ag2s.epublib.Constants; -import me.ag2s.epublib.domain.Author; -import me.ag2s.epublib.domain.EpubBook; -import me.ag2s.epublib.domain.Identifier; -import me.ag2s.epublib.domain.MediaTypes; -import me.ag2s.epublib.domain.Resource; -import me.ag2s.epublib.domain.TOCReference; -import me.ag2s.epublib.domain.TableOfContents; -import me.ag2s.epublib.util.StringUtil; - -//import io.documentnode.minilog.Logger; -//import javax.xml.stream.FactoryConfigurationError; - -/** - * Writes the ncx document as defined by namespace http://www.daisy.org/z3986/2005/ncx/ - * - * @author paul - */ -public class NCXDocument { - - public static final String NAMESPACE_NCX = "http://www.daisy.org/z3986/2005/ncx/"; - public static final String PREFIX_NCX = "ncx"; - public static final String NCX_ITEM_ID = "ncx"; - public static final String DEFAULT_NCX_HREF = "toc.ncx"; - public static final String PREFIX_DTB = "dtb"; - - private static String TAG = NCXDocument.class.getName(); - - private interface NCXTags { - - String ncx = "ncx"; - String meta = "meta"; - String navPoint = "navPoint"; - String navMap = "navMap"; - String navLabel = "navLabel"; - String content = "content"; - String text = "text"; - String docTitle = "docTitle"; - String docAuthor = "docAuthor"; - String head = "head"; - } - - private interface NCXAttributes { - - String src = "src"; - String name = "name"; - String content = "content"; - String id = "id"; - String playOrder = "playOrder"; - String clazz = "class"; - String version = "version"; - } - - private interface NCXAttributeValues { - - String chapter = "chapter"; - String version = "2005-1"; - - } - - public static Resource read(EpubBook book, EpubReader epubReader) { - Log.d(TAG, book.getVersion()); - String version = book.getVersion(); - if (version.startsWith("2.")) { - return NCXDocumentV2.read(book, epubReader); - } else if (version.startsWith("3.")) { - return NCXDocumentV3.read(book, epubReader); - } else { - return NCXDocumentV2.read(book, epubReader); - } - - } - - private static List readTOCReferences(NodeList navpoints, - EpubBook book) { - Log.d(TAG, book.getVersion()); - String version = book.getVersion(); - if (version.startsWith("2.")) { - return NCXDocumentV2.readTOCReferences(navpoints, book); - } else if (version.startsWith("3.")) { - return NCXDocumentV3.readTOCReferences(navpoints, book); - } else { - return NCXDocumentV2.readTOCReferences(navpoints, book); - } - - } - - static TOCReference readTOCReference(Element navpointElement, EpubBook book) { - Log.d(TAG, book.getVersion()); - String version = book.getVersion(); - if (version.startsWith("2.")) { - return NCXDocumentV2.readTOCReference(navpointElement, book); - } else if (version.startsWith("3.")) { - return NCXDocumentV3.readTOCReference(navpointElement, book); - } else { - return NCXDocumentV2.readTOCReference(navpointElement, book); - } - - } - - private static String readNavReference(Element navpointElement) { - Element contentElement = DOMUtil - .getFirstElementByTagNameNS(navpointElement, NAMESPACE_NCX, - NCXTags.content); - String result = DOMUtil - .getAttribute(contentElement, NAMESPACE_NCX, NCXAttributes.src); - try { - result = URLDecoder.decode(result, Constants.CHARACTER_ENCODING); - } catch (UnsupportedEncodingException e) { - Log.e(TAG, e.getMessage()); - } - return result; - } - - private static String readNavLabel(Element navpointElement) { - Element navLabel = DOMUtil - .getFirstElementByTagNameNS(navpointElement, NAMESPACE_NCX, - NCXTags.navLabel); - return DOMUtil.getTextChildrenContent(DOMUtil - .getFirstElementByTagNameNS(navLabel, NAMESPACE_NCX, NCXTags.text)); - } - - - public static void write(EpubWriter epubWriter, EpubBook book, - ZipOutputStream resultStream) throws IOException { - resultStream - .putNextEntry(new ZipEntry(book.getSpine().getTocResource().getHref())); - XmlSerializer out = EpubProcessorSupport.createXmlSerializer(resultStream); - write(out, book); - out.flush(); - } - - - /** - * Generates a resource containing an xml document containing the table of contents of the book in ncx format. - * - * @param xmlSerializer the serializer used - * @param book the book to serialize - * @throws IOException - * @throws IllegalStateException - * @throws IllegalArgumentException - * @1throws FactoryConfigurationError - */ - public static void write(XmlSerializer xmlSerializer, EpubBook book) - throws IllegalArgumentException, IllegalStateException, IOException { - write(xmlSerializer, book.getMetadata().getIdentifiers(), book.getTitle(), - book.getMetadata().getAuthors(), book.getTableOfContents()); - } - - public static Resource createNCXResource(EpubBook book) - throws IllegalArgumentException, IllegalStateException, IOException { - return createNCXResource(book.getMetadata().getIdentifiers(), - book.getTitle(), book.getMetadata().getAuthors(), - book.getTableOfContents()); - } - - public static Resource createNCXResource(List identifiers, - String title, List authors, TableOfContents tableOfContents) - throws IllegalArgumentException, IllegalStateException, IOException { - ByteArrayOutputStream data = new ByteArrayOutputStream(); - XmlSerializer out = EpubProcessorSupport.createXmlSerializer(data); - write(out, identifiers, title, authors, tableOfContents); - Resource resource = new Resource(NCX_ITEM_ID, data.toByteArray(), - DEFAULT_NCX_HREF, MediaTypes.NCX); - return resource; - } - - public static void write(XmlSerializer serializer, - List identifiers, String title, List authors, - TableOfContents tableOfContents) - throws IllegalArgumentException, IllegalStateException, IOException { - serializer.startDocument(Constants.CHARACTER_ENCODING, false); - serializer.setPrefix(EpubWriter.EMPTY_NAMESPACE_PREFIX, NAMESPACE_NCX); - serializer.startTag(NAMESPACE_NCX, NCXTags.ncx); -// serializer.writeNamespace("ncx", NAMESPACE_NCX); -// serializer.attribute("xmlns", NAMESPACE_NCX); - serializer - .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.version, - NCXAttributeValues.version); - serializer.startTag(NAMESPACE_NCX, NCXTags.head); - - for (Identifier identifier : identifiers) { - writeMetaElement(identifier.getScheme(), identifier.getValue(), - serializer); - } - - writeMetaElement("generator", Constants.EPUB4J_GENERATOR_NAME, serializer); - writeMetaElement("depth", String.valueOf(tableOfContents.calculateDepth()), - serializer); - writeMetaElement("totalPageCount", "0", serializer); - writeMetaElement("maxPageNumber", "0", serializer); - - serializer.endTag(NAMESPACE_NCX, "head"); - - serializer.startTag(NAMESPACE_NCX, NCXTags.docTitle); - serializer.startTag(NAMESPACE_NCX, NCXTags.text); - // write the first title - serializer.text(StringUtil.defaultIfNull(title)); - serializer.endTag(NAMESPACE_NCX, NCXTags.text); - serializer.endTag(NAMESPACE_NCX, NCXTags.docTitle); - - for (Author author : authors) { - serializer.startTag(NAMESPACE_NCX, NCXTags.docAuthor); - serializer.startTag(NAMESPACE_NCX, NCXTags.text); - serializer.text(author.getLastname() + ", " + author.getFirstname()); - serializer.endTag(NAMESPACE_NCX, NCXTags.text); - serializer.endTag(NAMESPACE_NCX, NCXTags.docAuthor); - } - - serializer.startTag(NAMESPACE_NCX, NCXTags.navMap); - writeNavPoints(tableOfContents.getTocReferences(), 1, serializer); - serializer.endTag(NAMESPACE_NCX, NCXTags.navMap); - - serializer.endTag(NAMESPACE_NCX, "ncx"); - serializer.endDocument(); - } - - - private static void writeMetaElement(String dtbName, String content, - XmlSerializer serializer) - throws IllegalArgumentException, IllegalStateException, IOException { - serializer.startTag(NAMESPACE_NCX, NCXTags.meta); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.name, - PREFIX_DTB + ":" + dtbName); - serializer - .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.content, - content); - serializer.endTag(NAMESPACE_NCX, NCXTags.meta); - } - - private static int writeNavPoints(List tocReferences, - int playOrder, - XmlSerializer serializer) - throws IllegalArgumentException, IllegalStateException, IOException { - for (TOCReference tocReference : tocReferences) { - if (tocReference.getResource() == null) { - playOrder = writeNavPoints(tocReference.getChildren(), playOrder, - serializer); - continue; - } - writeNavPointStart(tocReference, playOrder, serializer); - playOrder++; - if (!tocReference.getChildren().isEmpty()) { - playOrder = writeNavPoints(tocReference.getChildren(), playOrder, - serializer); - } - writeNavPointEnd(tocReference, serializer); - } - return playOrder; - } - - - private static void writeNavPointStart(TOCReference tocReference, - int playOrder, XmlSerializer serializer) - throws IllegalArgumentException, IllegalStateException, IOException { - serializer.startTag(NAMESPACE_NCX, NCXTags.navPoint); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.id, - "navPoint-" + playOrder); - serializer - .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.playOrder, - String.valueOf(playOrder)); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.clazz, - NCXAttributeValues.chapter); - serializer.startTag(NAMESPACE_NCX, NCXTags.navLabel); - serializer.startTag(NAMESPACE_NCX, NCXTags.text); - serializer.text(tocReference.getTitle()); - serializer.endTag(NAMESPACE_NCX, NCXTags.text); - serializer.endTag(NAMESPACE_NCX, NCXTags.navLabel); - serializer.startTag(NAMESPACE_NCX, NCXTags.content); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.src, - tocReference.getCompleteHref()); - serializer.endTag(NAMESPACE_NCX, NCXTags.content); - } - - private static void writeNavPointEnd(TOCReference tocReference, - XmlSerializer serializer) - throws IllegalArgumentException, IllegalStateException, IOException { - serializer.endTag(NAMESPACE_NCX, NCXTags.navPoint); - } -} diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/NCXDocumentV2.java b/epublib/src/main/java/me/ag2s/epublib/epub/NCXDocumentV2.java index 87972b75b..6147e0004 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/NCXDocumentV2.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/NCXDocumentV2.java @@ -19,7 +19,7 @@ import java.util.zip.ZipOutputStream; import me.ag2s.epublib.Constants; import me.ag2s.epublib.domain.Author; -import me.ag2s.epublib.domain.EpubBook; +import me.ag2s.epublib.domain.Book; import me.ag2s.epublib.domain.Identifier; import me.ag2s.epublib.domain.MediaTypes; import me.ag2s.epublib.domain.Resource; @@ -33,302 +33,310 @@ import me.ag2s.epublib.util.StringUtil; * * @author paul */ -public class NCXDocumentV2 extends NCXDocument{ - - public static final String NAMESPACE_NCX = "http://www.daisy.org/z3986/2005/ncx/"; - public static final String PREFIX_NCX = "ncx"; - public static final String NCX_ITEM_ID = "ncx"; - public static final String DEFAULT_NCX_HREF = "toc.ncx"; - public static final String PREFIX_DTB = "dtb"; - - private static String TAG= NCXDocumentV2.class.getName(); - - private interface NCXTags { - - String ncx = "ncx"; - String meta = "meta"; - String navPoint = "navPoint"; - String navMap = "navMap"; - String navLabel = "navLabel"; - String content = "content"; - String text = "text"; - String docTitle = "docTitle"; - String docAuthor = "docAuthor"; - String head = "head"; - } - - private interface NCXAttributes { - - String src = "src"; - String name = "name"; - String content = "content"; - String id = "id"; - String playOrder = "playOrder"; - String clazz = "class"; - String version = "version"; - } - - private interface NCXAttributeValues { - - String chapter = "chapter"; - String version = "2005-1"; - - } - - public static Resource read(EpubBook book, EpubReader epubReader) { - Resource ncxResource = null; - if (book.getSpine().getTocResource() == null) { - Log.e(TAG, "Book does not contain a table of contents file"); - return ncxResource; +public class NCXDocumentV2 { + + public static final String NAMESPACE_NCX = "http://www.daisy.org/z3986/2005/ncx/"; + @SuppressWarnings("unused") + public static final String PREFIX_NCX = "ncx"; + public static final String NCX_ITEM_ID = "ncx"; + public static final String DEFAULT_NCX_HREF = "toc.ncx"; + public static final String PREFIX_DTB = "dtb"; + + private static final String TAG = NCXDocumentV2.class.getName(); + + private interface NCXTags { + + String ncx = "ncx"; + String meta = "meta"; + String navPoint = "navPoint"; + String navMap = "navMap"; + String navLabel = "navLabel"; + String content = "content"; + String text = "text"; + String docTitle = "docTitle"; + String docAuthor = "docAuthor"; + String head = "head"; } - try { - ncxResource = book.getSpine().getTocResource(); - if (ncxResource == null) { + + private interface NCXAttributes { + + String src = "src"; + String name = "name"; + String content = "content"; + String id = "id"; + String playOrder = "playOrder"; + String clazz = "class"; + String version = "version"; + } + + private interface NCXAttributeValues { + + String chapter = "chapter"; + String version = "2005-1"; + + } + + @SuppressWarnings("unused") + public static Resource read(Book book, EpubReader epubReader) { + Resource ncxResource = null; + if (book.getSpine().getTocResource() == null) { + Log.e(TAG, "Book does not contain a table of contents file"); + return null; + } + try { + ncxResource = book.getSpine().getTocResource(); + if (ncxResource == null) { + return null; + } + Log.d(TAG, ncxResource.getHref()); + Document ncxDocument = ResourceUtil.getAsDocument(ncxResource); + Element navMapElement = DOMUtil + .getFirstElementByTagNameNS(ncxDocument.getDocumentElement(), + NAMESPACE_NCX, NCXTags.navMap); + if (navMapElement == null) { + return null; + } + + TableOfContents tableOfContents = new TableOfContents( + readTOCReferences(navMapElement.getChildNodes(), book)); + book.setTableOfContents(tableOfContents); + } catch (Exception e) { + Log.e(TAG, e.getMessage(), e); + } return ncxResource; - } - Log.d(TAG,ncxResource.getHref()); - Document ncxDocument = ResourceUtil.getAsDocument(ncxResource); - Element navMapElement = DOMUtil - .getFirstElementByTagNameNS(ncxDocument.getDocumentElement(), - NAMESPACE_NCX, NCXTags.navMap); - - TableOfContents tableOfContents = new TableOfContents( - readTOCReferences(navMapElement.getChildNodes(), book)); - book.setTableOfContents(tableOfContents); - } catch (Exception e) { - Log.e(TAG,e.getMessage(), e); } - return ncxResource; - } - static List readTOCReferences(NodeList navpoints, - EpubBook book) { - if (navpoints == null) { - return new ArrayList<>(); + static List readTOCReferences(NodeList navpoints, + Book book) { + if (navpoints == null) { + return new ArrayList<>(); + } + List result = new ArrayList<>( + navpoints.getLength()); + for (int i = 0; i < navpoints.getLength(); i++) { + Node node = navpoints.item(i); + if (node.getNodeType() != Document.ELEMENT_NODE) { + continue; + } + if (!(node.getLocalName().equals(NCXTags.navPoint))) { + continue; + } + TOCReference tocReference = readTOCReference((Element) node, book); + result.add(tocReference); + } + return result; + } + + static TOCReference readTOCReference(Element navpointElement, Book book) { + String label = readNavLabel(navpointElement); + //Log.d(TAG,"label:"+label); + String tocResourceRoot = StringUtil + .substringBeforeLast(book.getSpine().getTocResource().getHref(), '/'); + if (tocResourceRoot.length() == book.getSpine().getTocResource().getHref() + .length()) { + tocResourceRoot = ""; + } else { + tocResourceRoot = tocResourceRoot + "/"; + } + String reference = StringUtil + .collapsePathDots(tocResourceRoot + readNavReference(navpointElement)); + String href = StringUtil + .substringBefore(reference, Constants.FRAGMENT_SEPARATOR_CHAR); + String fragmentId = StringUtil + .substringAfter(reference, Constants.FRAGMENT_SEPARATOR_CHAR); + Resource resource = book.getResources().getByHref(href); + if (resource == null) { + Log.e(TAG, "Resource with href " + href + " in NCX document not found"); + } + Log.d(TAG, "label:" + label); + Log.d(TAG, "href:" + href); + Log.d(TAG, "fragmentId:" + fragmentId); + TOCReference result = new TOCReference(label, resource, fragmentId); + List childTOCReferences = readTOCReferences( + navpointElement.getChildNodes(), book); + result.setChildren(childTOCReferences); + return result; + } + + private static String readNavReference(Element navpointElement) { + Element contentElement = DOMUtil + .getFirstElementByTagNameNS(navpointElement, NAMESPACE_NCX, + NCXTags.content); + if (contentElement == null) { + return null; + } + String result = DOMUtil + .getAttribute(contentElement, NAMESPACE_NCX, NCXAttributes.src); + try { + result = URLDecoder.decode(result, Constants.CHARACTER_ENCODING); + } catch (UnsupportedEncodingException e) { + Log.e(TAG, e.getMessage()); + } + return result; } - List result = new ArrayList<>( - navpoints.getLength()); - for (int i = 0; i < navpoints.getLength(); i++) { - Node node = navpoints.item(i); - if (node.getNodeType() != Document.ELEMENT_NODE) { - continue; - } - if (!(node.getLocalName().equals(NCXTags.navPoint))) { - continue; - } - TOCReference tocReference = readTOCReference((Element) node, book); - result.add(tocReference); + + private static String readNavLabel(Element navpointElement) { + //Log.d(TAG,navpointElement.getTagName()); + Element navLabel = DOMUtil + .getFirstElementByTagNameNS(navpointElement, NAMESPACE_NCX, + NCXTags.navLabel); + assert navLabel != null; + return DOMUtil.getTextChildrenContent(DOMUtil + .getFirstElementByTagNameNS(navLabel, NAMESPACE_NCX, NCXTags.text)); + } + @SuppressWarnings("unused") + public static void write(EpubWriter epubWriter, Book book, + ZipOutputStream resultStream) throws IOException { + resultStream + .putNextEntry(new ZipEntry(book.getSpine().getTocResource().getHref())); + XmlSerializer out = EpubProcessorSupport.createXmlSerializer(resultStream); + write(out, book); + out.flush(); } - return result; - } - - static TOCReference readTOCReference(Element navpointElement, EpubBook book) { - String label = readNavLabel(navpointElement); - //Log.d(TAG,"label:"+label); - String tocResourceRoot = StringUtil - .substringBeforeLast(book.getSpine().getTocResource().getHref(), '/'); - if (tocResourceRoot.length() == book.getSpine().getTocResource().getHref() - .length()) { - tocResourceRoot = ""; - } else { - tocResourceRoot = tocResourceRoot + "/"; + + + /** + * Generates a resource containing an xml document containing the table of contents of the book in ncx format. + * + * @param xmlSerializer the serializer used + * @param book the book to serialize + * @throws IOException IOException + * @throws IllegalStateException IllegalStateException + * @throws IllegalArgumentException IllegalArgumentException + */ + public static void write(XmlSerializer xmlSerializer, Book book) + throws IllegalArgumentException, IllegalStateException, IOException { + write(xmlSerializer, book.getMetadata().getIdentifiers(), book.getTitle(), + book.getMetadata().getAuthors(), book.getTableOfContents()); } - String reference = StringUtil - .collapsePathDots(tocResourceRoot + readNavReference(navpointElement)); - String href = StringUtil - .substringBefore(reference, Constants.FRAGMENT_SEPARATOR_CHAR); - String fragmentId = StringUtil - .substringAfter(reference, Constants.FRAGMENT_SEPARATOR_CHAR); - Resource resource = book.getResources().getByHref(href); - if (resource == null) { - Log.e(TAG,"Resource with href " + href + " in NCX document not found"); + + public static Resource createNCXResource(Book book) + throws IllegalArgumentException, IllegalStateException, IOException { + return createNCXResource(book.getMetadata().getIdentifiers(), + book.getTitle(), book.getMetadata().getAuthors(), + book.getTableOfContents()); } - TOCReference result = new TOCReference(label, resource, fragmentId); - List childTOCReferences = readTOCReferences( - navpointElement.getChildNodes(), book); - result.setChildren(childTOCReferences); - return result; - } - - private static String readNavReference(Element navpointElement) { - Element contentElement = DOMUtil - .getFirstElementByTagNameNS(navpointElement, NAMESPACE_NCX, - NCXTags.content); - String result = DOMUtil - .getAttribute(contentElement, NAMESPACE_NCX, NCXAttributes.src); - try { - result = URLDecoder.decode(result, Constants.CHARACTER_ENCODING); - } catch (UnsupportedEncodingException e) { - Log.e(TAG,e.getMessage()); + + public static Resource createNCXResource(List identifiers, + String title, List authors, TableOfContents tableOfContents) + throws IllegalArgumentException, IllegalStateException, IOException { + ByteArrayOutputStream data = new ByteArrayOutputStream(); + XmlSerializer out = EpubProcessorSupport.createXmlSerializer(data); + write(out, identifiers, title, authors, tableOfContents); + return new Resource(NCX_ITEM_ID, data.toByteArray(), + DEFAULT_NCX_HREF, MediaTypes.NCX); } - return result; - } - - private static String readNavLabel(Element navpointElement) { - //Log.d(TAG,navpointElement.getTagName()); - Element navLabel = DOMUtil - .getFirstElementByTagNameNS(navpointElement, NAMESPACE_NCX, - NCXTags.navLabel); - return DOMUtil.getTextChildrenContent(DOMUtil - .getFirstElementByTagNameNS(navLabel, NAMESPACE_NCX, NCXTags.text)); - } - - - public static void write(EpubWriter epubWriter, EpubBook book, - ZipOutputStream resultStream) throws IOException { - resultStream - .putNextEntry(new ZipEntry(book.getSpine().getTocResource().getHref())); - XmlSerializer out = EpubProcessorSupport.createXmlSerializer(resultStream); - write(out, book); - out.flush(); - } - - - /** - * Generates a resource containing an xml document containing the table of contents of the book in ncx format. - * - * @param xmlSerializer the serializer used - * @param book the book to serialize - * - * @1throws FactoryConfigurationError - * @throws IOException - * @throws IllegalStateException - * @throws IllegalArgumentException - */ - public static void write(XmlSerializer xmlSerializer, EpubBook book) - throws IllegalArgumentException, IllegalStateException, IOException { - write(xmlSerializer, book.getMetadata().getIdentifiers(), book.getTitle(), - book.getMetadata().getAuthors(), book.getTableOfContents()); - } - - public static Resource createNCXResource(EpubBook book) - throws IllegalArgumentException, IllegalStateException, IOException { - return createNCXResource(book.getMetadata().getIdentifiers(), - book.getTitle(), book.getMetadata().getAuthors(), - book.getTableOfContents()); - } - - public static Resource createNCXResource(List identifiers, - String title, List authors, TableOfContents tableOfContents) - throws IllegalArgumentException, IllegalStateException, IOException { - ByteArrayOutputStream data = new ByteArrayOutputStream(); - XmlSerializer out = EpubProcessorSupport.createXmlSerializer(data); - write(out, identifiers, title, authors, tableOfContents); - Resource resource = new Resource(NCX_ITEM_ID, data.toByteArray(), - DEFAULT_NCX_HREF, MediaTypes.NCX); - return resource; - } - - public static void write(XmlSerializer serializer, - List identifiers, String title, List authors, - TableOfContents tableOfContents) - throws IllegalArgumentException, IllegalStateException, IOException { - serializer.startDocument(Constants.CHARACTER_ENCODING, false); - serializer.setPrefix(EpubWriter.EMPTY_NAMESPACE_PREFIX, NAMESPACE_NCX); - serializer.startTag(NAMESPACE_NCX, NCXTags.ncx); + + public static void write(XmlSerializer serializer, + List identifiers, String title, List authors, + TableOfContents tableOfContents) + throws IllegalArgumentException, IllegalStateException, IOException { + serializer.startDocument(Constants.CHARACTER_ENCODING, false); + serializer.setPrefix(EpubWriter.EMPTY_NAMESPACE_PREFIX, NAMESPACE_NCX); + serializer.startTag(NAMESPACE_NCX, NCXTags.ncx); // serializer.writeNamespace("ncx", NAMESPACE_NCX); // serializer.attribute("xmlns", NAMESPACE_NCX); - serializer - .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.version, - NCXAttributeValues.version); - serializer.startTag(NAMESPACE_NCX, NCXTags.head); - - for (Identifier identifier : identifiers) { - writeMetaElement(identifier.getScheme(), identifier.getValue(), - serializer); + serializer + .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.version, + NCXAttributeValues.version); + serializer.startTag(NAMESPACE_NCX, NCXTags.head); + + for (Identifier identifier : identifiers) { + writeMetaElement(identifier.getScheme(), identifier.getValue(), + serializer); + } + + writeMetaElement("generator", Constants.EPUB_GENERATOR_NAME, serializer); + writeMetaElement("depth", String.valueOf(tableOfContents.calculateDepth()), + serializer); + writeMetaElement("totalPageCount", "0", serializer); + writeMetaElement("maxPageNumber", "0", serializer); + + serializer.endTag(NAMESPACE_NCX, "head"); + + serializer.startTag(NAMESPACE_NCX, NCXTags.docTitle); + serializer.startTag(NAMESPACE_NCX, NCXTags.text); + // write the first title + serializer.text(StringUtil.defaultIfNull(title)); + serializer.endTag(NAMESPACE_NCX, NCXTags.text); + serializer.endTag(NAMESPACE_NCX, NCXTags.docTitle); + + for (Author author : authors) { + serializer.startTag(NAMESPACE_NCX, NCXTags.docAuthor); + serializer.startTag(NAMESPACE_NCX, NCXTags.text); + serializer.text(author.getLastname() + ", " + author.getFirstname()); + serializer.endTag(NAMESPACE_NCX, NCXTags.text); + serializer.endTag(NAMESPACE_NCX, NCXTags.docAuthor); + } + + serializer.startTag(NAMESPACE_NCX, NCXTags.navMap); + writeNavPoints(tableOfContents.getTocReferences(), 1, serializer); + serializer.endTag(NAMESPACE_NCX, NCXTags.navMap); + + serializer.endTag(NAMESPACE_NCX, "ncx"); + serializer.endDocument(); + } + + + private static void writeMetaElement(String dtbName, String content, + XmlSerializer serializer) + throws IllegalArgumentException, IllegalStateException, IOException { + serializer.startTag(NAMESPACE_NCX, NCXTags.meta); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.name, + PREFIX_DTB + ":" + dtbName); + serializer + .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.content, + content); + serializer.endTag(NAMESPACE_NCX, NCXTags.meta); } - writeMetaElement("generator", Constants.EPUB4J_GENERATOR_NAME, serializer); - writeMetaElement("depth", String.valueOf(tableOfContents.calculateDepth()), - serializer); - writeMetaElement("totalPageCount", "0", serializer); - writeMetaElement("maxPageNumber", "0", serializer); - - serializer.endTag(NAMESPACE_NCX, "head"); - - serializer.startTag(NAMESPACE_NCX, NCXTags.docTitle); - serializer.startTag(NAMESPACE_NCX, NCXTags.text); - // write the first title - serializer.text(StringUtil.defaultIfNull(title)); - serializer.endTag(NAMESPACE_NCX, NCXTags.text); - serializer.endTag(NAMESPACE_NCX, NCXTags.docTitle); - - for (Author author : authors) { - serializer.startTag(NAMESPACE_NCX, NCXTags.docAuthor); - serializer.startTag(NAMESPACE_NCX, NCXTags.text); - serializer.text(author.getLastname() + ", " + author.getFirstname()); - serializer.endTag(NAMESPACE_NCX, NCXTags.text); - serializer.endTag(NAMESPACE_NCX, NCXTags.docAuthor); + private static int writeNavPoints(List tocReferences, + int playOrder, + XmlSerializer serializer) + throws IllegalArgumentException, IllegalStateException, IOException { + for (TOCReference tocReference : tocReferences) { + if (tocReference.getResource() == null) { + playOrder = writeNavPoints(tocReference.getChildren(), playOrder, + serializer); + continue; + } + writeNavPointStart(tocReference, playOrder, serializer); + playOrder++; + if (!tocReference.getChildren().isEmpty()) { + playOrder = writeNavPoints(tocReference.getChildren(), playOrder, + serializer); + } + writeNavPointEnd(tocReference, serializer); + } + return playOrder; } - serializer.startTag(NAMESPACE_NCX, NCXTags.navMap); - writeNavPoints(tableOfContents.getTocReferences(), 1, serializer); - serializer.endTag(NAMESPACE_NCX, NCXTags.navMap); - - serializer.endTag(NAMESPACE_NCX, "ncx"); - serializer.endDocument(); - } - - - private static void writeMetaElement(String dtbName, String content, - XmlSerializer serializer) - throws IllegalArgumentException, IllegalStateException, IOException { - serializer.startTag(NAMESPACE_NCX, NCXTags.meta); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.name, - PREFIX_DTB + ":" + dtbName); - serializer - .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.content, - content); - serializer.endTag(NAMESPACE_NCX, NCXTags.meta); - } - - private static int writeNavPoints(List tocReferences, - int playOrder, - XmlSerializer serializer) - throws IllegalArgumentException, IllegalStateException, IOException { - for (TOCReference tocReference : tocReferences) { - if (tocReference.getResource() == null) { - playOrder = writeNavPoints(tocReference.getChildren(), playOrder, - serializer); - continue; - } - writeNavPointStart(tocReference, playOrder, serializer); - playOrder++; - if (!tocReference.getChildren().isEmpty()) { - playOrder = writeNavPoints(tocReference.getChildren(), playOrder, - serializer); - } - writeNavPointEnd(tocReference, serializer); + + private static void writeNavPointStart(TOCReference tocReference, + int playOrder, XmlSerializer serializer) + throws IllegalArgumentException, IllegalStateException, IOException { + serializer.startTag(NAMESPACE_NCX, NCXTags.navPoint); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.id, + "navPoint-" + playOrder); + serializer + .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.playOrder, + String.valueOf(playOrder)); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.clazz, + NCXAttributeValues.chapter); + serializer.startTag(NAMESPACE_NCX, NCXTags.navLabel); + serializer.startTag(NAMESPACE_NCX, NCXTags.text); + serializer.text(tocReference.getTitle()); + serializer.endTag(NAMESPACE_NCX, NCXTags.text); + serializer.endTag(NAMESPACE_NCX, NCXTags.navLabel); + serializer.startTag(NAMESPACE_NCX, NCXTags.content); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.src, + tocReference.getCompleteHref()); + serializer.endTag(NAMESPACE_NCX, NCXTags.content); + } + @SuppressWarnings("unused") + private static void writeNavPointEnd(TOCReference tocReference, + XmlSerializer serializer) + throws IllegalArgumentException, IllegalStateException, IOException { + serializer.endTag(NAMESPACE_NCX, NCXTags.navPoint); } - return playOrder; - } - - - private static void writeNavPointStart(TOCReference tocReference, - int playOrder, XmlSerializer serializer) - throws IllegalArgumentException, IllegalStateException, IOException { - serializer.startTag(NAMESPACE_NCX, NCXTags.navPoint); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.id, - "navPoint-" + playOrder); - serializer - .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.playOrder, - String.valueOf(playOrder)); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.clazz, - NCXAttributeValues.chapter); - serializer.startTag(NAMESPACE_NCX, NCXTags.navLabel); - serializer.startTag(NAMESPACE_NCX, NCXTags.text); - serializer.text(tocReference.getTitle()); - serializer.endTag(NAMESPACE_NCX, NCXTags.text); - serializer.endTag(NAMESPACE_NCX, NCXTags.navLabel); - serializer.startTag(NAMESPACE_NCX, NCXTags.content); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.src, - tocReference.getCompleteHref()); - serializer.endTag(NAMESPACE_NCX, NCXTags.content); - } - - private static void writeNavPointEnd(TOCReference tocReference, - XmlSerializer serializer) - throws IllegalArgumentException, IllegalStateException, IOException { - serializer.endTag(NAMESPACE_NCX, NCXTags.navPoint); - } } diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/NCXDocumentV3.java b/epublib/src/main/java/me/ag2s/epublib/epub/NCXDocumentV3.java index 743d8b0f2..2de8185d4 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/NCXDocumentV3.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/NCXDocumentV3.java @@ -6,79 +6,114 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import org.xmlpull.v1.XmlSerializer; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.ArrayList; import java.util.List; import me.ag2s.epublib.Constants; -import me.ag2s.epublib.domain.EpubBook; +import me.ag2s.epublib.domain.Author; +import me.ag2s.epublib.domain.Book; +import me.ag2s.epublib.domain.Identifier; +import me.ag2s.epublib.domain.MediaType; +import me.ag2s.epublib.domain.MediaTypes; import me.ag2s.epublib.domain.Resource; import me.ag2s.epublib.domain.TOCReference; import me.ag2s.epublib.domain.TableOfContents; import me.ag2s.epublib.util.ResourceUtil; import me.ag2s.epublib.util.StringUtil; -public class NCXDocumentV3 extends NCXDocument { - public static final String NAMESPACE_NCX = ""; - public static final String PREFIX_NCX = "html"; - public static final String NCX_ITEM_ID = "ncx"; +/** + * Writes the ncx document as defined by namespace http://www.daisy.org/z3986/2005/ncx/ + * + * @author Ag2S20150909 + */ + +public class NCXDocumentV3 { + public static final String NAMESPACE_XHTML = "http://www.w3.org/1999/xhtml"; + public static final String NAMESPACE_EPUB = "http://www.idpf.org/2007/ops"; + public static final String LANGUAGE = "en"; + @SuppressWarnings("unused") + public static final String PREFIX_XHTML = "html"; + public static final String NCX_ITEM_ID = "htmltoc"; public static final String DEFAULT_NCX_HREF = "toc.xhtml"; - public static final String PREFIX_DTB = "dtb"; - private static String TAG = NCXDocumentV3.class.getName(); + public static final String V3_NCX_PROPERTIES = "nav"; + public static final MediaType V3_NCX_MEDIATYPE = MediaTypes.XHTML; - private interface NCXTags { - //String nav="nav"; - //String li="li"; - //String ncx = "ncx"; - String meta = "meta"; - String navPoint = "li"; - String navMap = "nav"; - String navLabel = "a"; - String content = "a"; - String text = "text"; - String docTitle = "docTitle"; - String docAuthor = "docAuthor"; + private static final String TAG = NCXDocumentV3.class.getName(); + + private interface XHTMLTgs { + String html = "html"; String head = "head"; + String title = "title"; + String meta = "meta"; + String link = "link"; + String body = "body"; + String h1 = "h1"; + String h2 = "h2"; + String nav = "nav"; + String ol = "ol"; + String li = "li"; + String a = "a"; + String span = "span"; } - private interface NCXAttributes { - - String src = "href"; - String name = "name"; - String content = "content"; + private interface XHTMLAttributes { + String xmlns = "xmlns"; + String xmlns_epub = "xmlns:epub"; + String lang = "lang"; + String xml_lang = "xml:lang"; + String rel = "rel"; + String type = "type"; + String epub_type = "epub:type";//nav的必须属性 String id = "id"; - String playOrder = "playOrder"; - String clazz = "class"; - String version = "version"; - } + String role = "role"; + String href = "href"; + String http_equiv = "http-equiv"; + String content = "content"; - private interface NCXAttributeValues { + } - String chapter = "chapter"; - String version = "2007"; + private interface XHTMLAttributeValues { + String Content_Type = "Content-Type"; + String HTML_UTF8 = "text/html; charset=utf-8"; + String lang = "en"; + String epub_type = "toc"; + String role_toc = "doc-toc"; } - public static Resource read(EpubBook book, EpubReader epubReader) { + + /** + * 解析epub的目录文件 + * + * @param book Book + * @param epubReader epubreader + * @return Resource + */ + @SuppressWarnings("unused") + public static Resource read(Book book, EpubReader epubReader) { Resource ncxResource = null; if (book.getSpine().getTocResource() == null) { Log.e(TAG, "Book does not contain a table of contents file"); - return ncxResource; + return null; } try { ncxResource = book.getSpine().getTocResource(); if (ncxResource == null) { - return ncxResource; + return null; } //Log.d(TAG, ncxResource.getHref()); Document ncxDocument = ResourceUtil.getAsDocument(ncxResource); //Log.d(TAG, ncxDocument.getNodeName()); - Element navMapElement = (Element) ncxDocument.getElementsByTagName("nav").item(0); - navMapElement = (Element) navMapElement.getElementsByTagName("ol").item(0); + Element navMapElement = (Element) ncxDocument.getElementsByTagName(XHTMLTgs.nav).item(0); + navMapElement = (Element) navMapElement.getElementsByTagName(XHTMLTgs.ol).item(0); Log.d(TAG, navMapElement.getTagName()); TableOfContents tableOfContents = new TableOfContents( @@ -91,46 +126,42 @@ public class NCXDocumentV3 extends NCXDocument { return ncxResource; } - public static List doToc(Node n, EpubBook book) { + private static List doToc(Node n, Book book) { List result = new ArrayList<>(); if (n == null || n.getNodeType() != Document.ELEMENT_NODE) { return result; } else { Element el = (Element) n; - NodeList nodeList = el.getElementsByTagName("li"); + NodeList nodeList = el.getElementsByTagName(XHTMLTgs.li); for (int i = 0; i < nodeList.getLength(); i++) { result.add(readTOCReference((Element) nodeList.item(i), book)); } } - - return result; } static List readTOCReferences(NodeList navpoints, - EpubBook book) { + Book book) { if (navpoints == null) { return new ArrayList<>(); } //Log.d(TAG, "readTOCReferences:navpoints.getLength()" + navpoints.getLength()); - List result = new ArrayList<>(); + List result = new ArrayList<>(navpoints.getLength()); for (int i = 0; i < navpoints.getLength(); i++) { Node node = navpoints.item(i); + //如果该node是null,或者不是Element,跳出本次循环 if (node == null || node.getNodeType() != Document.ELEMENT_NODE) { continue; - } else { - Element el = (Element) node; - if (el.getTagName().equals("li")) { - result.add(readTOCReference(el, book)); - } - //NodeList nodeList=el.getElementsByTagName("li"); - //for (int i=0;i childTOCReferences = doToc(navpointElement, book); //readTOCReferences( //navpointElement.getChildNodes(), book); @@ -168,13 +206,24 @@ public class NCXDocumentV3 extends NCXDocument { return result; } + /** + * 获取目录节点的href + * + * @param navpointElement navpointElement + * @return String + */ private static String readNavReference(Element navpointElement) { + //https://www.w3.org/publishing/epub/epub-packages.html#sec-package-nav + //父级节点必须是 "li" //Log.d(TAG, "readNavReference:" + navpointElement.getTagName()); + Element contentElement = DOMUtil - .getFirstElementByTagNameNS(navpointElement, NAMESPACE_NCX, - NCXDocumentV3.NCXTags.content); + .getFirstElementByTagNameNS(navpointElement, "", XHTMLTgs.a); + if (contentElement == null) { + return null; + } String result = DOMUtil - .getAttribute(contentElement, NAMESPACE_NCX, NCXDocumentV3.NCXAttributes.src); + .getAttribute(contentElement, "", XHTMLAttributes.href); try { result = URLDecoder.decode(result, Constants.CHARACTER_ENCODING); } catch (UnsupportedEncodingException e) { @@ -185,13 +234,218 @@ public class NCXDocumentV3 extends NCXDocument { } + /** + * 获取目录节点里面的章节名 + * + * @param navpointElement navpointElement + * @return String + */ private static String readNavLabel(Element navpointElement) { + //https://www.w3.org/publishing/epub/epub-packages.html#sec-package-nav + //父级节点必须是 "li" //Log.d(TAG, "readNavLabel:" + navpointElement.getTagName()); - Element navLabel = DOMUtil - .getFirstElementByTagNameNS(navpointElement, NAMESPACE_NCX, - NCXDocumentV3.NCXTags.navLabel); - return navLabel.getTextContent();//DOMUtil.getTextChildrenContent(DOMUtil - //.getFirstElementByTagNameNS(navLabel, NAMESPACE_NCX, NCXDocumentV3.NCXTags.text)); + String label; + Element labelElement = DOMUtil.getFirstElementByTagNameNS(navpointElement, "", "a"); + assert labelElement != null; + label = labelElement.getTextContent(); + if (StringUtil.isNotBlank(label)) { + return label; + } else { + labelElement = DOMUtil.getFirstElementByTagNameNS(navpointElement, "", "span"); + } + assert labelElement != null; + label = labelElement.getTextContent(); + //如果通过 a 标签无法获取章节列表,则是无href章节名 + return label; + + } + + public static Resource createNCXResource(Book book) + throws IllegalArgumentException, IllegalStateException, IOException { + return createNCXResource(book.getMetadata().getIdentifiers(), + book.getTitle(), book.getMetadata().getAuthors(), + book.getTableOfContents()); + } + + public static Resource createNCXResource(List identifiers, + String title, List authors, TableOfContents tableOfContents) + throws IllegalArgumentException, IllegalStateException, IOException { + ByteArrayOutputStream data = new ByteArrayOutputStream(); + XmlSerializer out = EpubProcessorSupport.createXmlSerializer(data); + write(out, identifiers, title, authors, tableOfContents); + + Resource resource = new Resource(NCX_ITEM_ID, data.toByteArray(), + DEFAULT_NCX_HREF, V3_NCX_MEDIATYPE); + resource.setProperties(V3_NCX_PROPERTIES); + return resource; + } + + /** + * Generates a resource containing an xml document containing the table of contents of the book in ncx format. + * + * @param xmlSerializer the serializer used + * @param book the book to serialize + * @throws IOException IOException + * @throws IllegalStateException IllegalStateException + * @throws IllegalArgumentException IllegalArgumentException + */ + public static void write(XmlSerializer xmlSerializer, Book book) + throws IllegalArgumentException, IllegalStateException, IOException { + write(xmlSerializer, book.getMetadata().getIdentifiers(), book.getTitle(), + book.getMetadata().getAuthors(), book.getTableOfContents()); + } + + /** + * 写入 + * + * @param serializer serializer + * @param identifiers identifiers + * @param title title + * @param authors authors + * @param tableOfContents tableOfContents + */ + @SuppressWarnings("unused") + public static void write(XmlSerializer serializer, + List identifiers, String title, List authors, + TableOfContents tableOfContents) throws IllegalArgumentException, IllegalStateException, IOException { + serializer.startDocument(Constants.CHARACTER_ENCODING, false); + serializer.setPrefix(EpubWriter.EMPTY_NAMESPACE_PREFIX, NAMESPACE_XHTML); + serializer.startTag(NAMESPACE_XHTML, XHTMLTgs.html); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, XHTMLAttributes.xmlns_epub, NAMESPACE_EPUB); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, XHTMLAttributes.xml_lang, XHTMLAttributeValues.lang); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, XHTMLAttributes.lang, LANGUAGE); + //写入头部head标签 + writeHead(title, serializer); + //body开始 + serializer.startTag(NAMESPACE_XHTML, XHTMLTgs.body); + //h1开始 + serializer.startTag(NAMESPACE_XHTML, XHTMLTgs.h1); + serializer.text(title); + serializer.endTag(NAMESPACE_XHTML, XHTMLTgs.h1); + //h1关闭 + //nav开始 + serializer.startTag(NAMESPACE_XHTML, XHTMLTgs.nav); + serializer.attribute("", XHTMLAttributes.epub_type, XHTMLAttributeValues.epub_type); + serializer.attribute("", XHTMLAttributes.id, XHTMLAttributeValues.epub_type); + serializer.attribute("", XHTMLAttributes.role, XHTMLAttributeValues.role_toc); + //h2开始 + serializer.startTag(NAMESPACE_XHTML, XHTMLTgs.h2); + serializer.text("目录"); + serializer.endTag(NAMESPACE_XHTML, XHTMLTgs.h2); + + + writeNavPoints(tableOfContents.getTocReferences(), 1, serializer); + + + serializer.endTag(NAMESPACE_XHTML, XHTMLTgs.nav); + + //body关闭 + serializer.endTag(NAMESPACE_XHTML, XHTMLTgs.body); + + + serializer.endTag(NAMESPACE_XHTML, XHTMLTgs.html); + serializer.endDocument(); + + } + + private static int writeNavPoints(List tocReferences, + int playOrder, + XmlSerializer serializer) throws IOException { + writeOlStart(serializer); + for (TOCReference tocReference : tocReferences) { + if (tocReference.getResource() == null) { + playOrder = writeNavPoints(tocReference.getChildren(), playOrder, + serializer); + continue; + } + + + writeNavPointStart(tocReference, serializer); + + playOrder++; + if (!tocReference.getChildren().isEmpty()) { + playOrder = writeNavPoints(tocReference.getChildren(), playOrder, + serializer); + } + + writeNavPointEnd(tocReference, serializer); + } + writeOlSEnd(serializer); + return playOrder; + } + + private static void writeNavPointStart(TOCReference tocReference, XmlSerializer serializer) throws IOException { + writeLiStart(serializer); + String title = tocReference.getTitle(); + String href = tocReference.getCompleteHref(); + if (StringUtil.isNotBlank(href)) { + writeLabel(title, href, serializer); + } else { + writeLabel(title, serializer); + } + } + + @SuppressWarnings("unused") + private static void writeNavPointEnd(TOCReference tocReference, + XmlSerializer serializer) throws IOException { + writeLiEnd(serializer); + } + + protected static void writeLabel(String title, String href, XmlSerializer serializer) throws IOException { + serializer.startTag(NAMESPACE_XHTML, XHTMLTgs.a); + serializer.attribute("", XHTMLAttributes.href, href); + //attribute必须在Text之前设置。 + serializer.text(title); + //serializer.attribute(NAMESPACE_XHTML, XHTMLAttributes.href, href); + serializer.endTag(NAMESPACE_XHTML, XHTMLTgs.a); + } + + protected static void writeLabel(String title, XmlSerializer serializer) throws IOException { + serializer.startTag(NAMESPACE_XHTML, XHTMLTgs.span); + serializer.text(title); + serializer.endTag(NAMESPACE_XHTML, XHTMLTgs.span); + } + + private static void writeLiStart(XmlSerializer serializer) throws IOException { + serializer.startTag(NAMESPACE_XHTML, XHTMLTgs.li); + Log.d(TAG, "writeLiStart"); + } + + private static void writeLiEnd(XmlSerializer serializer) throws IOException { + serializer.endTag(NAMESPACE_XHTML, XHTMLTgs.li); + Log.d(TAG, "writeLiEND"); + } + + private static void writeOlStart(XmlSerializer serializer) throws IOException { + serializer.startTag(NAMESPACE_XHTML, XHTMLTgs.ol); + Log.d(TAG, "writeOlStart"); + } + + private static void writeOlSEnd(XmlSerializer serializer) throws IOException { + serializer.endTag(NAMESPACE_XHTML, XHTMLTgs.ol); + Log.d(TAG, "writeOlEnd"); + } + + private static void writeHead(String title, XmlSerializer serializer) throws IOException { + serializer.startTag(NAMESPACE_XHTML, XHTMLTgs.head); + //title + serializer.startTag(NAMESPACE_XHTML, XHTMLTgs.title); + serializer.text(StringUtil.defaultIfNull(title)); + serializer.endTag(NAMESPACE_XHTML, XHTMLTgs.title); + //link + serializer.startTag(NAMESPACE_XHTML, XHTMLTgs.link); + serializer.attribute("", XHTMLAttributes.rel, "stylesheet"); + serializer.attribute("", XHTMLAttributes.type, "text/css"); + serializer.attribute("", XHTMLAttributes.href, "css/style.css"); + serializer.endTag(NAMESPACE_XHTML, XHTMLTgs.link); + + //meta + serializer.startTag(NAMESPACE_XHTML, XHTMLTgs.meta); + serializer.attribute("", XHTMLAttributes.http_equiv, XHTMLAttributeValues.Content_Type); + serializer.attribute("", XHTMLAttributes.content, XHTMLAttributeValues.HTML_UTF8); + serializer.endTag(NAMESPACE_XHTML, XHTMLTgs.meta); + + serializer.endTag(NAMESPACE_XHTML, XHTMLTgs.head); } diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentBase.java b/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentBase.java index 04c8240f9..c7ce55b78 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentBase.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentBase.java @@ -14,8 +14,11 @@ public class PackageDocumentBase { public static final String NAMESPACE_DUBLIN_CORE = "http://purl.org/dc/elements/1.1/"; public static final String PREFIX_DUBLIN_CORE = "dc"; //public static final String PREFIX_OPF = "opf"; - //Some Epub Reader not reconize opt:packge,So just let it empty; + //在EPUB3标准中,packge前面没有opf头,一些epub阅读器也不支持opf头。 + //Some Epub Reader not reconize op:packge,So just let it empty; public static final String PREFIX_OPF = ""; + //添加 version 变量来区分Epub文件的版本 + //Add the version field to distinguish the version of EPUB file public static final String version="version"; public static final String dateFormat = "yyyy-MM-dd"; @@ -76,6 +79,10 @@ public class PackageDocumentBase { String version = "version"; String scheme = "scheme"; String property = "property"; + //add for epub3 + /** + * add for epub3 + */ String properties="properties"; } diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentMetadataReader.java b/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentMetadataReader.java index 8feab2660..c9ce14429 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentMetadataReader.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentMetadataReader.java @@ -2,21 +2,23 @@ package me.ag2s.epublib.epub; import android.util.Log; -import me.ag2s.epublib.domain.Author; -import me.ag2s.epublib.domain.Date; -import me.ag2s.epublib.domain.Identifier; -import me.ag2s.epublib.domain.Metadata; -import me.ag2s.epublib.util.StringUtil; -//import io.documentnode.minilog.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; + import javax.xml.namespace.QName; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; + +import me.ag2s.epublib.domain.Author; +import me.ag2s.epublib.domain.Date; +import me.ag2s.epublib.domain.Identifier; +import me.ag2s.epublib.domain.Metadata; +import me.ag2s.epublib.util.StringUtil; /** * Reads the package document metadata. @@ -28,7 +30,7 @@ import org.w3c.dom.NodeList; // package class PackageDocumentMetadataReader extends PackageDocumentBase { - private static String TAG= PackageDocumentMetadataReader.class.getName(); + private static final String TAG= PackageDocumentMetadataReader.class.getName(); public static Metadata readMetadata(Document packageDocument) { Metadata result = new Metadata(); @@ -76,12 +78,12 @@ class PackageDocumentMetadataReader extends PackageDocumentBase { /** * consumes meta tags that have a property attribute as defined in the standard. For example: * <meta property="rendition:layout">pre-paginated</meta> - * @param metadataElement - * @return + * @param metadataElement metadataElement + * @return Map */ private static Map readOtherProperties( Element metadataElement) { - Map result = new HashMap(); + Map result = new HashMap<>(); NodeList metaTags = metadataElement.getElementsByTagName(OPFTags.meta); for (int i = 0; i < metaTags.getLength(); i++) { @@ -101,12 +103,12 @@ class PackageDocumentMetadataReader extends PackageDocumentBase { /** * consumes meta tags that have a property attribute as defined in the standard. For example: * <meta property="rendition:layout">pre-paginated</meta> - * @param metadataElement - * @return + * @param metadataElement metadataElement + * @return Map */ private static Map readMetaProperties( Element metadataElement) { - Map result = new HashMap(); + Map result = new HashMap<>(); NodeList metaTags = metadataElement.getElementsByTagName(OPFTags.meta); for (int i = 0; i < metaTags.getLength(); i++) { @@ -126,9 +128,8 @@ class PackageDocumentMetadataReader extends PackageDocumentBase { if (packageElement == null) { return null; } - String result = packageElement + return packageElement .getAttributeNS(NAMESPACE_OPF, OPFAttributes.uniqueIdentifier); - return result; } private static List readCreators(Element metadataElement) { @@ -143,7 +144,7 @@ class PackageDocumentMetadataReader extends PackageDocumentBase { Element metadataElement) { NodeList elements = metadataElement .getElementsByTagNameNS(NAMESPACE_DUBLIN_CORE, authorTag); - List result = new ArrayList(elements.getLength()); + List result = new ArrayList<>(elements.getLength()); for (int i = 0; i < elements.getLength(); i++) { Element authorElement = (Element) elements.item(i); Author author = createAuthor(authorElement); @@ -158,7 +159,7 @@ class PackageDocumentMetadataReader extends PackageDocumentBase { private static List readDates(Element metadataElement) { NodeList elements = metadataElement .getElementsByTagNameNS(NAMESPACE_DUBLIN_CORE, DCTags.date); - List result = new ArrayList(elements.getLength()); + List result = new ArrayList<>(elements.getLength()); for (int i = 0; i < elements.getLength(); i++) { Element dateElement = (Element) elements.item(i); Date date; @@ -198,11 +199,11 @@ class PackageDocumentMetadataReader extends PackageDocumentBase { .getElementsByTagNameNS(NAMESPACE_DUBLIN_CORE, DCTags.identifier); if (identifierElements.getLength() == 0) { Log.e(TAG,"Package does not contain element " + DCTags.identifier); - return new ArrayList(); + return new ArrayList<>(); } String bookIdId = getBookIdId(metadataElement.getOwnerDocument()); - List result = new ArrayList( - identifierElements.getLength()); + List result = new ArrayList<>( + identifierElements.getLength()); for (int i = 0; i < identifierElements.getLength(); i++) { Element identifierElement = (Element) identifierElements.item(i); String schemeName = identifierElement diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentMetadataWriter.java b/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentMetadataWriter.java index 2dd935481..80caed08c 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentMetadataWriter.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentMetadataWriter.java @@ -1,42 +1,39 @@ package me.ag2s.epublib.epub; -import org.xmlpull.v1.XmlSerializer; - -import java.io.IOException; -import java.util.List; -import java.util.Map; - -import javax.xml.namespace.QName; - import me.ag2s.epublib.Constants; import me.ag2s.epublib.domain.Author; +import me.ag2s.epublib.domain.Book; import me.ag2s.epublib.domain.Date; -import me.ag2s.epublib.domain.EpubBook; import me.ag2s.epublib.domain.Identifier; import me.ag2s.epublib.util.StringUtil; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import javax.xml.namespace.QName; +import org.xmlpull.v1.XmlSerializer; public class PackageDocumentMetadataWriter extends PackageDocumentBase { /** * Writes the book's metadata. * - * @param book - * @param serializer - * @throws IOException - * @throws IllegalStateException - * @throws IllegalArgumentException + * @param book book + * @param serializer serializer + * @throws IOException IOException + * @throws IllegalStateException IllegalStateException + * @throws IllegalArgumentException IllegalArgumentException */ - public static void writeMetaData(EpubBook book, XmlSerializer serializer) - throws IllegalArgumentException, IllegalStateException, IOException { + public static void writeMetaData(Book book, XmlSerializer serializer) + throws IllegalArgumentException, IllegalStateException, IOException { serializer.startTag(NAMESPACE_OPF, OPFTags.metadata); serializer.setPrefix(PREFIX_DUBLIN_CORE, NAMESPACE_DUBLIN_CORE); serializer.setPrefix(PREFIX_OPF, NAMESPACE_OPF); writeIdentifiers(book.getMetadata().getIdentifiers(), serializer); writeSimpleMetdataElements(DCTags.title, book.getMetadata().getTitles(), - serializer); + serializer); writeSimpleMetdataElements(DCTags.subject, book.getMetadata().getSubjects(), - serializer); + serializer); writeSimpleMetdataElements(DCTags.description, book.getMetadata().getDescriptions(), serializer); writeSimpleMetdataElements(DCTags.publisher, @@ -117,7 +114,7 @@ public class PackageDocumentMetadataWriter extends PackageDocumentBase { OPFValues.generator); serializer .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.content, - Constants.EPUB4J_GENERATOR_NAME); + Constants.EPUB_GENERATOR_NAME); serializer.endTag(NAMESPACE_OPF, OPFTags.meta); serializer.endTag(NAMESPACE_OPF, OPFTags.metadata); @@ -142,11 +139,10 @@ public class PackageDocumentMetadataWriter extends PackageDocumentBase { * The first identifier for which the bookId is true is made the bookId identifier. * If no identifier has bookId == true then the first bookId identifier is written as the primary. * - * @param identifiers - * @param serializer - * @throws IOException - * @throws IllegalStateException - * @throws IllegalArgumentException + * @param identifiers identifiers + * @param serializer serializer + * @throws IllegalStateException e + * @throws IllegalArgumentException e * @ */ private static void writeIdentifiers(List identifiers, diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentReader.java b/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentReader.java index c986147d9..145febb02 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentReader.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentReader.java @@ -19,10 +19,8 @@ import java.util.List; import java.util.Map; import java.util.Set; -import javax.xml.parsers.ParserConfigurationException; - import me.ag2s.epublib.Constants; -import me.ag2s.epublib.domain.EpubBook; +import me.ag2s.epublib.domain.Book; import me.ag2s.epublib.domain.Guide; import me.ag2s.epublib.domain.GuideReference; import me.ag2s.epublib.domain.MediaType; @@ -34,8 +32,6 @@ import me.ag2s.epublib.domain.SpineReference; import me.ag2s.epublib.util.ResourceUtil; import me.ag2s.epublib.util.StringUtil; -//import io.documentnode.minilog.Logger; - /** * Reads the opf package document as defined by namespace http://www.idpf.org/2007/opf * @@ -44,22 +40,22 @@ import me.ag2s.epublib.util.StringUtil; */ public class PackageDocumentReader extends PackageDocumentBase { - private static String TAG= PackageDocumentReader.class.getName(); + private static final String TAG= PackageDocumentReader.class.getName(); private static final String[] POSSIBLE_NCX_ITEM_IDS = new String[]{"toc", "ncx", "ncxtoc","htmltoc"}; public static void read( - Resource packageResource, EpubReader epubReader, EpubBook book, - Resources resources) - throws UnsupportedEncodingException, SAXException, IOException, ParserConfigurationException { + Resource packageResource, EpubReader epubReader, Book book, + Resources resources) + throws SAXException, IOException { Document packageDocument = ResourceUtil.getAsDocument(packageResource); String packageHref = packageResource.getHref(); resources = fixHrefs(packageHref, resources); readGuide(packageDocument, epubReader, book, resources); // Books sometimes use non-identifier ids. We map these here to legal ones - Map idMapping = new HashMap(); + Map idMapping = new HashMap<>(); String version=DOMUtil.getAttribute(packageDocument.getDocumentElement(),PREFIX_OPF,PackageDocumentBase.version); resources = readManifest(packageDocument, packageHref, epubReader, @@ -90,13 +86,14 @@ public class PackageDocumentReader extends PackageDocumentBase { /** * Reads the manifest containing the resource ids, hrefs and mediatypes. * - * @param packageDocument - * @param packageHref - * @param epubReader - * @param resources - * @param idMapping + * @param packageDocument e + * @param packageHref e + * @param epubReader e + * @param resources e + * @param idMapping e * @return a Map with resources, with their id's as key. */ + @SuppressWarnings("unused") private static Resources readManifest(Document packageDocument, String packageHref, EpubReader epubReader, Resources resources, @@ -118,7 +115,7 @@ public class PackageDocumentReader extends PackageDocumentBase { .getAttribute(itemElement, NAMESPACE_OPF, OPFAttributes.id); String href = DOMUtil .getAttribute(itemElement, NAMESPACE_OPF, OPFAttributes.href); - String properties=DOMUtil.getAttribute(itemElement,NAMESPACE_OPF,OPFAttributes.properties); + try { href = URLDecoder.decode(href, Constants.CHARACTER_ENCODING); } catch (UnsupportedEncodingException e) { @@ -132,7 +129,10 @@ public class PackageDocumentReader extends PackageDocumentBase { continue; } resource.setId(id); + //for epub3 + String properties=DOMUtil.getAttribute(itemElement,NAMESPACE_OPF,OPFAttributes.properties); resource.setProperties(properties); + MediaType mediaType = MediaTypes.getMediaTypeByName(mediaTypeName); if (mediaType != null) { resource.setMediaType(mediaType); @@ -148,22 +148,23 @@ public class PackageDocumentReader extends PackageDocumentBase { * Reads the book's guide. * Here some more attempts are made at finding the cover page. * - * @param packageDocument - * @param epubReader - * @param book - * @param resources + * @param packageDocument r + * @param epubReader r + * @param book r + * @param resources g */ + @SuppressWarnings("unused") private static void readGuide(Document packageDocument, - EpubReader epubReader, EpubBook book, Resources resources) { + EpubReader epubReader, Book book, Resources resources) { Element guideElement = DOMUtil - .getFirstElementByTagNameNS(packageDocument.getDocumentElement(), - NAMESPACE_OPF, OPFTags.guide); + .getFirstElementByTagNameNS(packageDocument.getDocumentElement(), + NAMESPACE_OPF, OPFTags.guide); if (guideElement == null) { return; } Guide guide = book.getGuide(); NodeList guideReferences = guideElement - .getElementsByTagNameNS(NAMESPACE_OPF, OPFTags.reference); + .getElementsByTagNameNS(NAMESPACE_OPF, OPFTags.reference); for (int i = 0; i < guideReferences.getLength(); i++) { Element referenceElement = (Element) guideReferences.item(i); String resourceHref = DOMUtil @@ -204,8 +205,8 @@ public class PackageDocumentReader extends PackageDocumentBase { * Example: * If the packageHref is "OEBPS/content.opf" then a resource href like "OEBPS/foo/bar.html" will be turned into "foo/bar.html" * - * @param packageHref - * @param resourcesByHref + * @param packageHref f + * @param resourcesByHref g * @return The stripped package href */ static Resources fixHrefs(String packageHref, @@ -228,9 +229,9 @@ public class PackageDocumentReader extends PackageDocumentBase { /** * Reads the document's spine, containing all sections in reading order. * - * @param packageDocument - * @param resources - * @param idMapping + * @param packageDocument b + * @param resources b + * @param idMapping b * @return the document's spine, containing all sections in reading order. */ private static Spine readSpine(Document packageDocument, Resources resources, @@ -251,8 +252,8 @@ public class PackageDocumentReader extends PackageDocumentBase { .setTocResource(findTableOfContentsResource(tocResourceId, resources)); NodeList spineNodes = packageDocument .getElementsByTagNameNS(NAMESPACE_OPF, OPFTags.itemref); - List spineReferences = new ArrayList( - spineNodes.getLength()); + List spineReferences = new ArrayList<>( + spineNodes.getLength()); for (int i = 0; i < spineNodes.getLength(); i++) { Element spineItem = (Element) spineNodes.item(i); String itemref = DOMUtil @@ -267,7 +268,7 @@ public class PackageDocumentReader extends PackageDocumentBase { } Resource resource = resources.getByIdOrHref(id); if (resource == null) { - Log.e(TAG,"resource with id \'" + id + "\' not found"); + Log.e(TAG, "resource with id '" + id + "' not found"); continue; } @@ -286,13 +287,12 @@ public class PackageDocumentReader extends PackageDocumentBase { * Creates a spine out of all resources in the resources. * The generated spine consists of all XHTML pages in order of their href. * - * @param resources + * @param resources f * @return a spine created out of all resources in the resources. */ private static Spine generateSpineFromResources(Resources resources) { Spine result = new Spine(); - List resourceHrefs = new ArrayList(); - resourceHrefs.addAll(resources.getAllHrefs()); + List resourceHrefs = new ArrayList<>(resources.getAllHrefs()); Collections.sort(resourceHrefs, String.CASE_INSENSITIVE_ORDER); for (String resourceHref : resourceHrefs) { Resource resource = resources.getByHref(resourceHref); @@ -312,8 +312,8 @@ public class PackageDocumentReader extends PackageDocumentBase { * Here we try several ways of finding this table of contents resource. * We try the given attribute value, some often-used ones and finally look through all resources for the first resource with the table of contents mimetype. * - * @param tocResourceId - * @param resources + * @param tocResourceId g + * @param resources g * @return the Resource containing the table of contents */ static Resource findTableOfContentsResource(String tocResourceId, @@ -331,13 +331,13 @@ public class PackageDocumentReader extends PackageDocumentBase { tocResource = resources.findFirstResourceByMediaType(MediaTypes.NCX); if (tocResource == null) { - for (int i = 0; i < POSSIBLE_NCX_ITEM_IDS.length; i++) { - tocResource = resources.getByIdOrHref(POSSIBLE_NCX_ITEM_IDS[i]); + for (String possibleNcxItemId : POSSIBLE_NCX_ITEM_IDS) { + tocResource = resources.getByIdOrHref(possibleNcxItemId); if (tocResource != null) { break; } tocResource = resources - .getByIdOrHref(POSSIBLE_NCX_ITEM_IDS[i].toUpperCase()); + .getByIdOrHref(possibleNcxItemId.toUpperCase()); if (tocResource != null) { break; } @@ -363,13 +363,13 @@ public class PackageDocumentReader extends PackageDocumentBase { * Find all resources that have something to do with the coverpage and the cover image. * Search the meta tags and the guide references * - * @param packageDocument + * @param packageDocument s * @return all resources that have something to do with the coverpage and the cover image. */ // package static Set findCoverHrefs(Document packageDocument) { - Set result = new HashSet(); + Set result = new HashSet<>(); // try and find a meta tag with name = 'cover' and a non-blank id String coverResourceId = DOMUtil @@ -403,18 +403,16 @@ public class PackageDocumentReader extends PackageDocumentBase { /** * Finds the cover resource in the packageDocument and adds it to the book if found. * Keeps the cover resource in the resources map - * - * @param packageDocument - * @param book - * @1param resources + * @param packageDocument s + * @param book x */ - private static void readCover(Document packageDocument, EpubBook book) { + private static void readCover(Document packageDocument, Book book) { Collection coverHrefs = findCoverHrefs(packageDocument); for (String coverHref : coverHrefs) { Resource resource = book.getResources().getByHref(coverHref); if (resource == null) { - Log.e(TAG, "Cover resource " + coverHref + " not found"); + Log.e(TAG,"Cover resource " + coverHref + " not found"); continue; } if (resource.getMediaType() == MediaTypes.XHTML) { diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentWriter.java b/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentWriter.java index 8853c8363..28bc676b9 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentWriter.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentWriter.java @@ -2,16 +2,8 @@ package me.ag2s.epublib.epub; import android.util.Log; -import org.xmlpull.v1.XmlSerializer; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - import me.ag2s.epublib.Constants; -import me.ag2s.epublib.domain.EpubBook; +import me.ag2s.epublib.domain.Book; import me.ag2s.epublib.domain.Guide; import me.ag2s.epublib.domain.GuideReference; import me.ag2s.epublib.domain.MediaTypes; @@ -20,237 +12,242 @@ import me.ag2s.epublib.domain.Spine; import me.ag2s.epublib.domain.SpineReference; import me.ag2s.epublib.util.StringUtil; -//import io.documentnode.minilog.Logger; -//import javax.xml.stream.XMLStreamException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.xmlpull.v1.XmlSerializer; /** * Writes the opf package document as defined by namespace http://www.idpf.org/2007/opf * * @author paul - * */ public class PackageDocumentWriter extends PackageDocumentBase { - //private static final Logger log = Logger.create(PackageDocumentWriter.class); - private static String TAG= PackageDocumentWriter.class.getName(); - - public static void write(EpubWriter epubWriter, XmlSerializer serializer, - EpubBook book) throws IOException { - try { - serializer.startDocument(Constants.CHARACTER_ENCODING, false); - serializer.setPrefix(PREFIX_OPF, NAMESPACE_OPF); - serializer.setPrefix(PREFIX_DUBLIN_CORE, NAMESPACE_DUBLIN_CORE); - serializer.startTag(NAMESPACE_OPF, OPFTags.packageTag); - serializer - .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.version, - "2.0"); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, - OPFAttributes.uniqueIdentifier, BOOK_ID_ID); - - PackageDocumentMetadataWriter.writeMetaData(book, serializer); - - writeManifest(book, epubWriter, serializer); - writeSpine(book, epubWriter, serializer); - writeGuide(book, epubWriter, serializer); - - serializer.endTag(NAMESPACE_OPF, OPFTags.packageTag); - serializer.endDocument(); - serializer.flush(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + private static final String TAG = PackageDocumentWriter.class.getName(); + + public static void write(EpubWriter epubWriter, XmlSerializer serializer, + Book book) { + try { + serializer.startDocument(Constants.CHARACTER_ENCODING, false); + serializer.setPrefix(PREFIX_OPF, NAMESPACE_OPF); + serializer.setPrefix(PREFIX_DUBLIN_CORE, NAMESPACE_DUBLIN_CORE); + serializer.startTag(NAMESPACE_OPF, OPFTags.packageTag); + serializer + .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.version, + book.getVersion()); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, + OPFAttributes.uniqueIdentifier, BOOK_ID_ID); + + PackageDocumentMetadataWriter.writeMetaData(book, serializer); + + writeManifest(book, epubWriter, serializer); + writeSpine(book, epubWriter, serializer); + writeGuide(book, epubWriter, serializer); + + serializer.endTag(NAMESPACE_OPF, OPFTags.packageTag); + serializer.endDocument(); + serializer.flush(); + } catch (IOException e) { + e.printStackTrace(); + } } - } - - /** - * Writes the package's spine. - * - * @param book - * @param epubWriter - * @param serializer - * @throws IOException - * @throws IllegalStateException - * @throws IllegalArgumentException - * 1@throws XMLStreamException - */ - private static void writeSpine(EpubBook book, EpubWriter epubWriter, - XmlSerializer serializer) - throws IllegalArgumentException, IllegalStateException, IOException { - serializer.startTag(NAMESPACE_OPF, OPFTags.spine); - Resource tocResource = book.getSpine().getTocResource(); - String tocResourceId = tocResource.getId(); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.toc, - tocResourceId); - if (book.getCoverPage() != null // there is a cover page - && book.getSpine().findFirstResourceById(book.getCoverPage().getId()) - < 0) { // cover page is not already in the spine - // write the cover html file - serializer.startTag(NAMESPACE_OPF, OPFTags.itemref); - serializer - .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.idref, - book.getCoverPage().getId()); - serializer - .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.linear, - "no"); - serializer.endTag(NAMESPACE_OPF, OPFTags.itemref); + /** + * Writes the package's spine. + * + * @param book e + * @param epubWriter g + * @param serializer g + * @throws IOException g + * @throws IllegalStateException g + * @throws IllegalArgumentException 1@throws XMLStreamException + */ + @SuppressWarnings("unused") + private static void writeSpine(Book book, EpubWriter epubWriter, + XmlSerializer serializer) + throws IllegalArgumentException, IllegalStateException, IOException { + serializer.startTag(NAMESPACE_OPF, OPFTags.spine); + Resource tocResource = book.getSpine().getTocResource(); + String tocResourceId = tocResource.getId(); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.toc, + tocResourceId); + + if (book.getCoverPage() != null // there is a cover page + && book.getSpine().findFirstResourceById(book.getCoverPage().getId()) + < 0) { // cover page is not already in the spine + // write the cover html file + serializer.startTag(NAMESPACE_OPF, OPFTags.itemref); + serializer + .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.idref, + book.getCoverPage().getId()); + serializer + .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.linear, + "no"); + serializer.endTag(NAMESPACE_OPF, OPFTags.itemref); + } + writeSpineItems(book.getSpine(), serializer); + serializer.endTag(NAMESPACE_OPF, OPFTags.spine); } - writeSpineItems(book.getSpine(), serializer); - serializer.endTag(NAMESPACE_OPF, OPFTags.spine); - } - private static void writeManifest(EpubBook book, EpubWriter epubWriter, - XmlSerializer serializer) - throws IllegalArgumentException, IllegalStateException, IOException { - serializer.startTag(NAMESPACE_OPF, OPFTags.manifest); + private static void writeManifest(Book book, EpubWriter epubWriter, + XmlSerializer serializer) + throws IllegalArgumentException, IllegalStateException, IOException { + serializer.startTag(NAMESPACE_OPF, OPFTags.manifest); - serializer.startTag(NAMESPACE_OPF, OPFTags.item); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.id, - epubWriter.getNcxId()); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.href, - epubWriter.getNcxHref()); - serializer - .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.media_type, - epubWriter.getNcxMediaType()); - serializer.endTag(NAMESPACE_OPF, OPFTags.item); + serializer.startTag(NAMESPACE_OPF, OPFTags.item); -// writeCoverResources(book, serializer); + //For EPUB3 + if (book.isEpub3()) { + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.properties,NCXDocumentV3.V3_NCX_PROPERTIES); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.id, NCXDocumentV3.NCX_ITEM_ID); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.href, NCXDocumentV3.DEFAULT_NCX_HREF); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.media_type, NCXDocumentV3.V3_NCX_MEDIATYPE.getName()); + } else { + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.id, + epubWriter.getNcxId()); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.href, epubWriter.getNcxHref()); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.media_type, epubWriter.getNcxMediaType()); + } - for (Resource resource : getAllResourcesSortById(book)) { - writeItem(book, resource, serializer); - } + serializer.endTag(NAMESPACE_OPF, OPFTags.item); - serializer.endTag(NAMESPACE_OPF, OPFTags.manifest); - } +// writeCoverResources(book, serializer); - private static List getAllResourcesSortById(EpubBook book) { - List allResources = new ArrayList( - book.getResources().getAll()); - Collections.sort(allResources, new Comparator() { + for (Resource resource : getAllResourcesSortById(book)) { + writeItem(book, resource, serializer); + } - @Override - public int compare(Resource resource1, Resource resource2) { - return resource1.getId().compareToIgnoreCase(resource2.getId()); - } - }); - return allResources; - } + serializer.endTag(NAMESPACE_OPF, OPFTags.manifest); + } - /** - * Writes a resources as an item element - * - * @param resource - * @param serializer - * @throws IOException - * @throws IllegalStateException - * @throws IllegalArgumentException 1@throws XMLStreamException - */ - private static void writeItem(EpubBook book, Resource resource, - XmlSerializer serializer) - throws IllegalArgumentException, IllegalStateException, IOException { - if (resource == null || - (resource.getMediaType() == MediaTypes.NCX - && book.getSpine().getTocResource() != null)) { - return; + private static List getAllResourcesSortById(Book book) { + List allResources = new ArrayList<>( + book.getResources().getAll()); + Collections.sort(allResources, (resource1, resource2) -> resource1.getId().compareToIgnoreCase(resource2.getId())); + return allResources; } - if (StringUtil.isBlank(resource.getId())) { + + /** + * Writes a resources as an item element + * + * @param resource g + * @param serializer g + * @throws IOException g + * @throws IllegalStateException g + * @throws IllegalArgumentException 1@throws XMLStreamException + */ + private static void writeItem(Book book, Resource resource, + XmlSerializer serializer) + throws IllegalArgumentException, IllegalStateException, IOException { + if (resource == null || + (resource.getMediaType() == MediaTypes.NCX + && book.getSpine().getTocResource() != null)) { + return; + } + if (StringUtil.isBlank(resource.getId())) { // log.error("resource id must not be empty (href: " + resource.getHref() // + ", mediatype:" + resource.getMediaType() + ")"); - Log.e(TAG, "resource id must not be empty (href: " + resource.getHref() - + ", mediatype:" + resource.getMediaType() + ")"); - return; - } - if (StringUtil.isBlank(resource.getHref())) { + Log.e(TAG, "resource id must not be empty (href: " + resource.getHref() + + ", mediatype:" + resource.getMediaType() + ")"); + return; + } + if (StringUtil.isBlank(resource.getHref())) { // log.error("resource href must not be empty (id: " + resource.getId() // + ", mediatype:" + resource.getMediaType() + ")"); - Log.e(TAG,"resource href must not be empty (id: " + resource.getId() - + ", mediatype:" + resource.getMediaType() + ")"); - return; - } - if (resource.getMediaType() == null) { + Log.e(TAG, "resource href must not be empty (id: " + resource.getId() + + ", mediatype:" + resource.getMediaType() + ")"); + return; + } + if (resource.getMediaType() == null) { // log.error("resource mediatype must not be empty (id: " + resource.getId() // + ", href:" + resource.getHref() + ")"); - Log.e(TAG,"resource mediatype must not be empty (id: " + resource.getId() - + ", href:" + resource.getHref() + ")"); - return; - } - serializer.startTag(NAMESPACE_OPF, OPFTags.item); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.id, - resource.getId()); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.href, - resource.getHref()); - serializer - .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.media_type, - resource.getMediaType().getName()); - serializer.endTag(NAMESPACE_OPF, OPFTags.item); - } - - /** - * List all spine references - * @throws IOException - * @throws IllegalStateException - * @throws IllegalArgumentException - */ - private static void writeSpineItems(Spine spine, XmlSerializer serializer) - throws IllegalArgumentException, IllegalStateException, IOException { - for (SpineReference spineReference : spine.getSpineReferences()) { - serializer.startTag(NAMESPACE_OPF, OPFTags.itemref); - serializer - .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.idref, - spineReference.getResourceId()); - if (!spineReference.isLinear()) { + Log.e(TAG, "resource mediatype must not be empty (id: " + resource.getId() + + ", href:" + resource.getHref() + ")"); + return; + } + serializer.startTag(NAMESPACE_OPF, OPFTags.item); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.id, + resource.getId()); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.href, + resource.getHref()); serializer - .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.linear, - OPFValues.no); - } - serializer.endTag(NAMESPACE_OPF, OPFTags.itemref); + .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.media_type, + resource.getMediaType().getName()); + serializer.endTag(NAMESPACE_OPF, OPFTags.item); } - } - private static void writeGuide(EpubBook book, EpubWriter epubWriter, - XmlSerializer serializer) - throws IllegalArgumentException, IllegalStateException, IOException { - serializer.startTag(NAMESPACE_OPF, OPFTags.guide); - ensureCoverPageGuideReferenceWritten(book.getGuide(), epubWriter, - serializer); - for (GuideReference reference : book.getGuide().getReferences()) { - writeGuideReference(reference, serializer); + /** + * List all spine references + * + * @throws IOException f + * @throws IllegalStateException f + * @throws IllegalArgumentException f + */ + @SuppressWarnings("unused") + private static void writeSpineItems(Spine spine, XmlSerializer serializer) + throws IllegalArgumentException, IllegalStateException, IOException { + for (SpineReference spineReference : spine.getSpineReferences()) { + serializer.startTag(NAMESPACE_OPF, OPFTags.itemref); + serializer + .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.idref, + spineReference.getResourceId()); + if (!spineReference.isLinear()) { + serializer + .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.linear, + OPFValues.no); + } + serializer.endTag(NAMESPACE_OPF, OPFTags.itemref); + } } - serializer.endTag(NAMESPACE_OPF, OPFTags.guide); - } - private static void ensureCoverPageGuideReferenceWritten(Guide guide, - EpubWriter epubWriter, XmlSerializer serializer) - throws IllegalArgumentException, IllegalStateException, IOException { - if (!(guide.getGuideReferencesByType(GuideReference.COVER).isEmpty())) { - return; + private static void writeGuide(Book book, EpubWriter epubWriter, + XmlSerializer serializer) + throws IllegalArgumentException, IllegalStateException, IOException { + serializer.startTag(NAMESPACE_OPF, OPFTags.guide); + ensureCoverPageGuideReferenceWritten(book.getGuide(), epubWriter, + serializer); + for (GuideReference reference : book.getGuide().getReferences()) { + writeGuideReference(reference, serializer); + } + serializer.endTag(NAMESPACE_OPF, OPFTags.guide); } - Resource coverPage = guide.getCoverPage(); - if (coverPage != null) { - writeGuideReference( - new GuideReference(guide.getCoverPage(), GuideReference.COVER, - GuideReference.COVER), serializer); + + @SuppressWarnings("unused") + private static void ensureCoverPageGuideReferenceWritten(Guide guide, + EpubWriter epubWriter, XmlSerializer serializer) + throws IllegalArgumentException, IllegalStateException, IOException { + if (!(guide.getGuideReferencesByType(GuideReference.COVER).isEmpty())) { + return; + } + Resource coverPage = guide.getCoverPage(); + if (coverPage != null) { + writeGuideReference( + new GuideReference(guide.getCoverPage(), GuideReference.COVER, + GuideReference.COVER), serializer); + } } - } - private static void writeGuideReference(GuideReference reference, - XmlSerializer serializer) - throws IllegalArgumentException, IllegalStateException, IOException { - if (reference == null) { - return; - } - serializer.startTag(NAMESPACE_OPF, OPFTags.reference); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.type, - reference.getType()); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.href, - reference.getCompleteHref()); - if (StringUtil.isNotBlank(reference.getTitle())) { - serializer - .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.title, - reference.getTitle()); + private static void writeGuideReference(GuideReference reference, + XmlSerializer serializer) + throws IllegalArgumentException, IllegalStateException, IOException { + if (reference == null) { + return; + } + serializer.startTag(NAMESPACE_OPF, OPFTags.reference); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.type, + reference.getType()); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.href, + reference.getCompleteHref()); + if (StringUtil.isNotBlank(reference.getTitle())) { + serializer + .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.title, + reference.getTitle()); + } + serializer.endTag(NAMESPACE_OPF, OPFTags.reference); } - serializer.endTag(NAMESPACE_OPF, OPFTags.reference); - } } \ No newline at end of file diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/ResourcesLoader.java b/epublib/src/main/java/me/ag2s/epublib/epub/ResourcesLoader.java index f2114bc1b..df53b0162 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/ResourcesLoader.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/ResourcesLoader.java @@ -11,9 +11,10 @@ import me.ag2s.epublib.domain.Resource; import me.ag2s.epublib.domain.Resources; import me.ag2s.epublib.util.CollectionUtil; import me.ag2s.epublib.util.ResourceUtil; + import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.zip.ZipEntry; @@ -26,148 +27,147 @@ import java.util.zip.ZipInputStream; * Loads Resources from inputStreams, ZipFiles, etc * * @author paul - * */ public class ResourcesLoader { - private static String TAG=ResourceUtil.class.getName(); - - - /** - * Loads the entries of the zipFile as resources. - * - * The MediaTypes that are in the lazyLoadedTypes will not get their - * contents loaded, but are stored as references to entries into the - * ZipFile and are loaded on demand by the Resource system. - * - * @param zipFile - * @param defaultHtmlEncoding - * @param lazyLoadedTypes - * @return - * @throws IOException - */ - public static Resources loadResources(ZipFile zipFile, - String defaultHtmlEncoding, - List lazyLoadedTypes) throws IOException { - - LazyResourceProvider resourceProvider = - new EpubResourceProvider(zipFile.getName()); - - Resources result = new Resources(); - Enumeration entries = zipFile.entries(); - - while (entries.hasMoreElements()) { - ZipEntry zipEntry = entries.nextElement(); - - if (zipEntry == null || zipEntry.isDirectory()) { - continue; - } - - String href = zipEntry.getName(); - - Resource resource; - - if (shouldLoadLazy(href, lazyLoadedTypes)) { - resource = new LazyResource(resourceProvider, zipEntry.getSize(), href); - } else { - resource = ResourceUtil - .createResource(zipEntry, zipFile.getInputStream(zipEntry)); - } - - if (resource.getMediaType() == MediaTypes.XHTML) { - resource.setInputEncoding(defaultHtmlEncoding); - } - result.add(resource); + private static final String TAG = ResourcesLoader.class.getName(); + + + /** + * Loads the entries of the zipFile as resources. + *

+ * The MediaTypes that are in the lazyLoadedTypes will not get their + * contents loaded, but are stored as references to entries into the + * ZipFile and are loaded on demand by the Resource system. + * + * @param zipFile import epub zipfile + * @param defaultHtmlEncoding epub xhtml default encoding + * @param lazyLoadedTypes lazyLoadedTypes + * @return Resources + * @throws IOException IOException + */ + public static Resources loadResources(ZipFile zipFile, + String defaultHtmlEncoding, + List lazyLoadedTypes) throws IOException { + + LazyResourceProvider resourceProvider = + new EpubResourceProvider(zipFile.getName()); + + Resources result = new Resources(); + Enumeration entries = zipFile.entries(); + + while (entries.hasMoreElements()) { + ZipEntry zipEntry = entries.nextElement(); + + if (zipEntry == null || zipEntry.isDirectory()) { + continue; + } + + String href = zipEntry.getName(); + + Resource resource; + + if (shouldLoadLazy(href, lazyLoadedTypes)) { + resource = new LazyResource(resourceProvider, zipEntry.getSize(), href); + } else { + resource = ResourceUtil + .createResource(zipEntry, zipFile.getInputStream(zipEntry)); + } + + if (resource.getMediaType() == MediaTypes.XHTML) { + resource.setInputEncoding(defaultHtmlEncoding); + } + result.add(resource); + } + + return result; + } + + /** + * Whether the given href will load a mediaType that is in the + * collection of lazilyLoadedMediaTypes. + * + * @param href href + * @param lazilyLoadedMediaTypes lazilyLoadedMediaTypes + * @return Whether the given href will load a mediaType that is + * in the collection of lazilyLoadedMediaTypes. + */ + private static boolean shouldLoadLazy(String href, + Collection lazilyLoadedMediaTypes) { + if (CollectionUtil.isEmpty(lazilyLoadedMediaTypes)) { + return false; + } + MediaType mediaType = MediaTypes.determineMediaType(href); + return lazilyLoadedMediaTypes.contains(mediaType); } - return result; - } - - /** - * Whether the given href will load a mediaType that is in the - * collection of lazilyLoadedMediaTypes. - * - * @param href - * @param lazilyLoadedMediaTypes - * @return Whether the given href will load a mediaType that is - * in the collection of lazilyLoadedMediaTypes. - */ - private static boolean shouldLoadLazy(String href, - Collection lazilyLoadedMediaTypes) { - if (CollectionUtil.isEmpty(lazilyLoadedMediaTypes)) { - return false; + /** + * Loads all entries from the ZipInputStream as Resources. + *

+ * Loads the contents of all ZipEntries into memory. + * Is fast, but may lead to memory problems when reading large books + * on devices with small amounts of memory. + * + * @param zipInputStream zipInputStream + * @param defaultHtmlEncoding defaultHtmlEncoding + * @return Resources + * @throws IOException IOException + */ + public static Resources loadResources(ZipInputStream zipInputStream, + String defaultHtmlEncoding) throws IOException { + Resources result = new Resources(); + ZipEntry zipEntry; + do { + // get next valid zipEntry + zipEntry = getNextZipEntry(zipInputStream); + if ((zipEntry == null) || zipEntry.isDirectory()) { + continue; + } + + // store resource + Resource resource = ResourceUtil.createResource(zipEntry, zipInputStream); + if (resource.getMediaType() == MediaTypes.XHTML) { + resource.setInputEncoding(defaultHtmlEncoding); + } + result.add(resource); + } while (zipEntry != null); + + return result; } - MediaType mediaType = MediaTypes.determineMediaType(href); - return lazilyLoadedMediaTypes.contains(mediaType); - } - - /** - * Loads all entries from the ZipInputStream as Resources. - * - * Loads the contents of all ZipEntries into memory. - * Is fast, but may lead to memory problems when reading large books - * on devices with small amounts of memory. - * - * @param zipInputStream - * @param defaultHtmlEncoding - * @return - * @throws IOException - */ - public static Resources loadResources(ZipInputStream zipInputStream, - String defaultHtmlEncoding) throws IOException { - Resources result = new Resources(); - ZipEntry zipEntry; - do { - // get next valid zipEntry - zipEntry = getNextZipEntry(zipInputStream); - if ((zipEntry == null) || zipEntry.isDirectory()) { - continue; - } - - // store resource - Resource resource = ResourceUtil.createResource(zipEntry, zipInputStream); - if (resource.getMediaType() == MediaTypes.XHTML) { - resource.setInputEncoding(defaultHtmlEncoding); - } - result.add(resource); - } while (zipEntry != null); - - return result; - } - - - private static ZipEntry getNextZipEntry(ZipInputStream zipInputStream) - throws IOException { - try { - return zipInputStream.getNextEntry(); - } catch (ZipException e) { - //see Issue #122 Infinite loop. - //when reading a file that is not a real zip archive or a zero length file, zipInputStream.getNextEntry() - //throws an exception and does not advance, so loadResources enters an infinite loop - //log.error("Invalid or damaged zip file.", e); - Log.e(TAG,"",e); - try { - zipInputStream.closeEntry(); - } catch (Exception ignored) { - } - throw e; + + + private static ZipEntry getNextZipEntry(ZipInputStream zipInputStream) + throws IOException { + try { + return zipInputStream.getNextEntry(); + } catch (ZipException e) { + //see Issue #122 Infinite loop. + //when reading a file that is not a real zip archive or a zero length file, zipInputStream.getNextEntry() + //throws an exception and does not advance, so loadResources enters an infinite loop + //log.error("Invalid or damaged zip file.", e); + Log.e(TAG, e.getLocalizedMessage()); + try { + zipInputStream.closeEntry(); + } catch (Exception ignored) { + } + throw e; + } + } + + /** + * Loads all entries from the ZipInputStream as Resources. + *

+ * Loads the contents of all ZipEntries into memory. + * Is fast, but may lead to memory problems when reading large books + * on devices with small amounts of memory. + * + * @param zipFile zipFile + * @param defaultHtmlEncoding defaultHtmlEncoding + * @return Resources + * @throws IOException IOException + */ + public static Resources loadResources(ZipFile zipFile, String defaultHtmlEncoding) throws IOException { + List ls = new ArrayList<>(); + return loadResources(zipFile, defaultHtmlEncoding, ls); } - } - - /** - * Loads all entries from the ZipInputStream as Resources. - * - * Loads the contents of all ZipEntries into memory. - * Is fast, but may lead to memory problems when reading large books - * on devices with small amounts of memory. - * - * @param zipFile - * @param defaultHtmlEncoding - * @return - * @throws IOException - */ - public static Resources loadResources(ZipFile zipFile, - String defaultHtmlEncoding) throws IOException { - return loadResources(zipFile, defaultHtmlEncoding, Collections.emptyList()); - } } diff --git a/epublib/src/main/java/me/ag2s/epublib/util/CollectionUtil.java b/epublib/src/main/java/me/ag2s/epublib/util/CollectionUtil.java index e4d152ff6..e367fdc66 100644 --- a/epublib/src/main/java/me/ag2s/epublib/util/CollectionUtil.java +++ b/epublib/src/main/java/me/ag2s/epublib/util/CollectionUtil.java @@ -15,7 +15,7 @@ public class CollectionUtil { */ private static class IteratorEnumerationAdapter implements Enumeration { - private Iterator iterator; + private final Iterator iterator; public IteratorEnumerationAdapter(Iterator iter) { this.iterator = iter; @@ -34,21 +34,22 @@ public class CollectionUtil { /** * Creates an Enumeration out of the given Iterator. - * @param - * @param it + * @param g + * @param it g * @return an Enumeration created out of the given Iterator. */ + @SuppressWarnings("unused") public static Enumeration createEnumerationFromIterator( Iterator it) { - return new IteratorEnumerationAdapter(it); + return new IteratorEnumerationAdapter<>(it); } /** * Returns the first element of the list, null if the list is null or empty. * - * @param - * @param list + * @param f + * @param list f * @return the first element of the list, null if the list is null or empty. */ public static T first(List list) { @@ -61,7 +62,7 @@ public class CollectionUtil { /** * Whether the given collection is null or has no elements. * - * @param collection + * @param collection g * @return Whether the given collection is null or has no elements. */ public static boolean isEmpty(Collection collection) { diff --git a/epublib/src/main/java/me/ag2s/epublib/util/IOUtil.java b/epublib/src/main/java/me/ag2s/epublib/util/IOUtil.java index 823a73b74..8bb4bf8cc 100644 --- a/epublib/src/main/java/me/ag2s/epublib/util/IOUtil.java +++ b/epublib/src/main/java/me/ag2s/epublib/util/IOUtil.java @@ -23,10 +23,10 @@ public class IOUtil { /** * Gets the contents of the Reader as a byte[], with the given character encoding. * - * @param in - * @param encoding + * @param in g + * @param encoding g * @return the contents of the Reader as a byte[], with the given character encoding. - * @throws IOException + * @throws IOException g */ public static byte[] toByteArray(Reader in, String encoding) throws IOException { @@ -39,9 +39,9 @@ public class IOUtil { /** * Returns the contents of the InputStream as a byte[] * - * @param in + * @param in f * @return the contents of the InputStream as a byte[] - * @throws IOException + * @throws IOException f */ public static byte[] toByteArray(InputStream in) throws IOException { ByteArrayOutputStream result = new ByteArrayOutputStream(); @@ -59,7 +59,7 @@ public class IOUtil { * @param in the stream to read data from * @param size the size of the array to create * @return the array, or null - * @throws IOException + * @throws IOException f */ public static byte[] toByteArray(InputStream in, int size) throws IOException { @@ -89,8 +89,8 @@ public class IOUtil { * (nrRead + totalNrRead) < Integer.MAX_VALUE then nrRead + totalNrRead * is returned, -1 otherwise. * - * @param nrRead - * @param totalNrNread + * @param nrRead f + * @param totalNrNread f * @return if totalNrRead < 0 then totalNrRead is returned, if * (nrRead + totalNrRead) < Integer.MAX_VALUE then nrRead + totalNrRead * is returned, -1 otherwise. @@ -109,15 +109,15 @@ public class IOUtil { /** * Copies the contents of the InputStream to the OutputStream. * - * @param in - * @param out + * @param in f + * @param out f * @return the nr of bytes read, or -1 if the amount > Integer.MAX_VALUE - * @throws IOException + * @throws IOException f */ public static int copy(InputStream in, OutputStream out) throws IOException { byte[] buffer = new byte[IO_COPY_BUFFER_SIZE]; - int readSize = -1; + int readSize ; int result = 0; while ((readSize = in.read(buffer)) >= 0) { out.write(buffer, 0, readSize); @@ -130,14 +130,14 @@ public class IOUtil { /** * Copies the contents of the Reader to the Writer. * - * @param in - * @param out + * @param in f + * @param out f * @return the nr of characters read, or -1 if the amount > Integer.MAX_VALUE - * @throws IOException + * @throws IOException f */ public static int copy(Reader in, Writer out) throws IOException { char[] buffer = new char[IO_COPY_BUFFER_SIZE]; - int readSize = -1; + int readSize; int result = 0; while ((readSize = in.read(buffer)) >= 0) { out.write(buffer, 0, readSize); @@ -148,7 +148,7 @@ public class IOUtil { } public static String Stream2String(InputStream inputStream) { - String str=""; + String str; try { BufferedInputStream bis = new BufferedInputStream(inputStream); ByteArrayOutputStream buf = new ByteArrayOutputStream(); diff --git a/epublib/src/main/java/me/ag2s/epublib/util/NoCloseOutputStream.java b/epublib/src/main/java/me/ag2s/epublib/util/NoCloseOutputStream.java index d3af0803b..15a3893b6 100644 --- a/epublib/src/main/java/me/ag2s/epublib/util/NoCloseOutputStream.java +++ b/epublib/src/main/java/me/ag2s/epublib/util/NoCloseOutputStream.java @@ -11,9 +11,10 @@ import java.io.OutputStream; * * @author paul */ +@SuppressWarnings("unused") public class NoCloseOutputStream extends OutputStream { - private OutputStream outputStream; + private final OutputStream outputStream; public NoCloseOutputStream(OutputStream outputStream) { this.outputStream = outputStream; diff --git a/epublib/src/main/java/me/ag2s/epublib/util/NoCloseWriter.java b/epublib/src/main/java/me/ag2s/epublib/util/NoCloseWriter.java index 8587daf15..ad1da9c7c 100644 --- a/epublib/src/main/java/me/ag2s/epublib/util/NoCloseWriter.java +++ b/epublib/src/main/java/me/ag2s/epublib/util/NoCloseWriter.java @@ -11,16 +11,17 @@ import java.io.Writer; * * @author paul */ +@SuppressWarnings("unused") public class NoCloseWriter extends Writer { - private Writer writer; + private final Writer writer; public NoCloseWriter(Writer writer) { this.writer = writer; } @Override - public void close() throws IOException { + public void close() { } @Override diff --git a/epublib/src/main/java/me/ag2s/epublib/util/ResourceUtil.java b/epublib/src/main/java/me/ag2s/epublib/util/ResourceUtil.java index 3467a62b4..ec742c0b0 100644 --- a/epublib/src/main/java/me/ag2s/epublib/util/ResourceUtil.java +++ b/epublib/src/main/java/me/ag2s/epublib/util/ResourceUtil.java @@ -1,10 +1,9 @@ package me.ag2s.epublib.util; -import me.ag2s.epublib.Constants; -import me.ag2s.epublib.domain.MediaType; -import me.ag2s.epublib.domain.Resource; -import me.ag2s.epublib.epub.EpubProcessorSupport; -import me.ag2s.epublib.domain.MediaTypes; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -15,11 +14,12 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.ParserConfigurationException; -import org.w3c.dom.Document; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; +import me.ag2s.epublib.Constants; +import me.ag2s.epublib.domain.MediaType; +import me.ag2s.epublib.domain.MediaTypes; +import me.ag2s.epublib.domain.Resource; +import me.ag2s.epublib.epub.EpubProcessorSupport; /** * Various resource utility methods @@ -28,147 +28,148 @@ import org.xml.sax.SAXException; */ public class ResourceUtil { - public static Resource createHTMLResource(String title, String string) { - String html=createHtml(title,string); - MediaType mediaTypeProperty = MediaTypes.XHTML; - byte[] data = html.getBytes(); - Resource result = new Resource(data, mediaTypeProperty); - return result; - } - public static Resource createHTMLResource(String title, String string,String href) { - String html=createHtml(title,string); - MediaType mediaTypeProperty = MediaTypes.XHTML; - byte[] data = html.getBytes(); - Resource result = new Resource(null,data,href ,mediaTypeProperty); - return result; - } - private static String createHtml(String title,String txt){ - StringBuilder body= new StringBuilder(); - for(String s:txt.split("\\r?\\n")){ - s=s.trim(); - if(s!=null&&s.length()!=0) { - body.append("

").append(s).append("

"); - } + public static Resource createHTMLResource(String title, String string) { + String html = createHtml(title, string); + MediaType mediaTypeProperty = MediaTypes.XHTML; + byte[] data = html.getBytes(); + return new Resource(data, mediaTypeProperty); + } + + @SuppressWarnings("unused") + public static Resource createHTMLResource(String title, String string, String href) { + String html = createHtml(title, string); + MediaType mediaTypeProperty = MediaTypes.XHTML; + byte[] data = html.getBytes(); + return new Resource(null, data, href, mediaTypeProperty); + } + + @SuppressWarnings("unused") + private static String createHtml(String title, String txt) { + StringBuilder body = new StringBuilder(); + for (String s : txt.split("\\r?\\n")) { + s = s.trim(); + if (s.length() != 0) { + body.append("

").append(s).append("

"); + } + + } + String html = ""; + html += ""; + html += "" + title + "" + + "" + + ""; + html += "

" + title + "

" + + body + + ""; + + return html; + } + + @SuppressWarnings("unused") + public static Resource createResource(File file) throws IOException { + if (file == null) { + return null; + } + MediaType mediaType = MediaTypes.determineMediaType(file.getName()); + byte[] data = IOUtil.toByteArray(new FileInputStream(file)); + return new Resource(data, mediaType); + } + + + /** + * Creates a resource with as contents a html page with the given title. + * + * @param title v + * @param href v + * @return a resource with as contents a html page with the given title. + */ + @SuppressWarnings("unused") + public static Resource createResource(String title, String href) { + String content = + "" + title + "

" + title + + "

"; + return new Resource(null, content.getBytes(), href, MediaTypes.XHTML, + Constants.CHARACTER_ENCODING); + } + + /** + * Creates a resource out of the given zipEntry and zipInputStream. + * + * @param zipEntry v + * @param zipInputStream v + * @return a resource created out of the given zipEntry and zipInputStream. + * @throws IOException v + */ + public static Resource createResource(ZipEntry zipEntry, + ZipInputStream zipInputStream) throws IOException { + return new Resource(zipInputStream, zipEntry.getName()); } - String html=""; - html+=""; - html+=""+title+"" + - "" + - ""; - html+="

"+title+"

" + - body+ - ""; - - return html; - } - - public static Resource createResource(File file) throws IOException { - if (file == null) { - return null; + + public static Resource createResource(ZipEntry zipEntry, + InputStream zipInputStream) throws IOException { + return new Resource(zipInputStream, zipEntry.getName()); + } - MediaType mediaType = MediaTypes.determineMediaType(file.getName()); - byte[] data = IOUtil.toByteArray(new FileInputStream(file)); - Resource result = new Resource(data, mediaType); - return result; - } - - - /** - * Creates a resource with as contents a html page with the given title. - * - * @param title - * @param href - * @return a resource with as contents a html page with the given title. - */ - public static Resource createResource(String title, String href) { - String content = - "" + title + "

" + title - + "

"; - return new Resource(null, content.getBytes(), href, MediaTypes.XHTML, - Constants.CHARACTER_ENCODING); - } - - /** - * Creates a resource out of the given zipEntry and zipInputStream. - * - * @param zipEntry - * @param zipInputStream - * @return a resource created out of the given zipEntry and zipInputStream. - * @throws IOException - */ - public static Resource createResource(ZipEntry zipEntry, - ZipInputStream zipInputStream) throws IOException { - return new Resource(zipInputStream, zipEntry.getName()); - - } - - public static Resource createResource(ZipEntry zipEntry, - InputStream zipInputStream) throws IOException { - return new Resource(zipInputStream, zipEntry.getName()); - - } - - /** - * Converts a given string from given input character encoding to the requested output character encoding. - * - * @param inputEncoding - * @param outputEncoding - * @param input - * @return the string from given input character encoding converted to the requested output character encoding. - * @throws UnsupportedEncodingException - */ - public static byte[] recode(String inputEncoding, String outputEncoding, - byte[] input) throws UnsupportedEncodingException { - return new String(input, inputEncoding).getBytes(outputEncoding); - } - - /** - * Gets the contents of the Resource as an InputSource in a null-safe manner. - * - */ - public static InputSource getInputSource(Resource resource) - throws IOException { - if (resource == null) { - return null; + + /** + * Converts a given string from given input character encoding to the requested output character encoding. + * + * @param inputEncoding v + * @param outputEncoding v + * @param input v + * @return the string from given input character encoding converted to the requested output character encoding. + * @throws UnsupportedEncodingException v + */ + @SuppressWarnings("unused") + public static byte[] recode(String inputEncoding, String outputEncoding, + byte[] input) throws UnsupportedEncodingException { + return new String(input, inputEncoding).getBytes(outputEncoding); } - Reader reader = resource.getReader(); - if (reader == null) { - return null; + + /** + * Gets the contents of the Resource as an InputSource in a null-safe manner. + */ + @SuppressWarnings("unused") + public static InputSource getInputSource(Resource resource) + throws IOException { + if (resource == null) { + return null; + } + Reader reader = resource.getReader(); + if (reader == null) { + return null; + } + return new InputSource(reader); } - InputSource inputSource = new InputSource(reader); - return inputSource; - } - - - /** - * Reads parses the xml therein and returns the result as a Document - */ - public static Document getAsDocument(Resource resource) - throws SAXException, IOException, ParserConfigurationException { - return getAsDocument(resource, - EpubProcessorSupport.createDocumentBuilder()); - } - - /** - * Reads the given resources inputstream, parses the xml therein and returns the result as a Document - * - * @param resource - * @param documentBuilder - * @return the document created from the given resource - * @throws UnsupportedEncodingException - * @throws SAXException - * @throws IOException - * @throws ParserConfigurationException - */ - public static Document getAsDocument(Resource resource, - DocumentBuilder documentBuilder) - throws UnsupportedEncodingException, SAXException, IOException, ParserConfigurationException { - InputSource inputSource = getInputSource(resource); - if (inputSource == null) { - return null; + + + /** + * Reads parses the xml therein and returns the result as a Document + */ + public static Document getAsDocument(Resource resource) + throws SAXException, IOException { + return getAsDocument(resource, + EpubProcessorSupport.createDocumentBuilder()); + } + + /** + * Reads the given resources inputstream, parses the xml therein and returns the result as a Document + * + * @param resource v + * @param documentBuilder v + * @return the document created from the given resource + * @throws UnsupportedEncodingException v + * @throws SAXException v + * @throws IOException v + */ + public static Document getAsDocument(Resource resource, + DocumentBuilder documentBuilder) + throws UnsupportedEncodingException, SAXException, IOException { + InputSource inputSource = getInputSource(resource); + if (inputSource == null) { + return null; + } + return documentBuilder.parse(inputSource); } - Document result = documentBuilder.parse(inputSource); - return result; - } } diff --git a/epublib/src/main/java/me/ag2s/epublib/util/StreamWriterDelegate.txt b/epublib/src/main/java/me/ag2s/epublib/util/StreamWriterDelegate.txt deleted file mode 100644 index b07ad7a3c..000000000 --- a/epublib/src/main/java/me/ag2s/epublib/util/StreamWriterDelegate.txt +++ /dev/null @@ -1,202 +0,0 @@ -package me.ag2s.epublib.util; -/* - * Copyright (c) 2006, John Kristian - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of StAX-Utils nor the names of its contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -import javax.xml.namespace.NamespaceContext; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamWriter; - -/** - * Abstract class for writing filtered XML streams. This class provides methods - * that merely delegate to the contained stream. Subclasses should override some - * of these methods, and may also provide additional methods and fields. - * - * @author John Kristian - */ -public abstract class StreamWriterDelegate implements XMLStreamWriter { - - protected StreamWriterDelegate(XMLStreamWriter out) { - this.out = out; - } - - protected XMLStreamWriter out; - - public Object getProperty(String name) - throws IllegalArgumentException { - return out.getProperty(name); - } - - public NamespaceContext getNamespaceContext() { - return out.getNamespaceContext(); - } - - public void setNamespaceContext(NamespaceContext context) - throws XMLStreamException { - out.setNamespaceContext(context); - } - - public void setDefaultNamespace(String uri) - throws XMLStreamException { - out.setDefaultNamespace(uri); - } - - public void writeStartDocument() throws XMLStreamException { - out.writeStartDocument(); - } - - public void writeStartDocument(String version) - throws XMLStreamException { - out.writeStartDocument(version); - } - - public void writeStartDocument(String encoding, String version) - throws XMLStreamException { - out.writeStartDocument(encoding, version); - } - - public void writeDTD(String dtd) throws XMLStreamException { - out.writeDTD(dtd); - } - - public void writeProcessingInstruction(String target) - throws XMLStreamException { - out.writeProcessingInstruction(target); - } - - public void writeProcessingInstruction(String target, String data) - throws XMLStreamException { - out.writeProcessingInstruction(target, data); - } - - public void writeComment(String data) throws XMLStreamException { - out.writeComment(data); - } - - public void writeEmptyElement(String localName) - throws XMLStreamException { - out.writeEmptyElement(localName); - } - - public void writeEmptyElement(String namespaceURI, String localName) - throws XMLStreamException { - out.writeEmptyElement(namespaceURI, localName); - } - - public void writeEmptyElement(String prefix, String localName, - String namespaceURI) throws XMLStreamException { - out.writeEmptyElement(prefix, localName, namespaceURI); - } - - public void writeStartElement(String localName) - throws XMLStreamException { - out.writeStartElement(localName); - } - - public void writeStartElement(String namespaceURI, String localName) - throws XMLStreamException { - out.writeStartElement(namespaceURI, localName); - } - - public void writeStartElement(String prefix, String localName, - String namespaceURI) throws XMLStreamException { - out.writeStartElement(prefix, localName, namespaceURI); - } - - public void writeDefaultNamespace(String namespaceURI) - throws XMLStreamException { - out.writeDefaultNamespace(namespaceURI); - } - - public void writeNamespace(String prefix, String namespaceURI) - throws XMLStreamException { - out.writeNamespace(prefix, namespaceURI); - } - - public String getPrefix(String uri) throws XMLStreamException { - return out.getPrefix(uri); - } - - public void setPrefix(String prefix, String uri) - throws XMLStreamException { - out.setPrefix(prefix, uri); - } - - public void writeAttribute(String localName, String value) - throws XMLStreamException { - out.writeAttribute(localName, value); - } - - public void writeAttribute(String namespaceURI, String localName, - String value) throws XMLStreamException { - out.writeAttribute(namespaceURI, localName, value); - } - - public void writeAttribute(String prefix, String namespaceURI, - String localName, String value) throws XMLStreamException { - out.writeAttribute(prefix, namespaceURI, localName, value); - } - - public void writeCharacters(String text) throws XMLStreamException { - out.writeCharacters(text); - } - - public void writeCharacters(char[] text, int start, int len) - throws XMLStreamException { - out.writeCharacters(text, start, len); - } - - public void writeCData(String data) throws XMLStreamException { - out.writeCData(data); - } - - public void writeEntityRef(String name) throws XMLStreamException { - out.writeEntityRef(name); - } - - public void writeEndElement() throws XMLStreamException { - out.writeEndElement(); - } - - public void writeEndDocument() throws XMLStreamException { - out.writeEndDocument(); - } - - public void flush() throws XMLStreamException { - out.flush(); - } - - public void close() throws XMLStreamException { - out.close(); - } - -} - diff --git a/epublib/src/main/java/me/ag2s/epublib/util/StringUtil.java b/epublib/src/main/java/me/ag2s/epublib/util/StringUtil.java index 551d2af4f..677d6a157 100644 --- a/epublib/src/main/java/me/ag2s/epublib/util/StringUtil.java +++ b/epublib/src/main/java/me/ag2s/epublib/util/StringUtil.java @@ -6,270 +6,269 @@ import java.util.List; /** * Various String utility functions. - * + *

* Most of the functions herein are re-implementations of the ones in apache * commons StringUtils. The reason for re-implementing this is that the * functions are fairly simple and using my own implementation saves the * inclusion of a 200Kb jar file. * * @author paul.siegmann - * */ public class StringUtil { - /** - * Changes a path containing '..', '.' and empty dirs into a path that - * doesn't. X/foo/../Y is changed into 'X/Y', etc. Does not handle invalid - * paths like "../". - * - * @param path - * @return the normalized path - */ - public static String collapsePathDots(String path) { - String[] stringParts = path.split("/"); - List parts = new ArrayList(Arrays.asList(stringParts)); - for (int i = 0; i < parts.size() - 1; i++) { - String currentDir = parts.get(i); - if (currentDir.length() == 0 || currentDir.equals(".")) { - parts.remove(i); - i--; - } else if (currentDir.equals("..")) { - parts.remove(i - 1); - parts.remove(i - 1); - i -= 2; - } - } - StringBuilder result = new StringBuilder(); - if (path.startsWith("/")) { - result.append('/'); - } - for (int i = 0; i < parts.size(); i++) { - result.append(parts.get(i)); - if (i < (parts.size() - 1)) { - result.append('/'); - } + /** + * Changes a path containing '..', '.' and empty dirs into a path that + * doesn't. X/foo/../Y is changed into 'X/Y', etc. Does not handle invalid + * paths like "../". + * + * @param path path + * @return the normalized path + */ + public static String collapsePathDots(String path) { + String[] stringParts = path.split("/"); + List parts = new ArrayList<>(Arrays.asList(stringParts)); + for (int i = 0; i < parts.size() - 1; i++) { + String currentDir = parts.get(i); + if (currentDir.length() == 0 || currentDir.equals(".")) { + parts.remove(i); + i--; + } else if (currentDir.equals("..")) { + parts.remove(i - 1); + parts.remove(i - 1); + i -= 2; + } + } + StringBuilder result = new StringBuilder(); + if (path.startsWith("/")) { + result.append('/'); + } + for (int i = 0; i < parts.size(); i++) { + result.append(parts.get(i)); + if (i < (parts.size() - 1)) { + result.append('/'); + } + } + return result.toString(); } - return result.toString(); - } - /** - * Whether the String is not null, not zero-length and does not contain of - * only whitespace. - * - * @param text - * @return Whether the String is not null, not zero-length and does not contain of - */ - public static boolean isNotBlank(String text) { - return !isBlank(text); - } - - /** - * Whether the String is null, zero-length and does contain only whitespace. - * - * @return Whether the String is null, zero-length and does contain only whitespace. - */ - public static boolean isBlank(String text) { - if (isEmpty(text)) { - return true; - } - for (int i = 0; i < text.length(); i++) { - if (!Character.isWhitespace(text.charAt(i))) { - return false; - } + /** + * Whether the String is not null, not zero-length and does not contain of + * only whitespace. + * + * @param text text + * @return Whether the String is not null, not zero-length and does not contain of + */ + public static boolean isNotBlank(String text) { + return !isBlank(text); } - return true; - } - - /** - * Whether the given string is null or zero-length. - * - * @param text the input for this method - * @return Whether the given string is null or zero-length. - */ - public static boolean isEmpty(String text) { - return (text == null) || (text.length() == 0); - } - /** - * Whether the given source string ends with the given suffix, ignoring - * case. - * - * @param source - * @param suffix - * @return Whether the given source string ends with the given suffix, ignoring case. - */ - public static boolean endsWithIgnoreCase(String source, String suffix) { - if (isEmpty(suffix)) { - return true; + /** + * Whether the String is null, zero-length and does contain only whitespace. + * + * @return Whether the String is null, zero-length and does contain only whitespace. + */ + public static boolean isBlank(String text) { + if (isEmpty(text)) { + return true; + } + for (int i = 0; i < text.length(); i++) { + if (!Character.isWhitespace(text.charAt(i))) { + return false; + } + } + return true; } - if (isEmpty(source)) { - return false; - } - if (suffix.length() > source.length()) { - return false; - } - return source.substring(source.length() - suffix.length()) - .toLowerCase().endsWith(suffix.toLowerCase()); - } - /** - * If the given text is null return "", the original text otherwise. - * - * @param text - * @return If the given text is null "", the original text otherwise. - */ - public static String defaultIfNull(String text) { - return defaultIfNull(text, ""); - } - - /** - * If the given text is null return "", the given defaultValue otherwise. - * - * @param text - * @param defaultValue - * @return If the given text is null "", the given defaultValue otherwise. - */ - public static String defaultIfNull(String text, String defaultValue) { - if (text == null) { - return defaultValue; + /** + * Whether the given string is null or zero-length. + * + * @param text the input for this method + * @return Whether the given string is null or zero-length. + */ + public static boolean isEmpty(String text) { + return (text == null) || (text.length() == 0); } - return text; - } - /** - * Null-safe string comparator - * - * @param text1 - * @param text2 - * @return whether the two strings are equal - */ - public static boolean equals(String text1, String text2) { - if (text1 == null) { - return (text2 == null); + /** + * Whether the given source string ends with the given suffix, ignoring + * case. + * + * @param source source + * @param suffix suffix + * @return Whether the given source string ends with the given suffix, ignoring case. + */ + public static boolean endsWithIgnoreCase(String source, String suffix) { + if (isEmpty(suffix)) { + return true; + } + if (isEmpty(source)) { + return false; + } + if (suffix.length() > source.length()) { + return false; + } + return source.substring(source.length() - suffix.length()) + .toLowerCase().endsWith(suffix.toLowerCase()); } - return text1.equals(text2); - } - /** - * Pretty toString printer. - * - * @param keyValues - * @return a string representation of the input values - */ - public static String toString(Object... keyValues) { - StringBuilder result = new StringBuilder(); - result.append('['); - for (int i = 0; i < keyValues.length; i += 2) { - if (i > 0) { - result.append(", "); - } - result.append(keyValues[i]); - result.append(": "); - Object value = null; - if ((i + 1) < keyValues.length) { - value = keyValues[i + 1]; - } - if (value == null) { - result.append(""); - } else { - result.append('\''); - result.append(value); - result.append('\''); - } + /** + * If the given text is null return "", the original text otherwise. + * + * @param text text + * @return If the given text is null "", the original text otherwise. + */ + public static String defaultIfNull(String text) { + return defaultIfNull(text, ""); } - result.append(']'); - return result.toString(); - } - public static int hashCode(String... values) { - int result = 31; - for (int i = 0; i < values.length; i++) { - result ^= String.valueOf(values[i]).hashCode(); + /** + * If the given text is null return "", the given defaultValue otherwise. + * + * @param text d + * @param defaultValue d + * @return If the given text is null "", the given defaultValue otherwise. + */ + public static String defaultIfNull(String text, String defaultValue) { + if (text == null) { + return defaultValue; + } + return text; } - return result; - } - /** - * Gives the substring of the given text before the given separator. - * - * If the text does not contain the given separator then the given text is - * returned. - * - * @param text - * @param separator - * @return the substring of the given text before the given separator. - */ - public static String substringBefore(String text, char separator) { - if (isEmpty(text)) { - return text; - } - int sepPos = text.indexOf(separator); - if (sepPos < 0) { - return text; + /** + * Null-safe string comparator + * + * @param text1 d + * @param text2 d + * @return whether the two strings are equal + */ + public static boolean equals(String text1, String text2) { + if (text1 == null) { + return (text2 == null); + } + return text1.equals(text2); } - return text.substring(0, sepPos); - } - /** - * Gives the substring of the given text before the last occurrence of the - * given separator. - * - * If the text does not contain the given separator then the given text is - * returned. - * - * @param text - * @param separator - * @return the substring of the given text before the last occurrence of the given separator. - */ - public static String substringBeforeLast(String text, char separator) { - if (isEmpty(text)) { - return text; + /** + * Pretty toString printer. + * + * @param keyValues d + * @return a string representation of the input values + */ + public static String toString(Object... keyValues) { + StringBuilder result = new StringBuilder(); + result.append('['); + for (int i = 0; i < keyValues.length; i += 2) { + if (i > 0) { + result.append(", "); + } + result.append(keyValues[i]); + result.append(": "); + Object value = null; + if ((i + 1) < keyValues.length) { + value = keyValues[i + 1]; + } + if (value == null) { + result.append(""); + } else { + result.append('\''); + result.append(value); + result.append('\''); + } + } + result.append(']'); + return result.toString(); } - int cPos = text.lastIndexOf(separator); - if (cPos < 0) { - return text; + + public static int hashCode(String... values) { + int result = 31; + for (String value : values) { + result ^= String.valueOf(value).hashCode(); + } + return result; } - return text.substring(0, cPos); - } - /** - * Gives the substring of the given text after the last occurrence of the - * given separator. - * - * If the text does not contain the given separator then "" is returned. - * - * @param text - * @param separator - * @return the substring of the given text after the last occurrence of the given separator. - */ - public static String substringAfterLast(String text, char separator) { - if (isEmpty(text)) { - return text; + /** + * Gives the substring of the given text before the given separator. + *

+ * If the text does not contain the given separator then the given text is + * returned. + * + * @param text d + * @param separator d + * @return the substring of the given text before the given separator. + */ + public static String substringBefore(String text, char separator) { + if (isEmpty(text)) { + return text; + } + int sepPos = text.indexOf(separator); + if (sepPos < 0) { + return text; + } + return text.substring(0, sepPos); } - int cPos = text.lastIndexOf(separator); - if (cPos < 0) { - return ""; + + /** + * Gives the substring of the given text before the last occurrence of the + * given separator. + *

+ * If the text does not contain the given separator then the given text is + * returned. + * + * @param text d + * @param separator d + * @return the substring of the given text before the last occurrence of the given separator. + */ + public static String substringBeforeLast(String text, char separator) { + if (isEmpty(text)) { + return text; + } + int cPos = text.lastIndexOf(separator); + if (cPos < 0) { + return text; + } + return text.substring(0, cPos); } - return text.substring(cPos + 1); - } - /** - * Gives the substring of the given text after the given separator. - * - * If the text does not contain the given separator then "" is returned. - * - * @param text the input text - * @param c the separator char - * @return the substring of the given text after the given separator. - */ - public static String substringAfter(String text, char c) { - if (isEmpty(text)) { - return text; + /** + * Gives the substring of the given text after the last occurrence of the + * given separator. + *

+ * If the text does not contain the given separator then "" is returned. + * + * @param text d + * @param separator d + * @return the substring of the given text after the last occurrence of the given separator. + */ + public static String substringAfterLast(String text, char separator) { + if (isEmpty(text)) { + return text; + } + int cPos = text.lastIndexOf(separator); + if (cPos < 0) { + return ""; + } + return text.substring(cPos + 1); } - int cPos = text.indexOf(c); - if (cPos < 0) { - return ""; + + /** + * Gives the substring of the given text after the given separator. + *

+ * If the text does not contain the given separator then "" is returned. + * + * @param text the input text + * @param c the separator char + * @return the substring of the given text after the given separator. + */ + public static String substringAfter(String text, char c) { + if (isEmpty(text)) { + return text; + } + int cPos = text.indexOf(c); + if (cPos < 0) { + return ""; + } + return text.substring(cPos + 1); } - return text.substring(cPos + 1); - } } diff --git a/epublib/src/main/java/me/ag2s/epublib/util/commons/io/BOMInputStream.java b/epublib/src/main/java/me/ag2s/epublib/util/commons/io/BOMInputStream.java index 58f319274..d3b1f6d9e 100644 --- a/epublib/src/main/java/me/ag2s/epublib/util/commons/io/BOMInputStream.java +++ b/epublib/src/main/java/me/ag2s/epublib/util/commons/io/BOMInputStream.java @@ -85,6 +85,7 @@ public class BOMInputStream extends ProxyInputStream { * a {@link ByteOrderMark#UTF_8} BOM. * @param delegate the InputStream to delegate to */ + @SuppressWarnings("unused") public BOMInputStream(InputStream delegate) { this(delegate, false, ByteOrderMark.UTF_8); } @@ -96,6 +97,7 @@ public class BOMInputStream extends ProxyInputStream { * @param include true to include the UTF-8 BOM or * false to exclude it */ + @SuppressWarnings("unused") public BOMInputStream(InputStream delegate, boolean include) { this(delegate, include, ByteOrderMark.UTF_8); } @@ -106,6 +108,7 @@ public class BOMInputStream extends ProxyInputStream { * @param delegate the InputStream to delegate to * @param boms The BOMs to detect and exclude */ + @SuppressWarnings("unused") public BOMInputStream(InputStream delegate, ByteOrderMark... boms) { this(delegate, false, boms); } @@ -118,6 +121,7 @@ public class BOMInputStream extends ProxyInputStream { * false to exclude them * @param boms The BOMs to detect and optionally exclude */ + @SuppressWarnings("unused") public BOMInputStream(InputStream delegate, boolean include, ByteOrderMark... boms) { super(delegate); if (boms == null || boms.length == 0) { @@ -134,6 +138,7 @@ public class BOMInputStream extends ProxyInputStream { * if it does not * @throws IOException if an error reading the first bytes of the stream occurs */ + @SuppressWarnings("unused") public boolean hasBOM() throws IOException { return (getBOM() != null); } @@ -148,6 +153,7 @@ public class BOMInputStream extends ProxyInputStream { * is configured to detect * @throws IOException if an error reading the first bytes of the stream occurs */ + @SuppressWarnings("unused") public boolean hasBOM(ByteOrderMark bom) throws IOException { if (!boms.contains(bom)) { throw new IllegalArgumentException("Stream not configure to detect " + bom); diff --git a/epublib/src/main/java/me/ag2s/epublib/util/commons/io/ByteOrderMark.java b/epublib/src/main/java/me/ag2s/epublib/util/commons/io/ByteOrderMark.java index b2001d8ab..5ec600f3b 100644 --- a/epublib/src/main/java/me/ag2s/epublib/util/commons/io/ByteOrderMark.java +++ b/epublib/src/main/java/me/ag2s/epublib/util/commons/io/ByteOrderMark.java @@ -150,6 +150,7 @@ public class ByteOrderMark implements Serializable { * @return the length of the BOM's bytes */ @Override + @SuppressWarnings("NullableProblems") public String toString() { StringBuilder builder = new StringBuilder(); builder.append(getClass().getSimpleName()); diff --git a/epublib/src/main/java/me/ag2s/epublib/util/commons/io/ProxyInputStream.java b/epublib/src/main/java/me/ag2s/epublib/util/commons/io/ProxyInputStream.java index 894457903..25e5fd7d0 100644 --- a/epublib/src/main/java/me/ag2s/epublib/util/commons/io/ProxyInputStream.java +++ b/epublib/src/main/java/me/ag2s/epublib/util/commons/io/ProxyInputStream.java @@ -197,9 +197,9 @@ public abstract class ProxyInputStream extends FilterInputStream { * * @since Commons IO 2.0 * @param n number of bytes that the caller asked to be read - * @throws IOException if the pre-processing fails */ - protected void beforeRead(int n) throws IOException { + @SuppressWarnings("unused") + protected void beforeRead(int n) { } /** @@ -217,9 +217,9 @@ public abstract class ProxyInputStream extends FilterInputStream { * * @since Commons IO 2.0 * @param n number of bytes read, or -1 if the end of stream was reached - * @throws IOException if the post-processing fails */ - protected void afterRead(int n) throws IOException { + @SuppressWarnings("unused") + protected void afterRead(int n) { } /** diff --git a/epublib/src/main/java/me/ag2s/epublib/util/commons/io/XmlStreamReader.java b/epublib/src/main/java/me/ag2s/epublib/util/commons/io/XmlStreamReader.java index 99b6f0a19..bd0980932 100644 --- a/epublib/src/main/java/me/ag2s/epublib/util/commons/io/XmlStreamReader.java +++ b/epublib/src/main/java/me/ag2s/epublib/util/commons/io/XmlStreamReader.java @@ -30,6 +30,7 @@ import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.text.MessageFormat; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -105,6 +106,7 @@ public class XmlStreamReader extends Reader { * * @return the default encoding to use. */ + @SuppressWarnings("unused") public String getDefaultEncoding() { return defaultEncoding; } @@ -121,6 +123,7 @@ public class XmlStreamReader extends Reader { * @param file File to create a Reader from. * @throws IOException thrown if there is a problem reading the file. */ + @SuppressWarnings("unused") public XmlStreamReader(File file) throws IOException { this(new FileInputStream(file)); } @@ -224,6 +227,7 @@ public class XmlStreamReader extends Reader { * @throws IOException thrown if there is a problem reading the stream of * the URL. */ + @SuppressWarnings("unused") public XmlStreamReader(URL url) throws IOException { this(url.openConnection(), null); } @@ -249,15 +253,16 @@ public class XmlStreamReader extends Reader { */ public XmlStreamReader(URLConnection conn, String defaultEncoding) throws IOException { this.defaultEncoding = defaultEncoding; + @SuppressWarnings("unused") boolean lenient = true; String contentType = conn.getContentType(); InputStream is = conn.getInputStream(); BOMInputStream bom = new BOMInputStream(new BufferedInputStream(is, BUFFER_SIZE), false, BOMS); BOMInputStream pis = new BOMInputStream(bom, true, XML_GUESS_BYTES); if (conn instanceof HttpURLConnection || contentType != null) { - this.encoding = doHttpStream(bom, pis, contentType, lenient); + this.encoding = doHttpStream(bom, pis, contentType, true); } else { - this.encoding = doRawStream(bom, pis, lenient); + this.encoding = doRawStream(bom, pis, true); } this.reader = new InputStreamReader(pis, encoding); } @@ -509,11 +514,11 @@ public class XmlStreamReader extends Reader { // BOM is UTF-8 if (bomEnc.equals(UTF_8)) { if (xmlGuessEnc != null && !xmlGuessEnc.equals(UTF_8)) { - String msg = MessageFormat.format(RAW_EX_1, new Object[] { bomEnc, xmlGuessEnc, xmlEnc }); + String msg = MessageFormat.format(RAW_EX_1, bomEnc, xmlGuessEnc, xmlEnc); throw new XmlStreamReaderException(msg, bomEnc, xmlGuessEnc, xmlEnc); } if (xmlEnc != null && !xmlEnc.equals(UTF_8)) { - String msg = MessageFormat.format(RAW_EX_1, new Object[] { bomEnc, xmlGuessEnc, xmlEnc }); + String msg = MessageFormat.format(RAW_EX_1, bomEnc, xmlGuessEnc, xmlEnc); throw new XmlStreamReaderException(msg, bomEnc, xmlGuessEnc, xmlEnc); } return bomEnc; @@ -522,18 +527,18 @@ public class XmlStreamReader extends Reader { // BOM is UTF-16BE or UTF-16LE if (bomEnc.equals(UTF_16BE) || bomEnc.equals(UTF_16LE)) { if (xmlGuessEnc != null && !xmlGuessEnc.equals(bomEnc)) { - String msg = MessageFormat.format(RAW_EX_1, new Object[] { bomEnc, xmlGuessEnc, xmlEnc }); + String msg = MessageFormat.format(RAW_EX_1, bomEnc, xmlGuessEnc, xmlEnc); throw new XmlStreamReaderException(msg, bomEnc, xmlGuessEnc, xmlEnc); } if (xmlEnc != null && !xmlEnc.equals(UTF_16) && !xmlEnc.equals(bomEnc)) { - String msg = MessageFormat.format(RAW_EX_1, new Object[] { bomEnc, xmlGuessEnc, xmlEnc }); + String msg = MessageFormat.format(RAW_EX_1, bomEnc, xmlGuessEnc, xmlEnc); throw new XmlStreamReaderException(msg, bomEnc, xmlGuessEnc, xmlEnc); } return bomEnc; } // BOM is something else - String msg = MessageFormat.format(RAW_EX_2, new Object[] { bomEnc, xmlGuessEnc, xmlEnc }); + String msg = MessageFormat.format(RAW_EX_2, bomEnc, xmlGuessEnc, xmlEnc); throw new XmlStreamReaderException(msg, bomEnc, xmlGuessEnc, xmlEnc); } @@ -697,7 +702,7 @@ public class XmlStreamReader extends Reader { } Matcher m = ENCODING_PATTERN.matcher(prolog); if (m.find()) { - encoding = m.group(1).toUpperCase(); + encoding = Objects.requireNonNull(m.group(1)).toUpperCase(); encoding = encoding.substring(1, encoding.length() - 1); } } diff --git a/epublib/src/main/java/me/ag2s/epublib/util/commons/io/XmlStreamReaderException.java b/epublib/src/main/java/me/ag2s/epublib/util/commons/io/XmlStreamReaderException.java index 2b3bbec49..0f97df60c 100644 --- a/epublib/src/main/java/me/ag2s/epublib/util/commons/io/XmlStreamReaderException.java +++ b/epublib/src/main/java/me/ag2s/epublib/util/commons/io/XmlStreamReaderException.java @@ -120,6 +120,7 @@ public class XmlStreamReaderException extends IOException { * @return the MIME type in the content-type, null if there was not * content-type or the encoding detection did not involve HTTP. */ + @SuppressWarnings("unused") public String getContentTypeMime() { return contentTypeMime; } From 5b58ea45eb63ef2401902ca2866b602d71084e31 Mon Sep 17 00:00:00 2001 From: ag2s20150909 Date: Sat, 27 Mar 2021 20:29:17 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BC=98=E5=8C=96epublib,=E6=B8=85?= =?UTF-8?q?=E9=99=A4=E8=AD=A6=E5=91=8A=EF=BC=8C=E5=B0=9D=E8=AF=95=E5=85=BC?= =?UTF-8?q?=E5=AE=B9epub=20v3=E6=A0=BC=E5=BC=8F=E7=9A=84=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/io/legado/app/model/localBook/EpubFile.kt | 2 +- epublib/src/main/java/me/ag2s/epublib/domain/EpubBook.java | 1 + epublib/src/main/java/me/ag2s/epublib/epub/EpubReader.java | 7 ++++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/localBook/EpubFile.kt b/app/src/main/java/io/legado/app/model/localBook/EpubFile.kt index a11941d97..8a809e701 100644 --- a/app/src/main/java/io/legado/app/model/localBook/EpubFile.kt +++ b/app/src/main/java/io/legado/app/model/localBook/EpubFile.kt @@ -120,7 +120,7 @@ class EpubFile(var book: Book) { } resources.add(resource) } while (zipEntry != null) - if (resources.size() > 0) return EpubReader().readEpub(resources) + if (resources.size() > 0) return EpubReader().readEpubBook(resources) } catch (e: Exception) { e.printStackTrace() } diff --git a/epublib/src/main/java/me/ag2s/epublib/domain/EpubBook.java b/epublib/src/main/java/me/ag2s/epublib/domain/EpubBook.java index e21cb0fa5..a0feb3f98 100644 --- a/epublib/src/main/java/me/ag2s/epublib/domain/EpubBook.java +++ b/epublib/src/main/java/me/ag2s/epublib/domain/EpubBook.java @@ -5,4 +5,5 @@ package me.ag2s.epublib.domain; */ @SuppressWarnings("unused declaration") public class EpubBook extends Book { + } diff --git a/epublib/src/main/java/me/ag2s/epublib/epub/EpubReader.java b/epublib/src/main/java/me/ag2s/epublib/epub/EpubReader.java index fe9411d09..361fe8527 100644 --- a/epublib/src/main/java/me/ag2s/epublib/epub/EpubReader.java +++ b/epublib/src/main/java/me/ag2s/epublib/epub/EpubReader.java @@ -14,6 +14,7 @@ import java.util.zip.ZipInputStream; import me.ag2s.epublib.Constants; import me.ag2s.epublib.domain.Book; +import me.ag2s.epublib.domain.EpubBook; import me.ag2s.epublib.domain.MediaType; import me.ag2s.epublib.domain.MediaTypes; import me.ag2s.epublib.domain.Resource; @@ -30,7 +31,7 @@ public class EpubReader { private static final String TAG = EpubReader.class.getName(); private final BookProcessor bookProcessor = BookProcessor.IDENTITY_BOOKPROCESSOR; - + @SuppressWarnings("unused") public Book readEpub(InputStream in) throws IOException { return readEpub(in, Constants.CHARACTER_ENCODING); } @@ -97,9 +98,13 @@ public class EpubReader { return readEpub(resources); } + @SuppressWarnings("unused") public Book readEpub(Resources resources) { return readEpub(resources, new Book()); } + public EpubBook readEpubBook(Resources resources) { + return (EpubBook) readEpub(resources, new Book()); + } public Book readEpub(Resources resources, Book result) { if (result == null) {