import java.net.*;
import java.io.Serializable;
import java.util.*;
/*
* SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* EXPRESSLY DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, 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.
*/
/**
* Instances of this class are CPE Names, according to the
* CPE 2.0 specification (CPE web site).
* Each CPE Name is a URI with the scheme "cpe" and an absolute
* path part consisting of two-six components separated by colons.
* For example:
* cpe:/o:microsoft:windows-nt:xp:sp2:pro:en-us
*
* @version 1.4
* @author Neal Ziring, NSA
*/
public class CPEName implements Serializable
{
/** The CPE URI scheme name */
public static final String SCHEME = "cpe";
/** Value for the first component of a hardware CPE Name */
public static final String PART_HARDWARE = "h";
/** Value for the first component of an operating system CPE Name */
public static final String PART_OS = "o";
/** Maximum number of components in a CPE Name */
protected static final int MAX_COMPONENTS = 7;
/** Value for the first component of an application CPE Name */
public static final String PART_APPLICATION = "a";
/* object state - all of these are serializable */
private URI uri;
private String [] components;
/* cached state to speed up hashCode, not serialized */
private transient int hash_cache = 0;
/**
* Create a CPEName from a string.
*/
public CPEName(String name) throws URISyntaxException {
uri = new URI(name);
if (!(uri.getScheme().equals(SCHEME))) {
throw new URISyntaxException(name, "Bad CPE scheme, must be 'cpe:'");
}
String path;
path = uri.getPath();
if (path.startsWith("/")) {
path = path.substring(1);
}
components = path.split(":");
if (components.length > MAX_COMPONENTS) {
throw new URISyntaxException(name, "Bad CPE URI: maximum number of name components exceeded");
}
}
/**
* Return a string representation of the CPE Name
*/
public String toString() {
return uri.toString();
}
/**
* Return the hashcode.
*/
public int hashCode() {
if (hash_cache == 0) {
hash_cache = uri.toString().toLowerCase().hashCode();
}
return hash_cache;
}
/**
* Return true if this CPEName equals another. Note that
* this is different from matching!
*/
public boolean equals(Object o) {
CPEName that;
boolean answer = false;
if (o instanceof CPEName) {
that = (CPEName)o;
if (this.components.length == that.components.length) {
answer = true;
for(int i = 0; i < components.length; i++) {
if (!(components[i].equalsIgnoreCase(that.components[i]))) {
answer = false;
}
}
}
}
return answer;
}
/**
* Return the number of components in this CPE Name
* (including empty components).
*/
public int getLength() {
return components.length;
}
/**
* Return a specific component, or null if that
* component was not defined. The first component
* is number 0. If the input is invalid, then
* ArrayIndexOutOfBoundsException will be thrown.
*/
public String getComponent(int i) {
return components[i];
}
/**
* Return true iff this CPE Name matches one of a
* collection of known CPE Names. (This implements
* the CPE_Name_Match algorithm from the
* CPE 2.0 specification section 7.)
* Any members of the collection that are not CPEName
* objects will be ignored.
*/
public boolean nameMatch(Collection k) {
Object n_obj;
CPEName n;
Iterator ki;
for(ki = k.iterator(); ki.hasNext(); ) {
n_obj = ki.next();
// skip any members of k that are not CPE Names
if (!(n_obj instanceof CPEName)) continue;
n = (CPEName)n_obj;
// if length(n) >= length(this) then we may have a match
if (n.getLength() >= getLength()) {
boolean r = false;
// check each component of n and this
for(int i = 0; i < getLength(); i++) {
// components equal, or this component is empty
if (getComponent(i).equalsIgnoreCase(n.getComponent(i))
|| getComponent(i).equals(""))
{
r = true;
}
else {
r = false;
break;
}
}
// if r is true, then we have a match
if (r) { return true; }
}
}
return false;
}
/**
* Main for testing. Takes the first argument
* and treats it as a CPE Name.
*/
public static void main(String [] args) {
if (args.length == 0) {
System.err.println("Usage: java CPEName cpe-name [cpe-name ..]");
System.exit(1);
}
try {
int i;
String x = args[0];
CPEName cpe = new CPEName(x);
System.out.println("Name '" + cpe.toString() + "', length is " +
cpe.getLength());
for(i = 0; i < cpe.getLength(); i++) {
System.out.println("\tcomp[" + i + "] = '" +
cpe.getComponent(i) + "'");
}
if (args.length == 2) {
String x2 = args[1];
CPEName cpe2 = new CPEName(x2);
if (cpe.equals(cpe2)) {
System.out.println(cpe + " = " + cpe2);
}
else {
System.out.println(cpe + " != " + cpe2);
}
}
if (args.length > 2) {
Set k = new HashSet();
for(int j = 1; j < args.length; j++) {
CPEName cpe3 = new CPEName(args[j]);
System.out.println("Member of k: " + cpe3);
k.add(cpe3);
}
System.out.println("Set k has " + k.size() + " members.");
if (cpe.nameMatch(k)) {
System.out.println(cpe + " matches k");
}
else {
System.out.println(cpe + " does not match k");
}
}
}
catch (URISyntaxException ux) {
System.err.println("Error: " + ux);
ux.printStackTrace();
}
}
}