From d0f50febbb05483370d9cf5b1355e4224683a29f Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 22 Apr 2014 16:27:43 +0100 Subject: [PATCH] added vips_foreign_load_buffer() --- ChangeLog | 3 +- compile | 347 +++++++++++++++++++++++++++++++++ libvips/foreign/foreign.c | 80 +++++++- libvips/foreign/jpeg2vips.c | 19 +- libvips/foreign/jpegload.c | 7 + libvips/foreign/pngload.c | 1 + libvips/foreign/tiff.h | 1 + libvips/foreign/tiff2vips.c | 20 +- libvips/foreign/tiffload.c | 1 + libvips/foreign/vipsjpeg.h | 1 + libvips/foreign/vipspng.c | 12 +- libvips/foreign/vipspng.h | 1 + libvips/foreign/webp.h | 1 + libvips/foreign/webp2vips.c | 12 +- libvips/foreign/webpload.c | 1 + libvips/include/vips/foreign.h | 10 + 16 files changed, 506 insertions(+), 11 deletions(-) create mode 100755 compile diff --git a/ChangeLog b/ChangeLog index 04a1dffa..d76f1f81 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,7 +22,8 @@ argument order - support 16-bit palette TIFFs, plus palette TIFFs can have an alpha - add ".vips" as an alternative suffix for vips files -- add vips_tiffload_buffer() +- added vips_tiffload_buffer() +- added vips_foreign_load_buffer() 6/3/14 started 7.38.6 - grey ramp minimum was wrong diff --git a/compile b/compile new file mode 100755 index 00000000..531136b0 --- /dev/null +++ b/compile @@ -0,0 +1,347 @@ +#! /bin/sh +# Wrapper for compilers which do not understand '-c -o'. + +scriptversion=2012-10-14.11; # UTC + +# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +nl=' +' + +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent tools from complaining about whitespace usage. +IFS=" "" $nl" + +file_conv= + +# func_file_conv build_file lazy +# Convert a $build file to $host form and store it in $file +# Currently only supports Windows hosts. If the determined conversion +# type is listed in (the comma separated) LAZY, no conversion will +# take place. +func_file_conv () +{ + file=$1 + case $file in + / | /[!/]*) # absolute file, and not a UNC file + if test -z "$file_conv"; then + # lazily determine how to convert abs files + case `uname -s` in + MINGW*) + file_conv=mingw + ;; + CYGWIN*) + file_conv=cygwin + ;; + *) + file_conv=wine + ;; + esac + fi + case $file_conv/,$2, in + *,$file_conv,*) + ;; + mingw/*) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; + cygwin/*) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine/*) + file=`winepath -w "$file" || echo "$file"` + ;; + esac + ;; + esac +} + +# func_cl_dashL linkdir +# Make cl look for libraries in LINKDIR +func_cl_dashL () +{ + func_file_conv "$1" + if test -z "$lib_path"; then + lib_path=$file + else + lib_path="$lib_path;$file" + fi + linker_opts="$linker_opts -LIBPATH:$file" +} + +# func_cl_dashl library +# Do a library search-path lookup for cl +func_cl_dashl () +{ + lib=$1 + found=no + save_IFS=$IFS + IFS=';' + for dir in $lib_path $LIB + do + IFS=$save_IFS + if $shared && test -f "$dir/$lib.dll.lib"; then + found=yes + lib=$dir/$lib.dll.lib + break + fi + if test -f "$dir/$lib.lib"; then + found=yes + lib=$dir/$lib.lib + break + fi + if test -f "$dir/lib$lib.a"; then + found=yes + lib=$dir/lib$lib.a + break + fi + done + IFS=$save_IFS + + if test "$found" != yes; then + lib=$lib.lib + fi +} + +# func_cl_wrapper cl arg... +# Adjust compile command to suit cl +func_cl_wrapper () +{ + # Assume a capable shell + lib_path= + shared=: + linker_opts= + for arg + do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + eat=1 + case $2 in + *.o | *.[oO][bB][jJ]) + func_file_conv "$2" + set x "$@" -Fo"$file" + shift + ;; + *) + func_file_conv "$2" + set x "$@" -Fe"$file" + shift + ;; + esac + ;; + -I) + eat=1 + func_file_conv "$2" mingw + set x "$@" -I"$file" + shift + ;; + -I*) + func_file_conv "${1#-I}" mingw + set x "$@" -I"$file" + shift + ;; + -l) + eat=1 + func_cl_dashl "$2" + set x "$@" "$lib" + shift + ;; + -l*) + func_cl_dashl "${1#-l}" + set x "$@" "$lib" + shift + ;; + -L) + eat=1 + func_cl_dashL "$2" + ;; + -L*) + func_cl_dashL "${1#-L}" + ;; + -static) + shared=false + ;; + -Wl,*) + arg=${1#-Wl,} + save_ifs="$IFS"; IFS=',' + for flag in $arg; do + IFS="$save_ifs" + linker_opts="$linker_opts $flag" + done + IFS="$save_ifs" + ;; + -Xlinker) + eat=1 + linker_opts="$linker_opts $2" + ;; + -*) + set x "$@" "$1" + shift + ;; + *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) + func_file_conv "$1" + set x "$@" -Tp"$file" + shift + ;; + *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) + func_file_conv "$1" mingw + set x "$@" "$file" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift + done + if test -n "$linker_opts"; then + linker_opts="-link$linker_opts" + fi + exec "$@" $linker_opts + exit 1 +} + +eat= + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand '-c -o'. +Remove '-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file 'INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; + cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) + func_cl_wrapper "$@" # Doesn't return... + ;; +esac + +ofile= +cfile= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + # So we strip '-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no '-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # '.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` + +# Create the lock directory. +# Note: use '[/\\:.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + test "$cofile" = "$ofile" || mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index 33a01577..c754abe6 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -505,7 +505,7 @@ vips_foreign_load_new_from_foreign_sub( VipsForeignLoadClass *load_class, * * Searches for an operation you could use to load @filename. * - * See also: vips_foreign_read(). + * See also: vips_foreign_load(). * * Returns: the name of an operation on success, %NULL on error */ @@ -532,6 +532,46 @@ vips_foreign_find_load( const char *filename ) return( G_OBJECT_CLASS_NAME( load_class ) ); } +/* Can this VipsForeign open this buffer? + */ +static void * +vips_foreign_find_load_buffer_sub( VipsForeignLoadClass *load_class, + void **buf, size_t *len ) +{ + if( load_class->is_a_buffer && + load_class->is_a_buffer( *buf, *len ) ) + return( load_class ); + + return( NULL ); +} + +/** + * vips_foreign_find_load: + * @filename: file to find a loader for + * + * Searches for an operation you could use to load @filename. + * + * See also: vips_foreign_load_buffer(). + * + * Returns: the name of an operation on success, %NULL on error + */ +const char * +vips_foreign_find_load_buffer( void *buf, size_t len ) +{ + VipsForeignLoadClass *load_class; + + if( !(load_class = (VipsForeignLoadClass *) vips_foreign_map( + "VipsForeignLoad", + (VipsSListMap2Fn) vips_foreign_find_load_buffer_sub, + &buf, &len )) ) { + vips_error( "VipsForeignLoad", + "%s", _( "buffer is not in a known format" ) ); + return( NULL ); + } + + return( G_OBJECT_CLASS_NAME( load_class ) ); +} + /** * vips_foreign_find_load_options: * @filename: file to find a loader for @@ -1473,6 +1513,44 @@ vips_foreign_load( const char *filename, VipsImage **out, ... ) return( result ); } +/** + * vips_foreign_load_buffer: + * @buf: start of memory buffer + * @len: length of memory buffer + * @out: output image + * @...: %NULL-terminated list of optional named arguments + * + * Loads @buf, @len into @out using the loader recommended by + * vips_foreign_find_load_buffer(). + * + * See also: vips_foreign_save(), vips_foreign_load_options(). + * + * Returns: 0 on success, -1 on error + */ +int +vips_foreign_load_buffer( void *buf, size_t len, VipsImage **out, ... ) +{ + const char *operation; + VipsArea *area; + va_list ap; + int result; + + if( !(operation = vips_foreign_find_load_buffer( buf, len )) ) + return( -1 ); + + /* We don't take a copy of the data or free it. + */ + area = vips_area_new_blob( NULL, buf, len ); + + va_start( ap, out ); + result = vips_call_split( operation, ap, area, out ); + va_end( ap ); + + vips_area_unref( area ); + + return( result ); +} + /** * vips_foreign_save: * @in: image to write diff --git a/libvips/foreign/jpeg2vips.c b/libvips/foreign/jpeg2vips.c index 0eabd0fa..2483de3c 100644 --- a/libvips/foreign/jpeg2vips.c +++ b/libvips/foreign/jpeg2vips.c @@ -1247,14 +1247,27 @@ vips__jpeg_read_buffer( void *buf, size_t len, VipsImage *out, return( result ); } +int +vips__isjpeg_buffer( void *buf, size_t len ) +{ + guchar *str = (guchar *) buf; + + if( len >= 2 && + str[0] == 0xff && + str[1] == 0xd8 ) + return( 1 ); + + return( 0 ); +} + int vips__isjpeg( const char *filename ) { unsigned char buf[2]; - if( vips__get_bytes( filename, buf, 2 ) ) - if( (int) buf[0] == 0xff && (int) buf[1] == 0xd8 ) - return( 1 ); + if( vips__get_bytes( filename, buf, 2 ) && + vips__isjpeg_buffer( buf, 2 ) ) + return( 1 ); return( 0 ); } diff --git a/libvips/foreign/jpegload.c b/libvips/foreign/jpegload.c index c24dd690..7c9c1609 100644 --- a/libvips/foreign/jpegload.c +++ b/libvips/foreign/jpegload.c @@ -287,6 +287,12 @@ vips_foreign_load_jpeg_buffer_load( VipsForeignLoad *load ) return( 0 ); } +static gboolean +vips_foreign_load_jpeg_buffer_is_a( void *buf, size_t len ) +{ + return( vips__isjpeg_buffer( buf, len ) ); +} + static void vips_foreign_load_jpeg_buffer_class_init( VipsForeignLoadJpegBufferClass *class ) @@ -301,6 +307,7 @@ vips_foreign_load_jpeg_buffer_class_init( object_class->nickname = "jpegload_buffer"; object_class->description = _( "load jpeg from buffer" ); + load_class->is_a_buffer = vips_foreign_load_jpeg_buffer_is_a; load_class->header = vips_foreign_load_jpeg_buffer_header; load_class->load = vips_foreign_load_jpeg_buffer_load; diff --git a/libvips/foreign/pngload.c b/libvips/foreign/pngload.c index a4954f66..2d1ba065 100644 --- a/libvips/foreign/pngload.c +++ b/libvips/foreign/pngload.c @@ -198,6 +198,7 @@ vips_foreign_load_png_buffer_class_init( VipsForeignLoadPngBufferClass *class ) object_class->nickname = "pngload_buffer"; object_class->description = _( "load png from buffer" ); + load_class->is_a_buffer = vips__png_ispng_buffer; load_class->header = vips_foreign_load_png_buffer_header; load_class->load = vips_foreign_load_png_buffer_load; diff --git a/libvips/foreign/tiff.h b/libvips/foreign/tiff.h index 0813230f..4cb489d1 100644 --- a/libvips/foreign/tiff.h +++ b/libvips/foreign/tiff.h @@ -54,6 +54,7 @@ int vips__tiff_read_header( const char *filename, VipsImage *out, int page ); int vips__tiff_read( const char *filename, VipsImage *out, int page, gboolean readbehind ); gboolean vips__istifftiled( const char *filename ); +gboolean vips__istiff_buffer( void *buf, size_t len ); gboolean vips__istiff( const char *filename ); int vips__tiff_read_header_buffer( void *buf, size_t len, VipsImage *out, diff --git a/libvips/foreign/tiff2vips.c b/libvips/foreign/tiff2vips.c index fee5ff68..19ec69e0 100644 --- a/libvips/foreign/tiff2vips.c +++ b/libvips/foreign/tiff2vips.c @@ -1897,15 +1897,27 @@ vips__istifftiled( const char *filename ) return( tiled ); } +gboolean +vips__istiff_buffer( void *buf, size_t len ) +{ + char *str = (char *) buf; + + if( len >= 2 && + ((str[0] == 'M' && str[1] == 'M') || + (str[0] == 'I' && str[1] == 'I')) ) + return( TRUE ); + + return( FALSE ); +} + gboolean vips__istiff( const char *filename ) { unsigned char buf[2]; - if( vips__get_bytes( filename, buf, 2 ) ) - if( (buf[0] == 'M' && buf[1] == 'M') || - (buf[0] == 'I' && buf[1] == 'I') ) - return( TRUE ); + if( vips__get_bytes( filename, buf, 2 ) && + vips__istiff_buffer( buf, 2 ) ) + return( TRUE ); return( FALSE ); } diff --git a/libvips/foreign/tiffload.c b/libvips/foreign/tiffload.c index 1672faf7..a5c19b95 100644 --- a/libvips/foreign/tiffload.c +++ b/libvips/foreign/tiffload.c @@ -256,6 +256,7 @@ vips_foreign_load_tiff_buffer_class_init( object_class->nickname = "tiffload_buffer"; object_class->description = _( "load tiff from buffer" ); + load_class->is_a_buffer = vips__istiff_buffer; load_class->header = vips_foreign_load_tiff_buffer_header; load_class->load = vips_foreign_load_tiff_buffer_load; diff --git a/libvips/foreign/vipsjpeg.h b/libvips/foreign/vipsjpeg.h index 3e2872c2..c4271add 100644 --- a/libvips/foreign/vipsjpeg.h +++ b/libvips/foreign/vipsjpeg.h @@ -46,6 +46,7 @@ int vips__jpeg_write_buffer( VipsImage *in, gboolean optimize_coding, gboolean progressive, gboolean strip, gboolean no_subsample ); +int vips__isjpeg_buffer( void *buf, size_t len ); int vips__isjpeg( const char *filename ); int vips__jpeg_read_file( const char *name, VipsImage *out, gboolean header_only, int shrink, gboolean fail, gboolean readbehind ); diff --git a/libvips/foreign/vipspng.c b/libvips/foreign/vipspng.c index 5062741a..31ae0895 100644 --- a/libvips/foreign/vipspng.c +++ b/libvips/foreign/vipspng.c @@ -561,13 +561,23 @@ vips__png_read( const char *filename, VipsImage *out, gboolean readbehind ) return( 0 ); } +int +vips__png_ispng_buffer( void *buf, size_t len ) +{ + if( len >= 8 && + !png_sig_cmp( buf, 0, 8 ) ) + return( TRUE ); + + return( FALSE ); +} + int vips__png_ispng( const char *filename ) { unsigned char buf[8]; return( vips__get_bytes( filename, buf, 8 ) && - !png_sig_cmp( buf, 0, 8 ) ); + vips__png_ispng_buffer( buf, 8 ) ); } static void diff --git a/libvips/foreign/vipspng.h b/libvips/foreign/vipspng.h index 051ac55b..0bcd6467 100644 --- a/libvips/foreign/vipspng.h +++ b/libvips/foreign/vipspng.h @@ -37,6 +37,7 @@ extern "C" { int vips__png_header( const char *name, VipsImage *out ); int vips__png_read( const char *name, VipsImage *out, gboolean readbehind ); +int vips__png_ispng_buffer( void *buf, size_t len ); int vips__png_ispng( const char *filename ); gboolean vips__png_isinterlaced( const char *filename ); extern const char *vips__png_suffs[]; diff --git a/libvips/foreign/webp.h b/libvips/foreign/webp.h index 7441b893..28bf0906 100644 --- a/libvips/foreign/webp.h +++ b/libvips/foreign/webp.h @@ -37,6 +37,7 @@ extern "C" { extern const char *vips__webp_suffs[]; +int vips__iswebp_buffer( void *buf, size_t len ); int vips__iswebp( const char *filename ); int vips__webp_read_file_header( const char *name, VipsImage *out ); diff --git a/libvips/foreign/webp2vips.c b/libvips/foreign/webp2vips.c index 2611d4ff..2bd93736 100644 --- a/libvips/foreign/webp2vips.c +++ b/libvips/foreign/webp2vips.c @@ -87,13 +87,23 @@ typedef struct { WebPIDecoder *idec; } Read; +int +vips__iswebp_buffer( void *buf, size_t len ) +{ + if( len >= MINIMAL_HEADER && + WebPGetInfo( buf, MINIMAL_HEADER, NULL, NULL ) ) + return( 1 ); + + return( 0 ); +} + int vips__iswebp( const char *filename ) { unsigned char header[MINIMAL_HEADER]; if( vips__get_bytes( filename, header, MINIMAL_HEADER ) && - WebPGetInfo( header, MINIMAL_HEADER, NULL, NULL ) ) + vips__iswebp_buffer( header, MINIMAL_HEADER ) ) return( 1 ); return( 0 ); diff --git a/libvips/foreign/webpload.c b/libvips/foreign/webpload.c index 2099e8bf..9dd79249 100644 --- a/libvips/foreign/webpload.c +++ b/libvips/foreign/webpload.c @@ -233,6 +233,7 @@ vips_foreign_load_webp_buffer_class_init( object_class->nickname = "webpload_buffer"; object_class->description = _( "load webp from buffer" ); + load_class->is_a_buffer = vips__iswebp_buffer; load_class->header = vips_foreign_load_webp_buffer_header; load_class->load = vips_foreign_load_webp_buffer_load; diff --git a/libvips/include/vips/foreign.h b/libvips/include/vips/foreign.h index 0e13339a..f9d4d802 100644 --- a/libvips/include/vips/foreign.h +++ b/libvips/include/vips/foreign.h @@ -161,6 +161,13 @@ typedef struct _VipsForeignLoadClass { */ gboolean (*is_a)( const char * ); + /* Is a buffer in this format. + * + * This function should return %TRUE if the buffer contains an image of + * this type. + */ + gboolean (*is_a_buffer)( void *, size_t ); + /* Get the flags from a filename. * * This function should examine the file and return a set @@ -207,6 +214,7 @@ typedef struct _VipsForeignLoadClass { GType vips_foreign_load_get_type( void ); const char *vips_foreign_find_load( const char *filename ); +const char *vips_foreign_find_load_buffer( void *buf, size_t len ); const char *vips_foreign_find_load_options( const char *filename ); VipsForeignFlags vips_foreign_flags( const char *loader, const char *filename ); @@ -306,6 +314,8 @@ const char *vips_foreign_find_save_options( const char *filename ); */ int vips_foreign_load( const char *filename, VipsImage **out, ... ) __attribute__((sentinel)); +int vips_foreign_load_buffer( void *buf, size_t len, VipsImage **out, ... ) + __attribute__((sentinel)); int vips_foreign_save( VipsImage *in, const char *filename, ... ) __attribute__((sentinel));