pull/957/head
ag2s20150909 4 years ago
parent 77a1dbe7f4
commit 31ee3400b4
  1. 24
      app/src/main/java/io/legado/app/model/localBook/EpubFile.kt
  2. 52
      epublib/src/main/java/me/ag2s/epublib/epub/DOMUtil.java
  3. 15
      epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentMetadataReader.java
  4. 21
      epublib/src/main/java/me/ag2s/epublib/epub/PackageDocumentReader.java
  5. 32
      epublib/src/main/java/me/ag2s/epublib/epub/ResourcesLoader.java

@ -114,30 +114,16 @@ class EpubFile(var book: Book) {
} }
input ?: return null input ?: return null
FileUtils.writeInputStream(file, input) FileUtils.writeInputStream(file, input)
if (!file.exists()){
return EpubReader().readEpub(input)
}
} }
//通过懒加载读取epub
return EpubReader().readEpubLazy(ZipFile(file), "utf-8") return EpubReader().readEpubLazy(ZipFile(file), "utf-8")
// val inZip = ZipInputStream(input)
// var zipEntry: ZipEntry?
// val resources = Resources()
// do {
// zipEntry = inZip.nextEntry
// if ((zipEntry == null) || zipEntry.isDirectory || zipEntry == ZipEntry("<error>")) continue
// val resource = ResourceUtil.createResource(zipEntry, inZip)
// if (resource.mediaType == MediaTypes.XHTML) resource.inputEncoding = "UTF-8"
// if (zipEntry.name.endsWith(".opf")) {
// /*掌上书苑有很多自制书OPF的nameSpace格式不标准,强制修复成正确的格式*/
// val newS = String(resource.data).replace(
// "\\smlns=\"http://www.idpf.org/2007/opf\"".toRegex(),
// " xmlns=\"http://www.idpf.org/2007/opf\""
// )
// resource.data = newS.toByteArray()
// }
// resources.add(resource)
// } while (zipEntry != null)
// if (resources.size() > 0) return EpubReader().readEpub(resources)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }

@ -1,19 +1,20 @@
package me.ag2s.epublib.epub; package me.ag2s.epublib.epub;
import me.ag2s.epublib.util.StringUtil;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import org.w3c.dom.Text; import org.w3c.dom.Text;
import java.util.ArrayList;
import java.util.List;
import me.ag2s.epublib.util.StringUtil;
/** /**
* Utility methods for working with the DOM. * Utility methods for working with the DOM.
* *
* @author paul * @author paul
*
*/ */
// package // package
class DOMUtil { class DOMUtil {
@ -83,6 +84,47 @@ class DOMUtil {
return null; return null;
} }
/**
* Gets the first element that is a child of the parentElement and has the given namespace and tagName
*
* @param parentElement parentElement
* @param namespace namespace
* @param tagName tagName
* @return Element
*/
public static NodeList getElementsByTagNameNS(Element parentElement,
String namespace, String tagName) {
NodeList nodes = parentElement.getElementsByTagNameNS(namespace, tagName);
if (nodes.getLength() != 0) {
return nodes;
}
nodes = parentElement.getElementsByTagName(tagName);
if (nodes.getLength() == 0) {
return null;
}
return nodes;
}
/**
* Gets the first element that is a child of the parentElement and has the given namespace and tagName
*
* @param parentElement parentElement
* @param namespace namespace
* @param tagName tagName
* @return Element
*/
public static NodeList getElementsByTagNameNS(Document parentElement,
String namespace, String tagName) {
NodeList nodes = parentElement.getElementsByTagNameNS(namespace, tagName);
if (nodes.getLength() != 0) {
return nodes;
}
nodes = parentElement.getElementsByTagName(tagName);
if (nodes.getLength() == 0) {
return null;
}
return nodes;
}
/** /**
* Gets the first element that is a child of the parentElement and has the given namespace and tagName * Gets the first element that is a child of the parentElement and has the given namespace and tagName
* *
@ -107,7 +149,7 @@ class DOMUtil {
/** /**
* The contents of all Text nodes that are children of the given parentElement. * The contents of all Text nodes that are children of the given parentElement.
* The result is trim()-ed. * The result is trim()-ed.
* * <p>
* The reason for this more complicated procedure instead of just returning the data of the firstChild is that * 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 Characater is represented in the DOM as
* an individual Text node. * an individual Text node.

@ -22,7 +22,7 @@ import me.ag2s.epublib.util.StringUtil;
/** /**
* Reads the package document metadata. * Reads the package document metadata.
* * <p>
* In its own separate class because the PackageDocumentReader became a bit large and unwieldy. * In its own separate class because the PackageDocumentReader became a bit large and unwieldy.
* *
* @author paul * @author paul
@ -78,6 +78,7 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
/** /**
* consumes meta tags that have a property attribute as defined in the standard. For example: * consumes meta tags that have a property attribute as defined in the standard. For example:
* &lt;meta property="rendition:layout"&gt;pre-paginated&lt;/meta&gt; * &lt;meta property="rendition:layout"&gt;pre-paginated&lt;/meta&gt;
*
* @param metadataElement metadataElement * @param metadataElement metadataElement
* @return Map<QName, String> * @return Map<QName, String>
*/ */
@ -103,6 +104,7 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
/** /**
* consumes meta tags that have a property attribute as defined in the standard. For example: * consumes meta tags that have a property attribute as defined in the standard. For example:
* &lt;meta property="rendition:layout"&gt;pre-paginated&lt;/meta&gt; * &lt;meta property="rendition:layout"&gt;pre-paginated&lt;/meta&gt;
*
* @param metadataElement metadataElement * @param metadataElement metadataElement
* @return Map<String, String> * @return Map<String, String>
*/ */
@ -128,8 +130,8 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
if (packageElement == null) { if (packageElement == null) {
return null; return null;
} }
return packageElement return DOMUtil.getAttribute(packageElement, NAMESPACE_OPF, OPFAttributes.uniqueIdentifier);
.getAttributeNS(NAMESPACE_OPF, OPFAttributes.uniqueIdentifier);
} }
private static List<Author> readCreators(Element metadataElement) { private static List<Author> readCreators(Element metadataElement) {
@ -165,7 +167,7 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
Date date; Date date;
try { try {
date = new Date(DOMUtil.getTextChildrenContent(dateElement), date = new Date(DOMUtil.getTextChildrenContent(dateElement),
dateElement.getAttributeNS(NAMESPACE_OPF, OPFAttributes.event)); DOMUtil.getAttribute(dateElement, NAMESPACE_OPF, OPFAttributes.event));
result.add(date); result.add(date);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Log.e(TAG, e.getMessage()); Log.e(TAG, e.getMessage());
@ -189,7 +191,7 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
authorString.substring(spacePos + 1)); authorString.substring(spacePos + 1));
} }
result.setRole( result.setRole(
authorElement.getAttributeNS(NAMESPACE_OPF, OPFAttributes.role)); DOMUtil.getAttribute(authorElement, NAMESPACE_OPF, OPFAttributes.role));
return result; return result;
} }
@ -206,8 +208,7 @@ class PackageDocumentMetadataReader extends PackageDocumentBase {
identifierElements.getLength()); identifierElements.getLength());
for (int i = 0; i < identifierElements.getLength(); i++) { for (int i = 0; i < identifierElements.getLength(); i++) {
Element identifierElement = (Element) identifierElements.item(i); Element identifierElement = (Element) identifierElements.item(i);
String schemeName = identifierElement String schemeName = DOMUtil.getAttribute(identifierElement, NAMESPACE_OPF, DCAttributes.scheme);
.getAttributeNS(NAMESPACE_OPF, DCAttributes.scheme);
String identifierValue = DOMUtil String identifierValue = DOMUtil
.getTextChildrenContent(identifierElement); .getTextChildrenContent(identifierElement);
if (StringUtil.isBlank(identifierValue)) { if (StringUtil.isBlank(identifierValue)) {

@ -245,18 +245,18 @@ public class PackageDocumentReader extends PackageDocumentBase {
return generateSpineFromResources(resources); return generateSpineFromResources(resources);
} }
Spine result = new Spine(); Spine result = new Spine();
String tocResourceId = DOMUtil String tocResourceId = DOMUtil.getAttribute(spineElement, NAMESPACE_OPF, OPFAttributes.toc);
.getAttribute(spineElement, NAMESPACE_OPF, OPFAttributes.toc); Log.v(TAG,tocResourceId);
result result.setTocResource(findTableOfContentsResource(tocResourceId, resources));
.setTocResource(findTableOfContentsResource(tocResourceId, resources)); NodeList spineNodes = DOMUtil.getElementsByTagNameNS(packageDocument, NAMESPACE_OPF, OPFTags.itemref);
NodeList spineNodes = packageDocument if(spineNodes==null){
.getElementsByTagNameNS(NAMESPACE_OPF, OPFTags.itemref); Log.e(TAG,"spineNodes is null");
List<SpineReference> spineReferences = new ArrayList<>( return result;
spineNodes.getLength()); }
List<SpineReference> spineReferences = new ArrayList<>(spineNodes.getLength());
for (int i = 0; i < spineNodes.getLength(); i++) { for (int i = 0; i < spineNodes.getLength(); i++) {
Element spineItem = (Element) spineNodes.item(i); Element spineItem = (Element) spineNodes.item(i);
String itemref = DOMUtil String itemref = DOMUtil.getAttribute(spineItem, NAMESPACE_OPF, OPFAttributes.idref);
.getAttribute(spineItem, NAMESPACE_OPF, OPFAttributes.idref);
if (StringUtil.isBlank(itemref)) { if (StringUtil.isBlank(itemref)) {
Log.e(TAG, "itemref with missing or empty idref"); // XXX Log.e(TAG, "itemref with missing or empty idref"); // XXX
continue; continue;
@ -265,6 +265,7 @@ public class PackageDocumentReader extends PackageDocumentBase {
if (id == null) { if (id == null) {
id = itemref; id = itemref;
} }
Resource resource = resources.getByIdOrHref(id); Resource resource = resources.getByIdOrHref(id);
if (resource == null) { if (resource == null) {
Log.e(TAG, "resource with id '" + id + "' not found"); Log.e(TAG, "resource with id '" + id + "' not found");

@ -2,16 +2,6 @@ package me.ag2s.epublib.epub;
import android.util.Log; import android.util.Log;
import me.ag2s.epublib.domain.EpubResourceProvider;
import me.ag2s.epublib.domain.LazyResource;
import me.ag2s.epublib.domain.LazyResourceProvider;
import me.ag2s.epublib.domain.MediaType;
import me.ag2s.epublib.domain.MediaTypes;
import me.ag2s.epublib.domain.Resource;
import me.ag2s.epublib.domain.Resources;
import me.ag2s.epublib.util.CollectionUtil;
import me.ag2s.epublib.util.ResourceUtil;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -22,6 +12,16 @@ import java.util.zip.ZipException;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
import me.ag2s.epublib.domain.EpubResourceProvider;
import me.ag2s.epublib.domain.LazyResource;
import me.ag2s.epublib.domain.LazyResourceProvider;
import me.ag2s.epublib.domain.MediaType;
import me.ag2s.epublib.domain.MediaTypes;
import me.ag2s.epublib.domain.Resource;
import me.ag2s.epublib.domain.Resources;
import me.ag2s.epublib.util.CollectionUtil;
import me.ag2s.epublib.util.ResourceUtil;
/** /**
* Loads Resources from inputStreams, ZipFiles, etc * Loads Resources from inputStreams, ZipFiles, etc
@ -72,6 +72,12 @@ public class ResourcesLoader {
} else { } else {
resource = ResourceUtil resource = ResourceUtil
.createResource(zipEntry, zipFile.getInputStream(zipEntry)); .createResource(zipEntry, zipFile.getInputStream(zipEntry));
/*掌上书苑有很多自制书OPF的nameSpace格式不标准,强制修复成正确的格式*/
if (href.endsWith("opf")) {
String string = new String(resource.getData()).replace("smlns=\"", "xmlns=\"");
resource.setData(string.getBytes());
}
} }
if (resource.getMediaType() == MediaTypes.XHTML) { if (resource.getMediaType() == MediaTypes.XHTML) {
@ -123,9 +129,15 @@ public class ResourcesLoader {
if ((zipEntry == null) || zipEntry.isDirectory()) { if ((zipEntry == null) || zipEntry.isDirectory()) {
continue; continue;
} }
String href = zipEntry.getName();
// store resource // store resource
Resource resource = ResourceUtil.createResource(zipEntry, zipInputStream); Resource resource = ResourceUtil.createResource(zipEntry, zipInputStream);
///*掌上书苑有很多自制书OPF的nameSpace格式不标准,强制修复成正确的格式*/
if (href.endsWith("opf")) {
String string = new String(resource.getData()).replace("smlns=\"", "xmlns=\"");
resource.setData(string.getBytes());
}
if (resource.getMediaType() == MediaTypes.XHTML) { if (resource.getMediaType() == MediaTypes.XHTML) {
resource.setInputEncoding(defaultHtmlEncoding); resource.setInputEncoding(defaultHtmlEncoding);
} }

Loading…
Cancel
Save