• Main Page
  • Related Pages
  • Classes
  • Files
  • File List
  • File Members

stringpool.c

Go to the documentation of this file.
00001 /*
00002  * Audacious
00003  * Copyright © 2009 William Pitcock <nenolod@atheme.org>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; under version 3 of the License.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program.  If not, see <http://www.gnu.org/licenses>.
00016  *
00017  * The Audacious team does not consider modular code linking to
00018  * Audacious or using our public API to be a derived work.
00019  */
00020 
00021 /*
00022  * Note: This code used to do some normalization of strings: conversion to
00023  * UTF-8, conversion of the empty string to NULL, and (optionally) conversion
00024  * to uppercase.  However, because such conversions can change the length of the
00025  * string, they can lead to a double-free.
00026  *
00027  * Consider:
00028  *
00029  * stringpool_get is called twice with the same 99-character ISO-8859-1 string.
00030  * The string is short enough to be cached, so stringpool_get returns a cached,
00031  * 101-character UTF-8 string.  stringpool_unref is then called twice
00032  * with the cached string.  Now that it has been converted, it is too long to be
00033  * cached, so stringpool_unref simply frees it, twice.
00034  *
00035  * Therefore, it is essential for stringpool_get to return a string that is
00036  * exactly the same as the one passed it.
00037  *
00038  * --jlindgren
00039  */
00040 
00041 #include <glib.h>
00042 #include <mowgli.h>
00043 
00044 #include "audstrings.h"
00045 
00046 #define MAXLEN 100
00047 
00048 static void
00049 noopcanon(gchar *str)
00050 {
00051     return;
00052 }
00053 
00055 typedef struct {
00056     gint refcount;
00057     gchar *str;
00058 } PooledString;
00059 
00060 static mowgli_patricia_t *stringpool_tree = NULL;
00061 static GStaticMutex stringpool_mutex = G_STATIC_MUTEX_INIT;
00062 
00063 static inline gboolean stringpool_should_cache(const gchar *string)
00064 {
00065     const gchar *end = memchr(string, '\0', MAXLEN + 1);
00066     return end != NULL ? TRUE : FALSE;
00067 }
00068 
00069 gchar *
00070 stringpool_get(const gchar *str)
00071 {
00072     PooledString *ps;
00073 
00074     g_return_val_if_fail(str != NULL, NULL);
00075 
00076     if (!stringpool_should_cache(str))
00077         return g_strdup(str);
00078 
00079     g_static_mutex_lock(&stringpool_mutex);
00080 
00081     if (stringpool_tree == NULL)
00082         stringpool_tree = mowgli_patricia_create(noopcanon);
00083 
00084     if ((ps = mowgli_patricia_retrieve(stringpool_tree, str)) != NULL)
00085     {
00086         ps->refcount++;
00087 
00088         g_static_mutex_unlock(&stringpool_mutex);
00089         return ps->str;
00090     }
00091 
00092     ps = g_slice_new0(PooledString);
00093     ps->refcount++;
00094     ps->str = g_strdup(str);
00095     mowgli_patricia_add(stringpool_tree, str, ps);
00096 
00097     g_static_mutex_unlock(&stringpool_mutex);
00098     return ps->str;
00099 }
00100 
00101 void
00102 stringpool_unref(gchar *str)
00103 {
00104     PooledString *ps;
00105 
00106     g_return_if_fail(str != NULL);
00107 
00108     if (!stringpool_should_cache(str))
00109     {
00110         g_free(str);
00111         return;
00112     }
00113 
00114     g_return_if_fail(stringpool_tree != NULL);
00115 
00116     g_static_mutex_lock(&stringpool_mutex);
00117 
00118     ps = mowgli_patricia_retrieve(stringpool_tree, str);
00119     if (ps != NULL && --ps->refcount <= 0)
00120     {
00121         mowgli_patricia_delete(stringpool_tree, str);
00122         g_free(ps->str);
00123         g_slice_free(PooledString, ps);
00124     }
00125 
00126     g_static_mutex_unlock(&stringpool_mutex);
00127 }

Generated on Wed Apr 6 2011 for Audacious by  doxygen 1.7.1