diff src/xs_length.c @ 227:92bad4c7b998

Improved modularization of STIL and song-length database subsystems.
author Matti Hamalainen <ccr@tnsp.org>
date Sun, 19 Dec 2004 16:53:05 +0000
parents 16e3b2446a73
children 608f31f6c095
line wrap: on
line diff
--- a/src/xs_length.c	Sun Dec 19 15:25:03 2004 +0000
+++ b/src/xs_length.c	Sun Dec 19 16:53:05 2004 +0000
@@ -21,25 +21,15 @@
 */
 #include "xs_length.h"
 #include "xs_support.h"
-#include "xs_config.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
 #include <string.h>
 
 
-/*
- * Pointer to database in memory
+/* Database handling functions
  */
-static t_xs_sldb_node	*xs_sldb = NULL;
-static t_xs_sldb_node	**xs_sldbi = NULL;
-static gint		xs_sldbn   = 0;
-
-
-/*
- * Hash-database handling functions
- */
-t_xs_sldb_node *xs_sldb_node_new(void)
+static t_xs_sldb_node *xs_sldb_node_new(void)
 {
  t_xs_sldb_node *pResult;
  
@@ -51,124 +41,40 @@
 }
 
 
-void xs_sldb_node_free(t_xs_sldb_node *pNode)
+static void xs_sldb_node_free(t_xs_sldb_node *pNode)
 {
- if (pNode) g_free(pNode);
+ if (pNode)
+ 	{
+ 	/* Nothing much to do here ... */
+ 	g_free(pNode);
+ 	}
 }
 
 
-/*
- * Insert given node to db linked list
+/* Insert given node to db linked list
  */
-#define LPREV	(pNode->pPrev)
-#define LTHIS	(pNode)
-#define LNEXT	(pNode->pNext)
-
-void xs_sldb_node_insert(t_xs_sldb_node *pNode)
+static void xs_sldb_node_insert(t_xs_sldb *db, t_xs_sldb_node *pNode)
 {
- if (xs_sldb)
+ assert(db);
+ 
+ if (db->pNodes)
  	{
  	/* The first node's pPrev points to last node */
-	LPREV = xs_sldb->pPrev;		/* New node's prev = Previous last node */
-	xs_sldb->pPrev->pNext = pNode;	/* Previous last node's next = New node */
-	xs_sldb->pPrev = pNode;		/* New last node = New 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 {
- 	xs_sldb = pNode;			/* First node ... */
+ 	db->pNodes = pNode;			/* First node ... */
  	LPREV = pNode;				/* ... it's also last */
  	LNEXT = NULL;				/* But next is NULL! */
  	}
 }
 
 
-/*
- * Compare two given MD5-hashes.
- * Return: 0 if equal
- *         negative if testHash1 < testHash2
- *         positive if testHash1 > testHash2
- */
-gint xs_sldb_cmphash(t_xs_md5hash testHash1, t_xs_md5hash testHash2)
-{
- register gint i, res = 0;
-  
- /* Compute difference of hashes */
- for (i = 0; (i < XS_MD5HASH_LENGTH) && (!res); i++)
- 	res = (testHash1[i] - testHash2[i]);
-
- return res;
-}
-
-
-/*
- * Get song length from database
+/* Parses a time-entry in SLDB format
  */
-t_xs_sldb_node * xs_sldb_get(t_xs_md5hash pHash)
-{
- gint iStartNode, iEndNode, iQNode, r, i;
- gboolean iFound;
- t_xs_sldb_node *pResult;
-
- /* Check the database pointers */
- if (!xs_sldb || !xs_sldbi)
- 	return NULL;
- 	
- /* Look-up via index using binary search */
- pResult = NULL;
- iStartNode = 0;
- iEndNode = (xs_sldbn - 1);
- iQNode = (iEndNode / 2);
- iFound = FALSE;
-
- while ((!iFound) && ((iEndNode - iStartNode) > 128))
- 	{
- 	r = xs_sldb_cmphash(pHash, xs_sldbi[iQNode]->md5Hash);
- 	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 (xs_sldb_cmphash(pHash, xs_sldbi[i]->md5Hash) == 0)
-			iFound = TRUE;
-			else
-			i++;
-		}
-	
-	/* Check the result */
-	if (iFound)
-		pResult = xs_sldbi[i];
-
- 	} else {
-	/* Found via binary search */
- 	pResult = xs_sldbi[iQNode];
-	}
-
-
- return pResult;
-}
-
-
-/*
- * Parses a time-entry in SLDB format
- */
-gint32 xs_gettime(gchar *pcStr, int *piPos)
+static gint32 xs_sldb_gettime(gchar *pcStr, int *piPos)
 {
  gint32 iResult, iTemp;
 
@@ -204,16 +110,16 @@
 }
 
 
-/*
- * Read database to memory
+/* Read database to memory
  */
-gint xs_sldb_read(gchar *dbFilename)
+gint xs_sldb_read(t_xs_sldb *db, gchar *dbFilename)
 {
  FILE *inFile;
  gchar inLine[XS_BUFSIZE];
  guint lineNum, linePos;
  gboolean iOK;
  t_xs_sldb_node *tmpNode;
+ assert(db);
  
  /* Try to open the file */
  if ((inFile = fopen(dbFilename, "ra")) == NULL)
@@ -284,7 +190,7 @@
 			if (tmpNode->nLengths < XS_STIL_MAXENTRY)
 				{
 				tmpNode->sLengths[tmpNode->nLengths] =
-				xs_gettime(inLine, &linePos);
+				xs_sldb_gettime(inLine, &linePos);
 				tmpNode->nLengths++;
 				} else
 				iOK = FALSE;
@@ -292,7 +198,7 @@
 
 		/* Add an node to db in memory */
 		if (iOK)
-			xs_sldb_node_insert(tmpNode);
+			xs_sldb_node_insert(db, tmpNode);
 			else
 			xs_sldb_node_free(tmpNode);
 		}
@@ -314,10 +220,90 @@
 }
 
 
-/*
- * Compare two nodes' hashes
+/* Compare two given MD5-hashes.
+ * Return: 0 if equal
+ *         negative if testHash1 < testHash2
+ *         positive if testHash1 > testHash2
+ */
+static gint xs_sldb_cmphash(t_xs_md5hash testHash1, t_xs_md5hash testHash2)
+{
+ register gint i, res = 0;
+  
+ /* Compute difference of hashes */
+ for (i = 0; (i < XS_MD5HASH_LENGTH) && (!res); i++)
+ 	res = (testHash1[i] - testHash2[i]);
+
+ return res;
+}
+
+
+/* Get node from db index via binary search
  */
-gint xs_sldb_cmp(const void *pNode1, const void *pNode2)
+static t_xs_sldb_node * xs_sldb_get_node(t_xs_sldb *db, t_xs_md5hash pHash)
+{
+ gint iStartNode, iEndNode, iQNode, r, i;
+ gboolean iFound;
+ t_xs_sldb_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) > 128))
+ 	{
+ 	r = xs_sldb_cmphash(pHash, db->ppIndex[iQNode]->md5Hash);
+ 	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 (xs_sldb_cmphash(pHash, db->ppIndex[i]->md5Hash) == 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;
+}
+
+
+/* Compare two nodes
+ */
+static gint xs_sldb_cmp(const void *pNode1, const void *pNode2)
 {
  /* We assume here that we never ever get NULL-pointers or similar */
  return xs_sldb_cmphash((*(t_xs_sldb_node **) pNode1)->md5Hash,
@@ -325,70 +311,64 @@
 }
 
 
-/*
- * Initialize the song-length system
+/* (Re)create index
  */
-gint xs_songlen_init(void)
+gint xs_sldb_index(t_xs_sldb *db)
 {
  t_xs_sldb_node *pCurr;
  gint i;
-
-XSDEBUG("sldb_init()\n");
+ assert(db);
  
- /* Read the database */
- if (!xs_cfg.songlenDBPath)
- 	return -10;
-
- if (xs_sldb_read(xs_cfg.songlenDBPath) < 0)
- 	return -9;
-
-XSDEBUG("indexing...\n");
-
+ /* Free old index */
+ if (db->ppIndex)
+ 	{
+ 	g_free(db->ppIndex);
+ 	db->ppIndex = NULL;
+ 	}
+ 
  /* Get size of db */
- pCurr = xs_sldb;
- xs_sldbn = 0;
+ pCurr = db->pNodes;
+ db->n = 0;
  while (pCurr)
  	{
- 	xs_sldbn++;
+ 	db->n++;
  	pCurr = pCurr->pNext;
  	}
 
  /* Check number of nodes */
- if (xs_sldbn > 0)
+ if (db->n > 0)
 	{
 	/* Allocate memory for index-table */
-	xs_sldbi = (t_xs_sldb_node **) g_malloc(sizeof(t_xs_sldb_node *) * xs_sldbn);
-	if (!xs_sldbi) return -6;
+	db->ppIndex = (t_xs_sldb_node **) g_malloc(sizeof(t_xs_sldb_node *) * db->n);
+	if (!db->ppIndex) return -1;
 
 	/* Get node-pointers to table */
 	i = 0;
-	pCurr = xs_sldb;
-	while (pCurr)
+	pCurr = db->pNodes;
+	while (pCurr && (i < db->n))
 		{
-		xs_sldbi[i++] = pCurr;
+		db->ppIndex[i++] = pCurr;
 		pCurr = pCurr->pNext;
 		}
 
 	/* Sort the indexes */
-	qsort(xs_sldbi, xs_sldbn, sizeof(t_xs_sldb_node *), xs_sldb_cmp);
+	qsort(db->ppIndex, db->n, sizeof(t_xs_sldb_node *), xs_sldb_cmp);
 	}
 
- /* OK */
-XSDEBUG("init ok.\n");
  return 0;
 }
 
 
-/*
- * Close song-length system
+/* Free a given song-length database
  */
-void xs_songlen_close(void)
+void xs_sldb_free(t_xs_sldb *db)
 {
  t_xs_sldb_node *pCurr, *pNext;
  
- /* Free the memory allocated for database */
-XSDEBUG("sldb_close()\n");
- pCurr = xs_sldb;
+ if (!db) return;
+ 
+ /* Free the memory allocated for nodes */
+ pCurr = db->pNodes;
  while (pCurr)
  	{
  	pNext = pCurr->pNext;
@@ -396,19 +376,22 @@
  	pCurr = pNext;
  	}
 
- xs_sldb = NULL;
+ db->pNodes = NULL;
  
- /* Free memory allocated for indexes */
- if (xs_sldbi)
+ /* Free memory allocated for index */
+ if (db->ppIndex)
  	{
- 	g_free(xs_sldbi);
- 	xs_sldbi = NULL;
+ 	g_free(db->ppIndex);
+ 	db->ppIndex = NULL;
  	}
+
+ /* Free structure */
+ db->n = 0;
+ g_free(db);
 }
 
 
-/*
- * Compute md5hash of given SID-file
+/* Compute md5hash of given SID-file
  */
 typedef struct {
 	gchar	magicID[4];	/* "PSID" magic identifier */
@@ -434,83 +417,86 @@
 } t_xs_psidv2_header;
 
 
-guint16 rd_be16(FILE *f)
-{
- return (((guint16) fgetc(f)) << 8) |
- 	 ((guint16) fgetc(f));
-}
-
-
-guint32 rd_be32(FILE *f)
-{
- return (((guint32) fgetc(f)) << 24) |
- 	(((guint32) fgetc(f)) << 16) |
- 	(((guint32) fgetc(f)) << 8) |
- 	 ((guint32) fgetc(f));
-}
-
-
-gint rd_str(FILE *f, gchar *s, gint l)
-{
- return fread(s, sizeof(gchar), l, f);
-}
-
-#define MAX_MEMBUF (80*1024)
-
-gint xs_get_sid_hash(gchar *pcFilename, t_xs_md5hash hash)
+static gint xs_get_sid_hash(gchar *pcFilename, t_xs_md5hash hash)
 {
  FILE *inFile;
  t_xs_md5state inState;
  t_xs_psidv1_header psidH;
  t_xs_psidv2_header psidH2;
- guint8 songData[MAX_MEMBUF+1], ib8[2], i8;
+#ifdef XS_SIDBUF_DYNAMIC
+ guint8 *songData;
+#else
+ guint8 songData[XS_SIDBUF_SIZE];
+#endif
+ guint8 ib8[2], i8;
  gint iIndex, iRes;
 
-
  /* Try to open the file */
  if ((inFile = fopen(pcFilename, "rb")) == NULL)
  	return -1;
 
  /* Read PSID header in */
- rd_str(inFile, psidH.magicID, sizeof(psidH.magicID));
+ xs_rd_str(inFile, psidH.magicID, sizeof(psidH.magicID));
  if ((psidH.magicID[0] != 'P') || (psidH.magicID[1] != 'S') || 
      (psidH.magicID[2] != 'I') || (psidH.magicID[3] != 'D'))
+     {
+     fclose(inFile);
      return -2;
+     }
  
- psidH.version		= rd_be16(inFile);
- psidH.dataOffset	= rd_be16(inFile);
- psidH.loadAddress	= rd_be16(inFile);
- psidH.initAddress	= rd_be16(inFile);
- psidH.playAddress	= rd_be16(inFile);
- psidH.nSongs		= rd_be16(inFile);
- psidH.startSong	= rd_be16(inFile);
- psidH.speed		= rd_be32(inFile);
+ psidH.version		= xs_rd_be16(inFile);
+ psidH.dataOffset	= xs_rd_be16(inFile);
+ psidH.loadAddress	= xs_rd_be16(inFile);
+ psidH.initAddress	= xs_rd_be16(inFile);
+ psidH.playAddress	= xs_rd_be16(inFile);
+ psidH.nSongs		= xs_rd_be16(inFile);
+ psidH.startSong	= xs_rd_be16(inFile);
+ psidH.speed		= xs_rd_be32(inFile);
 
- rd_str(inFile, psidH.sidName, sizeof(psidH.sidName));
- rd_str(inFile, psidH.sidAuthor, sizeof(psidH.sidAuthor));
- rd_str(inFile, psidH.sidCopyright, sizeof(psidH.sidCopyright));
+ xs_rd_str(inFile, psidH.sidName, sizeof(psidH.sidName));
+ xs_rd_str(inFile, psidH.sidAuthor, sizeof(psidH.sidAuthor));
+ xs_rd_str(inFile, psidH.sidCopyright, sizeof(psidH.sidCopyright));
  
  /* Check if we need to load PSIDv2NG header ... */
  if (psidH.version == 2)
  	{
  	/* Yes, we need to */
- 	psidH2.flags		= rd_be16(inFile);
+ 	psidH2.flags		= xs_rd_be16(inFile);
  	psidH2.startPage	= fgetc(inFile);
  	psidH2.pageLength	= fgetc(inFile);
- 	psidH2.reserved		= rd_be16(inFile);
+ 	psidH2.reserved		= xs_rd_be16(inFile);
  	}
 
+#ifdef XS_SIDBUF_DYNAMIC
+ /* Allocate buffer */
+ songData = (guint8 *) g_malloc(XS_SIDBUF_SIZE * sizeof(guint8));
+ if (!songData)
+ 	{
+ 	fclose(inFile);
+ 	return -3;
+ 	}
+#endif
+ 
  /* Read data to buffer */
- iRes = fread(songData, sizeof(guint8), MAX_MEMBUF, inFile);
+ iRes = fread(songData, sizeof(guint8), XS_SIDBUF_SIZE, inFile);
  fclose(inFile);
 
  /* Initialize and start MD5-hash calculation */
  xs_md5_init(&inState);
  if (psidH.loadAddress == 0)
- 	/* COULD SOMEONE EXPLAIN WHY DO WE NEED THIS +2 STRIP???? */
+ 	{
+ 	/* Strip load address (2 first bytes) */
 	xs_md5_append(&inState, &songData[2], iRes-2);
-	else
+	} else {
+	/* Append "as is" */
 	xs_md5_append(&inState, songData, iRes);
+	}
+
+
+#ifdef XS_SIDBUF_DYNAMIC
+ /* Free buffer */
+ g_free(songData);
+#endif
 
  /* Append header data to hash */
 #define XSADDHASH(QDATAB) { ib8[0] = (QDATAB & 0xff); ib8[1] = (QDATAB >> 8); xs_md5_append(&inState, (guint8 *) &ib8, sizeof(ib8)); }
@@ -552,24 +538,18 @@
 }
 
 
-/*
- * Get song lengths
+/* Get song lengths
  */
-t_xs_sldb_node * xs_songlen_get(gchar *pcFilename)
+t_xs_sldb_node * xs_sldb_get(t_xs_sldb *db, gchar *pcFilename)
 {
  t_xs_sldb_node *pResult;
  t_xs_md5hash dbHash;
 
- pResult = NULL;
+ /* Get the hash and then look up from db */
+ if (xs_get_sid_hash(pcFilename, dbHash) == 0)
+	pResult = xs_sldb_get_node(db, dbHash);
+	else
+	pResult = NULL;
  
- if (xs_cfg.songlenDBEnable)
-	{
-	/* Get the hash and then look up from db */
-	if (xs_get_sid_hash(pcFilename, dbHash) == 0)
-		{
-		pResult = xs_sldb_get(dbHash);
-		}
-	}
-
  return pResult;
 }