diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2011-04-27 16:46:27 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2011-04-27 16:46:27 +0000 |
commit | 3d9c0628220175603757ea1fabce7a9d34a75739 (patch) | |
tree | a5c5af11c6856f0f084241212e45763af412f946 /apps/metadata | |
parent | 08bedf83051064c7dc9a7bb903ab9a34afe8d725 (diff) | |
download | rockbox-3d9c0628220175603757ea1fabce7a9d34a75739.tar.gz rockbox-3d9c0628220175603757ea1fabce7a9d34a75739.zip |
Get NSF fixed up a bit and parse metadata in the core.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29790 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/metadata')
-rw-r--r-- | apps/metadata/nsf.c | 228 |
1 files changed, 199 insertions, 29 deletions
diff --git a/apps/metadata/nsf.c b/apps/metadata/nsf.c index 9207a14048..58fc038b42 100644 --- a/apps/metadata/nsf.c +++ b/apps/metadata/nsf.c | |||
@@ -10,53 +10,223 @@ | |||
10 | #include "metadata_parsers.h" | 10 | #include "metadata_parsers.h" |
11 | #include "rbunicode.h" | 11 | #include "rbunicode.h" |
12 | 12 | ||
13 | bool get_nsf_metadata(int fd, struct mp3entry* id3) | 13 | struct NESM_HEADER |
14 | { | 14 | { |
15 | /* Use the trackname part of the id3 structure as a temporary buffer */ | 15 | uint32_t nHeader; |
16 | unsigned char* buf = (unsigned char *)id3->path; | 16 | uint8_t nHeaderExtra; |
17 | char *p; | 17 | uint8_t nVersion; |
18 | 18 | uint8_t nTrackCount; | |
19 | if ((lseek(fd, 0, SEEK_SET) < 0) | 19 | uint8_t nInitialTrack; |
20 | || (read(fd, buf, 110) < 110)) | 20 | uint16_t nLoadAddress; |
21 | { | 21 | uint16_t nInitAddress; |
22 | return false; | 22 | uint16_t nPlayAddress; |
23 | } | 23 | uint8_t szGameTitle[32]; |
24 | uint8_t szArtist[32]; | ||
25 | uint8_t szCopyright[32]; | ||
26 | uint16_t nSpeedNTSC; | ||
27 | uint8_t nBankSwitch[8]; | ||
28 | uint16_t nSpeedPAL; | ||
29 | uint8_t nNTSC_PAL; | ||
30 | uint8_t nExtraChip; | ||
31 | uint8_t nExpansion[4]; | ||
32 | } __attribute__((packed)); | ||
33 | |||
34 | struct NSFE_INFOCHUNK | ||
35 | { | ||
36 | uint16_t nLoadAddress; | ||
37 | uint16_t nInitAddress; | ||
38 | uint16_t nPlayAddress; | ||
39 | uint8_t nIsPal; | ||
40 | uint8_t nExt; | ||
41 | uint8_t nTrackCount; | ||
42 | uint8_t nStartingTrack; | ||
43 | } __attribute__((packed)); | ||
24 | 44 | ||
25 | id3->length = 120*1000; | ||
26 | id3->vbr = false; | ||
27 | id3->filesize = filesize(fd); | ||
28 | 45 | ||
29 | if (memcmp(buf,"NSFE",4) == 0) /* only NESM contain metadata */ | 46 | #define CHAR4_CONST(a, b, c, d) FOURCC(a, b, c, d) |
47 | |||
48 | static bool parse_nsfe(int fd, struct mp3entry *id3) | ||
49 | { | ||
50 | bool info_found = false; | ||
51 | bool end_found = false; | ||
52 | bool data_found = false; | ||
53 | |||
54 | struct NSFE_INFOCHUNK info; | ||
55 | memset(&info, 0, sizeof(struct NSFE_INFOCHUNK)); | ||
56 | |||
57 | /* default values */ | ||
58 | info.nTrackCount = 1; | ||
59 | id3->length = 2*1000*60; | ||
60 | |||
61 | /* begin reading chunks */ | ||
62 | while (!end_found) | ||
30 | { | 63 | { |
31 | return true; | 64 | int32_t chunk_size, chunk_type; |
32 | } | 65 | |
33 | else | 66 | if (read_uint32le(fd, &chunk_size) != (int)sizeof(uint32_t)) |
34 | { | 67 | return false; |
35 | if (memcmp(buf, "NESM",4) != 0) /* not a valid format*/ | 68 | |
36 | { | 69 | if (read_uint32be(fd, &chunk_type) != (int)sizeof(uint32_t)) |
37 | return false; | 70 | return false; |
38 | } | ||
39 | } | ||
40 | 71 | ||
41 | p = id3->id3v2buf; | 72 | switch (chunk_type) |
73 | { | ||
74 | case CHAR4_CONST('I', 'N', 'F', 'O'): | ||
75 | { | ||
76 | /* only one info chunk permitted */ | ||
77 | if (info_found) | ||
78 | return false; | ||
79 | |||
80 | info_found = true; | ||
81 | |||
82 | /* minimum size */ | ||
83 | if (chunk_size < 8) | ||
84 | return false; | ||
85 | |||
86 | ssize_t size = MIN((ssize_t)sizeof(struct NSFE_INFOCHUNK), | ||
87 | chunk_size); | ||
88 | |||
89 | if (read(fd, &info, size) != size) | ||
90 | return false; | ||
91 | |||
92 | if (size >= 9) | ||
93 | id3->length = info.nTrackCount*1000; | ||
94 | |||
95 | lseek(fd, chunk_size - size, SEEK_CUR); | ||
96 | break; | ||
97 | } | ||
98 | |||
99 | case CHAR4_CONST('a', 'u', 't', 'h'): | ||
100 | { | ||
101 | if (!info_found) | ||
102 | return false; | ||
103 | |||
104 | /* szGameTitle, szArtist, szCopyright */ | ||
105 | char ** const ar[] = { &id3->title, &id3->artist, &id3->album }; | ||
106 | |||
107 | char *p = id3->id3v2buf; | ||
108 | long buf_rem = sizeof (id3->id3v2buf); | ||
109 | unsigned int i; | ||
110 | |||
111 | for (i = 0; i < ARRAYLEN(ar) && chunk_size && buf_rem; i++) | ||
112 | { | ||
113 | long len = read_string(fd, p, buf_rem, '\0', chunk_size); | ||
114 | |||
115 | if (len < 0) | ||
116 | return false; | ||
117 | |||
118 | *ar[i] = p; | ||
119 | p += len; | ||
120 | buf_rem -= len; | ||
121 | |||
122 | if (chunk_size >= len) | ||
123 | chunk_size -= len; | ||
124 | else | ||
125 | chunk_size = 0; | ||
126 | } | ||
127 | |||
128 | lseek(fd, chunk_size, SEEK_CUR); | ||
129 | break; | ||
130 | } | ||
131 | |||
132 | |||
133 | case CHAR4_CONST('D', 'A', 'T', 'A'): | ||
134 | if (chunk_size < 1) | ||
135 | return false; | ||
136 | |||
137 | data_found = true; | ||
138 | /* fall through */ | ||
139 | case CHAR4_CONST('f', 'a', 'd', 'e'): | ||
140 | case CHAR4_CONST('t', 'i', 'm', 'e'): | ||
141 | case CHAR4_CONST('B', 'A', 'N', 'K'): | ||
142 | case CHAR4_CONST('p', 'l', 's', 't'): | ||
143 | case CHAR4_CONST('t', 'l', 'b', 'l'): /* we unfortunately can't use these anyway */ | ||
144 | { | ||
145 | if (!info_found) | ||
146 | return false; | ||
147 | |||
148 | lseek(fd, chunk_size, SEEK_CUR); | ||
149 | break; | ||
150 | } | ||
151 | |||
152 | case CHAR4_CONST('N', 'E', 'N', 'D'): | ||
153 | { | ||
154 | end_found = true; | ||
155 | break; | ||
156 | } | ||
157 | |||
158 | default: /* unknown chunk */ | ||
159 | { | ||
160 | /* check the first byte */ | ||
161 | chunk_type = (uint8_t)chunk_type; | ||
162 | |||
163 | /* chunk is vital... don't continue */ | ||
164 | if(chunk_type >= 'A' && chunk_type <= 'Z') | ||
165 | return false; | ||
166 | |||
167 | /* otherwise, just skip it */ | ||
168 | lseek(fd, chunk_size, SEEK_CUR); | ||
169 | break; | ||
170 | } | ||
171 | } /* end switch */ | ||
172 | } /* end while */ | ||
173 | |||
174 | /* | ||
175 | * if we exited the while loop without a 'return', we must have hit an NEND | ||
176 | * chunk if this is the case, the file was layed out as it was expected. | ||
177 | * now.. make sure we found both an info chunk, AND a data chunk... since | ||
178 | * these are minimum requirements for a valid NSFE file | ||
179 | */ | ||
180 | return info_found && data_found; | ||
181 | } | ||
182 | |||
183 | static bool parse_nesm(int fd, struct mp3entry *id3) | ||
184 | { | ||
185 | struct NESM_HEADER hdr; | ||
186 | char *p = id3->id3v2buf; | ||
187 | |||
188 | lseek(fd, 0, SEEK_SET); | ||
189 | if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) | ||
190 | return false; | ||
42 | 191 | ||
43 | /* Length */ | 192 | /* Length */ |
44 | id3->length = buf[6]*1000; | 193 | id3->length = hdr.nTrackCount*1000; |
45 | 194 | ||
46 | /* Title */ | 195 | /* Title */ |
47 | memcpy(p, &buf[14], 32); | ||
48 | id3->title = p; | 196 | id3->title = p; |
49 | p += strlen(p)+1; | 197 | p += strlcpy(p, hdr.szGameTitle, 32) + 1; |
50 | 198 | ||
51 | /* Artist */ | 199 | /* Artist */ |
52 | memcpy(p, &buf[46], 32); | ||
53 | id3->artist = p; | 200 | id3->artist = p; |
54 | p += strlen(p)+1; | 201 | p += strlcpy(p, hdr.szArtist, 32) + 1; |
55 | 202 | ||
56 | /* Copyright (per codec) */ | 203 | /* Copyright (per codec) */ |
57 | memcpy(p, &buf[78], 32); | ||
58 | id3->album = p; | 204 | id3->album = p; |
205 | strlcpy(p, hdr.szCopyright, 32); | ||
59 | 206 | ||
60 | return true; | 207 | return true; |
61 | } | 208 | } |
62 | 209 | ||
210 | bool get_nsf_metadata(int fd, struct mp3entry* id3) | ||
211 | { | ||
212 | uint32_t nsf_type; | ||
213 | |||
214 | if (lseek(fd, 0, SEEK_SET) < 0 || | ||
215 | read_uint32be(fd, &nsf_type) != (int)sizeof(nsf_type)) | ||
216 | return false; | ||
217 | |||
218 | id3->vbr = false; | ||
219 | id3->filesize = filesize(fd); | ||
220 | /* we only render 16 bits, 44.1KHz, Mono */ | ||
221 | id3->bitrate = 706; | ||
222 | id3->frequency = 44100; | ||
223 | |||
224 | if (nsf_type == CHAR4_CONST('N', 'S', 'F', 'E')) | ||
225 | return parse_nsfe(fd, id3); | ||
226 | else if (nsf_type == CHAR4_CONST('N', 'E', 'S', 'M')) | ||
227 | return parse_nesm(fd, id3); | ||
228 | |||
229 | /* not a valid format*/ | ||
230 | return false; | ||
231 | } | ||
232 | |||