Blame lib/driver/cdtext.c

Packit dd8086
/*
Packit dd8086
  Copyright (C) 2004-2005, 2008, 2011, 2012, 2013 Rocky Bernstein <rocky@gnu.org>
Packit dd8086
  toc reading routine adapted from cuetools
Packit dd8086
  Copyright (C) 2003 Svend Sanjay Sorensen <ssorensen@fastmail.fm>
Packit dd8086
Packit dd8086
  This program is free software: you can redistribute it and/or modify
Packit dd8086
  it under the terms of the GNU General Public License as published by
Packit dd8086
  the Free Software Foundation, either version 3 of the License, or
Packit dd8086
  (at your option) any later version.
Packit dd8086
Packit dd8086
  This program is distributed in the hope that it will be useful,
Packit dd8086
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit dd8086
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit dd8086
  GNU General Public License for more details.
Packit dd8086
Packit dd8086
  You should have received a copy of the GNU General Public License
Packit dd8086
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit dd8086
*/
Packit dd8086

Packit dd8086
#ifdef HAVE_CONFIG_H
Packit dd8086
# include "config.h"
Packit dd8086
# define __CDIO_CONFIG_H__ 1
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#include <cdio/cdtext.h>
Packit dd8086
#include <cdio/logging.h>
Packit dd8086
#include "cdtext_private.h"
Packit dd8086
#include <cdio/utf8.h>
Packit dd8086
Packit dd8086
#ifdef HAVE_STDLIB_H
Packit dd8086
#include <stdlib.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_STRING_H
Packit dd8086
#include <string.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#define _CDTEXT_DBCC
Packit dd8086
#define MAX_CDTEXT_GENRE_CODE     28
Packit dd8086
#define MAX_CDTEXT_LANGUAGE_CODE 127
Packit dd8086
Packit dd8086
const char *cdtext_field[MAX_CDTEXT_FIELDS] =
Packit dd8086
{
Packit dd8086
  "TITLE",
Packit dd8086
  "PERFORMER",
Packit dd8086
  "SONGWRITER",
Packit dd8086
  "COMPOSER",
Packit dd8086
  "MESSAGE",
Packit dd8086
  "ARRANGER",
Packit dd8086
  "ISRC",
Packit dd8086
  "UPC_EAN",
Packit dd8086
  "GENRE",
Packit dd8086
  "DISC_ID",
Packit dd8086
};
Packit dd8086
Packit dd8086
const char *cdtext_genre[MAX_CDTEXT_GENRE_CODE] =
Packit dd8086
{
Packit dd8086
  "Not Used",
Packit dd8086
  "Not Defined",
Packit dd8086
  "Adult Contemporary",
Packit dd8086
  "Alternative Rock",
Packit dd8086
  "Childrens Music",
Packit dd8086
  "Classical",
Packit dd8086
  "Contemporary Christian",
Packit dd8086
  "Country",
Packit dd8086
  "Dance",
Packit dd8086
  "Easy Listening",
Packit dd8086
  "Erotic",
Packit dd8086
  "Folk",
Packit dd8086
  "Gospel",
Packit dd8086
  "Hip Hop",
Packit dd8086
  "Jazz",
Packit dd8086
  "Latin",
Packit dd8086
  "Musical",
Packit dd8086
  "New Age",
Packit dd8086
  "Opera",
Packit dd8086
  "Operetta",
Packit dd8086
  "Pop Music",
Packit dd8086
  "Rap",
Packit dd8086
  "Reggae",
Packit dd8086
  "Rock Music",
Packit dd8086
  "Rhythm & Blues",
Packit dd8086
  "Sound Effects",
Packit dd8086
  "Spoken Word",
Packit dd8086
  "World Music"
Packit dd8086
};
Packit dd8086
Packit dd8086
const char *cdtext_language[MAX_CDTEXT_LANGUAGE_CODE] =
Packit dd8086
{
Packit dd8086
  "Unknown",
Packit dd8086
  "Albanian",
Packit dd8086
  "Breton",
Packit dd8086
  "Catalan",
Packit dd8086
  "Croatian",
Packit dd8086
  "Welsh",
Packit dd8086
  "Czech",
Packit dd8086
  "Danish",
Packit dd8086
  "German",
Packit dd8086
  "English",
Packit dd8086
  "Spanish",
Packit dd8086
  "Esperanto",
Packit dd8086
  "Estonian",
Packit dd8086
  "Basque",
Packit dd8086
  "Faroese",
Packit dd8086
  "French",
Packit dd8086
  "Frisian",
Packit dd8086
  "Irish",
Packit dd8086
  "Gaelic",
Packit dd8086
  "Galician",
Packit dd8086
  "Icelandic",
Packit dd8086
  "Italian",
Packit dd8086
  "Lappish",
Packit dd8086
  "Latin",
Packit dd8086
  "Latvian",
Packit dd8086
  "Luxembourgian",
Packit dd8086
  "Lithuanian",
Packit dd8086
  "Hungarian",
Packit dd8086
  "Maltese",
Packit dd8086
  "Dutch",
Packit dd8086
  "Norwegian",
Packit dd8086
  "Occitan",
Packit dd8086
  "Polish",
Packit dd8086
  "Portuguese",
Packit dd8086
  "Romanian",
Packit dd8086
  "Romansh",
Packit dd8086
  "Serbian",
Packit dd8086
  "Slovak",
Packit dd8086
  "Slovenian",
Packit dd8086
  "Finnish",
Packit dd8086
  "Swedish",
Packit dd8086
  "Turkish",
Packit dd8086
  "Flemish",
Packit dd8086
  "Wallon",
Packit dd8086
  "Zulu",
Packit dd8086
  "Vietnamese",
Packit dd8086
  "Uzbek",
Packit dd8086
  "Urdu",
Packit dd8086
  "Ukrainian",
Packit dd8086
  "Thai",
Packit dd8086
  "Telugu",
Packit dd8086
  "Tatar",
Packit dd8086
  "Tamil",
Packit dd8086
  "Tadzhik",
Packit dd8086
  "Swahili",
Packit dd8086
  "SrananTongo",
Packit dd8086
  "Somali",
Packit dd8086
  "Sinhalese",
Packit dd8086
  "Shona",
Packit dd8086
  "Serbo-croat",
Packit dd8086
  "Ruthenian",
Packit dd8086
  "Russian",
Packit dd8086
  "Russian",
Packit dd8086
  "Quechua",
Packit dd8086
  "Pushtu",
Packit dd8086
  "Punjabi",
Packit dd8086
  "Persian",
Packit dd8086
  "Papamiento",
Packit dd8086
  "Oriya",
Packit dd8086
  "Nepali",
Packit dd8086
  "Ndebele",
Packit dd8086
  "Marathi",
Packit dd8086
  "Moldavian",
Packit dd8086
  "Malaysian",
Packit dd8086
  "Malagasay",
Packit dd8086
  "Macedonian",
Packit dd8086
  "Laotian",
Packit dd8086
  "Korean",
Packit dd8086
  "Khmer",
Packit dd8086
  "Kazakh",
Packit dd8086
  "Kannada",
Packit dd8086
  "Japanese",
Packit dd8086
  "Indonesian",
Packit dd8086
  "Hindi",
Packit dd8086
  "Hebrew",
Packit dd8086
  "Hausa",
Packit dd8086
  "Gurani",
Packit dd8086
  "Gujurati",
Packit dd8086
  "Greek",
Packit dd8086
  "Georgian",
Packit dd8086
  "Fulani",
Packit dd8086
  "Dari",
Packit dd8086
  "Churash",
Packit dd8086
  "Chinese",
Packit dd8086
  "Burmese",
Packit dd8086
  "Bulgarian",
Packit dd8086
  "Bengali",
Packit dd8086
  "Bielorussian",
Packit dd8086
  "Bambora",
Packit dd8086
  "Azerbaijani",
Packit dd8086
  "Assamese",
Packit dd8086
  "Armenian",
Packit dd8086
  "Arabic",
Packit dd8086
  "Amharic"
Packit dd8086
};
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return string representation of given field type.
Packit dd8086
*/
Packit dd8086
const char *
Packit dd8086
cdtext_field2str(cdtext_field_t i)
Packit dd8086
{
Packit dd8086
  if (i >= MAX_CDTEXT_FIELDS)
Packit dd8086
    return "INVALID";
Packit dd8086
  else
Packit dd8086
    return cdtext_field[i];
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return string representation of the given genre code.
Packit dd8086
*/
Packit dd8086
const char *
Packit dd8086
cdtext_genre2str(cdtext_genre_t i)
Packit dd8086
{
Packit dd8086
  if (i >= MAX_CDTEXT_GENRE_CODE)
Packit dd8086
    return "INVALID";
Packit dd8086
  else
Packit dd8086
    return cdtext_genre[i];
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return string representation of the given language code.
Packit dd8086
*/
Packit dd8086
const char *
Packit dd8086
cdtext_lang2str(cdtext_lang_t i)
Packit dd8086
{
Packit dd8086
  if (i >= MAX_CDTEXT_LANGUAGE_CODE)
Packit dd8086
    return "INVALID";
Packit dd8086
  else
Packit dd8086
    return cdtext_language[i];
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Free memory associated with the given cdtext_t object.
Packit dd8086
Packit dd8086
  @param p_cdtext the CD-TEXT object
Packit dd8086
*/
Packit dd8086
void
Packit dd8086
cdtext_destroy(cdtext_t *p_cdtext)
Packit dd8086
{
Packit dd8086
  cdtext_field_t k;
Packit dd8086
  track_t j;
Packit dd8086
  int i;
Packit dd8086
Packit dd8086
  if (!p_cdtext) return;
Packit dd8086
  for (i=0; i
Packit dd8086
    for (j=0; j
Packit dd8086
      for (k=0; k < MAX_CDTEXT_FIELDS; k++) {
Packit dd8086
        if (p_cdtext->block[i].track[j].field[k]) {
Packit dd8086
          free(p_cdtext->block[i].track[j].field[k]);
Packit dd8086
          p_cdtext->block[i].track[j].field[k] = NULL;
Packit dd8086
        }
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
  free(p_cdtext);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Returns a copy of the return value of cdtext_get_const or NULL.
Packit dd8086
Packit dd8086
  Must be freed using cdio_free() when done.
Packit dd8086
  @see cdtext_get_const
Packit dd8086
*/
Packit dd8086
char *
Packit dd8086
cdtext_get(const cdtext_t *p_cdtext, cdtext_field_t field, track_t track)
Packit dd8086
{
Packit dd8086
  const char *ret = cdtext_get_const(p_cdtext, field, track);
Packit dd8086
  if (NULL == ret)
Packit dd8086
    return NULL;
Packit dd8086
  else
Packit dd8086
    return strdup(ret);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Returns value of the given field.
Packit dd8086
Packit dd8086
  NULL is returned if key is CDTEXT_INVALID or the field is not set.
Packit dd8086
  Strings are encoded in UTF-8.
Packit dd8086
Packit dd8086
  @param p_cdtext the CD-TEXT object
Packit dd8086
  @param field type of the field to return
Packit dd8086
  @param track specifies the track, 0 stands for disc
Packit dd8086
*/
Packit dd8086
const char *
Packit dd8086
cdtext_get_const(const cdtext_t *p_cdtext, cdtext_field_t field, track_t track)
Packit dd8086
{
Packit dd8086
  if (CDTEXT_FIELD_INVALID == field
Packit dd8086
      || NULL == p_cdtext
Packit dd8086
      || CDIO_CD_MAX_TRACKS < track)
Packit dd8086
    return NULL;
Packit dd8086
Packit dd8086
  return p_cdtext->block[p_cdtext->block_i].track[track].field[field];
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Returns the discs genre code.
Packit dd8086
Packit dd8086
  @param p_cdtext the CD-TEXT object
Packit dd8086
*/
Packit dd8086
cdtext_genre_t
Packit dd8086
cdtext_get_genre(const cdtext_t *p_cdtext)
Packit dd8086
{
Packit dd8086
  if (NULL == p_cdtext)
Packit dd8086
    return CDTEXT_GENRE_UNUSED;
Packit dd8086
  return p_cdtext->block[p_cdtext->block_i].genre_code;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Returns the currently active language.
Packit dd8086
Packit dd8086
  @param p_cdtext the CD-TEXT object
Packit dd8086
*/
Packit dd8086
cdtext_lang_t
Packit dd8086
cdtext_get_language(const cdtext_t *p_cdtext)
Packit dd8086
{
Packit dd8086
  if (NULL == p_cdtext)
Packit dd8086
    return CDTEXT_LANGUAGE_UNKNOWN;
Packit dd8086
  return p_cdtext->block[p_cdtext->block_i].language_code;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Returns the first track number.
Packit dd8086
Packit dd8086
  @param p_cdtext the CD-TEXT object
Packit dd8086
*/
Packit dd8086
track_t
Packit dd8086
cdtext_get_first_track(const cdtext_t *p_cdtext)
Packit dd8086
{
Packit dd8086
  if (NULL == p_cdtext)
Packit dd8086
    return 0;
Packit dd8086
  return p_cdtext->block[p_cdtext->block_i].first_track;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Returns the last track number.
Packit dd8086
Packit dd8086
  @param p_cdtext the CD-TEXT object
Packit dd8086
*/
Packit dd8086
track_t
Packit dd8086
cdtext_get_last_track(const cdtext_t *p_cdtext)
Packit dd8086
{
Packit dd8086
  if (NULL == p_cdtext)
Packit dd8086
    return 0;
Packit dd8086
  return p_cdtext->block[p_cdtext->block_i].last_track;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*
Packit dd8086
  Returns a list of available languages or NULL.
Packit dd8086
Packit dd8086
  Internally the list is stored in a static array.
Packit dd8086
Packit dd8086
  @param p_cdtext the CD-TEXT object
Packit dd8086
*/
Packit dd8086
cdtext_lang_t
Packit dd8086
*cdtext_list_languages(const cdtext_t *p_cdtext)
Packit dd8086
{
Packit dd8086
  static cdtext_lang_t avail[CDTEXT_NUM_BLOCKS_MAX];
Packit dd8086
  int i, j=0;
Packit dd8086
Packit dd8086
  if (NULL == p_cdtext)
Packit dd8086
    return NULL;
Packit dd8086
Packit dd8086
  for (i=0; i
Packit dd8086
  {
Packit dd8086
    avail[i] = CDTEXT_LANGUAGE_UNKNOWN;
Packit dd8086
    if (CDTEXT_LANGUAGE_UNKNOWN != p_cdtext->block[i].language_code)
Packit dd8086
      avail[j++] = p_cdtext->block[i].language_code;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  return avail;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Try to select the given language.
Packit dd8086
  Select default language if specified is not available or invalid and
Packit dd8086
  return false.
Packit dd8086
Packit dd8086
  @param p_cdtext the CD-TEXT object
Packit dd8086
  @param language language identifier
Packit dd8086
Packit dd8086
  @return true on success, false if language is not available
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
cdtext_select_language(cdtext_t *p_cdtext, cdtext_lang_t language)
Packit dd8086
{
Packit dd8086
  if(NULL == p_cdtext)
Packit dd8086
    return false;
Packit dd8086
Packit dd8086
  if (CDTEXT_LANGUAGE_UNKNOWN != language)
Packit dd8086
  {
Packit dd8086
    int i;
Packit dd8086
    for (i=0; i
Packit dd8086
      if (language == p_cdtext->block[i].language_code) {
Packit dd8086
        p_cdtext->block_i = i;
Packit dd8086
        return true;
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
  } else {
Packit dd8086
    p_cdtext->block_i = 0;
Packit dd8086
  }
Packit dd8086
  return false;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Initialize a new cdtext structure.
Packit dd8086
Packit dd8086
  When the structure is no longer needed, release the
Packit dd8086
  resources using cdtext_delete.
Packit dd8086
Packit dd8086
*/
Packit dd8086
cdtext_t
Packit dd8086
*cdtext_init(void)
Packit dd8086
{
Packit dd8086
  cdtext_field_t k;
Packit dd8086
  track_t j;
Packit dd8086
  int i;
Packit dd8086
  cdtext_t *p_cdtext;
Packit dd8086
Packit dd8086
  p_cdtext = (cdtext_t *) malloc(sizeof(struct cdtext_s));
Packit dd8086
Packit dd8086
  for (i=0; i
Packit dd8086
    for (j=0; j
Packit dd8086
      for (k=0; k < MAX_CDTEXT_FIELDS; k++) {
Packit dd8086
        p_cdtext->block[i].track[j].field[k] = NULL;
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
    p_cdtext->block[i].genre_code = CDTEXT_GENRE_UNUSED;
Packit dd8086
    p_cdtext->block[i].language_code = CDTEXT_LANGUAGE_UNKNOWN;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  p_cdtext->block_i = 0;
Packit dd8086
Packit dd8086
  return p_cdtext;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Returns associated cdtext_field_t if field is a CD-TEXT keyword.
Packit dd8086
Packit dd8086
  Internal function.
Packit dd8086
Packit dd8086
  @param key key to test
Packit dd8086
Packit dd8086
  @return CDTEXT_INVALID if the given keyword is invalid
Packit dd8086
*/
Packit dd8086
cdtext_field_t
Packit dd8086
cdtext_is_field (const char *key)
Packit dd8086
{
Packit dd8086
  unsigned int i;
Packit dd8086
Packit dd8086
  for (i = 0; i < MAX_CDTEXT_FIELDS ; i++)
Packit dd8086
    if (0 == strcmp(cdtext_field[i], key)) {
Packit dd8086
      return i;
Packit dd8086
    }
Packit dd8086
  return CDTEXT_FIELD_INVALID;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Returns associated cdtext_lang_t if argument is a supported language.
Packit dd8086
Packit dd8086
  Internal function.
Packit dd8086
Packit dd8086
  @param lang language to test
Packit dd8086
Packit dd8086
  @return CDTEXT_LANGUAGE_UNKNOWN if language is not supported
Packit dd8086
*/
Packit dd8086
cdtext_lang_t
Packit dd8086
cdtext_is_language(const char *lang)
Packit dd8086
{
Packit dd8086
  unsigned int i;
Packit dd8086
Packit dd8086
  for (i = 0; i < MAX_CDTEXT_LANGUAGE_CODE; i++)
Packit dd8086
    if (0 == strcmp(cdtext_language[i], lang)) {
Packit dd8086
      return i;
Packit dd8086
    }
Packit dd8086
  return CDTEXT_LANGUAGE_UNKNOWN;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Sets the given field at the given track to the given value.
Packit dd8086
Packit dd8086
  Recodes to UTF-8 if charset is not NULL.
Packit dd8086
Packit dd8086
  @param p_cdtext the CD-TEXT object
Packit dd8086
  @param key field to set
Packit dd8086
  @param value value to set
Packit dd8086
  @param track track to work on
Packit dd8086
  @param charset charset to convert from
Packit dd8086
 */
Packit dd8086
void
Packit dd8086
cdtext_set(cdtext_t *p_cdtext, cdtext_field_t key, const uint8_t *value,
Packit dd8086
           track_t track, const char *charset)
Packit dd8086
{
Packit dd8086
  if (NULL == value || key == CDTEXT_FIELD_INVALID
Packit dd8086
      || CDIO_CD_MAX_TRACKS < track)
Packit dd8086
    return;
Packit dd8086
Packit dd8086
  /* free old memory */
Packit dd8086
  if (p_cdtext->block[p_cdtext->block_i].track[track].field[key])
Packit dd8086
    free(p_cdtext->block[p_cdtext->block_i].track[track].field[key]);
Packit dd8086
Packit dd8086
  /* recode to UTF-8 */
Packit dd8086
  if (NULL != charset) {
Packit dd8086
    cdio_utf8_t *utf8_str = NULL;
Packit dd8086
    cdio_charset_to_utf8((const char*) value, strlen((const char*)value),
Packit dd8086
                        &utf8_str, charset);
Packit dd8086
    p_cdtext->block[p_cdtext->block_i].track[track].field[key] = (char *)utf8_str;
Packit dd8086
  } else
Packit dd8086
    p_cdtext->block[p_cdtext->block_i].track[track].field[key] = strdup((const char *)value);
Packit dd8086
}
Packit dd8086
Packit dd8086
#define CDTEXT_COMPARE_CHAR(buf, c, db) ((buf)[0] == c && (! db || (buf)[1] == c) )
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Read a binary CD-TEXT and fill a cdtext struct.
Packit dd8086
Packit dd8086
  @param p_cdtext the CD-TEXT object
Packit dd8086
  @param wdata the data
Packit dd8086
  @param i_data size of wdata
Packit dd8086
Packit dd8086
  @returns 0 on success, non-zero on failure
Packit dd8086
*/
Packit dd8086
int
Packit dd8086
cdtext_data_init(cdtext_t *p_cdtext, uint8_t *wdata, size_t i_data)
Packit dd8086
{
Packit dd8086
  uint8_t       *p_data;
Packit dd8086
  int           j;
Packit dd8086
  uint8_t       buffer[256];
Packit dd8086
  uint8_t       tab_buffer[256];
Packit dd8086
  int           i_buf = 0;
Packit dd8086
  int           i_block;
Packit dd8086
  int           i_seq = 0;
Packit dd8086
  int           i;
Packit dd8086
  cdtext_blocksize_t blocksize;
Packit dd8086
  char          *charset = NULL;
Packit dd8086
  uint8_t       cur_track;
Packit dd8086
Packit dd8086
  memset( buffer, 0, sizeof(buffer) );
Packit dd8086
  memset( tab_buffer, 0, sizeof(buffer) );
Packit dd8086
Packit dd8086
  p_data = wdata;
Packit dd8086
  if (i_data < CDTEXT_LEN_PACK || 0 != i_data % CDTEXT_LEN_PACK) {
Packit dd8086
    cdio_warn("CD-Text size is too small or not a multiple of pack size");
Packit dd8086
    return -1;
Packit dd8086
  }
Packit dd8086
Packit dd8086
#if 0
Packit dd8086
  for(i=0; i < i_data; i++)
Packit dd8086
    printf("%0x%c", wdata[i], ((i+1) % 18 == 0 ? '\n' : ' '));
Packit dd8086
#endif
Packit dd8086
Packit dd8086
Packit dd8086
  /* Iterate over blocks */
Packit dd8086
  i_block = -1;
Packit dd8086
  while(i_data > 0) {
Packit dd8086
    cdtext_pack_t pack;
Packit dd8086
    cdtext_read_pack(&pack, p_data);
Packit dd8086
Packit dd8086
    if (i_block != pack.block || i_seq != pack.seq) {
Packit dd8086
      cdtext_pack_t tpack;
Packit dd8086
      i_block = pack.block;
Packit dd8086
      if (i_block >= CDTEXT_NUM_BLOCKS_MAX) {
Packit dd8086
        cdio_warn("CD-TEXT: Invalid blocknumber %d.\n", i_block);
Packit dd8086
        return -1;
Packit dd8086
      }
Packit dd8086
      p_cdtext->block_i = i_block;
Packit dd8086
      i_seq = 0;
Packit dd8086
      memset( &blocksize, 0, CDTEXT_LEN_BLOCKSIZE);
Packit dd8086
Packit dd8086
      /* first read block size information for sanity checks and encoding */
Packit dd8086
      for(i=0; i <= i_data-CDTEXT_LEN_PACK; i+=CDTEXT_LEN_PACK) {
Packit dd8086
Packit dd8086
        if (p_data[i+0] == CDTEXT_PACK_BLOCKSIZE) {
Packit dd8086
          cdtext_read_pack(&tpack, p_data+i);
Packit dd8086
          switch (tpack.i_track) {
Packit dd8086
            case 0:
Packit dd8086
              blocksize.charcode      = tpack.text[0];
Packit dd8086
              blocksize.i_first_track = tpack.text[1];
Packit dd8086
              blocksize.i_last_track  = tpack.text[2];
Packit dd8086
              blocksize.copyright     = tpack.text[3];
Packit dd8086
              blocksize.i_packs[0]    = tpack.text[4];
Packit dd8086
              blocksize.i_packs[1]    = tpack.text[5];
Packit dd8086
              blocksize.i_packs[2]    = tpack.text[6];
Packit dd8086
              blocksize.i_packs[3]    = tpack.text[7];
Packit dd8086
              blocksize.i_packs[4]    = tpack.text[8];
Packit dd8086
              blocksize.i_packs[5]    = tpack.text[9];
Packit dd8086
              blocksize.i_packs[6]    = tpack.text[10];
Packit dd8086
              blocksize.i_packs[7]    = tpack.text[11];
Packit dd8086
              break;
Packit dd8086
            case 1:
Packit dd8086
              blocksize.i_packs[8]    = tpack.text[0];
Packit dd8086
              blocksize.i_packs[9]    = tpack.text[1];
Packit dd8086
              blocksize.i_packs[10]   = tpack.text[2];
Packit dd8086
              blocksize.i_packs[11]   = tpack.text[3];
Packit dd8086
              blocksize.i_packs[12]   = tpack.text[4];
Packit dd8086
              blocksize.i_packs[13]   = tpack.text[5];
Packit dd8086
              blocksize.i_packs[14]   = tpack.text[6];
Packit dd8086
              blocksize.i_packs[15]   = tpack.text[7];
Packit dd8086
              blocksize.lastseq[0]    = tpack.text[8];
Packit dd8086
              blocksize.lastseq[1]    = tpack.text[9];
Packit dd8086
              blocksize.lastseq[2]    = tpack.text[10];
Packit dd8086
              blocksize.lastseq[3]    = tpack.text[11];
Packit dd8086
              break;
Packit dd8086
            case 2:
Packit dd8086
              blocksize.lastseq[4]    = tpack.text[0];
Packit dd8086
              blocksize.lastseq[5]    = tpack.text[1];
Packit dd8086
              blocksize.lastseq[6]    = tpack.text[2];
Packit dd8086
              blocksize.lastseq[7]    = tpack.text[3];
Packit dd8086
              blocksize.langcode[0]   = tpack.text[4];
Packit dd8086
              blocksize.langcode[1]   = tpack.text[5];
Packit dd8086
              blocksize.langcode[2]   = tpack.text[6];
Packit dd8086
              blocksize.langcode[3]   = tpack.text[7];
Packit dd8086
              blocksize.langcode[4]   = tpack.text[8];
Packit dd8086
              blocksize.langcode[5]   = tpack.text[9];
Packit dd8086
              blocksize.langcode[6]   = tpack.text[10];
Packit dd8086
              blocksize.langcode[7]   = tpack.text[11];
Packit dd8086
              break;
Packit dd8086
          }
Packit dd8086
        }
Packit dd8086
      }
Packit dd8086
Packit dd8086
      if(blocksize.i_packs[15] == 3) {
Packit dd8086
        /* if there were 3 BLOCKSIZE packs */
Packit dd8086
        /* set copyright */
Packit dd8086
        p_cdtext->block[i_block].copyright = (0x03 == (blocksize.copyright & 0x03));
Packit dd8086
Packit dd8086
        /* set Language */
Packit dd8086
        if(blocksize.langcode[i_block] <= 0x7f)
Packit dd8086
          p_cdtext->block[i_block].language_code = blocksize.langcode[i_block];
Packit dd8086
Packit dd8086
        /* determine encoding */
Packit dd8086
        switch (blocksize.charcode){
Packit dd8086
          case CDTEXT_CHARCODE_ISO_8859_1:
Packit dd8086
            /* default */
Packit dd8086
            charset = (char *) "ISO-8859-1";
Packit dd8086
            break;
Packit dd8086
          case CDTEXT_CHARCODE_ASCII:
Packit dd8086
            charset = (char *) "ASCII";
Packit dd8086
            break;
Packit dd8086
          case CDTEXT_CHARCODE_SHIFT_JIS:
Packit dd8086
            charset = (char *) "SHIFT_JIS";
Packit dd8086
            break;
Packit dd8086
        }
Packit dd8086
Packit dd8086
        /* set track numbers */
Packit dd8086
        p_cdtext->block[i_block].first_track = blocksize.i_first_track;
Packit dd8086
        p_cdtext->block[i_block].last_track = blocksize.i_last_track;
Packit dd8086
Packit dd8086
      } else {
Packit dd8086
        cdio_warn("CD-TEXT: No blocksize information available for block %d.\n", i_block);
Packit dd8086
        return -1;
Packit dd8086
      }
Packit dd8086
Packit dd8086
    }
Packit dd8086
Packit dd8086
    cdtext_read_pack(&pack, p_data);
Packit dd8086
Packit dd8086
#ifndef _CDTEXT_DBCC
Packit dd8086
    if ( pack.db_chars ) {
Packit dd8086
      cdio_warn("CD-TEXT: Double-byte characters not supported");
Packit dd8086
      return -1;
Packit dd8086
    }
Packit dd8086
#endif
Packit dd8086
Packit dd8086
    cur_track = pack.i_track;
Packit dd8086
Packit dd8086
    /* read text packs first */
Packit dd8086
    j = 0;
Packit dd8086
    switch (pack.type) {
Packit dd8086
      case CDTEXT_PACK_GENRE:
Packit dd8086
        /* If pack.text starts with an unprintable character, it is likely to be the genre_code.
Packit dd8086
         * While the specification requires the first GENRE pack to start with the 2 byte genre code,
Packit dd8086
         * it is not specific about the following ones. */
Packit dd8086
        if (pack.text[0] <= 31) {
Packit dd8086
          j = 2;
Packit dd8086
          if (CDTEXT_GENRE_UNUSED == p_cdtext->block[i_block].genre_code)
Packit dd8086
            p_cdtext->block[i_block].genre_code = CDTEXT_GET_LEN16(pack.text);
Packit dd8086
        }
Packit dd8086
      case CDTEXT_PACK_TITLE:
Packit dd8086
      case CDTEXT_PACK_PERFORMER:
Packit dd8086
      case CDTEXT_PACK_SONGWRITER:
Packit dd8086
      case CDTEXT_PACK_COMPOSER:
Packit dd8086
      case CDTEXT_PACK_ARRANGER:
Packit dd8086
      case CDTEXT_PACK_MESSAGE:
Packit dd8086
      case CDTEXT_PACK_DISCID:
Packit dd8086
      case CDTEXT_PACK_UPC:
Packit dd8086
        while (j < CDTEXT_LEN_TEXTDATA) {
Packit dd8086
          /* not terminated */
Packit dd8086
Packit dd8086
          if ( i_buf+2 >= sizeof(buffer)) {
Packit dd8086
            cdio_warn("CD-TEXT: Field too long.");
Packit dd8086
            return -1;
Packit dd8086
          }
Packit dd8086
Packit dd8086
          /* if the first character is a TAB, copy the buffer */
Packit dd8086
          if ( i_buf == 0 && CDTEXT_COMPARE_CHAR(&pack.text[j], '\t', pack.db_chars)) {
Packit dd8086
            memcpy(tab_buffer, buffer, sizeof(tab_buffer));
Packit dd8086
          }
Packit dd8086
Packit dd8086
          if ( ! CDTEXT_COMPARE_CHAR(&pack.text[j], '\0', pack.db_chars)) {
Packit dd8086
            buffer[i_buf++] = pack.text[j];
Packit dd8086
            if(pack.db_chars)
Packit dd8086
              buffer[i_buf++] = pack.text[j+1];
Packit dd8086
          } else if(i_buf > 0) {
Packit dd8086
            /* if end of string */
Packit dd8086
Packit dd8086
            /* check if the buffer contains only the Tab Indicator */
Packit dd8086
            if ( CDTEXT_COMPARE_CHAR(buffer, '\t', pack.db_chars) ) {
Packit dd8086
              if ( cur_track <= blocksize.i_first_track ) {
Packit dd8086
                cdio_warn("CD-TEXT: Invalid use of Tab Indicator.");
Packit dd8086
                return -1;
Packit dd8086
              }
Packit dd8086
              memcpy(buffer, tab_buffer, sizeof(buffer));
Packit dd8086
            } else {
Packit dd8086
              buffer[i_buf++] = 0;
Packit dd8086
              if(pack.db_chars)
Packit dd8086
                buffer[i_buf++] = 0;
Packit dd8086
            }
Packit dd8086
Packit dd8086
            switch (pack.type) {
Packit dd8086
              case CDTEXT_PACK_TITLE:
Packit dd8086
                cdtext_set(p_cdtext, CDTEXT_FIELD_TITLE, buffer, cur_track, charset);
Packit dd8086
                break;
Packit dd8086
              case CDTEXT_PACK_PERFORMER:
Packit dd8086
                cdtext_set(p_cdtext, CDTEXT_FIELD_PERFORMER, buffer, cur_track, charset);
Packit dd8086
                break;
Packit dd8086
              case CDTEXT_PACK_SONGWRITER:
Packit dd8086
                cdtext_set(p_cdtext, CDTEXT_FIELD_SONGWRITER, buffer, cur_track, charset);
Packit dd8086
                break;
Packit dd8086
              case CDTEXT_PACK_COMPOSER:
Packit dd8086
                cdtext_set(p_cdtext, CDTEXT_FIELD_COMPOSER, buffer, cur_track, charset);
Packit dd8086
                break;
Packit dd8086
              case CDTEXT_PACK_ARRANGER:
Packit dd8086
                cdtext_set(p_cdtext, CDTEXT_FIELD_ARRANGER, buffer, cur_track, charset);
Packit dd8086
                break;
Packit dd8086
              case CDTEXT_PACK_MESSAGE:
Packit dd8086
                cdtext_set(p_cdtext, CDTEXT_FIELD_MESSAGE, buffer, cur_track, charset);
Packit dd8086
                break;
Packit dd8086
              case CDTEXT_PACK_DISCID:
Packit dd8086
                if (cur_track == 0)
Packit dd8086
                  cdtext_set(p_cdtext, CDTEXT_FIELD_DISCID, buffer, cur_track, NULL);
Packit dd8086
                break;
Packit dd8086
              case CDTEXT_PACK_GENRE:
Packit dd8086
                cdtext_set(p_cdtext, CDTEXT_FIELD_GENRE, buffer, cur_track, "ASCII");
Packit dd8086
                break;
Packit dd8086
              case CDTEXT_PACK_UPC:
Packit dd8086
                if (cur_track == 0)
Packit dd8086
                  cdtext_set(p_cdtext, CDTEXT_FIELD_UPC_EAN, buffer, cur_track, "ASCII");
Packit dd8086
                else
Packit dd8086
                  cdtext_set(p_cdtext, CDTEXT_FIELD_ISRC, buffer, cur_track, "ISO-8859-1");
Packit dd8086
                break;
Packit dd8086
            }
Packit dd8086
            i_buf = 0;
Packit dd8086
            ++cur_track;
Packit dd8086
Packit dd8086
          }
Packit dd8086
          if (pack.db_chars)
Packit dd8086
            j+=2;
Packit dd8086
          else
Packit dd8086
            j+=1;
Packit dd8086
        }
Packit dd8086
        break;
Packit dd8086
    }
Packit dd8086
    /* This would be the right place to parse TOC and TOC2 fields. */
Packit dd8086
Packit dd8086
    i_seq++;
Packit dd8086
    i_data-=CDTEXT_LEN_PACK;
Packit dd8086
    p_data+=CDTEXT_LEN_PACK;
Packit dd8086
  } /* end of while loop */
Packit dd8086
Packit dd8086
  p_cdtext->block_i = 0;
Packit dd8086
  return 0;
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Fills cdtext_pack_t with information read from p_data
Packit dd8086
Packit dd8086
  @param p_pack out
Packit dd8086
  @param p_data in
Packit dd8086
*/
Packit dd8086
int
Packit dd8086
cdtext_read_pack(cdtext_pack_t *p_pack, const uint8_t *p_data) {
Packit dd8086
  p_pack->type     = p_data[0];
Packit dd8086
  p_pack->i_track  = p_data[1];
Packit dd8086
  p_pack->seq      = p_data[2];
Packit dd8086
  p_pack->char_pos = p_data[3]        & 0x0F;
Packit dd8086
  p_pack->block    = (p_data[3] >> 4) & 0x07;
Packit dd8086
  p_pack->db_chars = (p_data[3] >> 7) & 0x01;
Packit dd8086
  p_pack->text[0]  = p_data[4];
Packit dd8086
  p_pack->text[1]  = p_data[5];
Packit dd8086
  p_pack->text[2]  = p_data[6];
Packit dd8086
  p_pack->text[3]  = p_data[7];
Packit dd8086
  p_pack->text[4]  = p_data[8];
Packit dd8086
  p_pack->text[5]  = p_data[9];
Packit dd8086
  p_pack->text[6]  = p_data[10];
Packit dd8086
  p_pack->text[7]  = p_data[11];
Packit dd8086
  p_pack->text[8]  = p_data[12];
Packit dd8086
  p_pack->text[9]  = p_data[13];
Packit dd8086
  p_pack->text[10] = p_data[14];
Packit dd8086
  p_pack->text[11] = p_data[15];
Packit dd8086
  p_pack->crc[0]   = p_data[16];
Packit dd8086
  p_pack->crc[1]   = p_data[17];
Packit dd8086
Packit dd8086
  return 0;
Packit dd8086
}