+ delete [] this->data; this->data = 0;
+ this->data_size = 0; this->key = 0;
+ int data_size = strlen(data)+1;
+
+ UndoStackItem *current = this;
+// Search for key buffer within interval
+ for( int i=UNDO_KEY_INTERVAL; --i>=0 && current && !current->key; current=PREVIOUS );
+
+ int need_key = current ? 0 : 1;
+// setting need_key = 1 forces all undo data items to key (not diffd)
+// int need_key = 1;
+ char *prev = 0; int prev_size = 0;
+ if( !need_key ) {
+#ifdef UNDO_INCREMENTAL
+ prev = previous->get_data();
+ prev_size = prev ? strlen(prev)+1 : 0;
+#else
+ prev = current->data;
+ prev_size = current->data_size;
+#endif
+ int min_size = data_size/16;
+// if the previous is a sizable incremental diff
+ if( previous && !previous->key &&
+ previous->data_size > min_size ) {
+// and this minimum diff distance is a lot different, need key
+ int dist = abs(data_size - prev_size);
+ if( abs(dist - previous->data_size) > min_size )
+ need_key = 1;
+ }
+ }
+ if( !need_key ) {
+ int bfr_size = BCTEXTLEN;
+ char *bfr = new char[bfr_size];
+ XMLBuffer xbfr(bfr_size, bfr, 1);
+ xbfr.write((char*)&data_size, sizeof(data_size));
+ UndoHashTable hash;
+ UndoVersion alines(va), blines(vb);
+ char *asp = data, *aep = asp + data_size-1;
+ char *bsp = prev, *bep = bsp + prev_size-1;
+ alines.append(new UndoLine(hash.bof, asp));
+ blines.append(new UndoLine(hash.bof, bsp));
+ alines.scan_lines(&hash, asp, aep);
+ blines.scan_lines(&hash, bsp, bep);
+ int asz = alines.size(), bsz = blines.size();
+// trim matching suffix
+ while( asz > 0 && bsz > 0 && alines[asz-1]->eq(blines[bsz-1]) ) {
+ aep = alines[--asz]->txt; alines.remove_object();
+ bep = blines[--bsz]->txt; blines.remove_object();
+ }
+// include for matching last item
+ alines.append(new UndoLine(hash.eof, aep));
+ blines.append(new UndoLine(hash.eof, bep));
+ hash.eof->line[va] = asz++;
+ hash.eof->line[vb] = bsz++;
+
+ int ai = 0, bi = 0;
+ while( ai < asz || bi < bsz ) {
+// skip running match
+ if( alines[ai]->eq(blines[bi]) ) { ++ai; ++bi; continue; }
+ char *adp = alines[ai]->txt, *bdp = blines[bi]->txt;
+// find best unique match
+ int ma = asz, mb = bsz;
+ int mx = ma + mb + 1;
+ for( int ia=ai; ia<asz && ia-ai<mx; ++ia ) {
+ UndoHash *ah = alines[ia]->hash;
+ if( ah->occurs[va] != 1 || ah->occurs[vb] != 1 ) continue;
+ int m = (ah->line[va] - ai) + (ah->line[vb] - bi);
+ if( m >= mx ) continue;
+ ma = ah->line[va]; mb = ah->line[vb]; mx = m;
+ }
+// trim suffix
+ while( ma > 0 && mb > 0 && alines[ma-1]->eq(blines[mb-1]) ) { --ma; --mb; }
+ char *ap = alines[ma]->txt, *bp = blines[mb]->txt;
+ ai = ma; bi = mb;
+ undo_record urecd;
+ urecd.new_ofs = adp - data;
+ urecd.new_len = ap - adp;
+ urecd.old_len = bp - bdp;
+ xbfr.write((const char*)&urecd, sizeof(urecd));
+ xbfr.write((const char*)adp, urecd.new_len);
+ }
+
+ int64_t pos = xbfr.otell();
+ if( abs(data_size-prev_size) < pos/2 ) {
+ this->data = new char[this->data_size = pos];
+ xbfr.iseek(0);
+ xbfr.read(this->data, pos);
+#if 1
+ int test_size = 0;
+ char *test_data = (char*)apply_difference(
+ (unsigned char *)prev, prev_size,
+ (unsigned char *)this->data, this->data_size,
+ &test_size);
+ if( test_size != data_size || memcmp(test_data, data, test_size) ) {
+ printf("UndoStackItem::set_data: *** incremental undo failed!\n");
+ delete [] this->data; this->data = 0; this->data_size = 0;
+ need_key = 1;
+ }
+ delete [] test_data;
+#endif
+ }
+ else
+ need_key = 1;
+ }
+
+#ifdef UNDO_INCREMENTAL
+ delete [] prev;
+#endif
+ if( need_key ) {
+ this->key = 1;
+ this->data = new char[this->data_size = data_size];
+ memcpy(this->data, data, this->data_size);
+ }