/* This file is part of Idest. Copyright (C) 2009-2011 Sergey Poznyakoff Idest 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 3, or (at your option) any later version. Idest 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 Idest. If not, see . */ #include "idest.h" unsigned version_option = 0; unsigned default_version_option = 0; unsigned convert_version; int latin1_option = 0; enum backup_type backup_type = no_backups; char *backup_dir; int verbose_option = 0; int describe_option = 0; int dry_run_option = 0; int all_frames = 0; char *source_file; struct id3_tag *source_tag; int source_vopt; char *format_name; char *batch_name; char **guile_argv; struct item_info { int item_id; char *name; char *frame_id; }; static struct item_info item_table[] = { { item_title, "title", ID3_FRAME_TITLE }, { item_artist, "artist", ID3_FRAME_ARTIST }, { item_album, "album", ID3_FRAME_ALBUM }, { item_year, "year", ID3_FRAME_YEAR }, { item_comment, "comment", ID3_FRAME_COMMENT }, { item_track, "track", ID3_FRAME_TRACK }, { item_genre, "genre", ID3_FRAME_GENRE }, }; static int item_count = sizeof(item_table)/sizeof(item_table[0]); static struct item_info * name_to_item_info(const char *arg) { int i; struct item_info *ip; for (i = 0, ip = item_table; i < item_count; i++, ip++) if (strcmp(arg, ip->name) == 0) return ip; return NULL; } static struct item_info * frame_id_to_item_info(const char *arg) { int i; struct item_info *ip; for (i = 0, ip = item_table; i < item_count; i++, ip++) if (strcmp(arg, ip->frame_id) == 0) return ip; return NULL; } const char * name_to_frame_id(const char *name) { struct item_info *info = name_to_item_info(name); if (!info) return NULL; return info->frame_id; } int frame_to_item_id(const char *arg) { struct item_info *ip = frame_id_to_item_info(arg); return ip ? ip->item_id : -1; } void qv_free(size_t qc, char **qv) { int i; for (i = 0; i < qc; i++) free(qv[i]); free(qv); } void verify_mp3(FILE *fp, const char *name) { char str[3]; unsigned short sig = 0; if (fread(str, sizeof(str), 1, fp) != 1) error(1, errno, "error reading %s", name); if (memcmp(str, "ID3", 3) == 0) { error(0, 0, "%s: warning: ID3 header found", name); return; } sig = ((unsigned char)str[0]) << 8 | ((unsigned char)str[1]); switch (sig & 0xFFFE) { case 0xFFFA: /* MPEG ADTS, layer III, v1 */ case 0xFFF2: /* MPEG ADTS, layer III, v2 */ case 0xFFFE: /* MPEG ADTS, layer III, v2.5 */ break; default: error(1, 0, "%s: not an mp3 file", name); } } void query_id3(const char *name) { query_tags(name); } void set_id3(const char *name) { if (backup_file(name)) error(1, 0, "cannot backup file %s", name); set_tags(name); } void del_id3(const char *name) { if (backup_file(name)) error(1, 0, "cannot backup file %s", name); del_tags(name); } void (*id3_mode[])(const char *) = { query_id3, set_id3, del_id3, info_id3 }; int mode = MODE_QUERY; const char *mode_option_str[] = { "--query", "--set", "--delete", "--info", "--list-frames" }; char **guile_argv_ptr; void set_guile_argv(int argc, char **av) { int i; guile_argv_ptr = xcalloc(argc + 4, sizeof(guile_argv_ptr[0])); guile_argv = guile_argv_ptr + 3; for (i = 0; i < argc; i++) guile_argv[i] = av[i]; guile_argv[i] = NULL; } #include "cmdline.h" int main(int argc, char **argv) { struct id3_file *file = NULL; set_program_name(argv[0]); get_options(argc, argv); if (!default_version_option) default_version_option = IDEST_ID3V_1|IDEST_ID3V_2; argc -= optind; argv += optind; if (format_name) { if (mode_set) error(1, 0, "--format cannot be used with %s", mode_option_str[mode]); if (guile_argv) error(1, 0, "--format cannot be used with --script"); if (batch_name) error(1, 0, "--format cannot be used with --batch"); set_guile_argv(argc, argv); *--guile_argv = format_name; *--guile_argv = "format"; } else if (batch_name) { if (mode_set) error(1, 0, "--batch cannot be used with %s", mode_option_str[mode]); if (guile_argv) error(1, 0, "--batch cannot be used with --script"); set_guile_argv(argc, argv); *--guile_argv = batch_name; *--guile_argv = "batch"; } if (dry_run_option) { if (!guile_argv) error(1, 0, "--dry-run used without --script or --format or --batch"); *--guile_argv = "dry-run"; } guile_init(&argc, &argv); if (mode == MODE_LIST) { if (argc) error(1, 0, "extra arguments"); list_supported_frames(); exit(0); } if (argc == 0) error(1, 0, "no files"); if (convert_version) mode = MODE_MOD; if (source_file) { int modified = 1; mode = MODE_MOD; file = id3_file_open(source_file, ID3_FILE_MODE_READONLY); if (!file) error(1, errno, "cannot open file %s", source_file); source_tag = id3_file_tag(file); source_vopt = guess_file_tag_options(file, &modified); } while (argc--) { char *name = *argv++; if (verbose_option) printf("%s:\n", name); id3_mode[mode](name); } if (file) id3_file_close(file); exit(0); }