package com.adobe.dp.epub.ops;
import java.io.IOException;
import java.io.StringReader;
import java.util.Stack;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
import com.adobe.dp.css.CSSParser;
import com.adobe.dp.css.CSSStylesheet;
import com.adobe.dp.css.InlineRule;
import com.adobe.dp.epub.opf.Publication;
import com.adobe.dp.epub.opf.ResourceRef;
import com.adobe.dp.epub.opf.StyleResource;
import com.adobe.dp.epub.style.EPUBCSSURLFactory;
import com.adobe.dp.epub.util.PathUtil;
class OPSDocumentBuilder extends DefaultHandler {
Publication epub;
OPSDocument document;
boolean isSVG;
StringBuffer text = new StringBuffer();
Stack elementStack = new Stack();
OPSDocumentBuilder(OPSDocument document) {
this.document = document;
epub = document.resource.getPublication();
isSVG = document.resource.getMediaType().equals("image/svg+xml");
}
private Element createElement(String uri, String local) throws SAXException {
if (uri.equals(OPSDocument.xhtmlns)) {
if (local.equals("img"))
return document.createImageElement("img");
if (local.equals("a"))
return document.createHyperlinkElement("a");
if (local.equals("td") || local.equals("th"))
return document.createTableCellElement(local, null, 1, 1);
return document.createElement(local);
} else if (uri.equals(OPSDocument.svgns)) {
if (local.equals("image"))
return document.createSVGImageElement("image");
return document.createSVGElement(local);
} else {
throw new SAXException("Unsupported namespace: " + uri);
}
}
private XRef makeXRef(String href) {
href = PathUtil.resolveRelativeReference(document.resource.getName(), href);
int hash = href.indexOf('#');
String path;
String id;
if (hash < 0) {
path = href;
id = null;
} else {
path = href.substring(0, hash);
id = href.substring(hash + 1);
}
ResourceRef resref = epub.getResourceRef(path);
if( resref == null )
return null;
return resref.getXRef(id);
}
private void assignAttributes(Element element, Attributes attributes) throws SAXException {
String id = attributes.getValue("id");
if (id != null)
element.setId(id);
String className = attributes.getValue("class");
if (className != null)
element.setClassName(className);
String styleStr = attributes.getValue("style");
InlineRule style = null;
if (styleStr != null) {
CSSParser parser = new CSSParser();
parser.setCSSURLFactory(new EPUBCSSURLFactory(document.resource));
style = parser.readInlineStyle(styleStr);
}
if (element instanceof ImageElement) {
ImageElement imageElement = (ImageElement) element;
String src = attributes.getValue("src");
if (src != null) {
String srcName = PathUtil.resolveRelativeReference(document.resource.getName(), src);
imageElement.setImageResource(epub.getResourceRef(srcName));
}
} else if (element instanceof HyperlinkElement) {
HyperlinkElement hyperlink = (HyperlinkElement) element;
String href = attributes.getValue("href");
if (href != null) {
if (href.matches("^[a-z0-9]+:.*"))
hyperlink.setExternalHRef(href);
else {
XRef xref = makeXRef(href);
if (xref == null)
System.err.println("Could not resolve: " + href);
else
hyperlink.setXRef(xref);
}
}
} else if (element instanceof TableCellElement) {
TableCellElement tc = (TableCellElement) element;
String val = attributes.getValue("colspan");
if (val != null) {
try {
tc.setColSpan(Integer.parseInt(val));
} catch (Exception e) {
e.printStackTrace();
}
}
val = attributes.getValue("rowspan");
if (val != null) {
try {
tc.setRowSpan(Integer.parseInt(val));
} catch (Exception e) {
e.printStackTrace();
}
}
val = attributes.getValue("align");
if (val != null)
tc.setAlign(val);
} else if (element instanceof SVGElement) {
SVGElement svg = (SVGElement) element;
int count = attributes.getLength();
for (int i = 0; i < count; i++) {
String uri = attributes.getURI(i);
String name = attributes.getLocalName(i);
if ((uri.equals("") && (name.equals("class") || name.equals("style") || name.equals("id")))
|| (uri.equals(OPSDocument.xmlns) && name.equals("lang")))
continue;
String value = attributes.getValue(i);
if (uri.equals(""))
svg.setAttribute(name, value);
else
svg.setAttribute(uri, name, value);
}
}
if (style != null)
element.setStyle(style);
}
private String flushText() {
if (text.length() > 0) {
String str = text.toString();
if (!elementStack.isEmpty()) {
Element parent = (Element) elementStack.peek();
if (!parent.isSection())
parent.add(str);
}
text.setLength(0);
return str;
}
return null;
}
public void characters(char[] ch, int start, int length) throws SAXException {
text.append(ch, start, length);
}
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
text.append(ch, start, length);
}
public void startDocument() throws SAXException {
}
public void endDocument() throws SAXException {
}
public void startPrefixMapping(String prefix, String uri) throws SAXException {
}
public void endPrefixMapping(String prefix) throws SAXException {
}
public void warning(SAXParseException e) throws SAXException {
}
public void error(SAXParseException e) throws SAXException {
}
public void fatalError(SAXParseException e) throws SAXException {
}
public void processingInstruction(String target, String data) throws SAXException {
}
public void setDocumentLocator(Locator locator) {
}
public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
flushText();
Element element;
if (uri.equals(OPSDocument.xhtmlns)) {
if (elementStack.isEmpty()) {
if (localName.equals("body")) {
element = document.getBody();
} else {
if (localName.equals("link")) {
String rel = attributes.getValue("rel");
if (rel.equals("stylesheet")) {
String href = attributes.getValue("href");
if (href != null) {
href = PathUtil.resolveRelativeReference(document.resource.getName(), href);
document.addStyleResource(epub.getResourceRef(href));
}
}
}
return;
}
} else {
element = createElement(uri, localName);
}
} else {
element = createElement(uri, localName);
}
assignAttributes(element, attributes);
if (!elementStack.isEmpty()) {
Element parent = (Element) elementStack.peek();
parent.add(element);
}
elementStack.push(element);
}
public void endElement(String uri, String localName, String name) throws SAXException {
String content = flushText();
if (uri.equals(OPSDocument.xhtmlns)) {
if (localName.equals("style")) {
CSSParser parser = new CSSParser();
parser.setCSSURLFactory(new EPUBCSSURLFactory(document.resource));
try {
CSSStylesheet css = parser.readStylesheet(new StringReader(content));
String inlineName = PathUtil.resolveRelativeReference(document.resource.getName(), "inline.css");
StyleResource sr = epub.createStyleResource(inlineName);
sr.setCSS(css);
document.addStyleResource(sr.getResourceRef());
} catch (IOException e) {
e.printStackTrace();
}
}
}
if (!elementStack.isEmpty()) {
elementStack.pop();
}
}
}