pietsch 2003/09/19 09:50:56
Added: test/java/org/apache/fop/util DigestFilter.java
test/java/org/apache/fop DigestFilterTestCase.java
Log:
SAX filter providing a MD5 checksum for ensuring XML input integrity.
Revision Changes Path
1.1 xml-fop/test/java/org/apache/fop/util/DigestFilter.java
Index: DigestFilter.java
===================================================================
/*
* $Id: DigestFilter.java,v 1.1 2003/09/19 16:50:56 pietsch Exp $
* ============================================================================
* The Apache Software License, Version 1.1
* ============================================================================
*
* Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by the Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "FOP" and "Apache Software Foundation" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache", nor may
* "Apache" appear in their name, without prior written permission of the
* Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
* DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ============================================================================
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the Apache Software Foundation and was originally created by
* James Tauber <[EMAIL PROTECTED]>. For more information on the Apache
* Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.fop.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.helpers.XMLFilterImpl;
/**
* SAX filter which produces a digest over the XML elements.
* Insignificant whitespace as determined by the, comments and
* processing instructions are not part of the digest.
* If the filter is namespace aware, the URI and local name for
* each element is digested, otherwise the QName. Attributes are
* sorted before the name-value pairs are digested.
*
*/
public class DigestFilter extends XMLFilterImpl {
private MessageDigest digest;
private byte value[];
private boolean isNamespaceAware;
public DigestFilter(String algorithm) throws NoSuchAlgorithmException {
digest = MessageDigest.getInstance(algorithm);
}
public byte[] getDigestValue() {
return value;
}
public String getDigestString() {
if (value != null) {
StringBuffer buffer = new StringBuffer(2 * value.length);
for (int i = 0; i < value.length; i++) {
int val = value[i];
int hi = (val >> 4) & 0xF;
int lo = val & 0xF;
if (hi < 10) {
buffer.append((char) (hi + 0x30));
} else {
buffer.append((char) (hi + 0x61 - 10));
}
if (lo < 10) {
buffer.append((char) (lo + 0x30));
} else {
buffer.append((char) (lo + 0x61 - 10));
}
}
return buffer.toString();
} else {
return null;
}
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#characters(char[], int, int)
*/
public void characters(char[] chars, int start, int length)
throws SAXException {
digest.update(new String(chars, start, length).getBytes());
super.characters(chars, start, length);
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#endDocument()
*/
public void endDocument() throws SAXException {
value = digest.digest();
super.endDocument();
}
/* (non-Javadoc)
* @see org.xml.sax.ContentHandler#startElement(java.lang.String,
java.lang.String, java.lang.String, org.xml.sax.Attributes)
*/
public void startElement(
String url,
String localName,
String qName,
Attributes attr)
throws SAXException {
Map map = new TreeMap();
if (isNamespaceAware) {
digest.update(url.getBytes());
digest.update(localName.getBytes());
for (int i = 0; i < attr.getLength(); i++) {
map.put(
attr.getLocalName(i) + attr.getURI(i),
attr.getValue(i));
}
} else {
digest.update(qName.getBytes());
for (int i = 0; i < attr.getLength(); i++) {
map.put(attr.getQName(i), attr.getValue(i));
}
}
for (Iterator i = map.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry)i.next();
digest.update(((String)entry.getKey()).getBytes());
digest.update(((String)entry.getValue()).getBytes());
}
super.startElement(url, localName, qName, attr);
}
/* (non-Javadoc)
* @see org.xml.sax.XMLReader#setFeature(java.lang.String, boolean)
*/
public void setFeature(String feature, boolean value)
throws SAXNotRecognizedException, SAXNotSupportedException {
if(feature.equals("http://xml.org/sax/features/namespaces")) {
isNamespaceAware = value;
}
super.setFeature(feature, value);
}
}
1.1 xml-fop/test/java/org/apache/fop/DigestFilterTestCase.java
Index: DigestFilterTestCase.java
===================================================================
/*
* $Id: DigestFilterTestCase.java,v 1.1 2003/09/19 16:50:56 pietsch Exp $
* ============================================================================
* The Apache Software License, Version 1.1
* ============================================================================
*
* Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by the Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "FOP" and "Apache Software Foundation" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache", nor may
* "Apache" appear in their name, without prior written permission of the
* Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
* DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ============================================================================
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the Apache Software Foundation and was originally created by
* James Tauber <[EMAIL PROTECTED]>. For more information on the Apache
* Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.fop;
import java.io.IOException;
import java.io.StringReader;
import java.security.NoSuchAlgorithmException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import junit.framework.TestCase;
import org.apache.fop.util.DigestFilter;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
/**
* Test case for digesting SAX filter.
*
*/
public class DigestFilterTestCase extends TestCase {
private SAXParserFactory parserFactory;
/* (non-Javadoc)
* @see junit.framework.TestCase#setUp()
*/
protected void setUp() {
parserFactory = SAXParserFactory.newInstance();
parserFactory.setNamespaceAware(true);
}
private boolean compareDigest(byte a[], byte b[]) {
if (a.length != b.length) {
return false;
}
for (int i = 0; i < a.length; i++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}
private String digestToString(byte digest[]) {
StringBuffer buffer = new StringBuffer(2 * digest.length);
for (int i = 0; i < digest.length; i++) {
int val = digest[i];
int hi = (val >> 4) & 0xF;
int lo = val & 0xF;
if (hi < 10) {
buffer.append((char) (hi + 0x30));
} else {
buffer.append((char) (hi + 0x61 - 10));
}
if (lo < 10) {
buffer.append((char) (lo + 0x30));
} else {
buffer.append((char) (lo + 0x61 - 10));
}
}
return buffer.toString();
}
private byte[] runTest(String input)
throws
NoSuchAlgorithmException,
ParserConfigurationException,
SAXException,
IOException {
XMLReader parser = parserFactory.newSAXParser().getXMLReader();
DigestFilter digestFilter = new DigestFilter("MD5");
digestFilter.setParent(parser);
digestFilter.setFeature("http://xml.org/sax/features/namespaces",true);
parser.setContentHandler(digestFilter);
InputSource inputSource = new InputSource(new StringReader(input));
parser.parse(inputSource);
return digestFilter.getDigestValue();
}
public final void testLineFeed()
throws
NoSuchAlgorithmException,
ParserConfigurationException,
SAXException,
IOException {
byte lfDigest[] = runTest("<a>\n</a>");
byte crlfDigest[] = runTest("<a>\r\n</a>");
assertTrue(
"LF: "
+ digestToString(lfDigest)
+ " CRLF: "
+ digestToString(crlfDigest),
compareDigest(lfDigest, crlfDigest));
}
public final void testAttributeOrder()
throws
NoSuchAlgorithmException,
ParserConfigurationException,
SAXException,
IOException {
byte sortDigest[] = runTest("<a a1='1' a2='2' a3='3'/>");
byte permutationDigest[] = runTest("<a a2='2' a3='3' a1='1'/>");
assertTrue(
"Sort: "
+ digestToString(sortDigest)
+ " permuted: "
+ digestToString(permutationDigest),
compareDigest(sortDigest, permutationDigest));
byte reverseDigest[] = runTest("<a a3='3' a2='2' a1='1'/>");
assertTrue(
"Sort: "
+ digestToString(sortDigest)
+ " permuted: "
+ digestToString(reverseDigest),
compareDigest(sortDigest, reverseDigest));
}
public final void testNamespacePrefix()
throws
NoSuchAlgorithmException,
ParserConfigurationException,
SAXException,
IOException {
byte prefix1Digest[] = runTest("<a:a xmlns:a='foo'/>");
byte prefix2Digest[] = runTest("<b:a xmlns:b='foo'/>");
assertTrue(
"prefix1: "
+ digestToString(prefix1Digest)
+ " prefix2: "
+ digestToString(prefix2Digest),
compareDigest(prefix1Digest, prefix2Digest));
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]