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