diff options
Diffstat (limited to 'registry/tools/regcompare.cxx')
-rw-r--r-- | registry/tools/regcompare.cxx | 2401 |
1 files changed, 2401 insertions, 0 deletions
diff --git a/registry/tools/regcompare.cxx b/registry/tools/regcompare.cxx new file mode 100644 index 000000000000..f41103afb826 --- /dev/null +++ b/registry/tools/regcompare.cxx @@ -0,0 +1,2401 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: regcompare.cxx,v $ + * $Revision: 1.27 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_registry.hxx" +#include <stdio.h> +#include <string.h> + +#include <set> +#include <vector> +#include "registry/registry.hxx" +#include "registry/reader.hxx" +#include "registry/version.h" +#include <rtl/ustring.hxx> +#include <rtl/alloc.h> +#include <osl/process.h> +#include <osl/diagnose.h> +#include <osl/thread.h> +#include <osl/file.hxx> + +#ifdef SAL_UNX +#define SEPARATOR '/' +#else +#define SEPARATOR '\\' +#endif + +using namespace ::rtl; +using namespace ::osl; + +OUString shortName(const OUString& fullName) +{ + return fullName.copy(fullName.lastIndexOf('/') + 1); +} + +sal_Bool isFileUrl(const OString& fileName) +{ + if (fileName.indexOf("file://") == 0 ) + return sal_True; + return sal_False; +} + +OUString convertToFileUrl(const OString& fileName) +{ + if ( isFileUrl(fileName) ) + { + return OStringToOUString(fileName, osl_getThreadTextEncoding()); + } + + OUString uUrlFileName; + OUString uFileName(fileName.getStr(), fileName.getLength(), osl_getThreadTextEncoding()); + if ( fileName.indexOf('.') == 0 || fileName.indexOf(SEPARATOR) < 0 ) + { + OUString uWorkingDir; + if (osl_getProcessWorkingDir(&uWorkingDir.pData) != osl_Process_E_None) + { + OSL_ASSERT(false); + } + if (FileBase::getAbsoluteFileURL(uWorkingDir, uFileName, uUrlFileName) + != FileBase::E_None) + { + OSL_ASSERT(false); + } + } else + { + if (FileBase::getFileURLFromSystemPath(uFileName, uUrlFileName) + != FileBase::E_None) + { + OSL_ASSERT(false); + } + } + + return uUrlFileName; +} + +#define U2S( s ) \ + OUStringToOString(s, RTL_TEXTENCODING_UTF8).getStr() +#define S2U( s ) \ + OStringToOUString(s, RTL_TEXTENCODING_UTF8) + +struct LessString +{ + sal_Bool operator()(const OUString& str1, const OUString& str2) const + { + return (str1 < str2); + } +}; + +typedef ::std::set< OUString > StringSet; + +class Options +{ +public: + Options() + : m_bFullCheck(sal_False) + , m_bForceOutput(sal_False) + , m_bUnoTypeCheck(sal_False) + , m_checkUnpublished(false) + {} + ~Options() + {} + + sal_Bool initOptions(int ac, char* av[], sal_Bool bCmdFile=sal_False); + + OString prepareHelp(); + OString prepareVersion(); + + const OString& getProgramName() + { return m_program; } + const OString& getRegName1() + { return m_regName1; } + const OString& getRegName2() + { return m_regName2; } + sal_Bool isStartKeyValid() + { return (m_startKey.getLength() > 0); }; + const OString& getStartKey() + { return m_startKey; } + sal_Bool existsExcludeKeys() + { return !m_excludeKeys.empty(); }; + StringSet& getExcludeKeys() + { return m_excludeKeys; } + sal_Bool matchedWithExcludeKey( const OUString& keyName); + sal_Bool fullCheck() + { return m_bFullCheck; } + sal_Bool forceOutput() + { return m_bForceOutput; } + sal_Bool unoTypeCheck() + { return m_bUnoTypeCheck; } + bool checkUnpublished() const { return m_checkUnpublished; } +protected: + OString m_program; + OString m_regName1; + OString m_regName2; + OString m_startKey; + StringSet m_excludeKeys; + sal_Bool m_bFullCheck; + sal_Bool m_bForceOutput; + sal_Bool m_bUnoTypeCheck; + bool m_checkUnpublished; +}; + +sal_Bool Options::initOptions(int ac, char* av[], sal_Bool bCmdFile) +{ + sal_Bool bRet = sal_True; + sal_uInt16 i=0; + + if (!bCmdFile) + { + bCmdFile = sal_True; + + m_program = av[0]; + + if (ac < 2) + { + fprintf(stdout, "%s", prepareHelp().getStr()); + bRet = sal_False; + } + + i = 1; + } else + { + i = 0; + } + + char *s=NULL; + for (; i < ac; i++) + { + if (av[i][0] == '-') + { + switch (av[i][1]) + { + case 'r': + case 'R': + { + sal_Bool bFirst = sal_True; + if (av[i][2] == '2') + { + bFirst = sal_False; + } else if (av[i][2] != '1') + { + fprintf(stdout, "%s: invalid option '%s'\n", m_program.getStr(), av[i]); + } + if (av[i][3] == '\0') + { + if (i < ac - 1 && av[i+1][0] != '-') + { + i++; + s = av[i]; + } else + { + fprintf(stdout, "%s: invalid option '%s'\n", m_program.getStr(), av[i]); + bRet = sal_False; + break; + } + } else + { + s = av[i] + 2; + } + + if ( bFirst ) + { + m_regName1 = OString(s); + } else + { + m_regName2 = OString(s); + } + } + break; + case 's': + case 'S': + if (av[i][2] == '\0') + { + if (i < ac - 1 && av[i+1][0] != '-') + { + i++; + s = av[i]; + } else + { + fprintf(stdout, "%s: invalid option '%s'\n", m_program.getStr(), av[i]); + bRet = sal_False; + break; + } + } else + { + s = av[i] + 2; + } + m_startKey = OString(s); + break; + case 'x': + case 'X': + if (av[i][2] == '\0') + { + if (i < ac - 1 && av[i+1][0] != '-') + { + i++; + s = av[i]; + } else + { + fprintf(stdout, "%s: invalid option '%s'\n", m_program.getStr(), av[i]); + bRet = sal_False; + break; + } + } else + { + s = av[i] + 2; + } + m_excludeKeys.insert(S2U(s)); + break; + case 'c': + case 'C': + if (av[i][2] != '\0') + { + fprintf(stdout, "%s: invalid option '%s'\n", m_program.getStr(), av[i]); + } + m_bFullCheck = sal_True; + break; + case 'f': + case 'F': + if (av[i][2] != '\0') + { + fprintf(stdout, "%s: invalid option '%s'\n", m_program.getStr(), av[i]); + bRet = sal_False; + } + m_bForceOutput = sal_True; + break; + case 't': + case 'T': + if (av[i][2] != '\0') + { + fprintf(stdout, "%s: invalid option '%s'\n", m_program.getStr(), av[i]); + } + m_bUnoTypeCheck = sal_True; + break; + case 'u': + case 'U': + if (av[i][2] != '\0') + { + fprintf(stdout, "%s: invalid option '%s'\n", m_program.getStr(), av[i]); + } + m_checkUnpublished = true; + break; + case 'h': + case '?': + if (av[i][2] != '\0') + { + fprintf(stdout, "%s: invalid option '%s'\n", m_program.getStr(), av[i]); + bRet = sal_False; + } else + { + fprintf(stdout, "%s", prepareHelp().getStr()); + exit(0); + } + break; + default: + fprintf(stdout, "%s: unknown option '%s'\n", m_program.getStr(), av[i]); + bRet = sal_False; + break; + } + } else + { + if (av[i][0] == '@') + { + FILE* cmdFile = fopen(av[i]+1, "r"); + if( cmdFile == NULL ) + { + fprintf(stdout, "%s", prepareHelp().getStr()); + bRet = sal_False; + } else + { + int rargc=0; + char* rargv[512]; + char buffer[512]; + + while ( fscanf(cmdFile, "%s", buffer) != EOF ) + { + rargv[rargc]= strdup(buffer); + rargc++; + } + fclose(cmdFile); + + bRet = initOptions(rargc, rargv, bCmdFile); + + for (long j=0; j < rargc; j++) + { + free(rargv[j]); + } + } + } else + { + fprintf(stdout, "%s: unknown option '%s'\n", m_program.getStr(), av[i]); + bRet = sal_False; + } + } + } + + if ( bRet ) + { + if ( m_regName1.getLength() == 0 ) + { + fprintf(stdout, "%s: missing option '-r1'\n", m_program.getStr()); + bRet = sal_False; + } + if ( m_regName2.getLength() == 0 ) + { + fprintf(stdout, "%s: missing option '-r2'\n", m_program.getStr()); + bRet = sal_False; + } + } + + return bRet; +} + +OString Options::prepareHelp() +{ + OString help("\nusing: "); + help += m_program + " -r1<filename> -r2<filename> [-options] | @<filename>\n"; + help += " -r1<filename> = filename specifies the name of the first registry.\n"; + help += " -r2<filename> = filename specifies the name of the second registry.\n"; + help += " @<filename> = filename specifies a command file.\n"; + help += "Options:\n"; + help += " -s<name> = name specifies the name of a start key. If no start key\n"; + help += " |S<name> is specified the comparison starts with the root key.\n"; + help += " -x<name> = name specifies the name of a key which won't be compared. All\n"; + help += " |X<name> subkeys won't be compared also. This option can be used more than once.\n"; + help += " -f|F = force the detailed output of any diffenrences. Default\n"; + help += " is that only the number of differences is returned.\n"; + help += " -c|C = make a complete check, that means any differences will be\n"; + help += " detected. Default is only a compatibility check that means\n"; + help += " only UNO typelibrary entries will be checked.\n"; + help += " -t|T = make an UNO type compatiblity check. This means that registry 2\n"; + help += " will be checked against registry 1. If a interface in r2 contains\n"; + help += " more methods or the methods are in a different order as in r1, r2 is\n"; + help += " incompatible to r1. But if a service in r2 supports more properties as\n"; + help += " in r1 and the new properties are 'optonal' it is compatible.\n"; + help += " -u|U = additionally check types that are unpublished in registry 1.\n"; + help += " -h|-? = print this help message and exit.\n"; + help += prepareVersion(); + + return help; +} + +OString Options::prepareVersion() +{ + OString version("\nSun Microsystems (R) "); + version += m_program + " Version 1.0\n\n"; + return version; +} + +sal_Bool Options::matchedWithExcludeKey( const OUString& keyName) +{ + if ( m_excludeKeys.empty() ) + return sal_False; + + StringSet::const_iterator iter = m_excludeKeys.begin(); + StringSet::const_iterator end = m_excludeKeys.end(); + + while ( iter != end ) + { + if ( keyName.indexOf(*iter) == 0) + return sal_True; + + ++iter; + } + + return sal_False; +} + +static Options options; + +static char const * getTypeClass(RTTypeClass typeClass) +{ + switch (typeClass) + { + case RT_TYPE_INTERFACE: + return "INTERFACE"; + case RT_TYPE_MODULE: + return "MODULE"; + case RT_TYPE_STRUCT: + return "STRUCT"; + case RT_TYPE_ENUM: + return "ENUM"; + case RT_TYPE_EXCEPTION: + return "EXCEPTION"; + case RT_TYPE_TYPEDEF: + return "TYPEDEF"; + case RT_TYPE_SERVICE: + return "SERVICE"; + case RT_TYPE_OBJECT: + return "OBJECT"; + case RT_TYPE_CONSTANTS: + return "CONSTANTS"; + default: + return "INVALID"; + } +} + +static OString getFieldAccess(RTFieldAccess fieldAccess) +{ + OString ret; + if ( (fieldAccess & RT_ACCESS_INVALID) == RT_ACCESS_INVALID ) + { + ret += OString("INVALID"); + } + if ( (fieldAccess & RT_ACCESS_READONLY) == RT_ACCESS_READONLY ) + { + ret += OString(ret.getLength() > 0 ? ",READONLY" : "READONLY"); + } + if ( (fieldAccess & RT_ACCESS_OPTIONAL) == RT_ACCESS_OPTIONAL ) + { + ret += OString(ret.getLength() > 0 ? ",OPTIONAL" : "OPTIONAL"); + } + if ( (fieldAccess & RT_ACCESS_MAYBEVOID) == RT_ACCESS_MAYBEVOID ) + { + ret += OString(ret.getLength() > 0 ? ",MAYBEVOID" : "MAYBEVOID"); + } + if ( (fieldAccess & RT_ACCESS_BOUND) == RT_ACCESS_BOUND ) + { + ret += OString(ret.getLength() > 0 ? ",BOUND" : "BOUND"); + } + if ( (fieldAccess & RT_ACCESS_CONSTRAINED) == RT_ACCESS_CONSTRAINED ) + { + ret += OString(ret.getLength() > 0 ? ",CONSTRAINED" : "CONSTRAINED"); + } + if ( (fieldAccess & RT_ACCESS_TRANSIENT) == RT_ACCESS_TRANSIENT ) + { + ret += OString(ret.getLength() > 0 ? ",TRANSIENT" : "TRANSIENT"); + } + if ( (fieldAccess & RT_ACCESS_MAYBEAMBIGUOUS) == RT_ACCESS_MAYBEAMBIGUOUS ) + { + ret += OString(ret.getLength() > 0 ? ",MAYBEAMBIGUOUS" : "MAYBEAMBIGUOUS"); + } + if ( (fieldAccess & RT_ACCESS_MAYBEDEFAULT) == RT_ACCESS_MAYBEDEFAULT ) + { + ret += OString(ret.getLength() > 0 ? ",MAYBEDEFAULT" : "MAYBEDEFAULT"); + } + if ( (fieldAccess & RT_ACCESS_REMOVEABLE) == RT_ACCESS_REMOVEABLE ) + { + ret += OString(ret.getLength() > 0 ? ",REMOVEABLE" : "REMOVEABLE"); + } + if ( (fieldAccess & RT_ACCESS_ATTRIBUTE) == RT_ACCESS_ATTRIBUTE ) + { + ret += OString(ret.getLength() > 0 ? ",ATTRIBUTE" : "ATTRIBUTE"); + } + if ( (fieldAccess & RT_ACCESS_PROPERTY) == RT_ACCESS_PROPERTY ) + { + ret += OString(ret.getLength() > 0 ? ",PROPERTY" : "PROPERTY"); + } + if ( (fieldAccess & RT_ACCESS_CONST) == RT_ACCESS_CONST ) + { + ret += OString(ret.getLength() > 0 ? ",CONST" : "CONST"); + } + if ( (fieldAccess & RT_ACCESS_READWRITE) == RT_ACCESS_READWRITE ) + { + ret += OString(ret.getLength() > 0 ? ",READWRITE" : "READWRITE"); + } + return ret; +} + +static char const * getConstValueType(RTConstValue& constValue) +{ + switch (constValue.m_type) + { + case RT_TYPE_BOOL: + return "sal_Bool"; + case RT_TYPE_BYTE: + return "sal_uInt8"; + case RT_TYPE_INT16: + return "sal_Int16"; + case RT_TYPE_UINT16: + return "sal_uInt16"; + case RT_TYPE_INT32: + return "sal_Int32"; + case RT_TYPE_UINT32: + return "sal_uInt32"; +// case RT_TYPE_INT64: +// return "sal_Int64"; +// case RT_TYPE_UINT64: +// return "sal_uInt64"; + case RT_TYPE_FLOAT: + return "float"; + case RT_TYPE_DOUBLE: + return "double"; + case RT_TYPE_STRING: + return "sal_Unicode*"; + default: + return "NONE"; + } +} +static void printConstValue(RTConstValue& constValue) +{ + switch (constValue.m_type) + { + case RT_TYPE_NONE: + fprintf(stdout, "none"); + break; + case RT_TYPE_BOOL: + fprintf(stdout, "%s", constValue.m_value.aBool ? "TRUE" : "FALSE"); + break; + case RT_TYPE_BYTE: + fprintf(stdout, "%d", constValue.m_value.aByte); + break; + case RT_TYPE_INT16: + fprintf(stdout, "%d", constValue.m_value.aShort); + break; + case RT_TYPE_UINT16: + fprintf(stdout, "%d", constValue.m_value.aUShort); + break; + case RT_TYPE_INT32: + fprintf( + stdout, "%ld", + sal::static_int_cast< long >(constValue.m_value.aLong)); + break; + case RT_TYPE_UINT32: + fprintf( + stdout, "%lu", + sal::static_int_cast< unsigned long >( + constValue.m_value.aULong)); + break; +// case RT_TYPE_INT64: +// fprintf(stdout, "%d", constValue.m_value.aHyper); +// case RT_TYPE_UINT64: +// fprintf(stdout, "%d", constValue.m_value.aUHyper); + case RT_TYPE_FLOAT: + fprintf(stdout, "%f", constValue.m_value.aFloat); + break; + case RT_TYPE_DOUBLE: + fprintf(stdout, "%f", constValue.m_value.aDouble); + break; + case RT_TYPE_STRING: + fprintf( + stdout, "%s", + (rtl::OUStringToOString( + constValue.m_value.aString, RTL_TEXTENCODING_UTF8). + getStr())); + break; + default: + break; + } +} + +static sal_uInt32 checkConstValue(const OUString& keyName, + RTTypeClass typeClass, + sal_Bool& bDump, + RTConstValue& constValue1, + RTConstValue& constValue2, + sal_uInt16 index1) +{ + switch (constValue1.m_type) + { + case RT_TYPE_INVALID: + break; + case RT_TYPE_BOOL: + if (constValue1.m_value.aBool != constValue2.m_value.aBool) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Field %d: Value1 = %s != Value2 = %s\n", index1, + constValue1.m_value.aBool ? "TRUE" : "FALSE", + constValue2.m_value.aBool ? "TRUE" : "FALSE"); + } + return 1; + } + break; + case RT_TYPE_BYTE: + if (constValue1.m_value.aByte != constValue2.m_value.aByte) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Field %d: Value1 = %d != Value2 = %d\n", index1, + constValue1.m_value.aByte, constValue2.m_value.aByte); + } + return 1; + } + break; + case RT_TYPE_INT16: + if (constValue1.m_value.aShort != constValue2.m_value.aShort) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Field %d: Value1 = %d != Value2 = %d\n", index1, + constValue1.m_value.aShort, constValue2.m_value.aShort); + } + return 1; + } + break; + case RT_TYPE_UINT16: + if (constValue1.m_value.aUShort != constValue2.m_value.aUShort) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Field %d: Value1 = %d != Value2 = %d\n", index1, + constValue1.m_value.aUShort, constValue2.m_value.aUShort); + } + return 1; + } + break; + case RT_TYPE_INT32: + if (constValue1.m_value.aLong != constValue2.m_value.aLong) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Field %d: Value1 = %ld != Value2 = %ld\n", index1, + sal::static_int_cast< long >(constValue1.m_value.aLong), + sal::static_int_cast< long >(constValue2.m_value.aLong)); + } + return 1; + } + break; + case RT_TYPE_UINT32: + if (constValue1.m_value.aULong != constValue2.m_value.aULong) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Field %d: Value1 = %lu != Value2 = %lu\n", index1, + sal::static_int_cast< unsigned long >(constValue1.m_value.aULong), + sal::static_int_cast< unsigned long >(constValue2.m_value.aULong)); + } + return 1; + } + break; + case RT_TYPE_INT64: + if (constValue1.m_value.aHyper != constValue2.m_value.aHyper) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf( + stdout, " Field %d: Value1 = %s != Value2 = %s\n", + index1, + rtl::OUStringToOString( + rtl::OUString::valueOf(constValue1.m_value.aHyper), + RTL_TEXTENCODING_ASCII_US).getStr(), + rtl::OUStringToOString( + rtl::OUString::valueOf(constValue2.m_value.aHyper), + RTL_TEXTENCODING_ASCII_US).getStr()); + } + return 1; + } + break; + case RT_TYPE_UINT64: + if (constValue1.m_value.aUHyper != constValue2.m_value.aUHyper) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf( + stdout, " Field %d: Value1 = %s != Value2 = %s\n", + index1, + rtl::OUStringToOString( + rtl::OUString::valueOf( + static_cast< sal_Int64 >( + constValue1.m_value.aUHyper)), + RTL_TEXTENCODING_ASCII_US).getStr(), + rtl::OUStringToOString( + rtl::OUString::valueOf( + static_cast< sal_Int64 >( + constValue2.m_value.aUHyper)), + RTL_TEXTENCODING_ASCII_US).getStr()); + // printing the unsigned values as signed should be + // acceptable... + } + return 1; + } + break; + case RT_TYPE_FLOAT: + if (constValue1.m_value.aFloat != constValue2.m_value.aFloat) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Field %d: Value1 = %f != Value2 = %f\n", index1, + constValue1.m_value.aFloat, constValue2.m_value.aFloat); + } + return 1; + } + break; + case RT_TYPE_DOUBLE: + if (constValue1.m_value.aDouble != constValue2.m_value.aDouble) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Field %d: Value1 = %f != Value2 = %f\n", index1, + constValue1.m_value.aDouble, constValue2.m_value.aDouble); + } + return 1; + } + break; + default: + OSL_ASSERT(false); + break; + } + return 0; +} + +static sal_uInt32 checkField(const OUString& keyName, + RTTypeClass typeClass, + sal_Bool& bDump, + typereg::Reader& reader1, + typereg::Reader& reader2, + sal_uInt16 index1, + sal_uInt16 index2) +{ + sal_uInt32 nError = 0; + if ( reader1.getFieldName(index1) != + reader2.getFieldName(index2) ) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Field %d: Name1 = %s != Name2 = %s\n", index1, + U2S(reader1.getFieldName(index1)), U2S(reader2.getFieldName(index2))); + } + nError++; + } + if ( reader1.getFieldTypeName(index1) != + reader2.getFieldTypeName(index2) ) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Field %d: Type1 = %s != Type2 = %s\n", index1, + U2S(reader1.getFieldTypeName(index1)), U2S(reader2.getFieldTypeName(index2))); + } + nError++; + } else + { + RTConstValue constValue1 = reader1.getFieldValue(index1); + RTConstValue constValue2 = reader2.getFieldValue(index2); + if ( constValue1.m_type != constValue2.m_type ) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Field %d: Access1 = %s != Access2 = %s\n", index1, + getConstValueType(constValue1), getConstValueType(constValue2)); + fprintf(stdout, " Field %d: Value1 = ", index1); + printConstValue(constValue1); + fprintf(stdout, " != Value2 = "); + printConstValue(constValue1); + fprintf(stdout, "\n;"); + } + nError++; + } else + { + nError += checkConstValue(keyName, typeClass, bDump, constValue1, constValue2, index1); + } + } + + if ( reader1.getFieldFlags(index1) != reader2.getFieldFlags(index2) ) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Field %d: FieldAccess1 = %s != FieldAccess2 = %s\n", index1, + getFieldAccess(reader1.getFieldFlags(index1)).getStr(), + getFieldAccess(reader1.getFieldFlags(index2)).getStr()); + } + nError++; + } + + if ( options.fullCheck() && + (reader1.getFieldDocumentation(index1) != reader2.getFieldDocumentation(index2)) ) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Field %d: Doku1 = %s\n Doku2 = %s\n", index1, + U2S(reader1.getFieldDocumentation(index1)), U2S(reader2.getFieldDocumentation(index2))); + } + nError++; + } + return nError; +} + +static char const * getMethodMode(RTMethodMode methodMode) +{ + switch ( methodMode ) + { + case RT_MODE_ONEWAY: + return "ONEWAY"; + case RT_MODE_ONEWAY_CONST: + return "ONEWAY,CONST"; + case RT_MODE_TWOWAY: + return "NONE"; + case RT_MODE_TWOWAY_CONST: + return "CONST"; + default: + return "INVALID"; + } +} + +static char const * getParamMode(RTParamMode paramMode) +{ + switch ( paramMode ) + { + case RT_PARAM_IN: + return "IN"; + case RT_PARAM_OUT: + return "OUT"; + case RT_PARAM_INOUT: + return "INOUT"; + default: + return "INVALID"; + } +} + +static sal_uInt32 checkMethod(const OUString& keyName, + RTTypeClass typeClass, + sal_Bool& bDump, + typereg::Reader& reader1, + typereg::Reader& reader2, + sal_uInt16 index) +{ + sal_uInt32 nError = 0; + if ( reader1.getMethodName(index) != + reader2.getMethodName(index) ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Method1 %d: Name1 = %s != Name2 = %s\n", index, + U2S(reader1.getMethodName(index)), + U2S(reader2.getMethodName(index))); + } + nError++; + } + + if ( reader1.getMethodReturnTypeName(index) != + reader2.getMethodReturnTypeName(index) ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Method1 %d: ReturnType1 = %s != ReturnType2 = %s\n", index, + U2S(reader1.getMethodReturnTypeName(index)), + U2S(reader2.getMethodReturnTypeName(index))); + } + nError++; + } + + sal_uInt16 nParams1 = (sal_uInt16)reader1.getMethodParameterCount(index); + sal_uInt16 nParams2 = (sal_uInt16)reader2.getMethodParameterCount(index); + if ( nParams1 != nParams2 ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Method %d : nParameters1 = %d != nParameters2 = %d\n", index, nParams1, nParams2); + } + nError++; + } + sal_uInt16 i=0; + for (i=0; i < nParams1 && i < nParams2; i++) + { + if ( reader1.getMethodParameterTypeName(index, i) != reader2.getMethodParameterTypeName(index, i) ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Method %d, Parameter %d: Type1 = %s != Type2 = %s\n", index, i, + U2S(reader1.getMethodParameterTypeName(index, i)), + U2S(reader2.getMethodParameterTypeName(index, i))); + } + nError++; + } + if ( options.fullCheck() && + (reader1.getMethodParameterName(index, i) != reader2.getMethodParameterName(index, i)) ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Method %d, Parameter %d: Name1 = %s != Name2 = %s\n", index, i, + U2S(reader1.getMethodParameterName(index, i)), + U2S(reader2.getMethodParameterName(index, i))); + } + nError++; + } + if ( reader1.getMethodParameterFlags(index, i) != reader2.getMethodParameterFlags(index, i) ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Method %d, Parameter %d: Mode1 = %s != Mode2 = %s\n", index, i, + getParamMode(reader1.getMethodParameterFlags(index, i)), + getParamMode(reader2.getMethodParameterFlags(index, i))); + } + nError++; + } + } + if ( i < nParams1 && options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Registry1: Method %d contains %d more parameters\n", index, nParams1 - i); + } + if ( i < nParams2 && options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Registry2: Method %d contains %d more parameters\n", index, nParams2 - i); + } + + sal_uInt16 nExcep1 = (sal_uInt16)reader1.getMethodExceptionCount(index); + sal_uInt16 nExcep2 = (sal_uInt16)reader2.getMethodExceptionCount(index); + if ( nExcep1 != nExcep2 ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " nExceptions1 = %d != nExceptions2 = %d\n", nExcep1, nExcep2); + } + nError++; + } + for (i=0; i < nExcep1 && i < nExcep2; i++) + { + if ( reader1.getMethodExceptionTypeName(index, i) != reader2.getMethodExceptionTypeName(index, i) ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Method %d, Exception %d: Name1 = %s != Name2 = %s\n", index, i, + U2S(reader1.getMethodExceptionTypeName(index, i)), + U2S(reader2.getMethodExceptionTypeName(index, i))); + } + nError++; + } + } + if ( i < nExcep1 && options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Registry1: Method %d contains %d more exceptions\n", index, nExcep1 - i); + } + if ( i < nExcep2 && options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Registry2: Method %d contains %d more exceptions\n", index, nExcep2 - i); + } + + if ( reader1.getMethodFlags(index) != reader2.getMethodFlags(index) ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Method %d: Mode1 = %s != Mode2 = %s\n", index, + getMethodMode(reader1.getMethodFlags(index)), + getMethodMode(reader2.getMethodFlags(index))); + } + nError++; + } + + if ( options.fullCheck() && + (reader1.getMethodDocumentation(index) != reader2.getMethodDocumentation(index)) ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Method %d: Doku1 = %s\n Doku2 = %s\n", index, + U2S(reader1.getMethodDocumentation(index)), + U2S(reader2.getMethodDocumentation(index))); + } + nError++; + } + return nError; +} + +static char const * getReferenceType(RTReferenceType refType) +{ + switch (refType) + { + case RT_REF_SUPPORTS: + return "RT_REF_SUPPORTS"; + case RT_REF_OBSERVES: + return "RT_REF_OBSERVES"; + case RT_REF_EXPORTS: + return "RT_REF_EXPORTS"; + case RT_REF_NEEDS: + return "RT_REF_NEEDS"; + default: + return "RT_REF_INVALID"; + } +} + +static sal_uInt32 checkReference(const OUString& keyName, + RTTypeClass typeClass, + sal_Bool& bDump, + typereg::Reader& reader1, + typereg::Reader& reader2, + sal_uInt16 index1, + sal_uInt16 index2) +{ + sal_uInt32 nError = 0; + if ( reader1.getReferenceTypeName(index1) != + reader2.getReferenceTypeName(index2) ) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Reference %d: Name1 = %s != Name2 = %s\n", index1, + U2S(reader1.getReferenceTypeName(index1)), + U2S(reader2.getReferenceTypeName(index2))); + } + nError++; + } + if ( reader1.getReferenceTypeName(index1) != + reader2.getReferenceTypeName(index2) ) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Reference %d: Type1 = %s != Type2 = %s\n", index1, + getReferenceType(reader1.getReferenceSort(index1)), + getReferenceType(reader2.getReferenceSort(index2))); + } + nError++; + } + if ( options.fullCheck() && + (reader1.getReferenceDocumentation(index1) != reader2.getReferenceDocumentation(index2)) ) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Reference %d: Doku1 = %s\n Doku2 = %s\n", index1, + U2S(reader1.getReferenceDocumentation(index1)), + U2S(reader2.getReferenceDocumentation(index2))); + } + nError++; + } + if ( reader1.getReferenceFlags(index1) != + reader2.getReferenceFlags(index2) ) + { + if ( options.forceOutput() && !options.unoTypeCheck() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Reference %d: Access1 = %s != Access2 = %s\n", index1, + getFieldAccess(reader1.getReferenceFlags(index1)).getStr(), + getFieldAccess(reader1.getReferenceFlags(index2)).getStr()); + } + nError++; + } + return nError; +} + +static sal_uInt32 checkFieldsWithoutOrder(const OUString& keyName, + RTTypeClass typeClass, + sal_Bool& bDump, + typereg::Reader& reader1, + typereg::Reader& reader2) +{ + sal_uInt32 nError = 0; + + sal_uInt16 nFields1 = (sal_uInt16)reader1.getFieldCount(); + sal_uInt16 nFields2 = (sal_uInt16)reader2.getFieldCount(); + sal_uInt16 i=0, j=0; + + if ( nFields1 > nFields2 ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " %s1 contains %d more properties as %s2\n", + getTypeClass(typeClass), nFields1-nFields2, getTypeClass(typeClass)); + } + } + + sal_Bool bFound = sal_False; + ::std::set< sal_uInt16 > moreProps; + + for (i=0; i < nFields1; i++) + { + for (j=0; j < nFields2; j++) + { + if (!checkField(keyName, typeClass, bDump, reader1, reader2, i, j)) + { + bFound = sal_True; + moreProps.insert(j); + break; + } + } + if (!bFound) + { + if (options.forceOutput()) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " incompatible change: Field %d ('%s') of r1 is not longer a property of this %s in r2\n", + i, U2S(shortName(reader1.getFieldName(i))), getTypeClass(typeClass)); + } + nError++; + } else + { + bFound = sal_False; + } + } + + if ( typeClass == RT_TYPE_SERVICE && !moreProps.empty() ) + { + for (j=0; j < nFields2; j++) + { + if ( moreProps.find(j) == moreProps.end() ) + { + if ( (reader2.getFieldFlags(j) & RT_ACCESS_OPTIONAL) != RT_ACCESS_OPTIONAL ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " incompatible change: Field %d ('%s') of r2 is a new property compared to this %s in r1 and is not 'optional'\n", + j, U2S(shortName(reader2.getFieldName(j))), getTypeClass(typeClass)); + } + nError++; + } + } + } + } + + return nError; +} + +static sal_uInt32 checkBlob(const OUString& keyName, typereg::Reader& reader1, sal_uInt32 size1, + typereg::Reader& reader2, sal_uInt32 size2) +{ + sal_uInt32 nError = 0; + sal_Bool bDump = sal_True; + + if ( options.fullCheck() && (size1 != size2) ) + { + if ( options.forceOutput() ) + { + fprintf( + stdout, " Size1 = %lu Size2 = %lu\n", + sal::static_int_cast< unsigned long >(size1), + sal::static_int_cast< unsigned long >(size2)); + } + } + if (reader1.isPublished()) { + if (!reader2.isPublished()) { + if (options.forceOutput()) { + if (bDump) { + fprintf(stdout, "?: %s\n", U2S(keyName)); + bDump = false; + } + fprintf(stdout, " published in 1 but unpublished in 2\n"); + } + ++nError; + } + } else if (!options.checkUnpublished()) { + return nError; + } + if ( reader1.getTypeClass() != reader2.getTypeClass() ) + { + if ( options.forceOutput() ) + { + if (bDump) { + fprintf(stdout, "?: %s\n", U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " TypeClass1 = %s != TypeClass2 = %s\n", + getTypeClass(reader1.getTypeClass()), + getTypeClass(reader2.getTypeClass())); + } + return ++nError; + } + + RTTypeClass typeClass = reader1.getTypeClass(); + + if ( reader1.getTypeName() != reader2.getTypeName() ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " TypeName1 = %s != TypeName2 = %s\n", + U2S(reader1.getTypeName()), U2S(reader2.getTypeName())); + } + nError++; + } + if ( (typeClass == RT_TYPE_INTERFACE || + typeClass == RT_TYPE_STRUCT || + typeClass == RT_TYPE_EXCEPTION) ) + { + if (reader1.getSuperTypeCount() != reader2.getSuperTypeCount()) { + if (bDump) { + fprintf( + stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = false; + } + fprintf( + stdout, " SuperTypeCount1 = %d != SuperTypeCount2 = %d\n", + static_cast< int >(reader1.getSuperTypeCount()), + static_cast< int >(reader2.getSuperTypeCount())); + ++nError; + } else { + for (sal_Int16 i = 0; i < reader1.getSuperTypeCount(); ++i) { + if (reader1.getSuperTypeName(i) != reader2.getSuperTypeName(i)) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " SuperTypeName1 = %s != SuperTypeName2 = %s\n", + U2S(reader1.getSuperTypeName(i)), U2S(reader2.getSuperTypeName(i))); + } + nError++; + } + } + } + } + sal_uInt16 nFields1 = (sal_uInt16)reader1.getFieldCount(); + sal_uInt16 nFields2 = (sal_uInt16)reader2.getFieldCount(); + sal_Bool bCheckNormal = sal_True; + + if ( (typeClass == RT_TYPE_SERVICE || + typeClass == RT_TYPE_MODULE || + typeClass == RT_TYPE_CONSTANTS) && options.unoTypeCheck() ) + { + bCheckNormal = sal_False; + } + + if ( bCheckNormal ) + { + if ( nFields1 != nFields2 ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " nFields1 = %d != nFields2 = %d\n", nFields1, nFields2); + } + nError++; + } + sal_uInt16 i; + for (i=0; i < nFields1 && i < nFields2; i++) + { + nError += checkField(keyName, typeClass, bDump, reader1, reader2, i, i); + } + if ( i < nFields1 && options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Registry1 contains %d more fields\n", nFields1 - i); + } + if ( i < nFields2 && options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Registry2 contains %d more fields\n", nFields2 - i); + } + } else + { + nError += checkFieldsWithoutOrder(keyName, typeClass, bDump, reader1, reader2); + } + + if ( typeClass == RT_TYPE_INTERFACE ) + { + sal_uInt16 nMethods1 = (sal_uInt16)reader1.getMethodCount(); + sal_uInt16 nMethods2 = (sal_uInt16)reader2.getMethodCount(); + if ( nMethods1 != nMethods2 ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " nMethods1 = %d != nMethods2 = %d\n", nMethods1, nMethods2); + } + nError++; + } + sal_uInt16 i; + for (i=0; i < nMethods1 && i < nMethods2; i++) + { + nError += checkMethod(keyName, typeClass, bDump, reader1, reader2, i); + } + if ( i < nMethods1 && options.forceOutput() ) + { + fprintf(stdout, " Registry1 contains %d more methods\n", nMethods1 - i); + } + if ( i < nMethods2 && options.forceOutput() ) + { + fprintf(stdout, " Registry2 contains %d more methods\n", nMethods2 - i); + } + } + if ( typeClass == RT_TYPE_SERVICE ) + { + sal_uInt16 nReference1 = (sal_uInt16)reader1.getReferenceCount(); + sal_uInt16 nReference2 = (sal_uInt16)reader2.getReferenceCount(); + + if ( !bCheckNormal ) + { + sal_uInt16 i=0, j=0; + + if ( nReference1 > nReference2 ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " service1 contains %d more references as service2\n", + nReference1-nReference2); + } + } + + sal_Bool bFound = sal_False; + ::std::set< sal_uInt16 > moreReferences; + + for (i=0; i < nReference1; i++) + { + for (j=0; j < nReference2; j++) + { + if (!checkReference(keyName, typeClass, bDump, reader1, reader2, i, j)) + { + bFound = sal_True; + moreReferences.insert(j); + break; + } + } + if (!bFound) + { + if (options.forceOutput()) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " incompatible change: Reference %d ('%s') in 'r1' is not longer a reference of this service in 'r2'\n", + i, U2S(shortName(reader1.getReferenceTypeName(i)))); + } + nError++; + } else + { + bFound = sal_False; + } + } + + if ( !moreReferences.empty() ) + { + for (j=0; j < nReference2; j++) + { + if ( moreReferences.find(j) == moreReferences.end() ) + { + if ( (reader2.getReferenceFlags(j) & RT_ACCESS_OPTIONAL) != RT_ACCESS_OPTIONAL ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " incompatible change: Reference %d ('%s') of r2 is a new reference compared to this service in r1 and is not 'optional'\n", + j, U2S(shortName(reader2.getReferenceTypeName(j)))); + } + nError++; + } + } + } + } + } else + { + if ( nReference1 != nReference2 ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " nReferences1 = %d != nReferences2 = %d\n", nReference1, nReference2); + } + nError++; + } + sal_uInt16 i; + for (i=0; i < nReference1 && i < nReference2; i++) + { + nError += checkReference(keyName, typeClass, bDump, reader1, reader2, i, i); + } + if ( i < nReference1 && options.forceOutput() ) + { + fprintf(stdout, " Registry1 contains %d more references\n", nReference1 - i); + } + if ( i < nReference2 && options.forceOutput() ) + { + fprintf(stdout, " Registry2 contains %d more references\n", nReference2 - i); + } + } + } + + if ( options.fullCheck() && (reader1.getDocumentation() != reader2.getDocumentation()) ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Doku1 = %s\n Doku2 = %s\n", + U2S(reader1.getDocumentation()), U2S(reader2.getDocumentation())); + } + nError++; + } +/* + if ( nError && + (!keyName.compareTo(OUString::createFromAscii("/UCR/drafts"), 11) || + !keyName.compareTo(OUString::createFromAscii("/drafts"), 7)) ) + { + if ( options.forceOutput() ) + { + if ( bDump ) + { + fprintf(stdout, "%s: %s\n", getTypeClass(typeClass), U2S(keyName)); + bDump = sal_False; + } + fprintf(stdout, " Note: \"drafts\" type changed incompatible, no effect to the final API\n"); + } + return 0; + } +*/ + return nError; +} + +static sal_uInt32 checkValueDifference(RegistryKey& key1, RegValueType valueType1, sal_uInt32 size1, + RegistryKey& key2, RegValueType valueType2, sal_uInt32 size2) +{ + OUString tmpName; + sal_uInt32 nError = 0; + + if ( valueType1 == valueType2 ) + { + sal_Bool bEqual = sal_True; + switch (valueType1) + { + case RG_VALUETYPE_LONGLIST: + { + RegistryValueList<sal_Int32> valueList1; + RegistryValueList<sal_Int32> valueList2; + key1.getLongListValue(tmpName, valueList1); + key2.getLongListValue(tmpName, valueList2); + sal_uInt32 length1 = valueList1.getLength(); + sal_uInt32 length2 = valueList1.getLength(); + if ( length1 != length2 ) + { + bEqual = sal_False; + break; + } + for (sal_uInt32 i=0; i<length1; i++) + { + if ( valueList1.getElement(i) != valueList2.getElement(i) ) + { + bEqual = sal_False; + break; + } + } + } + break; + case RG_VALUETYPE_STRINGLIST: + { + RegistryValueList<sal_Char*> valueList1; + RegistryValueList<sal_Char*> valueList2; + key1.getStringListValue(tmpName, valueList1); + key2.getStringListValue(tmpName, valueList2); + sal_uInt32 length1 = valueList1.getLength(); + sal_uInt32 length2 = valueList1.getLength(); + if ( length1 != length2 ) + { + bEqual = sal_False; + break; + } + for (sal_uInt32 i=0; i<length1; i++) + { + if ( strcmp(valueList1.getElement(i), valueList2.getElement(i)) != 0 ) + { + bEqual = sal_False; + break; + } + } + } + break; + case RG_VALUETYPE_UNICODELIST: + { + RegistryValueList<sal_Unicode*> valueList1; + RegistryValueList<sal_Unicode*> valueList2; + key1.getUnicodeListValue(tmpName, valueList1); + key2.getUnicodeListValue(tmpName, valueList2); + sal_uInt32 length1 = valueList1.getLength(); + sal_uInt32 length2 = valueList1.getLength(); + if ( length1 != length2 ) + { + bEqual = sal_False; + break; + } + for (sal_uInt32 i=0; i<length1; i++) + { + if ( rtl_ustr_compare(valueList1.getElement(i), valueList2.getElement(i)) != 0 ) + { + bEqual = sal_False; + break; + } + } + } + break; + default: + break; + } + + if ( bEqual) + { + RegValue value1 = rtl_allocateMemory(size1); + RegValue value2 = rtl_allocateMemory(size2); + + key1.getValue(tmpName, value1); + key2.getValue(tmpName, value2); + + bEqual = (rtl_compareMemory(value1, value2, size1) == 0 ); + + if ( !bEqual && valueType1 == RG_VALUETYPE_BINARY && valueType2 == RG_VALUETYPE_BINARY ) + { + typereg::Reader reader1( + value1, size1, false, TYPEREG_VERSION_1); + typereg::Reader reader2( + value2, size2, false, TYPEREG_VERSION_1); + + if ( reader1.isValid() && reader2.isValid() ) + { + return checkBlob(key1.getName(), reader1, size1, reader2, size2); + } + } + + rtl_freeMemory(value1); + rtl_freeMemory(value2); + + if ( bEqual ) + { + return 0; + } else + { + if ( options.forceOutput() ) + { + fprintf(stdout, "Difference: key values of key \"%s\" are different\n", + U2S(key1.getName())); + } + nError++; + } + } + } + + if ( options.forceOutput() ) + { + switch (valueType1) + { + case RG_VALUETYPE_NOT_DEFINED: + fprintf(stdout, " Registry 1: key has no value\n"); + break; + case RG_VALUETYPE_LONG: + case RG_VALUETYPE_STRING: + case RG_VALUETYPE_UNICODE: + { + RegValue value1 = rtl_allocateMemory(size1); + key1.getValue(tmpName, value1); + + switch (valueType1) + { + case RG_VALUETYPE_LONG: + fprintf(stdout, " Registry 1: Value: Type = RG_VALUETYPE_LONG\n"); + fprintf( + stdout, " Size = %lu\n", + sal::static_int_cast< unsigned long >(size1)); + fprintf(stdout, " Data = %p\n", value1); + break; + case RG_VALUETYPE_STRING: + fprintf(stdout, " Registry 1: Value: Type = RG_VALUETYPE_STRING\n"); + fprintf( + stdout, " Size = %lu\n", + sal::static_int_cast< unsigned long >(size1)); + fprintf(stdout, " Data = \"%s\"\n", (sal_Char*)value1); + break; + case RG_VALUETYPE_UNICODE: + { + OUString uStrValue((sal_Unicode*)value1); + fprintf(stdout, " Registry 1: Value: Type = RG_VALUETYPE_UNICODE\n"); + fprintf( + stdout, " Size = %lu\n", + sal::static_int_cast< unsigned long >(size1)); + fprintf(stdout, " Data = \"%s\"\n", U2S(uStrValue)); + } + break; + default: + OSL_ASSERT(false); + break; + } + + rtl_freeMemory(value1); + } + break; + case RG_VALUETYPE_BINARY: + fprintf(stdout, " Registry 1: Value: Type = RG_VALUETYPE_BINARY\n"); + break; + case RG_VALUETYPE_LONGLIST: + { + RegistryValueList<sal_Int32> valueList; + key1.getLongListValue(tmpName, valueList); + fprintf(stdout, " Registry 1: Value: Type = RG_VALUETYPE_LONGLIST\n"); + fprintf( + stdout, " Size = %lu\n", + sal::static_int_cast< unsigned long >(size1)); + sal_uInt32 length = valueList.getLength(); + for (sal_uInt32 i=0; i<length; i++) + { + fprintf( + stdout, " Data[%lu] = %ld\n", + sal::static_int_cast< unsigned long >(i), + sal::static_int_cast< long >(valueList.getElement(i))); + } + } + break; + case RG_VALUETYPE_STRINGLIST: + { + RegistryValueList<sal_Char*> valueList; + key1.getStringListValue(tmpName, valueList); + fprintf(stdout, " Registry 1: Value: Type = RG_VALUETYPE_STRINGLIST\n"); + fprintf( + stdout, " Size = %lu\n", + sal::static_int_cast< unsigned long >(size1)); + sal_uInt32 length = valueList.getLength(); + for (sal_uInt32 i=0; i<length; i++) + { + fprintf( + stdout, " Data[%lu] = \"%s\"\n", + sal::static_int_cast< unsigned long >(i), + valueList.getElement(i)); + } + } + break; + case RG_VALUETYPE_UNICODELIST: + { + RegistryValueList<sal_Unicode*> valueList; + key1.getUnicodeListValue(tmpName, valueList); + fprintf(stdout, " Registry 1: Value: Type = RG_VALUETYPE_UNICODELIST\n"); + fprintf( + stdout, " Size = %lu\n", + sal::static_int_cast< unsigned long >(size1)); + sal_uInt32 length = valueList.getLength(); + OUString uStrValue; + for (sal_uInt32 i=0; i<length; i++) + { + uStrValue = OUString(valueList.getElement(i)); + fprintf( + stdout, " Data[%lu] = \"%s\"\n", + sal::static_int_cast< unsigned long >(i), U2S(uStrValue)); + } + } + break; + } + + switch (valueType2) + { + case RG_VALUETYPE_NOT_DEFINED: + fprintf(stdout, " Registry 2: key has no value\n"); + break; + case RG_VALUETYPE_LONG: + case RG_VALUETYPE_STRING: + case RG_VALUETYPE_UNICODE: + { + RegValue value2 = rtl_allocateMemory(size2); + key2.getValue(tmpName, value2); + + switch (valueType2) + { + case RG_VALUETYPE_LONG: + fprintf(stdout, " Registry 2: Value: Type = RG_VALUETYPE_LONG\n"); + fprintf( + stdout, " Size = %lu\n", + sal::static_int_cast< unsigned long >(size2)); + fprintf(stdout, " Data = %p\n", value2); + break; + case RG_VALUETYPE_STRING: + fprintf(stdout, " Registry 2: Value: Type = RG_VALUETYPE_STRING\n"); + fprintf( + stdout, " Size = %lu\n", + sal::static_int_cast< unsigned long >(size2)); + fprintf(stdout, " Data = \"%s\"\n", (sal_Char*)value2); + break; + case RG_VALUETYPE_UNICODE: + { + OUString uStrValue((sal_Unicode*)value2); + fprintf(stdout, " Registry 2: Value: Type = RG_VALUETYPE_UNICODE\n"); + fprintf( + stdout, " Size = %lu\n", + sal::static_int_cast< unsigned long >(size2)); + fprintf(stdout, " Data = \"%s\"\n", U2S(uStrValue)); + } + break; + default: + OSL_ASSERT(false); + break; + } + + rtl_freeMemory(value2); + } + break; + case RG_VALUETYPE_BINARY: + fprintf(stdout, " Registry 2: Value: Type = RG_VALUETYPE_BINARY\n"); + break; + case RG_VALUETYPE_LONGLIST: + { + RegistryValueList<sal_Int32> valueList; + key2.getLongListValue(tmpName, valueList); + fprintf(stdout, " Registry 2: Value: Type = RG_VALUETYPE_LONGLIST\n"); + fprintf( + stdout, " Size = %lu\n", + sal::static_int_cast< unsigned long >(size2)); + sal_uInt32 length = valueList.getLength(); + for (sal_uInt32 i=0; i<length; i++) + { + fprintf( + stdout, " Data[%lu] = %ld\n", + sal::static_int_cast< unsigned long >(i), + sal::static_int_cast< long >(valueList.getElement(i))); + } + } + break; + case RG_VALUETYPE_STRINGLIST: + { + RegistryValueList<sal_Char*> valueList; + key2.getStringListValue(tmpName, valueList); + fprintf(stdout, " Registry 2: Value: Type = RG_VALUETYPE_STRINGLIST\n"); + fprintf( + stdout, " Size = %lu\n", + sal::static_int_cast< unsigned long >(size2)); + sal_uInt32 length = valueList.getLength(); + for (sal_uInt32 i=0; i<length; i++) + { + fprintf( + stdout, " Data[%lu] = \"%s\"\n", + sal::static_int_cast< unsigned long >(i), + valueList.getElement(i)); + } + } + break; + case RG_VALUETYPE_UNICODELIST: + { + RegistryValueList<sal_Unicode*> valueList; + key2.getUnicodeListValue(tmpName, valueList); + fprintf(stdout, " Registry 2: Value: Type = RG_VALUETYPE_UNICODELIST\n"); + fprintf( + stdout, " Size = %lu\n", + sal::static_int_cast< unsigned long >(size2)); + sal_uInt32 length = valueList.getLength(); + OUString uStrValue; + for (sal_uInt32 i=0; i<length; i++) + { + uStrValue = OUString(valueList.getElement(i)); + fprintf( + stdout, " Data[%lu] = \"%s\"\n", + sal::static_int_cast< unsigned long >(i), U2S(uStrValue)); + } + } + break; + } + } + return nError; +} + +static bool hasPublishedChildren(RegistryKey & key) { + RegistryKeyNames subKeyNames; + key.getKeyNames(rtl::OUString(), subKeyNames); + for (sal_uInt32 i = 0; i < subKeyNames.getLength(); ++i) { + rtl::OUString keyName(subKeyNames.getElement(i)); + if (!options.matchedWithExcludeKey(keyName)) { + keyName = keyName.copy(keyName.lastIndexOf('/') + 1); + RegistryKey subKey; + if (!key.openKey(keyName, subKey)) { + if (options.forceOutput()) { + fprintf( + stdout, + ("WARNING: could not open key \"%s\" in registry" + " \"%s\"\n"), + U2S(subKeyNames.getElement(i)), + options.getRegName1().getStr()); + } + } + if (subKey.isValid()) { + RegValueType type; + sal_uInt32 size; + if (subKey.getValueInfo(rtl::OUString(), &type, &size) + != REG_NO_ERROR) + { + if (options.forceOutput()) { + fprintf( + stdout, + ("WARNING: could not read key \"%s\" in registry" + " \"%s\"\n"), + U2S(subKeyNames.getElement(i)), + options.getRegName1().getStr()); + } + } else if (type == RG_VALUETYPE_BINARY) { + char * value = new char[size]; + bool published = false; + if (subKey.getValue(rtl::OUString(), value) != REG_NO_ERROR) + { + if (options.forceOutput()) { + fprintf( + stdout, + ("WARNING: could not read key \"%s\" in" + " registry \"%s\"\n"), + U2S(subKeyNames.getElement(i)), + options.getRegName1().getStr()); + } + } else { + published = typereg::Reader( + value, size, false, TYPEREG_VERSION_1). + isPublished(); + } + delete[] value; + if (published) { + return true; + } + } + } + } + } + return false; +} + +static sal_uInt32 checkDifferences( + RegistryKey& key, StringSet& keys, RegistryKeyNames& subKeyNames1, + RegistryKeyNames& subKeyNames2) +{ + sal_uInt32 nError = 0; + sal_uInt32 length1 = subKeyNames1.getLength(); + sal_uInt32 length2 = subKeyNames2.getLength(); + sal_uInt32 i,j; + + for (i=0; i<length1; i++) + { + sal_Bool bFound = sal_False; + for (j=0; j<length2; j++) + { + if ( subKeyNames1.getElement(i) == subKeyNames2.getElement(j) ) + { + bFound = sal_True; + keys.insert(subKeyNames1.getElement(i)); + break; + } + } + if ( !bFound ) + { + if ( options.fullCheck() ) + { + if ( options.forceOutput() ) + { + fprintf(stdout, "EXISTENCE: key \"%s\" exists only in registry \"%s\"\n", + U2S(subKeyNames1.getElement(i)), options.getRegName1().getStr()); + } + nError++; + } + else + { + rtl::OUString keyName(subKeyNames1.getElement(i)); + if (!options.matchedWithExcludeKey(keyName)) { + keyName = keyName.copy(keyName.lastIndexOf('/') + 1); + RegistryKey subKey; + if (key.openKey(keyName, subKey)) { + if (options.forceOutput()) { + fprintf( + stdout, + ("ERROR: could not open key \"%s\" in registry" + " \"%s\"\n"), + U2S(subKeyNames1.getElement(i)), + options.getRegName1().getStr()); + } + ++nError; + } + if (subKey.isValid()) { + RegValueType type; + sal_uInt32 size; + if (subKey.getValueInfo(rtl::OUString(), &type, &size) + != REG_NO_ERROR) + { + if (options.forceOutput()) { + fprintf( + stdout, + ("ERROR: could not read key \"%s\" in" + " registry \"%s\"\n"), + U2S(subKeyNames1.getElement(i)), + options.getRegName1().getStr()); + } + ++nError; + } else if (type == RG_VALUETYPE_BINARY) { + char * value = new char[size]; + if (subKey.getValue(rtl::OUString(), value) + != REG_NO_ERROR) + { + if (options.forceOutput()) { + fprintf( + stdout, + ("ERROR: could not read key \"%s\" in" + " registry \"%s\"\n"), + U2S(subKeyNames1.getElement(i)), + options.getRegName1().getStr()); + } + ++nError; + } else { + typereg::Reader reader( + value, size, false, TYPEREG_VERSION_1); + if (reader.getTypeClass() == RT_TYPE_MODULE) { + if (options.checkUnpublished() + || hasPublishedChildren(subKey)) + { + if (options.forceOutput()) { + fprintf( + stdout, + ("EXISTENCE: module \"%s\"" + " %sexists only in registry" + " 1\n"), + U2S(subKeyNames1.getElement( + i)), + (options.checkUnpublished() + ? "" + : "with published children ")); + } + ++nError; + } + } else if (options.checkUnpublished() + || reader.isPublished()) + { + if (options.forceOutput()) { + fprintf( + stdout, + ("EXISTENCE: %spublished key \"%s\"" + " exists only in registry 1\n"), + reader.isPublished() ? "" : "un", + U2S(subKeyNames1.getElement(i))); + } + ++nError; + } + } + delete[] value; + } + } + } + } + } + } + + for (i=0; i<length2; i++) + { + sal_Bool bFound = sal_False; + for (j=0; j<length1; j++) + { + if ( subKeyNames2.getElement(i) == subKeyNames1.getElement(j) ) + { + bFound = sal_True; + keys.insert(subKeyNames2.getElement(i)); + break; + } + } + if ( !bFound && options.fullCheck() ) + { + if ( options.forceOutput() ) + { + fprintf(stdout, "EXISTENCE: key \"%s\" exists only in registry \"%s\"\n", + U2S(subKeyNames2.getElement(i)), options.getRegName2().getStr()); + } + nError++; + } + } + return nError; +} + +static sal_uInt32 compareKeys(RegistryKey& key1, RegistryKey& key2) +{ + sal_uInt32 nError = 0; + + RegValueType valueType1 = RG_VALUETYPE_NOT_DEFINED; + RegValueType valueType2 = RG_VALUETYPE_NOT_DEFINED; + sal_uInt32 size1 = 0; + sal_uInt32 size2 = 0; + OUString tmpName; + RegError e1 = key1.getValueInfo(tmpName, &valueType1, &size1); + RegError e2 = key2.getValueInfo(tmpName, &valueType2, &size2); + + if ( e1 == e2 && e1 != REG_VALUE_NOT_EXISTS && e1 != REG_INVALID_VALUE ) + { + nError += checkValueDifference(key1, valueType1, size1, key2, valueType2, size2); + } else + { + if ( e1 != REG_INVALID_VALUE || e2 != REG_INVALID_VALUE ) + { + if ( options.forceOutput() ) + { + fprintf(stdout, "VALUES: key values of key \"%s\" are different\n", U2S(key1.getName())); + } + nError++; + } + } + + RegistryKeyNames subKeyNames1; + RegistryKeyNames subKeyNames2; + + key1.getKeyNames(tmpName, subKeyNames1); + key2.getKeyNames(tmpName, subKeyNames2); + + StringSet keys; + nError += checkDifferences(key1, keys, subKeyNames1, subKeyNames2); + + StringSet::iterator iter = keys.begin(); + StringSet::iterator end = keys.end(); + + RegistryKey subKey1, subKey2; + OUString keyName; + while ( iter != end ) + { + keyName = OUString(*iter); + if ( options.matchedWithExcludeKey(keyName) ) + { + ++iter; + continue; + } + + sal_Int32 nPos = keyName.lastIndexOf( '/' ); + keyName = keyName.copy( nPos != -1 ? nPos+1 : 0 ); + if ( key1.openKey(keyName, subKey1) ) + { + if ( options.forceOutput() ) + { + fprintf(stdout, "ERROR: could not open key \"%s\" in registry \"%s\"\n", + U2S(*iter), options.getRegName1().getStr()); + } + nError++; + } + if ( key2.openKey(keyName, subKey2) ) + { + if ( options.forceOutput() ) + { + fprintf(stdout, "ERROR: could not open key \"%s\" in registry \"%s\"\n", + U2S(*iter), options.getRegName2().getStr()); + } + nError++; + } + if ( subKey1.isValid() && subKey2.isValid() ) + { + nError += compareKeys(subKey1, subKey2); + } + subKey1.closeKey(); + subKey2.closeKey(); + ++iter; + } + + return nError; +} + +#if (defined UNX) || (defined OS2) || defined __MINGW32__ +int main( int argc, char * argv[] ) +#else +int _cdecl main( int argc, char * argv[] ) +#endif +{ + if ( !options.initOptions(argc, argv) ) + { + exit(1); + } + + OUString regName1( convertToFileUrl(options.getRegName1()) ); + OUString regName2( convertToFileUrl(options.getRegName2()) ); + + Registry reg1; + Registry reg2; + + if ( reg1.open(regName1, REG_READONLY) ) + { + fprintf(stdout, "%s: open registry \"%s\" failed\n", + options.getProgramName().getStr(), options.getRegName1().getStr()); + exit(2); + } + if ( reg2.open(regName2, REG_READONLY) ) + { + fprintf(stdout, "%s: open registry \"%s\" failed\n", + options.getProgramName().getStr(), options.getRegName2().getStr()); + exit(3); + } + + RegistryKey key1, key2; + if ( reg1.openRootKey(key1) ) + { + fprintf(stdout, "%s: open root key of registry \"%s\" failed\n", + options.getProgramName().getStr(), options.getRegName1().getStr()); + exit(4); + } + if ( reg2.openRootKey(key2) ) + { + fprintf(stdout, "%s: open root key of registry \"%s\" failed\n", + options.getProgramName().getStr(), options.getRegName2().getStr()); + exit(5); + } + if ( options.isStartKeyValid() ) + { + if ( options.matchedWithExcludeKey( S2U(options.getStartKey()) ) ) + { + fprintf(stdout, "%s: start key is equal to one of the exclude keys\n", + options.getProgramName().getStr()); + exit(6); + } + RegistryKey sk1, sk2; + if ( key1.openKey(S2U(options.getStartKey()), sk1) ) + { + fprintf(stdout, "%s: open start key of registry \"%s\" failed\n", + options.getProgramName().getStr(), options.getRegName1().getStr()); + exit(7); + } + if ( key2.openKey(S2U(options.getStartKey()), sk2) ) + { + fprintf(stdout, "%s: open start key of registry \"%s\" failed\n", + options.getProgramName().getStr(), options.getRegName2().getStr()); + exit(8); + } + + key1 = sk1; + key2 = sk2; + } + + sal_uInt32 nError = compareKeys(key1, key2); + if ( nError ) + { + if ( options.unoTypeCheck() ) + { + fprintf(stdout, "%s: registries are incompatible: %lu differences!\n", + options.getProgramName().getStr(), + sal::static_int_cast< unsigned long >(nError)); + } else + { + fprintf(stdout, "%s: registries contain %lu differences!\n", + options.getProgramName().getStr(), + sal::static_int_cast< unsigned long >(nError)); + } + } else + { + if ( options.unoTypeCheck() ) + { + fprintf(stdout, "%s: registries are compatible!\n", + options.getProgramName().getStr()); + } else + { + fprintf(stdout, "%s: registries are equal!\n", + options.getProgramName().getStr()); + } + } + + key1.closeKey(); + key2.closeKey(); + if ( reg1.close() ) + { + fprintf(stdout, "%s: closing registry \"%s\" failed\n", + options.getProgramName().getStr(), options.getRegName1().getStr()); + exit(9); + } + if ( reg2.close() ) + { + fprintf(stdout, "%s: closing registry \"%s\" failed\n", + options.getProgramName().getStr(), options.getRegName2().getStr()); + exit(10); + } + + return nError > 0 ? 11 : 0; +} + + |