/* Split filename into name / mode components. name and mode should both be * FILENAME_MAX chars. * * We look for the ':' splitting the name and mode by searching for the * rightmost occurence of the regexp ".[A-Za-z0-9]+:". Example: consider the * horror that is * * c:\silly:dir:name\fr:ed.tif:jpeg:95,,,,c:\icc\srgb.icc * */ void vips_filename_split( const char *path, char *name, char *mode ) { char *p; vips_strncpy( name, path, FILENAME_MAX ); /* Search back towards start stopping at each ':' char. */ for( p = name + strlen( name ) - 1; p > name; p -= 1 ) if( *p == ':' ) { char *q; for( q = p - 1; isalnum( *q ) && q > name; q -= 1 ) ; if( *q == '.' ) break; } if( *p == ':' ) { vips_strncpy( mode, p + 1, FILENAME_MAX ); *p = '\0'; } else strcpy( mode, "" ); }
/* Find the prefix part of a dir ... name is the name of this prog from argv0. * * dir name guess prefix * * /home/john/vips-7.6.4/bin/vips-7.6 vips-7.6 /home/john/vips-7.6.4 * /usr/local/bin/ip ip /usr/local * * all other forms ... return NULL. */ static char * extract_prefix( const char *dir, const char *name ) { char edir[PATH_MAX]; char vname[PATH_MAX]; int i; #ifdef DEBUG printf( "extract_prefix: trying for dir = \"%s\", name = \"%s\"\n", dir, name ); #endif /*DEBUG*/ /* Is dir relative? Prefix with cwd. */ if( !g_path_is_absolute( dir ) ) { vips_snprintf( edir, PATH_MAX, "%s" G_DIR_SEPARATOR_S "%s", get_current_dir(), dir ); } else { vips_strncpy( edir, dir, PATH_MAX ); } /* Chop off the trailing prog name, plus the trailing * G_DIR_SEPARATOR_S. */ if( !vips_ispostfix( edir, name ) ) return( NULL ); vips_strncpy( vname, edir, PATH_MAX ); vname[strlen( edir ) - strlen( name ) - 1] = '\0'; /* Remove any "/./", any trailing "/.", any trailing "/". */ for( i = 0; i < (int) strlen( vname ); i++ ) if( vips_isprefix( G_DIR_SEPARATOR_S "." G_DIR_SEPARATOR_S, vname + i ) ) memcpy( vname + i, vname + i + 2, strlen( vname + i + 2 ) + 1 ); if( vips_ispostfix( vname, G_DIR_SEPARATOR_S "." ) ) vname[strlen( vname ) - 2] = '\0'; if( vips_ispostfix( vname, G_DIR_SEPARATOR_S ) ) vname[strlen( vname ) - 1] = '\0'; #ifdef DEBUG printf( "extract_prefix: canonicalised path = \"%s\"\n", vname ); #endif /*DEBUG*/ /* Ought to be a "/bin" at the end now. */ if( !vips_ispostfix( vname, G_DIR_SEPARATOR_S "bin" ) ) return( NULL ); vname[strlen( vname ) - strlen( G_DIR_SEPARATOR_S "bin" )] = '\0'; #ifdef DEBUG printf( "extract_prefix: found \"%s\"\n", vname ); #endif /*DEBUG*/ return( vips_strdup( NULL, vname ) ); }
/* Split a vips8-style filename + options. * * filename and option_string must be VIPS_PATH_MAX in length. */ void vips__filename_split8( const char *name, char *filename, char *option_string ) { char *p; vips_strncpy( filename, name, VIPS_PATH_MAX ); if( (p = (char *) vips__find_rightmost_brackets( filename )) ) { vips_strncpy( option_string, p, VIPS_PATH_MAX ); *p = '\0'; } else vips_strncpy( option_string, "", VIPS_PATH_MAX ); }
/* Wrapper over (v)snprintf() ... missing on old systems. */ int vips_vsnprintf( char *str, size_t size, const char *format, va_list ap ) { #ifdef HAVE_VSNPRINTF return( vsnprintf( str, size, format, ap ) ); #else /*HAVE_VSNPRINTF*/ /* Bleurg! */ int n; static char buf[MAX_BUF]; if( size > MAX_BUF ) vips_error_exit( "panic: buffer overflow " "(request to write %d bytes to buffer of %d bytes)", size, MAX_BUF ); n = vsprintf( buf, format, ap ); if( n > MAX_BUF ) vips_error_exit( "panic: buffer overflow " "(%d bytes written to buffer of %d bytes)", n, MAX_BUF ); vips_strncpy( str, buf, size ); return( n ); #endif /*HAVE_VSNPRINTF*/ }
/* Wrapper over (v)snprintf() ... missing on old systems. */ int vips_vsnprintf( char *str, size_t size, const char *format, va_list ap ) { #ifdef HAVE_VSNPRINTF return( vsnprintf( str, size, format, ap ) ); #else /*HAVE_VSNPRINTF*/ /* Bleurg! */ int n; static char buf[MAX_BUF]; /* We can't return an error code, we may already have trashed the * stack. We must stop immediately. */ if( size > MAX_BUF ) vips_error_exit( "panic: buffer overflow " "(request to write %d bytes to buffer of %d bytes)", size, MAX_BUF ); n = vsprintf( buf, format, ap ); if( n > MAX_BUF ) vips_error_exit( "panic: buffer overflow " "(%d bytes written to buffer of %d bytes)", n, MAX_BUF ); vips_strncpy( str, buf, size ); return( n ); #endif /*HAVE_VSNPRINTF*/ }
/* Look for a file along PATH. If we find it, look for an enclosing prefix. */ static char * find_file( const char *name ) { const char *path = g_getenv( "PATH" ); char *prefix; char full_path[PATH_MAX]; if( !path ) return( NULL ); #ifdef DEBUG printf( "vips_guess_prefix: g_getenv( \"PATH\" ) == \"%s\"\n", path ); #endif /*DEBUG*/ #ifdef OS_WIN32 /* Windows always searches '.' first, so prepend cwd to path. */ vips_snprintf( full_path, PATH_MAX, "%s" G_SEARCHPATH_SEPARATOR_S "%s", get_current_dir(), path ); #else /*!OS_WIN32*/ vips_strncpy( full_path, path, PATH_MAX ); #endif /*OS_WIN32*/ if( (prefix = scan_path( full_path, name )) ) return( prefix ); return( NULL ); }
/* Given (eg.) "/poop/somefile.png", write @im to the thumbnail name, * (eg.) "/poop/tn_somefile.jpg". */ static int thumbnail_write( VipsObject *process, VipsImage *im, const char *filename ) { char *file; char *p; char buf[FILENAME_MAX]; char *output_name; file = g_path_get_basename( filename ); /* Remove the suffix from the file portion. */ if( (p = strrchr( file, '.' )) ) *p = '\0'; /* Don't use vips_snprintf(), we only want to optionally substitute a * single %s. */ vips_strncpy( buf, output_format, FILENAME_MAX ); vips__substitute( buf, FILENAME_MAX, file ); /* output_format can be an absolute path, in which case we discard the * path from the incoming file. */ if( g_path_is_absolute( output_format ) ) output_name = g_strdup( buf ); else { char *dir; dir = g_path_get_dirname( filename ); output_name = g_build_filename( dir, buf, NULL ); g_free( dir ); } vips_info( "vipsthumbnail", "thumbnailing %s as %s", filename, output_name ); g_free( file ); if( vips_image_write_to_file( im, output_name, NULL ) ) { g_free( output_name ); return( -1 ); } g_free( output_name ); return( 0 ); }
/* Fetch a token. If it's a string token terminated by a '[', fetch up to the * matching ']' as well, for example ".jpg[Q=90]". * * Return NULL for end of tokens. */ const char * vips__token_segment( const char *p, VipsToken *token, char *string, int size ) { const char *q; if( !(q = vips__token_must( p, token, string, size )) ) return( NULL ); /* If we stopped on [, read up to the matching ]. */ if( *token == VIPS_TOKEN_STRING && q[0] == '[' ) { VipsToken sub_token; char sub_string[VIPS_PATH_MAX]; int depth; int i; depth = 0; do { if( !(q = vips__token_must( q, &sub_token, sub_string, VIPS_PATH_MAX )) ) return( NULL ); switch( sub_token ) { case VIPS_TOKEN_LEFT: depth += 1; break; case VIPS_TOKEN_RIGHT: depth -= 1; break; default: break; } } while( !(sub_token == VIPS_TOKEN_RIGHT && depth == 0) ); i = VIPS_MIN( q - p, size ); vips_strncpy( string, p, i + 1 ); } return( q ); }
/** * vips_guess_prefix: * @argv0: program name (typically argv[0]) * @env_name: save prefix in this environment variable * * vips_guess_prefix() tries to guess the install directory. You should pass * in the value of argv[0] (the name your program was run as) as a clue to * help it out, plus the name of the environment variable you let the user * override your package install area with (eg. "VIPSHOME"). * * On success, vips_guess_prefix() returns the prefix it discovered, and as a * side effect, sets the environment variable (if it's not set). * * Don't free the return string! * * See also: vips_guess_libdir(). * * Returns: (transfer none): the install prefix as a static string, do not free. */ const char * vips_guess_prefix( const char *argv0, const char *env_name ) { const char *prefix; char *basename; char name[VIPS_PATH_MAX]; /* Already set? */ if( (prefix = g_getenv( env_name )) ) { #ifdef DEBUG printf( "vips_guess_prefix: found \"%s\" in environment\n", prefix ); #endif /*DEBUG*/ return( prefix ); } /* Get the program name from argv0. */ basename = g_path_get_basename( argv0 ); /* Add the exe suffix, if it's missing. */ if( strlen( VIPS_EXEEXT ) > 0 ) { const char *olds[] = { VIPS_EXEEXT }; vips__change_suffix( basename, name, VIPS_PATH_MAX, VIPS_EXEEXT, olds, 1 ); } else vips_strncpy( name, basename, VIPS_PATH_MAX ); g_free( basename ); #ifdef DEBUG printf( "vips_guess_prefix: argv0 = %s\n", argv0 ); printf( "vips_guess_prefix: name = %s\n", name ); #endif /*DEBUG*/ prefix = guess_prefix( argv0, name ); g_setenv( env_name, prefix, TRUE ); return( prefix ); }
static Read * read_new( const char *filename, VipsImage *im ) { Read *read; static int inited = 0; if( !inited ) { #ifdef HAVE_MAGICKCOREGENESIS MagickCoreGenesis( vips_get_argv0(), MagickFalse ); #else /*!HAVE_MAGICKCOREGENESIS*/ InitializeMagick( "" ); #endif /*HAVE_MAGICKCOREGENESIS*/ inited = 1; } if( !(read = VIPS_NEW( im, Read )) ) return( NULL ); read->filename = g_strdup( filename ); read->im = im; read->image = NULL; read->image_info = CloneImageInfo( NULL ); GetExceptionInfo( &read->exception ); read->n_frames = 0; read->frames = NULL; read->frame_height = 0; read->lock = g_mutex_new(); g_signal_connect( im, "close", G_CALLBACK( read_destroy ), read ); if( !read->image_info ) return( NULL ); vips_strncpy( read->image_info->filename, filename, MaxTextExtent ); #ifdef DEBUG printf( "magick2vips: read_new: %s\n", read->filename ); #endif /*DEBUG*/ return( read ); }
/* Break a command-line argument into tokens separated by whitespace. * * Strings can't be adjacent, so "hello world" (without quotes) is a single * string. Strings are written (with \" escaped) into @string. If the string * is larger than @size, it is silently null-termionated and truncated. * * Return NULL for end of tokens. */ const char * vips__token_get( const char *p, VipsToken *token, char *string, int size ) { const char *q; int ch; int n; int i; /* Parse this token with p. */ if( !p ) return( NULL ); /* Skip initial whitespace. */ p += strspn( p, " \t\n\r" ); if( !p[0] ) return( NULL ); switch( (ch = p[0]) ) { case '{': case '[': case '(': case '<': *token = VIPS_TOKEN_LEFT; p += 1; break; case ')': case ']': case '}': case '>': *token = VIPS_TOKEN_RIGHT; p += 1; break; case '=': *token = VIPS_TOKEN_EQUALS; p += 1; break; case ',': *token = VIPS_TOKEN_COMMA; p += 1; break; case '"': case '\'': /* Parse a quoted string. Copy up to ", interpret any \", * error if no closing ". */ *token = VIPS_TOKEN_STRING; do { /* Number of characters until the next quote * character or end of string. */ if( (q = strchr( p + 1, ch )) ) n = q - p + 1; else n = strlen( p + 1 ); /* How much can we copy to the buffer? */ i = VIPS_MIN( n, size ); vips_strncpy( string, p + 1, i ); /* We might have stopped at an escaped quote. If the * string was not truncated, swap the preceding * backslash for a quote. */ if( p[n + 1] == ch && p[n] == '\\' && i == n ) string[i - 1] = ch; string += i; size -= i; p += n + 1; } while( p[0] && p[-1] == '\\' ); p += 1; break; default: /* It's an unquoted string: read up to the next non-string * character. We don't allow two strings next to each other, * so the next break must be bracket, equals, comma. */ *token = VIPS_TOKEN_STRING; n = strcspn( p, "<[{()}]>=," ); i = VIPS_MIN( n, size ); vips_strncpy( string, p, i + 1 ); p += n; /* We remove leading whitespace, so we trim trailing * whitespace from unquoted strings too. Only if the string * hasn't been truncated. */ if( i == n ) while( i > 0 && isspace( string[i - 1] ) ) { string[i - 1] = '\0'; i--; } break; } return( p ); }
static Read * read_new( const char *filename, VipsImage *im, gboolean all_frames, const char *density, int page ) { Read *read; static int inited = 0; if( !inited ) { #ifdef HAVE_MAGICKCOREGENESIS MagickCoreGenesis( vips_get_argv0(), MagickFalse ); #else /*!HAVE_MAGICKCOREGENESIS*/ InitializeMagick( "" ); #endif /*HAVE_MAGICKCOREGENESIS*/ inited = 1; } if( !(read = VIPS_NEW( im, Read )) ) return( NULL ); read->filename = filename ? g_strdup( filename ) : NULL; read->all_frames = all_frames; read->page = page; read->im = im; read->image = NULL; read->image_info = CloneImageInfo( NULL ); GetExceptionInfo( &read->exception ); read->n_frames = 0; read->frames = NULL; read->frame_height = 0; read->lock = vips_g_mutex_new(); g_signal_connect( im, "close", G_CALLBACK( read_close ), read ); if( !read->image_info ) return( NULL ); if( filename ) vips_strncpy( read->image_info->filename, filename, MaxTextExtent ); /* Canvas resolution for rendering vector formats like SVG. */ VIPS_SETSTR( read->image_info->density, density ); #ifdef HAVE_SETIMAGEOPTION /* When reading DICOM images, we want to ignore any * window_center/_width setting, since it may put pixels outside the * 0-65535 range and lose data. * * These window settings are attached as vips metadata, so our caller * can interpret them if it wants. */ SetImageOption( read->image_info, "dcm:display-range", "reset" ); #endif /*HAVE_SETIMAGEOPTION*/ if( !all_frames ) { #ifdef HAVE_NUMBER_SCENES /* I can't find docs for these fields, but this seems to work. */ char page[256]; read->image_info->scene = read->page; read->image_info->number_scenes = 1; /* Some IMs must have the string version set as well. */ vips_snprintf( page, 256, "%d", read->page ); read->image_info->scenes = strdup( page ); #else /*!HAVE_NUMBER_SCENES*/ /* This works with GM 1.2.31 and probably others. */ read->image_info->subimage = read->page; read->image_info->subrange = 1; #endif } #ifdef DEBUG printf( "magick2vips: read_new: %s\n", read->filename ); #endif /*DEBUG*/ return( read ); }