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