gboolean metadata_write_perform(FileData *fd) { gboolean success; ExifData *exif; guint lf; g_assert(fd->change); lf = strlen(GQ_CACHE_EXT_METADATA); if (fd->change->dest && g_ascii_strncasecmp(fd->change->dest + strlen(fd->change->dest) - lf, GQ_CACHE_EXT_METADATA, lf) == 0) { success = metadata_legacy_write(fd); if (success) metadata_legacy_delete(fd, fd->change->dest); return success; } /* write via exiv2 */ /* we can either use cached metadata which have fd->modified_xmp already applied or read metadata from file and apply fd->modified_xmp metadata are read also if the file was modified meanwhile */ exif = exif_read_fd(fd); if (!exif) return FALSE; success = (fd->change->dest) ? exif_write_sidecar(exif, fd->change->dest) : exif_write(exif); /* write modified metadata */ exif_free_fd(fd, exif); if (fd->change->dest) /* this will create a FileData for the sidecar and link it to the main file (we can't wait until the sidecar is discovered by directory scanning because exif_read_fd is called before that and it would read the main file only and store the metadata in the cache) FIXME: this does not catch new sidecars created by independent external programs */ file_data_unref(file_data_new_group(fd->change->dest)); if (success) metadata_legacy_delete(fd, fd->change->dest); return success; }
static gboolean collection_load_private(CollectionData *cd, const gchar *path, CollectionLoadFlags flags) { gchar s_buf[GQ_COLLECTION_READ_BUFSIZE]; FILE *f; gchar *pathl; gboolean limit_failures = TRUE; gboolean success = TRUE; gboolean has_official_header = FALSE; gboolean has_geometry_header = FALSE; gboolean has_gqview_header = FALSE; gboolean need_header = TRUE; guint total = 0; guint fail = 0; gboolean changed = FALSE; CollectManagerEntry *entry = NULL; guint flush = !!(flags & COLLECTION_LOAD_FLUSH); guint append = !!(flags & COLLECTION_LOAD_APPEND); guint only_geometry = !!(flags & COLLECTION_LOAD_GEOMETRY); if (!only_geometry) { collection_load_stop(cd); if (flush) collect_manager_flush(); else entry = collect_manager_get_entry(path); if (!append) { collection_list_free(cd->list); cd->list = NULL; } } if (!path && !cd->path) return FALSE; if (!path) path = cd->path; DEBUG_1("collection load: append=%d flush=%d only_geometry=%d path=%s", append, flush, only_geometry, path); /* load it */ pathl = path_from_utf8(path); f = fopen(pathl, "r"); g_free(pathl); if (!f) { log_printf("Failed to open collection file: \"%s\"\n", path); return FALSE; } while (fgets(s_buf, sizeof(s_buf), f)) { gchar *buf; gchar *p = s_buf; /* Skip whitespaces and empty lines */ while (*p && g_ascii_isspace(*p)) p++; if (*p == '\n' || *p == '\r') continue; /* Parse comments */ if (*p == '#') { if (!need_header) continue; if (g_ascii_strncasecmp(p, GQ_COLLECTION_MARKER, strlen(GQ_COLLECTION_MARKER)) == 0) { /* Looks like an official collection, allow unchecked input. * All this does is allow adding files that may not exist, * which is needed for the collection manager to work. * Also unofficial files abort after too many invalid entries. */ has_official_header = TRUE; limit_failures = FALSE; } else if (strncmp(p, "#geometry:", 10 ) == 0 && scan_geometry(p + 10, &cd->window_x, &cd->window_y, &cd->window_w, &cd->window_h)) { has_geometry_header = TRUE; cd->window_read = TRUE; if (only_geometry) break; } else if (g_ascii_strncasecmp(p, "#GQview collection", strlen("#GQview collection")) == 0) { /* As 2008/04/15 there is no difference between our collection file format * and GQview 2.1.5 collection file format so ignore failures as well. */ has_gqview_header = TRUE; limit_failures = FALSE; } need_header = (!has_official_header && !has_gqview_header) || !has_geometry_header; continue; } if (only_geometry) continue; /* Read filenames */ while (*p && *p != '"') p++; if (*p) p++; buf = p; while (*p && *p != '"') p++; *p = 0; if (*buf) { gboolean valid; if (!flush) changed |= collect_manager_process_action(entry, &buf); valid = (buf[0] == G_DIR_SEPARATOR && collection_add_check(cd, file_data_new_group(buf), FALSE, TRUE)); if (!valid) DEBUG_1("collection invalid file: %s", buf); total++; if (!valid) { fail++; if (limit_failures && fail > GQ_COLLECTION_FAIL_MIN && fail * 100 / total > GQ_COLLECTION_FAIL_PERCENT) { log_printf("%d invalid filenames in unofficial collection file, closing: %s\n", fail, path); success = FALSE; break; } } } } DEBUG_1("collection files: total = %d fail = %d official=%d gqview=%d geometry=%d", total, fail, has_official_header, has_gqview_header, has_geometry_header); fclose(f); if (only_geometry) return has_geometry_header; if (!flush) { gchar *buf = NULL; while (collect_manager_process_action(entry, &buf)) { collection_add_check(cd, file_data_new_group(buf), FALSE, TRUE); changed = TRUE; g_free(buf); buf = NULL; } } cd->list = collection_list_sort(cd->list, cd->sort_method); if (!flush && changed && success) collection_save_private(cd, path); if (!flush) collect_manager_entry_reset(entry); if (!append) cd->changed = FALSE; return success; }