summaryrefslogtreecommitdiff
path: root/apps/metadata/asap.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/metadata/asap.c')
-rw-r--r--apps/metadata/asap.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/apps/metadata/asap.c b/apps/metadata/asap.c
new file mode 100644
index 0000000000..7e635a30e8
--- /dev/null
+++ b/apps/metadata/asap.c
@@ -0,0 +1,256 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: asap.c 17847 2008-06-28 18:10:04Z domonoky $
9 *
10 * Copyright (C) 2008 Dominik Wenger
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "id3.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "rbunicode.h"
32#include "debug.h"
33
34#define MAX_SONGS 32
35
36struct module_info
37{
38 char name[255];
39 char author[255];
40 char date[255];
41 int numSongs;
42 int defSong;
43 int numChannels;
44 int durations[32];
45 int loops[32];
46};
47
48static bool parse_dec(int *retval, const char *p, int minval, int maxval)
49{
50 int r = 0;
51 do {
52 char c = *p;
53 if (c >= '0' && c <= '9')
54 r = 10 * r + c - '0';
55 else
56 return false;
57 if (r > maxval)
58 return false;
59 } while (*++p != '\0');
60 if (r < minval)
61 return false;
62 *retval = r;
63 return true;
64}
65
66static bool parse_text(char *retval, const char *p)
67{
68 int i;
69 if (*p != '"')
70 return false;
71 p++;
72 if (p[0] == '<' && p[1] == '?' && p[2] == '>' && p[3] == '"')
73 return true;
74 i = 0;
75 while (*p != '"') {
76 if (i >= 127)
77 return false;
78 if (*p == '\0')
79 return false;
80 retval[i++] = *p++;
81 }
82 retval[i] = '\0';
83 return true;
84}
85
86static int ASAP_ParseDuration(const char *s)
87{
88 int r;
89 if (*s < '0' || *s > '9')
90 return -1;
91 r = *s++ - '0';
92 if (*s >= '0' && *s <= '9')
93 r = 10 * r + *s++ - '0';
94 if (*s == ':') {
95 s++;
96 if (*s < '0' || *s > '5')
97 return -1;
98 r = 60 * r + (*s++ - '0') * 10;
99 if (*s < '0' || *s > '9')
100 return -1;
101 r += *s++ - '0';
102 }
103 r *= 1000;
104 if (*s != '.')
105 return r;
106 s++;
107 if (*s < '0' || *s > '9')
108 return r;
109 r += 100 * (*s++ - '0');
110 if (*s < '0' || *s > '9')
111 return r;
112 r += 10 * (*s++ - '0');
113 if (*s < '0' || *s > '9')
114 return r;
115 r += *s - '0';
116 return r;
117}
118
119static bool parse_sap_header(int fd,struct module_info* info,int file_len)
120{
121 int module_index = 0;
122 int sap_signature = -1;
123 int duration_index = 0;
124 unsigned char cur_char = 0;
125 int i;
126
127 /* set defaults */
128
129 info->numSongs=1;
130 info->defSong=0;
131 info->numChannels=1;
132 for (i = 0; i < MAX_SONGS; i++) {
133 info->durations[i] = -1;
134 info->loops[i] = 0;
135 }
136
137 /* parse file */
138 while (1)
139 {
140 char line[256];
141 char *p;
142
143 if (module_index + 8 >= file_len)
144 return false;
145 /* read a char */
146 read(fd,&cur_char,1);
147 /* end of header */
148 if (cur_char == 0xff)
149 break;
150
151 i = 0;
152 while (cur_char != 0x0d)
153 {
154 line[i++] = cur_char;
155 module_index++;
156 if (module_index >= file_len || (unsigned)i >= sizeof(line) - 1)
157 return false;
158 /* read a char */
159 read(fd,&cur_char,1);
160 }
161 if (++module_index >= file_len )
162 return false;
163 /* read a char */
164 read(fd,&cur_char,1);
165 if ( cur_char != 0x0a)
166 return false;
167
168 line[i] = '\0';
169 for (p = line; *p != '\0'; p++) {
170 if (*p == ' ') {
171 *p++ = '\0';
172 break;
173 }
174 }
175
176 /* parse tags */
177 if(strcmp(line, "SAP") == 0)
178 sap_signature = 1;
179 if (sap_signature == -1)
180 return false;
181 if (strcmp(line,"AUTHOR") == 0)
182 {
183 if (parse_text(info->author, p) == false )
184 return false;
185 }
186 else if(strcmp(line,"NAME")==0)
187 {
188 if (parse_text(info->name, p) == false)
189 return false;
190 }
191 else if(strcmp(line,"DATE")==0)
192 {
193 if (parse_text(info->date, p) == false)
194 return false;
195 }
196 else if (strcmp(line,"SONGS")==0)
197 {
198 if (parse_dec(&info->numSongs, p,1,MAX_SONGS) == false )
199 return false;
200 }
201 else if (strcmp(line,"DEFSONG")==0)
202 {
203 if (parse_dec(&info->defSong, p,0,MAX_SONGS) == false)
204 return false;
205 }
206 else if (strcmp(line,"STEREO")==0)
207 {
208 info->numChannels = 2;
209 }
210 else if (strcmp(line,"TIME") == 0)
211 {
212 int duration = ASAP_ParseDuration(p);
213 if (duration < 0 || duration_index >= MAX_SONGS)
214 return false;
215 info->durations[duration_index] = duration;
216 if (strstr(p, "LOOP") != NULL)
217 info->loops[duration_index] = 1;
218 duration_index++;
219 }
220 }
221
222 lseek(fd,0,SEEK_SET);
223 return true;
224}
225
226
227bool get_asap_metadata(int fd, struct mp3entry* id3)
228{
229 char *buf = id3->id3v2buf;
230
231 int filelength = filesize(fd);
232 struct module_info *info;
233 info = (struct module_info *) buf;
234
235 if(parse_sap_header(fd,info,filelength) == false)
236 {
237 DEBUGF("parse sap header failed.\n");
238 return false;
239 }
240
241 id3->title = info->name;
242 id3->artist = info->author;
243 id3->year_string = info->date;
244 int length = info->durations[info->defSong];
245 if (length < 0)
246 length = 180 * 1000;
247 id3->length = length;
248
249 id3->bitrate = 706;
250 id3->frequency = 44100;
251
252 id3->vbr = false;
253 id3->filesize = filelength;
254
255 return true;
256}