Merge pull request #915 from ag2s20150909/master

Epublib优化
pull/921/head
kunfei 4 years ago committed by GitHub
commit fb2d43837b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      app/src/main/java/io/legado/app/model/localBook/EpubFile.kt
  2. 5
      epublib/src/main/AndroidManifest.xml
  3. 2
      epublib/src/main/java/me/ag2s/epublib/Constants.java
  4. 12
      epublib/src/main/java/me/ag2s/epublib/browsersupport/NavigationEvent.java
  5. 2
      epublib/src/main/java/me/ag2s/epublib/browsersupport/NavigationEventListener.java
  6. 22
      epublib/src/main/java/me/ag2s/epublib/browsersupport/NavigationHistory.java
  7. 21
      epublib/src/main/java/me/ag2s/epublib/browsersupport/Navigator.java
  8. 18
      epublib/src/main/java/me/ag2s/epublib/domain/Author.java
  9. 323
      epublib/src/main/java/me/ag2s/epublib/domain/Book.java
  10. 10
      epublib/src/main/java/me/ag2s/epublib/domain/Date.java
  11. 313
      epublib/src/main/java/me/ag2s/epublib/domain/EpubBook.java
  12. 10
      epublib/src/main/java/me/ag2s/epublib/domain/Guide.java
  13. 2
      epublib/src/main/java/me/ag2s/epublib/domain/GuideReference.java
  14. 7
      epublib/src/main/java/me/ag2s/epublib/domain/Identifier.java
  15. 7
      epublib/src/main/java/me/ag2s/epublib/domain/LazyResource.java
  16. 4
      epublib/src/main/java/me/ag2s/epublib/domain/ManifestItemProperties.java
  17. 4
      epublib/src/main/java/me/ag2s/epublib/domain/ManifestItemRefProperties.java
  18. 12
      epublib/src/main/java/me/ag2s/epublib/domain/MediaType.java
  19. 11
      epublib/src/main/java/me/ag2s/epublib/domain/MediaTypes.java
  20. 37
      epublib/src/main/java/me/ag2s/epublib/domain/Metadata.java
  21. 18
      epublib/src/main/java/me/ag2s/epublib/domain/Resource.java
  22. 2
      epublib/src/main/java/me/ag2s/epublib/domain/ResourceReference.java
  23. 73
      epublib/src/main/java/me/ag2s/epublib/domain/Resources.java
  24. 19
      epublib/src/main/java/me/ag2s/epublib/domain/Spine.java
  25. 6
      epublib/src/main/java/me/ag2s/epublib/domain/SpineReference.java
  26. 9
      epublib/src/main/java/me/ag2s/epublib/domain/TOCReference.java
  27. 25
      epublib/src/main/java/me/ag2s/epublib/domain/TableOfContents.java
  28. 10
      epublib/src/main/java/me/ag2s/epublib/domain/TitledResourceReference.java
  29. 4
      epublib/src/main/java/me/ag2s/epublib/epub/BookProcessor.java
  30. 18
      epublib/src/main/java/me/ag2s/epublib/epub/BookProcessorPipeline.java
  31. 49
      epublib/src/main/java/me/ag2s/epublib/epub/DOMUtil.java
  32. 19
      epublib/src/main/java/me/ag2s/epublib/epub/EpubProcessorSupport.java
  33. 67
      epublib/src/main/java/me/ag2s/epublib/epub/EpubReader.java
  34. 56
      epublib/src/main/java/me/ag2s/epublib/epub/EpubWriter.java
  35. 2
      epublib/src/main/java/me/ag2s/epublib/epub/HtmlProcessor.java
  36. 5
      epublib/src/main/java/me/ag2s/epublib/epub/Main.java
  37. 296
      epublib/src/main/java/me/ag2s/epublib/epub/NCXDocument.java
  38. 60
      epublib/src/main/java/me/ag2s/epublib/epub/NCXDocumentV2.java
  39. 372
      epublib/src/main/java/me/ag2s/epublib/epub/NCXDocumentV3.java
  40. 9
      epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentBase.java
  41. 47
      epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentMetadataReader.java
  42. 38
      epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentMetadataWriter.java
  43. 84
      epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentReader.java
  44. 99
      epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentWriter.java
  45. 50
      epublib/src/main/java/me/ag2s/epublib/epub/ResourcesLoader.java
  46. 15
      epublib/src/main/java/me/ag2s/epublib/util/CollectionUtil.java
  47. 34
      epublib/src/main/java/me/ag2s/epublib/util/IOUtil.java
  48. 3
      epublib/src/main/java/me/ag2s/epublib/util/NoCloseOutputStream.java
  49. 5
      epublib/src/main/java/me/ag2s/epublib/util/NoCloseWriter.java
  50. 103
      epublib/src/main/java/me/ag2s/epublib/util/ResourceUtil.java
  51. 202
      epublib/src/main/java/me/ag2s/epublib/util/StreamWriterDelegate.txt
  52. 49
      epublib/src/main/java/me/ag2s/epublib/util/StringUtil.java
  53. 6
      epublib/src/main/java/me/ag2s/epublib/util/commons/io/BOMInputStream.java
  54. 1
      epublib/src/main/java/me/ag2s/epublib/util/commons/io/ByteOrderMark.java
  55. 8
      epublib/src/main/java/me/ag2s/epublib/util/commons/io/ProxyInputStream.java
  56. 21
      epublib/src/main/java/me/ag2s/epublib/util/commons/io/XmlStreamReader.java
  57. 1
      epublib/src/main/java/me/ag2s/epublib/util/commons/io/XmlStreamReaderException.java

@ -120,7 +120,7 @@ class EpubFile(var book: Book) {
} }
resources.add(resource) resources.add(resource)
} while (zipEntry != null) } while (zipEntry != null)
if (resources.size() > 0) return EpubReader().readEpub(resources) if (resources.size() > 0) return EpubReader().readEpubBook(resources)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }

@ -1,7 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest package="me.ag2s.epublib">
package="me.ag2s.epublib">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
</manifest> </manifest>

@ -6,7 +6,7 @@ public interface Constants {
String CHARACTER_ENCODING = "UTF-8"; String CHARACTER_ENCODING = "UTF-8";
String DOCTYPE_XHTML = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">"; String DOCTYPE_XHTML = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">";
String NAMESPACE_XHTML = "http://www.w3.org/1999/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 = '#'; char FRAGMENT_SEPARATOR_CHAR = '#';
String DEFAULT_TOC_ID = "toc"; String DEFAULT_TOC_ID = "toc";
} }

@ -2,7 +2,7 @@ package me.ag2s.epublib.browsersupport;
import java.util.EventObject; 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.domain.Resource;
import me.ag2s.epublib.util.StringUtil; import me.ag2s.epublib.util.StringUtil;
@ -13,6 +13,7 @@ import me.ag2s.epublib.util.StringUtil;
* @author paul * @author paul
* *
*/ */
@SuppressWarnings("unused")
public class NavigationEvent extends EventObject { public class NavigationEvent extends EventObject {
private static final long serialVersionUID = -6346750144308952762L; private static final long serialVersionUID = -6346750144308952762L;
@ -20,7 +21,7 @@ public class NavigationEvent extends EventObject {
private Resource oldResource; private Resource oldResource;
private int oldSpinePos; private int oldSpinePos;
private Navigator navigator; private Navigator navigator;
private EpubBook oldBook; private Book oldBook;
private int oldSectionPos; private int oldSectionPos;
private String oldFragmentId; private String oldFragmentId;
@ -60,7 +61,7 @@ public class NavigationEvent extends EventObject {
this.oldFragmentId = oldFragmentId; this.oldFragmentId = oldFragmentId;
} }
public EpubBook getOldBook() { public Book getOldBook() {
return oldBook; return oldBook;
} }
@ -123,11 +124,11 @@ public class NavigationEvent extends EventObject {
} }
public void setOldBook(EpubBook oldBook) { public void setOldBook(Book oldBook) {
this.oldBook = oldBook; this.oldBook = oldBook;
} }
public EpubBook getCurrentBook() { public Book getCurrentBook() {
return getNavigator().getBook(); return getNavigator().getBook();
} }
@ -135,6 +136,7 @@ public class NavigationEvent extends EventObject {
return oldResource != getCurrentResource(); return oldResource != getCurrentResource();
} }
@SuppressWarnings("NullableProblems")
public String toString() { public String toString() {
return StringUtil.toString( return StringUtil.toString(
"oldSectionPos", oldSectionPos, "oldSectionPos", oldSectionPos,

@ -12,7 +12,7 @@ public interface NavigationEventListener {
/** /**
* Called whenever the user navigates to another position in the book. * Called whenever the user navigates to another position in the book.
* *
* @param navigationEvent * @param navigationEvent f
*/ */
void navigationPerformed(NavigationEvent navigationEvent); void navigationPerformed(NavigationEvent navigationEvent);
} }

@ -1,15 +1,15 @@
package me.ag2s.epublib.browsersupport; package me.ag2s.epublib.browsersupport;
import me.ag2s.epublib.domain.Book;
import me.ag2s.epublib.domain.Resource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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. * A history of the user's locations with the epub.
* *
* @author paul.siegmann * @author paul.siegmann
*
*/ */
public class NavigationHistory implements NavigationEventListener { public class NavigationHistory implements NavigationEventListener {
@ -36,8 +36,8 @@ public class NavigationHistory implements NavigationEventListener {
} }
private long lastUpdateTime = 0; private long lastUpdateTime = 0;
private List<Location> locations = new ArrayList<Location>(); private List<Location> locations = new ArrayList<>();
private Navigator navigator; private final Navigator navigator;
private int currentPos = -1; private int currentPos = -1;
private int currentSize = 0; private int currentSize = 0;
private int maxHistorySize = DEFAULT_MAX_HISTORY_SIZE; private int maxHistorySize = DEFAULT_MAX_HISTORY_SIZE;
@ -58,11 +58,11 @@ public class NavigationHistory implements NavigationEventListener {
return currentSize; return currentSize;
} }
public void initBook(EpubBook book) { public void initBook(Book book) {
if (book == null) { if (book == null) {
return; return;
} }
locations = new ArrayList<Location>(); locations = new ArrayList<>();
currentPos = -1; currentPos = -1;
currentSize = 0; currentSize = 0;
if (navigator.getCurrentResource() != null) { if (navigator.getCurrentResource() != null) {
@ -103,8 +103,8 @@ public class NavigationHistory implements NavigationEventListener {
* <br/> * <br/>
* If this nr of locations becomes larger then the historySize then the * If this nr of locations becomes larger then the historySize then the
* first item(s) will be removed. * first item(s) will be removed.
* *v
* @param location * @param location d
*/ */
public void addLocation(Location location) { public void addLocation(Location location) {
// do nothing if the new location matches the current 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. * Moves the current positions delta positions.
* *
* move(-1) to go one position back in history.<br/> * move(-1) to go one position back in history.<br/>
* move(1) to go one position forward.<br/> * move(1) to go one position forward.<br/>
* *
* @param delta * @param delta f
* *
* @return Whether we actually moved. If the requested value is illegal * @return Whether we actually moved. If the requested value is illegal
* it will return false, true otherwise. * it will return false, true otherwise.

@ -1,12 +1,11 @@
package me.ag2s.epublib.browsersupport; package me.ag2s.epublib.browsersupport;
import me.ag2s.epublib.domain.Book;
import me.ag2s.epublib.domain.Resource;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import me.ag2s.epublib.domain.EpubBook;
import me.ag2s.epublib.domain.Resource;
/** /**
* A helper class for epub browser applications. * A helper class for epub browser applications.
* *
@ -19,19 +18,19 @@ import me.ag2s.epublib.domain.Resource;
public class Navigator implements Serializable { public class Navigator implements Serializable {
private static final long serialVersionUID = 1076126986424925474L; private static final long serialVersionUID = 1076126986424925474L;
private EpubBook book; private Book book;
private int currentSpinePos; private int currentSpinePos;
private Resource currentResource; private Resource currentResource;
private int currentPagePos; private int currentPagePos;
private String currentFragmentId; private String currentFragmentId;
private List<NavigationEventListener> eventListeners = new ArrayList<>(); private final List<NavigationEventListener> eventListeners = new ArrayList<>();
public Navigator() { public Navigator() {
this(null); this(null);
} }
public Navigator(EpubBook book) { public Navigator(Book book) {
this.book = book; this.book = book;
this.currentSpinePos = 0; this.currentSpinePos = 0;
if (book != null) { if (book != null) {
@ -136,8 +135,8 @@ public class Navigator implements Serializable {
* Go to a specific section. * Go to a specific section.
* Illegal spine positions are silently ignored. * Illegal spine positions are silently ignored.
* *
* @param newSpinePos * @param newSpinePos f
* @param source * @param source f
* @return The current position within the spine * @return The current position within the spine
*/ */
public int gotoSpineSection(int newSpinePos, int newPagePos, Object source) { 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); 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); NavigationEvent navigationEvent = new NavigationEvent(source, this);
this.book = book; this.book = book;
this.currentFragmentId = null; this.currentFragmentId = null;
@ -187,14 +186,14 @@ public class Navigator implements Serializable {
* *
* If you want the eventListeners called use gotoSection(index); * If you want the eventListeners called use gotoSection(index);
* *
* @param currentIndex * @param currentIndex f
*/ */
public void setCurrentSpinePos(int currentIndex) { public void setCurrentSpinePos(int currentIndex) {
this.currentSpinePos = currentIndex; this.currentSpinePos = currentIndex;
this.currentResource = book.getSpine().getResource(currentIndex); this.currentResource = book.getSpine().getResource(currentIndex);
} }
public EpubBook getBook() { public Book getBook() {
return book; return book;
} }

@ -1,13 +1,15 @@
package me.ag2s.epublib.domain; package me.ag2s.epublib.domain;
import me.ag2s.epublib.util.StringUtil; import me.ag2s.epublib.util.StringUtil;
import java.io.Serializable; import java.io.Serializable;
/** /**
* Represents one of the authors of the book * Represents one of the authors of the book
* *
* @author paul * @author paul
*
*/ */
public class Author implements Serializable { public class Author implements Serializable {
@ -42,8 +44,11 @@ public class Author implements Serializable {
this.lastname = lastname; this.lastname = lastname;
} }
@Override
@SuppressWarnings("NullableProblems")
public String toString() { public String toString() {
return lastname + ", " + firstname; return this.lastname + ", " + this.firstname;
} }
public int hashCode() { public int hashCode() {
@ -59,13 +64,18 @@ public class Author implements Serializable {
&& StringUtil.equals(lastname, other.lastname); && StringUtil.equals(lastname, other.lastname);
} }
public Relator setRole(String code) { /**
* 设置贡献者的角色
*
* @param code 角色编号
*/
public void setRole(String code) {
Relator result = Relator.byCode(code); Relator result = Relator.byCode(code);
if (result == null) { if (result == null) {
result = Relator.AUTHOR; result = Relator.AUTHOR;
} }
this.relator = result; this.relator = result;
return result;
} }
public Relator getRelator() { public Relator getRelator() {

@ -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.
* <p>
* All resources of a Book (html, css, xml, fonts, images) are represented
* as Resources. See getResources() for access to these.<br/>
* A Book as 3 indexes into these Resources, as per the epub specification.<br/>
* <dl>
* <dt>Spine</dt>
* <dd>these are the Resources to be shown when a user reads the book from
* start to finish.</dd>
* <dt>Table of Contents<dt>
* <dd>The table of contents. Table of Contents references may be in a
* different order and contain different Resources than the spine, and often do.
* <dt>Guide</dt>
* <dd>The Guide has references to a set of special Resources like the
* cover page, the Glossary, the copyright page, etc.
* </dl>
* <p/>
* 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.
* <p>
* The Content page may be in the Table of Contents, the Guide, but not
* in the Spine.
* Etc.
* <p/>
* <p>
* 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.
* <p/>
* Consists of a list of "reachable" resources:
* <ul>
* <li>The coverpage</li>
* <li>The resources of the Spine that are not already in the result</li>
* <li>The resources of the Table of Contents that are not already in the
* result</li>
* <li>The resources of the Guide that are not already in the result</li>
* </ul>
* 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<Resource> getContents() {
Map<String, Resource> 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<String, Resource> 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;
}
}

@ -1,17 +1,17 @@
package me.ag2s.epublib.domain; package me.ag2s.epublib.domain;
import me.ag2s.epublib.epub.PackageDocumentBase; import me.ag2s.epublib.epub.PackageDocumentBase;
import java.io.Serializable; import java.io.Serializable;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Locale; import java.util.Locale;
/** /**
* A Date used by the book's metadata. * A Date used by the book's metadata.
* * <p>
* Examples: creation-date, modification-date, etc * Examples: creation-date, modification-date, etc
* *
* @author paul * @author paul
*
*/ */
public class Date implements Serializable { public class Date implements Serializable {
@ -37,6 +37,8 @@ public class Date implements Serializable {
return null; return null;
} }
@Override
@SuppressWarnings("NullableProblems")
public String toString() { public String toString() {
return value; return value;
} }
@ -65,7 +67,7 @@ public class Date implements Serializable {
} }
public Date(java.util.Date date, String event) { public Date(java.util.Date date, String event) {
this((new SimpleDateFormat(PackageDocumentBase.dateFormat,Locale.US)).format(date), this((new SimpleDateFormat(PackageDocumentBase.dateFormat, Locale.US)).format(date),
event); event);
} }
@ -94,6 +96,8 @@ public class Date implements Serializable {
this.event = event; this.event = event;
} }
@Override
@SuppressWarnings("NullableProblems")
public String toString() { public String toString() {
if (event == null) { if (event == null) {
return dateString; return dateString;

@ -1,316 +1,9 @@
package me.ag2s.epublib.domain; 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. * 这个是用于其它与Book类同名时替换的
*
* All resources of a Book (html, css, xml, fonts, images) are represented
* as Resources. See getResources() for access to these.<br/>
* A Book as 3 indexes into these Resources, as per the epub specification.<br/>
* <dl>
* <dt>Spine</dt>
* <dd>these are the Resources to be shown when a user reads the book from
* start to finish.</dd>
* <dt>Table of Contents<dt>
* <dd>The table of contents. Table of Contents references may be in a
* different order and contain different Resources than the spine, and often do.
* <dt>Guide</dt>
* <dd>The Guide has references to a set of special Resources like the
* cover page, the Glossary, the copyright page, etc.
* </dl>
* <p/>
* 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.
* <p/>
*
* Please see the illustration at: doc/schema.svg
*
* @author paul
* @author jake
*/
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() { @SuppressWarnings("unused declaration")
return metadata; public class EpubBook extends Book {
}
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.
* <p/>
* Consists of a list of "reachable" resources:
* <ul>
* <li>The coverpage</li>
* <li>The resources of the Spine that are not already in the result</li>
* <li>The resources of the Table of Contents that are not already in the
* result</li>
* <li>The resources of the Guide that are not already in the result</li>
* </ul>
* 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<Resource> getContents() {
Map<String, Resource> result = new LinkedHashMap<String, Resource>();
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<Resource>(result.values());
}
private static void addToContentsResult(Resource resource,
Map<String, Resource> 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;
}
} }

@ -25,7 +25,7 @@ public class Guide implements Serializable {
public static final String DEFAULT_COVER_TITLE = GuideReference.COVER; public static final String DEFAULT_COVER_TITLE = GuideReference.COVER;
private List<GuideReference> references = new ArrayList<GuideReference>(); private List<GuideReference> references = new ArrayList<>();
private static final int COVERPAGE_NOT_FOUND = -1; private static final int COVERPAGE_NOT_FOUND = -1;
private static final int COVERPAGE_UNITIALIZED = -2; private static final int COVERPAGE_UNITIALIZED = -2;
@ -51,7 +51,7 @@ public class Guide implements Serializable {
} }
return null; return null;
} }
@SuppressWarnings("UnusedReturnValue")
public int setCoverReference(GuideReference guideReference) { public int setCoverReference(GuideReference guideReference) {
if (coverPageIndex >= 0) { if (coverPageIndex >= 0) {
references.set(coverPageIndex, guideReference); references.set(coverPageIndex, guideReference);
@ -100,7 +100,7 @@ public class Guide implements Serializable {
setCoverReference(coverpageGuideReference); setCoverReference(coverpageGuideReference);
} }
@SuppressWarnings("UnusedReturnValue")
public ResourceReference addReference(GuideReference reference) { public ResourceReference addReference(GuideReference reference) {
this.references.add(reference); this.references.add(reference);
uncheckCoverPage(); uncheckCoverPage();
@ -111,13 +111,13 @@ public class Guide implements Serializable {
* A list of all GuideReferences that have the given * A list of all GuideReferences that have the given
* referenceTypeName (ignoring case). * referenceTypeName (ignoring case).
* *
* @param referenceTypeName * @param referenceTypeName referenceTypeName
* @return A list of all GuideReferences that have the given * @return A list of all GuideReferences that have the given
* referenceTypeName (ignoring case). * referenceTypeName (ignoring case).
*/ */
public List<GuideReference> getGuideReferencesByType( public List<GuideReference> getGuideReferencesByType(
String referenceTypeName) { String referenceTypeName) {
List<GuideReference> result = new ArrayList<GuideReference>(); List<GuideReference> result = new ArrayList<>();
for (GuideReference guideReference : references) { for (GuideReference guideReference : references) {
if (referenceTypeName.equalsIgnoreCase(guideReference.getType())) { if (referenceTypeName.equalsIgnoreCase(guideReference.getType())) {
result.add(guideReference); result.add(guideReference);

@ -20,7 +20,7 @@ public class GuideReference extends TitledResourceReference
/** /**
* the book cover(s), jacket information, etc. * 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 * human-readable page with title, author, publisher, and other metadata

@ -15,7 +15,7 @@ import java.util.UUID;
public class Identifier implements Serializable { public class Identifier implements Serializable {
private static final long serialVersionUID = 955949951416391810L; private static final long serialVersionUID = 955949951416391810L;
@SuppressWarnings("unused")
public interface Scheme { public interface Scheme {
String UUID = "UUID"; String UUID = "UUID";
@ -48,7 +48,7 @@ public class Identifier implements Serializable {
* If no identifier has bookId == true then the first bookId identifier * If no identifier has bookId == true then the first bookId identifier
* is written as the primary. * is written as the primary.
* *
* @param identifiers * @param identifiers i
* @return The first identifier for which the bookId is true is made * @return The first identifier for which the bookId is true is made
* the bookId identifier. * the bookId identifier.
*/ */
@ -119,7 +119,8 @@ public class Identifier implements Serializable {
return StringUtil.equals(scheme, ((Identifier) otherIdentifier).scheme) return StringUtil.equals(scheme, ((Identifier) otherIdentifier).scheme)
&& StringUtil.equals(value, ((Identifier) otherIdentifier).value); && StringUtil.equals(value, ((Identifier) otherIdentifier).value);
} }
@SuppressWarnings("NullableProblems")
@Override
public String toString() { public String toString() {
if (StringUtil.isBlank(scheme)) { if (StringUtil.isBlank(scheme)) {
return "" + value; return "" + value;

@ -3,7 +3,6 @@ package me.ag2s.epublib.domain;
import android.util.Log; import android.util.Log;
import me.ag2s.epublib.util.IOUtil; import me.ag2s.epublib.util.IOUtil;
//import io.documentnode.minilog.Logger;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -15,7 +14,7 @@ import java.io.InputStream;
public class LazyResource extends Resource { public class LazyResource extends Resource {
private static final long serialVersionUID = 5089400472352002866L; 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 LazyResourceProvider resourceProvider;
private final long cachedSize; private final long cachedSize;
@ -51,7 +50,7 @@ public class LazyResource extends Resource {
* *
* @return The contents of the Resource. * @return The contents of the Resource.
* *
* @throws IOException * @throws IOException IOException
*/ */
public InputStream getInputStream() throws IOException { public InputStream getInputStream() throws IOException {
if (isInitialized()) { if (isInitialized()) {
@ -64,7 +63,7 @@ public class LazyResource extends Resource {
/** /**
* Initializes the resource by loading its data into memory. * Initializes the resource by loading its data into memory.
* *
* @throws IOException * @throws IOException IOException
*/ */
public void initialize() throws IOException { public void initialize() throws IOException {
getData(); getData();

@ -1,5 +1,5 @@
package me.ag2s.epublib.domain; package me.ag2s.epublib.domain;
@SuppressWarnings("unused")
public enum ManifestItemProperties implements ManifestProperties { public enum ManifestItemProperties implements ManifestProperties {
COVER_IMAGE("cover-image"), COVER_IMAGE("cover-image"),
MATHML("mathml"), MATHML("mathml"),
@ -9,7 +9,7 @@ public enum ManifestItemProperties implements ManifestProperties {
SVG("svg"), SVG("svg"),
SWITCH("switch"); SWITCH("switch");
private String name; private final String name;
ManifestItemProperties(String name) { ManifestItemProperties(String name) {
this.name = name; this.name = name;

@ -1,10 +1,10 @@
package me.ag2s.epublib.domain; package me.ag2s.epublib.domain;
@SuppressWarnings("unused")
public enum ManifestItemRefProperties implements ManifestProperties { public enum ManifestItemRefProperties implements ManifestProperties {
PAGE_SPREAD_LEFT("page-spread-left"), PAGE_SPREAD_LEFT("page-spread-left"),
PAGE_SPREAD_RIGHT("page-spread-right"); PAGE_SPREAD_RIGHT("page-spread-right");
private String name; private final String name;
ManifestItemRefProperties(String name) { ManifestItemRefProperties(String name) {
this.name = name; this.name = name;

@ -18,9 +18,9 @@ import java.util.Collection;
public class MediaType implements Serializable { public class MediaType implements Serializable {
private static final long serialVersionUID = -7256091153727506788L; private static final long serialVersionUID = -7256091153727506788L;
private String name; private final String name;
private String defaultExtension; private final String defaultExtension;
private Collection<String> extensions; private final Collection<String> extensions;
public MediaType(String name, String defaultExtension) { public MediaType(String name, String defaultExtension) {
this(name, defaultExtension, new String[]{defaultExtension}); this(name, defaultExtension, new String[]{defaultExtension});
@ -39,11 +39,11 @@ public class MediaType implements Serializable {
} }
public MediaType(String name, String defaultExtension, public MediaType(String name, String defaultExtension,
Collection<String> extensions) { Collection<String> mextensions) {
super(); super();
this.name = name; this.name = name;
this.defaultExtension = defaultExtension; this.defaultExtension = defaultExtension;
this.extensions = extensions; this.extensions = mextensions;
} }
public String getName() { public String getName() {
@ -66,7 +66,7 @@ public class MediaType implements Serializable {
} }
return name.equals(((MediaType) otherMediaType).getName()); return name.equals(((MediaType) otherMediaType).getName());
} }
@SuppressWarnings("NullableProblems")
public String toString() { public String toString() {
return name; return name;
} }

@ -1,6 +1,5 @@
package me.ag2s.epublib.domain; package me.ag2s.epublib.domain;
import me.ag2s.epublib.domain.MediaType;
import me.ag2s.epublib.util.StringUtil; import me.ag2s.epublib.util.StringUtil;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -54,16 +53,16 @@ public class MediaTypes {
public static final MediaType PLS = new MediaType("application/pls+xml", public static final MediaType PLS = new MediaType("application/pls+xml",
".pls"); ".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, XHTML, EPUB, JPG, PNG, GIF, CSS, SVG, TTF, NCX, XPGT, OPENTYPE, WOFF,
SMIL, PLS, JAVASCRIPT, MP3, MP4, OGG SMIL, PLS, JAVASCRIPT, MP3, MP4, OGG
}; };
public static Map<String, MediaType> mediaTypesByName = new HashMap<String, MediaType>(); public static final Map<String, MediaType> mediaTypesByName = new HashMap<>();
static { static {
for (int i = 0; i < mediaTypes.length; i++) { for (MediaType mediaType : mediaTypes) {
mediaTypesByName.put(mediaTypes[i].getName(), mediaTypes[i]); mediaTypesByName.put(mediaType.getName(), mediaType);
} }
} }
@ -75,7 +74,7 @@ public class MediaTypes {
* Gets the MediaType based on the file extension. * Gets the MediaType based on the file extension.
* Null of no matching extension found. * Null of no matching extension found.
* *
* @param filename * @param filename filename
* @return the MediaType based on the file extension. * @return the MediaType based on the file extension.
*/ */
public static MediaType determineMediaType(String filename) { public static MediaType determineMediaType(String filename) {

@ -1,11 +1,13 @@
package me.ag2s.epublib.domain; package me.ag2s.epublib.domain;
import me.ag2s.epublib.util.StringUtil; import me.ag2s.epublib.util.StringUtil;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.xml.namespace.QName; import javax.xml.namespace.QName;
/** /**
@ -21,27 +23,28 @@ public class Metadata implements Serializable {
public static final String DEFAULT_LANGUAGE = "en"; public static final String DEFAULT_LANGUAGE = "en";
private boolean autoGeneratedId = true; private boolean autoGeneratedId;//true;
private List<Author> authors = new ArrayList<Author>(); private List<Author> authors = new ArrayList<>();
private List<Author> contributors = new ArrayList<Author>(); private List<Author> contributors = new ArrayList<>();
private List<Date> dates = new ArrayList<Date>(); private List<Date> dates = new ArrayList<>();
private String language = DEFAULT_LANGUAGE; private String language = DEFAULT_LANGUAGE;
private Map<QName, String> otherProperties = new HashMap<QName, String>(); private Map<QName, String> otherProperties = new HashMap<>();
private List<String> rights = new ArrayList<String>(); private List<String> rights = new ArrayList<>();
private List<String> titles = new ArrayList<String>(); private List<String> titles = new ArrayList<>();
private List<Identifier> identifiers = new ArrayList<Identifier>(); private List<Identifier> identifiers = new ArrayList<>();
private List<String> subjects = new ArrayList<String>(); private List<String> subjects = new ArrayList<>();
private String format = MediaTypes.EPUB.getName(); private String format = MediaTypes.EPUB.getName();
private List<String> types = new ArrayList<String>(); private List<String> types = new ArrayList<>();
private List<String> descriptions = new ArrayList<String>(); private List<String> descriptions = new ArrayList<>();
private List<String> publishers = new ArrayList<String>(); private List<String> publishers = new ArrayList<>();
private Map<String, String> metaAttributes = new HashMap<String, String>(); private Map<String, String> metaAttributes = new HashMap<>();
public Metadata() { public Metadata() {
identifiers.add(new Identifier()); identifiers.add(new Identifier());
autoGeneratedId = true; autoGeneratedId = true;
} }
@SuppressWarnings("unused")
public boolean isAutoGeneratedId() { public boolean isAutoGeneratedId() {
return autoGeneratedId; return autoGeneratedId;
} }
@ -59,6 +62,7 @@ public class Metadata implements Serializable {
this.otherProperties = otherProperties; this.otherProperties = otherProperties;
} }
@SuppressWarnings("unused")
public Date addDate(Date date) { public Date addDate(Date date) {
this.dates.add(date); this.dates.add(date);
return date; return date;
@ -72,6 +76,7 @@ public class Metadata implements Serializable {
this.dates = dates; this.dates = dates;
} }
@SuppressWarnings("UnusedReturnValue")
public Author addAuthor(Author author) { public Author addAuthor(Author author) {
authors.add(author); authors.add(author);
return author; return author;
@ -85,6 +90,7 @@ public class Metadata implements Serializable {
this.authors = authors; this.authors = authors;
} }
@SuppressWarnings("UnusedReturnValue")
public Author addContributor(Author contributor) { public Author addContributor(Author contributor) {
contributors.add(contributor); contributors.add(contributor);
return contributor; return contributor;
@ -154,6 +160,7 @@ public class Metadata implements Serializable {
return titles; return titles;
} }
@SuppressWarnings("UnusedReturnValue")
public String addPublisher(String publisher) { public String addPublisher(String publisher) {
this.publishers.add(publisher); this.publishers.add(publisher);
return publisher; return publisher;
@ -167,6 +174,7 @@ public class Metadata implements Serializable {
return publishers; return publishers;
} }
@SuppressWarnings("UnusedReturnValue")
public String addDescription(String description) { public String addDescription(String description) {
this.descriptions.add(description); this.descriptions.add(description);
return description; return description;
@ -180,6 +188,7 @@ public class Metadata implements Serializable {
return descriptions; return descriptions;
} }
@SuppressWarnings("unused")
public Identifier addIdentifier(Identifier identifier) { public Identifier addIdentifier(Identifier identifier) {
if (autoGeneratedId && (!(identifiers.isEmpty()))) { if (autoGeneratedId && (!(identifiers.isEmpty()))) {
identifiers.set(0, identifier); identifiers.set(0, identifier);
@ -207,6 +216,7 @@ public class Metadata implements Serializable {
return format; return format;
} }
@SuppressWarnings("UnusedReturnValue")
public String addType(String type) { public String addType(String type) {
this.types.add(type); this.types.add(type);
return type; return type;
@ -220,6 +230,7 @@ public class Metadata implements Serializable {
this.types = types; this.types = types;
} }
@SuppressWarnings("unused")
public String getMetaAttribute(String name) { public String getMetaAttribute(String name) {
return metaAttributes.get(name); return metaAttributes.get(name);
} }

@ -27,9 +27,9 @@ public class Resource implements Serializable {
private String properties; private String properties;
protected String originalHref; protected final String originalHref;
private MediaType mediaType; private MediaType mediaType;
private String inputEncoding = Constants.CHARACTER_ENCODING; private String inputEncoding;
protected byte[] data; protected byte[] data;
/** /**
@ -147,7 +147,7 @@ public class Resource implements Serializable {
* *
* @return The contents of the Resource. * @return The contents of the Resource.
* *
* @throws IOException * @throws IOException IOException
*/ */
public InputStream getInputStream() throws IOException { public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(getData()); return new ByteArrayInputStream(getData());
@ -174,7 +174,7 @@ public class Resource implements Serializable {
* Sets the data of the Resource. * 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. * 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) { public void setData(byte[] data) {
this.data = 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. * 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) { public void setId(String id) {
this.id = id; this.id = id;
@ -233,7 +233,7 @@ public class Resource implements Serializable {
/** /**
* Sets the Resource's href. * Sets the Resource's href.
* *
* @param href * @param href Resource's href.
*/ */
public void setHref(String href) { public void setHref(String href) {
this.href = href; this.href = href;
@ -252,7 +252,7 @@ public class Resource implements Serializable {
/** /**
* Sets the Resource's input character encoding. * Sets the Resource's input character encoding.
* *
* @param encoding * @param encoding Resource's input character encoding.
*/ */
public void setInputEncoding(String encoding) { public void setInputEncoding(String encoding) {
this.inputEncoding = 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. * 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. * @return the contents of the Resource as Reader.
* @throws IOException * @throws IOException IOException
*/ */
public Reader getReader() throws IOException { public Reader getReader() throws IOException {
return new XmlStreamReader(new ByteArrayInputStream(getData()), return new XmlStreamReader(new ByteArrayInputStream(getData()),
@ -315,7 +315,7 @@ public class Resource implements Serializable {
public void setProperties(String properties) { public void setProperties(String properties) {
this.properties = properties; this.properties = properties;
} }
@SuppressWarnings("NullableProblems")
public String toString() { public String toString() {
return StringUtil.toString("id", id, return StringUtil.toString("id", id,
"title", title, "title", title,

@ -20,7 +20,7 @@ public class ResourceReference implements Serializable {
/** /**
* Besides setting the resource it also sets the fragmentId to null. * Besides setting the resource it also sets the fragmentId to null.
* *
* @param resource * @param resource resource
*/ */
public void setResource(Resource resource) { public void setResource(Resource resource) {
this.resource = resource; this.resource = resource;

@ -2,6 +2,7 @@ package me.ag2s.epublib.domain;
import me.ag2s.epublib.Constants; import me.ag2s.epublib.Constants;
import me.ag2s.epublib.util.StringUtil; import me.ag2s.epublib.util.StringUtil;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -15,7 +16,6 @@ import java.util.Map;
* XHTML files, images and epub xml documents must be here. * XHTML files, images and epub xml documents must be here.
* *
* @author paul * @author paul
*
*/ */
public class Resources implements Serializable { public class Resources implements Serializable {
@ -28,10 +28,10 @@ public class Resources implements Serializable {
/** /**
* Adds a resource to the resources. * Adds a resource to the resources.
* * <p>
* Fixes the resources id and href if necessary. * Fixes the resources id and href if necessary.
* *
* @param resource * @param resource resource
* @return the newly added resource * @return the newly added resource
*/ */
public Resource add(Resource resource) { public Resource add(Resource resource) {
@ -44,7 +44,7 @@ public class Resources implements Serializable {
/** /**
* Checks the id of the given resource and changes to a unique identifier if it isn't one already. * Checks the id of the given resource and changes to a unique identifier if it isn't one already.
* *
* @param resource * @param resource resource
*/ */
public void fixResourceId(Resource resource) { public void fixResourceId(Resource resource) {
String resourceId = resource.getId(); String resourceId = resource.getId();
@ -67,7 +67,7 @@ public class Resources implements Serializable {
/** /**
* Check if the id is a valid identifier. if not: prepend with valid identifier * Check if the id is a valid identifier. if not: prepend with valid identifier
* *
* @param resource * @param resource resource
* @return a valid id * @return a valid id
*/ */
private String makeValidId(String resourceId, Resource resource) { private String makeValidId(String resourceId, Resource resource) {
@ -91,7 +91,7 @@ public class Resources implements Serializable {
/** /**
* Creates a new resource id that is guaranteed to be unique for this set of Resources * Creates a new resource id that is guaranteed to be unique for this set of Resources
* *
* @param resource * @param resource resource
* @return a new resource id that is guaranteed to be unique for this set of Resources * @return a new resource id that is guaranteed to be unique for this set of Resources
*/ */
private String createUniqueResourceId(Resource resource) { private String createUniqueResourceId(Resource resource) {
@ -117,7 +117,7 @@ public class Resources implements Serializable {
/** /**
* Whether the map of resources already contains a resource with the given id. * Whether the map of resources already contains a resource with the given id.
* *
* @param id * @param id id
* @return Whether the map of resources already contains a resource with the given id. * @return Whether the map of resources already contains a resource with the given id.
*/ */
public boolean containsId(String id) { public boolean containsId(String id) {
@ -135,7 +135,7 @@ public class Resources implements Serializable {
/** /**
* Gets the resource with the given id. * Gets the resource with the given id.
* *
* @param id * @param id id
* @return null if not found * @return null if not found
*/ */
public Resource getById(String id) { public Resource getById(String id) {
@ -149,6 +149,7 @@ public class Resources implements Serializable {
} }
return null; return null;
} }
public Resource getByProperties(String properties) { public Resource getByProperties(String properties) {
if (StringUtil.isBlank(properties)) { if (StringUtil.isBlank(properties)) {
return null; return null;
@ -164,7 +165,7 @@ public class Resources implements Serializable {
/** /**
* Remove the resource with the given href. * Remove the resource with the given href.
* *
* @param href * @param href href
* @return the removed resource, null if not found * @return the removed resource, null if not found
*/ */
public Resource remove(String href) { public Resource remove(String href) {
@ -205,6 +206,7 @@ public class Resources implements Serializable {
/** /**
* The number of resources * The number of resources
*
* @return The number of resources * @return The number of resources
*/ */
public int size() { public int size() {
@ -217,6 +219,7 @@ public class Resources implements Serializable {
* *
* @return The resources that make up this book. * @return The resources that make up this book.
*/ */
@SuppressWarnings("unused")
public Map<String, Resource> getResourceMap() { public Map<String, Resource> getResourceMap() {
return resources; return resources;
} }
@ -228,21 +231,33 @@ public class Resources implements Serializable {
/** /**
* Whether there exists a resource with the given href * Whether there exists a resource with the given href
* @param href *
* @param href href
* @return Whether there exists a resource with the given href * @return Whether there exists a resource with the given href
*/ */
public boolean containsByHref(String href) { public boolean notContainsByHref(String href) {
if (StringUtil.isBlank(href)) { if (StringUtil.isBlank(href)) {
return false; return true;
} } else {
return resources.containsKey( return !resources.containsKey(
StringUtil.substringBefore(href, Constants.FRAGMENT_SEPARATOR_CHAR)); StringUtil.substringBefore(href, Constants.FRAGMENT_SEPARATOR_CHAR));
} }
}
/**
* 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);
}
/** /**
* Sets the collection of Resources to the given collection of resources * Sets the collection of Resources to the given collection of resources
* *
* @param resources * @param resources resources
*/ */
public void set(Collection<Resource> resources) { public void set(Collection<Resource> resources) {
this.resources.clear(); this.resources.clear();
@ -252,7 +267,7 @@ public class Resources implements Serializable {
/** /**
* Adds all resources from the given Collection of resources to the existing collection. * Adds all resources from the given Collection of resources to the existing collection.
* *
* @param resources * @param resources resources
*/ */
public void addAll(Collection<Resource> resources) { public void addAll(Collection<Resource> resources) {
for (Resource resource : resources) { for (Resource resource : resources) {
@ -267,7 +282,7 @@ public class Resources implements Serializable {
* @param resources A map with as keys the resources href and as values the Resources * @param resources A map with as keys the resources href and as values the Resources
*/ */
public void set(Map<String, Resource> resources) { public void set(Map<String, Resource> resources) {
this.resources = new HashMap<String, Resource>(resources); this.resources = new HashMap<>(resources);
} }
@ -275,7 +290,7 @@ public class Resources implements Serializable {
* First tries to find a resource with as id the given idOrHref, if that * 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. * fails it tries to find one with the idOrHref as href.
* *
* @param idOrHref * @param idOrHref idOrHref
* @return the found Resource * @return the found Resource
*/ */
public Resource getByIdOrHref(String idOrHref) { public Resource getByIdOrHref(String idOrHref) {
@ -291,7 +306,7 @@ public class Resources implements Serializable {
* Gets the resource with the given href. * Gets the resource with the given href.
* If the given href contains a fragmentId then that fragment id will be ignored. * If the given href contains a fragmentId then that fragment id will be ignored.
* *
* @param href * @param href href
* @return null if not found. * @return null if not found.
*/ */
public Resource getByHref(String href) { public Resource getByHref(String href) {
@ -299,16 +314,15 @@ public class Resources implements Serializable {
return null; return null;
} }
href = StringUtil.substringBefore(href, Constants.FRAGMENT_SEPARATOR_CHAR); href = StringUtil.substringBefore(href, Constants.FRAGMENT_SEPARATOR_CHAR);
Resource result = resources.get(href); return resources.get(href);
return result;
} }
/** /**
* Gets the first resource (random order) with the give mediatype. * Gets the first resource (random order) with the give mediatype.
* * <p>
* Useful for looking up the table of contents as it's supposed to be the only resource with NCX mediatype. * Useful for looking up the table of contents as it's supposed to be the only resource with NCX mediatype.
* *
* @param mediaType * @param mediaType mediaType
* @return the first resource (random order) with the give mediatype. * @return the first resource (random order) with the give mediatype.
*/ */
public Resource findFirstResourceByMediaType(MediaType mediaType) { public Resource findFirstResourceByMediaType(MediaType mediaType) {
@ -317,10 +331,10 @@ public class Resources implements Serializable {
/** /**
* Gets the first resource (random order) with the give mediatype. * Gets the first resource (random order) with the give mediatype.
* * <p>
* Useful for looking up the table of contents as it's supposed to be the only resource with NCX mediatype. * Useful for looking up the table of contents as it's supposed to be the only resource with NCX mediatype.
* *
* @param mediaType * @param mediaType mediaType
* @return the first resource (random order) with the give mediatype. * @return the first resource (random order) with the give mediatype.
*/ */
public static Resource findFirstResourceByMediaType( public static Resource findFirstResourceByMediaType(
@ -336,11 +350,11 @@ public class Resources implements Serializable {
/** /**
* All resources that have the given MediaType. * All resources that have the given MediaType.
* *
* @param mediaType * @param mediaType mediaType
* @return All resources that have the given MediaType. * @return All resources that have the given MediaType.
*/ */
public List<Resource> getResourcesByMediaType(MediaType mediaType) { public List<Resource> getResourcesByMediaType(MediaType mediaType) {
List<Resource> result = new ArrayList<Resource>(); List<Resource> result = new ArrayList<>();
if (mediaType == null) { if (mediaType == null) {
return result; return result;
} }
@ -355,11 +369,12 @@ public class Resources implements Serializable {
/** /**
* All Resources that match any of the given list of MediaTypes * All Resources that match any of the given list of MediaTypes
* *
* @param mediaTypes * @param mediaTypes mediaType
* @return All Resources that match any of the given list of MediaTypes * @return All Resources that match any of the given list of MediaTypes
*/ */
@SuppressWarnings("unused")
public List<Resource> getResourcesByMediaTypes(MediaType[] mediaTypes) { public List<Resource> getResourcesByMediaTypes(MediaType[] mediaTypes) {
List<Resource> result = new ArrayList<Resource>(); List<Resource> result = new ArrayList<>();
if (mediaTypes == null) { if (mediaTypes == null) {
return result; return result;
} }

@ -22,13 +22,13 @@ public class Spine implements Serializable {
private List<SpineReference> spineReferences; private List<SpineReference> spineReferences;
public Spine() { public Spine() {
this(new ArrayList<SpineReference>()); this(new ArrayList<>());
} }
/** /**
* Creates a spine out of all the resources in the table of contents. * Creates a spine out of all the resources in the table of contents.
* *
* @param tableOfContents * @param tableOfContents tableOfContents
*/ */
public Spine(TableOfContents tableOfContents) { public Spine(TableOfContents tableOfContents) {
this.spineReferences = createSpineReferences( this.spineReferences = createSpineReferences(
@ -41,7 +41,7 @@ public class Spine implements Serializable {
public static List<SpineReference> createSpineReferences( public static List<SpineReference> createSpineReferences(
Collection<Resource> resources) { Collection<Resource> resources) {
List<SpineReference> result = new ArrayList<SpineReference>( List<SpineReference> result = new ArrayList<>(
resources.size()); resources.size());
for (Resource resource : resources) { for (Resource resource : resources) {
result.add(new SpineReference(resource)); result.add(new SpineReference(resource));
@ -61,7 +61,7 @@ public class Spine implements Serializable {
* Gets the resource at the given index. * Gets the resource at the given index.
* Null if not found. * Null if not found.
* *
* @param index * @param index index
* @return the resource at the given index. * @return the resource at the given index.
*/ */
public Resource getResource(int index) { public Resource getResource(int index) {
@ -76,7 +76,7 @@ public class Spine implements Serializable {
* *
* Null if not found. * Null if not found.
* *
* @param resourceId * @param resourceId resourceId
* @return the first resource that has the given resourceId. * @return the first resource that has the given resourceId.
*/ */
public int findFirstResourceById(String 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. * Adds the given spineReference to the spine references and returns it.
* *
* @param spineReference * @param spineReference spineReference
* @return the given spineReference * @return the given spineReference
*/ */
public SpineReference addSpineReference(SpineReference spineReference) { public SpineReference addSpineReference(SpineReference spineReference) {
if (spineReferences == null) { if (spineReferences == null) {
this.spineReferences = new ArrayList<SpineReference>(); this.spineReferences = new ArrayList<>();
} }
spineReferences.add(spineReference); spineReferences.add(spineReference);
return spineReference; return spineReference;
@ -112,6 +112,7 @@ public class Spine implements Serializable {
* *
* @return the given spineReference * @return the given spineReference
*/ */
@SuppressWarnings("unused")
public SpineReference addResource(Resource resource) { public SpineReference addResource(Resource resource) {
return addSpineReference(new SpineReference(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. * 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. * Put it here to be sure of the expected behaviours.
* *
* @param tocResource * @param tocResource tocResource
*/ */
public void setTocResource(Resource tocResource) { public void setTocResource(Resource tocResource) {
this.tocResource = tocResource; this.tocResource = tocResource;
@ -149,7 +150,7 @@ public class Spine implements Serializable {
/** /**
* The position within the spine of the given resource. * The position within the spine of the given resource.
* *
* @param currentResource * @param currentResource currentResource
* @return something &lt; 0 if not found. * @return something &lt; 0 if not found.
* *
*/ */

@ -12,7 +12,7 @@ import java.io.Serializable;
public class SpineReference extends ResourceReference implements Serializable { public class SpineReference extends ResourceReference implements Serializable {
private static final long serialVersionUID = -7921609197351510248L; private static final long serialVersionUID = -7921609197351510248L;
private boolean linear = true; private boolean linear;//default = true;
public SpineReference(Resource resource) { public SpineReference(Resource resource) {
this(resource, true); this(resource, true);
@ -28,7 +28,7 @@ public class SpineReference extends ResourceReference implements Serializable {
* Linear denotes whether the section is Primary or Auxiliary. * Linear denotes whether the section is Primary or Auxiliary.
* Usually the cover page has linear set to false and all the other sections * Usually the cover page has linear set to false and all the other sections
* have it set to true. * have it set to true.
* * <p>
* It's an optional property that readers may also ignore. * It's an optional property that readers may also ignore.
* *
* <blockquote>primary or auxiliary is useful for Reading Systems which * <blockquote>primary or auxiliary is useful for Reading Systems which
@ -37,9 +37,9 @@ public class SpineReference extends ResourceReference implements Serializable {
* a popup window apart from the main window which presents the primary * 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 * content. (For an example of the types of content that may be considered
* auxiliary, refer to the example below and the subsequent discussion.)</blockquote> * auxiliary, refer to the example below and the subsequent discussion.)</blockquote>
* @see <a href="http://www.idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.4">OPF Spine specification</a>
* *
* @return whether the section is Primary or Auxiliary. * @return whether the section is Primary or Auxiliary.
* @see <a href="http://www.idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.4">OPF Spine specification</a>
*/ */
public boolean isLinear() { public boolean isLinear() {
return linear; return linear;

@ -17,11 +17,8 @@ public class TOCReference extends TitledResourceReference
private static final long serialVersionUID = 5787958246077042456L; private static final long serialVersionUID = 5787958246077042456L;
private List<TOCReference> children; private List<TOCReference> children;
private static final Comparator<TOCReference> COMPARATOR_BY_TITLE_IGNORE_CASE = private static final Comparator<TOCReference> COMPARATOR_BY_TITLE_IGNORE_CASE = (tocReference1, tocReference2) -> String.CASE_INSENSITIVE_ORDER.compare(tocReference1.getTitle(), tocReference2.getTitle());
(tocReference1, tocReference2) -> @Deprecated
String.CASE_INSENSITIVE_ORDER
.compare(tocReference1.getTitle(), tocReference2.getTitle());
public TOCReference() { public TOCReference() {
this(null, null, null); this(null, null, null);
} }
@ -39,7 +36,7 @@ public class TOCReference extends TitledResourceReference
super(resource, title, fragmentId); super(resource, title, fragmentId);
this.children = children; this.children = children;
} }
@SuppressWarnings("unused")
public static Comparator<TOCReference> getComparatorByTitleIgnoreCase() { public static Comparator<TOCReference> getComparatorByTitleIgnoreCase() {
return COMPARATOR_BY_TITLE_IGNORE_CASE; return COMPARATOR_BY_TITLE_IGNORE_CASE;
} }

@ -29,7 +29,7 @@ public class TableOfContents implements Serializable {
private List<TOCReference> tocReferences; private List<TOCReference> tocReferences;
public TableOfContents() { public TableOfContents() {
this(new ArrayList<TOCReference>()); this(new ArrayList<>());
} }
public TableOfContents(List<TOCReference> tocReferences) { public TableOfContents(List<TOCReference> tocReferences) {
@ -48,6 +48,7 @@ public class TableOfContents implements Serializable {
* Calls addTOCReferenceAtLocation after splitting the path using the DEFAULT_PATH_SEPARATOR. * Calls addTOCReferenceAtLocation after splitting the path using the DEFAULT_PATH_SEPARATOR.
* @return the new TOCReference * @return the new TOCReference
*/ */
@SuppressWarnings("unused")
public TOCReference addSection(Resource resource, String path) { public TOCReference addSection(Resource resource, String path) {
return addSection(resource, path, DEFAULT_PATH_SEPARATOR); 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. * Calls addTOCReferenceAtLocation after splitting the path using the given pathSeparator.
* *
* @param resource * @param resource resource
* @param path * @param path path
* @param pathSeparator * @param pathSeparator pathSeparator
* @return the new TOCReference * @return the new TOCReference
*/ */
public TOCReference addSection(Resource resource, String path, 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. * Finds the first TOCReference in the given list that has the same title as the given Title.
* *
* @param title * @param title title
* @param tocReferences * @param tocReferences tocReferences
* @return null if not found. * @return null if not found.
*/ */
private static TOCReference findTocReferenceByTitle(String title, private static TOCReference findTocReferenceByTitle(String title,
@ -95,8 +96,8 @@ public class TableOfContents implements Serializable {
* will point to the given Resource</li> * will point to the given Resource</li>
* </ul> * </ul>
* *
* @param resource * @param resource resource
* @param pathElements * @param pathElements pathElements
* @return the new TOCReference * @return the new TOCReference
*/ */
public TOCReference addSection(Resource resource, String[] pathElements) { public TOCReference addSection(Resource resource, String[] pathElements) {
@ -105,8 +106,7 @@ public class TableOfContents implements Serializable {
} }
TOCReference result = null; TOCReference result = null;
List<TOCReference> currentTocReferences = this.tocReferences; List<TOCReference> currentTocReferences = this.tocReferences;
for (int i = 0; i < pathElements.length; i++) { for (String currentTitle : pathElements) {
String currentTitle = pathElements[i];
result = findTocReferenceByTitle(currentTitle, currentTocReferences); result = findTocReferenceByTitle(currentTitle, currentTocReferences);
if (result == null) { if (result == null) {
result = new TOCReference(currentTitle, 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 ""</li> * If this TOCReference didn't exist yet it will be created and have a title of ""</li>
* </ul> * </ul>
* *
* @param resource * @param resource resource
* @param pathElements * @param pathElements pathElements
* @return the new TOCReference * @return the new TOCReference
*/ */
@SuppressWarnings("unused")
public TOCReference addSection(Resource resource, int[] pathElements, public TOCReference addSection(Resource resource, int[] pathElements,
String sectionTitlePrefix, String sectionNumberSeparator) { String sectionTitlePrefix, String sectionNumberSeparator) {
if (pathElements == null || pathElements.length == 0) { if (pathElements == null || pathElements.length == 0) {

@ -2,6 +2,7 @@ package me.ag2s.epublib.domain;
import me.ag2s.epublib.Constants; import me.ag2s.epublib.Constants;
import me.ag2s.epublib.util.StringUtil; import me.ag2s.epublib.util.StringUtil;
import java.io.Serializable; import java.io.Serializable;
public class TitledResourceReference extends ResourceReference public class TitledResourceReference extends ResourceReference
@ -11,6 +12,13 @@ public class TitledResourceReference extends ResourceReference
private String fragmentId; private String fragmentId;
private String title; private String title;
/**
* 这会使title为null
*
* @param resource resource
*/
@Deprecated
@SuppressWarnings("unused")
public TitledResourceReference(Resource resource) { public TitledResourceReference(Resource resource) {
this(resource, null); this(resource, null);
} }
@ -58,8 +66,10 @@ public class TitledResourceReference extends ResourceReference
+ fragmentId; + fragmentId;
} }
} }
@Override @Override
public Resource getResource() { public Resource getResource() {
//修复getTitle为null的bug
resource.setTitle(title); resource.setTitle(title);
return resource; return resource;
} }

@ -1,6 +1,6 @@
package me.ag2s.epublib.epub; package me.ag2s.epublib.epub;
import me.ag2s.epublib.domain.EpubBook; import me.ag2s.epublib.domain.Book;
/** /**
* Post-processes a book. * Post-processes a book.
@ -16,5 +16,5 @@ public interface BookProcessor {
*/ */
BookProcessor IDENTITY_BOOKPROCESSOR = book -> book; BookProcessor IDENTITY_BOOKPROCESSOR = book -> book;
EpubBook processBook(EpubBook book); Book processBook(Book book);
} }

@ -2,25 +2,23 @@ package me.ag2s.epublib.epub;
import android.util.Log; import android.util.Log;
import me.ag2s.epublib.domain.Book;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import me.ag2s.epublib.domain.EpubBook;
//import io.documentnode.minilog.Logger;
/** /**
* A book processor that combines several other bookprocessors * A book processor that combines several other bookprocessors
* <p> *
* Fixes coverpage/coverimage. * Fixes coverpage/coverimage.
* Cleans up the XHTML. * Cleans up the XHTML.
* *
* @author paul.siegmann * @author paul.siegmann
*/ */
@SuppressWarnings("unused declaration")
public class BookProcessorPipeline implements BookProcessor { public class BookProcessorPipeline implements BookProcessor {
private static String TAG= BookProcessorPipeline.class.getName(); private static final String TAG= BookProcessorPipeline.class.getName();
private List<BookProcessor> bookProcessors; private List<BookProcessor> bookProcessors;
public BookProcessorPipeline() { public BookProcessorPipeline() {
@ -32,7 +30,7 @@ public class BookProcessorPipeline implements BookProcessor {
} }
@Override @Override
public EpubBook processBook(EpubBook book) { public Book processBook(Book book) {
if (bookProcessors == null) { if (bookProcessors == null) {
return book; return book;
} }
@ -40,7 +38,7 @@ public class BookProcessorPipeline implements BookProcessor {
try { try {
book = bookProcessor.processBook(book); book = bookProcessor.processBook(book);
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, e.getMessage(), e); Log.e(TAG,e.getMessage(), e);
} }
} }
return book; return book;
@ -48,14 +46,14 @@ public class BookProcessorPipeline implements BookProcessor {
public void addBookProcessor(BookProcessor bookProcessor) { public void addBookProcessor(BookProcessor bookProcessor) {
if (this.bookProcessors == null) { if (this.bookProcessors == null) {
bookProcessors = new ArrayList<BookProcessor>(); bookProcessors = new ArrayList<>();
} }
this.bookProcessors.add(bookProcessor); this.bookProcessors.add(bookProcessor);
} }
public void addBookProcessors(Collection<BookProcessor> bookProcessors) { public void addBookProcessors(Collection<BookProcessor> bookProcessors) {
if (this.bookProcessors == null) { if (this.bookProcessors == null) {
this.bookProcessors = new ArrayList<BookProcessor>(); this.bookProcessors = new ArrayList<>();
} }
this.bookProcessors.addAll(bookProcessors); this.bookProcessors.addAll(bookProcessors);
} }

@ -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. * 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 element element
* @param namespace * @param namespace namespace
* @param attribute * @param attribute attribute
* @return * @return String Attribute
*/ */
public static String getAttribute(Element element, String namespace, public static String getAttribute(Element element, String namespace,
String attribute) { 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. * 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 parentElement parentElement
* @param namespace * @param namespace namespace
* @param tagname * @param tagName tagName
* @return * @return List<String>
*/ */
public static List<String> getElementsTextChild(Element parentElement, public static List<String> getElementsTextChild(Element parentElement,
String namespace, String tagname) { String namespace, String tagName) {
NodeList elements = parentElement NodeList elements = parentElement
.getElementsByTagNameNS(namespace, tagname); .getElementsByTagNameNS(namespace, tagName);
List<String> result = new ArrayList<String>(elements.getLength()); //ArrayList 初始化时指定长度提高性能
List<String> result = new ArrayList<>(elements.getLength());
for (int i = 0; i < elements.getLength(); i++) { for (int i = 0; i < elements.getLength(); i++) {
result.add(getTextChildrenContent((Element) elements.item(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. * 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. * It then returns the value of the given resultAttributeName.
* *
* @param document * @param document document
* @param namespace * @param namespace namespace
* @param elementName * @param elementName elementName
* @param findAttributeName * @param findAttributeName findAttributeName
* @param findAttributeValue * @param findAttributeValue findAttributeValue
* @param resultAttributeName * @param resultAttributeName resultAttributeName
* @return * @return String value
*/ */
public static String getFindAttributeValue(Document document, public static String getFindAttributeValue(Document document,
String namespace, String elementName, String findAttributeName, 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 * Gets the first element that is a child of the parentElement and has the given namespace and tagName
* *
* @param parentElement * @param parentElement parentElement
* @param namespace * @param namespace namespace
* @param tagName * @param tagName tagName
* @return * @return Element
*/ */
public static Element getFirstElementByTagNameNS(Element parentElement, public static Element getFirstElementByTagNameNS(Element parentElement,
String namespace, String tagName) { 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 * when the text is Chinese characters then on Android each Characater is represented in the DOM as
* an individual Text node. * an individual Text node.
* *
* @param parentElement * @param parentElement parentElement
* @return * @return String value
*/ */
public static String getTextChildrenContent(Element parentElement) { public static String getTextChildrenContent(Element parentElement) {
if (parentElement == null) { if (parentElement == null) {

@ -3,7 +3,7 @@ package me.ag2s.epublib.epub;
import android.util.Log; import android.util.Log;
import me.ag2s.epublib.Constants; import me.ag2s.epublib.Constants;
//import io.documentnode.minilog.Logger;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -11,13 +11,14 @@ import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.io.Writer; import java.io.Writer;
import java.net.URL; import java.net.URL;
import java.util.Objects;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
//import org.kxml2.io.KXmlSerializer;
import org.xml.sax.EntityResolver; import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParserFactory; import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer; import org.xmlpull.v1.XmlSerializer;
@ -25,11 +26,10 @@ import org.xmlpull.v1.XmlSerializer;
* Various low-level support methods for reading/writing epubs. * Various low-level support methods for reading/writing epubs.
* *
* @author paul.siegmann * @author paul.siegmann
*
*/ */
public class EpubProcessorSupport { public class EpubProcessorSupport {
private static String TAG= EpubProcessorSupport.class.getName(); private static final String TAG = EpubProcessorSupport.class.getName();
protected static DocumentBuilderFactory documentBuilderFactory; protected static DocumentBuilderFactory documentBuilderFactory;
@ -43,7 +43,7 @@ public class EpubProcessorSupport {
@Override @Override
public InputSource resolveEntity(String publicId, String systemId) public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException { throws IOException {
String resourcePath; String resourcePath;
if (systemId.startsWith("http:")) { if (systemId.startsWith("http:")) {
URL url = new URL(systemId); URL url = new URL(systemId);
@ -55,13 +55,13 @@ public class EpubProcessorSupport {
previousLocation + systemId.substring(systemId.lastIndexOf('/')); previousLocation + systemId.substring(systemId.lastIndexOf('/'));
} }
if (this.getClass().getClassLoader().getResource(resourcePath) == null) { if (Objects.requireNonNull(this.getClass().getClassLoader()).getResource(resourcePath) == null) {
throw new RuntimeException( throw new RuntimeException(
"remote resource is not cached : [" + systemId "remote resource is not cached : [" + systemId
+ "] cannot continue"); + "] cannot continue");
} }
InputStream in = EpubProcessorSupport.class.getClassLoader() InputStream in = Objects.requireNonNull(EpubProcessorSupport.class.getClassLoader())
.getResourceAsStream(resourcePath); .getResourceAsStream(resourcePath);
return new InputSource(in); return new InputSource(in);
} }
@ -116,6 +116,7 @@ public class EpubProcessorSupport {
return new EntityResolverImpl(); return new EntityResolverImpl();
} }
@SuppressWarnings("unused")
public DocumentBuilderFactory getDocumentBuilderFactory() { public DocumentBuilderFactory getDocumentBuilderFactory() {
return documentBuilderFactory; return documentBuilderFactory;
} }
@ -131,7 +132,7 @@ public class EpubProcessorSupport {
result = documentBuilderFactory.newDocumentBuilder(); result = documentBuilderFactory.newDocumentBuilder();
result.setEntityResolver(getEntityResolver()); result.setEntityResolver(getEntityResolver());
} catch (ParserConfigurationException e) { } catch (ParserConfigurationException e) {
Log.e(TAG,e.getMessage()); Log.e(TAG, e.getMessage());
} }
return result; return result;
} }

@ -13,6 +13,7 @@ import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
import me.ag2s.epublib.Constants; import me.ag2s.epublib.Constants;
import me.ag2s.epublib.domain.Book;
import me.ag2s.epublib.domain.EpubBook; import me.ag2s.epublib.domain.EpubBook;
import me.ag2s.epublib.domain.MediaType; import me.ag2s.epublib.domain.MediaType;
import me.ag2s.epublib.domain.MediaTypes; import me.ag2s.epublib.domain.MediaTypes;
@ -21,28 +22,27 @@ import me.ag2s.epublib.domain.Resources;
import me.ag2s.epublib.util.ResourceUtil; import me.ag2s.epublib.util.ResourceUtil;
import me.ag2s.epublib.util.StringUtil; import me.ag2s.epublib.util.StringUtil;
//import io.documentnode.minilog.Logger;
/** /**
* Reads an epub file. * Reads an epub file.
* *
* @author paul * @author paul
*
*/ */
public class EpubReader { public class EpubReader {
private static String TAG= EpubReader.class.getName(); private static final String TAG = EpubReader.class.getName();
private BookProcessor bookProcessor = BookProcessor.IDENTITY_BOOKPROCESSOR; private final BookProcessor bookProcessor = BookProcessor.IDENTITY_BOOKPROCESSOR;
@SuppressWarnings("unused")
public EpubBook readEpub(InputStream in) throws IOException { public Book readEpub(InputStream in) throws IOException {
return readEpub(in, Constants.CHARACTER_ENCODING); return readEpub(in, Constants.CHARACTER_ENCODING);
} }
public EpubBook readEpub(ZipInputStream in) throws IOException { @SuppressWarnings("unused")
public Book readEpub(ZipInputStream in) throws IOException {
return readEpub(in, Constants.CHARACTER_ENCODING); return readEpub(in, Constants.CHARACTER_ENCODING);
} }
public EpubBook readEpub(ZipFile zipfile) throws IOException { @SuppressWarnings("unused")
public Book readEpub(ZipFile zipfile) throws IOException {
return readEpub(zipfile, Constants.CHARACTER_ENCODING); return readEpub(zipfile, Constants.CHARACTER_ENCODING);
} }
@ -52,9 +52,9 @@ public class EpubReader {
* @param in the inputstream from which to read the epub * @param in the inputstream from which to read the epub
* @param encoding the encoding to use for the html files within the epub * @param encoding the encoding to use for the html files within the epub
* @return the Book as read from the inputstream * @return the Book as read from the inputstream
* @throws IOException * @throws IOException IOException
*/ */
public EpubBook readEpub(InputStream in, String encoding) throws IOException { public Book readEpub(InputStream in, String encoding) throws IOException {
return readEpub(new ZipInputStream(in), encoding); return readEpub(new ZipInputStream(in), encoding);
} }
@ -65,19 +65,20 @@ public class EpubReader {
* @param zipFile the file to load * @param zipFile the file to load
* @param encoding the encoding for XHTML files * @param encoding the encoding for XHTML files
* @return this Book without loading all resources into memory. * @return this Book without loading all resources into memory.
* @throws IOException * @throws IOException IOException
*/ */
public EpubBook readEpubLazy(ZipFile zipFile, String encoding) @SuppressWarnings("unused")
public Book readEpubLazy(ZipFile zipFile, String encoding)
throws IOException { throws IOException {
return readEpubLazy(zipFile, encoding, return readEpubLazy(zipFile, encoding,
Arrays.asList(MediaTypes.mediaTypes)); Arrays.asList(MediaTypes.mediaTypes));
} }
public EpubBook readEpub(ZipInputStream in, String encoding) throws IOException { public Book readEpub(ZipInputStream in, String encoding) throws IOException {
return readEpub(ResourcesLoader.loadResources(in, encoding)); return readEpub(ResourcesLoader.loadResources(in, encoding));
} }
public EpubBook readEpub(ZipFile in, String encoding) throws IOException { public Book readEpub(ZipFile in, String encoding) throws IOException {
return readEpub(ResourcesLoader.loadResources(in, encoding)); return readEpub(ResourcesLoader.loadResources(in, encoding));
} }
@ -88,22 +89,26 @@ public class EpubReader {
* @param encoding the encoding for XHTML files * @param encoding the encoding for XHTML files
* @param lazyLoadedTypes a list of the MediaType to load lazily * @param lazyLoadedTypes a list of the MediaType to load lazily
* @return this Book without loading all resources into memory. * @return this Book without loading all resources into memory.
* @throws IOException * @throws IOException IOException
*/ */
public EpubBook readEpubLazy(ZipFile zipFile, String encoding, public Book readEpubLazy(ZipFile zipFile, String encoding,
List<MediaType> lazyLoadedTypes) throws IOException { List<MediaType> lazyLoadedTypes) throws IOException {
Resources resources = ResourcesLoader Resources resources = ResourcesLoader
.loadResources(zipFile, encoding, lazyLoadedTypes); .loadResources(zipFile, encoding, lazyLoadedTypes);
return readEpub(resources); return readEpub(resources);
} }
public EpubBook readEpub(Resources resources) throws IOException { @SuppressWarnings("unused")
return readEpub(resources, new EpubBook()); public Book readEpub(Resources resources) {
return readEpub(resources, new Book());
}
public EpubBook readEpubBook(Resources resources) {
return (EpubBook) readEpub(resources, new Book());
} }
public EpubBook readEpub(Resources resources, EpubBook result) throws IOException { public Book readEpub(Resources resources, Book result) {
if (result == null) { if (result == null) {
result = new EpubBook(); result = new Book();
} }
handleMimeType(result, resources); handleMimeType(result, resources);
String packageResourceHref = getPackageResourceHref(resources); String packageResourceHref = getPackageResourceHref(resources);
@ -117,26 +122,30 @@ public class EpubReader {
} }
private EpubBook postProcessBook(EpubBook book) { private Book postProcessBook(Book book) {
if (bookProcessor != null) { if (bookProcessor != null) {
book = bookProcessor.processBook(book); book = bookProcessor.processBook(book);
} }
return book; return book;
} }
private Resource processNcxResource(Resource packageResource, EpubBook book) { private Resource processNcxResource(Resource packageResource, Book book) {
Log.d(TAG, "OPF:getHref()" + packageResource.getHref()); Log.d(TAG, "OPF:getHref()" + packageResource.getHref());
if (book.isEpub3()) {
return NCXDocumentV3.read(book, this);
} else {
return NCXDocumentV2.read(book, this);
}
return NCXDocument.read(book, this);
} }
private Resource processPackageResource(String packageResourceHref, EpubBook book, private Resource processPackageResource(String packageResourceHref, Book book,
Resources resources) { Resources resources) {
Resource packageResource = resources.remove(packageResourceHref); Resource packageResource = resources.remove(packageResourceHref);
try { try {
PackageDocumentReader.read(packageResource, this, book, resources); PackageDocumentReader.read(packageResource, this, book, resources);
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG,e.getMessage(), e); Log.e(TAG, e.getMessage(), e);
} }
return packageResource; return packageResource;
} }
@ -156,7 +165,7 @@ public class EpubReader {
.getElementsByTagName("rootfile").item(0); .getElementsByTagName("rootfile").item(0);
result = rootFileElement.getAttribute("full-path"); result = rootFileElement.getAttribute("full-path");
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG,e.getMessage(), e); Log.e(TAG, e.getMessage(), e);
} }
if (StringUtil.isBlank(result)) { if (StringUtil.isBlank(result)) {
result = defaultResult; result = defaultResult;
@ -164,7 +173,9 @@ public class EpubReader {
return result; return result;
} }
private void handleMimeType(EpubBook result, Resources resources) { @SuppressWarnings("unused")
private void handleMimeType(Book result, Resources resources) {
resources.remove("mimetype"); resources.remove("mimetype");
//result.setResources(resources);
} }
} }

@ -2,8 +2,10 @@ package me.ag2s.epublib.epub;
import android.util.Log; 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.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -12,13 +14,7 @@ import java.io.Writer;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import org.xmlpull.v1.XmlSerializer;
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;
/** /**
* Generates an epub file. Not thread-safe, single use object. * Generates an epub file. Not thread-safe, single use object.
@ -27,12 +23,12 @@ import me.ag2s.epublib.util.IOUtil;
*/ */
public class EpubWriter { public class EpubWriter {
private static String TAG= EpubWriter.class.getName(); private static final String TAG= EpubWriter.class.getName();
// package // package
static final String EMPTY_NAMESPACE_PREFIX = ""; static final String EMPTY_NAMESPACE_PREFIX = "";
private BookProcessor bookProcessor = BookProcessor.IDENTITY_BOOKPROCESSOR; private BookProcessor bookProcessor;
public EpubWriter() { public EpubWriter() {
this(BookProcessor.IDENTITY_BOOKPROCESSOR); 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); book = processBook(book);
ZipOutputStream resultStream = new ZipOutputStream(out); ZipOutputStream resultStream = new ZipOutputStream(out);
writeMimeType(resultStream); writeMimeType(resultStream);
@ -55,17 +51,22 @@ public class EpubWriter {
resultStream.close(); resultStream.close();
} }
private EpubBook processBook(EpubBook book) { private Book processBook(Book book) {
if (bookProcessor != null) { if (bookProcessor != null) {
book = bookProcessor.processBook(book); book = bookProcessor.processBook(book);
} }
return book; return book;
} }
private void initTOCResource(EpubBook book) { private void initTOCResource(Book book) {
Resource tocResource; Resource tocResource;
try { try {
tocResource = NCXDocument.createNCXResource(book); if(book.isEpub3()){
tocResource = NCXDocumentV3.createNCXResource(book);
}else {
tocResource = NCXDocumentV2.createNCXResource(book);
}
Resource currentTocResource = book.getSpine().getTocResource(); Resource currentTocResource = book.getSpine().getTocResource();
if (currentTocResource != null) { if (currentTocResource != null) {
book.getResources().remove(currentTocResource.getHref()); book.getResources().remove(currentTocResource.getHref());
@ -80,8 +81,7 @@ public class EpubWriter {
} }
private void writeResources(EpubBook book, ZipOutputStream resultStream) private void writeResources(Book book, ZipOutputStream resultStream) {
throws IOException {
for (Resource resource : book.getResources().getAll()) { for (Resource resource : book.getResources().getAll()) {
writeResource(resource, resultStream); writeResource(resource, resultStream);
} }
@ -90,12 +90,10 @@ public class EpubWriter {
/** /**
* Writes the resource to the resultStream. * Writes the resource to the resultStream.
* *
* @param resource * @param resource resource
* @param resultStream * @param resultStream resultStream
* @throws IOException
*/ */
private void writeResource(Resource resource, ZipOutputStream resultStream) private void writeResource(Resource resource, ZipOutputStream resultStream) {
throws IOException {
if (resource == null) { if (resource == null) {
return; return;
} }
@ -110,7 +108,7 @@ public class EpubWriter {
} }
private void writePackageDocument(EpubBook book, ZipOutputStream resultStream) private void writePackageDocument(Book book, ZipOutputStream resultStream)
throws IOException { throws IOException {
resultStream.putNextEntry(new ZipEntry("OEBPS/content.opf")); resultStream.putNextEntry(new ZipEntry("OEBPS/content.opf"));
XmlSerializer xmlSerializer = EpubProcessorSupport XmlSerializer xmlSerializer = EpubProcessorSupport
@ -124,8 +122,8 @@ public class EpubWriter {
/** /**
* Writes the META-INF/container.xml file. * Writes the META-INF/container.xml file.
* *
* @param resultStream * @param resultStream resultStream
* @throws IOException * @throws IOException IOException
*/ */
private void writeContainer(ZipOutputStream resultStream) throws IOException { private void writeContainer(ZipOutputStream resultStream) throws IOException {
resultStream.putNextEntry(new ZipEntry("META-INF/container.xml")); 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. * Stores the mimetype as an uncompressed file in the ZipOutputStream.
* *
* @param resultStream * @param resultStream resultStream
* @throws IOException * @throws IOException IOException
*/ */
private void writeMimeType(ZipOutputStream resultStream) throws IOException { private void writeMimeType(ZipOutputStream resultStream) throws IOException {
ZipEntry mimetypeZipEntry = new ZipEntry("mimetype"); ZipEntry mimetypeZipEntry = new ZipEntry("mimetype");
@ -175,11 +173,13 @@ public class EpubWriter {
return MediaTypes.NCX.getName(); return MediaTypes.NCX.getName();
} }
@SuppressWarnings("unused")
public BookProcessor getBookProcessor() { public BookProcessor getBookProcessor() {
return bookProcessor; return bookProcessor;
} }
@SuppressWarnings("unused")
public void setBookProcessor(BookProcessor bookProcessor) { public void setBookProcessor(BookProcessor bookProcessor) {
this.bookProcessor = bookProcessor; this.bookProcessor = bookProcessor;
} }

@ -2,7 +2,7 @@ package me.ag2s.epublib.epub;
import me.ag2s.epublib.domain.Resource; import me.ag2s.epublib.domain.Resource;
import java.io.OutputStream; import java.io.OutputStream;
@SuppressWarnings("unused")
public interface HtmlProcessor { public interface HtmlProcessor {
void processHtmlResource(Resource resource, OutputStream out); void processHtmlResource(Resource resource, OutputStream out);

@ -1,5 +0,0 @@
package me.ag2s.epublib.epub;
public class Main {
}

@ -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<TOCReference> 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<Identifier> identifiers,
String title, List<Author> 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<Identifier> identifiers, String title, List<Author> 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<TOCReference> 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);
}
}

@ -19,7 +19,7 @@ import java.util.zip.ZipOutputStream;
import me.ag2s.epublib.Constants; import me.ag2s.epublib.Constants;
import me.ag2s.epublib.domain.Author; 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.Identifier;
import me.ag2s.epublib.domain.MediaTypes; import me.ag2s.epublib.domain.MediaTypes;
import me.ag2s.epublib.domain.Resource; import me.ag2s.epublib.domain.Resource;
@ -33,15 +33,16 @@ import me.ag2s.epublib.util.StringUtil;
* *
* @author paul * @author paul
*/ */
public class NCXDocumentV2 extends NCXDocument{ public class NCXDocumentV2 {
public static final String NAMESPACE_NCX = "http://www.daisy.org/z3986/2005/ncx/"; 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 PREFIX_NCX = "ncx";
public static final String NCX_ITEM_ID = "ncx"; public static final String NCX_ITEM_ID = "ncx";
public static final String DEFAULT_NCX_HREF = "toc.ncx"; public static final String DEFAULT_NCX_HREF = "toc.ncx";
public static final String PREFIX_DTB = "dtb"; public static final String PREFIX_DTB = "dtb";
private static String TAG= NCXDocumentV2.class.getName(); private static final String TAG = NCXDocumentV2.class.getName();
private interface NCXTags { private interface NCXTags {
@ -75,34 +76,38 @@ public class NCXDocumentV2 extends NCXDocument{
} }
public static Resource read(EpubBook book, EpubReader epubReader) { @SuppressWarnings("unused")
public static Resource read(Book book, EpubReader epubReader) {
Resource ncxResource = null; Resource ncxResource = null;
if (book.getSpine().getTocResource() == null) { if (book.getSpine().getTocResource() == null) {
Log.e(TAG, "Book does not contain a table of contents file"); Log.e(TAG, "Book does not contain a table of contents file");
return ncxResource; return null;
} }
try { try {
ncxResource = book.getSpine().getTocResource(); ncxResource = book.getSpine().getTocResource();
if (ncxResource == null) { if (ncxResource == null) {
return ncxResource; return null;
} }
Log.d(TAG,ncxResource.getHref()); Log.d(TAG, ncxResource.getHref());
Document ncxDocument = ResourceUtil.getAsDocument(ncxResource); Document ncxDocument = ResourceUtil.getAsDocument(ncxResource);
Element navMapElement = DOMUtil Element navMapElement = DOMUtil
.getFirstElementByTagNameNS(ncxDocument.getDocumentElement(), .getFirstElementByTagNameNS(ncxDocument.getDocumentElement(),
NAMESPACE_NCX, NCXTags.navMap); NAMESPACE_NCX, NCXTags.navMap);
if (navMapElement == null) {
return null;
}
TableOfContents tableOfContents = new TableOfContents( TableOfContents tableOfContents = new TableOfContents(
readTOCReferences(navMapElement.getChildNodes(), book)); readTOCReferences(navMapElement.getChildNodes(), book));
book.setTableOfContents(tableOfContents); book.setTableOfContents(tableOfContents);
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG,e.getMessage(), e); Log.e(TAG, e.getMessage(), e);
} }
return ncxResource; return ncxResource;
} }
static List<TOCReference> readTOCReferences(NodeList navpoints, static List<TOCReference> readTOCReferences(NodeList navpoints,
EpubBook book) { Book book) {
if (navpoints == null) { if (navpoints == null) {
return new ArrayList<>(); return new ArrayList<>();
} }
@ -122,7 +127,7 @@ public class NCXDocumentV2 extends NCXDocument{
return result; return result;
} }
static TOCReference readTOCReference(Element navpointElement, EpubBook book) { static TOCReference readTOCReference(Element navpointElement, Book book) {
String label = readNavLabel(navpointElement); String label = readNavLabel(navpointElement);
//Log.d(TAG,"label:"+label); //Log.d(TAG,"label:"+label);
String tocResourceRoot = StringUtil String tocResourceRoot = StringUtil
@ -141,8 +146,11 @@ public class NCXDocumentV2 extends NCXDocument{
.substringAfter(reference, Constants.FRAGMENT_SEPARATOR_CHAR); .substringAfter(reference, Constants.FRAGMENT_SEPARATOR_CHAR);
Resource resource = book.getResources().getByHref(href); Resource resource = book.getResources().getByHref(href);
if (resource == null) { if (resource == null) {
Log.e(TAG,"Resource with href " + href + " in NCX document not found"); 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); TOCReference result = new TOCReference(label, resource, fragmentId);
List<TOCReference> childTOCReferences = readTOCReferences( List<TOCReference> childTOCReferences = readTOCReferences(
navpointElement.getChildNodes(), book); navpointElement.getChildNodes(), book);
@ -154,12 +162,15 @@ public class NCXDocumentV2 extends NCXDocument{
Element contentElement = DOMUtil Element contentElement = DOMUtil
.getFirstElementByTagNameNS(navpointElement, NAMESPACE_NCX, .getFirstElementByTagNameNS(navpointElement, NAMESPACE_NCX,
NCXTags.content); NCXTags.content);
if (contentElement == null) {
return null;
}
String result = DOMUtil String result = DOMUtil
.getAttribute(contentElement, NAMESPACE_NCX, NCXAttributes.src); .getAttribute(contentElement, NAMESPACE_NCX, NCXAttributes.src);
try { try {
result = URLDecoder.decode(result, Constants.CHARACTER_ENCODING); result = URLDecoder.decode(result, Constants.CHARACTER_ENCODING);
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
Log.e(TAG,e.getMessage()); Log.e(TAG, e.getMessage());
} }
return result; return result;
} }
@ -169,12 +180,12 @@ public class NCXDocumentV2 extends NCXDocument{
Element navLabel = DOMUtil Element navLabel = DOMUtil
.getFirstElementByTagNameNS(navpointElement, NAMESPACE_NCX, .getFirstElementByTagNameNS(navpointElement, NAMESPACE_NCX,
NCXTags.navLabel); NCXTags.navLabel);
assert navLabel != null;
return DOMUtil.getTextChildrenContent(DOMUtil return DOMUtil.getTextChildrenContent(DOMUtil
.getFirstElementByTagNameNS(navLabel, NAMESPACE_NCX, NCXTags.text)); .getFirstElementByTagNameNS(navLabel, NAMESPACE_NCX, NCXTags.text));
} }
@SuppressWarnings("unused")
public static void write(EpubWriter epubWriter, Book book,
public static void write(EpubWriter epubWriter, EpubBook book,
ZipOutputStream resultStream) throws IOException { ZipOutputStream resultStream) throws IOException {
resultStream resultStream
.putNextEntry(new ZipEntry(book.getSpine().getTocResource().getHref())); .putNextEntry(new ZipEntry(book.getSpine().getTocResource().getHref()));
@ -189,19 +200,17 @@ public class NCXDocumentV2 extends NCXDocument{
* *
* @param xmlSerializer the serializer used * @param xmlSerializer the serializer used
* @param book the book to serialize * @param book the book to serialize
* * @throws IOException IOException
* @1throws FactoryConfigurationError * @throws IllegalStateException IllegalStateException
* @throws IOException * @throws IllegalArgumentException IllegalArgumentException
* @throws IllegalStateException
* @throws IllegalArgumentException
*/ */
public static void write(XmlSerializer xmlSerializer, EpubBook book) public static void write(XmlSerializer xmlSerializer, Book book)
throws IllegalArgumentException, IllegalStateException, IOException { throws IllegalArgumentException, IllegalStateException, IOException {
write(xmlSerializer, book.getMetadata().getIdentifiers(), book.getTitle(), write(xmlSerializer, book.getMetadata().getIdentifiers(), book.getTitle(),
book.getMetadata().getAuthors(), book.getTableOfContents()); book.getMetadata().getAuthors(), book.getTableOfContents());
} }
public static Resource createNCXResource(EpubBook book) public static Resource createNCXResource(Book book)
throws IllegalArgumentException, IllegalStateException, IOException { throws IllegalArgumentException, IllegalStateException, IOException {
return createNCXResource(book.getMetadata().getIdentifiers(), return createNCXResource(book.getMetadata().getIdentifiers(),
book.getTitle(), book.getMetadata().getAuthors(), book.getTitle(), book.getMetadata().getAuthors(),
@ -214,9 +223,8 @@ public class NCXDocumentV2 extends NCXDocument{
ByteArrayOutputStream data = new ByteArrayOutputStream(); ByteArrayOutputStream data = new ByteArrayOutputStream();
XmlSerializer out = EpubProcessorSupport.createXmlSerializer(data); XmlSerializer out = EpubProcessorSupport.createXmlSerializer(data);
write(out, identifiers, title, authors, tableOfContents); write(out, identifiers, title, authors, tableOfContents);
Resource resource = new Resource(NCX_ITEM_ID, data.toByteArray(), return new Resource(NCX_ITEM_ID, data.toByteArray(),
DEFAULT_NCX_HREF, MediaTypes.NCX); DEFAULT_NCX_HREF, MediaTypes.NCX);
return resource;
} }
public static void write(XmlSerializer serializer, public static void write(XmlSerializer serializer,
@ -238,7 +246,7 @@ public class NCXDocumentV2 extends NCXDocument{
serializer); serializer);
} }
writeMetaElement("generator", Constants.EPUB4J_GENERATOR_NAME, serializer); writeMetaElement("generator", Constants.EPUB_GENERATOR_NAME, serializer);
writeMetaElement("depth", String.valueOf(tableOfContents.calculateDepth()), writeMetaElement("depth", String.valueOf(tableOfContents.calculateDepth()),
serializer); serializer);
writeMetaElement("totalPageCount", "0", serializer); writeMetaElement("totalPageCount", "0", serializer);
@ -325,7 +333,7 @@ public class NCXDocumentV2 extends NCXDocument{
tocReference.getCompleteHref()); tocReference.getCompleteHref());
serializer.endTag(NAMESPACE_NCX, NCXTags.content); serializer.endTag(NAMESPACE_NCX, NCXTags.content);
} }
@SuppressWarnings("unused")
private static void writeNavPointEnd(TOCReference tocReference, private static void writeNavPointEnd(TOCReference tocReference,
XmlSerializer serializer) XmlSerializer serializer)
throws IllegalArgumentException, IllegalStateException, IOException { throws IllegalArgumentException, IllegalStateException, IOException {

@ -6,79 +6,114 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import org.xmlpull.v1.XmlSerializer;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import me.ag2s.epublib.Constants; 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.Resource;
import me.ag2s.epublib.domain.TOCReference; import me.ag2s.epublib.domain.TOCReference;
import me.ag2s.epublib.domain.TableOfContents; import me.ag2s.epublib.domain.TableOfContents;
import me.ag2s.epublib.util.ResourceUtil; import me.ag2s.epublib.util.ResourceUtil;
import me.ag2s.epublib.util.StringUtil; import me.ag2s.epublib.util.StringUtil;
public class NCXDocumentV3 extends NCXDocument { /**
public static final String NAMESPACE_NCX = ""; * Writes the ncx document as defined by namespace http://www.daisy.org/z3986/2005/ncx/
public static final String PREFIX_NCX = "html"; *
public static final String NCX_ITEM_ID = "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 DEFAULT_NCX_HREF = "toc.xhtml";
public static final String PREFIX_DTB = "dtb"; public static final String V3_NCX_PROPERTIES = "nav";
private static String TAG = NCXDocumentV3.class.getName(); public static final MediaType V3_NCX_MEDIATYPE = MediaTypes.XHTML;
private interface NCXTags { private static final String TAG = NCXDocumentV3.class.getName();
//String nav="nav";
//String li="li"; private interface XHTMLTgs {
//String ncx = "ncx"; String html = "html";
String meta = "meta";
String navPoint = "li";
String navMap = "nav";
String navLabel = "a";
String content = "a";
String text = "text";
String docTitle = "docTitle";
String docAuthor = "docAuthor";
String head = "head"; 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 { private interface XHTMLAttributes {
String xmlns = "xmlns";
String src = "href"; String xmlns_epub = "xmlns:epub";
String name = "name"; String lang = "lang";
String content = "content"; String xml_lang = "xml:lang";
String rel = "rel";
String type = "type";
String epub_type = "epub:type";//nav的必须属性
String id = "id"; String id = "id";
String playOrder = "playOrder"; String role = "role";
String clazz = "class"; String href = "href";
String version = "version"; String http_equiv = "http-equiv";
} String content = "content";
private interface NCXAttributeValues { }
String chapter = "chapter"; private interface XHTMLAttributeValues {
String version = "2007"; 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; Resource ncxResource = null;
if (book.getSpine().getTocResource() == null) { if (book.getSpine().getTocResource() == null) {
Log.e(TAG, "Book does not contain a table of contents file"); Log.e(TAG, "Book does not contain a table of contents file");
return ncxResource; return null;
} }
try { try {
ncxResource = book.getSpine().getTocResource(); ncxResource = book.getSpine().getTocResource();
if (ncxResource == null) { if (ncxResource == null) {
return ncxResource; return null;
} }
//Log.d(TAG, ncxResource.getHref()); //Log.d(TAG, ncxResource.getHref());
Document ncxDocument = ResourceUtil.getAsDocument(ncxResource); Document ncxDocument = ResourceUtil.getAsDocument(ncxResource);
//Log.d(TAG, ncxDocument.getNodeName()); //Log.d(TAG, ncxDocument.getNodeName());
Element navMapElement = (Element) ncxDocument.getElementsByTagName("nav").item(0); Element navMapElement = (Element) ncxDocument.getElementsByTagName(XHTMLTgs.nav).item(0);
navMapElement = (Element) navMapElement.getElementsByTagName("ol").item(0); navMapElement = (Element) navMapElement.getElementsByTagName(XHTMLTgs.ol).item(0);
Log.d(TAG, navMapElement.getTagName()); Log.d(TAG, navMapElement.getTagName());
TableOfContents tableOfContents = new TableOfContents( TableOfContents tableOfContents = new TableOfContents(
@ -91,46 +126,42 @@ public class NCXDocumentV3 extends NCXDocument {
return ncxResource; return ncxResource;
} }
public static List<TOCReference> doToc(Node n, EpubBook book) { private static List<TOCReference> doToc(Node n, Book book) {
List<TOCReference> result = new ArrayList<>(); List<TOCReference> result = new ArrayList<>();
if (n == null || n.getNodeType() != Document.ELEMENT_NODE) { if (n == null || n.getNodeType() != Document.ELEMENT_NODE) {
return result; return result;
} else { } else {
Element el = (Element) n; Element el = (Element) n;
NodeList nodeList = el.getElementsByTagName("li"); NodeList nodeList = el.getElementsByTagName(XHTMLTgs.li);
for (int i = 0; i < nodeList.getLength(); i++) { for (int i = 0; i < nodeList.getLength(); i++) {
result.add(readTOCReference((Element) nodeList.item(i), book)); result.add(readTOCReference((Element) nodeList.item(i), book));
} }
} }
return result; return result;
} }
static List<TOCReference> readTOCReferences(NodeList navpoints, static List<TOCReference> readTOCReferences(NodeList navpoints,
EpubBook book) { Book book) {
if (navpoints == null) { if (navpoints == null) {
return new ArrayList<>(); return new ArrayList<>();
} }
//Log.d(TAG, "readTOCReferences:navpoints.getLength()" + navpoints.getLength()); //Log.d(TAG, "readTOCReferences:navpoints.getLength()" + navpoints.getLength());
List<TOCReference> result = new ArrayList<>(); List<TOCReference> result = new ArrayList<>(navpoints.getLength());
for (int i = 0; i < navpoints.getLength(); i++) { for (int i = 0; i < navpoints.getLength(); i++) {
Node node = navpoints.item(i); Node node = navpoints.item(i);
//如果该node是null,或者不是Element,跳出本次循环
if (node == null || node.getNodeType() != Document.ELEMENT_NODE) { if (node == null || node.getNodeType() != Document.ELEMENT_NODE) {
continue; continue;
} else { }
Element el = (Element) node; Element el = (Element) node;
if (el.getTagName().equals("li")) { //如果该Element的name为”li“,将其添加到目录结果
if (el.getTagName().equals(XHTMLTgs.li)) {
result.add(readTOCReference(el, book)); result.add(readTOCReference(el, book));
} }
//NodeList nodeList=el.getElementsByTagName("li");
//for (int i=0;i<nodeList.getLength();i++){
//result.add(readTOCReference((Element) nodeList.item(i),book));
// }
}
//result.addAll(doToc(node, book));
} }
@ -138,7 +169,8 @@ public class NCXDocumentV3 extends NCXDocument {
} }
static TOCReference readTOCReference(Element navpointElement, EpubBook book) { static TOCReference readTOCReference(Element navpointElement, Book book) {
//章节的名称
String label = readNavLabel(navpointElement); String label = readNavLabel(navpointElement);
//Log.d(TAG, "label:" + label); //Log.d(TAG, "label:" + label);
String tocResourceRoot = StringUtil String tocResourceRoot = StringUtil
@ -160,7 +192,13 @@ public class NCXDocumentV3 extends NCXDocument {
if (resource == null) { if (resource == null) {
Log.e(TAG, "Resource with href " + href + " in NCX document not found"); Log.e(TAG, "Resource with href " + href + " in NCX document not found");
} }
Log.v(TAG, "label:" + label);
Log.v(TAG, "href:" + href);
Log.v(TAG, "fragmentId:" + fragmentId);
//父级目录
TOCReference result = new TOCReference(label, resource, fragmentId); TOCReference result = new TOCReference(label, resource, fragmentId);
//解析子级目录
List<TOCReference> childTOCReferences = doToc(navpointElement, book); List<TOCReference> childTOCReferences = doToc(navpointElement, book);
//readTOCReferences( //readTOCReferences(
//navpointElement.getChildNodes(), book); //navpointElement.getChildNodes(), book);
@ -168,13 +206,24 @@ public class NCXDocumentV3 extends NCXDocument {
return result; return result;
} }
/**
* 获取目录节点的href
*
* @param navpointElement navpointElement
* @return String
*/
private static String readNavReference(Element navpointElement) { 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()); //Log.d(TAG, "readNavReference:" + navpointElement.getTagName());
Element contentElement = DOMUtil Element contentElement = DOMUtil
.getFirstElementByTagNameNS(navpointElement, NAMESPACE_NCX, .getFirstElementByTagNameNS(navpointElement, "", XHTMLTgs.a);
NCXDocumentV3.NCXTags.content); if (contentElement == null) {
return null;
}
String result = DOMUtil String result = DOMUtil
.getAttribute(contentElement, NAMESPACE_NCX, NCXDocumentV3.NCXAttributes.src); .getAttribute(contentElement, "", XHTMLAttributes.href);
try { try {
result = URLDecoder.decode(result, Constants.CHARACTER_ENCODING); result = URLDecoder.decode(result, Constants.CHARACTER_ENCODING);
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
@ -185,13 +234,218 @@ public class NCXDocumentV3 extends NCXDocument {
} }
/**
* 获取目录节点里面的章节名
*
* @param navpointElement navpointElement
* @return String
*/
private static String readNavLabel(Element navpointElement) { 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()); //Log.d(TAG, "readNavLabel:" + navpointElement.getTagName());
Element navLabel = DOMUtil String label;
.getFirstElementByTagNameNS(navpointElement, NAMESPACE_NCX, Element labelElement = DOMUtil.getFirstElementByTagNameNS(navpointElement, "", "a");
NCXDocumentV3.NCXTags.navLabel); assert labelElement != null;
return navLabel.getTextContent();//DOMUtil.getTextChildrenContent(DOMUtil label = labelElement.getTextContent();
//.getFirstElementByTagNameNS(navLabel, NAMESPACE_NCX, NCXDocumentV3.NCXTags.text)); 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<Identifier> identifiers,
String title, List<Author> 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<Identifier> identifiers, String title, List<Author> 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<TOCReference> 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);
} }

@ -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 NAMESPACE_DUBLIN_CORE = "http://purl.org/dc/elements/1.1/";
public static final String PREFIX_DUBLIN_CORE = "dc"; public static final String PREFIX_DUBLIN_CORE = "dc";
//public static final String PREFIX_OPF = "opf"; //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 = ""; 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 version="version";
public static final String dateFormat = "yyyy-MM-dd"; public static final String dateFormat = "yyyy-MM-dd";
@ -76,6 +79,10 @@ public class PackageDocumentBase {
String version = "version"; String version = "version";
String scheme = "scheme"; String scheme = "scheme";
String property = "property"; String property = "property";
//add for epub3
/**
* add for epub3
*/
String properties="properties"; String properties="properties";
} }

@ -2,21 +2,23 @@ package me.ag2s.epublib.epub;
import android.util.Log; import android.util.Log;
import me.ag2s.epublib.domain.Author; import org.w3c.dom.Document;
import me.ag2s.epublib.domain.Date; import org.w3c.dom.Element;
import me.ag2s.epublib.domain.Identifier; import org.w3c.dom.Node;
import me.ag2s.epublib.domain.Metadata; import org.w3c.dom.NodeList;
import me.ag2s.epublib.util.StringUtil;
//import io.documentnode.minilog.Logger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.xml.namespace.QName; import javax.xml.namespace.QName;
import org.w3c.dom.Document;
import org.w3c.dom.Element; import me.ag2s.epublib.domain.Author;
import org.w3c.dom.Node; import me.ag2s.epublib.domain.Date;
import org.w3c.dom.NodeList; import me.ag2s.epublib.domain.Identifier;
import me.ag2s.epublib.domain.Metadata;
import me.ag2s.epublib.util.StringUtil;
/** /**
* Reads the package document metadata. * Reads the package document metadata.
@ -28,7 +30,7 @@ import org.w3c.dom.NodeList;
// package // package
class PackageDocumentMetadataReader extends PackageDocumentBase { 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) { public static Metadata readMetadata(Document packageDocument) {
Metadata result = new Metadata(); 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: * consumes meta tags that have a property attribute as defined in the standard. For example:
* &lt;meta property="rendition:layout"&gt;pre-paginated&lt;/meta&gt; * &lt;meta property="rendition:layout"&gt;pre-paginated&lt;/meta&gt;
* @param metadataElement * @param metadataElement metadataElement
* @return * @return Map<QName, String>
*/ */
private static Map<QName, String> readOtherProperties( private static Map<QName, String> readOtherProperties(
Element metadataElement) { Element metadataElement) {
Map<QName, String> result = new HashMap<QName, String>(); Map<QName, String> result = new HashMap<>();
NodeList metaTags = metadataElement.getElementsByTagName(OPFTags.meta); NodeList metaTags = metadataElement.getElementsByTagName(OPFTags.meta);
for (int i = 0; i < metaTags.getLength(); i++) { 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: * consumes meta tags that have a property attribute as defined in the standard. For example:
* &lt;meta property="rendition:layout"&gt;pre-paginated&lt;/meta&gt; * &lt;meta property="rendition:layout"&gt;pre-paginated&lt;/meta&gt;
* @param metadataElement * @param metadataElement metadataElement
* @return * @return Map<String, String>
*/ */
private static Map<String, String> readMetaProperties( private static Map<String, String> readMetaProperties(
Element metadataElement) { Element metadataElement) {
Map<String, String> result = new HashMap<String, String>(); Map<String, String> result = new HashMap<>();
NodeList metaTags = metadataElement.getElementsByTagName(OPFTags.meta); NodeList metaTags = metadataElement.getElementsByTagName(OPFTags.meta);
for (int i = 0; i < metaTags.getLength(); i++) { for (int i = 0; i < metaTags.getLength(); i++) {
@ -126,9 +128,8 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
if (packageElement == null) { if (packageElement == null) {
return null; return null;
} }
String result = packageElement return packageElement
.getAttributeNS(NAMESPACE_OPF, OPFAttributes.uniqueIdentifier); .getAttributeNS(NAMESPACE_OPF, OPFAttributes.uniqueIdentifier);
return result;
} }
private static List<Author> readCreators(Element metadataElement) { private static List<Author> readCreators(Element metadataElement) {
@ -143,7 +144,7 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
Element metadataElement) { Element metadataElement) {
NodeList elements = metadataElement NodeList elements = metadataElement
.getElementsByTagNameNS(NAMESPACE_DUBLIN_CORE, authorTag); .getElementsByTagNameNS(NAMESPACE_DUBLIN_CORE, authorTag);
List<Author> result = new ArrayList<Author>(elements.getLength()); List<Author> result = new ArrayList<>(elements.getLength());
for (int i = 0; i < elements.getLength(); i++) { for (int i = 0; i < elements.getLength(); i++) {
Element authorElement = (Element) elements.item(i); Element authorElement = (Element) elements.item(i);
Author author = createAuthor(authorElement); Author author = createAuthor(authorElement);
@ -158,7 +159,7 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
private static List<Date> readDates(Element metadataElement) { private static List<Date> readDates(Element metadataElement) {
NodeList elements = metadataElement NodeList elements = metadataElement
.getElementsByTagNameNS(NAMESPACE_DUBLIN_CORE, DCTags.date); .getElementsByTagNameNS(NAMESPACE_DUBLIN_CORE, DCTags.date);
List<Date> result = new ArrayList<Date>(elements.getLength()); List<Date> result = new ArrayList<>(elements.getLength());
for (int i = 0; i < elements.getLength(); i++) { for (int i = 0; i < elements.getLength(); i++) {
Element dateElement = (Element) elements.item(i); Element dateElement = (Element) elements.item(i);
Date date; Date date;
@ -198,10 +199,10 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
.getElementsByTagNameNS(NAMESPACE_DUBLIN_CORE, DCTags.identifier); .getElementsByTagNameNS(NAMESPACE_DUBLIN_CORE, DCTags.identifier);
if (identifierElements.getLength() == 0) { if (identifierElements.getLength() == 0) {
Log.e(TAG,"Package does not contain element " + DCTags.identifier); Log.e(TAG,"Package does not contain element " + DCTags.identifier);
return new ArrayList<Identifier>(); return new ArrayList<>();
} }
String bookIdId = getBookIdId(metadataElement.getOwnerDocument()); String bookIdId = getBookIdId(metadataElement.getOwnerDocument());
List<Identifier> result = new ArrayList<Identifier>( List<Identifier> result = new ArrayList<>(
identifierElements.getLength()); identifierElements.getLength());
for (int i = 0; i < identifierElements.getLength(); i++) { for (int i = 0; i < identifierElements.getLength(); i++) {
Element identifierElement = (Element) identifierElements.item(i); Element identifierElement = (Element) identifierElements.item(i);

@ -1,32 +1,29 @@
package me.ag2s.epublib.epub; 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.Constants;
import me.ag2s.epublib.domain.Author; import me.ag2s.epublib.domain.Author;
import me.ag2s.epublib.domain.Book;
import me.ag2s.epublib.domain.Date; import me.ag2s.epublib.domain.Date;
import me.ag2s.epublib.domain.EpubBook;
import me.ag2s.epublib.domain.Identifier; import me.ag2s.epublib.domain.Identifier;
import me.ag2s.epublib.util.StringUtil; 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 { public class PackageDocumentMetadataWriter extends PackageDocumentBase {
/** /**
* Writes the book's metadata. * Writes the book's metadata.
* *
* @param book * @param book book
* @param serializer * @param serializer serializer
* @throws IOException * @throws IOException IOException
* @throws IllegalStateException * @throws IllegalStateException IllegalStateException
* @throws IllegalArgumentException * @throws IllegalArgumentException IllegalArgumentException
*/ */
public static void writeMetaData(EpubBook book, XmlSerializer serializer) public static void writeMetaData(Book book, XmlSerializer serializer)
throws IllegalArgumentException, IllegalStateException, IOException { throws IllegalArgumentException, IllegalStateException, IOException {
serializer.startTag(NAMESPACE_OPF, OPFTags.metadata); serializer.startTag(NAMESPACE_OPF, OPFTags.metadata);
serializer.setPrefix(PREFIX_DUBLIN_CORE, NAMESPACE_DUBLIN_CORE); serializer.setPrefix(PREFIX_DUBLIN_CORE, NAMESPACE_DUBLIN_CORE);
@ -117,7 +114,7 @@ public class PackageDocumentMetadataWriter extends PackageDocumentBase {
OPFValues.generator); OPFValues.generator);
serializer serializer
.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.content, .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.meta);
serializer.endTag(NAMESPACE_OPF, OPFTags.metadata); 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. * 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. * If no identifier has bookId == true then the first bookId identifier is written as the primary.
* *
* @param identifiers * @param identifiers identifiers
* @param serializer * @param serializer serializer
* @throws IOException * @throws IllegalStateException e
* @throws IllegalStateException * @throws IllegalArgumentException e
* @throws IllegalArgumentException
* @ * @
*/ */
private static void writeIdentifiers(List<Identifier> identifiers, private static void writeIdentifiers(List<Identifier> identifiers,

@ -19,10 +19,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
import me.ag2s.epublib.Constants; 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.Guide;
import me.ag2s.epublib.domain.GuideReference; import me.ag2s.epublib.domain.GuideReference;
import me.ag2s.epublib.domain.MediaType; 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.ResourceUtil;
import me.ag2s.epublib.util.StringUtil; 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 * 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 { 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", private static final String[] POSSIBLE_NCX_ITEM_IDS = new String[]{"toc",
"ncx", "ncxtoc","htmltoc"}; "ncx", "ncxtoc","htmltoc"};
public static void read( public static void read(
Resource packageResource, EpubReader epubReader, EpubBook book, Resource packageResource, EpubReader epubReader, Book book,
Resources resources) Resources resources)
throws UnsupportedEncodingException, SAXException, IOException, ParserConfigurationException { throws SAXException, IOException {
Document packageDocument = ResourceUtil.getAsDocument(packageResource); Document packageDocument = ResourceUtil.getAsDocument(packageResource);
String packageHref = packageResource.getHref(); String packageHref = packageResource.getHref();
resources = fixHrefs(packageHref, resources); resources = fixHrefs(packageHref, resources);
readGuide(packageDocument, epubReader, book, resources); readGuide(packageDocument, epubReader, book, resources);
// Books sometimes use non-identifier ids. We map these here to legal ones // Books sometimes use non-identifier ids. We map these here to legal ones
Map<String, String> idMapping = new HashMap<String, String>(); Map<String, String> idMapping = new HashMap<>();
String version=DOMUtil.getAttribute(packageDocument.getDocumentElement(),PREFIX_OPF,PackageDocumentBase.version); String version=DOMUtil.getAttribute(packageDocument.getDocumentElement(),PREFIX_OPF,PackageDocumentBase.version);
resources = readManifest(packageDocument, packageHref, epubReader, resources = readManifest(packageDocument, packageHref, epubReader,
@ -90,13 +86,14 @@ public class PackageDocumentReader extends PackageDocumentBase {
/** /**
* Reads the manifest containing the resource ids, hrefs and mediatypes. * Reads the manifest containing the resource ids, hrefs and mediatypes.
* *
* @param packageDocument * @param packageDocument e
* @param packageHref * @param packageHref e
* @param epubReader * @param epubReader e
* @param resources * @param resources e
* @param idMapping * @param idMapping e
* @return a Map with resources, with their id's as key. * @return a Map with resources, with their id's as key.
*/ */
@SuppressWarnings("unused")
private static Resources readManifest(Document packageDocument, private static Resources readManifest(Document packageDocument,
String packageHref, String packageHref,
EpubReader epubReader, Resources resources, EpubReader epubReader, Resources resources,
@ -118,7 +115,7 @@ public class PackageDocumentReader extends PackageDocumentBase {
.getAttribute(itemElement, NAMESPACE_OPF, OPFAttributes.id); .getAttribute(itemElement, NAMESPACE_OPF, OPFAttributes.id);
String href = DOMUtil String href = DOMUtil
.getAttribute(itemElement, NAMESPACE_OPF, OPFAttributes.href); .getAttribute(itemElement, NAMESPACE_OPF, OPFAttributes.href);
String properties=DOMUtil.getAttribute(itemElement,NAMESPACE_OPF,OPFAttributes.properties);
try { try {
href = URLDecoder.decode(href, Constants.CHARACTER_ENCODING); href = URLDecoder.decode(href, Constants.CHARACTER_ENCODING);
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
@ -132,7 +129,10 @@ public class PackageDocumentReader extends PackageDocumentBase {
continue; continue;
} }
resource.setId(id); resource.setId(id);
//for epub3
String properties=DOMUtil.getAttribute(itemElement,NAMESPACE_OPF,OPFAttributes.properties);
resource.setProperties(properties); resource.setProperties(properties);
MediaType mediaType = MediaTypes.getMediaTypeByName(mediaTypeName); MediaType mediaType = MediaTypes.getMediaTypeByName(mediaTypeName);
if (mediaType != null) { if (mediaType != null) {
resource.setMediaType(mediaType); resource.setMediaType(mediaType);
@ -148,13 +148,14 @@ public class PackageDocumentReader extends PackageDocumentBase {
* Reads the book's guide. * Reads the book's guide.
* Here some more attempts are made at finding the cover page. * Here some more attempts are made at finding the cover page.
* *
* @param packageDocument * @param packageDocument r
* @param epubReader * @param epubReader r
* @param book * @param book r
* @param resources * @param resources g
*/ */
@SuppressWarnings("unused")
private static void readGuide(Document packageDocument, private static void readGuide(Document packageDocument,
EpubReader epubReader, EpubBook book, Resources resources) { EpubReader epubReader, Book book, Resources resources) {
Element guideElement = DOMUtil Element guideElement = DOMUtil
.getFirstElementByTagNameNS(packageDocument.getDocumentElement(), .getFirstElementByTagNameNS(packageDocument.getDocumentElement(),
NAMESPACE_OPF, OPFTags.guide); NAMESPACE_OPF, OPFTags.guide);
@ -204,8 +205,8 @@ public class PackageDocumentReader extends PackageDocumentBase {
* Example: * Example:
* If the packageHref is "OEBPS/content.opf" then a resource href like "OEBPS/foo/bar.html" will be turned into "foo/bar.html" * 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 packageHref f
* @param resourcesByHref * @param resourcesByHref g
* @return The stripped package href * @return The stripped package href
*/ */
static Resources fixHrefs(String packageHref, 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. * Reads the document's spine, containing all sections in reading order.
* *
* @param packageDocument * @param packageDocument b
* @param resources * @param resources b
* @param idMapping * @param idMapping b
* @return the document's spine, containing all sections in reading order. * @return the document's spine, containing all sections in reading order.
*/ */
private static Spine readSpine(Document packageDocument, Resources resources, private static Spine readSpine(Document packageDocument, Resources resources,
@ -251,7 +252,7 @@ public class PackageDocumentReader extends PackageDocumentBase {
.setTocResource(findTableOfContentsResource(tocResourceId, resources)); .setTocResource(findTableOfContentsResource(tocResourceId, resources));
NodeList spineNodes = packageDocument NodeList spineNodes = packageDocument
.getElementsByTagNameNS(NAMESPACE_OPF, OPFTags.itemref); .getElementsByTagNameNS(NAMESPACE_OPF, OPFTags.itemref);
List<SpineReference> spineReferences = new ArrayList<SpineReference>( List<SpineReference> spineReferences = new ArrayList<>(
spineNodes.getLength()); spineNodes.getLength());
for (int i = 0; i < spineNodes.getLength(); i++) { for (int i = 0; i < spineNodes.getLength(); i++) {
Element spineItem = (Element) spineNodes.item(i); Element spineItem = (Element) spineNodes.item(i);
@ -267,7 +268,7 @@ public class PackageDocumentReader extends PackageDocumentBase {
} }
Resource resource = resources.getByIdOrHref(id); Resource resource = resources.getByIdOrHref(id);
if (resource == null) { if (resource == null) {
Log.e(TAG,"resource with id \'" + id + "\' not found"); Log.e(TAG, "resource with id '" + id + "' not found");
continue; continue;
} }
@ -286,13 +287,12 @@ public class PackageDocumentReader extends PackageDocumentBase {
* Creates a spine out of all resources in the resources. * Creates a spine out of all resources in the resources.
* The generated spine consists of all XHTML pages in order of their href. * 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. * @return a spine created out of all resources in the resources.
*/ */
private static Spine generateSpineFromResources(Resources resources) { private static Spine generateSpineFromResources(Resources resources) {
Spine result = new Spine(); Spine result = new Spine();
List<String> resourceHrefs = new ArrayList<String>(); List<String> resourceHrefs = new ArrayList<>(resources.getAllHrefs());
resourceHrefs.addAll(resources.getAllHrefs());
Collections.sort(resourceHrefs, String.CASE_INSENSITIVE_ORDER); Collections.sort(resourceHrefs, String.CASE_INSENSITIVE_ORDER);
for (String resourceHref : resourceHrefs) { for (String resourceHref : resourceHrefs) {
Resource resource = resources.getByHref(resourceHref); 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. * 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. * 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 tocResourceId g
* @param resources * @param resources g
* @return the Resource containing the table of contents * @return the Resource containing the table of contents
*/ */
static Resource findTableOfContentsResource(String tocResourceId, static Resource findTableOfContentsResource(String tocResourceId,
@ -331,13 +331,13 @@ public class PackageDocumentReader extends PackageDocumentBase {
tocResource = resources.findFirstResourceByMediaType(MediaTypes.NCX); tocResource = resources.findFirstResourceByMediaType(MediaTypes.NCX);
if (tocResource == null) { if (tocResource == null) {
for (int i = 0; i < POSSIBLE_NCX_ITEM_IDS.length; i++) { for (String possibleNcxItemId : POSSIBLE_NCX_ITEM_IDS) {
tocResource = resources.getByIdOrHref(POSSIBLE_NCX_ITEM_IDS[i]); tocResource = resources.getByIdOrHref(possibleNcxItemId);
if (tocResource != null) { if (tocResource != null) {
break; break;
} }
tocResource = resources tocResource = resources
.getByIdOrHref(POSSIBLE_NCX_ITEM_IDS[i].toUpperCase()); .getByIdOrHref(possibleNcxItemId.toUpperCase());
if (tocResource != null) { if (tocResource != null) {
break; 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. * Find all resources that have something to do with the coverpage and the cover image.
* Search the meta tags and the guide references * 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. * @return all resources that have something to do with the coverpage and the cover image.
*/ */
// package // package
static Set<String> findCoverHrefs(Document packageDocument) { static Set<String> findCoverHrefs(Document packageDocument) {
Set<String> result = new HashSet<String>(); Set<String> result = new HashSet<>();
// try and find a meta tag with name = 'cover' and a non-blank id // try and find a meta tag with name = 'cover' and a non-blank id
String coverResourceId = DOMUtil 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. * Finds the cover resource in the packageDocument and adds it to the book if found.
* Keeps the cover resource in the resources map * Keeps the cover resource in the resources map
* * @param packageDocument s
* @param packageDocument * @param book x
* @param book
* @1param resources
*/ */
private static void readCover(Document packageDocument, EpubBook book) { private static void readCover(Document packageDocument, Book book) {
Collection<String> coverHrefs = findCoverHrefs(packageDocument); Collection<String> coverHrefs = findCoverHrefs(packageDocument);
for (String coverHref : coverHrefs) { for (String coverHref : coverHrefs) {
Resource resource = book.getResources().getByHref(coverHref); Resource resource = book.getResources().getByHref(coverHref);
if (resource == null) { if (resource == null) {
Log.e(TAG, "Cover resource " + coverHref + " not found"); Log.e(TAG,"Cover resource " + coverHref + " not found");
continue; continue;
} }
if (resource.getMediaType() == MediaTypes.XHTML) { if (resource.getMediaType() == MediaTypes.XHTML) {

@ -2,16 +2,8 @@ package me.ag2s.epublib.epub;
import android.util.Log; 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.Constants;
import me.ag2s.epublib.domain.EpubBook; import me.ag2s.epublib.domain.Book;
import me.ag2s.epublib.domain.Guide; import me.ag2s.epublib.domain.Guide;
import me.ag2s.epublib.domain.GuideReference; import me.ag2s.epublib.domain.GuideReference;
import me.ag2s.epublib.domain.MediaTypes; import me.ag2s.epublib.domain.MediaTypes;
@ -20,22 +12,24 @@ import me.ag2s.epublib.domain.Spine;
import me.ag2s.epublib.domain.SpineReference; import me.ag2s.epublib.domain.SpineReference;
import me.ag2s.epublib.util.StringUtil; import me.ag2s.epublib.util.StringUtil;
//import io.documentnode.minilog.Logger; import java.io.IOException;
//import javax.xml.stream.XMLStreamException; 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 * Writes the opf package document as defined by namespace http://www.idpf.org/2007/opf
* *
* @author paul * @author paul
*
*/ */
public class PackageDocumentWriter extends PackageDocumentBase { public class PackageDocumentWriter extends PackageDocumentBase {
//private static final Logger log = Logger.create(PackageDocumentWriter.class); private static final String TAG = PackageDocumentWriter.class.getName();
private static String TAG= PackageDocumentWriter.class.getName();
public static void write(EpubWriter epubWriter, XmlSerializer serializer, public static void write(EpubWriter epubWriter, XmlSerializer serializer,
EpubBook book) throws IOException { Book book) {
try { try {
serializer.startDocument(Constants.CHARACTER_ENCODING, false); serializer.startDocument(Constants.CHARACTER_ENCODING, false);
serializer.setPrefix(PREFIX_OPF, NAMESPACE_OPF); serializer.setPrefix(PREFIX_OPF, NAMESPACE_OPF);
@ -43,7 +37,7 @@ public class PackageDocumentWriter extends PackageDocumentBase {
serializer.startTag(NAMESPACE_OPF, OPFTags.packageTag); serializer.startTag(NAMESPACE_OPF, OPFTags.packageTag);
serializer serializer
.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.version, .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.version,
"2.0"); book.getVersion());
serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX,
OPFAttributes.uniqueIdentifier, BOOK_ID_ID); OPFAttributes.uniqueIdentifier, BOOK_ID_ID);
@ -57,7 +51,6 @@ public class PackageDocumentWriter extends PackageDocumentBase {
serializer.endDocument(); serializer.endDocument();
serializer.flush(); serializer.flush();
} catch (IOException e) { } catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} }
} }
@ -65,15 +58,15 @@ public class PackageDocumentWriter extends PackageDocumentBase {
/** /**
* Writes the package's spine. * Writes the package's spine.
* *
* @param book * @param book e
* @param epubWriter * @param epubWriter g
* @param serializer * @param serializer g
* @throws IOException * @throws IOException g
* @throws IllegalStateException * @throws IllegalStateException g
* @throws IllegalArgumentException * @throws IllegalArgumentException 1@throws XMLStreamException
* 1@throws XMLStreamException
*/ */
private static void writeSpine(EpubBook book, EpubWriter epubWriter, @SuppressWarnings("unused")
private static void writeSpine(Book book, EpubWriter epubWriter,
XmlSerializer serializer) XmlSerializer serializer)
throws IllegalArgumentException, IllegalStateException, IOException { throws IllegalArgumentException, IllegalStateException, IOException {
serializer.startTag(NAMESPACE_OPF, OPFTags.spine); serializer.startTag(NAMESPACE_OPF, OPFTags.spine);
@ -100,19 +93,26 @@ public class PackageDocumentWriter extends PackageDocumentBase {
} }
private static void writeManifest(EpubBook book, EpubWriter epubWriter, private static void writeManifest(Book book, EpubWriter epubWriter,
XmlSerializer serializer) XmlSerializer serializer)
throws IllegalArgumentException, IllegalStateException, IOException { throws IllegalArgumentException, IllegalStateException, IOException {
serializer.startTag(NAMESPACE_OPF, OPFTags.manifest); serializer.startTag(NAMESPACE_OPF, OPFTags.manifest);
serializer.startTag(NAMESPACE_OPF, OPFTags.item); serializer.startTag(NAMESPACE_OPF, OPFTags.item);
//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, serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.id,
epubWriter.getNcxId()); epubWriter.getNcxId());
serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.href, serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.href, epubWriter.getNcxHref());
epubWriter.getNcxHref()); serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.media_type, epubWriter.getNcxMediaType());
serializer }
.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.media_type,
epubWriter.getNcxMediaType());
serializer.endTag(NAMESPACE_OPF, OPFTags.item); serializer.endTag(NAMESPACE_OPF, OPFTags.item);
// writeCoverResources(book, serializer); // writeCoverResources(book, serializer);
@ -124,29 +124,23 @@ public class PackageDocumentWriter extends PackageDocumentBase {
serializer.endTag(NAMESPACE_OPF, OPFTags.manifest); serializer.endTag(NAMESPACE_OPF, OPFTags.manifest);
} }
private static List<Resource> getAllResourcesSortById(EpubBook book) { private static List<Resource> getAllResourcesSortById(Book book) {
List<Resource> allResources = new ArrayList<Resource>( List<Resource> allResources = new ArrayList<>(
book.getResources().getAll()); book.getResources().getAll());
Collections.sort(allResources, new Comparator<Resource>() { Collections.sort(allResources, (resource1, resource2) -> resource1.getId().compareToIgnoreCase(resource2.getId()));
@Override
public int compare(Resource resource1, Resource resource2) {
return resource1.getId().compareToIgnoreCase(resource2.getId());
}
});
return allResources; return allResources;
} }
/** /**
* Writes a resources as an item element * Writes a resources as an item element
* *
* @param resource * @param resource g
* @param serializer * @param serializer g
* @throws IOException * @throws IOException g
* @throws IllegalStateException * @throws IllegalStateException g
* @throws IllegalArgumentException 1@throws XMLStreamException * @throws IllegalArgumentException 1@throws XMLStreamException
*/ */
private static void writeItem(EpubBook book, Resource resource, private static void writeItem(Book book, Resource resource,
XmlSerializer serializer) XmlSerializer serializer)
throws IllegalArgumentException, IllegalStateException, IOException { throws IllegalArgumentException, IllegalStateException, IOException {
if (resource == null || if (resource == null ||
@ -164,14 +158,14 @@ public class PackageDocumentWriter extends PackageDocumentBase {
if (StringUtil.isBlank(resource.getHref())) { if (StringUtil.isBlank(resource.getHref())) {
// log.error("resource href must not be empty (id: " + resource.getId() // log.error("resource href must not be empty (id: " + resource.getId()
// + ", mediatype:" + resource.getMediaType() + ")"); // + ", mediatype:" + resource.getMediaType() + ")");
Log.e(TAG,"resource href must not be empty (id: " + resource.getId() Log.e(TAG, "resource href must not be empty (id: " + resource.getId()
+ ", mediatype:" + resource.getMediaType() + ")"); + ", mediatype:" + resource.getMediaType() + ")");
return; return;
} }
if (resource.getMediaType() == null) { if (resource.getMediaType() == null) {
// log.error("resource mediatype must not be empty (id: " + resource.getId() // log.error("resource mediatype must not be empty (id: " + resource.getId()
// + ", href:" + resource.getHref() + ")"); // + ", href:" + resource.getHref() + ")");
Log.e(TAG,"resource mediatype must not be empty (id: " + resource.getId() Log.e(TAG, "resource mediatype must not be empty (id: " + resource.getId()
+ ", href:" + resource.getHref() + ")"); + ", href:" + resource.getHref() + ")");
return; return;
} }
@ -188,10 +182,12 @@ public class PackageDocumentWriter extends PackageDocumentBase {
/** /**
* List all spine references * List all spine references
* @throws IOException *
* @throws IllegalStateException * @throws IOException f
* @throws IllegalArgumentException * @throws IllegalStateException f
* @throws IllegalArgumentException f
*/ */
@SuppressWarnings("unused")
private static void writeSpineItems(Spine spine, XmlSerializer serializer) private static void writeSpineItems(Spine spine, XmlSerializer serializer)
throws IllegalArgumentException, IllegalStateException, IOException { throws IllegalArgumentException, IllegalStateException, IOException {
for (SpineReference spineReference : spine.getSpineReferences()) { for (SpineReference spineReference : spine.getSpineReferences()) {
@ -208,7 +204,7 @@ public class PackageDocumentWriter extends PackageDocumentBase {
} }
} }
private static void writeGuide(EpubBook book, EpubWriter epubWriter, private static void writeGuide(Book book, EpubWriter epubWriter,
XmlSerializer serializer) XmlSerializer serializer)
throws IllegalArgumentException, IllegalStateException, IOException { throws IllegalArgumentException, IllegalStateException, IOException {
serializer.startTag(NAMESPACE_OPF, OPFTags.guide); serializer.startTag(NAMESPACE_OPF, OPFTags.guide);
@ -220,6 +216,7 @@ public class PackageDocumentWriter extends PackageDocumentBase {
serializer.endTag(NAMESPACE_OPF, OPFTags.guide); serializer.endTag(NAMESPACE_OPF, OPFTags.guide);
} }
@SuppressWarnings("unused")
private static void ensureCoverPageGuideReferenceWritten(Guide guide, private static void ensureCoverPageGuideReferenceWritten(Guide guide,
EpubWriter epubWriter, XmlSerializer serializer) EpubWriter epubWriter, XmlSerializer serializer)
throws IllegalArgumentException, IllegalStateException, IOException { throws IllegalArgumentException, IllegalStateException, IOException {

@ -11,9 +11,10 @@ import me.ag2s.epublib.domain.Resource;
import me.ag2s.epublib.domain.Resources; import me.ag2s.epublib.domain.Resources;
import me.ag2s.epublib.util.CollectionUtil; import me.ag2s.epublib.util.CollectionUtil;
import me.ag2s.epublib.util.ResourceUtil; import me.ag2s.epublib.util.ResourceUtil;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List; import java.util.List;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
@ -26,25 +27,24 @@ import java.util.zip.ZipInputStream;
* Loads Resources from inputStreams, ZipFiles, etc * Loads Resources from inputStreams, ZipFiles, etc
* *
* @author paul * @author paul
*
*/ */
public class ResourcesLoader { public class ResourcesLoader {
private static String TAG=ResourceUtil.class.getName(); private static final String TAG = ResourcesLoader.class.getName();
/** /**
* Loads the entries of the zipFile as resources. * Loads the entries of the zipFile as resources.
* * <p>
* The MediaTypes that are in the lazyLoadedTypes will not get their * The MediaTypes that are in the lazyLoadedTypes will not get their
* contents loaded, but are stored as references to entries into the * contents loaded, but are stored as references to entries into the
* ZipFile and are loaded on demand by the Resource system. * ZipFile and are loaded on demand by the Resource system.
* *
* @param zipFile * @param zipFile import epub zipfile
* @param defaultHtmlEncoding * @param defaultHtmlEncoding epub xhtml default encoding
* @param lazyLoadedTypes * @param lazyLoadedTypes lazyLoadedTypes
* @return * @return Resources
* @throws IOException * @throws IOException IOException
*/ */
public static Resources loadResources(ZipFile zipFile, public static Resources loadResources(ZipFile zipFile,
String defaultHtmlEncoding, String defaultHtmlEncoding,
@ -87,8 +87,8 @@ public class ResourcesLoader {
* Whether the given href will load a mediaType that is in the * Whether the given href will load a mediaType that is in the
* collection of lazilyLoadedMediaTypes. * collection of lazilyLoadedMediaTypes.
* *
* @param href * @param href href
* @param lazilyLoadedMediaTypes * @param lazilyLoadedMediaTypes lazilyLoadedMediaTypes
* @return Whether the given href will load a mediaType that is * @return Whether the given href will load a mediaType that is
* in the collection of lazilyLoadedMediaTypes. * in the collection of lazilyLoadedMediaTypes.
*/ */
@ -103,15 +103,15 @@ public class ResourcesLoader {
/** /**
* Loads all entries from the ZipInputStream as Resources. * Loads all entries from the ZipInputStream as Resources.
* * <p>
* Loads the contents of all ZipEntries into memory. * Loads the contents of all ZipEntries into memory.
* Is fast, but may lead to memory problems when reading large books * Is fast, but may lead to memory problems when reading large books
* on devices with small amounts of memory. * on devices with small amounts of memory.
* *
* @param zipInputStream * @param zipInputStream zipInputStream
* @param defaultHtmlEncoding * @param defaultHtmlEncoding defaultHtmlEncoding
* @return * @return Resources
* @throws IOException * @throws IOException IOException
*/ */
public static Resources loadResources(ZipInputStream zipInputStream, public static Resources loadResources(ZipInputStream zipInputStream,
String defaultHtmlEncoding) throws IOException { String defaultHtmlEncoding) throws IOException {
@ -145,7 +145,7 @@ public class ResourcesLoader {
//when reading a file that is not a real zip archive or a zero length file, zipInputStream.getNextEntry() //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 //throws an exception and does not advance, so loadResources enters an infinite loop
//log.error("Invalid or damaged zip file.", e); //log.error("Invalid or damaged zip file.", e);
Log.e(TAG,"",e); Log.e(TAG, e.getLocalizedMessage());
try { try {
zipInputStream.closeEntry(); zipInputStream.closeEntry();
} catch (Exception ignored) { } catch (Exception ignored) {
@ -156,18 +156,18 @@ public class ResourcesLoader {
/** /**
* Loads all entries from the ZipInputStream as Resources. * Loads all entries from the ZipInputStream as Resources.
* * <p>
* Loads the contents of all ZipEntries into memory. * Loads the contents of all ZipEntries into memory.
* Is fast, but may lead to memory problems when reading large books * Is fast, but may lead to memory problems when reading large books
* on devices with small amounts of memory. * on devices with small amounts of memory.
* *
* @param zipFile * @param zipFile zipFile
* @param defaultHtmlEncoding * @param defaultHtmlEncoding defaultHtmlEncoding
* @return * @return Resources
* @throws IOException * @throws IOException IOException
*/ */
public static Resources loadResources(ZipFile zipFile, public static Resources loadResources(ZipFile zipFile, String defaultHtmlEncoding) throws IOException {
String defaultHtmlEncoding) throws IOException { List<MediaType> ls = new ArrayList<>();
return loadResources(zipFile, defaultHtmlEncoding, Collections.emptyList()); return loadResources(zipFile, defaultHtmlEncoding, ls);
} }
} }

@ -15,7 +15,7 @@ public class CollectionUtil {
*/ */
private static class IteratorEnumerationAdapter<T> implements Enumeration<T> { private static class IteratorEnumerationAdapter<T> implements Enumeration<T> {
private Iterator<T> iterator; private final Iterator<T> iterator;
public IteratorEnumerationAdapter(Iterator<T> iter) { public IteratorEnumerationAdapter(Iterator<T> iter) {
this.iterator = iter; this.iterator = iter;
@ -34,21 +34,22 @@ public class CollectionUtil {
/** /**
* Creates an Enumeration out of the given Iterator. * Creates an Enumeration out of the given Iterator.
* @param <T> * @param <T> g
* @param it * @param it g
* @return an Enumeration created out of the given Iterator. * @return an Enumeration created out of the given Iterator.
*/ */
@SuppressWarnings("unused")
public static <T> Enumeration<T> createEnumerationFromIterator( public static <T> Enumeration<T> createEnumerationFromIterator(
Iterator<T> it) { Iterator<T> it) {
return new IteratorEnumerationAdapter<T>(it); return new IteratorEnumerationAdapter<>(it);
} }
/** /**
* Returns the first element of the list, null if the list is null or empty. * Returns the first element of the list, null if the list is null or empty.
* *
* @param <T> * @param <T> f
* @param list * @param list f
* @return the first element of the list, null if the list is null or empty. * @return the first element of the list, null if the list is null or empty.
*/ */
public static <T> T first(List<T> list) { public static <T> T first(List<T> list) {
@ -61,7 +62,7 @@ public class CollectionUtil {
/** /**
* Whether the given collection is null or has no elements. * 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. * @return Whether the given collection is null or has no elements.
*/ */
public static boolean isEmpty(Collection<?> collection) { public static boolean isEmpty(Collection<?> collection) {

@ -23,10 +23,10 @@ public class IOUtil {
/** /**
* Gets the contents of the Reader as a byte[], with the given character encoding. * Gets the contents of the Reader as a byte[], with the given character encoding.
* *
* @param in * @param in g
* @param encoding * @param encoding g
* @return the contents of the Reader as a byte[], with the given character encoding. * @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) public static byte[] toByteArray(Reader in, String encoding)
throws IOException { throws IOException {
@ -39,9 +39,9 @@ public class IOUtil {
/** /**
* Returns the contents of the InputStream as a byte[] * Returns the contents of the InputStream as a byte[]
* *
* @param in * @param in f
* @return the contents of the InputStream as a byte[] * @return the contents of the InputStream as a byte[]
* @throws IOException * @throws IOException f
*/ */
public static byte[] toByteArray(InputStream in) throws IOException { public static byte[] toByteArray(InputStream in) throws IOException {
ByteArrayOutputStream result = new ByteArrayOutputStream(); ByteArrayOutputStream result = new ByteArrayOutputStream();
@ -59,7 +59,7 @@ public class IOUtil {
* @param in the stream to read data from * @param in the stream to read data from
* @param size the size of the array to create * @param size the size of the array to create
* @return the array, or null * @return the array, or null
* @throws IOException * @throws IOException f
*/ */
public static byte[] toByteArray(InputStream in, int size) public static byte[] toByteArray(InputStream in, int size)
throws IOException { throws IOException {
@ -89,8 +89,8 @@ public class IOUtil {
* (nrRead + totalNrRead) &lt; Integer.MAX_VALUE then nrRead + totalNrRead * (nrRead + totalNrRead) &lt; Integer.MAX_VALUE then nrRead + totalNrRead
* is returned, -1 otherwise. * is returned, -1 otherwise.
* *
* @param nrRead * @param nrRead f
* @param totalNrNread * @param totalNrNread f
* @return if totalNrRead &lt; 0 then totalNrRead is returned, if * @return if totalNrRead &lt; 0 then totalNrRead is returned, if
* (nrRead + totalNrRead) &lt; Integer.MAX_VALUE then nrRead + totalNrRead * (nrRead + totalNrRead) &lt; Integer.MAX_VALUE then nrRead + totalNrRead
* is returned, -1 otherwise. * is returned, -1 otherwise.
@ -109,15 +109,15 @@ public class IOUtil {
/** /**
* Copies the contents of the InputStream to the OutputStream. * Copies the contents of the InputStream to the OutputStream.
* *
* @param in * @param in f
* @param out * @param out f
* @return the nr of bytes read, or -1 if the amount &gt; Integer.MAX_VALUE * @return the nr of bytes read, or -1 if the amount &gt; Integer.MAX_VALUE
* @throws IOException * @throws IOException f
*/ */
public static int copy(InputStream in, OutputStream out) public static int copy(InputStream in, OutputStream out)
throws IOException { throws IOException {
byte[] buffer = new byte[IO_COPY_BUFFER_SIZE]; byte[] buffer = new byte[IO_COPY_BUFFER_SIZE];
int readSize = -1; int readSize ;
int result = 0; int result = 0;
while ((readSize = in.read(buffer)) >= 0) { while ((readSize = in.read(buffer)) >= 0) {
out.write(buffer, 0, readSize); out.write(buffer, 0, readSize);
@ -130,14 +130,14 @@ public class IOUtil {
/** /**
* Copies the contents of the Reader to the Writer. * Copies the contents of the Reader to the Writer.
* *
* @param in * @param in f
* @param out * @param out f
* @return the nr of characters read, or -1 if the amount &gt; Integer.MAX_VALUE * @return the nr of characters read, or -1 if the amount &gt; Integer.MAX_VALUE
* @throws IOException * @throws IOException f
*/ */
public static int copy(Reader in, Writer out) throws IOException { public static int copy(Reader in, Writer out) throws IOException {
char[] buffer = new char[IO_COPY_BUFFER_SIZE]; char[] buffer = new char[IO_COPY_BUFFER_SIZE];
int readSize = -1; int readSize;
int result = 0; int result = 0;
while ((readSize = in.read(buffer)) >= 0) { while ((readSize = in.read(buffer)) >= 0) {
out.write(buffer, 0, readSize); out.write(buffer, 0, readSize);
@ -148,7 +148,7 @@ public class IOUtil {
} }
public static String Stream2String(InputStream inputStream) { public static String Stream2String(InputStream inputStream) {
String str=""; String str;
try { try {
BufferedInputStream bis = new BufferedInputStream(inputStream); BufferedInputStream bis = new BufferedInputStream(inputStream);
ByteArrayOutputStream buf = new ByteArrayOutputStream(); ByteArrayOutputStream buf = new ByteArrayOutputStream();

@ -11,9 +11,10 @@ import java.io.OutputStream;
* *
* @author paul * @author paul
*/ */
@SuppressWarnings("unused")
public class NoCloseOutputStream extends OutputStream { public class NoCloseOutputStream extends OutputStream {
private OutputStream outputStream; private final OutputStream outputStream;
public NoCloseOutputStream(OutputStream outputStream) { public NoCloseOutputStream(OutputStream outputStream) {
this.outputStream = outputStream; this.outputStream = outputStream;

@ -11,16 +11,17 @@ import java.io.Writer;
* *
* @author paul * @author paul
*/ */
@SuppressWarnings("unused")
public class NoCloseWriter extends Writer { public class NoCloseWriter extends Writer {
private Writer writer; private final Writer writer;
public NoCloseWriter(Writer writer) { public NoCloseWriter(Writer writer) {
this.writer = writer; this.writer = writer;
} }
@Override @Override
public void close() throws IOException { public void close() {
} }
@Override @Override

@ -1,10 +1,9 @@
package me.ag2s.epublib.util; package me.ag2s.epublib.util;
import me.ag2s.epublib.Constants; import org.w3c.dom.Document;
import me.ag2s.epublib.domain.MediaType; import org.xml.sax.InputSource;
import me.ag2s.epublib.domain.Resource; import org.xml.sax.SAXException;
import me.ag2s.epublib.epub.EpubProcessorSupport;
import me.ag2s.epublib.domain.MediaTypes;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
@ -15,11 +14,12 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document; import me.ag2s.epublib.Constants;
import org.xml.sax.InputSource; import me.ag2s.epublib.domain.MediaType;
import org.xml.sax.SAXException; import me.ag2s.epublib.domain.MediaTypes;
import me.ag2s.epublib.domain.Resource;
import me.ag2s.epublib.epub.EpubProcessorSupport;
/** /**
* Various resource utility methods * Various resource utility methods
@ -29,58 +29,61 @@ import org.xml.sax.SAXException;
public class ResourceUtil { public class ResourceUtil {
public static Resource createHTMLResource(String title, String string) { public static Resource createHTMLResource(String title, String string) {
String html=createHtml(title,string); String html = createHtml(title, string);
MediaType mediaTypeProperty = MediaTypes.XHTML; MediaType mediaTypeProperty = MediaTypes.XHTML;
byte[] data = html.getBytes(); byte[] data = html.getBytes();
Resource result = new Resource(data, mediaTypeProperty); return new Resource(data, mediaTypeProperty);
return result;
} }
public static Resource createHTMLResource(String title, String string,String href) {
String html=createHtml(title,string); @SuppressWarnings("unused")
public static Resource createHTMLResource(String title, String string, String href) {
String html = createHtml(title, string);
MediaType mediaTypeProperty = MediaTypes.XHTML; MediaType mediaTypeProperty = MediaTypes.XHTML;
byte[] data = html.getBytes(); byte[] data = html.getBytes();
Resource result = new Resource(null,data,href ,mediaTypeProperty); return new Resource(null, data, href, mediaTypeProperty);
return result; }
}
private static String createHtml(String title,String txt){ @SuppressWarnings("unused")
StringBuilder body= new StringBuilder(); private static String createHtml(String title, String txt) {
for(String s:txt.split("\\r?\\n")){ StringBuilder body = new StringBuilder();
s=s.trim(); for (String s : txt.split("\\r?\\n")) {
if(s!=null&&s.length()!=0) { s = s.trim();
if (s.length() != 0) {
body.append("<p>").append(s).append("</p>"); body.append("<p>").append(s).append("</p>");
} }
} }
String html="<?xml version=\"1.0\" encoding=\"utf-8\"?>"; String html = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
html+="<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">"; html += "<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">";
html+="<head><title>"+title+"</title>" + html += "<head><title>" + title + "</title>" +
"<link rel=\"stylesheet\" type=\"text/css\" href=\"css/style.css\"/>" + "<link rel=\"stylesheet\" type=\"text/css\" href=\"css/style.css\"/>" +
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/></head>"; "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/></head>";
html+="<body><h1>"+title+"</h1>" + html += "<body><h1>" + title + "</h1>" +
body+ body +
"</body></html>"; "</body></html>";
return html; return html;
} }
@SuppressWarnings("unused")
public static Resource createResource(File file) throws IOException { public static Resource createResource(File file) throws IOException {
if (file == null) { if (file == null) {
return null; return null;
} }
MediaType mediaType = MediaTypes.determineMediaType(file.getName()); MediaType mediaType = MediaTypes.determineMediaType(file.getName());
byte[] data = IOUtil.toByteArray(new FileInputStream(file)); byte[] data = IOUtil.toByteArray(new FileInputStream(file));
Resource result = new Resource(data, mediaType); return new Resource(data, mediaType);
return result;
} }
/** /**
* Creates a resource with as contents a html page with the given title. * Creates a resource with as contents a html page with the given title.
* *
* @param title * @param title v
* @param href * @param href v
* @return a resource with as contents a html page with the given title. * @return a resource with as contents a html page with the given title.
*/ */
@SuppressWarnings("unused")
public static Resource createResource(String title, String href) { public static Resource createResource(String title, String href) {
String content = String content =
"<html><head><title>" + title + "</title></head><body><h1>" + title "<html><head><title>" + title + "</title></head><body><h1>" + title
@ -92,10 +95,10 @@ public class ResourceUtil {
/** /**
* Creates a resource out of the given zipEntry and zipInputStream. * Creates a resource out of the given zipEntry and zipInputStream.
* *
* @param zipEntry * @param zipEntry v
* @param zipInputStream * @param zipInputStream v
* @return a resource created out of the given zipEntry and zipInputStream. * @return a resource created out of the given zipEntry and zipInputStream.
* @throws IOException * @throws IOException v
*/ */
public static Resource createResource(ZipEntry zipEntry, public static Resource createResource(ZipEntry zipEntry,
ZipInputStream zipInputStream) throws IOException { ZipInputStream zipInputStream) throws IOException {
@ -112,12 +115,13 @@ public class ResourceUtil {
/** /**
* Converts a given string from given input character encoding to the requested output character encoding. * Converts a given string from given input character encoding to the requested output character encoding.
* *
* @param inputEncoding * @param inputEncoding v
* @param outputEncoding * @param outputEncoding v
* @param input * @param input v
* @return the string from given input character encoding converted to the requested output character encoding. * @return the string from given input character encoding converted to the requested output character encoding.
* @throws UnsupportedEncodingException * @throws UnsupportedEncodingException v
*/ */
@SuppressWarnings("unused")
public static byte[] recode(String inputEncoding, String outputEncoding, public static byte[] recode(String inputEncoding, String outputEncoding,
byte[] input) throws UnsupportedEncodingException { byte[] input) throws UnsupportedEncodingException {
return new String(input, inputEncoding).getBytes(outputEncoding); return new String(input, inputEncoding).getBytes(outputEncoding);
@ -125,8 +129,8 @@ public class ResourceUtil {
/** /**
* Gets the contents of the Resource as an InputSource in a null-safe manner. * Gets the contents of the Resource as an InputSource in a null-safe manner.
*
*/ */
@SuppressWarnings("unused")
public static InputSource getInputSource(Resource resource) public static InputSource getInputSource(Resource resource)
throws IOException { throws IOException {
if (resource == null) { if (resource == null) {
@ -136,8 +140,7 @@ public class ResourceUtil {
if (reader == null) { if (reader == null) {
return null; return null;
} }
InputSource inputSource = new InputSource(reader); return new InputSource(reader);
return inputSource;
} }
@ -145,7 +148,7 @@ public class ResourceUtil {
* Reads parses the xml therein and returns the result as a Document * Reads parses the xml therein and returns the result as a Document
*/ */
public static Document getAsDocument(Resource resource) public static Document getAsDocument(Resource resource)
throws SAXException, IOException, ParserConfigurationException { throws SAXException, IOException {
return getAsDocument(resource, return getAsDocument(resource,
EpubProcessorSupport.createDocumentBuilder()); EpubProcessorSupport.createDocumentBuilder());
} }
@ -153,22 +156,20 @@ public class ResourceUtil {
/** /**
* Reads the given resources inputstream, parses the xml therein and returns the result as a Document * Reads the given resources inputstream, parses the xml therein and returns the result as a Document
* *
* @param resource * @param resource v
* @param documentBuilder * @param documentBuilder v
* @return the document created from the given resource * @return the document created from the given resource
* @throws UnsupportedEncodingException * @throws UnsupportedEncodingException v
* @throws SAXException * @throws SAXException v
* @throws IOException * @throws IOException v
* @throws ParserConfigurationException
*/ */
public static Document getAsDocument(Resource resource, public static Document getAsDocument(Resource resource,
DocumentBuilder documentBuilder) DocumentBuilder documentBuilder)
throws UnsupportedEncodingException, SAXException, IOException, ParserConfigurationException { throws UnsupportedEncodingException, SAXException, IOException {
InputSource inputSource = getInputSource(resource); InputSource inputSource = getInputSource(resource);
if (inputSource == null) { if (inputSource == null) {
return null; return null;
} }
Document result = documentBuilder.parse(inputSource); return documentBuilder.parse(inputSource);
return result;
} }
} }

@ -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 <a href="mailto:jk2006@engineer.com">John Kristian</a>
*/
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();
}
}

@ -6,14 +6,13 @@ import java.util.List;
/** /**
* Various String utility functions. * Various String utility functions.
* * <p>
* Most of the functions herein are re-implementations of the ones in apache * Most of the functions herein are re-implementations of the ones in apache
* commons StringUtils. The reason for re-implementing this is that the * commons StringUtils. The reason for re-implementing this is that the
* functions are fairly simple and using my own implementation saves the * functions are fairly simple and using my own implementation saves the
* inclusion of a 200Kb jar file. * inclusion of a 200Kb jar file.
* *
* @author paul.siegmann * @author paul.siegmann
*
*/ */
public class StringUtil { public class StringUtil {
@ -22,12 +21,12 @@ public class StringUtil {
* doesn't. X/foo/../Y is changed into 'X/Y', etc. Does not handle invalid * doesn't. X/foo/../Y is changed into 'X/Y', etc. Does not handle invalid
* paths like "../". * paths like "../".
* *
* @param path * @param path path
* @return the normalized path * @return the normalized path
*/ */
public static String collapsePathDots(String path) { public static String collapsePathDots(String path) {
String[] stringParts = path.split("/"); String[] stringParts = path.split("/");
List<String> parts = new ArrayList<String>(Arrays.asList(stringParts)); List<String> parts = new ArrayList<>(Arrays.asList(stringParts));
for (int i = 0; i < parts.size() - 1; i++) { for (int i = 0; i < parts.size() - 1; i++) {
String currentDir = parts.get(i); String currentDir = parts.get(i);
if (currentDir.length() == 0 || currentDir.equals(".")) { if (currentDir.length() == 0 || currentDir.equals(".")) {
@ -56,7 +55,7 @@ public class StringUtil {
* Whether the String is not null, not zero-length and does not contain of * Whether the String is not null, not zero-length and does not contain of
* only whitespace. * only whitespace.
* *
* @param text * @param text text
* @return Whether the String is not null, not zero-length and does not contain of * @return Whether the String is not null, not zero-length and does not contain of
*/ */
public static boolean isNotBlank(String text) { public static boolean isNotBlank(String text) {
@ -94,8 +93,8 @@ public class StringUtil {
* Whether the given source string ends with the given suffix, ignoring * Whether the given source string ends with the given suffix, ignoring
* case. * case.
* *
* @param source * @param source source
* @param suffix * @param suffix suffix
* @return Whether the given source string ends with the given suffix, ignoring case. * @return Whether the given source string ends with the given suffix, ignoring case.
*/ */
public static boolean endsWithIgnoreCase(String source, String suffix) { public static boolean endsWithIgnoreCase(String source, String suffix) {
@ -115,7 +114,7 @@ public class StringUtil {
/** /**
* If the given text is null return "", the original text otherwise. * If the given text is null return "", the original text otherwise.
* *
* @param text * @param text text
* @return If the given text is null "", the original text otherwise. * @return If the given text is null "", the original text otherwise.
*/ */
public static String defaultIfNull(String text) { public static String defaultIfNull(String text) {
@ -125,8 +124,8 @@ public class StringUtil {
/** /**
* If the given text is null return "", the given defaultValue otherwise. * If the given text is null return "", the given defaultValue otherwise.
* *
* @param text * @param text d
* @param defaultValue * @param defaultValue d
* @return If the given text is null "", the given defaultValue otherwise. * @return If the given text is null "", the given defaultValue otherwise.
*/ */
public static String defaultIfNull(String text, String defaultValue) { public static String defaultIfNull(String text, String defaultValue) {
@ -139,8 +138,8 @@ public class StringUtil {
/** /**
* Null-safe string comparator * Null-safe string comparator
* *
* @param text1 * @param text1 d
* @param text2 * @param text2 d
* @return whether the two strings are equal * @return whether the two strings are equal
*/ */
public static boolean equals(String text1, String text2) { public static boolean equals(String text1, String text2) {
@ -153,7 +152,7 @@ public class StringUtil {
/** /**
* Pretty toString printer. * Pretty toString printer.
* *
* @param keyValues * @param keyValues d
* @return a string representation of the input values * @return a string representation of the input values
*/ */
public static String toString(Object... keyValues) { public static String toString(Object... keyValues) {
@ -183,20 +182,20 @@ public class StringUtil {
public static int hashCode(String... values) { public static int hashCode(String... values) {
int result = 31; int result = 31;
for (int i = 0; i < values.length; i++) { for (String value : values) {
result ^= String.valueOf(values[i]).hashCode(); result ^= String.valueOf(value).hashCode();
} }
return result; return result;
} }
/** /**
* Gives the substring of the given text before the given separator. * Gives the substring of the given text before the given separator.
* * <p>
* If the text does not contain the given separator then the given text is * If the text does not contain the given separator then the given text is
* returned. * returned.
* *
* @param text * @param text d
* @param separator * @param separator d
* @return the substring of the given text before the given separator. * @return the substring of the given text before the given separator.
*/ */
public static String substringBefore(String text, char separator) { public static String substringBefore(String text, char separator) {
@ -213,12 +212,12 @@ public class StringUtil {
/** /**
* Gives the substring of the given text before the last occurrence of the * Gives the substring of the given text before the last occurrence of the
* given separator. * given separator.
* * <p>
* If the text does not contain the given separator then the given text is * If the text does not contain the given separator then the given text is
* returned. * returned.
* *
* @param text * @param text d
* @param separator * @param separator d
* @return the substring of the given text before the last occurrence of the given separator. * @return the substring of the given text before the last occurrence of the given separator.
*/ */
public static String substringBeforeLast(String text, char separator) { public static String substringBeforeLast(String text, char separator) {
@ -235,11 +234,11 @@ public class StringUtil {
/** /**
* Gives the substring of the given text after the last occurrence of the * Gives the substring of the given text after the last occurrence of the
* given separator. * given separator.
* * <p>
* If the text does not contain the given separator then "" is returned. * If the text does not contain the given separator then "" is returned.
* *
* @param text * @param text d
* @param separator * @param separator d
* @return the substring of the given text after the last occurrence of the given separator. * @return the substring of the given text after the last occurrence of the given separator.
*/ */
public static String substringAfterLast(String text, char separator) { public static String substringAfterLast(String text, char separator) {
@ -255,7 +254,7 @@ public class StringUtil {
/** /**
* Gives the substring of the given text after the given separator. * Gives the substring of the given text after the given separator.
* * <p>
* If the text does not contain the given separator then "" is returned. * If the text does not contain the given separator then "" is returned.
* *
* @param text the input text * @param text the input text

@ -85,6 +85,7 @@ public class BOMInputStream extends ProxyInputStream {
* a {@link ByteOrderMark#UTF_8} BOM. * a {@link ByteOrderMark#UTF_8} BOM.
* @param delegate the InputStream to delegate to * @param delegate the InputStream to delegate to
*/ */
@SuppressWarnings("unused")
public BOMInputStream(InputStream delegate) { public BOMInputStream(InputStream delegate) {
this(delegate, false, ByteOrderMark.UTF_8); 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 * @param include true to include the UTF-8 BOM or
* false to exclude it * false to exclude it
*/ */
@SuppressWarnings("unused")
public BOMInputStream(InputStream delegate, boolean include) { public BOMInputStream(InputStream delegate, boolean include) {
this(delegate, include, ByteOrderMark.UTF_8); this(delegate, include, ByteOrderMark.UTF_8);
} }
@ -106,6 +108,7 @@ public class BOMInputStream extends ProxyInputStream {
* @param delegate the InputStream to delegate to * @param delegate the InputStream to delegate to
* @param boms The BOMs to detect and exclude * @param boms The BOMs to detect and exclude
*/ */
@SuppressWarnings("unused")
public BOMInputStream(InputStream delegate, ByteOrderMark... boms) { public BOMInputStream(InputStream delegate, ByteOrderMark... boms) {
this(delegate, false, boms); this(delegate, false, boms);
} }
@ -118,6 +121,7 @@ public class BOMInputStream extends ProxyInputStream {
* false to exclude them * false to exclude them
* @param boms The BOMs to detect and optionally exclude * @param boms The BOMs to detect and optionally exclude
*/ */
@SuppressWarnings("unused")
public BOMInputStream(InputStream delegate, boolean include, ByteOrderMark... boms) { public BOMInputStream(InputStream delegate, boolean include, ByteOrderMark... boms) {
super(delegate); super(delegate);
if (boms == null || boms.length == 0) { if (boms == null || boms.length == 0) {
@ -134,6 +138,7 @@ public class BOMInputStream extends ProxyInputStream {
* if it does not * if it does not
* @throws IOException if an error reading the first bytes of the stream occurs * @throws IOException if an error reading the first bytes of the stream occurs
*/ */
@SuppressWarnings("unused")
public boolean hasBOM() throws IOException { public boolean hasBOM() throws IOException {
return (getBOM() != null); return (getBOM() != null);
} }
@ -148,6 +153,7 @@ public class BOMInputStream extends ProxyInputStream {
* is configured to detect * is configured to detect
* @throws IOException if an error reading the first bytes of the stream occurs * @throws IOException if an error reading the first bytes of the stream occurs
*/ */
@SuppressWarnings("unused")
public boolean hasBOM(ByteOrderMark bom) throws IOException { public boolean hasBOM(ByteOrderMark bom) throws IOException {
if (!boms.contains(bom)) { if (!boms.contains(bom)) {
throw new IllegalArgumentException("Stream not configure to detect " + bom); throw new IllegalArgumentException("Stream not configure to detect " + bom);

@ -150,6 +150,7 @@ public class ByteOrderMark implements Serializable {
* @return the length of the BOM's bytes * @return the length of the BOM's bytes
*/ */
@Override @Override
@SuppressWarnings("NullableProblems")
public String toString() { public String toString() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append(getClass().getSimpleName()); builder.append(getClass().getSimpleName());

@ -197,9 +197,9 @@ public abstract class ProxyInputStream extends FilterInputStream {
* *
* @since Commons IO 2.0 * @since Commons IO 2.0
* @param n number of bytes that the caller asked to be read * @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 * @since Commons IO 2.0
* @param n number of bytes read, or -1 if the end of stream was reached * @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) {
} }
/** /**

@ -30,6 +30,7 @@ import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Objects;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -105,6 +106,7 @@ public class XmlStreamReader extends Reader {
* *
* @return the default encoding to use. * @return the default encoding to use.
*/ */
@SuppressWarnings("unused")
public String getDefaultEncoding() { public String getDefaultEncoding() {
return defaultEncoding; return defaultEncoding;
} }
@ -121,6 +123,7 @@ public class XmlStreamReader extends Reader {
* @param file File to create a Reader from. * @param file File to create a Reader from.
* @throws IOException thrown if there is a problem reading the file. * @throws IOException thrown if there is a problem reading the file.
*/ */
@SuppressWarnings("unused")
public XmlStreamReader(File file) throws IOException { public XmlStreamReader(File file) throws IOException {
this(new FileInputStream(file)); 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 * @throws IOException thrown if there is a problem reading the stream of
* the URL. * the URL.
*/ */
@SuppressWarnings("unused")
public XmlStreamReader(URL url) throws IOException { public XmlStreamReader(URL url) throws IOException {
this(url.openConnection(), null); this(url.openConnection(), null);
} }
@ -249,15 +253,16 @@ public class XmlStreamReader extends Reader {
*/ */
public XmlStreamReader(URLConnection conn, String defaultEncoding) throws IOException { public XmlStreamReader(URLConnection conn, String defaultEncoding) throws IOException {
this.defaultEncoding = defaultEncoding; this.defaultEncoding = defaultEncoding;
@SuppressWarnings("unused")
boolean lenient = true; boolean lenient = true;
String contentType = conn.getContentType(); String contentType = conn.getContentType();
InputStream is = conn.getInputStream(); InputStream is = conn.getInputStream();
BOMInputStream bom = new BOMInputStream(new BufferedInputStream(is, BUFFER_SIZE), false, BOMS); BOMInputStream bom = new BOMInputStream(new BufferedInputStream(is, BUFFER_SIZE), false, BOMS);
BOMInputStream pis = new BOMInputStream(bom, true, XML_GUESS_BYTES); BOMInputStream pis = new BOMInputStream(bom, true, XML_GUESS_BYTES);
if (conn instanceof HttpURLConnection || contentType != null) { if (conn instanceof HttpURLConnection || contentType != null) {
this.encoding = doHttpStream(bom, pis, contentType, lenient); this.encoding = doHttpStream(bom, pis, contentType, true);
} else { } else {
this.encoding = doRawStream(bom, pis, lenient); this.encoding = doRawStream(bom, pis, true);
} }
this.reader = new InputStreamReader(pis, encoding); this.reader = new InputStreamReader(pis, encoding);
} }
@ -509,11 +514,11 @@ public class XmlStreamReader extends Reader {
// BOM is UTF-8 // BOM is UTF-8
if (bomEnc.equals(UTF_8)) { if (bomEnc.equals(UTF_8)) {
if (xmlGuessEnc != null && !xmlGuessEnc.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); throw new XmlStreamReaderException(msg, bomEnc, xmlGuessEnc, xmlEnc);
} }
if (xmlEnc != null && !xmlEnc.equals(UTF_8)) { 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); throw new XmlStreamReaderException(msg, bomEnc, xmlGuessEnc, xmlEnc);
} }
return bomEnc; return bomEnc;
@ -522,18 +527,18 @@ public class XmlStreamReader extends Reader {
// BOM is UTF-16BE or UTF-16LE // BOM is UTF-16BE or UTF-16LE
if (bomEnc.equals(UTF_16BE) || bomEnc.equals(UTF_16LE)) { if (bomEnc.equals(UTF_16BE) || bomEnc.equals(UTF_16LE)) {
if (xmlGuessEnc != null && !xmlGuessEnc.equals(bomEnc)) { 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); throw new XmlStreamReaderException(msg, bomEnc, xmlGuessEnc, xmlEnc);
} }
if (xmlEnc != null && !xmlEnc.equals(UTF_16) && !xmlEnc.equals(bomEnc)) { 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); throw new XmlStreamReaderException(msg, bomEnc, xmlGuessEnc, xmlEnc);
} }
return bomEnc; return bomEnc;
} }
// BOM is something else // 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); throw new XmlStreamReaderException(msg, bomEnc, xmlGuessEnc, xmlEnc);
} }
@ -697,7 +702,7 @@ public class XmlStreamReader extends Reader {
} }
Matcher m = ENCODING_PATTERN.matcher(prolog); Matcher m = ENCODING_PATTERN.matcher(prolog);
if (m.find()) { if (m.find()) {
encoding = m.group(1).toUpperCase(); encoding = Objects.requireNonNull(m.group(1)).toUpperCase();
encoding = encoding.substring(1, encoding.length() - 1); encoding = encoding.substring(1, encoding.length() - 1);
} }
} }

@ -120,6 +120,7 @@ public class XmlStreamReaderException extends IOException {
* @return the MIME type in the content-type, null if there was not * @return the MIME type in the content-type, null if there was not
* content-type or the encoding detection did not involve HTTP. * content-type or the encoding detection did not involve HTTP.
*/ */
@SuppressWarnings("unused")
public String getContentTypeMime() { public String getContentTypeMime() {
return contentTypeMime; return contentTypeMime;
} }

Loading…
Cancel
Save