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, 9 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

# User Rev Content
1 root 1.1 #include "EXTERN.h"
2     #include "perl.h"
3     #include "XSUB.h"
4    
5 root 1.3 #include "librsync.h"
6 root 1.1
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 root 1.3 copy_cb (void *cb, rs_long_t pos, size_t *len, void **buf)
88 root 1.1 {
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 root 1.2 RETVAL = self->in ? SvCUR (self->in) - self->in_ofs
278     : self->rs.eof_in ? -1
279     : 0;
280 root 1.1 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 root 1.2 RETVAL = SvREFCNT_inc (self->sig);
373 root 1.1 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 root 1.2 if (buffers->outsize)
396 root 1.1 {
397 root 1.2 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 root 1.1 }
411    
412     RETVAL = rs_job_iter (self->rs, &buffers->rs);
413    
414     buffers->in_ofs = in_len - buffers->rs.avail_in;
415 root 1.2
416     if (buffers->out)
417     SvCUR_set (buffers->out, buffers->outsize - buffers->rs.avail_out);
418 root 1.1 }
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