1 /*  cdrdao - write audio CD-Rs in disc-at-once mode
2  *
3  *  Copyright (C) 1998-2002  Andreas Mueller <andreas@daneb.de>
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 
20 #include "PQSubChannel16.h"
21 
22 #include <stdio.h>
23 #include <string.h>
24 #include <assert.h>
25 
26 #include "log.h"
27 
PQSubChannel16()28 PQSubChannel16::PQSubChannel16()
29 {
30   memset(data_, 0, 16);
31   type_ = QMODE1DATA;
32 }
33 
34 
~PQSubChannel16()35 PQSubChannel16::~PQSubChannel16()
36 {
37 }
38 
makeSubChannel(Type t)39 SubChannel *PQSubChannel16::makeSubChannel(Type t)
40 {
41   PQSubChannel16 *chan = new PQSubChannel16;
42 
43   chan->type_ = t;
44 
45   switch (t) {
46   case QMODE1TOC:
47   case QMODE1DATA:
48     chan->data_[0] = 0x01;
49     break;
50 
51   case QMODE2:
52     chan->data_[0] = 0x02;
53     break;
54 
55   case QMODE3:
56     chan->data_[0] = 0x03;
57     break;
58 
59   case QMODE5TOC:
60     chan->data_[0] = 0x05;
61     break;
62 
63   case QMODE_ILLEGAL:
64     chan->data_[0] = 0x00;
65     break;
66   }
67 
68   return chan;
69 }
70 
init(unsigned char * buf)71 void PQSubChannel16::init(unsigned char *buf)
72 {
73   memcpy(data_, buf, 16);
74 
75   switch (data_[0] & 0x0f) {
76   case 1:
77     type_ = QMODE1DATA;
78     break;
79 
80   case 2:
81     type_ = QMODE2;
82     break;
83 
84   case 3:
85     type_ = QMODE3;
86     break;
87 
88   case 5:
89     type_ = QMODE5TOC;
90     break;
91 
92   default:
93     type_ = QMODE_ILLEGAL;
94     break;
95   }
96 }
97 
makeSubChannel(unsigned char * buf)98 SubChannel *PQSubChannel16::makeSubChannel(unsigned char *buf)
99 {
100   PQSubChannel16 *chan = new PQSubChannel16;
101 
102   chan->init(buf);
103 
104   return chan;
105 }
106 
107 
data() const108 const unsigned char *PQSubChannel16::data() const
109 {
110   return data_;
111 }
112 
dataLength() const113 long PQSubChannel16::dataLength() const
114 {
115   return 16;
116 }
117 
118 // calculate the crc over Q sub channel bytes 0-9 and stores it in byte 10,11
calcCrc()119 void PQSubChannel16::calcCrc()
120 {
121   register unsigned short crc = 0;
122   register int i;
123 
124   for (i = 0; i < 10; i++) {
125     crc = crctab[(crc >> 8) ^ data_[i]] ^ (crc << 8);
126   }
127 
128   data_[10] = crc >> 8;
129   data_[11] = crc;
130 }
131 
checkCrc() const132 int PQSubChannel16::checkCrc() const
133 {
134   register unsigned short crc = 0;
135   register int i;
136 
137   if (!crcValid_) {
138     return 1;
139   }
140 
141   for (i = 0; i < 10; i++) {
142     crc = crctab[(crc >> 8) ^ data_[i]] ^ (crc << 8);
143   }
144 
145   if (data_[10] == (crc >> 8) && data_[11] == (crc & 0xff))
146     return 1;
147   else
148     return 0;
149 }
150 
151 // returns Q type
type() const152 SubChannel::Type PQSubChannel16::type() const
153 {
154   return type_;
155 }
156 
157 // set Q type
type(unsigned char type)158 void PQSubChannel16::type(unsigned char type)
159 {
160   switch (type & 0x0f) {
161   case 1:
162     type_ = QMODE1DATA;
163     break;
164 
165   case 2:
166     type_ = QMODE2;
167     break;
168 
169   case 3:
170     type_ = QMODE3;
171     break;
172 
173   case 5:
174     type_ = QMODE5TOC;
175     break;
176 
177   default:
178     type_ = QMODE_ILLEGAL;
179     break;
180   }
181 
182   data_[0] &= 0xf0;
183   data_[0] |= type & 0x0f;
184 }
185 
186 // sets P channel bit
pChannel(int f)187 void PQSubChannel16::pChannel(int f)
188 {
189   data_[15] = f != 0 ? 0x80 : 0;
190 }
191 
192 
193 // function for setting various Q sub channel fields
194 
ctl(int c)195 void PQSubChannel16::ctl(int c)
196 {
197   assert((c & 0x0f) == 0);
198 
199   data_[0] &= 0x0f;
200   data_[0] |= c & 0xf0;
201 }
202 
ctl() const203 unsigned char PQSubChannel16::ctl() const
204 {
205   return data_[0] >> 4;
206 }
207 
trackNr(int t)208 void PQSubChannel16::trackNr(int t)
209 {
210   assert(type_ == QMODE1DATA);
211   data_[1] = bcd(t);
212 }
213 
trackNr() const214 int PQSubChannel16::trackNr() const
215 {
216   assert(type_ == QMODE1DATA);
217   return bcd2int(data_[1]);
218 }
219 
indexNr(int i)220 void PQSubChannel16::indexNr(int i)
221 {
222   assert(type_ == QMODE1DATA);
223   data_[2] = bcd(i);
224 }
225 
indexNr() const226 int PQSubChannel16::indexNr() const
227 {
228   assert(type_ == QMODE1DATA);
229   return bcd2int(data_[2]);
230 }
231 
point(int p)232 void PQSubChannel16::point(int p)
233 {
234   assert(type_ == QMODE1TOC || type_ == QMODE5TOC);
235   data_[2] = bcd(p);
236 }
237 
min(int m)238 void PQSubChannel16::min(int m)
239 {
240   assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC);
241   data_[3] = bcd(m);
242 }
243 
min() const244 int PQSubChannel16::min() const
245 {
246   assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC);
247   return bcd2int(data_[3]);
248 }
249 
sec(int s)250 void PQSubChannel16::sec(int s)
251 {
252   assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC);
253   data_[4] = bcd(s);
254 }
255 
sec() const256 int PQSubChannel16::sec() const
257 {
258   assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC);
259   return bcd2int(data_[4]);
260 }
261 
frame(int f)262 void PQSubChannel16::frame(int f)
263 {
264   assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC);
265   data_[5] = bcd(f);
266 }
267 
frame() const268 int PQSubChannel16::frame() const
269 {
270   assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC);
271   return bcd2int(data_[5]);
272 }
273 
zero(int z)274 void PQSubChannel16::zero(int z)
275 {
276   assert(type_ == QMODE5TOC);
277   data_[6] = bcd(z);
278 }
279 
amin(int am)280 void PQSubChannel16::amin(int am)
281 {
282   assert(type_ == QMODE1DATA);
283   data_[7] = bcd(am);
284 }
285 
amin() const286 int PQSubChannel16::amin() const
287 {
288   assert(type_ == QMODE1DATA);
289   return bcd2int(data_[7]);
290 }
291 
asec(int as)292 void PQSubChannel16::asec(int as)
293 {
294   assert(type_ == QMODE1DATA);
295   data_[8] = bcd(as);
296 }
297 
asec() const298 int PQSubChannel16::asec() const
299 {
300   assert(type_ == QMODE1DATA);
301   return bcd2int(data_[8]);
302 }
303 
aframe(int af)304 void PQSubChannel16::aframe(int af)
305 {
306   assert(type_ == QMODE1DATA || type_ == QMODE2 || type_ == QMODE3);
307   data_[9] = bcd(af);
308 }
309 
aframe() const310 int PQSubChannel16::aframe() const
311 {
312   assert(type_ == QMODE1DATA || type_ == QMODE2 || type_ == QMODE3);
313   return bcd2int(data_[9]);
314 }
315 
pmin(int pm)316 void PQSubChannel16::pmin(int pm)
317 {
318   assert(type_ == QMODE1TOC || type_ == QMODE5TOC);
319   data_[7] = bcd(pm);
320 }
321 
psec(int ps)322 void PQSubChannel16::psec(int ps)
323 {
324   assert(type_ == QMODE1TOC || type_ == QMODE5TOC);
325   data_[8] = bcd(ps);
326 }
327 
pframe(int pf)328 void PQSubChannel16::pframe(int pf)
329 {
330   assert(type_ == QMODE1TOC || type_ == QMODE5TOC);
331   data_[9] = bcd(pf);
332 }
333 
catalog(char n1,char n2,char n3,char n4,char n5,char n6,char n7,char n8,char n9,char n10,char n11,char n12,char n13)334 void PQSubChannel16::catalog(char n1, char n2, char n3, char n4, char n5,
335 			     char n6, char n7, char n8, char n9, char n10,
336 			     char n11, char n12, char n13)
337 {
338   assert(type_ == QMODE2);
339 
340   encodeCatalogNumber(data_ + 1, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10,
341 		      n11, n12, n13);
342   data_[8] = 0;
343 }
344 
catalog() const345 const char *PQSubChannel16::catalog() const
346 {
347   static char buf[14];
348 
349   assert(type_ == QMODE2);
350 
351   decodeCatalogNumber(data_ + 1, &buf[0], &buf[1], &buf[2], &buf[3], &buf[4],
352 		      &buf[5], &buf[6], &buf[7], &buf[8], &buf[9], &buf[10],
353 		      &buf[11], &buf[12]);
354 
355   buf[13] = 0;
356 
357   return buf;
358 }
359 
isrc(char c1,char c2,char o1,char o2,char o3,char y1,char y2,char s1,char s2,char s3,char s4,char s5)360 void PQSubChannel16::isrc(char c1, char c2, char o1, char o2, char o3,
361 			  char y1, char y2, char s1, char s2, char s3,
362 			  char s4, char s5)
363 {
364   assert(type_ == QMODE3);
365 
366   encodeIsrcCode(data_ + 1, c1, c2, o1, o2, o3, y1, y2, s1, s2, s3, s4, s5);
367 }
368 
369 
isrc() const370 const char *PQSubChannel16::isrc() const
371 {
372   static char buf[13];
373 
374   assert(type_ == QMODE3);
375 
376   decodeIsrcCode(data_ + 1, &buf[0], &buf[1], &buf[2], &buf[3], &buf[4],
377 		 &buf[5], &buf[6], &buf[7], &buf[8], &buf[9], &buf[10],
378 		 &buf[11]);
379   buf[12] = 0;
380 
381   return buf;
382 }
383 
384 
print() const385 void PQSubChannel16::print() const
386 {
387   if (type_ != QMODE_ILLEGAL)
388     log_message(0, "P:%02x ", data_[15]);
389 
390   switch (type_) {
391   case QMODE1TOC:
392   case QMODE1DATA:
393   case QMODE5TOC:
394     log_message(0, "Q: (%02x) %02x,%02x %02x:%02x:%02x %02x %02x:%02x:%02x ",
395 	   data_[0], data_[1], data_[2], data_[3], data_[4], data_[5],
396 	   data_[6], data_[7], data_[8], data_[9]);
397     break;
398   case QMODE2:
399     log_message(0, "Q: (%02x) MCN: %s      %02x ", data_[0], catalog(), data_[9]);
400     break;
401   case QMODE3:
402     log_message(0, "Q: (%02x) ISRC: %s      %02x ", data_[0], isrc(), data_[9]);
403     break;
404   case QMODE_ILLEGAL:
405     log_message(0, "INVALID QMODE: %02x", data_[0]);
406     break;
407   }
408 
409   if (type_ != QMODE_ILLEGAL)
410     log_message(0, "%04x %d", (data_[10] << 8) | data_[11], checkCrc());
411 }
412 
checkConsistency()413 int PQSubChannel16::checkConsistency()
414 {
415   switch (type_) {
416   case QMODE1DATA:
417     if (!isBcd(data_[3]) || !isBcd(data_[4]) || !isBcd(data_[5]) ||
418 	!isBcd(data_[7]) || !isBcd(data_[8]) || !isBcd(data_[9]))
419       return 0;
420     break;
421 
422   case QMODE1TOC:
423   case QMODE2:
424   case QMODE3:
425   case QMODE5TOC:
426   case QMODE_ILLEGAL:
427     // no checks, yet
428     break;
429   }
430 
431   return SubChannel::checkConsistency();
432 }
433