Skip to content

Commit 2184361

Browse files
committed
Merge: Python apis for DiffState and DiffObject
1 parent 4578524 commit 2184361

2 files changed

Lines changed: 141 additions & 2 deletions

File tree

binaryninjacore.h

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,8 @@ extern "C"
354354
typedef struct BNStringRecognizer BNStringRecognizer;
355355
typedef struct BNCustomStringType BNCustomStringType;
356356
typedef struct BNDatabaseObject BNDatabaseObject;
357+
typedef struct BNDiffState BNDiffState;
358+
typedef struct BNDiffObject BNDiffObject;
357359

358360
typedef struct BNPluginVersion
359361
{
@@ -9130,8 +9132,25 @@ extern "C"
91309132
BINARYNINJACOREAPI size_t BNGetDatabaseObjectChildren(BNDatabaseObject* object, char*** names, BNDatabaseObject*** objects);
91319133
BINARYNINJACOREAPI char** BNGetDatabaseObjectDependencies(BNDatabaseObject* object, size_t* count);
91329134

9133-
// todo remove before release
9134-
BINARYNINJACOREAPI void BNTestMerge(BNDatabaseObject* base, BNDatabaseObject* left, BNDatabaseObject* right, BNDatabaseObject* result);
9135+
BINARYNINJACOREAPI BNDiffState* BNNewDiffStateReference(BNDiffState* state);
9136+
BINARYNINJACOREAPI void BNFreeDiffState(BNDiffState* state);
9137+
BINARYNINJACOREAPI BNDiffState* BNCreateDiffState(BNLogger* logger);
9138+
BINARYNINJACOREAPI char** BNGetDiffStateErrors(BNDiffState* state, size_t* count);
9139+
BINARYNINJACOREAPI void BNClearDiffStateErrors(BNDiffState* state);
9140+
BINARYNINJACOREAPI BNDiffObject* BNDiffStateGenerateDiff(BNDiffState* state, BNDatabaseObject* base, BNDatabaseObject* left, BNDatabaseObject* right);
9141+
BINARYNINJACOREAPI bool BNDiffStateApplyDiff(BNDiffState* state, BNDiffObject* diff, BNDatabaseObject* base, BNDatabaseObject* left, BNDatabaseObject* right, BNDatabaseObject* result);
9142+
BINARYNINJACOREAPI bool BNDiffStateIsDiffed(BNDiffState* state, BNDatabaseObject* object);
9143+
BINARYNINJACOREAPI bool BNDiffStateIsApplied(BNDiffState* state, BNDiffObject* object);
9144+
9145+
BINARYNINJACOREAPI BNDiffObject* BNNewDiffObjectReference(BNDiffObject* object);
9146+
BINARYNINJACOREAPI void BNFreeDiffObject(BNDiffObject* object);
9147+
BINARYNINJACOREAPI void BNFreeDiffObjectList(BNDiffObject** objects, size_t count);
9148+
BINARYNINJACOREAPI char* BNGetDiffObjectBase(BNDiffObject* object);
9149+
BINARYNINJACOREAPI char* BNGetDiffObjectLeft(BNDiffObject* object);
9150+
BINARYNINJACOREAPI char* BNGetDiffObjectRight(BNDiffObject* object);
9151+
BINARYNINJACOREAPI size_t BNGetDiffObjectChildren(BNDiffObject* object, char*** names, BNDiffObject*** objects);
9152+
BINARYNINJACOREAPI BNMergeStrategy BNGetDiffObjectMergeStrategy(BNDiffObject* object);
9153+
BINARYNINJACOREAPI void BNSetDiffObjectMergeStrategy(BNDiffObject* object, BNMergeStrategy strategy);
91359154

91369155
#ifdef __cplusplus
91379156
}

python/database.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,3 +440,123 @@ def dependencies(self) -> List[str]:
440440
return result
441441
finally:
442442
core.BNFreeStringList(deps, count.value)
443+
444+
445+
class DiffState:
446+
def __init__(self, logger=None, handle=None):
447+
if handle is not None:
448+
self.handle = core.handle_of_type(handle, core.BNDiffState)
449+
else:
450+
assert logger is not None, "Need logger to construct diff state"
451+
self.handle = core.BNCreateDiffState(logger.handle)
452+
453+
def __del__(self):
454+
core.BNFreeDiffState(self.handle)
455+
456+
@property
457+
def errors(self) -> List[str]:
458+
"""Get list of error messages (read-only)"""
459+
count = ctypes.c_size_t()
460+
errors = core.BNGetDiffStateErrors(self.handle, ctypes.byref(count))
461+
try:
462+
result = []
463+
for i in range(0, count.value):
464+
result.append(core.pyNativeStr(errors[i]))
465+
return result
466+
finally:
467+
core.BNFreeStringList(errors, count.value)
468+
469+
def clear_errors(self):
470+
"""Clear all error messages"""
471+
core.BNClearDiffStateErrors(self.handle)
472+
473+
def generate_diff(
474+
self, base: DatabaseObject, left: DatabaseObject, right: DatabaseObject
475+
) -> Optional['DiffObject']:
476+
"""Generate a three-way diff database objects"""
477+
handle = core.BNDiffStateGenerateDiff(
478+
self.handle, base.handle, left.handle, right.handle
479+
)
480+
if handle is None:
481+
return None
482+
return DiffObject(handle=handle)
483+
484+
def apply_diff(
485+
self, diff: 'DiffObject', base: DatabaseObject, left: DatabaseObject,
486+
right: DatabaseObject, result: DatabaseObject
487+
) -> bool:
488+
"""Apply a diff to database objects"""
489+
return core.BNDiffStateApplyDiff(
490+
self.handle, diff.handle, base.handle, left.handle, right.handle,
491+
result.handle
492+
)
493+
494+
def is_diffed(self, object: DatabaseObject) -> bool:
495+
"""Check if an object was used during generate_diff"""
496+
return core.BNDiffStateIsDiffed(self.handle, object.handle)
497+
498+
def is_applied(self, object: 'DiffObject') -> bool:
499+
"""Check if an object was used during apply_diff"""
500+
return core.BNDiffStateIsApplied(self.handle, object.handle)
501+
502+
503+
class DiffObject:
504+
def __init__(self, handle):
505+
self.handle = core.handle_of_type(handle, core.BNDiffObject)
506+
507+
def __del__(self):
508+
core.BNFreeDiffObject(self.handle)
509+
510+
@property
511+
def base(self) -> Optional[str]:
512+
"""Get the base path for the diff object (read-only)"""
513+
value = core.BNGetDiffObjectBase(self.handle)
514+
if value is None:
515+
return None
516+
return value
517+
518+
@property
519+
def left(self) -> Optional[str]:
520+
"""Get the left path for the diff object (read-only)"""
521+
value = core.BNGetDiffObjectLeft(self.handle)
522+
if value is None:
523+
return None
524+
return value
525+
526+
@property
527+
def right(self) -> Optional[str]:
528+
"""Get the right path for the diff object (read-only)"""
529+
value = core.BNGetDiffObjectRight(self.handle)
530+
if value is None:
531+
return None
532+
return value
533+
534+
@property
535+
def children(self) -> Dict[str, 'DiffObject']:
536+
"""Get dictionary of child diff objects (read-only)"""
537+
names = ctypes.POINTER(ctypes.c_char_p)()
538+
objects = ctypes.POINTER(ctypes.POINTER(core.BNDiffObject))()
539+
count = core.BNGetDiffObjectChildren(
540+
self.handle, ctypes.byref(names), ctypes.byref(objects)
541+
)
542+
543+
result = {}
544+
try:
545+
for i in range(count):
546+
name = core.pyNativeStr(names[i])
547+
obj_handle = core.BNNewDiffObjectReference(objects[i])
548+
result[name] = DiffObject(handle=obj_handle)
549+
return result
550+
finally:
551+
core.BNFreeDiffObjectList(objects, count)
552+
core.BNFreeStringList(names, count)
553+
554+
@property
555+
def strategy(self) -> 'MergeStrategy':
556+
"""Get the merge strategy for this diff object"""
557+
return core.BNGetDiffObjectMergeStrategy(self.handle)
558+
559+
@strategy.setter
560+
def strategy(self, value: 'MergeStrategy'):
561+
"""Set the merge strategy for this diff object"""
562+
core.BNSetDiffObjectMergeStrategy(self.handle, value)

0 commit comments

Comments
 (0)