From 6b4d713cb075b4e01550b5842ef36355ca9d05d3 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 3 Aug 2026 05:03:58 -0700 Subject: [PATCH 1/4] [API] Add FFI wrapper modifier to strong typedefs --- base/strong_typedef.h | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/base/strong_typedef.h b/base/strong_typedef.h index 1a2db87d0..136b266dc 100644 --- a/base/strong_typedef.h +++ b/base/strong_typedef.h @@ -22,6 +22,7 @@ #include // IWYU pragma: keep #include +#include #include #include #include @@ -89,6 +90,8 @@ // Hashable usable as a key in std and absl hash containers // Formattable formattable with fmt, forwarding format specs such as {:#x} to the // underlying type's formatter +// FfiWrapper implicit conversion to and from a C-style wrapper structure through +// the specified member, without making the underlying type implicit // NonExtractable removes the explicit operator T() and the Value() accessor, so the // underlying value can be constructed but never read back out. Every // other modifier continues to function as normal. @@ -115,6 +118,25 @@ namespace detail { template inline constexpr bool HasModifier = (std::is_same_v || ...); +template +concept FfiWrapperFor = requires(const Ffi& value) { + typename Mod::FfiType; + requires std::same_as; + { Mod::template FromFfi(value) } -> std::same_as; +}; + +template +inline constexpr bool HasFfiWrapper = (FfiWrapperFor || ...); + +template +constexpr T FromFfi(const Ffi& value) +{ + if constexpr (FfiWrapperFor) + return First::template FromFfi(value); + else + return FromFfi(value); +} + // Internal access to a StrongTypedef's underlying value so that modifiers have // access to it even when NonExtractable is in use. struct Access @@ -409,6 +431,33 @@ struct Formattable }; }; +// Enables implicit conversion to and from a C-style wrapper structure whose selected +// member stores the StrongTypedef's underlying value. Conversion to the underlying type +// itself remains explicit. +template +struct FfiWrapper +{ + using FfiType = Ffi; + + template + static constexpr T FromFfi(const Ffi& value) + { + return T(value.*ValueMember); + } + + template + requires requires(Ffi ffi, const T& value) { ffi.*ValueMember = value; } + struct Apply + { + constexpr operator Ffi() const + { + Ffi result {}; + result.*ValueMember = detail::Access::Get(static_cast(*this)); + return result; + } + }; +}; + // Disable both the explicit operator T() and the Value() accessor. // All other modifiers continue to function as normal. struct NonExtractable @@ -437,6 +486,13 @@ class BN_EMPTY_BASES StrongTypedef : public Mods::template Apply + requires detail::HasFfiWrapper, T, Mods...> + constexpr StrongTypedef(Ffi&& value) + : m_value(detail::FromFfi, Mods...>(value)) + { + } + explicit constexpr operator T() const noexcept(std::is_nothrow_copy_constructible_v) requires (!detail::HasModifier) { From e9bf26207a216cc17bcc2767236a8daea4a11326 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 3 Aug 2026 05:04:20 -0700 Subject: [PATCH 2/4] Add Binary Similarity APIs --- binaryninjacore.h | 435 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 433 insertions(+), 2 deletions(-) diff --git a/binaryninjacore.h b/binaryninjacore.h index b1e83870a..925c49968 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -37,14 +37,14 @@ // Current ABI version for linking to the core. This is incremented any time // there are changes to the API that affect linking, including new functions, // new types, or modifications to existing functions or types. -#define BN_CURRENT_CORE_ABI_VERSION 179 +#define BN_CURRENT_CORE_ABI_VERSION 180 // Minimum ABI version that is supported for loading of plugins. Plugins that // are linked to an ABI version less than this will not be able to load and // will require rebuilding. The minimum version is increased when there are // incompatible changes that break binary compatibility, such as changes to // existing types or functions. -#define BN_MINIMUM_CORE_ABI_VERSION 179 +#define BN_MINIMUM_CORE_ABI_VERSION 180 #define BN_DEMANGLER_MSVC "MS" #define BN_DEMANGLER_GNU3 "GNU3" @@ -359,6 +359,20 @@ extern "C" typedef struct BNConstantRenderer BNConstantRenderer; typedef struct BNStringRecognizer BNStringRecognizer; typedef struct BNCustomStringType BNCustomStringType; + typedef struct BNSimilarityProviderType BNSimilarityProviderType; + typedef struct BNSimilarityProvider BNSimilarityProvider; + typedef struct BNSimilarityProviderResults BNSimilarityProviderResults; + typedef struct BNSimilarityRenderContext BNSimilarityRenderContext; + typedef struct BNSimilarityView BNSimilarityView; + typedef struct BNDiffRenderer BNDiffRenderer; + typedef struct BNSimilaritySessionResolverType BNSimilaritySessionResolverType; + typedef struct BNSimilaritySessionResolver BNSimilaritySessionResolver; + typedef struct BNSimilaritySessionNode BNSimilaritySessionNode; + typedef struct BNSimilaritySessionGraph BNSimilaritySessionGraph; + typedef struct BNSimilaritySessionGraphReceiver BNSimilaritySessionGraphReceiver; + typedef struct BNSimilaritySessionCompletion BNSimilaritySessionCompletion; + typedef struct BNSimilaritySessionReceiver BNSimilaritySessionReceiver; + typedef struct BNSimilaritySession BNSimilaritySession; typedef struct BNVersionInfo { uint32_t major; @@ -4300,6 +4314,423 @@ extern "C" char* stringPostfix; } BNCustomStringTypeInfo; + typedef struct BNSimilarityEntityId + { + uint32_t value; + } BNSimilarityEntityId; + + typedef struct BNSimilarityResultId + { + uint64_t value; + } BNSimilarityResultId; + + typedef struct BNSimilaritySessionNodeId + { + uint32_t value; + } BNSimilaritySessionNodeId; + + typedef struct BNSimilaritySessionId + { + uint32_t value; + } BNSimilaritySessionId; + + typedef struct BNSimilarityProviderId + { + uint32_t value; + } BNSimilarityProviderId; + + typedef struct BNSimilaritySessionResolverId + { + uint32_t value; + } BNSimilaritySessionResolverId; + + typedef struct BNSimilarityEntityRef + { + BNSimilaritySessionNodeId nodeId; + BNSimilarityEntityId entityId; + } BNSimilarityEntityRef; + + BN_ENUM(uint8_t, BNSimilarityEntityType) + { + SimilarityEntityFunction = 0, + }; + + BN_ENUM(uint8_t, BNSimilarityApplyStatus) + { + SimilarityApplySuccess = 0, + SimilarityApplyNodeInactive = 1, + SimilarityApplyEntityNotFound = 2, + SimilarityApplyUnsupported = 3, + SimilarityApplyFailed = 4, + }; + + typedef struct BNSimilarityResult + { + BNSimilarityProviderId providerId; + uint8_t similarity; + uint8_t confidence; + BNSimilarityEntityRef target; + } BNSimilarityResult; + + typedef struct BNSimilarityEntityInfo + { + BNSimilarityEntityType type; + uint64_t address; + const char* name; + } BNSimilarityEntityInfo; + + BN_ENUM(uint8_t, BNSimilarityViewType) { + SimilarityViewFlowGraph = 0, + SimilarityViewLinear = 1, + }; + + BN_ENUM(uint8_t, BNSimilarityAnnotationType) { + SimilarityAnnotationAdded = 0, + SimilarityAnnotationRemoved = 1, + SimilarityAnnotationChanged = 2, + }; + + typedef struct BNSimilarityRangeAnnotation + { + uint64_t start; + uint64_t end; + BNSimilarityAnnotationType type; + } BNSimilarityRangeAnnotation; + + typedef struct BNSimilaritySessionCompletionQuery + { + bool hasNodeId; + BNSimilaritySessionNodeId nodeId; + bool hasProviderId; + BNSimilarityProviderId providerId; + bool hasResolverId; + BNSimilaritySessionResolverId resolverId; + } BNSimilaritySessionCompletionQuery; + + typedef struct BNCustomSimilarityProvider + { + void* context; + void (*externalRefTaken)(void* ctxt); + void (*externalRefReleased)(void* ctxt); + bool (*updateSettings)(void* ctxt, BNSettings* settings); + bool (*visitNode)(void* ctxt, BNSimilaritySessionNode* node, BNSimilarityProviderResults* results, + BNSimilaritySessionCompletion* completion); + bool (*visitNodeEdge)(void* ctxt, BNSimilaritySessionNode* from, BNSimilaritySessionNode* to, + BNSimilarityProviderResults* results, BNSimilaritySessionCompletion* completion); + char* (*getName)(void* ctxt, BNSimilaritySessionNode* node, BNSimilarityEntityId entity, + BNSimilarityResultId result); + BNSimilarityApplyStatus (*apply)(void* ctxt, BNSimilaritySessionNode* node, BNSimilarityEntityId entity, + BNSimilarityResultId result); + void (*render)(void* ctxt, BNSimilaritySessionNode* node, BNSimilarityEntityId entity, + BNSimilarityRenderContext* context, BNSimilarityResultId result); + void (*free)(void* ctxt); + } BNCustomSimilarityProvider; + + typedef struct BNCustomSimilarityProviderType + { + void* context; + BNSimilarityProvider* (*create)(void* ctxt, BNSettings* settings); + BNSettings* (*getDefaultSettings)(void* ctxt); + } BNCustomSimilarityProviderType; + + typedef struct BNCustomSimilaritySessionResolver + { + void* context; + void (*externalRefTaken)(void* ctxt); + void (*externalRefReleased)(void* ctxt); + bool (*updateSettings)(void* ctxt, BNSettings* settings); + void (*prepareForNode)(void* ctxt, BNSimilaritySession* session, BNSimilaritySessionNode* node, + BNSimilaritySessionCompletion* completion, BNSimilaritySessionResolverId resolverId); + void (*resolveForNode)(void* ctxt, BNSimilaritySession* session, BNSimilaritySessionNode* node, + const BNSimilarityEntityId* entities, size_t entityCount, BNSimilaritySessionCompletion* completion, + BNSimilaritySessionResolverId resolverId); + void (*free)(void* ctxt); + } BNCustomSimilaritySessionResolver; + + typedef struct BNCustomSimilaritySessionResolverType + { + void* context; + BNSimilaritySessionResolver* (*create)(void* ctxt, BNSimilaritySession* session, BNSettings* settings); + BNSettings* (*getDefaultSettings)(void* ctxt); + } BNCustomSimilaritySessionResolverType; + + typedef struct BNCustomSimilaritySessionReceiver + { + void* context; + void (*externalRefTaken)(void* ctxt); + void (*externalRefReleased)(void* ctxt); + void (*onStarted)(void* ctxt, BNSimilaritySessionCompletion* completion); + void (*onUpdated)(void* ctxt, BNSimilaritySessionNode* node, BNSimilarityProvider* provider, + const BNSimilarityEntityId* entities, size_t count); + void (*free)(void* ctxt); + } BNCustomSimilaritySessionReceiver; + + typedef struct BNCustomSimilaritySessionGraphReceiver + { + void* context; + void (*externalRefTaken)(void* ctxt); + void (*externalRefReleased)(void* ctxt); + void (*onGraphChanged)(void* ctxt); + void (*free)(void* ctxt); + } BNCustomSimilaritySessionGraphReceiver; + + BINARYNINJACOREAPI BNSimilarityProviderType* BNRegisterSimilarityProviderType( + const char* name, const char* description, BNCustomSimilarityProviderType* type); + BINARYNINJACOREAPI BNSimilarityProviderType* BNGetSimilarityProviderTypeByName(const char* name); + BINARYNINJACOREAPI BNSimilarityProviderType** BNGetSimilarityProviderTypeList(size_t* count); + BINARYNINJACOREAPI void BNFreeSimilarityProviderTypeList(BNSimilarityProviderType** types); + BINARYNINJACOREAPI char* BNSimilarityProviderTypeGetName(BNSimilarityProviderType* type); + BINARYNINJACOREAPI char* BNSimilarityProviderTypeGetDescription(BNSimilarityProviderType* type); + /*! Returns `nullptr` outside the Ultimate edition. */ + BINARYNINJACOREAPI BNSimilarityProvider* BNSimilarityProviderTypeCreateProvider( + BNSimilarityProviderType* type, BNSettings* settings); + BINARYNINJACOREAPI BNSettings* BNSimilarityProviderTypeGetDefaultSettings(BNSimilarityProviderType* type); + + BINARYNINJACOREAPI BNSimilarityProvider* BNCreateCustomSimilarityProvider( + BNSimilarityProviderType* type, BNCustomSimilarityProvider* callbacks); + BINARYNINJACOREAPI void BNSimilarityProviderVisitNode( + BNSimilarityProvider* provider, BNSimilaritySessionNode* node, BNSimilaritySessionCompletion* completion); + BINARYNINJACOREAPI void BNSimilarityProviderVisitNodeEdge(BNSimilarityProvider* provider, + BNSimilaritySessionNode* from, BNSimilaritySessionNode* to, BNSimilaritySessionCompletion* completion); + BINARYNINJACOREAPI bool BNSimilarityProviderPerformVisitNode(BNSimilarityProvider* provider, + BNSimilaritySessionNode* node, BNSimilarityProviderResults* results, BNSimilaritySessionCompletion* completion); + BINARYNINJACOREAPI bool BNSimilarityProviderPerformVisitNodeEdge(BNSimilarityProvider* provider, + BNSimilaritySessionNode* from, BNSimilaritySessionNode* to, BNSimilarityProviderResults* results, + BNSimilaritySessionCompletion* completion); + BINARYNINJACOREAPI BNSimilarityResultId BNSimilarityProviderResultsAddResult(BNSimilarityProviderResults* results, + const BNSimilarityEntityRef* source, const BNSimilarityEntityRef* target, + uint8_t similarity, uint8_t confidence); + BINARYNINJACOREAPI BNSimilarityProviderType* BNSimilarityProviderGetType(BNSimilarityProvider* provider); + BINARYNINJACOREAPI BNSimilarityProviderId BNSimilarityProviderGetId(BNSimilarityProvider* provider); + BINARYNINJACOREAPI char* BNSimilarityProviderGetName(BNSimilarityProvider* provider, + BNSimilaritySessionNode* node, BNSimilarityEntityId entity, BNSimilarityResultId result); + BINARYNINJACOREAPI BNSimilarityApplyStatus BNSimilarityProviderApply(BNSimilarityProvider* provider, + BNSimilaritySessionNode* node, BNSimilarityEntityId entity, BNSimilarityResultId result); + BINARYNINJACOREAPI BNSimilarityApplyStatus BNSimilaritySessionNodeApplyTarget(BNSimilaritySessionNode* node, + BNSimilarityEntityId entity, const BNSimilarityEntityRef* target); + BINARYNINJACOREAPI void BNSimilarityProviderRender( + BNSimilarityProvider* provider, BNSimilaritySessionNode* node, BNSimilarityEntityId entity, + BNSimilarityRenderContext* context, BNSimilarityResultId result); + + BINARYNINJACOREAPI BNSimilarityRenderContext* BNCreateSimilarityRenderContext(void); + BINARYNINJACOREAPI void BNSimilarityRenderContextSetPreferredViewType( + BNSimilarityRenderContext* context, BNFunctionViewType type); + BINARYNINJACOREAPI BNFunctionGraphType BNSimilarityRenderContextGetPreferredViewType( + BNSimilarityRenderContext* context); + BINARYNINJACOREAPI char* BNSimilarityRenderContextGetPreferredViewTypeName(BNSimilarityRenderContext* context); + BINARYNINJACOREAPI void BNSimilarityRenderContextAddFlowGraph( + BNSimilarityRenderContext* context, const char* group, BNFlowGraph* graph); + BINARYNINJACOREAPI void BNSimilarityRenderContextAddFlowGraphForEntity( + BNSimilarityRenderContext* context, const char* group, BNFlowGraph* graph, const BNSimilarityEntityRef* entity); + BINARYNINJACOREAPI void BNSimilarityRenderContextAddLinearView( + BNSimilarityRenderContext* context, const char* group, BNBinaryView* data, BNLinearViewObject* linearView); + BINARYNINJACOREAPI void BNSimilarityRenderContextAddLinearViewForEntity(BNSimilarityRenderContext* context, + const char* group, BNBinaryView* data, BNLinearViewObject* linearView, const BNSimilarityEntityRef* entity); + BINARYNINJACOREAPI BNSimilarityView** BNGetSimilarityRenderContextViews( + BNSimilarityRenderContext* context, size_t* count); + BINARYNINJACOREAPI void BNFreeSimilarityViewList(BNSimilarityView** views, size_t count); + BINARYNINJACOREAPI char* BNSimilarityViewGetGroup(BNSimilarityView* view); + BINARYNINJACOREAPI BNSimilarityViewType BNSimilarityViewGetType(BNSimilarityView* view); + BINARYNINJACOREAPI BNFlowGraph* BNSimilarityViewGetFlowGraph(BNSimilarityView* view); + BINARYNINJACOREAPI BNBinaryView* BNSimilarityViewGetLinearViewData(BNSimilarityView* view); + BINARYNINJACOREAPI BNLinearViewObject* BNSimilarityViewGetLinearView(BNSimilarityView* view); + BINARYNINJACOREAPI bool BNSimilarityViewGetEntity(BNSimilarityView* view, BNSimilarityEntityRef* entity); + BINARYNINJACOREAPI BNSimilarityView* BNNewSimilarityViewReference(BNSimilarityView* view); + BINARYNINJACOREAPI void BNFreeSimilarityView(BNSimilarityView* view); + BINARYNINJACOREAPI BNSimilarityRenderContext* BNNewSimilarityRenderContextReference( + BNSimilarityRenderContext* context); + BINARYNINJACOREAPI void BNFreeSimilarityRenderContext(BNSimilarityRenderContext* context); + BINARYNINJACOREAPI BNDiffRenderer* BNCreateDiffRenderer(void); + BINARYNINJACOREAPI void BNDiffRendererAddRangeAnnotation( + BNDiffRenderer* renderer, uint64_t start, uint64_t end, BNSimilarityAnnotationType type); + BINARYNINJACOREAPI void BNDiffRendererRenderFunction( + BNDiffRenderer* renderer, BNSimilarityRenderContext* context, BNFunction* function); + BINARYNINJACOREAPI void BNDiffRendererRenderFunctionForEntity(BNDiffRenderer* renderer, + BNSimilarityRenderContext* context, BNFunction* function, const BNSimilarityEntityRef* entity); + BINARYNINJACOREAPI void BNDiffRendererRenderFlowGraph( + BNDiffRenderer* renderer, BNSimilarityRenderContext* context, const char* group, BNFlowGraph* graph); + BINARYNINJACOREAPI void BNDiffRendererRenderFlowGraphForEntity(BNDiffRenderer* renderer, + BNSimilarityRenderContext* context, const char* group, BNFlowGraph* graph, const BNSimilarityEntityRef* entity); + BINARYNINJACOREAPI void BNDiffRendererRenderLinearView(BNDiffRenderer* renderer, BNSimilarityRenderContext* context, + const char* group, BNBinaryView* data, BNLinearViewObject* linearView); + BINARYNINJACOREAPI void BNDiffRendererRenderLinearViewForEntity(BNDiffRenderer* renderer, + BNSimilarityRenderContext* context, const char* group, BNBinaryView* data, BNLinearViewObject* linearView, + const BNSimilarityEntityRef* entity); + BINARYNINJACOREAPI BNDiffRenderer* BNNewDiffRendererReference(BNDiffRenderer* renderer); + BINARYNINJACOREAPI void BNFreeDiffRenderer(BNDiffRenderer* renderer); + BINARYNINJACOREAPI BNSimilarityProvider* BNNewSimilarityProviderReference(BNSimilarityProvider* provider); + BINARYNINJACOREAPI void BNFreeSimilarityProvider(BNSimilarityProvider* provider); + BINARYNINJACOREAPI void BNFreeSimilarityResultIdList(BNSimilarityResultId* results); + + BINARYNINJACOREAPI BNSimilaritySessionResolverType* BNRegisterSimilaritySessionResolverType( + const char* name, const char* description, BNCustomSimilaritySessionResolverType* type); + BINARYNINJACOREAPI BNSimilaritySessionResolverType* BNGetSimilaritySessionResolverTypeByName(const char* name); + BINARYNINJACOREAPI BNSimilaritySessionResolverType** BNGetSimilaritySessionResolverTypeList(size_t* count); + BINARYNINJACOREAPI void BNFreeSimilaritySessionResolverTypeList(BNSimilaritySessionResolverType** types); + BINARYNINJACOREAPI char* BNSimilaritySessionResolverTypeGetName(BNSimilaritySessionResolverType* type); + BINARYNINJACOREAPI char* BNSimilaritySessionResolverTypeGetDescription(BNSimilaritySessionResolverType* type); + BINARYNINJACOREAPI BNSimilaritySessionResolver* BNSimilaritySessionResolverTypeCreateResolver( + BNSimilaritySessionResolverType* type, BNSimilaritySession* session, BNSettings* settings); + BINARYNINJACOREAPI BNSettings* BNSimilaritySessionResolverTypeGetDefaultSettings( + BNSimilaritySessionResolverType* type); + + BINARYNINJACOREAPI BNSimilaritySessionResolver* BNCreateCustomSimilaritySessionResolver( + BNSimilaritySessionResolverType* type, BNSimilaritySession* session, + BNCustomSimilaritySessionResolver* callbacks); + BINARYNINJACOREAPI BNSimilaritySessionResolverType* BNSimilaritySessionResolverGetType( + BNSimilaritySessionResolver* resolver); + BINARYNINJACOREAPI BNSimilaritySessionResolverId BNSimilaritySessionResolverGetId( + BNSimilaritySessionResolver* resolver); + BINARYNINJACOREAPI void BNSimilaritySessionResolverPrepareForNode( + BNSimilaritySessionResolver* resolver, BNSimilaritySession* session, BNSimilaritySessionNode* node, + BNSimilaritySessionCompletion* completion); + BINARYNINJACOREAPI void BNSimilaritySessionResolverResolveForNode(BNSimilaritySessionResolver* resolver, + BNSimilaritySession* session, BNSimilaritySessionNode* node, const BNSimilarityEntityId* entities, + size_t entityCount, BNSimilaritySessionCompletion* completion); + BINARYNINJACOREAPI BNSimilaritySessionResolver* BNNewSimilaritySessionResolverReference(BNSimilaritySessionResolver* resolver); + BINARYNINJACOREAPI void BNFreeSimilaritySessionResolver(BNSimilaritySessionResolver* resolver); + BINARYNINJACOREAPI void BNFreeSimilaritySessionResolverList(BNSimilaritySessionResolver** resolvers, size_t count); + + BINARYNINJACOREAPI BNSimilaritySessionNode* BNCreateSimilaritySessionNode(BNBinaryView* view); + BINARYNINJACOREAPI BNSimilaritySessionNode* BNCreateSimilaritySessionNodeFromFile(BNFileMetadata* file); + BINARYNINJACOREAPI BNBinaryView* BNSimilaritySessionNodeGetView(BNSimilaritySessionNode* node); + BINARYNINJACOREAPI void BNSimilaritySessionNodeSetView(BNSimilaritySessionNode* node, BNBinaryView* view); + BINARYNINJACOREAPI BNFileMetadata* BNSimilaritySessionNodeGetFile(BNSimilaritySessionNode* node); + BINARYNINJACOREAPI BNSettings* BNSimilaritySessionNodeGetLoadOptions(BNSimilaritySessionNode* node); + BINARYNINJACOREAPI BNSimilaritySessionNodeId BNSimilaritySessionNodeGetId(BNSimilaritySessionNode* node); + BINARYNINJACOREAPI BNSimilarityEntityId BNSimilaritySessionNodeCreateEntity( + BNSimilaritySessionNode* node, const BNSimilarityEntityInfo* info); + BINARYNINJACOREAPI bool BNSimilaritySessionNodeRemoveEntity( + BNSimilaritySessionNode* node, BNSimilarityEntityId id); + BINARYNINJACOREAPI bool BNSimilaritySessionNodeGetEntity( + BNSimilaritySessionNode* node, BNSimilarityEntityId id, BNSimilarityEntityInfo* result); + BINARYNINJACOREAPI void BNFreeSimilarityEntityInfo(BNSimilarityEntityInfo* info); + BINARYNINJACOREAPI BNSimilarityEntityId* BNSimilaritySessionNodeGetEntities( + BNSimilaritySessionNode* node, size_t* count); + BINARYNINJACOREAPI bool BNSimilaritySessionNodeAddScheduledEntity( + BNSimilaritySessionNode* node, BNSimilarityEntityId id); + BINARYNINJACOREAPI bool BNSimilaritySessionNodeRemoveScheduledEntity( + BNSimilaritySessionNode* node, BNSimilarityEntityId id); + BINARYNINJACOREAPI BNSimilarityEntityId* BNSimilaritySessionNodeGetScheduledEntities( + BNSimilaritySessionNode* node, size_t* count); + BINARYNINJACOREAPI BNFunction* BNSimilaritySessionNodeGetEntityFunction( + BNSimilaritySessionNode* node, BNSimilarityEntityId id); + BINARYNINJACOREAPI BNSimilarityResultId* BNSimilaritySessionNodeGetResults( + BNSimilaritySessionNode* node, BNSimilarityEntityId entity, size_t* count); + BINARYNINJACOREAPI bool BNSimilaritySessionNodeGetResult( + BNSimilaritySessionNode* node, BNSimilarityResultId resultId, BNSimilarityResult* result); + BINARYNINJACOREAPI bool BNSimilaritySessionNodeSetResolvedResult( + BNSimilaritySessionNode* node, BNSimilarityEntityId entity, BNSimilarityResultId result); + BINARYNINJACOREAPI bool BNSimilaritySessionNodeGetResolvedResult( + BNSimilaritySessionNode* node, BNSimilarityEntityId entity, BNSimilarityResultId* result); + BINARYNINJACOREAPI bool BNSimilaritySessionNodeClearResolvedResult( + BNSimilaritySessionNode* node, BNSimilarityEntityId entity); + BINARYNINJACOREAPI void BNFreeSimilarityEntityList(BNSimilarityEntityId* entities); + BINARYNINJACOREAPI BNSimilaritySessionNodeId* BNSimilaritySessionNodeGetIncomingEdges(BNSimilaritySessionNode* node, size_t* count); + BINARYNINJACOREAPI BNSimilaritySessionNodeId* BNSimilaritySessionNodeGetOutgoingEdges(BNSimilaritySessionNode* node, size_t* count); + BINARYNINJACOREAPI void BNFreeSimilaritySessionNodeEdgeList(BNSimilaritySessionNodeId* edges); + BINARYNINJACOREAPI BNSimilaritySessionNode** BNSimilaritySessionNodeGetIncomingNodes( + BNSimilaritySessionNode* node, size_t* count); + BINARYNINJACOREAPI BNSimilaritySessionNode** BNSimilaritySessionNodeGetOutgoingNodes( + BNSimilaritySessionNode* node, size_t* count); + BINARYNINJACOREAPI BNSimilaritySessionNode* BNNewSimilaritySessionNodeReference(BNSimilaritySessionNode* node); + BINARYNINJACOREAPI void BNFreeSimilaritySessionNode(BNSimilaritySessionNode* node); + + BINARYNINJACOREAPI void BNSimilaritySessionGraphAddNode( + BNSimilaritySessionGraph* graph, BNSimilaritySessionNode* node); + BINARYNINJACOREAPI void BNSimilaritySessionGraphRemoveNode( + BNSimilaritySessionGraph* graph, BNSimilaritySessionNode* node); + BINARYNINJACOREAPI bool BNSimilaritySessionGraphIsValidEdge( + BNSimilaritySessionGraph* graph, BNSimilaritySessionNode* from, BNSimilaritySessionNode* to); + BINARYNINJACOREAPI bool BNSimilaritySessionGraphAddEdge( + BNSimilaritySessionGraph* graph, BNSimilaritySessionNode* from, BNSimilaritySessionNode* to); + BINARYNINJACOREAPI bool BNSimilaritySessionGraphRemoveEdge( + BNSimilaritySessionGraph* graph, BNSimilaritySessionNode* from, BNSimilaritySessionNode* to); + BINARYNINJACOREAPI BNSimilaritySessionNode* BNSimilaritySessionGraphGetNode( + BNSimilaritySessionGraph* graph, BNSimilaritySessionNodeId id); + BINARYNINJACOREAPI BNSimilaritySessionNode** BNSimilaritySessionGraphGetNodes( + BNSimilaritySessionGraph* graph, size_t* count); + BINARYNINJACOREAPI void BNFreeSimilaritySessionNodeList(BNSimilaritySessionNode** nodes, size_t count); + BINARYNINJACOREAPI BNSimilaritySessionNode*** BNSimilaritySessionGraphGetSchedule( + BNSimilaritySessionGraph* graph, size_t** nodeCounts, size_t* levelCount); + BINARYNINJACOREAPI void BNFreeSimilaritySessionNodeSchedule( + BNSimilaritySessionNode*** schedule, size_t* nodeCounts, size_t levelCount); + BINARYNINJACOREAPI BNSimilaritySessionGraph* BNNewSimilaritySessionGraphReference(BNSimilaritySessionGraph* node); + BINARYNINJACOREAPI void BNFreeSimilaritySessionGraph(BNSimilaritySessionGraph* graph); + BINARYNINJACOREAPI BNSimilaritySessionGraphReceiver* BNCreateCustomSimilaritySessionGraphReceiver( + BNCustomSimilaritySessionGraphReceiver* callbacks); + BINARYNINJACOREAPI BNSimilaritySessionGraphReceiver* BNNewSimilaritySessionGraphReceiverReference( + BNSimilaritySessionGraphReceiver* receiver); + BINARYNINJACOREAPI void BNFreeSimilaritySessionGraphReceiver(BNSimilaritySessionGraphReceiver* receiver); + BINARYNINJACOREAPI void BNFreeSimilaritySessionGraphReceiverList( + BNSimilaritySessionGraphReceiver** receivers, size_t count); + BINARYNINJACOREAPI void BNSimilaritySessionGraphReceiverNotifyGraphChanged( + BNSimilaritySessionGraphReceiver* receiver); + BINARYNINJACOREAPI void BNSimilaritySessionGraphAddReceiver( + BNSimilaritySessionGraph* graph, BNSimilaritySessionGraphReceiver* receiver); + BINARYNINJACOREAPI void BNSimilaritySessionGraphRemoveReceiver( + BNSimilaritySessionGraph* graph, BNSimilaritySessionGraphReceiver* receiver); + BINARYNINJACOREAPI BNSimilaritySessionGraphReceiver** BNSimilaritySessionGraphGetReceivers( + BNSimilaritySessionGraph* graph, size_t* count); + + BINARYNINJACOREAPI BNSimilaritySession* BNCreateSimilaritySession(); + BINARYNINJACOREAPI BNSimilaritySessionId BNSimilaritySessionGetId(BNSimilaritySession* session); + BINARYNINJACOREAPI BNSimilaritySessionReceiver* BNCreateCustomSimilaritySessionReceiver( + BNCustomSimilaritySessionReceiver* callbacks); + BINARYNINJACOREAPI BNSimilaritySessionReceiver* BNNewSimilaritySessionReceiverReference( + BNSimilaritySessionReceiver* receiver); + BINARYNINJACOREAPI void BNFreeSimilaritySessionReceiver(BNSimilaritySessionReceiver* receiver); + BINARYNINJACOREAPI void BNFreeSimilaritySessionReceiverList(BNSimilaritySessionReceiver** receivers, size_t count); + BINARYNINJACOREAPI void BNSimilaritySessionReceiverNotifyStart( + BNSimilaritySessionReceiver* receiver, BNSimilaritySessionCompletion* completion); + BINARYNINJACOREAPI void BNSimilaritySessionReceiverNotifyBatch(BNSimilaritySessionReceiver* receiver, + BNSimilaritySessionNode* node, BNSimilarityProvider* provider, + const BNSimilarityEntityId* entities, size_t count); + BINARYNINJACOREAPI void BNSimilaritySessionAddProvider( + BNSimilaritySession* session, BNSimilarityProvider* provider); + BINARYNINJACOREAPI void BNSimilaritySessionRemoveProvider( + BNSimilaritySession* session, BNSimilarityProvider* provider); + BINARYNINJACOREAPI bool BNSimilaritySessionUpdateProviderSettings( + BNSimilaritySession* session, BNSimilarityProvider* provider, BNSettings* settings); + BINARYNINJACOREAPI BNSimilarityProvider* BNSimilaritySessionGetProvider( + BNSimilaritySession* session, BNSimilarityProviderId id); + BINARYNINJACOREAPI BNSimilarityProvider** BNSimilaritySessionGetProviders( + BNSimilaritySession* session, size_t* count); + BINARYNINJACOREAPI void BNFreeSimilarityProviderList(BNSimilarityProvider** providers, size_t count); + BINARYNINJACOREAPI bool BNSimilaritySessionAddResolver( + BNSimilaritySession* session, BNSimilaritySessionResolver* resolver); + BINARYNINJACOREAPI bool BNSimilaritySessionRemoveResolver( + BNSimilaritySession* session, BNSimilaritySessionResolver* resolver); + BINARYNINJACOREAPI bool BNSimilaritySessionUpdateResolverSettings( + BNSimilaritySession* session, BNSimilaritySessionResolver* resolver, BNSettings* settings); + BINARYNINJACOREAPI BNSimilaritySessionResolver* BNSimilaritySessionGetResolver( + BNSimilaritySession* session, BNSimilaritySessionResolverId id); + BINARYNINJACOREAPI BNSimilaritySessionResolver** BNSimilaritySessionGetResolvers( + BNSimilaritySession* session, size_t* count); + BINARYNINJACOREAPI void BNSimilaritySessionAddReceiver( + BNSimilaritySession* session, BNSimilaritySessionReceiver* receiver); + BINARYNINJACOREAPI void BNSimilaritySessionRemoveReceiver( + BNSimilaritySession* session, BNSimilaritySessionReceiver* receiver); + BINARYNINJACOREAPI BNSimilaritySessionReceiver** BNSimilaritySessionGetReceivers( + BNSimilaritySession* session, size_t* count); + BINARYNINJACOREAPI BNSimilaritySessionGraph* BNSimilaritySessionGetGraph(BNSimilaritySession* session); + BINARYNINJACOREAPI BNSimilaritySessionCompletion* BNSimilaritySessionRun(BNSimilaritySession* session); + BINARYNINJACOREAPI BNSimilaritySession* BNNewSimilaritySessionReference(BNSimilaritySession* session); + BINARYNINJACOREAPI void BNFreeSimilaritySession(BNSimilaritySession* session); + + BINARYNINJACOREAPI BNSimilaritySessionCompletion* BNCreateSimilaritySessionCompletion(); + BINARYNINJACOREAPI bool BNSimilaritySessionCompletionIsFinished(BNSimilaritySessionCompletion* completion); + BINARYNINJACOREAPI void BNSimilaritySessionCompletionRequestStop(BNSimilaritySessionCompletion* completion); + BINARYNINJACOREAPI bool BNSimilaritySessionCompletionIsStopRequested(BNSimilaritySessionCompletion* completion); + BINARYNINJACOREAPI double BNSimilaritySessionCompletionGetProgress( + BNSimilaritySessionCompletion* completion, const BNSimilaritySessionCompletionQuery* query); + BINARYNINJACOREAPI void BNSimilaritySessionCompletionSetProgress( + BNSimilaritySessionCompletion* completion, const BNSimilaritySessionCompletionQuery* query, double progress); + BINARYNINJACOREAPI uint64_t BNSimilaritySessionCompletionGetTiming( + BNSimilaritySessionCompletion* completion, const BNSimilaritySessionCompletionQuery* query); + BINARYNINJACOREAPI BNSimilaritySessionCompletion* BNNewSimilaritySessionCompletionReference(BNSimilaritySessionCompletion* completion); + BINARYNINJACOREAPI void BNFreeSimilaritySessionCompletion(BNSimilaritySessionCompletion* completion); + BINARYNINJACOREAPI char* BNAllocString(const char* contents); BINARYNINJACOREAPI char* BNAllocStringWithLength(const char* contents, size_t len); BINARYNINJACOREAPI void BNFreeString(char* str); From 208960204d69df953da4840c7ddb1d951d92e071 Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 3 Aug 2026 05:04:20 -0700 Subject: [PATCH 3/4] [API] Expose flow graph construction --- binaryninjaapi.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 06a201922..3bfff5241 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -14049,8 +14049,6 @@ namespace BinaryNinja { protected: bool m_queryMode = false; - FlowGraph(BNFlowGraph* graph); - void FinishPrepareForLayout(); virtual void PrepareForLayout(); virtual void PopulateNodes(); @@ -14058,6 +14056,7 @@ namespace BinaryNinja { public: FlowGraph(); + FlowGraph(BNFlowGraph* graph); /*! Get the Function associated with this FlowGraph From c0b051e80238a79dbc1f419fa57fee3b0464034f Mon Sep 17 00:00:00 2001 From: Mason Reed Date: Mon, 3 Aug 2026 05:04:20 -0700 Subject: [PATCH 4/4] Add Binary Similarity APIs --- binaryninjaapi.h | 741 +++++++++++++++++++++++++ similarity.cpp | 1368 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2109 insertions(+) create mode 100644 similarity.cpp diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 3bfff5241..455a6e4c6 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -28,6 +28,7 @@ #endif #include "base/compiler.h" +#include "base/strong_typedef.h" #include "binaryninjacore.h" #include "exceptions.h" @@ -36,6 +37,7 @@ #include "vendor/nlohmann/json.hpp" #include +#include #include #include #include @@ -50,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +74,8 @@ #endif namespace BinaryNinja { + namespace st = ::bn::base::strong_typedef; + #ifdef __GNUC__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ static inline uint16_t ToLE16(uint16_t val) { return val; } @@ -623,6 +628,7 @@ namespace BinaryNinja { class InteractionHandler; class QualifiedName; class FlowGraph; + class LinearViewObject; class ReportCollection; struct FormInputField; struct ArchAndAddr; @@ -16663,6 +16669,730 @@ namespace BinaryNinja { std::optional GetDerivedStringReferenceForExpr(size_t expr); }; + class SimilarityProviderType; + + /*! Identifies an entity within a similarity-session node. */ + using SimilarityEntityId = + bn::base::StrongTypedef, st::Ordered, st::Hashable, + st::Incrementable>; + /*! Identifies a provider result within a similarity-session node. */ + using SimilarityResultId = + bn::base::StrongTypedef, st::Ordered, st::Hashable, + st::Incrementable>; + /*! Identifies a node across similarity sessions. */ + using SimilaritySessionNodeId = + bn::base::StrongTypedef, st::Ordered, + st::Hashable>; + /*! Identifies a similarity session. */ + using SimilaritySessionId = + bn::base::StrongTypedef, st::Ordered, st::Hashable>; + /*! Identifies a provider instance. */ + using SimilarityProviderId = + bn::base::StrongTypedef, st::Ordered, st::Hashable>; + /*! Identifies a resolver instance. */ + using SimilaritySessionResolverId = + bn::base::StrongTypedef, st::Ordered, + st::Hashable>; + + /*! Chooses which session completion data to read or update. + + A query cannot select both a provider and a resolver. Omitting all IDs selects the whole session. */ + struct SimilaritySessionCompletionQuery + { + std::optional nodeId; + std::optional providerId; + std::optional resolverId; + + static SimilaritySessionCompletionQuery ForSession() { return {}; } + static SimilaritySessionCompletionQuery ForNode(SimilaritySessionNodeId node) { return {.nodeId = node}; } + static SimilaritySessionCompletionQuery ForProvider(SimilarityProviderId provider) + { + return {.providerId = provider}; + } + static SimilaritySessionCompletionQuery ForResolver(SimilaritySessionResolverId resolver) + { + return {.resolverId = resolver}; + } + SimilaritySessionCompletionQuery WithProvider(SimilarityProviderId provider) const + { + return {.nodeId = nodeId, .providerId = provider}; + } + SimilaritySessionCompletionQuery WithResolver(SimilaritySessionResolverId resolver) const + { + return {.nodeId = nodeId, .resolverId = resolver}; + } + + [[nodiscard]] BNSimilaritySessionCompletionQuery ToRaw() const + { + return {nodeId.has_value(), nodeId.value_or(SimilaritySessionNodeId(0)), providerId.has_value(), + providerId.value_or(SimilarityProviderId(0)), resolverId.has_value(), + resolverId.value_or(SimilaritySessionResolverId(0))}; + } + }; + + /*! Identifies an entity within a session node. */ + struct SimilarityEntityRef + { + SimilaritySessionNodeId nodeId; + SimilarityEntityId entityId; + + SimilarityEntityRef(SimilaritySessionNodeId nodeId, SimilarityEntityId entityId) : + nodeId(nodeId), entityId(entityId) + {} + SimilarityEntityRef(const BNSimilarityEntityRef& ref) : nodeId(ref.nodeId), entityId(ref.entityId) {} + bool operator==(const SimilarityEntityRef& other) const = default; + bool operator<(const SimilarityEntityRef& other) const + { + return std::tie(nodeId, entityId) < std::tie(other.nodeId, other.entityId); + } + + [[nodiscard]] BNSimilarityEntityRef ToRaw() const + { + return {nodeId, entityId}; + } + }; + + /*! A match produced by a provider. + + Similarity and confidence range from 0 to 255, where 255 is strongest. Automatic metadata transfer requires + `target` to identify an active function. */ + struct SimilarityResult + { + /*! The provider which produced the match. */ + SimilarityProviderId providerId; + /*! The similarity of the two entities. */ + uint8_t similarity; + /*! The provider's confidence in the match. */ + uint8_t confidence; + /*! The matched entity, which may be used as the source for metadata transfer. */ + SimilarityEntityRef target; + + SimilarityResult(SimilarityProviderId provider, uint8_t similarity, uint8_t confidence, + const SimilarityEntityRef& target) : + providerId(provider), similarity(similarity), confidence(confidence), target(target) + {} + SimilarityResult(const BNSimilarityResult& result) : + providerId(result.providerId), similarity(result.similarity), confidence(result.confidence), + target(result.target) + {} + bool operator==(const SimilarityResult& other) const = default; + + [[nodiscard]] BNSimilarityResult ToRaw() const + { + return {providerId, similarity, confidence, target.ToRaw()}; + } + }; + + /*! Describes an entity, including its display name. */ + struct SimilarityEntityInfo + { + BNSimilarityEntityType type; + uint64_t address; + std::string name; + + SimilarityEntityInfo(BNSimilarityEntityType type, uint64_t address, std::string name = {}) : + type(type), address(address), name(std::move(name)) + {} + SimilarityEntityInfo(const BNSimilarityEntityInfo& info) : + type(info.type), address(info.address), name(info.name ? info.name : "") + {} + bool operator==(const SimilarityEntityInfo& other) const = default; + + [[nodiscard]] BNSimilarityEntityInfo ToRaw() const { return {type, address, name.c_str()}; } + }; + + /*! Applies a diff annotation to the half-open address range `[start, end)`. */ + struct SimilarityRangeAnnotation + { + uint64_t start; + uint64_t end; + BNSimilarityAnnotationType type; + + SimilarityRangeAnnotation(uint64_t start, uint64_t end, BNSimilarityAnnotationType type) : + start(start), end(end), type(type) + {} + SimilarityRangeAnnotation(const BNSimilarityRangeAnnotation& annotation) : + start(annotation.start), end(annotation.end), type(annotation.type) + {} + [[nodiscard]] BNSimilarityRangeAnnotation ToRaw() const { return {start, end, type}; } + }; + + /*! A flow-graph or linear view produced while rendering a similarity result. */ + class SimilarityView : + public CoreRefCountObject + { + public: + SimilarityView(BNSimilarityView* view); + + std::string GetGroup() const; + BNSimilarityViewType GetType() const; + /*! Returns the flow graph, or `nullptr` for a linear view. */ + Ref GetFlowGraph() const; + /*! Returns the data view, or `nullptr` for a flow graph. */ + Ref GetLinearViewData() const; + /*! Returns the linear view, or `nullptr` for a flow graph. */ + Ref GetLinearView() const; + /*! Returns the session entity for this view, if its renderer provided one. */ + std::optional GetEntity() const; + }; + + /*! Holds the grouped views used to display a similarity result. */ + class SimilarityRenderContext : + public CoreRefCountObject + { + public: + SimilarityRenderContext(); + SimilarityRenderContext(BNSimilarityRenderContext* context); + + /*! Sets the function representation preferred by renderers writing to this context. */ + void SetPreferredViewType(const FunctionViewType& type); + /*! Returns the function representation preferred by renderers writing to this context. */ + FunctionViewType GetPreferredViewType() const; + /*! Adds a flow graph to a view group. */ + void AddFlowGraph(const std::string& group, FlowGraph& graph); + /*! Adds a flow graph for a session entity to a view group. */ + void AddFlowGraph(const std::string& group, FlowGraph& graph, const SimilarityEntityRef& entity); + /*! Adds a linear view to a view group. */ + void AddLinearView(const std::string& group, BinaryView& data, LinearViewObject& linearView); + /*! Adds a linear view for a session entity to a view group. */ + void AddLinearView(const std::string& group, BinaryView& data, LinearViewObject& linearView, + const SimilarityEntityRef& entity); + /*! Returns views in insertion order. */ + std::vector> GetViews() const; + }; + + /*! Highlights annotated address ranges in flow-graph and linear views. */ + class DiffRenderer : public CoreRefCountObject + { + public: + DiffRenderer(); + DiffRenderer(BNDiffRenderer* renderer); + + /*! Adds a half-open address range to annotate. + + \note Empty ranges are ignored. */ + void AddRangeAnnotation(const SimilarityRangeAnnotation& annotation); + void AddRangeAnnotation(uint64_t start, uint64_t end, BNSimilarityAnnotationType type); + + /*! Renders graph and linear views for a function. */ + void Render(SimilarityRenderContext& context, Function& function); + /*! Renders graph and linear views for a function and session entity. */ + void Render(SimilarityRenderContext& context, Function& function, const SimilarityEntityRef& entity); + /*! Renders an annotated flow graph. */ + void Render(SimilarityRenderContext& context, const std::string& group, FlowGraph& graph); + /*! Renders an annotated flow graph for a session entity. */ + void Render(SimilarityRenderContext& context, const std::string& group, FlowGraph& graph, + const SimilarityEntityRef& entity); + /*! Renders an annotated linear view. */ + void Render( + SimilarityRenderContext& context, const std::string& group, BinaryView& data, LinearViewObject& linearView); + /*! Renders an annotated linear view for a session entity. */ + void Render(SimilarityRenderContext& context, const std::string& group, BinaryView& data, + LinearViewObject& linearView, const SimilarityEntityRef& entity); + }; + + class SimilaritySessionNode; + class SimilaritySessionCompletion; + + /*! Holds the provider results produced by a node or edge visit. + * + * Only use an instance during the provider callback that received it. A successful visit replaces earlier results + * for the same provider and node or edge. Results for unscheduled entities remain unchanged. */ + class SimilarityProviderResults + { + BNSimilarityProviderResults* m_object; + + public: + explicit SimilarityProviderResults(BNSimilarityProviderResults* results) : m_object(results) {} + + BNSimilarityProviderResults* GetObject() const { return m_object; } + + /*! Adds a result to the current visit. + * + * The result must belong to an entity scheduled for this visit. Node results belong to `source`; edge results + * belong to the entity on the destination node. Returns zero if the result could not be added. A later visit + * replaces the result and gives it a new ID. */ + SimilarityResultId AddResult(const SimilarityEntityRef& source, const SimilarityEntityRef& target, + uint8_t similarity, uint8_t confidence); + }; + + /*! Produces, applies, and renders similarity results for session entities. + * C++ implementations must be thread safe because callbacks may overlap across nodes and sessions. Provider visits + * must write changes through the given SimilarityProviderResults. Visits made by a session keep the visited node and + * both edge endpoints active. Direct calls must provide active views. */ + class SimilarityProvider : + public CoreRefCountObject + { + static bool UpdateSettingsCallback(void* ctxt, BNSettings* settings); + static bool VisitNodeCallback(void* ctxt, BNSimilaritySessionNode* node, BNSimilarityProviderResults* results, + BNSimilaritySessionCompletion* completion); + static bool VisitNodeEdgeCallback(void* ctxt, BNSimilaritySessionNode* from, BNSimilaritySessionNode* to, + BNSimilarityProviderResults* results, BNSimilaritySessionCompletion* completion); + static char* GetNameCallback( + void* ctxt, BNSimilaritySessionNode* node, BNSimilarityEntityId entity, BNSimilarityResultId result); + static BNSimilarityApplyStatus ApplyCallback( + void* ctxt, BNSimilaritySessionNode* node, BNSimilarityEntityId entity, BNSimilarityResultId result); + static void RenderCallback(void* ctxt, BNSimilaritySessionNode* node, BNSimilarityEntityId entity, + BNSimilarityRenderContext* context, BNSimilarityResultId result); + static void FreeContextCallback(void* ctxt); + + public: + SimilarityProvider(SimilarityProviderType* type); + SimilarityProvider(BNSimilarityProvider* provider); + + Ref GetType() const; + SimilarityProviderId GetId() const; + + /*! Replaces this provider's settings only if they are valid. + + Return false without changing the current settings when the new settings are invalid or updates are not + supported. Use SimilaritySession::UpdateProviderSettings so affected entities are scheduled again. */ + virtual bool UpdateSettings(Settings&) { return false; } + + /*! Performs a complete node visit. The core manages the result updates. */ + void VisitNode(SimilaritySessionNode& node, SimilaritySessionCompletion& completion); + /*! Performs a complete edge visit. The core manages the result updates. */ + void VisitNodeEdge( + SimilaritySessionNode& from, SimilaritySessionNode& to, SimilaritySessionCompletion& completion); + + /*! Visits a node and writes results for it. Return `false` to discard the visit. */ + virtual bool VisitNode(SimilaritySessionNode&, SimilarityProviderResults&, SimilaritySessionCompletion&) + { + return true; + } + + /*! Visits an edge after both endpoint nodes have been visited and writes results for the edge. + * Return `false` to discard the visit. */ + virtual bool VisitNodeEdge( + SimilaritySessionNode&, SimilaritySessionNode&, SimilarityProviderResults&, SimilaritySessionCompletion&) + { + return true; + } + + /*! Returns the display name for a result, if available. */ + virtual std::optional GetName(SimilaritySessionNode& node, + SimilarityEntityId entity, SimilarityResultId result) = 0; + + /*! Applies a result. The default implementation transfers metadata from the result target; overrides can call it + before adding provider-specific metadata. */ + virtual BNSimilarityApplyStatus Apply(SimilaritySessionNode& node, SimilarityEntityId entity, + SimilarityResultId result); + + /*! Adds views for a result to `context`. */ + virtual void Render(SimilaritySessionNode& node, SimilarityEntityId entity, + SimilarityRenderContext& context, SimilarityResultId result) = 0; + }; + + class CoreSimilarityProvider : public SimilarityProvider + { + public: + CoreSimilarityProvider(BNSimilarityProvider* provider); + + using SimilarityProvider::VisitNode; + using SimilarityProvider::VisitNodeEdge; + + bool VisitNode(SimilaritySessionNode& node, SimilarityProviderResults& results, + SimilaritySessionCompletion& completion) override; + bool VisitNodeEdge(SimilaritySessionNode& from, SimilaritySessionNode& to, SimilarityProviderResults& results, + SimilaritySessionCompletion& completion) override; + + std::optional GetName(SimilaritySessionNode& node, + SimilarityEntityId entity, SimilarityResultId result) override; + + BNSimilarityApplyStatus Apply( + SimilaritySessionNode& node, SimilarityEntityId entity, SimilarityResultId result) override; + + void Render(SimilaritySessionNode& node, SimilarityEntityId entity, + SimilarityRenderContext& context, SimilarityResultId result) override; + }; + + /*! Creates similarity providers with the given settings. */ + class SimilarityProviderType : public StaticCoreRefCountObject + { + std::string m_nameForRegister; + std::string m_descForRegister; + + static BNSimilarityProvider* CreateCallback(void* ctxt, BNSettings* settings); + static BNSettings* GetDefaultSettingsCallback(void* ctxt); + + public: + SimilarityProviderType(std::string name, std::string description); + SimilarityProviderType(BNSimilarityProviderType* formatter); + + /*! Registers a provider type for the lifetime of the process. */ + static void Register(SimilarityProviderType* type); + + static std::vector> GetList(); + static Ref GetByName(const std::string& name); + + std::string GetName() const; + std::string GetDescription() const; + + /*! Creates a provider with the given settings, or returns null. */ + virtual Ref Create(Settings& settings) = 0; + + /*! Returns the settings schema and defaults for this provider type, or null. */ + virtual Ref GetDefaultSettings() = 0; + }; + + class CoreSimilarityProviderType : public SimilarityProviderType + { + public: + CoreSimilarityProviderType(BNSimilarityProviderType* type); + + /*! Returns null outside the Ultimate edition. */ + Ref Create(Settings& settings) override; + + Ref GetDefaultSettings() override; + }; + + class SimilaritySession; + class SimilaritySessionReceiver; + class SimilaritySessionGraphReceiver; + class SimilaritySessionResolverType; + + /*! Selects a preferred result for each scheduled entity. + * C++ implementations must be thread safe because callbacks may overlap across nodes in the same processing group. */ + class SimilaritySessionResolver : + public CoreRefCountObject + { + static bool UpdateSettingsCallback(void* ctxt, BNSettings* settings); + static void PrepareForNodeCallback(void* ctxt, BNSimilaritySession* session, BNSimilaritySessionNode* node, + BNSimilaritySessionCompletion* completion, BNSimilaritySessionResolverId resolverId); + static void ResolveForNodeCallback(void* ctxt, BNSimilaritySession* session, BNSimilaritySessionNode* node, + const BNSimilarityEntityId* entities, size_t entityCount, BNSimilaritySessionCompletion* completion, + BNSimilaritySessionResolverId resolverId); + static void FreeContextCallback(void* ctxt); + + public: + /*! Creates a resolver for `session`. */ + SimilaritySessionResolver(SimilaritySessionResolverType* type, Ref session); + SimilaritySessionResolver(BNSimilaritySessionResolver* resolver); + + SimilaritySessionResolverId GetId() const; + Ref GetType() const; + + /*! Replaces this resolver's settings only if they are valid. + + Return false without changing the current settings when the new settings are invalid or updates are not + supported. Use SimilaritySession::UpdateResolverSettings so affected entities are resolved again. */ + virtual bool UpdateSettings(Settings&) { return false; } + + /*! Prepares a node before providers run. + + This is useful for large graphs where views may be unavailable, but the resolver needs to change the scheduled + entities or add entities itself. */ + virtual void PrepareForNode(SimilaritySession& session, SimilaritySessionNode& node, + SimilaritySessionCompletion& completion) {} + /*! Resolves provider results after all providers have visited the node. + + Call SetResolvedResult to select a result. Call AddScheduledEntity to request another provider and resolver + round for an entity. Only schedule work for `node`; the session owns scheduling between nodes. */ + virtual void ResolveForNode(SimilaritySession& session, SimilaritySessionNode& node, + const std::vector& entities, SimilaritySessionCompletion& completion) = 0; + }; + + class CoreSimilaritySessionResolver : public SimilaritySessionResolver + { + public: + CoreSimilaritySessionResolver(BNSimilaritySessionResolver* resolver); + + void PrepareForNode(SimilaritySession& session, SimilaritySessionNode& node, + SimilaritySessionCompletion& completion) override; + void ResolveForNode(SimilaritySession& session, SimilaritySessionNode& node, + const std::vector& entities, SimilaritySessionCompletion& completion) override; + }; + + /*! Creates resolvers with the given settings. */ + class SimilaritySessionResolverType : public StaticCoreRefCountObject + { + std::string m_nameForRegister; + std::string m_descForRegister; + + static BNSimilaritySessionResolver* CreateCallback( + void* ctxt, BNSimilaritySession* session, BNSettings* settings); + static BNSettings* GetDefaultSettingsCallback(void* ctxt); + + public: + SimilaritySessionResolverType(std::string name, std::string description); + SimilaritySessionResolverType(BNSimilaritySessionResolverType* type); + + /*! Registers a resolver type for the lifetime of the process. */ + static void Register(SimilaritySessionResolverType* type); + static Ref GetByName(const std::string& name); + static std::vector> GetList(); + + std::string GetName() const; + std::string GetDescription() const; + + /*! Creates a resolver for `session`, or returns null. The resolver must not keep `session` after this call. */ + virtual Ref Create(Ref session, Settings& settings) = 0; + /*! Returns the settings schema and defaults for this resolver type, or null. */ + virtual Ref GetDefaultSettings() = 0; + }; + + class CoreSimilaritySessionResolverType : public SimilaritySessionResolverType + { + public: + CoreSimilaritySessionResolverType(BNSimilaritySessionResolverType* type); + + Ref Create(Ref session, Settings& settings) override; + Ref GetDefaultSettings() override; + }; + + /*! The main unit of similarity processing. */ + class SimilaritySessionNode : + public CoreRefCountObject + { + public: + SimilaritySessionNode(BNSimilaritySessionNode* node); + /*! Creates a node for a non-null active view, keeps the view alive, and schedules its analyzed functions. */ + SimilaritySessionNode(Ref view); + /*! Creates a node whose view will be loaded from `file` when the session runs. + + `file` must be non-null. The session closes the view when the run no longer needs it, so the view may be + unavailable at other times. */ + SimilaritySessionNode(Ref file); + + /*! Returns the active view, or `nullptr` if the node is not loaded. + + A file-backed node may be unavailable outside a session run. */ + Ref GetView() const; + /*! Sets the active view. A view backed by a different FileMetadata is ignored. + + \note Do not mix files. */ + void SetView(Ref view); + /*! Returns the file used by the node. This is always valid. */ + Ref GetFile() const; + /*! Returns mutable settings used when the session loads this node's view. Modify them before running the session. */ + Ref GetLoadOptions() const; + SimilaritySessionNodeId GetId() const; + + /*! Adds an entity without scheduling it. Existing entities are reused, and a non-empty + name refreshes their display name. */ + SimilarityEntityId CreateEntity(const SimilarityEntityInfo& info); + /*! Removes an entity, its schedule, its provider results, and its selected result. + + To only unschedule it, call RemoveScheduledEntity. */ + bool RemoveEntity(SimilarityEntityId id); + /*! Returns information about an entity, or no value if `id` is not found. */ + std::optional GetEntity(SimilarityEntityId id); + /*! Returns every entity in the node, including entities used only as match targets. */ + std::vector GetEntities(); + /*! Schedules an entity for the next provider round. + + Nodes initially schedule all available entities. The session consumes each scheduled batch after providers + visit it. During a run, only the resolver currently processing this node may request another round. Schedule + entities from other contexts between runs. */ + bool AddScheduledEntity(SimilarityEntityId id); + /*! Unschedules an entity without removing it from the node. + + To remove it, call RemoveEntity. */ + bool RemoveScheduledEntity(SimilarityEntityId id); + /*! Returns the entities waiting for provider processing. */ + std::vector GetScheduledEntities(); + /*! Resolves a function entity against the active view, or returns `nullptr`. */ + Ref GetEntityFunction(SimilarityEntityId id); + /*! Returns the result IDs for an entity. */ + std::vector GetResults(SimilarityEntityId entity); + /*! Returns a stored result by its ID, which is unique within the node. */ + std::optional GetResult(SimilarityResultId result); + /*! Selects one of the entity's results. */ + bool SetResolvedResult(SimilarityEntityId entity, SimilarityResultId result); + std::optional GetResolvedResult(SimilarityEntityId entity); + bool ClearResolvedResult(SimilarityEntityId entity); + + /*! Returns incoming node IDs in ascending order. */ + std::vector GetIncomingEdges(); + /*! Returns outgoing node IDs in ascending order. */ + std::vector GetOutgoingEdges(); + /*! Returns incoming nodes ordered by ID. */ + std::vector> GetIncomingNodes(); + /*! Returns outgoing nodes ordered by ID. */ + std::vector> GetOutgoingNodes(); + }; + + /*! A graph that controls which binaries are compared and in what order. The graph cannot contain cycles. + + An edge from A to B makes A available as an incoming comparison node while B is processed. */ + class SimilaritySessionGraph : + public CoreRefCountObject + { + public: + SimilaritySessionGraph(BNSimilaritySessionGraph* graph); + + /*! Adds a node, moving it from its previous graph if necessary. If either graph is running, the node is unchanged. */ + void AddNode(Ref node); + /*! Removes a node and its incident edges. Graph mutations are ignored during a run. */ + void RemoveNode(SimilaritySessionNode& node); + /*! Returns a node, or `nullptr` if `id` is absent. */ + Ref GetNode(SimilaritySessionNodeId id); + std::vector> GetNodes(); + + /*! Returns whether an edge joins two graph members without duplicating an edge or creating a cycle. + * Returns false during a run. */ + bool IsValidEdge(SimilaritySessionNode& from, SimilaritySessionNode& to); + /*! Adds an edge. Returns false if invalid or while the graph is running. */ + bool AddEdge(SimilaritySessionNode& from, SimilaritySessionNode& to); + /*! Removes an edge. Returns false if absent or while the graph is running. */ + bool RemoveEdge(SimilaritySessionNode& from, SimilaritySessionNode& to); + void AddReceiver(Ref receiver); + void RemoveReceiver(SimilaritySessionGraphReceiver& receiver); + std::vector> GetReceivers(); + + /*! Returns groups of nodes in processing order. Nodes in the same group may run concurrently. */ + std::vector>> GetSchedule(); + }; + + /*! Receives notifications after nodes or edges are added to or removed from a session graph. */ + class SimilaritySessionGraphReceiver : + public CoreRefCountObject + { + static void OnGraphChangedCallback(void* ctxt); + static void FreeContextCallback(void* ctxt); + + public: + SimilaritySessionGraphReceiver(); + SimilaritySessionGraphReceiver(BNSimilaritySessionGraphReceiver* receiver); + + virtual void NotifyGraphChanged() {} + }; + + class CoreSimilaritySessionGraphReceiver : public SimilaritySessionGraphReceiver + { + public: + CoreSimilaritySessionGraphReceiver(BNSimilaritySessionGraphReceiver* receiver); + + void NotifyGraphChanged() override; + }; + + /*! Receives session-start and entity-batch notifications. + * C++ implementations must be thread safe. NotifyStart is called before Run returns. NotifyBatch runs on workers + * and may overlap across nodes and sessions. Receivers are observers and must not + * schedule work or mutate the active session. */ + class SimilaritySessionReceiver : + public CoreRefCountObject + { + static void OnStartedCallback(void* ctxt, BNSimilaritySessionCompletion* completion); + static void OnUpdatedCallback(void* ctxt, BNSimilaritySessionNode* node, BNSimilarityProvider* provider, + const BNSimilarityEntityId* entities, size_t count); + static void FreeContextCallback(void* ctxt); + + public: + SimilaritySessionReceiver(); + SimilaritySessionReceiver(BNSimilaritySessionReceiver* receiver); + + /*! Called when the session starts a run. + + This is mainly used to get the completion state for the run. */ + virtual void NotifyStart(SimilaritySessionCompletion& completion) {} + /*! Called when a provider's results, resolution state, or applied metadata changes for a batch of entities. */ + virtual void NotifyBatch(SimilaritySessionNode& node, SimilarityProvider& provider, + const std::vector& entities) + {} + }; + + class CoreSimilaritySessionReceiver : public SimilaritySessionReceiver + { + public: + CoreSimilaritySessionReceiver(BNSimilaritySessionReceiver* receiver); + + void NotifyStart(SimilaritySessionCompletion& completion) override; + void NotifyBatch(SimilaritySessionNode& node, SimilarityProvider& provider, + const std::vector& entities) override; + }; + + /*! Tracks stop requests, progress, and timing for a session run. */ + class SimilaritySessionCompletion : + public CoreRefCountObject + { + public: + SimilaritySessionCompletion(BNSimilaritySessionCompletion* completion); + /*! Creates an independent completion state, normally only for calling providers or resolvers directly. */ + SimilaritySessionCompletion(); + + bool IsFinished() const; + /*! Asks the run to stop. Long-running callbacks should check IsStopRequested regularly. */ + void RequestStop(); + bool IsStopRequested() const; + /*! Returns progress from 0.0 to 1.0. Exactly 1.0 means the selected part of the run has finished. */ + double GetProgress(const SimilaritySessionCompletionQuery& query) const; + /*! Increases progress for a node and one provider or resolver. Progress cannot decrease. + + \note Call this only from the provider or resolver selected by `query`. */ + void SetProgress(const SimilaritySessionCompletionQuery& query, double progress); + /*! Returns elapsed time for the selected part of the run. */ + std::chrono::milliseconds GetTiming(const SimilaritySessionCompletionQuery& query) const; + }; + + /*! Runs providers and resolvers over binaries arranged in a session graph. */ + class SimilaritySession : + public CoreRefCountObject + { + public: + SimilaritySession(BNSimilaritySession* session); + SimilaritySession(); + + SimilaritySessionId GetId() const; + + /*! Adds a provider and schedules entities processed by earlier runs for the next run. + + \note Ignored while a run is active. */ + void AddProvider(Ref provider); + /*! Removes a provider, clears its results, and marks affected entities for resolution. + + \note Ignored while a run is active. */ + void RemoveProvider(SimilarityProvider& provider); + /*! Updates a provider already in the session and schedules previously processed entities again. + + Returns false during a run, when the provider is absent, or when it rejects the settings. */ + bool UpdateProviderSettings(SimilarityProvider& provider, Settings& settings); + /*! Returns a provider, or `nullptr` if `id` is absent. */ + Ref GetProvider(SimilarityProviderId id); + std::vector> GetProviders(); + + /*! Adds a resolver created for this session and marks entities processed by earlier runs for resolution. + + \note Returns false during a run, for a duplicate, or for a resolver from another session. */ + bool AddResolver(Ref resolver); + /*! Removes a resolver. + + \note Returns false during a run, or if it is absent or belongs to another session. */ + bool RemoveResolver(SimilaritySessionResolver& resolver); + /*! Updates a resolver already in the session and marks previously processed entities for resolution. + + Returns false during a run, when the resolver is absent or belongs to another session, or when it rejects the + settings. */ + bool UpdateResolverSettings(SimilaritySessionResolver& resolver, Settings& settings); + /*! Returns a resolver, or `nullptr` if `id` is absent. */ + Ref GetResolver(SimilaritySessionResolverId id); + std::vector> GetResolvers(); + /*! Adds a receiver. A running session keeps using the receiver list it started with. */ + void AddReceiver(Ref receiver); + /*! Removes a receiver. A running session keeps using the receiver list it started with. */ + void RemoveReceiver(SimilaritySessionReceiver& receiver); + std::vector> GetReceivers(); + + Ref GetGraph(); + /*! Starts a background run with the current graph, providers, and resolvers. Changes are ignored until it finishes. + + \note Returns the active run's completion handle when already running. */ + Ref Run(); + }; + struct LineFormatterSettings { Ref highLevelIL; @@ -24460,6 +25190,17 @@ namespace std return std::hash()(value.operator std::string_view()); } }; + + template <> + struct hash + { + size_t operator()(BinaryNinja::SimilarityEntityRef const& value) const + { + const size_t nodeHash = std::hash()(value.nodeId); + const size_t entityHash = std::hash()(value.entityId); + return nodeHash ^ (entityHash + 0x9e3779b9 + (nodeHash << 6) + (nodeHash >> 2)); + } + }; } // namespace std diff --git a/similarity.cpp b/similarity.cpp new file mode 100644 index 000000000..501490968 --- /dev/null +++ b/similarity.cpp @@ -0,0 +1,1368 @@ +#include + +#include "binaryninjaapi.h" + +using namespace BinaryNinja; +using namespace std; + +namespace { + template + Result RunSimilarityCallback(const char* message, Result failure, Callback&& callback) noexcept + { + try + { + return callback(); + } + catch (const std::exception& exception) + { + LogErrorForException(exception, "%s", message); + } + catch (...) + { + LogError("%s", message); + } + return failure; + } + + template + void RunSimilarityCallback(const char* message, Callback&& callback) noexcept + { + try + { + callback(); + } + catch (const std::exception& exception) + { + LogErrorForException(exception, "%s", message); + } + catch (...) + { + LogError("%s", message); + } + } +} // namespace + +SimilarityView::SimilarityView(BNSimilarityView* view) +{ + m_object = view; +} + +string SimilarityView::GetGroup() const +{ + char* group = BNSimilarityViewGetGroup(m_object); + string result = group ? group : ""; + BNFreeString(group); + return result; +} + +BNSimilarityViewType SimilarityView::GetType() const +{ + return BNSimilarityViewGetType(m_object); +} + +Ref SimilarityView::GetFlowGraph() const +{ + BNFlowGraph* graph = BNSimilarityViewGetFlowGraph(m_object); + return graph ? Ref(new FlowGraph(graph)) : nullptr; +} + +Ref SimilarityView::GetLinearViewData() const +{ + BNBinaryView* data = BNSimilarityViewGetLinearViewData(m_object); + return data ? Ref(new BinaryView(data)) : nullptr; +} + +Ref SimilarityView::GetLinearView() const +{ + BNLinearViewObject* linearView = BNSimilarityViewGetLinearView(m_object); + return linearView ? Ref(new LinearViewObject(linearView)) : nullptr; +} + +optional SimilarityView::GetEntity() const +{ + BNSimilarityEntityRef entity; + if (!BNSimilarityViewGetEntity(m_object, &entity)) + return nullopt; + return SimilarityEntityRef(entity); +} + +SimilarityRenderContext::SimilarityRenderContext() +{ + m_object = BNCreateSimilarityRenderContext(); +} + +SimilarityRenderContext::SimilarityRenderContext(BNSimilarityRenderContext* context) +{ + m_object = context; +} + +void SimilarityRenderContext::SetPreferredViewType(const FunctionViewType& type) +{ + BNSimilarityRenderContextSetPreferredViewType(m_object, type.ToAPIObject()); +} + +FunctionViewType SimilarityRenderContext::GetPreferredViewType() const +{ + const BNFunctionGraphType type = BNSimilarityRenderContextGetPreferredViewType(m_object); + if (type != HighLevelLanguageRepresentationFunctionGraph) + return FunctionViewType(type); + char* name = BNSimilarityRenderContextGetPreferredViewTypeName(m_object); + FunctionViewType result {string(name)}; + BNFreeString(name); + return result; +} + +void SimilarityRenderContext::AddFlowGraph(const string& group, FlowGraph& graph) +{ + BNSimilarityRenderContextAddFlowGraph(m_object, group.c_str(), graph.GetObject()); +} + +void SimilarityRenderContext::AddFlowGraph(const string& group, FlowGraph& graph, const SimilarityEntityRef& entity) +{ + const BNSimilarityEntityRef rawEntity = entity.ToRaw(); + BNSimilarityRenderContextAddFlowGraphForEntity(m_object, group.c_str(), graph.GetObject(), &rawEntity); +} + +void SimilarityRenderContext::AddLinearView(const string& group, BinaryView& data, LinearViewObject& linearView) +{ + BNSimilarityRenderContextAddLinearView(m_object, group.c_str(), data.GetObject(), linearView.GetObject()); +} + +void SimilarityRenderContext::AddLinearView( + const string& group, BinaryView& data, LinearViewObject& linearView, const SimilarityEntityRef& entity) +{ + const BNSimilarityEntityRef rawEntity = entity.ToRaw(); + BNSimilarityRenderContextAddLinearViewForEntity( + m_object, group.c_str(), data.GetObject(), linearView.GetObject(), &rawEntity); +} + +vector> SimilarityRenderContext::GetViews() const +{ + size_t count = 0; + BNSimilarityView** views = BNGetSimilarityRenderContextViews(m_object, &count); + vector> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.push_back(new SimilarityView(BNNewSimilarityViewReference(views[i]))); + BNFreeSimilarityViewList(views, count); + return result; +} + +DiffRenderer::DiffRenderer() +{ + m_object = BNCreateDiffRenderer(); +} + +DiffRenderer::DiffRenderer(BNDiffRenderer* renderer) +{ + m_object = renderer; +} + +void DiffRenderer::AddRangeAnnotation(const SimilarityRangeAnnotation& annotation) +{ + AddRangeAnnotation(annotation.start, annotation.end, annotation.type); +} + +void DiffRenderer::AddRangeAnnotation(uint64_t start, uint64_t end, BNSimilarityAnnotationType type) +{ + BNDiffRendererAddRangeAnnotation(m_object, start, end, type); +} + +void DiffRenderer::Render(SimilarityRenderContext& context, Function& function) +{ + BNDiffRendererRenderFunction(m_object, context.GetObject(), function.GetObject()); +} + +void DiffRenderer::Render(SimilarityRenderContext& context, Function& function, const SimilarityEntityRef& entity) +{ + const BNSimilarityEntityRef rawEntity = entity.ToRaw(); + BNDiffRendererRenderFunctionForEntity(m_object, context.GetObject(), function.GetObject(), &rawEntity); +} + +void DiffRenderer::Render(SimilarityRenderContext& context, const string& group, FlowGraph& graph) +{ + BNDiffRendererRenderFlowGraph(m_object, context.GetObject(), group.c_str(), graph.GetObject()); +} + +void DiffRenderer::Render( + SimilarityRenderContext& context, const string& group, FlowGraph& graph, const SimilarityEntityRef& entity) +{ + const BNSimilarityEntityRef rawEntity = entity.ToRaw(); + BNDiffRendererRenderFlowGraphForEntity(m_object, context.GetObject(), group.c_str(), graph.GetObject(), &rawEntity); +} + +void DiffRenderer::Render( + SimilarityRenderContext& context, const string& group, BinaryView& data, LinearViewObject& linearView) +{ + BNDiffRendererRenderLinearView( + m_object, context.GetObject(), group.c_str(), data.GetObject(), linearView.GetObject()); +} + +void DiffRenderer::Render(SimilarityRenderContext& context, const string& group, BinaryView& data, + LinearViewObject& linearView, const SimilarityEntityRef& entity) +{ + const BNSimilarityEntityRef rawEntity = entity.ToRaw(); + BNDiffRendererRenderLinearViewForEntity( + m_object, context.GetObject(), group.c_str(), data.GetObject(), linearView.GetObject(), &rawEntity); +} + +SimilarityResultId SimilarityProviderResults::AddResult( + const SimilarityEntityRef& source, const SimilarityEntityRef& target, uint8_t similarity, uint8_t confidence) +{ + const BNSimilarityEntityRef rawSource = source.ToRaw(); + const BNSimilarityEntityRef rawTarget = target.ToRaw(); + return BNSimilarityProviderResultsAddResult(m_object, &rawSource, &rawTarget, similarity, confidence); +} + + +SimilarityProviderType::SimilarityProviderType(string name, string description) : + m_nameForRegister(std::move(name)), m_descForRegister(std::move(description)) +{} + + +SimilarityProviderType::SimilarityProviderType(BNSimilarityProviderType* type) +{ + m_object = type; +} + + +void SimilarityProviderType::Register(SimilarityProviderType* type) +{ + BNCustomSimilarityProviderType cb {}; + cb.context = type; + cb.create = CreateCallback; + cb.getDefaultSettings = GetDefaultSettingsCallback; + + type->AddRefForRegistration(); + type->m_object = + BNRegisterSimilarityProviderType(type->m_nameForRegister.c_str(), type->m_descForRegister.c_str(), &cb); +} + + +vector> SimilarityProviderType::GetList() +{ + size_t count; + BNSimilarityProviderType** list = BNGetSimilarityProviderTypeList(&count); + vector> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.push_back(new CoreSimilarityProviderType(list[i])); + BNFreeSimilarityProviderTypeList(list); + return result; +} + + +Ref SimilarityProviderType::GetByName(const string& name) +{ + BNSimilarityProviderType* result = BNGetSimilarityProviderTypeByName(name.c_str()); + if (!result) + return nullptr; + return new CoreSimilarityProviderType(result); +} + + +std::string SimilarityProviderType::GetName() const +{ + char* name = BNSimilarityProviderTypeGetName(m_object); + std::string result = name; + BNFreeString(name); + return result; +} + + +std::string SimilarityProviderType::GetDescription() const +{ + char* description = BNSimilarityProviderTypeGetDescription(m_object); + std::string result = description; + BNFreeString(description); + return result; +} + + +CoreSimilarityProviderType::CoreSimilarityProviderType(BNSimilarityProviderType* type) : SimilarityProviderType(type) {} + + +Ref CoreSimilarityProviderType::Create(Settings& settings) +{ + BNSimilarityProvider* provider = BNSimilarityProviderTypeCreateProvider(m_object, settings.m_object); + if (!provider) + return nullptr; + return new CoreSimilarityProvider(provider); +} + +Ref CoreSimilarityProviderType::GetDefaultSettings() +{ + BNSettings* settings = BNSimilarityProviderTypeGetDefaultSettings(m_object); + if (!settings) + return nullptr; + return new Settings(settings); +} + + +SimilarityProvider::SimilarityProvider(BNSimilarityProvider* provider) +{ + m_object = provider; +} + + +Ref SimilarityProvider::GetType() const +{ + return new CoreSimilarityProviderType(BNSimilarityProviderGetType(m_object)); +} + +SimilarityProviderId SimilarityProvider::GetId() const +{ + return BNSimilarityProviderGetId(m_object); +} + + +SimilarityProvider::SimilarityProvider(SimilarityProviderType* type) +{ + BNCustomSimilarityProvider cb {}; + cb.context = this; + cb.updateSettings = UpdateSettingsCallback; + cb.visitNode = VisitNodeCallback; + cb.visitNodeEdge = VisitNodeEdgeCallback; + cb.getName = GetNameCallback; + cb.apply = ApplyCallback; + cb.render = RenderCallback; + cb.free = FreeContextCallback; + + AddRefForRegistration(); + m_object = BNCreateCustomSimilarityProvider(type->m_object, &cb); +} + + +CoreSimilarityProvider::CoreSimilarityProvider(BNSimilarityProvider* provider) : SimilarityProvider(provider) {} + +bool SimilarityProvider::UpdateSettingsCallback(void* ctxt, BNSettings* settings) +{ + return RunSimilarityCallback("Unhandled exception updating similarity provider settings", false, [&]() { + CallbackRef provider(ctxt); + Ref settingsObj = new Settings(BNNewSettingsReference(settings)); + return provider->UpdateSettings(*settingsObj); + }); +} + +BNSimilarityApplyStatus SimilarityProvider::Apply( + SimilaritySessionNode& node, SimilarityEntityId entity, SimilarityResultId resultId) +{ + const auto result = node.GetResult(resultId); + if (!result) + return SimilarityApplyFailed; + const auto rawTarget = result->target.ToRaw(); + return BNSimilaritySessionNodeApplyTarget(node.GetObject(), entity, &rawTarget); +} + + +void SimilarityProvider::VisitNode(SimilaritySessionNode& node, SimilaritySessionCompletion& completion) +{ + BNSimilarityProviderVisitNode(m_object, node.GetObject(), completion.GetObject()); +} + +void SimilarityProvider::VisitNodeEdge( + SimilaritySessionNode& from, SimilaritySessionNode& to, SimilaritySessionCompletion& completion) +{ + BNSimilarityProviderVisitNodeEdge(m_object, from.GetObject(), to.GetObject(), completion.GetObject()); +} + +bool CoreSimilarityProvider::VisitNode( + SimilaritySessionNode& node, SimilarityProviderResults& results, SimilaritySessionCompletion& completion) +{ + return BNSimilarityProviderPerformVisitNode( + m_object, node.GetObject(), results.GetObject(), completion.GetObject()); +} + +bool CoreSimilarityProvider::VisitNodeEdge(SimilaritySessionNode& from, SimilaritySessionNode& to, + SimilarityProviderResults& results, SimilaritySessionCompletion& completion) +{ + return BNSimilarityProviderPerformVisitNodeEdge( + m_object, from.GetObject(), to.GetObject(), results.GetObject(), completion.GetObject()); +} + + +std::optional CoreSimilarityProvider::GetName( + SimilaritySessionNode& node, SimilarityEntityId entity, SimilarityResultId resultId) +{ + char* name = BNSimilarityProviderGetName(m_object, node.GetObject(), entity, resultId); + if (!name) + return std::nullopt; + std::string result = name; + BNFreeString(name); + return result; +} + + +BNSimilarityApplyStatus CoreSimilarityProvider::Apply(SimilaritySessionNode& node, SimilarityEntityId entity, + SimilarityResultId result) +{ + return BNSimilarityProviderApply(m_object, node.GetObject(), entity, result); +} + + +void CoreSimilarityProvider::Render(SimilaritySessionNode& node, SimilarityEntityId entity, + SimilarityRenderContext& context, SimilarityResultId result) +{ + BNSimilarityProviderRender(m_object, node.GetObject(), entity, context.GetObject(), result); +} + + +SimilaritySessionResolverType::SimilaritySessionResolverType(std::string name, std::string description) : + m_nameForRegister(std::move(name)), m_descForRegister(std::move(description)) +{} + + +SimilaritySessionResolverType::SimilaritySessionResolverType(BNSimilaritySessionResolverType* type) +{ + m_object = type; +} + + +void SimilaritySessionResolverType::Register(SimilaritySessionResolverType* type) +{ + BNCustomSimilaritySessionResolverType cb {}; + cb.context = type; + cb.create = CreateCallback; + cb.getDefaultSettings = GetDefaultSettingsCallback; + + type->AddRefForRegistration(); + type->m_object = + BNRegisterSimilaritySessionResolverType(type->m_nameForRegister.c_str(), type->m_descForRegister.c_str(), &cb); +} + + +std::vector> SimilaritySessionResolverType::GetList() +{ + size_t count; + BNSimilaritySessionResolverType** list = BNGetSimilaritySessionResolverTypeList(&count); + std::vector> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.push_back(new CoreSimilaritySessionResolverType(list[i])); + BNFreeSimilaritySessionResolverTypeList(list); + return result; +} + + +Ref SimilaritySessionResolverType::GetByName(const std::string& name) +{ + BNSimilaritySessionResolverType* result = BNGetSimilaritySessionResolverTypeByName(name.c_str()); + if (!result) + return nullptr; + return new CoreSimilaritySessionResolverType(result); +} + + +std::string SimilaritySessionResolverType::GetName() const +{ + char* name = BNSimilaritySessionResolverTypeGetName(m_object); + std::string result = name; + BNFreeString(name); + return result; +} + + +std::string SimilaritySessionResolverType::GetDescription() const +{ + char* description = BNSimilaritySessionResolverTypeGetDescription(m_object); + std::string result = description; + BNFreeString(description); + return result; +} + + +BNSimilaritySessionResolver* SimilaritySessionResolverType::CreateCallback( + void* ctxt, BNSimilaritySession* session, BNSettings* settings) +{ + return RunSimilarityCallback< + BNSimilaritySessionResolver*>("Unhandled exception creating similarity session resolver", nullptr, [&]() { + SimilaritySessionResolverType* type = (SimilaritySessionResolverType*)ctxt; + Ref sessionObj = new SimilaritySession(BNNewSimilaritySessionReference(session)); + Ref settingsObj = new Settings(BNNewSettingsReference(settings)); + Ref result = type->Create(sessionObj, *settingsObj); + if (!result) + return static_cast(nullptr); + return BNNewSimilaritySessionResolverReference(result->GetObject()); + }); +} + + +BNSettings* SimilaritySessionResolverType::GetDefaultSettingsCallback(void* ctxt) +{ + return RunSimilarityCallback< + BNSettings*>("Unhandled exception getting similarity session resolver settings", nullptr, [&]() { + SimilaritySessionResolverType* type = (SimilaritySessionResolverType*)ctxt; + Ref result = type->GetDefaultSettings(); + if (!result) + return static_cast(nullptr); + return BNNewSettingsReference(result->GetObject()); + }); +} + + +CoreSimilaritySessionResolverType::CoreSimilaritySessionResolverType(BNSimilaritySessionResolverType* type) : + SimilaritySessionResolverType(type) +{} + + +Ref CoreSimilaritySessionResolverType::Create( + Ref session, Settings& settings) +{ + BNSimilaritySessionResolver* resolver = + BNSimilaritySessionResolverTypeCreateResolver(m_object, session->GetObject(), settings.GetObject()); + if (!resolver) + return nullptr; + return new CoreSimilaritySessionResolver(resolver); +} + + +Ref CoreSimilaritySessionResolverType::GetDefaultSettings() +{ + BNSettings* settings = BNSimilaritySessionResolverTypeGetDefaultSettings(m_object); + if (!settings) + return nullptr; + return new Settings(settings); +} + + +SimilaritySessionResolver::SimilaritySessionResolver(BNSimilaritySessionResolver* resolver) +{ + m_object = resolver; +} + + +SimilaritySessionResolver::SimilaritySessionResolver( + SimilaritySessionResolverType* type, Ref session) +{ + BNCustomSimilaritySessionResolver cb {}; + cb.context = this; + cb.updateSettings = UpdateSettingsCallback; + cb.prepareForNode = PrepareForNodeCallback; + cb.resolveForNode = ResolveForNodeCallback; + cb.free = FreeContextCallback; + + AddRefForRegistration(); + m_object = BNCreateCustomSimilaritySessionResolver(type->GetObject(), session->GetObject(), &cb); +} + +bool SimilaritySessionResolver::UpdateSettingsCallback(void* ctxt, BNSettings* settings) +{ + return RunSimilarityCallback("Unhandled exception updating similarity resolver settings", false, [&]() { + CallbackRef resolver(ctxt); + Ref settingsObj = new Settings(BNNewSettingsReference(settings)); + return resolver->UpdateSettings(*settingsObj); + }); +} + + +SimilaritySessionResolverId SimilaritySessionResolver::GetId() const +{ + return BNSimilaritySessionResolverGetId(m_object); +} + + +Ref SimilaritySessionResolver::GetType() const +{ + return new CoreSimilaritySessionResolverType(BNSimilaritySessionResolverGetType(m_object)); +} + + +CoreSimilaritySessionResolver::CoreSimilaritySessionResolver(BNSimilaritySessionResolver* resolver) : + SimilaritySessionResolver(resolver) +{} + + +void CoreSimilaritySessionResolver::PrepareForNode( + SimilaritySession& session, SimilaritySessionNode& node, SimilaritySessionCompletion& completion) +{ + BNSimilaritySessionResolverPrepareForNode(m_object, session.GetObject(), node.GetObject(), completion.GetObject()); +} + + +void CoreSimilaritySessionResolver::ResolveForNode(SimilaritySession& session, SimilaritySessionNode& node, + const std::vector& entities, SimilaritySessionCompletion& completion) +{ + std::vector coreEntities; + coreEntities.reserve(entities.size()); + for (const auto entity : entities) + coreEntities.push_back(entity); + BNSimilaritySessionResolverResolveForNode(m_object, session.GetObject(), node.GetObject(), coreEntities.data(), + coreEntities.size(), completion.GetObject()); +} + + +SimilaritySessionNode::SimilaritySessionNode(BNSimilaritySessionNode* node) +{ + m_object = node; +} + + +SimilaritySessionNode::SimilaritySessionNode(Ref view) +{ + m_object = BNCreateSimilaritySessionNode(view->GetObject()); +} + + +SimilaritySessionNode::SimilaritySessionNode(Ref file) +{ + m_object = BNCreateSimilaritySessionNodeFromFile(file->GetObject()); +} + + +Ref SimilaritySessionNode::GetView() const +{ + BNBinaryView* view = BNSimilaritySessionNodeGetView(m_object); + if (!view) + return nullptr; + return new BinaryView(view); +} + + +void SimilaritySessionNode::SetView(Ref view) +{ + BNSimilaritySessionNodeSetView(m_object, view ? view->GetObject() : nullptr); +} + + +Ref SimilaritySessionNode::GetFile() const +{ + return new FileMetadata(BNSimilaritySessionNodeGetFile(m_object)); +} + +Ref SimilaritySessionNode::GetLoadOptions() const +{ + return new Settings(BNSimilaritySessionNodeGetLoadOptions(m_object)); +} + + +SimilaritySessionNodeId SimilaritySessionNode::GetId() const +{ + return BNSimilaritySessionNodeGetId(m_object); +} + + +SimilarityEntityId SimilaritySessionNode::CreateEntity(const SimilarityEntityInfo& info) +{ + auto rawInfo = info.ToRaw(); + return BNSimilaritySessionNodeCreateEntity(m_object, &rawInfo); +} + + +bool SimilaritySessionNode::RemoveEntity(SimilarityEntityId id) +{ + return BNSimilaritySessionNodeRemoveEntity(m_object, id); +} + + +std::optional SimilaritySessionNode::GetEntity(const SimilarityEntityId id) +{ + BNSimilarityEntityInfo result; + if (!BNSimilaritySessionNodeGetEntity(m_object, id, &result)) + return std::nullopt; + SimilarityEntityInfo info(result); + BNFreeSimilarityEntityInfo(&result); + return info; +} + + +std::vector SimilaritySessionNode::GetEntities() +{ + size_t count = 0; + BNSimilarityEntityId* entities = BNSimilaritySessionNodeGetEntities(m_object, &count); + std::vector result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.push_back(entities[i]); + BNFreeSimilarityEntityList(entities); + return result; +} + +bool SimilaritySessionNode::AddScheduledEntity(SimilarityEntityId id) +{ + return BNSimilaritySessionNodeAddScheduledEntity(m_object, id); +} + +bool SimilaritySessionNode::RemoveScheduledEntity(SimilarityEntityId id) +{ + return BNSimilaritySessionNodeRemoveScheduledEntity(m_object, id); +} + +std::vector SimilaritySessionNode::GetScheduledEntities() +{ + size_t count = 0; + BNSimilarityEntityId* entities = BNSimilaritySessionNodeGetScheduledEntities(m_object, &count); + std::vector result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.push_back(entities[i]); + BNFreeSimilarityEntityList(entities); + return result; +} + + +Ref SimilaritySessionNode::GetEntityFunction(const SimilarityEntityId id) +{ + BNFunction* function = BNSimilaritySessionNodeGetEntityFunction(m_object, id); + if (!function) + return nullptr; + return new Function(function); +} + +std::vector SimilaritySessionNode::GetResults(SimilarityEntityId entity) +{ + size_t count = 0; + BNSimilarityResultId* results = BNSimilaritySessionNodeGetResults(m_object, entity, &count); + std::vector out; + out.reserve(count); + for (size_t i = 0; i < count; i++) + out.push_back(results[i]); + BNFreeSimilarityResultIdList(results); + return out; +} + +std::optional SimilaritySessionNode::GetResult(SimilarityResultId resultId) +{ + BNSimilarityResult result; + if (!BNSimilaritySessionNodeGetResult(m_object, resultId, &result)) + return std::nullopt; + return SimilarityResult(result); +} + +bool SimilaritySessionNode::SetResolvedResult(SimilarityEntityId entity, SimilarityResultId result) +{ + return BNSimilaritySessionNodeSetResolvedResult(m_object, entity, result); +} + +std::optional SimilaritySessionNode::GetResolvedResult(SimilarityEntityId entity) +{ + BNSimilarityResultId result; + if (!BNSimilaritySessionNodeGetResolvedResult(m_object, entity, &result)) + return std::nullopt; + return result; +} + +bool SimilaritySessionNode::ClearResolvedResult(SimilarityEntityId entity) +{ + return BNSimilaritySessionNodeClearResolvedResult(m_object, entity); +} + + +std::vector SimilaritySessionNode::GetIncomingEdges() +{ + size_t count; + BNSimilaritySessionNodeId* edges = BNSimilaritySessionNodeGetIncomingEdges(m_object, &count); + std::vector result; + result.reserve(count); + for (size_t i = 0; i < count; ++i) + result.push_back(edges[i]); + BNFreeSimilaritySessionNodeEdgeList(edges); + return result; +} + + +std::vector SimilaritySessionNode::GetOutgoingEdges() +{ + size_t count; + BNSimilaritySessionNodeId* edges = BNSimilaritySessionNodeGetOutgoingEdges(m_object, &count); + std::vector result; + result.reserve(count); + for (size_t i = 0; i < count; ++i) + result.push_back(edges[i]); + BNFreeSimilaritySessionNodeEdgeList(edges); + return result; +} + + +std::vector> SimilaritySessionNode::GetIncomingNodes() +{ + size_t count = 0; + BNSimilaritySessionNode** nodes = BNSimilaritySessionNodeGetIncomingNodes(m_object, &count); + std::vector> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.emplace_back(new SimilaritySessionNode(BNNewSimilaritySessionNodeReference(nodes[i]))); + BNFreeSimilaritySessionNodeList(nodes, count); + return result; +} + + +std::vector> SimilaritySessionNode::GetOutgoingNodes() +{ + size_t count = 0; + BNSimilaritySessionNode** nodes = BNSimilaritySessionNodeGetOutgoingNodes(m_object, &count); + std::vector> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.emplace_back(new SimilaritySessionNode(BNNewSimilaritySessionNodeReference(nodes[i]))); + BNFreeSimilaritySessionNodeList(nodes, count); + return result; +} + + +SimilaritySessionGraph::SimilaritySessionGraph(BNSimilaritySessionGraph* graph) +{ + m_object = graph; +} + + +void SimilaritySessionGraph::AddNode(Ref node) +{ + BNSimilaritySessionGraphAddNode(m_object, node->GetObject()); +} + + +void SimilaritySessionGraph::RemoveNode(SimilaritySessionNode& node) +{ + BNSimilaritySessionGraphRemoveNode(m_object, node.GetObject()); +} + + +Ref SimilaritySessionGraph::GetNode(const SimilaritySessionNodeId id) +{ + BNSimilaritySessionNode* node = BNSimilaritySessionGraphGetNode(m_object, id); + if (!node) + return nullptr; + return new SimilaritySessionNode(node); +} + + +std::vector> SimilaritySessionGraph::GetNodes() +{ + size_t count; + BNSimilaritySessionNode** nodes = BNSimilaritySessionGraphGetNodes(m_object, &count); + std::vector> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.emplace_back(new SimilaritySessionNode(BNNewSimilaritySessionNodeReference(nodes[i]))); + BNFreeSimilaritySessionNodeList(nodes, count); + return result; +} + + +bool SimilaritySessionGraph::IsValidEdge(SimilaritySessionNode& from, SimilaritySessionNode& to) +{ + return BNSimilaritySessionGraphIsValidEdge(m_object, from.GetObject(), to.GetObject()); +} + + +bool SimilaritySessionGraph::AddEdge(SimilaritySessionNode& from, SimilaritySessionNode& to) +{ + return BNSimilaritySessionGraphAddEdge(m_object, from.GetObject(), to.GetObject()); +} + + +bool SimilaritySessionGraph::RemoveEdge(SimilaritySessionNode& from, SimilaritySessionNode& to) +{ + return BNSimilaritySessionGraphRemoveEdge(m_object, from.GetObject(), to.GetObject()); +} + + +void SimilaritySessionGraph::AddReceiver(Ref receiver) +{ + BNSimilaritySessionGraphAddReceiver(m_object, receiver->GetObject()); +} + + +void SimilaritySessionGraph::RemoveReceiver(SimilaritySessionGraphReceiver& receiver) +{ + BNSimilaritySessionGraphRemoveReceiver(m_object, receiver.GetObject()); +} + + +std::vector> SimilaritySessionGraph::GetReceivers() +{ + size_t count = 0; + BNSimilaritySessionGraphReceiver** receivers = BNSimilaritySessionGraphGetReceivers(m_object, &count); + std::vector> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + { + result.push_back( + new CoreSimilaritySessionGraphReceiver(BNNewSimilaritySessionGraphReceiverReference(receivers[i]))); + } + BNFreeSimilaritySessionGraphReceiverList(receivers, count); + return result; +} + + +std::vector>> SimilaritySessionGraph::GetSchedule() +{ + size_t* nodeCounts; + size_t levelCount; + BNSimilaritySessionNode*** schedule = BNSimilaritySessionGraphGetSchedule(m_object, &nodeCounts, &levelCount); + + std::vector>> result(levelCount); + for (size_t i = 0; i < levelCount; i++) + { + result[i].reserve(nodeCounts[i]); + for (size_t j = 0; j < nodeCounts[i]; j++) + result[i].push_back(new SimilaritySessionNode(BNNewSimilaritySessionNodeReference(schedule[i][j]))); + } + BNFreeSimilaritySessionNodeSchedule(schedule, nodeCounts, levelCount); + return result; +} + + +SimilaritySessionGraphReceiver::SimilaritySessionGraphReceiver(BNSimilaritySessionGraphReceiver* receiver) +{ + m_object = receiver; +} + + +SimilaritySessionGraphReceiver::SimilaritySessionGraphReceiver() +{ + BNCustomSimilaritySessionGraphReceiver cb {}; + cb.context = this; + cb.onGraphChanged = OnGraphChangedCallback; + cb.free = FreeContextCallback; + + AddRefForRegistration(); + m_object = BNCreateCustomSimilaritySessionGraphReceiver(&cb); +} + + +CoreSimilaritySessionGraphReceiver::CoreSimilaritySessionGraphReceiver(BNSimilaritySessionGraphReceiver* receiver) : + SimilaritySessionGraphReceiver(receiver) +{} + + +void CoreSimilaritySessionGraphReceiver::NotifyGraphChanged() +{ + BNSimilaritySessionGraphReceiverNotifyGraphChanged(m_object); +} + + +SimilaritySession::SimilaritySession(BNSimilaritySession* session) +{ + m_object = session; +} + + +SimilaritySession::SimilaritySession() +{ + m_object = BNCreateSimilaritySession(); +} + +SimilaritySessionId SimilaritySession::GetId() const +{ + return BNSimilaritySessionGetId(m_object); +} + + +void SimilaritySession::AddProvider(Ref provider) +{ + BNSimilaritySessionAddProvider(m_object, provider->GetObject()); +} + + +void SimilaritySession::RemoveProvider(SimilarityProvider& provider) +{ + BNSimilaritySessionRemoveProvider(m_object, provider.GetObject()); +} + +bool SimilaritySession::UpdateProviderSettings(SimilarityProvider& provider, Settings& settings) +{ + return BNSimilaritySessionUpdateProviderSettings(m_object, provider.GetObject(), settings.GetObject()); +} + + +Ref SimilaritySession::GetProvider(SimilarityProviderId id) +{ + BNSimilarityProvider* provider = BNSimilaritySessionGetProvider(m_object, id); + if (!provider) + return nullptr; + return new CoreSimilarityProvider(provider); +} + + +std::vector> SimilaritySession::GetProviders() +{ + size_t count; + BNSimilarityProvider** providers = BNSimilaritySessionGetProviders(m_object, &count); + std::vector> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.push_back(new CoreSimilarityProvider(BNNewSimilarityProviderReference(providers[i]))); + BNFreeSimilarityProviderList(providers, count); + return result; +} + + +bool SimilaritySession::AddResolver(Ref resolver) +{ + return BNSimilaritySessionAddResolver(m_object, resolver->GetObject()); +} + + +bool SimilaritySession::RemoveResolver(SimilaritySessionResolver& resolver) +{ + return BNSimilaritySessionRemoveResolver(m_object, resolver.GetObject()); +} + +bool SimilaritySession::UpdateResolverSettings(SimilaritySessionResolver& resolver, Settings& settings) +{ + return BNSimilaritySessionUpdateResolverSettings(m_object, resolver.GetObject(), settings.GetObject()); +} + + +Ref SimilaritySession::GetResolver(SimilaritySessionResolverId id) +{ + BNSimilaritySessionResolver* resolver = BNSimilaritySessionGetResolver(m_object, id); + if (!resolver) + return nullptr; + return new CoreSimilaritySessionResolver(resolver); +} + + +std::vector> SimilaritySession::GetResolvers() +{ + size_t count; + BNSimilaritySessionResolver** resolvers = BNSimilaritySessionGetResolvers(m_object, &count); + std::vector> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.push_back(new CoreSimilaritySessionResolver(BNNewSimilaritySessionResolverReference(resolvers[i]))); + BNFreeSimilaritySessionResolverList(resolvers, count); + return result; +} + + +Ref SimilaritySession::GetGraph() +{ + return new SimilaritySessionGraph(BNSimilaritySessionGetGraph(m_object)); +} + + +void SimilaritySession::AddReceiver(Ref receiver) +{ + BNSimilaritySessionAddReceiver(m_object, receiver->GetObject()); +} + + +void SimilaritySession::RemoveReceiver(SimilaritySessionReceiver& receiver) +{ + BNSimilaritySessionRemoveReceiver(m_object, receiver.GetObject()); +} + + +std::vector> SimilaritySession::GetReceivers() +{ + size_t count; + BNSimilaritySessionReceiver** receivers = BNSimilaritySessionGetReceivers(m_object, &count); + std::vector> result; + result.reserve(count); + for (size_t i = 0; i < count; i++) + result.push_back(new CoreSimilaritySessionReceiver(BNNewSimilaritySessionReceiverReference(receivers[i]))); + BNFreeSimilaritySessionReceiverList(receivers, count); + return result; +} + + +Ref SimilaritySession::Run() +{ + return new SimilaritySessionCompletion(BNSimilaritySessionRun(m_object)); +} + + +SimilaritySessionReceiver::SimilaritySessionReceiver(BNSimilaritySessionReceiver* receiver) +{ + m_object = receiver; +} + + +SimilaritySessionReceiver::SimilaritySessionReceiver() +{ + BNCustomSimilaritySessionReceiver cb {}; + cb.context = this; + cb.onStarted = OnStartedCallback; + cb.onUpdated = OnUpdatedCallback; + cb.free = FreeContextCallback; + + AddRefForRegistration(); + m_object = BNCreateCustomSimilaritySessionReceiver(&cb); +} + + +CoreSimilaritySessionReceiver::CoreSimilaritySessionReceiver(BNSimilaritySessionReceiver* receiver) : + SimilaritySessionReceiver(receiver) +{} + + +void CoreSimilaritySessionReceiver::NotifyStart(SimilaritySessionCompletion& completion) +{ + BNSimilaritySessionReceiverNotifyStart(m_object, completion.GetObject()); +} + + +void CoreSimilaritySessionReceiver::NotifyBatch( + SimilaritySessionNode& node, SimilarityProvider& provider, const std::vector& entities) +{ + std::vector coreEntities; + coreEntities.reserve(entities.size()); + for (const auto& entity : entities) + coreEntities.push_back(entity); + BNSimilaritySessionReceiverNotifyBatch( + m_object, node.GetObject(), provider.GetObject(), coreEntities.data(), coreEntities.size()); +} + + +SimilaritySessionCompletion::SimilaritySessionCompletion(BNSimilaritySessionCompletion* completion) +{ + m_object = completion; +} + + +SimilaritySessionCompletion::SimilaritySessionCompletion() +{ + m_object = BNCreateSimilaritySessionCompletion(); +} + +bool SimilaritySessionCompletion::IsFinished() const +{ + return BNSimilaritySessionCompletionIsFinished(m_object); +} + +void SimilaritySessionCompletion::RequestStop() +{ + BNSimilaritySessionCompletionRequestStop(m_object); +} + +bool SimilaritySessionCompletion::IsStopRequested() const +{ + return BNSimilaritySessionCompletionIsStopRequested(m_object); +} + +double SimilaritySessionCompletion::GetProgress(const SimilaritySessionCompletionQuery& query) const +{ + const BNSimilaritySessionCompletionQuery rawQuery = query.ToRaw(); + return BNSimilaritySessionCompletionGetProgress(m_object, &rawQuery); +} + +void SimilaritySessionCompletion::SetProgress(const SimilaritySessionCompletionQuery& query, double progress) +{ + const BNSimilaritySessionCompletionQuery rawQuery = query.ToRaw(); + BNSimilaritySessionCompletionSetProgress(m_object, &rawQuery, progress); +} + +std::chrono::milliseconds SimilaritySessionCompletion::GetTiming(const SimilaritySessionCompletionQuery& query) const +{ + const BNSimilaritySessionCompletionQuery rawQuery = query.ToRaw(); + return std::chrono::milliseconds(BNSimilaritySessionCompletionGetTiming(m_object, &rawQuery)); +} + + +BNSimilarityProvider* SimilarityProviderType::CreateCallback(void* ctxt, BNSettings* settings) +{ + return RunSimilarityCallback< + BNSimilarityProvider*>("Unhandled exception creating similarity provider", nullptr, [&]() { + SimilarityProviderType* type = (SimilarityProviderType*)ctxt; + Ref settingsObj = new Settings(BNNewSettingsReference(settings)); + Ref result = type->Create(*settingsObj); + if (!result) + return static_cast(nullptr); + return BNNewSimilarityProviderReference(result->GetObject()); + }); +} + + +BNSettings* SimilarityProviderType::GetDefaultSettingsCallback(void* ctxt) +{ + return RunSimilarityCallback< + BNSettings*>("Unhandled exception getting similarity provider settings", nullptr, [&]() { + SimilarityProviderType* type = (SimilarityProviderType*)ctxt; + Ref result = type->GetDefaultSettings(); + if (!result) + return static_cast(nullptr); + return BNNewSettingsReference(result->m_object); + }); +} + + +bool SimilarityProvider::VisitNodeCallback(void* ctxt, BNSimilaritySessionNode* node, + BNSimilarityProviderResults* results, BNSimilaritySessionCompletion* completion) +{ + try + { + CallbackRef provider(ctxt); + Ref nodeObj = new SimilaritySessionNode(BNNewSimilaritySessionNodeReference(node)); + SimilarityProviderResults resultsObj(results); + Ref completionObj = + new SimilaritySessionCompletion(BNNewSimilaritySessionCompletionReference(completion)); + return provider->VisitNode(*nodeObj, resultsObj, *completionObj); + } + catch (const std::exception& exception) + { + LogErrorForException(exception, "Unhandled exception in similarity provider node visit"); + return false; + } + catch (...) + { + LogError("Unhandled exception in similarity provider node visit"); + return false; + } +} + + +bool SimilarityProvider::VisitNodeEdgeCallback(void* ctxt, BNSimilaritySessionNode* from, BNSimilaritySessionNode* to, + BNSimilarityProviderResults* results, BNSimilaritySessionCompletion* completion) +{ + try + { + CallbackRef provider(ctxt); + Ref fromObj = new SimilaritySessionNode(BNNewSimilaritySessionNodeReference(from)); + Ref toObj = new SimilaritySessionNode(BNNewSimilaritySessionNodeReference(to)); + SimilarityProviderResults resultsObj(results); + Ref completionObj = + new SimilaritySessionCompletion(BNNewSimilaritySessionCompletionReference(completion)); + return provider->VisitNodeEdge(*fromObj, *toObj, resultsObj, *completionObj); + } + catch (const std::exception& exception) + { + LogErrorForException(exception, "Unhandled exception in similarity provider edge visit"); + return false; + } + catch (...) + { + LogError("Unhandled exception in similarity provider edge visit"); + return false; + } +} + + +char* SimilarityProvider::GetNameCallback( + void* ctxt, BNSimilaritySessionNode* node, BNSimilarityEntityId entity, BNSimilarityResultId resultId) +{ + return RunSimilarityCallback("Unhandled exception getting similarity result name", nullptr, [&]() { + CallbackRef provider(ctxt); + Ref nodeObj = new SimilaritySessionNode(BNNewSimilaritySessionNodeReference(node)); + std::optional name = provider->GetName(*nodeObj, entity, resultId); + if (!name) + return static_cast(nullptr); + return BNAllocString(name->c_str()); + }); +} + + +BNSimilarityApplyStatus SimilarityProvider::ApplyCallback(void* ctxt, BNSimilaritySessionNode* node, + BNSimilarityEntityId entity, BNSimilarityResultId resultId) +{ + return RunSimilarityCallback("Unhandled exception applying similarity result", SimilarityApplyFailed, [&]() { + CallbackRef provider(ctxt); + Ref nodeObj = new SimilaritySessionNode(BNNewSimilaritySessionNodeReference(node)); + return provider->Apply(*nodeObj, entity, resultId); + }); +} + + +void SimilarityProvider::RenderCallback(void* ctxt, BNSimilaritySessionNode* node, + BNSimilarityEntityId entity, BNSimilarityRenderContext* context, BNSimilarityResultId resultId) +{ + RunSimilarityCallback("Unhandled exception rendering similarity result", [&]() { + CallbackRef provider(ctxt); + Ref nodeObj = new SimilaritySessionNode(BNNewSimilaritySessionNodeReference(node)); + Ref contextObj = + new SimilarityRenderContext(BNNewSimilarityRenderContextReference(context)); + provider->Render(*nodeObj, entity, *contextObj, resultId); + }); +} + + +void SimilarityProvider::FreeContextCallback(void* ctxt) +{ + SimilarityProvider* provider = (SimilarityProvider*)ctxt; + provider->ReleaseForRegistration(); +} + + +void SimilaritySessionResolver::ResolveForNodeCallback(void* ctxt, BNSimilaritySession* session, + BNSimilaritySessionNode* node, const BNSimilarityEntityId* entities, size_t entityCount, + BNSimilaritySessionCompletion* completion, BNSimilaritySessionResolverId resolverId) +{ + RunSimilarityCallback("Unhandled exception resolving similarity results", [&]() { + (void)resolverId; + CallbackRef resolver(ctxt); + Ref sessionObj = new SimilaritySession(BNNewSimilaritySessionReference(session)); + Ref nodeObj = new SimilaritySessionNode(BNNewSimilaritySessionNodeReference(node)); + Ref completionObj = + new SimilaritySessionCompletion(BNNewSimilaritySessionCompletionReference(completion)); + std::vector entityList; + entityList.reserve(entityCount); + for (size_t i = 0; i < entityCount; i++) + entityList.push_back(entities[i]); + resolver->ResolveForNode(*sessionObj, *nodeObj, entityList, *completionObj); + }); +} + + +void SimilaritySessionResolver::PrepareForNodeCallback(void* ctxt, BNSimilaritySession* session, + BNSimilaritySessionNode* node, BNSimilaritySessionCompletion* completion, BNSimilaritySessionResolverId resolverId) +{ + RunSimilarityCallback("Unhandled exception preparing similarity resolver", [&]() { + (void)resolverId; + CallbackRef resolver(ctxt); + Ref sessionObj = new SimilaritySession(BNNewSimilaritySessionReference(session)); + Ref nodeObj = new SimilaritySessionNode(BNNewSimilaritySessionNodeReference(node)); + Ref completionObj = + new SimilaritySessionCompletion(BNNewSimilaritySessionCompletionReference(completion)); + resolver->PrepareForNode(*sessionObj, *nodeObj, *completionObj); + }); +} + + +void SimilaritySessionResolver::FreeContextCallback(void* ctxt) +{ + SimilaritySessionResolver* resolver = (SimilaritySessionResolver*)ctxt; + resolver->ReleaseForRegistration(); +} + + +void SimilaritySessionReceiver::OnStartedCallback(void* ctxt, BNSimilaritySessionCompletion* completion) +{ + RunSimilarityCallback("Unhandled exception starting similarity session receiver", [&]() { + CallbackRef receiver(ctxt); + Ref completionObj = + new SimilaritySessionCompletion(BNNewSimilaritySessionCompletionReference(completion)); + receiver->NotifyStart(*completionObj); + }); +} + + +void SimilaritySessionReceiver::OnUpdatedCallback(void* ctxt, BNSimilaritySessionNode* node, + BNSimilarityProvider* provider, const BNSimilarityEntityId* entities, size_t count) +{ + RunSimilarityCallback("Unhandled exception updating similarity session receiver", [&]() { + CallbackRef receiver(ctxt); + Ref nodeObj = new SimilaritySessionNode(BNNewSimilaritySessionNodeReference(node)); + Ref providerObj = new CoreSimilarityProvider(BNNewSimilarityProviderReference(provider)); + + std::vector entityList; + entityList.reserve(count); + for (size_t i = 0; i < count; i++) + entityList.push_back(entities[i]); + + receiver->NotifyBatch(*nodeObj, *providerObj, entityList); + }); +} + + +void SimilaritySessionReceiver::FreeContextCallback(void* ctxt) +{ + SimilaritySessionReceiver* receiver = (SimilaritySessionReceiver*)ctxt; + receiver->ReleaseForRegistration(); +} + + +void SimilaritySessionGraphReceiver::OnGraphChangedCallback(void* ctxt) +{ + RunSimilarityCallback("Unhandled exception updating similarity session graph receiver", [&]() { + CallbackRef receiver(ctxt); + receiver->NotifyGraphChanged(); + }); +} + + +void SimilaritySessionGraphReceiver::FreeContextCallback(void* ctxt) +{ + SimilaritySessionGraphReceiver* receiver = (SimilaritySessionGraphReceiver*)ctxt; + receiver->ReleaseForRegistration(); +}