blob: 67d91445290f0f9ea912195b09eedf2ebb5030e8 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#include "osl/thread.hxx"
#include "codemaker/commonjava.hxx"
#include "codemaker/commoncpp.hxx"
#include "codemaker/generatedtypeset.hxx"
#include "skeletoncommon.hxx"
#include <iostream>
using namespace ::rtl;
using namespace ::codemaker::cpp;
namespace skeletonmaker {
void printLicenseHeader(std::ostream& o, rtl::OString const & filename)
{
sal_Int32 index = -1;
#ifdef SAL_UNX
index = filename.lastIndexOf('/');
#else
index = filename.lastIndexOf('\\');
#endif
OString shortfilename(filename);
if ( index != -1 )
shortfilename = filename.copy(index+1);
o << "/**************************************************************\n"
" * \n"
" * Licensed to the Apache Software Foundation (ASF) under one\n"
" * or more contributor license agreements. See the NOTICE file\n"
" * distributed with this work for additional information\n"
" * regarding copyright ownership. The ASF licenses this file\n"
" * to you under the Apache License, Version 2.0 (the\n"
" * \"License\"); you may not use this file except in compliance\n"
" * with the License. You may obtain a copy of the License at\n"
" * \n"
" * http://www.apache.org/licenses/LICENSE-2.0\n"
" * \n"
" * Unless required by applicable law or agreed to in writing,\n"
" * software distributed under the License is distributed on an\n"
" * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n"
" * KIND, either express or implied. See the License for the\n"
" * specific language governing permissions and limitations\n"
" * under the License.\n"
" * \n"
" *************************************************************/\n\n";
}
bool getOutputStream(ProgramOptions const & options,
OString const & extension,
std::ostream** ppOutputStream,
OString & targetSourceFileName,
OString & tmpSourceFileName)
{
bool bStandardout = false;
if ( options.outputpath.equals("stdout") )
{
bStandardout = true;
*ppOutputStream = &std::cout;
return bStandardout;
}
targetSourceFileName = createFileNameFromType(
options.outputpath, options.implname.replace('.','/'), extension);
OString tmpDir = getTempDir(targetSourceFileName);
FileStream file;
file.createTempFile(tmpDir);
if( !file.isValid() )
{
OString message("cannot open ");
message += targetSourceFileName + " for writing";
throw CannotDumpException(message);
} else {
tmpSourceFileName = file.getName();
}
file.close();
*ppOutputStream = new std::ofstream(tmpSourceFileName.getStr(),
std::ios_base::binary);
return bStandardout;
}
codemaker::UnoType::Sort decomposeResolveAndCheck(
TypeManager const & manager, OString const & type,
bool resolveTypedefs, bool allowVoid, bool allowExtraEntities,
RTTypeClass * typeClass, OString * name, sal_Int32 * rank,
std::vector< OString > * arguments)
{
codemaker::UnoType::Sort sort = codemaker::decomposeAndResolve(
manager, type, resolveTypedefs, allowVoid, allowExtraEntities,
typeClass, name, rank, arguments);
for ( std::vector< OString >::iterator i(arguments->begin());
i != arguments->end(); ++i )
{
RTTypeClass typeClass2;
OString name2;
sal_Int32 rank2;
std::vector< OString > arguments2;
decomposeResolveAndCheck(
manager, *i, true, false, false, &typeClass2, &name2, &rank2,
&arguments2);
}
return sort;
}
bool containsAttribute(AttributeInfo& attributes, OString const & attrname)
{
for ( AttributeInfo::const_iterator i(attributes.begin());
i != attributes.end(); ++i ) {
if ( (*i).first == attrname ) {
return true;
}
}
return false;
}
// collect attributes including inherited attributes
void checkAttributes(TypeManager const & manager,
const typereg::Reader& reader,
AttributeInfo& attributes,
std::hash_set< OString, OStringHash >& propinterfaces)
{
OString typeName = codemaker::convertString(reader.getTypeName());
if ( typeName.equals("com/sun/star/beans/XPropertySet") ||
typeName.equals("com/sun/star/beans/XFastPropertySet") ||
// typeName.equals("com/sun/star/beans/XMultiPropertySet") ||
typeName.equals("com/sun/star/beans/XPropertyAccess") )
{
propinterfaces.insert(typeName);
}
for ( sal_uInt16 i = 0; i < reader.getSuperTypeCount(); ++i ) {
typereg::Reader supertype(manager.getTypeReader(
codemaker::convertString(
reader.getSuperTypeName(i))));
if ( !supertype.isValid() ) {
throw CannotDumpException(
"Bad type library entity "
+ codemaker::convertString(reader.getSuperTypeName(i)));
}
checkAttributes(manager, supertype, attributes, propinterfaces);
}
for ( sal_uInt16 i = 0; i < reader.getFieldCount(); ++i ) {
OString fieldName(
codemaker::convertString(reader.getFieldName(i)).
replace('/', '.'));
if ( !containsAttribute(attributes, fieldName) ) {
OString fieldType(
codemaker::convertString(reader.getFieldTypeName(i)).
replace('/', '.'));
attributes.push_back(AttributeInfo::value_type(
fieldName, std::pair<OString, sal_Int16>(
fieldType, reader.getFieldFlags(i))));
}
}
}
void checkType(TypeManager const & manager,
OString const & type,
std::hash_set< OString, OStringHash >& interfaceTypes,
std::hash_set< OString, OStringHash >& serviceTypes,
AttributeInfo& properties)
{
OString binType(type.replace('.', '/'));
typereg::Reader reader(manager.getTypeReader(binType));
if ( !reader.isValid() ) {
throw CannotDumpException("Bad type library entity " + binType);
}
switch ( reader.getTypeClass() )
{
case RT_TYPE_INTERFACE:
{
// com/sun/star/lang/XComponent should be also not in the list
// but it will be used for checking the impl helper and will be
// removed later if necessary.
if ( binType.equals("com/sun/star/lang/XTypeProvider") ||
binType.equals("com/sun/star/uno/XWeak") )
return;
if (interfaceTypes.find(type) == interfaceTypes.end()) {
interfaceTypes.insert(type);
}
}
break;
case RT_TYPE_SERVICE:
if ( serviceTypes.find(binType) == serviceTypes.end() ) {
serviceTypes.insert(binType);
if ( reader.getSuperTypeCount() > 0 ) {
OString supername(codemaker::convertString(
reader.getSuperTypeName(0).replace('/', '.')));
if ( interfaceTypes.find(supername) == interfaceTypes.end() ) {
interfaceTypes.insert(supername);
typereg::Reader supertype(manager.getTypeReader(
codemaker::convertString(
reader.getSuperTypeName(0))));
if ( !supertype.isValid() ) {
throw CannotDumpException(
"Bad type library entity "
+ codemaker::convertString(reader.getSuperTypeName(0)));
}
}
// check if constructors are specified, if yes automatically
// support of XInitialization. We will take care of the default
// constructor because in this case XInitialization is not called.
if ( reader.getMethodCount() > 1 ||
( reader.getMethodCount() == 1 &&
reader.getMethodName(0).getLength() > 0 ) )
{
OString s("com.sun.star.lang.XInitialization");
if ( interfaceTypes.find(s) == interfaceTypes.end() )
interfaceTypes.insert(s);
}
} else {
for ( sal_uInt16 i = 0; i < reader.getReferenceCount(); ++i ) {
OString referenceType(
codemaker::convertString(
reader.getReferenceTypeName(i)).replace('/', '.'));
if ( reader.getReferenceSort(i) == RT_REF_SUPPORTS ) {
checkType(manager, referenceType, interfaceTypes,
serviceTypes, properties);
} else if ( reader.getReferenceSort(i) == RT_REF_EXPORTS ) {
checkType(manager, referenceType, interfaceTypes,
serviceTypes, properties);
}
}
for ( sal_uInt16 i = 0; i < reader.getFieldCount(); ++i ) {
OString fieldName(
codemaker::convertString(reader.getFieldName(i)).
replace('/', '.'));
OString fieldType(
codemaker::convertString(reader.getFieldTypeName(i)).
replace('/', '.'));
properties.push_back(AttributeInfo::value_type(
fieldName, std::pair<OString, sal_Int16>(
fieldType, reader.getFieldFlags(i))));
}
}
}
break;
default:
OSL_ASSERT(false);
break;
}
}
void checkDefaultInterfaces(
std::hash_set< OString, OStringHash >& interfaces,
const std::hash_set< OString, OStringHash >& services,
const OString & propertyhelper)
{
if ( services.empty() ) {
if (interfaces.find("com.sun.star.lang.XServiceInfo") != interfaces.end())
interfaces.erase("com.sun.star.lang.XServiceInfo");
} else {
if (interfaces.find("com.sun.star.lang.XServiceInfo") == interfaces.end())
interfaces.insert("com.sun.star.lang.XServiceInfo");
}
if ( propertyhelper.equals("_") ) {
if (interfaces.find("com.sun.star.beans.XPropertySet")
!= interfaces.end())
interfaces.erase("com.sun.star.beans.XPropertySet");
if (interfaces.find("com.sun.star.beans.XFastPropertySet")
!= interfaces.end())
interfaces.erase("com.sun.star.beans.XFastPropertySet");
if (interfaces.find("com.sun.star.beans.XPropertyAccess")
!= interfaces.end())
interfaces.erase("com.sun.star.beans.XPropertyAccess");
}
}
bool checkServiceProperties(TypeManager const & manager,
const typereg::Reader & reader)
{
if ( reader.getFieldCount() > 0 )
return true;
if ( reader.getReferenceCount() > 0 ) {
for ( sal_uInt16 i = 0; i < reader.getReferenceCount(); ++i ) {
if ( reader.getReferenceSort(i) == RT_REF_EXPORTS ) {
typereg::Reader refreader(
manager.getTypeReader(
codemaker::convertString(reader.getReferenceTypeName(i))));
if ( checkServiceProperties(manager, refreader) )
return true;
}
}
}
return false;
}
OString checkPropertyHelper(
ProgramOptions const & options,
TypeManager const & manager,
const std::hash_set< OString, OStringHash >& services,
const std::hash_set< OString, OStringHash >& interfaces,
AttributeInfo& attributes,
std::hash_set< OString, OStringHash >& propinterfaces)
{
std::hash_set< OString, OStringHash >::const_iterator iter;
std::hash_set< OString, OStringHash >::const_iterator end;
if ( !services.empty() ) {
iter = services.begin();
end = services.end();
} else {
iter = interfaces.begin();
end = interfaces.end();
}
bool oldStyleWithProperties = false;
while ( iter != end ) {
typereg::Reader reader(manager.getTypeReader((*iter).replace('.', '/')));
if ( !services.empty() ) {
if ( options.supportpropertysetmixin && reader.getSuperTypeCount() > 0 )
{
typereg::Reader supertype(
manager.getTypeReader(
codemaker::convertString(
reader.getSuperTypeName(0))));
if ( !supertype.isValid() ) {
throw CannotDumpException(
"Bad type library entity "
+ codemaker::convertString(
reader.getSuperTypeName(0)));
}
checkAttributes(manager, supertype, attributes, propinterfaces);
if ( !(attributes.empty() || propinterfaces.empty()) ) {
return OUStringToOString(
supertype.getTypeName().replace('/', '.'),
osl_getThreadTextEncoding());
}
} else {
oldStyleWithProperties = checkServiceProperties(manager, reader);
}
} else {
checkAttributes(manager, reader, attributes, propinterfaces);
if ( !(attributes.empty() || propinterfaces.empty()) ) {
return OUStringToOString(
reader.getTypeName().replace('/', '.'),
osl_getThreadTextEncoding());
}
}
iter++;
}
return (oldStyleWithProperties ? "_" : "");
}
bool checkXComponentSupport(TypeManager const & manager,
typereg::Reader const & reader)
{
static OUString s(RTL_CONSTASCII_USTRINGPARAM(
"com/sun/star/lang/XComponent"));
if ( reader.getTypeName().equals(s) )
return true;
for ( sal_uInt16 i = 0; i < reader.getSuperTypeCount(); ++i ) {
typereg::Reader super(
manager.getTypeReader(
codemaker::convertString(
reader.getSuperTypeName(i))));
if ( !super.isValid() ) {
throw CannotDumpException(
"Bad type library entity "
+ codemaker::convertString(
reader.getSuperTypeName(i)));
}
if ( checkXComponentSupport(manager, super) )
return true;
}
return false;
}
// if XComponent is directly specified, return true and remove it from the
// supported interfaces list
bool checkXComponentSupport(TypeManager const & manager,
std::hash_set< OString, OStringHash >& interfaces)
{
if ( interfaces.empty() )
return false;
std::hash_set< OString, OStringHash >::const_iterator iter =
interfaces.begin();
while ( iter != interfaces.end() ) {
if ( (*iter).equals("com.sun.star.lang.XComponent") ) {
interfaces.erase("com.sun.star.lang.XComponent");
return true;
}
typereg::Reader reader(manager.getTypeReader((*iter).replace('.', '/')));
if ( checkXComponentSupport(manager, reader) )
return true;
iter++;
}
return false;
}
sal_uInt16 checkAdditionalPropertyFlags(typereg::Reader const & reader,
sal_uInt16 field, sal_uInt16 method)
{
sal_uInt16 flags = 0;
bool getterSupportsUnknown = false;
OUString su(RTL_CONSTASCII_USTRINGPARAM(
"com/sun/star/beans/UnknownPropertyException"));
if ( method < reader.getMethodCount()
&& reader.getMethodFlags(method) == RT_MODE_ATTRIBUTE_GET
&& reader.getMethodName(method) == reader.getFieldName(field) )
{
if ( reader.getMethodExceptionCount(method) > 0 ) {
for ( sal_uInt16 i = 0; i < reader.getMethodExceptionCount(method);
++i )
{
if (su.equals(reader.getMethodExceptionTypeName(method, i)))
getterSupportsUnknown = true;
}
}
method++;
}
if ( method < reader.getMethodCount()
&& reader.getMethodFlags(method) == RT_MODE_ATTRIBUTE_SET
&& reader.getMethodName(method) == reader.getFieldName(field) )
{
if ( reader.getMethodExceptionCount(method) > 0 ) {
OUString s(RTL_CONSTASCII_USTRINGPARAM(
"com/sun/star/beans/PropertyVetoException"));
for ( sal_uInt16 i = 0; i < reader.getMethodExceptionCount(method);
++i )
{
if ( s.equals(reader.getMethodExceptionTypeName(method, i)) )
flags |= RT_ACCESS_CONSTRAINED;
if ( getterSupportsUnknown &&
su.equals(reader.getMethodExceptionTypeName(method, i)) )
flags |= RT_ACCESS_OPTIONAL;
}
}
}
return flags;
}
// This function checks if the specified types for paramters and return
// types are allowed add-in types, for more info see the com.sun.star.sheet.AddIn
// service description
bool checkAddinType(TypeManager const & manager,
OString const & type, bool & bLastAny,
bool & bHasXPropertySet, bool bIsReturn)
{
RTTypeClass typeClass;
OString name;
sal_Int32 rank;
std::vector< OString > arguments;
codemaker::UnoType::Sort sort = codemaker::decomposeAndResolve(
manager, type, true, true, true, &typeClass, &name, &rank, &arguments);
if ( sort == codemaker::UnoType::SORT_LONG ||
sort == codemaker::UnoType::SORT_DOUBLE ||
sort == codemaker::UnoType::SORT_STRING )
{
if ( rank == 0 || rank ==2 )
return true;
}
if ( sort == codemaker::UnoType::SORT_ANY )
{
if ( rank <= 2 ) {
if ( rank ==1 ) {
if ( bIsReturn )
return false;
bLastAny = true;
}
return true;
}
}
if ( sort == codemaker::UnoType::SORT_COMPLEX &&
typeClass == RT_TYPE_INTERFACE )
{
if ( bIsReturn && type.equals("com/sun/star/sheet/XVolatileResult") )
return true;
if ( !bIsReturn && type.equals("com/sun/star/table/XCellRange") )
return true;
if ( !bIsReturn && type.equals("com/sun/star/beans/XPropertySet") )
{
if ( bHasXPropertySet ) {
return false;
} else {
bHasXPropertySet = true;
return true;
}
}
}
return false;
}
void checkAddInTypes(TypeManager const & manager,
typereg::Reader const & reader)
{
OString sType(codemaker::convertString(reader.getTypeName()).replace('/', '.'));
bool bLastAny = false;
bool bHasXPropertySet = false;
for ( sal_uInt16 m = 0; m < reader.getMethodCount(); ++m ) {
OString sMethod(codemaker::convertString(reader.getMethodName(m)));
OString sReturnType(codemaker::convertString(
reader.getMethodReturnTypeName(m)));
if ( !checkAddinType(
manager, sReturnType, bLastAny, bHasXPropertySet, true) )
{
OStringBuffer msg("the return type of the calc add-in function '");
msg.append(sType);
msg.append(":");
msg.append(sMethod);
msg.append("' is invalid. Please check your IDL defintion.");
throw CannotDumpException(msg.makeStringAndClear());
}
bHasXPropertySet = false;
for ( sal_uInt16 p = 0; p < reader.getMethodParameterCount(m); ++p ) {
bLastAny = false;
OString sParamType(codemaker::convertString(
reader.getMethodParameterTypeName(m, p)));
if ( !checkAddinType(manager, sParamType,
bLastAny, bHasXPropertySet, false) ||
bLastAny )
{
OStringBuffer msg("the type of the ");
msg.append((sal_Int32)p+1);
msg.append(". parameter of the calc add-in function '");
msg.append(sType);
msg.append(":");
msg.append(sMethod);
msg.append("' is invalid.");
if ( bLastAny )
msg.append(" The type 'sequence<any>' is allowed as last "
"parameter only.");
if ( bHasXPropertySet )
msg.append(" The type 'XPropertySet' is allowed only once.");
msg.append(" Please check your IDL definition.");
throw CannotDumpException(msg.makeStringAndClear());
}
}
}
}
void generateFunctionParamterMap(std::ostream& o,
ProgramOptions const & options,
TypeManager const & manager,
typereg::Reader const & reader,
::codemaker::GeneratedTypeSet & generated,
bool bFirst)
{
OString sType(codemaker::convertString(reader.getTypeName()));
if ( sType.equals("com/sun/star/uno/XInterface") ||
sType.equals("com/sun/star/lang/XLocalizable") ||
sType.equals("com/sun/star/lang/XServiceInfo") ||
// the next three checks becomes obsolete when configuration is used
sType.equals("com/sun/star/sheet/XAddIn") ||
sType.equals("com/sun/star/sheet/XCompatibilityNames") ||
sType.equals("com/sun/star/lang/XServiceName") )
{
return;
}
// check if the specified add-in functions supports valid types
checkAddInTypes(manager, reader);
for ( sal_uInt16 i = 0; i < reader.getSuperTypeCount(); ++i ) {
typereg::Reader super(
manager.getTypeReader(
codemaker::convertString(
reader.getSuperTypeName(i))));
if ( !super.isValid() ) {
throw CannotDumpException(
"Bad type library entity "
+ codemaker::convertString(
reader.getSuperTypeName(i)));
}
generateFunctionParamterMap(o, options, manager, super, generated, bFirst);
}
OString type(codemaker::convertString(reader.getTypeName()));
if ( generated.contains(type) )
return;
else
generated.add(type);
for ( sal_uInt16 m = 0; m < reader.getMethodCount(); ++m ) {
OString sMethod(codemaker::convertString(reader.getMethodName(m)));
if ( bFirst ) {
if (options.language == 2) {
o << " ParamMap fpm;\n";
}
else {
if ( options.java5 )
o << " java.util.Hashtable< Integer, String > fpm = "
"new java.util.Hashtable< Integer, String >();\n";
else
o << " java.util.Hashtable fpm = "
"new java.util.Hashtable();\n";
}
bFirst = false;
} else
if ( options.language == 2 ) {
o << " fpm = ParamMap();\n";
}
else {
if ( options.java5 )
o << " fpm = new java.util.Hashtable< "
"Integer, String >();\n";
else
o << " fpm = new java.util.Hashtable();\n";
}
for ( sal_uInt16 p = 0; p < reader.getMethodParameterCount(m); ++p ) {
if ( options.language == 2 ) {
o << " fpm[" << p
<< "] = ::rtl::OUString::createFromAscii(\""
<< codemaker::convertString(reader.getMethodParameterName(m, p))
<< "\");\n";
}
else {
if ( options.java5 )
o << " fpm.put(" << p << ", \""
<< codemaker::convertString(
reader.getMethodParameterName(m, p))
<< "\");\n";
else
o << " fpm.put(new Integer(" << p << "), \""
<< codemaker::convertString(
reader.getMethodParameterName(m, p))
<< "\");\n";
}
}
if ( options.language == 2 ) {
o << " m_functionMap[::rtl::OUString::createFromAscii(\""
<< sMethod << "\")] = fpm;\n\n";
}
else {
o << " m_functionMap.put(\"" << sMethod << "\", fpm);\n\n";
}
}
}
void generateFunctionParameterMap(std::ostream& o,
ProgramOptions const & options,
TypeManager const & manager,
const std::hash_set< OString, OStringHash >& interfaces)
{
::codemaker::GeneratedTypeSet generated;
bool bFirst = true;
std::hash_set< OString, OStringHash >::const_iterator iter = interfaces.begin();
while ( iter != interfaces.end() ) {
typereg::Reader reader(manager.getTypeReader((*iter).replace('.','/')));
if (!reader.isValid()) {
throw CannotDumpException(
"Bad type library entity "
+ codemaker::convertString(
reader.getTypeName()));
}
generateFunctionParamterMap(o, options, manager, reader, generated, bFirst);
iter++;
}
}
}