diff src/sid/xs_stil.c @ 12:3da1b8942b8b trunk

[svn] - remove src/Input src/Output src/Effect src/General src/Visualization src/Container
author nenolod
date Mon, 18 Sep 2006 03:14:20 -0700
parents src/Input/sid/xs_stil.c@13389e613d67
children 6c3c7b841382
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sid/xs_stil.c	Mon Sep 18 03:14:20 2006 -0700
@@ -0,0 +1,462 @@
+/*  
+   XMMS-SID - SIDPlay input plugin for X MultiMedia System (XMMS)
+
+   STIL-database handling functions
+   
+   Programmed and designed by Matti 'ccr' Hamalainen <ccr@tnsp.org>
+   (C) Copyright 1999-2005 Tecnic Software productions (TNSP)
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#include "xs_stil.h"
+#include "xs_support.h"
+#include "xs_config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+
+/* Database handling functions
+ */
+static t_xs_stil_node *xs_stildb_node_new(gchar * pcFilename)
+{
+	t_xs_stil_node *pResult;
+
+	/* Allocate memory for new node */
+	pResult = (t_xs_stil_node *) g_malloc0(sizeof(t_xs_stil_node));
+	if (!pResult)
+		return NULL;
+
+	pResult->pcFilename = g_strdup(pcFilename);
+	if (!pResult->pcFilename) {
+		g_free(pResult);
+		return NULL;
+	}
+
+	return pResult;
+}
+
+
+static void xs_stildb_node_free(t_xs_stil_node * pNode)
+{
+	gint i;
+
+	if (pNode) {
+		/* Free subtune information */
+		for (i = 0; i <= XS_STIL_MAXENTRY; i++) {
+			g_free(pNode->subTunes[i].pName);
+			g_free(pNode->subTunes[i].pAuthor);
+			g_free(pNode->subTunes[i].pInfo);
+		}
+
+		g_free(pNode->pcFilename);
+		g_free(pNode);
+	}
+}
+
+
+/* Insert given node to db linked list
+ */
+static void xs_stildb_node_insert(t_xs_stildb * db, t_xs_stil_node * pNode)
+{
+	assert(db);
+
+	if (db->pNodes) {
+		/* The first node's pPrev points to last node */
+		LPREV = db->pNodes->pPrev;	/* New node's prev = Previous last node */
+		db->pNodes->pPrev->pNext = pNode;	/* Previous last node's next = New node */
+		db->pNodes->pPrev = pNode;	/* New last node = New node */
+		LNEXT = NULL;	/* But next is NULL! */
+	} else {
+		db->pNodes = pNode;	/* First node ... */
+		LPREV = pNode;	/* ... it's also last */
+		LNEXT = NULL;	/* But next is NULL! */
+	}
+}
+
+
+/* Read database (additively) to given db-structure
+ */
+#define XS_STILDB_MULTI if (isMulti) { isMulti = FALSE; xs_pstrcat(&(tmpNode->subTunes[subEntry].pInfo), "\n"); }
+
+
+gint xs_stildb_read(t_xs_stildb * db, gchar * dbFilename)
+{
+	FILE *inFile;
+	gchar inLine[XS_BUF_SIZE + 16];	/* Since we add some chars here and there */
+	guint lineNum, linePos, eolPos;
+	t_xs_stil_node *tmpNode;
+	gboolean isError, isMulti;
+	gint subEntry;
+	assert(db);
+
+	/* Try to open the file */
+	if ((inFile = fopen(dbFilename, "ra")) == NULL) {
+		XSERR("Could not open STILDB '%s'\n", dbFilename);
+		return -1;
+	}
+
+	/* Read and parse the data */
+	lineNum = 0;
+	isError = FALSE;
+	isMulti = FALSE;
+	tmpNode = NULL;
+	subEntry = 0;
+
+	while (!feof(inFile) && !isError) {
+		fgets(inLine, XS_BUF_SIZE, inFile);
+		inLine[XS_BUF_SIZE - 1] = 0;
+		linePos = eolPos = 0;
+		xs_findeol(inLine, &eolPos);
+		inLine[eolPos] = 0;
+		lineNum++;
+
+		switch (inLine[0]) {
+		case '/':
+			/* Check if we are already parsing entry */
+			isMulti = FALSE;
+			if (tmpNode) {
+				XSERR("New entry ('%s') before end of current ('%s')! Possibly malformed STIL-file!\n",
+				      inLine, tmpNode->pcFilename);
+
+				xs_stildb_node_free(tmpNode);
+			}
+
+			/* A new node */
+			subEntry = 0;
+			tmpNode = xs_stildb_node_new(inLine);
+			if (!tmpNode) {
+				/* Allocation failed */
+				XSERR("Could not allocate new STILdb-node for '%s'!\n", inLine);
+				isError = TRUE;
+			}
+			break;
+
+		case '(':
+			/* A new sub-entry */
+			isMulti = FALSE;
+			linePos++;
+			if (inLine[linePos] == '#') {
+				linePos++;
+				if (inLine[linePos]) {
+					xs_findnum(inLine, &linePos);
+					inLine[linePos] = 0;
+					subEntry = atol(&inLine[2]);
+
+					/* Sanity check */
+					if ((subEntry < 1) || (subEntry > XS_STIL_MAXENTRY)) {
+						XSERR("Number of subEntry (%i) for '%s' is invalid\n", subEntry,
+						      tmpNode->pcFilename);
+						subEntry = 0;
+					}
+				}
+			}
+
+			break;
+
+		case 0:
+		case '#':
+		case '\n':
+		case '\r':
+			/* End of entry/field */
+			isMulti = FALSE;
+			if (tmpNode) {
+				/* Insert to database */
+				xs_stildb_node_insert(db, tmpNode);
+				tmpNode = NULL;
+			}
+			break;
+
+		default:
+			/* Check if we are parsing an entry */
+			if (!tmpNode) {
+				XSERR("Entry data encountered outside of entry!\n");
+				break;
+			}
+
+			/* Some other type */
+			if (strncmp(inLine, "   NAME:", 8) == 0) {
+				XS_STILDB_MULTI g_free(tmpNode->subTunes[subEntry].pName);
+				tmpNode->subTunes[subEntry].pName = g_strdup(&inLine[9]);
+			} else if (strncmp(inLine, " AUTHOR:", 8) == 0) {
+				XS_STILDB_MULTI g_free(tmpNode->subTunes[subEntry].pAuthor);
+				tmpNode->subTunes[subEntry].pAuthor = g_strdup(&inLine[9]);
+			} else if (strncmp(inLine, "  TITLE:", 8) == 0) {
+				XS_STILDB_MULTI inLine[eolPos++] = '\n';
+				inLine[eolPos++] = 0;
+				xs_pstrcat(&(tmpNode->subTunes[subEntry].pInfo), &inLine[2]);
+			} else if (strncmp(inLine, " ARTIST:", 8) == 0) {
+				XS_STILDB_MULTI inLine[eolPos++] = '\n';
+				inLine[eolPos++] = 0;
+				xs_pstrcat(&(tmpNode->subTunes[subEntry].pInfo), &inLine[1]);
+			} else if (strncmp(inLine, "COMMENT:", 8) == 0) {
+				XS_STILDB_MULTI isMulti = TRUE;
+				xs_pstrcat(&(tmpNode->subTunes[subEntry].pInfo), inLine);
+			} else if (strncmp(inLine, "        ", 8) == 0) {
+				xs_pstrcat(&(tmpNode->subTunes[subEntry].pInfo), &inLine[8]);
+			}
+			break;
+		}
+
+	}			/* while */
+
+	/* Check if there is one remaining node */
+	if (tmpNode)
+		xs_stildb_node_insert(db, tmpNode);
+
+	/* Close the file */
+	fclose(inFile);
+
+	return 0;
+}
+
+
+/* Compare two nodes
+ */
+static gint xs_stildb_cmp(const void *pNode1, const void *pNode2)
+{
+	/* We assume here that we never ever get NULL-pointers or similar */
+	return strcmp((*(t_xs_stil_node **) pNode1)->pcFilename, (*(t_xs_stil_node **) pNode2)->pcFilename);
+}
+
+
+/* (Re)create index
+ */
+gint xs_stildb_index(t_xs_stildb * db)
+{
+	t_xs_stil_node *pCurr;
+	gint i;
+
+	/* Free old index */
+	if (db->ppIndex) {
+		g_free(db->ppIndex);
+		db->ppIndex = NULL;
+	}
+
+	/* Get size of db */
+	pCurr = db->pNodes;
+	db->n = 0;
+	while (pCurr) {
+		db->n++;
+		pCurr = pCurr->pNext;
+	}
+
+	/* Check number of nodes */
+	if (db->n > 0) {
+		/* Allocate memory for index-table */
+		db->ppIndex = (t_xs_stil_node **) g_malloc(sizeof(t_xs_stil_node *) * db->n);
+		if (!db->ppIndex)
+			return -1;
+
+		/* Get node-pointers to table */
+		i = 0;
+		pCurr = db->pNodes;
+		while (pCurr && (i < db->n)) {
+			db->ppIndex[i++] = pCurr;
+			pCurr = pCurr->pNext;
+		}
+
+		/* Sort the indexes */
+		qsort(db->ppIndex, db->n, sizeof(t_xs_stil_node *), xs_stildb_cmp);
+	}
+
+	return 0;
+}
+
+/* Free a given STIL database
+ */
+void xs_stildb_free(t_xs_stildb * db)
+{
+	t_xs_stil_node *pCurr, *pNext;
+
+	if (!db)
+		return;
+
+	/* Free the memory allocated for nodes */
+	pCurr = db->pNodes;
+	while (pCurr) {
+		pNext = pCurr->pNext;
+		xs_stildb_node_free(pCurr);
+		pCurr = pNext;
+	}
+
+	db->pNodes = NULL;
+
+	/* Free memory allocated for index */
+	if (db->ppIndex) {
+		g_free(db->ppIndex);
+		db->ppIndex = NULL;
+	}
+
+	/* Free structure */
+	db->n = 0;
+	g_free(db);
+}
+
+
+/* Get STIL information node from database
+ */
+static t_xs_stil_node *xs_stildb_get_node(t_xs_stildb * db, gchar * pcFilename)
+{
+	gint iStartNode, iEndNode, iQNode, r, i;
+	gboolean iFound;
+	t_xs_stil_node *pResult;
+
+	/* Check the database pointers */
+	if (!db || !db->pNodes || !db->ppIndex)
+		return NULL;
+
+	/* Look-up via index using binary search */
+	pResult = NULL;
+	iStartNode = 0;
+	iEndNode = (db->n - 1);
+	iQNode = (iEndNode / 2);
+	iFound = FALSE;
+
+	while ((!iFound) && ((iEndNode - iStartNode) > XS_BIN_BAILOUT)) {
+		r = strcmp(pcFilename, db->ppIndex[iQNode]->pcFilename);
+		if (r < 0) {
+			/* Hash was in the <- LEFT side */
+			iEndNode = iQNode;
+			iQNode = iStartNode + ((iEndNode - iStartNode) / 2);
+		} else if (r > 0) {
+			/* Hash was in the RIGHT -> side */
+			iStartNode = iQNode;
+			iQNode = iStartNode + ((iEndNode - iStartNode) / 2);
+		} else
+			iFound = TRUE;
+	}
+
+	/* If not found already */
+	if (!iFound) {
+		/* Search the are linearly */
+		iFound = FALSE;
+		i = iStartNode;
+		while ((i <= iEndNode) && (!iFound)) {
+			if (strcmp(pcFilename, db->ppIndex[i]->pcFilename) == 0)
+				iFound = TRUE;
+			else
+				i++;
+		}
+
+		/* Check the result */
+		if (iFound)
+			pResult = db->ppIndex[i];
+
+	} else {
+		/* Found via binary search */
+		pResult = db->ppIndex[iQNode];
+	}
+
+	return pResult;
+}
+
+
+/*
+ * These should be moved out of this module some day ...
+ */
+static t_xs_stildb *xs_stildb_db = NULL;
+GStaticMutex xs_stildb_db_mutex = G_STATIC_MUTEX_INIT;
+extern GStaticMutex xs_cfg_mutex;
+
+gint xs_stil_init(void)
+{
+	g_static_mutex_lock(&xs_cfg_mutex);
+
+	if (!xs_cfg.stilDBPath) {
+		g_static_mutex_unlock(&xs_cfg_mutex);
+		return -1;
+	}
+
+	g_static_mutex_lock(&xs_stildb_db_mutex);
+
+	/* Check if already initialized */
+	if (xs_stildb_db)
+		xs_stildb_free(xs_stildb_db);
+
+	/* Allocate database */
+	xs_stildb_db = (t_xs_stildb *) g_malloc0(sizeof(t_xs_stildb));
+	if (!xs_stildb_db) {
+		g_static_mutex_unlock(&xs_cfg_mutex);
+		g_static_mutex_unlock(&xs_stildb_db_mutex);
+		return -2;
+	}
+
+	/* Read the database */
+	if (xs_stildb_read(xs_stildb_db, xs_cfg.stilDBPath) != 0) {
+		xs_stildb_free(xs_stildb_db);
+		xs_stildb_db = NULL;
+		g_static_mutex_unlock(&xs_cfg_mutex);
+		g_static_mutex_unlock(&xs_stildb_db_mutex);
+		return -3;
+	}
+
+	/* Create index */
+	if (xs_stildb_index(xs_stildb_db) != 0) {
+		xs_stildb_free(xs_stildb_db);
+		xs_stildb_db = NULL;
+		g_static_mutex_unlock(&xs_cfg_mutex);
+		g_static_mutex_unlock(&xs_stildb_db_mutex);
+		return -4;
+	}
+
+	g_static_mutex_unlock(&xs_cfg_mutex);
+	g_static_mutex_unlock(&xs_stildb_db_mutex);
+	return 0;
+}
+
+
+void xs_stil_close(void)
+{
+	g_static_mutex_lock(&xs_stildb_db_mutex);
+	xs_stildb_free(xs_stildb_db);
+	xs_stildb_db = NULL;
+	g_static_mutex_unlock(&xs_stildb_db_mutex);
+}
+
+
+t_xs_stil_node *xs_stil_get(gchar * pcFilename)
+{
+	t_xs_stil_node *pResult;
+	gchar *tmpFilename;
+
+	g_static_mutex_lock(&xs_stildb_db_mutex);
+	g_static_mutex_lock(&xs_cfg_mutex);
+
+	if (xs_cfg.stilDBEnable && xs_stildb_db) {
+		if (xs_cfg.hvscPath) {
+			/* Remove postfixed directory separator from HVSC-path */
+			tmpFilename = xs_strrchr(xs_cfg.hvscPath, '/');
+			if (tmpFilename && (tmpFilename[1] == 0))
+				tmpFilename[0] = 0;
+
+			/* Remove HVSC location-prefix from filename */
+			tmpFilename = strstr(pcFilename, xs_cfg.hvscPath);
+			if (tmpFilename)
+				tmpFilename += strlen(xs_cfg.hvscPath);
+			else
+				tmpFilename = pcFilename;
+		} else
+			tmpFilename = pcFilename;
+
+		pResult = xs_stildb_get_node(xs_stildb_db, tmpFilename);
+	} else
+		pResult = NULL;
+
+	g_static_mutex_unlock(&xs_stildb_db_mutex);
+	g_static_mutex_unlock(&xs_cfg_mutex);
+
+	return pResult;
+}