1 /*
2   Copyright (C) 2018 Thomas Schmitt
3   Copyright (C) 2004-2005, 2008, 2011, 2012, 2013 Rocky Bernstein <rocky@gnu.org>
4   toc reading routine adapted from cuetools
5   Copyright (C) 2003 Svend Sanjay Sorensen <ssorensen@fastmail.fm>
6 
7   This program is free software: you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation, either version 3 of the License, or
10   (at your option) any later version.
11 
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16 
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 # define __CDIO_CONFIG_H__ 1
24 #endif
25 
26 #include <cdio/cdtext.h>
27 #include <cdio/logging.h>
28 #include "cdtext_private.h"
29 #include <cdio/utf8.h>
30 
31 #ifdef HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif
34 
35 #ifdef HAVE_STRING_H
36 #include <string.h>
37 #endif
38 
39 #define _CDTEXT_DBCC
40 #define MAX_CDTEXT_GENRE_CODE     28
41 #define MAX_CDTEXT_LANGUAGE_CODE 127
42 
43 const char *cdtext_field[MAX_CDTEXT_FIELDS] =
44 {
45   "TITLE",
46   "PERFORMER",
47   "SONGWRITER",
48   "COMPOSER",
49   "MESSAGE",
50   "ARRANGER",
51   "ISRC",
52   "UPC_EAN",
53   "GENRE",
54   "DISC_ID",
55 };
56 
57 const char *cdtext_genre[MAX_CDTEXT_GENRE_CODE] =
58 {
59   "Not Used",
60   "Not Defined",
61   "Adult Contemporary",
62   "Alternative Rock",
63   "Childrens Music",
64   "Classical",
65   "Contemporary Christian",
66   "Country",
67   "Dance",
68   "Easy Listening",
69   "Erotic",
70   "Folk",
71   "Gospel",
72   "Hip Hop",
73   "Jazz",
74   "Latin",
75   "Musical",
76   "New Age",
77   "Opera",
78   "Operetta",
79   "Pop Music",
80   "Rap",
81   "Reggae",
82   "Rock Music",
83   "Rhythm & Blues",
84   "Sound Effects",
85   "Spoken Word",
86   "World Music"
87 };
88 
89 const char *cdtext_language[MAX_CDTEXT_LANGUAGE_CODE + 1] =
90 {
91   "Unknown",
92   "Albanian",
93   "Breton",
94   "Catalan",
95   "Croatian",
96   "Welsh",
97   "Czech",
98   "Danish",
99   "German",
100   "English",
101   "Spanish",
102   "Esperanto",
103   "Estonian",
104   "Basque",
105   "Faroese",
106   "French",
107   "Frisian",
108   "Irish",
109   "Gaelic",
110   "Galician",
111   "Icelandic",
112   "Italian",
113   "Lappish",
114   "Latin",
115   "Latvian",
116   "Luxembourgian",
117   "Lithuanian",
118   "Hungarian",
119   "Maltese",
120   "Dutch",
121   "Norwegian",
122   "Occitan",
123   "Polish",
124   "Portuguese",
125   "Romanian",
126   "Romansh",
127   "Serbian",
128   "Slovak",
129   "Slovenian",
130   "Finnish",
131   "Swedish",
132   "Turkish",
133   "Flemish",
134   "Wallon",
135   "", "", "", "", "", "", "", "", "", "",
136   "", "", "", "", "", "", "", "", "", "",
137   "", "", "", "", "",
138   "Zulu",
139   "Vietnamese",
140   "Uzbek",
141   "Urdu",
142   "Ukrainian",
143   "Thai",
144   "Telugu",
145   "Tatar",
146   "Tamil",
147   "Tadzhik",
148   "Swahili",
149   "SrananTongo",
150   "Somali",
151   "Sinhalese",
152   "Shona",
153   "Serbo-croat",
154   "Ruthenian",
155   "Russian",
156   "Quechua",
157   "Pushtu",
158   "Punjabi",
159   "Persian",
160   "Papamiento",
161   "Oriya",
162   "Nepali",
163   "Ndebele",
164   "Marathi",
165   "Moldavian",
166   "Malaysian",
167   "Malagasay",
168   "Macedonian",
169   "Laotian",
170   "Korean",
171   "Khmer",
172   "Kazakh",
173   "Kannada",
174   "Japanese",
175   "Indonesian",
176   "Hindi",
177   "Hebrew",
178   "Hausa",
179   "Gurani",
180   "Gujurati",
181   "Greek",
182   "Georgian",
183   "Fulani",
184   "Dari",
185   "Churash",
186   "Chinese",
187   "Burmese",
188   "Bulgarian",
189   "Bengali",
190   "Bielorussian",
191   "Bambora",
192   "Azerbaijani",
193   "Assamese",
194   "Armenian",
195   "Arabic",
196   "Amharic"
197 };
198 
199 /*!
200   Return string representation of given field type.
201 */
202 const char *
cdtext_field2str(cdtext_field_t i)203 cdtext_field2str(cdtext_field_t i)
204 {
205   if (i >= MAX_CDTEXT_FIELDS)
206     return "INVALID";
207   else
208     return cdtext_field[i];
209 }
210 
211 /*!
212   Return string representation of the given genre code.
213 */
214 const char *
cdtext_genre2str(cdtext_genre_t i)215 cdtext_genre2str(cdtext_genre_t i)
216 {
217   if (i >= MAX_CDTEXT_GENRE_CODE)
218     return "INVALID";
219   else
220     return cdtext_genre[i];
221 }
222 
223 /*!
224   Return string representation of the given language code.
225 */
226 const char *
cdtext_lang2str(cdtext_lang_t i)227 cdtext_lang2str(cdtext_lang_t i)
228 {
229   if (i <= CDTEXT_LANGUAGE_WALLON)
230     return cdtext_language[i];
231   else if (i >= CDTEXT_LANGUAGE_ZULU && i <= CDTEXT_LANGUAGE_AMHARIC)
232     return cdtext_language[i];
233   return "INVALID";
234 }
235 
236 /*!
237   Free memory associated with the given cdtext_t object.
238 
239   @param p_cdtext the CD-TEXT object
240 */
241 void
cdtext_destroy(cdtext_t * p_cdtext)242 cdtext_destroy(cdtext_t *p_cdtext)
243 {
244   cdtext_field_t k;
245   track_t j;
246   int i;
247 
248   if (!p_cdtext) return;
249   for (i=0; i<CDTEXT_NUM_BLOCKS_MAX; i++) {
250     for (j=0; j<CDTEXT_NUM_TRACKS_MAX; j++) {
251       for (k=0; k < MAX_CDTEXT_FIELDS; k++) {
252         if (p_cdtext->block[i].track[j].field[k]) {
253           free(p_cdtext->block[i].track[j].field[k]);
254           p_cdtext->block[i].track[j].field[k] = NULL;
255         }
256       }
257     }
258   }
259   free(p_cdtext);
260 }
261 
262 /*!
263   Returns a copy of the return value of cdtext_get_const or NULL.
264 
265   Must be freed using cdio_free() when done.
266   @see cdtext_get_const
267 */
268 char *
cdtext_get(const cdtext_t * p_cdtext,cdtext_field_t field,track_t track)269 cdtext_get(const cdtext_t *p_cdtext, cdtext_field_t field, track_t track)
270 {
271   const char *ret = cdtext_get_const(p_cdtext, field, track);
272   if (NULL == ret)
273     return NULL;
274   else
275     return strdup(ret);
276 }
277 
278 /*!
279   Returns value of the given field.
280 
281   NULL is returned if key is CDTEXT_INVALID or the field is not set.
282   Strings are encoded in UTF-8.
283 
284   @param p_cdtext the CD-TEXT object
285   @param field type of the field to return
286   @param track specifies the track, 0 stands for disc
287 */
288 const char *
cdtext_get_const(const cdtext_t * p_cdtext,cdtext_field_t field,track_t track)289 cdtext_get_const(const cdtext_t *p_cdtext, cdtext_field_t field, track_t track)
290 {
291   if (CDTEXT_FIELD_INVALID == field
292       || NULL == p_cdtext
293       || CDIO_CD_MAX_TRACKS < track)
294     return NULL;
295 
296   return p_cdtext->block[p_cdtext->block_i].track[track].field[field];
297 }
298 
299 /*!
300   Returns the discs genre code.
301 
302   @param p_cdtext the CD-TEXT object
303 */
304 cdtext_genre_t
cdtext_get_genre(const cdtext_t * p_cdtext)305 cdtext_get_genre(const cdtext_t *p_cdtext)
306 {
307   if (NULL == p_cdtext)
308     return CDTEXT_GENRE_UNUSED;
309   return p_cdtext->block[p_cdtext->block_i].genre_code;
310 }
311 
312 /*!
313   Returns the currently active language.
314 
315   @param p_cdtext the CD-TEXT object
316 */
317 cdtext_lang_t
cdtext_get_language(const cdtext_t * p_cdtext)318 cdtext_get_language(const cdtext_t *p_cdtext)
319 {
320   if (NULL == p_cdtext)
321     return CDTEXT_LANGUAGE_BLOCK_UNUSED;
322   return p_cdtext->block[p_cdtext->block_i].language_code;
323 }
324 
325 /*!
326   Returns the first track number.
327 
328   @param p_cdtext the CD-TEXT object
329 */
330 track_t
cdtext_get_first_track(const cdtext_t * p_cdtext)331 cdtext_get_first_track(const cdtext_t *p_cdtext)
332 {
333   if (NULL == p_cdtext)
334     return 0;
335   return p_cdtext->block[p_cdtext->block_i].first_track;
336 }
337 
338 /*!
339   Returns the last track number.
340 
341   @param p_cdtext the CD-TEXT object
342 */
343 track_t
cdtext_get_last_track(const cdtext_t * p_cdtext)344 cdtext_get_last_track(const cdtext_t *p_cdtext)
345 {
346   if (NULL == p_cdtext)
347     return 0;
348   return p_cdtext->block[p_cdtext->block_i].last_track;
349 }
350 
351 /*!
352   @deprecated Use cdtext_list_languages_v2()
353 
354   Returns a list of available languages or NULL.
355 
356   __WARNING__: The indices in the returned array _do not_ match the indexing
357            as expected by cdtext_set_language_index().
358            Use cdtext_select_language with the values of array elements.
359 
360   Internally the list is stored in a static array.
361 
362   @param p_cdtext the CD-TEXT object
363   @return NULL if p_cdtext is NULL.
364           Else an array of 8 cdtext_lang_t elements:
365           CDTEXT_LANGUAGE_UNKNOWN not only marks language code 0x00
366           but also invalid language codes and invalid language blocks.
367 */
368 cdtext_lang_t
cdtext_list_languages(const cdtext_t * p_cdtext)369 *cdtext_list_languages(const cdtext_t *p_cdtext)
370 {
371   static cdtext_lang_t avail[CDTEXT_NUM_BLOCKS_MAX];
372   int i, j=0;
373 
374   if (NULL == p_cdtext)
375     return NULL;
376 
377   for (i=0; i<CDTEXT_NUM_BLOCKS_MAX; i++)
378   {
379     avail[i] = CDTEXT_LANGUAGE_UNKNOWN;
380     if (CDTEXT_LANGUAGE_UNKNOWN != p_cdtext->block[i].language_code &&
381         CDTEXT_LANGUAGE_INVALID != p_cdtext->block[i].language_code &&
382         CDTEXT_LANGUAGE_BLOCK_UNUSED != p_cdtext->block[i].language_code)
383       avail[j++] = p_cdtext->block[i].language_code;
384   }
385 
386   return avail;
387 }
388 
389 /*!
390   Returns an array of available languages or NULL.
391   The index of an array element may be used to select the corresponding
392   language block by call cdtext_set_language_index().
393 
394   The return value is a pointer into the memory range of *p_cdtext.
395   Do not use it after having freed that memory range.
396 
397   @param p_cdtext the CD-TEXT object
398   @return NULL if p_cdtext is NULL, or an array of 8 cdtext_lang_t elements.
399 
400   If an enumeration is CDTEXT_LANGUAGE_INVALID, then the language block has an invalid
401   language code.
402 
403   If an enumeration is CDTEXT_LANGUAGE_BLOCK_UNUSED, then the block does not
404   exist on CD or could not be read in CD-TEXT for some reason.
405 
406   Otherwise, the enumeration of element will be a value in
407   CDTEXT_LANGUAGE_UNKNOWN to CDTEXT_LANGUAGE_AMHARIC, and is a block
408   in that language.
409 */
410 cdtext_lang_t
cdtext_list_languages_v2(cdtext_t * p_cdtext)411 *cdtext_list_languages_v2(cdtext_t *p_cdtext)
412 {
413   int i;
414 
415   if (NULL == p_cdtext)
416     return NULL;
417   for (i = 0; i < CDTEXT_NUM_BLOCKS_MAX; i++)
418   {
419     p_cdtext->languages[i] = p_cdtext->block[i].language_code;
420   }
421   return p_cdtext->languages;
422 }
423 
424 /*!
425   Select the given language by block index. See cdtext_list_languages_v2().
426   If the index is bad, or no language block with that index was read:
427   select the default language at index 0 and return false.
428 
429   @param p_cdtext the CD-TEXT object
430   @param idx      the desired index: 0 to 7.
431 
432   @return true on success, false if no language block is associated to idx
433 */
434 bool
cdtext_set_language_index(cdtext_t * p_cdtext,int idx)435 cdtext_set_language_index(cdtext_t *p_cdtext, int idx)
436 {
437   if (NULL == p_cdtext)
438     return false;
439   p_cdtext->block_i = 0;
440   if (idx < 0 || idx > 7)
441     return false;
442   if (p_cdtext->block[idx].language_code == CDTEXT_LANGUAGE_BLOCK_UNUSED)
443     return false;
444   p_cdtext->block_i = idx;
445   return true;
446 }
447 
448 /*!
449   Try to select the given language.
450   Select default language if specified is not available or invalid and
451   return false.
452 
453   @param p_cdtext the CD-TEXT object
454   @param language language identifier
455 
456   @return true on success, false if language is not available
457 */
458 bool
cdtext_select_language(cdtext_t * p_cdtext,cdtext_lang_t language)459 cdtext_select_language(cdtext_t *p_cdtext, cdtext_lang_t language)
460 {
461   if(NULL == p_cdtext)
462     return false;
463 
464   if (CDTEXT_LANGUAGE_BLOCK_UNUSED != language)
465   {
466     int i;
467     for (i=0; i<CDTEXT_NUM_BLOCKS_MAX; i++) {
468       if (language == p_cdtext->block[i].language_code) {
469         p_cdtext->block_i = i;
470         return true;
471       }
472     }
473   }
474   p_cdtext->block_i = 0;
475   return false;
476 }
477 
478 /*!
479   Initialize a new cdtext structure.
480 
481   When the structure is no longer needed, release the
482   resources using cdtext_delete.
483 
484 */
485 cdtext_t
cdtext_init(void)486 *cdtext_init(void)
487 {
488   cdtext_field_t k;
489   track_t j;
490   int i;
491   cdtext_t *p_cdtext;
492 
493   p_cdtext = (cdtext_t *) malloc(sizeof(struct cdtext_s));
494 
495   for (i=0; i<CDTEXT_NUM_BLOCKS_MAX; i++) {
496     for (j=0; j<CDTEXT_NUM_TRACKS_MAX; j++) {
497       for (k=0; k < MAX_CDTEXT_FIELDS; k++) {
498         p_cdtext->block[i].track[j].field[k] = NULL;
499       }
500     }
501     p_cdtext->block[i].genre_code = CDTEXT_GENRE_UNUSED;
502     p_cdtext->block[i].language_code = CDTEXT_LANGUAGE_BLOCK_UNUSED;
503   }
504 
505   p_cdtext->block_i = 0;
506 
507   return p_cdtext;
508 }
509 
510 /*!
511   Returns associated cdtext_field_t if field is a CD-TEXT keyword.
512 
513   Internal function.
514 
515   @param key key to test
516 
517   @return CDTEXT_INVALID if the given keyword is invalid
518 */
519 cdtext_field_t
cdtext_is_field(const char * key)520 cdtext_is_field (const char *key)
521 {
522   unsigned int i;
523 
524   for (i = 0; i < MAX_CDTEXT_FIELDS ; i++)
525     if (0 == strcmp(cdtext_field[i], key)) {
526       return i;
527     }
528   return CDTEXT_FIELD_INVALID;
529 }
530 
531 /*!
532   Return the language code of a given language string representation.
533   This is the inverse of cdtext_lang2str().
534 
535   @param lang language to look up
536 
537   @return if lang is among the possible results of cdtext_lang2str():
538           the cdtext_lang_t which is associated.
539           else: CDTEXT_LANGUAGE_INVALID
540 */
541 cdtext_lang_t
cdtext_str2lang(const char * lang)542 cdtext_str2lang (const char *lang)
543 {
544   unsigned int i;
545 
546   if(0 == lang[0]) /* The empty texts in cdtext_language[] are invalid */
547     return CDTEXT_LANGUAGE_INVALID;
548 
549   for (i = 0; i <= MAX_CDTEXT_LANGUAGE_CODE; i++)
550     if (0 == strcmp(cdtext_language[i], lang)) {
551       return i;
552     }
553   return CDTEXT_LANGUAGE_INVALID;
554 }
555 
556 /*!
557   Sets the given field at the given track to the given value.
558 
559   Recodes to UTF-8 if charset is not NULL.
560 
561   @param p_cdtext the CD-TEXT object
562   @param key field to set
563   @param value value to set
564   @param track track to work on
565   @param charset charset to convert from
566  */
567 void
cdtext_set(cdtext_t * p_cdtext,cdtext_field_t key,const uint8_t * value,track_t track,const char * charset)568 cdtext_set(cdtext_t *p_cdtext, cdtext_field_t key, const uint8_t *value,
569            track_t track, const char *charset)
570 {
571   if (NULL == value || key == CDTEXT_FIELD_INVALID
572       || CDIO_CD_MAX_TRACKS < track)
573     return;
574 
575   /* free old memory */
576   if (p_cdtext->block[p_cdtext->block_i].track[track].field[key])
577     free(p_cdtext->block[p_cdtext->block_i].track[track].field[key]);
578 
579   /* recode to UTF-8 */
580   if (NULL != charset) {
581     cdio_utf8_t *utf8_str = NULL;
582     cdio_charset_to_utf8((const char*) value, strlen((const char*)value),
583                         &utf8_str, charset);
584     p_cdtext->block[p_cdtext->block_i].track[track].field[key] = (char *)utf8_str;
585   } else
586     p_cdtext->block[p_cdtext->block_i].track[track].field[key] = strdup((const char *)value);
587 }
588 
589 #define CDTEXT_COMPARE_CHAR(buf, c, db) ((buf)[0] == c && (! db || (buf)[1] == c) )
590 
591 /*!
592   Read a binary CD-TEXT and fill a cdtext struct.
593 
594   @param p_cdtext the CD-TEXT object
595   @param wdata the data
596   @param i_data size of wdata
597 
598   @returns 0 on success, non-zero on failure
599 */
600 int
cdtext_data_init(cdtext_t * p_cdtext,uint8_t * wdata,size_t i_data)601 cdtext_data_init(cdtext_t *p_cdtext, uint8_t *wdata, size_t i_data)
602 {
603   uint8_t       *p_data;
604   int           j;
605   uint8_t       buffer[256];
606   uint8_t       tab_buffer[256];
607   int           i_buf = 0;
608   int           i_block;
609   int           i_seq = 0;
610   int           i;
611   cdtext_blocksize_t blocksize;
612   char          *charset = NULL;
613   uint8_t       cur_track;
614 
615   memset( buffer, 0, sizeof(buffer) );
616   memset( tab_buffer, 0, sizeof(buffer) );
617 
618   p_data = wdata;
619   if (i_data < CDTEXT_LEN_PACK || 0 != i_data % CDTEXT_LEN_PACK) {
620     cdio_warn("CD-Text size is too small or not a multiple of pack size");
621     return -1;
622   }
623 
624 #if 0
625   for(i=0; i < i_data; i++)
626     printf("%0x%c", wdata[i], ((i+1) % 18 == 0 ? '\n' : ' '));
627 #endif
628 
629 
630   /* Iterate over blocks */
631   i_block = -1;
632   while(i_data > 0) {
633     cdtext_pack_t pack;
634     cdtext_read_pack(&pack, p_data);
635 
636     if (i_block != pack.block || i_seq != pack.seq) {
637       cdtext_pack_t tpack;
638       i_block = pack.block;
639       if (i_block >= CDTEXT_NUM_BLOCKS_MAX) {
640         cdio_warn("CD-TEXT: Invalid blocknumber %d.\n", i_block);
641         return -1;
642       }
643       p_cdtext->block_i = i_block;
644       i_seq = 0;
645       memset( &blocksize, 0, CDTEXT_LEN_BLOCKSIZE);
646 
647       /* first read block size information for sanity checks and encoding */
648       for(i=0; i <= i_data-CDTEXT_LEN_PACK; i+=CDTEXT_LEN_PACK) {
649 
650         if (p_data[i+0] == CDTEXT_PACK_BLOCKSIZE) {
651           cdtext_read_pack(&tpack, p_data+i);
652           switch (tpack.i_track) {
653             case 0:
654               blocksize.charcode      = tpack.text[0];
655               blocksize.i_first_track = tpack.text[1];
656               blocksize.i_last_track  = tpack.text[2];
657               blocksize.copyright     = tpack.text[3];
658               blocksize.i_packs[0]    = tpack.text[4];
659               blocksize.i_packs[1]    = tpack.text[5];
660               blocksize.i_packs[2]    = tpack.text[6];
661               blocksize.i_packs[3]    = tpack.text[7];
662               blocksize.i_packs[4]    = tpack.text[8];
663               blocksize.i_packs[5]    = tpack.text[9];
664               blocksize.i_packs[6]    = tpack.text[10];
665               blocksize.i_packs[7]    = tpack.text[11];
666               break;
667             case 1:
668               blocksize.i_packs[8]    = tpack.text[0];
669               blocksize.i_packs[9]    = tpack.text[1];
670               blocksize.i_packs[10]   = tpack.text[2];
671               blocksize.i_packs[11]   = tpack.text[3];
672               blocksize.i_packs[12]   = tpack.text[4];
673               blocksize.i_packs[13]   = tpack.text[5];
674               blocksize.i_packs[14]   = tpack.text[6];
675               blocksize.i_packs[15]   = tpack.text[7];
676               blocksize.lastseq[0]    = tpack.text[8];
677               blocksize.lastseq[1]    = tpack.text[9];
678               blocksize.lastseq[2]    = tpack.text[10];
679               blocksize.lastseq[3]    = tpack.text[11];
680               break;
681             case 2:
682               blocksize.lastseq[4]    = tpack.text[0];
683               blocksize.lastseq[5]    = tpack.text[1];
684               blocksize.lastseq[6]    = tpack.text[2];
685               blocksize.lastseq[7]    = tpack.text[3];
686               blocksize.langcode[0]   = tpack.text[4];
687               blocksize.langcode[1]   = tpack.text[5];
688               blocksize.langcode[2]   = tpack.text[6];
689               blocksize.langcode[3]   = tpack.text[7];
690               blocksize.langcode[4]   = tpack.text[8];
691               blocksize.langcode[5]   = tpack.text[9];
692               blocksize.langcode[6]   = tpack.text[10];
693               blocksize.langcode[7]   = tpack.text[11];
694               break;
695           }
696         }
697       }
698 
699       if(blocksize.i_packs[15] == 3) {
700         cdtext_lang_t lcode;
701         /* if there were 3 BLOCKSIZE packs */
702         /* set copyright */
703         p_cdtext->block[i_block].copyright = (0x03 == (blocksize.copyright & 0x03));
704 
705         /* set Language */
706         lcode = blocksize.langcode[i_block];
707         if(lcode <= CDTEXT_LANGUAGE_WALLON ||
708           (lcode >= CDTEXT_LANGUAGE_ZULU && lcode <= CDTEXT_LANGUAGE_AMHARIC) )
709           p_cdtext->block[i_block].language_code = lcode;
710         else
711           p_cdtext->block[i_block].language_code = CDTEXT_LANGUAGE_INVALID;
712 
713         /* determine encoding */
714         switch (blocksize.charcode){
715           case CDTEXT_CHARCODE_ISO_8859_1:
716             /* default */
717             charset = (char *) "ISO-8859-1";
718             break;
719           case CDTEXT_CHARCODE_ASCII:
720             charset = (char *) "ASCII";
721             break;
722           case CDTEXT_CHARCODE_SHIFT_JIS:
723             charset = (char *) "SHIFT_JIS";
724             break;
725         }
726 
727         /* set track numbers */
728         p_cdtext->block[i_block].first_track = blocksize.i_first_track;
729         p_cdtext->block[i_block].last_track = blocksize.i_last_track;
730 
731       } else {
732         cdio_warn("CD-TEXT: No blocksize information available for block %d.\n", i_block);
733         return -1;
734       }
735 
736     }
737 
738     cdtext_read_pack(&pack, p_data);
739 
740 #ifndef _CDTEXT_DBCC
741     if ( pack.db_chars ) {
742       cdio_warn("CD-TEXT: Double-byte characters not supported");
743       return -1;
744     }
745 #endif
746 
747     cur_track = pack.i_track;
748 
749     /* read text packs first */
750     j = 0;
751     switch (pack.type) {
752       case CDTEXT_PACK_GENRE:
753         /* If pack.text starts with an unprintable character, it is likely to be the genre_code.
754          * While the specification requires the first GENRE pack to start with the 2 byte genre code,
755          * it is not specific about the following ones. */
756         if (pack.text[0] <= 31) {
757           j = 2;
758           if (CDTEXT_GENRE_UNUSED == p_cdtext->block[i_block].genre_code)
759             p_cdtext->block[i_block].genre_code = CDTEXT_GET_LEN16(pack.text);
760         }
761       case CDTEXT_PACK_TITLE:
762       case CDTEXT_PACK_PERFORMER:
763       case CDTEXT_PACK_SONGWRITER:
764       case CDTEXT_PACK_COMPOSER:
765       case CDTEXT_PACK_ARRANGER:
766       case CDTEXT_PACK_MESSAGE:
767       case CDTEXT_PACK_DISCID:
768       case CDTEXT_PACK_UPC:
769         while (j < CDTEXT_LEN_TEXTDATA) {
770           /* not terminated */
771 
772           if ( i_buf+2 >= sizeof(buffer)) {
773             cdio_warn("CD-TEXT: Field too long.");
774             return -1;
775           }
776 
777           /* if the first character is a TAB, copy the buffer */
778           if ( i_buf == 0 && CDTEXT_COMPARE_CHAR(&pack.text[j], '\t', pack.db_chars)) {
779             memcpy(tab_buffer, buffer, sizeof(tab_buffer));
780           }
781 
782           if ( ! CDTEXT_COMPARE_CHAR(&pack.text[j], '\0', pack.db_chars)) {
783             buffer[i_buf++] = pack.text[j];
784             if(pack.db_chars)
785               buffer[i_buf++] = pack.text[j+1];
786           } else if(i_buf > 0) {
787             /* if end of string */
788 
789             /* check if the buffer contains only the Tab Indicator */
790             if ( CDTEXT_COMPARE_CHAR(buffer, '\t', pack.db_chars) ) {
791               if ( cur_track <= blocksize.i_first_track ) {
792                 cdio_warn("CD-TEXT: Invalid use of Tab Indicator.");
793                 return -1;
794               }
795               memcpy(buffer, tab_buffer, sizeof(buffer));
796             } else {
797               buffer[i_buf++] = 0;
798               if(pack.db_chars)
799                 buffer[i_buf++] = 0;
800             }
801 
802             switch (pack.type) {
803               case CDTEXT_PACK_TITLE:
804                 cdtext_set(p_cdtext, CDTEXT_FIELD_TITLE, buffer, cur_track, charset);
805                 break;
806               case CDTEXT_PACK_PERFORMER:
807                 cdtext_set(p_cdtext, CDTEXT_FIELD_PERFORMER, buffer, cur_track, charset);
808                 break;
809               case CDTEXT_PACK_SONGWRITER:
810                 cdtext_set(p_cdtext, CDTEXT_FIELD_SONGWRITER, buffer, cur_track, charset);
811                 break;
812               case CDTEXT_PACK_COMPOSER:
813                 cdtext_set(p_cdtext, CDTEXT_FIELD_COMPOSER, buffer, cur_track, charset);
814                 break;
815               case CDTEXT_PACK_ARRANGER:
816                 cdtext_set(p_cdtext, CDTEXT_FIELD_ARRANGER, buffer, cur_track, charset);
817                 break;
818               case CDTEXT_PACK_MESSAGE:
819                 cdtext_set(p_cdtext, CDTEXT_FIELD_MESSAGE, buffer, cur_track, charset);
820                 break;
821               case CDTEXT_PACK_DISCID:
822                 if (cur_track == 0)
823                   cdtext_set(p_cdtext, CDTEXT_FIELD_DISCID, buffer, cur_track, NULL);
824                 break;
825               case CDTEXT_PACK_GENRE:
826                 cdtext_set(p_cdtext, CDTEXT_FIELD_GENRE, buffer, cur_track, "ASCII");
827                 break;
828               case CDTEXT_PACK_UPC:
829                 if (cur_track == 0)
830                   cdtext_set(p_cdtext, CDTEXT_FIELD_UPC_EAN, buffer, cur_track, "ASCII");
831                 else
832                   cdtext_set(p_cdtext, CDTEXT_FIELD_ISRC, buffer, cur_track, "ISO-8859-1");
833                 break;
834             }
835             i_buf = 0;
836             ++cur_track;
837 
838           }
839           if (pack.db_chars)
840             j+=2;
841           else
842             j+=1;
843         }
844         break;
845     }
846     /* This would be the right place to parse TOC and TOC2 fields. */
847 
848     i_seq++;
849     i_data-=CDTEXT_LEN_PACK;
850     p_data+=CDTEXT_LEN_PACK;
851   } /* end of while loop */
852 
853   p_cdtext->block_i = 0;
854   return 0;
855 }
856 
857 
858 /*!
859   Fills cdtext_pack_t with information read from p_data
860 
861   @param p_pack out
862   @param p_data in
863 */
864 int
cdtext_read_pack(cdtext_pack_t * p_pack,const uint8_t * p_data)865 cdtext_read_pack(cdtext_pack_t *p_pack, const uint8_t *p_data) {
866   p_pack->type     = p_data[0];
867   p_pack->i_track  = p_data[1];
868   p_pack->seq      = p_data[2];
869   p_pack->char_pos = p_data[3]        & 0x0F;
870   p_pack->block    = (p_data[3] >> 4) & 0x07;
871   p_pack->db_chars = (p_data[3] >> 7) & 0x01;
872   p_pack->text[0]  = p_data[4];
873   p_pack->text[1]  = p_data[5];
874   p_pack->text[2]  = p_data[6];
875   p_pack->text[3]  = p_data[7];
876   p_pack->text[4]  = p_data[8];
877   p_pack->text[5]  = p_data[9];
878   p_pack->text[6]  = p_data[10];
879   p_pack->text[7]  = p_data[11];
880   p_pack->text[8]  = p_data[12];
881   p_pack->text[9]  = p_data[13];
882   p_pack->text[10] = p_data[14];
883   p_pack->text[11] = p_data[15];
884   p_pack->crc[0]   = p_data[16];
885   p_pack->crc[1]   = p_data[17];
886 
887   return 0;
888 }
889