ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/File-Rdiff/Rdiff.xs
Revision: 1.3
Committed: Thu Jul 24 21:05:17 2008 UTC (15 years, 11 months ago) by root
Branch: MAIN
CVS Tags: rel-1_0, HEAD
Changes since 1.2: +2 -2 lines
Log Message:
1.0

File Contents

# Content
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 #include "librsync.h"
6
7 /* try to be compatible with older perls */
8 /* SvPV_nolen() macro first defined in 5.005_55 */
9 /* this is slow, not threadsafe, but works */
10 #include "patchlevel.h"
11 #if (PATCHLEVEL == 4) || ((PATCHLEVEL == 5) && (SUBVERSION < 55))
12 static STRLEN nolen_na;
13 # define SvPV_nolen(sv) SvPV ((sv), nolen_na)
14 #endif
15
16 static SV *trace_cb_sv;
17
18 typedef rs_stats_t * File__Rdiff__Stats;
19 typedef rs_signature_t *File__Rdiff__Signature;
20
21 typedef struct File__Rdiff__Buffers {
22 rs_buffers_t rs;
23 SV *in;
24 STRLEN in_ofs;
25 SV *out;
26 STRLEN outsize;
27 } *File__Rdiff__Buffers;
28
29 typedef struct File__Rdiff__Job {
30 rs_job_t *rs;
31 SV *sig;
32 } *File__Rdiff__Job;
33
34 static SV *new_sig (File__Rdiff__Signature sig)
35 {
36 SV *sv = NEWSV (0, 0);
37 sv_setref_pv (sv, "File::Rdiff::Signature", (void *)sig);
38
39 return sv;
40 }
41
42 static File__Rdiff__Signature
43 old_sig (SV *sv)
44 {
45 if (sv_derived_from(sv, "File::Rdiff::Signature"))
46 {
47 IV tmp = SvIV((SV*)SvRV(sv));
48 return INT2PTR(rs_signature_t *,tmp);
49 }
50 else
51 Perl_croak(aTHX_ "Object of type File::Rdiff::Signature expected");
52 }
53
54 static void
55 trace_cb (int level, char const *msg)
56 {
57 if (SvOK (trace_cb_sv))
58 {
59 dSP;
60
61 SAVETMPS; PUSHMARK(SP); EXTEND(SP,2);
62
63 PUSHs(sv_2mortal(newSViv(level)));
64 PUSHs(sv_2mortal(newSVpv(msg,0)));
65
66 PUTBACK; perl_call_sv (trace_cb_sv, G_VOID|G_DISCARD); SPAGAIN;
67
68 PUTBACK; FREETMPS;
69 }
70 else
71 rs_trace_stderr (level, msg);
72 }
73
74 /**
75 * \brief Callback used to retrieve parts of the basis file.
76 *
77 * \param pos Position where copying should begin.
78 *
79 * \param len On input, the amount of data that should be retrieved.
80 * Updated to show how much is actually available.
81 *
82 * \param buf On input, a buffer of at least \p *len bytes. May be
83 * updated to point to a buffer allocated by the callback if it
84 * prefers.
85 */
86 static rs_result
87 copy_cb (void *cb, rs_long_t pos, size_t *len, void **buf)
88 {
89 dSP;
90 SV *rbuf;
91
92 PUSHMARK(SP); EXTEND(SP,2);
93
94 PUSHs(sv_2mortal(newSViv(pos)));
95 PUSHs(sv_2mortal(newSViv(*len)));
96
97 PUTBACK; perl_call_sv ((SV *)cb, G_SCALAR); SPAGAIN;
98
99 rbuf = POPs;
100
101 PUTBACK;
102
103 if (SvIOKp (rbuf) && !SvPOKp (rbuf))
104 {
105 /* assume error code */
106 return SvIVX (rbuf);
107 }
108 else
109 {
110 /* assume data. we are not copying because we assume
111 * that the data will be consumed before the next FREETMPS,
112 * which should be just outside ther rs_job_iter call.
113 */
114 STRLEN slen;
115
116 *buf = SvPV (rbuf, slen);
117 *len = slen;
118
119 return RS_DONE;
120 }
121 }
122
123 MODULE = File::Rdiff PACKAGE = File::Rdiff
124
125 PROTOTYPES: ENABLE
126
127 BOOT:
128 {
129 HV * stash = gv_stashpv ("File::Rdiff", 0);
130
131 trace_cb_sv = newSVsv (&PL_sv_undef);
132
133 rs_trace_to (trace_cb);
134 rs_trace_set_level (RS_LOG_WARNING);
135
136 newCONSTSUB (stash, "LIBRSYNC_VERSION", newSVpv (rs_librsync_version, 0));
137
138 newCONSTSUB (stash, "LOG_EMERG", newSViv (RS_LOG_EMERG));
139 newCONSTSUB (stash, "LOG_ALERT", newSViv (RS_LOG_ALERT));
140 newCONSTSUB (stash, "LOG_CRIT", newSViv (RS_LOG_CRIT));
141 newCONSTSUB (stash, "LOG_ERR", newSViv (RS_LOG_ERR));
142 newCONSTSUB (stash, "LOG_WARNING", newSViv (RS_LOG_WARNING));
143 newCONSTSUB (stash, "LOG_NOTICE", newSViv (RS_LOG_NOTICE));
144 newCONSTSUB (stash, "LOG_INFO", newSViv (RS_LOG_INFO));
145 newCONSTSUB (stash, "LOG_DEBUG", newSViv (RS_LOG_DEBUG));
146 newCONSTSUB (stash, "DONE", newSViv (RS_DONE));
147 newCONSTSUB (stash, "BLOCKED", newSViv (RS_BLOCKED));
148 newCONSTSUB (stash, "RUNNING", newSViv (RS_RUNNING));
149 newCONSTSUB (stash, "TEST_SKIPPED", newSViv (RS_TEST_SKIPPED));
150 newCONSTSUB (stash, "IO_ERROR", newSViv (RS_IO_ERROR));
151 newCONSTSUB (stash, "SYNTAX_ERROR", newSViv (RS_SYNTAX_ERROR));
152 newCONSTSUB (stash, "MEM_ERROR", newSViv (RS_MEM_ERROR));
153 newCONSTSUB (stash, "INPUT_ENDED", newSViv (RS_INPUT_ENDED));
154 newCONSTSUB (stash, "BAD_MAGIC", newSViv (RS_BAD_MAGIC));
155 newCONSTSUB (stash, "UNIMPLEMENTED", newSViv (RS_UNIMPLEMENTED));
156 newCONSTSUB (stash, "CORRUPT", newSViv (RS_CORRUPT));
157 newCONSTSUB (stash, "INTERNAL_ERROR", newSViv (RS_INTERNAL_ERROR));
158 newCONSTSUB (stash, "PARAM_ERROR", newSViv (RS_PARAM_ERROR));
159 }
160
161 int
162 trace_level(level)
163 int level
164 PROTOTYPE: ;$
165 CODE:
166 static int oldlevel = RS_LOG_WARNING; /* see BOOT: */
167
168 RETVAL = oldlevel;
169 if (items)
170 {
171 oldlevel = level;
172 rs_trace_set_level (level);
173 }
174 OUTPUT:
175 RETVAL
176
177 SV *
178 trace_to(cb)
179 SV * cb
180 PROTOTYPE: ;&
181 CODE:
182 RETVAL = sv_2mortal (newSVsv (trace_cb_sv));
183 if (items)
184 sv_setsv (trace_cb_sv, cb);
185 OUTPUT:
186 RETVAL
187
188 void
189 supports_trace()
190 PROTOTYPE:
191 CODE:
192 if (rs_supports_trace())
193 XSRETURN_YES;
194 else
195 XSRETURN_NO;
196
197 SV *
198 strerror (resultcode)
199 int resultcode
200 CODE:
201 RETVAL = newSVpv (rs_strerror (resultcode), 0);
202 OUTPUT:
203 RETVAL
204
205 MODULE = File::Rdiff PACKAGE = File::Rdiff::Signature
206
207 int
208 build_hash_table(self)
209 File::Rdiff::Signature self
210 CODE:
211 RETVAL = rs_build_hash_table (self);
212 OUTPUT:
213 RETVAL
214
215 void
216 DESTROY(self)
217 File::Rdiff::Signature self
218 CODE:
219 rs_free_sumset (self);
220
221 void
222 dump(self)
223 File::Rdiff::Signature self
224 CODE:
225 rs_sumset_dump (self);
226
227 MODULE = File::Rdiff PACKAGE = File::Rdiff::Buffers
228
229 File::Rdiff::Buffers
230 new(class, outsize = 65536)
231 SV * class
232 STRLEN outsize
233 PROTOTYPE: $;$$
234 CODE:
235 Newz (0, RETVAL, 1, struct File__Rdiff__Buffers);
236 RETVAL->outsize = outsize;
237 OUTPUT:
238 RETVAL
239
240 void
241 DESTROY(self)
242 File::Rdiff::Buffers self
243 CODE:
244 if (self->in ) SvREFCNT_dec (self->in );
245 if (self->out) SvREFCNT_dec (self->out);
246 Safefree (self);
247
248 void
249 in(self,in)
250 File::Rdiff::Buffers self
251 SV * in
252 CODE:
253 if (self->in)
254 SvREFCNT_dec (self->in);
255 self->in = SvREFCNT_inc (in);
256 self->in_ofs = 0;
257
258 void
259 eof(self)
260 File::Rdiff::Buffers self
261 CODE:
262 self->rs.eof_in = 1;
263
264 SV *
265 out(self)
266 File::Rdiff::Buffers self
267 CODE:
268 RETVAL = self->out;
269 self->out = 0;
270 OUTPUT:
271 RETVAL
272
273 int
274 avail_in(self)
275 File::Rdiff::Buffers self
276 CODE:
277 RETVAL = self->in ? SvCUR (self->in) - self->in_ofs
278 : self->rs.eof_in ? -1
279 : 0;
280 OUTPUT:
281 RETVAL
282
283 int
284 avail_out(self)
285 File::Rdiff::Buffers self
286 CODE:
287 RETVAL = self->outsize - (self->out ? SvCUR (self->out) : 0);
288 OUTPUT:
289 RETVAL
290
291 int
292 size(self)
293 File::Rdiff::Buffers self
294 CODE:
295 RETVAL = self->out ? SvCUR (self->out) : 0;
296 OUTPUT:
297 RETVAL
298
299 MODULE = File::Rdiff PACKAGE = File::Rdiff::Job
300
301 File::Rdiff::Job
302 new_sig(class, new_block_len = RS_DEFAULT_BLOCK_LEN, strong_sum_len = RS_DEFAULT_STRONG_LEN)
303 SV * class
304 size_t new_block_len
305 size_t strong_sum_len
306 PROTOTYPE: $;$$
307 CODE:
308 Newz (0, RETVAL, 1, struct File__Rdiff__Job);
309 RETVAL->rs = rs_sig_begin (new_block_len, strong_sum_len);
310 OUTPUT:
311 RETVAL
312
313 File::Rdiff::Job
314 new_loadsig(class)
315 SV * class
316 CODE:
317 rs_signature_t *sig;
318 Newz (0, RETVAL, 1, struct File__Rdiff__Job);
319 RETVAL->rs = rs_loadsig_begin (&sig);
320 RETVAL->sig = new_sig (sig);
321 OUTPUT:
322 RETVAL
323
324 File::Rdiff::Job
325 new_delta(class, signature)
326 SV * class
327 SV * signature
328 CODE:
329 Newz (0, RETVAL, 1, struct File__Rdiff__Job);
330 RETVAL->rs = rs_delta_begin (old_sig (signature));
331 RETVAL->sig = newSVsv (signature);
332 OUTPUT:
333 RETVAL
334
335 File::Rdiff::Job
336 new_patch(class, cb_or_fh)
337 SV * class
338 SV * cb_or_fh
339 CODE:
340 rs_copy_cb *cb;
341 void *cb_arg;
342
343 if (SvROK (cb_or_fh) && SvTYPE (SvRV (cb_or_fh)) == SVt_PVCV)
344 {
345 cb = copy_cb;
346 cb_arg = (void *)cb_or_fh;
347 }
348 else
349 {
350 cb = rs_file_copy_cb;
351 cb_arg = (void *)IoIFP (sv_2io (cb_or_fh));
352 }
353
354 Newz (0, RETVAL, 1, struct File__Rdiff__Job);
355 RETVAL->rs = rs_patch_begin (cb, cb_arg);
356 OUTPUT:
357 RETVAL
358
359 void
360 DESTROY(self)
361 File::Rdiff::Job self
362 CODE:
363 if (self->sig)
364 SvREFCNT_dec (self->sig);
365 rs_job_free (self->rs);
366 Safefree (self);
367
368 SV *
369 signature(self)
370 File::Rdiff::Job self
371 CODE:
372 RETVAL = SvREFCNT_inc (self->sig);
373 OUTPUT:
374 RETVAL
375
376 int
377 iter(self,buffers)
378 File::Rdiff::Job self
379 File::Rdiff::Buffers buffers
380 CODE:
381 {
382 STRLEN in_len;
383
384 if (buffers->in)
385 {
386 buffers->rs.next_in = SvPV (buffers->in, in_len) + buffers->in_ofs;
387 buffers->rs.avail_in = in_len - buffers->in_ofs;
388 }
389 else
390 {
391 buffers->rs.next_in = 0;
392 buffers->rs.avail_in = 0;
393 }
394
395 if (buffers->outsize)
396 {
397 if (!buffers->out)
398 {
399 buffers->out = NEWSV (0, buffers->outsize);
400 SvPOK_on (buffers->out);
401 }
402
403 buffers->rs.next_out = SvEND (buffers->out);
404 buffers->rs.avail_out = buffers->outsize - SvCUR (buffers->out);
405 }
406 else
407 {
408 buffers->rs.next_out = 0;
409 buffers->rs.avail_out = 0;
410 }
411
412 RETVAL = rs_job_iter (self->rs, &buffers->rs);
413
414 buffers->in_ofs = in_len - buffers->rs.avail_in;
415
416 if (buffers->out)
417 SvCUR_set (buffers->out, buffers->outsize - buffers->rs.avail_out);
418 }
419 OUTPUT:
420 RETVAL
421
422 # void rs_hexify(char *to_buf, void const *from_buf, int from_len);
423 # size_t rs_unbase64(char *s);
424 # void rs_base64(unsigned char const *buf, int n, char *out);
425 # * \sa rs_format_stats(), rs_log_stats()
426 # */
427 # typedef struct rs_stats {
428 # char const *op; /**< Human-readable name of current
429 # * operation. For example, "delta". */
430 # int lit_cmds; /**< Number of literal commands. */
431 # rs_long_t lit_bytes; /**< Number of literal bytes. */
432 # rs_long_t lit_cmdbytes; /**< Number of bytes used in literal
433 # * command headers. */
434 #
435 # rs_long_t copy_cmds, copy_bytes, copy_cmdbytes;
436 # rs_long_t sig_cmds, sig_bytes;
437 # int false_matches;
438 #
439 # rs_long_t sig_blocks; /**< Number of blocks described by the
440 # signature. */
441 #
442 # size_t block_len;
443 #
444 # rs_long_t in_bytes; /**< Total bytes read from input. */
445 # rs_long_t out_bytes; /**< Total bytes written to output. */
446 # } rs_stats_t;
447 #
448 # char *rs_format_stats(rs_stats_t const *, char *, size_t);
449 #
450 # int rs_log_stats(rs_stats_t const *stats);
451 #
452 # const rs_stats_t * rs_job_statistics(rs_job_t *job);
453 #
454 # int rs_accum_value(rs_job_t *, char *sum, size_t sum_len);
455 #
456
457 MODULE = File::Rdiff PACKAGE = File::Rdiff
458
459 #ifndef RSYNC_NO_STDIO_INTERFACE
460
461 int
462 sig_file(old_file, sig_file, block_len = RS_DEFAULT_BLOCK_LEN, strong_len = RS_DEFAULT_STRONG_LEN)
463 FILE * old_file
464 FILE * sig_file
465 size_t block_len
466 size_t strong_len
467 PROTOTYPE: $$;$$
468 CODE:
469 RETVAL = rs_sig_file(old_file, sig_file, block_len, strong_len, 0);
470 OUTPUT:
471 RETVAL
472
473 File::Rdiff::Signature
474 loadsig_file(file)
475 FILE * file
476 CODE:
477 rs_result r = rs_loadsig_file(file, &RETVAL, 0);
478 if (r != RS_DONE)
479 XSRETURN_IV (r);
480 OUTPUT:
481 RETVAL
482
483 int
484 delta_file(signature, new_file, delta_file)
485 File::Rdiff::Signature signature
486 FILE * new_file
487 FILE * delta_file
488 CODE:
489 RETVAL = rs_delta_file (signature, new_file, delta_file, 0);
490 OUTPUT:
491 RETVAL
492
493 int
494 patch_file(basis_file, delta_file, new_file)
495 FILE * basis_file
496 FILE * delta_file
497 FILE * new_file
498 CODE:
499 RETVAL = rs_patch_file (basis_file, delta_file, new_file, 0);
500 OUTPUT:
501 RETVAL
502
503 #endif
504
505
506
507
508
509