libextractor  1.11
About: GNU libextractor is a library used to extract meta-data from files of arbitrary type.
  Fossies Dox: libextractor-1.11.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

nsfe_extractor.c
Go to the documentation of this file.
1 /*
2  * This file is part of libextractor.
3  * Copyright (C) 2007, 2009, 2012 Toni Ruottu and Christian Grothoff
4  *
5  * libextractor is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published
7  * by the Free Software Foundation; either version 3, or (at your
8  * option) any later version.
9  *
10  * libextractor is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with libextractor; see the file COPYING. If not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  */
21 /**
22  * @file plugins/nsfe_extractor.c
23  * @brief plugin to support Nes Sound Format files
24  * @author Toni Ruottu
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "extractor.h"
29 #include "convert.h"
30 
31 
32 /* television system flags */
33 #define PAL_FLAG 0x01
34 #define DUAL_FLAG 0x02
35 
36 /* sound chip flags */
37 #define VRCVI_FLAG 0x01
38 #define VRCVII_FLAG 0x02
39 #define FDS_FLAG 0x04
40 #define MMC5_FLAG 0x08
41 #define NAMCO_FLAG 0x10
42 #define SUNSOFT_FLAG 0x20
43 
44 /**
45  * "Header" of an NSFE file.
46  */
47 struct header
48 {
49  char magicid[4];
50 };
51 
52 
53 /**
54  * Read an unsigned integer at the current offset.
55  *
56  * @param data input data to parse
57  * @return parsed integer
58  */
59 static uint32_t
60 nsfeuint (const char *data)
61 {
62  uint32_t value = 0;
63  int i;
64 
65  for (i = 3; i > 0; i--)
66  {
67  value += (unsigned char) data[i];
68  value *= 0x100;
69  }
70  value += (unsigned char) data[0];
71  return value;
72 }
73 
74 
75 /**
76  * Copy string starting at 'data' with at most
77  * 'size' bytes. (strndup).
78  *
79  * @param data input data to copy
80  * @param size number of bytes in 'data'
81  * @return copy of the string at data
82  */
83 static char *
84 nsfestring (const char *data,
85  size_t size)
86 {
87  char *s;
88  size_t length;
89 
90  length = 0;
91  while ( (length < size) &&
92  (data[length] != '\0') )
93  length++;
94  if (NULL == (s = malloc (length + 1)))
95  return NULL;
96  memcpy (s, data, length);
97  s[length] = '\0';
98  return s;
99 }
100 
101 
102 /**
103  * Give metadata to LE; return if 'proc' returns non-zero.
104  *
105  * @param s metadata value as UTF8
106  * @param t metadata type to use
107  */
108 #define ADD(s,t) do { if (0 != ec->proc (ec->cls, "nsfe", t, \
109  EXTRACTOR_METAFORMAT_UTF8, \
110  "text/plain", s, strlen (s) \
111  + 1)) return 1; \
112 } while (0)
113 
114 
115 /**
116  * Give metadata to LE; return if 'proc' returns non-zero.
117  *
118  * @param s metadata value as UTF8, free at the end
119  * @param t metadata type to use
120  */
121 #define ADDF(s,t) do { if (0 != ec->proc (ec->cls, "nsfe", t, \
122  EXTRACTOR_METAFORMAT_UTF8, \
123  "text/plain", s, strlen (s) \
124  + 1)) { free (s); \
125  return 1; \
126  } free (s); } while (0)
127 
128 
129 /**
130  * Format of an 'INFO' chunk. Last two bytes are optional.
131  */
132 struct infochunk
133 {
134  /**
135  * Unknown.
136  */
137  uint16_t loadaddr;
138 
139  /**
140  * Unknown.
141  */
142  uint16_t initaddr;
143 
144  /**
145  * Unknown.
146  */
147  uint16_t playaddr;
148 
149  /**
150  * TV encoding flags.
151  */
152  char tvflags;
153 
154  /**
155  * Chipset encoding flags.
156  */
157  char chipflags;
158 
159  /**
160  * Number of songs.
161  */
162  unsigned char songs;
163 
164  /**
165  * Starting song.
166  */
167  unsigned char firstsong;
168 };
169 
170 
171 /**
172  * Extract data from the INFO chunk.
173  *
174  * @param ec extraction context
175  * @param size number of bytes in INFO chunk
176  * @return 0 to continue extrating
177  */
178 static int
180  uint32_t size)
181 {
182  void *data;
183  const struct infochunk *ichunk;
184  char songs[32];
185 
186  if (size < 8)
187  return 0;
188  if ((ssize_t) size >
189  ec->read (ec->cls,
190  &data,
191  size))
192  return 1;
193  ichunk = data;
194 
195  if (0 != (ichunk->tvflags & DUAL_FLAG))
196  {
198  }
199  else
200  {
201  if (0 != (ichunk->tvflags & PAL_FLAG))
203  else
205  }
206 
207  if (0 != (ichunk->chipflags & VRCVI_FLAG))
209  if (0 != (ichunk->chipflags & VRCVII_FLAG))
211  if (0 != (ichunk->chipflags & FDS_FLAG))
213  if (0 != (ichunk->chipflags & MMC5_FLAG))
215  if (0 != (ichunk->chipflags & NAMCO_FLAG))
217  if (0 != (ichunk->chipflags & SUNSOFT_FLAG))
218  ADD ("Sunsoft FME-07", EXTRACTOR_METATYPE_TARGET_ARCHITECTURE);
219 
220  if (size < sizeof (struct infochunk))
221  {
223  return 0;
224  }
225  snprintf (songs,
226  sizeof (songs),
227  "%d",
228  ichunk->songs);
230  snprintf (songs,
231  sizeof (songs),
232  "%d",
233  ichunk->firstsong);
235  return 0;
236 }
237 
238 
239 /**
240  * Extract data from the TLBL chunk.
241  *
242  * @param ec extraction context
243  * @param size number of bytes in TLBL chunk
244  * @return 0 to continue extrating
245  */
246 static int
248  uint32_t size)
249 {
250  char *title;
251  ssize_t left;
252  size_t length;
253  void *data;
254  const char *cdata;
255 
256  if ((ssize_t) size >
257  ec->read (ec->cls,
258  &data,
259  size))
260  return 1;
261  cdata = data;
262 
263  left = size;
264  while (left > 0)
265  {
266  title = nsfestring (&cdata[size - left], left);
267  if (NULL == title)
268  return 0;
269  length = strlen (title) + 1;
271  left -= length;
272  }
273  return 0;
274 }
275 
276 
277 /**
278  * Extract data from the AUTH chunk.
279  *
280  * @param ec extraction context
281  * @param size number of bytes in AUTH chunk
282  * @return 0 to continue extrating
283  */
284 static int
286  uint32_t size)
287 {
288  char *album;
289  char *artist;
290  char *copyright;
291  char *ripper;
292  uint32_t left = size;
293  void *data;
294  const char *cdata;
295 
296  if (left < 1)
297  return 0;
298  if ((ssize_t) size >
299  ec->read (ec->cls,
300  &data,
301  size))
302  return 1;
303  cdata = data;
304 
305  album = nsfestring (&cdata[size - left], left);
306  if (NULL != album)
307  {
308  left -= (strlen (album) + 1);
310  if (left < 1)
311  return 0;
312  }
313 
314  artist = nsfestring (&cdata[size - left], left);
315  if (NULL != artist)
316  {
317  left -= (strlen (artist) + 1);
319  if (left < 1)
320  return 0;
321  }
322 
323  copyright = nsfestring (&cdata[size - left], left);
324  if (NULL != copyright)
325  {
326  left -= (strlen (copyright) + 1);
327  ADDF (copyright, EXTRACTOR_METATYPE_COPYRIGHT);
328  if (left < 1)
329  return 0;
330  }
331  ripper = nsfestring (&cdata[size - left], left);
332  if (NULL != ripper)
334  return 0;
335 }
336 
337 
338 /**
339  * "extract" meta data from an Extended Nintendo Sound Format file
340  *
341  * NSFE specification revision 2 (Sep. 3, 2003) was used, while this
342  * piece of software was originally written.
343  *
344  * @param ec extraction context
345  */
346 void
348 {
349  const struct header *head;
350  void *data;
351  uint64_t off;
352  uint32_t chunksize;
353  int ret;
354 
355  if ((ssize_t) sizeof (struct header) >
356  ec->read (ec->cls,
357  &data,
358  sizeof (struct header)))
359  return;
360  head = data;
361  if (0 != memcmp (head->magicid, "NSFE", 4))
362  return;
363 
364  if (0 != ec->proc (ec->cls,
365  "nsfe",
368  "text/plain",
369  "audio/x-nsfe",
370  strlen ("audio/x-nsfe") + 1))
371  return;
372  off = sizeof (struct header);
373  ret = 0;
374  while (0 == ret)
375  {
376  if (off != ec->seek (ec->cls,
377  off,
378  SEEK_SET))
379  break;
380  if (8 >
381  ec->read (ec->cls,
382  &data,
383  8))
384  break;
385  chunksize = nsfeuint (data);
386  if (off + chunksize + 8LLU <= off)
387  break; /* protect against looping */
388  off += 8LLU + chunksize;
389  if (0 == memcmp (data + 4, "INFO", 4))
390  ret = info_extract (ec, chunksize);
391  else if (0 == memcmp (data + 4, "auth", 4))
392  ret = auth_extract (ec, chunksize);
393  else if (0 == memcmp (data + 4, "tlbl", 4))
394  ret = tlbl_extract (ec, chunksize);
395  /* Ignored chunks: DATA, NEND, plst, time, fade, BANK */
396  }
397 }
398 
399 
400 /* end of nsfe_extractor.c */
@ EXTRACTOR_METAFORMAT_UTF8
Definition: extractor.h:102
#define NULL
Definition: getopt1.c:60
@ EXTRACTOR_METATYPE_BROADCAST_TELEVISION_SYSTEM
Definition: extractor.h:291
@ EXTRACTOR_METATYPE_TARGET_ARCHITECTURE
Definition: extractor.h:224
@ EXTRACTOR_METATYPE_TITLE
Definition: extractor.h:134
@ EXTRACTOR_METATYPE_ARTIST
Definition: extractor.h:279
@ EXTRACTOR_METATYPE_COPYRIGHT
Definition: extractor.h:183
@ EXTRACTOR_METATYPE_STARTING_SONG
Definition: extractor.h:304
@ EXTRACTOR_METATYPE_MIMETYPE
Definition: extractor.h:129
@ EXTRACTOR_METATYPE_ALBUM
Definition: extractor.h:278
@ EXTRACTOR_METATYPE_RIPPER
Definition: extractor.h:328
@ EXTRACTOR_METATYPE_SONG_COUNT
Definition: extractor.h:303
static uint32_t nsfeuint(const char *data)
#define MMC5_FLAG
#define ADDF(s, t)
static int info_extract(struct EXTRACTOR_ExtractContext *ec, uint32_t size)
#define PAL_FLAG
#define VRCVI_FLAG
static int auth_extract(struct EXTRACTOR_ExtractContext *ec, uint32_t size)
void EXTRACTOR_nsfe_extract_method(struct EXTRACTOR_ExtractContext *ec)
static int tlbl_extract(struct EXTRACTOR_ExtractContext *ec, uint32_t size)
#define SUNSOFT_FLAG
#define VRCVII_FLAG
#define NAMCO_FLAG
static char * nsfestring(const char *data, size_t size)
#define DUAL_FLAG
#define ADD(s, t)
#define FDS_FLAG
plaform specifics
int64_t(* seek)(void *cls, int64_t pos, int whence)
Definition: extractor.h:509
EXTRACTOR_MetaDataProcessor proc
Definition: extractor.h:525
ssize_t(* read)(void *cls, void **data, size_t size)
Definition: extractor.h:494
char magicid[5]
Definition: nsf_extractor.c:52
unsigned char firstsong
uint16_t loadaddr
uint16_t playaddr
unsigned char songs
uint16_t initaddr