File Coverage

blib/lib/Archive/Libarchive/FFI.pm
Criterion Covered Total %
statement 37 54 68.5
branch 1 10 10.0
condition 0 3 0.0
subroutine 12 15 80.0
pod n/a
total 50 82 60.9


line stmt bran cond sub pod time code
1             package Archive::Libarchive::FFI;
2              
3 27     27   860155 use strict;
  27         65  
  27         1064  
4 27     27   144 use warnings;
  27         56  
  27         1046  
5 27     27   29904 use Alien::Libarchive::Installer;
  27         166815  
  27         1059  
6 27     27   44899 use Exporter::Tidy ();
  27         342  
  27         644  
7 27     27   27074 use Encode ();
  27         354127  
  27         849  
8 27     27   373 use Carp qw( croak );
  27         54  
  27         1780  
9 27     27   23592 use FFI::Raw ();
  27         234231  
  27         1104  
10 27         209 use FFI::Util qw(
11             deref_ptr_get
12             deref_uint64_get
13             deref_uint_get
14             deref_ulong_get
15             deref_int64_get
16             deref_size_t_get
17             buffer_to_scalar
18             scalar_to_buffer
19             deref_int_get
20             deref_str_get
21             :types
22 27     27   23927 );
  27         111894  
23              
24             BEGIN {
25              
26 27 50   27   14338 if(eval { require FFI::Sweet })
  27         12983  
27             {
28 0         0 FFI::Sweet->import;
29             }
30             else
31             {
32 27         18822 require Archive::Libarchive::FFI::SweetLite;
33 27         248 Archive::Libarchive::FFI::SweetLite->import;
34             }
35              
36             }
37              
38             # ABSTRACT: Perl bindings to libarchive via FFI
39             our $VERSION = '0.0802'; # VERSION
40              
41             ffi_lib(\$_) for Alien::Libarchive::Installer->system_install( test => 'ffi' )->dlls;
42              
43             require Archive::Libarchive::FFI::Constant;
44              
45             $Archive::Libarchive::FFI::on_attach ||= sub {};
46              
47             sub _attach_function ($$$;$)
48             {
49 0     0     eval {
50 0           attach_function($_[0], $_[1], $_[2], $_[3]);
51             };
52 0 0 0       warn $@ if $@ && $ENV{ARCHIVE_LIBARCHIVE_FFI_VERBOSE};
53             }
54              
55             sub _attach ($$$)
56             {
57 0     0     $Archive::Libarchive::FFI::on_attach->(@_);
58 0           my($name, $arg, $ret) = @_;
59 0 0         if(grep { $_ == FFI::Raw::str } ($ret, @$arg))
  0            
60             {
61 0 0         if(ref $name)
62             {
63 0           $name->[1] = "_" . $name->[1];
64             }
65             else
66             {
67 0           $name = [ $name => "_$name" ]
68             }
69             }
70 0 0         if($ret == _void)
71             {
72             _attach_function $name, $arg, $ret, sub {
73 0     0     my $code = shift;
74 0           $code->(@_);
75 0           ARCHIVE_OK();
76 0           };
77             }
78             else
79             {
80 0           _attach_function $name, $arg, $ret;
81             }
82             }
83              
84             _attach 'archive_version_number', undef, _int;
85              
86             require Archive::Libarchive::FFI::Callback;
87              
88             _attach 'archive_version_string', undef, _str;
89             _attach 'archive_clear_error', [ _ptr ], _void;
90             _attach 'archive_copy_error', [ _ptr ], _int;
91             _attach 'archive_errno', [ _ptr ], _int;
92             _attach 'archive_file_count', [ _ptr ], _int;
93             _attach 'archive_format', [ _ptr ], _int;
94             _attach 'archive_format_name', [ _ptr ], _str;
95             _attach 'archive_seek_data', [ _ptr, _int64, _int ], _int64;
96              
97             if(archive_version_number() >= 3000000)
98             {
99             _attach 'archive_error_string', [ _ptr ], _str;
100             }
101             else
102             {
103             _attach_function [ 'archive_error_string' => '_archive_error_string' ], [ _ptr ], _str, sub {
104             my($sub, $archive) = @_;
105             my $ret = $sub->($archive);
106             return if $ret eq '(Empty error message)';
107             return $ret;
108             };
109             }
110              
111             _attach 'archive_read_new', undef, _ptr;
112             _attach 'archive_read_support_format_all', [ _ptr ], _int;
113             _attach 'archive_read_open1', [ _ptr ], _int;
114             _attach 'archive_read_open_filename', [ _ptr, _str, _int ], _int;
115             _attach 'archive_read_data_skip', [ _ptr ], _int;
116             _attach 'archive_read_close', [ _ptr ], _int;
117             _attach 'archive_read_append_filter', [ _ptr, _int ], _int;
118             _attach 'archive_read_append_filter_program', [ _ptr, _str ], _int;
119             _attach 'archive_read_support_format_by_code', [ _ptr, _int ], _int;
120             _attach 'archive_read_header_position', [ _ptr ], _int64;
121             _attach 'archive_read_set_filter_option', [ _ptr, _str, _str, _str ], _int;
122             _attach 'archive_read_set_format_option', [ _ptr, _str, _str, _str ], _int;
123             _attach 'archive_read_set_option', [ _ptr, _str, _str, _str ], _int;
124             _attach 'archive_read_set_options', [ _ptr, _str ], _int;
125             _attach 'archive_read_set_format', [ _ptr, _str, _str, _str ], _int;
126             _attach 'archive_read_next_header2', [ _ptr, _ptr ], _int;
127             _attach 'archive_read_extract', [ _ptr, _ptr, _int ], _int;
128             _attach 'archive_read_extract2', [ _ptr, _ptr, _ptr ], _int;
129             _attach 'archive_read_extract_set_skip_file', [ _ptr, _int64, _int64 ], _void;
130              
131             if(archive_version_number() >= 3000000)
132             {
133             _attach 'archive_read_support_filter_program', [ _ptr, _str ], _int;
134             }
135             else
136             {
137             _attach ['archive_read_support_compression_program' => 'archive_read_support_filter_program'], [ _ptr, _str ], _int;
138             }
139              
140              
141             _attach 'archive_filter_code', [ _ptr, _int ], _int;
142             _attach 'archive_filter_count', [ _ptr ], _int;
143             _attach 'archive_filter_name', [ _ptr, _int ], _str;
144             _attach 'archive_filter_bytes', [ _ptr, _int ], _int64;
145              
146             _attach 'archive_write_new', undef, _ptr;
147             _attach 'archive_write_add_filter', [ _ptr, _int ], _int;
148             _attach 'archive_write_add_filter_by_name', [ _ptr, _str ], _int;
149             _attach 'archive_write_set_format', [ _ptr, _int ], _int;
150             _attach 'archive_write_set_format_by_name', [ _ptr, _str ], _int;
151             _attach 'archive_write_open_filename', [ _ptr, _str ], _int;
152             _attach 'archive_write_header', [ _ptr, _ptr ], _int;
153             _attach 'archive_write_close', [ _ptr ], _int;
154             _attach 'archive_write_disk_new', undef, _ptr;
155             _attach 'archive_write_disk_set_options', [ _ptr, _int ], _int;
156             _attach 'archive_write_finish_entry', [ _ptr ], _int;
157             _attach 'archive_write_disk_set_standard_lookup', [ _ptr ], _int;
158             _attach 'archive_write_zip_set_compression_deflate', [ _ptr ], _int;
159             _attach 'archive_write_zip_set_compression_store', [ _ptr ], _int;
160             _attach 'archive_write_set_filter_option', [ _ptr, _str, _str, _str ], _int;
161             _attach 'archive_write_set_format_option', [ _ptr, _str, _str, _str ], _int;
162             _attach 'archive_write_set_option', [ _ptr, _str, _str, _str ], _int;
163             _attach 'archive_write_set_options', [ _ptr, _str ], _int;
164             _attach 'archive_write_set_skip_file', [ _ptr, _int64, _int64 ], _int;
165             _attach 'archive_write_disk_gid', [ _ptr, _str, _int64 ], _int64;
166             _attach 'archive_write_disk_set_skip_file', [ _ptr, _int64, _int64 ], _int;
167             _attach 'archive_write_disk_uid', [ _ptr, _str, _int64 ], _int64;
168             _attach 'archive_write_fail', [ _ptr ], _int;
169             _attach 'archive_write_get_bytes_in_last_block', [ _ptr ], _int;
170             _attach 'archive_write_get_bytes_per_block', [ _ptr ], _int;
171             _attach 'archive_write_set_bytes_in_last_block', [ _ptr, _int ], _int;
172             _attach 'archive_write_set_bytes_per_block', [ _ptr, _int ], _int;
173              
174             if(archive_version_number() >= 3000000)
175             {
176             _attach 'archive_write_add_filter_program', [ _ptr, _str ], _int;
177             }
178             else
179             {
180             _attach ['archive_write_set_compression_program' => 'archive_write_add_filter_program'], [ _ptr, _str ], _int;
181             }
182              
183              
184             _attach 'archive_entry_clear', [ _ptr ], _void;
185             _attach 'archive_entry_clone', [ _ptr ], _ptr;
186             _attach 'archive_entry_free', [ _ptr ], _void;
187             _attach 'archive_entry_new', undef, _ptr;
188             _attach 'archive_entry_new2', [ _ptr ], _ptr;
189             _attach 'archive_entry_size', [ _ptr ], _int64;
190             _attach 'archive_entry_set_size', [ _ptr, _int64 ], _void;
191             _attach 'archive_entry_set_perm', [ _ptr, _int ], _void;
192             _attach 'archive_entry_set_filetype', [ _ptr, _int ], _void;
193             _attach 'archive_entry_set_mtime', [ _ptr, _time_t, _long ], _void;
194             _attach 'archive_entry_set_ctime', [ _ptr, _time_t, _long ], _void;
195             _attach 'archive_entry_set_atime', [ _ptr, _time_t, _long ], _void;
196             _attach 'archive_entry_set_birthtime', [ _ptr, _time_t, _long ], _void;
197             _attach 'archive_entry_atime_is_set', [ _ptr ], _int;
198             _attach 'archive_entry_atime', [ _ptr ], _time_t;
199             _attach 'archive_entry_atime_nsec', [ _ptr ], _long;
200             _attach 'archive_entry_birthtime_is_set', [ _ptr ], _int;
201             _attach 'archive_entry_birthtime', [ _ptr ], _time_t;
202             _attach 'archive_entry_birthtime_nsec', [ _ptr ], _long;
203             _attach 'archive_entry_ctime_is_set', [ _ptr ], _int;
204             _attach 'archive_entry_ctime', [ _ptr ], _time_t;
205             _attach 'archive_entry_ctime_nsec', [ _ptr ], _long;
206             _attach 'archive_entry_mtime_is_set', [ _ptr ], _int;
207             _attach 'archive_entry_mtime', [ _ptr ], _time_t;
208             _attach 'archive_entry_mtime_nsec', [ _ptr ], _long;
209             _attach 'archive_entry_dev_is_set', [ _ptr ], _int;
210             _attach 'archive_entry_dev', [ _ptr ], _dev_t;
211             _attach 'archive_entry_devmajor', [ _ptr ], _dev_t;
212             _attach 'archive_entry_devminor', [ _ptr ], _dev_t;
213             _attach 'archive_entry_fflags_text', [ _ptr ], _str;
214             _attach 'archive_entry_gid', [ _ptr ], _int64;
215             _attach 'archive_entry_rdev', [ _ptr ], _int64;
216             _attach 'archive_entry_rdevmajor', [ _ptr ], _int64;
217             _attach 'archive_entry_rdevminor', [ _ptr ], _int64;
218             _attach 'archive_entry_set_rdev', [ _ptr, _int64 ], _void;
219             _attach 'archive_entry_set_rdevmajor', [ _ptr, _int64 ], _void;
220             _attach 'archive_entry_set_rdevminor', [ _ptr, _int64 ], _void;
221             _attach 'archive_entry_filetype', [ _ptr ], _int;
222             _attach 'archive_entry_ino', [ _ptr ], _int64;
223             _attach 'archive_entry_ino_is_set', [ _ptr ], _int;
224             _attach 'archive_entry_mode', [ _ptr ], _int;
225             _attach 'archive_entry_nlink', [ _ptr ], _uint;
226             _attach 'archive_entry_perm', [ _ptr ], _int;
227             _attach 'archive_entry_set_dev', [ _ptr, _dev_t ], _void;
228             _attach 'archive_entry_set_devmajor', [ _ptr, _dev_t ], _void;
229             _attach 'archive_entry_set_devminor', [ _ptr, _dev_t ], _void;
230             _attach 'archive_entry_set_fflags', [ _ptr, _ulong, _ulong ], _void;
231             _attach 'archive_entry_set_gid', [ _ptr, _int64 ], _void;
232             _attach 'archive_entry_set_ino', [ _ptr, _int64 ], _void;
233             _attach 'archive_entry_set_link', [ _ptr, _str ], _void;
234             _attach 'archive_entry_set_mode', [ _ptr, _int ], _void;
235             _attach 'archive_entry_set_nlink', [ _ptr, _int ], _void;
236             _attach 'archive_entry_set_uid', [ _ptr, _int64 ], _void;
237             _attach 'archive_entry_size_is_set', [ _ptr ], _int;
238             _attach 'archive_entry_unset_atime', [ _ptr ], _void;
239             _attach 'archive_entry_unset_birthtime', [ _ptr ], _void;
240             _attach 'archive_entry_unset_ctime', [ _ptr ], _void;
241             _attach 'archive_entry_unset_mtime', [ _ptr ], _void;
242             _attach 'archive_entry_unset_size', [ _ptr ], _void;
243             _attach 'archive_entry_xattr_clear', [ _ptr ], _void;
244             _attach 'archive_entry_xattr_count', [ _ptr ], _int;
245             _attach 'archive_entry_xattr_reset', [ _ptr ], _int;
246             _attach 'archive_entry_uid', [ _ptr ], _int64;
247             _attach 'archive_entry_copy_sourcepath', [ _ptr, _str ], _void;
248             _attach 'archive_entry_acl', [ _ptr ], _ptr;
249             _attach 'archive_entry_acl_clear', [ _ptr ], _int;
250             _attach 'archive_entry_acl_reset', [ _ptr, _int ], _int;
251             _attach 'archive_entry_acl_text', [ _ptr, _int ], _str;
252             _attach 'archive_entry_acl_count', [ _ptr, _int ], _int;
253             _attach 'archive_entry_sparse_clear', [ _ptr ], _void;
254             _attach 'archive_entry_sparse_add_entry', [ _ptr, _int64, _int64 ], _void;
255             _attach 'archive_entry_sparse_count', [ _ptr ], _int;
256             _attach 'archive_entry_sparse_reset', [ _ptr ], _int;
257              
258             if(archive_version_number() >= 3000000)
259             {
260             _attach 'archive_entry_acl_add_entry', [ _ptr, _int, _int, _int, _int, _str ], _int;
261             }
262             else
263             {
264             _attach_function [ 'archive_entry_acl_add_entry' => '_archive_entry_acl_add_entry' ], [ _ptr, _int, _int, _int, _int, _str ], _void, sub {
265             shift->(@_);
266             ARCHIVE_OK();
267             };
268             }
269              
270             _attach 'archive_entry_linkresolver_free', [ _ptr ], _void;
271             _attach 'archive_entry_linkresolver_new', undef, _ptr;
272             _attach 'archive_entry_linkresolver_set_strategy', [ _ptr, _int ], _void;
273              
274             _attach 'archive_read_disk_descend', [ _ptr ], _int;
275             _attach 'archive_read_disk_can_descend', [ _ptr ], _int;
276             _attach 'archive_read_disk_current_filesystem', [ _ptr ], _int;
277             _attach 'archive_read_disk_current_filesystem_is_synthetic', [ _ptr ], _int;
278             _attach 'archive_read_disk_current_filesystem_is_remote', [ _ptr ], _int;
279             _attach 'archive_read_disk_set_atime_restored', [ _ptr ], _int;
280             _attach 'archive_read_disk_open', [ _ptr, _str ], _int;
281             _attach 'archive_read_disk_gname', [ _ptr, _int64 ], _str;
282             _attach 'archive_read_disk_uname', [ _ptr, _int64 ], _str;
283             _attach 'archive_read_disk_new', undef, _ptr;
284             _attach 'archive_read_disk_set_behavior', [ _ptr, _int ], _int;
285             _attach 'archive_read_disk_set_standard_lookup', [ _ptr ], _int;
286             _attach 'archive_read_disk_set_symlink_hybrid', [ _ptr ], _int;
287             _attach 'archive_read_disk_set_symlink_logical', [ _ptr ], _int;
288             _attach 'archive_read_disk_set_symlink_physical', [ _ptr ], _int;
289              
290             _attach 'archive_match_new', undef, _ptr;
291             _attach 'archive_match_free', [ _ptr ], _int;
292             _attach 'archive_match_excluded', [ _ptr, _ptr ], _int;
293             _attach 'archive_match_path_excluded', [ _ptr, _ptr ], _int;
294             _attach 'archive_match_time_excluded', [ _ptr, _ptr ], _int;
295             _attach 'archive_match_owner_excluded', [ _ptr, _ptr ], _int;
296             _attach 'archive_match_include_gid', [ _ptr, _int64 ], _int;
297             _attach 'archive_match_include_uid', [ _ptr, _int64 ], _int;
298             _attach 'archive_match_include_gname', [ _ptr, _str ], _int;
299             _attach 'archive_match_include_uname', [ _ptr, _str ], _int;
300             _attach 'archive_match_exclude_entry', [ _ptr, _int, _ptr ], _int;
301             _attach 'archive_match_exclude_pattern', [ _ptr, _str ], _int;
302             _attach 'archive_match_exclude_pattern_from_file', [ _ptr, _str, _int ], _int;
303             _attach 'archive_match_include_pattern', [ _ptr, _str ], _int;
304             _attach 'archive_match_include_pattern_from_file', [ _ptr, _str, _int ], _int;
305             _attach 'archive_match_include_file_time', [ _ptr, _int, _str ], _int;
306             _attach 'archive_match_include_time', [ _ptr, _int, _time_t, _long ], _int;
307             _attach 'archive_match_path_unmatched_inclusions', [ _ptr ], _int;
308              
309             foreach my $type (qw( all bzip2 compress gzip grzip lrzip lzip lzma lzop none rpm uu xz ))
310             {
311             my $name = "archive_read_support_filter_$type";
312             eval {
313             attach_function $name, [ _ptr ], _int;
314             };
315             if($@)
316             {
317             my $real = "archive_read_support_compression_$type";
318             eval { attach_function [ $real => $name ], [ _ptr ], _int };
319             }
320             }
321              
322             _attach "archive_read_support_format_$_", [ _ptr ], _int
323             for qw( 7zip ar cab cpio empty gnutar iso9660 lha mtree rar raw tar xar zip );
324              
325             foreach my $type (qw( b64encode bzip2 compress grzip gzip lrzip lzip lzma lzop none uuencode xz ))
326             {
327             my $name = "archive_write_add_filter_$type";
328             eval {
329             attach_function $name, [ _ptr ], _int;
330             };
331             if($@)
332             {
333             my $real = "archive_write_set_compression_$type";
334             eval { attach_function [ $real => $name ], [ _ptr ], _int };
335             }
336             }
337              
338             _attach "archive_write_set_format_$_", [ _ptr ], _int
339             for qw( 7zip ar_bsd ar_svr4 cpio cpio_newc gnutar iso9660 mtree mtree_classic
340             pax pax_restricted shar shar_dump ustar v7tar xar zip);
341              
342             _attach_function 'archive_match_include_date', [ _ptr, _int, _str ], _int;
343              
344             _attach_function 'archive_entry_sparse_next', [ _ptr, _ptr, _ptr ], _int, sub
345             {
346             my $offset = FFI::Raw::MemPtr->new_from_ptr(0);
347             my $length = FFI::Raw::MemPtr->new_from_ptr(0);
348             my $ret = $_[0]->($_[1], $offset, $length);
349             $_[2] = deref_int64_get($$offset);
350             $_[3] = deref_int64_get($$length);
351             return $ret;
352             };
353              
354             _attach_function 'archive_match_path_unmatched_inclusions_next', [ _ptr, _ptr ], _int, sub
355             {
356             my $pattern = FFI::Raw::MemPtr->new_from_ptr(0);
357             my $ret = $_[0]->($_[1], $pattern);
358             $_[2] = deref_str_get($$pattern);
359             return $ret;
360             };
361              
362             _attach_function 'archive_entry_fflags', [ _ptr, _ptr, _ptr ], _void, sub
363             {
364             my $set = FFI::Raw::MemPtr->new_from_ptr(0);
365             my $clear = FFI::Raw::MemPtr->new_from_ptr(0);
366             $_[0]->($_[1], $set, $clear);
367             $_[2] = deref_ulong_get($$set);
368             $_[3] = deref_ulong_get($$clear);
369             return ARCHIVE_OK();
370             };
371              
372             _attach_function 'archive_read_next_header', [ _ptr, _ptr ], _int, sub
373             {
374             my $entry = FFI::Raw::MemPtr->new_from_ptr(0);
375             my $ret = $_[0]->($_[1], $entry);
376             $_[2] = deref_ptr_get($$entry);
377             $ret;
378             };
379              
380             _attach_function 'archive_read_data', [ _ptr, _ptr, _size_t ], _int, sub
381             {
382             # 0 cb 1 archive 2 buffer 3 size
383             my $buffer = FFI::Raw::MemPtr->new($_[3]);
384             my $ret = $_[0]->($_[1], $buffer, $_[3]);
385             $_[2] = $buffer->tostr($ret);
386             $ret;
387             };
388              
389             _attach_function 'archive_read_data_block', [ _ptr, _ptr, _ptr, _ptr ], _int, sub
390             {
391             # 0 cb 1 archive 2 buffer 3 offset
392             my $buffer = FFI::Raw::MemPtr->new_from_ptr(0);
393             my $size = FFI::Raw::MemPtr->new_from_ptr(0);
394             my $offset = FFI::Raw::MemPtr->new_from_ptr(0);
395             my $ret = $_[0]->($_[1], $buffer, $size, $offset);
396             $size = deref_size_t_get($size);
397             $offset = deref_uint64_get($offset);
398             $_[2] = buffer_to_scalar(deref_ptr_get($$buffer), $size);
399             $_[3] = $offset;
400             $ret;
401             };
402              
403             _attach_function 'archive_entry_acl_next', [ _ptr, _int, _ptr, _ptr, _ptr, _ptr, _ptr ], _int, sub
404             {
405             # 0 cb 1 entry 2 want_type
406             my $type = FFI::Raw::MemPtr->new_from_ptr(0); # 3
407             my $permset = FFI::Raw::MemPtr->new_from_ptr(0); # 4
408             my $tag = FFI::Raw::MemPtr->new_from_ptr(0); # 5
409             my $qual = FFI::Raw::MemPtr->new_from_ptr(0); # 6
410             my $name = FFI::Raw::MemPtr->new_from_ptr(0); # 7
411             my $ret = $_[0]->($_[1], $_[2], $type, $permset, $tag, $qual, $name);
412             $_[3] = deref_int_get($type);
413             $_[4] = deref_int_get($permset);
414             $_[5] = deref_int_get($tag);
415             $_[6] = deref_int_get($qual);
416             $_[7] = deref_str_get($name);
417             $ret;
418             };
419              
420             _attach_function 'archive_write_data', [ _ptr, _ptr, _size_t ], _int, sub
421             {
422             my($cb, $archive, $buffer) = @_;
423 27     27   154725 my $size = do { use bytes; length($buffer) };
  27         68  
  27         261  
424             my $ptr = FFI::Raw::MemPtr->new_from_buf($buffer, $size);
425             $cb->($archive, $ptr, $size);
426             };
427              
428             _attach_function 'archive_write_data_block', [ _ptr, _ptr, _size_t, _int64 ], _int, sub
429             {
430             my($cb, $archive, $buffer, $offset) = @_;
431 27     27   3801 my $size = do { use bytes; length($buffer) };
  27         100  
  27         141  
432             my $ptr = FFI::Raw::MemPtr->new_from_buf($buffer, $size);
433             $cb->($archive, $ptr, $size, $offset);
434             };
435              
436             foreach my $name (qw( gname hardlink pathname symlink uname ))
437             {
438             _attach_function "archive_entry_$name", [ _ptr ], _str, sub
439             {
440             my($cb, $entry) = @_;
441             _decode($cb->($entry));
442             };
443             _attach_function [ "archive_entry_update_$name\_utf8" => "archive_entry_set_$name"], [ _ptr, _str ], _void, sub
444             {
445             my($cb, $entry, $name) = @_;
446             $cb->($entry, defined $name ? Encode::encode('UTF-8', $name) : $name);
447             ARCHIVE_OK();
448             };
449             }
450              
451             _attach_function 'archive_read_open_filenames', [ _ptr, _ptr, _size_t ], _int, sub
452             {
453             my($cb, $archive, $filenames, $bs) = @_;
454             croak 'archive_read_open_filename: third argument must be array reference' unless ref($filenames) eq 'ARRAY';
455             my @filenames = map { Encode::encode(archive_perl_codeset(), $_) } @$filenames;
456             my $ptr = pack( ('P' x @filenames).'L!', @filenames, 0);
457             $ptr = FFI::Raw::MemPtr->new_from_buf($ptr, length $ptr);
458             $cb->($archive, $ptr, $bs);
459             };
460              
461             _attach_function [ 'archive_entry_copy_mac_metadata' => 'archive_entry_set_mac_metadata' ], [ _ptr, _ptr, _size_t ], _void, sub
462             {
463             my($cb, $archive, $buffer) = @_;
464             my($ptr, $size) = scalar_to_buffer($buffer);
465             $cb->($archive, $ptr, $size);
466             ARCHIVE_OK();
467             };
468              
469             _attach_function 'archive_entry_xattr_add_entry', [ _ptr, _str, _ptr, _size_t ], _void, sub
470             {
471             my($cb, $entry, $name, $value) = @_;
472             my($ptr, $size) = scalar_to_buffer($value);
473             $cb->($entry, $name, $ptr, $size);
474             ARCHIVE_OK();
475             };
476              
477             _attach_function 'archive_entry_xattr_next', [ _ptr, _ptr, _ptr, _ptr ], _int, sub
478             {
479             my $name = FFI::Raw::MemPtr->new_from_ptr(0);
480             my $ptr = FFI::Raw::MemPtr->new_from_ptr(0);
481             my $size = FFI::Raw::MemPtr->new_from_ptr(0);
482            
483             my $ret = $_[0]->($_[1], $name, $ptr, $size);
484             $_[2] = deref_str_get($$name);
485             $_[3] = buffer_to_scalar(deref_ptr_get($$ptr), deref_size_t_get($$size));
486            
487             $ret;
488             };
489              
490 27     27   26368 do { no warnings 'once'; *archive_entry_copy_mac_metadata = \&archive_entry_set_mac_metadata };
  27         65  
  27         51049  
491              
492             _attach_function 'archive_entry_mac_metadata', [ _ptr, _ptr ], _ptr, sub
493             {
494             my($cb, $archive) = @_;
495             my $size = FFI::Raw::MemPtr->new_from_ptr(0);
496             my $ptr = $cb->($archive, $size);
497             my $buffer = buffer_to_scalar($ptr, deref_size_t_get($$size));
498             };
499              
500             _attach_function 'archive_set_error', [ _ptr, _int, _str, _str ], _void, sub
501             {
502             my($cb, $archive, $status, $format, @args) = @_;
503             $cb->($archive, $status, "%s", sprintf($format, @args));
504             ARCHIVE_OK();
505             };
506              
507             _attach_function [ 'archive_entry_copy_sourcepath' => '_archive_entry_set_sourcepath' ], [ _ptr, _str ], _void, sub
508             {
509             my($cb, $entry, $string) = @_;
510             $cb->($entry, $string);
511             ARCHIVE_OK();
512             };
513              
514             _attach_function [ 'archive_entry_sourcepath' => '_archive_entry_sourcepath' ], [ _ptr ], _str;
515              
516             _attach_function $_, [ _ptr, _str, _ptr, _size_t ],_int, sub
517             {
518             my($cb, $archive, $command, $signature) = @_;
519             $cb->($archive, $command, scalar_to_buffer($signature));
520             } for (
521             'archive_read_append_filter_program_signature',
522             # TODO:
523             # using archive_read_support_compression_program_signature for archive_read_support_filter_program_signature doesn't
524             # appear to actually work for libarchive 2.x, so I am commenting it out for now. This does appear to make it slightly
525             # out of sync with the capability of the XS version, so if you need this function either use the XS version, or
526             # upgrade to libarchie >= 3
527             # archive_version_number() >= 3000000 ? 'archive_read_support_filter_program_signature' : [ archive_read_support_compression_program_signature => 'archive_read_support_filter_program_signature']);
528             'archive_read_support_filter_program_signature');
529              
530             # this is an unusual one which doesn't need to be decoded
531             # because it should always be ASCII
532             _attach_function 'archive_entry_strmode', [ _ptr ], _str;
533              
534             _attach_function 'archive_entry_linkify', [ _ptr, _ptr, _ptr ], _void, sub
535             {
536             my $ptr1 = FFI::Raw::MemPtr->new_from_ptr($_[2]);
537             my $ptr2 = FFI::Raw::MemPtr->new_from_ptr($_[3]);
538             $_[0]->($_[1], $ptr1, $ptr2);
539             $_[2] = deref_ptr_get($ptr1);
540             $_[3] = deref_ptr_get($ptr2);
541             ARCHIVE_OK();
542             };
543              
544             _attach_function [ 'archive_entry_copy_fflags_text' => '_archive_entry_set_fflags_text' ], [ _ptr, _str ], _void, sub
545             {
546             my($sub, $entry, $text) = @_;
547             $sub->($entry, $text);
548             ARCHIVE_OK();
549             };
550              
551             _attach_function 'archive_read_disk_entry_from_file', [ _ptr, _ptr, _int, _ptr ], _int, sub
552             {
553             my($cb, $archive, $entry, $fh, $stat) = @_;
554             croak "stat field currently not supported"
555             if defined $stat;
556             my $fd = fileno $fh;
557             $fd = -1 unless defined $fd;
558             $cb->($archive, $entry, $fd, 0);
559             };
560              
561             if(eval q{ require I18N::Langinfo; 1 })
562             {
563             eval '# line '. __LINE__ . ' "' . __FILE__ . qq("\n) . q{
564             sub archive_perl_codeset
565             {
566             I18N::Langinfo::langinfo(I18N::Langinfo::CODESET());
567             }
568             sub archive_perl_utf8_mode
569             {
570             int(I18N::Langinfo::langinfo(I18N::Langinfo::CODESET()) eq 'UTF-8');
571             }
572             };
573             die $@ if $@;
574             }
575             else
576             {
577             eval '# line '. __LINE__ . ' "' . __FILE__ . qq("\n) . q{
578             sub archive_perl_codeset
579             {
580             'ANSI_X3.4-1968';
581             }
582             sub archive_perl_utf8_mode
583             {
584             0;
585             }
586             };
587             }
588              
589             require Archive::Libarchive::FFI::Common;
590              
591             eval '# line '. __LINE__ . ' "' . __FILE__ . qq("\n) . q{
592             use Exporter::Tidy
593             func => [grep /^archive_/, keys %Archive::Libarchive::FFI::],
594             const => [grep /^(AE_|ARCHIVE_)/, keys %Archive::Libarchive::FFI::];
595             }; die $@ if $@;
596              
597             1;
598              
599             __END__