1 /* This file is part of TCD 2.0.
2 cddb.c - CDDB remote and local functions.
3
4 Copyright (C) 1997-98 Tim P. Gerla <timg@rrv.net>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 Tim P. Gerla
21 RR 1, Box 40
22 Climax, MN 56523
23 timg@rrv.net
24 */
25
26 #include <pwd.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/stat.h>
31 #include <sys/param.h>
32 #include <unistd.h>
33
34 #include <SDL/SDL.h>
35
36 #include "cd-utils.h"
37 #include "cddb.h"
38
append_data(char * dest,const char * data,size_t maxlen)39 static void append_data(char *dest, const char *data, size_t maxlen)
40 {
41 const size_t destlen = strlen(dest);
42 dest += destlen;
43 if (maxlen <= destlen) {
44 return;
45 }
46 maxlen -= destlen;
47
48 while (maxlen > 1 && *data != '\0') {
49 if (*data == '\\') {
50 data++;
51 if (*data == 'n') {
52 *dest++ = '\n';
53 maxlen--;
54 data++;
55 } else if (*data == 't') {
56 *dest++ = '\t';
57 maxlen--;
58 data++;
59 } else {
60 *dest++ = *data++;
61 maxlen--;
62 }
63 } else {
64 *dest++ = *data++;
65 maxlen--;
66 }
67 }
68 *dest = '\0';
69 }
70
write_data(FILE * fp,const char * key,int num,const char * data)71 static void write_data(FILE * fp, const char *key, int num,
72 const char *data)
73 {
74 size_t nchars = 0;
75
76 fputs(key, fp);
77 if (num != -1) {
78 fprintf(fp, "%d", num);
79 }
80 putc('=', fp);
81 for (; *data != '\0'; data++) {
82 if (*data == '\n') {
83 fputs("\\n", fp);
84 nchars += 2;
85 } else if (data[0] == '\t') {
86 fputs("\\t", fp);
87 nchars += 2;
88 } else if (data[0] == '\\') {
89 fputs("\\\\", fp);
90 nchars += 2;
91 } else {
92 putc(*data, fp);
93 nchars += 1;
94 }
95 if (nchars > 60) {
96 putc('\n', fp);
97 fputs(key, fp);
98 if (num != -1) {
99 fprintf(fp, "%d", num);
100 }
101 putc('=', fp);
102 nchars = 0;
103 }
104 }
105 putc('\n', fp);
106 }
107
tcd_readcddb(struct cd_info * cd,SDL_CD * cdrom,const char * filename)108 static int tcd_readcddb(struct cd_info *cd, SDL_CD * cdrom, const char *filename)
109 {
110 FILE *fp;
111 char string[256];
112 size_t i;
113
114 /* zero out the extended data sections ... */
115 cd->disc_title[0] = '\0';
116 cd->extra_data[0] = '\0';
117 for (i = 0; i < (size_t) cdrom->numtracks; i++) {
118 cd->trk[i].name[0] = '\0';
119 cd->trk[i].extra_data[0] = '\0';
120 }
121
122 fp = fopen(filename, "r");
123 if (fp == NULL) {
124 return -1;
125 }
126
127 /* AC: dont feof.. feof is only true _after_ eof is read */
128 while (fgets(string, 255, fp) != NULL) {
129 if (strlen(string) > 0) {
130 string[strlen(string) - 1] = 0;
131 }
132
133 /* If it's a comment, ignore. */
134 if (string[0] == '#')
135 continue;
136
137 if (strncmp(string, "DTITLE=", 7) == 0) {
138 append_data(cd->disc_title, string + 7,
139 sizeof(cd->disc_title));
140 continue;
141 } else if (strncmp(string, "EXTD=", 5) == 0) {
142 append_data(cd->extra_data, string + 5,
143 sizeof(cd->extra_data));
144 } else if (strncmp(string, "TTITLE", 6) == 0) {
145 char *equals;
146 unsigned long trk = strtoul(string + 6, &equals, 10);
147 if (*equals == '=' && trk < lengthof(cd->trk)) {
148 append_data(cd->trk[trk].name, equals + 1,
149 sizeof(cd->trk[trk].name));
150 }
151 } else if (strncmp(string, "EXTT", 4) == 0) {
152 char *equals;
153 unsigned long trk = strtoul(string + 4, &equals, 10);
154 if (*equals == '=' && trk < lengthof(cd->trk)) {
155 append_data(cd->trk[trk].extra_data, equals + 1,
156 sizeof(cd->trk[trk].extra_data));
157 }
158 } else {
159 /* ignore everything that's unknown. */
160 }
161 }
162 fclose(fp);
163 return 0;
164 }
165
tcd_writecddb(struct cd_info * cd,SDL_CD * cdrom,const char * filename)166 static int tcd_writecddb(struct cd_info *cd, SDL_CD * cdrom, const char *filename)
167 {
168 FILE *fp;
169 size_t i;
170
171 if ((fp = fopen(filename, "w")) == NULL) {
172 return -1;
173 }
174 fputs("# xmcd CD Database Entry\n", fp);
175 fputs("#\n", fp);
176 fputs("# Track frame offsets:\n", fp);
177
178 /* Print the frame offsets */
179 for (i = 0; i < (size_t) cdrom->numtracks; i++) {
180 fprintf(fp, "# %u\n", cdrom->track[i].offset);
181 }
182
183 fputs("#\n", fp);
184 fprintf(fp, "# Disc length: %i seconds\n", cd_length(cdrom) / CD_FPS);
185 fprintf(fp, "# Submitted via: %s\n", PACKAGE_STRING);
186 fputs("#\n", fp);
187
188 fprintf(fp, "DISCID=%08lx\n", cddb_discid(cdrom));
189 write_data(fp, "DTITLE", -1, cd->disc_title);
190 for (i = 0; i < (size_t) cdrom->numtracks; i++) {
191 write_data(fp, "TTITLE", i, cd->trk[i].name);
192 }
193
194 write_data(fp, "EXTD", -1, cd->extra_data);
195 for (i = 0; i < (size_t) cdrom->numtracks; i++) {
196 write_data(fp, "EXTT", i, cd->trk[i].extra_data);
197 }
198 fprintf(fp, "PLAYORDER=\n");
199 fclose(fp);
200 return 0;
201 }
202
get_home_dir(void)203 static const char *get_home_dir(void)
204 {
205 char *result;
206 struct passwd *passwd;
207
208 if ((result = getenv("HOME")) != NULL) {
209 return result;
210 }
211 if ((passwd = getpwuid(getuid())) != NULL) {
212 if (passwd->pw_dir != NULL) {
213 return passwd->pw_dir;
214 }
215 }
216 (void) fprintf(stderr, "$HOME not set. giving up.\n");
217 exit(EXIT_FAILURE);
218 }
219
cddb_filename(unsigned long discid)220 static char *cddb_filename(unsigned long discid)
221 {
222 static char filename[MAXPATHLEN];
223 snprintf(filename, MAXPATHLEN-1, "%s/.tcd/%08lx", get_home_dir(), discid);
224 return filename;
225 }
226
tcd_readdiskinfo(struct tcd_state * cds,SDL_CD * cdrom)227 extern int tcd_readdiskinfo(struct tcd_state *cds, SDL_CD * cdrom)
228 {
229 int result;
230 char *filename;
231 struct cd_info *cd = &cds->cd_info;
232
233 result = 0;
234
235 if ((filename = cddb_filename(cddb_discid(cdrom))) != NULL)
236 result = tcd_readcddb(cd, cdrom, filename);
237
238 return result;
239 }
240
mkparentdir(char * filename)241 static void mkparentdir(char *filename)
242 {
243 char *slash;
244 for (slash = filename + 1; *slash; slash++) {
245 if (*slash == '/') {
246 *slash = '\0';
247 (void)mkdir(filename, 0777);
248 *slash = '/';
249 }
250 }
251 }
252
tcd_writediskinfo(struct cd_info * cd,SDL_CD * cdrom)253 void tcd_writediskinfo(struct cd_info *cd, SDL_CD * cdrom)
254 {
255 char *filename;
256
257 if ((filename = cddb_filename(cddb_discid(cdrom))) != NULL) {
258 mkparentdir(filename);
259 if (tcd_writecddb(cd, cdrom, filename) == 0) {
260 cd->modified = 0;
261 }
262 }
263 }
264