IDA C++ SDK 9.2
Loading...
Searching...
No Matches
diff3.hpp
Go to the documentation of this file.
1/*
2 * Interactive disassembler (IDA).
3 * Copyright (c) 2005-2025 Hex-Rays SA <support@hex-rays.com>
4 * ALL RIGHTS RESERVED.
5 */
6
7#ifndef _DIFF3_HPP
8#define _DIFF3_HPP
9
21
22// The diffing algorithms in this file match information tied to addresses.
23// So, if addresses do not match, the information will be considered to be different.
24
25//-------------------------------------------------------------------------
30{
34 bool empty() const { return start >= end; }
35 void clear() { start = end = 0; }
36 bool contains(diffpos_t p) const { return start <= p && p < end; }
38 {
39 start = p;
40 if ( end < start )
41 end = start;
42 }
44 {
45 end = p;
46 if ( end < start )
47 start = end;
48 }
49 void intersect(const diff_range_t &r)
50 {
51 if ( start < r.start )
52 start = r.start;
53 if ( end > r.end )
54 end = r.end;
55 if ( end < start )
56 end = start;
57 }
58
59 int compare(const diff_range_t &r) const { return start > r.start ? 1 : start < r.start ? -1 : 0; }
60
61 bool operator ==(const diff_range_t &r) const { return compare(r) == 0; }
62 bool operator !=(const diff_range_t &r) const { return compare(r) != 0; }
63};
65
66//------------------------------------------------------------------------
81
82//------------------------------------------------------------------------
90
91//------------------------------------------------------------------------
104
105//------------------------------------------------------------------------
113
114//------------------------------------------------------------------------
115struct diff_text_t : public qstrvec_t
116{
118};
121
122//--------------------------------------------------------------------------
131
132//------------------------------------------------------------------------
133#ifndef SWIG
134#define DECLARE_DIFF_SOURCE_HELPERS(decl)\
135decl void ida_export diff_source_merge_region(class diff_source_t *destination, class diff_source_t *source, const diff_range_t &dr);
136#else
137#define DECLARE_DIFF_SOURCE_HELPERS(decl)
138#endif // SWIG
139
141
142//------------------------------------------------------------------------
148class diff_source_t
149{
150 friend class diff3_engine_t;
151 diffpos_t get_lastpos(const diff_range_t &r)
152 {
153 diffpos_t last = check_position(r.end, DIFFPOS_BACKWARD);
154 if ( last < r.start )
155 last = r.end;
156 if ( last == BADDIFF )
157 last = r.start;
158 return last;
159 }
160
161 void _merge_region(diff_source_t *source, const diff_range_t &dr);
162
164
165public:
166 int dbctx_id;
167 diff_source_idx_t diffidx = NONE_IDX;
169 diff_source_t(int id) : dbctx_id(id) {}
170
171 virtual ~diff_source_t() {}
172
181 virtual void init_diff_source() {}
182
184 virtual void set_range(const diff_range_t &r) { range = r; }
185
187 virtual const diff_range_t &get_range() const { return range; }
188
192 virtual diffpos_t check_position(diffpos_t dpos, diffpos_check_t adj=DIFFPOS_CHECK) const = 0;
193
199 virtual diff_degree_t compare_chunks(diff_source_t *src2, diffpos_t dpos) const = 0;
200
210 virtual diff_degree_t find_next_diffpos(
211 diffpos_t * /*dpos1*/,
212 diffpos_t * /*dpos2*/,
213 diff_source_t * /*src2*/) const
214 {
215 return -1; // not implemented
216 }
217
220 virtual qstring print_diffpos_name(diffpos_t dpos) const = 0;
221
225 virtual void print_diffpos_details(qstrvec_t * /*out*/, diffpos_t /*dpos*/) const {}
226
230 virtual void merge_add(diff_source_t * /*src*/, diffpos_t /*dpos*/) {}
231
233 virtual void merge_del(diffpos_t /*dpos*/) {}
234
237 virtual void merge_replace(diff_source_t *src, diffpos_t dpos)
238 {
239 merge_del(dpos);
240 merge_add(src, dpos);
241 }
242
247 virtual void merge_region(diff_source_t *src, const diff_range_t &region)
248 {
249 diff_source_merge_region(this, src, region);
250 }
251
252#ifdef TESTABLE_BUILD
253 // dump the test results into the provided log file.
254 // nb: there is no need to switch dbctx, it is already done.
255 virtual void dump_merge_results(FILE * /*fp*/) const {}
256#endif
257
258 diff_texts_t print_range(const diff_range_t *r, bool with_details) const;
259 void test_diffpos_behavior() const;
260 bool is_valid_position(diffpos_t dpos) const
261 {
262 return get_range().contains(dpos) && check_position(dpos) == dpos;
263 }
264 diff_texts_t print_diff_source(bool with_details=true) const
265 {
266 return print_range(nullptr, with_details);
267 }
268};
269
270//------------------------------------------------------------------------
271enum merge_policy_t ENUM_SIZE(uint8)
272{
273 MERGE_POLICY_SKIP,
274 MERGE_POLICY_USE_LOCAL,
275 MERGE_POLICY_USE_REMOTE,
276 MERGE_POLICY_POSTPONE,
277 MERGE_POLICY_MDIFF,
278 MERGE_POLICY_VDIFF,
279 MERGE_POLICY_LAST,
280};
281
282//------------------------------------------------------------------------
287{
288 diff_source_t *src1;
289 diff_source_t *src2;
291 diff_result_t(diff_source_t *s1=nullptr, diff_source_t *s2=nullptr) : src1(s1), src2(s2) {}
292 qstrvec_t print_region(const diff_region_t &b, bool with_details=true) const;
293 qstrvec_t print_diff_result(bool with_details=true) const;
294 size_t size() const { return regions.size(); }
295 bool empty() const { return regions.empty(); }
296
303 size_t merge_diff_sources(merge_policy_t merge_policy, size_t i1=0, size_t i2=SIZE_MAX);
304private:
305 bool merge_one_region(size_t n, merge_policy_t merge_policy) const;
306};
307
308//------------------------------------------------------------------------
312{
313 friend class diff3_engine_t;
314protected:
315 diff_source_t *src1;
316 diff_source_t *src2;
317
318public:
319 diff_engine_t(diff_source_t *_src1, diff_source_t *_src2)
320 : src1(_src1), src2(_src2)
321 {
322 }
323 virtual bool get_diff_regions(diff_regions_t *out) = 0;
325};
326
327//------------------------------------------------------------------------
333{
334 // we maintain two positions to optimize calls to adjust_position
335 // if you decide to remove one of them, please ensure that
336 // std::lower_bound in testdiff3.cpp is not called too often
337 diffpos_t pos1;
338 diffpos_t pos2;
339 diff_degree_t calc_diff_degree(diff_degree_t cur_degree);
340public:
341 diff2_engine_t(diff_source_t *_src1, diff_source_t *_src2)
342 : diff_engine_t(_src1, _src2)
343 {
344 reset();
345 }
346 void reset();
347 virtual bool get_diff_regions(diff_regions_t *out) override;
349};
350
351//------------------------------------------------------------------------
357{
358 diff2_engine_t de1;
359 diff2_engine_t de2;
360 diff2_engine_t de3;
361
362public:
364 diff_source_t *base,
365 diff_source_t *src1,
366 diff_source_t *src2);
367 virtual ~diff3_engine_t() {}
368 virtual bool get_diff_regions(diff_regions_t *out) override;
369};
370
376 diff_source_t *base,
377 diff_source_t *src1,
378 diff_source_t *src2);
379
381 const char *const *headers,
382 const diff_texts_t *const *linevecs,
383 size_t n,
384 int psbs_flags=0);
385#define PSBS_DIFF_STARS 0x01
386#define PSBS_ONLY_DIFFS 0x02
387
388//-------------------------------------------------------------------------
397
398//-------------------------------------------------------------------------
402
404template<class T>
406{
410
412
413 void append(const T &v, size_t idx) { part.push_back(v[idx]); }
414 void reverse() { std::reverse(part.begin(), part.end()); }
415};
416// template specialisation for qstring vector
417template<>
419{
423
425
426 void append(const qstring &v, size_t idx) { part.append(v[idx]); }
427 void reverse() { if ( !part.empty() ) std::reverse(part.begin(), std::prev(part.end())); }
428};
431
433template<class T>
434class lcsdiff_res_t : public qvector<lcsdiff_res_part_t<T>>
435{
436public:
438 void eq(const T &v, size_t idx)
439 {
440 lcsdiff_res_part_t<T> &part = set_action(TDLA_EQ);
441 part.append(v, idx);
442 }
443
445 void add(const T &v, size_t idx)
446 {
447 lcsdiff_res_part_t<T> &part = set_action(TDLA_ADD);
448 part.append(v, idx);
449 }
450
452 void sub(const T &v, size_t idx)
453 {
454 lcsdiff_res_part_t<T> &part = set_action(TDLA_SUB);
455 part.append(v, idx);
456 }
457
458private:
459 lcsdiff_res_part_t<T> &set_action(lcsdiff_result_action_t wanted_action)
460 {
461 if ( this->empty() || this->back().action != wanted_action )
462 this->push_back(lcsdiff_res_part_t<T>(wanted_action));
463 return this->back();
464 }
465};
466
467//-------------------------------------------------------------------------
471template<class T>
473{
474protected:
475 const T &x;
476 const T &y;
477 const size_t n = 0;
478 const size_t m = 0;
480
481public:
484
485 //------------------------------------------------------------------
487 lcsdiff_t(const T &_x, const T &_y, size_t _n, size_t _m)
488 : x(_x),
489 y(_y),
490 n(_n),
491 m(_m)
492 {
493 // allocate storage for TABLE
494 // need an additional row/column at index 0
495 const size_t rows = n + 1;
496 const size_t cols = m + 1;
497 lcs_table.resize(rows * cols);
498
499 // compute the LCS for substring started from (i,j) indices
500 for ( size_t i=0; i < rows; ++i )
501 {
502 for ( size_t j=0; j < cols; ++j )
503 {
504 if ( i == 0 || j == 0 )
505 {
506 table(i, j) = 0;
507 }
508 else if ( x[i - 1] == y[j - 1] )
509 {
510 table(i, j) = 1 + table(i - 1, j - 1);
511 }
512 else
513 {
514 size_t l = table(i - 1, j);
515 size_t u = table(i, j - 1);
516 table(i, j) = qmax(l, u);
517 }
518 }
519 }
520 }
521
522 //------------------------------------------------------------------
525 void diff()
526 {
527 result.clear();
528 size_t i = n;
529 size_t j = m;
530 while ( i != 0 || j != 0 )
531 {
532 // end of seq reached
533 if ( i == 0 )
534 {
535 result.add(y, --j);
536 }
537 else if ( j == 0 )
538 {
539 result.sub(x, --i);
540 }
541 // Otherwise there's still parts of X and Y left. If the
542 // currently considered parts are equal, then we found an unchanged
543 // part which belongs to the longest common subsequence.
544 else if ( x[i - 1] == y[j - 1] )
545 {
546 result.eq(x, --i);
547 j--;
548 }
549 // In any other case, we go in the direction of the longest common subsequence.
550 else if ( table(i - 1, j) <= table(i, j - 1) )
551 {
552 result.add(y, --j);
553 }
554 else
555 {
556 result.sub(x, --i);
557 }
558 }
559 std::reverse(result.begin(), result.end());
560 for ( auto &part : result )
561 part.reverse();
562 }
563
564private:
565 size_t &table(size_t i, size_t j)
566 {
567 const size_t idx = i * (m + 1) + j;
568 QASSERT(2351, idx < lcs_table.size());
569 return lcs_table[idx];
570 }
571};
572
573//-------------------------------------------------------------------------
576{
578 {
581
582 // print lines
585
595 };
596
599
600 virtual void on_event(event_t ev, ...) = 0;
601};
602
603//-------------------------------------------------------------------------
604class txtdiff_t;
605
606#ifndef SWIG
607#define DECLARE_TXTDIFF_HELPERS(decl)\
608decl void ida_export txtdiff_t_diff_mod(txtdiff_t *_this);\
609decl void ida_export txtdiff_t_serialize(txtdiff_t *_this, txtdiff_printer_t &printer);
610#else
611#define DECLARE_TXTDIFF_HELPERS(decl)
612#endif // SWIG
613
614DECLARE_TXTDIFF_HELPERS(idaman)
615
616//------------------------------------------------------------------------
618class txtdiff_t : public lcsdiff_t<qstrvec_t>
619{
620public:
621 txtdiff_t(const qstrvec_t &_x, const qstrvec_t &_y)
622 : lcsdiff_t<qstrvec_t>(_x, _y, _x.size(), _y.size()) {}
623
624 //--------------------------------------------------------
628 void diff_mod() { txtdiff_t_diff_mod(this); }
629
630 //------------------------------------------------------------------------
633 void serialize(txtdiff_printer_t &printer) { txtdiff_t_serialize(this, printer); }
634
635 //--------------------------------------------------------
636 // Convenience methods
637
644 static void visual_diff(qstrvec_t *res, const qstrvec_t &x, const qstrvec_t &y, bool use_mod=true)
645 {
646 txtdiff_t d(x, y);
647 use_mod ? d.diff_mod() : d.diff();
648 for ( const auto &dl : d.result )
649 {
650 char c = dl.action == TDLA_EQ ? ' '
651 : dl.action == TDLA_ADD ? '+'
652 : dl.action == TDLA_SUB ? '-'
653 : '*'; // TDLA_MOD
654 for ( auto &p : dl.part )
655 res->push_back().sprnt("%c %s", c, p.c_str());
656 }
657 }
658
659private:
660 DECLARE_TXTDIFF_HELPERS(friend)
661 // do not call these functions directly, they are here only for exporting
662 void _diff_mod();
663 void _serialize(txtdiff_printer_t &printer);
664};
665#undef DECLARE_TXTDIFF_HELPERS
666
667//-------------------------------------------------------------------------
670{
683
686
687 virtual void on_event(event_t ev, ...) = 0;
688};
689
690//-------------------------------------------------------------------------
691class strdiff_t;
692
693#ifndef SWIG
694#define DECLARE_STRDIFF_HELPERS(decl)\
695decl void ida_export strdiff_t_serialize(strdiff_t *_this, strdiff_printer_t &printer);
696#else
697#define DECLARE_STRDIFF_HELPERS(decl)
698#endif // SWIG
699
700DECLARE_STRDIFF_HELPERS(idaman)
701
702//-------------------------------------------------------------------------
704class strdiff_t : public lcsdiff_t<qstring>
705{
706public:
707 strdiff_t(const qstring &_x, const qstring &_y)
708 : lcsdiff_t<qstring>(_x, _y, _x.length(), _y.length()) {}
709
710 //------------------------------------------------------------------------
712 void serialize(strdiff_printer_t &printer) { strdiff_t_serialize(this, printer); }
713
714private:
715 DECLARE_STRDIFF_HELPERS(friend)
716 // do not call these functions directly, they are here only for exporting
717 void _serialize(strdiff_printer_t &printer);
718};
719#undef DECLARE_STRDIFF_HELPERS
720#endif // _DIFF3_HPP
virtual bool get_diff_regions(diff_regions_t *out) override
diff2_engine_t(diff_source_t *_src1, diff_source_t *_src2)
Definition diff3.hpp:341
bool get_diff_region(diff_region_t *out)
A 3-way difference engine.
Definition diff3.hpp:357
virtual bool get_diff_regions(diff_regions_t *out) override
diff3_engine_t(diff_source_t *base, diff_source_t *src1, diff_source_t *src2)
virtual ~diff3_engine_t()
Definition diff3.hpp:367
diff_source_t * src1
Definition diff3.hpp:315
diff_source_t * src2
Definition diff3.hpp:316
diff_engine_t(diff_source_t *_src1, diff_source_t *_src2)
Definition diff3.hpp:319
virtual bool get_diff_regions(diff_regions_t *out)=0
friend class diff3_engine_t
Definition diff3.hpp:313
diff_result_t perform_diff()
result
Definition diff3.hpp:435
void add(const T &v, size_t idx)
vector's item should be added
Definition diff3.hpp:445
void sub(const T &v, size_t idx)
vector's item should be deleted
Definition diff3.hpp:452
void eq(const T &v, size_t idx)
vector's items are equal
Definition diff3.hpp:438
Calculate difference between two vectors.
Definition diff3.hpp:473
const size_t n
left argument size
Definition diff3.hpp:477
lcsdiff_t(const T &_x, const T &_y, size_t _n, size_t _m)
prepare LCS table
Definition diff3.hpp:487
sizevec_t lcs_table
table to store LCS for each step of the calculation
Definition diff3.hpp:479
void diff()
get a difference between two vectors RESULT will contain only TDLA_EQ, TDLA_ADD, TDLA_SUB actions
Definition diff3.hpp:525
result_t result
Definition diff3.hpp:483
const size_t m
right argument size
Definition diff3.hpp:478
const T & y
right argument
Definition diff3.hpp:476
const T & x
left argument
Definition diff3.hpp:475
lcsdiff_res_t< T > result_t
Definition diff3.hpp:482
Reimplementation of vector class from STL.
Definition pro.h:2250
bool empty(void) const
Definition pro.h:2424
const T & back(void) const
Definition pro.h:2431
qvector(void)
Definition pro.h:2328
void push_back(T &&x)
Definition pro.h:2361
size_t size(void) const
Get the number of elements in the qvector.
Definition pro.h:2423
diff_result_t perform_diff3(diff_source_t *base, diff_source_t *src1, diff_source_t *src2)
Perform 3-way difference.
diffpos_check_t
Definition diff3.hpp:107
@ DIFFPOS_BACKWARD
back off to the previous valid position
Definition diff3.hpp:111
@ DIFFPOS_FORWARD
advance to the next valid position
Definition diff3.hpp:110
@ DIFFPOS_CHECK
verify if the position is valid; if not, return the next valid position
Definition diff3.hpp:108
qvector< diff_text_t > diff_texts_t
Definition diff3.hpp:120
DECLARE_DIFF_SOURCE_HELPERS(idaman) class diff_source_t
A difference source.
Definition diff3.hpp:140
enum merge_policy_t ENUM_SIZE(uint8)
Definition diff3.hpp:271
diff_source_idx_t
standard indexes into dbctx_ids[] and similar arrays
Definition diff3.hpp:125
@ BASE_IDX
Definition diff3.hpp:129
@ LOCAL_IDX
Definition diff3.hpp:127
@ NONE_IDX
Definition diff3.hpp:126
@ REMOTE_IDX
Definition diff3.hpp:128
lcsdiff_result_action_t
diff result actions, lcsdiff_t::diff lcsdiff_t::diff_mod
Definition diff3.hpp:391
@ TDLA_MOD
updated items (new content)
Definition diff3.hpp:395
@ TDLA_SUB
removed items
Definition diff3.hpp:394
@ TDLA_ADD
added items
Definition diff3.hpp:393
@ TDLA_EQ
items are equal
Definition diff3.hpp:392
qvector< diff_region_t > diff_regions_t
Definition diff3.hpp:103
diff_action_t
Definition diff3.hpp:84
@ DIFF_USE1
use information from src1
Definition diff3.hpp:86
@ DIFF_BOTH
use information from both (conflict)
Definition diff3.hpp:88
@ DIFF_USE2
use information from src2
Definition diff3.hpp:87
@ DIFF_NONE
unknown
Definition diff3.hpp:85
DECLARE_TYPE_AS_MOVABLE(diff_range_t)
qstrvec_t put_side_by_side(const char *const *headers, const diff_texts_t *const *linevecs, size_t n, int psbs_flags=0)
ssize_t diff_degree_t
A difference degree.
Definition diff3.hpp:80
idaman size_t n
Definition pro.h:997
cexpr_t * e
Definition hexrays.hpp:7308
asize_t size
Definition kernwin.hpp:6339
void(idaapi *range_marker)(ea_t ea
Pointer to range marker function (for idaviews and hexviews) This pointer is initialized by setup_ran...
qvector< size_t > sizevec_t
vector of sizes
Definition pro.h:2767
size_t diffpos_t
Definition pro.h:479
ptrdiff_t ssize_t
Signed size_t - used to check for size overflows when the counter becomes negative.
Definition pro.h:381
constexpr diffpos_t BADDIFF
Definition pro.h:480
unsigned char uint8
unsigned 8 bit value
Definition pro.h:344
_qstring< char > qstring
regular string
Definition pro.h:3694
qvector< qstring > qstrvec_t
vector of strings
Definition pro.h:3697
A range of the difference source.
Definition diff3.hpp:30
diffpos_t end
Definition diff3.hpp:32
void set_start(diffpos_t p)
Definition diff3.hpp:37
bool contains(diffpos_t p) const
Definition diff3.hpp:36
void set_end(diffpos_t p)
Definition diff3.hpp:43
bool operator==(const diff_range_t &r) const
Definition diff3.hpp:61
int compare(const diff_range_t &r) const
Definition diff3.hpp:59
diff_range_t(diffpos_t s=0, diffpos_t e=0)
Definition diff3.hpp:33
void intersect(const diff_range_t &r)
Definition diff3.hpp:49
void clear()
Definition diff3.hpp:35
bool empty() const
Definition diff3.hpp:34
diffpos_t start
Definition diff3.hpp:31
bool operator!=(const diff_range_t &r) const
Definition diff3.hpp:62
A difference region.
Definition diff3.hpp:95
void clear()
Definition diff3.hpp:98
diff_degree_t diff_degree
Definition diff3.hpp:96
qstring dstr() const
bool is_useless() const
Definition diff3.hpp:99
diff_action_t action
Definition diff3.hpp:97
A difference result.
Definition diff3.hpp:287
diff_regions_t regions
Definition diff3.hpp:290
size_t size() const
Definition diff3.hpp:294
diff_source_t * src2
Definition diff3.hpp:289
bool empty() const
Definition diff3.hpp:295
qstrvec_t print_region(const diff_region_t &b, bool with_details=true) const
qstrvec_t print_diff_result(bool with_details=true) const
diff_source_t * src1
Definition diff3.hpp:288
size_t merge_diff_sources(merge_policy_t merge_policy, size_t i1=0, size_t i2=SIZE_MAX)
merge src1 and src2 into src1.
diff_result_t(diff_source_t *s1=nullptr, diff_source_t *s2=nullptr)
Definition diff3.hpp:291
Definition diff3.hpp:116
diffpos_t pos
Definition diff3.hpp:117
void reverse()
Definition diff3.hpp:427
void append(const qstring &v, size_t idx)
Definition diff3.hpp:426
qstring part
vector's items
Definition diff3.hpp:420
lcsdiff_res_part_t(lcsdiff_result_action_t _a)
Definition diff3.hpp:424
lcsdiff_result_action_t action
action for items, lcsdiff_result_action_t
Definition diff3.hpp:422
qstring x_part
previous content, only for TDLA_MOD
Definition diff3.hpp:421
difference result, stores vectors' items with action to be applied to construct Y from X
Definition diff3.hpp:406
T x_part
previous content, only for TDLA_MOD
Definition diff3.hpp:408
void append(const T &v, size_t idx)
Definition diff3.hpp:413
T part
vector's items
Definition diff3.hpp:407
void reverse()
Definition diff3.hpp:414
lcsdiff_res_part_t(lcsdiff_result_action_t _a)
Definition diff3.hpp:411
lcsdiff_result_action_t action
action for items, lcsdiff_result_action_t
Definition diff3.hpp:409
virtual void on_event(event_t ev,...)=0
strdiff_printer_t()
Definition diff3.hpp:684
virtual ~strdiff_printer_t()
Definition diff3.hpp:685
event_t
Definition diff3.hpp:672
@ del_chars
deleted chars from line X, TDLA_SUB
Definition diff3.hpp:680
@ add_chars
added chars to line from X, TDLA_ADD
Definition diff3.hpp:678
@ same_chars
the same chars, TDLA_EQ
Definition diff3.hpp:676
@ term_chars
end printing
Definition diff3.hpp:674
@ init_chars
start printing
Definition diff3.hpp:673
event_t
Definition diff3.hpp:578
@ del_line
line is removed from X, TDLA_SUB
Definition diff3.hpp:590
@ next_line
start to print next line
Definition diff3.hpp:583
@ add_line
line is added to X, TDLA_ADD
Definition diff3.hpp:588
@ mod_line
line is changed, TDLA_MOD
Definition diff3.hpp:592
@ init
start printing
Definition diff3.hpp:579
@ same_line
line is the same in X and Y, TDLA_EQ
Definition diff3.hpp:586
@ term
end printing
Definition diff3.hpp:580
txtdiff_printer_t()
Definition diff3.hpp:597
virtual ~txtdiff_printer_t()
Definition diff3.hpp:598
virtual void on_event(event_t ev,...)=0