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