|
|
|
/***************************************************************************
|
|
|
|
cdtext.c - description
|
|
|
|
-------------------
|
|
|
|
begin : Mon Feb 12 2001
|
|
|
|
copyright : (C) 2001,2003 by Alex Kern
|
|
|
|
email : alex.kern@gmx.de
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#ifdef libunicode
|
|
|
|
#include <tqunicode.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "include/wm_config.h"
|
|
|
|
#include "include/wm_struct.h"
|
|
|
|
#include "include/wm_cdrom.h"
|
|
|
|
#include "include/wm_database.h"
|
|
|
|
#include "include/wm_platform.h"
|
|
|
|
#include "include/wm_helpers.h"
|
|
|
|
#include "include/wm_cdinfo.h"
|
|
|
|
#include "include/wm_cdtext.h"
|
|
|
|
|
|
|
|
#define WM_MSG_CLASS WM_MSG_CLASS_MISC
|
|
|
|
|
|
|
|
/* local prototypes */
|
|
|
|
int free_cdtext_info_block(struct cdtext_info_block* cdtextinfoblock);
|
|
|
|
int free_cdtext_info(struct cdtext_info* cdtextinfo);
|
|
|
|
struct cdtext_info_block* malloc_cdtext_info_block(int count_of_tracks);
|
|
|
|
void get_data_from_cdtext_pack(
|
|
|
|
const struct cdtext_pack_data_header *pack,
|
|
|
|
const struct cdtext_pack_data_header *pack_previous,
|
|
|
|
cdtext_string *p_componente);
|
|
|
|
|
|
|
|
struct cdtext_info wm_cdtext_info = { 0, 0, 0, 0 };
|
|
|
|
|
|
|
|
int free_cdtext_info_block(struct cdtext_info_block* cdtextinfoblock)
|
|
|
|
{
|
|
|
|
if(cdtextinfoblock)
|
|
|
|
{
|
|
|
|
if(cdtextinfoblock->name)
|
|
|
|
free(cdtextinfoblock->name);
|
|
|
|
if(cdtextinfoblock->performer)
|
|
|
|
free(cdtextinfoblock->performer);
|
|
|
|
if(cdtextinfoblock->songwriter)
|
|
|
|
free(cdtextinfoblock->songwriter);
|
|
|
|
if(cdtextinfoblock->composer)
|
|
|
|
free(cdtextinfoblock->composer);
|
|
|
|
if(cdtextinfoblock->arranger)
|
|
|
|
free(cdtextinfoblock->arranger);
|
|
|
|
if(cdtextinfoblock->message)
|
|
|
|
free(cdtextinfoblock->message);
|
|
|
|
if(cdtextinfoblock->UPC_EAN_ISRC_code)
|
|
|
|
free(cdtextinfoblock->UPC_EAN_ISRC_code);
|
|
|
|
|
|
|
|
if(cdtextinfoblock->block_encoding_text)
|
|
|
|
free(cdtextinfoblock->block_encoding_text);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int free_cdtext_info(struct cdtext_info* cdtextinfo)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS,
|
|
|
|
"CDTEXT INFO: free_cdtext_info() called\n");
|
|
|
|
|
|
|
|
if(cdtextinfo)
|
|
|
|
{
|
|
|
|
for(i = 0; i < 8; i++)
|
|
|
|
{
|
|
|
|
if(cdtextinfo->blocks[i])
|
|
|
|
{
|
|
|
|
free_cdtext_info_block(cdtextinfo->blocks[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
memset(cdtextinfo, 0, sizeof(struct cdtext_info));
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct cdtext_info_block* malloc_cdtext_info_block(int count_of_tracks)
|
|
|
|
{
|
|
|
|
int memamount;
|
|
|
|
struct cdtext_info_block* lp_block;
|
|
|
|
|
|
|
|
lp_block = malloc(sizeof(struct cdtext_info_block));
|
|
|
|
if(!lp_block)
|
|
|
|
{
|
|
|
|
return (struct cdtext_info_block*)0;
|
|
|
|
}
|
|
|
|
memset(lp_block, 0, sizeof(struct cdtext_info_block));
|
|
|
|
|
|
|
|
memamount = count_of_tracks * sizeof(cdtext_string);
|
|
|
|
|
|
|
|
lp_block->name = malloc(memamount);
|
|
|
|
if(!lp_block->name)
|
|
|
|
return (struct cdtext_info_block*)free_cdtext_info_block(lp_block);
|
|
|
|
memset(lp_block->name, 0, memamount);
|
|
|
|
|
|
|
|
lp_block->performer = malloc(memamount);
|
|
|
|
if(!lp_block->performer)
|
|
|
|
return (struct cdtext_info_block*)free_cdtext_info_block(lp_block);
|
|
|
|
memset(lp_block->performer, 0, memamount);
|
|
|
|
|
|
|
|
lp_block->songwriter = malloc(memamount);
|
|
|
|
if(!lp_block->songwriter)
|
|
|
|
return (struct cdtext_info_block*)free_cdtext_info_block(lp_block);
|
|
|
|
memset(lp_block->songwriter, 0, memamount);
|
|
|
|
|
|
|
|
lp_block->composer = malloc(memamount);
|
|
|
|
if(!lp_block->composer)
|
|
|
|
return (struct cdtext_info_block*)free_cdtext_info_block(lp_block);
|
|
|
|
memset(lp_block->composer, 0, memamount);
|
|
|
|
|
|
|
|
lp_block->arranger = malloc(memamount);
|
|
|
|
if(!lp_block->arranger)
|
|
|
|
return (struct cdtext_info_block*)free_cdtext_info_block(lp_block);
|
|
|
|
memset(lp_block->arranger, 0, memamount);
|
|
|
|
|
|
|
|
lp_block->message = malloc(memamount);
|
|
|
|
if(!lp_block->message)
|
|
|
|
return (struct cdtext_info_block*)free_cdtext_info_block(lp_block);
|
|
|
|
memset(lp_block->message, 0, memamount);
|
|
|
|
|
|
|
|
lp_block->UPC_EAN_ISRC_code = malloc(memamount);
|
|
|
|
if(!lp_block->UPC_EAN_ISRC_code)
|
|
|
|
return (struct cdtext_info_block*)free_cdtext_info_block(lp_block);
|
|
|
|
memset(lp_block->UPC_EAN_ISRC_code, 0, memamount);
|
|
|
|
|
|
|
|
return lp_block;
|
|
|
|
}
|
|
|
|
|
|
|
|
void get_data_from_cdtext_pack(
|
|
|
|
const struct cdtext_pack_data_header *pack,
|
|
|
|
const struct cdtext_pack_data_header *pack_previous,
|
|
|
|
cdtext_string *p_componente)
|
|
|
|
{
|
|
|
|
|
|
|
|
int arr = pack->header_field_id2_tracknumber;
|
|
|
|
int i;
|
|
|
|
int language_block;
|
|
|
|
int unicode;
|
|
|
|
|
|
|
|
language_block = (pack->header_field_id4_block_no >> 4) & 0x07;
|
|
|
|
unicode = pack->header_field_id4_block_no & 0x80;
|
|
|
|
|
|
|
|
if(!unicode)
|
|
|
|
{
|
|
|
|
for(i = 0; i < DATAFIELD_LENGHT_IN_PACK; i++)
|
|
|
|
{
|
|
|
|
if(pack->text_data_field[i] == 0x00) /* end marker */
|
|
|
|
{
|
|
|
|
arr++;
|
|
|
|
}
|
|
|
|
else if(pack->text_data_field[i] == 0x09) /* repeat last marker */
|
|
|
|
{
|
|
|
|
/* ASSERT(arr > 0) */
|
|
|
|
strcat((char*)(p_componente[arr]), (char*)(p_componente[arr-1]));
|
|
|
|
arr++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strncat((char*)(p_componente[arr]), (char*)(&(pack->text_data_field[i])), 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef libunicode
|
|
|
|
else /* doublebytes ;-) */
|
|
|
|
{
|
|
|
|
for(i = 0; i < DATAFIELD_LENGHT_IN_PACK; i += 2)
|
|
|
|
{
|
|
|
|
if((Uchar)(pack->text_data_field[i]) == 0x0000) /* end marker */
|
|
|
|
{
|
|
|
|
arr++;
|
|
|
|
}
|
|
|
|
else if((Uchar)(pack->text_data_field[i]) == 0x0909) /* repeat last marker */
|
|
|
|
{
|
|
|
|
/* ASSERT(arr > 0) */
|
|
|
|
strcat((char*)(p_componente[arr]), (char*)(p_componente[arr-1]));
|
|
|
|
arr++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strncat((char*)(p_componente[arr]), u_uc_to_utf8((Uchar*)(&(pack->text_data_field[i]))), 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
else {
|
|
|
|
wm_lib_message(WM_MSG_LEVEL_ERROR | WM_MSG_CLASS, "can't handle unicode");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
struct cdtext_info*
|
|
|
|
get_glob_cdtext(struct wm_drive *d, int redo)
|
|
|
|
{
|
|
|
|
/* alloc cdtext_info */
|
|
|
|
|
|
|
|
unsigned char *buffer;
|
|
|
|
int buffer_length;
|
|
|
|
int ret;
|
|
|
|
int i;
|
|
|
|
struct cdtext_pack_data_header *pack, *pack_previous;
|
|
|
|
cdtext_string *p_componente;
|
|
|
|
struct cdtext_info_block *lp_block;
|
|
|
|
if(!d->proto || d->proto->gen_get_cdtext == NULL || d->proto->gen_get_trackcount == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!redo && wm_cdtext_info.valid) {
|
|
|
|
wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS, "CDTEXT DEBUG: recycle cdtext\n");
|
|
|
|
return &wm_cdtext_info;
|
|
|
|
} else
|
|
|
|
free_cdtext_info(&wm_cdtext_info);
|
|
|
|
|
|
|
|
lp_block = 0;
|
|
|
|
p_componente = 0;
|
|
|
|
buffer = 0;
|
|
|
|
buffer_length = 0;
|
|
|
|
|
|
|
|
ret = (d->proto->gen_get_cdtext)(d, &buffer, &buffer_length);
|
|
|
|
if(!ret)
|
|
|
|
{
|
|
|
|
(d->proto->gen_get_trackcount)(d, &(wm_cdtext_info.count_of_entries));
|
|
|
|
if( wm_cdtext_info.count_of_entries < 0 )
|
|
|
|
wm_cdtext_info.count_of_entries = 1;
|
|
|
|
else
|
|
|
|
wm_cdtext_info.count_of_entries++;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
pack = 0; /* NULL pointer*/
|
|
|
|
while(i < buffer_length)
|
|
|
|
{
|
|
|
|
pack_previous = pack;
|
|
|
|
pack = (struct cdtext_pack_data_header*)(buffer+i);
|
|
|
|
/* to implement: check_crc(pack); */
|
|
|
|
|
|
|
|
/* only for valid packs */
|
|
|
|
if(pack->header_field_id1_typ_of_pack >= 0x80 && pack->header_field_id1_typ_of_pack < 0x90)
|
|
|
|
{
|
|
|
|
int code, j;
|
|
|
|
wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS,
|
|
|
|
"CDTEXT DEBUG: valid packet at 0x%08X: 0x %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
|
|
|
i,
|
|
|
|
pack->header_field_id1_typ_of_pack,
|
|
|
|
pack->header_field_id2_tracknumber,
|
|
|
|
pack->header_field_id3_sequence,
|
|
|
|
pack->header_field_id4_block_no,
|
|
|
|
pack->text_data_field[0],
|
|
|
|
pack->text_data_field[1],
|
|
|
|
pack->text_data_field[2],
|
|
|
|
pack->text_data_field[3],
|
|
|
|
pack->text_data_field[4],
|
|
|
|
pack->text_data_field[5],
|
|
|
|
pack->text_data_field[6],
|
|
|
|
pack->text_data_field[7],
|
|
|
|
pack->text_data_field[8],
|
|
|
|
pack->text_data_field[9],
|
|
|
|
pack->text_data_field[10],
|
|
|
|
pack->text_data_field[11],
|
|
|
|
pack->crc_byte1,
|
|
|
|
pack->crc_byte2);
|
|
|
|
wm_cdtext_info.count_of_valid_packs++;
|
|
|
|
|
|
|
|
code = (pack->header_field_id4_block_no >> 4) & 0x07;
|
|
|
|
if(0 == lp_block || lp_block->block_code != code) /* find or create one new block */
|
|
|
|
{
|
|
|
|
lp_block = 0;
|
|
|
|
for(j = 0; j < MAX_LANGUAGE_BLOCKS && wm_cdtext_info.blocks[j] != 0 && 0 == lp_block; j++)
|
|
|
|
{
|
|
|
|
if(wm_cdtext_info.blocks[j]->block_code == code)
|
|
|
|
{
|
|
|
|
lp_block = wm_cdtext_info.blocks[j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(MAX_LANGUAGE_BLOCKS <= j)
|
|
|
|
{
|
|
|
|
free_cdtext_info(&wm_cdtext_info);
|
|
|
|
wm_lib_message(WM_MSG_LEVEL_ERROR | WM_MSG_CLASS,
|
|
|
|
"CDTEXT ERROR: more as 8 languageblocks defined\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(0 == lp_block)
|
|
|
|
{
|
|
|
|
/* make next new block */
|
|
|
|
lp_block = malloc_cdtext_info_block(wm_cdtext_info.count_of_entries);
|
|
|
|
if(0 == lp_block)
|
|
|
|
{
|
|
|
|
wm_lib_message(WM_MSG_LEVEL_ERROR | WM_MSG_CLASS,
|
|
|
|
"CDTEXT ERROR: out of memory, can't create a new language block\n");
|
|
|
|
free_cdtext_info(&wm_cdtext_info);
|
|
|
|
return NULL /*ENOMEM*/;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wm_cdtext_info.blocks[j] = lp_block;
|
|
|
|
wm_cdtext_info.blocks[j]->block_code = code;
|
|
|
|
wm_cdtext_info.blocks[j]->block_unicode = pack->header_field_id4_block_no & 0x80;
|
|
|
|
wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS,
|
|
|
|
"CDTEXT INFO: created a new language block; code %i, %s characters\n", code, lp_block->block_unicode?"doublebyte":"singlebyte");
|
|
|
|
/*
|
|
|
|
unsigned char block_encoding; not jet!
|
|
|
|
cdtext_string* block_encoding_text;
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(pack->header_field_id1_typ_of_pack)
|
|
|
|
{
|
|
|
|
case 0x80:
|
|
|
|
p_componente = (lp_block->name);
|
|
|
|
get_data_from_cdtext_pack(pack, pack_previous, p_componente);
|
|
|
|
break;
|
|
|
|
case 0x81:
|
|
|
|
p_componente = (lp_block->performer);
|
|
|
|
get_data_from_cdtext_pack(pack, pack_previous, p_componente);
|
|
|
|
break;
|
|
|
|
case 0x82:
|
|
|
|
p_componente = (lp_block->songwriter);
|
|
|
|
get_data_from_cdtext_pack(pack, pack_previous, p_componente);
|
|
|
|
break;
|
|
|
|
case 0x83:
|
|
|
|
p_componente = (lp_block->composer);
|
|
|
|
get_data_from_cdtext_pack(pack, pack_previous, p_componente);
|
|
|
|
break;
|
|
|
|
case 0x84:
|
|
|
|
p_componente = (lp_block->arranger);
|
|
|
|
get_data_from_cdtext_pack(pack, pack_previous, p_componente);
|
|
|
|
break;
|
|
|
|
case 0x85:
|
|
|
|
p_componente = (lp_block->message);
|
|
|
|
get_data_from_cdtext_pack(pack, pack_previous, p_componente);
|
|
|
|
break;
|
|
|
|
case 0x86:
|
|
|
|
memcpy((char*)(lp_block->binary_disc_identification_info),
|
|
|
|
(char*)(pack->text_data_field), DATAFIELD_LENGHT_IN_PACK);
|
|
|
|
break;
|
|
|
|
case 0x87:
|
|
|
|
memcpy((char*)(lp_block->binary_genreidentification_info),
|
|
|
|
(char*)(pack->text_data_field), DATAFIELD_LENGHT_IN_PACK);
|
|
|
|
break;
|
|
|
|
case 0x88:
|
|
|
|
wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS,
|
|
|
|
"CDTEXT INFO: PACK with code 0x88 (TOC)\n");
|
|
|
|
break;
|
|
|
|
case 0x89:
|
|
|
|
wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS,
|
|
|
|
"CDTEXT INFO: PACK with code 0x89 (second TOC)\n");
|
|
|
|
break;
|
|
|
|
case 0x8A:
|
|
|
|
case 0x8B:
|
|
|
|
case 0x8C:
|
|
|
|
wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS,
|
|
|
|
"CDTEXT INFO: PACK with code 0x%02X (reserved)\n", pack->header_field_id1_typ_of_pack);
|
|
|
|
break;
|
|
|
|
case 0x8D:
|
|
|
|
wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS,
|
|
|
|
"CDTEXT INFO: PACK with code 0x8D (for content provider only)\n");
|
|
|
|
break;
|
|
|
|
case 0x8E:
|
|
|
|
p_componente = (lp_block->UPC_EAN_ISRC_code);
|
|
|
|
get_data_from_cdtext_pack(pack, pack_previous, p_componente);
|
|
|
|
break;
|
|
|
|
case 0x8F:
|
|
|
|
memcpy((char*)(lp_block->binary_size_information),
|
|
|
|
(char*)(pack->text_data_field), DATAFIELD_LENGHT_IN_PACK);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS,
|
|
|
|
"CDTEXT ERROR: invalid packet at 0x%08X: 0x %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
|
|
|
i,
|
|
|
|
pack->header_field_id1_typ_of_pack,
|
|
|
|
pack->header_field_id2_tracknumber,
|
|
|
|
pack->header_field_id3_sequence,
|
|
|
|
pack->header_field_id4_block_no,
|
|
|
|
pack->text_data_field[0],
|
|
|
|
pack->text_data_field[1],
|
|
|
|
pack->text_data_field[2],
|
|
|
|
pack->text_data_field[3],
|
|
|
|
pack->text_data_field[4],
|
|
|
|
pack->text_data_field[5],
|
|
|
|
pack->text_data_field[6],
|
|
|
|
pack->text_data_field[7],
|
|
|
|
pack->text_data_field[8],
|
|
|
|
pack->text_data_field[9],
|
|
|
|
pack->text_data_field[10],
|
|
|
|
pack->text_data_field[11],
|
|
|
|
pack->crc_byte1,
|
|
|
|
pack->crc_byte2);
|
|
|
|
wm_cdtext_info.count_of_invalid_packs++;
|
|
|
|
}
|
|
|
|
i += sizeof(struct cdtext_pack_data_header);
|
|
|
|
} /* while */
|
|
|
|
}
|
|
|
|
|
|
|
|
if(0 == ret && wm_cdtext_info.count_of_valid_packs > 0)
|
|
|
|
wm_cdtext_info.valid = 1;
|
|
|
|
|
|
|
|
return &wm_cdtext_info;
|
|
|
|
}
|
|
|
|
|
|
|
|
void free_cdtext(void)
|
|
|
|
{
|
|
|
|
if (wm_cdtext_info.valid)
|
|
|
|
free_cdtext_info(&wm_cdtext_info);
|
|
|
|
}
|