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