package com.limegroup.gnutella.metadata;
import java.io.StringReader;
import java.io.IOException;
import org.apache.xerces.parsers.DOMParser;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.NamedNodeMap;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.limegroup.gnutella.xml.LimeXMLUtils;
/**
* An encapsulation of the XML that describes Windows Media's
* extended content encryption object.
*
* Construction will always succeed, but the object may be invalid.
* Consult WRMXML.isValid() to see if the given XML was valid.
*/
public class WRMXML {
public static final String PROTECTED = "licensed: ";
// The XML should look something like:
//<WRMHEADER>
// <DATA>
// <SECURITYVERSION>XXXX</SECURITYVERSION>
// <CID>XXXX</CID>
// <LAINFO>XXXX</LAINFO>
// <KID>XXXX</KID>
// <CHECKSUM>XXXX</CHECKSUM>
// </DATA>
// <SIGNATURE>
// <HASHALGORITHM type="XXXX"></HASHALGORITHM>
// <SIGNALGORITHM type="XXXX"></SIGNALGORITHM>
// <VALUE>XXXX</VALUE>
// </SIGNATURE>
//</WRMHEADER>
protected String _securityversion, _cid, _lainfo, _kid, _checksum;
protected String _hashalgorithm, _signalgorithm, _signatureValue;
protected Node _documentNode;
/**
* Parses the given XML & constructs a WRMXML object out of it.
*/
WRMXML(String xml) {
parse(xml);
}
/**
* Constructs a WRMXML object out of the given document.
*/
WRMXML(Node documentNode) {
parseDocument(documentNode);
}
/**
* Determines is this WRMXML is well formed.
* If it is not, no other methods are considered valid.
*/
public boolean isValid() {
return _documentNode != null &&
_lainfo != null &&
_hashalgorithm != null &&
_signalgorithm != null &&
_signatureValue != null;
}
public String getSecurityVersion() { return _securityversion; }
public String getCID() { return _cid; }
public String getLAInfo() { return _lainfo; }
public String getKID() { return _kid; }
public String getHashAlgorithm() { return _hashalgorithm; }
public String getSignAlgorithm() { return _signalgorithm; }
public String getSignatureValue() { return _signatureValue; }
public String getChecksum() { return _checksum; }
/** Parses the content encryption XML. */
protected void parse(String xml) {
DOMParser parser = new DOMParser();
InputSource is = new InputSource(new StringReader(xml));
try {
parser.parse(is);
} catch (IOException ioe) {
return;
} catch (SAXException saxe) {
return;
}
parseDocument(parser.getDocument().getDocumentElement());
}
/**
* Parses through the given document node, handing each child
* node to parseNode.
*/
protected void parseDocument(Node node) {
_documentNode = node;
if(!_documentNode.getNodeName().equals("WRMHEADER"))
return;
NodeList children = _documentNode.getChildNodes();
for(int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
parseNode(child.getNodeName(), child);
}
}
/**
* Parses a node.
* 'nodeName' is the parent node's name.
* All child elements of this node are sent to parseChild, and all
* attributes are parsed via parseAttributes.
*/
protected void parseNode(String nodeName, Node data) {
NodeList children = data.getChildNodes();
for(int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
parseAttributes(nodeName, child);
String name = child.getNodeName();
String value = LimeXMLUtils.getTextContent(child);
if(value == null)
continue;
value = value.trim();
if(value.equals(""))
continue;
parseChild(nodeName, name, null, value);
}
}
/**
* Parses the attributes of a given node.
* 'parentNodeName' is the parent node of this child, and child is the node
* which the attributes are part of.
* Attributes are sent to parseChild for parsing.
*/
protected void parseAttributes(String parentNodeName, Node child) {
NamedNodeMap nnm = child.getAttributes();
String name = child.getNodeName();
for(int i = 0; i < nnm.getLength(); i++) {
Node attribute = nnm.item(i);
String attrName = attribute.getNodeName();
String attrValue = attribute.getNodeValue();
if(attrValue == null)
continue;
attrValue = attrValue.trim();
if(attrValue.equals(""))
continue;
parseChild(parentNodeName, name, attrName, attrValue);
}
}
/**
* Parses a child of the data node.
* @param nodeName the parent node's name
* @param name the name of this node
* @param attribute the attribute's name, or null if not an attribute.
* @param value the value of the node's text content (or the attribute)
*/
protected void parseChild(String nodeName, String name, String attribute, String value) {
if(nodeName.equals("DATA")) {
if(attribute != null)
return;
if(name.equals("SECURITYVERSION"))
_securityversion = value;
else if(name.equals("CID"))
_cid = value;
else if(name.equals("LAINFO"))
_lainfo = value;
else if(name.equals("KID"))
_kid = value;
else if(name.equals("CHECKSUM"))
_checksum = value;
} else if(nodeName.equals("SIGNATURE")) {
if(name.equals("HASHALGORITHM") && "type".equals(attribute))
_hashalgorithm = value;
else if(name.equals("SIGNALGORITHM") && "type".equals(attribute))
_signalgorithm = value;
else if(name.equals("VALUE") && attribute == null)
_signatureValue = value;
}
}
}