| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- package me.ag2s.epublib.epub;
- import android.util.Log;
- import org.w3c.dom.Document;
- import org.w3c.dom.Element;
- import org.w3c.dom.Node;
- import org.w3c.dom.NodeList;
- import org.xmlpull.v1.XmlSerializer;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.io.UnsupportedEncodingException;
- import java.net.URLDecoder;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.zip.ZipEntry;
- import java.util.zip.ZipOutputStream;
- import me.ag2s.epublib.Constants;
- import me.ag2s.epublib.domain.Author;
- import me.ag2s.epublib.domain.EpubBook;
- import me.ag2s.epublib.domain.Identifier;
- import me.ag2s.epublib.domain.MediaTypes;
- import me.ag2s.epublib.domain.Resource;
- import me.ag2s.epublib.domain.TOCReference;
- import me.ag2s.epublib.domain.TableOfContents;
- import me.ag2s.epublib.util.ResourceUtil;
- import me.ag2s.epublib.util.StringUtil;
- /**
- * Writes the ncx document as defined by namespace http://www.daisy.org/z3986/2005/ncx/
- *
- * @author paul
- */
- public class NCXDocumentV2 {
- public static final String NAMESPACE_NCX = "http://www.daisy.org/z3986/2005/ncx/";
- @SuppressWarnings("unused")
- public static final String PREFIX_NCX = "ncx";
- public static final String NCX_ITEM_ID = "ncx";
- public static final String DEFAULT_NCX_HREF = "toc.ncx";
- public static final String PREFIX_DTB = "dtb";
- private static final String TAG = NCXDocumentV2.class.getName();
- private interface NCXTags {
- String ncx = "ncx";
- String meta = "meta";
- String navPoint = "navPoint";
- String navMap = "navMap";
- String navLabel = "navLabel";
- String content = "content";
- String text = "text";
- String docTitle = "docTitle";
- String docAuthor = "docAuthor";
- String head = "head";
- }
- private interface NCXAttributes {
- String src = "src";
- String name = "name";
- String content = "content";
- String id = "id";
- String playOrder = "playOrder";
- String clazz = "class";
- String version = "version";
- }
- private interface NCXAttributeValues {
- String chapter = "chapter";
- String version = "2005-1";
- }
- @SuppressWarnings("unused")
- public static Resource read(EpubBook book, EpubReader epubReader) {
- Resource ncxResource = null;
- if (book.getSpine().getTocResource() == null) {
- Log.e(TAG, "Book does not contain a table of contents file");
- return null;
- }
- try {
- ncxResource = book.getSpine().getTocResource();
- if (ncxResource == null) {
- return null;
- }
- Log.d(TAG, ncxResource.getHref());
- Document ncxDocument = ResourceUtil.getAsDocument(ncxResource);
- Element navMapElement = DOMUtil
- .getFirstElementByTagNameNS(ncxDocument.getDocumentElement(),
- NAMESPACE_NCX, NCXTags.navMap);
- if (navMapElement == null) {
- return null;
- }
- TableOfContents tableOfContents = new TableOfContents(
- readTOCReferences(navMapElement.getChildNodes(), book));
- book.setTableOfContents(tableOfContents);
- } catch (Exception e) {
- Log.e(TAG, e.getMessage(), e);
- }
- return ncxResource;
- }
- static List<TOCReference> readTOCReferences(NodeList navpoints,
- EpubBook 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(NCXTags.navPoint))) {
- continue;
- }
- TOCReference tocReference = readTOCReference((Element) node, book);
- result.add(tocReference);
- }
- return result;
- }
- static TOCReference readTOCReference(Element navpointElement, EpubBook book) {
- String label = readNavLabel(navpointElement);
- //Log.d(TAG,"label:"+label);
- String tocResourceRoot = StringUtil
- .substringBeforeLast(book.getSpine().getTocResource().getHref(), '/');
- if (tocResourceRoot.length() == book.getSpine().getTocResource().getHref()
- .length()) {
- tocResourceRoot = "";
- } else {
- tocResourceRoot = tocResourceRoot + "/";
- }
- String reference = StringUtil
- .collapsePathDots(tocResourceRoot + readNavReference(navpointElement));
- String href = StringUtil
- .substringBefore(reference, Constants.FRAGMENT_SEPARATOR_CHAR);
- String fragmentId = StringUtil
- .substringAfter(reference, Constants.FRAGMENT_SEPARATOR_CHAR);
- Resource resource = book.getResources().getByHref(href);
- if (resource == null) {
- Log.e(TAG, "Resource with href " + href + " in NCX document not found");
- }
- Log.v(TAG, "label:" + label);
- Log.v(TAG, "href:" + href);
- Log.v(TAG, "fragmentId:" + fragmentId);
- TOCReference result = new TOCReference(label, resource, fragmentId);
- List<TOCReference> childTOCReferences = readTOCReferences(
- navpointElement.getChildNodes(), book);
- result.setChildren(childTOCReferences);
- return result;
- }
- private static String readNavReference(Element navpointElement) {
- Element contentElement = DOMUtil
- .getFirstElementByTagNameNS(navpointElement, NAMESPACE_NCX,
- NCXTags.content);
- if (contentElement == null) {
- return null;
- }
- String result = DOMUtil
- .getAttribute(contentElement, NAMESPACE_NCX, NCXAttributes.src);
- try {
- result = URLDecoder.decode(result, Constants.CHARACTER_ENCODING);
- } catch (UnsupportedEncodingException e) {
- Log.e(TAG, e.getMessage());
- }
- return result;
- }
- private static String readNavLabel(Element navpointElement) {
- //Log.d(TAG,navpointElement.getTagName());
- Element navLabel = DOMUtil
- .getFirstElementByTagNameNS(navpointElement, NAMESPACE_NCX,
- NCXTags.navLabel);
- assert navLabel != null;
- return DOMUtil.getTextChildrenContent(DOMUtil
- .getFirstElementByTagNameNS(navLabel, NAMESPACE_NCX, NCXTags.text));
- }
- @SuppressWarnings("unused")
- public static void write(EpubWriter epubWriter, EpubBook book,
- ZipOutputStream resultStream) throws IOException {
- resultStream
- .putNextEntry(new ZipEntry(book.getSpine().getTocResource().getHref()));
- XmlSerializer out = EpubProcessorSupport.createXmlSerializer(resultStream);
- write(out, book);
- out.flush();
- }
- /**
- * Generates a resource containing an xml document containing the table of contents of the book in ncx format.
- *
- * @param xmlSerializer the serializer used
- * @param book the book to serialize
- * @throws IOException IOException
- * @throws IllegalStateException IllegalStateException
- * @throws IllegalArgumentException IllegalArgumentException
- */
- public static void write(XmlSerializer xmlSerializer, EpubBook book)
- throws IllegalArgumentException, IllegalStateException, IOException {
- write(xmlSerializer, book.getMetadata().getIdentifiers(), book.getTitle(),
- book.getMetadata().getAuthors(), book.getTableOfContents());
- }
- public static Resource createNCXResource(EpubBook book)
- throws IllegalArgumentException, IllegalStateException, IOException {
- return createNCXResource(book.getMetadata().getIdentifiers(),
- book.getTitle(), book.getMetadata().getAuthors(),
- book.getTableOfContents());
- }
- public static Resource createNCXResource(List<Identifier> identifiers,
- String title, List<Author> authors, TableOfContents tableOfContents)
- throws IllegalArgumentException, IllegalStateException, IOException {
- ByteArrayOutputStream data = new ByteArrayOutputStream();
- XmlSerializer out = EpubProcessorSupport.createXmlSerializer(data);
- write(out, identifiers, title, authors, tableOfContents);
- return new Resource(NCX_ITEM_ID, data.toByteArray(),
- DEFAULT_NCX_HREF, MediaTypes.NCX);
- }
- public static void write(XmlSerializer serializer,
- List<Identifier> identifiers, String title, List<Author> authors,
- TableOfContents tableOfContents)
- throws IllegalArgumentException, IllegalStateException, IOException {
- serializer.startDocument(Constants.CHARACTER_ENCODING, false);
- serializer.setPrefix(EpubWriter.EMPTY_NAMESPACE_PREFIX, NAMESPACE_NCX);
- serializer.startTag(NAMESPACE_NCX, NCXTags.ncx);
- // serializer.writeNamespace("ncx", NAMESPACE_NCX);
- // serializer.attribute("xmlns", NAMESPACE_NCX);
- serializer
- .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.version,
- NCXAttributeValues.version);
- serializer.startTag(NAMESPACE_NCX, NCXTags.head);
- for (Identifier identifier : identifiers) {
- writeMetaElement(identifier.getScheme(), identifier.getValue(),
- serializer);
- }
- writeMetaElement("generator", Constants.EPUB_GENERATOR_NAME, serializer);
- writeMetaElement("depth", String.valueOf(tableOfContents.calculateDepth()),
- serializer);
- writeMetaElement("totalPageCount", "0", serializer);
- writeMetaElement("maxPageNumber", "0", serializer);
- serializer.endTag(NAMESPACE_NCX, "head");
- serializer.startTag(NAMESPACE_NCX, NCXTags.docTitle);
- serializer.startTag(NAMESPACE_NCX, NCXTags.text);
- // write the first title
- serializer.text(StringUtil.defaultIfNull(title));
- serializer.endTag(NAMESPACE_NCX, NCXTags.text);
- serializer.endTag(NAMESPACE_NCX, NCXTags.docTitle);
- for (Author author : authors) {
- serializer.startTag(NAMESPACE_NCX, NCXTags.docAuthor);
- serializer.startTag(NAMESPACE_NCX, NCXTags.text);
- serializer.text(author.getLastname() + ", " + author.getFirstname());
- serializer.endTag(NAMESPACE_NCX, NCXTags.text);
- serializer.endTag(NAMESPACE_NCX, NCXTags.docAuthor);
- }
- serializer.startTag(NAMESPACE_NCX, NCXTags.navMap);
- writeNavPoints(tableOfContents.getTocReferences(), 1, serializer);
- serializer.endTag(NAMESPACE_NCX, NCXTags.navMap);
- serializer.endTag(NAMESPACE_NCX, "ncx");
- serializer.endDocument();
- }
- private static void writeMetaElement(String dtbName, String content,
- XmlSerializer serializer)
- throws IllegalArgumentException, IllegalStateException, IOException {
- serializer.startTag(NAMESPACE_NCX, NCXTags.meta);
- serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.name,
- PREFIX_DTB + ":" + dtbName);
- serializer
- .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.content,
- content);
- serializer.endTag(NAMESPACE_NCX, NCXTags.meta);
- }
- private static int writeNavPoints(List<TOCReference> tocReferences,
- int playOrder,
- XmlSerializer serializer)
- throws IllegalArgumentException, IllegalStateException, IOException {
- for (TOCReference tocReference : tocReferences) {
- if (tocReference.getResource() == null) {
- playOrder = writeNavPoints(tocReference.getChildren(), playOrder,
- serializer);
- continue;
- }
- writeNavPointStart(tocReference, playOrder, serializer);
- playOrder++;
- if (!tocReference.getChildren().isEmpty()) {
- playOrder = writeNavPoints(tocReference.getChildren(), playOrder,
- serializer);
- }
- writeNavPointEnd(tocReference, serializer);
- }
- return playOrder;
- }
- private static void writeNavPointStart(TOCReference tocReference,
- int playOrder, XmlSerializer serializer)
- throws IllegalArgumentException, IllegalStateException, IOException {
- serializer.startTag(NAMESPACE_NCX, NCXTags.navPoint);
- serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.id,
- "navPoint-" + playOrder);
- serializer
- .attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.playOrder,
- String.valueOf(playOrder));
- serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.clazz,
- NCXAttributeValues.chapter);
- serializer.startTag(NAMESPACE_NCX, NCXTags.navLabel);
- serializer.startTag(NAMESPACE_NCX, NCXTags.text);
- serializer.text(tocReference.getTitle());
- serializer.endTag(NAMESPACE_NCX, NCXTags.text);
- serializer.endTag(NAMESPACE_NCX, NCXTags.navLabel);
- serializer.startTag(NAMESPACE_NCX, NCXTags.content);
- serializer.attribute(EpubWriter.EMPTY_NAMESPACE_PREFIX, NCXAttributes.src,
- tocReference.getCompleteHref());
- serializer.endTag(NAMESPACE_NCX, NCXTags.content);
- }
- @SuppressWarnings("unused")
- private static void writeNavPointEnd(TOCReference tocReference,
- XmlSerializer serializer)
- throws IllegalArgumentException, IllegalStateException, IOException {
- serializer.endTag(NAMESPACE_NCX, NCXTags.navPoint);
- }
- }
|