Logo Search packages:      
Sourcecode: xmms-scrobbler version File versions

wma.c

/*
 *   libmetatag - A media file tag-reader library
 *   Copyright (C) 2004  Pipian
 *
 *   This library is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Lesser General Public
 *   License as published by the Free Software Foundation; either
 *   version 2.1 of the License, or (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *   Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public
 *   License along with this library; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef MAKE_BMP
#include "include/bmp_vfs.h"
#endif
#include "include/wma.h"
#include "include/tags.h"
#include "include/endian.h"
#include "../fmt.h"
#include "../config.h"
#include "include/unicode.h"
#define WMA_GUID  (unsigned char [16]) \
                  {     0x30, 0x26, 0xB2, 0x75, \
                  0x8E, 0x66, \
                  0xCF, 0x11, \
                  0xA6, 0xD9, \
                  0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }
#define CONTENT_GUID    (unsigned char [16]) \
                  {     0x33, 0x26, 0xB2, 0x75, \
                  0x8E, 0x66, \
                  0xCF, 0x11, \
                  0xA6, 0xD9, \
                  0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C }
#define EXTENDED_GUID   (unsigned char [16]) \
                  {     0x40, 0xA4, 0xD0, 0xD2, \
                  0x07, 0xE3, \
                  0xD2, 0x11, \
                  0x97, 0xF0, \
                  0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50 }
#define BUFFER_SIZE 4096

static wma_t *readAttributes(FILE *fp, int pos)
{
      wma_t *wma = calloc(sizeof(wma_t), 1);
      attribute_t *attribute;
      unsigned char *tag_buffer = NULL, *bp, cToInt[8], *data = NULL;
      int title_size, author_size, copyright_size, desc_size, rating_size,
            size, primary_items, i;

      fseek(fp, pos, SEEK_SET);
      fread(cToInt, 1, 8, fp);
      /* Yes, it's 64 bits in size, but I'm lazy and don't want to adjust. */
      size = le2int(cToInt);
      tag_buffer = malloc(size - 24);
      fread(tag_buffer, 1, size - 24, fp);
      bp = tag_buffer;
      title_size = le2short(bp);
      bp += 2;
      author_size = le2short(bp);
      bp += 2;
      copyright_size = le2short(bp);
      bp += 2;
      desc_size = le2short(bp);
      bp += 2;
      rating_size = le2short(bp);
      bp += 2;
      if(title_size > 0)
      {
            attribute = calloc(sizeof(attribute_t), 1);
            wma->items = realloc(wma->items,
                        (wma->numitems + 1) * sizeof(attribute_t *));
            attribute->name = malloc(6);
            strcpy((char *)attribute->name, "Title");
            data = malloc(title_size);
            memcpy(data, bp, title_size);
            bp += title_size;
            utf16le_to_utf8(data, title_size, &attribute->data);
            attribute->type = 0;
            wma->items[wma->numitems++] = attribute;
            free(data);
      }
      if(author_size > 0)
      {
            attribute = calloc(sizeof(attribute_t), 1);
            wma->items = realloc(wma->items,
                        (wma->numitems + 1) * sizeof(attribute_t *));
            attribute->name = malloc(7);
            strcpy((char *)attribute->name, "Author");
            data = malloc(author_size);
            memcpy(data, bp, author_size);
            bp += author_size;
            utf16le_to_utf8(data, author_size, &attribute->data);
            attribute->type = 0;
            wma->items[wma->numitems++] = attribute;
            free(data);
      }
      if(copyright_size > 0)
      {
            attribute = calloc(sizeof(attribute_t), 1);
            wma->items = realloc(wma->items,
                        (wma->numitems + 1) * sizeof(attribute_t *));
            attribute->name = malloc(10);
            strcpy((char *)attribute->name, "Copyright");
            data = malloc(copyright_size);
            memcpy(data, bp, copyright_size);
            bp += copyright_size;
            utf16le_to_utf8(data, copyright_size, &attribute->data);
            attribute->type = 0;
            wma->items[wma->numitems++] = attribute;
            free(data);
      }
      if(desc_size > 0)
      {
            attribute = calloc(sizeof(attribute_t), 1);
            wma->items = realloc(wma->items,
                        (wma->numitems + 1) * sizeof(attribute_t *));
            attribute->name = malloc(12);
            strcpy((char *)attribute->name, "Description");
            data = malloc(desc_size);
            memcpy(data, bp, desc_size);
            bp += desc_size;
            utf16le_to_utf8(data, desc_size, &attribute->data);
            attribute->type = 0;
            wma->items[wma->numitems++] = attribute;
            free(data);
      }
      if(rating_size > 0)
      {
            attribute = calloc(sizeof(attribute_t), 1);
            wma->items = realloc(wma->items,
                        (wma->numitems + 1) * sizeof(attribute_t *));
            attribute->name = malloc(7);
            strcpy((char *)attribute->name, "Rating");
            data = malloc(rating_size);
            memcpy(data, bp, rating_size);
            bp += rating_size;
            utf16le_to_utf8(data, desc_size, &attribute->data);
            attribute->type = 0;
            wma->items[wma->numitems++] = attribute;
            free(data);
      }
      primary_items = wma->numitems;

      fread(tag_buffer, 16, 1, fp);
      if(memcmp(tag_buffer, EXTENDED_GUID, 16))
      {
            free(tag_buffer);
            return wma;
      }
      fread(cToInt, 8, 1, fp);
      /*
       * Another 64-bit breakage. If you've got that large an amount of
       * metadata, you've got a problem.
       */
      size = le2int(cToInt);
      tag_buffer = realloc(tag_buffer, size);
      fread(tag_buffer, size, 1, fp);
      bp = tag_buffer;
      memcpy(cToInt, bp, 2);
      wma->numitems += le2short(cToInt);
      wma->items = realloc(wma->items,
                  wma->numitems * sizeof(attribute_t *));
      bp += 2;
      for(i = primary_items; i < wma->numitems; i++)
      {
            int type;

            attribute = calloc(sizeof(attribute_t), 1);

            memcpy(cToInt, bp, 2);
            size = le2short(cToInt);
            bp += 2;
            data = malloc(size);
            memcpy(data, bp, size);
            utf16le_to_utf8(data, size, &attribute->name);
            bp += size;
            memcpy(cToInt, bp, 2);
            type = le2short(cToInt);
            attribute->type = type;
            bp += 2;
            memcpy(cToInt, bp, 2);
            size = le2short(cToInt);
            bp += 2;
            data = realloc(data, size);
            memcpy(data, bp, size);
            switch(type)
            {
                  /* Type 0 is Little-endian UTF16 */
                  case 0:
                        utf16le_to_utf8(data, size, &attribute->data);
                        break;
                  /*
                   * Type 1 is binary
                   * Type 2 is boolean
                   * Type 3 is 32-bit integer (signed?)
                   * Type 4 is double
                   */
                  case 1:
                  case 2:
                  case 3:
                  case 4:
                  default:
                        attribute->data = malloc(size);
                        memcpy(attribute->data, data, size);
            }
            bp += size;
            
            wma->items[i] = attribute;          
      }

      free(tag_buffer);
      
      return wma;
}

int findWMA(char *filename) {
      
      FILE *fp;
      fp = fopen(filename, "r");

      if (!fp) {
            return 0;
      }

      fseek(fp, 0, SEEK_SET);

      unsigned char *tag_buffer, *bp;
      
      tag_buffer = malloc(BUFFER_SIZE);
      fread(tag_buffer, 1, BUFFER_SIZE, fp);
      bp = tag_buffer;
      if(memcmp(bp, WMA_GUID, 16))
      {
            free(tag_buffer);
            return 0;
      }
      bp += 30;
      if(memcmp(bp, CONTENT_GUID, 16))
      {
            free(tag_buffer);
            return 0;
      }

      free(tag_buffer);
      return 1;
}

int findWMAPos(FILE *fp) {
      unsigned char *tag_buffer, *bp;

      tag_buffer = malloc(BUFFER_SIZE);
      fread(tag_buffer, 1, BUFFER_SIZE, fp);
      bp = tag_buffer;
      if (memcmp(bp, WMA_GUID, 16)) {
            free(tag_buffer);
            return -1;
      }
      bp +=30;
      if (memcmp(bp, CONTENT_GUID, 16)) {
            free(tag_buffer);
            return -1;
      }

      free(tag_buffer);
      return bp - tag_buffer + 16;
}

wma_t *readWMA(char *filename)
{
      FILE *fp;
      wma_t *wma;
      int status;
      
      fp = fopen(filename, "r");

      if(!fp)
      {
            pdebug("Couldn't open file!", META_DEBUG);
            return NULL;
      }
      
      fseek(fp, 0, SEEK_SET);
      
      pdebug("Searching for tag...", META_DEBUG);
      status = findWMAPos(fp);
      if(status == 0)
      {
            fclose(fp);
            return NULL;
      }
      wma = readAttributes(fp, status);
      
      fclose(fp);
      
      return wma;
}

void freeWMA(wma_t *wma)
{
      int i;
      
      for(i = 0; i < wma->numitems; i++)
      {
            attribute_t *attribute;
            
            attribute = wma->items[i];
            free(attribute->name);
            free(attribute->data);
            free(attribute);
      }
      free(wma->items);
      free(wma);
}

int fetchWMA(char *filename, metatag_t *meta) {

      wma_t *wma;
      int i = 0;
      if (findWMA(filename)) {
            wma = readWMA(filename);

            for (i = 0; i < wma->numitems; i++) {
                  attribute_t *attribute = wma->items[i];
                  if (!strcmp((char *)attribute->name, "Title")) {
                        metatag_set_title(meta, (char *)attribute->data);
                  }
                  else if (!strcmp((char *)attribute->name, "Author")) {
                        metatag_set_artist(meta, (char *)attribute->data);
                  }
                  else if (!strcmp((char *)attribute->name, "WM/AlbumTitle")) {
                        metatag_set_album(meta, (char *)attribute->data);
                  }
            }
            freeWMA(wma);
            return 1;
      }

      return 0;
}

Generated by  Doxygen 1.6.0   Back to index