2007-08-29 18:23:50 +02:00
|
|
|
/* @(#) Frees all resources associated with IMAGE, and frees the memory
|
|
|
|
* @(#) occupied by IMAGE.
|
|
|
|
* @(#)
|
|
|
|
* @(#) int
|
|
|
|
* @(#) im_close( image )
|
|
|
|
* @(#) IMAGE *image;
|
|
|
|
* @(#)
|
|
|
|
* @(#) As above, but just free resources attached to IMAGE. After call, IMAGE
|
|
|
|
* @(#) is as if im_init() had just been called. Useful for closing and
|
|
|
|
* @(#) re-opening as another image type. See im_piocheck() etc.
|
|
|
|
* @(#)
|
|
|
|
* @(#) int
|
|
|
|
* @(#) im__close( image )
|
|
|
|
* @(#) IMAGE *image;
|
|
|
|
* @(#)
|
|
|
|
* @(#) Returns 0 on success and 1 on error.
|
|
|
|
*
|
|
|
|
* Copyright: Nicos Dessipris
|
|
|
|
* Written on: 12/04/1990
|
|
|
|
* Modified on :
|
|
|
|
* 24/7/92 JC
|
|
|
|
* - im_update_descfile code tidied up
|
|
|
|
* - free on NULL string when junking Hist fixed
|
|
|
|
* - now calls im_unmapfile
|
|
|
|
* - better behaviour if image has been opened and closed with
|
|
|
|
* no im_setupout call
|
|
|
|
* - better behaviour for half-made IMAGE descriptors
|
|
|
|
* 15/4/93 JC
|
|
|
|
* - additions for freeing partial images
|
|
|
|
* 29/4/93 JC
|
|
|
|
* - close callback list added
|
|
|
|
* 10/5/93 JC
|
|
|
|
* - im__close() added
|
|
|
|
* 9/11/93 JC
|
|
|
|
* - im_update_descfile -> write_descfile
|
|
|
|
* - if Hist is NULL, no longer makes up and writes .desc file
|
|
|
|
* 16/8/94 JC
|
|
|
|
* - evalend callbacks added
|
|
|
|
* - ANSIfied
|
|
|
|
* 24/10/95 JC
|
|
|
|
* - now tracks open images ... see also im_init() and debug.c
|
|
|
|
* 11/7/00 JC
|
|
|
|
* - SETBUF_FOREIGN added
|
|
|
|
* 16/1/04 JC
|
|
|
|
* - frees as much as possible on im_close() failure
|
|
|
|
* 6/6/05 Markus Wollgarten
|
|
|
|
* - free Meta on close
|
|
|
|
* 30/6/05 JC
|
|
|
|
* - actually, free Meta on final close, so we carry meta over on an
|
|
|
|
* im__close()/im_openin() pair (eg. see im_pincheck())
|
|
|
|
* 11/7/05
|
|
|
|
* - call im__writehist() to send history to XML after image data
|
|
|
|
* 3/1/07
|
|
|
|
* - free history_list
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
This file is part of VIPS.
|
|
|
|
|
|
|
|
VIPS is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, 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 Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
#define DEBUG_IO
|
|
|
|
#define DEBUG_NEW
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif /*HAVE_CONFIG_H*/
|
|
|
|
#include <vips/intl.h>
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif /*HAVE_UNISTD_H*/
|
|
|
|
#ifdef HAVE_IO_H
|
|
|
|
#include <io.h>
|
|
|
|
#endif /*HAVE_IO_H*/
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include <vips/vips.h>
|
|
|
|
#include <vips/internal.h>
|
|
|
|
#include <vips/debug.h>
|
|
|
|
|
|
|
|
#ifdef WITH_DMALLOC
|
|
|
|
#include <dmalloc.h>
|
|
|
|
#endif /*WITH_DMALLOC*/
|
|
|
|
|
|
|
|
/* Maximum file name length.
|
|
|
|
*/
|
|
|
|
#define NAMELEN 1024
|
|
|
|
|
|
|
|
/* Free any resources owned by this descriptor. The descriptor is left as if a
|
|
|
|
* call to im_init had just happened - ie. the filename is set, but no other
|
|
|
|
* resources are attached. Information is lost if this is a im_setbuf()
|
|
|
|
* image! On an error, return non-zero and leave the image in an indeterminate
|
|
|
|
* state. Too hard to recover gracefully.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
im__close( IMAGE *im )
|
|
|
|
{
|
|
|
|
int result = 0;
|
|
|
|
|
|
|
|
/* No action for NULL image.
|
|
|
|
*/
|
|
|
|
if( !im )
|
|
|
|
return( result );
|
|
|
|
|
|
|
|
#ifdef DEBUG_IO
|
|
|
|
printf( "im__close: starting for %s ..\n", im->filename );
|
|
|
|
#endif /*DEBUG_IO*/
|
|
|
|
|
|
|
|
/* Free any regions defined on this image. This will, in turn, call
|
|
|
|
* all stop functions still running, freeing all regions we have on
|
|
|
|
* other images, etc.
|
|
|
|
*/
|
|
|
|
#ifdef DEBUG_IO
|
|
|
|
printf( "im__close: freeing %d regions ..\n",
|
|
|
|
g_slist_length( (List *) im->regions ) );
|
|
|
|
#endif /*DEBUG_IO*/
|
|
|
|
while( im->regions )
|
|
|
|
im_region_free( (REGION *) im->regions->data );
|
|
|
|
|
|
|
|
/* That should mean we have no windows.
|
|
|
|
*/
|
|
|
|
if( im->windows ) {
|
|
|
|
GSList *p;
|
|
|
|
|
|
|
|
printf( "** im__close: leaked windows!\n" );
|
|
|
|
for( p = im->windows; p; p = p->next )
|
|
|
|
im_window_print( (im_window_t *) p->data );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure all evalend functions have been called, perform all close
|
|
|
|
* callbacks, and free eval callbacks.
|
|
|
|
*/
|
|
|
|
result |= im__trigger_callbacks( im->evalendfns );
|
|
|
|
IM_FREEF( im_slist_free_all, im->evalendfns );
|
|
|
|
IM_FREEF( im_slist_free_all, im->evalfns );
|
|
|
|
result |= im__trigger_callbacks( im->closefns );
|
|
|
|
IM_FREEF( im_slist_free_all, im->closefns );
|
|
|
|
|
|
|
|
/* Junk generate functions.
|
|
|
|
*/
|
|
|
|
im->start = NULL;
|
|
|
|
im->generate = NULL;
|
|
|
|
im->stop = NULL;
|
|
|
|
|
|
|
|
/* No more parent/child links.
|
|
|
|
*/
|
|
|
|
im__link_break_all( im );
|
|
|
|
|
|
|
|
/* What resources are associated with this IMAGE descriptor?
|
|
|
|
*/
|
|
|
|
if( im->baseaddr ) {
|
|
|
|
/* MMAP file.
|
|
|
|
*/
|
|
|
|
#ifdef DEBUG_IO
|
|
|
|
printf( "im__close: unmapping file ..\n" );
|
|
|
|
#endif /*DEBUG_IO*/
|
|
|
|
|
|
|
|
if( im_unmapfile( im ) )
|
|
|
|
return( -1 );
|
|
|
|
im->data = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Is there a file descriptor?
|
|
|
|
*/
|
|
|
|
if( im->fd != -1 ) {
|
|
|
|
#ifdef DEBUG_IO
|
|
|
|
printf( "im__close: closing output file ..\n" );
|
|
|
|
#endif /*DEBUG_IO*/
|
|
|
|
|
|
|
|
if( im->dtype == IM_OPENOUT && im__writehist( im ) ) {
|
|
|
|
im_errormsg( "im_close: unable to write metadata "
|
|
|
|
"for %s", im->filename );
|
|
|
|
result = -1;
|
|
|
|
}
|
|
|
|
if( close( im->fd ) == -1 ) {
|
|
|
|
im_errormsg( "im_close: unable to close fd (2) "
|
|
|
|
"for %s", im->filename );
|
|
|
|
result = -1;
|
|
|
|
}
|
|
|
|
im->fd = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Any image data?
|
|
|
|
*/
|
|
|
|
if( im->data ) {
|
|
|
|
/* Buffer image. Only free stuff we know we allocated.
|
|
|
|
*/
|
|
|
|
if( im->dtype == IM_SETBUF ) {
|
|
|
|
#ifdef DEBUG_IO
|
|
|
|
printf( "im__close: freeing buffer ..\n" );
|
|
|
|
#endif /*DEBUG_IO*/
|
|
|
|
im_free( im->data );
|
|
|
|
im->dtype = IM_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
im->data = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reset other state.
|
|
|
|
*/
|
|
|
|
im->dtype = IM_NONE;
|
|
|
|
im->dhint = IM_SMALLTILE;
|
|
|
|
im->kill = 0;
|
|
|
|
im->close_pending = 0;
|
|
|
|
im->sizeof_header = IM_SIZEOF_HEADER;
|
|
|
|
|
|
|
|
#ifdef DEBUG_IO
|
|
|
|
printf( "im__close: final success for %s (%p)\n",
|
|
|
|
im->filename, im );
|
|
|
|
#endif /*DEBUG_IO*/
|
|
|
|
|
|
|
|
return( result );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free resources and close descriptor.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
im_close( IMAGE *im )
|
|
|
|
{
|
|
|
|
int result = 0;
|
|
|
|
|
|
|
|
/* No action for NULL image.
|
|
|
|
*/
|
|
|
|
if( !im )
|
|
|
|
return( result );
|
|
|
|
|
|
|
|
/* Are there any regions left on this image? If there are, just set
|
|
|
|
* close_pending and return. The image will be then be closed when
|
|
|
|
* the last region is freed (see im_region_free()). This prevents
|
|
|
|
* some dangling region pointers.
|
|
|
|
*/
|
|
|
|
#ifdef DEBUG_IO
|
|
|
|
if( im->close_pending )
|
|
|
|
/* Strange! Just print a warning.
|
|
|
|
*/
|
|
|
|
printf( "im_close: im_close called twice on \"%s\"\n",
|
|
|
|
im->filename );
|
|
|
|
#endif /*DEBUG_IO*/
|
|
|
|
if( im->regions ) {
|
|
|
|
#ifdef DEBUG_IO
|
|
|
|
printf( "im_close: pending close for \"%s\"\n", im->filename );
|
|
|
|
#endif /*DEBUG_IO*/
|
|
|
|
im->close_pending = 1;
|
|
|
|
return( result );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Is this descriptor currently being closed somewhere else? Immediate
|
|
|
|
* return if it is. This prevents infinite descent if a close callback
|
|
|
|
* includes an im_close for this image. This can happen sometimes!
|
|
|
|
*/
|
|
|
|
if( im->closing )
|
|
|
|
return( result );
|
|
|
|
im->closing = 1;
|
|
|
|
|
|
|
|
/* Free IMAGE resources.
|
|
|
|
*/
|
|
|
|
if( im__close( im ) )
|
|
|
|
result = -1;
|
|
|
|
|
|
|
|
#ifdef DEBUG_NEW
|
|
|
|
printf( "im_close: freeing IMAGE 0x%p, \"%s\"\n", im, im->filename );
|
|
|
|
#endif /*DEBUG_NEW*/
|
|
|
|
|
|
|
|
/* Final cleanup.
|
|
|
|
*/
|
|
|
|
IM_FREEF( g_mutex_free, im->sslock );
|
|
|
|
IM_FREE( im->filename );
|
|
|
|
IM_FREE( im->Hist );
|
|
|
|
IM_FREEF( im__gslist_gvalue_free, im->history_list );
|
|
|
|
im__meta_destroy( im );
|
|
|
|
im__open_images = g_slist_remove( im__open_images, im );
|
2007-11-02 18:04:31 +01:00
|
|
|
im__time_destroy( im );
|
2007-08-29 18:23:50 +02:00
|
|
|
IM_FREE( im );
|
|
|
|
|
|
|
|
return( result );
|
|
|
|
}
|