2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)cdtext.c 1.10 04/03/01 Copyright 1999-2004 J. Schilling */
15 * Generic CD-Text support functions
17 * Copyright (c) 1999-2004 J. Schilling
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License version 2
22 * as published by the Free Software Foundation.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License along with
30 * this program; see the file COPYING. If not, write to the Free Software
31 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37 #include <unixstd.h> /* Include sys/types.h to make off_t available */
43 #include <usal/scsitransp.h> /* For write_leadin() */
49 #define PTI_TITLE 0x80 /* Album name and Track titles */
50 #define PTI_PERFORMER 0x81 /* Singer/player/conductor/orchestra */
51 #define PTI_SONGWRITER 0x82 /* Name of the songwriter */
52 #define PTI_COMPOSER 0x83 /* Name of the composer */
53 #define PTI_ARRANGER 0x84 /* Name of the arranger */
54 #define PTI_MESSAGE 0x85 /* Message from content provider or artist */
55 #define PTI_DISK_ID 0x86 /* Disk identification information */
56 #define PTI_GENRE 0x87 /* Genre identification / information */
57 #define PTI_TOC 0x88 /* TOC information */
58 #define PTI_TOC2 0x89 /* Second TOC */
59 #define PTI_RES_8A 0x8A /* Reserved 8A */
60 #define PTI_RES_8B 0x8B /* Reserved 8B */
61 #define PTI_RES_8C 0x8C /* Reserved 8C */
62 #define PTI_CLOSED_INFO 0x8D /* For internal use by content provider */
63 #define PTI_ISRC 0x8E /* UPC/EAN code of album and ISRC for tracks */
64 #define PTI_SIZE 0x8F /* Size information of the block */
68 typedef struct textpack {
69 Uchar pack_type; /* Pack Type indicator */
70 char track_no; /* Track Number (0..99) */
71 char seq_number; /* Sequence Number */
72 char block_number; /* Block # / Char pos */
73 char text[12]; /* CD-Text Data field */
74 char crc[2]; /* CRC 16 */
77 #define EXT_DATA 0x80 /* Extended data indicator in track_no */
78 #define DBCC 0x80 /* Double byte char indicator in block */
81 * CD-Text size example:
83 * 0 1 2 3 00 01 02 03 04 05 06 07 08 09 10 11 CRC16
85 * 8F 00 2B 00 01 01 0D 03 0C 0C 00 00 00 00 01 00 7B 3D
86 * 8F 01 2C 00 00 00 00 00 00 00 12 03 2D 00 00 00 DA B7
87 * 8F 02 2D 00 00 00 00 00 09 00 00 00 00 00 00 00 6A 24
93 * Pack Count 80= 12, 81 = 12, 86 = 1, 8e = 18, 8f = 3
98 typedef struct textsizes {
105 char language_codes[8];
108 typedef struct textargs {
119 BOOL checktextfile(char *fname);
120 static void setuptextdata(Uchar *bp, int len);
121 static BOOL cdtext_crc_ok(struct textpack *p);
122 void packtext(int tracks, track_t *trackp);
123 static BOOL anytext(int pack_type, int tracks, track_t *trackp);
124 static void fillup_pack(txtarg_t *ap);
125 static void fillpacks(txtarg_t *ap, char *from, int len, int track_no, int pack_type);
126 int write_cdtext(SCSI *usalp, cdr_t *dp, long startsec);
127 static void eight2six(Uchar *in, Uchar *out);
128 static void six2eight(Uchar *in, Uchar *out);
131 BOOL checktextfile(char *fname)
143 if ((f = fileopen(fname, "rb")) == NULL) {
144 errmsg("Cannot open '%s'.\n", fname);
148 j = fs % sizeof (struct textpack);
150 n = fileread(f, hbuf, 4);
153 errmsg("Cannot read '%s'.\n", fname);
155 errmsgno(EX_BAD, "File '%s' is too small for CD-Text.\n", fname);
158 len = hbuf[0] * 256 + hbuf[1];
162 errmsgno(EX_BAD, "Inconsistent CD-Text file '%s' length should be %d but is %lld\n",
163 fname, len+4, (Llong)fs);
167 errmsgno(EX_BAD, "Inconsistent CD-Text file '%s' not a multiple of pack length\n",
173 printf("Text len: %d\n", len);
176 errmsg("Cannot malloc CD-Text read buffer.\n");
179 n = fileread(f, bp, len);
181 tp = (struct textpack *)bp;
182 for (n = 0; n < len; n += sizeof (struct textpack), tp++) {
183 if (tp->pack_type < 0x80 || tp->pack_type > 0x8F) {
184 errmsgno(EX_BAD, "Illegal pack type 0x%02X pack #%ld in CD-Text file '%s'.\n",
185 tp->pack_type, (long)(n/sizeof (struct textpack)), fname);
188 crc = (tp->crc[0] & 0xFF) << 8 | (tp->crc[1] & 0xFF);
190 if (crc != calcCRC((Uchar *)tp, sizeof (*tp)-2)) {
191 if (cdtext_crc_ok(tp)) {
193 "Corrected CRC ERROR in pack #%ld (offset %d-%ld) in CD-Text file '%s'.\n",
194 (long)(n/sizeof (struct textpack)),
195 n+j, (long)(n+j+sizeof (struct textpack)),
198 errmsgno(EX_BAD, "CRC ERROR in pack #%ld (offset %d-%ld) in CD-Text file '%s'.\n",
199 (long)(n/sizeof (struct textpack)),
200 n+j, (long)(n+j+sizeof (struct textpack)),
206 setuptextdata(bp, len);
212 static void setuptextdata(Uchar *bp, int len)
220 printf("%ld packs %% 4 = %ld\n",
221 (long)(len/sizeof (struct textpack)),
222 (long)(len/sizeof (struct textpack)) % 4);
224 i = (len/sizeof (struct textpack)) % 4;
235 errmsg("Cannot malloc CD-Text write buffer.\n");
237 for (i = 0, j = 0; j < n; ) {
238 eight2six(&bp[i%len], &p[j]);
252 tp = (struct textpack *)bp;
254 for (n = 0; n < len; n += sizeof (struct textpack), tp++) {
255 crc = (tp->crc[0] & 0xFF) << 8 | (tp->crc[1] & 0xFF);
258 printf("Pack:%3d ", n/ sizeof (struct textpack));
259 printf("Pack type: %02X ", tp->pack_type & 0xFF);
260 printf("Track #: %2d ", tp->track_no & 0xFF);
261 printf("Sequence #:%3d ", tp->seq_number & 0xFF);
262 printf("Block #:%3d ", tp->block_number & 0xFF);
263 printf("CRC: %04X (%04X) ", crc, calcCRC((Uchar *)tp, sizeof (*tp)-2));
264 printf("Text: '%.12s'\n", tp->text);
265 movebytes(tp->text, p, 12);
268 printf("len total: %d\n", n);
269 f = fileopen("cdtext.out", "wctb");
271 filewrite(f, sbuf, p - sbuf);
279 static BOOL cdtext_crc_ok(struct textpack *p)
284 movebytes(p, &new, sizeof (struct textpack));
287 crc = calcCRC((Uchar *)&new, sizeof (struct textpack));
288 crc = flip_crc_error_corr((Uchar *)&new, sizeof (struct textpack), crc);
292 movebytes(&new, p, 18);
298 void packtext(int tracks, track_t *trackp)
303 struct textsizes tsize;
307 fillbytes(sbuf, sizeof (sbuf), 0);
308 fillbytes(&tsize, sizeof (tsize), 0);
310 tsize.charcode = CC_8859_1; /* ISO-8859-1 */
311 tsize.first_track = trackp[1].trackno;
312 tsize.last_track = trackp[1].trackno + tracks - 1;
313 #ifdef __FOUND_ON_COMMERCIAL_CD__
314 tsize.copyr_flags = 3; /* for titles/names */
316 tsize.copyr_flags = 0; /* no Copyr. limitat. */
318 tsize.pack_count[0x0F] = 3; /* 3 size packs */
319 tsize.last_seqnum[0] = 0; /* Start value only */
320 tsize.language_codes[0] = LANG_ENGLISH; /* English */
322 tp = (struct textpack *)sbuf;
329 for (type = 0; type <= 0x0E; type++) {
333 if (!anytext(type, tracks, trackp))
335 maxtrk = tsize.last_track;
339 for (i = 0; i <= maxtrk; i++) {
342 s = ((textptr_t *)s)->textcodes[type];
344 fillpacks(&targ, s, strlen(s)+1, i, 0x80| type);
346 fillpacks(&targ, "", 1, i, 0x80| type);
353 * targ.seqno overshoots by one and we add 3 size packs...
355 tsize.last_seqnum[0] = targ.seqno + 2;
357 for (i = 0; i < 3; i++) {
358 fillpacks(&targ, &((char *)(&tsize))[i*12], 12, i, 0x8f);
361 setuptextdata((Uchar *)sbuf, targ.seqno*18);
366 f = fileopen("cdtext.new", "wctb");
368 filewrite(f, sbuf, targ.seqno*18);
376 static BOOL anytext(int pack_type, int tracks, track_t *trackp)
381 for (i = 0; i <= tracks; i++) {
382 if (trackp[i].text == NULL)
384 p = ((textptr_t *)(trackp[i].text))->textcodes[pack_type];
385 if (p != NULL && *p != '\0')
391 static void fillup_pack(register txtarg_t *ap)
394 fillbytes(ap->p, &ap->tp->text[12] - ap->p, '\0');
395 fillcrc((Uchar *)ap->tp, sizeof (*ap->tp));
401 static void fillpacks(register txtarg_t *ap, register char *from, int len,
402 int track_no, int pack_type)
404 register int charpos;
406 register txtpack_t *tp;
414 tp->pack_type = pack_type;
415 if (pack_type != 0x8f)
416 ap->tsize->pack_count[pack_type & 0x0F]++;
417 tp->track_no = track_no;
418 tp->seq_number = ap->seqno++;
420 tp->block_number = charpos;
422 tp->block_number = 15;
424 for (; --len >= 0 && p < &tp->text[12]; charpos++) {
427 len++; /* Overshoot compensation */
429 if (p >= &tp->text[12]) {
430 fillcrc((Uchar *)tp, sizeof (*tp));
440 int write_cdtext(SCSI *usalp, cdr_t *dp, long startsec)
442 char *bp = (char *)textsub;
443 int buflen = textlen;
447 int secspt = textlen / 96;
448 int bytespt = textlen;
449 long maxdma = usalp->maxbuf;
455 if (maxdma >= (2*textlen)) {
457 * Try to make each CD-Text transfer use as much data
461 for (idx = 0; (idx + textlen) <= maxdma; idx += textlen)
462 movebytes(textsub, &bp[idx], textlen);
464 secspt = buflen / 96;
466 /*printf("textlen: %d buflen: %d secspt: %d\n", textlen, buflen, secspt);*/
467 } else if (maxdma < buflen) {
469 * We have more CD-Text data than we may transfer at once.
471 secspt = maxdma / 96;
472 bytespt = secspt * 96;
474 while (startsec < end) {
475 if ((end - startsec) < secspt) {
476 secspt = end - startsec;
477 bytespt = secspt * 96;
482 do { /* loop over CD-Text data buffer */
484 if ((idx + nbytes) > buflen) {
485 nbytes = buflen - idx;
488 /*printf("idx: %d nbytes: %d secs: %d startsec: %ld\n",*/
489 /*idx, nbytes, secs, startsec);*/
490 amount = write_secs(usalp, dp,
491 (char *)&bp[idx], startsec, nbytes, secs, FALSE);
493 printf("write CD-Text data: error after %ld bytes\n",
500 } while (idx < buflen && startsec < end);
507 * 3 input bytes (8 bit based) are converted into 4 output bytes (6 bit based).
509 static void eight2six(register Uchar *in, register Uchar *out)
514 out[0] = (c >> 2) & 0x3F;
515 out[1] = (c & 0x03) << 4;
518 out[1] |= (c & 0xF0) >> 4;
519 out[2] = (c & 0x0F) << 2;
522 out[2] |= (c & 0xC0) >> 6;
527 * 4 input bytes (6 bit based) are converted into 3 output bytes (8 bit based).
529 static void six2eight(register Uchar *in, register Uchar *out)