static gpointer gegl_tile_backend_file_set_tile (GeglTileSource *self, GeglTile *tile, gint x, gint y, gint z) { GeglTileBackend *backend; GeglTileBackendFile *tile_backend_file; GeglBufferTile *entry; backend = GEGL_TILE_BACKEND (self); tile_backend_file = GEGL_TILE_BACKEND_FILE (backend); entry = gegl_tile_backend_file_lookup_entry (tile_backend_file, x, y, z); if (entry == NULL) { entry = gegl_tile_backend_file_file_entry_new (tile_backend_file); entry->x = x; entry->y = y; entry->z = z; g_hash_table_insert (tile_backend_file->index, entry, entry); } entry->rev = gegl_tile_get_rev (tile); gegl_tile_backend_file_file_entry_write (tile_backend_file, entry, gegl_tile_get_data (tile)); gegl_tile_mark_as_stored (tile); return NULL; }
/* this is the only place that actually should * instantiate tiles, when the cache is large enough * that should make sure we don't hit this function * too often. */ static GeglTile * gegl_tile_backend_file_get_tile (GeglTileSource *self, gint x, gint y, gint z) { GeglTileBackend *backend; GeglTileBackendFile *tile_backend_file; GeglBufferTile *entry; GeglTile *tile = NULL; gint tile_size; backend = GEGL_TILE_BACKEND (self); tile_backend_file = GEGL_TILE_BACKEND_FILE (backend); entry = gegl_tile_backend_file_lookup_entry (tile_backend_file, x, y, z); if (!entry) return NULL; tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self)); tile = gegl_tile_new (tile_size); gegl_tile_set_rev (tile, entry->rev); gegl_tile_mark_as_stored (tile); gegl_tile_backend_file_file_entry_read (tile_backend_file, entry, gegl_tile_get_data (tile)); return tile; }
static gpointer gegl_tile_backend_file_flush (GeglTileSource *source, GeglTile *tile, gint x, gint y, gint z) { GeglTileBackend *backend; GeglTileBackendFile *self; GList *tiles; backend = GEGL_TILE_BACKEND (source); self = GEGL_TILE_BACKEND_FILE (backend); gegl_tile_backend_file_ensure_exist (self); GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "flushing %s", self->path); self->header.rev ++; self->header.next = self->next_pre_alloc; /* this is the offset we start handing out headers from*/ tiles = g_hash_table_get_keys (self->index); if (tiles == NULL) self->header.next = 0; else { GList *iter; for (iter = tiles; iter; iter = iter->next) { GeglBufferItem *item = iter->data; gegl_tile_backend_file_write_block (self, &item->block); } gegl_tile_backend_file_write_block (self, NULL); /* terminate the index */ g_list_free (tiles); } gegl_tile_backend_file_write_header (self); #if HAVE_GIO g_output_stream_flush (self->o, NULL, NULL); #else fsync (self->o); #endif GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "flushed %s", self->path); return (gpointer)0xf0f; }
static gpointer gegl_tile_backend_file_exist_tile (GeglTileSource *self, GeglTile *tile, gint x, gint y, gint z) { GeglTileBackend *backend; GeglTileBackendFile *tile_backend_file; GeglBufferTile *entry; backend = GEGL_TILE_BACKEND (self); tile_backend_file = GEGL_TILE_BACKEND_FILE (backend); entry = gegl_tile_backend_file_lookup_entry (tile_backend_file, x, y, z); return entry!=NULL?((gpointer)0x1):NULL; }
static void gegl_tile_backend_file_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { GeglTileBackendFile *self = GEGL_TILE_BACKEND_FILE (object); switch (property_id) { case PROP_PATH: g_value_set_string (value, self->path); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } }
static gpointer gegl_tile_backend_file_void_tile (GeglTileSource *self, GeglTile *tile, gint x, gint y, gint z) { GeglTileBackend *backend; GeglTileBackendFile *tile_backend_file; GeglBufferTile *entry; backend = GEGL_TILE_BACKEND (self); tile_backend_file = GEGL_TILE_BACKEND_FILE (backend); entry = gegl_tile_backend_file_lookup_entry (tile_backend_file, x, y, z); if (entry != NULL) { gegl_tile_backend_file_file_entry_destroy (entry, tile_backend_file); } return NULL; }
static GObject * gegl_tile_backend_file_constructor (GType type, guint n_params, GObjectConstructParam *params) { GObject *object; GeglTileBackendFile *self; GeglTileBackend *backend; object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params); self = GEGL_TILE_BACKEND_FILE (object); backend = GEGL_TILE_BACKEND (object); GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "constructing file backend: %s", self->path); self->file = g_file_new_for_commandline_arg (self->path); self->i = self->o = -1; self->index = g_hash_table_new (gegl_tile_backend_file_hashfunc, gegl_tile_backend_file_equalfunc); /* If the file already exists open it, assuming it is a GeglBuffer. */ if (g_access (self->path, F_OK) != -1) { goffset offset = 0; /* Install a monitor for changes to the file in case other applications * might be writing to the buffer */ self->monitor = g_file_monitor_file (self->file, G_FILE_MONITOR_NONE, NULL, NULL); g_signal_connect (self->monitor, "changed", G_CALLBACK (gegl_tile_backend_file_file_changed), self); self->o = g_open (self->path, O_RDWR|O_CREAT, 0770); if (self->o == -1) { /* Try again but this time with only read access. This is * a quick-fix for make distcheck, where img_cmp fails * when it opens a GeglBuffer file in the source tree * (which is read-only). */ self->o = g_open (self->path, O_RDONLY, 0770); if (self->o == -1) g_warning ("%s: Could not open '%s': %s", G_STRFUNC, self->path, g_strerror (errno)); } self->i = dup (self->o); self->header = gegl_buffer_read_header (self->i, &offset)->header; self->header.rev = self->header.rev -1; /* we are overriding all of the work of the actual constructor here, * a really evil hack :d */ backend->priv->tile_width = self->header.tile_width; backend->priv->tile_height = self->header.tile_height; backend->priv->format = babl_format (self->header.description); backend->priv->px_size = babl_format_get_bytes_per_pixel (backend->priv->format); backend->priv->tile_size = backend->priv->tile_width * backend->priv->tile_height * backend->priv->px_size; /* insert each of the entries into the hash table */ gegl_tile_backend_file_load_index (self, TRUE); self->exist = TRUE; g_assert (self->i != -1); g_assert (self->o != -1); /* to autoflush gegl_buffer_set */ /* XXX: poking at internals, icky */ backend->priv->shared = TRUE; } else { self->exist = FALSE; /* this is also the default, the file will be created on demand */ } g_assert (self->file); backend->priv->header = &self->header; return object; }
static GObject * gegl_tile_backend_file_constructor (GType type, guint n_params, GObjectConstructParam *params) { GObject *object; GeglTileBackendFile *self; GeglTileBackend *backend; object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params); self = GEGL_TILE_BACKEND_FILE (object); backend = GEGL_TILE_BACKEND (object); GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "constructing file backend: %s", self->path); #if HAVE_GIO self->file = g_file_new_for_commandline_arg (self->path); #else self->i = self->o = -1; #endif self->index = g_hash_table_new (gegl_tile_backend_file_hashfunc, gegl_tile_backend_file_equalfunc); /* If the file already exists open it, assuming it is a GeglBuffer. */ #if HAVE_GIO if (g_file_query_exists (self->file, NULL)) #else if (access (self->path, F_OK) != -1) #endif { goffset offset = 0; #if HAVE_GIO /* Install a monitor for changes to the file in case other applications * might be writing to the buffer */ self->monitor = g_file_monitor_file (self->file, G_FILE_MONITOR_NONE, NULL, NULL); g_signal_connect (self->monitor, "changed", G_CALLBACK (gegl_tile_backend_file_file_changed), self); { GError *error = NULL; self->io = G_IO_STREAM (g_file_open_readwrite (self->file, NULL, &error)); if (error) { /* Try again but this time with only read access. This is * a quick-fix for make distcheck, where img_cmp fails * when it opens a GeglBuffer file in the source tree * (which is read-only). */ g_error_free (error); error = NULL; self->i = G_INPUT_STREAM (g_file_read (self->file, NULL, &error)); if (error) { g_warning ("%s: %s", G_STRLOC, error->message); g_error_free (error); error = NULL; } } else { self->o = g_io_stream_get_output_stream (self->io); self->i = g_io_stream_get_input_stream (self->io); } } #else self->o = open (self->path, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); self->i = dup (self->o); #endif /*self->i = G_INPUT_STREAM (g_file_read (self->file, NULL, NULL));*/ self->header = gegl_buffer_read_header (self->i, &offset)->header; self->header.rev = self->header.rev -1; /* we are overriding all of the work of the actual constructor here, * a really evil hack :d */ backend->priv->tile_width = self->header.tile_width; backend->priv->tile_height = self->header.tile_height; backend->priv->format = babl_format (self->header.description); backend->priv->px_size = babl_format_get_bytes_per_pixel (backend->priv->format); backend->priv->tile_size = backend->priv->tile_width * backend->priv->tile_height * backend->priv->px_size; /* insert each of the entries into the hash table */ gegl_tile_backend_file_load_index (self, TRUE); self->exist = TRUE; #if HAVE_GIO /* We can only assert input stream, we won't have an output * stream on read-only files */ g_assert (self->i); #else g_assert (self->i != -1); g_assert (self->o != -1); #endif /* to autoflush gegl_buffer_set */ /* XXX: poking at internals, icky */ backend->priv->shared = TRUE; } else { self->exist = FALSE; /* this is also the default, the file will be created on demand */ } #if HAVE_GIO g_assert (self->file); #endif backend->priv->header = &self->header; return object; }