version 1.26.10.1, 2003/08/13 19:39:50
|
version 1.58.4.4, 2008/02/19 22:09:39
|
|
|
//%///////////////////////////////////////////////////////////////////////////// |
//%2006//////////////////////////////////////////////////////////////////////// |
// | // |
// Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM, |
// Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development |
// The Open Group, Tivoli Systems |
// Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems. |
|
// Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.; |
|
// IBM Corp.; EMC Corporation, The Open Group. |
|
// Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.; |
|
// IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group. |
|
// Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.; |
|
// EMC Corporation; VERITAS Software Corporation; The Open Group. |
|
// Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.; |
|
// EMC Corporation; Symantec Corporation; The Open Group. |
// | // |
// Permission is hereby granted, free of charge, to any person obtaining a copy | // Permission is hereby granted, free of charge, to any person obtaining a copy |
// of this software and associated documentation files (the "Software"), to | // of this software and associated documentation files (the "Software"), to |
|
|
// | // |
//============================================================================== | //============================================================================== |
// | // |
// Author: Mike Brasher (mbrasher@bmc.com) |
|
// |
|
// Modified By: Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com) |
|
// Carol Ann Krug Graves, Hewlett-Packard Company |
|
// (carolann_graves@hp.com) |
|
// |
|
//%///////////////////////////////////////////////////////////////////////////// | //%///////////////////////////////////////////////////////////////////////////// |
| |
#include <Pegasus/Common/Config.h> | #include <Pegasus/Common/Config.h> |
#include <cctype> |
|
#include <cstring> | #include <cstring> |
#include <iostream> | #include <iostream> |
#include "HashTable.h" | #include "HashTable.h" |
#include "CIMObjectPath.h" | #include "CIMObjectPath.h" |
#include "Indentor.h" | #include "Indentor.h" |
#include "CIMName.h" | #include "CIMName.h" |
#include "Destroyer.h" |
|
#include "XmlWriter.h" | #include "XmlWriter.h" |
#include "XmlReader.h" | #include "XmlReader.h" |
#include "ArrayInternal.h" | #include "ArrayInternal.h" |
#include "CIMOMPort.h" |
#include "HostLocator.h" |
| |
PEGASUS_NAMESPACE_BEGIN | PEGASUS_NAMESPACE_BEGIN |
| |
|
|
{ | { |
switch (str[i]) | switch (str[i]) |
{ | { |
case '\n': |
case '\\': |
result.append("\\n"); |
result.append("\\\\"); |
break; |
|
|
|
case '\r': |
|
result.append("\\r"); |
|
break; |
|
|
|
case '\t': |
|
result.append("\\t"); |
|
break; | break; |
| |
case '"': | case '"': |
|
|
_rep = new CIMKeyBindingRep(*x._rep); | _rep = new CIMKeyBindingRep(*x._rep); |
} | } |
| |
CIMKeyBinding::CIMKeyBinding(const CIMName& name, const String& value, Type type) |
CIMKeyBinding::CIMKeyBinding( |
|
const CIMName& name, |
|
const String& value, |
|
Type type) |
{ | { |
_rep = new CIMKeyBindingRep(name, value, type); | _rep = new CIMKeyBindingRep(name, value, type); |
} | } |
|
|
case CIMTYPE_REFERENCE: | case CIMTYPE_REFERENCE: |
kbType = REFERENCE; | kbType = REFERENCE; |
break; | break; |
|
// case CIMTYPE_REAL32: |
|
// case CIMTYPE_REAL64: |
|
case CIMTYPE_OBJECT: |
|
#ifdef PEGASUS_EMBEDDED_INSTANCE_SUPPORT |
|
case CIMTYPE_INSTANCE: |
|
#endif // PEGASUS_EMBEDDED_INSTANCE_SUPPORT |
|
// From PEP 194: EmbeddedObjects cannot be keys. |
|
throw TypeMismatchException(); |
|
break; |
default: | default: |
kbType = NUMERIC; | kbType = NUMERIC; |
break; | break; |
|
|
kbValue = XmlReader::stringToValue(0, getValue().getCString(), | kbValue = XmlReader::stringToValue(0, getValue().getCString(), |
value.getType()); | value.getType()); |
break; | break; |
|
// case CIMTYPE_REAL32: |
|
// case CIMTYPE_REAL64: |
|
case CIMTYPE_OBJECT: |
|
#ifdef PEGASUS_EMBEDDED_INSTANCE_SUPPORT |
|
case CIMTYPE_INSTANCE: |
|
#endif // PEGASUS_EMBEDDED_INSTANCE_SUPPORT |
|
// From PEP 194: EmbeddedObjects cannot be keys. |
|
return false; |
|
break; |
default: // Numerics | default: // Numerics |
if (getType() != NUMERIC) return false; | if (getType() != NUMERIC) return false; |
kbValue = XmlReader::stringToValue(0, getValue().getCString(), | kbValue = XmlReader::stringToValue(0, getValue().getCString(), |
|
|
| |
Boolean operator==(const CIMKeyBinding& x, const CIMKeyBinding& y) | Boolean operator==(const CIMKeyBinding& x, const CIMKeyBinding& y) |
{ | { |
return |
// Check that the names and types match |
x.getName().equal(y.getName()) && |
if (!(x.getName().equal(y.getName())) || |
String::equal(x.getValue(), y.getValue()) && |
!(x.getType() == y.getType())) |
x.getType() == y.getType(); |
{ |
|
return false; |
|
} |
|
|
|
switch (x.getType()) |
|
{ |
|
case CIMKeyBinding::REFERENCE: |
|
try |
|
{ |
|
// References should be compared as CIMObjectPaths |
|
return (CIMObjectPath(x.getValue()) == CIMObjectPath(y.getValue())); |
|
} |
|
catch (Exception&) |
|
{ |
|
// If CIMObjectPath parsing fails, just compare strings |
|
return String::equal(x.getValue(), y.getValue()); |
|
} |
|
break; |
|
case CIMKeyBinding::BOOLEAN: |
|
// Case-insensitive comparison is sufficient for booleans |
|
return String::equalNoCase(x.getValue(), y.getValue()); |
|
break; |
|
case CIMKeyBinding::NUMERIC: |
|
// Note: This comparison assumes XML syntax for integers |
|
// First try comparing as unsigned integers |
|
{ |
|
Uint64 xValue; |
|
Uint64 yValue; |
|
if (XmlReader::stringToUnsignedInteger( |
|
x.getValue().getCString(), xValue) && |
|
XmlReader::stringToUnsignedInteger( |
|
y.getValue().getCString(), yValue)) |
|
{ |
|
return (xValue == yValue); |
|
} |
|
} |
|
// Next try comparing as signed integers |
|
{ |
|
Sint64 xValue; |
|
Sint64 yValue; |
|
if (XmlReader::stringToSignedInteger( |
|
x.getValue().getCString(), xValue) && |
|
XmlReader::stringToSignedInteger( |
|
y.getValue().getCString(), yValue)) |
|
{ |
|
return (xValue == yValue); |
|
} |
|
} |
|
// Note: Keys may not be real values, so don't try comparing as reals |
|
// We couldn't parse the numbers, so just compare the strings |
|
return String::equal(x.getValue(), y.getValue()); |
|
break; |
|
default: // CIMKeyBinding::STRING |
|
return String::equal(x.getValue(), y.getValue()); |
|
break; |
|
} |
|
|
|
PEGASUS_UNREACHABLE(return false;) |
} | } |
| |
| |
|
|
return *this; | return *this; |
} | } |
| |
|
static Boolean isValidHostname(const String& hostname) |
|
{ |
|
HostLocator addr(hostname); |
|
|
|
return addr.isValid(); |
|
} |
|
|
// | // |
// Contains port as well (e.g., myhost:1234). | // Contains port as well (e.g., myhost:1234). |
// | // |
|
|
String& host) | String& host) |
{ | { |
// See if there is a host name (true if it begins with "//"): | // See if there is a host name (true if it begins with "//"): |
// Host is of the from <hostname>-<port> and begins with "//" |
// Host is of the form <hostname>:<port> and begins with "//" |
// and ends with "/": | // and ends with "/": |
| |
if (p[0] != '/' || p[1] != '/') | if (p[0] != '/' || p[1] != '/') |
|
|
| |
p += 2; | p += 2; |
| |
//---------------------------------------------------------------------- |
char* slash = strchr(p, '/'); |
// Validate the hostname. A domain is allowed after the hostname. |
if (!slash) |
// Eg. xyz.company.com |
|
// Hostnames must match the following regular expression: |
|
// ^([A-Za-z][A-Za-z0-9-]*)(\.[A-Za-z][A-Za-z0-9-]*)*$ |
|
//---------------------------------------------------------------------- |
|
|
|
char* q = p; |
|
|
|
Boolean foundDot = true; |
|
while (foundDot == true) |
|
{ | { |
foundDot = false; |
|
|
|
if (!isalpha(*q)) |
|
throw MalformedObjectNameException(objectName); | throw MalformedObjectNameException(objectName); |
|
|
q++; |
|
|
|
while (isalnum(*q) || *q == '-') |
|
{ |
|
q++; |
|
} | } |
| |
if (*q == '.') |
String hostname = String(p, (Uint32)(slash - p)); |
{ |
if (!CIMObjectPathRep::isValidHostname(hostname)) |
q++; |
|
foundDot = true; |
|
} |
|
} |
|
|
|
// We now expect a port (or default the port). |
|
|
|
if (*q == ':') |
|
{ |
|
q++; |
|
// Check for a port number: |
|
|
|
if (!isdigit(*q)) |
|
throw MalformedObjectNameException(objectName); |
|
|
|
while (isdigit(*q)) |
|
q++; |
|
|
|
// Finally, assign the host name: |
|
|
|
host.assign(p, q - p); |
|
} |
|
else |
|
{ |
|
host.assign(p, q - p); |
|
|
|
// Assign the default port number: |
|
|
|
host.append(":"); |
|
host.append(PEGASUS_CIMOM_DEFAULT_PORT_STRING); |
|
} |
|
|
|
// Check for slash terminating the entire sequence: |
|
|
|
if (*q != '/') |
|
{ | { |
host.clear(); |
|
throw MalformedObjectNameException(objectName); | throw MalformedObjectNameException(objectName); |
} | } |
|
host = hostname; |
| |
p = ++q; |
// Do not step past the '/'; it will be consumed by the namespace parser |
|
p = slash; |
| |
return true; | return true; |
} | } |
|
|
} | } |
| |
/** | /** |
ATTN: RK - Association classes have keys whose types are |
ATTN-RK: The DMTF specification for the string form of an |
references. These reference values must be treated specially |
object path makes it impossible for a parser to distinguish |
in the XML encoding, using the VALUE.REFERENCE tag structure. |
between a key values of String type and Reference type. |
|
|
Pegasus had been passing reference values simply as String |
Given the ambiguity, this implementation takes a guess at the |
values. For example, EnumerateInstanceNames returned |
type of a quoted key value. If the value can be parsed into |
KEYVALUEs of string type rather than VALUE.REFERENCEs. |
a CIMObjectPath with at least one key binding, the type is |
|
set to REFERENCE. Otherwise, the type is set to STRING. |
I've modified the XmlReader::getKeyBindingElement() and |
Note: This algorithm appears to be in line with what the Sun |
XmlWriter::appendInstanceNameElement() methods to read and write |
WBEM Services implementation does. |
the XML in the proper format. However, making that change |
|
required that a CIMObjectPath object be able to distinguish |
To be totally correct, it would be necessary to retrieve the |
between a key of String type and a key of reference type. |
class definition and look up the types of the key properties |
|
to determine how to interpret the key values. This is clearly |
I've modified the String format of CIMObjectPaths slightly to |
too inefficient for internal transformations between |
allow efficient processing of references whose keys are also |
CIMObjectPaths and String values. |
of reference type. The "official" form uses the same |
|
encoding for key values of String type and of reference type, |
|
and so it would be necessary to retrieve the class definition |
|
and look up the types of the key properties to determine how |
|
to treat the key values. This is clearly too inefficient for |
|
internal transformations between CIMObjectPaths and String |
|
values. |
|
|
|
The workaround is to encode a 'R' at the beginning of the |
|
value for a key of reference type (before the opening '"'). |
|
This allows the parser to know a priori whether the key is of |
|
String or reference type. |
|
|
|
In this example: |
|
|
|
MyClass.Key1="StringValue",Key2=R"RefClass.KeyA="StringA",KeyB=10" |
|
|
|
Property Key1 of class MyClass is of String type, and so it |
|
gets the usual encoding. Key2 is a reference property, so |
|
the extra 'R' is inserted before its encoded value. Note |
|
that this algorithm is recursive, such that RefClass could |
|
include KeyC of reference type, which would also get encoded |
|
with the 'R' notation. |
|
|
|
The toString() method inserts the 'R' to provide symmetry. A |
|
new CIMKeyBinding type (REFERENCE) has been defined to denote |
|
keys in a CIMObjectPath that are of reference type. This |
|
CIMKeyBinding type must be used appropriately for |
|
CIMObjectPath::toString() to behave correctly. |
|
|
|
A result of this change is that instances names in the |
|
instance repository will include this extra 'R' character. |
|
Note that for user-facing uses of the String encoding of |
|
instance names (such as might appear in MOF for static |
|
association instances or in the CGI client), this solution |
|
is non-standard and therefore unacceptable. It is likely |
|
that these points will need to process the more expensive |
|
operation of retrieving the class definition to determine |
|
the key property types. |
|
*/ | */ |
void _parseKeyBindingPairs( | void _parseKeyBindingPairs( |
const String& objectName, | const String& objectName, |
|
|
p = equalsign + 1; | p = equalsign + 1; |
CIMKeyBinding::Type type; | CIMKeyBinding::Type type; |
| |
if (*p == 'R') |
if (*p == '"') |
{ | { |
p++; |
// Could be CIMKeyBinding::STRING or CIMKeyBinding::REFERENCE |
| |
type = CIMKeyBinding::REFERENCE; |
p++; |
| |
if (*p++ != '"') |
Array<Uint8> keyValueUTF8; |
throw MalformedObjectNameException(objectName); |
keyValueUTF8.reserveCapacity(128); |
| |
while (*p && *p != '"') | while (*p && *p != '"') |
{ | { |
// ATTN: need to handle special characters here: |
|
|
|
if (*p == '\\') | if (*p == '\\') |
*p++; |
{ |
|
p++; |
|
|
|
if ((*p != '\\') && (*p != '"')) |
|
{ |
|
throw MalformedObjectNameException(objectName); |
|
} |
|
} |
| |
valueString.append(*p++); |
keyValueUTF8.append(*p++); |
} | } |
| |
if (*p++ != '"') | if (*p++ != '"') |
throw MalformedObjectNameException(objectName); | throw MalformedObjectNameException(objectName); |
} |
|
else if (*p == '"') |
|
{ |
|
p++; |
|
| |
|
// Convert the UTF-8 value to a UTF-16 String |
|
|
|
valueString.assign( |
|
(const char*)keyValueUTF8.getData(), |
|
keyValueUTF8.size()); |
|
|
|
/* |
|
Guess at the type of this quoted key value. If the value |
|
can be parsed into a CIMObjectPath with at least one key |
|
binding, the type is assumed to be a REFERENCE. Otherwise, |
|
the type is set to STRING. (See method header for details.) |
|
*/ |
type = CIMKeyBinding::STRING; | type = CIMKeyBinding::STRING; |
| |
while (*p && *p != '"') |
/* Performance shortcut will check for |
|
equal sign instead of doing the full |
|
CIMObjectPath creation and exception handling |
|
*/ |
|
keyValueUTF8.append('\0'); |
|
if (strchr((const char*)keyValueUTF8.getData(), '=')) |
{ | { |
// ATTN: need to handle special characters here: |
// found an equal sign, high probability for a reference |
|
try |
if (*p == '\\') |
{ |
*p++; |
CIMObjectPath testForPath(valueString); |
|
if (testForPath.getKeyBindings().size() > 0) |
valueString.append(*p++); |
{ |
|
// We've found a reference value! |
|
type = CIMKeyBinding::REFERENCE; |
|
} |
|
} |
|
catch (const Exception &) |
|
{ |
|
// Not a reference value; leave type as STRING |
|
} |
} | } |
|
|
if (*p++ != '"') |
|
throw MalformedObjectNameException(objectName); |
|
} | } |
else if (toupper(*p) == 'T' || toupper(*p) == 'F') | else if (toupper(*p) == 'T' || toupper(*p) == 'F') |
{ | { |
|
|
isComma = true; | isComma = true; |
} | } |
| |
|
if (*p == '-') |
|
{ |
Sint64 x; | Sint64 x; |
|
|
if (!XmlReader::stringToSignedInteger(p, x)) | if (!XmlReader::stringToSignedInteger(p, x)) |
throw MalformedObjectNameException(objectName); | throw MalformedObjectNameException(objectName); |
|
} |
|
else |
|
{ |
|
Uint64 x; |
|
if (!XmlReader::stringToUnsignedInteger(p, x)) |
|
throw MalformedObjectNameException(objectName); |
|
} |
| |
valueString.assign(p, n); | valueString.assign(p, n); |
| |
|
|
| |
// Convert to a C String first: | // Convert to a C String first: |
| |
CString pCString = objectName.getCStringUTF8(); |
CString pCString = objectName.getCString(); |
char* p = const_cast<char*>((const char*) pCString); | char* p = const_cast<char*>((const char*) pCString); |
Boolean gotHost; | Boolean gotHost; |
Boolean gotNamespace; | Boolean gotNamespace; |
|
|
| |
void CIMObjectPath::setHost(const String& host) | void CIMObjectPath::setHost(const String& host) |
{ | { |
|
if ((host != String::EMPTY) && !CIMObjectPathRep::isValidHostname(host)) |
|
{ |
|
throw MalformedObjectNameException(host); |
|
} |
|
|
_rep->_host = host; | _rep->_host = host; |
} | } |
| |
|
|
| |
CIMKeyBinding::Type type = keyBindings[i].getType(); | CIMKeyBinding::Type type = keyBindings[i].getType(); |
| |
if (type == CIMKeyBinding::REFERENCE) |
if (type == CIMKeyBinding::STRING || |
objectName.append('R'); |
type == CIMKeyBinding::REFERENCE) |
|
|
if (type == CIMKeyBinding::STRING || type == CIMKeyBinding::REFERENCE) |
|
objectName.append('"'); | objectName.append('"'); |
| |
objectName.append(value); | objectName.append(value); |
| |
if (type == CIMKeyBinding::STRING || type == CIMKeyBinding::REFERENCE) |
if (type == CIMKeyBinding::STRING || |
|
type == CIMKeyBinding::REFERENCE) |
objectName.append('"'); | objectName.append('"'); |
| |
if (i + 1 != n) | if (i + 1 != n) |
|
|
{ | { |
CIMObjectPath ref = *this; | CIMObjectPath ref = *this; |
| |
// ATTN-RK-P2-20020510: Need to make hostname and namespace lower case? |
// Normalize hostname by changing to lower case |
|
ref._rep->_host.toLower(); // ICU_TODO: |
|
|
|
// Normalize namespace by changing to lower case |
|
if (!ref._rep->_nameSpace.isNull()) |
|
{ |
|
String nameSpaceLower = ref._rep->_nameSpace.getString(); |
|
nameSpaceLower.toLower(); // ICU_TODO: |
|
ref._rep->_nameSpace = nameSpaceLower; |
|
} |
| |
|
// Normalize class name by changing to lower case |
|
if (!ref._rep->_className.isNull()) |
|
{ |
String classNameLower = ref._rep->_className.getString (); | String classNameLower = ref._rep->_className.getString (); |
classNameLower.toLower(); // ICU_TODO: | classNameLower.toLower(); // ICU_TODO: |
ref._rep->_className = classNameLower; | ref._rep->_className = classNameLower; |
|
} |
| |
for (Uint32 i = 0, n = ref._rep->_keyBindings.size(); i < n; i++) | for (Uint32 i = 0, n = ref._rep->_keyBindings.size(); i < n; i++) |
{ | { |
|
// Normalize key binding name by changing to lower case |
|
if (!ref._rep->_keyBindings[i]._rep->_name.isNull()) |
|
{ |
String keyBindingNameLower = | String keyBindingNameLower = |
ref._rep->_keyBindings[i]._rep->_name.getString (); | ref._rep->_keyBindings[i]._rep->_name.getString (); |
keyBindingNameLower.toLower(); |
keyBindingNameLower.toLower(); // ICU_TODO: |
ref._rep->_keyBindings[i]._rep->_name = keyBindingNameLower; | ref._rep->_keyBindings[i]._rep->_name = keyBindingNameLower; |
} | } |
| |
// ATTN-RK-20020826: Need to sort keys? |
// Normalize the key value |
|
switch (ref._rep->_keyBindings[i]._rep->_type) |
|
{ |
|
case CIMKeyBinding::REFERENCE: |
|
try |
|
{ |
|
// Convert reference to CIMObjectPath and recurse |
|
ref._rep->_keyBindings[i]._rep->_value = |
|
CIMObjectPath(ref._rep->_keyBindings[i]._rep->_value). |
|
_toStringCanonical(); |
|
} |
|
catch (Exception&) |
|
{ |
|
// Leave value unchanged if the CIMObjectPath parsing fails |
|
} |
|
break; |
|
case CIMKeyBinding::BOOLEAN: |
|
// Normalize the boolean string by changing to lower case |
|
ref._rep->_keyBindings[i]._rep->_value.toLower(); // ICU_TODO: |
|
break; |
|
case CIMKeyBinding::NUMERIC: |
|
// Normalize the numeric string by converting to integer and back |
|
Uint64 uValue; |
|
Sint64 sValue; |
|
// First try converting to unsigned integer |
|
if (XmlReader::stringToUnsignedInteger( |
|
ref._rep->_keyBindings[i]._rep->_value.getCString(), |
|
uValue)) |
|
{ |
|
char buffer[32]; // Should need 21 chars max |
|
sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "u", uValue); |
|
ref._rep->_keyBindings[i]._rep->_value = String(buffer); |
|
} |
|
// Next try converting to signed integer |
|
else if (XmlReader::stringToSignedInteger( |
|
ref._rep->_keyBindings[i]._rep->_value.getCString(), |
|
sValue)) |
|
{ |
|
char buffer[32]; // Should need 21 chars max |
|
sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "d", sValue); |
|
ref._rep->_keyBindings[i]._rep->_value = String(buffer); |
|
} |
|
// Leave value unchanged if it cannot be converted to an integer |
|
break; |
|
default: // CIMKeyBinding::STRING |
|
// No normalization required for STRING |
|
break; |
|
} |
|
} |
|
|
|
// Note: key bindings are sorted when set in the CIMObjectPath |
| |
return ref.toString(); | return ref.toString(); |
} | } |
|
|
Boolean CIMObjectPath::identical(const CIMObjectPath& x) const | Boolean CIMObjectPath::identical(const CIMObjectPath& x) const |
{ | { |
return | return |
String::equal(_rep->_host, x._rep->_host) && |
String::equalNoCase(_rep->_host, x._rep->_host) && |
_rep->_nameSpace.equal(x._rep->_nameSpace) && | _rep->_nameSpace.equal(x._rep->_nameSpace) && |
_rep->_className.equal(x._rep->_className) && | _rep->_className.equal(x._rep->_className) && |
_rep->_keyBindings == x._rep->_keyBindings; | _rep->_keyBindings == x._rep->_keyBindings; |
|
|
return !operator==(x, y); | return !operator==(x, y); |
} | } |
| |
#ifndef PEGASUS_REMOVE_DEPRECATED |
|
PEGASUS_STD(ostream)& operator<<( |
|
PEGASUS_STD(ostream)& os, |
|
const CIMObjectPath& x) |
|
{ |
|
return os << x.toString(); |
|
} |
|
#endif |
|
|
|
PEGASUS_NAMESPACE_END | PEGASUS_NAMESPACE_END |