public void testGetResourcesByMediaType1() { Resources resources = new Resources(); resources.add(new Resource( System.Text.Encoding.UTF8.GetBytes("foo"), MediatypeService.XHTML)); resources.add(new Resource(System.Text.Encoding.UTF8.GetBytes("bar"), MediatypeService.XHTML)); Assert.AreEqual(0, resources.getResourcesByMediaType(MediatypeService.PNG).Count); Assert.AreEqual(2, resources.getResourcesByMediaType(MediatypeService.XHTML).Count); Assert.AreEqual(2, resources.getResourcesByMediaTypes(new MediaType[] { MediatypeService.XHTML }).Count); }
/// /// <param name="packageResource"></param> /// <param name="epubReader"></param> /// <param name="book"></param> /// <param name="resources"></param> public static void read(Resource packageResource, EpubReader epubReader, Book book, Resources resources) { XElement packageDocument = XElement.Load(packageResource.getInputStream()); String packageHref = packageResource.getHref(); resources = fixHrefs(packageHref, resources); readGuide(packageDocument, epubReader, book, resources); System.Collections.Generic.Dictionary<string, string> idMapping = new Dictionary<string, string>(); resources = readManifest(packageDocument, packageHref, epubReader, resources, idMapping); book.setResources(resources); readCover(packageDocument, book); // book.setMetadata(PackageDocumentMetadataReader.readMetadata(packageDocument, book.getResources())); book.setSpine(readSpine(packageDocument, epubReader, 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)); } }
/// <summary> /// Reads the manifest containing the resource ids, hrefs and mediatypes. /// </summary> /// <param>book</param> /// <param>resourcesByHref</param> /// <param>a Map with resources, with their id's as key.</param> /// <param name="packageDocument"></param> /// <param name="packageHref"></param> /// <param name="epubReader"></param> /// <param name="resources"></param> /// <param name="idMapping"></param> private static Resources readManifest(XElement packageDocument, String packageHref, EpubReader epubReader, Resources resources, Dictionary<String, String> idMapping) { XElement manifestElement = DOMUtil.getFirstElementByTagNameNS(packageDocument, NAMESPACE_OPF, OPFTags.manifest); Resources result = new Resources(); if (manifestElement == null) { return result; } var itemElements = packageDocument.Elements(NAMESPACE_OPF + OPFTags.item).Elements<XElement>(); foreach (XElement itemElement in (from e in itemElements where e.Value.Trim() != string.Empty select e)) { String id = DOMUtil.getAttribute(itemElement, OPFAttributes.id); String href = DOMUtil.getAttribute(itemElement, OPFAttributes.href); try { href = System.Web.HttpUtility.UrlDecode(href, System.Text.Encoding.GetEncoding(Constants.ENCODING)); } catch (Exception e) { //log.error(e.getMessage()); } String mediaTypeName = DOMUtil.getAttribute(itemElement, 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.Add(id, resource.getId()); } return result; }
/// <summary> /// Reads the document's spine, containing all sections in reading order. /// </summary> /// <param>book</param> /// <param>resourcesById</param> /// <param name="packageDocument"></param> /// <param name="epubReader"></param> /// <param name="resources"></param> /// <param name="idMapping"></param> private static Spine readSpine(XElement packageDocument, EpubReader epubReader, Resources resources, Dictionary<String, String> idMapping) { XElement spineElement = DOMUtil.getFirstElementByTagNameNS(packageDocument, 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(); result.setTocResource(findTableOfContentsResource(spineElement, resources)); var spineNodes = packageDocument.Elements(NAMESPACE_OPF + OPFTags.itemref).Elements<XElement>(); IEnumerator spineNode = spineNodes.GetEnumerator(); List<SpineReference> spineReferences = new List<SpineReference>(); while (spineNode.MoveNext()) { XElement spineItem = (XElement)spineNode.Current; String itemref = DOMUtil.getAttribute(spineItem, OPFAttributes.idref); if (StringUtil.isBlank(itemref)) { //log.error("itemref with missing or empty idref"); // XXX continue; } String id = idMapping[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.Equals(DOMUtil.getAttribute(spineItem, OPFAttributes.linear))) { spineReference.setLinear(false); } spineReferences.Add(spineReference); } result.setSpineReferences(spineReferences); return result; }
/// <summary> /// Creates a spine out of all resources in the resources. The generated spine /// consists of all XHTML pages in order of their href. /// </summary> /// <param name="resources"></param> private static Spine generateSpineFromResources(Resources resources) { Spine result = new Spine(); List<String> resourceHrefs = new List<String>(resources.getAllHrefs()); foreach (String resourceHref in 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; }
/// <summary> /// Reads the book's guide. Here some more attempts are made at finding the cover /// page. /// </summary> /// <param name="packageDocument"></param> /// <param name="epubReader"></param> /// <param name="book"></param> /// <param name="resources">resources</param> private static void readGuide(XElement packageDocument, EpubReader epubReader, Book book, Resources resources) { XElement guideElement = DOMUtil.getFirstElementByTagNameNS(packageDocument, NAMESPACE_OPF, OPFTags.guide); if (guideElement == null) { return; } Guide guide = book.getGuide(); var guideReferences = packageDocument.Elements(NAMESPACE_OPF + OPFTags.reference).Elements<XElement>(); foreach (XElement referenceElement in (from e in guideReferences where e.Value.Trim() != string.Empty select e)) { String resourceHref = DOMUtil.getAttribute(referenceElement, 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, 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, OPFAttributes.title); if (GuideReference.COVER.Equals(type)) { continue; // cover is handled elsewhere } GuideReference reference = new GuideReference(resource, type, title, StringUtil.substringAfter(resourceHref, Constants.FRAGMENT_SEPARATOR_CHAR)); guide.addReference(reference); } }
/// <summary> /// 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. /// </summary> /// <param>resourcesById</param> /// <param name="spineElement"></param> /// <param name="resources"></param> private static Resource findTableOfContentsResource(XElement spineElement, Resources resources) { String tocResourceId = DOMUtil.getAttribute(spineElement, OPFAttributes.toc); Resource tocResource = null; if (StringUtil.isNotBlank(tocResourceId)) { tocResource = resources.getByIdOrHref(tocResourceId); } if (tocResource != null) { return tocResource; } for (int i = 0; i < POSSIBLE_NCX_ITEM_IDS.Length; i++) { tocResource = resources.getByIdOrHref(POSSIBLE_NCX_ITEM_IDS[i]); if (tocResource != null) { return tocResource; } tocResource = resources.getByIdOrHref(POSSIBLE_NCX_ITEM_IDS[i].ToUpper()); if (tocResource != null) { return tocResource; } } // get the first resource with the NCX mediatype tocResource = resources.findFirstResourceByMediaType(MediatypeService.NCX); 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; }
/// <summary> /// 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" /// </summary> /// <param name="packageHref"></param> /// <param name="resourcesByHref"></param> private static Resources fixHrefs(String packageHref, Resources resourcesByHref) { int lastSlashPos = packageHref.IndexOf('/'); if (lastSlashPos < 0) { return resourcesByHref; } Resources result = new Resources(); foreach (Resource resource in resourcesByHref.getAll()) { if (StringUtil.isNotBlank(resource.getHref()) || resource.getHref().Length > lastSlashPos) { resource.setHref(resource.getHref().Substring(lastSlashPos + 1)); } result.add(resource); } return result; }
/// /// <param name="in"></param> /// <param name="defaultHtmlEncoding"></param> private Resources readResources(ZipInputStream zipInputStream, String defaultHtmlEncoding) { Resources result = new Resources(); for (ZipEntry zipEntry = zipInputStream.GetNextEntry(); zipEntry != null; zipEntry = zipInputStream.GetNextEntry()) { if (zipEntry.IsDirectory) { continue; } Resource resource = ResourceUtil.createResource(zipEntry, zipInputStream); if (resource.getMediaType() == MediatypeService.XHTML) { resource.setInputEncoding(defaultHtmlEncoding); } result.add(resource); } return result; }
/// /// <param name="packageResourceHref"></param> /// <param name="book"></param> /// <param name="resources"></param> private Resource processPackageResource(String packageResourceHref, Book book, Resources resources) { Resource packageResource = resources.remove(packageResourceHref); try { PackageDocumentReader.read(packageResource, this, book, resources); } catch (Exception e) { //log.error(e.getMessage(), e); } return packageResource; }
/// /// <param name="result"></param> /// <param name="resources"></param> private void handleMimeType(Book result, Resources resources) { resources.remove("mimetype"); }
/// /// <param name="resources"></param> private String getPackageResourceHref(Resources resources) { String defaultResult = "OEBPS/content.opf"; String result = defaultResult; Resource containerResource = resources.remove("META-INF/container.xml"); if (containerResource == null) { return result; } try { XElement xElement = XElement.Load(containerResource.getInputStream()); XNamespace ns = (xElement.Attribute("xmlns") != null) ? xElement.Attribute("xmlns").Value : XNamespace.None; return xElement.Descendants(ns + "rootfile").FirstOrDefault((XElement p) => p.Attribute("media-type") != null && p.Attribute("media-type").Value.Equals("application/oebps-package+xml", System.StringComparison.InvariantCultureIgnoreCase)).Attribute("full-path").Value; } catch (Exception e) { //log.error(e.getMessage(), e); } if (StringUtil.isBlank(result)) { result = defaultResult; } return result; return ""; }
/// /// <param name="resources"></param> public void setResources(Resources resources) { this.resources = resources; }