1 /* -*- Mode: C; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */
2 
3 /*
4  * GImageView
5  * Copyright (C) 2001 Takuro Ashie
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  *
21  * $Id: gimv_image_info.c,v 1.6 2004/09/21 08:44:32 makeinu Exp $
22  */
23 
24 #include <stdio.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 
29 #include "gimageview.h"
30 
31 #include "fileutil.h"
32 #include "fr-archive.h"
33 #include "gfileutil.h"
34 #include "gimv_comment.h"
35 #include "gimv_anim.h"
36 #include "gimv_image.h"
37 #include "gimv_image_info.h"
38 #include "gimv_mime_types.h"
39 #include "gimv_thumb.h"
40 #include "gimv_thumb_cache.h"
41 #include "prefs.h"
42 
43 
44 static GHashTable *gimv_image_info_table = NULL;
45 static GHashTable *comment_table    = NULL;
46 static GHashTable *archive_table    = NULL;
47 static GHashTable *link_table       = NULL;
48 
49 
50 /******************************************************************************
51  *
52  *   Private Functions.
53  *
54  ******************************************************************************/
55 static GimvImageInfo *
gimv_image_info_new(const gchar * filename)56 gimv_image_info_new (const gchar *filename)
57 {
58    GimvImageInfo *info;
59 
60    info = g_new0 (GimvImageInfo, 1);
61    g_return_val_if_fail (info, NULL);
62 
63    info->filename     = g_strdup (filename);
64    info->format       = gimv_image_detect_type_by_ext (filename);
65    info->width        = -1;
66    info->height       = -1;
67    info->depth        = -1;
68    info->flags        = 0;
69 
70    info->ref_count = 1;
71 
72    return info;
73 }
74 
75 
76 /******************************************************************************
77  *
78  *   Public Functions.
79  *
80  ******************************************************************************/
81 GimvImageInfo *
gimv_image_info_get(const gchar * filename)82 gimv_image_info_get (const gchar *filename)
83 {
84    GimvImageInfo *info;
85    struct stat st;
86 
87    g_return_val_if_fail (filename, NULL);
88 
89    if (!gimv_image_info_table) {
90       gimv_image_info_table = g_hash_table_new (g_str_hash, g_str_equal);
91    }
92 
93    info = g_hash_table_lookup (gimv_image_info_table, filename);
94    if (!info) {
95       if (!file_exists (filename)) return NULL;
96       info = gimv_image_info_new (filename);
97       if (!info) return NULL;
98       stat (filename, &info->st);
99       g_hash_table_insert (gimv_image_info_table, info->filename, info);
100    } else {
101       if (stat (filename, &st)) return NULL;
102       if (info->st.st_size != st.st_size
103           || info->st.st_mtime != st.st_mtime
104           || info->st.st_ctime != st.st_ctime)
105       {
106          info->st = st;
107          info->width = -1;
108          info->height = -1;
109          info->flags &= ~GIMV_IMAGE_INFO_SYNCED_FLAG;
110       }
111       gimv_image_info_ref (info);
112    }
113 
114    return info;
115 }
116 
117 
118 GimvImageInfo *
gimv_image_info_get_url(const gchar * url)119 gimv_image_info_get_url (const gchar *url)
120 {
121    GimvImageInfo *info;
122 
123    g_return_val_if_fail (url, NULL);
124 
125    if (!gimv_image_info_table) {
126       gimv_image_info_table = g_hash_table_new (g_str_hash, g_str_equal);
127    }
128 
129    info = g_hash_table_lookup (gimv_image_info_table, url);
130    if (!info) {
131       info = gimv_image_info_new (url);
132       if (!info) return NULL;
133       info->flags |= GIMV_IMAGE_INFO_URL_FLAG;
134       g_hash_table_insert (gimv_image_info_table, info->filename, info);
135    } else {
136       gimv_image_info_ref (info);
137    }
138 
139    return info;
140 }
141 
142 
143 GimvImageInfo *
gimv_image_info_get_with_archive(const gchar * filename,FRArchive * archive,struct stat * st)144 gimv_image_info_get_with_archive (const gchar *filename,
145                                   FRArchive   *archive,
146                                   struct stat *st)
147 {
148    GimvImageInfo *info;
149    gchar buf[MAX_PATH_LEN];
150 
151    g_return_val_if_fail (filename, NULL);
152    g_return_val_if_fail (archive, NULL);
153 
154    if (!gimv_image_info_table)
155       gimv_image_info_table = g_hash_table_new (g_str_hash, g_str_equal);
156 
157    if (!archive_table)
158       archive_table = g_hash_table_new (g_direct_hash, g_direct_equal);
159 
160    g_snprintf (buf, MAX_PATH_LEN, "%s/%s", archive->filename, filename);
161 
162    info = g_hash_table_lookup (gimv_image_info_table, buf);
163    if (!info) {
164       info = gimv_image_info_new (filename);
165       g_hash_table_insert (gimv_image_info_table, g_strdup (buf), info);
166       g_hash_table_insert (archive_table, info, archive);
167    } else {
168       /* FIXME!! update if needed */
169       /* gimv_image_info_ref (info); */
170    }
171 
172    if (st)
173       info->st = *st;
174 
175    info->flags |= GIMV_IMAGE_INFO_ARCHIVE_MEMBER_FLAG;
176 
177    return info;
178 }
179 
180 
181 GimvImageInfo *
gimv_image_info_lookup(const gchar * filename)182 gimv_image_info_lookup (const gchar *filename)
183 {
184    GimvImageInfo *info;
185 
186    info = g_hash_table_lookup (gimv_image_info_table, filename);
187 
188    if (info)
189       gimv_image_info_ref (info);
190 
191    return info;
192 }
193 
194 
195 void
gimv_image_info_finalize(GimvImageInfo * info)196 gimv_image_info_finalize (GimvImageInfo *info)
197 {
198    guint num;
199    gchar buf[MAX_PATH_LEN];
200 
201    g_return_if_fail (info);
202 
203    /* remove data from hash table */
204    if (info->flags & GIMV_IMAGE_INFO_ARCHIVE_MEMBER_FLAG) {
205       gchar *orig_key;
206       GimvImageInfo *value;
207       gboolean success = FALSE;
208       FRArchive *archive = g_hash_table_lookup (archive_table, info);
209 
210       if (archive) {
211          g_snprintf (buf, MAX_PATH_LEN, "%s/%s",
212                      archive->filename, info->filename);
213          success = g_hash_table_lookup_extended (gimv_image_info_table, buf,
214                                                  (gpointer) &orig_key,
215                                                  (gpointer) &value);
216          g_hash_table_remove (archive_table, info);
217       }
218       if (success) {
219          g_hash_table_remove (gimv_image_info_table, buf);
220          g_free (orig_key);
221       }
222    } else {
223       g_hash_table_remove (gimv_image_info_table, info->filename);
224    }
225 
226    gimv_image_info_set_comment (info, NULL);
227    gimv_image_info_set_link (info, NULL);
228 
229    if (info->filename) {
230       g_free (info->filename);
231       info->filename = NULL;
232    }
233    g_free (info);
234 
235    /* destroy hash table if needed */
236    num = g_hash_table_size (gimv_image_info_table);
237    if (num < 1) {
238       g_hash_table_destroy (gimv_image_info_table);
239       gimv_image_info_table = NULL;
240    }
241 }
242 
243 
244 GimvImageInfo *
gimv_image_info_ref(GimvImageInfo * info)245 gimv_image_info_ref (GimvImageInfo *info)
246 {
247    g_return_val_if_fail (info, NULL);
248 
249    info->ref_count++;
250 
251    if (info->flags & GIMV_IMAGE_INFO_ARCHIVE_MEMBER_FLAG) {
252       FRArchive *archive = g_hash_table_lookup (archive_table, info);
253       if (archive)
254          fr_archive_ref (archive);
255    }
256 
257    return info;
258 }
259 
260 
261 void
gimv_image_info_unref(GimvImageInfo * info)262 gimv_image_info_unref (GimvImageInfo *info)
263 {
264    FRArchive *archive = NULL;
265 
266    g_return_if_fail (info);
267 
268    if (info->flags & GIMV_IMAGE_INFO_ARCHIVE_MEMBER_FLAG)
269       archive = g_hash_table_lookup (archive_table, info);
270 
271    info->ref_count--;
272 
273    if (info->ref_count < 1) {
274       gimv_image_info_finalize (info);
275    }
276 
277    if (archive)
278       fr_archive_unref (FR_ARCHIVE (archive));
279 }
280 
281 
282 /* used by fr-command */
283 void
gimv_image_info_unref_with_archive(GimvImageInfo * info)284 gimv_image_info_unref_with_archive (GimvImageInfo *info)
285 {
286    g_return_if_fail (info);
287 
288    info->ref_count--;
289    /* info->archive = NULL; */
290 
291    if (info->ref_count < 1)
292       gimv_image_info_finalize (info);
293 }
294 
295 
296 void
gimv_image_info_set_size(GimvImageInfo * info,gint width,gint height)297 gimv_image_info_set_size (GimvImageInfo *info, gint width, gint height)
298 {
299    g_return_if_fail (info);
300 
301    if (info->flags & GIMV_IMAGE_INFO_SYNCED_FLAG) return;
302 
303    info->width  = width;
304    info->height = height;
305 }
306 
307 
308 void
gimv_image_info_set_comment(GimvImageInfo * info,GimvComment * comment)309 gimv_image_info_set_comment (GimvImageInfo *info, GimvComment *comment)
310 {
311    GimvComment *prev;
312 
313    g_return_if_fail (info);
314 
315    if (!comment_table)
316       comment_table = g_hash_table_new (g_direct_hash, g_direct_equal);
317 
318    prev = g_hash_table_lookup (comment_table, info);
319    if (prev) {
320       g_hash_table_remove (comment_table, info);
321       /* comment_unref (prev); */
322    }
323 
324    if (comment) {
325       /* comment_ref (comment); */
326       g_hash_table_insert (comment_table, info, comment);
327    }
328 }
329 
330 
331 GimvComment *
gimv_image_info_get_comment(GimvImageInfo * info)332 gimv_image_info_get_comment (GimvImageInfo *info)
333 {
334    g_return_val_if_fail (info, NULL);
335 
336    if (!comment_table) return NULL;
337    return g_hash_table_lookup (comment_table, info);
338 }
339 
340 
341 void
gimv_image_info_set_link(GimvImageInfo * info,const gchar * link)342 gimv_image_info_set_link (GimvImageInfo *info, const gchar *link)
343 {
344    gchar *old_link;
345 
346    g_return_if_fail (info);
347 
348    if (!link_table)
349       link_table = g_hash_table_new (g_direct_hash, g_direct_equal);
350 
351    old_link = g_hash_table_lookup (link_table, info);
352    if (old_link) {
353       g_hash_table_remove (link_table, info);
354       g_free (old_link);
355    }
356 
357    if (link && *link)
358       g_hash_table_insert (link_table, info, g_strdup (link));
359 }
360 
361 
362 FRArchive *
gimv_image_info_get_archive(GimvImageInfo * info)363 gimv_image_info_get_archive (GimvImageInfo *info)
364 {
365    g_return_val_if_fail (info, NULL);
366 
367    if (!archive_table) return NULL;
368    return g_hash_table_lookup (archive_table, info);
369 }
370 
371 
372 void
gimv_image_info_set_flags(GimvImageInfo * info,GimvImageInfoFlags flags)373 gimv_image_info_set_flags (GimvImageInfo *info, GimvImageInfoFlags flags)
374 {
375    g_return_if_fail (info);
376 
377    if (!(info->flags & GIMV_IMAGE_INFO_SYNCED_FLAG)
378        || (flags & GIMV_IMAGE_INFO_SYNCED_FLAG))
379    {
380       info->flags |= flags;
381    }
382 }
383 
384 
385 void
gimv_image_info_unset_flags(GimvImageInfo * info,GimvImageInfoFlags flags)386 gimv_image_info_unset_flags (GimvImageInfo *info, GimvImageInfoFlags flags)
387 {
388    g_return_if_fail (info);
389 
390    if (!(info->flags & GIMV_IMAGE_INFO_SYNCED_FLAG)
391        || (flags & GIMV_IMAGE_INFO_SYNCED_FLAG))
392    {
393       info->flags &= ~flags;
394    }
395 }
396 
397 
398 gboolean
gimv_image_info_is_dir(GimvImageInfo * info)399 gimv_image_info_is_dir (GimvImageInfo *info)
400 {
401    g_return_val_if_fail (info, FALSE);
402 
403    if (isdir (gimv_image_info_get_path (info)))
404       return TRUE;
405 
406    return FALSE;
407 }
408 
409 
410 gboolean
gimv_image_info_is_archive(GimvImageInfo * info)411 gimv_image_info_is_archive (GimvImageInfo *info)
412 {
413    g_return_val_if_fail (info, FALSE);
414 
415    if (fr_archive_utils_get_file_name_ext (gimv_image_info_get_path (info)))
416       return TRUE;
417 
418    return FALSE;
419 }
420 
421 
422 gboolean
gimv_image_info_is_in_archive(GimvImageInfo * info)423 gimv_image_info_is_in_archive (GimvImageInfo *info)
424 {
425    g_return_val_if_fail (info, FALSE);
426 
427    if (info->flags & GIMV_IMAGE_INFO_ARCHIVE_MEMBER_FLAG)
428       return TRUE;
429    else
430       return FALSE;
431 }
432 
433 
434 gboolean
gimv_image_info_is_url(GimvImageInfo * info)435 gimv_image_info_is_url (GimvImageInfo *info)
436 {
437    g_return_val_if_fail (info, FALSE);
438 
439    if (info->flags & GIMV_IMAGE_INFO_URL_FLAG)
440       return TRUE;
441    else
442       return FALSE;
443 }
444 
445 
446 gboolean
gimv_image_info_is_animation(GimvImageInfo * info)447 gimv_image_info_is_animation (GimvImageInfo *info)
448 {
449    g_return_val_if_fail (info, FALSE);
450 
451    if (info->flags & GIMV_IMAGE_INFO_ANIMATION_FLAG)
452       return TRUE;
453 
454    return FALSE;
455 }
456 
457 
458 gboolean
gimv_image_info_is_movie(GimvImageInfo * info)459 gimv_image_info_is_movie (GimvImageInfo *info)
460 {
461    const gchar *ext;
462    const gchar *type;
463 
464    g_return_val_if_fail (info, FALSE);
465 
466    if ((info->flags & GIMV_IMAGE_INFO_MOVIE_FLAG)
467        || (info->flags & GIMV_IMAGE_INFO_MRL_FLAG))
468    {
469       return TRUE;
470    }
471 
472    ext  = fileutil_get_extention (info->filename);
473    type = gimv_mime_types_get_type_from_ext (ext);
474 
475    if (type
476        && (!g_strncasecmp (type, "video", 5))
477        && g_strcasecmp (type, "video/x-mng")) /* FIXME!! */
478    {
479       return TRUE;
480    }
481 
482    return FALSE;
483 }
484 
485 
486 gboolean
gimv_image_info_is_audio(GimvImageInfo * info)487 gimv_image_info_is_audio (GimvImageInfo *info)
488 {
489    const gchar *ext;
490    const gchar *type;
491 
492    g_return_val_if_fail (info, FALSE);
493 
494    ext  = gimv_mime_types_get_extension (info->filename);
495    type = gimv_mime_types_get_type_from_ext (ext);
496 
497    if (type && !g_strncasecmp (type, "audio", 5))
498       return TRUE;
499 
500    return FALSE;
501 }
502 
503 
504 gboolean
gimv_image_info_is_same(GimvImageInfo * info1,GimvImageInfo * info2)505 gimv_image_info_is_same (GimvImageInfo *info1, GimvImageInfo *info2)
506 {
507    FRArchive *arc1 = NULL, *arc2 = NULL;
508 
509    g_return_val_if_fail (info1, FALSE);
510    g_return_val_if_fail (info2, FALSE);
511    g_return_val_if_fail (info1->filename && *info1->filename, FALSE);
512    g_return_val_if_fail (info2->filename && *info2->filename, FALSE);
513 
514    if (strcmp (info1->filename, info2->filename))
515       return FALSE;
516 
517    if (!(info1->flags & GIMV_IMAGE_INFO_ARCHIVE_MEMBER_FLAG)
518        && !(info2->flags & GIMV_IMAGE_INFO_ARCHIVE_MEMBER_FLAG))
519    {
520       return TRUE;
521    }
522 
523    if (archive_table) {
524       arc1 = g_hash_table_lookup (archive_table, info1);
525       arc2 = g_hash_table_lookup (archive_table, info2);
526    }
527 
528    if (arc1 && arc1->filename && *arc1->filename
529        && arc2 && arc2->filename && *arc2->filename
530        && !strcmp (arc1->filename, arc2->filename))
531    {
532       return TRUE;
533    }
534 
535    return FALSE;
536 }
537 
538 
539 const gchar *
gimv_image_info_get_path(GimvImageInfo * info)540 gimv_image_info_get_path (GimvImageInfo *info)
541 {
542    g_return_val_if_fail (info, NULL);
543 
544    return info->filename;
545 }
546 
547 
548 gchar *
gimv_image_info_get_path_with_archive(GimvImageInfo * info)549 gimv_image_info_get_path_with_archive (GimvImageInfo *info)
550 {
551    FRArchive *arc;
552 
553    g_return_val_if_fail (info, NULL);
554 
555    if (!(info->flags & GIMV_IMAGE_INFO_ARCHIVE_MEMBER_FLAG))
556       return g_strdup (info->filename);
557 
558    arc = g_hash_table_lookup (archive_table, info);
559    g_return_val_if_fail (arc, NULL);
560 
561    return g_strconcat (arc->filename, "/", info->filename, NULL);
562 }
563 
564 
565 const gchar *
gimv_image_info_get_archive_path(GimvImageInfo * info)566 gimv_image_info_get_archive_path (GimvImageInfo *info)
567 {
568    FRArchive *arc;
569 
570    g_return_val_if_fail (info, NULL);
571    g_return_val_if_fail (info->flags & GIMV_IMAGE_INFO_ARCHIVE_MEMBER_FLAG,
572                          NULL);
573 
574    arc = g_hash_table_lookup (archive_table, info);
575 
576    return arc->filename;
577 }
578 
579 
580 gboolean
gimv_image_info_need_temp_file(GimvImageInfo * info)581 gimv_image_info_need_temp_file (GimvImageInfo *info)
582 {
583    g_return_val_if_fail (info, FALSE);
584 
585    if (gimv_image_info_is_in_archive (info))
586       return TRUE;
587    else
588       return FALSE;
589 }
590 
591 
592 gchar *
gimv_image_info_get_temp_file_path(GimvImageInfo * info)593 gimv_image_info_get_temp_file_path (GimvImageInfo *info)
594 {
595    FRArchive *archive;
596    gchar *temp_dir;
597    gchar *filename, buf[MAX_PATH_LEN];
598 
599    g_return_val_if_fail (info, NULL);
600    g_return_val_if_fail (archive_table, FALSE);
601 
602    archive = g_hash_table_lookup (archive_table, info);
603    g_return_val_if_fail (archive, NULL);
604 
605    filename = info->filename;
606 
607    temp_dir = gtk_object_get_data (GTK_OBJECT (archive), "temp-dir");
608 
609    g_return_val_if_fail (temp_dir && *temp_dir, NULL);
610 
611    g_snprintf (buf, MAX_PATH_LEN, "%s/%s",
612                temp_dir, filename);
613 
614    return g_strdup (buf);
615 }
616 
617 
618 gchar *
gimv_image_info_get_temp_file(GimvImageInfo * info)619 gimv_image_info_get_temp_file (GimvImageInfo *info)
620 {
621    gboolean success;
622    gchar *filename;
623 
624    /* load the image */
625    if (!gimv_image_info_need_temp_file (info))
626       return NULL;
627 
628    filename = gimv_image_info_get_temp_file_path (info);
629    g_return_val_if_fail (filename, NULL);
630 
631    if (file_exists (filename)) {
632       return filename;
633    }
634 
635    success = gimv_image_info_extract_archive (info);
636    if (success)
637       return filename;
638 
639    g_free (filename);
640    return NULL;
641 }
642 
643 
644 /*
645  *  FIXME!!
646  *  If archive was already destroyed, create FRArchive object first.
647  *  To detect whether archive was destroyed or not, check info->archive.
648  *  When archive is destroyed, fr-archive class will set this value to NULL
649  *  by using gimv_image_info_unref_with_archive ().
650  */
651 gboolean
gimv_image_info_extract_archive(GimvImageInfo * info)652 gimv_image_info_extract_archive (GimvImageInfo *info)
653 {
654    FRArchive *archive;
655    GList *filelist = NULL;
656    gchar *temp_dir;
657    gchar *filename, *temp_file, buf[MAX_PATH_LEN];
658 
659    g_return_val_if_fail (info, FALSE);
660    g_return_val_if_fail (archive_table, FALSE);
661 
662    archive = g_hash_table_lookup (archive_table, info);
663    g_return_val_if_fail (archive, FALSE);
664 
665    filename = info->filename;
666 
667    temp_dir = gtk_object_get_data (GTK_OBJECT (archive), "temp-dir");
668 
669    g_return_val_if_fail (temp_dir && *temp_dir, FALSE);
670 
671    g_snprintf (buf, MAX_PATH_LEN, "%s/%s",
672                temp_dir, filename);
673    temp_file = buf;
674 
675    if (!file_exists (temp_file) && !archive->process->running) {
676       ensure_dir_exists (temp_dir);
677       filelist = g_list_append (filelist, filename);
678 
679       fr_archive_extract (archive, filelist, temp_dir,
680                           FALSE, TRUE, FALSE);
681 
682       gtk_main ();   /* will be quited by callback function
683                         of archive (see fileload.c) */
684    }
685 
686    if (file_exists (temp_file)) {
687       return TRUE;
688    } else {
689       return FALSE;
690    }
691 }
692 
693 
694 GimvIO *
gimv_image_info_get_gio(GimvImageInfo * info)695 gimv_image_info_get_gio (GimvImageInfo *info)
696 {
697    gboolean need_temp;
698    const gchar *filename;
699    gchar *temp_file = NULL;
700    GimvIO *gio = NULL;
701 
702    g_return_val_if_fail (info, NULL);
703 
704    need_temp = gimv_image_info_need_temp_file (info);
705    if (need_temp) {
706       temp_file = gimv_image_info_get_temp_file (info);
707       filename = temp_file;
708    } else {
709       filename = gimv_image_info_get_path (info);
710    }
711 
712    if (filename)
713       gio = gimv_io_new (filename, "rb");
714 
715    g_free (temp_file);
716 
717    return gio;
718 }
719 
720 
721 const gchar *
gimv_image_info_get_format(GimvImageInfo * info)722 gimv_image_info_get_format (GimvImageInfo *info)
723 {
724    g_return_val_if_fail (info, NULL);
725 
726    return info->format;
727 }
728 
729 
730 void
gimv_image_info_get_image_size(GimvImageInfo * info,gint * width_ret,gint * height_ret)731 gimv_image_info_get_image_size (GimvImageInfo *info,
732                            gint *width_ret, gint *height_ret)
733 {
734    g_return_if_fail (width_ret && height_ret);
735    *width_ret = -1;
736    *height_ret = -1;
737 
738    g_return_if_fail (info);
739 
740    *width_ret  = info->width;
741    *height_ret = info->height;
742 }
743 
744 
745 /* FIXME */
746 gboolean
gimv_image_info_rename_image(GimvImageInfo * info,const gchar * filename)747 gimv_image_info_rename_image (GimvImageInfo *info, const gchar *filename)
748 {
749    struct stat st;
750    gboolean success;
751    gchar *cache_type;
752    gchar *src_cache_path, *dest_cache_path;
753    gchar *src_comment, *dest_comment;
754 
755    g_return_val_if_fail (info, FALSE);
756    g_return_val_if_fail (info->filename, FALSE);
757    g_return_val_if_fail (!(info->flags & GIMV_IMAGE_INFO_ARCHIVE_MEMBER_FLAG),
758                          FALSE);
759    g_return_val_if_fail (filename, FALSE);
760 
761    /* rename the file */
762    success = !rename(info->filename, filename);
763    if (!success) return FALSE;
764 
765    /* rename cache */
766    src_cache_path = gimv_thumb_find_thumbcache (gimv_image_info_get_path (info),
767                                                 &cache_type);
768    if (src_cache_path) {
769       dest_cache_path
770          = gimv_thumb_cache_get_path (filename, cache_type);
771       if (rename (src_cache_path, dest_cache_path) < 0)
772          g_print (_("Faild to rename cache file :%s\n"), filename);
773       g_free (src_cache_path);
774       g_free (dest_cache_path);
775    }
776 
777    /* rename comment */
778    src_comment = gimv_comment_find_file (gimv_image_info_get_path (info));
779    if (src_comment) {
780       dest_comment = gimv_comment_get_path (filename);
781       if (rename (src_comment, dest_comment) < 0)
782          g_print (_("Faild to rename comment file :%s\n"), dest_comment);
783       g_free (src_comment);
784       g_free (dest_comment);
785    }
786 
787    if (stat (filename, &st)) return FALSE;
788    info->st = st;
789    g_free (info->filename);
790    info->filename = (gchar *) g_strdup (filename);
791 
792    return success;
793 }
794