"Fossies" - the Fresh Open Source Software Archive

Member "libextractor-1.11/src/plugins/nsfe_extractor.c" (30 Jan 2021, 9205 Bytes) of package /linux/privat/libextractor-1.11.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "nsfe_extractor.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.6_vs_1.7.

    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
  179 info_extract (struct EXTRACTOR_ExtractContext *ec,
  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   {
  197     ADD ("PAL/NTSC", EXTRACTOR_METATYPE_BROADCAST_TELEVISION_SYSTEM);
  198   }
  199   else
  200   {
  201     if (0 != (ichunk->tvflags & PAL_FLAG))
  202       ADD ("PAL", EXTRACTOR_METATYPE_BROADCAST_TELEVISION_SYSTEM);
  203     else
  204       ADD ("NTSC", EXTRACTOR_METATYPE_BROADCAST_TELEVISION_SYSTEM);
  205   }
  206 
  207   if (0 != (ichunk->chipflags & VRCVI_FLAG))
  208     ADD ("VRCVI", EXTRACTOR_METATYPE_TARGET_ARCHITECTURE);
  209   if (0 != (ichunk->chipflags & VRCVII_FLAG))
  210     ADD ("VRCVII", EXTRACTOR_METATYPE_TARGET_ARCHITECTURE);
  211   if (0 != (ichunk->chipflags & FDS_FLAG))
  212     ADD ("FDS Sound", EXTRACTOR_METATYPE_TARGET_ARCHITECTURE);
  213   if (0 != (ichunk->chipflags & MMC5_FLAG))
  214     ADD ("MMC5 audio", EXTRACTOR_METATYPE_TARGET_ARCHITECTURE);
  215   if (0 != (ichunk->chipflags & NAMCO_FLAG))
  216     ADD ("Namco 106", EXTRACTOR_METATYPE_TARGET_ARCHITECTURE);
  217   if (0 != (ichunk->chipflags & SUNSOFT_FLAG))
  218     ADD ("Sunsoft FME-07", EXTRACTOR_METATYPE_TARGET_ARCHITECTURE);
  219 
  220   if (size < sizeof (struct infochunk))
  221   {
  222     ADD ("1", EXTRACTOR_METATYPE_SONG_COUNT);
  223     return 0;
  224   }
  225   snprintf (songs,
  226             sizeof (songs),
  227             "%d",
  228             ichunk->songs);
  229   ADD (songs, EXTRACTOR_METATYPE_SONG_COUNT);
  230   snprintf (songs,
  231             sizeof (songs),
  232             "%d",
  233             ichunk->firstsong);
  234   ADD (songs, EXTRACTOR_METATYPE_STARTING_SONG);
  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
  247 tlbl_extract (struct EXTRACTOR_ExtractContext *ec,
  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;
  270     ADDF (title, EXTRACTOR_METATYPE_TITLE);
  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
  285 auth_extract (struct EXTRACTOR_ExtractContext *ec,
  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);
  309     ADDF (album, EXTRACTOR_METATYPE_ALBUM);
  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);
  318     ADDF (artist, EXTRACTOR_METATYPE_ARTIST);
  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)
  333     ADDF (ripper, EXTRACTOR_METATYPE_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
  347 EXTRACTOR_nsfe_extract_method (struct EXTRACTOR_ExtractContext *ec)
  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",
  366                      EXTRACTOR_METATYPE_MIMETYPE,
  367                      EXTRACTOR_METAFORMAT_UTF8,
  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 */