(file) Return to CIMObjectPath.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

   1 karl  1.45 //%2005////////////////////////////////////////////////////////////////////////
   2 chip  1.1  //
   3 karl  1.43 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
   4            // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
   5            // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
   6 karl  1.30 // IBM Corp.; EMC Corporation, The Open Group.
   7 karl  1.43 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
   8            // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
   9 karl  1.45 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
  10            // EMC Corporation; VERITAS Software Corporation; The Open Group.
  11 chip  1.1  //
  12            // Permission is hereby granted, free of charge, to any person obtaining a copy
  13            // of this software and associated documentation files (the "Software"), to
  14            // deal in the Software without restriction, including without limitation the
  15            // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  16            // sell copies of the Software, and to permit persons to whom the Software is
  17            // furnished to do so, subject to the following conditions:
  18 chip  1.47 //
  19 chip  1.1  // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
  20            // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
  21            // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
  22            // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  23            // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  24            // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  25            // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26            // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27            //
  28            //==============================================================================
  29            //
  30 kumpf 1.2  // Author: Mike Brasher (mbrasher@bmc.com)
  31 chip  1.1  //
  32 kumpf 1.2  // Modified By: Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
  33 kumpf 1.9  //              Carol Ann Krug Graves, Hewlett-Packard Company
  34            //                (carolann_graves@hp.com)
  35 dave.sudlik 1.44 //              Dave Sudlik, IBM (dsudlik@us.ibm.com)
  36 vijay.eli   1.51 //              Vijay Eli, IBM (vijayeli@in.ibm.com), bug#2556.
  37 chip        1.1  //
  38                  //%/////////////////////////////////////////////////////////////////////////////
  39                  
  40 kumpf       1.2  #include <Pegasus/Common/Config.h>
  41                  #include <cstring>
  42 kumpf       1.22 #include <iostream>
  43 kumpf       1.2  #include "HashTable.h"
  44                  #include "CIMObjectPath.h"
  45                  #include "Indentor.h"
  46                  #include "CIMName.h"
  47                  #include "XmlWriter.h"
  48                  #include "XmlReader.h"
  49 kumpf       1.11 #include "ArrayInternal.h"
  50 chip        1.1  
  51                  PEGASUS_NAMESPACE_BEGIN
  52 kumpf       1.2  
  53 kumpf       1.16 #define PEGASUS_ARRAY_T CIMKeyBinding
  54 kumpf       1.2  # include "ArrayImpl.h"
  55                  #undef PEGASUS_ARRAY_T
  56                  
  57                  #define PEGASUS_ARRAY_T CIMObjectPath
  58                  # include "ArrayImpl.h"
  59                  #undef PEGASUS_ARRAY_T
  60                  
  61                  // ATTN: KS May 2002 P0 Add resolve method to CIMObjectPath.
  62                  // Add a resolve method to this class to verify that the
  63                  // reference is correct (that the class name corresponds to a real
  64                  // class and that the property names are really keys and that all keys
  65                  // of the class or used. Also be sure that there is a valid conversion
  66                  // between the string value and the value of that property).
  67                  //
  68                  // ATTN: also check to see that the reference refers to a class that is the
  69                  // same or derived from the _className member.
  70                  
  71                  ////////////////////////////////////////////////////////////////////////////////
  72                  //
  73                  // Local routines:
  74                  //
  75 kumpf       1.2  ////////////////////////////////////////////////////////////////////////////////
  76                  
  77                  static String _escapeSpecialCharacters(const String& str)
  78                  {
  79                      String result;
  80                  
  81                      for (Uint32 i = 0, n = str.size(); i < n; i++)
  82                      {
  83                          switch (str[i])
  84                          {
  85 kumpf       1.28             case '\\':
  86                                  result.append("\\\\");
  87 kumpf       1.2                  break;
  88                  
  89                              case '"':
  90 kumpf       1.13                 result.append("\\\"");
  91 kumpf       1.2                  break;
  92                  
  93                              default:
  94 kumpf       1.13                 result.append(str[i]);
  95 kumpf       1.2          }
  96                      }
  97                  
  98                      return result;
  99                  }
 100                  
 101 kumpf       1.16 static void _BubbleSort(Array<CIMKeyBinding>& x)
 102 kumpf       1.2  {
 103                      Uint32 n = x.size();
 104                  
 105 kumpf       1.24     //
 106 chip        1.47     //  If the key is a reference, the keys in the reference must also be
 107 kumpf       1.24     //  sorted
 108                      //
 109                      for (Uint32 k = 0; k < n ; k++)
 110                          if (x[k].getType () == CIMKeyBinding::REFERENCE)
 111                          {
 112                              CIMObjectPath tmp (x[k].getValue ());
 113                              Array <CIMKeyBinding> keyBindings = tmp.getKeyBindings ();
 114                              _BubbleSort (keyBindings);
 115                              tmp.setKeyBindings (keyBindings);
 116                              x[k].setValue (tmp.toString ());
 117                          }
 118                  
 119 kumpf       1.2      if (n < 2)
 120                          return;
 121                  
 122                      for (Uint32 i = 0; i < n - 1; i++)
 123                      {
 124                          for (Uint32 j = 0; j < n - 1; j++)
 125                          {
 126 chip        1.47             if (String::compareNoCase(x[j].getName().getString(),
 127 kumpf       1.17                                       x[j+1].getName().getString()) > 0)
 128 kumpf       1.2              {
 129 kumpf       1.16                 CIMKeyBinding t = x[j];
 130 kumpf       1.2                  x[j] = x[j+1];
 131                                  x[j+1] = t;
 132                              }
 133                          }
 134                      }
 135                  }
 136                  
 137                  ////////////////////////////////////////////////////////////////////////////////
 138                  //
 139 kumpf       1.16 // CIMKeyBinding
 140 kumpf       1.2  //
 141                  ////////////////////////////////////////////////////////////////////////////////
 142                  
 143 kumpf       1.16 class CIMKeyBindingRep
 144 kumpf       1.2  {
 145                  public:
 146 kumpf       1.16     CIMKeyBindingRep()
 147 kumpf       1.2      {
 148                      }
 149                  
 150 kumpf       1.16     CIMKeyBindingRep(const CIMKeyBindingRep& x)
 151 kumpf       1.2          : _name(x._name), _value(x._value), _type(x._type)
 152                      {
 153                      }
 154                  
 155 kumpf       1.16     CIMKeyBindingRep(
 156 kumpf       1.7          const CIMName& name,
 157 kumpf       1.2          const String& value,
 158 kumpf       1.16         CIMKeyBinding::Type type)
 159 kumpf       1.2          : _name(name), _value(value), _type(type)
 160                      {
 161                      }
 162                  
 163 kumpf       1.16     ~CIMKeyBindingRep()
 164 kumpf       1.2      {
 165                      }
 166                  
 167 kumpf       1.16     CIMKeyBindingRep& operator=(const CIMKeyBindingRep& x)
 168 kumpf       1.2      {
 169                          if (&x != this)
 170                          {
 171                              _name = x._name;
 172                              _value = x._value;
 173                              _type = x._type;
 174                          }
 175                          return *this;
 176                      }
 177                  
 178 kumpf       1.7      CIMName _name;
 179 kumpf       1.2      String _value;
 180 kumpf       1.16     CIMKeyBinding::Type _type;
 181 kumpf       1.2  };
 182                  
 183                  
 184 a.arora     1.39 CIMKeyBinding::CIMKeyBinding()
 185 kumpf       1.2  {
 186 a.arora     1.39     _rep = new CIMKeyBindingRep();
 187 kumpf       1.2  }
 188                  
 189 a.arora     1.39 CIMKeyBinding::CIMKeyBinding(const CIMKeyBinding& x)
 190 kumpf       1.2  {
 191 a.arora     1.39     _rep = new CIMKeyBindingRep(*x._rep);
 192 kumpf       1.2  }
 193                  
 194 a.arora     1.39 CIMKeyBinding::CIMKeyBinding(const CIMName& name, const String& value, Type type)
 195 kumpf       1.2  {
 196 a.arora     1.39     _rep = new CIMKeyBindingRep(name, value, type);
 197 kumpf       1.2  }
 198                  
 199 kumpf       1.18 CIMKeyBinding::CIMKeyBinding(const CIMName& name, const CIMValue& value)
 200                  {
 201 kumpf       1.21     if (value.isArray())
 202 kumpf       1.20     {
 203                          throw TypeMismatchException();
 204                      }
 205                  
 206 kumpf       1.18     String kbValue = value.toString();
 207                      Type kbType;
 208                  
 209                      switch (value.getType())
 210                      {
 211                      case CIMTYPE_BOOLEAN:
 212                          kbType = BOOLEAN;
 213                          break;
 214                      case CIMTYPE_CHAR16:
 215                      case CIMTYPE_STRING:
 216                      case CIMTYPE_DATETIME:
 217                          kbType = STRING;
 218                          break;
 219                      case CIMTYPE_REFERENCE:
 220                          kbType = REFERENCE;
 221                          break;
 222 dave.sudlik 1.46 //  case CIMTYPE_REAL32:
 223                  //  case CIMTYPE_REAL64:
 224 dave.sudlik 1.44     case CIMTYPE_OBJECT:
 225 dave.sudlik 1.46         // From PEP 194: EmbeddedObjects cannot be keys.
 226 dave.sudlik 1.44         throw TypeMismatchException();
 227                          break;
 228 kumpf       1.18     default:
 229                          kbType = NUMERIC;
 230                          break;
 231                      }
 232                  
 233 a.arora     1.39     _rep = new CIMKeyBindingRep(name, kbValue, kbType);
 234 kumpf       1.18 }
 235                  
 236 kumpf       1.16 CIMKeyBinding::~CIMKeyBinding()
 237 kumpf       1.2  {
 238 a.arora     1.39     delete _rep;
 239 kumpf       1.2  }
 240                  
 241 kumpf       1.16 CIMKeyBinding& CIMKeyBinding::operator=(const CIMKeyBinding& x)
 242 kumpf       1.2  {
 243 a.arora     1.39     *_rep = *x._rep;
 244 kumpf       1.2      return *this;
 245                  }
 246                  
 247 kumpf       1.16 const CIMName& CIMKeyBinding::getName() const
 248 kumpf       1.2  {
 249                      return _rep->_name;
 250                  }
 251                  
 252 kumpf       1.16 void CIMKeyBinding::setName(const CIMName& name)
 253 kumpf       1.2  {
 254                      _rep->_name = name;
 255                  }
 256                  
 257 kumpf       1.16 const String& CIMKeyBinding::getValue() const
 258 kumpf       1.2  {
 259                      return _rep->_value;
 260                  }
 261                  
 262 kumpf       1.16 void CIMKeyBinding::setValue(const String& value)
 263 kumpf       1.2  {
 264                      _rep->_value = value;
 265                  }
 266                  
 267 kumpf       1.16 CIMKeyBinding::Type CIMKeyBinding::getType() const
 268 kumpf       1.2  {
 269                      return _rep->_type;
 270                  }
 271                  
 272 kumpf       1.16 void CIMKeyBinding::setType(CIMKeyBinding::Type type)
 273 kumpf       1.2  {
 274                      _rep->_type = type;
 275                  }
 276 kumpf       1.18 
 277                  Boolean CIMKeyBinding::equal(CIMValue value)
 278                  {
 279 kumpf       1.21     if (value.isArray())
 280 kumpf       1.20     {
 281                          return false;
 282                      }
 283                  
 284 kumpf       1.18     CIMValue kbValue;
 285                  
 286                      try
 287                      {
 288                          switch (value.getType())
 289                          {
 290                          case CIMTYPE_CHAR16:
 291 kumpf       1.20             if (getType() != STRING) return false;
 292 kumpf       1.18             kbValue.set(getValue()[0]);
 293                              break;
 294                          case CIMTYPE_DATETIME:
 295 kumpf       1.20             if (getType() != STRING) return false;
 296 kumpf       1.18             kbValue.set(CIMDateTime(getValue()));
 297                              break;
 298                          case CIMTYPE_STRING:
 299 kumpf       1.20             if (getType() != STRING) return false;
 300 kumpf       1.18             kbValue.set(getValue());
 301                              break;
 302                          case CIMTYPE_REFERENCE:
 303 kumpf       1.20             if (getType() != REFERENCE) return false;
 304 kumpf       1.18             kbValue.set(CIMObjectPath(getValue()));
 305                              break;
 306 kumpf       1.20         case CIMTYPE_BOOLEAN:
 307                              if (getType() != BOOLEAN) return false;
 308                              kbValue = XmlReader::stringToValue(0, getValue().getCString(),
 309                                                                 value.getType());
 310                              break;
 311 dave.sudlik 1.46 //      case CIMTYPE_REAL32:
 312                  //      case CIMTYPE_REAL64:
 313 dave.sudlik 1.44         case CIMTYPE_OBJECT:
 314 dave.sudlik 1.46             // From PEP 194: EmbeddedObjects cannot be keys.
 315 dave.sudlik 1.44             return false;
 316                              break;
 317 kumpf       1.20         default:  // Numerics
 318                              if (getType() != NUMERIC) return false;
 319 kumpf       1.18             kbValue = XmlReader::stringToValue(0, getValue().getCString(),
 320                                                                 value.getType());
 321                              break;
 322                          }
 323                      }
 324 kumpf       1.19     catch (Exception&)
 325 kumpf       1.18     {
 326                          return false;
 327                      }
 328                  
 329                      return value.equal(kbValue);
 330                  }
 331 kumpf       1.2  
 332 kumpf       1.16 Boolean operator==(const CIMKeyBinding& x, const CIMKeyBinding& y)
 333 kumpf       1.2  {
 334 kumpf       1.33     // Check that the names and types match
 335                      if (!(x.getName().equal(y.getName())) ||
 336                          !(x.getType() == y.getType()))
 337                      {
 338                          return false;
 339                      }
 340                  
 341                      switch (x.getType())
 342                      {
 343                      case CIMKeyBinding::REFERENCE:
 344                          try
 345                          {
 346                              // References should be compared as CIMObjectPaths
 347                              return (CIMObjectPath(x.getValue()) == CIMObjectPath(y.getValue()));
 348                          }
 349                          catch (Exception&)
 350                          {
 351                              // If CIMObjectPath parsing fails, just compare strings
 352                              return (String::equal(x.getValue(), y.getValue()));
 353                          }
 354                          break;
 355 kumpf       1.33     case CIMKeyBinding::BOOLEAN:
 356                          // Case-insensitive comparison is sufficient for booleans
 357                          return (String::equalNoCase(x.getValue(), y.getValue()));
 358                          break;
 359                      case CIMKeyBinding::NUMERIC:
 360                          // Note: This comparison assumes XML syntax for integers
 361                          // First try comparing as unsigned integers
 362                          {
 363                              Uint64 xValue;
 364                              Uint64 yValue;
 365                              if (XmlReader::stringToUnsignedInteger(
 366                                      x.getValue().getCString(), xValue) &&
 367                                  XmlReader::stringToUnsignedInteger(
 368                                      y.getValue().getCString(), yValue))
 369                              {
 370                                  return (xValue == yValue);
 371                              }
 372                          }
 373                          // Next try comparing as signed integers
 374                          {
 375                              Sint64 xValue;
 376 kumpf       1.33             Sint64 yValue;
 377                              if (XmlReader::stringToSignedInteger(
 378                                      x.getValue().getCString(), xValue) &&
 379                                  XmlReader::stringToSignedInteger(
 380                                      y.getValue().getCString(), yValue))
 381                              {
 382                                  return (xValue == yValue);
 383                              }
 384                          }
 385                          // Note: Keys may not be real values, so don't try comparing as reals
 386                          // We couldn't parse the numbers, so just compare the strings
 387                          return (String::equal(x.getValue(), y.getValue()));
 388                          break;
 389                      default:  // CIMKeyBinding::STRING
 390                          return (String::equal(x.getValue(), y.getValue()));
 391                          break;
 392                      }
 393                  
 394                      PEGASUS_UNREACHABLE(return false;)
 395 kumpf       1.2  }
 396                  
 397                  
 398                  ////////////////////////////////////////////////////////////////////////////////
 399                  //
 400                  // CIMObjectPath
 401                  //
 402                  ////////////////////////////////////////////////////////////////////////////////
 403                  
 404                  class CIMObjectPathRep
 405                  {
 406                  public:
 407                      CIMObjectPathRep()
 408                      {
 409                      }
 410                  
 411                      CIMObjectPathRep(const CIMObjectPathRep& x)
 412                          : _host(x._host), _nameSpace(x._nameSpace),
 413                          _className(x._className), _keyBindings(x._keyBindings)
 414                      {
 415                      }
 416 kumpf       1.2  
 417                      CIMObjectPathRep(
 418                          const String& host,
 419 kumpf       1.7          const CIMNamespaceName& nameSpace,
 420                          const CIMName& className,
 421 kumpf       1.16         const Array<CIMKeyBinding>& keyBindings)
 422 kumpf       1.2          : _host(host), _nameSpace(nameSpace),
 423                          _className(className), _keyBindings(keyBindings)
 424                      {
 425                      }
 426                  
 427                      ~CIMObjectPathRep()
 428                      {
 429                      }
 430                  
 431                      CIMObjectPathRep& operator=(const CIMObjectPathRep& x)
 432                      {
 433                          if (&x != this)
 434                          {
 435                              _host = x._host;
 436                              _nameSpace = x._nameSpace;
 437                              _className = x._className;
 438                              _keyBindings = x._keyBindings;
 439                          }
 440                          return *this;
 441                      }
 442                  
 443 kumpf       1.34     static Boolean isValidHostname(const String& hostname)
 444                      {
 445                          //------------------------------------------------------------------
 446                          // Validate the hostname.  The hostname value may or may not be a
 447                          // fully-qualified domain name (e.g., xyz.company.com) or may be an
 448                          // IP address.  A port number may follow the hostname.
 449                          // Hostnames must match one of the following regular expressions:
 450 dave.sudlik 1.42         // ^([A-Za-z0-9][A-Za-z0-9-]*)(\.[A-Za-z][A-Za-z0-9-]*)*(:[0-9]*)?$
 451 kumpf       1.34         // ^([0-9]*\.[0-9]*\.[0-9]*\.[0-9]*)(:[0-9]*)?$
 452 dave.sudlik 1.42         // Note for Bug#1462. Be careful here, from RFC 1123:
 453 chip        1.47         // - The syntax of a legal Internet host name was specified in
 454                          //   RFC-952 [DNS:4]. One aspect of host name syntax is hereby
 455                          //   changed: the restriction on the first character is relaxed to
 456                          //   allow either a letter or a digit.
 457 dave.sudlik 1.42         // - If a dotted-decimal number can be entered without identifying
 458                          //   delimiters, then a full syntactic check must be made, because
 459                          //   a segment of a host domain name is now allowed to begin with a
 460                          //   digit and could legally be entirely numeric (see Section 6.1.2.4).
 461                          //   However, a valid host name can never have the dotted-decimal form
 462                          //   #.#.#.#, since at least the highest-level component label will be
 463 chip        1.47         //   alphabetic.
 464 dave.sudlik 1.42         // The algorithm below has been updated accordingly.
 465 kumpf       1.34         //------------------------------------------------------------------
 466                  
 467                          Uint32 i = 0;
 468                  
 469 dave.sudlik 1.42         Boolean isValid = false;
 470                  
 471 david.dillard 1.50         if (isdigit(hostname[0]))
 472 kumpf         1.34         {
 473 dave.sudlik   1.42             //--------------------------------------------------------------
 474 chip          1.47             // Attempt to validate an IP address, but keep in mind that it
 475 dave.sudlik   1.42             // might be a host name, since the leading character can now be
 476                                // a digit.
 477                                //--------------------------------------------------------------
 478                                isValid = true;
 479 kumpf         1.34 
 480                                for (Uint32 octet=1; octet<=4; octet++)
 481                                {
 482                                    Uint32 octetValue = 0;
 483                    
 484 dave.sudlik   1.42                 //----------------------------------------------------------
 485                                    // If a non-digit is encountered in the input parameter,
 486                                    // then break from here and attempt to validate as host name.
 487                                    //----------------------------------------------------------
 488 david.dillard 1.50                 if (!isdigit(hostname[i]))
 489 kumpf         1.34                 {
 490 dave.sudlik   1.42                     isValid = false;
 491                                        break;
 492 kumpf         1.34                 }
 493                    
 494 david.dillard 1.50                 while (isdigit(hostname[i]))  // skip over digits
 495 kumpf         1.34                 {
 496                                        octetValue = octetValue*10 + (hostname[i] - '0');
 497                                        i++;
 498                                    }
 499                    
 500                                    if (octetValue > 255)
 501                                    {
 502 dave.sudlik   1.42                     isValid = false;
 503                                        break;
 504 kumpf         1.34                 }
 505                    
 506 dave.sudlik   1.42                 // Check for invalid character in IP address
 507 kumpf         1.34                 if ((octet != 4) && (hostname[i++] != '.'))
 508                                    {
 509 dave.sudlik   1.42                     isValid = false;
 510                                        break;
 511                                    }
 512                    
 513                                    // Check for the case where it's a valid host name that happens
 514                                    // to have 4 (or more) leading all-numeric host segments.
 515                                    if ((octet == 4) && (hostname[i] != ':') && hostname[i] != char(0))
 516                                    {
 517                                        isValid = false;
 518                                        break;
 519 kumpf         1.34                 }
 520                                }
 521                            }
 522 dave.sudlik   1.42         if (!isValid)   // if it is not a valid IP address
 523 kumpf         1.34         {
 524 dave.sudlik   1.42             i = 0;  // reset index for host name check
 525                    
 526                                // Validate a host name
 527                                isValid = true;
 528 kumpf         1.34 
 529                                Boolean expectHostSegment = true;
 530 dave.sudlik   1.42             Boolean hostSegmentIsNumeric;
 531 kumpf         1.34 
 532                                while (expectHostSegment == true)
 533                                {
 534                                    expectHostSegment = false;
 535 dave.sudlik   1.42                 hostSegmentIsNumeric = true; // assume all-numeric host segment
 536 kumpf         1.34 
 537 david.dillard 1.50                 if (!isalnum(hostname[i]))
 538 kumpf         1.34                 {
 539                                        return false;
 540                                    }
 541                    
 542 vijay.eli     1.51                 while (isalnum(hostname[i]) || (hostname[i] == '-') ||
 543                                                                   (hostname[i] == '_'))
 544 kumpf         1.34                 {
 545 dave.sudlik   1.42                     // If a non-digit is encountered, set "all-numeric"
 546                                        // flag to false
 547 vijay.eli     1.51                     if (isalpha(hostname[i]) || (hostname[i] == '-') ||
 548                                                                    (hostname[i] == '_')) {
 549 dave.sudlik   1.42                         hostSegmentIsNumeric = false;
 550                                        }
 551 kumpf         1.34                     i++;
 552                                    }
 553                    
 554                                    if (hostname[i] == '.')
 555                                    {
 556                                        i++;
 557                                        expectHostSegment = true;
 558                                    }
 559                                }
 560 dave.sudlik   1.42             // If the last Host Segment is all numeric, then return false.
 561                                // RFC 1123 says "highest-level component label will be alphabetic".
 562                                if (hostSegmentIsNumeric) {
 563                                    return false;
 564                                }
 565                            }
 566                    
 567                            if (!isValid) // if not a valid IP address or host name
 568                            {
 569                                return false;
 570 kumpf         1.34         }
 571                    
 572                            // Check for a port number:
 573                    
 574                            if (hostname[i] == ':')
 575                            {
 576 david.dillard 1.50             if (!isdigit(hostname[++i]))
 577 kumpf         1.34             {
 578                                    return false;
 579                                }
 580 chip          1.47 
 581 david.dillard 1.50             while (isdigit(hostname[++i]));
 582 kumpf         1.34         }
 583                    
 584                            return (hostname[i] == char(0));
 585                        }
 586                    
 587 kumpf         1.2      //
 588                        // Contains port as well (e.g., myhost:1234).
 589                        //
 590                        String _host;
 591                    
 592 kumpf         1.7      CIMNamespaceName _nameSpace;
 593                        CIMName _className;
 594 kumpf         1.16     Array<CIMKeyBinding> _keyBindings;
 595 kumpf         1.2  };
 596                    
 597                    
 598 a.arora       1.39 CIMObjectPath::CIMObjectPath()
 599 kumpf         1.2  {
 600 a.arora       1.39     _rep = new CIMObjectPathRep();
 601 kumpf         1.2  }
 602                    
 603 a.arora       1.39 CIMObjectPath::CIMObjectPath(const CIMObjectPath& x)
 604 kumpf         1.2  {
 605 a.arora       1.39     _rep = new CIMObjectPathRep(*x._rep);
 606 kumpf         1.2  }
 607                    
 608                    CIMObjectPath::CIMObjectPath(const String& objectName)
 609                    {
 610                        // Test the objectName out to see if we get an exception
 611                        CIMObjectPath tmpRef;
 612                        tmpRef.set(objectName);
 613                    
 614 a.arora       1.39     _rep = new CIMObjectPathRep(*tmpRef._rep);
 615 kumpf         1.2  }
 616                    
 617                    CIMObjectPath::CIMObjectPath(
 618                        const String& host,
 619 kumpf         1.7      const CIMNamespaceName& nameSpace,
 620                        const CIMName& className,
 621 kumpf         1.16     const Array<CIMKeyBinding>& keyBindings)
 622 kumpf         1.2  {
 623                        // Test the objectName out to see if we get an exception
 624                        CIMObjectPath tmpRef;
 625                        tmpRef.set(host, nameSpace, className, keyBindings);
 626                    
 627 a.arora       1.39     _rep = new CIMObjectPathRep(*tmpRef._rep);
 628 kumpf         1.2  }
 629                    
 630                    CIMObjectPath::~CIMObjectPath()
 631                    {
 632 a.arora       1.39     delete _rep;
 633 kumpf         1.2  }
 634                    
 635                    CIMObjectPath& CIMObjectPath::operator=(const CIMObjectPath& x)
 636                    {
 637 a.arora       1.39     *_rep = *x._rep;
 638 kumpf         1.2      return *this;
 639                    }
 640                    
 641                    void CIMObjectPath::clear()
 642                    {
 643                        _rep->_host.clear();
 644                        _rep->_nameSpace.clear();
 645                        _rep->_className.clear();
 646                        _rep->_keyBindings.clear();
 647                    }
 648                    
 649                    void CIMObjectPath::set(
 650                        const String& host,
 651 kumpf         1.7      const CIMNamespaceName& nameSpace,
 652                        const CIMName& className,
 653 kumpf         1.16     const Array<CIMKeyBinding>& keyBindings)
 654 kumpf         1.2  {
 655                       setHost(host);
 656                       setNameSpace(nameSpace);
 657                       setClassName(className);
 658                       setKeyBindings(keyBindings);
 659                    }
 660                    
 661 kumpf         1.22 Boolean _parseHostElement(
 662 kumpf         1.2      const String& objectName,
 663                        char*& p,
 664 kumpf         1.9      String& host)
 665 kumpf         1.2  {
 666                        // See if there is a host name (true if it begins with "//"):
 667 kumpf         1.32     // Host is of the form <hostname>:<port> and begins with "//"
 668 kumpf         1.2      // and ends with "/":
 669                    
 670                        if (p[0] != '/' || p[1] != '/')
 671                        {
 672                            return false;
 673                        }
 674                    
 675                        p += 2;
 676                    
 677 kumpf         1.34     char* slash = strchr(p, '/');
 678                        if (!slash)
 679 chuck         1.23     {
 680 kumpf         1.34         throw MalformedObjectNameException(objectName);
 681 kumpf         1.2      }
 682                    
 683 kumpf         1.34     String hostname = String(p, (Uint32)(slash - p));
 684                        if (!CIMObjectPathRep::isValidHostname(hostname))
 685 kumpf         1.2      {
 686 kumpf         1.10         throw MalformedObjectNameException(objectName);
 687 kumpf         1.2      }
 688 kumpf         1.34     host = hostname;
 689 kumpf         1.2  
 690 kumpf         1.31     // Do not step past the '/'; it will be consumed by the namespace parser
 691 kumpf         1.34     p = slash;
 692 kumpf         1.2  
 693                        return true;
 694                    }
 695                    
 696 kumpf         1.22 Boolean _parseNamespaceElement(
 697 kumpf         1.2      const String& objectName,
 698                        char*& p,
 699 kumpf         1.7      CIMNamespaceName& nameSpace)
 700 kumpf         1.2  {
 701                        // If we don't find a valid namespace name followed by a ':', we
 702                        // assume we're not looking at a namespace name.
 703                    
 704 kumpf         1.7      char* colon = strchr(p, ':');
 705                        if (!colon)
 706                        {
 707                            return false;
 708                        }
 709                    
 710 chip          1.47     // A ':' as part of a keybinding value should not be interpreted as
 711 kumpf         1.25     // a namespace delimiter.  Since keybinding pairs follow the first '.'
 712                        // in the object path string, the ':' delimiter only counts if it
 713                        // appears before the '.'.
 714                    
 715                        char* dot = strchr(p, '.');
 716                        if (dot && (dot < colon))
 717                        {
 718                            return false;
 719                        }
 720                    
 721 kumpf         1.2      //----------------------------------------------------------------------
 722                        // Validate the namespace path.  Namespaces must match the following
 723                        // regular expression: "[A-Za-z_]+(/[A-Za-z_]+)*"
 724                        //----------------------------------------------------------------------
 725                    
 726 david         1.27     String namespaceName = String(p, (Uint32)(colon - p));
 727 kumpf         1.7      if (!CIMNamespaceName::legal(namespaceName))
 728 kumpf         1.2      {
 729 kumpf         1.10         throw MalformedObjectNameException(objectName);
 730 kumpf         1.2      }
 731 kumpf         1.7      nameSpace = namespaceName;
 732 kumpf         1.2  
 733 kumpf         1.7      p = colon+1;
 734 kumpf         1.2      return true;
 735                    }
 736                    
 737                    /**
 738 kumpf         1.29     ATTN-RK: The DMTF specification for the string form of an
 739                        object path makes it impossible for a parser to distinguish
 740                        between a key values of String type and Reference type.
 741                    
 742                        Given the ambiguity, this implementation takes a guess at the
 743                        type of a quoted key value.  If the value can be parsed into
 744                        a CIMObjectPath with at least one key binding, the type is
 745                        set to REFERENCE.  Otherwise, the type is set to STRING.
 746                        Note: This algorithm appears to be in line with what the Sun
 747                        WBEM Services implementation does.
 748                    
 749                        To be totally correct, it would be necessary to retrieve the
 750                        class definition and look up the types of the key properties
 751                        to determine how to interpret the key values.  This is clearly
 752                        too inefficient for internal transformations between
 753                        CIMObjectPaths and String values.
 754 kumpf         1.2  */
 755 kumpf         1.22 void _parseKeyBindingPairs(
 756 kumpf         1.2      const String& objectName,
 757                        char*& p,
 758 chip          1.47     Array<CIMKeyBinding>& keyBindings)
 759 kumpf         1.2  {
 760                        // Get the key-value pairs:
 761                    
 762                        while (*p)
 763                        {
 764                            // Get key part:
 765                    
 766 kumpf         1.5          char* equalsign = strchr(p, '=');
 767                            if (!equalsign)
 768 kumpf         1.2          {
 769 kumpf         1.10             throw MalformedObjectNameException(objectName);
 770 kumpf         1.2          }
 771                    
 772 kumpf         1.5          *equalsign = 0;
 773 kumpf         1.2  
 774 kumpf         1.17         if (!CIMName::legal(p))
 775 kumpf         1.10             throw MalformedObjectNameException(objectName);
 776 kumpf         1.2  
 777 kumpf         1.17         CIMName keyName (p);
 778                    
 779 kumpf         1.2          // Get the value part:
 780                    
 781                            String valueString;
 782 kumpf         1.5          p = equalsign + 1;
 783 kumpf         1.16         CIMKeyBinding::Type type;
 784 kumpf         1.2  
 785 kumpf         1.29         if (*p == '"')
 786 kumpf         1.2          {
 787 kumpf         1.29             // Could be CIMKeyBinding::STRING or CIMKeyBinding::REFERENCE
 788                    
 789 kumpf         1.2              p++;
 790                    
 791                                while (*p && *p != '"')
 792                                {
 793                                    if (*p == '\\')
 794 kumpf         1.28                 {
 795 kumpf         1.2                      *p++;
 796                    
 797 kumpf         1.28                     if ((*p != '\\') && (*p != '"'))
 798                                        {
 799                                            throw MalformedObjectNameException(objectName);
 800                                        }
 801                                    }
 802                    
 803 kumpf         1.2                  valueString.append(*p++);
 804                                }
 805                    
 806                                if (*p++ != '"')
 807 kumpf         1.10                 throw MalformedObjectNameException(objectName);
 808 kumpf         1.2  
 809 kumpf         1.29             /*
 810                                    Guess at the type of this quoted key value.  If the value
 811                                    can be parsed into a CIMObjectPath with at least one key
 812                                    binding, the type is assumed to be a REFERENCE.  Otherwise,
 813                                    the type is set to STRING.  (See method header for details.)
 814                                 */
 815 kumpf         1.16             type = CIMKeyBinding::STRING;
 816 kumpf         1.2  
 817 kumpf         1.29             try
 818 kumpf         1.2              {
 819 kumpf         1.29                 CIMObjectPath testForPath(valueString);
 820                                    if (testForPath.getKeyBindings().size() > 0)
 821 kumpf         1.28                 {
 822 kumpf         1.29                     // We've found a reference value!
 823                                        type = CIMKeyBinding::REFERENCE;
 824 kumpf         1.28                 }
 825 kumpf         1.2              }
 826 david.dillard 1.41             catch (const Exception &)
 827 kumpf         1.29             {
 828                                    // Not a reference value; leave type as STRING
 829                                }
 830 kumpf         1.2          }
 831                            else if (toupper(*p) == 'T' || toupper(*p) == 'F')
 832                            {
 833 kumpf         1.16             type = CIMKeyBinding::BOOLEAN;
 834 kumpf         1.2  
 835                                char* r = p;
 836                                Uint32 n = 0;
 837                    
 838                                while (*r && *r != ',')
 839                                {
 840                                    *r = toupper(*r);
 841                                    r++;
 842                                    n++;
 843                                }
 844                    
 845                                if (!(((strncmp(p, "TRUE", n) == 0) && n == 4) ||
 846                                      ((strncmp(p, "FALSE", n) == 0) && n == 5)))
 847 kumpf         1.10                 throw MalformedObjectNameException(objectName);
 848 kumpf         1.2  
 849                                valueString.assign(p, n);
 850                    
 851                                p = p + n;
 852                            }
 853                            else
 854                            {
 855 kumpf         1.16             type = CIMKeyBinding::NUMERIC;
 856 kumpf         1.2  
 857                                char* r = p;
 858                                Uint32 n = 0;
 859                    
 860                                while (*r && *r != ',')
 861                                {
 862                                    r++;
 863                                    n++;
 864                                }
 865                    
 866                                Boolean isComma = false;
 867                                if (*r)
 868                                {
 869                                    *r = '\0';
 870                                    isComma = true;
 871                                }
 872                    
 873                                Sint64 x;
 874                    
 875                                if (!XmlReader::stringToSignedInteger(p, x))
 876 kumpf         1.10                 throw MalformedObjectNameException(objectName);
 877 kumpf         1.2  
 878                                valueString.assign(p, n);
 879                    
 880                                if (isComma)
 881                                {
 882                                    *r = ',';
 883                                }
 884                    
 885                                p = p + n;
 886                            }
 887                    
 888 chip          1.47         keyBindings.append(CIMKeyBinding(keyName.getString (), valueString,
 889 kumpf         1.17             type));
 890 kumpf         1.2  
 891                            if (*p)
 892                            {
 893                                if (*p++ != ',')
 894                                {
 895 kumpf         1.10                 throw MalformedObjectNameException(objectName);
 896 kumpf         1.2              }
 897                            }
 898                        }
 899                    
 900                        _BubbleSort(keyBindings);
 901                    }
 902                    
 903 chip          1.47 void CIMObjectPath::set(const String& objectName)
 904 kumpf         1.2  {
 905                        clear();
 906                    
 907                        //--------------------------------------------------------------------------
 908                        // We will extract components from an object name. Here is an sample
 909                        // object name:
 910                        //
 911                        //     //atp:9999/root/cimv25:TennisPlayer.first="Patrick",last="Rafter"
 912                        //--------------------------------------------------------------------------
 913                    
 914                        // Convert to a C String first:
 915                    
 916 david         1.37     CString pCString = objectName.getCString();
 917 kumpf         1.26     char* p = const_cast<char*>((const char*) pCString);
 918 kumpf         1.2      Boolean gotHost;
 919                        Boolean gotNamespace;
 920                    
 921                        gotHost = _parseHostElement(objectName, p, _rep->_host);
 922                        gotNamespace = _parseNamespaceElement(objectName, p, _rep->_nameSpace);
 923                    
 924                        if (gotHost && !gotNamespace)
 925                        {
 926 kumpf         1.10         throw MalformedObjectNameException(objectName);
 927 kumpf         1.2      }
 928                    
 929                        // Extract the class name:
 930                    
 931                        char* dot = strchr(p, '.');
 932                    
 933                        if (!dot)
 934                        {
 935                            if (!CIMName::legal(p))
 936                            {
 937 kumpf         1.10             throw MalformedObjectNameException(objectName);
 938 kumpf         1.2          }
 939                    
 940                            // ATTN: remove this later: a reference should only be able to hold
 941                            // an instance name.
 942                    
 943 kumpf         1.17         _rep->_className = CIMName (p);
 944 kumpf         1.2          return;
 945                        }
 946                    
 947 david         1.27     String className = String(p, (Uint32)(dot - p));
 948 kumpf         1.7      if (!CIMName::legal(className))
 949                        {
 950 kumpf         1.10         throw MalformedObjectNameException(objectName);
 951 kumpf         1.7      }
 952                        _rep->_className = className;
 953 kumpf         1.2  
 954                        // Advance past dot:
 955                    
 956                        p = dot + 1;
 957                    
 958                        _parseKeyBindingPairs(objectName, p, _rep->_keyBindings);
 959                    }
 960                    
 961                    CIMObjectPath& CIMObjectPath::operator=(const String& objectName)
 962                    {
 963                        set(objectName);
 964                        return *this;
 965                    }
 966                    
 967                    const String& CIMObjectPath::getHost() const
 968                    {
 969                        return _rep->_host;
 970                    }
 971                    
 972                    void CIMObjectPath::setHost(const String& host)
 973                    {
 974 kumpf         1.35     if ((host != String::EMPTY) && !CIMObjectPathRep::isValidHostname(host))
 975                        {
 976                            throw MalformedObjectNameException(host);
 977                        }
 978                    
 979 kumpf         1.2      _rep->_host = host;
 980                    }
 981                    
 982 kumpf         1.7  const CIMNamespaceName& CIMObjectPath::getNameSpace() const
 983 kumpf         1.2  {
 984                        return _rep->_nameSpace;
 985                    }
 986                    
 987 kumpf         1.7  void CIMObjectPath::setNameSpace(const CIMNamespaceName& nameSpace)
 988 kumpf         1.2  {
 989                       _rep->_nameSpace = nameSpace;
 990                    }
 991                    
 992 kumpf         1.7  const CIMName& CIMObjectPath::getClassName() const
 993 kumpf         1.2  {
 994                        return _rep->_className;
 995                    }
 996                    
 997 kumpf         1.7  void CIMObjectPath::setClassName(const CIMName& className)
 998 kumpf         1.2  {
 999                        _rep->_className = className;
1000                    }
1001                    
1002 kumpf         1.16 const Array<CIMKeyBinding>& CIMObjectPath::getKeyBindings() const
1003 kumpf         1.2  {
1004                        return _rep->_keyBindings;
1005                    }
1006                    
1007 kumpf         1.16 void CIMObjectPath::setKeyBindings(const Array<CIMKeyBinding>& keyBindings)
1008 kumpf         1.2  {
1009                        _rep->_keyBindings = keyBindings;
1010                        _BubbleSort(_rep->_keyBindings);
1011                    }
1012                    
1013 kumpf         1.15 String CIMObjectPath::toString() const
1014 kumpf         1.2  {
1015                        String objectName;
1016                    
1017                        // Get the host:
1018                    
1019 kumpf         1.15     if (_rep->_host.size())
1020 kumpf         1.2      {
1021                            objectName = "//";
1022 kumpf         1.13         objectName.append(_rep->_host);
1023                            objectName.append("/");
1024 kumpf         1.2      }
1025                    
1026                        // Get the namespace (if we have a host name, we must write namespace):
1027                    
1028 kumpf         1.7      if (!_rep->_nameSpace.isNull() || _rep->_host.size())
1029 kumpf         1.2      {
1030 kumpf         1.17         objectName.append(_rep->_nameSpace.getString ());
1031 kumpf         1.13         objectName.append(":");
1032 kumpf         1.2      }
1033                    
1034                        // Get the class name:
1035                    
1036 kumpf         1.17     objectName.append(getClassName().getString ());
1037 kumpf         1.2  
1038 kumpf         1.9      //
1039                        //  ATTN-CAKG-P2-20020726:  The following condition does not correctly
1040                        //  distinguish instanceNames from classNames in every case
1041                        //  The instanceName of a singleton instance of a keyless class has no
1042                        //  key bindings
1043                        //
1044                        if (_rep->_keyBindings.size () != 0)
1045 kumpf         1.2      {
1046                            objectName.append('.');
1047                    
1048                            // Append each key-value pair:
1049                    
1050 kumpf         1.16         const Array<CIMKeyBinding>& keyBindings = getKeyBindings();
1051 kumpf         1.2  
1052                            for (Uint32 i = 0, n = keyBindings.size(); i < n; i++)
1053                            {
1054 kumpf         1.17             objectName.append(keyBindings[i].getName().getString ());
1055 kumpf         1.2              objectName.append('=');
1056                    
1057                                const String& value = _escapeSpecialCharacters(
1058                                    keyBindings[i].getValue());
1059                    
1060 kumpf         1.16             CIMKeyBinding::Type type = keyBindings[i].getType();
1061 chip          1.47 
1062 kumpf         1.16             if (type == CIMKeyBinding::STRING || type == CIMKeyBinding::REFERENCE)
1063 kumpf         1.2                  objectName.append('"');
1064                    
1065                                objectName.append(value);
1066                    
1067 kumpf         1.16             if (type == CIMKeyBinding::STRING || type == CIMKeyBinding::REFERENCE)
1068 kumpf         1.2                  objectName.append('"');
1069                    
1070                                if (i + 1 != n)
1071                                    objectName.append(',');
1072                            }
1073                        }
1074                    
1075                        return objectName;
1076                    }
1077                    
1078 kumpf         1.15 String CIMObjectPath::_toStringCanonical() const
1079 kumpf         1.2  {
1080                        CIMObjectPath ref = *this;
1081                    
1082 kumpf         1.33     // Normalize hostname by changing to lower case
1083 chip          1.47     ref._rep->_host.toLower(); // ICU_TODO:
1084 kumpf         1.2  
1085 kumpf         1.33     // Normalize namespace by changing to lower case
1086                        if (!ref._rep->_nameSpace.isNull())
1087                        {
1088                            String nameSpaceLower = ref._rep->_nameSpace.getString();
1089 chip          1.47         nameSpaceLower.toLower(); // ICU_TODO:
1090 kumpf         1.33         ref._rep->_nameSpace = nameSpaceLower;
1091                        }
1092                    
1093                        // Normalize class name by changing to lower case
1094                        if (!ref._rep->_className.isNull())
1095                        {
1096                            String classNameLower = ref._rep->_className.getString();
1097 chip          1.47         classNameLower.toLower(); // ICU_TODO:
1098 kumpf         1.33         ref._rep->_className = classNameLower;
1099                        }
1100 kumpf         1.2  
1101                        for (Uint32 i = 0, n = ref._rep->_keyBindings.size(); i < n; i++)
1102                        {
1103 kumpf         1.33         // Normalize key binding name by changing to lower case
1104                            if (!ref._rep->_keyBindings[i]._rep->_name.isNull())
1105                            {
1106 chip          1.47             String keyBindingNameLower =
1107 kumpf         1.33                 ref._rep->_keyBindings[i]._rep->_name.getString();
1108                                keyBindingNameLower.toLower(); // ICU_TODO:
1109                                ref._rep->_keyBindings[i]._rep->_name = keyBindingNameLower;
1110                            }
1111                    
1112                            // Normalize the key value
1113                            switch (ref._rep->_keyBindings[i]._rep->_type)
1114                            {
1115                            case CIMKeyBinding::REFERENCE:
1116                                try
1117                                {
1118                                    // Convert reference to CIMObjectPath and recurse
1119                                    ref._rep->_keyBindings[i]._rep->_value =
1120                                        CIMObjectPath(ref._rep->_keyBindings[i]._rep->_value).
1121                                            _toStringCanonical();
1122                                }
1123                                catch (Exception&)
1124                                {
1125                                    // Leave value unchanged if the CIMObjectPath parsing fails
1126                                }
1127                                break;
1128 kumpf         1.33         case CIMKeyBinding::BOOLEAN:
1129                                // Normalize the boolean string by changing to lower case
1130                                ref._rep->_keyBindings[i]._rep->_value.toLower(); // ICU_TODO:
1131                                break;
1132                            case CIMKeyBinding::NUMERIC:
1133                                // Normalize the numeric string by converting to integer and back
1134                                Uint64 uValue;
1135                                Sint64 sValue;
1136                                // First try converting to unsigned integer
1137                                if (XmlReader::stringToUnsignedInteger(
1138                                        ref._rep->_keyBindings[i]._rep->_value.getCString(),
1139                                            uValue))
1140                                {
1141                                    char buffer[32];  // Should need 21 chars max
1142                                    sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "u", uValue);
1143                                    ref._rep->_keyBindings[i]._rep->_value = String(buffer);
1144                                }
1145                                // Next try converting to signed integer
1146                                else if (XmlReader::stringToSignedInteger(
1147                                             ref._rep->_keyBindings[i]._rep->_value.getCString(),
1148                                                 sValue))
1149 kumpf         1.33             {
1150                                    char buffer[32];  // Should need 21 chars max
1151                                    sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "d", sValue);
1152                                    ref._rep->_keyBindings[i]._rep->_value = String(buffer);
1153                                }
1154                                // Leave value unchanged if it cannot be converted to an integer
1155                                break;
1156                            default:  // CIMKeyBinding::STRING
1157                                // No normalization required for STRING
1158                                break;
1159                            }
1160 kumpf         1.2      }
1161                    
1162 kumpf         1.33     // Note: key bindings are sorted when set in the CIMObjectPath
1163 kumpf         1.12 
1164 kumpf         1.15     return ref.toString();
1165 kumpf         1.2  }
1166                    
1167                    Boolean CIMObjectPath::identical(const CIMObjectPath& x) const
1168                    {
1169                        return
1170 kumpf         1.33         String::equalNoCase(_rep->_host, x._rep->_host) &&
1171 kumpf         1.7          _rep->_nameSpace.equal(x._rep->_nameSpace) &&
1172                            _rep->_className.equal(x._rep->_className) &&
1173 kumpf         1.2          _rep->_keyBindings == x._rep->_keyBindings;
1174                    }
1175                    
1176                    Uint32 CIMObjectPath::makeHashCode() const
1177                    {
1178 kumpf         1.12     return HashFunc<String>::hash(_toStringCanonical());
1179 kumpf         1.2  }
1180                    
1181                    Boolean operator==(const CIMObjectPath& x, const CIMObjectPath& y)
1182                    {
1183                        return x.identical(y);
1184                    }
1185                    
1186                    Boolean operator!=(const CIMObjectPath& x, const CIMObjectPath& y)
1187                    {
1188                        return !operator==(x, y);
1189                    }
1190                    
1191 chip          1.1  PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2