/************************************************************** * * 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 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( 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( 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 parameters 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 definition."); 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' 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++; } } }