xref: /AOO41X/main/registry/tools/regcompare.cxx (revision 51134e9e39c88e9bb15b60ce91daabe8d062137a)
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:
Options_Impl(char const * program)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 
getRegName1() const59     std::string const & getRegName1() const { return m_regName1; }
getRegName2() const60     std::string const & getRegName2() const { return m_regName2; }
61 
isStartKeyValid() const62     bool isStartKeyValid() const { return (m_startKey.getLength() > 0); }
getStartKey() const63     OUString const & getStartKey() const { return m_startKey; }
64     bool matchedWithExcludeKey( const OUString& keyName) const;
65 
fullCheck() const66     bool fullCheck() const { return m_bFullCheck; }
forceOutput() const67     bool forceOutput() const { return m_bForceOutput; }
unoTypeCheck() const68     bool unoTypeCheck() const { return m_bUnoTypeCheck; }
checkUnpublished() const69     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 
makeOUString(std::string const & s)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 
shortName(rtl::OUString const & fullName)94 inline rtl::OUString shortName(rtl::OUString const & fullName)
95 {
96     return fullName.copy(fullName.lastIndexOf('/') + 1);
97 }
98 
setRegName_Impl(char c,std::string const & param)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
printUsage_Impl() const110 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
initOptions_Impl(std::vector<std::string> & rArgs)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 
matchedWithExcludeKey(const OUString & keyName) const273 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 
getTypeClass(RTTypeClass typeClass)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 
getFieldAccess(RTFieldAccess fieldAccess)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 
getConstValueType(RTConstValue & constValue)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 
printConstValue(RTConstValue & constValue)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 
dumpTypeClass(sal_Bool & rbDump,RTTypeClass typeClass,OUString const & keyName)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 
checkConstValue(Options_Impl const & options,const OUString & keyName,RTTypeClass typeClass,sal_Bool & bDump,RTConstValue & constValue1,RTConstValue & constValue2,sal_uInt16 index1)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 
checkField(Options_Impl const & options,const OUString & keyName,RTTypeClass typeClass,sal_Bool & bDump,typereg::Reader & reader1,typereg::Reader & reader2,sal_uInt16 index1,sal_uInt16 index2)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 
getMethodMode(RTMethodMode methodMode)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 
getParamMode(RTParamMode paramMode)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 
checkMethod(Options_Impl const & options,const OUString & keyName,RTTypeClass typeClass,sal_Bool & bDump,typereg::Reader & reader1,typereg::Reader & reader2,sal_uInt16 index)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 
getReferenceType(RTReferenceType refType)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 
checkReference(Options_Impl const & options,const OUString & keyName,RTTypeClass typeClass,sal_Bool & bDump,typereg::Reader & reader1,typereg::Reader & reader2,sal_uInt16 index1,sal_uInt16 index2)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 
checkFieldsWithoutOrder(Options_Impl const & options,const OUString & keyName,RTTypeClass typeClass,sal_Bool & bDump,typereg::Reader & reader1,typereg::Reader & reader2)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 
checkBlob(Options_Impl const & options,const OUString & keyName,typereg::Reader & reader1,sal_uInt32 size1,typereg::Reader & reader2,sal_uInt32 size2)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 
checkValueDifference(Options_Impl const & options,RegistryKey & key1,RegValueType valueType1,sal_uInt32 size1,RegistryKey & key2,RegValueType valueType2,sal_uInt32 size2)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 
hasPublishedChildren(Options_Impl const & options,RegistryKey & key)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 
checkDifferences(Options_Impl const & options,RegistryKey & key,StringSet & keys,RegistryKeyNames & subKeyNames1,RegistryKeyNames & subKeyNames2)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 
compareKeys(Options_Impl const & options,RegistryKey & key1,RegistryKey & key2)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__
main(int argc,char * argv[])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