void babl_init_db (void) { const char *path = fish_cache_path (); long length = -1; char seps[] = "\n\r"; Babl *babl = NULL; char *contents = NULL; char *token; char *tokp; const Babl *from_format = NULL; const Babl *to_format = NULL; time_t tim = time (NULL); if (getenv ("BABL_DEBUG_CONVERSIONS")) return; babl_file_get_contents (path, &contents, &length, NULL); if (!contents) return; token = strtok_r (contents, seps, &tokp); while( token != NULL ) { switch (token[0]) { case '-': /* finalize */ if (babl) { if (((babl->fish.pixels + babl->fish.processings) % 100) == (tim % 100)) { /* 1% chance of individual cached conversions being dropped - * making sure mis-measured conversions do not stick around for a long time*/ babl_free (babl); } else babl_db_insert (babl_fish_db(), babl); } from_format = NULL; to_format = NULL; babl=NULL; break; case '#': /* if babl has changed in git .. drop whole cache */ { if (strcmp ( token, cache_header ())) { free (contents); return; } } break; case '\t': if (strchr (token, '=')) { char seps2[] = " "; char *tokp2; char *token2; char name[4096]; _babl_fish_create_name (name, from_format, to_format, 1); babl = babl_db_exist_by_name (babl_fish_db (), name); if (babl) { fprintf (stderr, "%s:%i: loading of cache failed\n", __FUNCTION__, __LINE__); return; } babl = babl_calloc (1, sizeof (BablFishPath) + strlen (name) + 1); babl_set_destructor (babl, _babl_fish_path_destroy); babl->class_type = BABL_FISH_PATH; babl->instance.id = babl_fish_get_id (from_format, to_format); babl->instance.name = ((char *) babl) + sizeof (BablFishPath); strcpy (babl->instance.name, name); babl->fish.source = from_format; babl->fish.destination = to_format; babl->fish_path.conversion_list = babl_list_init_with_size (10); token2 = strtok_r (&token[1], seps2, &tokp2); while( token2 != NULL ) { if (!strncmp (token2, "error=", 6)) { babl->fish.error = babl_parse_double (token2 + 6); } else if (!strncmp (token2, "cost=", 5)) { babl->fish_path.cost = babl_parse_double (token2 + 5); } else if (!strncmp (token2, "pixels=", 7)) { babl->fish.pixels = strtol (token2 + 7, NULL, 10); } else if (!strncmp (token2, "processings=", 12)) { babl->fish.processings = strtol (token2 + 12, NULL, 10); } token2 = strtok_r (NULL, seps2, &tokp2); } } else { Babl *conv = (void*)babl_db_find(babl_conversion_db(), &token[1]); if (!conv) { return; } else babl_list_insert_last (babl->fish_path.conversion_list, conv); } break; default: if (!from_format) { from_format = (void*)babl_db_find(babl_format_db(), token); if (!from_format) return; } else { to_format = (void*)babl_db_find(babl_format_db(), token); if (!to_format) return; } break; } token = strtok_r (NULL, seps, &tokp); } if (contents) free (contents); }
const Babl * babl_fish (const void *source, const void *destination) { const Babl *source_format = NULL; const Babl *destination_format = NULL; babl_assert (source); babl_assert (destination); if (BABL_IS_BABL (source)) source_format = source; if (!source_format) source_format = babl_format ((char *) source); if (!source_format) { babl_log ("args=(%p, %p) source format invalid", source, destination); return NULL; } if (BABL_IS_BABL (destination)) destination_format = destination; if (!destination_format) destination_format = babl_format ((char *) destination); if (!destination_format) { babl_log ("args=(%p, %p) destination format invalid", source, destination); return NULL; } { int hashval; BablHashTable *id_htable; BablFindFish ffish = {(Babl *) NULL, (Babl *) NULL, (Babl *) NULL, 0, (Babl *) NULL, (Babl *) NULL}; /* some vendor compilers can't compile non-constant elements of * compound struct initializers */ ffish.source = source_format; ffish.destination = destination_format; id_htable = (babl_fish_db ())->id_hash; hashval = babl_hash_by_int (id_htable, babl_fish_get_id (source_format, destination_format)); if (source_format == destination_format) { /* In the case of equal source and destination formats * we will search through the fish database for reference fish * to handle the memcpy */ babl_hash_table_find (id_htable, hashval, find_memcpy_fish, (void *) &ffish); } else { /* In the case of different source and destination formats * we will search through the fish database for appropriate fish path * to handle the conversion. In the case that preexistent * fish path is found, we'll return it. In the case BABL_FISH * instance with the same source/destination is found, we'll * return reference fish. * In the case neither fish path nor BABL_FISH path are found, * we'll try to construct new fish path for requested * source/destination. In the case new fish path is found, we'll * return it, otherwise we'll create dummy BABL_FISH instance and * insert it into the fish database to indicate non-existent fish * path. */ babl_hash_table_find (id_htable, hashval, find_fish_path, (void *) &ffish); if (ffish.fish_path) { /* we have found suitable fish path in the database */ return ffish.fish_path; } if (!ffish.fish_fish) { /* we haven't tried to search for suitable path yet */ Babl *fish_path = babl_fish_path (source_format, destination_format); if (fish_path) { return fish_path; } else { /* there isn't a suitable path for requested formats, * let's create a dummy BABL_FISH instance and insert * it into the fish database to indicate that such path * does not exist. */ char *name = "X"; /* name does not matter */ Babl *fish = babl_calloc (1, sizeof (BablFish) + strlen (name) + 1); fish->class_type = BABL_FISH; fish->instance.id = babl_fish_get_id (source_format, destination_format); fish->instance.name = ((char *) fish) + sizeof (BablFish); strcpy (fish->instance.name, name); fish->fish.source = source_format; fish->fish.destination = destination_format; babl_db_insert (babl_fish_db (), fish); } } } if (ffish.fish_ref) { /* we have already found suitable reference fish */ return ffish.fish_ref; } else { /* we have to create new reference fish */ return babl_fish_reference (source_format, destination_format); } } }
Babl * babl_fish_path (const Babl *source, const Babl *destination) { Babl *babl = NULL; char name[BABL_MAX_NAME_LEN]; create_name (name, source, destination, 1); babl = babl_db_exist_by_name (babl_fish_db (), name); if (babl) { /* There is an instance already registered by the required name, * returning the preexistent one instead. */ return babl; } babl = babl_calloc (1, sizeof (BablFishPath) + strlen (name) + 1); babl_set_destructor (babl, babl_fish_path_destroy); babl->class_type = BABL_FISH_PATH; babl->instance.id = babl_fish_get_id (source, destination); babl->instance.name = ((char *) babl) + sizeof (BablFishPath); strcpy (babl->instance.name, name); babl->fish.source = source; babl->fish.destination = destination; babl->fish.processings = 0; babl->fish.pixels = 0; babl->fish.error = BABL_MAX_COST_VALUE; babl->fish_path.cost = BABL_MAX_COST_VALUE; babl->fish_path.loss = BABL_MAX_COST_VALUE; babl->fish_path.conversion_list = babl_list_init_with_size (BABL_HARD_MAX_PATH_LENGTH); { PathContext pc; pc.current_path = babl_list_init_with_size (BABL_HARD_MAX_PATH_LENGTH); pc.fish_path = babl; pc.to_format = (Babl *) destination; if (babl_in_fish_path <= 0) babl_mutex_lock (babl_format_mutex); /* we hold a global lock whilerunning get_conversion_path since * it depends on keeping the various format.visited members in * a consistent state, this code path is not performance critical * since created fishes are cached. */ babl_in_fish_path++; get_conversion_path (&pc, (Babl *) source, 0, max_path_length ()); babl_in_fish_path--; if (babl_in_fish_path <= 0) babl_mutex_unlock (babl_format_mutex); babl_free (pc.current_path); } if (babl_list_size (babl->fish_path.conversion_list) == 0) { babl_free (babl); return NULL; } /* Since there is not an already registered instance by the required * name, inserting newly created class into database. */ babl_db_insert (babl_fish_db (), babl); return babl; }