1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2016 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.1 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available at through the world-wide-web at |
10 | http://www.php.net/license/3_1.txt. |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Marcin Gibula <mg@iceni.pl> |
16 +----------------------------------------------------------------------+
17
18 $Id$
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "php.h"
26 #include "php_ini.h"
27 #include "ext/standard/info.h"
28 #include "php_xdiff.h"
29
30 #ifndef ZEND_ARG_INFO_WITH_DEFAULT_VALUE
31 #define ZEND_ARG_INFO_WITH_DEFAULT_VALUE(pass_by_ref, name, default_value) \
32 ZEND_ARG_INFO(pass_by_ref, name)
33 #endif
34 #if PHP_VERSION_ID < 70200
35 #undef ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX
36 #define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, class_name, allow_null) \
37 static const zend_internal_arg_info name[] = { \
38 { (const char*)(zend_uintptr_t)(required_num_args), ( #class_name ), 0, return_reference, allow_null, 0 },
39 #endif
40
41 #ifndef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX
42 #define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(name, return_reference, required_num_args, class_name, allow_null) \
43 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, class_name, allow_null)
44 #endif
45
46 #ifndef ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE
47 #define ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(pass_by_ref, name, type_hint, allow_null, default_value) \
48 ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null)
49 #endif
50
51 #include "xdiff_arginfo.h"
52
53 #ifdef PHP_WIN32
54 /* libxdiff is compiled with /Zp1 */
55 # pragma pack(push, 1)
56 #endif
57 #include <xdiff.h>
58 #ifdef PHP_WIN32
59 # pragma pack(pop)
60 #endif
61
62 /* Not exported by header file */
63 extern char libxdiff_version[];
64
65 struct string_buffer {
66 char *ptr;
67 unsigned long size;
68 };
69
70 static int load_mm_file(const char *filepath, mmfile_t *dest);
71 static int load_into_mm_file(const char *buffer, unsigned long size, mmfile_t *dest);
72 static int append_string(void *ptr, mmbuffer_t *buffer, int array_size);
73 static int append_stream(void *ptr, mmbuffer_t *buffer, int array_size);
74 static int init_string(struct string_buffer *string);
75 static void free_string(struct string_buffer *string);
76 static void invalidate_string(struct string_buffer *string);
77
78 static int make_diff(char *filepath1, char *filepath2, xdemitcb_t *output, int context, int minimal);
79 static int make_diff_str(char *str1, int size1, char *str2, int size2, xdemitcb_t *output, int context, int minimal);
80 static int make_bdiff(char *filepath1, char *filepath2, xdemitcb_t *output);
81 static int make_bdiff_str(char *str1, int size1, char *str2, int size2, xdemitcb_t *output);
82 static int make_patch(char *file_path, char *patch_path, xdemitcb_t *output, xdemitcb_t *error, int flags);
83 static int make_patch_str(char *file, int size1, char *patch, int size2, xdemitcb_t *output, xdemitcb_t *error, int flags);
84 static int make_bpatch(char *file_path, char *patch_path, xdemitcb_t *output);
85 static int make_bpatch_str(char *file, int size1, char *patch, int size2, xdemitcb_t *output);
86 static int make_merge3(char *filepath1, char *filepath2, char *filepath3, xdemitcb_t *output, xdemitcb_t *error);
87 static int make_merge3_str(char *content1, int size1, char *content2, int size2, char *content3, int size3, xdemitcb_t *output, xdemitcb_t *error);
88 static int make_rabdiff(char *filepath1, char *filepath2, xdemitcb_t *output);
89 static int make_rabdiff_str(char *str1, int size1, char *str2, int size2, xdemitcb_t *output);
90
xdiff_malloc(void * foo,unsigned int size)91 static void *xdiff_malloc(void *foo, unsigned int size)
92 {
93 return emalloc(size);
94 }
95
xdiff_free(void * foo,void * ptr)96 static void xdiff_free(void *foo, void *ptr)
97 {
98 if (ptr) {
99 efree(ptr);
100 }
101 }
102
xdiff_realloc(void * foo,void * ptr,unsigned int nsize)103 static void *xdiff_realloc(void *foo, void *ptr, unsigned int nsize)
104 {
105 return erealloc(ptr, nsize);
106 }
107
108 static memallocator_t allocator = { NULL, xdiff_malloc, xdiff_free, xdiff_realloc };
109
110 /* {{{ xdiff_module_entry
111 */
112 zend_module_entry xdiff_module_entry = {
113 #if ZEND_MODULE_API_NO >= 20010901
114 STANDARD_MODULE_HEADER,
115 #endif
116 "xdiff",
117 ext_functions,
118 PHP_MINIT(xdiff),
119 NULL,
120 NULL,
121 NULL,
122 PHP_MINFO(xdiff),
123 #if ZEND_MODULE_API_NO >= 20010901
124 PHP_XDIFF_VERSION,
125 #endif
126 STANDARD_MODULE_PROPERTIES
127 };
128 /* }}} */
129
130 #ifdef COMPILE_DL_XDIFF
131 ZEND_GET_MODULE(xdiff)
132 #endif
133
134 /* {{{ PHP_MINIT_FUNCTION
135 */
PHP_MINIT_FUNCTION(xdiff)136 PHP_MINIT_FUNCTION(xdiff)
137 {
138 xdl_set_allocator(&allocator);
139
140 REGISTER_LONG_CONSTANT("XDIFF_PATCH_NORMAL", XDL_PATCH_NORMAL, CONST_CS | CONST_PERSISTENT);
141 REGISTER_LONG_CONSTANT("XDIFF_PATCH_REVERSE", XDL_PATCH_REVERSE, CONST_CS | CONST_PERSISTENT);
142 REGISTER_LONG_CONSTANT("XDIFF_PATCH_IGNORESPACE", XDL_PATCH_IGNOREBSPACE, CONST_CS | CONST_PERSISTENT);
143
144 return SUCCESS;
145 }
146 /* }}} */
147
148 /* {{{ PHP_MINFO_FUNCTION
149 */
PHP_MINFO_FUNCTION(xdiff)150 PHP_MINFO_FUNCTION(xdiff)
151 {
152 php_info_print_table_start();
153 php_info_print_table_header(2, "xdiff support", "enabled");
154 php_info_print_table_row(2, "extension version", PHP_XDIFF_VERSION);
155 php_info_print_table_row(2, "libxdiff version", libxdiff_version);
156 php_info_print_table_end();
157 }
158 /* }}} */
159
160 /* {{{ proto mixed xdiff_string_diff(string str1, string str2, [int context, [bool minimal]])
161 */
PHP_FUNCTION(xdiff_string_diff)162 PHP_FUNCTION(xdiff_string_diff)
163 {
164 zend_string *str1, *str2;
165 int retval;
166 zend_bool minimal = 0;
167 zend_long context = 3;
168 xdemitcb_t output;
169 struct string_buffer string;
170
171 if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|lb", &str1, &str2, &context, &minimal) == FAILURE) {
172 RETURN_FALSE;
173 }
174
175 RETVAL_FALSE;
176
177 retval = init_string(&string);
178 if (!retval)
179 goto out;
180
181 output.priv= &string;
182 output.outf = append_string;
183
184 make_diff_str(str1->val, str1->len, str2->val, str2->len, &output, context, minimal);
185 RETVAL_STRINGL(string.ptr, string.size);
186 free_string(&string);
187 out:
188 return;
189 }
190 /* }}} */
191
192 /* {{{ proto bool xdiff_file_diff(string file1, string file2, string dest, [int context, [bool minimal]])
193 */
PHP_FUNCTION(xdiff_file_diff)194 PHP_FUNCTION(xdiff_file_diff)
195 {
196 zend_string *filepath1, *filepath2, *dest;
197 int retval;
198 zend_bool minimal = 0;
199 zend_long context = 3;
200 xdemitcb_t output;
201 php_stream *output_stream;
202
203 if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSS|lb", &filepath1, &filepath2, &dest, &context, &minimal) == FAILURE) {
204 RETURN_FALSE;
205 }
206
207 RETVAL_FALSE;
208
209 output_stream = php_stream_open_wrapper(dest->val, "wb", REPORT_ERRORS, NULL);
210 if (!output_stream)
211 goto out;
212
213 output.priv = output_stream;
214 output.outf = append_stream;
215
216 retval = make_diff(filepath1->val, filepath2->val, &output, context, minimal);
217 if (!retval)
218 goto out_stream_close;
219
220 RETVAL_TRUE;
221
222 out_stream_close:
223 php_stream_close(output_stream);
224 out:
225 return;
226 }
227 /* }}} */
228
229 /* {{{ proto mixed xdiff_string_diff_binary(string str1, string str2)
230 */
PHP_FUNCTION(xdiff_string_bdiff)231 PHP_FUNCTION(xdiff_string_bdiff)
232 {
233 zend_string *str1, *str2;
234 int retval;
235 xdemitcb_t output;
236 struct string_buffer string;
237
238 if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &str1, &str2) == FAILURE) {
239 RETURN_FALSE;
240 }
241
242 RETVAL_FALSE;
243
244 retval = init_string(&string);
245 if (!retval)
246 goto out;
247
248 output.priv= &string;
249 output.outf = append_string;
250
251 make_bdiff_str(str1->val, str1->len, str2->val, str2->len, &output);
252 RETVAL_STRINGL(string.ptr, string.size);
253 free_string(&string);
254
255 out:
256 return;
257 }
258 /* }}} */
259
260 /* {{{ proto bool xdiff_file_diff_binary(string file1, string file2, string dest)
261 */
PHP_FUNCTION(xdiff_file_bdiff)262 PHP_FUNCTION(xdiff_file_bdiff)
263 {
264 zend_string *filepath1, *filepath2, *result;
265 int retval;
266 xdemitcb_t output;
267 php_stream *output_stream;
268
269 if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSS", &filepath1, &filepath2, &result) == FAILURE) {
270 RETURN_FALSE;
271 }
272
273 RETVAL_FALSE;
274
275 output_stream = php_stream_open_wrapper(result->val, "wb", REPORT_ERRORS, NULL);
276 if (!output_stream)
277 goto out;
278
279 output.priv = output_stream;
280 output.outf = append_stream;
281
282 retval = make_bdiff(filepath1->val, filepath2->val, &output);
283 if (!retval)
284 goto out_stream_close;
285
286 RETVAL_TRUE;
287
288 out_stream_close:
289 php_stream_close(output_stream);
290 out:
291 return;
292 }
293 /* }}} */
294
295 /* {{{ proto mixed xdiff_string_rabdiff(string str1, string str2)
296 */
PHP_FUNCTION(xdiff_string_rabdiff)297 PHP_FUNCTION(xdiff_string_rabdiff)
298 {
299 zend_string *str1, *str2;
300 int retval;
301 xdemitcb_t output;
302 struct string_buffer string;
303
304 if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &str1, &str2) == FAILURE) {
305 RETURN_FALSE;
306 }
307
308 RETVAL_FALSE;
309
310 retval = init_string(&string);
311 if (!retval)
312 goto out;
313
314 output.priv= &string;
315 output.outf = append_string;
316
317 make_rabdiff_str(str1->val, str1->len, str2->val, str2->len, &output);
318 RETVAL_STRINGL(string.ptr, string.size);
319 free_string(&string);
320
321 out:
322 return;
323 }
324 /* }}} */
325
326 /* {{{ proto bool xdiff_file_rabdiff(string file1, string file2, string dest)
327 */
PHP_FUNCTION(xdiff_file_rabdiff)328 PHP_FUNCTION(xdiff_file_rabdiff)
329 {
330 zend_string *filepath1, *filepath2, *result;
331 int retval;
332 xdemitcb_t output;
333 php_stream *output_stream;
334
335 if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSS", &filepath1, &filepath2, &result) == FAILURE) {
336 RETURN_FALSE;
337 }
338
339 RETVAL_FALSE;
340
341 output_stream = php_stream_open_wrapper(result->val, "wb", REPORT_ERRORS, NULL);
342 if (!output_stream)
343 goto out;
344
345 output.priv = output_stream;
346 output.outf = append_stream;
347
348 retval = make_rabdiff(filepath1->val, filepath2->val, &output);
349 if (!retval)
350 goto out_stream_close;
351
352 RETVAL_TRUE;
353
354 out_stream_close:
355 php_stream_close(output_stream);
356 out:
357 return;
358 }
359 /* }}} */
360
361 /* {{{ proto bool xdiff_file_bdiff_size(string file1, string file2, string dest)
362 */
PHP_FUNCTION(xdiff_file_bdiff_size)363 PHP_FUNCTION(xdiff_file_bdiff_size)
364 {
365 zend_string *filepath;
366 int retval;
367 long result;
368 mmfile_t file;
369
370 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &filepath) == FAILURE) {
371 RETURN_FALSE;
372 }
373
374 RETVAL_FALSE;
375
376 retval = load_mm_file(filepath->val, &file);
377 if (!retval)
378 goto out;
379
380 result = xdl_bdiff_tgsize(&file);
381 if (result < 0)
382 goto out_free_mmfile;
383
384 RETVAL_LONG(result);
385
386 out_free_mmfile:
387 xdl_free_mmfile(&file);
388 out:
389 return;
390 }
391 /* }}} */
392
393 /* {{{ proto bool xdiff_string_bdiff_size(string file1, string file2, string dest)
394 */
PHP_FUNCTION(xdiff_string_bdiff_size)395 PHP_FUNCTION(xdiff_string_bdiff_size)
396 {
397 zend_string *patch;
398 int retval;
399 long result;
400 mmfile_t file;
401
402 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &patch) == FAILURE) {
403 RETURN_FALSE;
404 }
405
406 RETVAL_FALSE;
407
408 retval = load_into_mm_file(patch->val, patch->len, &file);
409 if (!retval)
410 goto out;
411
412 result = xdl_bdiff_tgsize(&file);
413 if (result < 0)
414 goto out_free_mmfile;
415
416 RETVAL_LONG(result);
417
418 out_free_mmfile:
419 xdl_free_mmfile(&file);
420 out:
421 return;
422 }
423 /* }}} */
424
425 /* {{{ proto mixed xdiff_file_patch(string file, string patch, string dest [, int flags])
426 */
PHP_FUNCTION(xdiff_file_patch)427 PHP_FUNCTION(xdiff_file_patch)
428 {
429 php_stream *output_stream;
430 zend_string *src_path, *patch_path, *dest_path;
431 int retval;
432 zend_long flags = XDL_PATCH_NORMAL; /* DIFF_PATCH_NORMAL */
433 xdemitcb_t output, error_output;
434 struct string_buffer error_string;
435
436 if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSS|l", &src_path, &patch_path, &dest_path, &flags) == FAILURE) {
437 RETURN_FALSE;
438 }
439
440 RETVAL_FALSE;
441
442 output_stream = php_stream_open_wrapper(dest_path->val, "wb", REPORT_ERRORS, NULL);
443 if (!output_stream)
444 goto out;
445
446 output.outf = append_stream;
447 output.priv = output_stream;
448
449 retval = init_string(&error_string);
450 if (!retval)
451 goto out_stream_close;
452
453 error_output.priv= &error_string;
454 error_output.outf = append_string;
455
456 retval = make_patch(src_path->val, patch_path->val, &output, &error_output, flags);
457 if (retval < 0)
458 goto out_free_string;
459
460 if (error_string.size > 0) {
461 RETVAL_STRINGL(error_string.ptr, error_string.size);
462 } else {
463 RETVAL_TRUE;
464 }
465
466 out_free_string:
467 free_string(&error_string);
468 out_stream_close:
469 php_stream_close(output_stream);
470 out:
471 return;
472 }
473 /* }}} */
474
475 /* {{{ proto string xdiff_string_patch(string file, string patch [, int flags, [string error]])
476 */
PHP_FUNCTION(xdiff_string_patch)477 PHP_FUNCTION(xdiff_string_patch)
478 {
479 zval *error_ref = NULL;
480 zend_string *src, *patch;
481 int retval;
482 zend_long flags = XDL_PATCH_NORMAL; /* DIFF_PATCH_NORMAL */
483 xdemitcb_t output, error_output;
484 struct string_buffer output_string, error_string;
485
486 if (zend_parse_parameters_ex(0, ZEND_NUM_ARGS(), "SS|lz", &src, &patch, &flags, &error_ref) == FAILURE) {
487 RETURN_FALSE;
488 }
489
490 RETVAL_FALSE;
491
492 retval = init_string(&output_string);
493 if (!retval)
494 goto out;
495
496 output.priv = &output_string;
497 output.outf = append_string;
498
499 retval = init_string(&error_string);
500 if (!retval)
501 goto out_free_output_string;
502
503 error_output.priv= &error_string;
504 error_output.outf = append_string;
505
506 retval = make_patch_str(src->val, src->len, patch->val, patch->len, &output, &error_output, flags);
507 if (retval < 0)
508 goto out_free_error_string;
509
510 if (error_string.size > 0 && error_ref) {
511 ZVAL_STRINGL(error_ref, error_string.ptr, error_string.size);
512 }
513
514 if (output_string.size > 0) {
515 RETVAL_STRINGL(output_string.ptr, output_string.size);
516 } else {
517 RETVAL_EMPTY_STRING();
518 }
519
520 out_free_error_string:
521 free_string(&error_string);
522 out_free_output_string:
523 free_string(&output_string);
524 out:
525 return;
526 }
527 /* }}} */
528
529 /* {{{ proto bool xdiff_file_patch_binary(string file, string patch, string dest)
530 */
PHP_FUNCTION(xdiff_file_bpatch)531 PHP_FUNCTION(xdiff_file_bpatch)
532 {
533 php_stream *output_stream;
534 zend_string *src_path, *patch_path, *dest_path;
535 int retval;
536 xdemitcb_t output;
537
538 if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSS", &src_path, &patch_path, &dest_path) == FAILURE) {
539 RETURN_FALSE;
540 }
541
542 RETVAL_FALSE;
543
544 output_stream = php_stream_open_wrapper(dest_path->val, "wb", REPORT_ERRORS, NULL);
545 if (!output_stream)
546 goto out;
547
548 output.outf = append_stream;
549 output.priv = output_stream;
550
551 retval = make_bpatch(src_path->val, patch_path->val, &output);
552 php_stream_close(output_stream);
553
554 if (retval == 0)
555 RETVAL_TRUE;
556
557 out:
558 return;
559 }
560 /* }}} */
561
562 /* {{{ proto string xdiff_string_patch_binary(string str, string patch)
563 */
PHP_FUNCTION(xdiff_string_bpatch)564 PHP_FUNCTION(xdiff_string_bpatch)
565 {
566 zend_string *src, *patch;
567 int retval;
568 xdemitcb_t output;
569 struct string_buffer output_string;
570
571 if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &src, &patch) == FAILURE) {
572 RETURN_FALSE;
573 }
574
575 RETVAL_FALSE;
576
577 retval = init_string(&output_string);
578 if (!retval)
579 goto out;
580
581 output.priv = &output_string;
582 output.outf = append_string;
583
584 retval = make_bpatch_str(src->val, src->len, patch->val, patch->len, &output);
585 if (retval < 0)
586 goto out_free_string;
587
588 RETVAL_STRINGL(output_string.ptr, output_string.size);
589
590 out_free_string:
591 free_string(&output_string);
592 out:
593 return;
594 }
595 /* }}} */
596
597 /* {{{ proto mixed xdiff_file_merge3(string file1, string file2, string file3, string dest)
598 */
PHP_FUNCTION(xdiff_file_merge3)599 PHP_FUNCTION(xdiff_file_merge3)
600 {
601 zend_string *file1, *file2, *file3, *dest;
602 php_stream *output_stream;
603 struct string_buffer string;
604 xdemitcb_t output, error_output;
605 int retval;
606
607 if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSSS", &file1, &file2, &file3, &dest) == FAILURE) {
608 RETURN_FALSE;
609 }
610
611 RETVAL_FALSE;
612
613 output_stream = php_stream_open_wrapper(dest->val, "wb", REPORT_ERRORS, NULL);
614 if (!output_stream)
615 goto out;
616
617 output.priv = output_stream;
618 output.outf = append_stream;
619
620 retval = init_string(&string);
621 if (!retval)
622 goto out_stream_close;
623
624 error_output.priv = &string;
625 error_output.outf = append_string;
626
627 retval = make_merge3(file1->val, file2->val, file3->val, &output, &error_output);
628 if (!retval)
629 goto out_free_string;
630
631 if (string.size > 0) {
632 RETVAL_STRINGL(string.ptr, string.size);
633 } else {
634 RETVAL_TRUE;
635 }
636
637 out_free_string:
638 free_string(&string);
639 out_stream_close:
640 php_stream_close(output_stream);
641 out:
642 return;
643 }
644 /* }}} */
645
646 /* {{{ proto string xdiff_string_merge3(string str1, string str2, string str3 [, string error])
647 */
PHP_FUNCTION(xdiff_string_merge3)648 PHP_FUNCTION(xdiff_string_merge3)
649 {
650 zval *error_ref = NULL;
651 zend_string *file1, *file2, *file3;
652 struct string_buffer output_string, error_string;
653 xdemitcb_t output, error_output;
654 int retval;
655
656 if (zend_parse_parameters_ex(0, ZEND_NUM_ARGS(), "SSS|z", &file1, &file2, &file3, &error_ref) == FAILURE) {
657 RETURN_FALSE;
658 }
659
660 RETVAL_FALSE;
661
662 retval = init_string(&output_string);
663 if (!retval)
664 goto out;
665
666 output.priv = &output_string;
667 output.outf = append_string;
668
669 retval = init_string(&error_string);
670 if (!retval)
671 goto out_free_output_string;
672
673 error_output.priv = &error_string;
674 error_output.outf = append_string;
675
676 retval = make_merge3_str(file1->val, file1->len, file2->val, file2->len, file3->val, file3->len, &output, &error_output);
677 if (!retval)
678 goto out_free_error_string;
679
680 if (error_string.size > 0 && error_ref) {
681 ZVAL_STRINGL(error_ref, error_string.ptr, error_string.size);
682 }
683
684 if (output_string.size > 0) {
685 RETVAL_STRINGL(output_string.ptr, output_string.size);
686 } else {
687 RETVAL_TRUE;
688 }
689
690 out_free_error_string:
691 free_string(&error_string);
692 out_free_output_string:
693 free_string(&output_string);
694 out:
695 return;
696 }
697 /* }}} */
698
load_mm_file(const char * filepath,mmfile_t * dest)699 static int load_mm_file(const char *filepath, mmfile_t *dest)
700 {
701 int retval;
702 off_t filesize;
703 void *ptr;
704 php_stream *src;
705 php_stream_statbuf stat;
706
707 src = php_stream_open_wrapper((char *) filepath, "rb", REPORT_ERRORS, NULL);
708 if (!src)
709 goto out;
710
711 retval = php_stream_stat(src, &stat);
712 if (retval < 0)
713 goto out_stream_close;
714
715 filesize = stat.sb.st_size;
716
717 retval = xdl_init_mmfile(dest, filesize, XDL_MMF_ATOMIC);
718 if (retval < 0)
719 goto out_stream_close;
720
721 ptr = xdl_mmfile_writeallocate(dest, (long) filesize);
722 if (!ptr)
723 goto out_free_mmfile;
724
725 php_stream_read(src, ptr, filesize);
726 php_stream_close(src);
727
728 return 1;
729
730 out_free_mmfile:
731 xdl_free_mmfile(dest);
732 out_stream_close:
733 php_stream_close(src);
734 out:
735 return 0;
736 }
737
load_into_mm_file(const char * buffer,unsigned long size,mmfile_t * dest)738 static int load_into_mm_file(const char *buffer, unsigned long size, mmfile_t *dest)
739 {
740 int retval;
741 void *ptr;
742
743 retval = xdl_init_mmfile(dest, size, XDL_MMF_ATOMIC);
744 if (retval < 0)
745 goto out;
746
747 ptr = xdl_mmfile_writeallocate(dest, (long) size);
748 if (!ptr)
749 goto out_free_mmfile;
750
751 memcpy(ptr, buffer, size);
752 return 1;
753
754 out_free_mmfile:
755 xdl_free_mmfile(dest);
756 out:
757 return 0;
758 }
759
append_string(void * ptr,mmbuffer_t * buffer,int array_size)760 static int append_string(void *ptr, mmbuffer_t *buffer, int array_size)
761 {
762 struct string_buffer *string = ptr;
763 void *new_ptr;
764 unsigned int i;
765
766 for (i = 0; i < array_size; i++) {
767 new_ptr = erealloc(string->ptr, string->size + buffer[i].size + 1);
768 if (!new_ptr) {
769 efree(string->ptr);
770 return -1;
771 }
772
773 string->ptr = new_ptr;
774 memcpy(string->ptr + string->size, buffer[i].ptr, buffer[i].size);
775 string->size += buffer[i].size;
776 }
777 if (array_size) {
778 string->ptr[string->size] = '\0';
779 }
780
781 return 0;
782 }
783
append_stream(void * ptr,mmbuffer_t * buffer,int array_size)784 static int append_stream(void *ptr, mmbuffer_t *buffer, int array_size)
785 {
786 php_stream *stream = ptr;
787 unsigned int i;
788
789 for (i = 0; i < array_size; i++) {
790 php_stream_write(stream, buffer[i].ptr, buffer[i].size);
791 }
792
793 return 1;
794 }
795
init_string(struct string_buffer * string)796 static int init_string(struct string_buffer *string)
797 {
798 string->ptr = emalloc(1);
799 if (!string->ptr)
800 return 0;
801
802 string->size = 0;
803 memset(string->ptr, 0, 1);
804
805 return 1;
806 }
807
invalidate_string(struct string_buffer * string)808 static void invalidate_string(struct string_buffer *string)
809 {
810 string->ptr = NULL;
811 }
812
free_string(struct string_buffer * string)813 static void free_string(struct string_buffer *string)
814 {
815 if (string->ptr)
816 efree(string->ptr);
817 }
818
make_diff(char * filepath1,char * filepath2,xdemitcb_t * output,int context,int minimal)819 static int make_diff(char *filepath1, char *filepath2, xdemitcb_t *output, int context, int minimal)
820 {
821 mmfile_t file1, file2;
822 xpparam_t params;
823 xdemitconf_t conf;
824 int retval, result = 0;
825
826 retval = load_mm_file(filepath1, &file1);
827 if (!retval)
828 goto out;
829
830 retval = load_mm_file(filepath2, &file2);
831 if (!retval)
832 goto out_free_mmfile;
833
834 params.flags = (minimal) ? XDF_NEED_MINIMAL : 0;
835 conf.ctxlen = abs(context);
836
837 retval = xdl_diff(&file1, &file2, ¶ms, &conf, output);
838 if (retval < 0)
839 goto out_free_mmfile2;
840
841 result = 1;
842
843 out_free_mmfile2:
844 xdl_free_mmfile(&file2);
845 out_free_mmfile:
846 xdl_free_mmfile(&file1);
847 out:
848 return result;
849 }
850
make_diff_str(char * str1,int size1,char * str2,int size2,xdemitcb_t * output,int context,int minimal)851 static int make_diff_str(char *str1, int size1, char *str2, int size2, xdemitcb_t *output, int context, int minimal)
852 {
853 mmfile_t file1, file2;
854 xpparam_t params;
855 xdemitconf_t conf;
856 int retval, result = 0;
857
858 retval = load_into_mm_file(str1, size1, &file1);
859 if (!retval)
860 goto out;
861
862 retval = load_into_mm_file(str2, size2, &file2);
863 if (!retval)
864 goto out_free_mmfile;
865
866 params.flags = (minimal) ? XDF_NEED_MINIMAL : 0;
867 conf.ctxlen = abs(context);
868
869 retval = xdl_diff(&file1, &file2, ¶ms, &conf, output);
870 if (retval < 0)
871 goto out_free_mmfile2;
872
873 result = 1;
874
875 out_free_mmfile2:
876 xdl_free_mmfile(&file2);
877 out_free_mmfile:
878 xdl_free_mmfile(&file1);
879 out:
880 return result;
881 }
882
make_bdiff(char * filepath1,char * filepath2,xdemitcb_t * output)883 static int make_bdiff(char *filepath1, char *filepath2, xdemitcb_t *output)
884 {
885 mmfile_t file1, file2;
886 bdiffparam_t params;
887 int retval, result = 0;
888
889 retval = load_mm_file(filepath1, &file1);
890 if (!retval)
891 goto out;
892
893 retval = load_mm_file(filepath2, &file2);
894 if (!retval)
895 goto out_free_mmfile;
896
897 params.bsize = 16;
898
899 retval = xdl_bdiff(&file1, &file2, ¶ms, output);
900 if (retval < 0)
901 goto out_free_mmfile2;
902
903 result = 1;
904
905 out_free_mmfile2:
906 xdl_free_mmfile(&file2);
907 out_free_mmfile:
908 xdl_free_mmfile(&file1);
909 out:
910 return result;
911 }
912
make_bdiff_str(char * str1,int size1,char * str2,int size2,xdemitcb_t * output)913 static int make_bdiff_str(char *str1, int size1, char *str2, int size2, xdemitcb_t *output)
914 {
915 mmfile_t file1, file2;
916 bdiffparam_t params;
917 int retval, result = 0;
918
919 retval = load_into_mm_file(str1, size1, &file1);
920 if (!retval)
921 goto out;
922
923 retval = load_into_mm_file(str2, size2, &file2);
924 if (!retval)
925 goto out_free_mmfile;
926
927 params.bsize = 16;
928
929 retval = xdl_bdiff(&file1, &file2, ¶ms, output);
930 if (retval < 0)
931 goto out_free_mmfile2;
932
933 result = 1;
934
935 out_free_mmfile2:
936 xdl_free_mmfile(&file2);
937 out_free_mmfile:
938 xdl_free_mmfile(&file1);
939 out:
940 return result;
941 }
942
make_rabdiff(char * filepath1,char * filepath2,xdemitcb_t * output)943 static int make_rabdiff(char *filepath1, char *filepath2, xdemitcb_t *output)
944 {
945 mmfile_t file1, file2;
946 int retval, result = 0;
947
948 retval = load_mm_file(filepath1, &file1);
949 if (!retval)
950 goto out;
951
952 retval = load_mm_file(filepath2, &file2);
953 if (!retval)
954 goto out_free_mmfile;
955
956 retval = xdl_rabdiff(&file1, &file2, output);
957 if (retval < 0)
958 goto out_free_mmfile2;
959
960 result = 1;
961
962 out_free_mmfile2:
963 xdl_free_mmfile(&file2);
964 out_free_mmfile:
965 xdl_free_mmfile(&file1);
966 out:
967 return result;
968 }
969
make_rabdiff_str(char * str1,int size1,char * str2,int size2,xdemitcb_t * output)970 static int make_rabdiff_str(char *str1, int size1, char *str2, int size2, xdemitcb_t *output)
971 {
972 mmfile_t file1, file2;
973 int retval, result = 0;
974
975 retval = load_into_mm_file(str1, size1, &file1);
976 if (!retval)
977 goto out;
978
979 retval = load_into_mm_file(str2, size2, &file2);
980 if (!retval)
981 goto out_free_mmfile;
982
983 retval = xdl_rabdiff(&file1, &file2, output);
984 if (retval < 0)
985 goto out_free_mmfile2;
986
987 result = 1;
988
989 out_free_mmfile2:
990 xdl_free_mmfile(&file2);
991 out_free_mmfile:
992 xdl_free_mmfile(&file1);
993 out:
994 return result;
995 }
996
make_patch(char * file_path,char * patch_path,xdemitcb_t * output,xdemitcb_t * error,int flags)997 static int make_patch(char *file_path, char *patch_path, xdemitcb_t *output, xdemitcb_t *error, int flags)
998 {
999 mmfile_t file, patch;
1000 int retval, result = 0;
1001
1002 retval = load_mm_file(file_path, &file);
1003 if (!retval)
1004 goto out;
1005
1006 retval = load_mm_file(patch_path, &patch);
1007 if (!retval)
1008 goto out_free_mmfile;
1009
1010 retval = xdl_patch(&file, &patch, flags, output, error);
1011 if (retval < 0)
1012 goto out_free_mmfile2;
1013
1014 result = 1;
1015
1016 out_free_mmfile2:
1017 xdl_free_mmfile(&patch);
1018 out_free_mmfile:
1019 xdl_free_mmfile(&file);
1020 out:
1021 return result;
1022 }
1023
make_patch_str(char * file,int size1,char * patch,int size2,xdemitcb_t * output,xdemitcb_t * error,int flags)1024 static int make_patch_str(char *file, int size1, char *patch, int size2, xdemitcb_t *output, xdemitcb_t *error, int flags)
1025 {
1026 mmfile_t file_mm, patch_mm;
1027 int retval, result = 0;
1028
1029 retval = load_into_mm_file(file, size1, &file_mm);
1030 if (!retval)
1031 goto out;
1032
1033 retval = load_into_mm_file(patch, size2, &patch_mm);
1034 if (!retval)
1035 goto out_free_mmfile;
1036
1037 retval = xdl_patch(&file_mm, &patch_mm, flags, output, error);
1038 if (retval < 0)
1039 goto out_free_mmfile2;
1040
1041 result = 1;
1042
1043 out_free_mmfile2:
1044 xdl_free_mmfile(&patch_mm);
1045 out_free_mmfile:
1046 xdl_free_mmfile(&file_mm);
1047 out:
1048 return result;
1049 }
1050
make_bpatch(char * file_path,char * patch_path,xdemitcb_t * output)1051 static int make_bpatch(char *file_path, char *patch_path, xdemitcb_t *output)
1052 {
1053 mmfile_t file_mm, patch_mm;
1054 int retval, result = 0;
1055
1056 retval = load_mm_file(file_path, &file_mm);
1057 if (!retval)
1058 goto out;
1059
1060 retval = load_mm_file(patch_path, &patch_mm);
1061 if (!retval)
1062 goto out_free_mmfile;
1063
1064 retval = xdl_bpatch(&file_mm, &patch_mm, output);
1065 if (retval < 0)
1066 goto out_free_mmfile2;
1067
1068 result = 1;
1069
1070 out_free_mmfile2:
1071 xdl_free_mmfile(&patch_mm);
1072 out_free_mmfile:
1073 xdl_free_mmfile(&file_mm);
1074 out:
1075 return result;
1076 }
1077
make_bpatch_str(char * file,int size1,char * patch,int size2,xdemitcb_t * output)1078 static int make_bpatch_str(char *file, int size1, char *patch, int size2, xdemitcb_t *output)
1079 {
1080 mmfile_t file_mm, patch_mm;
1081 int retval, result = 0;
1082
1083 retval = load_into_mm_file(file, size1, &file_mm);
1084 if (!retval)
1085 goto out;
1086
1087 retval = load_into_mm_file(patch, size2, &patch_mm);
1088 if (!retval)
1089 goto out_free_mmfile;
1090
1091 retval = xdl_bpatch(&file_mm, &patch_mm, output);
1092 if (retval < 0)
1093 goto out_free_mmfile2;
1094
1095 result = 1;
1096
1097 out_free_mmfile2:
1098 xdl_free_mmfile(&patch_mm);
1099 out_free_mmfile:
1100 xdl_free_mmfile(&file_mm);
1101 out:
1102 return result;
1103 }
1104
make_merge3(char * filepath1,char * filepath2,char * filepath3,xdemitcb_t * output,xdemitcb_t * error)1105 static int make_merge3(char *filepath1, char *filepath2, char *filepath3, xdemitcb_t *output, xdemitcb_t *error)
1106 {
1107 mmfile_t file1, file2, file3;
1108 int retval, result = 0;
1109
1110 retval = load_mm_file(filepath1, &file1);
1111 if (!retval)
1112 goto out;
1113
1114 retval = load_mm_file(filepath2, &file2);
1115 if (!retval)
1116 goto out_free_mmfile;
1117
1118 retval = load_mm_file(filepath3, &file3);
1119 if (!retval)
1120 goto out_free_mmfile2;
1121
1122 retval = xdl_merge3(&file1, &file2, &file3, output, error);
1123 if (retval < 0)
1124 goto out_free_mmfile3;
1125
1126 result = 1;
1127
1128 out_free_mmfile3:
1129 xdl_free_mmfile(&file3);
1130 out_free_mmfile2:
1131 xdl_free_mmfile(&file2);
1132 out_free_mmfile:
1133 xdl_free_mmfile(&file1);
1134 out:
1135 return result;
1136 }
1137
make_merge3_str(char * content1,int size1,char * content2,int size2,char * content3,int size3,xdemitcb_t * output,xdemitcb_t * error)1138 static int make_merge3_str(char *content1, int size1, char *content2, int size2, char *content3, int size3, xdemitcb_t *output, xdemitcb_t *error)
1139 {
1140 mmfile_t file1, file2, file3;
1141 int retval, result = 0;
1142
1143 retval = load_into_mm_file(content1, size1, &file1);
1144 if (!retval)
1145 goto out;
1146
1147 retval = load_into_mm_file(content2, size2, &file2);
1148 if (!retval)
1149 goto out_free_mmfile;
1150
1151 retval = load_into_mm_file(content3, size3, &file3);
1152 if (!retval)
1153 goto out_free_mmfile2;
1154
1155 retval = xdl_merge3(&file1, &file2, &file3, output, error);
1156 if (retval < 0)
1157 goto out_free_mmfile3;
1158
1159 result = 1;
1160
1161 out_free_mmfile3:
1162 xdl_free_mmfile(&file3);
1163 out_free_mmfile2:
1164 xdl_free_mmfile(&file2);
1165 out_free_mmfile:
1166 xdl_free_mmfile(&file1);
1167 out:
1168 return result;
1169 }
1170
1171 /*
1172 * Local variables:
1173 * tab-width: 4
1174 * c-basic-offset: 4
1175 * End:
1176 * vim600: noet sw=4 ts=4 fdm=marker
1177 * vim<600: noet sw=4 ts=4
1178 */
1179