/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "sal/config.h" #include #include #include #include #include "osl/endian.h" #include "osl/file.h" #include "rtl/ref.hxx" #include "rtl/ustring.hxx" #include "sal/log.hxx" #include "sal/types.h" #include "salhelper/simplereferenceobject.hxx" #include "unoidl/unoidl.hxx" #include "unoidl/unoidlprovider.hxx" namespace { // sizeof (Memory16) == 2 struct Memory16 { unsigned char byte[2]; sal_uInt16 getUnsigned16() const { return static_cast< sal_uInt16 >(byte[0]) | (static_cast< sal_uInt16 >(byte[1]) << 8); } }; // sizeof (Memory32) == 4 struct Memory32 { unsigned char byte[4]; sal_uInt32 getUnsigned32() const { return static_cast< sal_uInt32 >(byte[0]) | (static_cast< sal_uInt32 >(byte[1]) << 8) | (static_cast< sal_uInt32 >(byte[2]) << 16) | (static_cast< sal_uInt32 >(byte[3]) << 24); } float getIso60599Binary32() const { union { unsigned char buf[4]; float f; // assuming float is ISO 60599 binary32 } sa; #if defined OSL_LITENDIAN sa.buf[0] = byte[0]; sa.buf[1] = byte[1]; sa.buf[2] = byte[2]; sa.buf[3] = byte[3]; #else sa.buf[0] = byte[3]; sa.buf[1] = byte[2]; sa.buf[2] = byte[1]; sa.buf[3] = byte[0]; #endif return sa.f; } }; // sizeof (Memory64) == 8 struct Memory64 { unsigned char byte[8]; sal_uInt64 getUnsigned64() const { return static_cast< sal_uInt64 >(byte[0]) | (static_cast< sal_uInt64 >(byte[1]) << 8) | (static_cast< sal_uInt64 >(byte[2]) << 16) | (static_cast< sal_uInt64 >(byte[3]) << 24) | (static_cast< sal_uInt64 >(byte[4]) << 32) | (static_cast< sal_uInt64 >(byte[5]) << 40) | (static_cast< sal_uInt64 >(byte[6]) << 48) | (static_cast< sal_uInt64 >(byte[7]) << 56); } double getIso60599Binary64() const { union { unsigned char buf[8]; double d; // assuming double is ISO 60599 binary64 } sa; #if defined OSL_LITENDIAN sa.buf[0] = byte[0]; sa.buf[1] = byte[1]; sa.buf[2] = byte[2]; sa.buf[3] = byte[3]; sa.buf[4] = byte[4]; sa.buf[5] = byte[5]; sa.buf[6] = byte[6]; sa.buf[7] = byte[7]; #else sa.buf[0] = byte[7]; sa.buf[1] = byte[6]; sa.buf[2] = byte[5]; sa.buf[3] = byte[4]; sa.buf[4] = byte[3]; sa.buf[5] = byte[2]; sa.buf[6] = byte[1]; sa.buf[7] = byte[0]; #endif return sa.d; } }; } namespace unoidl { namespace detail { class MappedFile: public salhelper::SimpleReferenceObject { public: explicit MappedFile(OUString const & fileUrl); sal_uInt8 read8(sal_uInt32 offset) const; sal_uInt16 read16(sal_uInt32 offset) const; sal_uInt32 read32(sal_uInt32 offset) const; sal_uInt64 read64(sal_uInt32 offset) const; float readIso60599Binary32(sal_uInt32 offset) const; double readIso60599Binary64(sal_uInt32 offset) const; OUString readNameNul(sal_uInt32 offset) const; OUString readNameLen(sal_uInt32 offset, sal_uInt32 * newOffset = 0) const; OUString uri; oslFileHandle handle; sal_uInt64 size; void * address; private: virtual ~MappedFile(); sal_uInt8 get8(sal_uInt32 offset) const; sal_uInt16 get16(sal_uInt32 offset) const; sal_uInt32 get32(sal_uInt32 offset) const; sal_uInt64 get64(sal_uInt32 offset) const; float getIso60599Binary32(sal_uInt32 offset) const; double getIso60599Binary64(sal_uInt32 offset) const; }; MappedFile::MappedFile(OUString const & fileUrl): uri(fileUrl) { oslFileError e = osl_openFile(uri.pData, &handle, osl_File_OpenFlag_Read); switch (e) { case osl_File_E_None: break; case osl_File_E_NOENT: throw NoSuchFileException(uri); default: throw FileFormatException(uri, "cannot open: " + OUString::number(e)); } e = osl_getFileSize(handle, &size); if (e == osl_File_E_None) { e = osl_mapFile( handle, &address, size, 0, osl_File_MapFlag_RandomAccess); } if (e != osl_File_E_None) { oslFileError e2 = osl_closeFile(handle); SAL_WARN_IF( e2 != osl_File_E_None, "unoidl", "cannot close " << uri << ": " << +e2); throw FileFormatException(uri, "cannot mmap: " + OUString::number(e)); } } sal_uInt8 MappedFile::read8(sal_uInt32 offset) const { assert(size >= 8); if (offset > size - 1) { throw FileFormatException( uri, "UNOIDL format: offset for 8-bit value too large"); } return get8(offset); } sal_uInt16 MappedFile::read16(sal_uInt32 offset) const { assert(size >= 8); if (offset > size - 2) { throw FileFormatException( uri, "UNOIDL format: offset for 16-bit value too large"); } return get16(offset); } sal_uInt32 MappedFile::read32(sal_uInt32 offset) const { assert(size >= 8); if (offset > size - 4) { throw FileFormatException( uri, "UNOIDL format: offset for 32-bit value too large"); } return get32(offset); } sal_uInt64 MappedFile::read64(sal_uInt32 offset) const { assert(size >= 8); if (offset > size - 8) { throw FileFormatException( uri, "UNOIDL format: offset for 64-bit value too large"); } return get64(offset); } float MappedFile::readIso60599Binary32(sal_uInt32 offset) const { assert(size >= 8); if (offset > size - 4) { throw FileFormatException( uri, "UNOIDL format: offset for 32-bit value too large"); } return getIso60599Binary32(offset); } double MappedFile::readIso60599Binary64(sal_uInt32 offset) const { assert(size >= 8); if (offset > size - 8) { throw FileFormatException( uri, "UNOIDL format: offset for 64-bit value too large"); } return getIso60599Binary64(offset); } OUString MappedFile::readNameNul(sal_uInt32 offset) const { if (offset > size) { throw FileFormatException( uri, "UNOIDL format: offset for string too large"); } sal_uInt64 end = offset; for (;; ++end) { if (end == size) { throw FileFormatException( uri, "UNOIDL format: string misses trailing NUL"); } if (static_cast< char const * >(address)[end] == 0) { break; } } if (end - offset > SAL_MAX_INT32) { throw FileFormatException(uri, "UNOIDL format: string too long"); } OUString name; if (!rtl_convertStringToUString( &name.pData, static_cast< char const * >(address) + offset, end - offset, RTL_TEXTENCODING_ASCII_US, (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR))) { throw FileFormatException(uri, "UNOIDL format: name is not ASCII"); } return name; } OUString MappedFile::readNameLen(sal_uInt32 offset, sal_uInt32 * newOffset) const { sal_uInt32 len = read32(offset); if ((len & 0x80000000) == 0) { if (newOffset != 0) { *newOffset = offset + 4; } offset = len; len = read32(offset); if ((len & 0x80000000) == 0) { throw FileFormatException( uri, "UNOIDL format: name length high bit unset"); } len &= ~0x80000000; } else { len &= ~0x80000000; if (newOffset != 0) { *newOffset = offset + 4 + len; } } if (len > SAL_MAX_INT32 || len > size - offset - 4) { throw FileFormatException( uri, "UNOIDL format: size of name is too large"); } OUString name; if (!rtl_convertStringToUString( &name.pData, static_cast< char const * >(address) + offset + 4, len, RTL_TEXTENCODING_ASCII_US, (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR))) { throw FileFormatException(uri, "UNOIDL format: name is not ASCII"); } return name; } MappedFile::~MappedFile() { oslFileError e = osl_unmapMappedFile(handle, address, size); SAL_WARN_IF(e != osl_File_E_None, "unoidl", "cannot unmap: " << +e); e = osl_closeFile(handle); SAL_WARN_IF(e != osl_File_E_None, "unoidl", "cannot close: " << +e); } sal_uInt8 MappedFile::get8(sal_uInt32 offset) const { assert(size >= 8); assert(offset <= size - 1); return static_cast< char const * >(address)[offset]; } sal_uInt16 MappedFile::get16(sal_uInt32 offset) const { assert(size >= 8); assert(offset <= size - 2); return reinterpret_cast< Memory16 const * >( static_cast< char const * >(address) + offset)->getUnsigned16(); } sal_uInt32 MappedFile::get32(sal_uInt32 offset) const { assert(size >= 8); assert(offset <= size - 4); return reinterpret_cast< Memory32 const * >( static_cast< char const * >(address) + offset)->getUnsigned32(); } sal_uInt64 MappedFile::get64(sal_uInt32 offset) const { assert(size >= 8); assert(offset <= size - 8); return reinterpret_cast< Memory64 const * >( static_cast< char const * >(address) + offset)->getUnsigned64(); } float MappedFile::getIso60599Binary32(sal_uInt32 offset) const { assert(size >= 8); assert(offset <= size - 4); return reinterpret_cast< Memory32 const * >( static_cast< char const * >(address) + offset)->getIso60599Binary32(); } double MappedFile::getIso60599Binary64(sal_uInt32 offset) const { assert(size >= 8); assert(offset <= size - 8); return reinterpret_cast< Memory64 const * >( static_cast< char const * >(address) + offset)->getIso60599Binary64(); } // sizeof (MapEntry) == 8 struct MapEntry { Memory32 name; Memory32 data; }; } namespace { enum Compare { COMPARE_LESS, COMPARE_GREATER, COMPARE_EQUAL }; Compare compare( rtl::Reference< detail::MappedFile > const & file, OUString const & name, sal_Int32 nameOffset, sal_Int32 nameLength, detail::MapEntry const * entry) { assert(file.is()); assert(entry != 0); sal_uInt32 off = entry->name.getUnsigned32(); if (off > file->size - 1) { // at least a trailing NUL throw FileFormatException( file->uri, "UNOIDL format: string offset too large"); } assert(nameLength >= 0); sal_uInt64 min = std::min( static_cast< sal_uInt64 >(nameLength), file->size - off); for (sal_uInt64 i = 0; i != min; ++i) { sal_Unicode c1 = name[nameOffset + i]; sal_Unicode c2 = static_cast< unsigned char const * >(file->address)[ off + i]; if (c1 < c2) { return COMPARE_LESS; } else if (c1 > c2 || c2 == 0) { // ...the "|| c2 == 0" is for the odd case where name erroneously // contains NUL characters return COMPARE_GREATER; } } if (static_cast< sal_uInt64 >(nameLength) == min) { if (file->size - off == min) { throw FileFormatException( file->uri, "UNOIDL format: string misses trailing NUL"); } return static_cast< unsigned char const * >(file->address)[off + min] == 0 ? COMPARE_EQUAL : COMPARE_LESS; } else { return COMPARE_GREATER; } } sal_uInt32 findInMap( rtl::Reference< detail::MappedFile > const & file, detail::MapEntry const * mapBegin, sal_uInt32 mapSize, OUString const & name, sal_Int32 nameOffset, sal_Int32 nameLength) { if (mapSize == 0) { return 0; } sal_uInt32 n = mapSize / 2; detail::MapEntry const * p = mapBegin + n; switch (compare(file, name, nameOffset, nameLength, p)) { case COMPARE_LESS: return findInMap(file, mapBegin, n, name, nameOffset, nameLength); case COMPARE_GREATER: return findInMap( file, p + 1, mapSize - n - 1, name, nameOffset, nameLength); default: // COMPARE_EQUAL break; } sal_uInt32 off = mapBegin[n].data.getUnsigned32(); if (off == 0) { throw FileFormatException( file->uri, "UNOIDL format: map entry data offset is null"); } return off; } ConstantValue readConstant( rtl::Reference< detail::MappedFile > const & file, sal_uInt32 offset) { assert(file.is()); int v = file->read8(offset); int type = v & 0x7F; bool deprecated = (v & 0x80) != 0; (void)deprecated;//TODO switch (type) { case 0: // BOOLEAN v = file->read8(offset + 1); switch (v) { case 0: return ConstantValue(false); case 1: return ConstantValue(true); default: throw FileFormatException( file->uri, ("UNOIDL format: bad boolean constant value " + OUString::number(v))); } case 1: // BYTE return ConstantValue(static_cast< sal_Int8 >(file->read8(offset + 1))); //TODO: implementation-defined behavior of conversion from sal_uInt8 // to sal_Int8 relies on two's complement representation case 2: // SHORT return ConstantValue( static_cast< sal_Int16 >(file->read16(offset + 1))); //TODO: implementation-defined behavior of conversion from // sal_uInt16 to sal_Int16 relies on two's complement representation case 3: // UNSIGNED SHORT return ConstantValue(file->read16(offset + 1)); case 4: // LONG return ConstantValue( static_cast< sal_Int32 >(file->read32(offset + 1))); //TODO: implementation-defined behavior of conversion from // sal_uInt32 to sal_Int32 relies on two's complement representation case 5: // UNSIGNED LONG return ConstantValue(file->read32(offset + 1)); case 6: // HYPER return ConstantValue( static_cast< sal_Int64 >(file->read64(offset + 1))); //TODO: implementation-defined behavior of conversion from // sal_uInt64 to sal_Int64 relies on two's complement representation case 7: // UNSIGNED HYPER return ConstantValue(file->read64(offset + 1)); case 8: // FLOAT return ConstantValue(file->readIso60599Binary32(offset + 1)); case 9: // DOUBLE return ConstantValue(file->readIso60599Binary64(offset + 1)); default: throw FileFormatException( file->uri, "UNOIDL format: bad constant type byte " + OUString::number(v)); } } rtl::Reference< Entity > readEntity( rtl::Reference< detail::MappedFile > const & file, sal_uInt32 offset); class UnoidlCursor: public MapCursor { public: UnoidlCursor( rtl::Reference< detail::MappedFile > file, detail::MapEntry const * mapBegin, sal_uInt32 mapSize): file_(file), mapIndex_(mapBegin), mapEnd_(mapBegin + mapSize) {} private: virtual ~UnoidlCursor() throw () {} virtual rtl::Reference< Entity > getNext(OUString * name); rtl::Reference< detail::MappedFile > file_; detail::MapEntry const * mapIndex_; detail::MapEntry const * mapEnd_; }; rtl::Reference< Entity > UnoidlCursor::getNext(OUString * name) { assert(name != 0); rtl::Reference< Entity > ent; if (mapIndex_ != mapEnd_) { *name = file_->readNameNul(mapIndex_->name.getUnsigned32()); ent = readEntity(file_, mapIndex_->data.getUnsigned32()); ++mapIndex_; } return ent; } class UnoidlModuleEntity: public ModuleEntity { public: UnoidlModuleEntity( rtl::Reference< detail::MappedFile > const & file, sal_uInt32 mapOffset, sal_uInt32 mapSize): file_(file), mapBegin_( reinterpret_cast< detail::MapEntry const * >( static_cast< char const * >(file_->address) + mapOffset)), mapSize_(mapSize) { assert(file.is()); } private: virtual ~UnoidlModuleEntity() throw () {} virtual std::vector< OUString > getMemberNames() const; virtual rtl::Reference< MapCursor > createCursor() const { return new UnoidlCursor(file_, mapBegin_, mapSize_); } rtl::Reference< detail::MappedFile > file_; detail::MapEntry const * mapBegin_; sal_uInt32 mapSize_; }; std::vector< OUString > UnoidlModuleEntity::getMemberNames() const { std::vector< OUString > names; for (sal_uInt32 i = 0; i != mapSize_; ++i) { names.push_back(file_->readNameNul(mapBegin_[i].name.getUnsigned32())); } return names; } rtl::Reference< Entity > readEntity( rtl::Reference< detail::MappedFile > const & file, sal_uInt32 offset) { assert(file.is()); int v = file->read8(offset); int type = v & 0x3F; bool published = (v & 0x80) != 0; bool deprecated = (v & 0x40) != 0; (void)deprecated;//TODO bool flag = (v & 0x20) != 0; switch (type) { case 0: // module { if (v != 0) { throw FileFormatException( file->uri, ("UNOIDL format: bad module type byte " + OUString::number(v))); } sal_uInt32 n = file->read32(offset + 1); if (n > SAL_MAX_INT32) { throw FileFormatException( file->uri, "UNOIDL format: too many items in module"); } if (offset + 5 + 8 * n > file->size) { //TODO: overflow throw FileFormatException( file->uri, "UNOIDL format: module map offset + size too large"); } return new UnoidlModuleEntity(file, offset + 5, n); } case 1: // enum type { sal_uInt32 n = file->read32(offset + 1); if (n > SAL_MAX_INT32) { throw FileFormatException( file->uri, "UNOIDL format: too many members of enum type"); } offset += 5; std::vector< EnumTypeEntity::Member > mems; for (sal_uInt32 i = 0; i != n; ++i) { OUString memName(file->readNameLen(offset, &offset)); sal_Int32 memValue = static_cast< sal_Int32 >( file->read32(offset)); //TODO: implementation-defined behavior of conversion from // sal_uInt32 to sal_Int32 relies on two's complement // representation offset += 4; mems.push_back(EnumTypeEntity::Member(memName, memValue)); } return new EnumTypeEntity(published, mems); } case 2: // plain struct type without base case 2 | 0x20: // plain struct type with base { ++offset; OUString base; if (flag) { base = file->readNameLen(offset, &offset); if (base.isEmpty()) { throw FileFormatException( file->uri, ("UNOIDL format: empty base type name of plain struct" " type")); } } sal_uInt32 n = file->read32(offset); if (n > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many direct members of plain struct" " type")); } offset += 4; std::vector< PlainStructTypeEntity::Member > mems; for (sal_uInt32 i = 0; i != n; ++i) { OUString memName(file->readNameLen(offset, &offset)); OUString memType(file->readNameLen(offset, &offset)); mems.push_back(PlainStructTypeEntity::Member(memName, memType)); } return new PlainStructTypeEntity(published, base, mems); } case 3: // polymorphic struct type template { sal_uInt32 n = file->read32(offset + 1); if (n > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many type parameters of polymorphic" " struct type template")); } offset += 5; std::vector< OUString > params; for (sal_uInt32 i = 0; i != n; ++i) { params.push_back(file->readNameLen(offset, &offset)); } n = file->read32(offset); if (n > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many members of polymorphic struct" " type template")); } offset += 4; std::vector< PolymorphicStructTypeTemplateEntity::Member > mems; for (sal_uInt32 i = 0; i != n; ++i) { v = file->read8(offset); ++offset; OUString memName(file->readNameLen(offset, &offset)); OUString memType(file->readNameLen(offset, &offset)); if (v > 1) { throw FileFormatException( file->uri, ("UNOIDL format: bad flags " + OUString::number(v) + " for member " + memName + " of polymorphic struct type template")); } mems.push_back( PolymorphicStructTypeTemplateEntity::Member( memName, memType, v == 1)); } return new PolymorphicStructTypeTemplateEntity( published, params, mems); } case 4: // exception type without base case 4 | 0x20: // exception type with base { ++offset; OUString base; if (flag) { base = file->readNameLen(offset, &offset); if (base.isEmpty()) { throw FileFormatException( file->uri, ("UNOIDL format: empty base type name of exception" " type")); } } sal_uInt32 n = file->read32(offset); if (n > SAL_MAX_INT32) { throw FileFormatException( file->uri, "UNOIDL format: too many direct members of exception type"); } offset += 4; std::vector< ExceptionTypeEntity::Member > mems; for (sal_uInt32 i = 0; i != n; ++i) { OUString memName(file->readNameLen(offset, &offset)); OUString memType(file->readNameLen(offset, &offset)); mems.push_back(ExceptionTypeEntity::Member(memName, memType)); } return new ExceptionTypeEntity(published, base, mems); } case 5: // interface type { sal_uInt32 n = file->read32(offset + 1); if (n > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many direct mandatory bases of" " interface type")); } offset += 5; std::vector< OUString > mandBases; for (sal_uInt32 i = 0; i != n; ++i) { mandBases.push_back(file->readNameLen(offset, &offset)); } n = file->read32(offset); if (n > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many direct optional bases of" " interface type")); } offset += 4; std::vector< OUString > optBases; for (sal_uInt32 i = 0; i != n; ++i) { optBases.push_back(file->readNameLen(offset, &offset)); } sal_uInt32 nAttrs = file->read32(offset); if (nAttrs > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many direct attributes of interface" " type")); } offset += 4; std::vector< InterfaceTypeEntity::Attribute > attrs; for (sal_uInt32 i = 0; i != nAttrs; ++i) { v = file->read8(offset); ++offset; OUString attrName(file->readNameLen(offset, &offset)); OUString attrType(file->readNameLen(offset, &offset)); if (v > 0x03) { throw FileFormatException( file->uri, ("UNOIDL format: bad flags for direct attribute " + attrName + " of interface type")); } std::vector< OUString > getExcs; sal_uInt32 m = file->read32(offset); if (m > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many getter exceptions for direct" " attribute " + attrName + " of interface type")); } offset += 4; for (sal_uInt32 j = 0; j != m; ++j) { getExcs.push_back(file->readNameLen(offset, &offset)); } std::vector< OUString > setExcs; if ((v & 0x02) == 0) { m = file->read32(offset); if (m > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many setter exceptions for" " direct attribute " + attrName + " of interface type")); } offset += 4; for (sal_uInt32 j = 0; j != m; ++j) { setExcs.push_back(file->readNameLen(offset, &offset)); } } attrs.push_back( InterfaceTypeEntity::Attribute( attrName, attrType, (v & 0x01) != 0, (v & 0x02) != 0, getExcs, setExcs)); } sal_uInt32 nMeths = file->read32(offset); if (nMeths > SAL_MAX_INT32 - nAttrs) { throw FileFormatException( file->uri, ("UNOIDL format: too many direct attributes and methods of" " interface type")); } offset += 4; std::vector< InterfaceTypeEntity::Method > meths; for (sal_uInt32 i = 0; i != nMeths; ++i) { OUString methName(file->readNameLen(offset, &offset)); OUString methType(file->readNameLen(offset, &offset)); sal_uInt32 m = file->read32(offset); if (m > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many parameters for method " + methName + " of interface type")); } offset += 4; std::vector< InterfaceTypeEntity::Method::Parameter > params; for (sal_uInt32 j = 0; j != m; ++j) { v = file->read8(offset); ++offset; OUString paramName(file->readNameLen(offset, &offset)); OUString paramType(file->readNameLen(offset, &offset)); InterfaceTypeEntity::Method::Parameter::Direction dir; switch (v) { case 0: dir = InterfaceTypeEntity::Method::Parameter:: DIRECTION_IN; break; case 1: dir = InterfaceTypeEntity::Method::Parameter:: DIRECTION_OUT; break; case 2: dir = InterfaceTypeEntity::Method::Parameter:: DIRECTION_IN_OUT; break; default: throw FileFormatException( file->uri, ("UNOIDL format: bad direction " + OUString::number(v) + " of parameter " + paramName + " for method " + methName + " of interface type")); } params.push_back( InterfaceTypeEntity::Method::Parameter( paramName, paramType, dir)); } std::vector< OUString > excs; m = file->read32(offset); if (m > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many exceptions for method " + methName + " of interface type")); } offset += 4; for (sal_uInt32 j = 0; j != m; ++j) { excs.push_back(file->readNameLen(offset, &offset)); } meths.push_back( InterfaceTypeEntity::Method( methName, methType, params, excs)); } return new InterfaceTypeEntity( published, mandBases, optBases, attrs, meths); } case 6: // typedef return new TypedefEntity(published, file->readNameLen(offset + 1)); case 7: // constant group { sal_uInt32 n = file->read32(offset + 1); if (n > SAL_MAX_INT32) { throw FileFormatException( file->uri, "UNOIDL format: too many constants in constant group"); } if (offset + 5 + 8 * n > file->size) { //TODO: overflow throw FileFormatException( file->uri, ("UNOIDL format: constant group map offset + size too" " large")); } detail::MapEntry const * p = reinterpret_cast< detail::MapEntry const * >( static_cast< char const * >(file->address) + offset + 5); std::vector< ConstantGroupEntity::Member > mems; for (sal_uInt32 i = 0; i != n; ++i) { mems.push_back( ConstantGroupEntity::Member( file->readNameNul(p[i].name.getUnsigned32()), readConstant(file, p[i].data.getUnsigned32()))); } return new ConstantGroupEntity(published, mems); } case 8: // single-interface--based service without default constructor case 8 | 0x20: // single-interface--based service with default constructor { OUString base(file->readNameLen(offset + 1, &offset)); std::vector< SingleInterfaceBasedServiceEntity::Constructor > ctors; if (flag) { ctors.push_back( SingleInterfaceBasedServiceEntity::Constructor()); } else { sal_uInt32 n = file->read32(offset); if (n > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many constructors of" " single-interface--based service")); } offset += 4; for (sal_uInt32 i = 0; i != n; ++i) { OUString ctorName(file->readNameLen(offset, &offset)); sal_uInt32 m = file->read32(offset); if (m > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many parameters for" " constructor " + ctorName + " of single-interface--based service")); } offset += 4; std::vector< SingleInterfaceBasedServiceEntity::Constructor:: Parameter > params; for (sal_uInt32 j = 0; j != m; ++j) { v = file->read8(offset); ++offset; OUString paramName(file->readNameLen(offset, &offset)); OUString paramType(file->readNameLen(offset, &offset)); bool rest; switch (v) { case 0: rest = false; break; case 0x04: rest = true; break; default: throw FileFormatException( file->uri, ("UNOIDL format: bad mode " + OUString::number(v) + " of parameter " + paramName + " for constructor " + ctorName + " of single-interface--based service")); } params.push_back( SingleInterfaceBasedServiceEntity::Constructor:: Parameter( paramName, paramType, rest)); } std::vector< OUString > excs; m = file->read32(offset); if (m > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many exceptions for" " constructor " + ctorName + " of single-interface--based service")); } offset += 4; for (sal_uInt32 j = 0; j != m; ++j) { excs.push_back(file->readNameLen(offset, &offset)); } ctors.push_back( SingleInterfaceBasedServiceEntity::Constructor( ctorName, params, excs)); } } return new SingleInterfaceBasedServiceEntity( published, base, ctors); } case 9: // accumulation-based service { sal_uInt32 n = file->read32(offset + 1); if (n > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many direct mandatory service bases of" " accumulation-based service")); } offset += 5; std::vector< OUString > mandServs; for (sal_uInt32 i = 0; i != n; ++i) { mandServs.push_back(file->readNameLen(offset, &offset)); } n = file->read32(offset); if (n > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many direct optional service bases of" " accumulation-based service")); } offset += 4; std::vector< OUString > optServs; for (sal_uInt32 i = 0; i != n; ++i) { optServs.push_back(file->readNameLen(offset, &offset)); } n = file->read32(offset); if (n > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many direct mandatory interface bases" " of accumulation-based service")); } offset += 4; std::vector< OUString > mandIfcs; for (sal_uInt32 i = 0; i != n; ++i) { mandIfcs.push_back(file->readNameLen(offset, &offset)); } n = file->read32(offset); if (n > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many direct optional interface bases" " of accumulation-based service")); } offset += 4; std::vector< OUString > optIfcs; for (sal_uInt32 i = 0; i != n; ++i) { optIfcs.push_back(file->readNameLen(offset, &offset)); } n = file->read32(offset); if (n > SAL_MAX_INT32) { throw FileFormatException( file->uri, ("UNOIDL format: too many direct properties of" " accumulation-based service")); } offset += 4; std::vector< AccumulationBasedServiceEntity::Property > props; for (sal_uInt32 i = 0; i != n; ++i) { sal_uInt16 attrs = file->read16(offset); offset += 2; OUString propName(file->readNameLen(offset, &offset)); OUString propType(file->readNameLen(offset, &offset)); if (attrs > 0x01FF) { // see css.beans.PropertyAttribute throw FileFormatException( file->uri, ("UNOIDL format: bad mode " + OUString::number(v) + " of property " + propName + " for accumulation-based servcie")); } props.push_back( AccumulationBasedServiceEntity::Property( propName, propType, static_cast< AccumulationBasedServiceEntity::Property:: Attributes >( attrs))); } return new AccumulationBasedServiceEntity( published, mandServs, optServs, mandIfcs, optIfcs, props); } case 10: // interface-based singleton return new InterfaceBasedSingletonEntity( published, file->readNameLen(offset + 1)); case 11: // service-based singleton return new ServiceBasedSingletonEntity( published, file->readNameLen(offset + 1)); default: throw FileFormatException( file->uri, "UNOIDL format: bad type byte " + OUString::number(v)); } } } UnoidlProvider::UnoidlProvider(OUString const & uri): file_(new detail::MappedFile(uri)) { if (file_->size < 8 || std::memcmp(file_->address, "UNOIDL\0\xFF", 8) != 0) { throw FileFormatException( file_->uri, "UNOIDL format: does not begin with magic UNOIDL\\0\\xFF"); } sal_uInt32 off = file_->read32(8); mapSize_ = file_->read32(12); if (off + 8 * mapSize_ > file_->size) { //TODO: overflow throw FileFormatException( file_->uri, "UNOIDL format: root map offset + size too large"); } mapBegin_ = reinterpret_cast< detail::MapEntry const * >( static_cast< char const * >(file_->address) + off); } rtl::Reference< MapCursor > UnoidlProvider::createRootCursor() const { return new UnoidlCursor(file_, mapBegin_, mapSize_); } rtl::Reference< Entity > UnoidlProvider::findEntity(OUString const & name) const { bool cnst; sal_uInt32 off = find(name, &cnst); return off == 0 || cnst ? rtl::Reference< Entity >() : getEntity(off); } sal_uInt32 UnoidlProvider::find(OUString const & name, bool * constant) const { detail::MapEntry const * mapBegin = mapBegin_; sal_uInt32 mapSize = mapSize_; bool cgroup = false; for (sal_Int32 i = 0;;) { sal_Int32 j = name.indexOf('.', i); if (j == -1) { j = name.getLength(); } sal_Int32 off = findInMap(file_, mapBegin, mapSize, name, i, j - i); if (off == 0) { return 0; } if (j == name.getLength()) { if (constant != 0) { *constant = cgroup; } return off; } if (cgroup) { return 0; //TODO: throw an exception instead here, where the segments of a // constant's name are a prefix of the requested name's // segments? } int v = file_->read8(off); if (v != 0) { // module if ((v & 0x3F) == 7) { // constant group cgroup = true; } else { return 0; //TODO: throw an exception instead here, where the segments // of a non-module, non-constant-group entity's name are a // prefix of the requested name's segments? } } mapSize = file_->read32(off + 1); if (8 * mapSize > file_->size - off - 5) { //TODO: overflow throw FileFormatException( file_->uri, "UNOIDL format: map offset + size too large"); } mapBegin = reinterpret_cast< detail::MapEntry const * >( static_cast< char const * >(file_->address) + off + 5); i = j + 1; } } rtl::Reference< Entity > UnoidlProvider::getEntity(sal_uInt32 offset) const { return readEntity(file_, offset); } ConstantValue UnoidlProvider::getConstant(sal_uInt32 offset) const { return readConstant(file_, offset); } UnoidlProvider::~UnoidlProvider() throw () {} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */