cannam@85: /* cannam@85: ** Copyright (C) 2005-2011 Erik de Castro Lopo cannam@85: ** cannam@85: ** This program is free software; you can redistribute it and/or modify cannam@85: ** it under the terms of the GNU General Public License as published by cannam@85: ** the Free Software Foundation; either version 2 of the License, or cannam@85: ** (at your option) any later version. cannam@85: ** cannam@85: ** This program is distributed in the hope that it will be useful, cannam@85: ** but WITHOUT ANY WARRANTY; without even the implied warranty of cannam@85: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the cannam@85: ** GNU General Public License for more details. cannam@85: ** cannam@85: ** You should have received a copy of the GNU General Public License cannam@85: ** along with this program; if not, write to the Free Software cannam@85: ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. cannam@85: */ cannam@85: cannam@85: #include "config.h" cannam@85: cannam@85: #include cannam@85: #include cannam@85: #include cannam@85: #include cannam@85: #include cannam@85: #include cannam@85: cannam@85: #include cannam@85: cannam@85: #include "regtest.h" cannam@85: cannam@85: #if HAVE_SQLITE3 cannam@85: cannam@85: #include cannam@85: cannam@85: typedef struct cannam@85: { sqlite3 *sql ; cannam@85: cannam@85: int count ; cannam@85: int ekey_max ; cannam@85: cannam@85: /* Filename and pathname for file. */ cannam@85: char filename [256] ; cannam@85: char pathname [512] ; cannam@85: cannam@85: /* Storage for createding SQL commands. Must be larger than logbuf below. */ cannam@85: char cmdbuf [1 << 15] ; cannam@85: cannam@85: /* Storage for log buffer retrieved from SNDFILE* .*/ cannam@85: char logbuf [1 << 14] ; cannam@85: cannam@85: } REGTEST_DB ; cannam@85: cannam@85: /* In checksum.c */ cannam@85: int calc_checksum (SNDFILE * file, const SF_INFO * info) ; cannam@85: cannam@85: static void get_filename_pathname (REGTEST_DB * db, const char *filepath) ; cannam@85: static void single_quote_replace (char * buf) ; cannam@85: cannam@85: static int get_ekey_from_filename (REGTEST_DB * db, const char *filepath) ; cannam@85: static int get_filename_pathname_by_ekey (REGTEST_DB * db, int ekey) ; cannam@85: static int check_file_by_ekey (REGTEST_DB * db, int ekey) ; cannam@85: cannam@85: static int count_callback (REGTEST_DB * db, int argc, char **argv, char **colname) ; cannam@85: static int ekey_max_callback (REGTEST_DB * db, int argc, char **argv, char **colname) ; cannam@85: static int callback (void *unused, int argc, char **argv, char **colname) ; cannam@85: cannam@85: REG_DB * cannam@85: db_open (const char * db_name) cannam@85: { REGTEST_DB * db ; cannam@85: int err ; cannam@85: cannam@85: if ((db = malloc (sizeof (REGTEST_DB))) == NULL) cannam@85: { perror ("malloc") ; cannam@85: exit (1) ; cannam@85: } ; cannam@85: cannam@85: if ((err = sqlite3_open (db_name, &(db->sql))) != 0) cannam@85: { printf ("Can't open database: %s\n", sqlite3_errmsg (db->sql)) ; cannam@85: sqlite3_close (db->sql) ; cannam@85: free (db) ; cannam@85: exit (1) ; cannam@85: } ; cannam@85: cannam@85: return (REG_DB *) db ; cannam@85: } /* db_open */ cannam@85: cannam@85: int cannam@85: db_create (const char * db_name) cannam@85: { REGTEST_DB * db ; cannam@85: const char *cmd ; cannam@85: char * errmsg = NULL ; cannam@85: int err ; cannam@85: cannam@85: db = (REGTEST_DB *) db_open (db_name) ; cannam@85: cannam@85: cmd = "create table sndfile (ekey INTEGER PRIMARY KEY," cannam@85: "fname VARCHAR(1)," cannam@85: "fpath VARCHAR(1)," cannam@85: "srate INTEGER," cannam@85: "frames VARCHAR(1)," cannam@85: "channels INTEGER," cannam@85: "format VARCHAR(1)," cannam@85: "checksum VARCHAR(1)," cannam@85: "logbuf VARCHAR(1)" cannam@85: ");" ; cannam@85: cannam@85: err = sqlite3_exec (db->sql, cmd, callback, 0, &errmsg) ; cannam@85: if (err != SQLITE_OK) cannam@85: printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; cannam@85: cannam@85: sqlite3_close (db->sql) ; cannam@85: free (db) ; cannam@85: cannam@85: return 0 ; cannam@85: } /* db_create */ cannam@85: cannam@85: int cannam@85: db_close (REG_DB * db_handle) cannam@85: { REGTEST_DB * db ; cannam@85: cannam@85: db = (REGTEST_DB *) db_handle ; cannam@85: cannam@85: sqlite3_close (db->sql) ; cannam@85: free (db) ; cannam@85: cannam@85: return 0 ; cannam@85: } /* db_close */ cannam@85: cannam@85: /*============================================================================== cannam@85: */ cannam@85: cannam@85: int cannam@85: db_file_exists (REG_DB * db_handle, const char * filename) cannam@85: { REGTEST_DB * db ; cannam@85: const char * cptr ; cannam@85: char * errmsg ; cannam@85: int err ; cannam@85: cannam@85: db = (REGTEST_DB *) db_handle ; cannam@85: cannam@85: if ((cptr = strrchr (filename, '/')) != NULL) cannam@85: filename = cptr + 1 ; cannam@85: cannam@85: snprintf (db->cmdbuf, sizeof (db->cmdbuf), "select fname from sndfile where fname='%s'", filename) ; cannam@85: cannam@85: db->count = 0 ; cannam@85: err = sqlite3_exec (db->sql, db->cmdbuf, (sqlite3_callback) count_callback, db, &errmsg) ; cannam@85: if (err == 0 && db->count == 1) cannam@85: return 1 ; cannam@85: cannam@85: return 0 ; cannam@85: } /* db_file_exists */ cannam@85: cannam@85: int cannam@85: db_add_file (REG_DB * db_handle, const char * filepath) cannam@85: { REGTEST_DB * db ; cannam@85: SNDFILE * sndfile ; cannam@85: SF_INFO info ; cannam@85: char * errmsg ; cannam@85: int err, checksum ; cannam@85: cannam@85: db = (REGTEST_DB *) db_handle ; cannam@85: cannam@85: get_filename_pathname (db, filepath) ; cannam@85: cannam@85: if (db_file_exists (db_handle, filepath)) cannam@85: { printf (" %s : already in database\n", db->filename) ; cannam@85: return 0 ; cannam@85: } ; cannam@85: cannam@85: memset (&info, 0, sizeof (info)) ; cannam@85: sndfile = sf_open (db->pathname, SFM_READ, &info) ; cannam@85: sf_command (sndfile, SFC_GET_LOG_INFO, db->logbuf, sizeof (db->logbuf)) ; cannam@85: checksum = (sndfile == NULL) ? 0 : calc_checksum (sndfile, &info) ; cannam@85: sf_close (sndfile) ; cannam@85: cannam@85: if (sndfile == NULL) cannam@85: { printf (" %s : could not open : %s\n", db->filename, sf_strerror (NULL)) ; cannam@85: puts (db->logbuf) ; cannam@85: return 1 ; cannam@85: } ; cannam@85: cannam@85: single_quote_replace (db->logbuf) ; cannam@85: cannam@85: snprintf (db->cmdbuf, sizeof (db->cmdbuf), "insert into sndfile " cannam@85: "(fname, fpath, srate, frames, channels, format, checksum, logbuf) values" cannam@85: "('%s','%s',%d,'%ld', %d, '0x%08x', '0x%08x', '%s');", cannam@85: db->filename, db->pathname, info.samplerate, (long) info.frames, info.channels, info.format, checksum, db->logbuf) ; cannam@85: cannam@85: if (strlen (db->cmdbuf) >= sizeof (db->cmdbuf) - 1) cannam@85: { printf ("strlen (db->cmdbuf) too long.\n") ; cannam@85: exit (1) ; cannam@85: } ; cannam@85: cannam@85: err = sqlite3_exec (db->sql, db->cmdbuf, callback, 0, &errmsg) ; cannam@85: if (err != SQLITE_OK) cannam@85: { printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; cannam@85: puts (db->cmdbuf) ; cannam@85: } ; cannam@85: cannam@85: return 0 ; cannam@85: } /* db_add_file */ cannam@85: cannam@85: int cannam@85: db_check_file (REG_DB * db_handle, const char * filepath) cannam@85: { REGTEST_DB * db ; cannam@85: int ekey ; cannam@85: cannam@85: if (db_file_exists (db_handle, filepath) == 0) cannam@85: { printf ("\nFile not in database.\n\n") ; cannam@85: exit (0) ; cannam@85: } ; cannam@85: cannam@85: db = (REGTEST_DB *) db_handle ; cannam@85: cannam@85: ekey = get_ekey_from_filename (db, filepath) ; cannam@85: cannam@85: return check_file_by_ekey (db, ekey) ; cannam@85: } /* db_check_file */ cannam@85: cannam@85: /*============================================================================== cannam@85: */ cannam@85: cannam@85: int cannam@85: db_check_all (REG_DB * db_handle) cannam@85: { REGTEST_DB * db ; cannam@85: char * errmsg ; cannam@85: int err, ekey ; cannam@85: cannam@85: db = (REGTEST_DB *) db_handle ; cannam@85: cannam@85: db->ekey_max = 0 ; cannam@85: cannam@85: snprintf (db->cmdbuf, sizeof (db->cmdbuf), "select ekey from sndfile") ; cannam@85: cannam@85: err = sqlite3_exec (db->sql, db->cmdbuf, (sqlite3_callback) ekey_max_callback, db, &errmsg) ; cannam@85: if (err != SQLITE_OK) cannam@85: { printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; cannam@85: puts (db->cmdbuf) ; cannam@85: } ; cannam@85: cannam@85: for (ekey = 1 ; ekey <= db->ekey_max ; ekey++) cannam@85: if (get_filename_pathname_by_ekey (db, ekey) != 0) cannam@85: check_file_by_ekey (db, ekey) ; cannam@85: cannam@85: return 0 ; cannam@85: } /* db_check_all */ cannam@85: cannam@85: cannam@85: int cannam@85: db_list_all (REG_DB * db_handle) cannam@85: { cannam@85: printf ("%s : %p\n", __func__, db_handle) ; cannam@85: return 0 ; cannam@85: } /* db_list_all */ cannam@85: cannam@85: int cannam@85: db_del_entry (REG_DB * db_handle, const char * entry) cannam@85: { cannam@85: printf ("%s : %p %s\n", __func__, db_handle, entry) ; cannam@85: return 0 ; cannam@85: } /* db_del_entry */ cannam@85: cannam@85: /*============================================================================== cannam@85: */ cannam@85: cannam@85: static int cannam@85: get_ekey_from_filename (REGTEST_DB * db, const char *filepath) cannam@85: { char * errmsg, **result ; cannam@85: int err, ekey = 0, rows, cols ; cannam@85: cannam@85: get_filename_pathname (db, filepath) ; cannam@85: cannam@85: snprintf (db->cmdbuf, sizeof (db->cmdbuf), "select ekey from sndfile where fname='%s'", db->filename) ; cannam@85: cannam@85: err = sqlite3_get_table (db->sql, db->cmdbuf, &result, &rows, &cols, &errmsg) ; cannam@85: if (err != SQLITE_OK) cannam@85: { printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; cannam@85: puts (db->cmdbuf) ; cannam@85: } ; cannam@85: cannam@85: if (cols != 1 || rows != 1) cannam@85: { printf ("Bad juju!! rows = %d cols = %d\n", rows, cols) ; cannam@85: exit (1) ; cannam@85: } ; cannam@85: cannam@85: ekey = strtol (result [1], NULL, 10) ; cannam@85: cannam@85: sqlite3_free_table (result) ; cannam@85: cannam@85: return ekey ; cannam@85: } /* get_ekey_from_filename */ cannam@85: cannam@85: static int cannam@85: get_filename_pathname_by_ekey (REGTEST_DB * db, int ekey) cannam@85: { char *errmsg, **result ; cannam@85: int err, rows, cols ; cannam@85: cannam@85: snprintf (db->cmdbuf, sizeof (db->cmdbuf), "select fname,fpath from sndfile where ekey='%d'", ekey) ; cannam@85: cannam@85: err = sqlite3_get_table (db->sql, db->cmdbuf, &result, &rows, &cols, &errmsg) ; cannam@85: if (err != SQLITE_OK) cannam@85: { printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; cannam@85: puts (db->cmdbuf) ; cannam@85: return 0 ; cannam@85: } ; cannam@85: cannam@85: if (cols != 2 || rows != 1) cannam@85: { printf ("\nError (%s %d) : rows = %d cols = %d\n", __func__, __LINE__, rows, cols) ; cannam@85: exit (1) ; cannam@85: } ; cannam@85: cannam@85: snprintf (db->filename, sizeof (db->filename), "%s", result [2]) ; cannam@85: snprintf (db->pathname, sizeof (db->pathname), "%s", result [3]) ; cannam@85: cannam@85: sqlite3_free_table (result) ; cannam@85: cannam@85: return 1 ; cannam@85: } /* get_filename_pathname_by_ekey */ cannam@85: cannam@85: static int cannam@85: check_file_by_ekey (REGTEST_DB * db, int ekey) cannam@85: { SNDFILE * sndfile ; cannam@85: SF_INFO info ; cannam@85: char * errmsg, **result ; cannam@85: int err, k, rows, cols, checksum ; cannam@85: cannam@85: printf (" %s : ", db->filename) ; cannam@85: fflush (stdout) ; cannam@85: cannam@85: memset (&info, 0, sizeof (info)) ; cannam@85: sndfile = sf_open (db->pathname, SFM_READ, &info) ; cannam@85: sf_command (sndfile, SFC_GET_LOG_INFO, db->logbuf, sizeof (db->logbuf)) ; cannam@85: checksum = (sndfile == NULL) ? 0 : calc_checksum (sndfile, &info) ; cannam@85: sf_close (sndfile) ; cannam@85: cannam@85: if (sndfile == NULL) cannam@85: { printf ("\n\nError : Could not open '%s' : %s\n", db->pathname, sf_strerror (NULL)) ; cannam@85: puts (db->logbuf) ; cannam@85: exit (1) ; cannam@85: } ; cannam@85: cannam@85: single_quote_replace (db->logbuf) ; cannam@85: cannam@85: snprintf (db->cmdbuf, sizeof (db->cmdbuf), "select fname,srate,frames,channels,format," cannam@85: "checksum,logbuf from sndfile where ekey='%d'", ekey) ; cannam@85: cannam@85: err = sqlite3_get_table (db->sql, db->cmdbuf, &result, &rows, &cols, &errmsg) ; cannam@85: if (err != SQLITE_OK) cannam@85: { printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; cannam@85: puts (db->cmdbuf) ; cannam@85: } ; cannam@85: cannam@85: for (k = 0 ; k < cols ; k++) cannam@85: { if (strcmp (result [k], "fname") == 0) cannam@85: { if (strcmp (result [k + cols], db->filename) == 0) cannam@85: continue ; cannam@85: printf ("\n\nError : fname doesn't match : %s != %s\n", result [k + cols], db->filename) ; cannam@85: } ; cannam@85: cannam@85: if (strcmp (result [k], "srate") == 0) cannam@85: { if (strtol (result [k + cols], NULL, 10) == info.samplerate) cannam@85: continue ; cannam@85: printf ("\n\nError : srate doesn't match : %s == %d\n", result [k + cols], info.samplerate) ; cannam@85: } ; cannam@85: cannam@85: if (strcmp (result [k], "frames") == 0) cannam@85: { if (strtoll (result [k + cols], NULL, 10) == info.frames) cannam@85: continue ; cannam@85: printf ("\n\nError : frames doesn't match : %s == %ld\n", result [k + cols], (long) info.frames) ; cannam@85: } ; cannam@85: cannam@85: if (strcmp (result [k], "channels") == 0) cannam@85: { if (strtol (result [k + cols], NULL, 10) == info.channels) cannam@85: continue ; cannam@85: printf ("\n\nError : channels doesn't match : %s == %d\n", result [k + cols], info.channels) ; cannam@85: } ; cannam@85: cannam@85: if (strcmp (result [k], "format") == 0) cannam@85: { if (strtol (result [k + cols], NULL, 16) == info.format) cannam@85: continue ; cannam@85: printf ("\n\nError : format doesn't match : %s == 0x%08x\n", result [k + cols], info.format) ; cannam@85: } ; cannam@85: cannam@85: if (strcmp (result [k], "checksum") == 0) cannam@85: { int db_val = (int) strtoll (result [k + cols], NULL, 16) ; cannam@85: cannam@85: if (db_val == checksum) cannam@85: continue ; cannam@85: printf ("\n\nError : checksum doesn't match : 0x%08x == 0x%08x\n", db_val, checksum) ; cannam@85: } ; cannam@85: cannam@85: if (strcmp (result [k], "logbuf") == 0) cannam@85: continue ; cannam@85: cannam@85: printf ("\nHere is the old logubuffer :\n\n%s\n\nand the new :\n\n%s\n\n", result [2 * cols - 1], db->logbuf) ; cannam@85: exit (1) ; cannam@85: } ; cannam@85: cannam@85: sqlite3_free_table (result) ; cannam@85: cannam@85: puts ("ok") ; cannam@85: cannam@85: return 0 ; cannam@85: } /* check_file_by_ekey */ cannam@85: cannam@85: /*============================================================================== cannam@85: */ cannam@85: cannam@85: static void cannam@85: get_filename_pathname (REGTEST_DB * db, const char *filepath) cannam@85: { const char * cptr ; cannam@85: int slen ; cannam@85: cannam@85: if (filepath [0] != '/') cannam@85: { memset (db->pathname, 0, sizeof (db->pathname)) ; cannam@85: if (getcwd (db->pathname, sizeof (db->pathname)) == NULL) cannam@85: { perror ("\ngetcwd failed") ; cannam@85: exit (1) ; cannam@85: } ; cannam@85: cannam@85: slen = strlen (db->pathname) ; cannam@85: db->pathname [slen ++] = '/' ; cannam@85: snprintf (db->pathname + slen, sizeof (db->pathname) - slen, "%s", filepath) ; cannam@85: } cannam@85: else cannam@85: snprintf (db->pathname, sizeof (db->pathname), "%s", filepath) ; cannam@85: cannam@85: if ((cptr = strrchr (db->pathname, '/')) == NULL) cannam@85: { printf ("\nError : bad pathname %s\n", filepath) ; cannam@85: exit (1) ; cannam@85: } ; cannam@85: cannam@85: snprintf (db->filename, sizeof (db->filename), "%s", cptr + 1) ; cannam@85: } /* get filename_pathname */ cannam@85: cannam@85: static void cannam@85: single_quote_replace (char * buf) cannam@85: { while ((buf = strchr (buf, '\'')) != 0) cannam@85: buf [0] = '"' ; cannam@85: } /* single_quote_replace */ cannam@85: cannam@85: static int cannam@85: count_callback (REGTEST_DB * db, int argc, char **argv, char **colname) cannam@85: { db->count ++ ; cannam@85: cannam@85: (void) argc ; cannam@85: (void) argv ; cannam@85: (void) colname ; cannam@85: return 0 ; cannam@85: } /* count_callback */ cannam@85: cannam@85: static int cannam@85: ekey_max_callback (REGTEST_DB * db, int argc, char **argv, char **unused) cannam@85: { int ekey ; cannam@85: cannam@85: (void) argc ; cannam@85: (void) unused ; cannam@85: cannam@85: ekey = strtol (argv [0], NULL, 10) ; cannam@85: if (ekey > db->ekey_max) cannam@85: db->ekey_max = ekey ; cannam@85: cannam@85: return 0 ; cannam@85: } /* ekey_max_callback */ cannam@85: cannam@85: static int cannam@85: callback (void *unused, int argc, char **argv, char **colname) cannam@85: { int k ; cannam@85: cannam@85: (void) unused ; cannam@85: cannam@85: for (k = 0 ; k < argc ; k++) cannam@85: printf ("%s = %s\n", colname [k], argv [k] ? argv [k] : "NULL") ; cannam@85: cannam@85: printf ("\n") ; cannam@85: cannam@85: return 0 ; cannam@85: } /* callback */ cannam@85: cannam@85: #else cannam@85: cannam@85: int dummy (void) ; cannam@85: cannam@85: int cannam@85: dummy (void) cannam@85: { /* cannam@85: ** Empty dummy fnction so tha compiler doesn't winge about an cannam@85: ** empty file. cannam@85: */ cannam@85: return 0 ; cannam@85: } /* dummy */ cannam@85: cannam@85: #endif