static svn_error_t *ra_svn_apply_textdelta(void *file_baton, const char *base_checksum, apr_pool_t *pool, svn_txdelta_window_handler_t *wh, void **wh_baton) { ra_svn_baton_t *b = file_baton; svn_stream_t *diff_stream; /* Tell the other side we're starting a text delta. */ SVN_ERR(check_for_error(b->eb, pool)); SVN_ERR(svn_ra_svn__write_cmd_apply_textdelta(b->conn, pool, b->token, base_checksum)); /* Transform the window stream to an svndiff stream. Reuse the * file baton for the stream handler, since it has all the * needed information. */ diff_stream = svn_stream_create(b, pool); svn_stream_set_write(diff_stream, ra_svn_svndiff_handler); svn_stream_set_close(diff_stream, ra_svn_svndiff_close_handler); /* If the connection does not support SVNDIFF1 or if we don't want to use * compression, use the non-compressing "version 0" implementation */ if ( svn_ra_svn_compression_level(b->conn) > 0 && svn_ra_svn_has_capability(b->conn, SVN_RA_SVN_CAP_SVNDIFF1)) svn_txdelta_to_svndiff3(wh, wh_baton, diff_stream, 1, b->conn->compression_level, pool); else svn_txdelta_to_svndiff3(wh, wh_baton, diff_stream, 0, b->conn->compression_level, pool); return SVN_NO_ERROR; }
static svn_error_t * apply_textdelta(void *file_baton, const char *base_checksum, apr_pool_t *pool, svn_txdelta_window_handler_t *handler, void **handler_baton) { edit_baton_t *eb = file_baton; SVN_ERR(dav_svn__brigade_puts(eb->bb, eb->output, "<S:apply-textdelta")); if (base_checksum) SVN_ERR(dav_svn__brigade_printf(eb->bb, eb->output, " checksum=\"%s\">", base_checksum)); else SVN_ERR(dav_svn__brigade_puts(eb->bb, eb->output, ">")); svn_txdelta_to_svndiff3(handler, handler_baton, dav_svn__make_base64_output_stream(eb->bb, eb->output, pool), eb->svndiff_version, eb->compression_level, pool); eb->sending_textdelta = TRUE; return SVN_NO_ERROR; }
/* This implements the svn_repos_file_rev_handler2_t interface. */ static svn_error_t * file_rev_handler(void *baton, const char *path, svn_revnum_t revnum, apr_hash_t *rev_props, svn_boolean_t merged_revision, svn_txdelta_window_handler_t *window_handler, void **window_baton, apr_array_header_t *props, apr_pool_t *pool) { struct file_rev_baton *frb = baton; apr_pool_t *subpool = svn_pool_create(pool); apr_hash_index_t *hi; int i; SVN_ERR(maybe_send_header(frb)); SVN_ERR(dav_svn__brigade_printf(frb->bb, frb->output, "<S:file-rev path=\"%s\" rev=\"%ld\">" DEBUG_CR, apr_xml_quote_string(pool, path, 1), revnum)); /* Send rev props. */ for (hi = apr_hash_first(pool, rev_props); hi; hi = apr_hash_next(hi)) { const void *key; void *val; const char *pname; const svn_string_t *pval; svn_pool_clear(subpool); apr_hash_this(hi, &key, NULL, &val); pname = key; pval = val; SVN_ERR(send_prop(frb, "rev-prop", pname, pval, subpool)); } /* Send file prop changes. */ for (i = 0; i < props->nelts; ++i) { const svn_prop_t *prop = &APR_ARRAY_IDX(props, i, svn_prop_t); svn_pool_clear(subpool); if (prop->value) SVN_ERR(send_prop(frb, "set-prop", prop->name, prop->value, subpool)); else { /* Property was removed. */ SVN_ERR(dav_svn__brigade_printf(frb->bb, frb->output, "<S:remove-prop name=\"%s\"/>" DEBUG_CR, apr_xml_quote_string(subpool, prop->name, 1))); } } /* Send whether this was the result of a merge or not. */ if (merged_revision) SVN_ERR(dav_svn__brigade_puts(frb->bb, frb->output, "<S:merged-revision/>")); /* Maybe send text delta. */ if (window_handler) { svn_stream_t *base64_stream; base64_stream = dav_svn__make_base64_output_stream(frb->bb, frb->output, pool); svn_txdelta_to_svndiff3(&frb->window_handler, &frb->window_baton, base64_stream, frb->svndiff_version, frb->compression_level, pool); *window_handler = delta_window_handler; *window_baton = frb; /* Start the txdelta element wich will be terminated by the window handler together with the file-rev element. */ SVN_ERR(dav_svn__brigade_puts(frb->bb, frb->output, "<S:txdelta>")); } else /* No txdelta, so terminate the element here. */ SVN_ERR(dav_svn__brigade_puts(frb->bb, frb->output, "</S:file-rev>" DEBUG_CR)); svn_pool_destroy(subpool); return SVN_NO_ERROR; }
inline Try<Diff> diff(const std::string& from, const std::string& to) { // Initialize the Apache Portable Runtime subsystem, as necessary // for using the svn library. initialize(); // Note that svn_pool_create wraps apr_pool_create_ex, which is // thread safe, see: http://goo.gl/NX0hps. apr_pool_t* pool = svn_pool_create(NULL); // First we need to produce a text delta stream by diffing 'source' // against 'target'. svn_string_t source; source.data = from.data(); source.len = from.length(); svn_string_t target; target.data = to.data(); target.len = to.length(); svn_txdelta_stream_t* delta; #if SVN_VER_MAJOR >= 1 && SVN_VER_MINOR >= 8 svn_txdelta2( &delta, svn_stream_from_string(&source, pool), svn_stream_from_string(&target, pool), false, pool); #else svn_txdelta( &delta, svn_stream_from_string(&source, pool), svn_stream_from_string(&target, pool), pool); #endif // Now we want to convert this text delta stream into an svndiff // format based diff. Setup the handler that will consume the text // delta and produce the svndiff. svn_txdelta_window_handler_t handler; void* baton = NULL; svn_stringbuf_t* diff = svn_stringbuf_create_ensure(1024, pool); #if SVN_VER_MAJOR >= 1 && SVN_VER_MINOR >= 7 svn_txdelta_to_svndiff3( &handler, &baton, svn_stream_from_stringbuf(diff, pool), 0, SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, pool); #elif SVN_VER_MAJOR >= 1 && SVN_VER_MINOR >= 4 svn_txdelta_to_svndiff2( &handler, &baton, svn_stream_from_stringbuf(diff, pool), 0, pool); #else svn_txdelta_to_svndiff( svn_stream_from_stringbuf(diff, pool), pool, &handler, &baton); #endif // Now feed the text delta to the handler. svn_error_t* error = svn_txdelta_send_txstream(delta, handler, baton, pool); if (error != NULL) { char buffer[1024]; std::string message(svn_err_best_message(error, buffer, 1024)); svn_pool_destroy(pool); return Error(message); } Diff d(std::string(diff->data, diff->len)); svn_pool_destroy(pool); return d; }
int main(int argc, char **argv) { svn_error_t *err; apr_status_t apr_err; apr_file_t *source_file; apr_file_t *target_file; svn_stream_t *stdout_stream; svn_txdelta_stream_t *txdelta_stream; svn_txdelta_window_handler_t svndiff_handler; svn_stream_t *encoder; void *svndiff_baton; apr_pool_t *pool; int version = 0; if (argc < 3) { printf("usage: %s source target [version]\n", argv[0]); exit(0); } apr_initialize(); pool = svn_pool_create(NULL); apr_err = apr_file_open(&source_file, argv[1], (APR_READ | APR_BINARY), APR_OS_DEFAULT, pool); if (apr_err) { fprintf(stderr, "unable to open \"%s\" for reading\n", argv[1]); exit(1); } apr_err = apr_file_open(&target_file, argv[2], (APR_READ | APR_BINARY), APR_OS_DEFAULT, pool); if (apr_err) { fprintf(stderr, "unable to open \"%s\" for reading\n", argv[2]); exit(1); } if (argc == 4) version = atoi(argv[3]); svn_txdelta(&txdelta_stream, svn_stream_from_aprfile(source_file, pool), svn_stream_from_aprfile(target_file, pool), pool); err = svn_stream_for_stdout(&stdout_stream, pool); if (err) svn_handle_error2(err, stdout, TRUE, "svndiff-test: "); #ifdef QUOPRINT_SVNDIFFS encoder = svn_quoprint_encode(stdout_stream, pool); #else encoder = svn_base64_encode(stdout_stream, pool); #endif /* use maximum compression level */ svn_txdelta_to_svndiff3(&svndiff_handler, &svndiff_baton, encoder, version, 9, pool); err = svn_txdelta_send_txstream(txdelta_stream, svndiff_handler, svndiff_baton, pool); if (err) svn_handle_error2(err, stdout, TRUE, "svndiff-test: "); apr_file_close(source_file); apr_file_close(target_file); svn_pool_destroy(pool); apr_terminate(); exit(0); }
/* (Note: *LAST_SEED is an output parameter.) */ static svn_error_t * do_random_combine_test(apr_pool_t *pool, apr_uint32_t *last_seed) { apr_uint32_t seed, maxlen; apr_size_t bytes_range; int i, iterations, dump_files, print_windows; const char *random_bytes; /* Initialize parameters and print out the seed in case we dump core or something. */ init_params(&seed, &maxlen, &iterations, &dump_files, &print_windows, &random_bytes, &bytes_range, pool); for (i = 0; i < iterations; i++) { /* Generate source and target for the delta and its application. */ apr_uint32_t subseed_base = svn_test_rand((*last_seed = seed, &seed)); apr_file_t *source = generate_random_file(maxlen, subseed_base, &seed, random_bytes, bytes_range, dump_files, pool); apr_file_t *middle = generate_random_file(maxlen, subseed_base, &seed, random_bytes, bytes_range, dump_files, pool); apr_file_t *target = generate_random_file(maxlen, subseed_base, &seed, random_bytes, bytes_range, dump_files, pool); apr_file_t *source_copy = copy_tempfile(source, pool); apr_file_t *middle_copy = copy_tempfile(middle, pool); apr_file_t *target_regen = open_tempfile(NULL, pool); svn_txdelta_stream_t *txdelta_stream_A; svn_txdelta_stream_t *txdelta_stream_B; svn_txdelta_window_handler_t handler; svn_stream_t *stream; void *handler_baton; /* Set up a four-stage pipeline: create two deltas, combine them and convert the result to svndiff format, parse that back into delta format, and apply it to a copy of the source file to see if we get the same target back. */ apr_pool_t *delta_pool = svn_pool_create(pool); /* Make stage 4: apply the text delta. */ svn_txdelta_apply(svn_stream_from_aprfile(source_copy, delta_pool), svn_stream_from_aprfile(target_regen, delta_pool), NULL, NULL, delta_pool, &handler, &handler_baton); /* Make stage 3: reparse the text delta. */ stream = svn_txdelta_parse_svndiff(handler, handler_baton, TRUE, delta_pool); /* Make stage 2: encode the text delta in svndiff format using varying compression levels. */ svn_txdelta_to_svndiff3(&handler, &handler_baton, stream, 1, i % 10, delta_pool); /* Make stage 1: create the text deltas. */ svn_txdelta2(&txdelta_stream_A, svn_stream_from_aprfile(source, delta_pool), svn_stream_from_aprfile(middle, delta_pool), FALSE, delta_pool); svn_txdelta2(&txdelta_stream_B, svn_stream_from_aprfile(middle_copy, delta_pool), svn_stream_from_aprfile(target, delta_pool), FALSE, delta_pool); { svn_txdelta_window_t *window_A; svn_txdelta_window_t *window_B; svn_txdelta_window_t *composite; apr_pool_t *wpool = svn_pool_create(delta_pool); do { SVN_ERR(svn_txdelta_next_window(&window_A, txdelta_stream_A, wpool)); if (print_windows) delta_window_print(window_A, "A ", stdout); SVN_ERR(svn_txdelta_next_window(&window_B, txdelta_stream_B, wpool)); if (print_windows) delta_window_print(window_B, "B ", stdout); if (!window_B) break; assert(window_A != NULL || window_B->src_ops == 0); if (window_B->src_ops == 0) { composite = window_B; composite->sview_len = 0; } else composite = svn_txdelta_compose_windows(window_A, window_B, wpool); if (print_windows) delta_window_print(composite, "AB", stdout); /* The source view length should not be 0 if there are source copy ops in the window. */ if (composite && composite->sview_len == 0 && composite->src_ops > 0) return svn_error_create (SVN_ERR_FS_GENERAL, NULL, "combined delta window is inconsistent"); SVN_ERR(handler(composite, handler_baton)); svn_pool_clear(wpool); } while (composite != NULL); svn_pool_destroy(wpool); } svn_pool_destroy(delta_pool); SVN_ERR(compare_files(target, target_regen, dump_files)); apr_file_close(source); apr_file_close(middle); apr_file_close(target); apr_file_close(source_copy); apr_file_close(middle_copy); apr_file_close(target_regen); } return SVN_NO_ERROR; }
/* Implements svn_test_driver_t. */ static svn_error_t * random_test(apr_pool_t *pool) { apr_uint32_t seed, maxlen; apr_size_t bytes_range; int i, iterations, dump_files, print_windows; const char *random_bytes; /* Initialize parameters and print out the seed in case we dump core or something. */ init_params(&seed, &maxlen, &iterations, &dump_files, &print_windows, &random_bytes, &bytes_range, pool); for (i = 0; i < iterations; i++) { /* Generate source and target for the delta and its application. */ apr_uint32_t subseed_base = svn_test_rand(&seed); apr_file_t *source = generate_random_file(maxlen, subseed_base, &seed, random_bytes, bytes_range, dump_files, pool); apr_file_t *target = generate_random_file(maxlen, subseed_base, &seed, random_bytes, bytes_range, dump_files, pool); apr_file_t *source_copy = copy_tempfile(source, pool); apr_file_t *target_regen = open_tempfile(NULL, pool); svn_txdelta_stream_t *txdelta_stream; svn_txdelta_window_handler_t handler; svn_stream_t *stream; void *handler_baton; /* Set up a four-stage pipeline: create a delta, convert it to svndiff format, parse it back into delta format, and apply it to a copy of the source file to see if we get the same target back. */ apr_pool_t *delta_pool = svn_pool_create(pool); /* Make stage 4: apply the text delta. */ svn_txdelta_apply(svn_stream_from_aprfile(source_copy, delta_pool), svn_stream_from_aprfile(target_regen, delta_pool), NULL, NULL, delta_pool, &handler, &handler_baton); /* Make stage 3: reparse the text delta. */ stream = svn_txdelta_parse_svndiff(handler, handler_baton, TRUE, delta_pool); /* Make stage 2: encode the text delta in svndiff format using varying compression levels. */ svn_txdelta_to_svndiff3(&handler, &handler_baton, stream, 1, i % 10, delta_pool); /* Make stage 1: create the text delta. */ svn_txdelta2(&txdelta_stream, svn_stream_from_aprfile(source, delta_pool), svn_stream_from_aprfile(target, delta_pool), FALSE, delta_pool); SVN_ERR(svn_txdelta_send_txstream(txdelta_stream, handler, handler_baton, delta_pool)); svn_pool_destroy(delta_pool); SVN_ERR(compare_files(target, target_regen, dump_files)); apr_file_close(source); apr_file_close(target); apr_file_close(source_copy); apr_file_close(target_regen); } return SVN_NO_ERROR; }