NAME
FFI::Platypus::Buffer - Convert scalars to C buffers
VERSION
version 1.24
SYNOPSIS
use FFI::Platypus::Buffer;
my($pointer, $size) = scalar_to_buffer $scalar;
my $scalar2 = buffer_to_scalar $pointer, $size;
DESCRIPTION
A common pattern in C is to pass a "buffer" or region of memory into a function with a pair of arguments, an opaque pointer and the size of the memory region. In Perl the equivalent structure is a scalar containing a string of bytes. This module provides portable functions for converting a Perl string or scalar into a buffer and back.
These functions are implemented using pack and unpack and so they should be relatively fast.
Both functions are exported by default, but you can explicitly export one or neither if you so choose.
A better way to do this might be with custom types see FFI::Platypus::API and FFI::Platypus::Type. These functions were taken from the now obsolete FFI::Util module, as they may be useful in some cases.
Caution: This module provides great power in the way that you interact with C code, but with that power comes great responsibility. Since you are dealing with blocks of memory you need to take care to understand the underlying ownership model of these pointers.
FUNCTIONS
scalar_to_buffer
my($pointer, $size) = scalar_to_buffer $scalar;
Convert a string scalar into a buffer. Returned in order are a pointer to the start of the string scalar's memory region and the size of the region.
You should NEVER try to free $pointer
.
When you pass this pointer and size into a C function, it has direct access to the data stored in your scalar, so it is important that you not resize or free the scalar while it is in use by the C code. Typically if you are passing a buffer into a C function which reads or writes to the buffer, but does not keep the pointer for later use you are okay. If the buffer is in use long term by the C code, then you should consider copying the buffer instead. For example:
use FFI::Platypus::Buffer qw( scalar_to_buffer );
use FFI::Platypus::Memory qw( malloc memcpy free )
my($ptr, $size) = scalar_to_buffer $string;
c_function_thaat_does_not_keep_ptr( $ptr, $size); # okay
my($ptr, $size) = scalar_to_buffer $string;
my $ptr_copy = malloc($size);
memcpy($ptr_copy, $ptr, $size);
c_function_that_DOES_keep_ptr( $ptr_copy, $size); # also okay
...
# later when you know that the c code is no longer using the pointer
# Since you allocated the copy, you are responsible for free'ing it.
free($ptr_copy);
scalar_to_pointer
my $pointer = scalar_to_pointer $scalar;
Get the pointer to the scalar. (Similar to scalar_to_buffer
above, but the size of the scalar is not computed or returned).
Not exported by default, but may be exported on request.
buffer_to_scalar
my $scalar = buffer_to_scalar $pointer, $size;
Convert the buffer region defined by the pointer and size into a string scalar.
Because of the way memory management works in Perl, the buffer is copied from the buffer into the scalar. If this pointer was returned from C land, then you should only free it if you allocated it.
grow
grow $scalar, $size, \%options;
Ensure that the scalar can contain at least $size
bytes. The following are recognized:
- clear => boolean
-
If true,
$scalar
is cleared prior to being enlarged. This avoids copying the existing contents to the reallocated memory if they are not needed.For example, after $scalar = "my string"; grow $scalar, 100, { clear => 0 };
$scalar == "my string"
, while after$scalar = "my string"; grow $scalar, 100;
length($scalar) == 0
It defaults to
true
. - set_length => boolean
-
If true, the length of the string in the
$scalar
is set to$size
. (See the discussion in "set_used_length".) This is useful if a foreign function writes exactly$size
bytes to$scalar
, as it avoids a subsequent call toset_used_length
. Contrast thisgrow my $scalar, 100; read_exactly_100_bytes_into_scalar( scalar_to_pointer($scalar) ); @chars = unpack( 'c*', $scalar );
with this:
grow my $scalar, 100, { set_length => 0 }; read_exactly_100_bytes_into_scalar( scalar_to_pointer($scalar) ); set_used_length( $scalar, 100 ); @chars = unpack( 'c*', $scalar );
It defaults to
true
.
Any pointers obtained with scalar_to_pointer
or scalar_to_buffer
are no longer valid after growing the scalar.
Not exported by default, but may be exported on request.
set_used_length
set_used_length $scalar, $length;
Update Perl's notion of the length of the string in the scalar. A string scalar keeps track of two lengths: the number of available bytes and the number of used bytes. When a string scalar is used as a buffer by a foreign function, it is necessary to indicate to Perl how many bytes were actually written to it so that Perl's string functions (such as substr
or unpack
) will work correctly.
If $length
is larger than what the scalar can hold, it is set to the maximum possible size.
In the following example, the foreign routine read_doubles
may fill the buffer with up to a set number of doubles, returning the number actually written.
my $sizeof_double = $ffi->sizeof( 'double' );
my $max_doubles = 100;
my $max_length = $max_doubles * $sizeof_double;
my $buffer; # length($buffer) == 0
grow $buffer, $max_length; # length($buffer) is still 0
my $pointer = scalar_to_pointer($buffer);
my $num_read = read_doubles( $pointer, $max_doubles );
# length($buffer) is still == 0
set_used_length $buffer, $num_read * $sizeof_double;
# length($buffer) is finally != 0
# unpack the native doubles into a Perl array
my @doubles = unpack( 'd*', $buffer ); # @doubles == $num_read
Not exported by default, but may be exported on request.
SEE ALSO
- FFI::Platypus
-
Main Platypus documentation.
AUTHOR
Author: Graham Ollis <plicease@cpan.org>
Contributors:
Bakkiaraj Murugesan (bakkiaraj)
Dylan Cali (calid)
pipcet
Zaki Mughal (zmughal)
Fitz Elliott (felliott)
Vickenty Fesunov (vyf)
Gregor Herrmann (gregoa)
Shlomi Fish (shlomif)
Damyan Ivanov
Ilya Pavlov (Ilya33)
Petr Pisar (ppisar)
Mohammad S Anwar (MANWAR)
Håkon Hægland (hakonhagland, HAKONH)
Meredith (merrilymeredith, MHOWARD)
Diab Jerius (DJERIUS)
COPYRIGHT AND LICENSE
This software is copyright (c) 2015,2016,2017,2018,2019 by Graham Ollis.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.