1 /* vdelta-test.c -- test driver for text deltas
2  *
3  * ====================================================================
4  *    Licensed to the Apache Software Foundation (ASF) under one
5  *    or more contributor license agreements.  See the NOTICE file
6  *    distributed with this work for additional information
7  *    regarding copyright ownership.  The ASF licenses this file
8  *    to you under the Apache License, Version 2.0 (the
9  *    "License"); you may not use this file except in compliance
10  *    with the License.  You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  *    Unless required by applicable law or agreed to in writing,
15  *    software distributed under the License is distributed on an
16  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  *    KIND, either express or implied.  See the License for the
18  *    specific language governing permissions and limitations
19  *    under the License.
20  * ====================================================================
21  */
22 
23 #define APR_WANT_STDIO
24 #include <apr_want.h>
25 
26 #include <apr_general.h>
27 #include <assert.h>
28 
29 #include "../svn_test.h"
30 
31 #include "svn_ctype.h"
32 #include "svn_delta.h"
33 #include "svn_error.h"
34 #include "svn_pools.h"
35 
36 #include "../../libsvn_delta/delta.h"
37 #include "delta-window-test.h"
38 
39 static apr_off_t
print_delta_window(const svn_txdelta_window_t * window,const char * tag,int quiet,FILE * stream)40 print_delta_window(const svn_txdelta_window_t *window,
41                    const char *tag, int quiet, FILE *stream)
42 {
43   if (quiet)
44     return delta_window_size_estimate(window);
45   else
46     return delta_window_print(window, tag, stream);
47 }
48 
49 
50 static void
do_one_diff(apr_file_t * source_file,apr_file_t * target_file,int * count,apr_off_t * len,int quiet,apr_pool_t * pool,const char * tag,FILE * stream)51 do_one_diff(apr_file_t *source_file, apr_file_t *target_file,
52             int *count, apr_off_t *len,
53             int quiet, apr_pool_t *pool,
54             const char *tag, FILE* stream)
55 {
56   svn_txdelta_stream_t *delta_stream = NULL;
57   svn_txdelta_window_t *delta_window = NULL;
58   apr_pool_t *fpool = svn_pool_create(pool);
59   apr_pool_t *wpool = svn_pool_create(pool);
60 
61   *count = 0;
62   *len = 0;
63   svn_txdelta2(&delta_stream,
64                svn_stream_from_aprfile(source_file, fpool),
65                svn_stream_from_aprfile(target_file, fpool),
66                FALSE,
67                fpool);
68   do {
69     svn_error_t *err;
70     err = svn_txdelta_next_window(&delta_window, delta_stream, wpool);
71     if (err)
72       svn_handle_error2(err, stderr, TRUE, "vdelta-test: ");
73     if (delta_window != NULL)
74       {
75         *len += print_delta_window(delta_window, tag, quiet, stream);
76         svn_pool_clear(wpool);
77         ++*count;
78       }
79   } while (delta_window != NULL);
80   fprintf(stream, "%s: (LENGTH %" APR_OFF_T_FMT " +%d)\n", tag, *len, *count);
81 
82   svn_pool_destroy(fpool);
83   svn_pool_destroy(wpool);
84 }
85 
86 
87 static void
do_one_test_cycle(apr_file_t * source_file_A,apr_file_t * target_file_A,apr_file_t * source_file_B,apr_file_t * target_file_B,int quiet,apr_pool_t * pool)88 do_one_test_cycle(apr_file_t *source_file_A, apr_file_t *target_file_A,
89                   apr_file_t *source_file_B, apr_file_t *target_file_B,
90                   int quiet, apr_pool_t *pool)
91 {
92   int count_A = 0;
93   apr_off_t len_A = 0;
94 
95   int count_B = 0;
96   apr_off_t len_B = 0;
97 
98   do_one_diff(source_file_A, target_file_A,
99               &count_A, &len_A, quiet, pool, "A ", stdout);
100 
101   if (source_file_B)
102     {
103       apr_pool_t *fpool = svn_pool_create(pool);
104       apr_pool_t *wpool = svn_pool_create(pool);
105       svn_txdelta_stream_t *stream_A = NULL;
106       svn_txdelta_stream_t *stream_B = NULL;
107       svn_txdelta_window_t *window_A = NULL;
108       svn_txdelta_window_t *window_B = NULL;
109       svn_txdelta_window_t *window_AB = NULL;
110       int count_AB = 0;
111       apr_off_t len_AB = 0;
112 
113       putc('\n', stdout);
114       do_one_diff(source_file_B, target_file_B,
115                   &count_B, &len_B, quiet, pool, "B ", stdout);
116 
117       putc('\n', stdout);
118 
119       {
120         apr_off_t offset = 0;
121 
122         apr_file_seek(source_file_A, APR_SET, &offset);
123         apr_file_seek(target_file_A, APR_SET, &offset);
124         apr_file_seek(source_file_B, APR_SET, &offset);
125         apr_file_seek(target_file_B, APR_SET, &offset);
126       }
127 
128       svn_txdelta2(&stream_A,
129                    svn_stream_from_aprfile(source_file_A, fpool),
130                    svn_stream_from_aprfile(target_file_A, fpool),
131                    FALSE,
132                    fpool);
133       svn_txdelta2(&stream_B,
134                    svn_stream_from_aprfile(source_file_B, fpool),
135                    svn_stream_from_aprfile(target_file_B, fpool),
136                    FALSE,
137                    fpool);
138 
139       for (count_AB = 0; count_AB < count_B; ++count_AB)
140         {
141           svn_error_t *err;
142 
143           err = svn_txdelta_next_window(&window_A, stream_A, wpool);
144           if (err)
145             svn_handle_error2(err, stderr, TRUE, "vdelta-test: ");
146           err = svn_txdelta_next_window(&window_B, stream_B, wpool);
147           if (err)
148             svn_handle_error2(err, stderr, TRUE, "vdelta-test: ");
149 
150           /* Note: It's not possible that window_B is null, we already
151              counted the number of windows in the second delta. */
152           assert(window_A != NULL || window_B->src_ops == 0);
153           if (window_B->src_ops == 0)
154             {
155               window_AB = window_B;
156               window_AB->sview_len = 0;
157             }
158           else
159             window_AB = svn_txdelta_compose_windows(window_A, window_B,
160                                                     wpool);
161           len_AB += print_delta_window(window_AB, "AB", quiet, stdout);
162           svn_pool_clear(wpool);
163         }
164 
165       fprintf(stdout, "AB: (LENGTH %" APR_OFF_T_FMT " +%d)\n",
166               len_AB, count_AB);
167     }
168 }
169 
170 
171 static apr_file_t *
open_binary_read(const char * path,apr_pool_t * pool)172 open_binary_read(const char *path, apr_pool_t *pool)
173 {
174   apr_status_t apr_err;
175   apr_file_t *fp;
176 
177   apr_err = apr_file_open(&fp, path, (APR_READ | APR_BINARY),
178                           APR_OS_DEFAULT, pool);
179 
180   if (apr_err)
181     {
182       fprintf(stderr, "unable to open \"%s\" for reading\n", path);
183       exit(1);
184     }
185 
186   return fp;
187 }
188 
189 
190 int
main(int argc,char ** argv)191 main(int argc, char **argv)
192 {
193   apr_file_t *source_file_A = NULL;
194   apr_file_t *target_file_A = NULL;
195 
196   apr_file_t *source_file_B = NULL;
197   apr_file_t *target_file_B = NULL;
198 
199   apr_pool_t *pool;
200   int quiet = 0;
201   int repeat = 1;
202 
203   while (argc > 1)
204     {
205       const char *const arg = argv[1];
206       if (arg[0] != '-')
207         break;
208 
209       if (arg[1] == 'q')
210         quiet = 1;
211       else if (svn_ctype_isdigit(arg[1]))
212         repeat = atoi(arg + 1);
213       else
214         break;
215       --argc; ++argv;
216     }
217 
218   apr_initialize();
219   pool = svn_pool_create(NULL);
220 
221   if (argc == 2)
222     {
223       target_file_A = open_binary_read(argv[1], pool);
224     }
225   else if (argc == 3)
226     {
227       source_file_A = open_binary_read(argv[1], pool);
228       target_file_A = open_binary_read(argv[2], pool);
229     }
230   else if (argc == 4)
231     {
232       source_file_A = open_binary_read(argv[1], pool);
233       target_file_A = open_binary_read(argv[2], pool);
234       source_file_B = open_binary_read(argv[2], pool);
235       target_file_B = open_binary_read(argv[3], pool);
236     }
237   else
238     {
239       fprintf(stderr,
240               "Usage: vdelta-test [-q] [-<repeat>] <target>\n"
241               "   or: vdelta-test [-q] [-<repeat>] <source> <target>\n"
242               "   or: vdelta-test [-q] [-<repeat>] "
243               "<source> <intermediate> <target>\n");
244       exit(1);
245     }
246 
247   while (0 < repeat--)
248     {
249       apr_off_t offset = 0;
250 
251       do_one_test_cycle(source_file_A, target_file_A,
252                         source_file_B, target_file_B,
253                         quiet, pool);
254 
255       if (source_file_A) apr_file_seek(source_file_A, APR_SET, &offset);
256       if (target_file_A) apr_file_seek(target_file_A, APR_SET, &offset);
257       if (source_file_B) apr_file_seek(source_file_B, APR_SET, &offset);
258       if (target_file_B) apr_file_seek(target_file_B, APR_SET, &offset);
259     }
260 
261   if (source_file_A) apr_file_close(source_file_A);
262   if (target_file_A) apr_file_close(target_file_A);
263   if (source_file_B) apr_file_close(source_file_B);
264   if (target_file_B) apr_file_close(source_file_B);
265 
266   svn_pool_destroy(pool);
267   apr_terminate();
268   exit(0);
269 }
270