File indexing completed on 2024-04-21 04:54:22

0001 /***************************************************************************
0002                           cdtext.c  -  description
0003                              -------------------
0004     begin                : Mon Feb 12 2001
0005     copyright            : (C) 2001,2003 by Alex Kern
0006     email                : alex.kern@gmx.de
0007  ***************************************************************************/
0008 
0009 /***************************************************************************
0010  *                                                                         *
0011  *   This program is free software; you can redistribute it and/or modify  *
0012  *   it under the terms of the GNU General Public License as published by  *
0013  *   the Free Software Foundation; either version 2 of the License, or     *
0014  *   (at your option) any later version.                                   *
0015  *                                                                         *
0016  ***************************************************************************/
0017 
0018 #include <errno.h>
0019 #include <stdio.h>
0020 #include <unistd.h>
0021 #include <stdlib.h>
0022 #include <string.h>
0023 #include <sys/types.h>
0024 #ifdef libunicode
0025   #include <unicode.h>
0026 #endif
0027 
0028 #include "include/wm_config.h"
0029 #include "include/wm_struct.h"
0030 #include "include/wm_cdrom.h"
0031 #include "include/wm_platform.h"
0032 #include "include/wm_helpers.h"
0033 #include "include/wm_cdtext.h"
0034 #include "include/wm_scsi.h"
0035 
0036 #define WM_MSG_CLASS WM_MSG_CLASS_MISC
0037 
0038 /* local prototypes */
0039 int free_cdtext_info_block(struct cdtext_info_block* cdtextinfoblock);
0040 int free_cdtext_info(struct cdtext_info* cdtextinfo);
0041 struct cdtext_info_block* malloc_cdtext_info_block(int count_of_tracks);
0042 void get_data_from_cdtext_pack(
0043   const struct cdtext_pack_data_header *pack,
0044   cdtext_string *p_componente);
0045 
0046 struct cdtext_info wm_cdtext_info;
0047 
0048 int free_cdtext_info_block(struct cdtext_info_block* cdtextinfoblock)
0049 {
0050   if(cdtextinfoblock)
0051   {
0052     if(cdtextinfoblock->name)
0053       free(cdtextinfoblock->name);
0054     if(cdtextinfoblock->performer)
0055       free(cdtextinfoblock->performer);
0056     if(cdtextinfoblock->songwriter)
0057       free(cdtextinfoblock->songwriter);
0058     if(cdtextinfoblock->composer)
0059       free(cdtextinfoblock->composer);
0060     if(cdtextinfoblock->arranger)
0061       free(cdtextinfoblock->arranger);
0062     if(cdtextinfoblock->message)
0063       free(cdtextinfoblock->message);
0064     if(cdtextinfoblock->UPC_EAN_ISRC_code)
0065       free(cdtextinfoblock->UPC_EAN_ISRC_code);
0066 
0067     if(cdtextinfoblock->block_encoding_text)
0068       free(cdtextinfoblock->block_encoding_text);
0069   }
0070 
0071   return 0;
0072 }
0073 
0074 int free_cdtext_info(struct cdtext_info* cdtextinfo)
0075 {
0076   int i;
0077   wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS,
0078     "CDTEXT INFO: free_cdtext_info() called\n");
0079 
0080   if(cdtextinfo)
0081   {
0082     for(i = 0; i < 8; i++)
0083     {
0084       if(cdtextinfo->blocks[i])
0085       {
0086         free_cdtext_info_block(cdtextinfo->blocks[i]);
0087       }
0088     }
0089     memset(cdtextinfo, 0, sizeof(struct cdtext_info));
0090   }
0091 
0092   return 0;
0093 }
0094 
0095 struct cdtext_info_block* malloc_cdtext_info_block(int count_of_tracks)
0096 {
0097   int memamount;
0098   struct cdtext_info_block* lp_block;
0099 
0100   lp_block = malloc(sizeof(struct cdtext_info_block));
0101   if(!lp_block)
0102   {
0103     return (struct cdtext_info_block*)0;
0104   }
0105   memset(lp_block, 0, sizeof(struct cdtext_info_block));
0106 
0107   memamount = count_of_tracks * sizeof(cdtext_string);
0108 
0109   lp_block->name = malloc(memamount);
0110   if(!lp_block->name)
0111     goto bail_out;
0112   memset(lp_block->name, 0, memamount);
0113 
0114   lp_block->performer = malloc(memamount);
0115   if(!lp_block->performer)
0116     goto bail_out;
0117   memset(lp_block->performer, 0, memamount);
0118 
0119   lp_block->songwriter = malloc(memamount);
0120   if(!lp_block->songwriter)
0121     goto bail_out;
0122   memset(lp_block->songwriter, 0, memamount);
0123 
0124   lp_block->composer = malloc(memamount);
0125   if(!lp_block->composer)
0126     goto bail_out;
0127   memset(lp_block->composer, 0, memamount);
0128 
0129   lp_block->arranger = malloc(memamount);
0130   if(!lp_block->arranger)
0131     goto bail_out;
0132   memset(lp_block->arranger, 0, memamount);
0133 
0134   lp_block->message = malloc(memamount);
0135   if(!lp_block->message)
0136     goto bail_out;
0137   memset(lp_block->message, 0, memamount);
0138 
0139   lp_block->UPC_EAN_ISRC_code = malloc(memamount);
0140   if(!lp_block->UPC_EAN_ISRC_code)
0141     goto bail_out;
0142   memset(lp_block->UPC_EAN_ISRC_code, 0, memamount);
0143 
0144   return lp_block;
0145 
0146 bail_out:
0147   free_cdtext_info_block(lp_block);
0148   free(lp_block);
0149   return 0;
0150 }
0151 
0152 void get_data_from_cdtext_pack(
0153   const struct cdtext_pack_data_header *pack,
0154   cdtext_string *p_componente)
0155 {
0156 
0157   int arr = pack->header_field_id2_tracknumber;
0158   int i;
0159   int language_block;
0160   int unicode;
0161 
0162   language_block = (pack->header_field_id4_block_no >> 4) & 0x07;
0163   unicode = pack->header_field_id4_block_no & 0x80;
0164 
0165   if(!unicode)
0166   {
0167     for(i = 0; i < DATAFIELD_LENGHT_IN_PACK; i++)
0168     {
0169       if(pack->text_data_field[i] == 0x00) /* end marker */
0170       {
0171         arr++;
0172       }
0173       else if(pack->text_data_field[i] == 0x09) /* repeat last marker */
0174       {
0175         /* ASSERT(arr > 0) */
0176         strcat((char*)(p_componente[arr]), (char*)(p_componente[arr-1]));
0177         arr++;
0178       }
0179       else
0180       {
0181         strncat((char*)(p_componente[arr]), (char*)(&(pack->text_data_field[i])), 1);
0182       }
0183     }
0184   }
0185 #ifdef libunicode
0186   else /* doublebytes ;-) */
0187   {
0188     for(i = 0; i < DATAFIELD_LENGHT_IN_PACK; i += 2)
0189     {
0190       if((Uchar)(pack->text_data_field[i]) == 0x0000) /* end marker */
0191       {
0192         arr++;
0193       }
0194       else if((Uchar)(pack->text_data_field[i]) == 0x0909) /* repeat last marker */
0195       {
0196         /* ASSERT(arr > 0) */
0197         strcat((char*)(p_componente[arr]), (char*)(p_componente[arr-1]));
0198         arr++;
0199       }
0200       else
0201       {
0202         strncat((char*)(p_componente[arr]), u_uc_to_utf8((Uchar*)(&(pack->text_data_field[i]))), 1);
0203       }
0204     }
0205   }
0206 #else
0207   else {
0208      wm_lib_message(WM_MSG_LEVEL_ERROR | WM_MSG_CLASS, "cannot handle unicode");
0209   }
0210 #endif
0211 }
0212 
0213 struct cdtext_info *get_glob_cdtext(struct wm_drive *d, int redo)
0214 {
0215   /* alloc cdtext_info */
0216 
0217   unsigned char *buffer;
0218   int buffer_length;
0219   int ret;
0220   int i;
0221   struct cdtext_pack_data_header *pack, *pack_previous;
0222   cdtext_string *p_componente;
0223   struct cdtext_info_block *lp_block;
0224 
0225   if(!redo && wm_cdtext_info.valid) {
0226     wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS, "CDTEXT DEBUG: recycle cdtext\n");
0227     return &wm_cdtext_info;
0228   } else {
0229     free_cdtext_info(&wm_cdtext_info);
0230   }
0231 
0232   lp_block = 0;
0233   p_componente = 0;
0234   buffer = 0;
0235   buffer_length = 0;
0236 
0237   ret = wm_scsi_get_cdtext(d, &buffer, &buffer_length);
0238   if(!ret)
0239   {
0240     if(!d->proto.get_trackcount || d->proto.get_trackcount(d, &wm_cdtext_info.count_of_entries) < 0)
0241       wm_cdtext_info.count_of_entries = 1;
0242     else
0243       wm_cdtext_info.count_of_entries++;
0244 
0245     i = 0;
0246 
0247     pack = 0; /* NULL pointer*/
0248     while(i < buffer_length)
0249     {
0250       pack_previous = pack;
0251       pack = (struct cdtext_pack_data_header*)(buffer+i);
0252       /* to implement: check_crc(pack); */
0253 
0254       /* only for valid packs */
0255       if(pack->header_field_id1_typ_of_pack >= 0x80 && pack->header_field_id1_typ_of_pack < 0x90)
0256       {
0257         int code, j;
0258           wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS,
0259             "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",
0260             i,
0261             pack->header_field_id1_typ_of_pack,
0262             pack->header_field_id2_tracknumber,
0263             pack->header_field_id3_sequence,
0264             pack->header_field_id4_block_no,
0265             pack->text_data_field[0],
0266             pack->text_data_field[1],
0267             pack->text_data_field[2],
0268             pack->text_data_field[3],
0269             pack->text_data_field[4],
0270             pack->text_data_field[5],
0271             pack->text_data_field[6],
0272             pack->text_data_field[7],
0273             pack->text_data_field[8],
0274             pack->text_data_field[9],
0275             pack->text_data_field[10],
0276             pack->text_data_field[11],
0277             pack->crc_byte1,
0278             pack->crc_byte2);
0279         wm_cdtext_info.count_of_valid_packs++;
0280 
0281         code = (pack->header_field_id4_block_no >> 4) & 0x07;
0282         if(0 == lp_block || lp_block->block_code != code) /* find or create one new block */
0283         {
0284           lp_block = 0;
0285           for(j = 0; j < MAX_LANGUAGE_BLOCKS && wm_cdtext_info.blocks[j] != 0 && 0 == lp_block; j++)
0286           {
0287             if(wm_cdtext_info.blocks[j]->block_code == code)
0288             {
0289               lp_block = wm_cdtext_info.blocks[j];
0290             }
0291           }
0292 
0293           if(MAX_LANGUAGE_BLOCKS <= j)
0294           {
0295             free_cdtext_info(&wm_cdtext_info);
0296             wm_lib_message(WM_MSG_LEVEL_ERROR | WM_MSG_CLASS,
0297               "CDTEXT ERROR: more as 8 languageblocks defined\n");
0298             return NULL;
0299           }
0300 
0301           if(0 == lp_block)
0302           {
0303             /* make next new block */
0304             lp_block = malloc_cdtext_info_block(wm_cdtext_info.count_of_entries);
0305             if(0 == lp_block)
0306             {
0307               wm_lib_message(WM_MSG_LEVEL_ERROR | WM_MSG_CLASS,
0308                 "CDTEXT ERROR: out of memory, cannot create a new language block\n");
0309               free_cdtext_info(&wm_cdtext_info);
0310               return NULL /*ENOMEM*/;
0311             }
0312             else
0313             {
0314               wm_cdtext_info.blocks[j] = lp_block;
0315               wm_cdtext_info.blocks[j]->block_code = code;
0316               wm_cdtext_info.blocks[j]->block_unicode = pack->header_field_id4_block_no & 0x80;
0317               wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS,
0318                 "CDTEXT INFO: created a new language block; code %i, %s characters\n", code, lp_block->block_unicode?"doublebyte":"singlebyte");
0319 /*
0320   unsigned char block_encoding; not jet!
0321   cdtext_string* block_encoding_text;
0322 */
0323             }
0324           }
0325         }
0326       }
0327 
0328       switch(pack->header_field_id1_typ_of_pack)
0329       {
0330         case 0x80:
0331           p_componente = (lp_block->name);
0332           get_data_from_cdtext_pack(pack, p_componente);
0333           break;
0334         case 0x81:
0335           p_componente = (lp_block->performer);
0336           get_data_from_cdtext_pack(pack, p_componente);
0337           break;
0338         case 0x82:
0339           p_componente = (lp_block->songwriter);
0340           get_data_from_cdtext_pack(pack, p_componente);
0341           break;
0342         case 0x83:
0343           p_componente = (lp_block->composer);
0344           get_data_from_cdtext_pack(pack, p_componente);
0345           break;
0346         case 0x84:
0347           p_componente = (lp_block->arranger);
0348           get_data_from_cdtext_pack(pack, p_componente);
0349           break;
0350         case 0x85:
0351           p_componente = (lp_block->message);
0352           get_data_from_cdtext_pack(pack, p_componente);
0353           break;
0354         case 0x86:
0355           memcpy((char*)(lp_block->binary_disc_identification_info),
0356           (char*)(pack->text_data_field),  DATAFIELD_LENGHT_IN_PACK);
0357           break;
0358         case 0x87:
0359           memcpy((char*)(lp_block->binary_genreidentification_info),
0360           (char*)(pack->text_data_field),  DATAFIELD_LENGHT_IN_PACK);
0361           break;
0362         case 0x88:
0363          wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS,
0364            "CDTEXT INFO: PACK with code 0x88 (TOC)\n");
0365           break;
0366         case 0x89:
0367          wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS,
0368            "CDTEXT INFO: PACK with code 0x89 (second TOC)\n");
0369           break;
0370         case 0x8A:
0371         case 0x8B:
0372         case 0x8C:
0373           wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS,
0374             "CDTEXT INFO: PACK with code 0x%02X (reserved)\n", pack->header_field_id1_typ_of_pack);
0375           break;
0376         case 0x8D:
0377           wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS,
0378             "CDTEXT INFO: PACK with code 0x8D (for content provider only)\n");
0379           break;
0380         case 0x8E:
0381           p_componente = (lp_block->UPC_EAN_ISRC_code);
0382           get_data_from_cdtext_pack(pack, p_componente);
0383           break;
0384         case 0x8F:
0385           memcpy((char*)(lp_block->binary_size_information),
0386           (char*)(pack->text_data_field), DATAFIELD_LENGHT_IN_PACK);
0387           break;
0388         default:
0389           wm_lib_message(WM_MSG_LEVEL_DEBUG | WM_MSG_CLASS,
0390             "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",
0391             i,
0392             pack->header_field_id1_typ_of_pack,
0393             pack->header_field_id2_tracknumber,
0394             pack->header_field_id3_sequence,
0395             pack->header_field_id4_block_no,
0396             pack->text_data_field[0],
0397             pack->text_data_field[1],
0398             pack->text_data_field[2],
0399             pack->text_data_field[3],
0400             pack->text_data_field[4],
0401             pack->text_data_field[5],
0402             pack->text_data_field[6],
0403             pack->text_data_field[7],
0404             pack->text_data_field[8],
0405             pack->text_data_field[9],
0406             pack->text_data_field[10],
0407             pack->text_data_field[11],
0408             pack->crc_byte1,
0409             pack->crc_byte2);
0410           wm_cdtext_info.count_of_invalid_packs++;
0411       }
0412       i += sizeof(struct cdtext_pack_data_header);
0413     } /* while */
0414   }
0415 
0416   if(0 == ret && wm_cdtext_info.count_of_valid_packs > 0)
0417     wm_cdtext_info.valid = 1;
0418 
0419   return &wm_cdtext_info;
0420 }
0421 
0422 void free_cdtext(void)
0423 {
0424   if (wm_cdtext_info.valid)
0425     free_cdtext_info(&wm_cdtext_info);
0426 }