/* Get file length ... 64-bitally. -1 for error. */ gint64 vips_file_length( int fd ) { #ifdef OS_WIN32 struct _stati64 st; if( _fstati64( fd, &st ) == -1 ) { #else /*!OS_WIN32*/ struct stat st; if( fstat( fd, &st ) == -1 ) { #endif /*OS_WIN32*/ vips_error_system( errno, "vips_file_length", "%s", _( "unable to get file stats" ) ); return( -1 ); } return( st.st_size ); } /* Wrap write() up */ int vips__write( int fd, const void *buf, size_t count ) { do { size_t nwritten = write( fd, buf, count ); if( nwritten == (size_t) -1 ) { vips_error_system( errno, "vips__write", "%s", _( "write failed" ) ); return( -1 ); } buf = (void *) ((char *) buf + nwritten); count -= nwritten; } while( count > 0 ); return( 0 ); } #ifdef OS_WIN32 /* Set the create date on a file. On Windows, the create date may be copied * over from an existing file of the same name, unless you reset it. * * See https://blogs.msdn.microsoft.com/oldnewthing/20050715-14/?p=34923 */ void vips__set_create_time( int fd ) { HANDLE handle; SYSTEMTIME st; FILETIME ft; if( (handle = _get_osfhandle( fd )) == INVALID_HANDLE_VALUE ) return; GetSystemTime( &st ); SystemTimeToFileTime( &st, &ft ); SetFileTime( handle, &ft, &ft, &ft ); }
/* Need our own ftruncate(), since ftruncate() on win32 can't do long files. DANGER ... this moves the file pointer to the end of file on win32, but not on *nix; don't make any assumptions about the file pointer position after calling this */ int vips__ftruncate( int fd, gint64 pos ) { #ifdef OS_WIN32 { HANDLE hFile = (HANDLE) _get_osfhandle( fd ); LARGE_INTEGER p; p.QuadPart = pos; if( vips__seek( fd, pos ) ) return( -1 ); if( !SetEndOfFile( hFile ) ) { vips_error_system( GetLastError(), "vips__ftruncate", "%s", _( "unable to truncate" ) ); return( -1 ); } } #else /*!OS_WIN32*/ if( ftruncate( fd, pos ) ) { vips_error_system( errno, "vips__ftruncate", "%s", _( "unable to truncate" ) ); return( -1 ); } #endif /*OS_WIN32*/ return( 0 ); }
/* Get file length ... 64-bitally. -1 for error. */ gint64 vips_file_length( int fd ) { #ifdef OS_WIN32 struct _stati64 st; if( _fstati64( fd, &st ) == -1 ) { #else /*!OS_WIN32*/ struct stat st; if( fstat( fd, &st ) == -1 ) { #endif /*OS_WIN32*/ vips_error_system( errno, "vips_file_length", "%s", _( "unable to get file stats" ) ); return( -1 ); } return( st.st_size ); } /* Wrap write() up */ int vips__write( int fd, const void *buf, size_t count ) { do { size_t nwritten = write( fd, buf, count ); if( nwritten == (size_t) -1 ) { vips_error_system( errno, "vips__write", "%s", _( "write failed" ) ); return( -1 ); } buf = (void *) ((char *) buf + nwritten); count -= nwritten; } while( count > 0 ); return( 0 ); } /* Does a filename contain a directory separator? */ static gboolean filename_hasdir( const char *filename ) { char *dirname; gboolean hasdir; dirname = g_path_get_dirname( filename ); hasdir = (strcmp( dirname, "." ) != 0); g_free( dirname ); return( hasdir ); }
/* Init function for doublevec input. */ static int input_doublevec_init( im_object *obj, char *str ) { im_doublevec_object *dv = *obj; char **strv; int nargs; int i; strv = g_strsplit( str, VEC_SEPS, -1 ); nargs = g_strv_length( strv ); if( !(dv->vec = VIPS_ARRAY( NULL, nargs, double )) ) { g_strfreev( strv ); return( -1 ); } dv->n = nargs; for( i = 0; i < nargs; i++ ) { dv->vec[i] = g_ascii_strtod( strv[i], NULL ); if( errno ) { vips_error_system( errno, "input_doublevec_init", _( "bad double \"%s\"" ), strv[i] ); g_strfreev( strv ); return( -1 ); } } g_strfreev( strv ); return( 0 ); }
/* Open for write for image files. */ int vips__open_image_write( const char *filename, gboolean temp ) { int flags; int fd; flags = MODE_WRITE; #ifdef _O_TEMPORARY /* On Windows, setting O_TEMP gets the file automatically * deleted on process exit, even if the processes crashes. See * vips_image_rewind() for what we do to help on *nix. */ if( temp ) flags |= _O_TEMPORARY; #endif /*_O_TEMPORARY*/ if( (fd = vips_tracked_open( filename, flags, 0666 )) < 0 ) { vips_error_system( errno, "VipsImage", _( "unable to write to \"%s\"" ), filename ); return( -1 ); } return( fd ); }
int vips__munmap( const void *start, size_t length ) { #ifdef OS_WIN32 if( !UnmapViewOfFile( (void *) start ) ) { vips_error_system( GetLastError(), "vips_mapfile", "%s", _( "unable to UnmapViewOfFile" ) ); return( -1 ); } #else /*!OS_WIN32*/ if( munmap( (void *) start, length ) < 0 ) { vips_error_system( errno, "vips_mapfile", "%s", _( "unable to munmap file" ) ); return( -1 ); } #endif /*OS_WIN32*/ return( 0 ); }
/* Like fwrite(), but returns non-zero on error and sets error message. */ int vips__file_write( void *data, size_t size, size_t nmemb, FILE *stream ) { size_t n; if( !data ) return( 0 ); if( (n = fwrite( data, size, nmemb, stream )) != nmemb ) { vips_error_system( errno, "vips__file_write", _( "write error (%zd out of %zd blocks written)" ), n, nmemb ); return( -1 ); } return( 0 ); }
/* Open for read for image files. */ int vips__open_image_read( const char *filename ) { int fd; /* Try to open read-write, so that calls to vips_image_inplace() will * work. When we later mmap this file, we set read-only, so there * is little danger of scrubbing over files we own. */ fd = vips_tracked_open( filename, MODE_READWRITE ); if( fd == -1 ) /* Open read-write failed. Fall back to open read-only. */ fd = vips_tracked_open( filename, MODE_READONLY ); if( fd == -1 ) { vips_error_system( errno, "VipsImage", _( "unable to open \"%s\"" ), filename ); return( -1 ); } return( fd ); }
/* Init function for intvec input. */ static int input_intvec_init( im_object *obj, char *str ) { im_intvec_object *iv = *obj; char **strv; int nargs; int i; strv = g_strsplit( str, VEC_SEPS, -1 ); nargs = g_strv_length( strv ); if( !(iv->vec = VIPS_ARRAY( NULL, nargs, int )) ) { g_strfreev( strv ); return( -1 ); } iv->n = nargs; for( i = 0; i < nargs; i++ ) { long int val= strtol( strv[i], NULL, 10 ); if( errno ) { vips_error_system( errno, "input_intvec_init", _( "bad integer \"%s\"" ), strv[i] ); g_strfreev( strv ); return( -1 ); } if( INT_MAX < val || INT_MIN > val ) { vips_error( "input_intvec_init", "%ld overflows integer type", val ); } iv->vec[i] = (int) val; } g_strfreev( strv ); return( 0 ); }
/* Need our own seek(), since lseek() on win32 can't do long files. */ int vips__seek( int fd, gint64 pos ) { #ifdef OS_WIN32 { HANDLE hFile = (HANDLE) _get_osfhandle( fd ); LARGE_INTEGER p; p.QuadPart = pos; if( !SetFilePointerEx( hFile, p, NULL, FILE_BEGIN ) ) { vips_error_system( GetLastError(), "vips__seek", "%s", _( "unable to seek" ) ); return( -1 ); } } #else /*!OS_WIN32*/ if( lseek( fd, pos, SEEK_SET ) == (off_t) -1 ) { vips_error( "vips__seek", "%s", _( "unable to seek" ) ); return( -1 ); } #endif /*OS_WIN32*/ return( 0 ); }
FILE * vips__file_open_write( const char *filename, gboolean text_mode ) { char *mode; FILE *fp; #ifdef BINARY_OPEN if( text_mode ) mode = "w"; else mode = "wb"; #else /*BINARY_OPEN*/ mode = "w"; #endif /*BINARY_OPEN*/ if( !(fp = vips__fopen( filename, mode )) ) { vips_error_system( errno, "vips__file_open_write", _( "unable to open file \"%s\" for writing" ), filename ); return( NULL ); } return( fp ); }
/* Open a file. We take an optional fallback dir as well and will try opening * there if opening directly fails. * * This is used for things like finding ICC profiles. We try to open the file * directly first, and if that fails and the filename does not contain a * directory separator, we try looking in the fallback dir. */ FILE * vips__file_open_read( const char *filename, const char *fallback_dir, gboolean text_mode ) { char *mode; FILE *fp; #ifdef BINARY_OPEN if( text_mode ) mode = "r"; else mode = "rb"; #else /*BINARY_OPEN*/ mode = "r"; #endif /*BINARY_OPEN*/ if( (fp = vips__fopen( filename, mode )) ) return( fp ); if( fallback_dir && !filename_hasdir( filename ) ) { char *path; path = g_build_filename( fallback_dir, filename, NULL ); fp = vips__fopen( path, mode ); g_free( path ); if( fp ) return( fp ); } vips_error_system( errno, "vips__file_open_read", _( "unable to open file \"%s\" for reading" ), filename ); return( NULL ); }
static int read_csv( FILE *fp, VipsImage *out, int skip, int lines, const char *whitespace, const char *separator, gboolean read_image ) { int i; char whitemap[256]; char sepmap[256]; const char *p; fpos_t pos; int columns; int ch; double d; double *buf; int y; /* Make our char maps. */ for( i = 0; i < 256; i++ ) { whitemap[i] = 0; sepmap[i] = 0; } for( p = whitespace; *p; p++ ) whitemap[(int) *p] = 1; for( p = separator; *p; p++ ) sepmap[(int) *p] = 1; /* Skip first few lines. */ for( i = 0; i < skip; i++ ) if( !skip_line( fp ) ) { vips_error( "csv2vips", "%s", _( "end of file while skipping start" ) ); return( -1 ); } /* Parse the first line to get number of columns. Only bother checking * fgetpos() the first time we use it: assume it's working after this. */ if( fgetpos( fp, &pos ) ) { vips_error_system( errno, "csv2vips", "%s", _( "unable to seek" ) ); return( -1 ); } for( columns = 0; (ch = read_double( fp, whitemap, sepmap, skip + 1, columns + 1, &d )) == 0; columns++ ) ; fsetpos( fp, &pos ); if( columns == 0 ) { vips_error( "csv2vips", "%s", _( "empty line" ) ); return( -1 ); } /* If lines is -1, we have to scan the whole file to get the * number of lines out. */ if( lines == -1 ) { fgetpos( fp, &pos ); for( lines = 0; skip_line( fp ); lines++ ) ; fsetpos( fp, &pos ); } vips_image_init_fields( out, columns, lines, 1, VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, 1.0, 1.0 ); vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL ); /* Just reading the header? We are done. */ if( !read_image ) return( 0 ); if( !(buf = VIPS_ARRAY( out, VIPS_IMAGE_N_ELEMENTS( out ), double )) ) return( -1 ); for( y = 0; y < lines; y++ ) { int x; for( x = 0; x < columns; x++ ) { int lineno = y + skip + 1; int colno = x + 1; ch = read_double( fp, whitemap, sepmap, lineno, colno, &d ); if( ch == EOF ) { vips_error( "csv2vips", _( "unexpected EOF, line %d col %d" ), lineno, colno ); return( -1 ); } else if( ch == '\n' ) { vips_error( "csv2vips", _( "unexpected EOL, line %d col %d" ), lineno, colno ); return( -1 ); } else if( ch ) /* Parse error. */ return( -1 ); buf[x] = d; } if( vips_image_write_line( out, y, (VipsPel *) buf ) ) return( -1 ); /* Skip over the '\n' to the next line. */ skip_line( fp ); } return( 0 ); }
void * vips__mmap( int fd, int writeable, size_t length, gint64 offset ) { void *baseaddr; #ifdef DEBUG printf( "vips__mmap: length = 0x%zx, offset = 0x%lx\n", length, offset ); #endif /*DEBUG*/ #ifdef OS_WIN32 { HANDLE hFile = (HANDLE) _get_osfhandle( fd ); DWORD flProtect; DWORD dwDesiredAccess; HANDLE hMMFile; ULARGE_INTEGER quad; DWORD dwFileOffsetHigh; DWORD dwFileOffsetLow; if( writeable ) { flProtect = PAGE_READWRITE; dwDesiredAccess = FILE_MAP_WRITE; } else { flProtect = PAGE_READONLY; dwDesiredAccess = FILE_MAP_READ; } quad.QuadPart = offset; dwFileOffsetLow = quad.LowPart; dwFileOffsetHigh = quad.HighPart; if( !(hMMFile = CreateFileMapping( hFile, NULL, flProtect, 0, 0, NULL )) ) { vips_error_system( GetLastError(), "vips_mapfile", "%s", _( "unable to CreateFileMapping" ) ); printf( "CreateFileMapping failed: %s\n", vips_error_buffer() ); return( NULL ); } if( !(baseaddr = (char *)MapViewOfFile( hMMFile, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, length )) ) { vips_error_system( GetLastError(), "vips_mapfile", "%s", _( "unable to MapViewOfFile" ) ); printf( "MapViewOfFile failed: %s\n", vips_error_buffer() ); CloseHandle( hMMFile ); return( NULL ); } /* Can close mapping now ... view stays until UnmapViewOfFile(). FIXME ... is this a performance problem? */ CloseHandle( hMMFile ); } #else /*!OS_WIN32*/ { int prot; int flags; if( writeable ) prot = PROT_WRITE; else prot = PROT_READ; flags = MAP_SHARED; /* OS X caches mmapped files very aggressively if this flags is not * set. Scanning a large file without this flag will cause every other * process to get swapped out and kill performance. */ #ifdef MAP_NOCACHE flags |= MAP_NOCACHE; #endif /*MAP_NOCACHE*/ /* Casting gint64 to off_t should be safe, even on *nixes without * LARGEFILE. */ baseaddr = mmap( 0, length, prot, flags, fd, (off_t) offset ); if( baseaddr == MAP_FAILED ) { vips_error_system( errno, "vips_mapfile", "%s", _( "unable to mmap" ) ); g_warning( _( "map failed (%s), " "running very low on system resources, " "expect a crash soon" ), strerror( errno ) ); return( NULL ); } } #endif /*OS_WIN32*/ return( baseaddr ); }
/* From im_rwcheck() ... image needs to be a completely mapped read-only file, * we try to remap it read-write. */ int vips_remapfilerw( VipsImage *image ) { void *baseaddr; #ifdef OS_WIN32 { HANDLE hFile = (HANDLE) _get_osfhandle( image->fd ); HANDLE hMMFile; if( !(hMMFile = CreateFileMapping( hFile, NULL, PAGE_READWRITE, 0, 0, NULL )) ) { vips_error_system( GetLastError(), "vips_mapfile", "%s", _( "unable to CreateFileMapping" ) ); return( -1 ); } if( !UnmapViewOfFile( image->baseaddr ) ) { vips_error_system( GetLastError(), "vips_mapfile", "%s", _( "unable to UnmapViewOfFile" ) ); return( -1 ); } if( !(baseaddr = (char *)MapViewOfFileEx( hMMFile, FILE_MAP_WRITE, 0, 0, 0, image->baseaddr )) ) { vips_error_system( GetLastError(), "vips_mapfile", "%s", _( "unable to MapViewOfFile" ) ); CloseHandle( hMMFile ); return( -1 ); } /* Can close mapping now ... view stays until UnmapViewOfFile(). FIXME ... is this a performance problem? */ CloseHandle( hMMFile ); } #else /*!OS_WIN32*/ { assert( image->dtype == VIPS_IMAGE_MMAPIN ); baseaddr = mmap( image->baseaddr, image->length, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, image->fd, 0 ); if( baseaddr == (void *)-1 ) { vips_error( "vips_mapfile", _( "unable to mmap: \"%s\" - %s" ), image->filename, strerror( errno ) ); return( -1 ); } } #endif /*OS_WIN32*/ image->dtype = VIPS_IMAGE_MMAPINRW; if( baseaddr != image->baseaddr ) { vips_error( "vips_mapfile", _( "unable to mmap \"%s\" to same " "address" ), image->filename ); image->baseaddr = baseaddr; return( -1 ); } return( 0 ); }
/* Get file length ... 64-bitally. -1 for error. */ gint64 vips_file_length( int fd ) { #ifdef OS_WIN32 struct _stati64 st; if( _fstati64( fd, &st ) == -1 ) { #else /*!OS_WIN32*/ struct stat st; if( fstat( fd, &st ) == -1 ) { #endif /*OS_WIN32*/ vips_error_system( errno, "vips_file_length", "%s", _( "unable to get file stats" ) ); return( -1 ); } return( st.st_size ); } /* Wrap write() up */ int vips__write( int fd, const void *buf, size_t count ) { do { size_t nwritten = write( fd, buf, count ); if( nwritten == (size_t) -1 ) { vips_error_system( errno, "vips__write", "%s", _( "write failed" ) ); return( -1 ); } buf = (void *) ((char *) buf + nwritten); count -= nwritten; } while( count > 0 ); return( 0 ); } /* open() with a utf8 filename, setting errno. */ int vips__open( const char *filename, int flags, ... ) { int fd; mode_t mode; va_list ap; va_start( ap, flags ); mode = va_arg( ap, int ); va_end( ap ); #ifdef OS_WIN32 { wchar_t *path16; if( !(path16 = (wchar_t *) g_utf8_to_utf16( filename, -1, NULL, NULL, NULL )) ) { errno = EACCES; return( -1 ); } fd = _wopen( path16, flags, mode ); g_free( path16 ); } #else /*!OS_WIN32*/ fd = open( filename, flags, mode ); #endif return( fd ); }