/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ /* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace com::sun::star::uno { class XInterface; } namespace { template OUString hex(T value, sal_Int32 width) { OUStringBuffer buf(OUString::number(value, 16)); while (buf.getLength() < width) { buf.insert(0, '0'); } return buf.makeStringAndClear(); } css::uno::TypeDescription getTypeDescription(css::uno::Type const& type) { typelib_TypeDescription* d = nullptr; type.getDescription(&d); return css::uno::TypeDescription(d); } OUString getIdentifier(css::uno::Reference const& constant) { auto const n = constant->getName(); auto const i = n.lastIndexOf('.'); if (i == -1 || i == n.getLength() - 1) { throw css::uno::DeploymentException("bad constant name " + n); } return n.copy(i + 1); } OUString dumpBitset(css::uno::Sequence> const& constants, sal_uInt64 value) { OUStringBuffer buf; auto a = value; for (auto const& i : constants) { sal_uInt64 c; if ((i->getConstantValue() >>= c) && std::bitset<64>{ c }.count() == 1 && (a & c) != 0) { if (!buf.isEmpty()) { buf.append('+'); } buf.append(getIdentifier(i)); a &= ~c; } } return a == 0 && !buf.isEmpty() ? buf.makeStringAndClear() : OUString::number(value); } class Dump : public cppu::BaseMutex, public cppu::WeakComponentImplHelper { public: explicit Dump(css::uno::Reference const& context) : WeakComponentImplHelper(m_aMutex) , manager_(context->getValueByName( u"/singletons/com.sun.star.reflection.theTypeDescriptionManager"_ustr), css::uno::UNO_QUERY_THROW) { } void SAL_CALL disposing() override { osl::MutexGuard g(m_aMutex); manager_.clear(); } OUString SAL_CALL dumpValue(css::uno::Any const& value) override { switch (value.getValueTypeClass()) { case css::uno::TypeClass_VOID: return u"void"_ustr; case css::uno::TypeClass_BOOLEAN: return OUString::boolean(value.get()); case css::uno::TypeClass_BYTE: return OUString::number(value.get()); case css::uno::TypeClass_SHORT: return OUString::number(value.get()); case css::uno::TypeClass_UNSIGNED_SHORT: return OUString::number(value.get()); case css::uno::TypeClass_LONG: return OUString::number(value.get()); case css::uno::TypeClass_UNSIGNED_LONG: return OUString::number(value.get()); case css::uno::TypeClass_HYPER: return OUString::number(value.get()); case css::uno::TypeClass_UNSIGNED_HYPER: return OUString::number(value.get()); case css::uno::TypeClass_FLOAT: return OUString::number(value.get()); case css::uno::TypeClass_DOUBLE: return OUString::number(value.get()); case css::uno::TypeClass_CHAR: return "U+" + hex(value.get(), 16); case css::uno::TypeClass_STRING: { auto const s = value.get(); OUStringBuffer buf; for (sal_Int32 i = 0; i != s.getLength();) { auto const c = s.iterateCodePoints(&i); if (c >= u8' ' && c <= u8'~') { if (c == u8'\"' || c == u8'\\') { buf.append('\\'); } buf.append(char(c)); } else if (c <= 0xFFFF) { buf.append("\\u" + hex(c, 4)); } else { buf.append("\\U" + hex(c, 8)); } } return "\"" + buf + "\""; } case css::uno::TypeClass_TYPE: return value.get().getTypeName(); case css::uno::TypeClass_SEQUENCE: { css::uno::Type const t(reinterpret_cast( getTypeDescription(value.getValueType()).get()) ->pType); auto const n = getTypeDescription(t).get()->nSize; auto const s = *static_cast(value.getValue()); OUStringBuffer buf; for (sal_Int32 i = 0; i != s->nElements; ++i) { if (i != 0) { buf.append(", "); } css::uno::Any const e(s->elements + i * n, t); buf.append(t == cppu::UnoType::get() ? dumpAny(e) : dumpValue(e)); } return "[" + buf + "]"; } case css::uno::TypeClass_ENUM: { auto const d = getTypeDescription(value.getValueType()); auto const ed = reinterpret_cast(d.get()); auto const e = *static_cast(value.getValue()); for (sal_Int32 i = 0; i != ed->nEnumValues; ++i) { if (ed->pEnumValues[i] == e) { return OUString(ed->ppEnumNames[i]); } } return OUString::number(e); } case css::uno::TypeClass_STRUCT: case css::uno::TypeClass_EXCEPTION: { auto const d = getTypeDescription(value.getValueType()); OUStringBuffer buf; dumpCompoundType(reinterpret_cast(d.get()), value.getValue(), &buf); return "[" + buf + "]"; } case css::uno::TypeClass_INTERFACE: { auto const p = *static_cast(value.getValue()); return p == nullptr ? u"null"_ustr : OUString("0x" + hex(reinterpret_cast(p), SAL_TYPES_SIZEOFPOINTER * 2)); } default: O3TL_UNREACHABLE; } } OUString SAL_CALL dumpAny(css::uno::Any const& value) override { return "[" + value.getValueTypeName() + ": " + dumpValue(value) + "]"; } OUString SAL_CALL dumpConstant(OUString const& constantsGroup, css::uno::Any const& value) override { css::uno::Reference manager; { osl::MutexGuard g(m_aMutex); if (rBHelper.bDisposed) { throw css::lang::DisposedException(u"css.reflection.Dumper"_ustr); } manager = manager_; } css::uno::Reference g; try { manager_->getByHierarchicalName(constantsGroup) >>= g; } catch (css::container::NoSuchElementException) { } if (!g.is()) { throw css::lang::IllegalArgumentException("not a constants group: " + constantsGroup, {}, 0); } auto const s = g->getConstants(); switch (value.getValueTypeClass()) { case css::uno::TypeClass_BOOLEAN: for (auto const& i : s) { if (i->getConstantValue() == value) { return getIdentifier(i); } } return OUString::boolean(value.get()); case css::uno::TypeClass_BYTE: case css::uno::TypeClass_SHORT: case css::uno::TypeClass_LONG: case css::uno::TypeClass_HYPER: { auto const v = value.get(); for (auto const& i : s) { sal_Int64 c; if ((i->getConstantValue() >>= c) && c == v) { return getIdentifier(i); } } return v >= 0 ? dumpBitset(s, v) : OUString::number(v); } case css::uno::TypeClass_UNSIGNED_SHORT: case css::uno::TypeClass_UNSIGNED_LONG: case css::uno::TypeClass_UNSIGNED_HYPER: { auto const v = value.get(); for (auto const& i : s) { sal_uInt64 c; if ((i->getConstantValue() >>= c) && c == v) { return getIdentifier(i); } } return dumpBitset(s, v); } case css::uno::TypeClass_FLOAT: case css::uno::TypeClass_DOUBLE: { auto const v = value.get(); for (auto const& i : s) { double c; if ((i->getConstantValue() >>= c) && c == v) { return getIdentifier(i); } } return OUString::number(v); } default: throw css::lang::IllegalArgumentException( "not a numeric type: " + value.getValueTypeName(), {}, 1); } } private: css::uno::Reference manager_; void dumpCompoundType(typelib_CompoundTypeDescription const* description, void const* data, OUStringBuffer* buffer) { if (auto base = description->pBaseTypeDescription) { dumpCompoundType(base, data, buffer); } for (sal_Int32 i = 0; i != description->nMembers; ++i) { if (!buffer->isEmpty()) { buffer->append(", "); } buffer->append(OUString::unacquired(description->ppMemberNames + i) + ": "); css::uno::Type t(description->ppTypeRefs[i]); css::uno::Any const m(static_cast(data) + description->pMemberOffsets[i], t); buffer->append(t == cppu::UnoType::get() ? dumpAny(m) : dumpValue(m)); } } }; } extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* com_sun_star_comp_stoc_Dump_get_implementation(css::uno::XComponentContext* context, css::uno::Sequence const& arguments) { SAL_WARN_IF(arguments.hasElements(), "stoc", "unexpected singleton arguments"); return cppu::acquire(new Dump(context)); } /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */