start adding mmap input to stream

This commit is contained in:
John Cupitt 2019-10-15 10:09:24 +01:00
parent 88aa1bca86
commit 28daeb1a8a
4 changed files with 118 additions and 1 deletions

View File

@ -136,6 +136,7 @@ void *vips__link_map( VipsImage *image, gboolean upstream,
char *vips__b64_encode( const unsigned char *data, size_t data_length );
unsigned char *vips__b64_decode( const char *buffer, size_t *data_length );
gboolean vips__mmap_supported( int fd );
void *vips__mmap( int fd, int writeable, size_t length, gint64 offset );
int vips__munmap( const void *start, size_t length );
int vips_mapfile( VipsImage * );

View File

@ -129,6 +129,11 @@ typedef struct _VipsStreamInput {
*/
gboolean seekable;
/* TRUE is this descriptor supports mmap(). If not, then we have to
* read() the whole thing.
*/
gboolean mapable;
/*< private >*/
/* The current read point.
@ -148,6 +153,11 @@ typedef struct _VipsStreamInput {
*/
VipsBlob *blob;
/* If we've mmaped the file, the base and length.
*/
const void *baseaddr;
size_t length;
} VipsStreamInput;
typedef struct _VipsStreamInputClass {

View File

@ -90,6 +90,59 @@
#include <io.h>
#endif /*OS_WIN32*/
/* Does this fd support mmap. Pipes won't, for example.
*/
gboolean
vips__mmap_supported( int fd )
{
void *baseaddr;
size_t length = 4096;
off_t offset = 0;
#ifdef OS_WIN32
{
HANDLE hFile = (HANDLE) _get_osfhandle( fd );
DWORD flProtect;
HANDLE hMMFile;
DWORD dwDesiredAccess;
ULARGE_INTEGER quad;
DWORD dwFileOffsetHigh;
DWORD dwFileOffsetLow;
flProtect = PAGE_READONLY;
if( !(hMMFile = CreateFileMapping( hFile,
NULL, flProtect, 0, 0, NULL )) )
return( FALSE );
dwDesiredAccess = FILE_MAP_READ;
quad.QuadPart = offset;
dwFileOffsetLow = quad.LowPart;
dwFileOffsetHigh = quad.HighPart;
if( !(baseaddr = (char *)MapViewOfFile( hMMFile, dwDesiredAccess,
dwFileOffsetHigh, dwFileOffsetLow, length )) ) {
CloseHandle( hMMFile );
return( FALSE );
}
CloseHandle( hMMFile );
UnmapViewOfFile( baseaddr );
}
#else /*!OS_WIN32*/
{
int prot = PROT_READ;
int flags = MAP_SHARED;
baseaddr = mmap( 0, length, prot, flags, fd, (off_t) offset );
if( baseaddr == MAP_FAILED )
return( FALSE );
munmap( baseaddr, length );
}
#endif /*OS_WIN32*/
return( TRUE );
}
void *
vips__mmap( int fd, int writeable, size_t length, gint64 offset )
{

View File

@ -63,6 +63,7 @@
#include <unistd.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include <vips/debug.h>
/* Try to make an O_BINARY ... sometimes need the leading '_'.
@ -270,6 +271,9 @@ vips_stream_input_build( VipsObject *object )
*/
if( lseek( stream->descriptor, 0, SEEK_CUR ) != -1 )
input->seekable = TRUE;
if( vips__mmap_supported( stream->descriptor ) )
input->mapable = TRUE;
}
if( vips_object_argument_isset( object, "blob" ) )
@ -396,6 +400,7 @@ vips_stream_input_class_init( VipsStreamInputClass *class )
static void
vips_stream_input_init( VipsStreamInput *input )
{
input->length = -1;
}
/**
@ -606,9 +611,57 @@ vips_stream_input_read( VipsStreamInput *input,
return( bytes_read );
}
unsigned char *
static const void *
vips_stream_input_try_map( VipsStreamInput *input, size_t *length )
{
VipsStream *stream = VIPS_STREAM( input );
if( input->length < 0 )
input->length = vips_file_length( stream->descriptor );
if( input->length < 0 )
return( NULL );
if( !input->baseaddr ) {
input->baseaddr = vips__mmap( stream->descriptor,
FALSE, input->length, 0 );
if( !input->baseaddr )
return( NULL );
}
if( length )
*length = input->length;
return( input->baseaddr );
}
const void *
vips_stream_input_map( VipsStreamInput *input, size_t *length )
{
/* Memory source ... easy!
*/
if( input->blob )
return( vips_blob_get( input->blob, length ) );
/* An input that supports mmap.
*/
if( input->mapable ) {
if( !input->baseaddr ) {
input->baseaddr = vips_stream_input_try_map( input,
&input->length );
if( !input->baseaddr )
return( NULL );
}
if( length )
*length = input->length;
return( input->baseaddr );
}
/* Have to read() the whole thing.
*/
return( NULL );
}
int