diff options
Diffstat (limited to 'apps/metadata/nsf.c')
-rw-r--r-- | apps/metadata/nsf.c | 278 |
1 files changed, 0 insertions, 278 deletions
diff --git a/apps/metadata/nsf.c b/apps/metadata/nsf.c deleted file mode 100644 index 2fa6f36b12..0000000000 --- a/apps/metadata/nsf.c +++ /dev/null | |||
@@ -1,278 +0,0 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <string.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <ctype.h> | ||
5 | #include <inttypes.h> | ||
6 | |||
7 | #include "system.h" | ||
8 | #include "metadata.h" | ||
9 | #include "metadata_common.h" | ||
10 | #include "metadata_parsers.h" | ||
11 | #include "rbunicode.h" | ||
12 | #include "string-extra.h" | ||
13 | |||
14 | /* NOTE: This file was modified to work properly with the new nsf codec based | ||
15 | on Game_Music_Emu */ | ||
16 | |||
17 | struct NESM_HEADER | ||
18 | { | ||
19 | uint32_t nHeader; | ||
20 | uint8_t nHeaderExtra; | ||
21 | uint8_t nVersion; | ||
22 | uint8_t nTrackCount; | ||
23 | uint8_t nInitialTrack; | ||
24 | uint16_t nLoadAddress; | ||
25 | uint16_t nInitAddress; | ||
26 | uint16_t nPlayAddress; | ||
27 | uint8_t szGameTitle[32]; | ||
28 | uint8_t szArtist[32]; | ||
29 | uint8_t szCopyright[32]; | ||
30 | uint16_t nSpeedNTSC; | ||
31 | uint8_t nBankSwitch[8]; | ||
32 | uint16_t nSpeedPAL; | ||
33 | uint8_t nNTSC_PAL; | ||
34 | uint8_t nExtraChip; | ||
35 | uint8_t nExpansion[4]; | ||
36 | } __attribute__((packed)); | ||
37 | |||
38 | struct NSFE_INFOCHUNK | ||
39 | { | ||
40 | uint16_t nLoadAddress; | ||
41 | uint16_t nInitAddress; | ||
42 | uint16_t nPlayAddress; | ||
43 | uint8_t nIsPal; | ||
44 | uint8_t nExt; | ||
45 | uint8_t nTrackCount; | ||
46 | uint8_t nStartingTrack; | ||
47 | } __attribute__((packed)); | ||
48 | |||
49 | |||
50 | #define CHAR4_CONST(a, b, c, d) FOURCC(a, b, c, d) | ||
51 | #define CHUNK_INFO 0x0001 | ||
52 | #define CHUNK_DATA 0x0002 | ||
53 | #define CHUNK_NEND 0x0004 | ||
54 | #define CHUNK_plst 0x0008 | ||
55 | #define CHUNK_time 0x0010 | ||
56 | #define CHUNK_fade 0x0020 | ||
57 | #define CHUNK_tlbl 0x0040 | ||
58 | #define CHUNK_auth 0x0080 | ||
59 | #define CHUNK_BANK 0x0100 | ||
60 | |||
61 | static bool parse_nsfe(int fd, struct mp3entry *id3) | ||
62 | { | ||
63 | unsigned int chunks_found = 0; | ||
64 | long track_count = 0; | ||
65 | long playlist_count = 0; | ||
66 | |||
67 | struct NSFE_INFOCHUNK info; | ||
68 | memset(&info, 0, sizeof(struct NSFE_INFOCHUNK)); | ||
69 | |||
70 | /* default values */ | ||
71 | info.nTrackCount = 1; | ||
72 | id3->length = 150 * 1000; | ||
73 | |||
74 | /* begin reading chunks */ | ||
75 | while (!(chunks_found & CHUNK_NEND)) | ||
76 | { | ||
77 | uint32_t chunk_size, chunk_type; | ||
78 | |||
79 | if (read_uint32le(fd, &chunk_size) != (int)sizeof(uint32_t)) | ||
80 | return false; | ||
81 | |||
82 | if (read_uint32be(fd, &chunk_type) != (int)sizeof(uint32_t)) | ||
83 | return false; | ||
84 | |||
85 | switch (chunk_type) | ||
86 | { | ||
87 | /* first three types are mandatory (but don't worry about NEND | ||
88 | anyway) */ | ||
89 | case CHAR4_CONST('I', 'N', 'F', 'O'): | ||
90 | { | ||
91 | if (chunks_found & CHUNK_INFO) | ||
92 | return false; /* only one info chunk permitted */ | ||
93 | |||
94 | chunks_found |= CHUNK_INFO; | ||
95 | |||
96 | /* minimum size */ | ||
97 | if (chunk_size < 8) | ||
98 | return false; | ||
99 | |||
100 | ssize_t size = MIN(sizeof(struct NSFE_INFOCHUNK), chunk_size); | ||
101 | |||
102 | if (read(fd, &info, size) != size) | ||
103 | return false; | ||
104 | |||
105 | if (size >= 9) | ||
106 | track_count = info.nTrackCount; | ||
107 | |||
108 | chunk_size -= size; | ||
109 | break; | ||
110 | } | ||
111 | |||
112 | case CHAR4_CONST('D', 'A', 'T', 'A'): | ||
113 | { | ||
114 | if (!(chunks_found & CHUNK_INFO)) | ||
115 | return false; | ||
116 | |||
117 | if (chunks_found & CHUNK_DATA) | ||
118 | return false; /* only one may exist */ | ||
119 | |||
120 | if (chunk_size < 1) | ||
121 | return false; | ||
122 | |||
123 | chunks_found |= CHUNK_DATA; | ||
124 | break; | ||
125 | } | ||
126 | |||
127 | case CHAR4_CONST('N', 'E', 'N', 'D'): | ||
128 | { | ||
129 | /* just end parsing regardless of whether or not this really is the | ||
130 | last chunk/data (but it _should_ be) */ | ||
131 | chunks_found |= CHUNK_NEND; | ||
132 | continue; | ||
133 | } | ||
134 | |||
135 | /* remaining types are optional */ | ||
136 | |||
137 | case CHAR4_CONST('a', 'u', 't', 'h'): | ||
138 | { | ||
139 | if (chunks_found & CHUNK_auth) | ||
140 | return false; /* only one may exist */ | ||
141 | |||
142 | chunks_found |= CHUNK_auth; | ||
143 | |||
144 | /* szGameTitle, szArtist, szCopyright */ | ||
145 | char ** const ar[] = { &id3->title, &id3->artist, &id3->album }; | ||
146 | |||
147 | char *p = id3->id3v2buf; | ||
148 | long buf_rem = sizeof (id3->id3v2buf); | ||
149 | unsigned int i; | ||
150 | |||
151 | for (i = 0; i < ARRAYLEN(ar) && chunk_size && buf_rem; i++) | ||
152 | { | ||
153 | long len = read_string(fd, p, buf_rem, '\0', chunk_size); | ||
154 | |||
155 | if (len < 0) | ||
156 | return false; | ||
157 | |||
158 | *ar[i] = p; | ||
159 | p += len; | ||
160 | buf_rem -= len; | ||
161 | |||
162 | if (chunk_size >= (uint32_t)len) | ||
163 | chunk_size -= len; | ||
164 | else | ||
165 | chunk_size = 0; | ||
166 | } | ||
167 | |||
168 | break; | ||
169 | } | ||
170 | |||
171 | case CHAR4_CONST('p', 'l', 's', 't'): | ||
172 | { | ||
173 | if (chunks_found & CHUNK_plst) | ||
174 | return false; /* only one may exist */ | ||
175 | |||
176 | chunks_found |= CHUNK_plst; | ||
177 | |||
178 | /* each byte is the index of one track */ | ||
179 | playlist_count = chunk_size; | ||
180 | break; | ||
181 | } | ||
182 | |||
183 | case CHAR4_CONST('t', 'i', 'm', 'e'): | ||
184 | case CHAR4_CONST('f', 'a', 'd', 'e'): | ||
185 | case CHAR4_CONST('t', 'l', 'b', 'l'): /* we unfortunately can't use these anyway */ | ||
186 | { | ||
187 | /* don't care how many of these there are even though there should | ||
188 | be only one */ | ||
189 | if (!(chunks_found & CHUNK_INFO)) | ||
190 | return false; | ||
191 | |||
192 | case CHAR4_CONST('B', 'A', 'N', 'K'): | ||
193 | break; | ||
194 | } | ||
195 | |||
196 | default: /* unknown chunk */ | ||
197 | { | ||
198 | /* check the first byte */ | ||
199 | chunk_type = (uint8_t)chunk_type; | ||
200 | |||
201 | /* chunk is vital... don't continue */ | ||
202 | if(chunk_type >= 'A' && chunk_type <= 'Z') | ||
203 | return false; | ||
204 | |||
205 | /* otherwise, just skip it */ | ||
206 | break; | ||
207 | } | ||
208 | } /* end switch */ | ||
209 | |||
210 | lseek(fd, chunk_size, SEEK_CUR); | ||
211 | } /* end while */ | ||
212 | |||
213 | if (track_count | playlist_count) | ||
214 | id3->length = MAX(track_count, playlist_count)*1000; | ||
215 | |||
216 | /* Single subtrack files will be treated differently | ||
217 | by gme's nsf codec */ | ||
218 | if (id3->length <= 1000) id3->length = 150 * 1000; | ||
219 | |||
220 | /* | ||
221 | * if we exited the while loop without a 'return', we must have hit an NEND | ||
222 | * chunk if this is the case, the file was layed out as it was expected. | ||
223 | * now.. make sure we found both an info chunk, AND a data chunk... since | ||
224 | * these are minimum requirements for a valid NSFE file | ||
225 | */ | ||
226 | return (chunks_found & (CHUNK_INFO | CHUNK_DATA)) == | ||
227 | (CHUNK_INFO | CHUNK_DATA); | ||
228 | } | ||
229 | |||
230 | static bool parse_nesm(int fd, struct mp3entry *id3) | ||
231 | { | ||
232 | struct NESM_HEADER hdr; | ||
233 | char *p = id3->id3v2buf; | ||
234 | |||
235 | lseek(fd, 0, SEEK_SET); | ||
236 | if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) | ||
237 | return false; | ||
238 | |||
239 | /* Length */ | ||
240 | id3->length = (hdr.nTrackCount > 1 ? hdr.nTrackCount : 150) * 1000; | ||
241 | |||
242 | /* Title */ | ||
243 | id3->title = p; | ||
244 | p += strlcpy(p, hdr.szGameTitle, 32) + 1; | ||
245 | |||
246 | /* Artist */ | ||
247 | id3->artist = p; | ||
248 | p += strlcpy(p, hdr.szArtist, 32) + 1; | ||
249 | |||
250 | /* Copyright (per codec) */ | ||
251 | id3->album = p; | ||
252 | strlcpy(p, hdr.szCopyright, 32); | ||
253 | |||
254 | return true; | ||
255 | } | ||
256 | |||
257 | bool get_nsf_metadata(int fd, struct mp3entry* id3) | ||
258 | { | ||
259 | uint32_t nsf_type; | ||
260 | if (lseek(fd, 0, SEEK_SET) < 0 || | ||
261 | read_uint32be(fd, &nsf_type) != (int)sizeof(nsf_type)) | ||
262 | return false; | ||
263 | |||
264 | id3->vbr = false; | ||
265 | id3->filesize = filesize(fd); | ||
266 | /* we only render 16 bits, 44.1KHz, Mono */ | ||
267 | id3->bitrate = 706; | ||
268 | id3->frequency = 44100; | ||
269 | |||
270 | if (nsf_type == CHAR4_CONST('N', 'S', 'F', 'E')) | ||
271 | return parse_nsfe(fd, id3); | ||
272 | else if (nsf_type == CHAR4_CONST('N', 'E', 'S', 'M')) | ||
273 | return parse_nesm(fd, id3); | ||
274 | |||
275 | /* not a valid format*/ | ||
276 | return false; | ||
277 | } | ||
278 | |||