LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/registry/tools - regcompare.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 299 911 32.8 %
Date: 2013-07-09 Functions: 22 36 61.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10