0001: /*
0002: * The contents of this file are subject to the terms
0003: * of the Common Development and Distribution License
0004: * (the License). You may not use this file except in
0005: * compliance with the License.
0006: *
0007: * You can obtain a copy of the license at
0008: * https://glassfish.dev.java.net/public/CDDLv1.0.html.
0009: * See the License for the specific language governing
0010: * permissions and limitations under the License.
0011: *
0012: * When distributing Covered Code, include this CDDL
0013: * Header Notice in each file and include the License file
0014: * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
0015: * If applicable, add the following below the CDDL Header,
0016: * with the fields enclosed by brackets [] replaced by
0017: * you own identifying information:
0018: * "Portions Copyrighted [year] [name of copyright owner]"
0019: *
0020: * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
0021: */
0022:
0023: /*
0024: * Copyright 1999-2004 The Apache Software Foundation.
0025: *
0026: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
0027: * use this file except in compliance with the License. You may obtain a copy of
0028: * the License at
0029: *
0030: * http://www.apache.org/licenses/LICENSE-2.0
0031: *
0032: * Unless required by applicable law or agreed to in writing, software
0033: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
0034: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
0035: * License for the specific language governing permissions and limitations under
0036: * the License.
0037: *
0038: */
0039: package com.sun.xml.wss.impl.transform;
0040:
0041: import com.sun.xml.wss.logging.LogDomainConstants;
0042: import java.util.HashSet;
0043: import java.util.Iterator;
0044: import java.util.Set;
0045: import java.util.SortedSet;
0046: import java.util.TreeSet;
0047:
0048: import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException;
0049: import com.sun.org.apache.xml.internal.security.c14n.helper.C14nHelper;
0050: import com.sun.org.apache.xml.internal.security.transforms.params.InclusiveNamespaces;
0051: import com.sun.org.apache.xml.internal.security.utils.Constants;
0052: import java.util.logging.Logger;
0053: import org.w3c.dom.Attr;
0054: import org.w3c.dom.Element;
0055: import org.w3c.dom.NamedNodeMap;
0056: import org.w3c.dom.Node;
0057:
0058: import java.io.IOException;
0059: import java.io.OutputStream;
0060: import java.io.UnsupportedEncodingException;
0061: import java.util.ArrayList;
0062: import java.util.List;
0063: import java.util.ListIterator;
0064:
0065: import javax.xml.parsers.DocumentBuilderFactory;
0066:
0067: import com.sun.org.apache.xml.internal.security.c14n.helper.AttrCompare;
0068: import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
0069: import com.sun.xml.wss.impl.MessageConstants;
0070: import javax.xml.crypto.Data;
0071: import javax.xml.crypto.NodeSetData;
0072: import javax.xml.crypto.URIDereferencer;
0073: import javax.xml.crypto.URIReferenceException;
0074: import javax.xml.crypto.XMLCryptoContext;
0075: import javax.xml.crypto.dom.DOMURIReference;
0076: import org.w3c.dom.Comment;
0077: import org.w3c.dom.ProcessingInstruction;
0078:
0079: /**
0080: * Implements " <A
0081: * HREF="http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/">Exclusive XML
0082: * Canonicalization, Version 1.0 </A>" <BR />
0083: * Credits: During restructuring of the Canonicalizer framework, Ren??
0084: * Kollmorgen from Software AG submitted an implementation of ExclC14n which
0085: * fitted into the old architecture and which based heavily on my old (and slow)
0086: * implementation of "Canonical XML". A big "thank you" to Ren?? for this.
0087: * <BR />
0088: * <i>THIS </i> implementation is a complete rewrite of the algorithm.
0089: *
0090: * @author Christian Geuer-Pollmann <geuerp@apache.org>
0091: * @author K.Venugopal@sun.com
0092: * @version $Revision: 1.6 $
0093: * @see <a href="http://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/ Exclusive#">
0094: * XML Canonicalization, Version 1.0</a>
0095: */
0096: public class Canonicalizer20010315ExclOmitComments {
0097: private static Logger logger = Logger.getLogger(
0098: LogDomainConstants.IMPL_SIGNATURE_DOMAIN,
0099: LogDomainConstants.IMPL_SIGNATURE_DOMAIN_BUNDLE);
0100: private static final byte[] _END_PI = { '?', '>' };
0101: private static final byte[] _BEGIN_PI = { '<', '?' };
0102: private static final byte[] _END_COMM = { '-', '-', '>' };
0103: private static final byte[] _BEGIN_COMM = { '<', '!', '-', '-' };
0104: private static final byte[] __XA_ = { '&', '#', 'x', 'A', ';' };
0105: private static final byte[] __X9_ = { '&', '#', 'x', '9', ';' };
0106: private static final byte[] _QUOT_ = { '&', 'q', 'u', 'o', 't', ';' };
0107: private static final byte[] __XD_ = { '&', '#', 'x', 'D', ';' };
0108: private static final byte[] _GT_ = { '&', 'g', 't', ';' };
0109: private static final byte[] _LT_ = { '&', 'l', 't', ';' };
0110: private static final byte[] _END_TAG = { '<', '/' };
0111: private static final byte[] _AMP_ = { '&', 'a', 'm', 'p', ';' };
0112: final static AttrCompare COMPARE = new AttrCompare();
0113: final static String XML = "xml";
0114: final static String XMLNS = "xmlns";
0115: final static byte[] equalsStr = { '=', '\"' };
0116: static final int NODE_BEFORE_DOCUMENT_ELEMENT = -1;
0117: static final int NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT = 0;
0118: static final int NODE_AFTER_DOCUMENT_ELEMENT = 1;
0119: //The null xmlns definiton.
0120: protected static final Attr nullNode;
0121:
0122: static {
0123: try {
0124: nullNode = DocumentBuilderFactory
0125: .newInstance()
0126: .newDocumentBuilder()
0127: .newDocument()
0128: .createAttributeNS(Constants.NamespaceSpecNS, XMLNS);
0129: nullNode.setValue("");
0130: } catch (Exception e) {
0131: throw new RuntimeException("Unable to create nullNode"/*,*/
0132: + e);
0133: }
0134: }
0135: XMLCryptoContext cryptoContext = null;
0136: boolean _includeComments;
0137: boolean reset = false;
0138: Set _xpathNodeSet = null;
0139: /**
0140: * The node to be skiped/excluded from the DOM tree
0141: * in subtree canonicalizations.
0142: */
0143: Node _excludeNode = null;
0144: //OutputStream _writer = new ByteArrayOutputStream();//null;
0145: OutputStream _writer = null;
0146: /**
0147: * This Set contains the names (Strings like "xmlns" or "xmlns:foo") of
0148: * the inclusive namespaces.
0149: */
0150: TreeSet _inclusiveNSSet = null;
0151: Set tokenSet = new HashSet();
0152: static final String XMLNS_URI = Constants.NamespaceSpecNS;
0153:
0154: /**
0155: * Constructor Canonicalizer20010315ExclOmitComments
0156: *
0157: */
0158: public Canonicalizer20010315ExclOmitComments() {
0159: this ._includeComments = false;
0160: }
0161:
0162: /**
0163: * Method engineCanonicalizeXPathNodeSet
0164: * @inheritDoc
0165: * @param xpathNodeSet
0166: * @param inclusiveNamespaces
0167: * @throws CanonicalizationException
0168: */
0169: public void engineCanonicalizeXPathNodeSet(Set xpathNodeSet,
0170: String inclusiveNamespaces, java.io.OutputStream stream,
0171: XMLCryptoContext context) throws CanonicalizationException,
0172: URIReferenceException {
0173:
0174: try {
0175: _writer = stream;
0176: this ._inclusiveNSSet = (TreeSet) InclusiveNamespaces
0177: .prefixStr2Set(inclusiveNamespaces);
0178: if (xpathNodeSet.size() == 0) {
0179: //return new byte[0];
0180: return;
0181: }
0182: this ._xpathNodeSet = xpathNodeSet;
0183: cryptoContext = context;
0184: try {
0185: Node rootNodeOfC14n = XMLUtils
0186: .getOwnerDocument(this ._xpathNodeSet);
0187: this .canonicalizeXPathNodeSet(rootNodeOfC14n,
0188: new NameSpaceSymbTable());
0189: //this._writer.close();
0190: /* if (this._writer instanceof ByteArrayOutputStream) {
0191: byte [] sol=((ByteArrayOutputStream)this._writer).toByteArray();
0192: if (reset) {
0193: ((ByteArrayOutputStream)this._writer).reset();
0194: }
0195: return sol;
0196: }
0197: return null;
0198: */
0199: return;
0200: } catch (UnsupportedEncodingException ex) {
0201: throw new CanonicalizationException("empty", ex);
0202: } catch (IOException ex) {
0203: throw new CanonicalizationException("empty", ex);
0204: }
0205: } finally {
0206: this ._inclusiveNSSet = null;
0207: }
0208: }
0209:
0210: /**
0211: * @inheritDoc
0212: * @param E
0213: * @throws CanonicalizationException
0214: */
0215: final Iterator handleAttributes(Element E, NameSpaceSymbTable ns,
0216: boolean isOutputElement) throws CanonicalizationException {
0217: // result will contain the attrs which have to be outputted
0218: SortedSet result = new TreeSet(COMPARE);
0219: NamedNodeMap attrs = null;
0220: int attrsLength = 0;
0221: if (E.hasAttributes()) {
0222: attrs = E.getAttributes();
0223: attrsLength = attrs.getLength();
0224: }
0225:
0226: //The prefix visibly utilized(in the attribute or in the name) in the element
0227: Set visiblyUtilized = null;
0228: //It's the output selected.
0229: //boolean isOutputElement = this._xpathNodeSet.contains(E);
0230: if (isOutputElement) {
0231: visiblyUtilized = (Set) this ._inclusiveNSSet.clone();
0232: }
0233:
0234: for (int i = 0; i < attrsLength; i++) {
0235: Attr N = (Attr) attrs.item(i);
0236: String NName = N.getLocalName();
0237: String NNodeValue = N.getNodeValue();
0238: /*if ( !this._xpathNodeSet.contains(N) && !this.tokenSet.contains(N)) {
0239: //The node is not in the nodeset(if there is a nodeset)
0240: continue;
0241: }*/
0242:
0243: if (!XMLNS_URI.equals(N.getNamespaceURI())) {
0244: //Not a namespace definition.
0245: if (isOutputElement) {
0246: //The Element is output element, add his prefix(if used) to visibyUtilized
0247: String prefix = N.getPrefix();
0248: if ((prefix != null)
0249: && (!prefix.equals(XML) && !prefix
0250: .equals(XMLNS))) {
0251: visiblyUtilized.add(prefix);
0252: }
0253: //Add to the result.
0254: result.add(N);
0255: }
0256: continue;
0257: }
0258:
0259: if (ns.addMapping(NName, NNodeValue, N)) {
0260: //New definiton check if it is relative
0261: if (C14nHelper.namespaceIsRelative(NNodeValue)) {
0262: Object exArgs[] = { E.getTagName(), NName,
0263: N.getNodeValue() };
0264: throw new CanonicalizationException(
0265: "c14n.Canonicalizer.RelativeNamespace",
0266: exArgs);
0267: }
0268: }
0269: }
0270:
0271: if (isOutputElement) {
0272: //The element is visible, handle the xmlns definition
0273: Attr xmlns = E.getAttributeNodeNS(XMLNS_URI, XMLNS);
0274: if ((xmlns != null)
0275: && (!this ._xpathNodeSet.contains(xmlns))) {
0276: //There is a definition but the xmlns is not selected by the xpath.
0277: //then xmlns=""
0278: ns.addMapping(XMLNS, "", nullNode);
0279: }
0280:
0281: if (E.getNamespaceURI() != null) {
0282: String prefix = E.getPrefix();
0283: if ((prefix == null) || (prefix.length() == 0)) {
0284: visiblyUtilized.add(XMLNS);
0285: } else {
0286: visiblyUtilized.add(prefix);
0287: }
0288: } else {
0289: visiblyUtilized.add(XMLNS);
0290: }
0291: //This can be optimezed by I don't have time
0292: //visiblyUtilized.addAll(this._inclusiveNSSet);
0293: Iterator it = visiblyUtilized.iterator();
0294: while (it.hasNext()) {
0295: String s = (String) it.next();
0296: Attr key = ns.getMapping(s);
0297: if (key == null) {
0298: continue;
0299: }
0300: result.add(key);
0301: }
0302: } else /*if (_circunvented)*/{
0303: Iterator it = this ._inclusiveNSSet.iterator();
0304: while (it.hasNext()) {
0305: String s = (String) it.next();
0306: Attr key = ns.getMappingWithoutRendered(s);
0307: if (key == null) {
0308: continue;
0309: }
0310: result.add(key);
0311: }
0312: }
0313:
0314: return result.iterator();
0315: }
0316:
0317: /**
0318: * Checks whether a Comment or ProcessingInstruction is before or after the
0319: * document element. This is needed for prepending or appending "\n"s.
0320: *
0321: * @param currentNode comment or pi to check
0322: * @return NODE_BEFORE_DOCUMENT_ELEMENT, NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT or NODE_AFTER_DOCUMENT_ELEMENT
0323: * @see #NODE_BEFORE_DOCUMENT_ELEMENT
0324: * @see #NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT
0325: * @see #NODE_AFTER_DOCUMENT_ELEMENT
0326: */
0327: final static int getPositionRelativeToDocumentElement(
0328: Node currentNode) {
0329:
0330: if ((currentNode == null)
0331: || (currentNode.getParentNode().getNodeType() != Node.DOCUMENT_NODE)) {
0332: return NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT;
0333: }
0334: Element documentElement = currentNode.getOwnerDocument()
0335: .getDocumentElement();
0336: if ((documentElement == null)
0337: || (documentElement == currentNode)) {
0338: return NODE_NOT_BEFORE_OR_AFTER_DOCUMENT_ELEMENT;
0339: }
0340:
0341: for (Node x = currentNode; x != null; x = x.getNextSibling()) {
0342: if (x == documentElement) {
0343: return NODE_BEFORE_DOCUMENT_ELEMENT;
0344: }
0345: }
0346:
0347: return NODE_AFTER_DOCUMENT_ELEMENT;
0348: }
0349:
0350: /**
0351: * Canoicalizes all the nodes included in the currentNode and contained in the
0352: * _xpathNodeSet field.
0353: *
0354: * @param currentNode
0355: * @param ns
0356: * @throws CanonicalizationException
0357: * @throws IOException
0358: */
0359: final void canonicalizeXPathNodeSet(Node currentNode,
0360: NameSpaceSymbTable ns) throws CanonicalizationException,
0361: IOException, URIReferenceException {
0362: boolean currentNodeIsVisible = this ._xpathNodeSet
0363: .contains(currentNode);
0364:
0365: switch (currentNode.getNodeType()) {
0366:
0367: case Node.DOCUMENT_TYPE_NODE:
0368: default:
0369: break;
0370:
0371: case Node.ENTITY_NODE:
0372: case Node.NOTATION_NODE:
0373: case Node.DOCUMENT_FRAGMENT_NODE:
0374: case Node.ATTRIBUTE_NODE:
0375: throw new CanonicalizationException("empty");
0376: case Node.DOCUMENT_NODE:
0377: for (Node currentChild = currentNode.getFirstChild(); currentChild != null; currentChild = currentChild
0378: .getNextSibling()) {
0379: canonicalizeXPathNodeSet(currentChild, ns);
0380: }
0381: break;
0382:
0383: case Node.COMMENT_NODE:
0384: if (currentNodeIsVisible && this ._includeComments) {
0385: outputCommentToWriter((Comment) currentNode,
0386: this ._writer);
0387: }
0388: break;
0389:
0390: case Node.PROCESSING_INSTRUCTION_NODE:
0391: if (currentNodeIsVisible) {
0392: outputPItoWriter((ProcessingInstruction) currentNode,
0393: this ._writer);
0394: }
0395: break;
0396:
0397: case Node.TEXT_NODE: {
0398: if (currentNodeIsVisible
0399: && currentNode
0400: .getParentNode()
0401: .getLocalName()
0402: .equals(
0403: MessageConstants.WSSE_BINARY_SECURITY_TOKEN_LNAME)
0404: && currentNode.getParentNode().getNamespaceURI()
0405: .equals(MessageConstants.WSSE_NS)) {
0406: outputTextToWriter(currentNode.getNodeValue(),
0407: this ._writer, true);
0408: }
0409: break;
0410: }
0411:
0412: case Node.CDATA_SECTION_NODE:
0413: if (currentNodeIsVisible) {
0414: outputTextToWriter(currentNode.getNodeValue(),
0415: this ._writer);
0416:
0417: for (Node nextSibling = currentNode.getNextSibling(); (nextSibling != null)
0418: && ((nextSibling.getNodeType() == Node.TEXT_NODE) || (nextSibling
0419: .getNodeType() == Node.CDATA_SECTION_NODE)); nextSibling = nextSibling
0420: .getNextSibling()) {
0421: /* The XPath data model allows to select only the first of a
0422: * sequence of mixed text and CDATA nodes. But we must output
0423: * them all, so we must search:
0424: *
0425: * @see http://nagoya.apache.org/bugzilla/show_bug.cgi?id=6329
0426: */
0427: outputTextToWriter(nextSibling.getNodeValue(),
0428: this ._writer);
0429: }
0430: }
0431: break;
0432:
0433: case Node.ELEMENT_NODE:
0434: String localName = currentNode.getLocalName();
0435: Element currentElement = null;
0436: if (currentNodeIsVisible && localName != null
0437: && localName.equals("SecurityTokenReference")) {
0438: String namespaceURI = currentNode.getNamespaceURI();
0439: currentElement = (Element) currentNode;
0440: if (namespaceURI != null
0441: && namespaceURI
0442: .equals(MessageConstants.WSSE_NS)) {
0443: currentElement = (Element) deReference(currentNode,
0444: cryptoContext);
0445: STRTransformImpl.toNodeSet(currentElement,
0446: this .tokenSet);
0447: removeNodes(currentNode, this ._xpathNodeSet);
0448: //currentNode = currentElement;
0449: printBinaryToken(currentElement, ns);
0450: //new NameSpaceSymbTable());
0451: this .tokenSet.clear();
0452: break;
0453: }
0454: }
0455: currentElement = (Element) currentNode;
0456:
0457: OutputStream writer = this ._writer;
0458: String tagName = currentElement.getTagName();
0459: if (currentNodeIsVisible) {
0460: //This is an outputNode.
0461: ns.outputNodePush();
0462: writer.write('<');
0463: writeStringToUtf8(tagName, writer);
0464: } else {
0465: //Not an outputNode.
0466: ns.push();
0467: }
0468:
0469: // we output all Attrs which are available
0470: Iterator attrs = handleAttributes(currentElement, ns,
0471: currentNodeIsVisible);
0472: while (attrs.hasNext()) {
0473: Attr attr = (Attr) attrs.next();
0474: outputAttrToWriter(attr.getNodeName(), attr
0475: .getNodeValue(), writer);
0476: }
0477:
0478: if (currentNodeIsVisible) {
0479: writer.write('>');
0480: }
0481:
0482: // traversal
0483: for (Node currentChild = currentNode.getFirstChild(); currentChild != null; currentChild = currentChild
0484: .getNextSibling()) {
0485: canonicalizeXPathNodeSet(currentChild, ns);
0486: }
0487:
0488: if (currentNodeIsVisible) {
0489: writer.write(_END_TAG);
0490: writeStringToUtf8(tagName, writer);
0491: //this._writer.write(currentElement.getTagName().getBytes("UTF8"));
0492: writer.write('>');
0493: ns.outputNodePop();
0494: } else {
0495: ns.pop();
0496: }
0497: break;
0498: }
0499: }
0500:
0501: /**
0502: * Adds to ns the definitons from the parent elements of el
0503: * @param el
0504: * @param ns
0505: */
0506: final static void getParentNameSpaces(Element el,
0507: NameSpaceSymbTable ns) {
0508: List parents = new ArrayList();
0509: Node n1 = el.getParentNode();
0510: if (!(n1 instanceof Element)) {
0511: return;
0512: }
0513: //Obtain all the parents of the elemnt
0514: Element parent = (Element) el.getParentNode();
0515: while (parent != null) {
0516: parents.add(parent);
0517: Node n = parent.getParentNode();
0518: if (!(n instanceof Element)) {
0519: break;
0520: }
0521: parent = (Element) n;
0522: }
0523: //Visit them in reverse order.
0524: ListIterator it = parents.listIterator(parents.size());
0525: while (it.hasPrevious()) {
0526: Element ele = (Element) it.previous();
0527: if (!ele.hasAttributes()) {
0528: continue;
0529: }
0530: NamedNodeMap attrs = ele.getAttributes();
0531: int attrsLength = attrs.getLength();
0532: for (int i = 0; i < attrsLength; i++) {
0533: Attr N = (Attr) attrs.item(i);
0534: if (!Constants.NamespaceSpecNS.equals(N
0535: .getNamespaceURI())) {
0536: //Not a namespace definition, ignore.
0537: continue;
0538: }
0539:
0540: String NName = N.getLocalName();
0541: String NValue = N.getNodeValue();
0542: if (XML.equals(NName)
0543: && Constants.XML_LANG_SPACE_SpecNS
0544: .equals(NValue)) {
0545: continue;
0546: }
0547: ns.addMapping(NName, NValue, N);
0548: }
0549: }
0550: Attr nsprefix;
0551: if (((nsprefix = ns.getMappingWithoutRendered("xmlns")) != null)
0552: && "".equals(nsprefix.getValue())) {
0553: ns.addMappingAndRender("xmlns", "", nullNode);
0554: }
0555: }
0556:
0557: /**
0558: * Outputs an Attribute to the internal Writer.
0559: *
0560: * The string value of the node is modified by replacing
0561: * <UL>
0562: * <LI>all ampersands (&) with <CODE>&amp;</CODE></LI>
0563: * <LI>all open angle brackets (<) with <CODE>&lt;</CODE></LI>
0564: * <LI>all quotation mark characters with <CODE>&quot;</CODE></LI>
0565: * <LI>and the whitespace characters <CODE>#x9</CODE>, #xA, and #xD, with character
0566: * references. The character references are written in uppercase
0567: * hexadecimal with no leading zeroes (for example, <CODE>#xD</CODE> is represented
0568: * by the character reference <CODE>&#xD;</CODE>)</LI>
0569: * </UL>
0570: *
0571: * @param name
0572: * @param value
0573: * @param writer
0574: * @throws IOException
0575: */
0576: static final void outputAttrToWriter(final String name,
0577: final String value, final OutputStream writer)
0578: throws IOException {
0579: writer.write(' ');
0580: writeStringToUtf8(name, writer);
0581: writer.write(equalsStr);
0582: byte[] toWrite;
0583: final int length = value.length();
0584: for (int i = 0; i < length; i++) {
0585: char c = value.charAt(i);
0586:
0587: switch (c) {
0588:
0589: case '&':
0590: toWrite = _AMP_;
0591: //writer.write(_AMP_);
0592: break;
0593:
0594: case '<':
0595: toWrite = _LT_;
0596: //writer.write(_LT_);
0597: break;
0598:
0599: case '"':
0600: toWrite = _QUOT_;
0601: //writer.write(_QUOT_);
0602: break;
0603:
0604: case 0x09: // '\t'
0605: toWrite = __X9_;
0606: //writer.write(__X9_);
0607: break;
0608:
0609: case 0x0A: // '\n'
0610: toWrite = __XA_;
0611: //writer.write(__XA_);
0612: break;
0613:
0614: case 0x0D: // '\r'
0615: toWrite = __XD_;
0616: //writer.write(__XD_);
0617: break;
0618:
0619: default:
0620: writeCharToUtf8(c, writer);
0621: //this._writer.write(c);
0622: continue;
0623: }
0624: writer.write(toWrite);
0625: }
0626:
0627: writer.write('\"');
0628: }
0629:
0630: final static void writeCharToUtf8(final char c,
0631: final OutputStream out) throws IOException {
0632: char ch;
0633: if (/*(c >= 0x0001) &&*/(c <= 0x007F)) {
0634: out.write(c);
0635: return;
0636: } else if (c > 0x07FF) {
0637: ch = (char) (c >>> 12);
0638: if (ch > 0) {
0639: out.write(0xE0 | (ch & 0x0F));
0640: } else {
0641: out.write(0xE0);
0642: }
0643: out.write(0x80 | ((c >>> 6) & 0x3F));
0644: out.write(0x80 | ((c) & 0x3F));
0645: return;
0646:
0647: } else {
0648: ch = (char) (c >>> 6);
0649: if (ch > 0) {
0650: out.write(0xC0 | (ch & 0x1F));
0651: } else {
0652: out.write(0xC0);
0653: }
0654: out.write(0x80 | ((c) & 0x3F));
0655: return;
0656: }
0657:
0658: }
0659:
0660: final static void writeStringToUtf8(final String str,
0661: final OutputStream out) throws IOException {
0662: final int length = str.length();
0663: int i = 0;
0664: char ch, c;
0665: while (i < length) {
0666: c = str.charAt(i++);
0667: if (/*(c >= 0x0001) &&*/(c <= 0x007F)) {
0668: out.write(c);
0669: continue;
0670: } else if (c > 0x07FF) {
0671: ch = (char) (c >>> 12);
0672: if (ch > 0) {
0673: out.write(0xE0 | (ch & 0x0F));
0674: } else {
0675: out.write(0xE0);
0676: }
0677: out.write(0x80 | ((c >>> 6) & 0x3F));
0678: out.write(0x80 | ((c) & 0x3F));
0679: continue;
0680: } else {
0681: ch = (char) (c >>> 6);
0682: if (ch > 0) {
0683: out.write(0xC0 | (ch & 0x1F));
0684: } else {
0685: out.write(0xC0);
0686: }
0687: out.write(0x80 | ((c) & 0x3F));
0688: continue;
0689: }
0690: }
0691:
0692: }
0693:
0694: /**
0695: * Outputs a PI to the internal Writer.
0696: *
0697: * @param currentPI
0698: * @param writer TODO
0699: * @throws IOException
0700: */
0701: static final void outputPItoWriter(ProcessingInstruction currentPI,
0702: OutputStream writer) throws IOException {
0703: final int position = getPositionRelativeToDocumentElement(currentPI);
0704:
0705: if (position == NODE_AFTER_DOCUMENT_ELEMENT) {
0706: writer.write('\n');
0707: }
0708: writer.write(_BEGIN_PI);
0709:
0710: final String target = currentPI.getTarget();
0711: int length = target.length();
0712:
0713: for (int i = 0; i < length; i++) {
0714: char c = target.charAt(i);
0715: if (c == 0x0D) {
0716: writer.write(__XD_);
0717: } else {
0718: writeCharToUtf8(c, writer);
0719: }
0720: }
0721:
0722: final String data = currentPI.getData();
0723:
0724: length = data.length();
0725:
0726: if (length > 0) {
0727: writer.write(' ');
0728:
0729: for (int i = 0; i < length; i++) {
0730: char c = data.charAt(i);
0731: if (c == 0x0D) {
0732: writer.write(__XD_);
0733: } else {
0734: writeCharToUtf8(c, writer);
0735: }
0736: }
0737: }
0738:
0739: writer.write(_END_PI);
0740: if (position == NODE_BEFORE_DOCUMENT_ELEMENT) {
0741: writer.write('\n');
0742: }
0743: }
0744:
0745: /**
0746: * Method outputCommentToWriter
0747: *
0748: * @param currentComment
0749: * @param writer TODO
0750: * @throws IOException
0751: */
0752: static final void outputCommentToWriter(Comment currentComment,
0753: OutputStream writer) throws IOException {
0754: final int position = getPositionRelativeToDocumentElement(currentComment);
0755: if (position == NODE_AFTER_DOCUMENT_ELEMENT) {
0756: writer.write('\n');
0757: }
0758: writer.write(_BEGIN_COMM);
0759:
0760: final String data = currentComment.getData();
0761: final int length = data.length();
0762:
0763: for (int i = 0; i < length; i++) {
0764: char c = data.charAt(i);
0765: if (c == 0x0D) {
0766: writer.write(__XD_);
0767: } else {
0768: writeCharToUtf8(c, writer);
0769: }
0770: }
0771:
0772: writer.write(_END_COMM);
0773: if (position == NODE_BEFORE_DOCUMENT_ELEMENT) {
0774: writer.write('\n');
0775: }
0776: }
0777:
0778: /**
0779: * Outputs a Text of CDATA section to the internal Writer.
0780: *
0781: * @param text
0782: * @param writer TODO
0783: * @throws IOException
0784: */
0785: static final void outputTextToWriter(final String text,
0786: final OutputStream writer) throws IOException {
0787: outputTextToWriter(text, writer, false);
0788: }
0789:
0790: /**
0791: * Outputs a Text of CDATA section to the internal Writer.
0792: *
0793: * @param text
0794: * @param writer TODO
0795: * @param skipWhiteSpace S ::= (#x20 | #x9 | #xD | #xA)+
0796: * @throws IOException
0797: */
0798: static final void outputTextToWriter(final String text,
0799: final OutputStream writer, boolean skipWhiteSpace)
0800: throws IOException {
0801: final int length = text.length();
0802: byte[] toWrite;
0803: for (int i = 0; i < length; i++) {
0804: char c = text.charAt(i);
0805:
0806: switch (c) {
0807:
0808: case '&':
0809: writer.write(_AMP_);
0810: break;
0811:
0812: case '<':
0813: writer.write(_LT_);
0814: break;
0815:
0816: case '>':
0817: writer.write(_GT_);
0818: break;
0819:
0820: case 0xD:
0821: if (!skipWhiteSpace) {
0822: writer.write(__XD_);
0823: }
0824: break;
0825: case 0xA:
0826: if (!skipWhiteSpace) {
0827: writeCharToUtf8(c, writer);
0828: }
0829: break;
0830: case 0x9:
0831: if (!skipWhiteSpace) {
0832: writeCharToUtf8(c, writer);
0833: }
0834: break;
0835: case 0x20:
0836: if (!skipWhiteSpace) {
0837: writeCharToUtf8(c, writer);
0838: }
0839: break;
0840: default:
0841: writeCharToUtf8(c, writer);
0842: continue;
0843: }
0844: }
0845: }
0846:
0847: /**
0848: * @return Returns the _includeComments.
0849: */
0850: final public boolean is_includeComments() {
0851: return _includeComments;
0852: }
0853:
0854: /**
0855: * @param comments The _includeComments to set.
0856: */
0857: final public void set_includeComments(boolean comments) {
0858: _includeComments = comments;
0859: }
0860:
0861: /**
0862: * @param _writer The _writer to set.
0863: */
0864: public void setWriter(OutputStream _writer) {
0865: this ._writer = _writer;
0866: }
0867:
0868: protected static Node deReference(final Node node,
0869: XMLCryptoContext context) throws URIReferenceException {
0870:
0871: /*NodeList nodeList = ((Document)node).getElementsByTagNameNS(WSSE_EXT,"SecurityTokenReference");
0872: final Node domNode = nodeList.item(0);*/
0873: URIDereferencer dereferencer = context.getURIDereferencer();
0874:
0875: //Dereference SecurityTokenReference;
0876: DOMURIReference domReference = new DOMURIReference() {
0877: public Node getHere() {
0878: return node;
0879: }
0880:
0881: public String getURI() {
0882: return null;
0883: }
0884:
0885: public String getType() {
0886: return null;
0887: }
0888: };
0889: Data data = dereferencer.dereference(domReference, context);
0890: //Node parentNode = node.getParentNode();
0891: Iterator nodeIterator = ((NodeSetData) data).iterator();
0892: if (nodeIterator.hasNext()) {
0893: return (Node) nodeIterator.next();
0894: } else {
0895: throw new URIReferenceException("URI "
0896: + ((Element) node).getAttribute("URI")
0897: + "not found");
0898: }
0899: }
0900:
0901: void removeNodes(Node rootNode, Set result) {
0902: try {
0903: switch (rootNode.getNodeType()) {
0904: case Node.ELEMENT_NODE:
0905: result.remove(rootNode);
0906: //no return keep working
0907: case Node.DOCUMENT_NODE:
0908: for (Node r = rootNode.getFirstChild(); r != null; r = r
0909: .getNextSibling()) {
0910: removeNodes(r, result);
0911: }
0912: return;
0913: default:
0914: result.remove(rootNode);
0915: }
0916: } catch (Exception ex) {
0917: //log
0918: }
0919: return;
0920: }
0921:
0922: final void printBinaryToken(Node currentNode, NameSpaceSymbTable ns)
0923: throws CanonicalizationException, IOException,
0924: URIReferenceException {
0925: //handle EKSHA1 under DKT
0926: if (currentNode == null)
0927: return;
0928:
0929: boolean currentNodeIsVisible = this ._xpathNodeSet
0930: .contains(currentNode);
0931: if (!currentNodeIsVisible) {
0932: currentNodeIsVisible = this .tokenSet.contains(currentNode);
0933: }
0934: switch (currentNode.getNodeType()) {
0935:
0936: case Node.DOCUMENT_TYPE_NODE:
0937: default:
0938: break;
0939:
0940: case Node.ENTITY_NODE:
0941: case Node.NOTATION_NODE:
0942: case Node.DOCUMENT_FRAGMENT_NODE:
0943: case Node.ATTRIBUTE_NODE:
0944: throw new CanonicalizationException("empty");
0945: case Node.DOCUMENT_NODE:
0946: for (Node currentChild = currentNode.getFirstChild(); currentChild != null; currentChild = currentChild
0947: .getNextSibling()) {
0948: printBinaryToken(currentChild, ns);
0949: }
0950: break;
0951:
0952: case Node.COMMENT_NODE:
0953: if (currentNodeIsVisible && this ._includeComments) {
0954: outputCommentToWriter((Comment) currentNode,
0955: this ._writer);
0956: }
0957: break;
0958:
0959: case Node.PROCESSING_INSTRUCTION_NODE:
0960: if (currentNodeIsVisible) {
0961: outputPItoWriter((ProcessingInstruction) currentNode,
0962: this ._writer);
0963: }
0964: break;
0965:
0966: case Node.TEXT_NODE: {
0967: if (currentNodeIsVisible
0968: && currentNode
0969: .getParentNode()
0970: .getLocalName()
0971: .equals(
0972: MessageConstants.WSSE_BINARY_SECURITY_TOKEN_LNAME)
0973: && currentNode.getParentNode().getNamespaceURI()
0974: .equals(MessageConstants.WSSE_NS)) {
0975: NamedNodeMap nmap = currentNode.getParentNode()
0976: .getAttributes();
0977: Node node = nmap.getNamedItemNS(
0978: MessageConstants.WSU_NS, "Id");
0979: if (node == null) {
0980: //System.out.println("ID FOUND");
0981: outputTextToWriter(currentNode.getNodeValue(),
0982: this ._writer, true);
0983: } else {
0984: outputTextToWriter(currentNode.getNodeValue(),
0985: this ._writer, false);
0986: }
0987: }
0988: break;
0989: }
0990:
0991: case Node.CDATA_SECTION_NODE:
0992: if (currentNodeIsVisible) {
0993: outputTextToWriter(currentNode.getNodeValue(),
0994: this ._writer);
0995:
0996: for (Node nextSibling = currentNode.getNextSibling(); (nextSibling != null)
0997: && ((nextSibling.getNodeType() == Node.TEXT_NODE) || (nextSibling
0998: .getNodeType() == Node.CDATA_SECTION_NODE)); nextSibling = nextSibling
0999: .getNextSibling()) {
1000: /* The XPath data model allows to select only the first of a
1001: * sequence of mixed text and CDATA nodes. But we must output
1002: * them all, so we must search:
1003: *
1004: * @see http://nagoya.apache.org/bugzilla/show_bug.cgi?id=6329
1005: */
1006: outputTextToWriter(nextSibling.getNodeValue(),
1007: this ._writer);
1008: }
1009: }
1010: break;
1011:
1012: case Node.ELEMENT_NODE:
1013: String localName = currentNode.getLocalName();
1014: Element currentElement = null;
1015: currentElement = (Element) currentNode;
1016:
1017: OutputStream writer = this ._writer;
1018: String tagName = currentElement.getTagName();
1019: if (currentNodeIsVisible) {
1020: //This is an outputNode.
1021: ns.outputNodePush();
1022: writer.write('<');
1023: writeStringToUtf8(tagName, writer);
1024: } else {
1025: //Not an outputNode.
1026: ns.push();
1027: }
1028:
1029: // we output all Attrs which are available
1030: Attr defNS = currentElement.getAttributeNodeNS(
1031: MessageConstants.NAMESPACES_NS, "xmlns");
1032: Iterator attrs = handleAttributes(currentElement, ns,
1033: currentNodeIsVisible);
1034: if (defNS != null)
1035: outputAttrToWriter(defNS.getNodeName(), defNS
1036: .getNodeValue(), writer);
1037: while (attrs.hasNext()) {
1038: Attr attr = (Attr) attrs.next();
1039: outputAttrToWriter(attr.getNodeName(), attr
1040: .getNodeValue(), writer);
1041: }
1042:
1043: if (currentNodeIsVisible) {
1044: writer.write('>');
1045: }
1046:
1047: // traversal
1048: for (Node currentChild = currentNode.getFirstChild(); currentChild != null; currentChild = currentChild
1049: .getNextSibling()) {
1050: printBinaryToken(currentChild, ns);
1051: }
1052:
1053: if (currentNodeIsVisible) {
1054: writer.write(_END_TAG);
1055: writeStringToUtf8(tagName, writer);
1056: //this._writer.write(currentElement.getTagName().getBytes("UTF8"));
1057: writer.write('>');
1058: ns.outputNodePop();
1059: } else {
1060: ns.pop();
1061: }
1062: break;
1063: }
1064: }
1065: }
|