/* ** Copyright (C) 2005-2011 Erik de Castro Lopo ** ** 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include #if HAVE_UNISTD_H #include #else #include "sf_unistd.h" #endif #include #include #ifdef HAVE_DIRECT_H #include #endif #include #include #include "regtest.h" #if HAVE_SQLITE3 #include #include typedef struct { sqlite3 *sql ; int count ; int ekey_max ; /* Filename and pathname for file. */ char filename [256] ; char pathname [512] ; /* Storage for createding SQL commands. Must be larger than logbuf below. */ char cmdbuf [1 << 15] ; /* Storage for log buffer retrieved from SNDFILE* .*/ char logbuf [1 << 14] ; } REGTEST_DB ; /* In checksum.c */ int calc_checksum (SNDFILE * file, const SF_INFO * info) ; static void get_filename_pathname (REGTEST_DB * db, const char *filepath) ; static void single_quote_replace (char * buf) ; static int get_ekey_from_filename (REGTEST_DB * db, const char *filepath) ; static int get_filename_pathname_by_ekey (REGTEST_DB * db, int ekey) ; static int check_file_by_ekey (REGTEST_DB * db, int ekey) ; static int count_callback (REGTEST_DB * db, int argc, char **argv, char **colname) ; static int ekey_max_callback (REGTEST_DB * db, int argc, char **argv, char **colname) ; static int callback (void *unused, int argc, char **argv, char **colname) ; static const char *db_basename (const char *fname); /* Windows accepts both '\\' and '/' in paths */ #ifdef _WIN32 #define IS_SLASH(c) ((c) == '\\' || (c) == '/') #define HAS_DRIVELETTER(path) (isalpha ((int)(path[0])) && path[1] == ':' && IS_SLASH(path[2])) #else #define IS_SLASH(c) ((c) == '/') #define HAS_DRIVELETTER(path) 0 #endif REG_DB * db_open (const char * db_name) { REGTEST_DB * db ; int err ; if ((db = malloc (sizeof (REGTEST_DB))) == NULL) { perror ("malloc") ; exit (1) ; } ; if ((err = sqlite3_open (db_name, &(db->sql))) != 0) { printf ("Can't open database: %s\n", sqlite3_errmsg (db->sql)) ; sqlite3_close (db->sql) ; free (db) ; exit (1) ; } ; return (REG_DB *) db ; } /* db_open */ int db_create (const char * db_name) { REGTEST_DB * db ; const char *cmd ; char * errmsg = NULL ; int err ; db = (REGTEST_DB *) db_open (db_name) ; cmd = "create table sndfile (ekey INTEGER PRIMARY KEY," "fname VARCHAR(1)," "fpath VARCHAR(1)," "srate INTEGER," "frames VARCHAR(1)," "channels INTEGER," "format VARCHAR(1)," "checksum VARCHAR(1)," "logbuf VARCHAR(1)" ");" ; err = sqlite3_exec (db->sql, cmd, callback, 0, &errmsg) ; if (err != SQLITE_OK) printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; sqlite3_close (db->sql) ; free (db) ; return 0 ; } /* db_create */ int db_close (REG_DB * db_handle) { REGTEST_DB * db ; db = (REGTEST_DB *) db_handle ; sqlite3_close (db->sql) ; free (db) ; return 0 ; } /* db_close */ /*============================================================================== */ int db_file_exists (REG_DB * db_handle, const char * filename) { REGTEST_DB * db ; char * errmsg ; int err ; db = (REGTEST_DB *) db_handle ; filename = db_basename (filename); snprintf (db->cmdbuf, sizeof (db->cmdbuf), "select fname from sndfile where fname='%s'", filename) ; db->count = 0 ; err = sqlite3_exec (db->sql, db->cmdbuf, (sqlite3_callback) count_callback, db, &errmsg) ; if (err == 0 && db->count == 1) return 1 ; return 0 ; } /* db_file_exists */ int db_add_file (REG_DB * db_handle, const char * filepath) { REGTEST_DB * db ; SNDFILE * sndfile ; SF_INFO info ; char * errmsg ; int err, checksum ; db = (REGTEST_DB *) db_handle ; get_filename_pathname (db, filepath) ; if (db_file_exists (db_handle, filepath)) { printf (" %s : already in database\n", db->filename) ; return 0 ; } ; memset (&info, 0, sizeof (info)) ; sndfile = sf_open (db->pathname, SFM_READ, &info) ; sf_command (sndfile, SFC_GET_LOG_INFO, db->logbuf, sizeof (db->logbuf)) ; checksum = (sndfile == NULL) ? 0 : calc_checksum (sndfile, &info) ; sf_close (sndfile) ; if (sndfile == NULL) { printf (" %s : could not open : %s, filepath: '%s'\n", db->filename, sf_strerror (NULL), filepath) ; puts (db->logbuf) ; return 1 ; } ; single_quote_replace (db->logbuf) ; snprintf (db->cmdbuf, sizeof (db->cmdbuf), "insert into sndfile " "(fname, fpath, srate, frames, channels, format, checksum, logbuf) values" "('%s','%s',%d,'%ld', %d, '0x%08x', '0x%08x', '%s');", db->filename, db->pathname, info.samplerate, (long) info.frames, info.channels, info.format, checksum, db->logbuf) ; if (strlen (db->cmdbuf) >= sizeof (db->cmdbuf) - 1) { printf ("strlen (db->cmdbuf) too long.\n") ; exit (1) ; } ; err = sqlite3_exec (db->sql, db->cmdbuf, callback, 0, &errmsg) ; if (err != SQLITE_OK) { printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; puts (db->cmdbuf) ; } ; return 0 ; } /* db_add_file */ int db_check_file (REG_DB * db_handle, const char * filepath) { REGTEST_DB * db ; int ekey ; if (db_file_exists (db_handle, filepath) == 0) { printf ("\nFile not in database.\n\n") ; exit (0) ; } ; db = (REGTEST_DB *) db_handle ; ekey = get_ekey_from_filename (db, filepath) ; return check_file_by_ekey (db, ekey) ; } /* db_check_file */ /*============================================================================== */ int db_check_all (REG_DB * db_handle) { REGTEST_DB * db ; char * errmsg ; int err, ekey ; db = (REGTEST_DB *) db_handle ; db->ekey_max = 0 ; snprintf (db->cmdbuf, sizeof (db->cmdbuf), "select ekey from sndfile") ; err = sqlite3_exec (db->sql, db->cmdbuf, (sqlite3_callback) ekey_max_callback, db, &errmsg) ; if (err != SQLITE_OK) { printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; puts (db->cmdbuf) ; } ; for (ekey = 1 ; ekey <= db->ekey_max ; ekey++) if (get_filename_pathname_by_ekey (db, ekey) != 0) check_file_by_ekey (db, ekey) ; return 0 ; } /* db_check_all */ int db_list_all (REG_DB * db_handle) { printf ("%s : %p\n", __func__, (void *) db_handle) ; return 0 ; } /* db_list_all */ int db_del_entry (REG_DB * db_handle, const char * entry) { printf ("%s : %p %s\n", __func__, (void *) db_handle, entry) ; return 0 ; } /* db_del_entry */ /*============================================================================== */ static int get_ekey_from_filename (REGTEST_DB * db, const char *filepath) { char * errmsg, **result ; int err, ekey = 0, rows, cols ; get_filename_pathname (db, filepath) ; snprintf (db->cmdbuf, sizeof (db->cmdbuf), "select ekey from sndfile where fname='%s'", db->filename) ; err = sqlite3_get_table (db->sql, db->cmdbuf, &result, &rows, &cols, &errmsg) ; if (err != SQLITE_OK) { printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; puts (db->cmdbuf) ; } ; if (cols != 1 || rows != 1) { printf ("Bad juju!! rows = %d cols = %d\n", rows, cols) ; exit (1) ; } ; ekey = strtol (result [1], NULL, 10) ; sqlite3_free_table (result) ; return ekey ; } /* get_ekey_from_filename */ static int get_filename_pathname_by_ekey (REGTEST_DB * db, int ekey) { char *errmsg, **result ; int err, rows, cols ; snprintf (db->cmdbuf, sizeof (db->cmdbuf), "select fname,fpath from sndfile where ekey='%d'", ekey) ; err = sqlite3_get_table (db->sql, db->cmdbuf, &result, &rows, &cols, &errmsg) ; if (err != SQLITE_OK) { printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; puts (db->cmdbuf) ; return 0 ; } ; if (cols != 2 || rows != 1) { printf ("\nError (%s %d) : rows = %d cols = %d\n", __func__, __LINE__, rows, cols) ; exit (1) ; } ; snprintf (db->filename, sizeof (db->filename), "%s", result [2]) ; snprintf (db->pathname, sizeof (db->pathname), "%s", result [3]) ; sqlite3_free_table (result) ; return 1 ; } /* get_filename_pathname_by_ekey */ static int check_file_by_ekey (REGTEST_DB * db, int ekey) { SNDFILE * sndfile ; SF_INFO info ; char * errmsg, **result ; int err, k, rows, cols, checksum ; printf (" %s : ", db->filename) ; fflush (stdout) ; memset (&info, 0, sizeof (info)) ; sndfile = sf_open (db->pathname, SFM_READ, &info) ; sf_command (sndfile, SFC_GET_LOG_INFO, db->logbuf, sizeof (db->logbuf)) ; checksum = (sndfile == NULL) ? 0 : calc_checksum (sndfile, &info) ; sf_close (sndfile) ; if (sndfile == NULL) { printf ("\n\nError : Could not open '%s' : %s\n", db->pathname, sf_strerror (NULL)) ; puts (db->logbuf) ; exit (1) ; } ; single_quote_replace (db->logbuf) ; snprintf (db->cmdbuf, sizeof (db->cmdbuf), "select fname,srate,frames,channels,format," "checksum,logbuf from sndfile where ekey='%d'", ekey) ; err = sqlite3_get_table (db->sql, db->cmdbuf, &result, &rows, &cols, &errmsg) ; if (err != SQLITE_OK) { printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; puts (db->cmdbuf) ; } ; for (k = 0 ; k < cols ; k++) { if (strcmp (result [k], "fname") == 0) { if (strcmp (result [k + cols], db->filename) == 0) continue ; printf ("\n\nError : fname doesn't match : %s != %s\n", result [k + cols], db->filename) ; } ; if (strcmp (result [k], "srate") == 0) { if (strtol (result [k + cols], NULL, 10) == info.samplerate) continue ; printf ("\n\nError : srate doesn't match : %s == %d\n", result [k + cols], info.samplerate) ; } ; if (strcmp (result [k], "frames") == 0) { if (strtoll (result [k + cols], NULL, 10) == info.frames) continue ; printf ("\n\nError : frames doesn't match : %s == %ld\n", result [k + cols], (long) info.frames) ; } ; if (strcmp (result [k], "channels") == 0) { if (strtol (result [k + cols], NULL, 10) == info.channels) continue ; printf ("\n\nError : channels doesn't match : %s == %d\n", result [k + cols], info.channels) ; } ; if (strcmp (result [k], "format") == 0) { if (strtol (result [k + cols], NULL, 16) == info.format) continue ; printf ("\n\nError : format doesn't match : %s == 0x%08x\n", result [k + cols], info.format) ; } ; if (strcmp (result [k], "checksum") == 0) { int db_val = (int) strtoll (result [k + cols], NULL, 16) ; if (db_val == checksum) continue ; printf ("\n\nError : checksum doesn't match : 0x%08x == 0x%08x\n", db_val, checksum) ; } ; if (strcmp (result [k], "logbuf") == 0) continue ; printf ("\nHere is the old logubuffer :\n\n%s\n\nand the new :\n\n%s\n\n", result [2 * cols - 1], db->logbuf) ; exit (1) ; } ; sqlite3_free_table (result) ; puts ("ok") ; return 0 ; } /* check_file_by_ekey */ /*============================================================================== */ static void get_filename_pathname (REGTEST_DB * db, const char *filepath) { const char * basename = db_basename (filepath) ; size_t slen ; /* Test for a relative path */ if (!IS_SLASH(filepath [0]) && !HAS_DRIVELETTER(filepath)) { memset (db->pathname, 0, sizeof (db->pathname)) ; if (getcwd (db->pathname, sizeof (db->pathname)) == NULL) { perror ("\ngetcwd failed") ; exit (1) ; } ; slen = strlen (db->pathname) ; /* a '/' is fine for Windows too */ snprintf (db->pathname + slen, sizeof (db->pathname) - slen, "/%s", filepath) ; } else snprintf (db->pathname, sizeof (db->pathname), "%s", filepath) ; snprintf (db->filename, sizeof (db->filename), "%s", basename) ; basename = db_basename (db->pathname) ; if (basename == db->pathname) { printf ("\nError : bad pathname %s\n", filepath) ; exit (1) ; } ; } /* get filename_pathname */ static void single_quote_replace (char * buf) { while ((buf = strchr (buf, '\'')) != 0) buf [0] = '"' ; } /* single_quote_replace */ static int count_callback (REGTEST_DB * db, int argc, char **argv, char **colname) { db->count ++ ; (void) argc ; (void) argv ; (void) colname ; return 0 ; } /* count_callback */ static int ekey_max_callback (REGTEST_DB * db, int argc, char **argv, char **unused) { int ekey ; (void) argc ; (void) unused ; ekey = strtol (argv [0], NULL, 10) ; if (ekey > db->ekey_max) db->ekey_max = ekey ; return 0 ; } /* ekey_max_callback */ static int callback (void *unused, int argc, char **argv, char **colname) { int k ; (void) unused ; for (k = 0 ; k < argc ; k++) printf ("%s = %s\n", colname [k], argv [k] ? argv [k] : "NULL") ; printf ("\n") ; return 0 ; } /* callback */ /* * Win32: Strip drive-letter and directory from a filename. * non-Win32: Strip directory from a filename. */ static const char *db_basename (const char *fname) { const char *base = fname; #if !defined(_WIN32) const char *slash = strrchr (base, '/'); if (slash) base = slash + 1 ; #else if (fname[0] && fname[1] == ':') { fname += 2; base = fname; } while (*fname) { if (IS_SLASH(*fname)) base = fname + 1; fname++; } #endif return base ; } #else int dummy (void) ; int dummy (void) { /* ** Empty dummy fnction so tha compiler doesn't winge about an ** empty file. */ return 0 ; } /* dummy */ #endif