support for binding :commands to keys
[cmus.git] / cmus / track_db.c
blob79dddf56f15867d61a2d992c299b5378c0f51277
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, strlen(key) + 1, data, data_size);
96 if (rc) {
97 d_print("error: %s\n", strerror(errno));
98 free(data);
102 static struct track_info *data_to_track_info(const void *data, unsigned int data_size)
104 struct track_info *ti;
105 const char *str;
106 int count, i;
108 if (data_size < 8)
109 return NULL;
110 ti = xnew(struct track_info, 1);
111 ti->ref = 1;
112 ti->filename = NULL;
114 str = data;
115 ti->mtime = *(uint32_t *)str; str += 4;
116 ti->duration = *(uint32_t *)str; str += 4;
118 count = 0;
119 if (data_size > 8) {
120 int pos = 0;
122 while (pos < data_size - 8) {
123 if (str[pos] == 0)
124 count++;
125 pos++;
127 if (str[data_size - 9] != 0 || count % 2) {
128 free(ti);
129 return NULL;
131 count /= 2;
133 ti->comments = xnew(struct keyval, count + 1);
134 for (i = 0; i < count; i++) {
135 int len;
136 char *s;
138 len = strlen(str);
139 s = xmalloc(len + 1);
140 memcpy(s, str, len + 1);
141 str += len + 1;
142 ti->comments[i].key = s;
144 len = strlen(str);
145 s = xmalloc(len + 1);
146 memcpy(s, str, len + 1);
147 str += len + 1;
148 ti->comments[i].val = s;
150 ti->comments[i].key = NULL;
151 ti->comments[i].val = NULL;
152 return ti;
155 struct track_info *track_db_get_track(struct track_db *db, const char *filename)
157 struct track_info *ti;
158 struct keyval *comments;
159 int duration;
160 void *data;
161 unsigned int data_size;
162 int rc;
163 time_t mtime = file_get_mtime(filename);
165 rc = db_query(db->db, filename, &data, &data_size);
166 if (rc == 1) {
167 /* found */
168 ti = data_to_track_info(data, data_size);
169 free(data);
170 if (mtime != -1 && ti->mtime == mtime) {
171 /* mtime not changed, return data */
172 ti->filename = xstrdup(filename);
173 return ti;
176 /* db data not up to date, remove data */
177 db_remove(db->db, filename, strlen(filename) + 1);
178 track_info_unref(ti);
179 } else if (rc == 0) {
180 /* not found */
181 } else {
182 /* error */
183 d_print("error: %s\n", rc == -1 ? strerror(errno) : "-2");
184 return NULL;
187 if (player_get_fileinfo(filename, &duration, &comments)) {
188 d_print("INVALID: '%s'\n", filename);
189 return NULL;
191 ti = xnew(struct track_info, 1);
192 ti->ref = 1;
193 ti->filename = xstrdup(filename);
194 ti->comments = comments;
195 ti->duration = duration;
196 ti->mtime = mtime;
197 track_db_insert(db, filename, ti);
198 return ti;