aac: Collect all interesting ID3 frames
[cmus.git] / track_db.c
blob808375f9bda02796dc992bf8960206a7ba1cf703
1 /*
2 * Copyright 2004 Timo Hirvonen
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
20 #include "track_db.h"
21 #include "db.h"
22 #include "xmalloc.h"
23 #include "player.h"
24 #include "utils.h"
25 #include "debug.h"
27 #include <inttypes.h>
29 struct track_db {
30 struct db *db;
34 * data format:
36 * u32 mtime
37 * u32 duration
38 * N
39 * string key
40 * string value
43 struct track_db *track_db_new(const char *filename_base)
45 struct track_db *db;
46 int rc;
48 db = xnew(struct track_db, 1);
49 db->db = db_new(filename_base);
50 rc = db_load(db->db);
51 if (rc) {
52 d_print("error: %s\n", rc == -1 ? strerror(errno) : "-2");
54 return db;
57 int track_db_close(struct track_db *db)
59 int rc;
61 rc = db_close(db->db);
62 free(db);
63 return rc;
66 void track_db_insert(struct track_db *db, const char *filename, struct track_info *ti)
68 char *key, *data, *ptr;
69 int data_size, i, rc;
71 data_size = 8;
72 for (i = 0; ti->comments[i].key; i++) {
73 data_size += strlen(ti->comments[i].key) + 1;
74 data_size += strlen(ti->comments[i].val) + 1;
76 data = xmalloc(data_size);
77 *(uint32_t *)(data + 0) = ti->mtime;
78 *(uint32_t *)(data + 4) = ti->duration;
79 ptr = data + 8;
80 for (i = 0; ti->comments[i].key; i++) {
81 char *s;
82 int size;
84 s = ti->comments[i].key;
85 size = strlen(s) + 1;
86 memcpy(ptr, s, size);
87 ptr += size;
89 s = ti->comments[i].val;
90 size = strlen(s) + 1;
91 memcpy(ptr, s, size);
92 ptr += size;
94 key = xstrdup(filename);
95 rc = db_insert(db->db, key, data, data_size);
96 if (rc) {
97 d_print("error: %s\n", strerror(errno));
98 free(data);
102 static int data_to_track_info(const void *data, unsigned int data_size, struct track_info *ti)
104 const char *str = data;
105 int count, i;
107 if (data_size < 8)
108 return -1;
110 ti->mtime = *(uint32_t *)str; str += 4;
111 ti->duration = *(uint32_t *)str; str += 4;
113 count = 0;
114 if (data_size > 8) {
115 int pos = 0;
117 while (pos < data_size - 8) {
118 if (str[pos] == 0)
119 count++;
120 pos++;
122 if (str[data_size - 9] != 0 || count % 2)
123 return -1;
124 count /= 2;
126 ti->comments = xnew(struct keyval, count + 1);
127 for (i = 0; i < count; i++) {
128 int len;
129 char *s;
131 len = strlen(str);
132 s = xmalloc(len + 1);
133 memcpy(s, str, len + 1);
134 str += len + 1;
135 ti->comments[i].key = s;
137 len = strlen(str);
138 s = xmalloc(len + 1);
139 memcpy(s, str, len + 1);
140 str += len + 1;
141 ti->comments[i].val = s;
143 ti->comments[i].key = NULL;
144 ti->comments[i].val = NULL;
145 return 0;
148 struct track_info *track_db_get_track(struct track_db *db, const char *filename)
150 struct track_info *ti;
151 struct keyval *comments;
152 int duration;
153 void *data;
154 unsigned int data_size;
155 int rc;
156 time_t mtime = file_get_mtime(filename);
158 rc = db_query(db->db, filename, &data, &data_size);
159 if (rc == 1) {
160 /* found */
161 ti = track_info_new(filename);
162 if (data_to_track_info(data, data_size, ti)) {
163 free(ti);
164 free(data);
165 return NULL;
167 free(data);
168 if (mtime != -1 && ti->mtime == mtime) {
169 /* mtime not changed, return the data */
170 return ti;
173 /* db data not up to date, remove data */
174 db_remove(db->db, filename);
175 track_info_unref(ti);
176 } else if (rc == 0) {
177 /* not found */
178 } else {
179 /* error */
180 d_print("error: %s\n", rc == -1 ? strerror(errno) : "-2");
181 return NULL;
184 if (player_get_fileinfo(filename, &duration, &comments)) {
185 d_print("INVALID: '%s'\n", filename);
186 return NULL;
189 ti = track_info_new(filename);
190 ti->comments = comments;
191 ti->duration = duration;
192 ti->mtime = mtime;
194 track_db_insert(db, filename, ti);
195 return ti;