📄 st-cache.c
字号:
/* * Copyright (c) 2004 Jean-Yves Lefort * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Jean-Yves Lefort nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <stdarg.h>#include <errno.h>#include <glib.h>#include <glib/gi18n.h>#include "sg-util.h"#include "sgtk-util.h"#include "st-handler.h"#include "st-handler-field.h"#include "st-handlers.h"#include "st-settings.h"#include "st-cache.h"/*** cpp *********************************************************************/#define CATEGORIES_MAGIC 0x43435453 /* STCC (little endian integer) */#define CATEGORIES_VERSION 0#define STREAMS_MAGIC 0x43535453 /* STSC (little endian integer) */#define STREAMS_VERSION 0#define st_cache_read_int(channel, int_ptr, err) \ st_cache_read_any((channel), (int_ptr), sizeof(int), (err))#define st_cache_read_double(channel, double_ptr, err) \ st_cache_read_any((channel), (double_ptr), sizeof(double), (err))/*** type definitions ********************************************************/typedef enum{ ATOM_CATEGORY_NAME, ATOM_CATEGORY_FLAGS, ATOM_CATEGORY_PARENT, ATOM_CATEGORY_LABEL, ATOM_CATEGORY_URL_POSTFIX} CategoryAtom;typedef enum{ ATOM_STREAM_NAME, ATOM_STREAM_FIELDS} StreamAtom;typedef enum{ VALUE_TYPE_BOOLEAN, VALUE_TYPE_INT, VALUE_TYPE_UINT, VALUE_TYPE_DOUBLE, VALUE_TYPE_STRING, VALUE_TYPE_VALUE_ARRAY, VALUE_TYPE_PIXBUF} ValueType;typedef struct{ GIOChannel *channel; gboolean status; GError **err;} SaveInfo;typedef enum{ OPEN_MODE_READ, OPEN_MODE_WRITE} OpenMode;/*** function declarations ***************************************************/static gboolean st_cache_save_handler (STHandler *handler, GError **err);static gboolean st_cache_save_category_cb (STCategoryStore *store, STCategoryBag *bag, STCategoryBag *parent, gpointer data);static gboolean st_cache_save_category (GIOChannel *channel, STCategoryBag *category_bag, STCategoryBag *parent_bag, GError **err);static gboolean st_cache_save_streams (STCategoryBag *category_bag, STStreamStore *streams, GError **err);static gboolean st_cache_save_stream_cb (STStreamStore *store, STStreamBag *bag, gpointer data);static gboolean st_cache_save_stream (GIOChannel *channel, STStreamBag *stream_bag, GError **err);static gboolean st_cache_save_value (GIOChannel *channel, const GValue *value, GError **err);static char *st_cache_get_filename (const char *str);static char *st_cache_get_handler_directory (STHandler *handler);static char *st_cache_get_categories_filename (STHandler *handler);static char *st_cache_get_streams_filename (STHandler *handler, const char *category_name);static GIOChannel *st_cache_io_channel_new_file (const char *filename, OpenMode mode, int magic, int version, int subversion, GError **err);static GIOChannel *st_cache_io_channel_new_categories (const char *filename, OpenMode mode, GError **err);static GIOChannel *st_cache_io_channel_new_streams (STHandler *handler, const char *filename, OpenMode mode, GError **err);static gboolean st_cache_write (GIOChannel *channel, const char *format, ...);static gboolean st_cache_write_int (GIOChannel *channel, int i, GError **err);static gboolean st_cache_write_double (GIOChannel *channel, double d, GError **err);static gboolean st_cache_write_buffer (GIOChannel *channel, const char *buf, int len, GError **err);static gboolean st_cache_write_string (GIOChannel *channel, const char *str, GError **err);static void st_cache_append_category (STHandler *handler, GHashTable *parents, GNode *categories, STCategoryBag *category_bag, const char *parent_name);static gboolean st_cache_load_value (GIOChannel *channel, GValue *value, GError **err);static gboolean st_cache_read_any (GIOChannel *channel, gpointer ptr, int len, GError **err);static gboolean st_cache_read_buffer (GIOChannel *channel, char **buf, int *len, GError **err);static gboolean st_cache_read_string (GIOChannel *channel, char **str, GError **err);/*** implementation **********************************************************/gbooleanst_cache_save (GError **err){ GSList *l; SG_LIST_FOREACH(l, st_handlers_list) if (! st_cache_save_handler(l->data, err)) return FALSE; return TRUE;}static gbooleanst_cache_save_handler (STHandler *handler, GError **err){ char *dirname; SaveInfo info; STCategoryStore *categories; g_return_val_if_fail(ST_IS_HANDLER(handler), FALSE); dirname = st_cache_get_handler_directory(handler); if (! g_file_test(dirname, G_FILE_TEST_IS_DIR) && (mkdir(dirname, 0755) < 0)) { g_set_error(err, 0, 0, _("unable to create directory %s: %s"), dirname, g_strerror(errno)); g_free(dirname); return FALSE; } g_free(dirname); if (ST_HANDLER_HAS_CATEGORIES(handler)) { char *filename; filename = st_cache_get_categories_filename(handler); info.channel = st_cache_io_channel_new_categories(filename, OPEN_MODE_WRITE, err); g_free(filename); if (! info.channel) return FALSE; } else info.channel = NULL; info.status = TRUE; info.err = err; categories = st_handler_get_categories(handler); st_category_store_foreach(categories, st_cache_save_category_cb, &info); g_object_unref(categories); if (info.channel) { if (info.status) { if (g_io_channel_shutdown(info.channel, TRUE, err) != G_IO_STATUS_NORMAL) info.status = FALSE; } else g_io_channel_shutdown(info.channel, FALSE, NULL); g_io_channel_unref(info.channel); } return info.status;}static gbooleanst_cache_save_category_cb (STCategoryStore *store, STCategoryBag *bag, STCategoryBag *parent, gpointer data){ SaveInfo *info = data; info->status = st_cache_save_category(info->channel, bag, parent, info->err); return ! info->status;}static gbooleanst_cache_save_category (GIOChannel *channel, STCategoryBag *category_bag, STCategoryBag *parent_bag, GError **err){ STStreamStore *streams; g_return_val_if_fail(ST_IS_CATEGORY_BAG(category_bag), FALSE); if (channel) { if (! st_cache_write(channel, "isii", ATOM_CATEGORY_NAME, ST_CATEGORY(category_bag)->name, ATOM_CATEGORY_FLAGS, category_bag->flags, err)) return FALSE; if (parent_bag) { if (! st_cache_write(channel, "is", ATOM_CATEGORY_PARENT, ST_CATEGORY(parent_bag)->name, err)) return FALSE; } if (! ST_CATEGORY_BAG_IS_STOCK(category_bag)) { if (! st_cache_write(channel, "isis", ATOM_CATEGORY_LABEL, ST_CATEGORY(category_bag)->label, ATOM_CATEGORY_URL_POSTFIX, ST_CATEGORY(category_bag)->url_postfix, err)) return FALSE; } } streams = st_handler_get_streams(category_bag->handler, ST_CATEGORY(category_bag)->name); if (streams) { gboolean status; status = st_stream_store_is_touched(streams) ? st_cache_save_streams(category_bag, streams, err) : TRUE; g_object_unref(streams); if (! status) return FALSE; } return TRUE;}static gbooleanst_cache_save_streams (STCategoryBag *category_bag, STStreamStore *streams, GError **err){ char *filename; SaveInfo info; g_return_val_if_fail(ST_IS_CATEGORY_BAG(category_bag), FALSE); g_return_val_if_fail(ST_IS_STREAM_STORE(streams), FALSE); filename = st_cache_get_streams_filename(category_bag->handler, ST_CATEGORY(category_bag)->name); info.channel = st_cache_io_channel_new_streams(category_bag->handler, filename, OPEN_MODE_WRITE, err); g_free(filename); if (! info.channel) return FALSE; info.status = st_cache_write_int(info.channel, sgtk_tree_model_get_count(GTK_TREE_MODEL(streams)), err); if (info.status) { info.err = err; st_stream_store_foreach(streams, st_cache_save_stream_cb, &info); } if (info.status) { if (g_io_channel_shutdown(info.channel, TRUE, err) != G_IO_STATUS_NORMAL) info.status = FALSE; } else g_io_channel_shutdown(info.channel, FALSE, NULL); g_io_channel_unref(info.channel); return info.status;}static gbooleanst_cache_save_stream_cb (STStreamStore *store, STStreamBag *bag, gpointer data){ SaveInfo *info = data; info->status = st_cache_save_stream(info->channel, bag, info->err); return ! info->status;}static gbooleanst_cache_save_stream (GIOChannel *channel, STStreamBag *stream_bag, GError **err){ GSList *fields; GSList *l; g_return_val_if_fail(channel != NULL, FALSE); g_return_val_if_fail(ST_IS_STREAM_BAG(stream_bag), FALSE); fields = st_handler_get_fields(stream_bag->handler); if (! st_cache_write(channel, "isii", ATOM_STREAM_NAME, ST_STREAM(stream_bag)->name, ATOM_STREAM_FIELDS, g_slist_length(fields) - st_handler_count_fields(stream_bag->handler, ST_HANDLER_FIELD_VOLATILE), err)) return FALSE; SG_LIST_FOREACH(l, fields) { STHandlerField *field = l->data; if (! ST_HANDLER_FIELD_IS_VOLATILE(field)) { GValue value = { 0, }; gboolean status; st_stream_bag_get_field(stream_bag, field, &value); status = st_cache_save_value(channel, &value, err); g_value_unset(&value); if (! status) return FALSE; } } return TRUE;}static gbooleanst_cache_save_value (GIOChannel *channel, const GValue *value, GError **err){ ValueType type; g_return_val_if_fail(channel != NULL, FALSE); g_return_val_if_fail(G_IS_VALUE(value), FALSE); if (G_VALUE_HOLDS_BOOLEAN(value)) type = VALUE_TYPE_BOOLEAN; else if (G_VALUE_HOLDS_INT(value)) type = VALUE_TYPE_INT; else if (G_VALUE_HOLDS_UINT(value)) type = VALUE_TYPE_UINT; else if (G_VALUE_HOLDS_DOUBLE(value)) type = VALUE_TYPE_DOUBLE; else if (G_VALUE_HOLDS_STRING(value)) type = VALUE_TYPE_STRING; else if (G_VALUE_HOLDS(value, G_TYPE_VALUE_ARRAY)) type = VALUE_TYPE_VALUE_ARRAY; else if (G_VALUE_HOLDS(value, GDK_TYPE_PIXBUF)) type = VALUE_TYPE_PIXBUF; else g_return_val_if_reached(FALSE); if (! st_cache_write_int(channel, type, err)) return FALSE; switch (type) { case VALUE_TYPE_BOOLEAN: if (! st_cache_write_int(channel, g_value_get_boolean(value), err)) return FALSE; break; case VALUE_TYPE_INT: if (! st_cache_write_int(channel, g_value_get_int(value), err)) return FALSE; break; case VALUE_TYPE_UINT: if (! st_cache_write_int(channel, g_value_get_uint(value), err)) return FALSE; break; case VALUE_TYPE_DOUBLE: if (! st_cache_write_double(channel, g_value_get_double(value), err)) return FALSE; break; case VALUE_TYPE_STRING: if (! st_cache_write_string(channel, g_value_get_string(value), err)) return FALSE; break; case VALUE_TYPE_VALUE_ARRAY: { GValueArray *value_array = g_value_get_boxed(value); int i; if (! st_cache_write_int(channel, value_array->n_values, err)) return FALSE; for (i = 0; i < value_array->n_values; i++) if (! st_cache_save_value(channel, g_value_array_get_nth(value_array, i), err)) return FALSE; break; } case VALUE_TYPE_PIXBUF: { GdkPixbuf *pixbuf;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -