/*
* ====================================================================
* Copyright (c) 2004-2012 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.tmatesoft.svn.core.internal.io.dav.handlers;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNProperty;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.internal.io.dav.DAVElement;
import org.tmatesoft.svn.core.internal.util.SVNBase64;
import org.tmatesoft.svn.core.internal.util.SVNHashMap;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
/**
* @author TMate Software Ltd.
* @version 1.3
*/
public abstract class BasicDAVHandler extends DefaultHandler {
protected static final Collection SVN_DAV_NAMESPACES_LIST = new LinkedList();
protected static final Collection SVN_NAMESPACES_LIST = new LinkedList();
protected static final Collection DAV_NAMESPACES_LIST = new LinkedList();
static {
SVN_DAV_NAMESPACES_LIST.add(DAVElement.SVN_NAMESPACE);
SVN_DAV_NAMESPACES_LIST.add(DAVElement.DAV_NAMESPACE);
SVN_NAMESPACES_LIST.add(DAVElement.SVN_NAMESPACE);
DAV_NAMESPACES_LIST.add(DAVElement.DAV_NAMESPACE);
}
private static final Object ROOT = new Object();
private Map myPrefixesMap;
private List myNamespacesCollection;
private String myNamespace;
private StringBuffer myCDATA;
private Stack myParent;
private byte[] myDeltaBuffer;
protected BasicDAVHandler() {
myPrefixesMap = new SVNHashMap();
myNamespacesCollection = new LinkedList();
myParent = new Stack();
}
private void setNamespace(String uri) {
if ("".equals(uri)) {
myNamespace = null;
} else {
myNamespace = uri;
}
}
protected void init() {
myPrefixesMap.clear();
myNamespacesCollection.clear();
myParent.clear();
myParent.push(ROOT);
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
setNamespace(uri);
DAVElement element = getDAVElement(qName, localName, myNamespace);
try {
startElement(getParent(), element, attributes);
} catch (SVNException e) {
SVNDebugLog.getDefaultLog().logFine(SVNLogType.NETWORK, e);
throw new SAXException(e);
}
myParent.push(element);
myCDATA = new StringBuffer();
}
public void endElement(String uri, String localName, String qName) throws SAXException {
myParent.pop();
String namespace = uri != null && !"".equals(uri) ? uri : myNamespace;
DAVElement element = getDAVElement(qName, localName, namespace);
try {
endElement(getParent(), element, myCDATA);
} catch (SVNException e) {
SVNDebugLog.getDefaultLog().logFine(SVNLogType.NETWORK, e);
throw new SAXException(e);
}
myCDATA = null;
}
public void characters(char[] ch, int start, int length) throws SAXException {
if (myCDATA != null) {
myCDATA.append(ch, start, length);
}
}
public void startPrefixMapping(String prefix, String uri) throws SAXException {
Stack mappings = (Stack) myPrefixesMap.get(prefix);
if (mappings == null) {
mappings = new Stack();
myPrefixesMap.put(prefix, mappings);
}
mappings.push(uri);
if (!myNamespacesCollection.contains(uri)) {
myNamespacesCollection.add(uri);
}
}
public void endPrefixMapping(String prefix) throws SAXException {
Stack mappings = (Stack) myPrefixesMap.get(prefix);
if (mappings != null) {
mappings.pop();
}
}
protected abstract void startElement(DAVElement parent, DAVElement element, Attributes attrs) throws SVNException;
protected abstract void endElement(DAVElement parent, DAVElement element, StringBuffer cdata) throws SVNException;
protected void invalidXML() throws SVNException {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.XML_MALFORMED, "Malformed XML"), SVNLogType.NETWORK);
}
protected List getNamespaces() {
return myNamespacesCollection;
}
private DAVElement getParent() {
Object parent = myParent.peek();
if (parent == ROOT) {
return null;
}
return (DAVElement) parent;
}
private DAVElement getDAVElement(String qName, String localName, String namespace) {
if (qName == null || qName.trim().length() == 0) {
qName = localName;
}
String prefix = namespace;
int index = qName.indexOf(':');
if (index >= 0) {
prefix = qName.substring(0, index);
Stack prefixes = (Stack) myPrefixesMap.get(prefix);
if (prefixes != null && !prefixes.isEmpty()) {
prefix = (String) prefixes.peek();
}
qName = qName.substring(index + 1);
}
return DAVElement.getElement(prefix, qName);
}
protected SVNPropertyValue createPropertyValue(DAVElement element, String propertyName, StringBuffer cdata, String encoding) throws SVNException {
if ("base64".equalsIgnoreCase(encoding)) {
return createPropertyValueFromBase64(element, propertyName, cdata);
}
if (encoding != null && !"".equals(encoding)) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.XML_UNKNOWN_ENCODING,
"Unknown XML encoding: ''{0}''", encoding);
SVNErrorManager.error(err, SVNLogType.NETWORK);
}
if (useStringProperty(element, propertyName)) {
return SVNPropertyValue.create(cdata.toString());
}
byte[] rawValue;
try {
rawValue = cdata.toString().getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
rawValue = cdata.toString().getBytes();
}
return SVNPropertyValue.create(propertyName, rawValue);
}
protected SVNPropertyValue createPropertyValueFromBase64(DAVElement element, String propertyName, StringBuffer cdata) {
StringBuffer sb = SVNBase64.normalizeBase64(cdata);
byte[] buffer = allocateBuffer(sb.length());
int length = SVNBase64.base64ToByteArray(sb, buffer);
if (useStringProperty(element, propertyName)) {
String str;
try {
str = new String(buffer, 0, length, "UTF-8");
} catch (UnsupportedEncodingException e) {
str = new String(buffer, 0, length);
}
return SVNPropertyValue.create(str);
}
return SVNPropertyValue.create(propertyName, buffer, 0, length);
}
private boolean useStringProperty(DAVElement element, String propertyName) {
String namespace = element == null ? null : element.getNamespace();
return SVNProperty.isSVNProperty(propertyName) ||
DAVElement.SVN_DAV_PROPERTY_NAMESPACE.equals(namespace) ||
DAVElement.SVN_SVN_PROPERTY_NAMESPACE.equals(namespace) ||
DAVElement.SVN_NAMESPACE.equals(namespace) ||
DAVElement.DAV_NAMESPACE.equals(namespace);
}
protected byte[] allocateBuffer(int length) {
if (myDeltaBuffer == null || myDeltaBuffer.length < length) {
myDeltaBuffer = new byte[length * 3 / 2];
}
return myDeltaBuffer;
}
}