xref: /aoo42x/main/registry/tools/regcompare.cxx (revision 51134e9e)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_registry.hxx"
26 
27 #include "registry/registry.hxx"
28 #include "registry/reader.hxx"
29 #include "registry/version.h"
30 #include "fileurl.hxx"
31 #include "options.hxx"
32 
33 #include <rtl/ustring.hxx>
34 #include <osl/diagnose.h>
35 
36 #include <stdio.h>
37 #include <string.h>
38 
39 #include <set>
40 #include <vector>
41 #include <string>
42 
43 using namespace rtl;
44 using namespace registry::tools;
45 
46 typedef std::set< rtl::OUString > StringSet;
47 
48 class Options_Impl : public Options
49 {
50 public:
51 	explicit Options_Impl(char const * program)
52 		: Options(program),
53           m_bFullCheck(false),
54           m_bForceOutput(false),
55           m_bUnoTypeCheck(false),
56           m_checkUnpublished(false)
57 		{}
58 
59     std::string const & getRegName1() const { return m_regName1; }
60     std::string const & getRegName2() const { return m_regName2; }
61 
62 	bool isStartKeyValid() const { return (m_startKey.getLength() > 0); }
63 	OUString const & getStartKey() const { return m_startKey; }
64     bool matchedWithExcludeKey( const OUString& keyName) const;
65 
66 	bool fullCheck() const { return m_bFullCheck; }
67 	bool forceOutput() const { return m_bForceOutput; }
68 	bool unoTypeCheck() const { return m_bUnoTypeCheck; }
69     bool checkUnpublished() const { return m_checkUnpublished; }
70 
71 protected:
72     bool setRegName_Impl(char c, std::string const & param);
73 
74 	virtual void printUsage_Impl() const;
75 	virtual bool initOptions_Impl (std::vector< std::string > & rArgs);
76 
77     std::string m_regName1;
78     std::string m_regName2;
79 	OUString    m_startKey;
80 	StringSet	m_excludeKeys;
81 	bool m_bFullCheck;
82 	bool m_bForceOutput;
83 	bool m_bUnoTypeCheck;
84     bool m_checkUnpublished;
85 };
86 
87 #define U2S( s ) OUStringToOString(s, RTL_TEXTENCODING_UTF8).getStr()
88 
89 inline rtl::OUString makeOUString (std::string const & s)
90 {
91     return rtl::OUString(s.c_str(), s.size(), RTL_TEXTENCODING_UTF8, OSTRING_TO_OUSTRING_CVTFLAGS);
92 }
93 
94 inline rtl::OUString shortName(rtl::OUString const & fullName)
95 {
96     return fullName.copy(fullName.lastIndexOf('/') + 1);
97 }
98 
99 bool Options_Impl::setRegName_Impl(char c, std::string const & param)
100 {
101     bool one = (c == '1'), two = (c == '2');
102     if (one)
103         m_regName1 = param;
104     if (two)
105         m_regName2 = param;
106     return (one || two);
107 }
108 
109 //virtual
110 void Options_Impl::printUsage_Impl() const
111 {
112     std::string const & rProgName = getProgramName();
113     fprintf(stderr,
114             "Usage: %s -r1<filename> -r2<filename> [-options] | @<filename>\n", rProgName.c_str()
115             );
116     fprintf(stderr,
117             "    -r1<filename>  = filename specifies the name of the first registry.\n"
118             "    -r2<filename>  = filename specifies the name of the second registry.\n"
119             "    @<filename>    = filename specifies a command file.\n"
120             "Options:\n"
121             "    -s<name>  = name specifies the name of a start key. If no start key\n"
122             "     |S<name>   is specified the comparison starts with the root key.\n"
123             "    -x<name>  = name specifies the name of a key which won't be compared. All\n"
124             "     |X<name>   subkeys won't be compared also. This option can be used more than once.\n"
125             "    -f|F      = force the detailed output of any diffenrences. Default\n"
126             "                is that only the number of differences is returned.\n"
127             "    -c|C      = make a complete check, that means any differences will be\n"
128             "                detected. Default is only a compatibility check that means\n"
129             "                only UNO typelibrary entries will be checked.\n"
130             "    -t|T      = make an UNO type compatiblity check. This means that registry 2\n"
131             "                will be checked against registry 1. If a interface in r2 contains\n"
132             "                more methods or the methods are in a different order as in r1, r2 is\n"
133             "                incompatible to r1. But if a service in r2 supports more properties as\n"
134             "                in r1 and the new properties are 'optional' it is compatible.\n"
135             "    -u|U      = additionally check types that are unpublished in registry 1.\n"
136             "    -h|-?     = print this help message and exit.\n"
137             );
138     fprintf(stderr,
139             "\n%s Version 1.0\n\n", rProgName.c_str()
140             );
141 }
142 
143 // virtual
144 bool Options_Impl::initOptions_Impl (std::vector< std::string > & rArgs)
145 {
146     std::vector< std::string >::const_iterator first = rArgs.begin(), last = rArgs.end();
147     for (; first != last; ++first)
148 	{
149 		if ((*first)[0] != '-')
150 		{
151             return badOption("invalid", (*first).c_str());
152         }
153         switch ((*first)[1])
154         {
155         case 'r':
156         case 'R':
157             {
158                 if (!((++first != last) && ((*first)[0] != '-')))
159                 {
160                     return badOption("invalid", (*first).c_str());
161                 }
162 
163                 std::string option(*first), param;
164                 if (option.size() == 1)
165                 {
166                     // "-r<n><space><param>"
167                     if (!((++first != last) && ((*first)[0] != '-')))
168                     {
169                         return badOption("invalid", (*first).c_str());
170                     }
171                     param = (*first);
172                 }
173                 else
174                 {
175                     // "-r<n><param>"
176                     param = std::string(&(option[1]), option.size() - 1);
177                 }
178                 if (!setRegName_Impl(option[0], param))
179                 {
180                     return badOption("invalid", option.c_str());
181                 }
182                 break;
183             }
184         case 's':
185         case 'S':
186             {
187                 if (!((++first != last) && ((*first)[0] != '-')))
188                 {
189                     return badOption("invalid", (*first).c_str());
190                 }
191                 m_startKey = makeOUString(*first);
192                 break;
193             }
194         case 'x':
195         case 'X':
196             {
197                 if (!((++first != last) && ((*first)[0] != '-')))
198                 {
199                     return badOption("invalid", (*first).c_str());
200                 }
201                 m_excludeKeys.insert(makeOUString(*first));
202                 break;
203             }
204         case 'f':
205         case 'F':
206             {
207 			    if ((*first).size() > 2)
208                 {
209                     return badOption("invalid", (*first).c_str());
210                 }
211                 m_bForceOutput = sal_True;
212                 break;
213             }
214         case 'c':
215         case 'C':
216             {
217 			    if ((*first).size() > 2)
218                 {
219                     return badOption("invalid", (*first).c_str());
220                 }
221                 m_bFullCheck = sal_True;
222                 break;
223             }
224         case 't':
225         case 'T':
226             {
227 			    if ((*first).size() > 2)
228                 {
229                     return badOption("invalid", (*first).c_str());
230                 }
231                 m_bUnoTypeCheck = sal_True;
232                 break;
233             }
234         case 'u':
235         case 'U':
236             {
237 			    if ((*first).size() > 2)
238                 {
239                     return badOption("invalid", (*first).c_str());
240                 }
241                 m_checkUnpublished = true;
242                 break;
243             }
244         case 'h':
245         case '?':
246             {
247 			    if ((*first).size() > 2)
248                 {
249                     return badOption("invalid", (*first).c_str());
250                 }
251                 return printUsage();
252                 // break; // Unreachable
253             }
254         default:
255             {
256                 return badOption("unknown", (*first).c_str());
257                 // break; // Unreachable
258             }
259         }
260     }
261 
262     if ( m_regName1.size() == 0 )
263     {
264         return badOption("missing", "-r1");
265     }
266     if ( m_regName2.size() == 0 )
267     {
268         return badOption("missing", "-r2");
269     }
270     return true;
271 }
272 
273 bool Options_Impl::matchedWithExcludeKey( const OUString& keyName) const
274 {
275     if (!m_excludeKeys.empty())
276     {
277         StringSet::const_iterator first = m_excludeKeys.begin(), last = m_excludeKeys.end();
278         for (; first != last; ++first)
279         {
280             if (keyName.indexOf(*first) == 0)
281                 return true;
282         }
283     }
284     return false;
285 }
286 
287 static char const * getTypeClass(RTTypeClass typeClass)
288 {
289 	switch (typeClass)
290 	{
291 		case RT_TYPE_INTERFACE:
292 			return "INTERFACE";
293 		case RT_TYPE_MODULE:
294 			return "MODULE";
295 		case RT_TYPE_STRUCT:
296 			return "STRUCT";
297 		case RT_TYPE_ENUM:
298 			return "ENUM";
299 		case RT_TYPE_EXCEPTION:
300 			return "EXCEPTION";
301 		case RT_TYPE_TYPEDEF:
302 			return "TYPEDEF";
303 		case RT_TYPE_SERVICE:
304 			return "SERVICE";
305 		case RT_TYPE_OBJECT:
306 			return "OBJECT";
307 		case RT_TYPE_CONSTANTS:
308 			return "CONSTANTS";
309         default:
310             return "INVALID";
311 	}
312 }
313 
314 static OString getFieldAccess(RTFieldAccess fieldAccess)
315 {
316 	OString ret;
317 	if ( (fieldAccess & RT_ACCESS_INVALID) == RT_ACCESS_INVALID )
318 	{
319 		ret += OString("INVALID");
320 	}
321 	if ( (fieldAccess & RT_ACCESS_READONLY) == RT_ACCESS_READONLY )
322 	{
323 		ret += OString(ret.getLength() > 0 ? ",READONLY" : "READONLY");
324 	}
325 	if ( (fieldAccess & RT_ACCESS_OPTIONAL) == RT_ACCESS_OPTIONAL )
326 	{
327 		ret += OString(ret.getLength() > 0 ? ",OPTIONAL" : "OPTIONAL");
328 	}
329 	if ( (fieldAccess & RT_ACCESS_MAYBEVOID) == RT_ACCESS_MAYBEVOID )
330 	{
331 		ret += OString(ret.getLength() > 0 ? ",MAYBEVOID" : "MAYBEVOID");
332 	}
333 	if ( (fieldAccess & RT_ACCESS_BOUND) == RT_ACCESS_BOUND )
334 	{
335 		ret += OString(ret.getLength() > 0 ? ",BOUND" : "BOUND");
336 	}
337 	if ( (fieldAccess & RT_ACCESS_CONSTRAINED) == RT_ACCESS_CONSTRAINED )
338 	{
339 		ret += OString(ret.getLength() > 0 ? ",CONSTRAINED" : "CONSTRAINED");
340 	}
341 	if ( (fieldAccess & RT_ACCESS_TRANSIENT) == RT_ACCESS_TRANSIENT )
342 	{
343 		ret += OString(ret.getLength() > 0 ? ",TRANSIENT" : "TRANSIENT");
344 	}
345 	if ( (fieldAccess & RT_ACCESS_MAYBEAMBIGUOUS) == RT_ACCESS_MAYBEAMBIGUOUS )
346 	{
347 		ret += OString(ret.getLength() > 0 ? ",MAYBEAMBIGUOUS" : "MAYBEAMBIGUOUS");
348 	}
349 	if ( (fieldAccess & RT_ACCESS_MAYBEDEFAULT) == RT_ACCESS_MAYBEDEFAULT )
350 	{
351 		ret += OString(ret.getLength() > 0 ? ",MAYBEDEFAULT" : "MAYBEDEFAULT");
352 	}
353 	if ( (fieldAccess & RT_ACCESS_REMOVEABLE) == RT_ACCESS_REMOVEABLE )
354 	{
355 		ret += OString(ret.getLength() > 0 ? ",REMOVEABLE" : "REMOVEABLE");
356 	}
357 	if ( (fieldAccess & RT_ACCESS_ATTRIBUTE) == RT_ACCESS_ATTRIBUTE )
358 	{
359 		ret += OString(ret.getLength() > 0 ? ",ATTRIBUTE" : "ATTRIBUTE");
360 	}
361 	if ( (fieldAccess & RT_ACCESS_PROPERTY) == RT_ACCESS_PROPERTY )
362 	{
363 		ret += OString(ret.getLength() > 0 ? ",PROPERTY" : "PROPERTY");
364 	}
365 	if ( (fieldAccess & RT_ACCESS_CONST) == RT_ACCESS_CONST )
366 	{
367 		ret += OString(ret.getLength() > 0 ? ",CONST" : "CONST");
368 	}
369 	if ( (fieldAccess & RT_ACCESS_READWRITE) == RT_ACCESS_READWRITE )
370 	{
371 		ret += OString(ret.getLength() > 0 ? ",READWRITE" : "READWRITE");
372 	}
373 	return ret;
374 }
375 
376 static char const * getConstValueType(RTConstValue& constValue)
377 {
378 	switch (constValue.m_type)
379 	{
380 		case RT_TYPE_BOOL:
381 			return "sal_Bool";
382 		case RT_TYPE_BYTE:
383 			return "sal_uInt8";
384 		case RT_TYPE_INT16:
385 			return "sal_Int16";
386 		case RT_TYPE_UINT16:
387 			return "sal_uInt16";
388 		case RT_TYPE_INT32:
389 			return "sal_Int32";
390 		case RT_TYPE_UINT32:
391 			return "sal_uInt32";
392 //		case RT_TYPE_INT64:
393 //			return "sal_Int64";
394 //		case RT_TYPE_UINT64:
395 //			return "sal_uInt64";
396 		case RT_TYPE_FLOAT:
397 			return "float";
398 		case RT_TYPE_DOUBLE:
399 			return "double";
400 		case RT_TYPE_STRING:
401 			return "sal_Unicode*";
402         default:
403             return "NONE";
404 	}
405 }
406 
407 static void printConstValue(RTConstValue& constValue)
408 {
409 	switch (constValue.m_type)
410 	{
411 		case RT_TYPE_NONE:
412 			fprintf(stdout, "none");
413             break;
414 		case RT_TYPE_BOOL:
415 			fprintf(stdout, "%s", constValue.m_value.aBool ? "TRUE" : "FALSE");
416             break;
417 		case RT_TYPE_BYTE:
418 			fprintf(stdout, "%d", constValue.m_value.aByte);
419             break;
420 		case RT_TYPE_INT16:
421 			fprintf(stdout, "%d", constValue.m_value.aShort);
422             break;
423 		case RT_TYPE_UINT16:
424 			fprintf(stdout, "%d", constValue.m_value.aUShort);
425             break;
426 		case RT_TYPE_INT32:
427 			fprintf(
428                 stdout, "%ld",
429                 sal::static_int_cast< long >(constValue.m_value.aLong));
430             break;
431 		case RT_TYPE_UINT32:
432 			fprintf(
433                 stdout, "%lu",
434                 sal::static_int_cast< unsigned long >(
435                     constValue.m_value.aULong));
436             break;
437 //		case RT_TYPE_INT64:
438 //			fprintf(stdout, "%d", constValue.m_value.aHyper);
439 //		case RT_TYPE_UINT64:
440 //			fprintf(stdout, "%d", constValue.m_value.aUHyper);
441 		case RT_TYPE_FLOAT:
442 			fprintf(stdout, "%f", constValue.m_value.aFloat);
443             break;
444 		case RT_TYPE_DOUBLE:
445 			fprintf(stdout, "%f", constValue.m_value.aDouble);
446             break;
447 		case RT_TYPE_STRING:
448 			fprintf(
449                 stdout, "%s",
450                 (rtl::OUStringToOString(
451                     constValue.m_value.aString, RTL_TEXTENCODING_UTF8).
452                  getStr()));
453             break;
454         default:
455             break;
456 	}
457 }
458 
459 static void dumpTypeClass(sal_Bool & rbDump, RTTypeClass typeClass, OUString const & keyName)
460 {
461     if (rbDump)
462         fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName));
463     rbDump = sal_False;
464 }
465 
466 static sal_uInt32 checkConstValue(Options_Impl const & options,
467                                   const OUString& keyName,
468 								  RTTypeClass typeClass,
469 								  sal_Bool & bDump,
470 								  RTConstValue& constValue1,
471 								  RTConstValue& constValue2,
472 								  sal_uInt16 index1)
473 {
474 	switch (constValue1.m_type)
475 	{
476         case RT_TYPE_INVALID:
477             break;
478 		case RT_TYPE_BOOL:
479 			if (constValue1.m_value.aBool != constValue2.m_value.aBool)
480 			{
481 				if ( options.forceOutput() && !options.unoTypeCheck() )
482 				{
483                     dumpTypeClass(bDump, typeClass, keyName);
484                     fprintf(stdout, "  Field %d: Value1 = %s  !=  Value2 = %s\n", index1,
485                             constValue1.m_value.aBool ? "TRUE" : "FALSE",
486                             constValue2.m_value.aBool ? "TRUE" : "FALSE");
487 				}
488 				return 1;
489 			}
490 			break;
491 		case RT_TYPE_BYTE:
492 			if (constValue1.m_value.aByte != constValue2.m_value.aByte)
493 			{
494 				if ( options.forceOutput() && !options.unoTypeCheck() )
495 				{
496 					dumpTypeClass(bDump, typeClass, keyName);
497                     fprintf(stdout, "  Field %d: Value1 = %d  !=  Value2 = %d\n", index1,
498                             constValue1.m_value.aByte, constValue2.m_value.aByte);
499 				}
500 				return 1;
501 			}
502 			break;
503 		case RT_TYPE_INT16:
504 			if (constValue1.m_value.aShort != constValue2.m_value.aShort)
505 			{
506 				if ( options.forceOutput() && !options.unoTypeCheck() )
507 				{
508                     dumpTypeClass(bDump, typeClass, keyName);
509                     fprintf(stdout, "  Field %d: Value1 = %d  !=  Value2 = %d\n", index1,
510                             constValue1.m_value.aShort, constValue2.m_value.aShort);
511 				}
512 				return 1;
513 			}
514 			break;
515 		case RT_TYPE_UINT16:
516 			if (constValue1.m_value.aUShort != constValue2.m_value.aUShort)
517 			{
518 				if ( options.forceOutput() && !options.unoTypeCheck() )
519 				{
520                     dumpTypeClass(bDump, typeClass, keyName);
521                     fprintf(stdout, "  Field %d: Value1 = %d  !=  Value2 = %d\n", index1,
522                             constValue1.m_value.aUShort, constValue2.m_value.aUShort);
523 				}
524 				return 1;
525 			}
526 			break;
527 		case RT_TYPE_INT32:
528 			if (constValue1.m_value.aLong != constValue2.m_value.aLong)
529 			{
530 				if ( options.forceOutput() && !options.unoTypeCheck() )
531 				{
532                     dumpTypeClass(bDump, typeClass, keyName);
533                     fprintf(stdout, "  Field %d: Value1 = %ld  !=  Value2 = %ld\n", index1,
534                             sal::static_int_cast< long >(constValue1.m_value.aLong),
535                             sal::static_int_cast< long >(constValue2.m_value.aLong));
536 				}
537 				return 1;
538 			}
539 			break;
540 		case RT_TYPE_UINT32:
541 			if (constValue1.m_value.aULong != constValue2.m_value.aULong)
542 			{
543 				if ( options.forceOutput() && !options.unoTypeCheck() )
544 				{
545                     dumpTypeClass(bDump, typeClass, keyName);
546                     fprintf(stdout, "  Field %d: Value1 = %lu  !=  Value2 = %lu\n", index1,
547                             sal::static_int_cast< unsigned long >(constValue1.m_value.aULong),
548                             sal::static_int_cast< unsigned long >(constValue2.m_value.aULong));
549 				}
550 				return 1;
551 			}
552 			break;
553 		case RT_TYPE_INT64:
554 			if (constValue1.m_value.aHyper != constValue2.m_value.aHyper)
555 			{
556 				if ( options.forceOutput() && !options.unoTypeCheck() )
557 				{
558                     dumpTypeClass(bDump, typeClass, keyName);
559 					fprintf(
560                         stdout, "  Field %d: Value1 = %s  !=  Value2 = %s\n",
561                         index1,
562                         rtl::OUStringToOString(
563                             rtl::OUString::valueOf(constValue1.m_value.aHyper),
564                             RTL_TEXTENCODING_ASCII_US).getStr(),
565                         rtl::OUStringToOString(
566                             rtl::OUString::valueOf(constValue2.m_value.aHyper),
567                             RTL_TEXTENCODING_ASCII_US).getStr());
568 				}
569 				return 1;
570 			}
571 			break;
572 		case RT_TYPE_UINT64:
573 			if (constValue1.m_value.aUHyper != constValue2.m_value.aUHyper)
574 			{
575 				if ( options.forceOutput() && !options.unoTypeCheck() )
576 				{
577                     dumpTypeClass(bDump, typeClass, keyName);
578 					fprintf(
579                         stdout, "  Field %d: Value1 = %s  !=  Value2 = %s\n",
580                         index1,
581                         rtl::OUStringToOString(
582                             rtl::OUString::valueOf(
583                                 static_cast< sal_Int64 >(
584                                     constValue1.m_value.aUHyper)),
585                             RTL_TEXTENCODING_ASCII_US).getStr(),
586                         rtl::OUStringToOString(
587                             rtl::OUString::valueOf(
588                                 static_cast< sal_Int64 >(
589                                     constValue2.m_value.aUHyper)),
590                             RTL_TEXTENCODING_ASCII_US).getStr());
591                         // printing the unsigned values as signed should be
592                         // acceptable...
593 				}
594 				return 1;
595 			}
596 			break;
597 		case RT_TYPE_FLOAT:
598 			if (constValue1.m_value.aFloat != constValue2.m_value.aFloat)
599 			{
600 				if ( options.forceOutput() && !options.unoTypeCheck() )
601 				{
602                     dumpTypeClass(bDump, typeClass, keyName);
603                     fprintf(stdout, "  Field %d: Value1 = %f  !=  Value2 = %f\n", index1,
604                             constValue1.m_value.aFloat, constValue2.m_value.aFloat);
605 				}
606 				return 1;
607 			}
608 			break;
609 		case RT_TYPE_DOUBLE:
610 			if (constValue1.m_value.aDouble != constValue2.m_value.aDouble)
611 			{
612 				if ( options.forceOutput() && !options.unoTypeCheck() )
613 				{
614                     dumpTypeClass(bDump, typeClass, keyName);
615                     fprintf(stdout, "  Field %d: Value1 = %f  !=  Value2 = %f\n", index1,
616                             constValue1.m_value.aDouble, constValue2.m_value.aDouble);
617 				}
618 				return 1;
619 			}
620 			break;
621         default:
622             OSL_ASSERT(false);
623             break;
624 	}
625 	return 0;
626 }
627 
628 static sal_uInt32 checkField(Options_Impl const & options,
629                              const OUString& keyName,
630 							 RTTypeClass typeClass,
631 							 sal_Bool & bDump,
632 							 typereg::Reader& reader1,
633 							 typereg::Reader& reader2,
634 							 sal_uInt16 index1,
635                              sal_uInt16 index2)
636 {
637 	sal_uInt32 nError = 0;
638 	if ( reader1.getFieldName(index1) != reader2.getFieldName(index2) )
639 	{
640 		if ( options.forceOutput() && !options.unoTypeCheck() )
641 		{
642             dumpTypeClass (bDump, typeClass, keyName);
643             fprintf(stdout, "  Field %d: Name1 = %s  !=  Name2 = %s\n", index1,
644                     U2S(reader1.getFieldName(index1)), U2S(reader2.getFieldName(index2)));
645 		}
646 		nError++;
647 	}
648 	if ( reader1.getFieldTypeName(index1) != reader2.getFieldTypeName(index2) )
649 	{
650 		if ( options.forceOutput() && !options.unoTypeCheck() )
651 		{
652             dumpTypeClass (bDump, typeClass, keyName);
653             fprintf(stdout, "  Field %d: Type1 = %s  !=  Type2 = %s\n", index1,
654                     U2S(reader1.getFieldTypeName(index1)), U2S(reader2.getFieldTypeName(index2)));
655 		}
656 		nError++;
657 	}
658     else
659 	{
660 		RTConstValue constValue1 = reader1.getFieldValue(index1);
661 		RTConstValue constValue2 = reader2.getFieldValue(index2);
662 		if ( constValue1.m_type != constValue2.m_type )
663 		{
664 			if ( options.forceOutput() && !options.unoTypeCheck() )
665 			{
666                 dumpTypeClass (bDump, typeClass, keyName);
667                 fprintf(stdout, "  Field %d: Access1 = %s  !=  Access2 = %s\n", index1,
668                         getConstValueType(constValue1), getConstValueType(constValue2));
669                 fprintf(stdout, "  Field %d: Value1 = ", index1);
670                 printConstValue(constValue1);
671                 fprintf(stdout, "  !=  Value2 = ");
672                 printConstValue(constValue1);
673                 fprintf(stdout, "\n;");
674 			}
675 			nError++;
676 		}
677         else
678 		{
679 			nError += checkConstValue(options, keyName, typeClass, bDump, constValue1, constValue2, index1);
680 		}
681 	}
682 
683 	if ( reader1.getFieldFlags(index1) != reader2.getFieldFlags(index2) )
684 	{
685 		if ( options.forceOutput() && !options.unoTypeCheck() )
686 		{
687             dumpTypeClass (bDump, typeClass, keyName);
688             fprintf(stdout, "  Field %d: FieldAccess1 = %s  !=  FieldAccess2 = %s\n", index1,
689                     getFieldAccess(reader1.getFieldFlags(index1)).getStr(),
690                     getFieldAccess(reader1.getFieldFlags(index2)).getStr());
691 		}
692 		nError++;
693 	}
694 
695 	if ( options.fullCheck() && (reader1.getFieldDocumentation(index1) != reader2.getFieldDocumentation(index2)) )
696 	{
697 		if ( options.forceOutput() && !options.unoTypeCheck() )
698 		{
699             dumpTypeClass (bDump, typeClass, keyName);
700             fprintf(stdout, "  Field %d: Doku1 = %s\n             Doku2 = %s\n", index1,
701                     U2S(reader1.getFieldDocumentation(index1)), U2S(reader2.getFieldDocumentation(index2)));
702 		}
703 		nError++;
704 	}
705 	return nError;
706 }
707 
708 static char const * getMethodMode(RTMethodMode methodMode)
709 {
710 	switch ( methodMode )
711 	{
712 		case RT_MODE_ONEWAY:
713 			return "ONEWAY";
714 		case RT_MODE_ONEWAY_CONST:
715 			return "ONEWAY,CONST";
716 		case RT_MODE_TWOWAY:
717 			return "NONE";
718 		case RT_MODE_TWOWAY_CONST:
719 			return "CONST";
720         default:
721         	return "INVALID";
722 	}
723 }
724 
725 static char const * getParamMode(RTParamMode paramMode)
726 {
727 	switch ( paramMode )
728 	{
729 		case RT_PARAM_IN:
730 			return "IN";
731 		case RT_PARAM_OUT:
732 			return "OUT";
733 		case RT_PARAM_INOUT:
734 			return "INOUT";
735         default:
736         	return "INVALID";
737 	}
738 }
739 
740 static sal_uInt32 checkMethod(Options_Impl const & options,
741                               const OUString& keyName,
742 							  RTTypeClass typeClass,
743 							  sal_Bool & bDump,
744 							  typereg::Reader& reader1,
745 							  typereg::Reader& reader2,
746 							  sal_uInt16 index)
747 {
748 	sal_uInt32 nError = 0;
749 	if ( reader1.getMethodName(index) != reader2.getMethodName(index) )
750 	{
751 		if ( options.forceOutput() )
752 		{
753             dumpTypeClass (bDump, typeClass, keyName);
754 			fprintf(stdout, "  Method1 %d: Name1 = %s  !=  Name2 = %s\n", index,
755 					U2S(reader1.getMethodName(index)),
756 					U2S(reader2.getMethodName(index)));
757 		}
758 		nError++;
759 	}
760 
761 	if ( reader1.getMethodReturnTypeName(index) != reader2.getMethodReturnTypeName(index) )
762 	{
763 		if ( options.forceOutput() )
764 		{
765             dumpTypeClass (bDump, typeClass, keyName);
766 			fprintf(stdout, "  Method1 %d: ReturnType1 = %s  !=  ReturnType2 = %s\n", index,
767 					U2S(reader1.getMethodReturnTypeName(index)),
768 					U2S(reader2.getMethodReturnTypeName(index)));
769 		}
770 		nError++;
771 	}
772 
773 	sal_uInt16 nParams1 = (sal_uInt16)reader1.getMethodParameterCount(index);
774 	sal_uInt16 nParams2 = (sal_uInt16)reader2.getMethodParameterCount(index);
775 	if ( nParams1 != nParams2 )
776 	{
777 		if ( options.forceOutput() )
778 		{
779             dumpTypeClass (bDump, typeClass, keyName);
780 			fprintf(stdout, "  Method %d : nParameters1 = %d  !=  nParameters2 = %d\n", index, nParams1, nParams2);
781 		}
782 		nError++;
783 	}
784 	sal_uInt16 i=0;
785 	for (i=0; i < nParams1 && i < nParams2; i++)
786 	{
787 		if ( reader1.getMethodParameterTypeName(index, i) != reader2.getMethodParameterTypeName(index, i) )
788 		{
789 			if ( options.forceOutput() )
790 			{
791                 dumpTypeClass (bDump, typeClass, keyName);
792 				fprintf(stdout, "  Method %d, Parameter %d: Type1 = %s  !=  Type2 = %s\n", index, i,
793 						U2S(reader1.getMethodParameterTypeName(index, i)),
794 						U2S(reader2.getMethodParameterTypeName(index, i)));
795 			}
796 			nError++;
797 		}
798 		if ( options.fullCheck() && (reader1.getMethodParameterName(index, i) != reader2.getMethodParameterName(index, i)) )
799 		{
800 			if ( options.forceOutput() )
801 			{
802                 dumpTypeClass (bDump, typeClass, keyName);
803 				fprintf(stdout, "  Method %d, Parameter %d: Name1 = %s  !=  Name2 = %s\n", index, i,
804 						U2S(reader1.getMethodParameterName(index, i)),
805 						U2S(reader2.getMethodParameterName(index, i)));
806 			}
807 			nError++;
808 		}
809 		if ( reader1.getMethodParameterFlags(index, i) != reader2.getMethodParameterFlags(index, i) )
810 		{
811 			if ( options.forceOutput() )
812 			{
813                 dumpTypeClass (bDump, typeClass, keyName);
814 				fprintf(stdout, "  Method %d, Parameter %d: Mode1 = %s  !=  Mode2 = %s\n", index, i,
815 						getParamMode(reader1.getMethodParameterFlags(index, i)),
816 						getParamMode(reader2.getMethodParameterFlags(index, i)));
817 			}
818 			nError++;
819 		}
820 	}
821 	if ( i < nParams1 && options.forceOutput() )
822 	{
823         dumpTypeClass (bDump, typeClass, keyName);
824 		fprintf(stdout, "  Registry1: Method %d contains %d more parameters\n", index, nParams1 - i);
825 	}
826 	if ( i < nParams2 && options.forceOutput() )
827 	{
828         dumpTypeClass (bDump, typeClass, keyName);
829 		fprintf(stdout, "  Registry2: Method %d contains %d more parameters\n", index, nParams2 - i);
830 	}
831 
832 	sal_uInt16 nExcep1 = (sal_uInt16)reader1.getMethodExceptionCount(index);
833 	sal_uInt16 nExcep2 = (sal_uInt16)reader2.getMethodExceptionCount(index);
834 	if ( nExcep1 != nExcep2 )
835 	{
836 		if ( options.forceOutput() )
837 		{
838             dumpTypeClass (bDump, typeClass, keyName);
839 			fprintf(stdout, "  nExceptions1 = %d  !=  nExceptions2 = %d\n", nExcep1, nExcep2);
840 		}
841 		nError++;
842 	}
843 	for (i=0; i < nExcep1 && i < nExcep2; i++)
844 	{
845 		if ( reader1.getMethodExceptionTypeName(index, i) != reader2.getMethodExceptionTypeName(index, i) )
846 		{
847 			if ( options.forceOutput() )
848 			{
849                 dumpTypeClass (bDump, typeClass, keyName);
850 				fprintf(stdout, "  Method %d, Exception %d: Name1 = %s  !=  Name2 = %s\n", index, i,
851 						U2S(reader1.getMethodExceptionTypeName(index, i)),
852 						U2S(reader2.getMethodExceptionTypeName(index, i)));
853 			}
854 			nError++;
855 		}
856 	}
857 	if ( i < nExcep1 && options.forceOutput() )
858 	{
859         dumpTypeClass (bDump, typeClass, keyName);
860 		fprintf(stdout, "  Registry1: Method %d contains %d more exceptions\n", index, nExcep1 - i);
861 	}
862 	if ( i < nExcep2 && options.forceOutput() )
863 	{
864         dumpTypeClass (bDump, typeClass, keyName);
865 		fprintf(stdout, "  Registry2: Method %d contains %d more exceptions\n", index, nExcep2 - i);
866 	}
867 
868 	if ( reader1.getMethodFlags(index) != reader2.getMethodFlags(index) )
869 	{
870 		if ( options.forceOutput() )
871 		{
872             dumpTypeClass (bDump, typeClass, keyName);
873 			fprintf(stdout, "  Method %d: Mode1 = %s  !=  Mode2 = %s\n", index,
874 					getMethodMode(reader1.getMethodFlags(index)),
875 					getMethodMode(reader2.getMethodFlags(index)));
876 		}
877 		nError++;
878 	}
879 
880 	if ( options.fullCheck() && (reader1.getMethodDocumentation(index) != reader2.getMethodDocumentation(index)) )
881 	{
882 		if ( options.forceOutput() )
883 		{
884             dumpTypeClass (bDump, typeClass, keyName);
885 			fprintf(stdout, "  Method %d: Doku1 = %s\n              Doku2 = %s\n", index,
886 					U2S(reader1.getMethodDocumentation(index)),
887 					U2S(reader2.getMethodDocumentation(index)));
888 		}
889 		nError++;
890 	}
891 	return nError;
892 }
893 
894 static char const * getReferenceType(RTReferenceType refType)
895 {
896 	switch (refType)
897 	{
898 		case RT_REF_SUPPORTS:
899 			return "RT_REF_SUPPORTS";
900 		case RT_REF_OBSERVES:
901 			return "RT_REF_OBSERVES";
902 		case RT_REF_EXPORTS:
903 			return "RT_REF_EXPORTS";
904 		case RT_REF_NEEDS:
905 			return "RT_REF_NEEDS";
906         default:
907         	return "RT_REF_INVALID";
908 	}
909 }
910 
911 static sal_uInt32 checkReference(Options_Impl const & options,
912                                  const OUString& keyName,
913 								 RTTypeClass typeClass,
914 								 sal_Bool & bDump,
915 								 typereg::Reader& reader1,
916 							   	 typereg::Reader& reader2,
917 							   	 sal_uInt16 index1,
918 								 sal_uInt16 index2)
919 {
920 	sal_uInt32 nError = 0;
921 	if ( reader1.getReferenceTypeName(index1) != reader2.getReferenceTypeName(index2) )
922 	{
923 		if ( options.forceOutput() && !options.unoTypeCheck() )
924 		{
925             dumpTypeClass (bDump, typeClass, keyName);
926 			fprintf(stdout, "  Reference %d: Name1 = %s  !=  Name2 = %s\n", index1,
927 					U2S(reader1.getReferenceTypeName(index1)),
928 					U2S(reader2.getReferenceTypeName(index2)));
929 		}
930 		nError++;
931 	}
932 	if ( reader1.getReferenceTypeName(index1) != reader2.getReferenceTypeName(index2) )
933 	{
934 		if ( options.forceOutput() && !options.unoTypeCheck() )
935 		{
936             dumpTypeClass (bDump, typeClass, keyName);
937 			fprintf(stdout, "  Reference %d: Type1 = %s  !=  Type2 = %s\n", index1,
938 					getReferenceType(reader1.getReferenceSort(index1)),
939 					getReferenceType(reader2.getReferenceSort(index2)));
940 		}
941 		nError++;
942 	}
943 	if ( options.fullCheck() && (reader1.getReferenceDocumentation(index1) != reader2.getReferenceDocumentation(index2)) )
944 	{
945 		if ( options.forceOutput() && !options.unoTypeCheck() )
946 		{
947             dumpTypeClass (bDump, typeClass, keyName);
948 			fprintf(stdout, "  Reference %d: Doku1 = %s\n                 Doku2 = %s\n", index1,
949 					U2S(reader1.getReferenceDocumentation(index1)),
950 					U2S(reader2.getReferenceDocumentation(index2)));
951 		}
952 		nError++;
953 	}
954 	if ( reader1.getReferenceFlags(index1) != reader2.getReferenceFlags(index2) )
955 	{
956 		if ( options.forceOutput() && !options.unoTypeCheck() )
957 		{
958             dumpTypeClass (bDump, typeClass, keyName);
959 			fprintf(stdout, "  Reference %d: Access1 = %s  !=  Access2 = %s\n", index1,
960 					getFieldAccess(reader1.getReferenceFlags(index1)).getStr(),
961 					getFieldAccess(reader1.getReferenceFlags(index2)).getStr());
962 		}
963 		nError++;
964 	}
965 	return nError;
966 }
967 
968 static sal_uInt32 checkFieldsWithoutOrder(Options_Impl const & options,
969                                           const OUString& keyName,
970                                           RTTypeClass typeClass,
971                                           sal_Bool & bDump,
972                                           typereg::Reader& reader1,
973                                           typereg::Reader& reader2)
974 {
975 	sal_uInt32 nError = 0;
976 
977 	sal_uInt16 nFields1 = (sal_uInt16)reader1.getFieldCount();
978 	sal_uInt16 nFields2 = (sal_uInt16)reader2.getFieldCount();
979     sal_uInt16 i=0, j=0;
980 
981     if ( nFields1 > nFields2 )
982     {
983 		if ( options.forceOutput() )
984 		{
985             dumpTypeClass (bDump, typeClass, keyName);
986             fprintf(stdout, "  %s1 contains %d more properties as %s2\n",
987                     getTypeClass(typeClass), nFields1-nFields2, getTypeClass(typeClass));
988         }
989     }
990 
991     sal_Bool bFound = sal_False;
992     ::std::set< sal_uInt16 > moreProps;
993 
994     for (i=0; i < nFields1; i++)
995     {
996         for (j=0; j < nFields2; j++)
997         {
998             if (!checkField(options, keyName, typeClass, bDump, reader1, reader2, i, j))
999             {
1000                 bFound =  sal_True;
1001                 moreProps.insert(j);
1002                 break;
1003             }
1004         }
1005         if (!bFound)
1006         {
1007             if (options.forceOutput())
1008             {
1009                 dumpTypeClass (bDump, typeClass, keyName);
1010                 fprintf(stdout, "  incompatible change: Field %d ('%s') of r1 is not longer a property of this %s in r2\n",
1011                         i, U2S(shortName(reader1.getFieldName(i))), getTypeClass(typeClass));
1012             }
1013             nError++;
1014         }
1015         else
1016 		{
1017 			bFound = sal_False;
1018 		}
1019     }
1020 
1021     if ( typeClass == RT_TYPE_SERVICE && !moreProps.empty() )
1022     {
1023         for (j=0; j < nFields2; j++)
1024         {
1025             if ( moreProps.find(j) == moreProps.end() )
1026             {
1027                 if ( (reader2.getFieldFlags(j) & RT_ACCESS_OPTIONAL) != RT_ACCESS_OPTIONAL )
1028                 {
1029                     if ( options.forceOutput() )
1030                     {
1031                         dumpTypeClass (bDump, typeClass, keyName);
1032                         fprintf(stdout,
1033                                 "  incompatible change: Field %d ('%s') of r2 is a new property"
1034                                 " compared to this %s in r1 and is not 'optional'\n",
1035                                 j, U2S(shortName(reader2.getFieldName(j))), getTypeClass(typeClass));
1036                     }
1037                     nError++;
1038                 }
1039             }
1040         }
1041     }
1042 
1043     return nError;
1044 }
1045 
1046 static sal_uInt32 checkBlob(
1047     Options_Impl const & options,
1048     const OUString& keyName,
1049     typereg::Reader& reader1, sal_uInt32 size1,
1050     typereg::Reader& reader2, sal_uInt32 size2)
1051 {
1052 	sal_uInt32 nError = 0;
1053 	sal_Bool bDump = sal_True;
1054 
1055 	if ( options.fullCheck() && (size1 != size2) )
1056 	{
1057 		if ( options.forceOutput() )
1058 		{
1059 			fprintf(
1060                 stdout, "    Size1 = %lu    Size2 = %lu\n",
1061                 sal::static_int_cast< unsigned long >(size1),
1062                 sal::static_int_cast< unsigned long >(size2));
1063 		}
1064 	}
1065     if (reader1.isPublished())
1066     {
1067         if (!reader2.isPublished())
1068         {
1069             if (options.forceOutput())
1070             {
1071                 dumpTypeClass(bDump, /*"?"*/ reader1.getTypeClass(), keyName);
1072                 fprintf(stdout, "    published in 1 but unpublished in 2\n");
1073             }
1074             ++nError;
1075         }
1076     }
1077     else if (!options.checkUnpublished())
1078     {
1079         return nError;
1080     }
1081 	if ( reader1.getTypeClass() != reader2.getTypeClass() )
1082 	{
1083 		if ( options.forceOutput() )
1084 		{
1085             dumpTypeClass(bDump, /*"?"*/ reader1.getTypeClass(), keyName);
1086 			fprintf(stdout, "    TypeClass1 = %s  !=  TypeClass2 = %s\n",
1087 					getTypeClass(reader1.getTypeClass()),
1088 					getTypeClass(reader2.getTypeClass()));
1089 		}
1090 		return ++nError;
1091 	}
1092 
1093 	RTTypeClass typeClass = reader1.getTypeClass();
1094 	if ( reader1.getTypeName() != reader2.getTypeName() )
1095 	{
1096 		if ( options.forceOutput() )
1097 		{
1098             dumpTypeClass(bDump, typeClass, keyName);
1099 			fprintf(stdout, "    TypeName1 = %s  !=  TypeName2 = %s\n",
1100 					U2S(reader1.getTypeName()), U2S(reader2.getTypeName()));
1101 		}
1102 		nError++;
1103 	}
1104 	if ( (typeClass == RT_TYPE_INTERFACE ||
1105 		  typeClass == RT_TYPE_STRUCT ||
1106 		  typeClass == RT_TYPE_EXCEPTION) )
1107 	{
1108         if (reader1.getSuperTypeCount() != reader2.getSuperTypeCount())
1109         {
1110             dumpTypeClass(bDump, typeClass, keyName);
1111             fprintf(
1112                 stdout, "    SuperTypeCount1 = %d  !=  SuperTypeCount2 = %d\n",
1113                 static_cast< int >(reader1.getSuperTypeCount()),
1114                 static_cast< int >(reader2.getSuperTypeCount()));
1115             ++nError;
1116         } else
1117         {
1118             for (sal_Int16 i = 0; i < reader1.getSuperTypeCount(); ++i)
1119             {
1120                 if (reader1.getSuperTypeName(i) != reader2.getSuperTypeName(i))
1121                 {
1122                     if ( options.forceOutput() )
1123                     {
1124                         dumpTypeClass(bDump, typeClass, keyName);
1125                         fprintf(stdout, "    SuperTypeName1 = %s  !=  SuperTypeName2 = %s\n",
1126                                 U2S(reader1.getSuperTypeName(i)), U2S(reader2.getSuperTypeName(i)));
1127                     }
1128                     nError++;
1129                 }
1130             }
1131         }
1132 	}
1133 
1134 	sal_uInt16 nFields1 = (sal_uInt16)reader1.getFieldCount();
1135 	sal_uInt16 nFields2 = (sal_uInt16)reader2.getFieldCount();
1136 	sal_Bool bCheckNormal = sal_True;
1137 
1138 	if ( (typeClass == RT_TYPE_SERVICE ||
1139           typeClass == RT_TYPE_MODULE ||
1140           typeClass == RT_TYPE_CONSTANTS) && options.unoTypeCheck() )
1141 	{
1142 		bCheckNormal = sal_False;
1143 	}
1144 
1145 	if ( bCheckNormal )
1146 	{
1147         if ( nFields1 != nFields2 )
1148         {
1149             if ( options.forceOutput() )
1150             {
1151                 dumpTypeClass(bDump, typeClass, keyName);
1152                 fprintf(stdout, "    nFields1 = %d  !=  nFields2 = %d\n", nFields1, nFields2);
1153             }
1154             nError++;
1155         }
1156 
1157         sal_uInt16 i;
1158         for (i=0; i < nFields1 && i < nFields2; i++)
1159         {
1160             nError += checkField(options, keyName, typeClass, bDump, reader1, reader2, i, i);
1161         }
1162         if ( i < nFields1 && options.forceOutput() )
1163         {
1164             dumpTypeClass(bDump, typeClass, keyName);
1165             fprintf(stdout, "    Registry1 contains %d more fields\n", nFields1 - i);
1166         }
1167         if ( i < nFields2 && options.forceOutput() )
1168         {
1169             dumpTypeClass(bDump, typeClass, keyName);
1170             fprintf(stdout, "    Registry2 contains %d more fields\n", nFields2 - i);
1171         }
1172     }
1173     else
1174     {
1175         nError += checkFieldsWithoutOrder(options, keyName, typeClass, bDump, reader1, reader2);
1176     }
1177 
1178 	if ( typeClass == RT_TYPE_INTERFACE )
1179 	{
1180 		sal_uInt16 nMethods1 = (sal_uInt16)reader1.getMethodCount();
1181 		sal_uInt16 nMethods2 = (sal_uInt16)reader2.getMethodCount();
1182 		if ( nMethods1 != nMethods2 )
1183 		{
1184 			if ( options.forceOutput() )
1185 			{
1186                 dumpTypeClass(bDump, typeClass, keyName);
1187 				fprintf(stdout, "    nMethods1 = %d  !=  nMethods2 = %d\n", nMethods1, nMethods2);
1188 			}
1189 			nError++;
1190 		}
1191 
1192         sal_uInt16 i;
1193 		for (i=0; i < nMethods1 && i < nMethods2; i++)
1194 		{
1195 			nError += checkMethod(options, keyName, typeClass, bDump, reader1, reader2, i);
1196 		}
1197 		if ( i < nMethods1 && options.forceOutput() )
1198 		{
1199 			fprintf(stdout, "    Registry1 contains %d more methods\n", nMethods1 - i);
1200 		}
1201 		if ( i < nMethods2 && options.forceOutput() )
1202 		{
1203 			fprintf(stdout, "    Registry2 contains %d more methods\n", nMethods2 - i);
1204 		}
1205 	}
1206 	if ( typeClass == RT_TYPE_SERVICE )
1207 	{
1208         sal_uInt16 nReference1 = (sal_uInt16)reader1.getReferenceCount();
1209 		sal_uInt16 nReference2 = (sal_uInt16)reader2.getReferenceCount();
1210 
1211 		if ( !bCheckNormal )
1212 		{
1213 			sal_uInt16 i=0, j=0;
1214 
1215 			if ( nReference1 > nReference2 )
1216 			{
1217 				if ( options.forceOutput() )
1218 				{
1219                     dumpTypeClass(bDump, typeClass, keyName);
1220 					fprintf(stdout, "    service1 contains %d more references as service2\n",
1221 							nReference1-nReference2);
1222 				}
1223 			}
1224 
1225 			sal_Bool bFound = sal_False;
1226             ::std::set< sal_uInt16 > moreReferences;
1227 
1228 			for (i=0; i < nReference1; i++)
1229 			{
1230 				for (j=0; j < nReference2; j++)
1231 				{
1232 					if (!checkReference(options, keyName, typeClass, bDump, reader1, reader2, i, j))
1233 					{
1234 						bFound =  sal_True;
1235                         moreReferences.insert(j);
1236 						break;
1237 					}
1238 				}
1239 				if (!bFound)
1240 				{
1241 					if (options.forceOutput())
1242 					{
1243                         dumpTypeClass(bDump, typeClass, keyName);
1244 						fprintf(stdout,
1245                                 "  incompatible change: Reference %d ('%s') in 'r1' is not longer a reference"
1246                                 " of this service in 'r2'\n",
1247 							    i, U2S(shortName(reader1.getReferenceTypeName(i))));
1248 					}
1249 					nError++;
1250 				}
1251                 else
1252 				{
1253 					bFound = sal_False;
1254 				}
1255 			}
1256 
1257             if ( !moreReferences.empty() )
1258             {
1259                 for (j=0; j < nReference2; j++)
1260                 {
1261                     if ( moreReferences.find(j) == moreReferences.end() )
1262                     {
1263                         if ( (reader2.getReferenceFlags(j) & RT_ACCESS_OPTIONAL) != RT_ACCESS_OPTIONAL )
1264                         {
1265                             if ( options.forceOutput() )
1266                             {
1267                                 dumpTypeClass(bDump, typeClass, keyName);
1268                                 fprintf(stdout,
1269                                         "  incompatible change: Reference %d ('%s') of r2 is a new reference"
1270                                         " compared to this service in r1 and is not 'optional'\n",
1271 									    j, U2S(shortName(reader2.getReferenceTypeName(j))));
1272                             }
1273                             nError++;
1274                         }
1275                     }
1276                 }
1277             }
1278 		}
1279         else
1280 		{
1281 			if ( nReference1 != nReference2 )
1282 			{
1283 				if ( options.forceOutput() )
1284 				{
1285                     dumpTypeClass(bDump, typeClass, keyName);
1286 					fprintf(stdout, "    nReferences1 = %d  !=  nReferences2 = %d\n", nReference1, nReference2);
1287 				}
1288 				nError++;
1289 			}
1290 
1291             sal_uInt16 i;
1292 			for (i=0; i < nReference1 && i < nReference2; i++)
1293 			{
1294 				nError += checkReference(options, keyName, typeClass, bDump, reader1, reader2, i, i);
1295 			}
1296 			if ( i < nReference1 && options.forceOutput() )
1297 			{
1298 				fprintf(stdout, "    Registry1 contains %d more references\n", nReference1 - i);
1299 			}
1300 			if ( i < nReference2 && options.forceOutput() )
1301 			{
1302 				fprintf(stdout, "    Registry2 contains %d more references\n", nReference2 - i);
1303 			}
1304 		}
1305 	}
1306 
1307 	if ( options.fullCheck() && (reader1.getDocumentation() != reader2.getDocumentation()) )
1308 	{
1309 		if ( options.forceOutput() )
1310 		{
1311             dumpTypeClass(bDump, typeClass, keyName);
1312 			fprintf(stdout, "    Doku1 = %s\n    Doku2 = %s\n",
1313 					U2S(reader1.getDocumentation()), U2S(reader2.getDocumentation()));
1314 		}
1315 		nError++;
1316 	}
1317 	return nError;
1318 }
1319 
1320 static sal_uInt32 checkValueDifference(
1321     Options_Impl const & options,
1322     RegistryKey& key1, RegValueType valueType1, sal_uInt32 size1,
1323     RegistryKey& key2, RegValueType valueType2, sal_uInt32 size2)
1324 {
1325 	OUString tmpName;
1326 	sal_uInt32 nError = 0;
1327 
1328 	if ( valueType1 == valueType2 )
1329 	{
1330 		sal_Bool bEqual = sal_True;
1331         switch (valueType1)
1332         {
1333         case RG_VALUETYPE_LONGLIST:
1334             {
1335 				RegistryValueList<sal_Int32> valueList1;
1336 				RegistryValueList<sal_Int32> valueList2;
1337 				key1.getLongListValue(tmpName, valueList1);
1338 				key2.getLongListValue(tmpName, valueList2);
1339 				sal_uInt32 length1 = valueList1.getLength();
1340 				sal_uInt32 length2 = valueList1.getLength();
1341 				if ( length1 != length2 )
1342 				{
1343 					bEqual = sal_False;
1344 					break;
1345 				}
1346 				for (sal_uInt32 i=0; i<length1; i++)
1347 				{
1348 					if ( valueList1.getElement(i) != valueList2.getElement(i) )
1349 					{
1350 						bEqual = sal_False;
1351 						break;
1352 					}
1353 				}
1354             }
1355             break;
1356         case RG_VALUETYPE_STRINGLIST:
1357             {
1358 				RegistryValueList<sal_Char*> valueList1;
1359 				RegistryValueList<sal_Char*> valueList2;
1360 				key1.getStringListValue(tmpName, valueList1);
1361 				key2.getStringListValue(tmpName, valueList2);
1362 				sal_uInt32 length1 = valueList1.getLength();
1363 				sal_uInt32 length2 = valueList1.getLength();
1364 				if ( length1 != length2 )
1365 				{
1366 					bEqual = sal_False;
1367 					break;
1368 				}
1369 				for (sal_uInt32 i=0; i<length1; i++)
1370 				{
1371 					if ( strcmp(valueList1.getElement(i), valueList2.getElement(i)) != 0 )
1372 					{
1373 						bEqual = sal_False;
1374 						break;
1375 					}
1376 				}
1377             }
1378             break;
1379         case RG_VALUETYPE_UNICODELIST:
1380             {
1381 				RegistryValueList<sal_Unicode*> valueList1;
1382 				RegistryValueList<sal_Unicode*> valueList2;
1383 				key1.getUnicodeListValue(tmpName, valueList1);
1384 				key2.getUnicodeListValue(tmpName, valueList2);
1385 				sal_uInt32 length1 = valueList1.getLength();
1386 				sal_uInt32 length2 = valueList1.getLength();
1387 				if ( length1 != length2 )
1388 				{
1389 					bEqual = sal_False;
1390 					break;
1391 				}
1392 				for (sal_uInt32 i=0; i<length1; i++)
1393 				{
1394 					if ( rtl_ustr_compare(valueList1.getElement(i), valueList2.getElement(i)) != 0 )
1395 					{
1396 						bEqual = sal_False;
1397 						break;
1398 					}
1399 				}
1400             }
1401             break;
1402         default:
1403             break;
1404         }
1405 
1406 		if ( bEqual)
1407 		{
1408             std::vector< sal_uInt8 > value1(size1);
1409 			key1.getValue(tmpName, &value1[0]);
1410 
1411             std::vector< sal_uInt8 > value2(size2);
1412 			key2.getValue(tmpName, &value2[0]);
1413 
1414 			bEqual = (rtl_compareMemory(&value1[0], &value2[0], value1.size()) == 0 );
1415 			if ( !bEqual && valueType1 == RG_VALUETYPE_BINARY && valueType2 == RG_VALUETYPE_BINARY )
1416 			{
1417                 typereg::Reader reader1(&value1[0], value1.size(), false, TYPEREG_VERSION_1);
1418                 typereg::Reader reader2(&value2[0], value2.size(), false, TYPEREG_VERSION_1);
1419 				if ( reader1.isValid() && reader2.isValid() )
1420 				{
1421 					return checkBlob(options, key1.getName(), reader1, size1, reader2, size2);
1422 				}
1423 			}
1424 			if ( bEqual )
1425 			{
1426 				return 0;
1427 			}
1428             else
1429 			{
1430 				if ( options.forceOutput() )
1431 				{
1432 					fprintf(stdout, "Difference: key values of key \"%s\" are different\n", U2S(key1.getName()));
1433 				}
1434 				nError++;
1435 			}
1436 		}
1437 	}
1438 
1439 	if ( options.forceOutput() )
1440 	{
1441 		switch (valueType1)
1442 		{
1443 		case RG_VALUETYPE_NOT_DEFINED:
1444 			fprintf(stdout, "    Registry 1: key has no value\n");
1445 			break;
1446 		case RG_VALUETYPE_LONG:
1447             {
1448                 std::vector< sal_uInt8 > value1(size1);
1449                 key1.getValue(tmpName, &value1[0]);
1450 
1451                 fprintf(stdout, "    Registry 1: Value: Type = RG_VALUETYPE_LONG\n");
1452                 fprintf(
1453                     stdout, "                       Size = %lu\n",
1454                     sal::static_int_cast< unsigned long >(size1));
1455                 fprintf(stdout, "                       Data = %p\n", &value1[0]);
1456             }
1457             break;
1458 		case RG_VALUETYPE_STRING:
1459             {
1460                 std::vector< sal_uInt8 > value1(size1);
1461                 key1.getValue(tmpName, &value1[0]);
1462 
1463                 fprintf(stdout, "    Registry 1: Value: Type = RG_VALUETYPE_STRING\n");
1464                 fprintf(
1465                     stdout, "                       Size = %lu\n",
1466                     sal::static_int_cast< unsigned long >(size1));
1467                 fprintf(stdout, "                       Data = \"%s\"\n", reinterpret_cast<char const*>(&value1[0]));
1468             }
1469             break;
1470 		case RG_VALUETYPE_UNICODE:
1471             {
1472                 std::vector< sal_uInt8 > value1(size1);
1473                 key1.getValue(tmpName, &value1[0]);
1474 
1475                 OUString uStrValue(reinterpret_cast<sal_Unicode const*>(&value1[0]));
1476                 fprintf(stdout, "    Registry 1: Value: Type = RG_VALUETYPE_UNICODE\n");
1477                 fprintf(
1478                     stdout, "                       Size = %lu\n",
1479                     sal::static_int_cast< unsigned long >(size1));
1480                 fprintf(stdout, "                       Data = \"%s\"\n", U2S(uStrValue));
1481             }
1482             break;
1483 		case RG_VALUETYPE_BINARY:
1484 			fprintf(stdout, "    Registry 1: Value: Type = RG_VALUETYPE_BINARY\n");
1485 			break;
1486 		case RG_VALUETYPE_LONGLIST:
1487 			{
1488                 RegistryValueList<sal_Int32> valueList;
1489                 key1.getLongListValue(tmpName, valueList);
1490                 fprintf(stdout, "    Registry 1: Value: Type = RG_VALUETYPE_LONGLIST\n");
1491                 fprintf(
1492                     stdout, "                       Size = %lu\n",
1493                     sal::static_int_cast< unsigned long >(size1));
1494                 sal_uInt32 length = valueList.getLength();
1495                 for (sal_uInt32 i=0; i<length; i++)
1496                 {
1497                     fprintf(
1498                         stdout, "                       Data[%lu] = %ld\n",
1499                         sal::static_int_cast< unsigned long >(i),
1500                         sal::static_int_cast< long >(valueList.getElement(i)));
1501                 }
1502 			}
1503 			break;
1504 		case RG_VALUETYPE_STRINGLIST:
1505 			{
1506                 RegistryValueList<sal_Char*> valueList;
1507                 key1.getStringListValue(tmpName, valueList);
1508                 fprintf(stdout, "    Registry 1: Value: Type = RG_VALUETYPE_STRINGLIST\n");
1509                 fprintf(
1510                     stdout, "                       Size = %lu\n",
1511                     sal::static_int_cast< unsigned long >(size1));
1512                 sal_uInt32 length = valueList.getLength();
1513                 for (sal_uInt32 i=0; i<length; i++)
1514                 {
1515                     fprintf(
1516                         stdout, "                       Data[%lu] = \"%s\"\n",
1517                         sal::static_int_cast< unsigned long >(i),
1518                         valueList.getElement(i));
1519                 }
1520 			}
1521 			break;
1522 		case RG_VALUETYPE_UNICODELIST:
1523 			{
1524                 RegistryValueList<sal_Unicode*> valueList;
1525                 key1.getUnicodeListValue(tmpName, valueList);
1526                 fprintf(stdout, "    Registry 1: Value: Type = RG_VALUETYPE_UNICODELIST\n");
1527                 fprintf(
1528                     stdout, "                       Size = %lu\n",
1529                     sal::static_int_cast< unsigned long >(size1));
1530                 sal_uInt32 length = valueList.getLength();
1531                 OUString uStrValue;
1532                 for (sal_uInt32 i=0; i<length; i++)
1533                 {
1534                     uStrValue = OUString(valueList.getElement(i));
1535                     fprintf(
1536                         stdout, "                       Data[%lu] = \"%s\"\n",
1537                         sal::static_int_cast< unsigned long >(i), U2S(uStrValue));
1538                 }
1539 			}
1540 			break;
1541 		}
1542 
1543 		switch (valueType2)
1544 		{
1545 		case RG_VALUETYPE_NOT_DEFINED:
1546 			fprintf(stdout, "    Registry 2: key has no value\n");
1547 			break;
1548 		case RG_VALUETYPE_LONG:
1549             {
1550                 std::vector< sal_uInt8 > value2(size2);
1551                 key2.getValue(tmpName, &value2[0]);
1552 
1553 				fprintf(stdout, "    Registry 2: Value: Type = RG_VALUETYPE_LONG\n");
1554 				fprintf(
1555                     stdout, "                       Size = %lu\n",
1556                     sal::static_int_cast< unsigned long >(size2));
1557 				fprintf(stdout, "                       Data = %p\n", &value2[0]);
1558             }
1559             break;
1560 		case RG_VALUETYPE_STRING:
1561             {
1562                 std::vector< sal_uInt8 > value2(size2);
1563                 key2.getValue(tmpName, &value2[0]);
1564 
1565 				fprintf(stdout, "    Registry 2: Value: Type = RG_VALUETYPE_STRING\n");
1566 				fprintf(
1567                     stdout, "                       Size = %lu\n",
1568                     sal::static_int_cast< unsigned long >(size2));
1569 				fprintf(stdout, "                       Data = \"%s\"\n", reinterpret_cast<char const*>(&value2[0]));
1570             }
1571             break;
1572 		case RG_VALUETYPE_UNICODE:
1573             {
1574                 std::vector< sal_uInt8 > value2(size2);
1575                 key2.getValue(tmpName, &value2[0]);
1576 
1577 				OUString uStrValue(reinterpret_cast<sal_Unicode const*>(&value2[0]));
1578 				fprintf(stdout, "    Registry 2: Value: Type = RG_VALUETYPE_UNICODE\n");
1579 				fprintf(
1580                     stdout, "                       Size = %lu\n",
1581                     sal::static_int_cast< unsigned long >(size2));
1582 				fprintf(stdout, "                       Data = \"%s\"\n", U2S(uStrValue));
1583             }
1584             break;
1585 		case RG_VALUETYPE_BINARY:
1586 			fprintf(stdout, "    Registry 2: Value: Type = RG_VALUETYPE_BINARY\n");
1587 			break;
1588 		case RG_VALUETYPE_LONGLIST:
1589 			{
1590                 RegistryValueList<sal_Int32> valueList;
1591                 key2.getLongListValue(tmpName, valueList);
1592                 fprintf(stdout, "    Registry 2: Value: Type = RG_VALUETYPE_LONGLIST\n");
1593                 fprintf(
1594                     stdout, "                       Size = %lu\n",
1595                     sal::static_int_cast< unsigned long >(size2));
1596                 sal_uInt32 length = valueList.getLength();
1597                 for (sal_uInt32 i=0; i<length; i++)
1598                 {
1599                     fprintf(
1600                         stdout, "                       Data[%lu] = %ld\n",
1601                         sal::static_int_cast< unsigned long >(i),
1602                         sal::static_int_cast< long >(valueList.getElement(i)));
1603                 }
1604 			}
1605 			break;
1606 		case RG_VALUETYPE_STRINGLIST:
1607 			{
1608                 RegistryValueList<sal_Char*> valueList;
1609                 key2.getStringListValue(tmpName, valueList);
1610                 fprintf(stdout, "    Registry 2: Value: Type = RG_VALUETYPE_STRINGLIST\n");
1611                 fprintf(
1612                     stdout, "                       Size = %lu\n",
1613                     sal::static_int_cast< unsigned long >(size2));
1614                 sal_uInt32 length = valueList.getLength();
1615                 for (sal_uInt32 i=0; i<length; i++)
1616                 {
1617                     fprintf(
1618                         stdout, "                       Data[%lu] = \"%s\"\n",
1619                         sal::static_int_cast< unsigned long >(i),
1620                         valueList.getElement(i));
1621                 }
1622 			}
1623 			break;
1624 		case RG_VALUETYPE_UNICODELIST:
1625 			{
1626                 RegistryValueList<sal_Unicode*> valueList;
1627                 key2.getUnicodeListValue(tmpName, valueList);
1628                 fprintf(stdout, "    Registry 2: Value: Type = RG_VALUETYPE_UNICODELIST\n");
1629                 fprintf(
1630                     stdout, "                       Size = %lu\n",
1631                     sal::static_int_cast< unsigned long >(size2));
1632                 sal_uInt32 length = valueList.getLength();
1633                 OUString uStrValue;
1634                 for (sal_uInt32 i=0; i<length; i++)
1635                 {
1636                     uStrValue = OUString(valueList.getElement(i));
1637                     fprintf(
1638                         stdout, "                       Data[%lu] = \"%s\"\n",
1639                         sal::static_int_cast< unsigned long >(i), U2S(uStrValue));
1640                 }
1641 			}
1642 			break;
1643 		}
1644 	}
1645 	return nError;
1646 }
1647 
1648 static bool hasPublishedChildren(Options_Impl const & options, RegistryKey & key)
1649 {
1650 	RegistryKeyNames subKeyNames;
1651 	key.getKeyNames(rtl::OUString(), subKeyNames);
1652     for (sal_uInt32 i = 0; i < subKeyNames.getLength(); ++i)
1653     {
1654         rtl::OUString keyName(subKeyNames.getElement(i));
1655         if (!options.matchedWithExcludeKey(keyName))
1656         {
1657             keyName = keyName.copy(keyName.lastIndexOf('/') + 1);
1658             RegistryKey subKey;
1659             if (!key.openKey(keyName, subKey))
1660             {
1661                 if (options.forceOutput())
1662                 {
1663                     fprintf(
1664                         stdout,
1665                         ("WARNING: could not open key \"%s\" in registry"
1666                          " \"%s\"\n"),
1667                         U2S(subKeyNames.getElement(i)),
1668                         options.getRegName1().c_str());
1669                 }
1670             }
1671             if (subKey.isValid())
1672             {
1673                 RegValueType type;
1674                 sal_uInt32 size;
1675                 if (subKey.getValueInfo(rtl::OUString(), &type, &size) != REG_NO_ERROR)
1676                 {
1677                     if (options.forceOutput())
1678                     {
1679                         fprintf(
1680                             stdout,
1681                             ("WARNING: could not read key \"%s\" in registry"
1682                              " \"%s\"\n"),
1683                             U2S(subKeyNames.getElement(i)),
1684                             options.getRegName1().c_str());
1685                     }
1686                 }
1687                 else if (type == RG_VALUETYPE_BINARY)
1688                 {
1689                     bool published = false;
1690                     std::vector< sal_uInt8 > value(size);
1691                     if (subKey.getValue(rtl::OUString(), &value[0]) != REG_NO_ERROR)
1692                     {
1693                         if (options.forceOutput())
1694                         {
1695                             fprintf(
1696                                 stdout,
1697                                 ("WARNING: could not read key \"%s\" in"
1698                                  " registry \"%s\"\n"),
1699                                 U2S(subKeyNames.getElement(i)),
1700                                 options.getRegName1().c_str());
1701                         }
1702                     }
1703                     else
1704                     {
1705                         published = typereg::Reader(&value[0], value.size(), false, TYPEREG_VERSION_1).isPublished();
1706                     }
1707                     if (published)
1708                     {
1709                         return true;
1710                     }
1711                 }
1712             }
1713         }
1714     }
1715     return false;
1716 }
1717 
1718 static sal_uInt32 checkDifferences(
1719     Options_Impl const & options,
1720     RegistryKey& key, StringSet& keys,
1721     RegistryKeyNames& subKeyNames1,
1722     RegistryKeyNames& subKeyNames2)
1723 {
1724 	sal_uInt32 nError = 0;
1725 	sal_uInt32 length1 = subKeyNames1.getLength();
1726 	sal_uInt32 length2 = subKeyNames2.getLength();
1727 	sal_uInt32 i,j;
1728 
1729 	for (i=0; i<length1; i++)
1730 	{
1731         sal_Bool bFound = sal_False;
1732 		for (j=0; j<length2; j++)
1733 		{
1734 			if ( subKeyNames1.getElement(i) == subKeyNames2.getElement(j) )
1735 			{
1736 				bFound = sal_True;
1737 				keys.insert(subKeyNames1.getElement(i));
1738 				break;
1739 			}
1740 		}
1741 		if ( !bFound )
1742 		{
1743             if ( options.fullCheck() )
1744             {
1745                 if ( options.forceOutput() )
1746                 {
1747                     fprintf(stdout, "EXISTENCE: key \"%s\" exists only in registry \"%s\"\n",
1748                             U2S(subKeyNames1.getElement(i)), options.getRegName1().c_str());
1749                 }
1750                 nError++;
1751             }
1752             else
1753             {
1754                 rtl::OUString keyName(subKeyNames1.getElement(i));
1755                 if (!options.matchedWithExcludeKey(keyName))
1756                 {
1757                     keyName = keyName.copy(keyName.lastIndexOf('/') + 1);
1758                     RegistryKey subKey;
1759                     if (key.openKey(keyName, subKey))
1760                     {
1761                         if (options.forceOutput())
1762                         {
1763                             fprintf(
1764                                 stdout,
1765                                 ("ERROR: could not open key \"%s\" in registry"
1766                                  " \"%s\"\n"),
1767                                 U2S(subKeyNames1.getElement(i)),
1768                                 options.getRegName1().c_str());
1769                         }
1770                         ++nError;
1771                     }
1772                     if (subKey.isValid())
1773                     {
1774                         RegValueType type;
1775                         sal_uInt32 size;
1776                         if (subKey.getValueInfo(rtl::OUString(), &type, &size) != REG_NO_ERROR)
1777                         {
1778                             if (options.forceOutput())
1779                             {
1780                                 fprintf(
1781                                     stdout,
1782                                     ("ERROR: could not read key \"%s\" in"
1783                                      " registry \"%s\"\n"),
1784                                     U2S(subKeyNames1.getElement(i)),
1785                                     options.getRegName1().c_str());
1786                             }
1787                             ++nError;
1788                         }
1789                         else if (type == RG_VALUETYPE_BINARY)
1790                         {
1791                             std::vector< sal_uInt8 > value(size);
1792                             if (subKey.getValue(rtl::OUString(), &value[0]) != REG_NO_ERROR)
1793                             {
1794                                 if (options.forceOutput())
1795                                 {
1796                                     fprintf(
1797                                         stdout,
1798                                         ("ERROR: could not read key \"%s\" in"
1799                                          " registry \"%s\"\n"),
1800                                         U2S(subKeyNames1.getElement(i)),
1801                                         options.getRegName1().c_str());
1802                                 }
1803                                 ++nError;
1804                             }
1805                             else
1806                             {
1807                                 typereg::Reader reader(&value[0], value.size(), false, TYPEREG_VERSION_1);
1808                                 if (reader.getTypeClass() == RT_TYPE_MODULE)
1809                                 {
1810                                     if (options.checkUnpublished() || hasPublishedChildren(options, subKey))
1811                                     {
1812                                         if (options.forceOutput())
1813                                         {
1814                                             fprintf(
1815                                                 stdout,
1816                                                 ("EXISTENCE: module \"%s\""
1817                                                  " %sexists only in registry"
1818                                                  " 1\n"),
1819                                                 U2S(subKeyNames1.getElement(i)),
1820                                                 (options.checkUnpublished()
1821                                                  ? ""
1822                                                  : "with published children "));
1823                                         }
1824                                         ++nError;
1825                                     }
1826                                 }
1827                                 else if (options.checkUnpublished() || reader.isPublished())
1828                                 {
1829                                     if (options.forceOutput())
1830                                     {
1831                                         fprintf(
1832                                             stdout,
1833                                             ("EXISTENCE: %spublished key \"%s\""
1834                                              " exists only in registry 1\n"),
1835                                             reader.isPublished() ? "" : "un",
1836                                             U2S(subKeyNames1.getElement(i)));
1837                                     }
1838                                     ++nError;
1839                                 }
1840                             }
1841                         }
1842                     }
1843                 }
1844             }
1845 		}
1846 	}
1847 
1848 	for (i=0; i<length2; i++)
1849 	{
1850         sal_Bool bFound = sal_False;
1851 		for (j=0; j<length1; j++)
1852 		{
1853 			if ( subKeyNames2.getElement(i) == subKeyNames1.getElement(j) )
1854 			{
1855 				bFound = sal_True;
1856 				keys.insert(subKeyNames2.getElement(i));
1857 				break;
1858 			}
1859 		}
1860 		if ( !bFound && options.fullCheck() )
1861 		{
1862 			if ( options.forceOutput() )
1863 			{
1864 				fprintf(stdout, "EXISTENCE: key \"%s\" exists only in registry \"%s\"\n",
1865 						U2S(subKeyNames2.getElement(i)), options.getRegName2().c_str());
1866 			}
1867 			nError++;
1868 		}
1869 	}
1870 	return nError;
1871 }
1872 
1873 static sal_uInt32 compareKeys(
1874     Options_Impl const & options,
1875     RegistryKey& key1,
1876     RegistryKey& key2)
1877 {
1878 	sal_uInt32 nError = 0;
1879 
1880 	RegValueType valueType1 = RG_VALUETYPE_NOT_DEFINED;
1881 	RegValueType valueType2 = RG_VALUETYPE_NOT_DEFINED;
1882 	sal_uInt32 size1 = 0;
1883 	sal_uInt32 size2 = 0;
1884 
1885 	OUString tmpName;
1886 	RegError e1 = key1.getValueInfo(tmpName, &valueType1, &size1);
1887 	RegError e2 = key2.getValueInfo(tmpName, &valueType2, &size2);
1888 	if ( (e1 == e2) && (e1 != REG_VALUE_NOT_EXISTS) && (e1 != REG_INVALID_VALUE) )
1889 	{
1890 		nError += checkValueDifference(options, key1, valueType1, size1, key2, valueType2, size2);
1891 	}
1892     else
1893 	{
1894 		if ( (e1 != REG_INVALID_VALUE) || (e2 != REG_INVALID_VALUE) )
1895 		{
1896 			if ( options.forceOutput() )
1897 			{
1898 				fprintf(stdout, "VALUES: key values of key \"%s\" are different\n", U2S(key1.getName()));
1899 			}
1900 			nError++;
1901 		}
1902 	}
1903 
1904 	RegistryKeyNames subKeyNames1;
1905 	RegistryKeyNames subKeyNames2;
1906 
1907 	key1.getKeyNames(tmpName, subKeyNames1);
1908 	key2.getKeyNames(tmpName, subKeyNames2);
1909 
1910 	StringSet keys;
1911 	nError += checkDifferences(options, key1, keys, subKeyNames1, subKeyNames2);
1912 
1913 	StringSet::iterator iter = keys.begin();
1914 	StringSet::iterator end = keys.end();
1915 
1916 	while ( iter !=  end )
1917 	{
1918         OUString keyName(*iter);
1919 		if ( options.matchedWithExcludeKey(keyName) )
1920 		{
1921 			++iter;
1922 			continue;
1923 		}
1924 
1925         sal_Int32 nPos = keyName.lastIndexOf( '/' );
1926         keyName = keyName.copy( nPos != -1 ? nPos+1 : 0 );
1927 
1928         RegistryKey subKey1;
1929 		if ( key1.openKey(keyName, subKey1) )
1930 		{
1931 			if ( options.forceOutput() )
1932 			{
1933 				fprintf(stdout, "ERROR: could not open key \"%s\" in registry \"%s\"\n",
1934 						U2S(*iter), options.getRegName1().c_str());
1935 			}
1936 			nError++;
1937 		}
1938 
1939         RegistryKey subKey2;
1940 		if ( key2.openKey(keyName, subKey2) )
1941 		{
1942 			if ( options.forceOutput() )
1943 			{
1944 				fprintf(stdout, "ERROR: could not open key \"%s\" in registry \"%s\"\n",
1945 						U2S(*iter), options.getRegName2().c_str());
1946 			}
1947 			nError++;
1948 		}
1949 
1950 		if ( subKey1.isValid() && subKey2.isValid() )
1951 		{
1952 			nError += compareKeys(options, subKey1, subKey2);
1953 		}
1954 		++iter;
1955 	}
1956 
1957 	return nError;
1958 }
1959 
1960 #if (defined UNX) || (defined OS2) || defined __MINGW32__
1961 int main( int argc, char * argv[] )
1962 #else
1963 int _cdecl main( int argc, char * argv[] )
1964 #endif
1965 {
1966     std::vector< std::string > args;
1967 
1968     Options_Impl options(argv[0]);
1969     for (int i = 1; i < argc; i++)
1970     {
1971         if (!Options::checkArgument(args, argv[i], strlen(argv[i])))
1972         {
1973             // failure.
1974             options.printUsage();
1975             return (1);
1976         }
1977     }
1978 	if (!options.initOptions(args))
1979 	{
1980 		return (1);
1981 	}
1982 
1983 	OUString regName1( convertToFileUrl(options.getRegName1().c_str(), options.getRegName1().size()) );
1984 	OUString regName2( convertToFileUrl(options.getRegName2().c_str(), options.getRegName2().size()) );
1985 
1986 	Registry reg1, reg2;
1987 	if ( reg1.open(regName1, REG_READONLY) )
1988 	{
1989 		fprintf(stdout, "%s: open registry \"%s\" failed\n",
1990 				options.getProgramName().c_str(), options.getRegName1().c_str());
1991 		return (2);
1992 	}
1993 	if ( reg2.open(regName2, REG_READONLY) )
1994 	{
1995 		fprintf(stdout, "%s: open registry \"%s\" failed\n",
1996 				options.getProgramName().c_str(), options.getRegName2().c_str());
1997 		return (3);
1998 	}
1999 
2000 	RegistryKey key1, key2;
2001 	if ( reg1.openRootKey(key1) )
2002 	{
2003 		fprintf(stdout, "%s: open root key of registry \"%s\" failed\n",
2004 				options.getProgramName().c_str(), options.getRegName1().c_str());
2005 		return (4);
2006 	}
2007 	if ( reg2.openRootKey(key2) )
2008 	{
2009 		fprintf(stdout, "%s: open root key of registry \"%s\" failed\n",
2010 				options.getProgramName().c_str(), options.getRegName2().c_str());
2011 		return (5);
2012 	}
2013 
2014 	if ( options.isStartKeyValid() )
2015 	{
2016 		if ( options.matchedWithExcludeKey( options.getStartKey() ) )
2017 		{
2018 			fprintf(stdout, "%s: start key is equal to one of the exclude keys\n",
2019 					options.getProgramName().c_str());
2020 			return (6);
2021 		}
2022 		RegistryKey sk1, sk2;
2023 		if ( key1.openKey(options.getStartKey(), sk1) )
2024 		{
2025 			fprintf(stdout, "%s: open start key of registry \"%s\" failed\n",
2026 					options.getProgramName().c_str(), options.getRegName1().c_str());
2027 			return (7);
2028 		}
2029 		if ( key2.openKey(options.getStartKey(), sk2) )
2030 		{
2031 			fprintf(stdout, "%s: open start key of registry \"%s\" failed\n",
2032 					options.getProgramName().c_str(), options.getRegName2().c_str());
2033 			return (8);
2034 		}
2035 
2036 		key1 = sk1;
2037 		key2 = sk2;
2038 	}
2039 
2040 	sal_uInt32 nError = compareKeys(options, key1, key2);
2041 	if ( nError )
2042 	{
2043 		if ( options.unoTypeCheck() )
2044 		{
2045 			fprintf(stdout, "%s: registries are incompatible: %lu differences!\n",
2046 					options.getProgramName().c_str(),
2047                     sal::static_int_cast< unsigned long >(nError));
2048 		}
2049         else
2050 		{
2051 			fprintf(stdout, "%s: registries contain %lu differences!\n",
2052 					options.getProgramName().c_str(),
2053                     sal::static_int_cast< unsigned long >(nError));
2054 		}
2055 	}
2056     else
2057 	{
2058 		if ( options.unoTypeCheck() )
2059 		{
2060 			fprintf(stdout, "%s: registries are compatible!\n",
2061 					options.getProgramName().c_str());
2062 		}
2063         else
2064 		{
2065 			fprintf(stdout, "%s: registries are equal!\n",
2066 					options.getProgramName().c_str());
2067 		}
2068 	}
2069 
2070 	key1.releaseKey();
2071 	key2.releaseKey();
2072 	if ( reg1.close() )
2073 	{
2074 		fprintf(stdout, "%s: closing registry \"%s\" failed\n",
2075 				options.getProgramName().c_str(), options.getRegName1().c_str());
2076         return (9);
2077 	}
2078 	if ( reg2.close() )
2079 	{
2080 		fprintf(stdout, "%s: closing registry \"%s\" failed\n",
2081 				options.getProgramName().c_str(), options.getRegName2().c_str());
2082         return (10);
2083 	}
2084 
2085 	return ((nError > 0) ? 11 : 0);
2086 }
2087