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 rishika.kedia 1.59 Uint32 octetValue = 0, j = 0;
|
486 kumpf 1.34
|
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 rishika.kedia 1.59 if (j == 3)
501 {
502 isValid = false;
503 break;
504 }
|
505 kumpf 1.34 octetValue = octetValue*10 + (hostname[i] - '0');
506 i++;
|
507 rishika.kedia 1.59 j++;
|
508 kumpf 1.34 }
509
510 if (octetValue > 255)
511 {
|
512 dave.sudlik 1.42 isValid = false;
513 break;
|
514 kumpf 1.34 }
515
|
516 dave.sudlik 1.42 // Check for invalid character in IP address
|
517 kumpf 1.34 if ((octet != 4) && (hostname[i++] != '.'))
518 {
|
519 dave.sudlik 1.42 isValid = false;
520 break;
521 }
522
523 // Check for the case where it's a valid host name that happens
524 // to have 4 (or more) leading all-numeric host segments.
|
525 kumpf 1.57 if ((octet == 4) && (hostname[i] != ':') &&
526 hostname[i] != char(0))
|
527 dave.sudlik 1.42 {
528 isValid = false;
529 break;
|
530 kumpf 1.34 }
531 }
532 }
|
533 dave.sudlik 1.42 if (!isValid) // if it is not a valid IP address
|
534 kumpf 1.34 {
|
535 dave.sudlik 1.42 i = 0; // reset index for host name check
536
537 // Validate a host name
538 isValid = true;
|
539 kumpf 1.34
540 Boolean expectHostSegment = true;
|
541 dave.sudlik 1.42 Boolean hostSegmentIsNumeric;
|
542 kumpf 1.34
543 while (expectHostSegment == true)
544 {
545 expectHostSegment = false;
|
546 dave.sudlik 1.42 hostSegmentIsNumeric = true; // assume all-numeric host segment
|
547 kumpf 1.34
|
548 kumpf 1.53 if (!(isascii(hostname[i]) &&
549 (isalnum(hostname[i]) || (hostname[i] == '_'))))
|
550 kumpf 1.34 {
551 return false;
552 }
553
|
554 kumpf 1.52 while (isascii(hostname[i]) &&
555 (isalnum(hostname[i]) || (hostname[i] == '-') ||
556 (hostname[i] == '_')))
|
557 kumpf 1.34 {
|
558 dave.sudlik 1.42 // If a non-digit is encountered, set "all-numeric"
559 // flag to false
|
560 vijay.eli 1.51 if (isalpha(hostname[i]) || (hostname[i] == '-') ||
|
561 kumpf 1.58 (hostname[i] == '_'))
562 {
|
563 dave.sudlik 1.42 hostSegmentIsNumeric = false;
564 }
|
565 kumpf 1.34 i++;
566 }
567
568 if (hostname[i] == '.')
569 {
570 i++;
571 expectHostSegment = true;
572 }
573 }
|
574 dave.sudlik 1.42 // If the last Host Segment is all numeric, then return false.
575 // RFC 1123 says "highest-level component label will be alphabetic".
|
576 kumpf 1.58 if (hostSegmentIsNumeric)
577 {
|
578 dave.sudlik 1.42 return false;
579 }
580 }
581
582 if (!isValid) // if not a valid IP address or host name
583 {
584 return false;
|
585 kumpf 1.34 }
586
587 // Check for a port number:
588
589 if (hostname[i] == ':')
590 {
|
591 kumpf 1.52 i++;
|
592 dave.sudlik 1.60 // First check that there is at least one digit specified for the
593 // port number if the ':' delimiter is present. Note that there is
594 // a question as to whether ':' can exist without the port number.
595 // ATTN: See bug 6424.
|
596 kumpf 1.52 if (!(isascii(hostname[i]) && isdigit(hostname[i])))
|
597 kumpf 1.34 {
598 return false;
599 }
|
600 dave.sudlik 1.60
601 Uint32 port = (hostname[i] - '0');
|
602 kumpf 1.52 i++;
|
603 chip 1.47
|
604 dave.sudlik 1.60 // Check that remaining characters in port number are all digits,
605 // and that the port number can be represented by 16-bits.
|
606 kumpf 1.52 while (isascii(hostname[i]) && isdigit(hostname[i]))
607 {
|
608 dave.sudlik 1.60 port = port*10 + (hostname[i] - '0');
609 if(port > 65535)
610 {
611 return false;
612 }
|
613 kumpf 1.52 i++;
614 }
|
615 kumpf 1.34 }
616
617 return (hostname[i] == char(0));
618 }
619
|
620 kumpf 1.2 //
621 // Contains port as well (e.g., myhost:1234).
622 //
623 String _host;
624
|
625 kumpf 1.7 CIMNamespaceName _nameSpace;
626 CIMName _className;
|
627 kumpf 1.16 Array<CIMKeyBinding> _keyBindings;
|
628 kumpf 1.2 };
629
630
|
631 a.arora 1.39 CIMObjectPath::CIMObjectPath()
|
632 kumpf 1.2 {
|
633 a.arora 1.39 _rep = new CIMObjectPathRep();
|
634 kumpf 1.2 }
635
|
636 a.arora 1.39 CIMObjectPath::CIMObjectPath(const CIMObjectPath& x)
|
637 kumpf 1.2 {
|
638 a.arora 1.39 _rep = new CIMObjectPathRep(*x._rep);
|
639 kumpf 1.2 }
640
641 CIMObjectPath::CIMObjectPath(const String& objectName)
642 {
643 // Test the objectName out to see if we get an exception
644 CIMObjectPath tmpRef;
645 tmpRef.set(objectName);
646
|
647 a.arora 1.39 _rep = new CIMObjectPathRep(*tmpRef._rep);
|
648 kumpf 1.2 }
649
650 CIMObjectPath::CIMObjectPath(
651 const String& host,
|
652 kumpf 1.7 const CIMNamespaceName& nameSpace,
653 const CIMName& className,
|
654 kumpf 1.16 const Array<CIMKeyBinding>& keyBindings)
|
655 kumpf 1.2 {
656 // Test the objectName out to see if we get an exception
657 CIMObjectPath tmpRef;
658 tmpRef.set(host, nameSpace, className, keyBindings);
659
|
660 a.arora 1.39 _rep = new CIMObjectPathRep(*tmpRef._rep);
|
661 kumpf 1.2 }
662
663 CIMObjectPath::~CIMObjectPath()
664 {
|
665 a.arora 1.39 delete _rep;
|
666 kumpf 1.2 }
667
668 CIMObjectPath& CIMObjectPath::operator=(const CIMObjectPath& x)
669 {
|
670 a.arora 1.39 *_rep = *x._rep;
|
671 kumpf 1.2 return *this;
672 }
673
674 void CIMObjectPath::clear()
675 {
676 _rep->_host.clear();
677 _rep->_nameSpace.clear();
678 _rep->_className.clear();
679 _rep->_keyBindings.clear();
680 }
681
682 void CIMObjectPath::set(
683 const String& host,
|
684 kumpf 1.7 const CIMNamespaceName& nameSpace,
685 const CIMName& className,
|
686 kumpf 1.16 const Array<CIMKeyBinding>& keyBindings)
|
687 kumpf 1.2 {
688 setHost(host);
689 setNameSpace(nameSpace);
690 setClassName(className);
691 setKeyBindings(keyBindings);
692 }
693
|
694 kumpf 1.22 Boolean _parseHostElement(
|
695 kumpf 1.2 const String& objectName,
696 char*& p,
|
697 kumpf 1.9 String& host)
|
698 kumpf 1.2 {
699 // See if there is a host name (true if it begins with "//"):
|
700 kumpf 1.32 // Host is of the form <hostname>:<port> and begins with "//"
|
701 kumpf 1.2 // and ends with "/":
702
703 if (p[0] != '/' || p[1] != '/')
704 {
705 return false;
706 }
707
708 p += 2;
709
|
710 kumpf 1.34 char* slash = strchr(p, '/');
711 if (!slash)
|
712 chuck 1.23 {
|
713 kumpf 1.34 throw MalformedObjectNameException(objectName);
|
714 kumpf 1.2 }
715
|
716 kumpf 1.34 String hostname = String(p, (Uint32)(slash - p));
717 if (!CIMObjectPathRep::isValidHostname(hostname))
|
718 kumpf 1.2 {
|
719 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
720 kumpf 1.2 }
|
721 kumpf 1.34 host = hostname;
|
722 kumpf 1.2
|
723 kumpf 1.31 // Do not step past the '/'; it will be consumed by the namespace parser
|
724 kumpf 1.34 p = slash;
|
725 kumpf 1.2
726 return true;
727 }
728
|
729 kumpf 1.22 Boolean _parseNamespaceElement(
|
730 kumpf 1.2 const String& objectName,
731 char*& p,
|
732 kumpf 1.7 CIMNamespaceName& nameSpace)
|
733 kumpf 1.2 {
734 // If we don't find a valid namespace name followed by a ':', we
735 // assume we're not looking at a namespace name.
736
|
737 kumpf 1.7 char* colon = strchr(p, ':');
738 if (!colon)
739 {
740 return false;
741 }
742
|
743 chip 1.47 // A ':' as part of a keybinding value should not be interpreted as
|
744 kumpf 1.25 // a namespace delimiter. Since keybinding pairs follow the first '.'
745 // in the object path string, the ':' delimiter only counts if it
746 // appears before the '.'.
747
748 char* dot = strchr(p, '.');
749 if (dot && (dot < colon))
750 {
751 return false;
752 }
753
|
754 kumpf 1.2 //----------------------------------------------------------------------
755 // Validate the namespace path. Namespaces must match the following
756 // regular expression: "[A-Za-z_]+(/[A-Za-z_]+)*"
757 //----------------------------------------------------------------------
758
|
759 david 1.27 String namespaceName = String(p, (Uint32)(colon - p));
|
760 kumpf 1.7 if (!CIMNamespaceName::legal(namespaceName))
|
761 kumpf 1.2 {
|
762 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
763 kumpf 1.2 }
|
764 kumpf 1.7 nameSpace = namespaceName;
|
765 kumpf 1.2
|
766 kumpf 1.7 p = colon+1;
|
767 kumpf 1.2 return true;
768 }
769
770 /**
|
771 kumpf 1.29 ATTN-RK: The DMTF specification for the string form of an
772 object path makes it impossible for a parser to distinguish
773 between a key values of String type and Reference type.
774
775 Given the ambiguity, this implementation takes a guess at the
776 type of a quoted key value. If the value can be parsed into
777 a CIMObjectPath with at least one key binding, the type is
778 set to REFERENCE. Otherwise, the type is set to STRING.
779 Note: This algorithm appears to be in line with what the Sun
780 WBEM Services implementation does.
781
782 To be totally correct, it would be necessary to retrieve the
783 class definition and look up the types of the key properties
784 to determine how to interpret the key values. This is clearly
785 too inefficient for internal transformations between
786 CIMObjectPaths and String values.
|
787 kumpf 1.2 */
|
788 kumpf 1.22 void _parseKeyBindingPairs(
|
789 kumpf 1.2 const String& objectName,
790 char*& p,
|
791 chip 1.47 Array<CIMKeyBinding>& keyBindings)
|
792 kumpf 1.2 {
793 // Get the key-value pairs:
794
795 while (*p)
796 {
797 // Get key part:
798
|
799 kumpf 1.5 char* equalsign = strchr(p, '=');
800 if (!equalsign)
|
801 kumpf 1.2 {
|
802 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
803 kumpf 1.2 }
804
|
805 kumpf 1.5 *equalsign = 0;
|
806 kumpf 1.2
|
807 kumpf 1.17 if (!CIMName::legal(p))
|
808 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
809 kumpf 1.2
|
810 kumpf 1.17 CIMName keyName (p);
811
|
812 kumpf 1.2 // Get the value part:
813
814 String valueString;
|
815 kumpf 1.5 p = equalsign + 1;
|
816 kumpf 1.16 CIMKeyBinding::Type type;
|
817 kumpf 1.2
|
818 kumpf 1.29 if (*p == '"')
|
819 kumpf 1.2 {
|
820 kumpf 1.29 // Could be CIMKeyBinding::STRING or CIMKeyBinding::REFERENCE
821
|
822 kumpf 1.2 p++;
823
824 while (*p && *p != '"')
825 {
826 if (*p == '\\')
|
827 kumpf 1.28 {
|
828 kumpf 1.2 *p++;
829
|
830 kumpf 1.28 if ((*p != '\\') && (*p != '"'))
831 {
832 throw MalformedObjectNameException(objectName);
833 }
834 }
835
|
836 kumpf 1.2 valueString.append(*p++);
837 }
838
839 if (*p++ != '"')
|
840 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
841 kumpf 1.2
|
842 kumpf 1.29 /*
843 Guess at the type of this quoted key value. If the value
844 can be parsed into a CIMObjectPath with at least one key
845 binding, the type is assumed to be a REFERENCE. Otherwise,
846 the type is set to STRING. (See method header for details.)
847 */
|
848 kumpf 1.16 type = CIMKeyBinding::STRING;
|
849 kumpf 1.2
|
850 kumpf 1.29 try
|
851 kumpf 1.2 {
|
852 kumpf 1.29 CIMObjectPath testForPath(valueString);
853 if (testForPath.getKeyBindings().size() > 0)
|
854 kumpf 1.28 {
|
855 kumpf 1.29 // We've found a reference value!
856 type = CIMKeyBinding::REFERENCE;
|
857 kumpf 1.28 }
|
858 kumpf 1.2 }
|
859 david.dillard 1.41 catch (const Exception &)
|
860 kumpf 1.29 {
861 // Not a reference value; leave type as STRING
862 }
|
863 kumpf 1.2 }
864 else if (toupper(*p) == 'T' || toupper(*p) == 'F')
865 {
|
866 kumpf 1.16 type = CIMKeyBinding::BOOLEAN;
|
867 kumpf 1.2
868 char* r = p;
869 Uint32 n = 0;
870
871 while (*r && *r != ',')
872 {
873 *r = toupper(*r);
874 r++;
875 n++;
876 }
877
878 if (!(((strncmp(p, "TRUE", n) == 0) && n == 4) ||
879 ((strncmp(p, "FALSE", n) == 0) && n == 5)))
|
880 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
881 kumpf 1.2
882 valueString.assign(p, n);
883
884 p = p + n;
885 }
886 else
887 {
|
888 kumpf 1.16 type = CIMKeyBinding::NUMERIC;
|
889 kumpf 1.2
890 char* r = p;
891 Uint32 n = 0;
892
893 while (*r && *r != ',')
894 {
895 r++;
896 n++;
897 }
898
899 Boolean isComma = false;
900 if (*r)
901 {
902 *r = '\0';
903 isComma = true;
904 }
905
|
906 r.kieninger 1.56 if (*p == '-')
907 {
908 Sint64 x;
909 if (!XmlReader::stringToSignedInteger(p, x))
910 throw MalformedObjectNameException(objectName);
911 }
912 else
913 {
914 Uint64 x;
915 if (!XmlReader::stringToUnsignedInteger(p, x))
916 throw MalformedObjectNameException(objectName);
917 }
|
918 kumpf 1.2
919 valueString.assign(p, n);
920
921 if (isComma)
922 {
923 *r = ',';
924 }
925
926 p = p + n;
927 }
928
|
929 chip 1.47 keyBindings.append(CIMKeyBinding(keyName.getString (), valueString,
|
930 kumpf 1.17 type));
|
931 kumpf 1.2
932 if (*p)
933 {
934 if (*p++ != ',')
935 {
|
936 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
937 kumpf 1.2 }
938 }
939 }
940
941 _BubbleSort(keyBindings);
942 }
943
|
944 chip 1.47 void CIMObjectPath::set(const String& objectName)
|
945 kumpf 1.2 {
946 clear();
947
948 //--------------------------------------------------------------------------
949 // We will extract components from an object name. Here is an sample
950 // object name:
951 //
952 // //atp:9999/root/cimv25:TennisPlayer.first="Patrick",last="Rafter"
953 //--------------------------------------------------------------------------
954
955 // Convert to a C String first:
956
|
957 david 1.37 CString pCString = objectName.getCString();
|
958 kumpf 1.26 char* p = const_cast<char*>((const char*) pCString);
|
959 kumpf 1.2 Boolean gotHost;
960 Boolean gotNamespace;
961
962 gotHost = _parseHostElement(objectName, p, _rep->_host);
963 gotNamespace = _parseNamespaceElement(objectName, p, _rep->_nameSpace);
964
965 if (gotHost && !gotNamespace)
966 {
|
967 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
968 kumpf 1.2 }
969
970 // Extract the class name:
971
972 char* dot = strchr(p, '.');
973
974 if (!dot)
975 {
976 if (!CIMName::legal(p))
977 {
|
978 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
979 kumpf 1.2 }
980
981 // ATTN: remove this later: a reference should only be able to hold
982 // an instance name.
983
|
984 kumpf 1.17 _rep->_className = CIMName (p);
|
985 kumpf 1.2 return;
986 }
987
|
988 david 1.27 String className = String(p, (Uint32)(dot - p));
|
989 kumpf 1.7 if (!CIMName::legal(className))
990 {
|
991 kumpf 1.10 throw MalformedObjectNameException(objectName);
|
992 kumpf 1.7 }
993 _rep->_className = className;
|
994 kumpf 1.2
995 // Advance past dot:
996
997 p = dot + 1;
998
999 _parseKeyBindingPairs(objectName, p, _rep->_keyBindings);
1000 }
1001
1002 CIMObjectPath& CIMObjectPath::operator=(const String& objectName)
1003 {
1004 set(objectName);
1005 return *this;
1006 }
1007
1008 const String& CIMObjectPath::getHost() const
1009 {
1010 return _rep->_host;
1011 }
1012
1013 void CIMObjectPath::setHost(const String& host)
1014 {
|
1015 kumpf 1.35 if ((host != String::EMPTY) && !CIMObjectPathRep::isValidHostname(host))
1016 {
1017 throw MalformedObjectNameException(host);
1018 }
1019
|
1020 kumpf 1.2 _rep->_host = host;
1021 }
1022
|
1023 kumpf 1.7 const CIMNamespaceName& CIMObjectPath::getNameSpace() const
|
1024 kumpf 1.2 {
1025 return _rep->_nameSpace;
1026 }
1027
|
1028 kumpf 1.7 void CIMObjectPath::setNameSpace(const CIMNamespaceName& nameSpace)
|
1029 kumpf 1.2 {
1030 _rep->_nameSpace = nameSpace;
1031 }
1032
|
1033 kumpf 1.7 const CIMName& CIMObjectPath::getClassName() const
|
1034 kumpf 1.2 {
1035 return _rep->_className;
1036 }
1037
|
1038 kumpf 1.7 void CIMObjectPath::setClassName(const CIMName& className)
|
1039 kumpf 1.2 {
1040 _rep->_className = className;
1041 }
1042
|
1043 kumpf 1.16 const Array<CIMKeyBinding>& CIMObjectPath::getKeyBindings() const
|
1044 kumpf 1.2 {
1045 return _rep->_keyBindings;
1046 }
1047
|
1048 kumpf 1.16 void CIMObjectPath::setKeyBindings(const Array<CIMKeyBinding>& keyBindings)
|
1049 kumpf 1.2 {
1050 _rep->_keyBindings = keyBindings;
1051 _BubbleSort(_rep->_keyBindings);
1052 }
1053
|
1054 kumpf 1.15 String CIMObjectPath::toString() const
|
1055 kumpf 1.2 {
1056 String objectName;
1057
1058 // Get the host:
1059
|
1060 kumpf 1.15 if (_rep->_host.size())
|
1061 kumpf 1.2 {
1062 objectName = "//";
|
1063 kumpf 1.13 objectName.append(_rep->_host);
1064 objectName.append("/");
|
1065 kumpf 1.2 }
1066
1067 // Get the namespace (if we have a host name, we must write namespace):
1068
|
1069 kumpf 1.7 if (!_rep->_nameSpace.isNull() || _rep->_host.size())
|
1070 kumpf 1.2 {
|
1071 kumpf 1.17 objectName.append(_rep->_nameSpace.getString ());
|
1072 kumpf 1.13 objectName.append(":");
|
1073 kumpf 1.2 }
1074
1075 // Get the class name:
1076
|
1077 kumpf 1.17 objectName.append(getClassName().getString ());
|
1078 kumpf 1.2
|
1079 kumpf 1.9 //
1080 // ATTN-CAKG-P2-20020726: The following condition does not correctly
1081 // distinguish instanceNames from classNames in every case
1082 // The instanceName of a singleton instance of a keyless class has no
1083 // key bindings
1084 //
1085 if (_rep->_keyBindings.size () != 0)
|
1086 kumpf 1.2 {
1087 objectName.append('.');
1088
1089 // Append each key-value pair:
1090
|
1091 kumpf 1.16 const Array<CIMKeyBinding>& keyBindings = getKeyBindings();
|
1092 kumpf 1.2
1093 for (Uint32 i = 0, n = keyBindings.size(); i < n; i++)
1094 {
|
1095 kumpf 1.17 objectName.append(keyBindings[i].getName().getString ());
|
1096 kumpf 1.2 objectName.append('=');
1097
1098 const String& value = _escapeSpecialCharacters(
1099 keyBindings[i].getValue());
1100
|
1101 kumpf 1.16 CIMKeyBinding::Type type = keyBindings[i].getType();
|
1102 chip 1.47
|
1103 kumpf 1.57 if (type == CIMKeyBinding::STRING ||
1104 type == CIMKeyBinding::REFERENCE)
|
1105 kumpf 1.2 objectName.append('"');
1106
1107 objectName.append(value);
1108
|
1109 kumpf 1.57 if (type == CIMKeyBinding::STRING ||
1110 type == CIMKeyBinding::REFERENCE)
|
1111 kumpf 1.2 objectName.append('"');
1112
1113 if (i + 1 != n)
1114 objectName.append(',');
1115 }
1116 }
1117
1118 return objectName;
1119 }
1120
|
1121 kumpf 1.15 String CIMObjectPath::_toStringCanonical() const
|
1122 kumpf 1.2 {
1123 CIMObjectPath ref = *this;
1124
|
1125 kumpf 1.33 // Normalize hostname by changing to lower case
|
1126 chip 1.47 ref._rep->_host.toLower(); // ICU_TODO:
|
1127 kumpf 1.2
|
1128 kumpf 1.33 // Normalize namespace by changing to lower case
1129 if (!ref._rep->_nameSpace.isNull())
1130 {
1131 String nameSpaceLower = ref._rep->_nameSpace.getString();
|
1132 chip 1.47 nameSpaceLower.toLower(); // ICU_TODO:
|
1133 kumpf 1.33 ref._rep->_nameSpace = nameSpaceLower;
1134 }
1135
1136 // Normalize class name by changing to lower case
1137 if (!ref._rep->_className.isNull())
1138 {
1139 String classNameLower = ref._rep->_className.getString();
|
1140 chip 1.47 classNameLower.toLower(); // ICU_TODO:
|
1141 kumpf 1.33 ref._rep->_className = classNameLower;
1142 }
|
1143 kumpf 1.2
1144 for (Uint32 i = 0, n = ref._rep->_keyBindings.size(); i < n; i++)
1145 {
|
1146 kumpf 1.33 // Normalize key binding name by changing to lower case
1147 if (!ref._rep->_keyBindings[i]._rep->_name.isNull())
1148 {
|
1149 chip 1.47 String keyBindingNameLower =
|
1150 kumpf 1.33 ref._rep->_keyBindings[i]._rep->_name.getString();
1151 keyBindingNameLower.toLower(); // ICU_TODO:
1152 ref._rep->_keyBindings[i]._rep->_name = keyBindingNameLower;
1153 }
1154
1155 // Normalize the key value
1156 switch (ref._rep->_keyBindings[i]._rep->_type)
1157 {
1158 case CIMKeyBinding::REFERENCE:
1159 try
1160 {
1161 // Convert reference to CIMObjectPath and recurse
1162 ref._rep->_keyBindings[i]._rep->_value =
1163 CIMObjectPath(ref._rep->_keyBindings[i]._rep->_value).
1164 _toStringCanonical();
1165 }
1166 catch (Exception&)
1167 {
1168 // Leave value unchanged if the CIMObjectPath parsing fails
1169 }
1170 break;
1171 kumpf 1.33 case CIMKeyBinding::BOOLEAN:
1172 // Normalize the boolean string by changing to lower case
1173 ref._rep->_keyBindings[i]._rep->_value.toLower(); // ICU_TODO:
1174 break;
1175 case CIMKeyBinding::NUMERIC:
1176 // Normalize the numeric string by converting to integer and back
1177 Uint64 uValue;
1178 Sint64 sValue;
1179 // First try converting to unsigned integer
1180 if (XmlReader::stringToUnsignedInteger(
1181 ref._rep->_keyBindings[i]._rep->_value.getCString(),
1182 uValue))
1183 {
1184 char buffer[32]; // Should need 21 chars max
1185 sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "u", uValue);
1186 ref._rep->_keyBindings[i]._rep->_value = String(buffer);
1187 }
1188 // Next try converting to signed integer
1189 else if (XmlReader::stringToSignedInteger(
1190 ref._rep->_keyBindings[i]._rep->_value.getCString(),
1191 sValue))
1192 kumpf 1.33 {
1193 char buffer[32]; // Should need 21 chars max
1194 sprintf(buffer, "%" PEGASUS_64BIT_CONVERSION_WIDTH "d", sValue);
1195 ref._rep->_keyBindings[i]._rep->_value = String(buffer);
1196 }
1197 // Leave value unchanged if it cannot be converted to an integer
1198 break;
1199 default: // CIMKeyBinding::STRING
1200 // No normalization required for STRING
1201 break;
1202 }
|
1203 kumpf 1.2 }
1204
|
1205 kumpf 1.33 // Note: key bindings are sorted when set in the CIMObjectPath
|
1206 kumpf 1.12
|
1207 kumpf 1.15 return ref.toString();
|
1208 kumpf 1.2 }
1209
1210 Boolean CIMObjectPath::identical(const CIMObjectPath& x) const
1211 {
1212 return
|
1213 kumpf 1.33 String::equalNoCase(_rep->_host, x._rep->_host) &&
|
1214 kumpf 1.7 _rep->_nameSpace.equal(x._rep->_nameSpace) &&
1215 _rep->_className.equal(x._rep->_className) &&
|
1216 kumpf 1.2 _rep->_keyBindings == x._rep->_keyBindings;
1217 }
1218
1219 Uint32 CIMObjectPath::makeHashCode() const
1220 {
|
1221 kumpf 1.12 return HashFunc<String>::hash(_toStringCanonical());
|
1222 kumpf 1.2 }
1223
1224 Boolean operator==(const CIMObjectPath& x, const CIMObjectPath& y)
1225 {
1226 return x.identical(y);
1227 }
1228
1229 Boolean operator!=(const CIMObjectPath& x, const CIMObjectPath& y)
1230 {
1231 return !operator==(x, y);
1232 }
1233
|
1234 chip 1.1 PEGASUS_NAMESPACE_END
|