Logo Search packages:      
Sourcecode: tcd version File versions  Download package

cddb.c

/* This file is part of TCD 2.0.
   cddb.c - CDDB remote and local functions.

   Copyright (C) 1997-98 Tim P. Gerla <timg@rrv.net>
   
   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.
                                    
   Tim P. Gerla
   RR 1, Box 40
   Climax, MN  56523
   timg@rrv.net
*/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <SDL/SDL.h>

#include "cd-utils.h"
#include "cddb.h"
#include "concat-strings.h"

static int fputs_complete(FILE *fp, const char *s)
{
    size_t len = strlen(s);
    ssize_t written;
    while (len != 0) {
        if ((written = fwrite(s, 1, len, fp)) <= 0) {
            return -1;
        }
        s += written;
        len -= written;
    }
    return 0;
}

#define fputs_complete_or_return(m_fp, m_s) \
    if (fputs_complete(m_fp, m_s) == -1) return -1

static void append_data(char *dest, const char *data, size_t maxlen)
{
    const size_t destlen = strlen(dest);
    dest += destlen;
    if (maxlen <= destlen) {
        return;
    }
    maxlen -= destlen;

    while (maxlen > 1 && *data != '\0') {
        if (*data == '\\') {
            data++;
            if (*data == 'n') {
                *dest++ = '\n';
                maxlen--;
                data++;
            } else if (*data == 't') {
                *dest++ = '\t';
                maxlen--;
                data++;
            } else {
                *dest++ = *data++;
                maxlen--;
            }
        } else {
            *dest++ = *data++;
            maxlen--;
        }
    }
    *dest = '\0';
}

static int write_data(FILE * fp, const char *key, int num,
                       const char *data)
{
    size_t nchars = 0;

    fputs_complete_or_return(fp, key);
    if (num != -1) {
        if (fprintf(fp, "%d", num) <= 0) {
            return -1;
        }
    }
    if (putc('=', fp) == EOF) {
      return -1;
    }
    for (; *data != '\0'; data++) {
        if (*data == '\n') {
            fputs_complete_or_return(fp, "\\n");
            nchars += 2;
        } else if (data[0] == '\t') {
            fputs_complete_or_return(fp, "\\t");
            nchars += 2;
        } else if (data[0] == '\\') {
            fputs_complete_or_return(fp, "\\\\");
            nchars += 2;
        } else {
            if (putc(*data, fp) == EOF) {
                  return -1;
            }
            nchars += 1;
        }
        if (nchars > 60) {
            fputs_complete_or_return(fp, "\n");
            fputs_complete_or_return(fp, key);
            if (num != -1) {
                if (fprintf(fp, "%d", num) <= 0) {
                    return -1;
                }
            }
            fputs_complete_or_return(fp, "=");
            nchars = 0;
        }
    }
    fputs_complete_or_return(fp, "\n");
    return 0;
}

static int tcd_readcddb(struct cd_info *cd, const char *filename)
{
    FILE *fp;
    char string[256];

    tcd_cleardiscinfo(cd);
    fp = fopen(filename, "r");
    if (fp == NULL) {
        return -1;
    }

    /* AC: dont feof.. feof is only true _after_ eof is read */
    while (fgets(string, 255, fp) != NULL) {
        if (strlen(string) > 0) {
            string[strlen(string) - 1] = '\0';
        }

        /* If it's a comment, ignore. */
        if (string[0] == '#')
            continue;

        if (strncmp(string, "DTITLE=", 7) == 0) {
            append_data(cd->disc_title, string + 7,
                        sizeof(cd->disc_title));
            continue;
        } else if (strncmp(string, "EXTD=", 5) == 0) {
            append_data(cd->extra_data, string + 5,
                        sizeof(cd->extra_data));
        } else if (strncmp(string, "TTITLE", 6) == 0) {
            char *equals;
            unsigned long trk = strtoul(string + 6, &equals, 10);
            if (*equals == '=' && trk < (unsigned long) lengthof(cd->trk)) {
                append_data(cd->trk[trk].name, equals + 1,
                            sizeof(cd->trk[trk].name));
            }
        } else if (strncmp(string, "EXTT", 4) == 0) {
            char *equals;
            unsigned long trk = strtoul(string + 4, &equals, 10);
            if (*equals == '=' && trk < (unsigned long) lengthof(cd->trk)) {
                append_data(cd->trk[trk].extra_data, equals + 1,
                            sizeof(cd->trk[trk].extra_data));
            }
        } else {
            /* ignore everything that's unknown. */
        }
    }
    return fclose(fp);
}

#define fputs_complete_or_cleanup(m_fp, m_s) \
    if (fputs_complete(m_fp, m_s) == -1) goto cleanup

static int tcd_writecddb(const struct cd_info *cd, const SDL_CD * cdrom, const char *filename)
{
    FILE *fp;
    size_t i;

    if ((fp = fopen(filename, "w")) == NULL) {
        return -1;
    }
    fputs_complete_or_cleanup(fp, "# xmcd CD Database Entry\n");
    fputs_complete_or_cleanup(fp, "#\n");
    fputs_complete_or_cleanup(fp, "# Track frame offsets:\n");

    /* Print the frame offsets */
    for (i = 0; i < (size_t) cdrom->numtracks; i++) {
        if (fprintf(fp, "# %u\n", cdrom->track[i].offset) <= 0) {
            goto cleanup;
        }
    }

    fputs_complete_or_cleanup(fp, "#\n");
    if (fprintf(fp, "# Disc length: %i seconds\n", cd_length(cdrom) / CD_FPS) <= 0) {
      goto cleanup;
    }
    if (fprintf(fp, "# Submitted via: %s\n", PACKAGE_STRING) <= 0) {
      goto cleanup;
    }
    fputs_complete_or_cleanup(fp, "#\n");

    if (fprintf(fp, "DISCID=%08lx\n", cddb_discid(cdrom)) <= 0) {
      goto cleanup;
    }
    if (write_data(fp, "DTITLE", -1, cd->disc_title) == -1) {
      goto cleanup;
    }
    for (i = 0; i < (size_t) cdrom->numtracks; i++) {
        if (write_data(fp, "TTITLE", (int) i, cd->trk[i].name) == -1) {
            goto cleanup;
        }
    }

    if (write_data(fp, "EXTD", -1, cd->extra_data) == -1) {
      goto cleanup;
    }
    for (i = 0; i < (size_t) cdrom->numtracks; i++) {
        if (write_data(fp, "EXTT", (int) i, cd->trk[i].extra_data) == -1) {
            goto cleanup;
        }
    }
    fputs_complete_or_cleanup(fp, "PLAYORDER=\n");
    return fclose(fp);

cleanup:
    (void) fclose(fp);
    return -1;
}

static const char *get_home_dir(void)
{
    char *result;
    struct passwd *passwd;

    if ((result = getenv("HOME")) != NULL) {
        return result;
    }
    if ((passwd = getpwuid(getuid())) != NULL) {
        if (passwd->pw_dir != NULL) {
            return passwd->pw_dir;
        }
    }
    (void) fprintf(stderr, "$HOME not set. giving up.\n");
    exit(EXIT_FAILURE);
}

static char *cddb_filename(unsigned long discid)
{
    char cd_id[9];
    sprintf(cd_id, "%08lx", discid);
    return concat_strings(get_home_dir(), "/.tcd/", cd_id, NULL);
}

extern int tcd_readdiscinfo(struct cd_info *cd, const SDL_CD * cdrom)
{
    int result;
    char *filename;

    result = 0;
    if ((filename = cddb_filename(cddb_discid(cdrom))) != NULL) {
        result = tcd_readcddb(cd, filename);
        free(filename);
    }
    return result;
}

static void mkparentdir(char *filename)
{
    char *slash;
    for (slash = filename + 1; *slash != '\0'; slash++) {
        if (*slash == '/') {
            *slash = '\0';
            (void)mkdir(filename, 0777);
            *slash = '/';
        }
    }
}

extern int tcd_writediscinfo(struct cd_info *cd, const SDL_CD * cdrom)
{
    char *filename;
    int result = -1;

    if ((filename = cddb_filename(cddb_discid(cdrom))) == NULL) {
      return -1;
    }
    mkparentdir(filename);
    if (tcd_writecddb(cd, cdrom, filename) == -1) {
        goto cleanup;
    }
    result = 0;
    cd->modified = 0;

cleanup:
    free(filename);
    return result;
}

extern void tcd_cleardiscinfo(struct cd_info *cd)
{
    size_t i;
    /* zero out the extended data sections ... */
    cd->disc_title[0] = '\0';
    cd->extra_data[0] = '\0';
    for (i = 0; i < lengthof(cd->trk); i++) {
        cd->trk[i].name[0] = '\0';
        cd->trk[i].extra_data[0] = '\0';
    }
    cd->modified = 0;
}

Generated by  Doxygen 1.6.0   Back to index