diff --git a/.gitignore b/.gitignore index 30b8f556..b3644e4a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ epublib-tools/.classpath epublib-tools/.project epublib-core/.settings epublib-tools/.settings/ +!/.idea/ +*.iml diff --git a/epublib-core/pom.xml b/epublib-core/pom.xml index 208226f6..0a31418a 100644 --- a/epublib-core/pom.xml +++ b/epublib-core/pom.xml @@ -1,4 +1,4 @@ - + @@ -15,11 +15,16 @@ nl.siegmann.epublib epublib-parent - 4.0 + 4.0.1-EPUB3-SNAPSHOT ../epublib-parent/pom.xml + + commons-io + commons-io + 2.11.0 + net.sf.kxml kxml2 diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/domain/Author.java b/epublib-core/src/main/java/nl/siegmann/epublib/domain/Author.java index ca529b9d..4b3772ad 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/domain/Author.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/domain/Author.java @@ -16,7 +16,17 @@ public class Author implements Serializable { private String firstname; private String lastname; - private Relator relator = Relator.AUTHOR; + private Relator relator; + + public Scheme getScheme() { + return scheme; + } + + public void setScheme(Scheme scheme) { + this.scheme = scheme; + } + + private Scheme scheme; public Author(String singleName) { this("", singleName); diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/domain/Book.java b/epublib-core/src/main/java/nl/siegmann/epublib/domain/Book.java index 152d5b69..4e7ec789 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/domain/Book.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/domain/Book.java @@ -6,12 +6,9 @@ import java.util.List; import java.util.Map; - - - /** * Representation of a Book. - * + *
* All resources of a Book (html, css, xml, fonts, images) are represented as Resources. See getResources() for access to these.
* A Book as 3 indexes into these Resources, as per the epub specification.
*
@@ -28,268 +25,6 @@ * The Content page may be in the Table of Contents, the Guide, but not in the Spine. * Etc. *

- - - - - - - - - - - - - - - - - - - - - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Spine - - - - - - - -Table of Contents - - - - - - - -Guide - -Chapter 1 - -Chapter 1 - -Part 2 - -Chapter 2 - -Chapter 1 - -Chapter 2 - -Cover - -Resources - -Preface - - - - - - - - - - - - - - - - - - - - * @author paul * */ @@ -302,10 +37,11 @@ public class Book implements Serializable { private Spine spine = new Spine(); private TableOfContents tableOfContents = new TableOfContents(); private Guide guide = new Guide(); - private Resource opfResource; + private OpfResource opfResource; private Resource ncxResource; private Resource coverImage; - + private Resource navResource; + /** * Adds the resource to the table of contents of the book as a child section of the given parentSection * @@ -440,7 +176,7 @@ public void setCoverPage(Resource coverPage) { * * @return the first non-blank title from the book's metadata. */ - public String getTitle() { + public Title getTitle() { return getMetadata().getFirstTitle(); } @@ -511,11 +247,11 @@ private static void addToContentsResult(Resource resource, Map } } - public Resource getOpfResource() { + public OpfResource getOpfResource() { return opfResource; } - public void setOpfResource(Resource opfResource) { + public void setOpfResource(OpfResource opfResource) { this.opfResource = opfResource; } @@ -526,5 +262,13 @@ public void setNcxResource(Resource ncxResource) { public Resource getNcxResource() { return ncxResource; } + + public Resource getNavResource() { + return navResource; + } + + public void setNavResource(Resource navResource) { + this.navResource = navResource; + } } diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/domain/Identifier.java b/epublib-core/src/main/java/nl/siegmann/epublib/domain/Identifier.java index a6e30acd..ce810d2d 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/domain/Identifier.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/domain/Identifier.java @@ -20,16 +20,9 @@ public class Identifier implements Serializable { * */ private static final long serialVersionUID = 955949951416391810L; - - public interface Scheme { - String UUID = "UUID"; - String ISBN = "ISBN"; - String URL = "URL"; - String URI = "URI"; - } private boolean bookId = false; - private String scheme; + private Scheme scheme; private String value; /** @@ -40,11 +33,19 @@ public Identifier() { } - public Identifier(String scheme, String value) { + public Identifier(Scheme scheme, String value) { this.scheme = scheme; this.value = value; } + public Scheme getScheme() { + return scheme; + } + + public void setScheme(Scheme scheme) { + this.scheme = scheme; + } + /** * 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. @@ -72,12 +73,6 @@ public static Identifier getBookIdIdentifier(List identifiers) { return result; } - public String getScheme() { - return scheme; - } - public void setScheme(String scheme) { - this.scheme = scheme; - } public String getValue() { return value; } @@ -104,19 +99,19 @@ public boolean isBookId() { } public int hashCode() { - return StringUtil.defaultIfNull(scheme).hashCode() ^ StringUtil.defaultIfNull(value).hashCode(); + return StringUtil.defaultIfNull(scheme.getName()).hashCode() ^ StringUtil.defaultIfNull(value).hashCode(); } public boolean equals(Object otherIdentifier) { if(! (otherIdentifier instanceof Identifier)) { return false; } - return StringUtil.equals(scheme, ((Identifier) otherIdentifier).scheme) + return StringUtil.equals(scheme.getName(), ((Identifier) otherIdentifier).scheme.getName()) && StringUtil.equals(value, ((Identifier) otherIdentifier).value); } public String toString() { - if (StringUtil.isBlank(scheme)) { + if (StringUtil.isBlank(scheme.getName())) { return "" + value; } return "" + scheme + ":" + value; diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/domain/LazyResource.java b/epublib-core/src/main/java/nl/siegmann/epublib/domain/LazyResource.java index 1983dd31..3cae9a19 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/domain/LazyResource.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/domain/LazyResource.java @@ -4,15 +4,14 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import nl.siegmann.epublib.service.MediatypeService; import nl.siegmann.epublib.util.IOUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * A Resource that loads its data only on-demand. * This way larger books can fit into memory and can be opened faster. @@ -28,7 +27,7 @@ public class LazyResource extends Resource { private String filename; private long cachedSize; - private static final Logger LOG = LoggerFactory.getLogger(LazyResource.class); + private static final Logger LOG = Logger.getLogger(LazyResource.class.getName()); /** * Creates a Lazy resource, by not actually loading the data for this entry. @@ -102,8 +101,9 @@ public void initialize() throws IOException { public byte[] getData() throws IOException { if ( data == null ) { - - LOG.debug("Initializing lazy resource " + filename + "#" + this.getHref() ); + if (LOG.isLoggable(Level.FINE)) { + LOG.fine("Initializing lazy resource " + filename + "#" + this.getHref()); + } InputStream in = getResourceStream(); byte[] readData = IOUtil.toByteArray(in, (int) this.cachedSize); diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/domain/Metadata.java b/epublib-core/src/main/java/nl/siegmann/epublib/domain/Metadata.java index 4fbbc312..f2a99b4b 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/domain/Metadata.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/domain/Metadata.java @@ -25,7 +25,11 @@ public class Metadata implements Serializable { */ private static final long serialVersionUID = -2437262888962149444L; - public static final String DEFAULT_LANGUAGE = "en"; + /** + * Default language is now set to "undefined" so people can check if the epub declares a language. + * They may want to try and detect the language based on the book text if there's no language metadata. + */ + public static final String DEFAULT_LANGUAGE = "und"; private boolean autoGeneratedId = true; private List authors = new ArrayList(); @@ -34,7 +38,7 @@ public class Metadata implements Serializable { private String language = DEFAULT_LANGUAGE; private Map otherProperties = new HashMap(); private List rights = new ArrayList(); - private List titles = new ArrayList(); + private List titles = new ArrayList<>(); private List<Identifier> identifiers = new ArrayList<Identifier>(); private List<String> subjects = new ArrayList<String>(); private String format = MediatypeService.EPUB.getName(); @@ -126,27 +130,27 @@ public List<String> getRights() { * * @return the first non-blank title of the book. */ - public String getFirstTitle() { + public Title getFirstTitle() { if (titles == null || titles.isEmpty()) { - return ""; + return Title.EMPTY; } - for (String title: titles) { - if (StringUtil.isNotBlank(title)) { + for (Title title: titles) { + if (StringUtil.isNotBlank(title.value)) { return title; } } - return ""; + return Title.EMPTY; } - public String addTitle(String title) { + public Title addTitle(Title title) { this.titles.add(title); return title; } - public void setTitles(List<String> titles) { + public void setTitles(List<Title> titles) { this.titles = titles; } - public List<String> getTitles() { + public List<Title> getTitles() { return titles; } diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/domain/OpfResource.java b/epublib-core/src/main/java/nl/siegmann/epublib/domain/OpfResource.java new file mode 100644 index 00000000..603d3b9d --- /dev/null +++ b/epublib-core/src/main/java/nl/siegmann/epublib/domain/OpfResource.java @@ -0,0 +1,38 @@ +package nl.siegmann.epublib.domain; + +import java.io.IOException; + +public class OpfResource extends Resource { + + public static final String DEFAULT_VERSION = "2.0"; + + private String version; + + private String prefix; + + public OpfResource(Resource resource) throws IOException { + super( + resource.getId(), + resource.getData(), + resource.getHref(), + resource.getMediaType(), + resource.getInputEncoding() + ); + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } +} diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/domain/Resource.java b/epublib-core/src/main/java/nl/siegmann/epublib/domain/Resource.java index e8fefc18..9cbd7efc 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/domain/Resource.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/domain/Resource.java @@ -32,7 +32,10 @@ public class Resource implements Serializable { private MediaType mediaType; private String inputEncoding = Constants.CHARACTER_ENCODING; protected byte[] data; - + private boolean isNav; + private boolean containingSvg; + private boolean isScripted; + /** * Creates an empty Resource with the given href. * @@ -137,6 +140,30 @@ public Resource(String id, byte[] data, String href, MediaType mediaType, String this.inputEncoding = inputEncoding; this.data = data; } + + public boolean isNav() { + return isNav; + } + + public void setNav(boolean nav) { + isNav = nav; + } + + public boolean isContainingSvg() { + return containingSvg; + } + + public void setContainingSvg(boolean containingSvg) { + this.containingSvg = containingSvg; + } + + public boolean isScripted() { + return isScripted; + } + + public void setScripted(boolean scripted) { + isScripted = scripted; + } /** * Gets the contents of the Resource as an InputStream. diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/domain/Resources.java b/epublib-core/src/main/java/nl/siegmann/epublib/domain/Resources.java index d7b88a9c..a04eda99 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/domain/Resources.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/domain/Resources.java @@ -28,9 +28,19 @@ public class Resources implements Serializable { private static final String IMAGE_PREFIX = "image_"; private static final String ITEM_PREFIX = "item_"; private int lastId = 1; - + private Resource navResource; + private Map<String, Resource> resources = new HashMap<String, Resource>(); - + + public Resource getNavResource() { + return navResource; + } + + public void setNavResource(Resource navResource) { + this.navResource = navResource; + } + + /** * Adds a resource to the resources. * diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/domain/Scheme.java b/epublib-core/src/main/java/nl/siegmann/epublib/domain/Scheme.java new file mode 100644 index 00000000..dd8818c5 --- /dev/null +++ b/epublib-core/src/main/java/nl/siegmann/epublib/domain/Scheme.java @@ -0,0 +1,36 @@ +package nl.siegmann.epublib.domain; + +public class Scheme { + + public final static Scheme UUID = new Scheme("UUID"); + + public final static Scheme ISBN = new Scheme("ISBN"); + + private String name; + private String value; + + public Scheme(String name) { + this.name = name; + } + + public Scheme(String name, String value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/domain/Title.java b/epublib-core/src/main/java/nl/siegmann/epublib/domain/Title.java new file mode 100644 index 00000000..dd960681 --- /dev/null +++ b/epublib-core/src/main/java/nl/siegmann/epublib/domain/Title.java @@ -0,0 +1,49 @@ +package nl.siegmann.epublib.domain; + +import java.util.Objects; + +public class Title { + + public static final Title EMPTY = new Title(""); + + String value; + String type; + + public Title(String value) { + this.value = value; + } + + public Title(String value, String type) { + this.value = value; + this.type = type; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Title title = (Title) o; + return Objects.equals(value, title.value) && Objects.equals(type, title.type); + } + + @Override + public int hashCode() { + return Objects.hash(value, type); + } +} diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/epub/BookProcessor.java b/epublib-core/src/main/java/nl/siegmann/epublib/epub/BookProcessor.java index 3cbc296b..d0015ab0 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/epub/BookProcessor.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/epub/BookProcessor.java @@ -15,7 +15,7 @@ public interface BookProcessor { /** * A BookProcessor that returns the input book unchanged. */ - public BookProcessor IDENTITY_BOOKPROCESSOR = new BookProcessor() { + BookProcessor IDENTITY_BOOKPROCESSOR = new BookProcessor() { @Override public Book processBook(Book book) { diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/epub/BookProcessorPipeline.java b/epublib-core/src/main/java/nl/siegmann/epublib/epub/BookProcessorPipeline.java index 84f797b5..9138304a 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/epub/BookProcessorPipeline.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/epub/BookProcessorPipeline.java @@ -3,11 +3,11 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import nl.siegmann.epublib.domain.Book; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * A book processor that combines several other bookprocessors @@ -20,7 +20,7 @@ */ public class BookProcessorPipeline implements BookProcessor { - private Logger log = LoggerFactory.getLogger(BookProcessorPipeline.class); + private Logger log = Logger.getLogger(BookProcessorPipeline.class.getName()); private List<BookProcessor> bookProcessors; public BookProcessorPipeline() { @@ -41,7 +41,7 @@ public Book processBook(Book book) { try { book = bookProcessor.processBook(book); } catch(Exception e) { - log.error(e.getMessage(), e); + log.log(Level.SEVERE, e.getMessage(), e); } } return book; diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/epub/DOMUtil.java b/epublib-core/src/main/java/nl/siegmann/epublib/epub/DOMUtil.java index a28fa84f..95f4ea38 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/epub/DOMUtil.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/epub/DOMUtil.java @@ -17,37 +17,26 @@ * @author paul * */ -// package class DOMUtil { /** * First tries to get the attribute value by doing an getAttributeNS on the element, if that gets an empty element it does a getAttribute without namespace. - * - * @param element - * @param namespace - * @param attribute - * @return */ - public static String getAttribute(Element element, String namespace, String attribute) { - String result = element.getAttributeNS(namespace, attribute); - if (StringUtil.isEmpty(result)) { - result = element.getAttribute(attribute); + public static String getAttribute(Node element, String namespace, String attribute) { + Node node = element.getAttributes().getNamedItemNS(namespace, attribute); + if (node == null) { + node = element.getAttributes().getNamedItem(attribute); } - return result; + return node != null ? node.getNodeValue() : ""; } /** - * Gets all descendant elements of the given parentElement with the given namespace and tagname and returns their text child as a list of String. - * - * @param parentElement - * @param namespace - * @param tagname - * @return + * Gets all descendant elements of the given parentElement with the given namespace and tag name and returns their text child as a list of String. */ - public static List<String> getElementsTextChild(Element parentElement, String namespace, String tagname) { - NodeList elements = parentElement.getElementsByTagNameNS(namespace, tagname); - List<String> result = new ArrayList<String>(elements.getLength()); + public static List<String> getElementsTextChild(Element parentElement, String namespace, String tagName) { + NodeList elements = parentElement.getElementsByTagNameNS(namespace, tagName); + List<String> result = new ArrayList<>(elements.getLength()); for(int i = 0; i < elements.getLength(); i++) { result.add(getTextChildrenContent((Element) elements.item(i))); } @@ -57,14 +46,6 @@ public static List<String> getElementsTextChild(Element parentElement, String na /** * Finds in the current document the first element with the given namespace and elementName and with the given findAttributeName and findAttributeValue. * It then returns the value of the given resultAttributeName. - * - * @param document - * @param namespace - * @param elementName - * @param findAttributeName - * @param findAttributeValue - * @param resultAttributeName - * @return */ public static String getFindAttributeValue(Document document, String namespace, String elementName, String findAttributeName, String findAttributeValue, String resultAttributeName) { NodeList metaTags = document.getElementsByTagNameNS(namespace, elementName); @@ -80,11 +61,6 @@ public static String getFindAttributeValue(Document document, String namespace, /** * Gets the first element that is a child of the parentElement and has the given namespace and tagName - * - * @param parentElement - * @param namespace - * @param tagName - * @return */ public static Element getFirstElementByTagNameNS(Element parentElement, String namespace, String tagName) { NodeList nodes = parentElement.getElementsByTagNameNS(namespace, tagName); @@ -99,11 +75,8 @@ public static Element getFirstElementByTagNameNS(Element parentElement, String n * The result is trim()-ed. * * The reason for this more complicated procedure instead of just returning the data of the firstChild is that - * 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 Character is represented in the DOM as * an individual Text node. - * - * @param parentElement - * @return */ public static String getTextChildrenContent(Element parentElement) { if(parentElement == null) { diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/epub/EpubProcessorSupport.java b/epublib-core/src/main/java/nl/siegmann/epublib/epub/EpubProcessorSupport.java index 70faba6a..63e8f219 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/epub/EpubProcessorSupport.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/epub/EpubProcessorSupport.java @@ -1,5 +1,14 @@ package nl.siegmann.epublib.epub; +import nl.siegmann.epublib.Constants; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xmlpull.v1.XmlPullParserFactory; +import org.xmlpull.v1.XmlSerializer; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -7,20 +16,7 @@ import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.URL; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import nl.siegmann.epublib.Constants; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xml.sax.EntityResolver; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xmlpull.v1.XmlPullParserFactory; -import org.xmlpull.v1.XmlSerializer; +import java.util.logging.Logger; /** * Various low-level support methods for reading/writing epubs. @@ -30,7 +26,7 @@ */ public class EpubProcessorSupport { - private static final Logger log = LoggerFactory.getLogger(EpubProcessorSupport.class); + private static final Logger log = Logger.getLogger(EpubProcessorSupport.class.getName()); protected static DocumentBuilderFactory documentBuilderFactory; @@ -42,8 +38,7 @@ static class EntityResolverImpl implements EntityResolver { private String previousLocation; @Override - public InputSource resolveEntity(String publicId, String systemId) - throws SAXException, IOException { + public InputSource resolveEntity(String publicId, String systemId) throws IOException { String resourcePath; if (systemId.startsWith("http:")) { URL url = new URL(systemId); @@ -82,7 +77,7 @@ public static XmlSerializer createXmlSerializer(Writer out) { result.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); result.setOutput(out); } catch (Exception e) { - log.error("When creating XmlSerializer: " + e.getClass().getName() + ": " + e.getMessage()); + log.severe("When creating XmlSerializer: " + e.getClass().getName() + ": " + e.getMessage()); } return result; } @@ -99,10 +94,6 @@ public static EntityResolver getEntityResolver() { return new EntityResolverImpl(); } - public DocumentBuilderFactory getDocumentBuilderFactory() { - return documentBuilderFactory; - } - /** * Creates a DocumentBuilder that looks up dtd's and schema's from epublib's classpath. * @@ -114,7 +105,7 @@ public static DocumentBuilder createDocumentBuilder() { result = documentBuilderFactory.newDocumentBuilder(); result.setEntityResolver(getEntityResolver()); } catch (ParserConfigurationException e) { - log.error(e.getMessage()); + log.severe(e.getMessage()); } return result; } diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/epub/EpubReader.java b/epublib-core/src/main/java/nl/siegmann/epublib/epub/EpubReader.java index 3765d53e..2610dc30 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/epub/EpubReader.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/epub/EpubReader.java @@ -4,20 +4,17 @@ import java.io.InputStream; import java.util.Arrays; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import net.sf.jazzlib.ZipFile; import net.sf.jazzlib.ZipInputStream; import nl.siegmann.epublib.Constants; -import nl.siegmann.epublib.domain.Book; -import nl.siegmann.epublib.domain.MediaType; -import nl.siegmann.epublib.domain.Resource; -import nl.siegmann.epublib.domain.Resources; +import nl.siegmann.epublib.domain.*; import nl.siegmann.epublib.service.MediatypeService; import nl.siegmann.epublib.util.ResourceUtil; import nl.siegmann.epublib.util.StringUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -29,18 +26,20 @@ */ public class EpubReader { - private static final Logger log = LoggerFactory.getLogger(EpubReader.class); - private BookProcessor bookProcessor = BookProcessor.IDENTITY_BOOKPROCESSOR; + private static final Logger log = Logger.getLogger(EpubReader.class.getName()); + private final BookProcessor bookProcessor = BookProcessor.IDENTITY_BOOKPROCESSOR; public Book readEpub(InputStream in) throws IOException { return readEpub(in, Constants.CHARACTER_ENCODING); } + @SuppressWarnings("unused") public Book readEpub(ZipInputStream in) throws IOException { return readEpub(in, Constants.CHARACTER_ENCODING); } - public Book readEpub(ZipFile zipfile) throws IOException { + @SuppressWarnings("unused") + public Book readEpub(ZipFile zipfile) throws IOException { return readEpub(zipfile, Constants.CHARACTER_ENCODING); } @@ -50,7 +49,6 @@ public Book readEpub(ZipFile zipfile) throws IOException { * @param in the inputstream from which to read the epub * @param encoding the encoding to use for the html files within the epub * @return the Book as read from the inputstream - * @throws IOException */ public Book readEpub(InputStream in, String encoding) throws IOException { return readEpub(new ZipInputStream(in), encoding); @@ -65,8 +63,8 @@ public Book readEpub(InputStream in, String encoding) throws IOException { * @param encoding the encoding for XHTML files * * @return this Book without loading all resources into memory. - * @throws IOException */ + @SuppressWarnings("unused") public Book readEpubLazy(ZipFile zipFile, String encoding ) throws IOException { return readEpubLazy(zipFile, encoding, Arrays.asList(MediatypeService.mediatypes) ); } @@ -86,7 +84,6 @@ public Book readEpub(ZipFile in, String encoding) throws IOException { * @param encoding the encoding for XHTML files * @param lazyLoadedTypes a list of the MediaType to load lazily * @return this Book without loading all resources into memory. - * @throws IOException */ public Book readEpubLazy(ZipFile zipFile, String encoding, List<MediaType> lazyLoadedTypes ) throws IOException { Resources resources = ResourcesLoader.loadResources(zipFile, encoding, lazyLoadedTypes); @@ -101,11 +98,14 @@ public Book readEpub(Resources resources, Book result) throws IOException{ if (result == null) { result = new Book(); } - handleMimeType(result, resources); + handleMimeType(resources); String packageResourceHref = getPackageResourceHref(resources); - Resource packageResource = processPackageResource(packageResourceHref, result, resources); + OpfResource packageResource = processPackageResource(packageResourceHref, result, resources); result.setOpfResource(packageResource); - Resource ncxResource = processNcxResource(packageResource, result); + Resource ncxResource = processNcxResource(result); + if (ncxResource == null) { + NavDocument.read(result); + } result.setNcxResource(ncxResource); result = postProcessBook(result); return result; @@ -119,16 +119,18 @@ private Book postProcessBook(Book book) { return book; } - private Resource processNcxResource(Resource packageResource, Book book) { + private Resource processNcxResource(Book book) { return NCXDocument.read(book, this); } - private Resource processPackageResource(String packageResourceHref, Book book, Resources resources) { - Resource packageResource = resources.remove(packageResourceHref); + private OpfResource processPackageResource(String packageResourceHref, Book book, Resources resources) throws IOException { + OpfResource packageResource = new OpfResource( + resources.remove(packageResourceHref) + ); try { - PackageDocumentReader.read(packageResource, this, book, resources); + PackageDocumentReader.read(packageResource, book, resources); } catch (Exception e) { - log.error(e.getMessage(), e); + log.log(Level.SEVERE, e.getMessage(), e); } return packageResource; } @@ -146,7 +148,7 @@ private String getPackageResourceHref(Resources resources) { Element rootFileElement = (Element) ((Element) document.getDocumentElement().getElementsByTagName("rootfiles").item(0)).getElementsByTagName("rootfile").item(0); result = rootFileElement.getAttribute("full-path"); } catch (Exception e) { - log.error(e.getMessage(), e); + log.log(Level.SEVERE, e.getMessage(), e); } if(StringUtil.isBlank(result)) { result = defaultResult; @@ -154,7 +156,7 @@ private String getPackageResourceHref(Resources resources) { return result; } - private void handleMimeType(Book result, Resources resources) { + private void handleMimeType(Resources resources) { resources.remove("mimetype"); } } diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/epub/EpubWriter.java b/epublib-core/src/main/java/nl/siegmann/epublib/epub/EpubWriter.java index f08d5587..1dbff7c7 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/epub/EpubWriter.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/epub/EpubWriter.java @@ -5,12 +5,13 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.zip.CRC32; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import nl.siegmann.epublib.domain.OpfResource; import org.xmlpull.v1.XmlSerializer; import nl.siegmann.epublib.domain.Book; @@ -26,7 +27,7 @@ */ public class EpubWriter { - private final static Logger log = LoggerFactory.getLogger(EpubWriter.class); + private final static Logger log = Logger.getLogger(EpubWriter.class.getName()); // package static final String EMPTY_NAMESPACE_PREFIX = ""; @@ -48,7 +49,13 @@ public void write(Book book, OutputStream out) throws IOException { ZipOutputStream resultStream = new ZipOutputStream(out); writeMimeType(resultStream); writeContainer(resultStream); - initTOCResource(book); + if( + null == book.getOpfResource() + || OpfResource.DEFAULT_VERSION.equals(book.getOpfResource().getVersion()) + || !book.getTableOfContents().getTocReferences().isEmpty() + ) { + initTOCResource(book); + } writeResources(book, resultStream); writePackageDocument(book, resultStream); resultStream.close(); @@ -72,7 +79,7 @@ private void initTOCResource(Book book) { book.getSpine().setTocResource(tocResource); book.getResources().add(tocResource); } catch (Exception e) { - log.error("Error writing table of contents: " + e.getClass().getName() + ": " + e.getMessage()); + log.severe("Error writing table of contents: " + e.getClass().getName() + ": " + e.getMessage()); } } @@ -101,7 +108,7 @@ private void writeResource(Resource resource, ZipOutputStream resultStream) IOUtil.copy(inputStream, resultStream); inputStream.close(); } catch(Exception e) { - log.error(e.getMessage(), e); + log.log(Level.SEVERE, e.getMessage(), e); } } diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/epub/NCXDocument.java b/epublib-core/src/main/java/nl/siegmann/epublib/epub/NCXDocument.java index 6ec61026..77cd3a30 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/epub/NCXDocument.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/epub/NCXDocument.java @@ -6,6 +6,8 @@ import java.net.URLDecoder; import java.util.ArrayList; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -22,8 +24,6 @@ import nl.siegmann.epublib.util.ResourceUtil; import nl.siegmann.epublib.util.StringUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -44,7 +44,7 @@ public class NCXDocument { public static final String DEFAULT_NCX_HREF = "toc.ncx"; public static final String PREFIX_DTB = "dtb"; - private static final Logger log = LoggerFactory.getLogger(NCXDocument.class); + private static final Logger log = Logger.getLogger(NCXDocument.class.getName()); private interface NCXTags { String ncx = "ncx"; @@ -79,7 +79,7 @@ private interface NCXAttributeValues { public static Resource read(Book book, EpubReader epubReader) { Resource ncxResource = null; if(book.getSpine().getTocResource() == null) { - log.error("Book does not contain a table of contents file"); + log.severe("Book does not contain a table of contents file"); return ncxResource; } try { @@ -89,10 +89,12 @@ public static Resource read(Book book, EpubReader epubReader) { } Document ncxDocument = ResourceUtil.getAsDocument(ncxResource); Element navMapElement = DOMUtil.getFirstElementByTagNameNS(ncxDocument.getDocumentElement(), NAMESPACE_NCX, NCXTags.navMap); - TableOfContents tableOfContents = new TableOfContents(readTOCReferences(navMapElement.getChildNodes(), book)); - book.setTableOfContents(tableOfContents); + if (null != navMapElement) { + TableOfContents tableOfContents = new TableOfContents(readTOCReferences(navMapElement.getChildNodes(), book)); + book.setTableOfContents(tableOfContents); + } } catch (Exception e) { - log.error(e.getMessage(), e); + log.log(Level.SEVERE, e.getMessage(), e); } return ncxResource; } @@ -129,7 +131,7 @@ static TOCReference readTOCReference(Element navpointElement, Book book) { String fragmentId = StringUtil.substringAfter(reference, Constants.FRAGMENT_SEPARATOR_CHAR); Resource resource = book.getResources().getByHref(href); if (resource == null) { - log.error("Resource with href " + href + " in NCX document not found"); + log.severe("Resource with href " + href + " in NCX document not found"); } TOCReference result = new TOCReference(label, resource, fragmentId); List<TOCReference> childTOCReferences = readTOCReferences(navpointElement.getChildNodes(), book); @@ -143,7 +145,7 @@ private static String readNavReference(Element navpointElement) { try { result = URLDecoder.decode(result, Constants.CHARACTER_ENCODING); } catch (UnsupportedEncodingException e) { - log.error(e.getMessage()); + log.severe(e.getMessage()); } return result; } @@ -174,11 +176,11 @@ public static void write(EpubWriter epubWriter, Book book, ZipOutputStream resul * @throws 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()); + write(xmlSerializer, book.getMetadata().getIdentifiers(), book.getTitle().getValue(), book.getMetadata().getAuthors(), book.getTableOfContents()); } public static Resource createNCXResource(Book book) throws IllegalArgumentException, IllegalStateException, IOException { - return createNCXResource(book.getMetadata().getIdentifiers(), book.getTitle(), book.getMetadata().getAuthors(), book.getTableOfContents()); + return createNCXResource(book.getMetadata().getIdentifiers(), book.getTitle().getValue(), 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(); @@ -198,7 +200,7 @@ public static void write(XmlSerializer serializer, List<Identifier> identifiers, serializer.startTag(NAMESPACE_NCX, NCXTags.head); for(Identifier identifier: identifiers) { - writeMetaElement(identifier.getScheme(), identifier.getValue(), serializer); + writeMetaElement(identifier.getScheme().getName(), identifier.getValue(), serializer); } writeMetaElement("generator", Constants.EPUBLIB_GENERATOR_NAME, serializer); diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/epub/NavDocument.java b/epublib-core/src/main/java/nl/siegmann/epublib/epub/NavDocument.java new file mode 100644 index 00000000..8bf46823 --- /dev/null +++ b/epublib-core/src/main/java/nl/siegmann/epublib/epub/NavDocument.java @@ -0,0 +1,97 @@ +package nl.siegmann.epublib.epub; + +import nl.siegmann.epublib.Constants; +import nl.siegmann.epublib.domain.Book; +import nl.siegmann.epublib.domain.Resource; +import nl.siegmann.epublib.domain.TOCReference; +import nl.siegmann.epublib.domain.TableOfContents; +import nl.siegmann.epublib.util.ResourceUtil; +import nl.siegmann.epublib.util.StringUtil; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static nl.siegmann.epublib.Constants.NAMESPACE_XHTML; + +public class NavDocument { + private static final Logger log = Logger.getLogger(NavDocument.class.getName()); + + private static final String NAV_TAG = "nav"; + private static final String A_HREF_TAG = "a"; + private static final String HREF_ATTR = "href"; + + public static void read(Book book) { + Resource navResource = book.getNavResource(); + try { + Document navDocument = ResourceUtil.getAsDocument(navResource); + Element navMapElement = DOMUtil.getFirstElementByTagNameNS(navDocument.getDocumentElement(), NAMESPACE_XHTML, NAV_TAG); + if (null != navMapElement) { + NodeList nodes = navMapElement.getElementsByTagNameNS(NAMESPACE_XHTML, A_HREF_TAG); + if(nodes.getLength() > 0) { + List<TOCReference> tocReferences = readTOCReferences(nodes, book); + TableOfContents tableOfContents = new TableOfContents(tocReferences); + book.setTableOfContents(tableOfContents); + } + } + } catch (Exception e) { + log.log(Level.SEVERE, e.getMessage(), e); + } + } + + private static List<TOCReference> readTOCReferences(NodeList navPoints, Book book) { + if(navPoints == null) { + return new ArrayList<>(); + } + List<TOCReference> result = new ArrayList<>(navPoints.getLength()); + for(int i = 0; i < navPoints.getLength(); i++) { + Node node = navPoints.item(i); + if (node.getNodeType() != Document.ELEMENT_NODE) { + continue; + } + if (! (node.getLocalName().equals(A_HREF_TAG))) { + continue; + } + TOCReference tocReference = readTOCReference((Element) node, book); + result.add(tocReference); + } + return result; + } + + static TOCReference readTOCReference(Element navPoint, Book book) { + String label = DOMUtil.getTextChildrenContent(navPoint); + + String navResourceHref = book.getNavResource().getHref(); + String navResourceRoot = StringUtil.substringBeforeLast(navResourceHref, '/'); + if (navResourceRoot.length() == navResourceHref.length()) { + navResourceRoot = ""; + } else { + navResourceRoot = navResourceRoot + "/"; + } + String reference = StringUtil.collapsePathDots(navResourceRoot + readNavReference(navPoint)); + String href = StringUtil.substringBefore(reference, Constants.FRAGMENT_SEPARATOR_CHAR); + String fragmentId = StringUtil.substringAfter(reference, Constants.FRAGMENT_SEPARATOR_CHAR); + Resource resource = book.getResources().getByHref(href); + if (resource == null) { + log.severe("Resource with href " + href + " in NCX document not found"); + } + return new TOCReference(label, resource, fragmentId); + } + + private static String readNavReference(Element navPoint) { + String result = DOMUtil.getAttribute(navPoint, NAMESPACE_XHTML, HREF_ATTR); + try { + result = URLDecoder.decode(result, Constants.CHARACTER_ENCODING); + } catch (UnsupportedEncodingException e) { + log.severe(e.getMessage()); + } + return result; + } +} diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentBase.java b/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentBase.java index 564fc289..84ad74de 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentBase.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentBase.java @@ -68,6 +68,11 @@ protected interface OPFAttributes { String version = "version"; String scheme = "scheme"; String property = "property"; + String properties = "properties"; + String refines = "refines"; + String identifier_type = "identifier-type"; + String title_type = "title-type"; + String prefix = "prefix"; } protected interface OPFValues { @@ -75,5 +80,8 @@ protected interface OPFValues { String reference_cover = "cover"; String no = "no"; String generator = "generator"; + String nav = "nav"; + String svg = "svg"; + String scripted = "scripted"; } -} \ No newline at end of file +} diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentMetadataReader.java b/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentMetadataReader.java index 2ce2de0b..15724395 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentMetadataReader.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentMetadataReader.java @@ -1,55 +1,48 @@ package nl.siegmann.epublib.epub; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.xml.namespace.QName; - -import nl.siegmann.epublib.domain.Author; -import nl.siegmann.epublib.domain.Date; -import nl.siegmann.epublib.domain.Identifier; -import nl.siegmann.epublib.domain.Metadata; +import nl.siegmann.epublib.domain.*; import nl.siegmann.epublib.util.StringUtil; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import javax.xml.namespace.QName; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + /** * Reads the package document metadata. - * + * <p> * In its own separate class because the PackageDocumentReader became a bit large and unwieldy. - * - * @author paul * + * @author paul */ // package class PackageDocumentMetadataReader extends PackageDocumentBase { - private static final Logger log = LoggerFactory.getLogger(PackageDocumentMetadataReader.class); - - public static Metadata readMetadata(Document packageDocument) { - Metadata result = new Metadata(); - Element metadataElement = DOMUtil.getFirstElementByTagNameNS(packageDocument.getDocumentElement(), NAMESPACE_OPF, OPFTags.metadata); - if(metadataElement == null) { - log.error("Package does not contain element " + OPFTags.metadata); - return result; - } - result.setTitles(DOMUtil.getElementsTextChild(metadataElement, NAMESPACE_DUBLIN_CORE, DCTags.title)); - result.setPublishers(DOMUtil.getElementsTextChild(metadataElement, NAMESPACE_DUBLIN_CORE, DCTags.publisher)); - result.setDescriptions(DOMUtil.getElementsTextChild(metadataElement, NAMESPACE_DUBLIN_CORE, DCTags.description)); - result.setRights(DOMUtil.getElementsTextChild(metadataElement, NAMESPACE_DUBLIN_CORE, DCTags.rights)); - result.setTypes(DOMUtil.getElementsTextChild(metadataElement, NAMESPACE_DUBLIN_CORE, DCTags.type)); - result.setSubjects(DOMUtil.getElementsTextChild(metadataElement, NAMESPACE_DUBLIN_CORE, DCTags.subject)); - result.setIdentifiers(readIdentifiers(metadataElement)); - result.setAuthors(readCreators(metadataElement)); - result.setContributors(readContributors(metadataElement)); - result.setDates(readDates(metadataElement)); + private static final Logger log = Logger.getLogger(PackageDocumentMetadataReader.class.getName()); + + public static Metadata readMetadata(Document packageDocument) { + Metadata result = new Metadata(); + Element metadataElement = DOMUtil.getFirstElementByTagNameNS(packageDocument.getDocumentElement(), NAMESPACE_OPF, OPFTags.metadata); + if (metadataElement == null) { + log.severe("Package does not contain element " + OPFTags.metadata); + return result; + } + result.setTitles(readTitles(metadataElement)); + result.setPublishers(DOMUtil.getElementsTextChild(metadataElement, NAMESPACE_DUBLIN_CORE, DCTags.publisher)); + result.setDescriptions(DOMUtil.getElementsTextChild(metadataElement, NAMESPACE_DUBLIN_CORE, DCTags.description)); + result.setRights(DOMUtil.getElementsTextChild(metadataElement, NAMESPACE_DUBLIN_CORE, DCTags.rights)); + result.setTypes(DOMUtil.getElementsTextChild(metadataElement, NAMESPACE_DUBLIN_CORE, DCTags.type)); + result.setSubjects(DOMUtil.getElementsTextChild(metadataElement, NAMESPACE_DUBLIN_CORE, DCTags.subject)); + result.setIdentifiers(readIdentifiers(metadataElement)); + result.setAuthors(readCreators(metadataElement)); + result.setContributors(readContributors(metadataElement)); + result.setDates(readDates(metadataElement)); result.setOtherProperties(readOtherProperties(metadataElement)); result.setMetaAttributes(readMetaProperties(metadataElement)); Element languageTag = DOMUtil.getFirstElementByTagNameNS(metadataElement, NAMESPACE_DUBLIN_CORE, DCTags.language); @@ -58,138 +51,216 @@ public static Metadata readMetadata(Document packageDocument) { } - return result; - } - - /** - * consumes meta tags that have a property attribute as defined in the standard. For example: - * <meta property="rendition:layout">pre-paginated</meta> - * @param metadataElement - * @return - */ - private static Map<QName, String> readOtherProperties(Element metadataElement) { - Map<QName, String> result = new HashMap<QName, String>(); - - NodeList metaTags = metadataElement.getElementsByTagName(OPFTags.meta); - for (int i = 0; i < metaTags.getLength(); i++) { - Node metaNode = metaTags.item(i); - Node property = metaNode.getAttributes().getNamedItem(OPFAttributes.property); - if (property != null) { - String name = property.getNodeValue(); - String value = metaNode.getTextContent(); - result.put(new QName(name), value); - } - } - - return result; - } - - /** - * consumes meta tags that have a property attribute as defined in the standard. For example: - * <meta property="rendition:layout">pre-paginated</meta> - * @param metadataElement - * @return - */ - private static Map<String, String> readMetaProperties(Element metadataElement) { - Map<String, String> result = new HashMap<String, String>(); - - NodeList metaTags = metadataElement.getElementsByTagName(OPFTags.meta); - for (int i = 0; i < metaTags.getLength(); i++) { - Element metaElement = (Element) metaTags.item(i); - String name = metaElement.getAttribute(OPFAttributes.name); - String value = metaElement.getAttribute(OPFAttributes.content); - result.put(name, value); - } - - return result; - } - - private static String getBookIdId(Document document) { - Element packageElement = DOMUtil.getFirstElementByTagNameNS(document.getDocumentElement(), NAMESPACE_OPF, OPFTags.packageTag); - if(packageElement == null) { - return null; - } - String result = packageElement.getAttributeNS(NAMESPACE_OPF, OPFAttributes.uniqueIdentifier); - return result; - } - - private static List<Author> readCreators(Element metadataElement) { - return readAuthors(DCTags.creator, metadataElement); - } - - private static List<Author> readContributors(Element metadataElement) { - return readAuthors(DCTags.contributor, metadataElement); - } - - private static List<Author> readAuthors(String authorTag, Element metadataElement) { - NodeList elements = metadataElement.getElementsByTagNameNS(NAMESPACE_DUBLIN_CORE, authorTag); - List<Author> result = new ArrayList<Author>(elements.getLength()); - for(int i = 0; i < elements.getLength(); i++) { - Element authorElement = (Element) elements.item(i); - Author author = createAuthor(authorElement); - if (author != null) { - result.add(author); - } - } - return result; - - } - - private static List<Date> readDates(Element metadataElement) { - NodeList elements = metadataElement.getElementsByTagNameNS(NAMESPACE_DUBLIN_CORE, DCTags.date); - List<Date> result = new ArrayList<Date>(elements.getLength()); - for(int i = 0; i < elements.getLength(); i++) { - Element dateElement = (Element) elements.item(i); - Date date; - try { - date = new Date(DOMUtil.getTextChildrenContent(dateElement), dateElement.getAttributeNS(NAMESPACE_OPF, OPFAttributes.event)); - result.add(date); - } catch(IllegalArgumentException e) { - log.error(e.getMessage()); - } - } - return result; - - } - - private static Author createAuthor(Element authorElement) { - String authorString = DOMUtil.getTextChildrenContent(authorElement); - if (StringUtil.isBlank(authorString)) { - return null; - } - int spacePos = authorString.lastIndexOf(' '); - Author result; - if(spacePos < 0) { - result = new Author(authorString); - } else { - result = new Author(authorString.substring(0, spacePos), authorString.substring(spacePos + 1)); - } - result.setRole(authorElement.getAttributeNS(NAMESPACE_OPF, OPFAttributes.role)); - return result; - } - - - private static List<Identifier> readIdentifiers(Element metadataElement) { - NodeList identifierElements = metadataElement.getElementsByTagNameNS(NAMESPACE_DUBLIN_CORE, DCTags.identifier); - if(identifierElements.getLength() == 0) { - log.error("Package does not contain element " + DCTags.identifier); - return new ArrayList<Identifier>(); - } - String bookIdId = getBookIdId(metadataElement.getOwnerDocument()); - List<Identifier> result = new ArrayList<Identifier>(identifierElements.getLength()); - for(int i = 0; i < identifierElements.getLength(); i++) { - Element identifierElement = (Element) identifierElements.item(i); - String schemeName = identifierElement.getAttributeNS(NAMESPACE_OPF, DCAttributes.scheme); - String identifierValue = DOMUtil.getTextChildrenContent(identifierElement); - if (StringUtil.isBlank(identifierValue)) { - continue; - } - Identifier identifier = new Identifier(schemeName, identifierValue); - if(identifierElement.getAttribute("id").equals(bookIdId) ) { - identifier.setBookId(true); - } - result.add(identifier); - } - return result; - } + return result; + } + + private static List<Title> readTitles(Element metadataElement) { + List<Title> result = new ArrayList<>(); + NodeList titleElements = metadataElement.getOwnerDocument().getElementsByTagNameNS(NAMESPACE_DUBLIN_CORE, DCTags.title); + + for (int j = 0; j < titleElements.getLength(); j++) { + Node titleElement = titleElements.item(j); + result.add( + new Title( + titleElement.getTextContent(), + findTitleType(titleElement, metadataElement) + ) + ); + } + return result; + } + + private static String findTitleType(Node titleElement, Element metadataElement) { + // Try to find redefine as used in epub 3 + NodeList metaElements = metadataElement.getOwnerDocument().getElementsByTagNameNS("*", "meta"); + for (int j = 0; j < metaElements.getLength(); j++) { + Node metaElement = metaElements.item(j); + Node refines = metaElement.getAttributes().getNamedItem(OPFAttributes.refines); + Node property = metaElement.getAttributes().getNamedItem(OPFAttributes.property); + if ( + null != refines + && null != property + && refines.getNodeValue().equals( + "#" + DOMUtil.getAttribute( + titleElement, + EpubWriter.EMPTY_NAMESPACE_PREFIX, + OPFAttributes.id + ) + ) + ) { + return metaElement.getTextContent(); + } + } + return null; + } + + /** + * consumes meta tags that have a property attribute as defined in the standard. For example: + * <meta property="rendition:layout">pre-paginated</meta> + */ + private static Map<QName, String> readOtherProperties(Element metadataElement) { + Map<QName, String> result = new HashMap<>(); + + NodeList metaTags = metadataElement.getElementsByTagName(OPFTags.meta); + for (int i = 0; i < metaTags.getLength(); i++) { + Node metaNode = metaTags.item(i); + Node property = metaNode.getAttributes().getNamedItem(OPFAttributes.property); + Node refines = metaNode.getAttributes().getNamedItem(OPFAttributes.refines); + if (property != null && refines == null) { + String name = property.getNodeValue(); + String value = metaNode.getTextContent(); + result.put(new QName(name), value); + } + } + + return result; + } + + /** + * consumes meta tags that have a property attribute as defined in the standard. For example: + * <meta property="rendition:layout">pre-paginated</meta> + */ + private static Map<String, String> readMetaProperties(Element metadataElement) { + Map<String, String> result = new HashMap<>(); + + NodeList metaTags = metadataElement.getElementsByTagName(OPFTags.meta); + for (int i = 0; i < metaTags.getLength(); i++) { + Element metaElement = (Element) metaTags.item(i); + String name = metaElement.getAttribute(OPFAttributes.name); + String value = metaElement.getAttribute(OPFAttributes.content); + result.put(name, value); + } + + return result; + } + + private static String getBookIdId(Document document) { + Element packageElement = DOMUtil.getFirstElementByTagNameNS(document.getDocumentElement(), NAMESPACE_OPF, OPFTags.packageTag); + if (packageElement == null) { + return null; + } + return packageElement.getAttributeNS(NAMESPACE_OPF, OPFAttributes.uniqueIdentifier); + } + + private static List<Author> readCreators(Element metadataElement) { + return readAuthors(DCTags.creator, metadataElement); + } + + private static List<Author> readContributors(Element metadataElement) { + return readAuthors(DCTags.contributor, metadataElement); + } + + private static List<Author> readAuthors(String authorTag, Element metadataElement) { + NodeList elements = metadataElement.getElementsByTagNameNS(NAMESPACE_DUBLIN_CORE, authorTag); + List<Author> result = new ArrayList<>(elements.getLength()); + for (int i = 0; i < elements.getLength(); i++) { + Element authorElement = (Element) elements.item(i); + Author author = createAuthor(authorElement); + if (author != null) { + result.add(author); + } + } + return result; + + } + + private static List<Date> readDates(Element metadataElement) { + NodeList elements = metadataElement.getElementsByTagNameNS(NAMESPACE_DUBLIN_CORE, DCTags.date); + List<Date> result = new ArrayList<>(elements.getLength()); + for (int i = 0; i < elements.getLength(); i++) { + Element dateElement = (Element) elements.item(i); + Date date; + try { + date = new Date(DOMUtil.getTextChildrenContent(dateElement), dateElement.getAttributeNS(NAMESPACE_OPF, OPFAttributes.event)); + result.add(date); + } catch (IllegalArgumentException e) { + log.severe(e.getMessage()); + } + } + return result; + + } + + private static Author createAuthor(Element authorElement) { + String authorString = DOMUtil.getTextChildrenContent(authorElement); + if (StringUtil.isBlank(authorString)) { + return null; + } + int spacePos = authorString.lastIndexOf(' '); + Author result; + if (spacePos < 0) { + result = new Author(authorString); + } else { + result = new Author(authorString.substring(0, spacePos), authorString.substring(spacePos + 1)); + } + + String role = DOMUtil.getAttribute(authorElement, NAMESPACE_OPF, OPFAttributes.role); + if (StringUtil.isNotBlank(role)) { + result.setRole(role); + } else { + // Try to find redefine as used in epub 3 + NodeList metaElements = authorElement.getOwnerDocument().getElementsByTagNameNS("*", "meta"); + for (int j = 0; j < metaElements.getLength(); j++) { + Node metaElement = metaElements.item(j); + Node refines = metaElement.getAttributes().getNamedItem(OPFAttributes.refines); + Node property = metaElement.getAttributes().getNamedItem(OPFAttributes.property); + Node schemeNode = metaElement.getAttributes().getNamedItem(OPFAttributes.scheme); + if ( + null != refines + && null != property + && null != schemeNode + && refines.getNodeValue().equals("#" + authorElement.getAttribute("id")) + && OPFAttributes.role.equals(property.getNodeValue()) + ) { + result.setRole(metaElement.getTextContent()); + result.setScheme(new Scheme(schemeNode.getNodeValue())); + } + } + } + return result; + } + + + private static List<Identifier> readIdentifiers(Element metadataElement) { + NodeList identifierElements = metadataElement.getElementsByTagNameNS(NAMESPACE_DUBLIN_CORE, DCTags.identifier); + if (identifierElements.getLength() == 0) { + log.severe("Package does not contain element " + DCTags.identifier); + return new ArrayList<>(); + } + String bookIdId = getBookIdId(metadataElement.getOwnerDocument()); + List<Identifier> result = new ArrayList<>(identifierElements.getLength()); + for (int i = 0; i < identifierElements.getLength(); i++) { + Element identifierElement = (Element) identifierElements.item(i); + Scheme scheme = new Scheme(identifierElement.getAttributeNS(NAMESPACE_OPF, DCAttributes.scheme)); + if (StringUtil.isBlank(scheme.getName())) { + //Try to find redefine meta element as used in opf version 3 + NodeList metaElements = identifierElement.getOwnerDocument().getElementsByTagNameNS("*", "meta"); + for (int j = 0; j < metaElements.getLength(); j++) { + Node metaElement = metaElements.item(j); + Node refines = metaElement.getAttributes().getNamedItem(OPFAttributes.refines); + Node property = metaElement.getAttributes().getNamedItem(OPFAttributes.property); + Node schemeNode = metaElement.getAttributes().getNamedItem(OPFAttributes.scheme); + if ( + null != refines + && null != property + && null != schemeNode + && refines.getNodeValue().equals("#" + identifierElement.getAttribute("id")) + && "identifier-type".equals(property.getNodeValue()) + ) { + scheme = new Scheme(schemeNode.getNodeValue(), metaElement.getTextContent()); + } + } + } + String identifierValue = DOMUtil.getTextChildrenContent(identifierElement); + if (StringUtil.isBlank(identifierValue)) { + continue; + } + Identifier identifier = new Identifier(scheme, identifierValue); + if (identifierElement.getAttribute("id").equals(bookIdId)) { + identifier.setBookId(true); + } + result.add(identifier); + } + return result; + } } diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentMetadataWriter.java b/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentMetadataWriter.java index 58839fc4..315faecf 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentMetadataWriter.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentMetadataWriter.java @@ -1,66 +1,70 @@ package nl.siegmann.epublib.epub; -import java.io.IOException; -import java.util.List; -import java.util.Map; - -import javax.xml.namespace.QName; - import nl.siegmann.epublib.Constants; import nl.siegmann.epublib.domain.Author; import nl.siegmann.epublib.domain.Book; import nl.siegmann.epublib.domain.Date; import nl.siegmann.epublib.domain.Identifier; +import nl.siegmann.epublib.domain.Relator; +import nl.siegmann.epublib.domain.Title; import nl.siegmann.epublib.util.StringUtil; - import org.xmlpull.v1.XmlSerializer; +import javax.xml.namespace.QName; +import java.io.IOException; +import java.util.List; +import java.util.Map; + public class PackageDocumentMetadataWriter extends PackageDocumentBase { /** * Writes the book's metadata. - * - * @param book - * @param serializer - * @throws IOException - * @throws IllegalStateException - * @throws IllegalArgumentException */ public static void writeMetaData(Book book, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { - serializer.startTag(NAMESPACE_OPF, OPFTags.metadata); - serializer.setPrefix(PREFIX_DUBLIN_CORE, NAMESPACE_DUBLIN_CORE); + serializer.setPrefix(PREFIX_DUBLIN_CORE, NAMESPACE_DUBLIN_CORE); + + serializer.startTag(NAMESPACE_OPF, OPFTags.metadata); + + serializer.setPrefix(PREFIX_DUBLIN_CORE, NAMESPACE_DUBLIN_CORE); serializer.setPrefix(PREFIX_OPF, NAMESPACE_OPF); - - writeIdentifiers(book.getMetadata().getIdentifiers(), serializer); - writeSimpleMetdataElements(DCTags.title, book.getMetadata().getTitles(), serializer); - writeSimpleMetdataElements(DCTags.subject, book.getMetadata().getSubjects(), serializer); - writeSimpleMetdataElements(DCTags.description, book.getMetadata().getDescriptions(), serializer); - writeSimpleMetdataElements(DCTags.publisher, book.getMetadata().getPublishers(), serializer); - writeSimpleMetdataElements(DCTags.type, book.getMetadata().getTypes(), serializer); - writeSimpleMetdataElements(DCTags.rights, book.getMetadata().getRights(), serializer); + + if(isEpub3(book)) { + writeIdentifiersEpub3(book.getMetadata().getIdentifiers(), serializer); + } else { + writeIdentifiersEpub2(book.getMetadata().getIdentifiers(), serializer); + } + writeTitles(book.getMetadata().getTitles(), serializer); + writeSimpleMetadataElements(DCTags.subject, book.getMetadata().getSubjects(), serializer); + writeSimpleMetadataElements(DCTags.description, book.getMetadata().getDescriptions(), serializer); + writeSimpleMetadataElements(DCTags.publisher, book.getMetadata().getPublishers(), serializer); + writeSimpleMetadataElements(DCTags.type, book.getMetadata().getTypes(), serializer); + writeSimpleMetadataElements(DCTags.rights, book.getMetadata().getRights(), serializer); // write authors + int countAuthors = 1; for(Author author: book.getMetadata().getAuthors()) { - serializer.startTag(NAMESPACE_DUBLIN_CORE, DCTags.creator); - serializer.attribute(NAMESPACE_OPF, OPFAttributes.role, author.getRelator().getCode()); - serializer.attribute(NAMESPACE_OPF, OPFAttributes.file_as, author.getLastname() + ", " + author.getFirstname()); - serializer.text(author.getFirstname() + " " + author.getLastname()); - serializer.endTag(NAMESPACE_DUBLIN_CORE, DCTags.creator); + if(isEpub3(book)){ + writeAuthorEpub3Syntax(serializer, author, DCTags.creator, countAuthors++); + } else { + writeAuthorEpub2Syntax(serializer, author, DCTags.creator); + } } // write contributors + countAuthors = 1; for(Author author: book.getMetadata().getContributors()) { - serializer.startTag(NAMESPACE_DUBLIN_CORE, DCTags.contributor); - serializer.attribute(NAMESPACE_OPF, OPFAttributes.role, author.getRelator().getCode()); - serializer.attribute(NAMESPACE_OPF, OPFAttributes.file_as, author.getLastname() + ", " + author.getFirstname()); - serializer.text(author.getFirstname() + " " + author.getLastname()); - serializer.endTag(NAMESPACE_DUBLIN_CORE, DCTags.contributor); + if(isEpub3(book)){ + writeAuthorEpub3Syntax(serializer, author, DCTags.contributor, countAuthors++); + } else { + writeAuthorEpub2Syntax(serializer, author, DCTags.contributor); + } } // write dates for (Date date: book.getMetadata().getDates()) { - serializer.startTag(NAMESPACE_DUBLIN_CORE, DCTags.date); + serializer.setPrefix(PREFIX_OPF, NAMESPACE_OPF); + serializer.startTag(NAMESPACE_DUBLIN_CORE, DCTags.date); if (date.getEvent() != null) { serializer.attribute(NAMESPACE_OPF, OPFAttributes.event, date.getEvent().toString()); } @@ -78,15 +82,22 @@ public static void writeMetaData(Book book, XmlSerializer serializer) throws Ill // write other properties if(book.getMetadata().getOtherProperties() != null) { for(Map.Entry<QName, String> mapEntry: book.getMetadata().getOtherProperties().entrySet()) { - serializer.startTag(mapEntry.getKey().getNamespaceURI(), OPFTags.meta); + String namespaceURI = mapEntry.getKey().getNamespaceURI(); + serializer.startTag( + StringUtil.isNotBlank(namespaceURI) ? namespaceURI : NAMESPACE_OPF, + OPFTags.meta + ); serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.property, mapEntry.getKey().getLocalPart()); serializer.text(mapEntry.getValue()); - serializer.endTag(mapEntry.getKey().getNamespaceURI(), OPFTags.meta); + serializer.endTag( + StringUtil.isNotBlank(namespaceURI) ? namespaceURI : NAMESPACE_OPF, + OPFTags.meta + ); } } - // write coverimage + // write cover image if(book.getCoverImage() != null) { // write the cover image serializer.startTag(NAMESPACE_OPF, OPFTags.meta); serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.name, OPFValues.meta_cover); @@ -102,8 +113,75 @@ public static void writeMetaData(Book book, XmlSerializer serializer) throws Ill serializer.endTag(NAMESPACE_OPF, OPFTags.metadata); } - - private static void writeSimpleMetdataElements(String tagName, List<String> values, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { + + private static void writeTitles(List<Title> titles, final XmlSerializer serializer) throws IOException { + int counter = 0; + for (Title title : titles) { + writeTitle(title, serializer, counter++); + } + } + + private static void writeTitle(Title title, XmlSerializer serializer, int counter) throws IOException { + String titleId = DCTags.title + counter; + serializer.startTag(NAMESPACE_DUBLIN_CORE, DCTags.title); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.id, titleId); + serializer.text(title.getValue()); + serializer.endTag(NAMESPACE_DUBLIN_CORE, DCTags.title); + if(StringUtil.isNotBlank(title.getType())){ + serializer.startTag(NAMESPACE_OPF, OPFTags.meta); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, "refines", "#" + titleId); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.property, OPFAttributes.title_type); + serializer.text(title.getType()); + serializer.endTag(NAMESPACE_OPF, OPFTags.meta); + } + } + + private static boolean isEpub3(Book book) { + return null != book.getOpfResource() && book.getOpfResource().getVersion().equals("3.0"); + } + + private static void writeAuthorEpub2Syntax(XmlSerializer serializer, Author author, String creator) throws IOException { + serializer.setPrefix(PREFIX_OPF, NAMESPACE_OPF); + serializer.startTag(NAMESPACE_DUBLIN_CORE, creator); + if(null != author.getRelator()) { + serializer.attribute(NAMESPACE_OPF, OPFAttributes.role, author.getRelator().getCode()); + } + serializer.attribute(NAMESPACE_OPF, OPFAttributes.file_as, author.getLastname() + ", " + author.getFirstname()); + serializer.text(author.getFirstname() + " " + author.getLastname()); + serializer.endTag(NAMESPACE_DUBLIN_CORE, creator); + } + + private static void writeAuthorEpub3Syntax(XmlSerializer serializer, Author author, String creator, int countAuthors) throws IOException { + String authorId = creator + countAuthors; + serializer.startTag(NAMESPACE_DUBLIN_CORE, creator); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.id, authorId); + serializer.text(author.getFirstname() + " " + author.getLastname()); + serializer.endTag(NAMESPACE_DUBLIN_CORE, creator); + + if(!( + null == author.getScheme() + && (null == author.getRelator() || Relator.AUTHOR.getName().equals(author.getRelator().getCode())) + )){ + serializer.startTag(NAMESPACE_OPF, OPFTags.meta); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, "refines", "#" + authorId); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.property, OPFAttributes.role); + if(null != author.getScheme()) { + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.scheme, author.getScheme().getName()); + } + serializer.text(author.getRelator().getCode()); + serializer.endTag(NAMESPACE_OPF, OPFTags.meta); + } + + + serializer.startTag(NAMESPACE_OPF, OPFTags.meta); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, "refines", "#" + authorId); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.property, OPFAttributes.file_as); + serializer.text(author.getLastname() + ", " + author.getFirstname()); + serializer.endTag(NAMESPACE_OPF, OPFTags.meta); + + } + + private static void writeSimpleMetadataElements(String tagName, List<String> values, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { for(String value: values) { if (StringUtil.isBlank(value)) { continue; @@ -119,23 +197,16 @@ private static void writeSimpleMetdataElements(String tagName, List<String> valu * Writes out the complete list of Identifiers to the package document. * The first identifier for which the bookId is true is made the bookId identifier. * If no identifier has bookId == true then the first bookId identifier is written as the primary. - * - * @param identifiers - * @param serializer - * @throws IOException - * @throws IllegalStateException - * @throws IllegalArgumentException - * @ */ - private static void writeIdentifiers(List<Identifier> identifiers, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { + private static void writeIdentifiersEpub2(List<Identifier> identifiers, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { Identifier bookIdIdentifier = Identifier.getBookIdIdentifier(identifiers); if(bookIdIdentifier == null) { return; } - + serializer.startTag(NAMESPACE_DUBLIN_CORE, DCTags.identifier); serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, DCAttributes.id, BOOK_ID_ID); - serializer.attribute(NAMESPACE_OPF, OPFAttributes.scheme, bookIdIdentifier.getScheme()); + serializer.attribute(NAMESPACE_OPF, OPFAttributes.scheme, bookIdIdentifier.getScheme().getName()); serializer.text(bookIdIdentifier.getValue()); serializer.endTag(NAMESPACE_DUBLIN_CORE, DCTags.identifier); @@ -144,10 +215,52 @@ private static void writeIdentifiers(List<Identifier> identifiers, XmlSerializer continue; } serializer.startTag(NAMESPACE_DUBLIN_CORE, DCTags.identifier); - serializer.attribute(NAMESPACE_OPF, "scheme", identifier.getScheme()); + if(null != identifier.getScheme() && StringUtil.isNotBlank(identifier.getScheme().getName())) { + serializer.attribute(NAMESPACE_OPF, "scheme", identifier.getScheme().getName()); + } serializer.text(identifier.getValue()); serializer.endTag(NAMESPACE_DUBLIN_CORE, DCTags.identifier); } } + /** + * Writes out the complete list of Identifiers to the package document. + * 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. + */ + private static void writeIdentifiersEpub3(List<Identifier> identifiers, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { + Identifier bookIdIdentifier = Identifier.getBookIdIdentifier(identifiers); + if(bookIdIdentifier == null) { + return; + } + + writeIdentifier(serializer, bookIdIdentifier, 0); + + int idCount = 1; + for(Identifier identifier: identifiers.subList(1, identifiers.size())) { + if(identifier == bookIdIdentifier) { + continue; + } + writeIdentifier(serializer, bookIdIdentifier, idCount++); + } + } + + private static void writeIdentifier(XmlSerializer serializer, Identifier bookIdIdentifier, int counter) throws IOException { + String bookId = (counter > 0) ? BOOK_ID_ID.concat(String.valueOf(counter)) : BOOK_ID_ID; + serializer.startTag(NAMESPACE_DUBLIN_CORE, DCTags.identifier); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, DCAttributes.id, bookId); + serializer.text(bookIdIdentifier.getValue()); + serializer.endTag(NAMESPACE_DUBLIN_CORE, DCTags.identifier); + + String schemeValue = bookIdIdentifier.getScheme().getValue(); + if(StringUtil.isNotBlank(schemeValue)) { + serializer.startTag(NAMESPACE_OPF, OPFTags.meta); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.refines, "#" + bookId); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.property, OPFAttributes.identifier_type); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.scheme, bookIdIdentifier.getScheme().getName()); + serializer.text(schemeValue); + serializer.endTag(NAMESPACE_OPF, OPFTags.meta); + } + } + } diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentReader.java b/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentReader.java index 8fa34895..362b7250 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentReader.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentReader.java @@ -1,72 +1,84 @@ package nl.siegmann.epublib.epub; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.xml.parsers.ParserConfigurationException; - import nl.siegmann.epublib.Constants; -import nl.siegmann.epublib.domain.Book; -import nl.siegmann.epublib.domain.Guide; -import nl.siegmann.epublib.domain.GuideReference; -import nl.siegmann.epublib.domain.MediaType; -import nl.siegmann.epublib.domain.Resource; -import nl.siegmann.epublib.domain.Resources; -import nl.siegmann.epublib.domain.Spine; -import nl.siegmann.epublib.domain.SpineReference; +import nl.siegmann.epublib.domain.*; import nl.siegmann.epublib.service.MediatypeService; import nl.siegmann.epublib.util.ResourceUtil; import nl.siegmann.epublib.util.StringUtil; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.*; +import java.util.logging.Logger; + /** * Reads the opf package document as defined by namespace http://www.idpf.org/2007/opf - * - * @author paul * + * @author paul */ public class PackageDocumentReader extends PackageDocumentBase { - - private static final Logger log = LoggerFactory.getLogger(PackageDocumentReader.class); - private static final String[] POSSIBLE_NCX_ITEM_IDS = new String[] {"toc", "ncx", "ncxtoc"}; - - - public static void read(Resource packageResource, EpubReader epubReader, Book book, Resources resources) throws UnsupportedEncodingException, SAXException, IOException, ParserConfigurationException { - Document packageDocument = ResourceUtil.getAsDocument(packageResource); - String packageHref = packageResource.getHref(); - resources = fixHrefs(packageHref, resources); - readGuide(packageDocument, epubReader, book, resources); - - // Books sometimes use non-identifier ids. We map these here to legal ones - Map<String, String> idMapping = new HashMap<String, String>(); - - resources = readManifest(packageDocument, packageHref, epubReader, resources, idMapping); - book.setResources(resources); - readCover(packageDocument, book); - book.setMetadata(PackageDocumentMetadataReader.readMetadata(packageDocument)); - book.setSpine(readSpine(packageDocument, book.getResources(), idMapping)); - - // if we did not find a cover page then we make the first page of the book the cover page - if (book.getCoverPage() == null && book.getSpine().size() > 0) { - book.setCoverPage(book.getSpine().getResource(0)); - } - } - + + private static final Logger log = Logger.getLogger(PackageDocumentReader.class.getName()); + private static final String[] POSSIBLE_NCX_ITEM_IDS = new String[]{"toc", "ncx", "ncxtoc"}; + + + public static void read(OpfResource packageResource, Book book, Resources resources) throws SAXException, IOException, ParserConfigurationException { + Document packageDocument = ResourceUtil.getAsDocument(packageResource); + String packageHref = packageResource.getHref(); + resources = fixHrefs(packageHref, resources); + if (null != packageDocument) { + packageResource.setVersion( + getOpfVersion(packageDocument) + ); + packageResource.setPrefix( + getOpfPrefix(packageDocument) + ); + } + readGuide(packageDocument, book, resources); + + // Books sometimes use non-identifier ids. We map these here to legal ones + Map<String, String> idMapping = new HashMap<>(); + + resources = readManifest(packageDocument, resources, idMapping); + book.setResources(resources); + book.setNavResource(resources.getNavResource()); + readCover(packageDocument, book); + book.setMetadata(PackageDocumentMetadataReader.readMetadata(packageDocument)); + book.setSpine(readSpine(packageDocument, book.getResources(), idMapping)); + + // if we did not find a cover page then we make the first page of the book the cover page + if (book.getCoverPage() == null && book.getSpine().size() > 0) { + book.setCoverPage(book.getSpine().getResource(0)); + } + } + + private static String getOpfVersion(Document packageDocument) { + NodeList packageNodes = packageDocument.getElementsByTagNameNS("*", "package"); + if (packageNodes.getLength() <= 0) return null; + Node packageNode = packageNodes.item(0); + if (!packageNode.hasAttributes()) return null; + Node versionNode = packageNode.getAttributes().getNamedItem("version"); + if (null == versionNode) return null; + return versionNode.getNodeValue(); + } + + private static String getOpfPrefix(Document packageDocument) { + NodeList packageNodes = packageDocument.getElementsByTagNameNS("*", "package"); + if (packageNodes.getLength() <= 0) return null; + Node packageNode = packageNodes.item(0); + if (!packageNode.hasAttributes()) return null; + Node prefixNode = packageNode.getAttributes().getNamedItem("prefix"); + if (null == prefixNode) return null; + return prefixNode.getNodeValue(); + } + // private static Resource readCoverImage(Element metadataElement, Resources resources) { // String coverResourceId = DOMUtil.getFindAttributeValue(metadataElement.getOwnerDocument(), NAMESPACE_OPF, OPFTags.meta, OPFAttributes.name, OPFValues.meta_cover, OPFAttributes.content); // if (StringUtil.isBlank(coverResourceId)) { @@ -75,302 +87,282 @@ public static void read(Resource packageResource, EpubReader epubReader, Book bo // Resource coverResource = resources.getByIdOrHref(coverResourceId); // return coverResource; // } - - - - /** - * Reads the manifest containing the resource ids, hrefs and mediatypes. - * - * @param packageDocument - * @param packageHref - * @param epubReader - * @param book - * @param resourcesByHref - * @return a Map with resources, with their id's as key. - */ - private static Resources readManifest(Document packageDocument, String packageHref, - EpubReader epubReader, Resources resources, Map<String, String> idMapping) { - Element manifestElement = DOMUtil.getFirstElementByTagNameNS(packageDocument.getDocumentElement(), NAMESPACE_OPF, OPFTags.manifest); - Resources result = new Resources(); - if(manifestElement == null) { - log.error("Package document does not contain element " + OPFTags.manifest); - return result; - } - NodeList itemElements = manifestElement.getElementsByTagNameNS(NAMESPACE_OPF, OPFTags.item); - for(int i = 0; i < itemElements.getLength(); i++) { - Element itemElement = (Element) itemElements.item(i); - String id = DOMUtil.getAttribute(itemElement, NAMESPACE_OPF, OPFAttributes.id); - String href = DOMUtil.getAttribute(itemElement, NAMESPACE_OPF, OPFAttributes.href); - try { - href = URLDecoder.decode(href, Constants.CHARACTER_ENCODING); - } catch (UnsupportedEncodingException e) { - log.error(e.getMessage()); - } - String mediaTypeName = DOMUtil.getAttribute(itemElement, NAMESPACE_OPF, OPFAttributes.media_type); - Resource resource = resources.remove(href); - if(resource == null) { - log.error("resource with href '" + href + "' not found"); - continue; - } - resource.setId(id); - MediaType mediaType = MediatypeService.getMediaTypeByName(mediaTypeName); - if(mediaType != null) { - resource.setMediaType(mediaType); - } - result.add(resource); - idMapping.put(id, resource.getId()); - } - return result; - } - - - - - /** - * Reads the book's guide. - * Here some more attempts are made at finding the cover page. - * - * @param packageDocument - * @param epubReader - * @param book - * @param resources - */ - private static void readGuide(Document packageDocument, - EpubReader epubReader, Book book, Resources resources) { - Element guideElement = DOMUtil.getFirstElementByTagNameNS(packageDocument.getDocumentElement(), NAMESPACE_OPF, OPFTags.guide); - if(guideElement == null) { - return; - } - Guide guide = book.getGuide(); - NodeList guideReferences = guideElement.getElementsByTagNameNS(NAMESPACE_OPF, OPFTags.reference); - for (int i = 0; i < guideReferences.getLength(); i++) { - Element referenceElement = (Element) guideReferences.item(i); - String resourceHref = DOMUtil.getAttribute(referenceElement, NAMESPACE_OPF, OPFAttributes.href); - if (StringUtil.isBlank(resourceHref)) { - continue; - } - Resource resource = resources.getByHref(StringUtil.substringBefore(resourceHref, Constants.FRAGMENT_SEPARATOR_CHAR)); - if (resource == null) { - log.error("Guide is referencing resource with href " + resourceHref + " which could not be found"); - continue; - } - String type = DOMUtil.getAttribute(referenceElement, NAMESPACE_OPF, OPFAttributes.type); - if (StringUtil.isBlank(type)) { - log.error("Guide is referencing resource with href " + resourceHref + " which is missing the 'type' attribute"); - continue; - } - String title = DOMUtil.getAttribute(referenceElement, NAMESPACE_OPF, OPFAttributes.title); - if (GuideReference.COVER.equalsIgnoreCase(type)) { - continue; // cover is handled elsewhere - } - GuideReference reference = new GuideReference(resource, type, title, StringUtil.substringAfter(resourceHref, Constants.FRAGMENT_SEPARATOR_CHAR)); - guide.addReference(reference); - } - } - - - /** - * Strips off the package prefixes up to the href of the packageHref. - * - * Example: - * If the packageHref is "OEBPS/content.opf" then a resource href like "OEBPS/foo/bar.html" will be turned into "foo/bar.html" - * - * @param packageHref - * @param resourcesByHref - * @return The stripped package href - */ - static Resources fixHrefs(String packageHref, - Resources resourcesByHref) { - int lastSlashPos = packageHref.lastIndexOf('/'); - if(lastSlashPos < 0) { - return resourcesByHref; - } - Resources result = new Resources(); - for(Resource resource: resourcesByHref.getAll()) { - if(StringUtil.isNotBlank(resource.getHref()) - && resource.getHref().length() > lastSlashPos) { - resource.setHref(resource.getHref().substring(lastSlashPos + 1)); - } - result.add(resource); - } - return result; - } - - /** - * Reads the document's spine, containing all sections in reading order. - * - * @param packageDocument - * @param epubReader - * @param book - * @param resourcesById - * @return the document's spine, containing all sections in reading order. - */ - private static Spine readSpine(Document packageDocument, Resources resources, Map<String, String> idMapping) { - - Element spineElement = DOMUtil.getFirstElementByTagNameNS(packageDocument.getDocumentElement(), NAMESPACE_OPF, OPFTags.spine); - if (spineElement == null) { - log.error("Element " + OPFTags.spine + " not found in package document, generating one automatically"); - return generateSpineFromResources(resources); - } - Spine result = new Spine(); - String tocResourceId = DOMUtil.getAttribute(spineElement, NAMESPACE_OPF, OPFAttributes.toc); - result.setTocResource(findTableOfContentsResource(tocResourceId, resources)); - NodeList spineNodes = packageDocument.getElementsByTagNameNS(NAMESPACE_OPF, OPFTags.itemref); - List<SpineReference> spineReferences = new ArrayList<SpineReference>(spineNodes.getLength()); - for(int i = 0; i < spineNodes.getLength(); i++) { - Element spineItem = (Element) spineNodes.item(i); - String itemref = DOMUtil.getAttribute(spineItem, NAMESPACE_OPF, OPFAttributes.idref); - if(StringUtil.isBlank(itemref)) { - log.error("itemref with missing or empty idref"); // XXX - continue; - } - String id = idMapping.get(itemref); - if (id == null) { - id = itemref; - } - Resource resource = resources.getByIdOrHref(id); - if(resource == null) { - log.error("resource with id \'" + id + "\' not found"); - continue; - } - - SpineReference spineReference = new SpineReference(resource); - if (OPFValues.no.equalsIgnoreCase(DOMUtil.getAttribute(spineItem, NAMESPACE_OPF, OPFAttributes.linear))) { - spineReference.setLinear(false); - } - spineReferences.add(spineReference); - } - result.setSpineReferences(spineReferences); - return result; - } - - /** - * Creates a spine out of all resources in the resources. - * The generated spine consists of all XHTML pages in order of their href. - * - * @param resources - * @return a spine created out of all resources in the resources. - */ - private static Spine generateSpineFromResources(Resources resources) { - Spine result = new Spine(); - List<String> resourceHrefs = new ArrayList<String>(); - resourceHrefs.addAll(resources.getAllHrefs()); - Collections.sort(resourceHrefs, String.CASE_INSENSITIVE_ORDER); - for (String resourceHref: resourceHrefs) { - Resource resource = resources.getByHref(resourceHref); - if (resource.getMediaType() == MediatypeService.NCX) { - result.setTocResource(resource); - } else if (resource.getMediaType() == MediatypeService.XHTML) { - result.addSpineReference(new SpineReference(resource)); - } - } - return result; - } - - - /** - * The spine tag should contain a 'toc' attribute with as value the resource id of the 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. - * - * @param spineElement - * @param resourcesById - * @return the Resource containing the table of contents - */ - static Resource findTableOfContentsResource(String tocResourceId, Resources resources) { - Resource tocResource = null; - if (StringUtil.isNotBlank(tocResourceId)) { - tocResource = resources.getByIdOrHref(tocResourceId); - } - - if (tocResource != null) { - return tocResource; - } - - // get the first resource with the NCX mediatype - tocResource = resources.findFirstResourceByMediaType(MediatypeService.NCX); - - if (tocResource == null) { - for (int i = 0; i < POSSIBLE_NCX_ITEM_IDS.length; i++) { - tocResource = resources.getByIdOrHref(POSSIBLE_NCX_ITEM_IDS[i]); - if (tocResource != null) { - break; - } - tocResource = resources.getByIdOrHref(POSSIBLE_NCX_ITEM_IDS[i].toUpperCase()); - if (tocResource != null) { - break; - } - } - } - - if (tocResource == null) { - log.error("Could not find table of contents resource. Tried resource with id '" + tocResourceId + "', " + Constants.DEFAULT_TOC_ID + ", " + Constants.DEFAULT_TOC_ID.toUpperCase() + " and any NCX resource."); - } - return tocResource; - } - - - /** - * Find all resources that have something to do with the coverpage and the cover image. - * Search the meta tags and the guide references - * - * @param packageDocument - * @return all resources that have something to do with the coverpage and the cover image. - */ - // package - static Set<String> findCoverHrefs(Document packageDocument) { - - Set<String> result = new HashSet<String>(); - - // try and find a meta tag with name = 'cover' and a non-blank id - String coverResourceId = DOMUtil.getFindAttributeValue(packageDocument, NAMESPACE_OPF, - OPFTags.meta, OPFAttributes.name, OPFValues.meta_cover, - OPFAttributes.content); - - if (StringUtil.isNotBlank(coverResourceId)) { - String coverHref = DOMUtil.getFindAttributeValue(packageDocument, NAMESPACE_OPF, - OPFTags.item, OPFAttributes.id, coverResourceId, - OPFAttributes.href); - if (StringUtil.isNotBlank(coverHref)) { - result.add(coverHref); - } else { - result.add(coverResourceId); // maybe there was a cover href put in the cover id attribute - } - } - // try and find a reference tag with type is 'cover' and reference is not blank - String coverHref = DOMUtil.getFindAttributeValue(packageDocument, NAMESPACE_OPF, - OPFTags.reference, OPFAttributes.type, OPFValues.reference_cover, - OPFAttributes.href); - if (StringUtil.isNotBlank(coverHref)) { - result.add(coverHref); - } - return result; - } - - /** - * Finds the cover resource in the packageDocument and adds it to the book if found. - * Keeps the cover resource in the resources map - * @param packageDocument - * @param book - * @param resources - */ - private static void readCover(Document packageDocument, Book book) { - - Collection<String> coverHrefs = findCoverHrefs(packageDocument); - for (String coverHref: coverHrefs) { - Resource resource = book.getResources().getByHref(coverHref); - if (resource == null) { - log.error("Cover resource " + coverHref + " not found"); - continue; - } - if (resource.getMediaType() == MediatypeService.XHTML) { - book.setCoverPage(resource); - } else if (MediatypeService.isBitmapImage(resource.getMediaType())) { - book.setCoverImage(resource); - } - } - } - + + + /** + * Reads the manifest containing the resource ids, hrefs and mediatypes. + * + * @return a Map with resources, with their id's as key. + */ + private static Resources readManifest(Document packageDocument, Resources resources, Map<String, String> idMapping) { + Element manifestElement = DOMUtil.getFirstElementByTagNameNS(packageDocument.getDocumentElement(), NAMESPACE_OPF, OPFTags.manifest); + Resources result = new Resources(); + if (manifestElement == null) { + log.severe("Package document does not contain element " + OPFTags.manifest); + return result; + } + NodeList itemElements = manifestElement.getElementsByTagNameNS(NAMESPACE_OPF, OPFTags.item); + for (int i = 0; i < itemElements.getLength(); i++) { + Element itemElement = (Element) itemElements.item(i); + String id = DOMUtil.getAttribute(itemElement, NAMESPACE_OPF, OPFAttributes.id); + String href = DOMUtil.getAttribute(itemElement, NAMESPACE_OPF, OPFAttributes.href); + String property = DOMUtil.getAttribute(itemElement, NAMESPACE_OPF, OPFAttributes.properties); + try { + href = URLDecoder.decode(href, Constants.CHARACTER_ENCODING); + } catch (UnsupportedEncodingException e) { + log.severe(e.getMessage()); + } + String mediaTypeName = DOMUtil.getAttribute(itemElement, NAMESPACE_OPF, OPFAttributes.media_type); + Resource resource = resources.remove(href); + if (resource == null) { + log.severe("resource with href '" + href + "' not found"); + continue; + } + resource.setId(id); + if (StringUtil.equals(property, OPFValues.nav)) { + resource.setNav(true); + result.setNavResource(resource); + } else { + resource.setNav(false); + } + resource.setContainingSvg(StringUtil.equals(property, OPFValues.svg)); + resource.setScripted(StringUtil.equals(property, OPFValues.scripted)); + MediaType mediaType = MediatypeService.getMediaTypeByName(mediaTypeName); + if (mediaType != null) { + resource.setMediaType(mediaType); + } + result.add(resource); + idMapping.put(id, resource.getId()); + } + return result; + } + + + /** + * Reads the book's guide. + * Here some more attempts are made at finding the cover page. + */ + private static void readGuide(Document packageDocument, Book book, Resources resources) { + Element guideElement = DOMUtil.getFirstElementByTagNameNS(packageDocument.getDocumentElement(), NAMESPACE_OPF, OPFTags.guide); + if (guideElement == null) { + return; + } + Guide guide = book.getGuide(); + NodeList guideReferences = guideElement.getElementsByTagNameNS(NAMESPACE_OPF, OPFTags.reference); + for (int i = 0; i < guideReferences.getLength(); i++) { + Element referenceElement = (Element) guideReferences.item(i); + String resourceHref = DOMUtil.getAttribute(referenceElement, NAMESPACE_OPF, OPFAttributes.href); + if (StringUtil.isBlank(resourceHref)) { + continue; + } + Resource resource = resources.getByHref(StringUtil.substringBefore(resourceHref, Constants.FRAGMENT_SEPARATOR_CHAR)); + if (resource == null) { + log.severe("Guide is referencing resource with href " + resourceHref + " which could not be found"); + continue; + } + String type = DOMUtil.getAttribute(referenceElement, NAMESPACE_OPF, OPFAttributes.type); + if (StringUtil.isBlank(type)) { + log.severe("Guide is referencing resource with href " + resourceHref + " which is missing the 'type' attribute"); + continue; + } + String title = DOMUtil.getAttribute(referenceElement, NAMESPACE_OPF, OPFAttributes.title); + if (GuideReference.COVER.equalsIgnoreCase(type)) { + continue; // cover is handled elsewhere + } + GuideReference reference = new GuideReference(resource, type, title, StringUtil.substringAfter(resourceHref, Constants.FRAGMENT_SEPARATOR_CHAR)); + guide.addReference(reference); + } + } + + + /** + * Strips off the package prefixes up to the href of the packageHref. + * <p> + * Example: + * If the packageHref is "OEBPS/content.opf" then a resource href like "OEBPS/foo/bar.html" will be turned into "foo/bar.html" + * + * @return The stripped package href + */ + static Resources fixHrefs(String packageHref, + Resources resourcesByHref) { + int lastSlashPos = packageHref.lastIndexOf('/'); + if (lastSlashPos < 0) { + return resourcesByHref; + } + Resources result = new Resources(); + for (Resource resource : resourcesByHref.getAll()) { + if (StringUtil.isNotBlank(resource.getHref()) + && resource.getHref().length() > lastSlashPos) { + resource.setHref(resource.getHref().substring(lastSlashPos + 1)); + } + result.add(resource); + } + return result; + } + + /** + * Reads 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, Map<String, String> idMapping) { + + Element spineElement = DOMUtil.getFirstElementByTagNameNS(packageDocument.getDocumentElement(), NAMESPACE_OPF, OPFTags.spine); + if (spineElement == null) { + log.severe("Element " + OPFTags.spine + " not found in package document, generating one automatically"); + return generateSpineFromResources(resources); + } + Spine result = new Spine(); + String tocResourceId = DOMUtil.getAttribute(spineElement, NAMESPACE_OPF, OPFAttributes.toc); + result.setTocResource(findTableOfContentsResource(tocResourceId, resources)); + NodeList spineNodes = packageDocument.getElementsByTagNameNS(NAMESPACE_OPF, OPFTags.itemref); + List<SpineReference> spineReferences = new ArrayList<>(spineNodes.getLength()); + for (int i = 0; i < spineNodes.getLength(); i++) { + Element spineItem = (Element) spineNodes.item(i); + String itemref = DOMUtil.getAttribute(spineItem, NAMESPACE_OPF, OPFAttributes.idref); + if (StringUtil.isBlank(itemref)) { + log.severe("itemref with missing or empty idref"); // XXX + continue; + } + String id = idMapping.get(itemref); + if (id == null) { + id = itemref; + } + Resource resource = resources.getByIdOrHref(id); + if (resource == null) { + log.severe("resource with id '" + id + "' not found"); + continue; + } + + SpineReference spineReference = new SpineReference(resource); + if (OPFValues.no.equalsIgnoreCase(DOMUtil.getAttribute(spineItem, NAMESPACE_OPF, OPFAttributes.linear))) { + spineReference.setLinear(false); + } + spineReferences.add(spineReference); + } + result.setSpineReferences(spineReferences); + return result; + } + + /** + * Creates a spine out of all resources in the resources. + * The generated spine consists of all XHTML pages in order of their href. + * + * @return a spine created out of all resources in the resources. + */ + private static Spine generateSpineFromResources(Resources resources) { + Spine result = new Spine(); + List<String> resourceHrefs = new ArrayList<>(resources.getAllHrefs()); + Collections.sort(resourceHrefs, String.CASE_INSENSITIVE_ORDER); + for (String resourceHref : resourceHrefs) { + Resource resource = resources.getByHref(resourceHref); + if (resource.getMediaType() == MediatypeService.NCX) { + result.setTocResource(resource); + } else if (resource.getMediaType() == MediatypeService.XHTML) { + result.addSpineReference(new SpineReference(resource)); + } + } + return result; + } + + + /** + * The spine tag should contain a 'toc' attribute with as value the resource id of the table of contents resource. + * <p> + * 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. + * + * @return the Resource containing the table of contents + */ + static Resource findTableOfContentsResource(String tocResourceId, Resources resources) { + Resource tocResource = null; + if (StringUtil.isNotBlank(tocResourceId)) { + tocResource = resources.getByIdOrHref(tocResourceId); + } + + if (tocResource != null) { + return tocResource; + } + + // get the first resource with the NCX mediatype + tocResource = resources.findFirstResourceByMediaType(MediatypeService.NCX); + + if (tocResource == null) { + for (String possibleNcxItemId : POSSIBLE_NCX_ITEM_IDS) { + tocResource = resources.getByIdOrHref(possibleNcxItemId); + if (tocResource != null) { + break; + } + tocResource = resources.getByIdOrHref(possibleNcxItemId.toUpperCase()); + if (tocResource != null) { + break; + } + } + } + + if (tocResource == null) { + log.severe("Could not find table of contents resource. Tried resource with id '" + tocResourceId + "', " + Constants.DEFAULT_TOC_ID + ", " + Constants.DEFAULT_TOC_ID.toUpperCase() + " and any NCX resource."); + } + return tocResource; + } + + + /** + * Find all resources that have something to do with the coverpage and the cover image. + * Search the meta tags and the guide references + * + * @return all resources that have something to do with the coverpage and the cover image. + */ + // package + static Set<String> findCoverHrefs(Document packageDocument) { + + Set<String> result = new HashSet<>(); + + // try and find a meta tag with name = 'cover' and a non-blank id + String coverResourceId = DOMUtil.getFindAttributeValue(packageDocument, NAMESPACE_OPF, + OPFTags.meta, OPFAttributes.name, OPFValues.meta_cover, + OPFAttributes.content); + + if (StringUtil.isNotBlank(coverResourceId)) { + String coverHref = DOMUtil.getFindAttributeValue(packageDocument, NAMESPACE_OPF, + OPFTags.item, OPFAttributes.id, coverResourceId, + OPFAttributes.href); + if (StringUtil.isNotBlank(coverHref)) { + result.add(coverHref); + } else { + result.add(coverResourceId); // maybe there was a cover href put in the cover id attribute + } + } + // try and find a reference tag with type is 'cover' and reference is not blank + String coverHref = DOMUtil.getFindAttributeValue(packageDocument, NAMESPACE_OPF, + OPFTags.reference, OPFAttributes.type, OPFValues.reference_cover, + OPFAttributes.href); + if (StringUtil.isNotBlank(coverHref)) { + result.add(coverHref); + } + return result; + } + + /** + * Finds the cover resource in the packageDocument and adds it to the book if found. + * Keeps the cover resource in the resources map + */ + private static void readCover(Document packageDocument, Book book) { + + Collection<String> coverHrefs = findCoverHrefs(packageDocument); + for (String coverHref : coverHrefs) { + Resource resource = book.getResources().getByHref(coverHref); + if (resource == null) { + log.severe("Cover resource " + coverHref + " not found"); + continue; + } + if (resource.getMediaType() == MediatypeService.XHTML) { + book.setCoverPage(resource); + } else if (MediatypeService.isBitmapImage(resource.getMediaType())) { + book.setCoverImage(resource); + } + } + } + } diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentWriter.java b/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentWriter.java index bcd62607..91dc18fa 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentWriter.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/epub/PackageDocumentWriter.java @@ -1,13 +1,5 @@ package nl.siegmann.epublib.epub; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import javax.xml.stream.XMLStreamException; - import nl.siegmann.epublib.Constants; import nl.siegmann.epublib.domain.Book; import nl.siegmann.epublib.domain.Guide; @@ -17,187 +9,200 @@ import nl.siegmann.epublib.domain.SpineReference; import nl.siegmann.epublib.service.MediatypeService; import nl.siegmann.epublib.util.StringUtil; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; 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 java.util.logging.Logger; + +import static nl.siegmann.epublib.domain.OpfResource.DEFAULT_VERSION; + /** * Writes the opf package document as defined by namespace http://www.idpf.org/2007/opf - * - * @author paul * + * @author paul */ public class PackageDocumentWriter extends PackageDocumentBase { - private static final Logger log = LoggerFactory.getLogger(PackageDocumentWriter.class); - - public static void write(EpubWriter epubWriter, XmlSerializer serializer, Book book) throws IOException { - try { - serializer.startDocument(Constants.CHARACTER_ENCODING, false); - serializer.setPrefix(PREFIX_OPF, NAMESPACE_OPF); - serializer.setPrefix(PREFIX_DUBLIN_CORE, NAMESPACE_DUBLIN_CORE); - serializer.startTag(NAMESPACE_OPF, OPFTags.packageTag); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.version, "2.0"); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.uniqueIdentifier, BOOK_ID_ID); - - PackageDocumentMetadataWriter.writeMetaData(book, serializer); - - writeManifest(book, epubWriter, serializer); - writeSpine(book, epubWriter, serializer); - writeGuide(book, epubWriter, serializer); - - serializer.endTag(NAMESPACE_OPF, OPFTags.packageTag); - serializer.endDocument(); - serializer.flush(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - - /** - * Writes the package's spine. - * - * @param book - * @param epubWriter - * @param serializer - * @throws IOException - * @throws IllegalStateException - * @throws IllegalArgumentException - * @throws XMLStreamException - */ - private static void writeSpine(Book book, EpubWriter epubWriter, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { - serializer.startTag(NAMESPACE_OPF, OPFTags.spine); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.toc, book.getSpine().getTocResource().getId()); - - if(book.getCoverPage() != null // there is a cover page - && book.getSpine().findFirstResourceById(book.getCoverPage().getId()) < 0) { // cover page is not already in the spine - // write the cover html file - serializer.startTag(NAMESPACE_OPF, OPFTags.itemref); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.idref, book.getCoverPage().getId()); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.linear, "no"); - serializer.endTag(NAMESPACE_OPF, OPFTags.itemref); - } - writeSpineItems(book.getSpine(), serializer); - serializer.endTag(NAMESPACE_OPF, OPFTags.spine); - } - - - private static void writeManifest(Book book, EpubWriter epubWriter, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { - serializer.startTag(NAMESPACE_OPF, OPFTags.manifest); - - serializer.startTag(NAMESPACE_OPF, OPFTags.item); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.id, epubWriter.getNcxId()); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.href, epubWriter.getNcxHref()); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.media_type, epubWriter.getNcxMediaType()); - serializer.endTag(NAMESPACE_OPF, OPFTags.item); + private static final Logger log = Logger.getLogger(PackageDocumentWriter.class.getName()); + + public static void write(EpubWriter epubWriter, XmlSerializer serializer, Book book) throws IOException { + try { + serializer.startDocument(Constants.CHARACTER_ENCODING, false); + serializer.setPrefix(EpubWriter.EMPTY_NAMESPACE_PREFIX, NAMESPACE_OPF); +// serializer.setPrefix(PREFIX_DUBLIN_CORE, NAMESPACE_DUBLIN_CORE); + serializer.startTag(NAMESPACE_OPF, OPFTags.packageTag); + String version = DEFAULT_VERSION; + if (null != book.getOpfResource()) { + version = book.getOpfResource().getVersion(); + } + serializer.attribute( + EpubWriter.EMPTY_NAMESPACE_PREFIX, + OPFAttributes.version, StringUtil.isNotBlank(version) ? version : DEFAULT_VERSION + ); + if (null != book.getOpfResource() && StringUtil.isNotBlank(book.getOpfResource().getPrefix())) { + serializer.attribute( + EpubWriter.EMPTY_NAMESPACE_PREFIX, + OPFAttributes.prefix, book.getOpfResource().getPrefix() + ); + } + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.uniqueIdentifier, BOOK_ID_ID); + + PackageDocumentMetadataWriter.writeMetaData(book, serializer); + + writeManifest(book, epubWriter, serializer); + writeSpine(book, serializer); + writeGuide(book, serializer); + + serializer.endTag(NAMESPACE_OPF, OPFTags.packageTag); + serializer.endDocument(); + serializer.flush(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + + /** + * Writes the package's spine. + */ + private static void writeSpine(Book book, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { + serializer.startTag(NAMESPACE_OPF, OPFTags.spine); + if (null != book.getSpine().getTocResource()) { + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.toc, book.getSpine().getTocResource().getId()); + } + if (book.getCoverPage() != null // there is a cover page + && book.getSpine().findFirstResourceById(book.getCoverPage().getId()) < 0) { // cover page is not already in the spine + // write the cover html file + serializer.startTag(NAMESPACE_OPF, OPFTags.itemref); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.idref, book.getCoverPage().getId()); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.linear, "no"); + serializer.endTag(NAMESPACE_OPF, OPFTags.itemref); + } + writeSpineItems(book.getSpine(), serializer); + serializer.endTag(NAMESPACE_OPF, OPFTags.spine); + + } + + + private static void writeManifest(Book book, EpubWriter epubWriter, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { + serializer.startTag(NAMESPACE_OPF, OPFTags.manifest); + + if (null != book.getSpine().getTocResource()) { + serializer.startTag(NAMESPACE_OPF, OPFTags.item); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.id, epubWriter.getNcxId()); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.href, epubWriter.getNcxHref()); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.media_type, epubWriter.getNcxMediaType()); + serializer.endTag(NAMESPACE_OPF, OPFTags.item); + } // writeCoverResources(book, serializer); - - for(Resource resource: getAllResourcesSortById(book)) { - writeItem(book, resource, serializer); - } - - serializer.endTag(NAMESPACE_OPF, OPFTags.manifest); - } - - private static List<Resource> getAllResourcesSortById(Book book) { - List<Resource> allResources = new ArrayList<Resource>(book.getResources().getAll()); - Collections.sort(allResources, new Comparator<Resource>() { - - @Override - public int compare(Resource resource1, Resource resource2) { - return resource1.getId().compareToIgnoreCase(resource2.getId()); - } - }); - return allResources; - } - - /** - * Writes a resources as an item element - * @param resource - * @param serializer - * @throws IOException - * @throws IllegalStateException - * @throws IllegalArgumentException - * @throws XMLStreamException - */ - private static void writeItem(Book book, Resource resource, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { - if(resource == null || - (resource.getMediaType() == MediatypeService.NCX - && book.getSpine().getTocResource() != null)) { - return; - } - if(StringUtil.isBlank(resource.getId())) { - log.error("resource id must not be empty (href: " + resource.getHref() + ", mediatype:" + resource.getMediaType() + ")"); - return; - } - if(StringUtil.isBlank(resource.getHref())) { - log.error("resource href must not be empty (id: " + resource.getId() + ", mediatype:" + resource.getMediaType() + ")"); - return; - } - if(resource.getMediaType() == null) { - log.error("resource mediatype must not be empty (id: " + resource.getId() + ", href:" + resource.getHref() + ")"); - return; - } - serializer.startTag(NAMESPACE_OPF, OPFTags.item); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.id, resource.getId()); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.href, resource.getHref()); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.media_type, resource.getMediaType().getName()); - serializer.endTag(NAMESPACE_OPF, OPFTags.item); - } - - /** - * List all spine references - * @throws IOException - * @throws IllegalStateException - * @throws IllegalArgumentException - */ - private static void writeSpineItems(Spine spine, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { - for(SpineReference spineReference: spine.getSpineReferences()) { - serializer.startTag(NAMESPACE_OPF, OPFTags.itemref); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.idref, spineReference.getResourceId()); - if (! spineReference.isLinear()) { - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.linear, OPFValues.no); - } - serializer.endTag(NAMESPACE_OPF, OPFTags.itemref); - } - } - - private static void writeGuide(Book book, EpubWriter epubWriter, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { - serializer.startTag(NAMESPACE_OPF, OPFTags.guide); - ensureCoverPageGuideReferenceWritten(book.getGuide(), epubWriter, serializer); - for (GuideReference reference: book.getGuide().getReferences()) { - writeGuideReference(reference, serializer); - } - serializer.endTag(NAMESPACE_OPF, OPFTags.guide); - } - - private static void ensureCoverPageGuideReferenceWritten(Guide guide, - EpubWriter epubWriter, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { - if (! (guide.getGuideReferencesByType(GuideReference.COVER).isEmpty())) { - return; - } - Resource coverPage = guide.getCoverPage(); - if (coverPage != null) { - writeGuideReference(new GuideReference(guide.getCoverPage(), GuideReference.COVER, GuideReference.COVER), serializer); - } - } - - - private static void writeGuideReference(GuideReference reference, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { - if (reference == null) { - return; - } - serializer.startTag(NAMESPACE_OPF, OPFTags.reference); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.type, reference.getType()); - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.href, reference.getCompleteHref()); - if (StringUtil.isNotBlank(reference.getTitle())) { - serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.title, reference.getTitle()); - } - serializer.endTag(NAMESPACE_OPF, OPFTags.reference); - } -} \ No newline at end of file + + for (Resource resource : getAllResourcesSortById(book)) { + writeItem(book, resource, serializer); + } + + serializer.endTag(NAMESPACE_OPF, OPFTags.manifest); + } + + private static List<Resource> getAllResourcesSortById(Book book) { + List<Resource> allResources = new ArrayList<>(book.getResources().getAll()); + Collections.sort(allResources, new Comparator<Resource>() { + + @Override + public int compare(Resource resource1, Resource resource2) { + return resource1.getId().compareToIgnoreCase(resource2.getId()); + } + }); + return allResources; + } + + /** + * Writes a resources as an item element + */ + private static void writeItem(Book book, Resource resource, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { + if (resource == null || + (resource.getMediaType() == MediatypeService.NCX + && book.getSpine().getTocResource() != null)) { + return; + } + if (StringUtil.isBlank(resource.getId())) { + log.severe("resource id must not be empty (href: " + resource.getHref() + ", mediatype:" + resource.getMediaType() + ")"); + return; + } + if (StringUtil.isBlank(resource.getHref())) { + log.severe("resource href must not be empty (id: " + resource.getId() + ", mediatype:" + resource.getMediaType() + ")"); + return; + } + if (resource.getMediaType() == null) { + log.severe("resource mediatype must not be empty (id: " + resource.getId() + ", href:" + resource.getHref() + ")"); + return; + } + serializer.startTag(NAMESPACE_OPF, OPFTags.item); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.id, resource.getId()); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.href, resource.getHref()); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.media_type, resource.getMediaType().getName()); + if (resource.isNav()) { + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.properties, OPFValues.nav); + } + if (resource.isContainingSvg()) { + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.properties, OPFValues.svg); + } + if (resource.isScripted()) { + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.properties, OPFValues.scripted); + } + serializer.endTag(NAMESPACE_OPF, OPFTags.item); + } + + /** + * List all spine references + */ + private static void writeSpineItems(Spine spine, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { + for (SpineReference spineReference : spine.getSpineReferences()) { + serializer.startTag(NAMESPACE_OPF, OPFTags.itemref); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.idref, spineReference.getResourceId()); + if (!spineReference.isLinear()) { + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.linear, OPFValues.no); + } + serializer.endTag(NAMESPACE_OPF, OPFTags.itemref); + } + } + + private static void writeGuide(Book book, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { + serializer.startTag(NAMESPACE_OPF, OPFTags.guide); + ensureCoverPageGuideReferenceWritten(book.getGuide(), serializer); + for (GuideReference reference : book.getGuide().getReferences()) { + writeGuideReference(reference, serializer); + } + serializer.endTag(NAMESPACE_OPF, OPFTags.guide); + } + + private static void ensureCoverPageGuideReferenceWritten(Guide guide, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { + if (!(guide.getGuideReferencesByType(GuideReference.COVER).isEmpty())) { + return; + } + Resource coverPage = guide.getCoverPage(); + if (coverPage != null) { + writeGuideReference(new GuideReference(guide.getCoverPage(), GuideReference.COVER, GuideReference.COVER), serializer); + } + } + + + private static void writeGuideReference(GuideReference reference, XmlSerializer serializer) throws IllegalArgumentException, IllegalStateException, IOException { + if (reference == null) { + return; + } + serializer.startTag(NAMESPACE_OPF, OPFTags.reference); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.type, reference.getType()); + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.href, reference.getCompleteHref()); + if (StringUtil.isNotBlank(reference.getTitle())) { + serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, OPFAttributes.title, reference.getTitle()); + } + serializer.endTag(NAMESPACE_OPF, OPFTags.reference); + } +} diff --git a/epublib-core/src/main/java/nl/siegmann/epublib/epub/ResourcesLoader.java b/epublib-core/src/main/java/nl/siegmann/epublib/epub/ResourcesLoader.java index 19fb3e15..bef67d18 100644 --- a/epublib-core/src/main/java/nl/siegmann/epublib/epub/ResourcesLoader.java +++ b/epublib-core/src/main/java/nl/siegmann/epublib/epub/ResourcesLoader.java @@ -1,11 +1,12 @@ package nl.siegmann.epublib.epub; import java.io.IOException; -import java.io.InputStream; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import net.sf.jazzlib.ZipEntry; import net.sf.jazzlib.ZipException; @@ -19,8 +20,6 @@ import nl.siegmann.epublib.util.CollectionUtil; import nl.siegmann.epublib.util.ResourceUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Loads Resources from inputStreams, ZipFiles, etc @@ -29,7 +28,7 @@ * */ public class ResourcesLoader { - private static final Logger LOG = LoggerFactory.getLogger(ResourcesLoader.class); + private static final Logger log = Logger.getLogger(ResourcesLoader.class.getName()); /** * Loads the entries of the zipFile as resources. @@ -130,7 +129,7 @@ private static ZipEntry getNextZipEntry(ZipInputStream zipInputStream) throws IO //see <a href="https://github.com/psiegman/epublib/issues/122">Issue #122 Infinite loop</a>. //when reading a file that is not a real zip archive or a zero length file, zipInputStream.getNextEntry() //throws an exception and does not advance, so loadResources enters an infinite loop - LOG.error("Invalid or damaged zip file.", e); + log.log(Level.SEVERE, "Invalid or damaged zip file.", e); try { zipInputStream.closeEntry(); } catch (Exception ignored) {} throw e; } diff --git a/epublib-core/src/test/java/nl/siegmann/epublib/epub/EpubReaderTest.java b/epublib-core/src/test/java/nl/siegmann/epublib/epub/EpubReaderTest.java index b3ea9691..523e5d3b 100644 --- a/epublib-core/src/test/java/nl/siegmann/epublib/epub/EpubReaderTest.java +++ b/epublib-core/src/test/java/nl/siegmann/epublib/epub/EpubReaderTest.java @@ -7,6 +7,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import nl.siegmann.epublib.domain.OpfResource; import org.junit.Test; import nl.siegmann.epublib.domain.Book; @@ -73,4 +74,61 @@ public void testReadEpub_opf_ncx_docs() throws IOException { assertEquals(MediatypeService.NCX, readBook.getNcxResource() .getMediaType()); } + + @Test + public void testReadEpub_opf_ncx_version() throws IOException { + Book book = new Book(); + + book.setOpfResource(new OpfResource(new Resource(this.getClass().getResourceAsStream( + "/opf/test3.opf"), "content.opf"))); + book.getOpfResource().setVersion("3.0"); + book.setCoverImage(new Resource(this.getClass().getResourceAsStream( + "/book1/cover.png"), "cover.png")); + book.addSection("Introduction", new Resource(this.getClass() + .getResourceAsStream("/book1/chapter1.html"), "chapter1.html")); + book.generateSpineFromTableOfContents(); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + (new EpubWriter()).write(book, out); + byte[] epubData = out.toByteArray(); + Book readBook = new EpubReader().readEpub(new ByteArrayInputStream( + epubData)); + assertNotNull(readBook.getCoverPage()); + assertEquals(1, readBook.getSpine().size()); + assertEquals(1, readBook.getTableOfContents().size()); + assertNotNull(readBook.getOpfResource()); + assertEquals("3.0", readBook.getOpfResource().getVersion()); + assertNotNull(readBook.getNcxResource()); + assertEquals(MediatypeService.NCX, readBook.getNcxResource() + .getMediaType()); + } + + @Test + public void testReadEpub_opf_prefix() throws IOException { + Book book = new Book(); + + book.setOpfResource(new OpfResource(new Resource(this.getClass().getResourceAsStream( + "/opf/test3.opf"), "content.opf"))); + book.getOpfResource().setVersion("3.0"); + book.getOpfResource().setPrefix("test_prefix"); + book.setCoverImage(new Resource(this.getClass().getResourceAsStream( + "/book1/cover.png"), "cover.png")); + book.addSection("Introduction", new Resource(this.getClass() + .getResourceAsStream("/book1/chapter1.html"), "chapter1.html")); + book.generateSpineFromTableOfContents(); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + (new EpubWriter()).write(book, out); + byte[] epubData = out.toByteArray(); + Book readBook = new EpubReader().readEpub(new ByteArrayInputStream( + epubData)); + assertNotNull(readBook.getCoverPage()); + assertEquals(1, readBook.getSpine().size()); + assertEquals(1, readBook.getTableOfContents().size()); + assertNotNull(readBook.getOpfResource()); + assertEquals("test_prefix", readBook.getOpfResource().getPrefix()); + assertNotNull(readBook.getNcxResource()); + assertEquals(MediatypeService.NCX, readBook.getNcxResource() + .getMediaType()); + } } diff --git a/epublib-core/src/test/java/nl/siegmann/epublib/epub/EpubWriterTest.java b/epublib-core/src/test/java/nl/siegmann/epublib/epub/EpubWriterTest.java index 1951031d..aedb7b18 100644 --- a/epublib-core/src/test/java/nl/siegmann/epublib/epub/EpubWriterTest.java +++ b/epublib-core/src/test/java/nl/siegmann/epublib/epub/EpubWriterTest.java @@ -1,107 +1,92 @@ package nl.siegmann.epublib.epub; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; - -import nl.siegmann.epublib.domain.Author; -import nl.siegmann.epublib.domain.Book; -import nl.siegmann.epublib.domain.GuideReference; -import nl.siegmann.epublib.domain.Identifier; -import nl.siegmann.epublib.domain.Resource; -import nl.siegmann.epublib.domain.TOCReference; +import nl.siegmann.epublib.domain.*; import nl.siegmann.epublib.util.CollectionUtil; - import org.junit.Assert; import org.junit.Test; +import java.io.*; + public class EpubWriterTest { - @Test - public void testBook1() throws IOException { - // create test book - Book book = createTestBook(); - - // write book to byte[] - byte[] bookData = writeBookToByteArray(book); - FileOutputStream fileOutputStream = new FileOutputStream("foo.zip"); - fileOutputStream.write(bookData); - fileOutputStream.flush(); - fileOutputStream.close(); - Assert.assertNotNull(bookData); - Assert.assertTrue(bookData.length > 0); - - // read book from byte[] - Book readBook = new EpubReader().readEpub(new ByteArrayInputStream(bookData)); - - // assert book values are correct - Assert.assertEquals(book.getMetadata().getTitles(), readBook.getMetadata().getTitles()); - Assert.assertEquals(Identifier.Scheme.ISBN, CollectionUtil.first(readBook.getMetadata().getIdentifiers()).getScheme()); - Assert.assertEquals(CollectionUtil.first(book.getMetadata().getIdentifiers()).getValue(), CollectionUtil.first(readBook.getMetadata().getIdentifiers()).getValue()); - Assert.assertEquals(CollectionUtil.first(book.getMetadata().getAuthors()), CollectionUtil.first(readBook.getMetadata().getAuthors())); - Assert.assertEquals(1, readBook.getGuide().getGuideReferencesByType(GuideReference.COVER).size()); - Assert.assertEquals(5, readBook.getSpine().size()); - Assert.assertNotNull(book.getCoverPage()); - Assert.assertNotNull(book.getCoverImage()); - Assert.assertEquals(4, readBook.getTableOfContents().size()); - - } - - /** - * Test for a very old bug where epublib would throw a NullPointerException when writing a book with a cover that has no id. - * @throws IOException - * @throws FileNotFoundException - * - */ - public void testWritingBookWithCoverWithNullId() throws FileNotFoundException, IOException { - Book book = new Book(); - book.getMetadata().addTitle("Epub test book 1"); - book.getMetadata().addAuthor(new Author("Joe", "Tester")); - InputStream is = this.getClass().getResourceAsStream("/book1/cover.png"); - book.setCoverImage(new Resource(is, "cover.png")); - // Add Chapter 1 - InputStream is1 = this.getClass().getResourceAsStream("/book1/chapter1.html"); - book.addSection("Introduction", new Resource(is1, "chapter1.html")); - - EpubWriter epubWriter = new EpubWriter(); - epubWriter.write(book, new FileOutputStream("test1_book1.epub")); - } - - private Book createTestBook() throws IOException { - Book book = new Book(); - - book.getMetadata().addTitle("Epublib test book 1"); - book.getMetadata().addTitle("test2"); - - book.getMetadata().addIdentifier(new Identifier(Identifier.Scheme.ISBN, "987654321")); - book.getMetadata().addAuthor(new Author("Joe", "Tester")); - book.setCoverPage(new Resource(this.getClass().getResourceAsStream("/book1/cover.html"), "cover.html")); - book.setCoverImage(new Resource(this.getClass().getResourceAsStream("/book1/cover.png"), "cover.png")); - book.addSection("Chapter 1", new Resource(this.getClass().getResourceAsStream("/book1/chapter1.html"), "chapter1.html")); - book.addResource(new Resource(this.getClass().getResourceAsStream("/book1/book1.css"), "book1.css")); - TOCReference chapter2 = book.addSection("Second chapter", new Resource(this.getClass().getResourceAsStream("/book1/chapter2.html"), "chapter2.html")); - book.addResource(new Resource(this.getClass().getResourceAsStream("/book1/flowers_320x240.jpg"), "flowers.jpg")); - book.addSection(chapter2, "Chapter 2 section 1", new Resource(this.getClass().getResourceAsStream("/book1/chapter2_1.html"), "chapter2_1.html")); - book.addSection("Chapter 3", new Resource(this.getClass().getResourceAsStream("/book1/chapter3.html"), "chapter3.html")); - return book; - } - - - private byte[] writeBookToByteArray(Book book) throws IOException { - EpubWriter epubWriter = new EpubWriter(); - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - epubWriter.write(book, out); - return out.toByteArray(); - } + @Test + public void testBook1() throws IOException { + // create test book + Book book = createTestBook(); + + // write book to byte[] + byte[] bookData = writeBookToByteArray(book); + FileOutputStream fileOutputStream = new FileOutputStream("foo.zip"); + fileOutputStream.write(bookData); + fileOutputStream.flush(); + fileOutputStream.close(); + Assert.assertNotNull(bookData); + Assert.assertTrue(bookData.length > 0); + + // read book from byte[] + Book readBook = new EpubReader().readEpub(new ByteArrayInputStream(bookData)); + + // assert book values are correct + Assert.assertEquals(book.getMetadata().getTitles(), readBook.getMetadata().getTitles()); + Assert.assertEquals(Scheme.ISBN.getName(), CollectionUtil.first(readBook.getMetadata().getIdentifiers()).getScheme().getName()); + Assert.assertEquals(CollectionUtil.first(book.getMetadata().getIdentifiers()).getValue(), CollectionUtil.first(readBook.getMetadata().getIdentifiers()).getValue()); + Assert.assertEquals(CollectionUtil.first(book.getMetadata().getAuthors()), CollectionUtil.first(readBook.getMetadata().getAuthors())); + Assert.assertEquals(1, readBook.getGuide().getGuideReferencesByType(GuideReference.COVER).size()); + Assert.assertEquals(5, readBook.getSpine().size()); + Assert.assertNotNull(book.getCoverPage()); + Assert.assertNotNull(book.getCoverImage()); + Assert.assertEquals(4, readBook.getTableOfContents().size()); + + } + + /** + * Test for a very old bug where epublib would throw a NullPointerException when writing a book with a cover that has no id. + * + * @throws IOException + * @throws FileNotFoundException + */ + @Test + public void testWritingBookWithCoverWithNullId() throws FileNotFoundException, IOException { + Book book = new Book(); + book.getMetadata().addTitle(new Title("Epub test book 1")); + book.getMetadata().addAuthor(new Author("Joe", "Tester")); + InputStream is = this.getClass().getResourceAsStream("/book1/cover.png"); + book.setCoverImage(new Resource(is, "cover.png")); + // Add Chapter 1 + InputStream is1 = this.getClass().getResourceAsStream("/book1/chapter1.html"); + book.addSection("Introduction", new Resource(is1, "chapter1.html")); + + EpubWriter epubWriter = new EpubWriter(); + epubWriter.write(book, new FileOutputStream("test1_book1.epub")); + } + + private Book createTestBook() throws IOException { + Book book = new Book(); + + book.getMetadata().addTitle(new Title("Epublib test book 1")); + book.getMetadata().addTitle(new Title("test2")); + + book.getMetadata().addIdentifier(new Identifier(Scheme.ISBN, "987654321")); + book.getMetadata().addAuthor(new Author("Joe", "Tester")); + book.setCoverPage(new Resource(this.getClass().getResourceAsStream("/book1/cover.html"), "cover.html")); + book.setCoverImage(new Resource(this.getClass().getResourceAsStream("/book1/cover.png"), "cover.png")); + book.addSection("Chapter 1", new Resource(this.getClass().getResourceAsStream("/book1/chapter1.html"), "chapter1.html")); + book.addResource(new Resource(this.getClass().getResourceAsStream("/book1/book1.css"), "book1.css")); + TOCReference chapter2 = book.addSection("Second chapter", new Resource(this.getClass().getResourceAsStream("/book1/chapter2.html"), "chapter2.html")); + book.addResource(new Resource(this.getClass().getResourceAsStream("/book1/flowers_320x240.jpg"), "flowers.jpg")); + book.addSection(chapter2, "Chapter 2 section 1", new Resource(this.getClass().getResourceAsStream("/book1/chapter2_1.html"), "chapter2_1.html")); + book.addSection("Chapter 3", new Resource(this.getClass().getResourceAsStream("/book1/chapter3.html"), "chapter3.html")); + return book; + } + + + private byte[] writeBookToByteArray(Book book) throws IOException { + EpubWriter epubWriter = new EpubWriter(); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + epubWriter.write(book, out); + return out.toByteArray(); + } // // public static void writeEpub(BookDTO dto) throws IOException{ // Book book = new Book(); diff --git a/epublib-core/src/test/java/nl/siegmann/epublib/epub/NavDocumentTest.java b/epublib-core/src/test/java/nl/siegmann/epublib/epub/NavDocumentTest.java new file mode 100644 index 00000000..f5269e8c --- /dev/null +++ b/epublib-core/src/test/java/nl/siegmann/epublib/epub/NavDocumentTest.java @@ -0,0 +1,127 @@ +package nl.siegmann.epublib.epub; + +import nl.siegmann.epublib.domain.Book; +import nl.siegmann.epublib.domain.Resource; +import nl.siegmann.epublib.domain.TOCReference; +import nl.siegmann.epublib.domain.TableOfContents; +import nl.siegmann.epublib.service.MediatypeService; +import org.junit.Assert; +import org.junit.Test; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +public class NavDocumentTest { + String navDataWithResourcesInSubFolder = "<?xml version='1.0' encoding='utf-8'?>\n" + + "<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\" lang=\"en\" xml:lang=\"en\">\n" + + "<body>\n" + + "<nav epub:type=\"toc\">\n" + + " <ol>\n" + + " <li><a href=\"text/part0000.html\">Title Page</a></li>\n" + + " <li><a href=\"text/part0001.html#UGI0-c67f0a5a7d524f06bbddb81b8d1876f5\">Copyright</a></li>\n" + + " <li><a href=\"text/part0002.html\">Introduction</a></li>\n" + + " </ol>\n" + + "</nav>\n" + + "</body>\n" + + "</html>"; + + String navDataWithResourcesInSameFolder = "<?xml version='1.0' encoding='utf-8'?>\n" + + "<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\" lang=\"en\" xml:lang=\"en\">\n" + + "<body>\n" + + "<nav epub:type=\"toc\">\n" + + " <ol>\n" + + " <li><a href=\"part0000.html\">Title Page</a></li>\n" + + " <li><a href=\"part0001.html#UGI0-c67f0a5a7d524f06bbddb81b8d1876f5\">Copyright</a></li>\n" + + " <li><a href=\"part0002.html\">Introduction</a></li>\n" + + " </ol>\n" + + "</nav>\n" + + "</body>\n" + + "</html>"; + + private void addResource(Book book, String filename) { + Resource chapterResource = new Resource("id1", "Hello, world !".getBytes(), filename, MediatypeService.XHTML); + book.addResource(chapterResource); + book.getSpine().addResource(chapterResource); + } + + @Test + public void testReadWithNonRootLevelNav() { + Book book = new Book(); + Resource navResource = new Resource(navDataWithResourcesInSubFolder.getBytes(StandardCharsets.UTF_8), "oebps/nav.xhtml"); + book.setNavResource(navResource); + + addResource(book, "oebps/text/part0000.html"); + addResource(book, "oebps/text/part0001.html"); + addResource(book, "oebps/text/part0002.html"); + + NavDocument.read(book); + + TableOfContents tableOfContents = book.getTableOfContents(); + Assert.assertEquals(3, tableOfContents.size()); + + List<TOCReference> tocReferences = book.getTableOfContents().getTocReferences(); + + Assert.assertEquals("oebps/text/part0000.html", tocReferences.get(0).getCompleteHref()); + Assert.assertEquals("Title Page", tocReferences.get(0).getTitle()); + + Assert.assertEquals("oebps/text/part0001.html#UGI0-c67f0a5a7d524f06bbddb81b8d1876f5", tocReferences.get(1).getCompleteHref()); + Assert.assertEquals("Copyright", tocReferences.get(1).getTitle()); + + Assert.assertEquals("oebps/text/part0002.html", tocReferences.get(2).getCompleteHref()); + Assert.assertEquals("Introduction", tocReferences.get(2).getTitle()); + } + + @Test + public void testReadWithRootLevelNav_AndResourcesInSubFolder() { + Book book = new Book(); + Resource navResource = new Resource(navDataWithResourcesInSubFolder.getBytes(StandardCharsets.UTF_8), "nav.xhtml"); + book.setNavResource(navResource); + + addResource(book, "text/part0000.html"); + addResource(book, "text/part0001.html"); + addResource(book, "text/part0002.html"); + + NavDocument.read(book); + + TableOfContents tableOfContents = book.getTableOfContents(); + Assert.assertEquals(3, tableOfContents.size()); + + List<TOCReference> tocReferences = book.getTableOfContents().getTocReferences(); + + Assert.assertEquals("text/part0000.html", tocReferences.get(0).getCompleteHref()); + Assert.assertEquals("Title Page", tocReferences.get(0).getTitle()); + + Assert.assertEquals("text/part0001.html#UGI0-c67f0a5a7d524f06bbddb81b8d1876f5", tocReferences.get(1).getCompleteHref()); + Assert.assertEquals("Copyright", tocReferences.get(1).getTitle()); + + Assert.assertEquals("text/part0002.html", tocReferences.get(2).getCompleteHref()); + Assert.assertEquals("Introduction", tocReferences.get(2).getTitle()); + } + + @Test + public void testReadWithRootLevelNav_AndResourcesInSameFolder() { + Book book = new Book(); + Resource navResource = new Resource(navDataWithResourcesInSameFolder.getBytes(StandardCharsets.UTF_8), "nav.xhtml"); + book.setNavResource(navResource); + + addResource(book, "part0000.html"); + addResource(book, "part0001.html"); + addResource(book, "part0002.html"); + + NavDocument.read(book); + + TableOfContents tableOfContents = book.getTableOfContents(); + Assert.assertEquals(3, tableOfContents.size()); + + List<TOCReference> tocReferences = book.getTableOfContents().getTocReferences(); + + Assert.assertEquals("part0000.html", tocReferences.get(0).getCompleteHref()); + Assert.assertEquals("Title Page", tocReferences.get(0).getTitle()); + + Assert.assertEquals("part0001.html#UGI0-c67f0a5a7d524f06bbddb81b8d1876f5", tocReferences.get(1).getCompleteHref()); + Assert.assertEquals("Copyright", tocReferences.get(1).getTitle()); + + Assert.assertEquals("part0002.html", tocReferences.get(2).getCompleteHref()); + Assert.assertEquals("Introduction", tocReferences.get(2).getTitle()); + } +} diff --git a/epublib-core/src/test/java/nl/siegmann/epublib/epub/PackageDocumentMetadataReaderTest.java b/epublib-core/src/test/java/nl/siegmann/epublib/epub/PackageDocumentMetadataReaderTest.java index d6603e53..3b052e0d 100644 --- a/epublib-core/src/test/java/nl/siegmann/epublib/epub/PackageDocumentMetadataReaderTest.java +++ b/epublib-core/src/test/java/nl/siegmann/epublib/epub/PackageDocumentMetadataReaderTest.java @@ -36,9 +36,9 @@ public void testReadsLanguage() { } @Test - public void testDefaultsToEnglish() { + public void testDefaultsToUndefined() { Metadata metadata = getMetadata("/opf/test_default_language.opf"); - assertEquals("en", metadata.getLanguage()); + assertEquals("und", metadata.getLanguage()); } private Metadata getMetadata(String file) { @@ -84,13 +84,13 @@ public void test2() throws SAXException, IOException { Metadata metadata = PackageDocumentMetadataReader.readMetadata(metadataDocument); // then - Assert.assertEquals("Three Men in a Boat", metadata.getFirstTitle()); + Assert.assertEquals("Three Men in a Boat", metadata.getFirstTitle().getValue()); // test identifier Assert.assertNotNull(metadata.getIdentifiers()); Assert.assertEquals(1, metadata.getIdentifiers().size()); Identifier identifier = metadata.getIdentifiers().get(0); - Assert.assertEquals("URI", identifier.getScheme()); + Assert.assertEquals("URI", identifier.getScheme().getName()); Assert.assertEquals("zelda@mobileread.com:2010040720", identifier.getValue()); Assert.assertEquals("8", metadata.getMetaAttribute("calibre:rating")); diff --git a/epublib-core/src/test/java/nl/siegmann/epublib/epub/PackageDocumentReaderTest.java b/epublib-core/src/test/java/nl/siegmann/epublib/epub/PackageDocumentReaderTest.java index c331dac5..ea6a7a0c 100644 --- a/epublib-core/src/test/java/nl/siegmann/epublib/epub/PackageDocumentReaderTest.java +++ b/epublib-core/src/test/java/nl/siegmann/epublib/epub/PackageDocumentReaderTest.java @@ -148,4 +148,5 @@ public void testFixHrefs_invalid_prefix() { // then Assert.assertTrue(true); } + } diff --git a/epublib-core/src/test/java/nl/siegmann/epublib/epub/ResourcesLoaderTest.java b/epublib-core/src/test/java/nl/siegmann/epublib/epub/ResourcesLoaderTest.java index a4ea4da9..3ddcfbef 100644 --- a/epublib-core/src/test/java/nl/siegmann/epublib/epub/ResourcesLoaderTest.java +++ b/epublib-core/src/test/java/nl/siegmann/epublib/epub/ResourcesLoaderTest.java @@ -8,6 +8,7 @@ import nl.siegmann.epublib.domain.Resources; import nl.siegmann.epublib.service.MediatypeService; import nl.siegmann.epublib.util.IOUtil; +import org.apache.commons.io.input.UnixLineEndingInputStream; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; @@ -153,7 +154,7 @@ private void verifyResources(Resources resources) throws IOException { Assert.assertEquals("OEBPS/book1.css", resource.getHref()); Assert.assertEquals(MediatypeService.CSS, resource.getMediaType()); Assert.assertEquals(65, resource.getData().length); - expectedData = IOUtil.toByteArray(this.getClass().getResourceAsStream("/book1/book1.css")); + expectedData = IOUtil.toByteArray(new UnixLineEndingInputStream(getClass().getResourceAsStream("/book1/book1.css"), false)); Assert.assertArrayEquals(expectedData, resource.getData()); @@ -163,7 +164,7 @@ private void verifyResources(Resources resources) throws IOException { Assert.assertEquals("OEBPS/chapter1.html", resource.getHref()); Assert.assertEquals(MediatypeService.XHTML, resource.getMediaType()); Assert.assertEquals(247, resource.getData().length); - expectedData = IOUtil.toByteArray(this.getClass().getResourceAsStream("/book1/chapter1.html")); + expectedData = IOUtil.toByteArray(new UnixLineEndingInputStream(getClass().getResourceAsStream("/book1/chapter1.html"), false)); Assert.assertArrayEquals(expectedData, resource.getData()); } } diff --git a/epublib-core/src/test/java/nl/siegmann/epublib/epub/Simple1.java b/epublib-core/src/test/java/nl/siegmann/epublib/epub/Simple1.java index 8801836d..0cdc52fc 100644 --- a/epublib-core/src/test/java/nl/siegmann/epublib/epub/Simple1.java +++ b/epublib-core/src/test/java/nl/siegmann/epublib/epub/Simple1.java @@ -2,10 +2,7 @@ import java.io.FileOutputStream; -import nl.siegmann.epublib.domain.Author; -import nl.siegmann.epublib.domain.Book; -import nl.siegmann.epublib.domain.Resource; -import nl.siegmann.epublib.domain.TOCReference; +import nl.siegmann.epublib.domain.*; public class Simple1 { public static void main(String[] args) { @@ -14,7 +11,7 @@ public static void main(String[] args) { Book book = new Book(); // Set the title - book.getMetadata().addTitle("Epublib test book 1"); + book.getMetadata().addTitle(new Title("Epublib test book 1")); // Add an Author book.getMetadata().addAuthor(new Author("Joe", "Tester")); @@ -49,4 +46,4 @@ public static void main(String[] args) { e.printStackTrace(); } } -} \ No newline at end of file +} diff --git a/epublib-core/src/test/resources/chm1/CHM-example.hhc b/epublib-core/src/test/resources/chm1/CHM-example.hhc index b6cd630d..2a2fc7b8 100644 --- a/epublib-core/src/test/resources/chm1/CHM-example.hhc +++ b/epublib-core/src/test/resources/chm1/CHM-example.hhc @@ -1,108 +1,108 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<HTML> -<HEAD> -<meta name="GENERATOR" content="Microsoft® HTML Help Workshop 4.1"> -<!-- Sitemap 1.0 --> -</HEAD><BODY> -<OBJECT type="text/site properties"> - <param name="Window Styles" value="0x800025"> -</OBJECT> -<UL> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="Welcome"> - <param name="Local" value="index.htm"> - </OBJECT> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="Context-sensitive example"> - </OBJECT> - <UL> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="Context sensitive help topic 10000"> - <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> - </OBJECT> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="Context sensitive help topic 10010"> - <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> - </OBJECT> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="Context sensitive help topic 20000"> - <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> - </OBJECT> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="Context sensitive help topic 20010"> - <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> - </OBJECT> - </UL> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="Garden"> - <param name="Local" value="Garden/Garden.htm"> - </OBJECT> - <UL> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="Flowers"> - <param name="Local" value="Garden/flowers.htm"> - </OBJECT> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="How one grows trees"> - <param name="Local" value="Garden/tree.htm"> - </OBJECT> - </UL> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="HTMLHelp Examples"> - </OBJECT> - <UL> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="Attention (!) - Close CHM Window automatically"> - <param name="Local" value="HTMLHelp_Examples/CloseWindowAutomatically.htm"> - </OBJECT> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="How to split HTML topics"> - <param name="Local" value="HTMLHelp_Examples/topic_split_example.htm"> - </OBJECT> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="How to use shortcut links"> - <param name="Local" value="HTMLHelp_Examples/shortcut_link.htm"> - </OBJECT> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="How to jump to a anchor"> - <param name="Local" value="HTMLHelp_Examples/Jump_to_anchor.htm#AnchorSample"> - </OBJECT> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="How to jump to a second anchor"> - <param name="Local" value="HTMLHelp_Examples/Jump_to_anchor.htm#SecondAnchor"> - </OBJECT> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="How to use HTMLHelp PopUp's"> - <param name="Local" value="HTMLHelp_Examples/pop-up_example.htm"> - </OBJECT> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="How to link to HTML files (not embedded)"> - <param name="Local" value="HTMLHelp_Examples/Simple_link_example.htm"> - </OBJECT> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="How to link to PDF (embedded) from topic"> - <param name="Local" value="HTMLHelp_Examples/LinkPDFfromCHM.htm"> - </OBJECT> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="How to link to PDF (local not embedded)"> - <param name="Local" value="HTMLHelp_Examples/example-external-pdf.htm"> - </OBJECT> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="How to link to PDF (server)"> - <param name="Local" value="http://www.help-info.de/download/pdf/example.pdf"> - <param name="ImageNumber" value="13"> - </OBJECT> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="How to jump directly from here (e.g. VW)"> - <param name="Local" value="http://www.volkswagen.co.uk/home"> - <param name="ImageNumber" value="13"> - </OBJECT> - <LI> <OBJECT type="text/sitemap"> - <param name="Name" value="How to open a second window (e.g. VW)"> - <param name="Local" value="http://www.volkswagen.co.uk/home"> - <param name="WindowName" value="wndTopic"> - <param name="ImageNumber" value="13"> - </OBJECT> - </UL> -</UL> -</BODY></HTML> +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> +<HTML> +<HEAD> +<meta name="GENERATOR" content="Microsoft® HTML Help Workshop 4.1"> +<!-- Sitemap 1.0 --> +</HEAD><BODY> +<OBJECT type="text/site properties"> + <param name="Window Styles" value="0x800025"> +</OBJECT> +<UL> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="Welcome"> + <param name="Local" value="index.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="Context-sensitive example"> + </OBJECT> + <UL> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="Context sensitive help topic 10000"> + <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="Context sensitive help topic 10010"> + <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="Context sensitive help topic 20000"> + <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="Context sensitive help topic 20010"> + <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> + </OBJECT> + </UL> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="Garden"> + <param name="Local" value="Garden/Garden.htm"> + </OBJECT> + <UL> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="Flowers"> + <param name="Local" value="Garden/flowers.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="How one grows trees"> + <param name="Local" value="Garden/tree.htm"> + </OBJECT> + </UL> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="HTMLHelp Examples"> + </OBJECT> + <UL> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="Attention (!) - Close CHM Window automatically"> + <param name="Local" value="HTMLHelp_Examples/CloseWindowAutomatically.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="How to split HTML topics"> + <param name="Local" value="HTMLHelp_Examples/topic_split_example.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="How to use shortcut links"> + <param name="Local" value="HTMLHelp_Examples/shortcut_link.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="How to jump to a anchor"> + <param name="Local" value="HTMLHelp_Examples/Jump_to_anchor.htm#AnchorSample"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="How to jump to a second anchor"> + <param name="Local" value="HTMLHelp_Examples/Jump_to_anchor.htm#SecondAnchor"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="How to use HTMLHelp PopUp's"> + <param name="Local" value="HTMLHelp_Examples/pop-up_example.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="How to link to HTML files (not embedded)"> + <param name="Local" value="HTMLHelp_Examples/Simple_link_example.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="How to link to PDF (embedded) from topic"> + <param name="Local" value="HTMLHelp_Examples/LinkPDFfromCHM.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="How to link to PDF (local not embedded)"> + <param name="Local" value="HTMLHelp_Examples/example-external-pdf.htm"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="How to link to PDF (server)"> + <param name="Local" value="http://www.help-info.de/download/pdf/example.pdf"> + <param name="ImageNumber" value="13"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="How to jump directly from here (e.g. VW)"> + <param name="Local" value="http://www.volkswagen.co.uk/home"> + <param name="ImageNumber" value="13"> + </OBJECT> + <LI> <OBJECT type="text/sitemap"> + <param name="Name" value="How to open a second window (e.g. VW)"> + <param name="Local" value="http://www.volkswagen.co.uk/home"> + <param name="WindowName" value="wndTopic"> + <param name="ImageNumber" value="13"> + </OBJECT> + </UL> +</UL> +</BODY></HTML> diff --git a/epublib-core/src/test/resources/chm1/CHM-example.hhk b/epublib-core/src/test/resources/chm1/CHM-example.hhk index e65f2011..f2ee57c6 100644 --- a/epublib-core/src/test/resources/chm1/CHM-example.hhk +++ b/epublib-core/src/test/resources/chm1/CHM-example.hhk @@ -1,458 +1,458 @@ -<html> -<head> -<meta name="generator" content="Help Information® Keyword Index Tool (KIT) 0.6.1"> -<!-- Sitemap 1.0 --> -</head> -<body> -<object type="text/site properties"> - <param name="FrameName" value="right"> - <param name="Font" value="Verdana,8,0"> -</object> -<ul> -<li><object type="text/sitemap"> - <param name="Name" value="10000"> - <param name="Name" value="Context sensitive help topic 10000"> - <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="10010"> - <param name="Name" value="Context sensitive help topic 10010"> - <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="20000"> - <param name="Name" value="Context sensitive help topic 20000"> - <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="20010"> - <param name="Name" value="Context sensitive help topic 20010"> - <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="alias"> - <param name="Name" value="Context sensitive help topic 10000"> - <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> - <param name="Name" value="Context sensitive help topic 10010"> - <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> - <param name="Name" value="Context sensitive help topic 20000"> - <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> - <param name="Name" value="Context sensitive help topic 20010"> - <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="anchor"> - <param name="Name" value="How to jump to a anchor"> - <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm"> - <param name="Name" value="How to jump to a anchor"> - <param name="Local" value="HTMLHelp_Examples/pop-up_example.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="AnchorSample InnerText Headline"> - <param name="Name" value="How to jump to a anchor"> - <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm#AnchorSample"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="AnchorSample"> - <param name="Name" value="How to jump to a anchor"> - <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm#AnchorSample"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="Attention"> - <param name="Name" value="Attention (!) - Close Window automatically"> - <param name="Local" value="HTMLHelp_Examples/CloseWindowAutomatically.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="automatically"> - <param name="Name" value="Attention (!) - Close Window automatically"> - <param name="Local" value="HTMLHelp_Examples/CloseWindowAutomatically.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="Bookmark"> - <param name="Name" value="How to jump to a anchor"> - <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="Boxes"> - <param name="Name" value="XP Style for RadioButton and Check Boxes"> - <param name="Local" value="HTMLHelp_Examples/xp-style_radio-button_check-boxes.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="Check"> - <param name="Name" value="XP Style for RadioButton and Check Boxes"> - <param name="Local" value="HTMLHelp_Examples/xp-style_radio-button_check-boxes.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="CHM"> - <param name="Name" value="Linking to PDF from CHM"> - <param name="Local" value="HTMLHelp_Examples/LinkPDFfromCHM.htm"> - <param name="Name" value="Using CHM shortcut links"> - <param name="Local" value="HTMLHelp_Examples/shortcut_link.htm"> - <param name="Name" value="Linking from CHM with standard HTML"> - <param name="Local" value="HTMLHelp_Examples/simple_link_example.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="Close"> - <param name="Name" value="Attention (!) - Close Window automatically"> - <param name="Local" value="HTMLHelp_Examples/CloseWindowAutomatically.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="content"> - <param name="Name" value="External Topic"> - <param name="Local" value="external_files/external_topic.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="Contents"> - <param name="Name" value="Welcome"> - <param name="Local" value="index.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="Context"> - <param name="Name" value="Context sensitive help topic 10000"> - <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> - <param name="Name" value="Context sensitive help topic 10010"> - <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> - <param name="Name" value="Context sensitive help topic 20000"> - <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> - <param name="Name" value="Context sensitive help topic 20010"> - <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="contextID"> - <param name="Name" value="Context sensitive help topic 10000"> - <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> - <param name="Name" value="Context sensitive help topic 10010"> - <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> - <param name="Name" value="Context sensitive help topic 20000"> - <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> - <param name="Name" value="Context sensitive help topic 20010"> - <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="download"> - <param name="Name" value="How to jump to a anchor"> - <param name="Local" value="HTMLHelp_Examples/pop-up_example.htm"> - <param name="Name" value="Topic split example"> - <param name="Local" value="HTMLHelp_Examples/topic_split_example.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="Example"> - <param name="Name" value="Example load PDF from TOC"> - <param name="Local" value="HTMLHelp_Examples/example-external-pdf.htm"> - <param name="Name" value="Topic split example"> - <param name="Local" value="HTMLHelp_Examples/topic_split_example.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="External"> - <param name="Name" value="External Topic"> - <param name="Local" value="external_files/external_topic.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="flowers"> - <param name="Name" value="Flowers"> - <param name="Local" value="Garden/flowers.htm"> - <param name="Name" value="Flowers"> - <param name="Local" value="Garden/flowers.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="garden"> - <param name="Name" value="Flowers"> - <param name="Local" value="Garden/flowers.htm"> - <param name="Name" value="Garden"> - <param name="Local" value="Garden/garden.htm"> - <param name="Name" value="Garden"> - <param name="Local" value="Garden/garden.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="grows"> - <param name="Name" value="How one grows trees"> - <param name="Local" value="Garden/tree.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="Headline"> - <param name="Name" value="How to jump to a anchor"> - <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm#AnchorSample"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="help"> - <param name="Name" value="Context sensitive help topic 10000"> - <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> - <param name="Name" value="Context sensitive help topic 10010"> - <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> - <param name="Name" value="Context sensitive help topic 20000"> - <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> - <param name="Name" value="Context sensitive help topic 20010"> - <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="hole"> - <param name="Name" value="How one grows trees"> - <param name="Local" value="Garden/tree.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="home"> - <param name="Name" value="Garden"> - <param name="Local" value="Garden/garden.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="How"> - <param name="Name" value="How one grows trees"> - <param name="Local" value="Garden/tree.htm"> - <param name="Name" value="How to jump to a anchor"> - <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm"> - <param name="Name" value="How to jump to a anchor"> - <param name="Local" value="HTMLHelp_Examples/pop-up_example.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="HTML"> - <param name="Name" value="Linking from CHM with standard HTML"> - <param name="Local" value="HTMLHelp_Examples/simple_link_example.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="Index"> - <param name="Name" value="How to jump to a anchor"> - <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="InnerText"> - <param name="Name" value="How to jump to a anchor"> - <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm#AnchorSample"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="internet connection"> - <param name="Name" value="How to jump to a anchor"> - <param name="Local" value="HTMLHelp_Examples/pop-up_example.htm"> - <param name="Name" value="Topic split example"> - <param name="Local" value="HTMLHelp_Examples/topic_split_example.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="jump"> - <param name="Name" value="How to jump to a anchor"> - <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm"> - <param name="Name" value="How to jump to a anchor"> - <param name="Local" value="HTMLHelp_Examples/pop-up_example.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="Link"> - <param name="Name" value="Using CHM shortcut links"> - <param name="Local" value="HTMLHelp_Examples/shortcut_link.htm"> - <param name="Name" value="Using window.open"> - <param name="Local" value="HTMLHelp_Examples/using_window_open.htm"> - <param name="Name" value="XP Style for RadioButton and Check Boxes"> - <param name="Local" value="HTMLHelp_Examples/xp-style_radio-button_check-boxes.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="Linking"> - <param name="Name" value="Linking to PDF from CHM"> - <param name="Local" value="HTMLHelp_Examples/LinkPDFfromCHM.htm"> - <param name="Name" value="Linking from CHM with standard HTML"> - <param name="Local" value="HTMLHelp_Examples/simple_link_example.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="links"> - <param name="Name" value="Using CHM shortcut links"> - <param name="Local" value="HTMLHelp_Examples/shortcut_link.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="load"> - <param name="Name" value="Example load PDF from TOC"> - <param name="Local" value="HTMLHelp_Examples/example-external-pdf.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="map"> - <param name="Name" value="Context sensitive help topic 10000"> - <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> - <param name="Name" value="Context sensitive help topic 10010"> - <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> - <param name="Name" value="Context sensitive help topic 20000"> - <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> - <param name="Name" value="Context sensitive help topic 20010"> - <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="open"> - <param name="Name" value="Using window.open"> - <param name="Local" value="HTMLHelp_Examples/using_window_open.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="PDF"> - <param name="Name" value="Example load PDF from TOC"> - <param name="Local" value="HTMLHelp_Examples/example-external-pdf.htm"> - <param name="Name" value="Linking to PDF from CHM"> - <param name="Local" value="HTMLHelp_Examples/LinkPDFfromCHM.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="plant"> - <param name="Name" value="Garden"> - <param name="Local" value="Garden/garden.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="RadioButton"> - <param name="Name" value="XP Style for RadioButton and Check Boxes"> - <param name="Local" value="HTMLHelp_Examples/xp-style_radio-button_check-boxes.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="SecondAnchor"> - <param name="Name" value="How to jump to a anchor"> - <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm#SecondAnchor"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="sensitive"> - <param name="Name" value="Context sensitive help topic 10000"> - <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> - <param name="Name" value="Context sensitive help topic 10010"> - <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> - <param name="Name" value="Context sensitive help topic 20000"> - <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> - <param name="Name" value="Context sensitive help topic 20010"> - <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="Shortcut"> - <param name="Name" value="Using CHM shortcut links"> - <param name="Local" value="HTMLHelp_Examples/shortcut_link.htm"> - <param name="Name" value="Using CHM shortcut links"> - <param name="Local" value="HTMLHelp_Examples/shortcut_link.htm"> - <param name="Name" value="Using window.open"> - <param name="Local" value="HTMLHelp_Examples/using_window_open.htm"> - <param name="Name" value="XP Style for RadioButton and Check Boxes"> - <param name="Local" value="HTMLHelp_Examples/xp-style_radio-button_check-boxes.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="split"> - <param name="Name" value="Topic split example"> - <param name="Local" value="HTMLHelp_Examples/topic_split_example.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="standard"> - <param name="Name" value="Linking from CHM with standard HTML"> - <param name="Local" value="HTMLHelp_Examples/simple_link_example.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="Style"> - <param name="Name" value="XP Style for RadioButton and Check Boxes"> - <param name="Local" value="HTMLHelp_Examples/xp-style_radio-button_check-boxes.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="TOC"> - <param name="Name" value="Example load PDF from TOC"> - <param name="Local" value="HTMLHelp_Examples/example-external-pdf.htm"> - <param name="Name" value="How to jump to a anchor"> - <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="topic"> - <param name="Name" value="Context sensitive help topic 10000"> - <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> - <param name="Name" value="Context sensitive help topic 10010"> - <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> - <param name="Name" value="Context sensitive help topic 20000"> - <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> - <param name="Name" value="Context sensitive help topic 20010"> - <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> - <param name="Name" value="External Topic"> - <param name="Local" value="external_files/external_topic.htm"> - <param name="Name" value="Topic split example"> - <param name="Local" value="HTMLHelp_Examples/topic_split_example.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="tree"> - <param name="Name" value="How one grows trees"> - <param name="Local" value="Garden/tree.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="trees"> - <param name="Name" value="How one grows trees"> - <param name="Local" value="Garden/tree.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="Using"> - <param name="Name" value="Using CHM shortcut links"> - <param name="Local" value="HTMLHelp_Examples/shortcut_link.htm"> - <param name="Name" value="Using window.open"> - <param name="Local" value="HTMLHelp_Examples/using_window_open.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="Welcome"> - <param name="Name" value="Welcome"> - <param name="Local" value="index.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="windmill"> - <param name="Name" value="Linking from CHM with standard HTML"> - <param name="Local" value="HTMLHelp_Examples/simple_link_example.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="Window"> - <param name="Name" value="Attention (!) - Close Window automatically"> - <param name="Local" value="HTMLHelp_Examples/CloseWindowAutomatically.htm"> - <param name="Name" value="Using window.open"> - <param name="Local" value="HTMLHelp_Examples/using_window_open.htm"> - </object> - </li> -<li><object type="text/sitemap"> - <param name="Name" value="XP"> - <param name="Name" value="XP Style for RadioButton and Check Boxes"> - <param name="Local" value="HTMLHelp_Examples/xp-style_radio-button_check-boxes.htm"> - </object> - </li> -</ul> -</body> -</html> +<html> +<head> +<meta name="generator" content="Help Information® Keyword Index Tool (KIT) 0.6.1"> +<!-- Sitemap 1.0 --> +</head> +<body> +<object type="text/site properties"> + <param name="FrameName" value="right"> + <param name="Font" value="Verdana,8,0"> +</object> +<ul> +<li><object type="text/sitemap"> + <param name="Name" value="10000"> + <param name="Name" value="Context sensitive help topic 10000"> + <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="10010"> + <param name="Name" value="Context sensitive help topic 10010"> + <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="20000"> + <param name="Name" value="Context sensitive help topic 20000"> + <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="20010"> + <param name="Name" value="Context sensitive help topic 20010"> + <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="alias"> + <param name="Name" value="Context sensitive help topic 10000"> + <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> + <param name="Name" value="Context sensitive help topic 10010"> + <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> + <param name="Name" value="Context sensitive help topic 20000"> + <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> + <param name="Name" value="Context sensitive help topic 20010"> + <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="anchor"> + <param name="Name" value="How to jump to a anchor"> + <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm"> + <param name="Name" value="How to jump to a anchor"> + <param name="Local" value="HTMLHelp_Examples/pop-up_example.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="AnchorSample InnerText Headline"> + <param name="Name" value="How to jump to a anchor"> + <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm#AnchorSample"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="AnchorSample"> + <param name="Name" value="How to jump to a anchor"> + <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm#AnchorSample"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="Attention"> + <param name="Name" value="Attention (!) - Close Window automatically"> + <param name="Local" value="HTMLHelp_Examples/CloseWindowAutomatically.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="automatically"> + <param name="Name" value="Attention (!) - Close Window automatically"> + <param name="Local" value="HTMLHelp_Examples/CloseWindowAutomatically.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="Bookmark"> + <param name="Name" value="How to jump to a anchor"> + <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="Boxes"> + <param name="Name" value="XP Style for RadioButton and Check Boxes"> + <param name="Local" value="HTMLHelp_Examples/xp-style_radio-button_check-boxes.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="Check"> + <param name="Name" value="XP Style for RadioButton and Check Boxes"> + <param name="Local" value="HTMLHelp_Examples/xp-style_radio-button_check-boxes.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="CHM"> + <param name="Name" value="Linking to PDF from CHM"> + <param name="Local" value="HTMLHelp_Examples/LinkPDFfromCHM.htm"> + <param name="Name" value="Using CHM shortcut links"> + <param name="Local" value="HTMLHelp_Examples/shortcut_link.htm"> + <param name="Name" value="Linking from CHM with standard HTML"> + <param name="Local" value="HTMLHelp_Examples/simple_link_example.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="Close"> + <param name="Name" value="Attention (!) - Close Window automatically"> + <param name="Local" value="HTMLHelp_Examples/CloseWindowAutomatically.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="content"> + <param name="Name" value="External Topic"> + <param name="Local" value="external_files/external_topic.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="Contents"> + <param name="Name" value="Welcome"> + <param name="Local" value="index.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="Context"> + <param name="Name" value="Context sensitive help topic 10000"> + <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> + <param name="Name" value="Context sensitive help topic 10010"> + <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> + <param name="Name" value="Context sensitive help topic 20000"> + <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> + <param name="Name" value="Context sensitive help topic 20010"> + <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="contextID"> + <param name="Name" value="Context sensitive help topic 10000"> + <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> + <param name="Name" value="Context sensitive help topic 10010"> + <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> + <param name="Name" value="Context sensitive help topic 20000"> + <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> + <param name="Name" value="Context sensitive help topic 20010"> + <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="download"> + <param name="Name" value="How to jump to a anchor"> + <param name="Local" value="HTMLHelp_Examples/pop-up_example.htm"> + <param name="Name" value="Topic split example"> + <param name="Local" value="HTMLHelp_Examples/topic_split_example.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="Example"> + <param name="Name" value="Example load PDF from TOC"> + <param name="Local" value="HTMLHelp_Examples/example-external-pdf.htm"> + <param name="Name" value="Topic split example"> + <param name="Local" value="HTMLHelp_Examples/topic_split_example.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="External"> + <param name="Name" value="External Topic"> + <param name="Local" value="external_files/external_topic.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="flowers"> + <param name="Name" value="Flowers"> + <param name="Local" value="Garden/flowers.htm"> + <param name="Name" value="Flowers"> + <param name="Local" value="Garden/flowers.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="garden"> + <param name="Name" value="Flowers"> + <param name="Local" value="Garden/flowers.htm"> + <param name="Name" value="Garden"> + <param name="Local" value="Garden/garden.htm"> + <param name="Name" value="Garden"> + <param name="Local" value="Garden/garden.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="grows"> + <param name="Name" value="How one grows trees"> + <param name="Local" value="Garden/tree.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="Headline"> + <param name="Name" value="How to jump to a anchor"> + <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm#AnchorSample"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="help"> + <param name="Name" value="Context sensitive help topic 10000"> + <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> + <param name="Name" value="Context sensitive help topic 10010"> + <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> + <param name="Name" value="Context sensitive help topic 20000"> + <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> + <param name="Name" value="Context sensitive help topic 20010"> + <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="hole"> + <param name="Name" value="How one grows trees"> + <param name="Local" value="Garden/tree.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="home"> + <param name="Name" value="Garden"> + <param name="Local" value="Garden/garden.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="How"> + <param name="Name" value="How one grows trees"> + <param name="Local" value="Garden/tree.htm"> + <param name="Name" value="How to jump to a anchor"> + <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm"> + <param name="Name" value="How to jump to a anchor"> + <param name="Local" value="HTMLHelp_Examples/pop-up_example.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="HTML"> + <param name="Name" value="Linking from CHM with standard HTML"> + <param name="Local" value="HTMLHelp_Examples/simple_link_example.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="Index"> + <param name="Name" value="How to jump to a anchor"> + <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="InnerText"> + <param name="Name" value="How to jump to a anchor"> + <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm#AnchorSample"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="internet connection"> + <param name="Name" value="How to jump to a anchor"> + <param name="Local" value="HTMLHelp_Examples/pop-up_example.htm"> + <param name="Name" value="Topic split example"> + <param name="Local" value="HTMLHelp_Examples/topic_split_example.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="jump"> + <param name="Name" value="How to jump to a anchor"> + <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm"> + <param name="Name" value="How to jump to a anchor"> + <param name="Local" value="HTMLHelp_Examples/pop-up_example.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="Link"> + <param name="Name" value="Using CHM shortcut links"> + <param name="Local" value="HTMLHelp_Examples/shortcut_link.htm"> + <param name="Name" value="Using window.open"> + <param name="Local" value="HTMLHelp_Examples/using_window_open.htm"> + <param name="Name" value="XP Style for RadioButton and Check Boxes"> + <param name="Local" value="HTMLHelp_Examples/xp-style_radio-button_check-boxes.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="Linking"> + <param name="Name" value="Linking to PDF from CHM"> + <param name="Local" value="HTMLHelp_Examples/LinkPDFfromCHM.htm"> + <param name="Name" value="Linking from CHM with standard HTML"> + <param name="Local" value="HTMLHelp_Examples/simple_link_example.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="links"> + <param name="Name" value="Using CHM shortcut links"> + <param name="Local" value="HTMLHelp_Examples/shortcut_link.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="load"> + <param name="Name" value="Example load PDF from TOC"> + <param name="Local" value="HTMLHelp_Examples/example-external-pdf.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="map"> + <param name="Name" value="Context sensitive help topic 10000"> + <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> + <param name="Name" value="Context sensitive help topic 10010"> + <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> + <param name="Name" value="Context sensitive help topic 20000"> + <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> + <param name="Name" value="Context sensitive help topic 20010"> + <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="open"> + <param name="Name" value="Using window.open"> + <param name="Local" value="HTMLHelp_Examples/using_window_open.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="PDF"> + <param name="Name" value="Example load PDF from TOC"> + <param name="Local" value="HTMLHelp_Examples/example-external-pdf.htm"> + <param name="Name" value="Linking to PDF from CHM"> + <param name="Local" value="HTMLHelp_Examples/LinkPDFfromCHM.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="plant"> + <param name="Name" value="Garden"> + <param name="Local" value="Garden/garden.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="RadioButton"> + <param name="Name" value="XP Style for RadioButton and Check Boxes"> + <param name="Local" value="HTMLHelp_Examples/xp-style_radio-button_check-boxes.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="SecondAnchor"> + <param name="Name" value="How to jump to a anchor"> + <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm#SecondAnchor"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="sensitive"> + <param name="Name" value="Context sensitive help topic 10000"> + <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> + <param name="Name" value="Context sensitive help topic 10010"> + <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> + <param name="Name" value="Context sensitive help topic 20000"> + <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> + <param name="Name" value="Context sensitive help topic 20010"> + <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="Shortcut"> + <param name="Name" value="Using CHM shortcut links"> + <param name="Local" value="HTMLHelp_Examples/shortcut_link.htm"> + <param name="Name" value="Using CHM shortcut links"> + <param name="Local" value="HTMLHelp_Examples/shortcut_link.htm"> + <param name="Name" value="Using window.open"> + <param name="Local" value="HTMLHelp_Examples/using_window_open.htm"> + <param name="Name" value="XP Style for RadioButton and Check Boxes"> + <param name="Local" value="HTMLHelp_Examples/xp-style_radio-button_check-boxes.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="split"> + <param name="Name" value="Topic split example"> + <param name="Local" value="HTMLHelp_Examples/topic_split_example.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="standard"> + <param name="Name" value="Linking from CHM with standard HTML"> + <param name="Local" value="HTMLHelp_Examples/simple_link_example.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="Style"> + <param name="Name" value="XP Style for RadioButton and Check Boxes"> + <param name="Local" value="HTMLHelp_Examples/xp-style_radio-button_check-boxes.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="TOC"> + <param name="Name" value="Example load PDF from TOC"> + <param name="Local" value="HTMLHelp_Examples/example-external-pdf.htm"> + <param name="Name" value="How to jump to a anchor"> + <param name="Local" value="HTMLHelp_Examples/jump_to_anchor.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="topic"> + <param name="Name" value="Context sensitive help topic 10000"> + <param name="Local" value="Context-sensitive_example/contextID-10000.htm"> + <param name="Name" value="Context sensitive help topic 10010"> + <param name="Local" value="Context-sensitive_example/contextID-10010.htm"> + <param name="Name" value="Context sensitive help topic 20000"> + <param name="Local" value="Context-sensitive_example/contextID-20000.htm"> + <param name="Name" value="Context sensitive help topic 20010"> + <param name="Local" value="Context-sensitive_example/contextID-20010.htm"> + <param name="Name" value="External Topic"> + <param name="Local" value="external_files/external_topic.htm"> + <param name="Name" value="Topic split example"> + <param name="Local" value="HTMLHelp_Examples/topic_split_example.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="tree"> + <param name="Name" value="How one grows trees"> + <param name="Local" value="Garden/tree.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="trees"> + <param name="Name" value="How one grows trees"> + <param name="Local" value="Garden/tree.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="Using"> + <param name="Name" value="Using CHM shortcut links"> + <param name="Local" value="HTMLHelp_Examples/shortcut_link.htm"> + <param name="Name" value="Using window.open"> + <param name="Local" value="HTMLHelp_Examples/using_window_open.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="Welcome"> + <param name="Name" value="Welcome"> + <param name="Local" value="index.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="windmill"> + <param name="Name" value="Linking from CHM with standard HTML"> + <param name="Local" value="HTMLHelp_Examples/simple_link_example.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="Window"> + <param name="Name" value="Attention (!) - Close Window automatically"> + <param name="Local" value="HTMLHelp_Examples/CloseWindowAutomatically.htm"> + <param name="Name" value="Using window.open"> + <param name="Local" value="HTMLHelp_Examples/using_window_open.htm"> + </object> + </li> +<li><object type="text/sitemap"> + <param name="Name" value="XP"> + <param name="Name" value="XP Style for RadioButton and Check Boxes"> + <param name="Local" value="HTMLHelp_Examples/xp-style_radio-button_check-boxes.htm"> + </object> + </li> +</ul> +</body> +</html> diff --git a/epublib-core/src/test/resources/chm1/HTMLHelp_Examples/CloseWindowAutomatically.htm b/epublib-core/src/test/resources/chm1/HTMLHelp_Examples/CloseWindowAutomatically.htm index daf776f0..2655be2d 100644 --- a/epublib-core/src/test/resources/chm1/HTMLHelp_Examples/CloseWindowAutomatically.htm +++ b/epublib-core/src/test/resources/chm1/HTMLHelp_Examples/CloseWindowAutomatically.htm @@ -1,58 +1,58 @@ -<?xml version="1.0" encoding="iso-8859-1"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xmlns:MSHelp="http://msdn.microsoft.com/mshelp"> -<head> -<title>Attention (!) - Close Window automatically - - - - - - - - - - - - - - - - - -
go to home ...
- -

Close Window automatically

-

One can close HTML Help window without getting a click from user by the following - code. Use "Close" ActiveX Control and Javascript as shown below.

-

Code

-

 

-

<OBJECT id=hhctrl type="application/x-oleobject"
- classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11"
- codebase="hhctrl.ocx#Version=5,2,3790,233">
- <PARAM name="Command" value="Close">
- </OBJECT>
- <script type="text/javascript" language="JavaScript">
- <!--
- window.setTimeout('hhctrl.Click();',1000);
- // -->
- </script>

-

 

-

 

-

 

-

 

- - - - - -
back to top ...
-
-

 

- - + + + + +Attention (!) - Close Window automatically + + + + + + + + + + + + + + + + + +
go to home ...
+ +

Close Window automatically

+

One can close HTML Help window without getting a click from user by the following + code. Use "Close" ActiveX Control and Javascript as shown below.

+

Code

+

 

+

<OBJECT id=hhctrl type="application/x-oleobject"
+ classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11"
+ codebase="hhctrl.ocx#Version=5,2,3790,233">
+ <PARAM name="Command" value="Close">
+ </OBJECT>
+ <script type="text/javascript" language="JavaScript">
+ <!--
+ window.setTimeout('hhctrl.Click();',1000);
+ // -->
+ </script>

+

 

+

 

+

 

+

 

+ + + + + +
back to top ...
+
+

 

+ + diff --git a/epublib-core/src/test/resources/opf/test2.opf b/epublib-core/src/test/resources/opf/test2.opf index 615b4194..9a389928 100644 --- a/epublib-core/src/test/resources/opf/test2.opf +++ b/epublib-core/src/test/resources/opf/test2.opf @@ -18,6 +18,6 @@ - + - + diff --git a/epublib-core/src/test/resources/opf/test3.opf b/epublib-core/src/test/resources/opf/test3.opf new file mode 100644 index 00000000..fe58f592 --- /dev/null +++ b/epublib-core/src/test/resources/opf/test3.opf @@ -0,0 +1,17 @@ + + + + Epublib test book 1 + Joe Tester + 2010-05-27 + en + + + + + + + + + + diff --git a/epublib-parent/pom.xml b/epublib-parent/pom.xml index e2ac8d8e..d75547a7 100644 --- a/epublib-parent/pom.xml +++ b/epublib-parent/pom.xml @@ -9,7 +9,7 @@ epublib-parent epublib-parent pom - 4.0 + 4.0.1-EPUB3-SNAPSHOT A java library for reading/writing/manipulating epub files http://www.siegmann.nl/epublib 2009 @@ -122,9 +122,13 @@ - github.repo - file:///D:/private/project/git-maven-repo/mvn-repo/releases + thirdparty + https://tools.pageplace.de/nexus/content/repositories/thirdparty + + snapshot_repo + https://tools.pageplace.de/nexus/content/repositories/snapshots/ + @@ -157,24 +161,6 @@ - - org.apache.maven.plugins - maven-javadoc-plugin - ${maven-javadoc-plugin.version} - - - 8 - none - - - - attach-javadocs - - jar - - - - diff --git a/epublib-tools/pom.xml b/epublib-tools/pom.xml index 66035581..22535c47 100644 --- a/epublib-tools/pom.xml +++ b/epublib-tools/pom.xml @@ -15,7 +15,7 @@ nl.siegmann.epublib epublib-parent - 4.0 + 4.0.1-EPUB3-SNAPSHOT ../epublib-parent/pom.xml diff --git a/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/CoverpageBookProcessor.java b/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/CoverpageBookProcessor.java index 0268635f..a1a64d85 100644 --- a/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/CoverpageBookProcessor.java +++ b/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/CoverpageBookProcessor.java @@ -22,8 +22,6 @@ import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -41,7 +39,7 @@ public class CoverpageBookProcessor implements BookProcessor { public static int MAX_COVER_IMAGE_SIZE = 999; - private static final Logger log = LoggerFactory.getLogger(CoverpageBookProcessor.class); + private static final Logger log = Logger.getLogger(CoverpageBookProcessor.class); public static final String DEFAULT_COVER_PAGE_ID = "cover"; public static final String DEFAULT_COVER_PAGE_HREF = "cover.html"; public static final String DEFAULT_COVER_IMAGE_ID = "cover-image"; @@ -141,7 +139,7 @@ private Resource getFirstImageSource(Resource titlePageResource, Resources resou } } } catch (Exception e) { - log.error(e.getMessage(), e); + log.severe(e.getMessage(), e); } return null; } diff --git a/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/DefaultBookProcessorPipeline.java b/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/DefaultBookProcessorPipeline.java index 38f6c4e6..b118ae4a 100644 --- a/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/DefaultBookProcessorPipeline.java +++ b/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/DefaultBookProcessorPipeline.java @@ -7,8 +7,6 @@ import nl.siegmann.epublib.epub.BookProcessor; import nl.siegmann.epublib.epub.BookProcessorPipeline; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * A book processor that combines several other bookprocessors @@ -21,7 +19,7 @@ */ public class DefaultBookProcessorPipeline extends BookProcessorPipeline { - private Logger log = LoggerFactory.getLogger(DefaultBookProcessorPipeline.class); + private Logger log = Logger.getLogger(DefaultBookProcessorPipeline.class); public DefaultBookProcessorPipeline() { super(createDefaultBookProcessors()); diff --git a/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/HtmlBookProcessor.java b/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/HtmlBookProcessor.java index 4b3f131b..3ccfa455 100644 --- a/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/HtmlBookProcessor.java +++ b/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/HtmlBookProcessor.java @@ -9,8 +9,6 @@ import nl.siegmann.epublib.epub.BookProcessor; import nl.siegmann.epublib.service.MediatypeService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Helper class for BookProcessors that only manipulate html type resources. @@ -20,7 +18,7 @@ */ public abstract class HtmlBookProcessor implements BookProcessor { - private final static Logger log = LoggerFactory.getLogger(HtmlBookProcessor.class); + private final static Logger log = Logger.getLogger(HtmlBookProcessor.class); public static final String OUTPUT_ENCODING = "UTF-8"; public HtmlBookProcessor() { @@ -32,7 +30,7 @@ public Book processBook(Book book) { try { cleanupResource(resource, book); } catch (IOException e) { - log.error(e.getMessage(), e); + log.severe(e.getMessage(), e); } } return book; diff --git a/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/HtmlCleanerBookProcessor.java b/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/HtmlCleanerBookProcessor.java index a662a207..f71de092 100644 --- a/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/HtmlCleanerBookProcessor.java +++ b/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/HtmlCleanerBookProcessor.java @@ -16,8 +16,6 @@ import org.htmlcleaner.EpublibXmlSerializer; import org.htmlcleaner.HtmlCleaner; import org.htmlcleaner.TagNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Cleans up regular html into xhtml. Uses HtmlCleaner to do this. @@ -29,7 +27,7 @@ public class HtmlCleanerBookProcessor extends HtmlBookProcessor implements BookProcessor { @SuppressWarnings("unused") - private final static Logger log = LoggerFactory.getLogger(HtmlCleanerBookProcessor.class); + private final static Logger log = Logger.getLogger(HtmlCleanerBookProcessor.class); private HtmlCleaner htmlCleaner; diff --git a/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/TextReplaceBookProcessor.java b/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/TextReplaceBookProcessor.java index 5bd46edf..c44b7400 100644 --- a/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/TextReplaceBookProcessor.java +++ b/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/TextReplaceBookProcessor.java @@ -12,8 +12,6 @@ import nl.siegmann.epublib.epub.BookProcessor; import org.apache.commons.io.IOUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Cleans up regular html into xhtml. @@ -25,7 +23,7 @@ public class TextReplaceBookProcessor extends HtmlBookProcessor implements BookProcessor { @SuppressWarnings("unused") - private final static Logger log = LoggerFactory.getLogger(TextReplaceBookProcessor.class); + private final static Logger log = Logger.getLogger(TextReplaceBookProcessor.class); public TextReplaceBookProcessor() { } diff --git a/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/XslBookProcessor.java b/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/XslBookProcessor.java index 45ed504c..c4db3bf7 100644 --- a/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/XslBookProcessor.java +++ b/epublib-tools/src/main/java/nl/siegmann/epublib/bookprocessor/XslBookProcessor.java @@ -24,8 +24,6 @@ import nl.siegmann.epublib.epub.BookProcessor; import nl.siegmann.epublib.epub.EpubProcessorSupport; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; @@ -40,7 +38,7 @@ */ public class XslBookProcessor extends HtmlBookProcessor implements BookProcessor { - private final static Logger log = LoggerFactory.getLogger(XslBookProcessor.class); + private final static Logger log = Logger.getLogger(XslBookProcessor.class); private Transformer transformer; @@ -67,7 +65,7 @@ public byte[] processHtml(Resource resource, Book book, String encoding) throws try { transformer.transform(htmlSource, streamResult); } catch (TransformerException e) { - log.error(e.getMessage(), e); + log.severe(e.getMessage(), e); throw new IOException(e); } result = out.toByteArray(); diff --git a/epublib-tools/src/main/java/nl/siegmann/epublib/search/SearchIndex.java b/epublib-tools/src/main/java/nl/siegmann/epublib/search/SearchIndex.java index 1c1c5d11..e9364b22 100644 --- a/epublib-tools/src/main/java/nl/siegmann/epublib/search/SearchIndex.java +++ b/epublib-tools/src/main/java/nl/siegmann/epublib/search/SearchIndex.java @@ -15,8 +15,6 @@ import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * A searchindex for searching through a book. @@ -26,7 +24,7 @@ */ public class SearchIndex { - private static final Logger log = LoggerFactory.getLogger(SearchIndex.class); + private static final Logger log = Logger.getLogger(SearchIndex.class); public static int NBSP = 0x00A0; @@ -117,7 +115,7 @@ public static String getSearchContent(Resource resource) { try { result = getSearchContent(resource.getReader()); } catch (IOException e) { - log.error(e.getMessage()); + log.severe(e.getMessage()); } return result; } diff --git a/epublib-tools/src/main/java/nl/siegmann/epublib/util/ToolsResourceUtil.java b/epublib-tools/src/main/java/nl/siegmann/epublib/util/ToolsResourceUtil.java index 3f84e175..d0a075de 100644 --- a/epublib-tools/src/main/java/nl/siegmann/epublib/util/ToolsResourceUtil.java +++ b/epublib-tools/src/main/java/nl/siegmann/epublib/util/ToolsResourceUtil.java @@ -21,8 +21,6 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringEscapeUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -35,7 +33,7 @@ */ public class ToolsResourceUtil { - private static Logger log = LoggerFactory.getLogger(ToolsResourceUtil.class); + private static Logger log = Logger.getLogger(ToolsResourceUtil.class); public static String getTitle(Resource resource) { @@ -88,7 +86,7 @@ public static String findTitleFromXhtml(Resource resource) { } } } catch (IOException e) { - log.error(e.getMessage()); + log.severe(e.getMessage()); } resource.setTitle(title); return title; diff --git a/epublib-tools/src/main/java/nl/siegmann/epublib/util/VFSUtil.java b/epublib-tools/src/main/java/nl/siegmann/epublib/util/VFSUtil.java index 4124ca42..7e4ceab4 100644 --- a/epublib-tools/src/main/java/nl/siegmann/epublib/util/VFSUtil.java +++ b/epublib-tools/src/main/java/nl/siegmann/epublib/util/VFSUtil.java @@ -24,7 +24,7 @@ */ public class VFSUtil { - private static final Logger log = LoggerFactory.getLogger(VFSUtil.class); + private static final Logger log = Logger.getLogger(VFSUtil.class); public static Resource createResource(FileObject rootDir, FileObject file, String inputEncoding) throws IOException { MediaType mediaType = MediatypeService.determineMediaType(file.getName().getBaseName()); @@ -57,8 +57,8 @@ public static FileObject resolveFileObject(String inputLocation) throws FileSyst try { result = VFS.getManager().resolveFile(new File("."), inputLocation); } catch (Exception e1) { - log.error(e.getMessage(), e); - log.error(e1.getMessage(), e); + log.severe(e.getMessage(), e); + log.severe(e1.getMessage(), e); } } return result; @@ -80,8 +80,8 @@ public static InputStream resolveInputStream(String inputLocation) throws FileSy try { result = new FileInputStream(inputLocation); } catch (FileNotFoundException e1) { - log.error(e.getMessage(), e); - log.error(e1.getMessage(), e); + log.severe(e.getMessage(), e); + log.severe(e1.getMessage(), e); } } return result; diff --git a/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/ContentPane.java b/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/ContentPane.java index ae76fac6..53357710 100644 --- a/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/ContentPane.java +++ b/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/ContentPane.java @@ -32,8 +32,6 @@ import nl.siegmann.epublib.util.DesktopUtil; import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Displays a page @@ -175,7 +173,7 @@ private static void scrollToElement(JEditorPane editorPane, HTMLDocument.Iterato rectangle.height = visibleRectangle.height; editorPane.scrollRectToVisible(rectangle); } catch (BadLocationException e) { - log.error(e.getMessage()); + log.severe(e.getMessage()); } } @@ -256,7 +254,7 @@ public void displayPage(Resource resource, int sectionPos) { editorPane.setDocument(document); scrollToCurrentPosition(sectionPos); } catch (Exception e) { - log.error("When reading resource " + resource.getId() + "(" + log.severe("When reading resource " + resource.getId() + "(" + resource.getHref() + ") :" + e.getMessage(), e); } } @@ -297,7 +295,7 @@ public void hyperlinkUpdate(HyperlinkEvent event) { Resource resource = navigator.getBook().getResources().getByHref(resourceHref); if (resource == null) { - log.error("Resource with url " + resourceHref + " not found"); + log.severe("Resource with url " + resourceHref + " not found"); } else { navigator.gotoResource(resource, this); } @@ -344,7 +342,7 @@ private String calculateTargetHref(URL clickUrl) { resourceHref = URLDecoder.decode(resourceHref, Constants.CHARACTER_ENCODING); } catch (UnsupportedEncodingException e) { - log.error(e.getMessage()); + log.severe(e.getMessage()); } resourceHref = resourceHref.substring(ImageLoaderCache.IMAGE_URL_PREFIX .length()); diff --git a/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/HTMLDocumentFactory.java b/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/HTMLDocumentFactory.java index 3af997b0..c180b72e 100644 --- a/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/HTMLDocumentFactory.java +++ b/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/HTMLDocumentFactory.java @@ -21,8 +21,6 @@ import nl.siegmann.epublib.service.MediatypeService; import org.apache.commons.io.IOUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Creates swing HTML documents from resources. @@ -34,7 +32,7 @@ */ public class HTMLDocumentFactory implements NavigationEventListener { - private static final Logger log = LoggerFactory.getLogger(HTMLDocumentFactory.class); + private static final Logger log = Logger.getLogger(HTMLDocumentFactory.class); // After opening the book we wait a while before we starting indexing the rest of the pages. // This way the book opens, everything settles down, and while the user looks at the cover page @@ -169,7 +167,7 @@ private HTMLDocument createDocument(Resource resource) { parserCallback.flush(); result = document; } catch (Exception e) { - log.error(e.getMessage()); + log.severe(e.getMessage()); } return result; } @@ -198,7 +196,7 @@ public void run() { try { Thread.sleep(DOCUMENT_CACHE_INDEXER_WAIT_TIME); } catch (InterruptedException e) { - log.error(e.getMessage()); + log.severe(e.getMessage()); } addAllDocumentsToCache(book); } diff --git a/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/ImageLoaderCache.java b/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/ImageLoaderCache.java index 2ca5a250..e7d56327 100644 --- a/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/ImageLoaderCache.java +++ b/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/ImageLoaderCache.java @@ -19,8 +19,6 @@ import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * This class is a trick to get the JEditorKit to load its images from the epub file instead of from the given url. @@ -37,7 +35,7 @@ class ImageLoaderCache extends Dictionary { public static final String IMAGE_URL_PREFIX = "http:/"; - private static final Logger log = LoggerFactory.getLogger(ImageLoaderCache.class); + private static final Logger log = Logger.getLogger(ImageLoaderCache.class); private Map cache = new HashMap(); private Book book; @@ -74,7 +72,7 @@ public void initImageLoader(HTMLDocument document) { try { document.setBase(new URL(ImageLoaderCache.IMAGE_URL_PREFIX)); } catch (MalformedURLException e) { - log.error(e.getMessage()); + log.severe(e.getMessage()); } setContextResource(navigator.getCurrentResource()); document.getDocumentProperties().put("imageCache", this); @@ -102,7 +100,7 @@ private Image createImage(Resource imageResource) { try { result = ImageIO.read(imageResource.getInputStream()); } catch (IOException e) { - log.error(e.getMessage()); + log.severe(e.getMessage()); } return result; } diff --git a/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/MetadataPane.java b/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/MetadataPane.java index da439835..9c5303e6 100644 --- a/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/MetadataPane.java +++ b/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/MetadataPane.java @@ -24,12 +24,10 @@ import nl.siegmann.epublib.domain.Resource; import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class MetadataPane extends JPanel implements NavigationEventListener { - private static final Logger log = LoggerFactory.getLogger(MetadataPane.class); + private static final Logger log = Logger.getLogger(MetadataPane.class); private static final long serialVersionUID = -2810193923996466948L; private JScrollPane scrollPane; @@ -69,7 +67,7 @@ private void setCoverImage(JPanel contentPanel, Book book) { try { Image image = ImageIO.read(coverImageResource.getInputStream()); if (image == null) { - log.error("Unable to load cover image from book"); + log.severe("Unable to load cover image from book"); return; } image = image.getScaledInstance(200, -1, Image.SCALE_SMOOTH); @@ -77,7 +75,7 @@ private void setCoverImage(JPanel contentPanel, Book book) { // label.setSize(100, 100); contentPanel.add(label, BorderLayout.NORTH); } catch (IOException e) { - log.error("Unable to load cover image from book", e.getMessage()); + log.severe("Unable to load cover image from book", e.getMessage()); } } diff --git a/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/Viewer.java b/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/Viewer.java index eea823f8..e0c3bd01 100644 --- a/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/Viewer.java +++ b/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/Viewer.java @@ -34,13 +34,11 @@ import nl.siegmann.epublib.epub.EpubWriter; import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class Viewer { - static final Logger log = LoggerFactory.getLogger(Viewer.class); + static final Logger log = Logger.getLogger(Viewer.class); private final JFrame mainWindow; private BrowseBar browseBar; private JSplitPane mainSplitPane; @@ -57,7 +55,7 @@ public Viewer(InputStream bookStream) { book = (new EpubReader()).readEpub(bookStream); gotoBook(book); } catch (IOException e) { - log.error(e.getMessage(), e); + log.severe(e.getMessage(), e); } } @@ -161,7 +159,7 @@ public void actionPerformed(ActionEvent e) { Book book = (new EpubReader()).readEpub(new FileInputStream(selectedFile)); gotoBook(book); } catch (Exception e1) { - log.error(e1.getMessage(), e1); + log.severe(e1.getMessage(), e1); } } }); @@ -192,7 +190,7 @@ public void actionPerformed(ActionEvent e) { try { (new EpubWriter()).write(navigator.getBook(), new FileOutputStream(selectedFile)); } catch (Exception e1) { - log.error(e1.getMessage(), e1); + log.severe(e1.getMessage(), e1); } } }); @@ -311,7 +309,7 @@ private static InputStream getBookInputStream(String[] args) { try { result = new FileInputStream(bookFile); } catch (Exception e) { - log.error("Unable to open " + bookFile, e); + log.severe("Unable to open " + bookFile, e); } } if (result == null) { @@ -325,7 +323,7 @@ public static void main(String[] args) throws FileNotFoundException, IOException try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { - log.error("Unable to set native look and feel", e); + log.severe("Unable to set native look and feel", e); } final InputStream bookStream = getBookInputStream(args); diff --git a/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/ViewerUtil.java b/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/ViewerUtil.java index 7f9e3b0e..eef5c3cc 100644 --- a/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/ViewerUtil.java +++ b/epublib-tools/src/main/java/nl/siegmann/epublib/viewer/ViewerUtil.java @@ -6,12 +6,10 @@ import javax.swing.ImageIcon; import javax.swing.JButton; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class ViewerUtil { - private static Logger log = LoggerFactory.getLogger(ViewerUtil.class); + private static Logger log = Logger.getLogger(ViewerUtil.class); /** * Creates a button with the given icon. The icon will be loaded from the classpath. @@ -41,7 +39,7 @@ static ImageIcon createImageIcon(String iconName) { Image image = ImageIO.read(ViewerUtil.class.getResourceAsStream(fullIconPath)); result = new ImageIcon(image); } catch(Exception e) { - log.error("Icon \'" + fullIconPath + "\' not found"); + log.severe("Icon \'" + fullIconPath + "\' not found"); } return result; }